/* ==========================================================================
   Revogen Framework CSS
   ÙŠÙØ­Ù…ÙŽÙ‘Ù„ Ø¨Ø¹Ø¯ BootstrapØŒ Ù‚Ø¨Ù„ Ø§Ù„Ø«ÙŠÙ…Ø§Øª ÙˆØ§Ù„ØªØ®ØµÙŠØµØ§Øª.

   ÙŠØ­ÙˆÙŠ:
   1. ØªØ¹Ø±ÙŠÙØ§Øª Ø§Ù„Ø®Ø· (Tajawal) - subsets Ù…Ù†ÙØµÙ„Ø© Ù„Ø£Ø¯Ø§Ø¡ Ø£ÙØ¶Ù„
   2. Design Tokens (CSS variables) - Ù‚Ø§Ø¨Ù„Ø© Ù„Ù„ØªØ¬Ø§ÙˆØ² Ù…Ù† Ø§Ù„Ø«ÙŠÙ…
   3. Dark mode tokens
   4. ØªØ­Ø³ÙŠÙ†Ø§Øª Ø¹Ø§Ù…Ø© Ø¹Ù„Ù‰ Bootstrap (RTL refinements, typography)
   ========================================================================== */


/* ==========================================================================
   1. Font: Tajawal
   subset Arabic ÙŠÙØ­Ù…ÙŽÙ‘Ù„ ÙÙ‚Ø· Ù„Ùˆ ØµÙØ­Ø© ØªØ­ÙˆÙŠ Ø­Ø±ÙˆÙ Ø¹Ø±Ø¨ÙŠØ©
   subset Latin ÙŠÙØ­Ù…ÙŽÙ‘Ù„ ÙÙ‚Ø· Ù„Ùˆ ØµÙØ­Ø© ØªØ­ÙˆÙŠ Ø­Ø±ÙˆÙ Ù„Ø§ØªÙŠÙ†ÙŠØ©
   ========================================================================== */

@font-face {
    font-family: 'Tajawal';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/Tajawal-400-arabic.woff2') format('woff2');
    unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

@font-face {
    font-family: 'Tajawal';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/Tajawal-400-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Tajawal';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/Tajawal-500-arabic.woff2') format('woff2');
    unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

@font-face {
    font-family: 'Tajawal';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/Tajawal-500-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Tajawal';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/Tajawal-700-arabic.woff2') format('woff2');
    unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

@font-face {
    font-family: 'Tajawal';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/Tajawal-700-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   1b. Optional fonts — selectable from /admin/settings (Appearance tab).
   Bundled offline (no CDN). Default stays Tajawal; admin can switch.
   ========================================================================== */
/* "Droid Arabic Kufi" was deprecated by Google; the modern successor is
   "Noto Kufi Arabic" (same kufi aesthetic, actively maintained, full
   coverage). We keep the user-visible label "Droid Arabic Kufi" but ship
   the working Noto Kufi font behind it. Variable axis covers 400-900. */
@font-face {
    font-family: 'Droid Arabic Kufi';
    font-style: normal; font-weight: 400 900; font-display: swap;
    src: url('../fonts/NotoKufiArabic-arabic.woff2') format('woff2');
    unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
    font-family: 'Cairo';
    font-style: normal; font-weight: 400 900; font-display: swap;
    src: url('../fonts/Cairo-arabic-400.woff2') format('woff2');
    unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
    font-family: 'Almarai';
    font-style: normal; font-weight: 400; font-display: swap;
    src: url('../fonts/Almarai-arabic-400.woff2') format('woff2');
    unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
    font-family: 'Almarai';
    font-style: normal; font-weight: 700; font-display: swap;
    src: url('../fonts/Almarai-arabic-700.woff2') format('woff2');
    unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
    font-family: 'IBM Plex Sans Arabic';
    font-style: normal; font-weight: 400; font-display: swap;
    src: url('../fonts/IBMPlexSansArabic-arabic-400.woff2') format('woff2');
    unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
    font-family: 'IBM Plex Sans Arabic';
    font-style: normal; font-weight: 700; font-display: swap;
    src: url('../fonts/IBMPlexSansArabic-arabic-700.woff2') format('woff2');
    unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}


/* ==========================================================================
   2. Design Tokens
   Ù‚Ø§Ø¨Ù„Ø© Ù„Ù„ØªØ¬Ø§ÙˆØ² ÙÙŠ Ø§Ù„Ø«ÙŠÙ…Ø§Øª (public/assets/themes/*.css)
   ========================================================================== */

:root {
    /* Typography */
    --font-primary: 'Tajawal', 'Cairo', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono: ui-monospace, 'Cascadia Code', 'SF Mono', Menlo, Consolas, monospace;

    --text-xs:   0.75rem;
    --text-sm:   0.875rem;
    --text-base: 1rem;
    --text-lg:   1.125rem;
    --text-xl:   1.25rem;
    --text-2xl:  1.5rem;
    --text-3xl:  1.875rem;

    /* Neutral palette */
    --color-bg:         #ffffff;
    --color-bg-alt:     #f8f9fa;
    --color-bg-hover:   #f1f3f5;
    --color-border:     #e9ecef;
    --color-border-strong: #dee2e6;
    --color-text:       #212529;
    --color-text-muted: #6c757d;
    /* OP-46 (2026-06-11 theme-polish): 868e96 was 3.32:1 on white (sub-AA
       across labels/empty-dashes/bell-times/report-secondary). 6f7880 ≈4.5
       while staying lighter than --color-text-muted (6c757d) so the
       3-tier hierarchy survives. REVERT: 868e96. */
    --color-text-soft:  rgb(111 120 128);

    /* Accent = indigo (Ù…ÙÙˆØ­ÙŽÙ‘Ø¯ Ø¹Ø¨Ø± Ø§Ù„Ø¥Ø·Ø§Ø± ÙƒÙ„Ù‘Ù‡) */
    --color-accent:       #6366f1;   /* indigo-500 */
    --color-accent-hover: #4f46e5;   /* indigo-600 */
    --color-accent-soft:  #eef2ff;   /* indigo-50 */
    /* OP-27 (2026-06-11 theme-polish): two companion tokens.
       --color-accent-fg  = ink for text/icons sitting ON solid accent
       surfaces (filled buttons, badges). White over indigo-500 in light.
       --color-accent-ink = accent-coloured TEXT over page backgrounds,
       mixed toward --color-text so it stays readable (pure accent text
       washes out). -ink re-resolves in dark via the dark accent/text
       tokens; -fg is overridden there explicitly.
       REVERT: delete these two declarations + the dark-block pair. */
    --color-accent-fg:  white;
    --color-accent-ink: color-mix(in srgb, var(--color-accent) 58%, var(--color-text));

    /* Semantic (Tailwind modern) */
    --color-success: #16a34a;   /* green-600 */
    --color-warning: #ca8a04;   /* yellow-600 */
    --color-danger:  #dc2626;   /* red-600 */
    /* OP-29 (2026-06-11): deep red that does NOT lighten in dark — for
       solid danger surfaces carrying white text (admin pill). */
    --color-danger-deep: rgb(220 38 38);   /* red-600 ثابت */
    --color-info:    #0891b2;   /* cyan-600 */

    /* FR-143 conditional-formatting palette (owner 2026-06-15) — extends the 5
       semantic colors with more distinct, contrast-tuned hues. Theme-aware
       (dark variants in the dark block). Defined as tokens (NOT raw hex in
       components); the 5 semantic ones are aliased so the whole palette lives
       under ONE namespace and the selector/engine iterate it uniformly. */
    --rvg-fmt-accent:  var(--color-accent);
    --rvg-fmt-success: var(--color-success);
    --rvg-fmt-info:    var(--color-info);
    --rvg-fmt-warning: var(--color-warning);
    --rvg-fmt-danger:  var(--color-danger);
    --rvg-fmt-purple:  rgb(147 51 234);   /* violet-600  */
    --rvg-fmt-teal:    rgb(13 148 136);   /* teal-600    */
    --rvg-fmt-pink:    rgb(219 39 119);   /* pink-600    */
    --rvg-fmt-orange:  rgb(234 88 12);   /* orange-600  */
    --rvg-fmt-lime:    rgb(101 163 13);   /* lime-600    */
    --rvg-fmt-brown:   rgb(146 64 14);   /* amber-800   */
    --rvg-fmt-slate:   rgb(71 85 105);   /* slate-600   */

    /* Spacing (4px base) */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-8: 2rem;
    --space-10: 2.5rem;

    /* Radius */
    --radius-sm: 4px;
    --radius-md: 6px;
    --radius-lg: 8px;
    --radius-xl: 12px;

    /* Shadows - Ø®Ø§ÙØªØ© */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
    --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.06);
    --shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.08);

    /* Transitions */
    --transition: 150ms ease;
    --transition-slow: 300ms ease;

    /* FR-119 (2026-06-04) — Unified modal tokens.
       Single source of truth for every modal in the framework: backdrop
       colour, blur, AND large-modal width. ANY new modal MUST reference
       these tokens — never hard-code rgba/vw values. The backdrop tint
       is theme-aware (color-mix(text 50%, transparent)) so it warms
       slightly in dark mode without separate dark-mode rules. */
    --rvg-modal-backdrop-bg:    color-mix(in srgb, var(--color-text) 50%, transparent);
    --rvg-modal-backdrop-blur:  blur(2px);
    --rvg-modal-width-large:    90vw;
}


/* ==========================================================================
   3. Dark mode
   Ù…ÙÙØ¹ÙŽÙ‘Ù„ Ø¹Ø¨Ø± data-bs-theme="dark" (Ù…ØªÙˆØ§ÙÙ‚ Ù…Ø¹ Bootstrap 5.3+)
   ========================================================================== */

[data-bs-theme="dark"] {
    --color-bg:         #18181b;
    --color-bg-alt:     #27272a;
    --color-bg-hover:   #3f3f46;
    --color-border:     #3f3f46;
    --color-border-strong: #52525b;
    --color-text:       #fafafa;
    --color-text-muted: #a1a1aa;
    /* OP-46: dark was 71717a (≈3.6 on dark surfaces) → gray-400. */
    --color-text-soft:  rgb(156 163 175);   /* gray-400 */
    /* OP-51 (2026-06-11 theme-polish): backdrop token derived from
       --color-text → near-WHITE veil in dark mode (inverted). True dim. */
    --rvg-modal-backdrop-bg: rgb(0 0 0 / 0.55);
    /* OP-35b (2026-06-11): bright financial variants — bridge properties
       so atlas (whose dark surfaces are LIGHTER slate) can lift the
       semantic tokens without a var() self-reference cycle. */
    --color-success-bright: color-mix(in srgb, var(--color-success) 72%, white);
    /* danger needs more white than success: red's luminance ceiling at 72%
       capped contrast at 3.3 on atlas slate — 56% clears 4.5. */
    --color-danger-bright:  color-mix(in srgb, var(--color-danger) 56%, white);

    --color-accent:       #818cf8;   /* indigo-400 */
    --color-accent-hover: #a5b4fc;   /* indigo-300 */
    --color-accent-soft:  rgba(129, 140, 248, 0.15);
    /* OP-27 (2026-06-11 theme-polish): dark accent is LIGHTENED
       (indigo-400) — white ink on it fails contrast, so -fg flips to
       slate-900 ink. --rvg-thead-bg = dedicated dark table-head surface
       (slate-800), slightly distinct from --color-bg-alt zinc.
       REVERT: delete these two declarations. */
    --color-accent-fg:  rgb(15 23 42);   /* slate-900 */
    --rvg-thead-bg:     rgb(30 41 59);   /* slate-800 */

    --color-success: #22c55e;
    --color-warning: #eab308;
    --color-danger:  #ef4444;
    --color-info:    #06b6d4;

    /* FR-143 palette — brighter dark variants (the 5 aliases re-resolve via
       the dark semantic tokens above automatically; only the 7 added hues
       need explicit lift for contrast on dark surfaces). */
    --rvg-fmt-purple:  rgb(168 85 247);   /* violet-500 */
    --rvg-fmt-teal:    rgb(45 212 191);   /* teal-400   */
    --rvg-fmt-pink:    rgb(244 114 182);   /* pink-400   */
    --rvg-fmt-orange:  rgb(251 146 60);   /* orange-400 */
    --rvg-fmt-lime:    rgb(163 230 53);   /* lime-400   */
    --rvg-fmt-brown:   rgb(217 119 6);   /* amber-600  */
    --rvg-fmt-slate:   rgb(148 163 184);   /* slate-400  */

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.24);
    --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.32);
    --shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.40);
}


/* ==========================================================================
   4. Base typography & resets (ØªØ­Ø³ÙŠÙ†Ø§Øª Ø®ÙÙŠÙØ© ÙÙˆÙ‚ Bootstrap)
   ========================================================================== */

html {
    font-size: 16px;
}

body {
    font-family: var(--font-primary);
    font-size: var(--text-base);
    line-height: 1.6;
    color: var(--color-text);
    background: var(--color-bg-alt);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-primary);
    font-weight: 700;
    line-height: 1.3;
    color: var(--color-text);
}

code, kbd, pre, samp {
    font-family: var(--font-mono);
}

/* OP-63 (2026-06-11 theme-polish): unified keyboard-focus ring.
   :where() pins specificity at (0,1,0) — just the :focus-visible — so
   EVERY existing ring keeps winning: quick-create/edit outline (0,2,0),
   .rvg-sel__btn ring (0,2,0), [class*="inp-"] rings, Bootstrap
   .form-control:focus (0,2,0). This only catches interactive elements
   that today have NO ring at all. :focus-visible (not :focus) = keyboard
   only — mouse clicks stay ring-free.
   REVERT: delete this whole rule block. */
:where(button, input, select, .rvg-sel__btn, a[class*="rvg-"]):focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 30%, transparent);
}


/* ==========================================================================
   4.5. Ù‚Ø§Ø¹Ø¯Ø© Ù…ÙÙ‚ÙŠÙŽÙ‘Ø¯Ø©: Ø§Ù„Ø£Ø±Ù‚Ø§Ù… Ø¯Ø§Ø¦Ù…Ø§Ù‹ Ù„Ø§ØªÙŠÙ†ÙŠÙ‘Ø© (0-9) ÙÙŠ ÙƒÙ„ Ø§Ù„Ù†Ø¸Ø§Ù…
   Ù†Ù…Ù†Ø¹ Ø§Ù„Ø®Ø·Ù‘ Ù…Ù† Ø§Ù„ØªØ¨Ø¯ÙŠÙ„ Ø§Ù„ØªÙ„Ù‚Ø§Ø¦ÙŠÙ‘ Ù„Ø£Ø±Ù‚Ø§Ù… Ø¹Ø±Ø¨ÙŠÙ‘Ø©-Ù‡Ù†Ø¯ÙŠÙ‘Ø© (Ù -Ù©)
   ÙŠØ·Ø¨ÙŽÙ‘Ù‚ ÙÙŠ Ø§Ù„Ø´Ø§Ø´Ø© ÙˆØ§Ù„Ø·Ø¨Ø§Ø¹Ø© ÙƒÙ‚Ø§Ø¹Ø¯Ø© Ù…ÙÙ„Ø²ÙÙ…Ø©.
   ========================================================================== */

html {
    font-feature-settings: "lnum" 1, "tnum" 1;
}
*, *::before, *::after {
    font-variant-numeric: lining-nums tabular-nums;
    -moz-font-feature-settings: "lnum" 1, "tnum" 1;
    -webkit-font-feature-settings: "lnum" 1, "tnum" 1;
    font-feature-settings: "lnum" 1, "tnum" 1;
}


/* ==========================================================================
   5. Revogen utility: icon helper (ÙŠØ³ØªØ®Ø¯Ù… SVG sprite)
   usage: <svg class="revogen-icon"><use href="/assets/icons/bootstrap-icons.svg#book"/></svg>
   ========================================================================== */

.revogen-icon {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
    fill: currentColor;
}

.revogen-icon--lg { width: 1.5em; height: 1.5em; }
.revogen-icon--xl { width: 2em;   height: 2em;   }

/* ==========================================================================
   FR-019 â€” Active simple-filter chips on list pages.
   Shown when the user landed via a "view all" link from a parent's
   children-preview tab. Clicking âœ• removes the filter and reloads the
   unscoped list at /{table}. Inherits theme accent â€” respects the
   admin-set `app_color_accent` and dark mode automatically.
   ========================================================================== */
.rvg-filter-chips      { display:flex; flex-wrap:wrap; gap:8px; margin:0 0 14px; }
.rvg-filter-chip       { display:inline-flex; align-items:center; gap:6px;
                         padding:5px 10px 5px 12px;
                         background:var(--color-accent-soft);
                         color:var(--color-accent);
                         border:1px solid var(--color-accent-soft);
                         border-radius:8px; font-size:13px; line-height:1.3; }
.rvg-filter-chip-label { opacity:.85; }
.rvg-filter-chip-value { font-weight:600; color:var(--color-accent-hover); }
.rvg-filter-chip-clear { margin-inline-start:4px; color:inherit;
                         text-decoration:none; font-size:12px; line-height:1;
                         width:18px; height:18px;
                         display:inline-flex; align-items:center; justify-content:center;
                         border-radius:50%;
                         transition:background-color .15s, color .15s; }
.rvg-filter-chip-clear:hover { background:var(--color-accent-soft);
                               color:var(--color-accent-hover); }

/* ==========================================================================
   FR-020 â€” Lookup typeahead wrap.
   Sits ABOVE the <select> when `lookup_search: true`. The search input
   triggers a debounced request to /admin/lookup which rewrites the
   select's options live.
   ========================================================================== */
.rvg-lookup-search-wrap   { display:flex; align-items:center; gap:8px;
                             margin-bottom:6px; }
.rvg-lookup-search-input  { flex:1 1 auto; min-width:0;
                             padding:7px 11px;
                             background:var(--color-bg);
                             color:var(--color-text);
                             border:1px solid var(--color-border);
                             border-radius:6px;
                             font-size:13px; font-family:inherit;
                             transition:border-color .15s, box-shadow .15s; }
.rvg-lookup-search-input:focus { outline:0;
                                  border-color:var(--color-accent);
                                  box-shadow:0 0 0 3px var(--color-accent-soft); }
.rvg-lookup-search-status { font-size:12px; color:var(--color-text-muted);
                             min-width:80px; text-align:start; }

/* ==========================================================================
   Quick Create row + "+" button â€” visual chrome only.
   The actual dialog flow is FR-026: the "+" fetches the target table's
   own create form via `/{target}/create?embed=quick_create` and injects
   the response into a shared modal. JS lives in revogen.js.
   ========================================================================== */
/* Quick Create row â€” fuses select + "+" button into a single visual control.
   Uses logical properties so the seam is on the inline-END of the select
   regardless of writing direction (LTR or RTL). */
/* OP-52a (2026-06-11): the row could overflow its card on phones (the eye
   button measured x=-1, ~20px outside the card edge) — clamp the chain. */
.rvg-quick-create-row { display:flex; align-items:stretch; gap:0; min-width:0; max-width:100%; }
/* OP-52c: the rvgSelect widget's min-content (long option labels) blocked
   shrinking — the eye button then overflowed the row start by ~7px @390. */
.rvg-quick-create-row .rvg-sel { min-width: 0; }
.rvg-quick-create-row > .inp-,
.rvg-quick-create-row > select {
    flex:1 1 auto; min-width:0;
    border-start-end-radius:0;
    border-end-end-radius:0;
}
/* Quick Create (+) Ùˆ Quick Edit (ðŸ‘) buttons â€” Ù…ØªÙ†Ø§Ø³Ù‚ÙŠÙ† Ø¨ØµØ±ÙŠØ§Ù‹.
   ÙƒÙ„Ø§Ù‡Ù…Ø§ muted ÙÙŠ Ø§Ù„Ø±Ø§Ø­Ø©ØŒ ÙŠØµØ¨ØºØ§Ù† Ø¨Ù€accent Ø¹Ù†Ø¯ Ø§Ù„Ù€hover ÙÙ‚Ø·.
   icon size Ù…ÙˆØ­ÙŽÙ‘Ø¯ 14px â€” Ø£ØµØºØ± ÙˆÙ…Ø­Ø§Ø°Ù Ù„Ù€text input neighbouring. */
.rvg-quick-create-btn,
.rvg-quick-edit-btn {
    flex: 0 0 auto;
    min-width: 32px; padding: 0 10px; height: auto;
    background: var(--color-bg-alt);
    color: var(--color-text-muted, #6c757d);
    border: 1px solid color-mix(in srgb, var(--color-accent) 46%, transparent);
    border-inline-start: 0;
    border-radius: 0;
    cursor: pointer;
    line-height: 1;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background-color .15s, color .15s, border-color .15s;
}
.rvg-quick-create-btn:hover,
.rvg-quick-edit-btn:hover {
    background: var(--color-accent-soft);
    color: var(--color-accent);
    border-color: var(--color-accent);
}
.rvg-quick-create-btn:active {
    background: var(--color-accent);
    color: #fff;
}
@media (max-width: 480px) {
    /* OP-52a: slimmer +/eye buttons on phones reclaim ~30px for the select. */
    .rvg-quick-create-btn,
    .rvg-quick-edit-btn { min-width: 30px; padding: 0 7px; }
}
.rvg-quick-create-btn:focus-visible,
.rvg-quick-edit-btn:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 1px;
    z-index: 1;
}
.rvg-quick-create-btn .revogen-icon,
.rvg-quick-edit-btn .revogen-icon {
    width: 14px; height: 14px;
}
/* Ø¢Ø®Ø± Ø²Ø± ÙÙŠ Ø§Ù„ØµÙÙ‘ ÙŠØ­Ù…Ù„ end-rounding â€” Ø£ÙŠÙ‹Ù‘Ø§ ÙƒØ§Ù† (+ Ø£Ùˆ eye Ù„Ùˆ Ø§Ù„Ø­Ù‚Ù„
   Ù…Ø§ ÙŠØ­ÙˆÙŠ quick_create). Ø§Ù„Ù€`:last-child` ÙŠØ¶Ù…Ù† Ø¥Ù†Ù‘ Ø§Ù„Ø²Ø§ÙˆÙŠØ© Ø§Ù„Ù…ØºÙ„Ù‚Ø©
   ØªØ¨Ù‚Ù‰ ØµØ­ÙŠØ­Ø© ÙÙŠ ÙƒÙ„Ø§ Ø§Ù„Ø­Ø§Ù„ØªÙŠÙ†. */
.rvg-quick-create-row > .rvg-quick-create-btn:last-child,
.rvg-quick-create-row > .rvg-quick-edit-btn:last-child {
    border-start-end-radius: 6px;
    border-end-end-radius: 6px;
}

/* FR-113 — Field-mirror toggle. Plain checkbox + label inline with the
   field's main label. No chrome — just the checkbox tinted with the
   project's accent color. */
.rvg-mirror-toggle {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-inline-start: 10px;
    font-size: 12px;
    font-weight: 500;
    color: var(--color-text-muted, #4b5563);
    cursor: pointer;
    user-select: none;
    line-height: 1.2;
    vertical-align: middle;
}
.rvg-mirror-toggle .rvg-mirror-checkbox {
    width: 13px; height: 13px;
    margin: 0;
    accent-color: var(--color-accent, #3b82f6);
    cursor: pointer;
}
.rvg-mirror-toggle .rvg-mirror-label {
    white-space: nowrap;
}
/* Small screens — drop the toggle to the next line under the label so
   neither gets clipped. */
@media (max-width: 520px) {
    .rvg-mirror-toggle {
        display: flex;
        margin-inline-start: 0;
        margin-top: 4px;
        width: fit-content;
    }
}

dialog.rvg-qc-dialog {
    border:none; border-radius:14px; padding:0;
    width:min(420px, 92vw); max-height:88vh;
    background:var(--color-bg); color:var(--color-text);
    box-shadow:0 24px 60px -16px rgba(0,0,0,.35);
    font-family:var(--font-primary);
}
dialog.rvg-qc-dialog::backdrop { background: var(--rvg-modal-backdrop-bg); backdrop-filter: var(--rvg-modal-backdrop-blur); }
dialog.rvg-qc-dialog .rvg-qc-head {
    display:flex; align-items:center; justify-content:space-between;
    padding:16px 18px 12px;
    border-bottom:1px solid var(--color-border);
}
dialog.rvg-qc-dialog .rvg-qc-head h3 {
    margin:0; font-size:16px; font-weight:700; color:var(--color-text);
}
.rvg-qc-close {
    background:transparent; border:none; cursor:pointer;
    width:28px; height:28px; border-radius:6px;
    color:var(--color-text-muted); font-size:16px;
    transition:background .15s, color .15s;
}
.rvg-qc-close:hover { background:var(--color-bg-hover); color:var(--color-text); }
/* OP-45 (2026-06-11): modal close ≥40px tap target on touch widths. */
@media (max-width: 768px) {
    .rvg-qc-close { min-width: 40px; min-height: 40px; }
}

dialog.rvg-qc-dialog .rvg-qc-body { padding:16px 18px; }
.rvg-qc-field { margin-bottom:14px; }
.rvg-qc-field label {
    display:block; font-size:13px; font-weight:600;
    color:var(--color-text); margin-bottom:6px;
}
.rvg-qc-req { color:#ef4444; }
.rvg-qc-field input,
.rvg-qc-field textarea {
    width:100%; padding:9px 12px;
    background:var(--color-bg); color:var(--color-text);
    border:1px solid var(--color-border); border-radius:8px;
    font-size:14px; font-family:inherit;
    transition:border-color .15s, box-shadow .15s;
}
.rvg-qc-field input:focus,
.rvg-qc-field textarea:focus {
    outline:0; border-color:var(--color-accent);
    box-shadow:0 0 0 3px var(--color-accent-soft);
}
.rvg-qc-field input.is-invalid,
.rvg-qc-field textarea.is-invalid { border-color:#ef4444; }
.rvg-qc-error {
    margin:4px 0 0; font-size:12px; color:#ef4444; min-height:0;
}
.rvg-qc-form-error {
    background:rgba(239,68,68,.10);
    border:1px solid rgba(239,68,68,.30);
    color:#dc2626;
    padding:10px 12px; border-radius:8px; font-size:13px; margin-bottom:12px;
}

dialog.rvg-qc-dialog .rvg-qc-foot {
    display:flex; gap:10px; justify-content:flex-end;
    padding:12px 18px 16px;
    border-top:1px solid var(--color-border);
}
.rvg-qc-cancel, .rvg-qc-save {
    padding:8px 18px; border-radius:7px;
    font-size:14px; font-weight:600; cursor:pointer;
    border:1px solid transparent; font-family:inherit;
}
.rvg-qc-cancel { background:transparent; color:var(--color-text);
                 border-color:var(--color-border); }
.rvg-qc-cancel:hover { background:var(--color-bg-hover); }
.rvg-qc-save { background:var(--color-accent); color:#fff; }
.rvg-qc-save:hover:not(:disabled) { background:var(--color-accent-hover); }
.rvg-qc-save:disabled { opacity:.6; cursor:not-allowed; }

/* ====================== Unified field validation visuals ======================
   FR-032 â€” Single visual contract used by:
     - server-side errors rendered by form.twig (FR-015 onward)
     - client-side live validation in revogen.js (HTML5 Constraint API)
     - unique-check Alpine widget (debounced /check-unique)

   States the wrapper can carry:
     - `.fg-has-error`  â†’ red input border + `.fg-error-msg` div with red text
     - `.fg-is-valid`   â†’ soft green border + green âœ“ next to the input
     - (none)           â†’ pristine

   The red-border styling is already defined per-table inside form.twig.
   The rules below are project-wide. */

.fg-error-msg {
    font-size: var(--text-xs);
    color: var(--color-danger);
    margin-top: var(--space-1);
    display: flex;
    align-items: center;
    gap: 4px;
}

/* Valid state â€” green border + âœ“ icon as the input's background-image
   (NOT a positioned ::after on the wrapper). Background-image is always
   vertically centered on the input itself, so the icon lands inside the
   field regardless of label height, status divs underneath, or any
   other layout quirks. Trailing edge in RTL = visual left, set via
   `left 12px` since `background-position` doesn't honour `inset-inline`. */
.fg-is-valid > input,
.fg-is-valid > textarea,
.fg-is-valid input[type="text"],
.fg-is-valid input[type="email"],
.fg-is-valid input[type="url"],
.fg-is-valid input[type="tel"],
.fg-is-valid input[type="number"],
.fg-is-valid input[type="password"],
.fg-is-valid input[type="search"],
.fg-is-valid textarea {
    border-color: color-mix(in srgb, var(--color-success) 50%, var(--color-border));
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%2310b981' d='M13.485 1.929a.75.75 0 0 1 .086 1.057l-7.5 9a.75.75 0 0 1-1.143 0l-3-3.5a.75.75 0 1 1 1.144-.972l2.428 2.832 6.928-8.317a.75.75 0 0 1 1.057-.1z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: left 12px center;
    background-size: 14px;
    padding-inline-end: 36px;
}
/* In LTR languages, trailing edge is right. */
[dir="ltr"] .fg-is-valid > input,
[dir="ltr"] .fg-is-valid > textarea,
[dir="ltr"] .fg-is-valid input[type="text"],
[dir="ltr"] .fg-is-valid input[type="email"],
[dir="ltr"] .fg-is-valid input[type="url"],
[dir="ltr"] .fg-is-valid input[type="tel"],
[dir="ltr"] .fg-is-valid input[type="number"],
[dir="ltr"] .fg-is-valid input[type="password"],
[dir="ltr"] .fg-is-valid input[type="search"],
[dir="ltr"] .fg-is-valid textarea {
    background-position: right 12px center;
}

/* FR-119 (2026-06-04) — `<input type="number">` is internally rendered
   LTR by browsers (digit display) regardless of the page direction. The
   `padding-inline-end: 36px` above thus resolves to `padding-RIGHT: 36px`
   on these inputs even in an RTL page, while the ✓ icon is positioned
   at `left 12px` — so the padding lands on the WRONG side, pushing the
   right-aligned digits 24px away from the right edge for no reason. Pin
   the padding to the physical side matching the icon for numerics. */
[dir="rtl"] .fg-is-valid input[type="number"] {
    padding-inline-end: var(--space-3);
    padding-left: 36px;
}
/* Selects already use a background chevron on the leading edge â€” keep
   the green border but skip the âœ“ (would override the chevron). The
   border is enough indication for a chosen-from-list field anyway. */
.fg-is-valid > select,
.fg-is-valid select {
    border-color: color-mix(in srgb, var(--color-success) 50%, var(--color-border));
}
.fg-is-valid > input:focus,
.fg-is-valid > textarea:focus,
.fg-is-valid > select:focus,
.fg-is-valid input:focus,
.fg-is-valid textarea:focus,
.fg-is-valid select:focus {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-success) 18%, transparent);
}

/* Belt-and-suspenders: if unique-check declares a duplicate while the
   live validator is still mid-debounce, both classes can briefly coexist
   on the wrapper. The duplicate state must always win â€” red border + no âœ“. */
.fg-is-duplicate.fg-is-valid > input,
.fg-is-duplicate.fg-is-valid > textarea,
.fg-is-duplicate.fg-is-valid input,
.fg-is-duplicate.fg-is-valid textarea {
    border-color: var(--color-danger);
    background-image: none;
    padding-inline-end: 12px;  /* restore default â€” no icon to make room for */
}


/* Don't show unique-check's "available" / "checking..." status messages
   when the field has a format-level error. Mixing "âœ“ available" with
   "âŒ invalid format" on the same field produced contradictory UX. The
   Alpine widget already gates `formatValid` in JS; this rule covers any
   timing race where Alpine hasn't re-evaluated yet. */
.fg-has-error .fg-uniq-ok,
.fg-has-error .fg-uniq-checking { display: none !important; }

/* FR-026 â€” Shared dialog that hosts the embedded create form fetched from
   `/<target>/create?embed=quick_create`.

   ROOT-CAUSE FIX (2026-04-27): the previous version forced `display:flex`
   unconditionally, which overrode `<dialog>`'s default `display:none` for
   the unopened state. Result: the empty dialog rendered ALWAYS â€” visible
   on every form page even though `showModal()` was never called, with no
   way to close it (because it wasn't actually open from the browser's
   point of view). Same root cause produced the "select dropdown hidden
   behind modal body" report: without `showModal()` the dialog isn't in
   Top Layer, so native select dropdowns rendered in the normal stacking
   context get covered by the dialog's own body styling.

   The fix: shape rules use `[open]` selector so they apply only when the
   dialog is actually open. Closed dialogs revert to `display:none`. */
/* ROOT-CAUSE FIX (2026-04-27 v4) â€” div-based modal (no Top Layer).

   Background: previous versions used `<dialog>:showModal()` for the Top
   Layer integration. That interacted poorly with native `<select>`
   dropdowns on Chromium-derived browsers â€” option lists rendered behind
   or outside the dialog, leaving the user unable to select anything.

   Fix: drop showModal() entirely. The host is now a plain `<div>` with
   z-indexed overlay + manual ESC + backdrop-click close in JS. Native
   select popups render in their own OS-level layer above the modal â€”
   exactly what the user expects.

   The `[hidden]` attribute (set by JS on close) keeps it out of the
   render tree until openDialog() removes it. */

/* Backdrop â€” covers the page beneath the modal. Click closes (handled in JS). */
.rvg-qc-backdrop {
    position: fixed;
    inset: 0;
    background: var(--rvg-modal-backdrop-bg);
    backdrop-filter: var(--rvg-modal-backdrop-blur);
    z-index: 9998;
}

/* `[hidden]` attribute must beat the modal/backdrop `display:flex` rule
   below, so `closeDialog()` actually hides the dialog when it sets
   `hidden=""`. Without `!important`, class specificity wins and the
   modal stays visible after save. */
.rvg-qc-backdrop[hidden],
.rvg-qc-modal[hidden] { display: none !important; }

/* ==========================================================================
   Inline flash banner â€” replaces toast for save/error feedback.
   Banner stack lives at top of <main class="rvg-main"> (auto-injected by
   `window.rvgFlash`). Banners fade in, sit visible for ~3.5s, then fade
   out + collapse. Click dismisses immediately.

   Variants: success / error / warning / info â€” colours come from
   `--color-accent`/danger/warning tokens so the dark mode + admin's
   accent are honoured.
   ========================================================================== */
/* Page-level host â€” anchored at the top of <main>, overlaying the page
   header without reflowing layout. The banner sits ABOVE all page
   content but BELOW the topbar/navbar (which has its own stacking
   context). Centred horizontally; auto-fades. */
.rvg-flash-host {
    position: absolute;
    top: 8px;
    inset-inline: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 0 16px;
    pointer-events: none;
    z-index: 50;
}
.rvg-flash-host > .rvg-flash {
    width: min(640px, 100%);
}

/* Modal host â€” overlays the head's title area while a banner is active.
   `inset-inline-start: 60px` reserves room for the close button so the
   user can still dismiss the modal. Background blends into the head so
   it looks like a head colour change rather than a separate stripe.
   Form below the head is untouched (zero shift). */
.rvg-flash-host--in-modal {
    position: absolute;
    inset: 0;
    inset-inline-end: 60px;  /* keep close button on the end side clickable */
    margin: 0;
    padding: 6px 14px;
    z-index: 6;
    background: var(--color-bg);
    border-radius: 14px 0 0 0;
    display: flex;
    align-items: center;
    justify-content: center;
}
.rvg-flash-host--in-modal > .rvg-flash {
    padding: 8px 12px 8px 14px;
    min-width: 0;
    font-size: 13.5px;
    border-radius: 8px;
    box-shadow: none;
}
.rvg-flash-host--in-modal > .rvg-flash .rvg-flash__icon svg {
    width: 15px;
    height: 15px;
}
.rvg-flash-host--in-modal > .rvg-flash .rvg-flash__close {
    width: 20px;
    height: 20px;
}
.rvg-flash-host--in-modal > .rvg-flash .rvg-flash__close svg {
    width: 11px;
    height: 11px;
}

/* Banner â€” minimal system-style notification.
   Card on the page bg, 1px border, small accent dot, dismiss Ã— button.
   No gradients. No blur. No progress bar. No drama. */
.rvg-flash {
    --rvg-flash-accent: var(--color-accent);
    display: inline-flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px 12px 18px;
    min-width: min(420px, 100%);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    color: var(--color-text);
    font-weight: 500;
    font-size: 15px;
    line-height: 1.35;
    box-shadow: 0 4px 14px -6px rgba(0, 0, 0, 0.12);
    pointer-events: auto;
    transition: opacity 180ms ease, transform 220ms ease;
    max-width: 100%;
}

.rvg-flash--enter { opacity: 0; transform: translateY(-6px); }
.rvg-flash--leave { opacity: 0; transform: translateY(-3px); transition-duration: 160ms; }

.rvg-flash__icon {
    flex: 0 0 auto;
    display: inline-flex;
    color: var(--rvg-flash-accent);
}
.rvg-flash__icon svg { width: 18px; height: 18px; }

.rvg-flash__msg {
    flex: 0 1 auto;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rvg-flash__close {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    /* Push to the opposite end so the close button sits FAR from the
       icon â€” visual balance instead of crowding next to the text. */
    margin-inline-start: auto;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: 6px;
    color: var(--color-text-muted, #6c757d);
    cursor: pointer;
    opacity: 0.55;
    transition: opacity 120ms ease, background 120ms ease;
}
.rvg-flash__close:hover { opacity: 1; background: var(--color-bg-hover); }
.rvg-flash__close svg { width: 13px; height: 13px; }

.rvg-flash--success { --rvg-flash-accent: #16a34a; }
.rvg-flash--error   { --rvg-flash-accent: #dc2626; }
.rvg-flash--warning { --rvg-flash-accent: #d97706; }
.rvg-flash--info    { --rvg-flash-accent: var(--color-accent); }

/* Modal panel â€” centered, fixed, scrollable when content overflows.
   CRITICAL: do NOT use `transform: translate(-50%, -50%)` for centering.
   `transform` on a fixed-position ancestor creates a new containing block
   for fixed-position descendants (CSS Containing Block spec), which means
   the date picker popup (and any other `position: fixed` widget rendered
   inside the modal) gets anchored to the MODAL instead of the viewport.
   That breaks `getBoundingClientRect`-based coordinates so the popup
   appears off-screen / behind the modal. Use `inset: 0` + `margin: auto`
   for centering instead â€” no transform, no containing-block trap. */
.rvg-qc-modal.rvg-qc-dialog-shared {
    position: fixed;
    inset: 0;
    margin: auto;
    /* Width from the unified framework token (90vw) — shared with
       lines-modal and adv-search-modal. NEVER hard-code a width here. */
    width: var(--rvg-modal-width-large);
    height: fit-content;
    max-height: 92vh;
    z-index: 9999;
    background: var(--color-bg);
    color: var(--color-text);
    border-radius: 14px;
    box-shadow: 0 24px 60px -16px rgba(0, 0, 0, 0.35);
    font-family: var(--font-primary);
    display: flex;
    flex-direction: column;
    overflow: hidden;        /* wrap; the body inside scrolls */
}

/* Lock background scroll while the modal is open. */
.rvg-qc-modal-open { overflow: hidden; }

.rvg-qc-modal.rvg-qc-dialog-shared .rvg-qc-shared-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 22px 12px;
    border-bottom: 1px solid var(--color-border);
    flex: 0 0 auto;
    /* Anchor for `.rvg-flash-host--in-modal` so the banner overlays the
       title without pushing the form below. */
    position: relative;
}
.rvg-qc-modal.rvg-qc-dialog-shared .rvg-qc-shared-head h3 {
    margin: 0; font-size: 16px; font-weight: 700; color: var(--color-text);
}
.rvg-qc-modal.rvg-qc-dialog-shared .rvg-qc-shared-body {
    padding: 16px 22px 18px;
    overflow-y: auto;
    flex: 1 1 auto;
    min-height: 0;
    /* Anchor for `.rvg-flash-host--in-modal` so banners overlay the top
       of the form without shifting layout. */
    position: relative;
}

/* Responsive — phones / very narrow tablets. The desktop centering uses
   `min(960px, 96vw)`; on small screens give the modal more room, tighter
   padding, and remove the floating gap so it acts like a full-height sheet. */
@media (max-width: 640px) {
    .rvg-qc-modal.rvg-qc-dialog-shared {
        width: 100vw;
        max-width: 100vw;
        max-height: 100dvh;
        height: 100dvh;
        border-radius: 0;
        box-shadow: none;
    }
    .rvg-qc-modal.rvg-qc-dialog-shared .rvg-qc-shared-head {
        padding: 12px 14px 10px;
    }
    .rvg-qc-modal.rvg-qc-dialog-shared .rvg-qc-shared-head h3 {
        font-size: 15px;
    }
    .rvg-qc-modal.rvg-qc-dialog-shared .rvg-qc-shared-body {
        padding: 12px 14px 16px;
    }
}

.rvg-qc-loading {
    margin:18px 0; text-align:center;
    color:var(--color-text-muted); font-size:13px;
}
.rvg-qc-error {
    margin:18px 0; padding:10px 12px;
    background:color-mix(in srgb, var(--color-danger) 8%, var(--color-bg));
    border:1px solid color-mix(in srgb, var(--color-danger) 30%, transparent);
    color:var(--color-danger); border-radius:8px; font-size:13px;
}

/* FR-028 — Slim toolbar inside the embed dialog. Hosts the table singular
   name on one side and the column-switcher on the other. The dialog's own
   shared-head carries the action title (إضافة/تعديل سريع), while this
   toolbar identifies WHICH table the form is for + lets the user pick the
   form's column count. */
[class$="-embed-toolbar"] {
    display:flex; align-items:center; justify-content:space-between;
    padding:0 0 12px; margin-bottom:12px;
    border-bottom:1px dashed var(--color-border);
}
[class$="-embed-toolbar"] .rvg-qc-embed-name {
    display:inline-flex; align-items:center; gap:6px;
    font-weight:600; font-size:0.95rem;
    color:var(--color-text);
}
[class$="-embed-toolbar"] .rvg-qc-embed-name .revogen-icon {
    width:1.05rem; height:1.05rem;
    color:var(--color-accent); opacity:0.85;
}
.rvg-qc-embed-tools {
    display:inline-flex; align-items:center; gap:8px;
}

/* Footer carries the embed Save/Cancel pair (the standalone page_header
   block is suppressed in embed mode). The class is generated as
   `form-{table}-embed-footer` â€” match by suffix attribute pattern.

   NOT `position: sticky`: sticky creates a stacking context that traps
   native <select> popups behind it. Plain block layout â€” the dialog
   itself handles scrolling. */
form[data-rvg-quick-create-embed] [class$="-embed-footer"] {
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    padding: 14px 0 4px;
    margin-top: 18px;
    border-top: 1px solid var(--color-border);
    background: var(--color-bg);
}
form[data-rvg-quick-create-embed] {
    /* Tighten the embedded form so the "card" inside the dialog doesn't
       double up the chrome â€” the dialog itself is the card. */
    background:transparent;
}
form[data-rvg-quick-create-embed] [class*="-card"] {
    border:none !important; box-shadow:none !important;
    padding:0 !important; background:transparent !important;
}

/* ==========================================================================
 * MIGRATED FROM overrides.css (2026-04-28)
 * ÙƒÙ„ Ø§Ù„Ù‚ÙˆØ§Ø¹Ø¯ Ø£Ø¯Ù†Ø§Ù‡ ÙƒØ§Ù†Øª ÙÙŠ public/assets/custom/overrides.css.
 * Ù†ÙÙ‚Ù„Øª Ù‡Ù†Ø§ Ù„ÙŠØµÙŠØ± revogen.css Ø§Ù„Ù€ canonical Ø§Ù„Ù…Ø±ÙƒØ²ÙŠ Ùˆ overrides.css
 * ÙŠØ¨Ù‚Ù‰ Ø³Ù„ÙˆØª ØªØ®ØµÙŠØµ Ù„Ù„Ù…Ø´Ø±ÙˆØ¹ â€” ÙØ§Ø¶ÙŠ Ø§ÙØªØ±Ø§Ø¶ÙŠØ§Ù‹.
 * ========================================================================= */

/* m2m â€” checkbox group ÙÙŠ forms + chips ÙÙŠ detail */
.rvg-m2m-checkboxes {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
    padding: 10px 12px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background: var(--color-surface-soft, #f8fafc);
}
.rvg-m2m-check {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    font-size: 0.9rem;
    color: var(--color-text, #1f2937);
}
.rvg-m2m-check input {
    cursor: pointer;
    accent-color: var(--color-accent, #2563eb);
}
.rvg-m2m-chip {
    display: inline-block;
    padding: 3px 10px;
    margin: 2px 4px;
    border-radius: 999px;
    background: var(--color-surface-soft, #eef2ff);
    color: var(--color-accent, #2563eb);
    font-size: 0.85rem;
    line-height: 1.5;
}
[class*="-m2m-chips"] { margin-top: 4px; }
[class*="-m2m-label"] {
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--color-text-muted, #64748b);
    margin-top: 12px;
    text-transform: capitalize;
}

/* state-machine — badge + action buttons.
 * Scoped via [class*="dv-"] guard so we only match the detail-view widget
 * (markup uses `dv-{table}-state` / `-state-label` / `-state-actions`).
 * Without the guard, the bare `[class*="-state"]` selector also caught
 * auto-generated `cell-{table}-state` TDs in list views (any table with
 * an enum field literally named `state`), inflating row height and
 * breaking the table layout. */
[class*="dv-"][class*="-state"] { margin: 16px 0; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
[class*="dv-"][class*="-state-label"] { font-weight: 600; font-size: 0.85rem; color: var(--color-text-muted, #64748b); }
.rvg-state-badge {
    display: inline-block;
    padding: 4px 14px;
    border-radius: 999px;
    font-size: 0.9rem;
    font-weight: 600;
    line-height: 1.6;
}
[class*="dv-"][class*="-state-actions"] { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.rvg-state-btn {
    border: none;
    padding: 6px 14px;
    border-radius: 6px;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.08s, filter 0.15s;
}
.rvg-state-btn:hover { filter: brightness(1.1); }
.rvg-state-btn:active { transform: translateY(1px); }

/* FR-146 — state-change advance form + progress log */
.rvg-state { display: flex; flex-direction: column; gap: var(--space-3); }
.rvg-state-head { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.rvg-state-advance {
    display: flex; flex-direction: column; gap: var(--space-2);
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-alt);
}
.rvg-state-advance-form { display: flex; flex-direction: column; gap: var(--space-2); }
.rvg-state-advance-fields { display: flex; gap: var(--space-3); flex-wrap: wrap; }
.rvg-state-field { display: flex; flex-direction: column; gap: 4px; flex: 1 1 180px; }
.rvg-state-field-label { font-size: var(--text-xs); color: var(--color-text-muted); }
.rvg-state-input {
    width: 100%;
    padding: 6px 10px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font: inherit;
    color: var(--color-text);
    background: var(--color-bg);
}
.rvg-state-advance-form .rvg-state-btn { align-self: flex-start; }

.rvg-state-log { margin-top: var(--space-2); }
.rvg-state-log-title { font-size: var(--text-xs); font-weight: 600; color: var(--color-text-muted); margin-bottom: var(--space-2); }
.rvg-state-log-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.rvg-state-log-item {
    display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
    padding: 6px 10px;
    border-inline-start: 3px solid var(--color-border);
    background: var(--color-bg-alt);
    border-radius: var(--radius-sm);
}
.rvg-state-badge-sm { padding: 2px 10px; font-size: var(--text-xs); }
.rvg-state-log-date { font-size: var(--text-sm); font-weight: 600; color: var(--color-text); }
.rvg-state-log-note { font-size: var(--text-sm); color: var(--color-text-soft); }
.rvg-state-log-meta { margin-inline-start: auto; font-size: var(--text-xs); color: var(--color-text-muted); }
@media (max-width: 520px) {
    .rvg-state-advance-fields { flex-direction: column; }
    .rvg-state-log-meta { margin-inline-start: 0; flex-basis: 100%; }
}

/* Notifications bell (header) */
.rvg-bell { position: relative; display: inline-block; }
.rvg-bell-btn { position: relative; }
.rvg-bell-badge {
    position: absolute;
    top: -4px;
    inset-inline-end: -4px;
    min-width: 18px; height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: #ef4444;
    color: #fff;
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
}
.rvg-bell-panel {
    position: absolute;
    top: calc(100% + 6px);
    inset-inline-end: 0;
    width: min(380px, calc(100vw - 24px));
    max-height: 70vh;
    background: var(--chrome-bg, #fff);
    border: 1px solid var(--chrome-border, #e2e8f0);
    border-radius: 10px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
    z-index: 1050;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
/* OP-34 (2026-06-11 theme-polish): on phones the panel was positioned
   relative to the bell (inset-inline-end:0 pins it to the bell's edge in
   RTL) and overflowed ~27px off-screen because the bell sits ~51px from
   the viewport edge while the width formula assumed ≤24px. Below 520px,
   pin the panel to the VIEWPORT instead (bottom-sheet style from the
   popover kit). REVERT: delete this block. */
@media (max-width: 520px) {
    .rvg-bell-panel {
        position: fixed;
        top: 64px;
        inset-inline: 12px;
        width: auto;
        max-height: calc(100vh - 88px);
    }
}
/* OP-55 (2026-06-11): bell failure state. */
.rvg-bell-empty.rvg-bell-error { color: var(--color-danger); display: flex; flex-direction: column; gap: 8px; align-items: center; }
.rvg-bell-retry {
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    padding: 4px 14px;
    font-size: 12px;
    color: var(--color-text);
    cursor: pointer;
}
.rvg-bell-retry:hover { border-color: var(--color-accent); color: var(--color-accent); }
.rvg-bell-head {
    display: flex; justify-content: space-between; align-items: center;
    padding: 10px 14px;
    border-bottom: 1px solid var(--chrome-border, #e2e8f0);
}
.rvg-bell-markall {
    background: none; border: none;
    color: var(--color-accent, #2563eb);
    font-size: 0.8rem; cursor: pointer;
}
.rvg-bell-list { overflow-y: auto; flex: 1; max-height: 56vh; }
.rvg-bell-empty { padding: 24px; text-align: center; color: var(--color-text-soft, #94a3b8); font-size: 0.9rem; }
.rvg-bell-item {
    display: block;
    padding: 10px 14px;
    border-bottom: 1px solid var(--chrome-border, #e2e8f0);
    text-decoration: none;
    color: inherit;
    transition: background 0.15s;
}
.rvg-bell-item:hover { background: var(--chrome-bg-hover, #f4f4f5); }
.rvg-bell-item[data-read="0"] { background: var(--chrome-accent-soft, #eef2ff); }
.rvg-bell-item-title { font-weight: 600; font-size: 0.9rem; margin-bottom: 2px; }
.rvg-bell-item-body  { font-size: 0.82rem; color: var(--color-text-muted, #64748b); }
.rvg-bell-item-time  { font-size: 0.72rem; color: var(--color-text-soft, #94a3b8); margin-top: 2px; }
.rvg-bell-item-success { border-inline-start: 3px solid #10b981; }
.rvg-bell-item-warning { border-inline-start: 3px solid #f59e0b; }
.rvg-bell-item-danger  { border-inline-start: 3px solid #ef4444; }
.rvg-bell-item-info    { border-inline-start: 3px solid #3b82f6; }
.rvg-bell-foot {
    padding: 8px 14px;
    text-align: center;
    border-top: 1px solid var(--chrome-border, #e2e8f0);
}
.rvg-bell-foot a { color: var(--color-accent, #2563eb); font-size: 0.85rem; text-decoration: none; }

/* Web Push toggle (Layer 2) â€” sits between the list and the "View all" footer. */
.rvg-bell-push { border-top: 1px solid var(--chrome-border, #e2e8f0); }
.rvg-bell-push-btn {
    display: flex; align-items: center; gap: 10px;
    width: 100%;
    padding: 10px 14px;
    background: transparent;
    border: 0;
    font-size: 0.82rem;
    color: var(--color-text, #0f172a);
    cursor: pointer;
    text-align: inherit;
}
.rvg-bell-push-btn:hover:not(:disabled) { background: color-mix(in oklab, var(--color-accent, #2563eb) 6%, transparent); }
.rvg-bell-push-btn:disabled { opacity: 0.55; cursor: progress; }
.rvg-bell-push-icon { display: inline-flex; width: 16px; color: var(--color-text-soft, #64748b); }
.rvg-bell-push-label { flex: 1; }
.rvg-bell-push-dot { width: 8px; height: 8px; border-radius: 50%; }
.rvg-bell-push-dot.is-on  { background: #10b981; box-shadow: 0 0 0 3px color-mix(in oklab, #10b981 25%, transparent); }
.rvg-bell-push-dot.is-off { background: #cbd5e1; }
.rvg-bell-push-test {
    display: block;
    width: calc(100% - 28px);
    margin: 0 14px 10px;
    padding: 6px 10px;
    background: transparent;
    border: 1px dashed color-mix(in oklab, var(--color-accent, #2563eb) 45%, transparent);
    border-radius: 6px;
    font-size: 0.75rem;
    color: var(--color-accent, #2563eb);
    cursor: pointer;
}
.rvg-bell-push-test:hover:not(:disabled) { background: color-mix(in oklab, var(--color-accent, #2563eb) 8%, transparent); }
.rvg-bell-push-test:disabled { opacity: 0.55; cursor: progress; }

/* Profile dropdown â€” inline language + theme selectors (replaces separate navbar buttons) */
.rvg-popover-subhead {
    padding: 6px 14px 2px;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-soft, #94a3b8);
}
/* OP-72 (2026-06-11): compact one-row swatch dots — the labeled 2-column
   pill grid ate ~200px of menu height. Names moved to title tooltips
   (atlas-swatch pattern). REVERT: restore this block from git history. */
.rvg-profile-themes {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 4px 10px 8px;
}
/* specificity bump: the generic `.rvg-popover button { width:100% }`
   in dashboard.twig was stretching each dot full-width (one per row). */
.rvg-user-menu .rvg-popover .rvg-profile-theme-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    position: relative;
    transition: transform 0.12s;
}
.rvg-user-menu .rvg-popover .rvg-profile-theme-pill:hover { transform: scale(1.15); }
.rvg-user-menu .rvg-popover .rvg-profile-theme-pill.is-active::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid var(--color-accent);
}
.rvg-profile-theme-dot {
    width: 18px; height: 18px;
    border-radius: 50%;
    flex-shrink: 0;
    box-shadow: 0 0 0 1px rgba(0,0,0,0.12) inset;
}
.rvg-profile-theme-name { display: none; }
/* OP-72 — appearance segmented row (was 3 stacked full-width buttons). */
.rvg-user-menu .rvg-profile-mode {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
    padding: 2px 10px 6px;
}
.rvg-user-menu .rvg-profile-mode > button {
    flex-direction: column;
    gap: 4px;
    padding: 8px 4px;
    font-size: 0.72rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    justify-content: center;
}

/* Navbar locale switcher â€” single button showing target language */
.rvg-nav-locale {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 34px;
    padding: 0 10px;
    border: 1px solid transparent;
    border-radius: 8px;
    background: transparent;
    color: var(--color-text-muted, #64748b);
    font-size: 0.78rem;
    font-weight: 600;
    font-family: var(--font-mono, ui-monospace, monospace);
    letter-spacing: 0.02em;
    text-decoration: none;
    cursor: pointer;
    transition: all 0.15s;
}
.rvg-nav-locale:hover {
    background: var(--color-surface-soft, #f4f4f5);
    color: var(--color-accent, #2563eb);
    border-color: var(--chrome-border, #e2e8f0);
}
.rvg-nav-locale svg {
    width: 15px;
    height: 15px;
    opacity: 0.75;
}
.rvg-nav-locale-code {
    line-height: 1;
}
@media (max-width: 640px) {
    .rvg-nav-locale-code { display: none; }  /* Ø¹Ù„Ù‰ Ø§Ù„Ù…ÙˆØ¨Ø§ÙŠÙ„ Ø§Ù„Ø£ÙŠÙ‚ÙˆÙ†Ø© ÙÙ‚Ø· */
}

/* ========================================================================
   Form page action buttons â€” compact Ø¹Ù„Ù‰ Ø§Ù„Ù…ÙˆØ¨Ø§ÙŠÙ„
   Ø§Ù„Ø£Ø²Ø±Ø§Ø± Ø§Ù„Ø«Ø§Ù†ÙˆÙŠÙ‘Ø© (Ø¥Ù„ØºØ§Ø¡ / Ù…Ø¹Ø§ÙŠÙ†Ø© / Ø·Ø¨Ø§Ø¹Ø©) = Ø£ÙŠÙ‚ÙˆÙ†Ø§Øª ÙÙ‚Ø·.
   Ø²Ø±Ù‘ Ø§Ù„Ø­ÙØ¸ Ø§Ù„Ø±Ø¦ÙŠØ³ÙŠ = ÙŠØ­ØªÙØ¸ Ø¨Ø§Ù„Ø£ÙŠÙ‚ÙˆÙ†Ø© + Ø§Ù„Ù†ØµÙ‘.
   Ø§Ù„Ù…Ø¨Ø¯ÙŽÙ‘Ù„ (layout switcher) ÙŠØ®ØªÙÙŠ â€” ØºÙŠØ± Ù…ÙÙŠØ¯ Ø¹Ù„Ù‰ Ø´Ø§Ø´Ø© ØµØºÙŠØ±Ø©.
   ======================================================================== */
/* Ù‚Ø§Ø¹Ø¯Ø© Ù…ÙˆØ­Ù‘Ø¯Ø©: Ø¹Ù„Ù‰ Ø´Ø§Ø´Ø§Øª â‰¤ 1024px (laptops ØµØºÙŠØ±Ø©ØŒ tabletsØŒ Ù…ÙˆØ¨Ø§ÙŠÙ„)
   ÙƒÙ„Ù‘ Ø£Ø²Ø±Ø§Ø± Ø§Ù„Ù€ page-header ØªÙ†Ø¶ØºØ· Ù„Ø£ÙŠÙ‚ÙˆÙ†Ø© ÙÙ‚Ø· â€” back/view/save Ù…Ø¹Ø§Ù‹.
   `!important` Ù„Ù„ØªØºÙ„Ù‘Ø¨ Ø¹Ù„Ù‰ Ø£ÙŠÙ‘ font-size Ù„Ø§Ø­Ù‚ Ù…Ù† Ù‚ÙˆØ§Ø¹Ø¯ Ø§Ù„Ø£Ù†ÙˆØ§Ø¹
   (rvg-btn-primary ÙˆØºÙŠØ±Ù‡Ø§). */
@media (max-width: 1024px) {
    .rvg-layout-switcher { display: none !important; }

    .rvg-page-header-actions [class*="btn-back-"],
    .rvg-page-header-actions [class*="btn-view-"],
    .rvg-page-header-actions [class*="btn-save-"] {
        padding: 7px 10px !important;
        font-size: 0 !important;
        gap: 0 !important;
    }
    .rvg-page-header-actions [class*="btn-back-"] svg,
    .rvg-page-header-actions [class*="btn-view-"] svg,
    .rvg-page-header-actions [class*="btn-save-"] svg {
        font-size: 1rem !important;
        width: 16px !important; height: 16px !important;
        margin: 0 !important;
    }

    .rvg-page-header-actions {
        gap: 4px !important;
        flex-wrap: nowrap;
    }
}

@media (max-width: 768px) {

    /* Header row Ù‚Ø¯ ÙŠØ­ØªØ§Ø¬ ØªÙ‚Ù„Ù‘Øµ padding â€” Ø­Ø¬Ù… Ø§Ù„Ø®Ø·Ù‘ ÙŠÙØ­Ø³Ø¨Ù‡ `clamp()`
       ÙÙŠ Ø§Ù„Ù‚Ø§Ø¹Ø¯Ø© Ø§Ù„Ø£Ø³Ø§Ø³ÙŠÙ‘Ø©ØŒ ÙÙ„Ø§ Ø­Ø§Ø¬Ø© Ù„Ø¥Ø¹Ø§Ø¯Ø© ØªØ¹Ø±ÙŠÙÙ‡ Ù‡Ù†Ø§. Ø§Ù„Ù€ ellipsis
       Ø¨Ø§Ù‚Ù ÙƒÙ€ fallback Ù„Ùˆ Ø§Ù„Ø§Ø³Ù… Ø·ÙˆÙŠÙ„ Ø¬Ø¯Ø§Ù‹ Ø¬Ø¯Ø§Ù‹ ÙŠØªØ¬Ø§ÙˆØ² Ø­ØªÙ‘Ù‰ Ø§Ù„Ø­Ø¯Ù‘ Ø§Ù„Ø£Ø¯Ù†Ù‰. */
    .rvg-page-header { padding: 10px 12px; }
    .rvg-page-title-text {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
        max-width: none;
    }

    /* Ø§Ù„Ù€ actions row ÙŠØªÙ…Ø¯Ù‘Ø¯ Ø¨Ø¹Ø±Ø¶ Ù…Ù†Ø§Ø³Ø¨ ÙˆÙ„Ø§ ÙŠÙ„ØªÙÙ‘ */
    .rvg-page-header-actions {
        gap: 6px !important;
        flex-wrap: nowrap;
    }
}

/* Ø¹Ù„Ù‰ Ø´Ø§Ø´Ø§Øª ØµØºÙŠØ±Ø© (â‰¤ 640px) â€” Ø­ØªÙ‘Ù‰ Ø²Ø±Ù‘ Ø§Ù„Ø­ÙØ¸ ÙŠØµØ¨Ø­ Ø£ÙŠÙ‚ÙˆÙ†Ø© ÙÙ‚Ø·ØŒ ÙˆÙƒÙ„Ù‘
   Ø§Ù„Ø¥Ø¬Ø±Ø§Ø¡Ø§Øª ØªÙ†Ø¶ØºØ· Ø¨Ø­Ø´ÙˆØ© Ø£ØµØºØ±ØŒ Ø¹Ø´Ø§Ù† Ù…Ø³Ø§Ø­Ø© Ø§Ù„Ø¹Ù†ÙˆØ§Ù† ØªØ¨Ù‚Ù‰ Ù…Ø­ØªØ±Ù…Ø©. */
@media (max-width: 640px) {
    .rvg-page-header-actions {
        gap: 4px !important;
    }
    .rvg-page-header-actions [class*="btn-save-"] {
        font-size: 0;
        padding: 7px 10px;
        gap: 0;
    }
    .rvg-page-header-actions [class*="btn-save-"] svg {
        font-size: 1rem;
        width: 16px; height: 16px;
        margin: 0;
    }
    /* Ø§Ù„Ù€ back/view Ø£ØµÙ„Ø§Ù‹ icon-only Ù…Ù† Ù‚Ø§Ø¹Ø¯Ø© 768pxØŒ Ù†Ø¶Ù…Ù† Ø§Ù„Ø­Ø´ÙˆØ© Ø§Ù„Ù…ØªØ³Ø§ÙˆÙŠØ©. */
    .rvg-page-header-actions [class*="btn-back-"],
    .rvg-page-header-actions [class*="btn-view-"] {
        padding: 7px 10px;
    }
    /* Ø§Ù„Ø¹Ù†ÙˆØ§Ù† â€” `clamp()` ÙŠØªÙƒÙÙ‘Ù„ Ø¨Ø­Ø¬Ù… Ø§Ù„Ø®Ø·Ù‘ØŒ Ù†Ø²ÙŠÙ„ Ø§Ù„Ù€ max-width Ù„Ø¦Ù„Ø§
       ÙŠÙØ¬Ø¨Ø± Ø§Ù„Ù†ØµÙ‘ Ø¹Ù„Ù‰ Ø§Ù„Ø§Ø®ØªØ²Ø§Ù„ Ù„Ù€ "ØªØ¹..." Ø­ØªÙ‘Ù‰ Ø¹Ù„Ù‰ Ø´Ø§Ø´Ø§Øª ØµØºÙŠØ±Ø©. */
    .rvg-page-title-text { max-width: none; }
}

/* ========================================================================
   Ù‚Ø§Ø¹Ø¯Ø© Ø¹Ø§Ù…Ù‘Ø© Ù„Ù„Ù†ÙˆØ§ÙŠØ§ (semantic intent) Ø¹Ø¨Ø± ÙƒÙ„ ØµÙØ­Ø§Øª Ø§Ù„ØªØ·Ø¨ÙŠÙ‚.
   Ø§Ù„ÙÙƒØ±Ø©: Ø§Ù„Ø²Ø±Ù‘ Ù…Ø­Ø§ÙŠØ¯ Ø§ÙØªØ±Ø§Ø¶ÙŠØ§Ù‹ØŒ ÙˆÙŠÙƒØ´Ù Ø¹Ù† Ù†ÙŠÙ‘ØªÙ‡ ÙÙ‚Ø· Ø¹Ù†Ø¯ hover.

     - btn-view-*  (Ù…Ø¹Ø§ÙŠÙ†Ø©/Ø¹Ø±Ø¶)      â†’ Ø£Ø®Ø¶Ø± (Ø¥Ø¬Ø±Ø§Ø¡ Ø¢Ù…Ù†)
     - btn-edit-*  (ØªØ¹Ø¯ÙŠÙ„/Ø·Ø¨Ø§Ø¹Ø©)      â†’ Ø¨Ø±ØªÙ‚Ø§Ù„ÙŠÙ‘ (ÙŠØ¤Ø¯Ù‘ÙŠ Ù„ØªØºÙŠÙŠØ± â€” Ø­Ø°Ø±)
     - btn-delete-*                  â†’ Ø£Ø­Ù…Ø± (ÙŠÙÙØ¶ÙŽÙ‘Ù„ Ø¥Ø¶Ø§ÙØ© rvg-btn-danger ØµØ±Ø§Ø­Ø©)

   `btn-back-*` Ù…ØªØ¹Ø¯Ù‘Ø¯ Ø§Ù„Ù…Ø¹Ù†Ù‰: ÙÙŠ ØµÙØ­Ø© Ø§Ù„ØªÙØ§ØµÙŠÙ„ = Ø±Ø¬ÙˆØ¹ Ø¢Ù…Ù† (Ø£Ø®Ø¶Ø±)ØŒ ÙÙŠ Ø§Ù„ÙÙˆØ±Ù…
   = Ø¥Ù„ØºØ§Ø¡ Ø§Ù„ØªØºÙŠÙŠØ±Ø§Øª (Ø£Ø­Ù…Ø±). Ù„Ø°Ù„Ùƒ Ù†ØªØ±ÙƒÙ‡ Ø¨Ù„Ø§ Ù‚Ø§Ø¹Ø¯Ø© Ø¹Ø§Ù…Ù‘Ø© â€” ÙŠÙØ¶Ø§Ù rvg-btn-danger
   Ø£Ùˆ rvg-btn-success ØµØ±Ø§Ø­Ø©Ù‹ Ø­Ø³Ø¨ Ø§Ù„Ø³ÙŠØ§Ù‚.
   ======================================================================== */
[class*="btn-view-"]:hover:not(:disabled) {
    color: var(--color-success, #10b981) !important;
    border-color: var(--color-success, #10b981) !important;
}
[class*="btn-edit-"]:hover:not(:disabled) {
    color: var(--color-warning, #d97706) !important;
    border-color: var(--color-warning, #d97706) !important;
}
/* Ø§Ø³ØªØ«Ù†Ø§Ø¡ Ø§Ù„Ø­Ø§Ù„Ø© "Ù†Ø´Ø·" ÙÙŠ toolbar-style Ù„Ù€ layout switcher ÙˆÙ†Ø¸Ø§Ø¦Ø±Ù‡ â€” Ù„Ø§ Ù†Ø±ÙŠØ¯
   Ù‚Ù„Ø¨ Ù„ÙˆÙ†Ù‡Ø§ Ø¹Ù†Ø¯ hover Ù„Ø£Ù†Ù‡Ø§ ØªØ¹Ø¨Ù‘Ø± Ø¹Ù† Ø­Ø§Ù„Ø©ØŒ Ù„Ø§ Ø¥Ø¬Ø±Ø§Ø¡. */
.rvg-layout-switcher button:hover:not(:disabled) {
    color: inherit !important;
    border-color: transparent !important;
}

/* ========================================================================
   Page-header action bar — unified button sizing.
   ────────────────────────────────────────────────────────────────────────
   FR-119 (2026-06-03) ROOT-CAUSE FIX. All buttons inside
   `.rvg-page-header-actions` share ONE size system (height + padding +
   font). The ONLY visual distinction between rvg-btn-primary,
   rvg-btn-ghost, rvg-btn-secondary, rvg-btn-danger, etc. is COLOR
   (fill / outline / border-color), NOT geometry.

   Pre-FR state: rvg-btn-primary, [class*="btn-add-"], and rvg-btn-ghost
   each had their own padding (8px 18px / 8px 16px / inherited)
   producing visibly different button heights in the same row.

   This single block enforces uniform sizing across all `<a>` and
   `<button>` direct children. The mobile blocks below ONLY adjust the
   size — they DO NOT change the system (every button still shares one
   height at every viewport).
   ======================================================================== */
.rvg-page-header-actions {
    align-items: center;
    gap: var(--space-2) !important;
}
.rvg-page-header-actions > a,
.rvg-page-header-actions > button,
.rvg-page-header-actions > form > button {
    /* Unified box: 36px tall, 14px horizontal padding, 13px text.
       `!important` on padding beats atlas.css per-variant rules (e.g.
       `.rvg-btn-primary { padding: 8px 18px }`) without forcing
       `!important` everywhere. */
    box-sizing: border-box;
    height: 36px;
    padding: 0 14px !important;
    font-size: var(--text-sm);
    line-height: 1;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.rvg-page-header-actions > form { display: inline-flex; }
.rvg-page-header-actions .revogen-icon {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
}

@media (max-width: 768px) {
    /* Shrink — every page-header button stays uniform, just smaller.
       Owner rule (FR-119): "smaller, NOT hidden". Single selector list
       beats 12 specific variant selectors (was the patch storm cause). */
    .rvg-page-header-actions > a,
    .rvg-page-header-actions > button,
    .rvg-page-header-actions > form > button {
        height: 32px !important;
        padding: 0 10px !important;
        font-size: var(--text-xs) !important;
        gap: 4px !important;
    }
    .rvg-page-header-actions .revogen-icon {
        width: 13px !important;
        height: 13px !important;
    }
}

@media (max-width: 420px) {
    /* Tiny phones — one more shrink step. Labels remain visible. */
    .rvg-page-header-actions > a,
    .rvg-page-header-actions > button,
    .rvg-page-header-actions > form > button {
        height: 28px !important;
        padding: 0 8px !important;
        font-size: 11px !important;
        gap: 3px !important;
    }
    .rvg-page-header-actions .revogen-icon {
        width: 12px !important;
        height: 12px !important;
    }
}

/* ========================================================================
   Record meta popover â€” Ù„Ù„Ù…Ø¯Ø±Ø§Ø¡ ÙÙ‚Ø·ØŒ Ø¹Ù„Ù‰ ØµÙØ­ØªÙŽÙŠ detail/edit.
   Ù…ÙˆØ¶Ø¹Ù‡: Ø§Ù„Ø±ÙƒÙ† Ø§Ù„Ø£Ø³ÙÙ„ Ø¹Ù„Ù‰ Ø¬Ù‡Ø© Ø§Ù„Ù†Ù‡Ø§ÙŠØ© (ÙŠØ³Ø§Ø± ÙÙŠ RTLØŒ ÙŠÙ…ÙŠÙ† ÙÙŠ LTR)
   Ø¯Ø§Ø®Ù„ Ø§Ù„ÙÙˆØ±Ù… Ù†ÙØ³Ù‡. Ø§Ù„ÙÙˆØ±Ù… ÙŠØ­ØµÙ„ Ø¹Ù„Ù‰ position:relative Ø¶Ù…Ù†ÙŠØ§Ù‹.
   ======================================================================== */
/* Ø§Ù„Ø­Ø§ÙˆÙŠØ© Ø§Ù„ØªÙŠ ØªØ±ØªØ¨Ø· Ø¨Ù‡Ø§ Ø§Ù„Ø£ÙŠÙ‚ÙˆÙ†Ø©: Ø§Ù„ÙÙˆØ±Ù… ÙÙŠ editØŒ container Ø§Ù„ØªÙØ§ØµÙŠÙ„ ÙÙŠ detail */
form[class^="form-"],
[class^="dv-"][class$="-container"] {
    position: relative;
}

.rvg-rmeta {
    /* Anchored to the bottom-end corner of the form / detail container
       (both have `position: relative` set above). The popover itself is
       teleported to <body> in `_record_meta.twig`, so this absolute
       positioning only affects the small icon button — no overflow
       clipping risk on the popover.

       Suppressed entirely in embed (quick-edit dialog) mode at the Twig
       level (see form.twig — `{% if not is_embed %}` gate), so it can
       never overlap the embed footer's Save/Cancel buttons. */
    position: absolute;
    bottom: 12px;
    inset-inline-end: 12px;
    z-index: 10;
    display: inline-flex;
    align-items: center;
}
/* OP-52b (2026-06-11): 28px was sub-target and the FAB sat over content
   («عرض الكل» + textarea corner). 36px + the :has() rules below reserve
   real space in the hosting containers so nothing renders beneath it. */
.rvg-rmeta-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: var(--color-accent, #2563eb);
    color: #fff;
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(0,0,0,0.12);
    transition: all 0.15s;
}
.rvg-rmeta-btn:hover {
    box-shadow: 0 3px 12px rgba(0,0,0,0.18);
    background: var(--color-accent-hover, #1d4ed8);
}
.rvg-rmeta-btn svg { width: 15px; height: 15px; }
/* OP-52b: reserve the FAB's corner — any positioned host that contains
   .rvg-rmeta gets enough bottom padding that content can't sit under it. */
/* OP-49b: الفورم لم يعد يحوي rvg-rmeta عائماً (صار داخل الفوتر) —
   الحجز يبقى للـdetail فقط. */
div:has(> .rvg-rmeta) {
    padding-bottom: 64px;
}

/* Popover Ù…ÙØ·ÙŠÙŽÙ‘Ø± (x-teleport="body") Ø®Ø§Ø±Ø¬ Ø§Ù„ÙÙˆØ±Ù… â€” Ù„Ø§ ÙŠÙÙ‚ØµÙ‘ Ù…Ù† Ø§Ù„Ù€ overflow
   ÙˆÙ„Ø§ ÙŠØ®ØªÙÙŠ ØªØ­Øª Ø§Ù„Ù€ navbar. Ù…ÙˆØ¶Ø¹Ù‡ ÙŠÙØ­Ø³ÙŽØ¨ Ù…Ù† Ù…ÙˆÙ‚Ø¹ Ø§Ù„Ø²Ø±Ù‘ ÙÙŠ Ø§Ù„Ù€ viewport. */
.rvg-rmeta-popover {
    position: fixed;
    width: min(380px, calc(100vw - 40px));
    background: var(--color-bg, #fff);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.18);
    /* Higher than the quick-create/edit modal (9999) so it surfaces ABOVE
       the dialog when triggered from inside it. */
    z-index: 10001;
    overflow: hidden;
    max-height: 70vh;
    overflow-y: auto;
}

@media (max-width: 560px) {
    .rvg-rmeta-btn { width: 40px; height: 40px; }
}

/* Embed (Quick Edit dialog) — record meta sits in the toolbar next to
   the layout switcher instead of being absolute-positioned at the
   bottom-end of the form (which would overlap the dialog's Save/Cancel
   footer). The slot wrapper neutralises the parent `.rvg-rmeta`'s
   `position: absolute`, the icon flows inline. The teleported popover
   keeps its `position: fixed` + z-index: 10001 so it surfaces above the
   modal. */
.rvg-qc-embed-tools .rvg-rmeta-slot {
    display: inline-flex;
    align-items: center;
}
.rvg-qc-embed-tools .rvg-rmeta-slot .rvg-rmeta {
    position: static;
    inset: auto;
    z-index: auto;
}

.rvg-rmeta-head {
    display: flex; align-items: center; gap: 8px;
    padding: 12px 16px;
    background: var(--color-bg-alt, #fafafa);
    border-bottom: 1px solid var(--color-border, #e2e8f0);
    font-weight: 600;
    color: var(--color-text, #1f2937);
    font-size: 0.9rem;
}
.rvg-rmeta-head svg { width: 16px; height: 16px; color: var(--color-accent, #2563eb); }

.rvg-rmeta-block {
    padding: 12px 16px;
}
.rvg-rmeta-block + .rvg-rmeta-block { border-top: 1px solid var(--color-border, #e2e8f0); }

.rvg-rmeta-label {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-soft, #94a3b8);
    margin-bottom: 6px;
}

.rvg-rmeta-identity {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    font-size: 0.9rem;
    color: var(--color-text, #1f2937);
}
.rvg-rmeta-avatar,
.rvg-rmeta-avatar-placeholder {
    width: 28px; height: 28px;
    border-radius: 8px;
    flex-shrink: 0;
}
.rvg-rmeta-avatar { object-fit: cover; }
.rvg-rmeta-avatar-placeholder {
    background: var(--color-accent, #2563eb);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 0.75rem;
}
.rvg-rmeta-identity code {
    font-family: var(--font-mono);
    background: var(--color-surface-soft, #f4f4f5);
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 0.75rem;
    color: var(--color-text-muted, #64748b);
}
.rvg-rmeta-group-tag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px; height: 28px;
    border-radius: 8px;
    background: color-mix(in oklab, var(--color-accent, #2563eb) 15%, white);
    color: var(--color-accent, #2563eb);
    flex-shrink: 0;
}
.rvg-rmeta-group-tag svg { width: 13px; height: 13px; }

.rvg-rmeta-actions {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.rvg-rmeta-actions a {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    margin-inline-start: -4px;
    border-radius: 6px;
    font-size: 0.82rem;
    color: var(--color-text-muted, #64748b);
    text-decoration: none;
    transition: all 0.12s;
}
.rvg-rmeta-actions a:hover {
    background: var(--color-surface-soft, #f4f4f5);
    color: var(--color-accent, #2563eb);
}
.rvg-rmeta-actions svg { width: 13px; height: 13px; opacity: 0.7; flex-shrink: 0; }

.rvg-rmeta-empty {
    color: var(--color-text-soft, #94a3b8);
    font-style: italic;
    font-size: 0.85rem;
}

/* Timeline at the bottom */
.rvg-rmeta-timeline { background: var(--color-bg-alt, #fafafa); }
.rvg-rmeta-timeline-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding: 4px 0;
    font-size: 0.82rem;
}
.rvg-rmeta-timeline-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--color-text-muted, #64748b);
}
.rvg-rmeta-timeline-label svg {
    width: 12px; height: 12px;
    opacity: 0.6;
}
.rvg-rmeta-timeline-value {
    color: var(--color-text, #1f2937);
    font-variant-numeric: tabular-nums;
    text-align: end;
}
.rvg-rmeta-timeline-value small {
    display: block;
    font-size: 0.72rem;
    color: var(--color-text-muted, #64748b);
    margin-top: 2px;
}

/* ========================================================================
   Page Header â€” ØªØ­Ø³ÙŠÙ† Ù…Ø³Ø·Ù‘Ø­ Ø¨Ø¯ÙˆÙ† bg/shadow/borders:
   ÙÙ‚Ø· typography Ø£ÙØ¶Ù„ + spacing Ù…Ø±ÙŠØ­ + divider Ù†Ø§Ø¹Ù… ØªØ­Øª Ø§Ù„Ù€ header.
   ======================================================================== */
.rvg-main {
    padding-top: calc(var(--space-6) + 16px) !important;
}

/* Page header â€” Ø¨Ø·Ø§Ù‚Ø© Ù…Ø­Ø§ÙŠØ¯Ø© Ù…Ø¹ Ø´Ø±ÙŠØ· accent Ø¹Ù„Ù‰ Ø§Ù„Ø­Ø§ÙØ© Ø§Ù„Ø§Ø¨ØªØ¯Ø§Ø¦ÙŠÙ‘Ø©.
   Ù…Ø·Ø§Ø¨Ù‚Ø© Ù„ØªØµÙ…ÙŠÙ… .bk-hero (admin/backups). */
.rvg-page-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-4);
    background: var(--color-bg);
    /* border: 1px solid var(--color-border); */
    border-radius: var(--radius-lg);
    /* border-inline-start: 3px solid var(--color-accent); */
}
.rvg-page-header .rvg-page-header-main {
    flex: 1;
    align-items: baseline;
    gap: var(--space-4, 16px);
}

/* Ø§Ù„Ø¹Ù†ÙˆØ§Ù† â€” Ø£ÙƒØ¨Ø± ÙˆØ£Ø«Ù‚Ù„ØŒ Ø§Ù„Ø£ÙŠÙ‚ÙˆÙ†Ø© Ø¨Ù„ÙˆÙ† accent Ø®ÙÙŠÙ.
   `clamp()` ÙŠØµØºÙ‘Ø± Ø§Ù„Ø®Ø·Ù‘ ØªÙ„Ù‚Ø§Ø¦ÙŠØ§Ù‹ Ù…Ø¹ ØªÙ‚Ù„Ù‘Øµ Ø§Ù„Ø¹Ø±Ø¶ Ø¨Ø¯Ù„Ø§Ù‹ Ù…Ù† Ø§Ù„Ù€ ellipsisØŒ
   Ù„ÙŠØ¨Ù‚Ù‰ Ø§Ø³Ù… Ø§Ù„Ø¬Ø¯ÙˆÙ„ Ø§Ù„ÙƒØ§Ù…Ù„ Ø¸Ø§Ù‡Ø± Ø¹Ù„Ù‰ Ø´Ø§Ø´Ø§Øª Ø§Ù„Ù…ÙˆØ¨Ø§ÙŠÙ„ ÙˆØ§Ù„ØªØ§Ø¨. */
.rvg-page-header .rvg-page-title {
    font-size: clamp(0.95rem, 0.55vw + 0.78rem, 1.4rem) !important;
    font-weight: 700 !important;
    letter-spacing: -0.01em;
}
.rvg-page-header .rvg-page-title .revogen-icon {
    width: 1.35rem !important;
    height: 1.35rem !important;
    color: var(--color-accent, #2563eb);
    opacity: 0.85;
}
/* Page-title link wraps both the icon AND the title text — clicking
   anywhere on the heading navigates back to the table's list. Plain
   hover: icon goes full-opacity, no background, no decoration. */
.rvg-page-header .rvg-page-title .rvg-page-title-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: inherit;
    text-decoration: none;
    transition: color 0.15s ease;
}
.rvg-page-header .rvg-page-title .rvg-page-title-link:hover .revogen-icon {
    opacity: 1;
}
.rvg-page-header .rvg-page-title .rvg-page-title-link:hover .rvg-page-title-text {
    color: var(--color-accent);
}

/* Ø§Ù„Ø¹Ø¯Ù‘Ø§Ø¯ (7) â€” Ø±Ù‚Ù… Ù†Ø§Ø¹Ù… Ø¨Ø¬Ø§Ù†Ø¨ Ø§Ù„Ø¹Ù†ÙˆØ§Ù† (Ø¨Ø¯ÙˆÙ† pill â€” ÙÙ‚Ø· Ù„ÙˆÙ† Ù…Ø®ØªÙ„Ù) */
.rvg-page-header [class*="list-"][class*="-count"] {
    color: var(--color-text-soft, #94a3b8);
    font-weight: 500;
    font-size: 0.9rem;
    margin-inline-start: 8px;
    vertical-align: baseline;
}

/* Ø²Ø±Ù‘ Ø§Ù„Ø¥Ø¶Ø§ÙØ© â€” flat filledØŒ Ù„Ø§ Ø¸Ù„Ù‘ ÙˆÙ„Ø§ gradient */
/* FR-119 (2026-06-03): padding removed so the Add button inherits the
   generic action sizing (`height: 36px; padding: 0 14px`). The pre-FR
   `padding: 8px 16px !important` left Add at ~32px tall while siblings
   rendered at 36px — visible size mismatch in the page header row. */
.rvg-page-header-actions [class*="btn-add-"] {
    background: var(--color-accent, #2563eb) !important;
    color: #fff !important;
    border: 1px solid var(--color-accent, #2563eb) !important;
    font-weight: 500 !important;
    transition: background 0.15s !important;
}
.rvg-page-header-actions [class*="btn-add-"]:hover {
    background: var(--color-accent-hover, #1d4ed8) !important;
    border-color: var(--color-accent-hover, #1d4ed8) !important;
}

/* ========================================================================
   List page toolbar â€” mobile layout
   ÙŠØªØ­ÙˆÙ‘Ù„ Ø¥Ù„Ù‰ Ø³Ø·Ø±ÙŠÙ†: Ø§Ù„Ø¨Ø­Ø« Ø¨Ø¹Ø±Ø¶ ÙƒØ§Ù…Ù„ ÙÙˆÙ‚ØŒ Ø§Ù„Ø£Ø¯ÙˆØ§Øª ØªØ­Øª.
   Ø§Ù„Ù€ class names Ø¯ÙŠÙ†Ø§Ù…ÙŠÙƒÙŠÙ‘Ø© (list-{table}-toolbar) ÙÙ†Ø³ØªØ®Ø¯Ù… attribute selectors.
   ======================================================================== */
/* FR-119 (2026-06-03) — STRIPPED: see CSS comment block above (List
   page toolbar — mobile layout). The mobile attribute-selector rules
   that used to live in this slot collided with list.twig's per-table
   inline rules. Mobile chrome now lives entirely in list.twig (one
   source of truth per-table). */

/* ==========================================================================
 * FR-118 (2026-06-04) — Data-scale cluster (`tables/_data_scale.twig`).
 * Single 34×34 toggle icon (zoom-in) opens a small popover that holds the
 * three adjustment buttons (A− / 100% / A+). Reused by both the framework
 * list toolbar AND the transfers reports — chrome lives here so every
 * consumer gets the same look without duplicated CSS.
 *
 * Layout positioning (margin-inline-start: auto / etc.) is the CONSUMER's
 * job — pass `extra_class` to the partial and style that class in the
 * consumer's own CSS scope.
 * ========================================================================= */
.rvg-data-scale {
    position: relative;       /* popover anchor */
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    box-sizing: border-box;
}
.rvg-data-scale-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: var(--rvg-tb-h, 34px);
    height: var(--rvg-tb-h, 34px);
    padding: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--rvg-tb-radius, var(--radius-sm));
    background: var(--color-bg);
    color: var(--color-text-muted);
    font-family: inherit;
    cursor: pointer;
    transition: var(--transition);
}
.rvg-data-scale-toggle:hover {
    background: var(--color-bg-hover);
    color: var(--color-text);
}
.rvg-data-scale-toggle.is-dirty {
    border-color: var(--color-accent);
    color: var(--color-accent);
}
.rvg-data-scale-toggle[aria-expanded="true"] {
    background: var(--color-bg-alt);
    color: var(--color-text);
}
.rvg-data-scale-popover {
    position: absolute;
    top: calc(100% + 4px);
    inset-inline-end: 0;
    z-index: 100;
    display: inline-flex;
    align-items: stretch;
    height: var(--rvg-tb-h, 34px);
    border: 1px solid var(--color-border);
    border-radius: var(--rvg-tb-radius, var(--radius-sm));
    background: var(--color-bg);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    overflow: hidden;
}
.rvg-data-scale-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 44px;
    height: 100%;
    padding: 0;
    border: 0;
    border-inline-end: 1px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-text-muted);
    font-family: inherit;
    font-size: var(--text-xs);
    font-weight: 600;
    cursor: pointer;
    transition: var(--transition);
}
.rvg-data-scale-btn:last-child { border-inline-end: 0; }
.rvg-data-scale-btn:hover:not(:disabled) {
    background: var(--color-bg-hover);
    color: var(--color-text);
}
.rvg-data-scale-btn:active:not(:disabled) { background: var(--color-bg-alt); }
.rvg-data-scale-btn:disabled { opacity: 0.4; cursor: default; }
.rvg-data-scale-btn.is-reset {
    min-width: 52px;
    color: var(--color-accent);
    font-variant-numeric: tabular-nums;
}

/* ==========================================================================
 * MIGRATED FROM custom/searchable-select.css (2026-04-28)
 * Searchable Select â€” ØªØµÙ…ÙŠÙ… Ù…ØªÙˆØ§ÙÙ‚ Ù…Ø¹ Ø§Ù„Ù€ theme (ÙŠØ³ØªØ®Ø¯Ù… CSS variables)
 * ÙŠÙØ·Ø¨ÙŽÙ‘Ù‚ ØªÙ„Ù‚Ø§Ø¦ÙŠÙ‘Ø§Ù‹ Ø¹Ù„Ù‰ ÙƒÙ„Ù‘ <select> (Ø¥Ù„Ø§ Ù…Ø§ ÙƒØ§Ù† data-no-search)
 * ========================================================================= */

.rvg-sel {
    position: relative;
    display: block;
    width: 100%;
    font-family: inherit;
    font-size: var(--text-sm, 14px);
    line-height: 1.4;
    box-sizing: border-box;
}
.rvg-sel * { box-sizing: border-box; }

/* inline mode â€” Ù„Ù„Ù€ toolbars ÙˆØ§Ù„Ù€ selects Ø§Ù„ØµØºÙŠØ±Ø© */
.rvg-sel--inline {
    display: inline-block;
    width: auto;
    min-width: 160px;
    max-width: 100%;
    vertical-align: middle;
}

/* ============ Button (ÙŠØ³ØªØ¨Ø¯Ù„ Ù…Ø¸Ù‡Ø± Ø§Ù„Ù€ select) ============ */
/* Owner rule (2026-05-02): every form input (text, number, date, email,
   url, tel, password, search, color, time, datetime, textarea, native
   <select>) uses the same faded-accent border as the searchable-select
   widget. `color-mix(... var(--color-accent) 46% ...)` matches
   `#cba97a75` on the default gold theme and adapts cleanly to dark mode
   + custom accent picks.

   Scoped via the framework's `inp-<table>-<name>` class so Bootstrap
   widgets (search box in the topbar, navbar pickers, etc.) keep their
   own chrome. `[class*="inp-"]` is broad on purpose â€” every dna-driven
   form field carries this prefix. */
[class*="inp-"]:is(input, textarea, select):not([type="hidden"]):not([type="checkbox"]):not([type="radio"]) {
    border: 1px solid color-mix(in srgb, var(--color-accent) 46%, transparent);
}
[class*="inp-"]:is(input, textarea, select):hover:not(:disabled):not([readonly]) {
    border-color: color-mix(in srgb, var(--color-accent) 65%, transparent);
}
[class*="inp-"]:is(input, textarea, select):focus-visible,
[class*="inp-"]:is(input, textarea, select):focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-accent) 20%, transparent);
}

/* FR-119 (2026-06-04) — Input height unification.
   Text/number/email/url/tel/password/affix-wrap all render at 44.23px
   naturally (padding 8.8 + line-height 24.64 + border 2). Bring outlier
   controls (color/file) to the same 44px baseline so every form row has
   a consistent height. Date/time inputs are regular `<input>` and follow
   the same path automatically. */
[class*="inp-"][type="color"] {
    min-height: 44px;
    height: 44px;
    padding: 4px 6px;
    box-sizing: border-box;
}
/* file input: استُثني من تَوحيد الارتِفاع — يَبقى على الـbrowser default. */

.rvg-sel__btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 7px 12px;
    box-sizing: border-box;
    background: var(--color-bg);
    /* Same faded accent border applied above to native inputs â€” keeps
       the searchable-select widget visually identical to a normal field. */
    border: 1px solid color-mix(in srgb, var(--color-accent) 46%, transparent);
    border-radius: var(--radius-sm, 4px);
    color: var(--color-text);
    font-family: inherit;
    font-size: inherit;
    line-height: inherit;
    cursor: pointer;
    text-align: start;
    transition: border-color 120ms ease, background 120ms ease, box-shadow 120ms ease;
    min-height: 44px;
}
.rvg-sel__btn:hover:not(:disabled) {
    border-color: color-mix(in srgb, var(--color-accent) 50%, var(--color-border));
    background: var(--color-bg-hover, var(--color-bg-alt));
}
.rvg-sel__btn:focus-visible,
.rvg-sel.is-open .rvg-sel__btn {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-accent) 20%, transparent);
}
.rvg-sel__btn:disabled {
    opacity: 0.55;
    cursor: not-allowed;
    background: var(--color-bg-alt);
}

.rvg-sel__label {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.rvg-sel__label.is-placeholder {
    color: var(--color-text-muted);
    font-weight: 400;
}

.rvg-sel__caret {
    flex-shrink: 0;
    color: var(--color-text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: transform 180ms ease, color 120ms ease;
}
.rvg-sel.is-open .rvg-sel__caret {
    color: var(--color-accent);
    transform: rotate(180deg);
}

/* ============ Panel (popup) ============ */
.rvg-sel__panel {
    position: absolute;
    inset-inline-start: 0;
    inset-inline-end: 0;
    top: calc(100% + 4px);
    z-index: 9999;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md, 6px);
    box-shadow:
        0 6px 24px rgba(0, 0, 0, 0.12),
        0 2px 8px rgba(0, 0, 0, 0.06);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    min-width: 220px;
    max-height: 360px;
}
[data-bs-theme="dark"] .rvg-sel__panel {
    box-shadow:
        0 8px 28px rgba(0, 0, 0, 0.5),
        0 2px 8px rgba(0, 0, 0, 0.3);
}
.rvg-sel__panel[hidden] { display: none !important; }

/* Ø¥Ø°Ø§ Ù…Ø§ ÙÙŠ Ù…Ø³Ø§Ø­Ø© Ø£Ø³ÙÙ„ â†’ ÙŠÙØªØ­ Ù„Ø£Ø¹Ù„Ù‰ */
.rvg-sel__panel.is-above {
    top: auto;
    bottom: calc(100% + 4px);
}

/* Portal mode â€” when the panel is reparented to <body> (opens from a
   select whose ancestors use CSS columns / transform / overflow-hidden),
   positioning switches from absolute-inside-wrap to fixed-in-viewport.
   JS writes top/left/width as inline styles; we only need to (a) force
   the fixed layout primitive and (b) clear the RTL logical insets from
   the default .rvg-sel__panel rule. We do NOT use !important on top or
   bottom â€” that would beat the JS-set inline coordinates and the panel
   would render at `auto` (= collapsed). */
.rvg-sel__panel--portal {
    position: fixed !important;
    inset-inline-start: auto;
    inset-inline-end:   auto;
    right: auto;
    left:  auto;
}

/* inline mode â€” panel ÙŠØ§Ø®Ø° Ø¹Ø±Ø¶Ù‡ Ø§Ù„Ø·Ø¨ÙŠØ¹ÙŠÙ‘ */
.rvg-sel--inline .rvg-sel__panel {
    inset-inline-start: 0;
    inset-inline-end: auto;
    width: max-content;
    min-width: 100%;
}

/* ============ Search input ============ */
.rvg-sel__search-wrap {
    position: relative;
    padding: 8px;
    background: var(--color-bg-alt);
    border-bottom: 1px solid var(--color-border);
}
.rvg-sel__search-icon {
    position: absolute;
    top: 50%;
    inset-inline-start: 18px;
    transform: translateY(-50%);
    color: var(--color-text-muted);
    pointer-events: none;
    display: inline-flex;
}
.rvg-sel__search {
    width: 100%;
    padding: 7px 12px;
    padding-inline-start: 32px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm, 4px);
    background: var(--color-bg);
    font-family: inherit;
    font-size: 13px;
    color: var(--color-text);
    line-height: 1.4;
    outline: none;
    transition: border-color 120ms ease, box-shadow 120ms ease;
}
.rvg-sel__search:focus {
    border-color: var(--color-accent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-accent) 18%, transparent);
}
.rvg-sel__search::placeholder {
    color: var(--color-text-soft);
}

/* ============ List of options ============ */
.rvg-sel__list {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 4px 0;
    scrollbar-width: thin;
    scrollbar-color: var(--color-border) transparent;
}
.rvg-sel__list::-webkit-scrollbar { width: 8px; }
.rvg-sel__list::-webkit-scrollbar-thumb {
    background: var(--color-border);
    border-radius: 4px;
}
.rvg-sel__list::-webkit-scrollbar-track { background: transparent; }

.rvg-sel__item {
    padding: 7px 14px;
    font-size: 13px;
    color: var(--color-text);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: background 100ms ease, color 100ms ease;
    user-select: none;
    border-inline-start: 3px solid transparent;
}
.rvg-sel__item:hover {
    background: var(--color-bg-hover, var(--color-bg-alt));
}
.rvg-sel__item.is-highlighted {
    background: var(--color-accent-soft);
    color: var(--color-accent);
    border-inline-start-color: var(--color-accent);
}
.rvg-sel__item.is-selected {
    background: color-mix(in srgb, var(--color-accent) 10%, var(--color-bg));
    color: var(--color-accent);
    font-weight: 600;
    border-inline-start-color: var(--color-accent);
}
.rvg-sel__item.is-selected.is-highlighted {
    background: var(--color-accent-soft);
}

.rvg-sel__empty {
    padding: 16px 12px;
    text-align: center;
    color: var(--color-text-muted);
    font-size: 13px;
}

/* ============ FR-035 â€” Lazy-mode states inside the Searchable Select panel ============ */
.rvg-sel__lazy-state {
    padding: 16px 12px;
    text-align: center;
    color: var(--color-text-muted);
    font-size: 13px;
    line-height: 1.5;
}
.rvg-sel__lazy-state.is-loading {
    color: var(--color-accent);
    font-style: italic;
}
.rvg-sel__lazy-state.is-error {
    color: #dc2626;
}
[data-bs-theme="dark"] .rvg-sel__lazy-state.is-error { color: #f87171; }
.rvg-sel__lazy-state.is-empty {
    color: var(--color-text);
    font-weight: 500;
}

.rvg-sel__lazy-qc {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: 4px 8px 8px;
    padding: 10px 12px;
    border: 1px dashed color-mix(in srgb, var(--color-accent) 45%, transparent);
    background: color-mix(in srgb, var(--color-accent) 8%, transparent);
    color: var(--color-accent);
    border-radius: 8px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    width: calc(100% - 16px);
    font-family: inherit;
    transition: background 120ms, border-color 120ms;
}
.rvg-sel__lazy-qc:hover {
    background: color-mix(in srgb, var(--color-accent) 16%, transparent);
    border-style: solid;
    border-color: var(--color-accent);
}
.rvg-sel__lazy-qc:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 1px;
}
.rvg-sel__lazy-qc-icon {
    flex-shrink: 0;
}

/* ============ ØªØ­Ø³ÙŠÙ†Ø§Øª Ù„Ù„Ù€ admin navbar Ø§Ù„Ø¯Ø§ÙƒÙ† ============ */
body.revogen-admin-chrome .rvg-sel__panel {
    /* Ù„Ø§ Ø´ÙŠØ¡ â€” Ù†ÙØ³ Ø§Ù„Ù€ panelØŒ Ù„ÙƒÙ† Ù†Ù…Ù†Ø¹ ÙˆØ±Ø§Ø«Ø© Ø®Ù„ÙÙŠÙ‘Ø© Ø§Ù„Ù†Ø§ÙØ¨Ø§Ø± Ø§Ù„Ø¯Ø§ÙƒÙ†Ø© Ø¥Ù† ÙƒØ§Ù† Ø¯Ø§Ø®Ù„ Ø§Ù„Ù€ header */
}
body.revogen-admin-chrome .rvg-header .rvg-sel__btn {
    background: color-mix(in srgb, #ffffff 6%, transparent);
    border-color: color-mix(in srgb, #ffffff 14%, transparent);
    color: color-mix(in srgb, #ffffff 90%, transparent);
}
body.revogen-admin-chrome .rvg-header .rvg-sel__btn:hover {
    background: color-mix(in srgb, var(--color-accent) 22%, transparent);
    border-color: color-mix(in srgb, var(--color-accent) 45%, transparent);
    color: #ffffff;
}

/* ============ Print: Ø£Ø¸Ù‡ÙØ± Ø§Ù„Ù€ native select ============ */
@media print {
    .rvg-sel__btn,
    .rvg-sel__panel { display: none !important; }
    .rvg-sel select {
        position: static !important;
        width: auto !important;
        height: auto !important;
        padding: initial !important;
        margin: initial !important;
        overflow: visible !important;
        clip: auto !important;
        white-space: normal !important;
        border: 1px solid #999 !important;
    }
}

/* ============================================================================
   Universal modal system â€” used by both Classic (dashboard.twig) and Atlas
   shells. SINGLE SOURCE OF TRUTH â€” any visual tweak applies everywhere
   without manual mirror maintenance. (Previously duplicated inline in
   dashboard.twig + scoped in atlas.css â†’ drift risk.)
============================================================================ */
.rvg-modal-backdrop {
    position: fixed; inset: 0;
    background: var(--rvg-modal-backdrop-bg);
    backdrop-filter: var(--rvg-modal-backdrop-blur);
    z-index: 1900;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
}
.rvg-modal {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: 0 24px 48px rgba(0, 0, 0, 0.20);
    max-width: 440px;
    width: 100%;
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}
.rvg-modal-header {
    display: flex; align-items: center; gap: var(--space-3);
}
.rvg-modal-header .revogen-icon {
    width: 2rem; height: 2rem;
    color: var(--color-danger);
    flex-shrink: 0;
}
.rvg-modal-title {
    font-size: var(--text-lg);
    font-weight: 600;
    margin: 0;
    color: var(--color-text);
}
.rvg-modal-body {
    font-size: var(--text-sm);
    line-height: 1.6;
    color: var(--color-text-muted);
    margin: 0;
}
.rvg-modal-body strong {
    color: var(--color-text);
    background: var(--color-bg-alt);
    padding: 2px 6px;
    border-radius: var(--radius-sm);
    font-weight: 500;
}
.rvg-modal-footer {
    display: flex; gap: var(--space-2);
    justify-content: flex-end;
    flex-wrap: wrap;
}
.rvg-modal-input-wrap {
    margin: 0 0 var(--space-4);
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.rvg-modal-input-label {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-text);
}
.rvg-modal-btn {
    display: inline-flex; align-items: center; gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-text);
    font-family: inherit; font-size: var(--text-sm);
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.rvg-modal-btn:hover { background: var(--color-bg-hover); }
.rvg-modal-btn-danger {
    background: var(--color-danger);
    border-color: var(--color-danger);
    color: #fff; font-weight: 500;
}
.rvg-modal-btn-danger:hover {
    background: #b91c1c; border-color: #b91c1c; color: #fff;
}
.rvg-modal-btn-warning {
    background: #f59e0b;
    border-color: #f59e0b;
    color: #fff; font-weight: 500;
}
.rvg-modal-btn-warning:hover {
    background: #d97706; border-color: #d97706; color: #fff;
}
/* Primary uses --color-accent in Classic. Atlas overrides this in atlas.css
   to use the gold (--atlas-light) palette â€” only ONE rule mirrored. */
.rvg-modal-btn-primary {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: #fff; font-weight: 500;
}
.rvg-modal-btn-primary:hover {
    background: var(--color-accent-hover, var(--color-accent));
    filter: brightness(1.05);
}
.rvg-modal.rvg-modal--success .rvg-modal-header .revogen-icon { color: var(--color-success); }
.rvg-modal.rvg-modal--warning .rvg-modal-header .revogen-icon { color: var(--color-warning); }
.rvg-modal.rvg-modal--danger  .rvg-modal-header .revogen-icon { color: var(--color-danger); }

/* ============================================================================
   Print frame — UNIVERSAL running header + footer for `window.print()`.
   SINGLE SOURCE OF TRUTH for every dashboard / atlas page that calls print.

   ── ARCHITECTURE ────────────────────────────────────────────────────────────
   The print chrome (header + footer) is wrapped INSIDE a real HTML
   `<table class="rvg-print-frame">` whose `<thead>` is the header and
   `<tfoot>` is the footer. The page content lives in `<tbody>`.

   This is the ONLY technique that reliably repeats running chrome on every
   printed page across Chrome, Edge, Firefox, and Safari. Browsers natively
   repeat `<thead>` on every printed page (since the 90s) and `<tfoot>` on
   every page (Chromium since v96, Firefox/Safari since forever). The print
   engine itself measures the rendered <thead>/<tfoot> heights and reserves
   exactly that much body space per page — NO magic @page margin numbers,
   NO position:fixed overlays, NO JavaScript probes, NO clipping.

   ── WHY THE OLD APPROACH BROKE ──────────────────────────────────────────────
   The previous version used `position: fixed` + `@page margin: 3.2cm 1.5cm
   2.5cm`. Two compounding failures clipped body content (table header rows
   sliced at the top, last cells sliced at the bottom):
     1. Chromium positions `position: fixed` relative to each page's viewport
        but doesn't enforce that the @page margin corridor is ≥ the fixed
        element's actual rendered height. When chrome content wrapped (long
        footer text, long page title, multi-line user meta) it grew beyond
        the corridor and overlapped body.
     2. The corridor sizes were guesses tuned to one specific font/zoom
        combination — any deviation (different user, longer title, footer
        wrap) destroyed the reserved space.
   Real <table> + <thead>/<tfoot> + `display: contents` (the voucher pattern)
   sidesteps both: the browser auto-measures and reserves the correct space
   for whatever the chrome actually renders.

   ── SCREEN vs PRINT ─────────────────────────────────────────────────────────
   On screen, every table element gets `display: contents` so the scaffold
   layout box evaporates entirely — children of `<td>` become direct children
   of `<main>`. Zero impact on existing screen CSS, Alpine, or JS that targets
   `.rvg-main > *` / `.atlas-main > *`. `display: contents` is supported in
   every browser since 2018; safe and stable.

   On print, native table semantics are restored (`display: table` /
   `table-header-group` / `table-row-group` / `table-footer-group`). The
   running chrome appears, the body flows freely, no overlap is possible.
============================================================================ */

/* ── Screen: scaffold is invisible ──────────────────────────────────────────
   `display: contents` strips the table layout box; children phase through
   to their grandparent (`.rvg-main` / `.atlas-main`). All existing screen
   styling continues to apply to the inner content unchanged. */
.rvg-print-frame,
.rvg-print-frame > thead,
.rvg-print-frame > tbody,
.rvg-print-frame > tfoot,
.rvg-print-frame > thead > tr,
.rvg-print-frame > tbody > tr,
.rvg-print-frame > tfoot > tr,
.rvg-print-frame > thead > tr > td,
.rvg-print-frame > tbody > tr > td,
.rvg-print-frame > tfoot > tr > td {
    display: contents;
}

/* The chrome itself (.rvg-print-header / .rvg-print-footer) is hidden on
   screen — only visible during print. */
.rvg-print-header,
.rvg-print-footer { display: none; }

@media print {
    /* ── @page: simple symmetric margins ──────────────────────────────────
       No magic corridors. The print engine reserves chrome space per page
       by measuring rendered <thead>/<tfoot> — these @page margins are just
       the paper-edge breathing room outside that. */
    @page { margin: 10mm 10mm 10mm; }

    /* Chrome bug #348796223 — RTL print scale offset fix. */
    html { direction: ltr !important; }
    body { direction: rtl !important; unicode-bidi: isolate; }
    * {
        -webkit-print-color-adjust: exact !important;
                print-color-adjust: exact !important;
    }

    /* ── Print frame: switch from `display: contents` back to native table
       semantics so <thead> repeats on every page and <tfoot> reserves
       bottom-margin space per page. */
    .rvg-print-frame {
        display: table !important;
        width: 100% !important;
        border-collapse: collapse !important;
        table-layout: fixed;
    }
    .rvg-print-frame > thead { display: table-header-group !important; }
    .rvg-print-frame > tbody { display: table-row-group   !important; }
    .rvg-print-frame > tfoot { display: table-footer-group !important; }
    .rvg-print-frame > thead > tr,
    .rvg-print-frame > tbody > tr,
    .rvg-print-frame > tfoot > tr { display: table-row !important; }
    .rvg-print-frame > thead > tr > td,
    .rvg-print-frame > tbody > tr > td,
    .rvg-print-frame > tfoot > tr > td {
        display: table-cell !important;
        padding: 0 !important;
        vertical-align: top;
    }

    /* ── Header (running — repeats on every printed page) ─────────────────
       3-column grid: brand (RTL-start) · title (centre) · meta (RTL-end).
       The meta column carries a tiny date/time stamp so the title centre
       column never drifts when one side has more content than the other.
       A polished accent stripe under the row gives a clean professional
       finish without a harsh black border. */
    .rvg-print-header {
        display: grid !important;
        grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
        align-items: center;
        gap: 14px;
        padding: 6px 4mm 10px;
        background: #fff;
        font-family: inherit;
        position: relative;
        border-bottom: 1px solid color-mix(in srgb,
            var(--atlas-dark-soft, var(--color-accent, #4a3520)) 18%, #fff);
        margin-bottom: 8px;
    }
    .rvg-print-header::after {
        /* Accent gradient stripe under the row — the visual signature of
           the running header. Token-driven so palette swaps propagate. */
        content: '';
        position: absolute;
        bottom: -1px; left: 0; right: 0;
        height: 2px;
        background: linear-gradient(to left,
            var(--atlas-light, #d4af6f) 0,
            var(--atlas-dark-soft, var(--color-accent, #4a3520)) 50%,
            var(--atlas-light, #d4af6f) 100%);
        opacity: 0.85;
    }

    /* Brand cluster (RTL-start = visually right). `justify-self: start`
       pins it to its column's start edge so it never drifts toward the
       title centre. */
    .rvg-print-brand {
        display: flex;
        align-items: center;
        gap: 10px;
        justify-self: start;
        min-width: 0;
    }
    .rvg-print-header-logo,
    .rvg-print-header-logo-fallback {
        height: 42px;
        width: auto;
        max-width: 130px;
        object-fit: contain;
        display: block;
        flex-shrink: 0;
    }
    .rvg-print-header-logo-fallback {
        width: 42px;
        text-align: center;
        line-height: 42px;
        background: var(--atlas-dark-soft, var(--color-accent, #4a3520));
        color: #fff;
        border-radius: 8px;
        font-weight: 700;
        font-size: 20px;
    }
    .rvg-print-brand-text {
        line-height: 1.25;
        text-align: start;
        min-width: 0;
    }
    .rvg-print-brand-name {
        font-size: 13px;
        font-weight: 700;
        color: var(--color-text, #1a1a1a);
        margin: 0;
        letter-spacing: -0.01em;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .rvg-print-brand-tagline {
        font-size: 9.5px;
        color: var(--color-text-muted, #6b6b6b);
        margin-top: 2px;
        display: block;
        letter-spacing: 0.02em;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* Title (centre column, auto-width — flanking 1fr tracks keep it
       geometrically centred). Title + count chip share a baseline. */
    .rvg-print-page-title {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        justify-self: center;
        text-align: center;
        font-size: 14px;
        font-weight: 700;
        color: var(--color-text, #1a1a1a);
        line-height: 1.25;
        max-width: 100%;
    }
    .rvg-print-page-title-text {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        letter-spacing: 0.02em;
    }
    /* Page-count chip — discrete pill anchored next to the title.
       Soft accent tint reads as a UI element, not punctuation. */
    .rvg-print-page-count {
        display: inline-block;
        padding: 1px 9px;
        background: color-mix(in srgb,
            var(--atlas-dark-soft, var(--color-accent, #4a3520)) 11%, #fff);
        color: var(--atlas-dark-soft, var(--color-accent, #4a3520));
        border-radius: 999px;
        font-size: 9.5px;
        font-weight: 700;
        letter-spacing: 0.04em;
        line-height: 1.5;
        font-variant-numeric: tabular-nums;
        white-space: nowrap;
    }
    .rvg-print-page-count:empty { display: none; }

    /* Meta cluster (RTL-end = visually left). Date + time stacked.
       Pinned to column end so title stays geometrically centred. */
    .rvg-print-header-meta {
        display: flex;
        flex-direction: column;
        align-items: flex-end;
        justify-self: end;
        line-height: 1.25;
        font-variant-numeric: tabular-nums;
        font-size: 10px;
        color: var(--color-text-muted, #6b6b6b);
    }
    .rvg-print-header-date {
        font-weight: 700;
        color: var(--color-text, #1a1a1a);
        letter-spacing: 0.02em;
    }
    .rvg-print-header-time {
        margin-top: 1px;
        opacity: 0.75;
    }

    /* ── Footer (running — repeats on every printed page) ─────────────────
       Symmetrical with the header — accent stripe on top instead of bottom.
       2-column grid: footer text (RTL-start) · meta (RTL-end). */
    .rvg-print-footer {
        display: grid !important;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: center;
        gap: 16px;
        padding: 8px 4mm 6px;
        background: #fff;
        position: relative;
        margin-top: 8px;
        border-top: 1px solid color-mix(in srgb,
            var(--atlas-dark-soft, var(--color-accent, #4a3520)) 18%, #fff);
        font-family: inherit;
    }
    .rvg-print-footer::before {
        content: '';
        position: absolute;
        top: -1px; left: 0; right: 0;
        height: 2px;
        background: linear-gradient(to left,
            var(--atlas-light, #d4af6f) 0,
            var(--atlas-dark-soft, var(--color-accent, #4a3520)) 50%,
            var(--atlas-light, #d4af6f) 100%);
        opacity: 0.75;
    }
    .rvg-print-footer-text {
        font-size: 10px;
        color: var(--color-text, #2c2c2c);
        font-weight: 500;
        line-height: 1.4;
        min-width: 0;
        text-align: start;
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
    .rvg-print-footer-meta {
        display: flex;
        align-items: center;
        gap: 8px;
        font-size: 9.5px;
        color: var(--color-text-muted, #6b6b6b);
        font-variant-numeric: tabular-nums;
        line-height: 1.4;
        justify-self: end;
    }
    .rvg-print-footer-user {
        color: var(--color-text, #1a1a1a);
        font-weight: 700;
    }
    .rvg-print-footer-handle {
        color: var(--color-text-muted, #6b6b6b);
        opacity: 0.85;
    }
    .rvg-print-footer-handle::before {
        content: '·';
        margin-inline-end: 6px;
        color: color-mix(in srgb, var(--color-border, #c4c4c4) 70%, transparent);
        font-weight: 400;
    }
    .rvg-print-footer-stamp {
        color: var(--color-text, #1a1a1a);
        font-weight: 600;
    }
    .rvg-print-footer-stamp::before {
        content: '·';
        margin-inline-end: 6px;
        color: color-mix(in srgb, var(--color-border, #c4c4c4) 70%, transparent);
        font-weight: 400;
    }
}

/* ============================================================================
   Print — classic shell chrome strip. The classic dashboard layout uses a
   2-column CSS grid (sidebar | main); without an override the sidebar
   prints alongside every page. Hide the sidebar + header + toasts + popovers
   + open modals, collapse the grid to a single column, and let `.rvg-main`
   take the full width. Atlas shell handles this separately in atlas.css.
============================================================================ */
@media print {
    body.revogen-dashboard-page .rvg-sidebar,
    body.revogen-dashboard-page .rvg-header,
    body.revogen-dashboard-page .rvg-toasts,
    body.revogen-dashboard-page .rvg-modal-backdrop,
    body.revogen-dashboard-page .rvg-popover,
    body.revogen-dashboard-page dialog[open]:not(.rvg-print-header):not(.rvg-print-footer),
    body.revogen-dashboard-page [popover]:not(.rvg-print-header):not(.rvg-print-footer) {
        display: none !important;
        visibility: hidden !important;
    }
    /* Collapse the dashboard grid so .rvg-main fills the printed page.
       Without this the empty sidebar column leaves a blank left/right band
       and the main column stays at its (full-viewport - sidebar) width. */
    body.revogen-dashboard-page .revogen-dashboard {
        display: block !important;
        grid-template-columns: none !important;
        grid-template-rows:    none !important;
        grid-template-areas:   none !important;
    }
    body.revogen-dashboard-page .rvg-main {
        grid-area: auto !important;
        max-width: 100% !important;
        width: 100% !important;
        margin: 0 !important;
        padding: 0 !important;
        background: #fff !important;
        border: none !important;
        box-shadow: none !important;
        position: static !important;
    }
    /* Belt-and-braces — sticky elements inside .rvg-main leave ghost offsets
       and weird mid-page anchoring during print. Neutralise sticky everywhere
       inside the printable pane EXCEPT the print-frame scaffold itself
       (whose <thead>/<tfoot> need their native table-header-group /
       table-footer-group display to repeat on every page).

       The scaffold elements carry distinct classes (.rvg-print-frame-head /
       .rvg-print-frame-body / .rvg-print-frame-foot) so we can target them
       precisely via `:not()` and never accidentally hit a data-table that
       happens to live inside a downstream <td>. */
    body.revogen-dashboard-page .rvg-main *[style*="position: sticky"],
    body.revogen-dashboard-page .rvg-main .is-sticky,
    body.revogen-dashboard-page .rvg-main thead:not(.rvg-print-frame-head),
    body.revogen-dashboard-page .rvg-main thead:not(.rvg-print-frame-head) th,
    body.revogen-dashboard-page .rvg-main tfoot:not(.rvg-print-frame-foot),
    body.revogen-dashboard-page .rvg-main tfoot:not(.rvg-print-frame-foot) tr,
    body.revogen-dashboard-page .rvg-main tfoot:not(.rvg-print-frame-foot) td,
    body.revogen-dashboard-page .rvg-main tfoot:not(.rvg-print-frame-foot) th {
        position: static !important;
        bottom: auto !important;
        top:    auto !important;
        z-index: auto !important;
    }
    /* Data-table tfoot prints as part of the body flow (not bottom-pinned).
       SKIP the scaffold's own <tfoot> — it MUST keep table-footer-group
       (the @media print rule earlier in this stylesheet sets it). */
    body.revogen-dashboard-page .rvg-main tfoot:not(.rvg-print-frame-foot) {
        display: table-row-group !important;
    }
    /* Keep data-table rows/cells from being sliced across pages — but NEVER
       the scaffold's own rows/cells (which MUST split: that's the whole
       point of the architecture). The scaffold parts carry .rvg-print-frame*
       classes so we exclude them precisely. */
    body.revogen-dashboard-page .rvg-main tr,
    body.revogen-dashboard-page .rvg-main td,
    body.revogen-dashboard-page .rvg-main th {
        page-break-inside: avoid;
        break-inside: avoid;
    }
    /* Belt-and-braces — force the scaffold body cell to ALLOW page breaks.
       Overrides the generic rule above (same specificity won → later rule
       wins). Without this the long table body would refuse to split. */
    body.revogen-dashboard-page .rvg-main .rvg-print-frame,
    body.revogen-dashboard-page .rvg-main .rvg-print-frame-body,
    body.revogen-dashboard-page .rvg-main .rvg-print-frame-body > tr,
    body.revogen-dashboard-page .rvg-main .rvg-print-frame-body > tr > td {
        page-break-inside: auto !important;
        break-inside: auto !important;
    }
    /* Scaffold cells must have zero cell-padding — inner divs supply their
       own spacing. Without this, any page-wide `td { padding: ... }` rule
       would push the chrome down by the cell padding on every page. */
    body.revogen-dashboard-page .rvg-main .rvg-print-frame > thead > tr > td,
    body.revogen-dashboard-page .rvg-main .rvg-print-frame > tbody > tr > td,
    body.revogen-dashboard-page .rvg-main .rvg-print-frame > tfoot > tr > td {
        padding: 0 !important;
        border: 0 !important;
        line-height: inherit !important;
        vertical-align: top !important;
    }
}

/* ============================================================================
   Print — generic page-fragmentation fixes (framework list + every CRUD page).

   ── WHY THIS BLOCK EXISTS ────────────────────────────────────────────────────
   The scaffold above gives us a running header/footer THAT REPEATS PER PAGE.
   For that to work, the print engine has to be ALLOWED to fragment the
   scaffold's <tbody> across multiple printed pages. Three classes of
   pre-existing screen styles silently DEFEAT that:

     (a) `overflow: clip` / `overflow: hidden` on <html>, <body>, or any
         ancestor of the scaffold — these create "fragmentation containers"
         and Chromium refuses to break a fragmentation container across pages.
         Result: ALL of <tbody>'s content squeezes onto page 1, the scaffold's
         <thead>/<tfoot> appear ONCE, no per-page repetition.

     (b) `max-height: 80vh` (and similar viewport-relative caps) on internal
         scroll wrappers like `.list-{table}-scroll`. In print, `100vh` ≡
         paper page height, so the wrapper caps the inner data table at
         ~80% of a single page and the rest visually overflows (because
         `overflow: visible` is set in print) ONTO the scaffold's <tfoot>.
         The chrome looks "wrapped oddly" / "in the wrong place" on any
         standard list page.

     (c) Nested `<thead>` on the inner data table is `display:
         table-header-group` by default, which makes it COMPETE with the
         scaffold's outer thead for the page-header slot inside Chromium's
         fragmenter. Force the inner thead to a normal row-group so only
         the scaffold's thead repeats.

   These three are interacting. Custom report templates that use their own
   print zone (`.rpt-print-zone` pattern — see app reports for examples)
   escape all three because they `display: none` everything else and show
   only a clean flat table. Framework lists print their FULL DOM, so each
   defect bites.

   ── WHY NOT TARGET .list-{table} SPECIFICALLY ────────────────────────────────
   Every CRUD page in this framework — list, view, edit, dashboard hub,
   admin — is rendered inside the scaffold and may contain a scroll wrapper
   or sticky thead somewhere in its body. A generic rule is the only robust
   answer; targeted patches are whack-a-mole.

   ── WHAT THIS BLOCK DOES NOT BREAK ───────────────────────────────────────────
   * Custom report templates with their own `.rpt-print-zone` — they already
     hide everything outside the zone (`.rpt-page > *:not(.rpt-print-zone)`)
     and supply their own print stylesheet. None of the rules here override
     their explicit `display: table-header-group` on inner print-zone tables.
   * The voucher prints (`prints/_voucher_layout.twig`) — they use a separate
     base layout (`prints/_layout.twig`) without `.rvg-main` / `.atlas-main`,
     so these `.rvg-main` / `.atlas-main` selectors don't reach them.
   * The scaffold itself — every rule uses `:not(.rvg-print-frame-head)` /
     `:not(.rvg-print-frame-foot)` exclusions where it matters, and the
     scaffold's own `display: table-*-group !important` rules win on the
     scaffold parts.
============================================================================ */
@media print {
    /* (a) Lift overflow clipping from the document root + body. Without this,
       Chromium treats <html> as a fragmentation container that cannot be
       split across pages, and the scaffold's <thead>/<tfoot> repeat ONCE on
       page 1 only. The screen-mode `overflow-x: clip` on <html> + body lives
       in dashboard.twig (intentional — prevents stray horizontal scroll on
       the dashboard); print MUST reset it. */
    html, body {
        overflow: visible !important;
        overflow-x: visible !important;
        overflow-y: visible !important;
        height: auto !important;
        max-height: none !important;
    }

    /* (b) Any internal scroll surface inside the printable pane must not
       constrain vertical extent. Targets BOTH shells via attribute-prefix
       matching for the framework's `list-*-scroll` convention, and a
       generic catch-all for any explicit `overflow: auto/scroll` element.
       The scaffold itself (`.rvg-print-frame`) is excluded — its <tbody>
       MUST be allowed to be the fragmentation root. */
    body.revogen-dashboard-page .rvg-main [class$="-scroll"],
    body.revogen-dashboard-page .rvg-main [class*="-scroll "],
    body.revogen-atlas-shell .atlas-main [class$="-scroll"],
    body.revogen-atlas-shell .atlas-main [class*="-scroll "] {
        max-height: none !important;
        height: auto !important;
        overflow: visible !important;
        overflow-x: visible !important;
        overflow-y: visible !important;
        /* Drop transforms/contain/isolation that would create a stacking
           or fragmentation context blocking page breaks. */
        contain: none !important;
        isolation: auto !important;
        transform: none !important;
    }

    /* (c) Nested <thead> note — we DELIBERATELY leave non-scaffold <thead>
       elements as `display: table-header-group` (the browser default).
       Browsers handle nested table-header-group correctly: each table has
       its own thead-repeat scope. The scaffold's outer thead repeats as
       the page running header; the inner data-table's thead repeats as
       the table's column header within its own span. This is exactly the
       working pattern in custom report templates that use a print zone
       (the inner zone table thead repeats AS WELL AS the scaffold's
       running header).

       If you ever need to suppress an inner thead's repeat (e.g. for a
       presentation table where the column header should NOT repeat),
       add `display: table-row-group` inline in that specific template —
       do NOT add a generic suppressor here, it would break reports. */

    /* (d) Belt-and-braces — any ancestor of the scaffold body that has a
       lingering `contain`, `isolation`, or `transform` from screen styling
       (e.g. is-sticky-headers' transform on .list-{table}) creates a new
       fragmentation context. Neutralise all three across the printable
       pane. The scaffold itself is excluded so its own
       `border-collapse: collapse` table semantics survive. */
    body.revogen-dashboard-page .rvg-main *:not(.rvg-print-frame):not(.rvg-print-header):not(.rvg-print-footer),
    body.revogen-atlas-shell .atlas-main *:not(.rvg-print-frame):not(.rvg-print-header):not(.rvg-print-footer) {
        contain: none !important;
        isolation: auto !important;
    }

    /* (e) Allow every non-scaffold `<table>` inside the printable pane to
       be split across pages. Sticky-frozen-column geometry on screen sets
       `table-layout: fixed` + explicit pixel widths; in print we want the
       browser to size for paper. Width/max-width are intentionally NOT
       overridden here — the inner stylesheets already set sensible widths
       (e.g. `.pz-table { width: 100% }` on reports) and forcing 100% would
       break narrower presentational tables. */
    body.revogen-dashboard-page .rvg-main table:not(.rvg-print-frame),
    body.revogen-atlas-shell .atlas-main table:not(.rvg-print-frame) {
        table-layout: auto !important;
        page-break-inside: auto !important;
        break-inside: auto !important;
    }

    /* (f) Any `min-height: 100vh` / `min-height: 100dvh` / large `max-height`
       on shell-level containers becomes catastrophic in print where 100vh ≡
       paper height. Reset them on every layout box inside the printable
       pane. The scaffold itself is excluded to keep its `display: table`
       sizing free of artificial constraints. */
    body.revogen-dashboard-page .rvg-main *:not(.rvg-print-frame),
    body.revogen-atlas-shell .atlas-main *:not(.rvg-print-frame) {
        min-height: 0 !important;
    }
    /* Same for `max-height` — limit to the wrappers that commonly carry it.
       Avoid blanket `max-height: none !important` on `*` because some
       legitimate elements (e.g. truncated cells) rely on max-height for
       their visual design. Scope to scroll wrappers, sticky containers,
       and the framework's list card. */
    body.revogen-dashboard-page .rvg-main .rvg-list-card,
    body.revogen-dashboard-page .rvg-main [class*="-card"],
    body.revogen-atlas-shell .atlas-main .rvg-list-card,
    body.revogen-atlas-shell .atlas-main [class*="-card"] {
        max-height: none !important;
        height: auto !important;
        overflow: visible !important;
    }

    /* ── Hide the in-body page title row on print ──────────────────────────
       The scaffold's running header already prints the page title + total
       on EVERY page. Keeping the screen-level `.rvg-page-header` (which
       holds the same title + a noisier count format like "50 of 41,839")
       just duplicates the chrome. Hide it in print universally — saves
       vertical space and removes the redundant heading on page 1. */
    body.revogen-dashboard-page .rvg-main .rvg-page-header,
    body.revogen-atlas-shell .atlas-main .rvg-page-header {
        display: none !important;
    }
}

/* ==========================================================================
   FR-037 â€” Lookup Context Panel.

   Read-only info card rendered above (or beside) a form when a lookup
   field with `lookup_context` is chosen. Pattern modeled after
   .rvg-rmeta-* â€” soft surface, accent-tinted header, definition list.

   Theme-token only (--color-bg-alt, --color-border, --color-text-soft,
   --color-accent). RTL-safe via `padding-inline-*` / `margin-inline-*`.
   ========================================================================== */

.rvg-lkctx-host {
    margin-block-end: var(--space-3, 0.75rem);
}
.rvg-lkctx-host[hidden] { display: none; }

/* FR-072 — Card with accent header strip + grid body */
.rvg-lkctx-card {
    /* Surface tracks the active theme (light → #fff, dark → #1f1f23
       via --color-bg). Previously hard-coded #fff stayed white even
       under [data-bs-theme="dark"], breaking the rest of the page's
       palette. */
    background: var(--color-bg, #fff);
    border: 1px solid var(--color-border, #e9ecef);
    border-radius: var(--radius-md, 8px);
    margin-block-end: var(--space-3, 0.75rem);
    color: var(--color-text, #1f2937);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
    overflow: hidden;
}

/* Accent header strip — title sits inside an accent-coloured bar so it
   reads as "section header" rather than just bold text. */
.rvg-lkctx-card__title {
    margin: 0;
    padding: 0.6rem 1rem;
    background: color-mix(in srgb, var(--color-accent, #6366f1) 12%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--color-accent, #6366f1) 25%, transparent);
    font-size: 0.9rem;
    font-weight: 700;
    color: color-mix(in srgb, var(--color-accent, #6366f1) 85%, var(--color-text) 15%);
    letter-spacing: 0.02em;
    display: flex;
    align-items: center;
    gap: 8px;
    /* FR-089 — header is a toggle for collapse */
    cursor: pointer;
    user-select: none;
    transition: background 0.15s ease;
}
.rvg-lkctx-card__title:hover,
.rvg-lkctx-card__title:focus-visible {
    background: color-mix(in srgb, var(--color-accent, #6366f1) 18%, transparent);
    outline: none;
}
.rvg-lkctx-card__title::before {
    content: '';
    width: 4px;
    height: 16px;
    background: var(--color-accent, #6366f1);
    border-radius: 2px;
}

/* FR-089 — chevron icon + smooth collapse animation. The chevron is
   appended into the title via JS so legacy and grouped layouts get the
   same affordance. */
.rvg-lkctx-chevron {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    color: color-mix(in srgb, var(--color-accent, #6366f1) 75%, var(--color-text) 25%);
    transition: transform 0.25s ease;
    margin-inline-start: auto;
}
.rvg-lkctx-chevron svg {
    width: 14px;
    height: 14px;
    fill: currentColor;
}
.rvg-lkctx-card--collapsed .rvg-lkctx-chevron {
    transform: rotate(-90deg);
}

.rvg-lkctx-list,
.rvg-lkctx-card__body {
    overflow-y: hidden;
    max-height: 1000px;
    opacity: 1;
    transition: max-height 0.3s ease, opacity 0.2s ease, padding 0.3s ease;
}
.rvg-lkctx-card--collapsed .rvg-lkctx-list,
.rvg-lkctx-card--collapsed .rvg-lkctx-card__body {
    max-height: 0;
    opacity: 0;
    padding-block-start: 0;
    padding-block-end: 0;
}

/* FR-089 — loading state: centred spinner replaces "loading…" text */
.rvg-lkctx-state--loading {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.75rem 1rem;
    min-height: 90px;
}
.rvg-lkctx-spinner {
    display: inline-block;
    width: 36px;
    height: 36px;
    border: 4px solid color-mix(in srgb, var(--color-accent, #6366f1) 18%, transparent);
    border-top-color: var(--color-accent, #6366f1);
    border-radius: 50%;
    animation: rvg-lkctx-spin 0.85s linear infinite;
}
@keyframes rvg-lkctx-spin {
    to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
    .rvg-lkctx-spinner { animation-duration: 2s; }
}

/* Grid body — auto-fit so columns fill the available width, then drop to
   fewer columns when there isn't enough room. No more horizontal scroll. */
/* FR-155 — canonical summary-card layout: a horizontal row of icon-on-top
   facts separated by a thin vertical rule (promoted from the presence per-table
   design into the generic renderer; the per-field icon comes from the dna /
   the summary-cards console — data-driven, no per-table script). */
.rvg-lkctx-list {
    display: flex;
    flex-wrap: nowrap;
    justify-content: center;
    overflow-x: auto;
    gap: 0.5rem;
    margin: 0;
    padding: 0.85rem;
    width: 100%;
    list-style: none;
    scrollbar-width: thin;
    scrollbar-color: var(--color-border, #e9ecef) transparent;
}
.rvg-lkctx-list::-webkit-scrollbar { height: 6px; }
.rvg-lkctx-list::-webkit-scrollbar-thumb { background: var(--color-border, #e9ecef); border-radius: 3px; }

.rvg-lkctx-item {
    /* FR-155 — equal columns that fill the full width; no max cap so a single
       item stretches to 100% and centers its content (owner 2026-06-23). */
    flex: 1 1 0;
    min-width: 130px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 5px;
    padding: 0.25rem 0.6rem 0.5rem;
    background: transparent;
    border: none;
    position: relative;
}
/* thin vertical divider between adjacent facts (RTL-safe) — «الفواصل» */
.rvg-lkctx-list .rvg-lkctx-item + .rvg-lkctx-item::before {
    content: '';
    position: absolute;
    inset-block: 18%;
    inset-inline-start: calc(-0.25rem - 0.5px);
    width: 1px;
    background: var(--color-border, #e5e7eb);
    opacity: 0.75;
    pointer-events: none;
}

/* icon-on-top block — rendered from the field's `icon` (set in the console) */
.rvg-lkctx-itemicon {
    width: 52px;
    height: 52px;
    border-radius: 14px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--color-accent, #6366f1);
}
.rvg-lkctx-itemicon svg { width: 26px; height: 26px; fill: currentColor; }

@media (max-width: 768px) {
    .rvg-lkctx-list { gap: 0.4rem; padding: 0.6rem; }
    .rvg-lkctx-item { flex: 0 0 auto; min-width: 140px; }
    .rvg-lkctx-itemicon { width: 46px; height: 46px; border-radius: 12px; }
    .rvg-lkctx-itemicon svg { width: 22px; height: 22px; }
}

.rvg-lkctx-label {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--color-text-soft, #868e96);
    margin: 0;
    line-height: 1.2;
}

.rvg-lkctx-value {
    font-weight: 700;
    font-size: 0.92rem;
    color: var(--color-text, #1f2937);
    font-variant-numeric: tabular-nums;
    margin: 0;
    line-height: 1.35;
    /* honour the `\n` of a two-line merge ({a}\n{b}) as a real line break;
       single-line values are unaffected (no newline to render). */
    white-space: pre-line;
    min-width: 0;
}

/* ==========================================================================
   FR-081 — grouped layouts: chips + timeline.

   Composes with the legacy card (.rvg-lkctx-card) — the grouped card
   carries `.rvg-lkctx-card--grouped` and houses one or more
   `<section class="rvg-lkctx-group rvg-lkctx-group--{chips|timeline}">`.

   Design rules:
   - Token-only colors (--color-accent, --color-border, --color-bg-alt,
     --color-text*) — respects every theme + dark mode + accent.
   - "No padding waste" — chip body min-paddings, no excessive gaps.
   - RTL-safe via padding-inline-* / margin-inline-*.
   - Mobile (≤520px): chips wrap onto rows (still compact), timeline
     becomes vertical chain. Zero horizontal scrollbars.
   ========================================================================== */

.rvg-lkctx-card--grouped .rvg-lkctx-card__body {
    padding: 0.5rem 0.75rem 0.65rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.rvg-lkctx-group__title {
    margin: 0 0 0.35rem;
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--color-text-soft, #868e96);
    text-transform: uppercase;
    letter-spacing: 0.07em;
}

.rvg-lkctx-group__body {
    /* default flex; specific layouts override below */
    display: flex;
    align-items: stretch;
}

/* ─── Chips layout — grid distributes evenly across full width ─────── */
.rvg-lkctx-group--chips .rvg-lkctx-group__body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
    gap: 0.5rem;
}

.rvg-lkctx-chip {
    display: flex;             /* fills its grid cell */
    align-items: center;
    gap: 0.55rem;
    padding: 0.45rem 0.7rem;
    background: var(--color-bg-alt, #f8f9fa);
    border: 1px solid var(--color-border, #e9ecef);
    border-radius: var(--radius-sm, 6px);
    border-inline-start: 3px solid color-mix(in srgb, var(--color-accent, #6366f1) 70%, transparent);
    line-height: 1.25;
    min-width: 0;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.rvg-lkctx-chip:hover {
    border-inline-start-color: var(--color-accent, #6366f1);
    background: color-mix(in srgb, var(--color-accent, #6366f1) 4%, var(--color-bg-alt, #f8f9fa));
}

.rvg-lkctx-chip__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    color: color-mix(in srgb, var(--color-accent, #6366f1) 88%, var(--color-text) 12%);
    flex-shrink: 0;
}
.rvg-lkctx-icon {
    width: 100%;
    height: 100%;
    fill: currentColor;
}

.rvg-lkctx-chip__body {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.2;
    flex: 1;
}

.rvg-lkctx-chip__label {
    font-size: 0.66rem;
    font-weight: 600;
    color: var(--color-text-soft, #868e96);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    white-space: nowrap;
}

.rvg-lkctx-chip__value {
    font-size: 0.92rem;
    font-weight: 700;
    color: var(--color-text, #1f2937);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.rvg-lkctx-chip__value--empty {
    color: var(--color-text-soft, #adb5bd);
    font-weight: 500;
    font-style: italic;
}

/* ─── Timeline layout — equal-width steps + solid line between bubbles ─ */
.rvg-lkctx-group--timeline .rvg-lkctx-group__body {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: 0;
    padding-block: 0.35rem;
}

.rvg-lkctx-step {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: 1 1 0;
    min-width: 0;
    position: relative;
    text-align: center;
    padding-inline: 0.4rem;
}

.rvg-lkctx-step__bubble {
    width: 2.6rem;
    height: 2.6rem;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--color-accent, #6366f1) 16%, var(--color-bg, #fff));
    color: color-mix(in srgb, var(--color-accent, #6366f1) 90%, var(--color-text) 10%);
    border: 2px solid color-mix(in srgb, var(--color-accent, #6366f1) 75%, transparent);
    position: relative;
    z-index: 1;
}
.rvg-lkctx-step__bubble .rvg-lkctx-icon {
    width: 1.25rem;
    height: 1.25rem;
}

.rvg-lkctx-step__caption {
    margin-block-start: 0.3rem;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
    max-width: 100%;
}

.rvg-lkctx-step__label {
    font-size: 0.65rem;
    font-weight: 600;
    color: var(--color-text-soft, #868e96);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    white-space: nowrap;
}

.rvg-lkctx-step__value {
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--color-text, #1f2937);
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}
.rvg-lkctx-step__value--empty {
    color: var(--color-text-soft, #adb5bd);
    font-weight: 500;
    font-style: italic;
}

/* Horizontal solid connector line between bubbles.
   - Anchored at the step's centre (inset-inline-start: 50%) and spans
     100% of step width → the visible segment runs from this step's
     bubble centre to the next step's bubble centre.
   - Vertically centred on the bubble (top = bubble half-height).
   - z-index 0 slides it under the bubble (which is z-index 1). */
.rvg-lkctx-step__arrow {
    position: absolute;
    top: 1.3rem;             /* half of bubble height (2.6rem / 2) */
    inset-inline-start: 50%;
    width: 100%;
    height: 2px;
    background: color-mix(in srgb, var(--color-accent, #6366f1) 55%, transparent);
    pointer-events: none;
    z-index: 0;
}

/* ─── Mobile (≤ 520px) — timeline becomes vertical chain ───────────── */
@media (max-width: 520px) {
    .rvg-lkctx-group--timeline .rvg-lkctx-group__body {
        flex-direction: column;
        align-items: flex-start;
        overflow-x: visible;
        gap: 0.35rem;
    }
    .rvg-lkctx-step {
        flex-direction: row;
        align-items: center;
        gap: 0.6rem;
        text-align: start;
        min-width: 0;
        width: 100%;
        padding-inline: 0;
    }
    .rvg-lkctx-step__bubble {
        flex-shrink: 0;
    }
    .rvg-lkctx-step__caption {
        margin-block-start: 0;
        align-items: flex-start;
    }
    /* Vertical connector to the right of bubble centre, under the step.
       Reset desktop's horizontal positioning entirely. */
    .rvg-lkctx-step__arrow {
        position: static;
        top: auto;
        inset-inline-end: auto;
        width: 2px;
        height: 0.65rem;
        margin-inline-start: 1.3rem;
        background: color-mix(in srgb, var(--color-accent, #6366f1) 55%, transparent);
    }
    /* Chips: stay grid, tighter padding on small screens */
    .rvg-lkctx-group--chips .rvg-lkctx-group__body {
        grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr));
        gap: 0.4rem;
    }
    .rvg-lkctx-chip { padding: 0.4rem 0.55rem; }
}

/* ───────────────────────────────────────────────────────────────────
   FR-038 — `field.readonly` visual cue.

   Wrapper-level `.is-readonly` is appended by form.twig whenever the
   field is rendered as not-editable (either dna `readonly: true` or
   the legacy `readonly_on_edit` on update). Token-based colors only,
   so dark-mode + admin's accent flow through with zero overrides.
   RTL-safe (margin/padding-free). Click-blocking is achieved by the
   underlying `[readonly]` / `[disabled]` attribute set on the input;
   `cursor: not-allowed` here is purely the visual hint.
   ─────────────────────────────────────────────────────────────────── */
.is-readonly {
    opacity: 0.85;
}
.is-readonly :is(input, select, textarea):is([readonly], [disabled]),
.is-readonly .rvg-dp-trigger[disabled],
.is-readonly .fg-enum-pill[disabled]:not(.is-active),
.is-readonly .fg-bool-pill input[type="checkbox"][disabled] {
    background: color-mix(in srgb, var(--color-bg-alt, #f8f9fa) 80%, transparent);
    border-color: color-mix(in srgb, var(--color-border, #e9ecef) 70%, transparent);
    color: var(--color-text-soft, #868e96);
    cursor: not-allowed;
}
/* Readonly enum-pill group (e.g. transfers.state post-creation) — when
   the field is locked the non-active choices are visual noise. Hide them
   and let the active pill stand alone as a clear status badge. */
.is-readonly .fg-enum-pills .fg-enum-pill[disabled]:not(.is-active) {
    display: none;
}
.is-readonly .fg-enum-pills {
    background: transparent;
    border: none;
    padding: 0;
}
.is-readonly .fg-enum-pill.is-active[disabled] {
    cursor: default;
}
.is-readonly :is(input, select, textarea):is([readonly], [disabled]):hover,
.is-readonly :is(input, select, textarea):is([readonly], [disabled]):focus {
    /* Suppress the accent-tinted hover/focus border for fields the user
       cannot edit — keeps the visual signal honest. */
    border-color: color-mix(in srgb, var(--color-border, #e9ecef) 70%, transparent) !important;
    box-shadow: none !important;
}
/* Disabled `<input type="color">` browsers vary — make sure the swatch
   itself looks inert too. */
.is-readonly input[type="color"][disabled] {
    filter: grayscale(0.4);
    cursor: not-allowed;
}

/* FR-075 — audit field rendered as static text in the form (created/
   updated by/at, created_by_group). Matches the visual weight of a
   readonly input so the form rhythm stays consistent. */
.fg-audit-static {
    display: flex; align-items: center;
    min-height: 44px;
    padding: 8px 12px;
    background: color-mix(in srgb, var(--color-bg-alt, #f8f9fa) 80%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-accent) 46%, transparent);
    border-radius: var(--radius-md, 6px);
    color: var(--color-text-soft, #868e96);
    font-size: 14px;
    cursor: not-allowed;
}
.fg-audit-static-empty { opacity: 0.6; }
.fg-audit-static-user,
.fg-audit-static-group { color: var(--color-text); font-weight: 500; }
.fg-audit-static-datetime {
    display: inline-flex; gap: 8px; align-items: center;
}
.fg-audit-static-date { color: var(--color-text); font-weight: 500; }
.fg-audit-static-time {
    color: var(--color-text-soft);
    font-variant-numeric: tabular-nums;
    font-size: 13px;
}

/* FR-077 — Admin-customisable totals row cells.
   Modifier classes attached by list.twig when admin set sum_color or
   sum_size in field_overrides. Both modifiers stack; absence of either
   leaves the cell at its default styling.
   `!important` is intentional: list.twig ships a per-table CSS rule
   `.list-{table}-totals .list-{table}-total-cell strong { color: accent; }`
   with specificity (0,2,1) that beats any reasonably-flat selector here.
   The admin's pick is an explicit override of that default — so we win. */
.rvg-list-sum--default strong { color: var(--color-accent) !important; }
.rvg-list-sum--accent  strong { color: var(--color-accent) !important; }
.rvg-list-sum--success strong { color: var(--color-success, #16a34a) !important; }
.rvg-list-sum--warning strong { color: var(--color-warning, #d97706) !important; }
.rvg-list-sum--danger  strong { color: var(--color-danger,  #dc2626) !important; }
.rvg-list-sum--muted   strong { color: var(--color-text-soft) !important; font-weight: 500 !important; }
.rvg-list-sum--info    strong { color: var(--color-info) !important; }
.rvg-list-sum--dark    strong { color: var(--color-text) !important; font-weight: 700 !important; }

.rvg-list-sum--sm strong { font-size: 11px !important; font-weight: 600 !important; }
.rvg-list-sum--md strong { font-size: 13px !important; font-weight: 700 !important; }
.rvg-list-sum--lg strong { font-size: 16px !important; font-weight: 700 !important; }
.rvg-list-sum--xl strong { font-size: 20px !important; font-weight: 800 !important; letter-spacing: 0.5px !important; }
.rvg-list-sum--lg small,
.rvg-list-sum--xl small { font-size: 12px !important; }

/* FR-094 — lookup thumbnail stacked above its label.
   Opt-in per lookup field via `lookup_thumbnail_field` on dna; rendered
   in list cells, detail values, and children preview rows. Vertical stack
   (icon on top, label below, centred) — matches the agreed UX. */
.rvg-lookup-thumb-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    line-height: 1.2;
    text-align: center;
}
.rvg-lookup-thumb-cell img {
    width: 34px;
    height: 34px;
    object-fit: contain;
    border-radius: 6px;
    flex-shrink: 0;
}

/* ==========================================================================
   iOS Safari — disable form field auto-zoom on focus
   ──────────────────────────────────────────────────────────────────────────
   iOS Safari auto-zooms when the user taps any input/select/textarea
   whose computed font-size is < 16px. It's an "accessibility" feature
   that makes small text easier to read, but it's disruptive: the page
   reflows, and the user has to manually zoom back out.
   
   The fix is to ensure every form field renders at ≥16px on mobile.
   We do NOT add `maximum-scale=1` to the viewport meta tag — that would
   disable the user's ability to pinch-zoom the page on demand. This rule
   ONLY changes the input font size so iOS no longer feels the need to
   zoom for us.
   
   Applied as a media query so desktop typography (often 14px for dense
   tables/forms) is untouched.
   ========================================================================== */
@media (max-width: 768px) {
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]),
    select,
    textarea {
        font-size: 16px;
    }
}


/* ==========================================================================
   FR-101 — Inline children grid (master+detail in one form)
   --------------------------------------------------------------------------
   The block is a card under the parent's regular fields. Designed to feel
   like one of the form's `.fg-*` field groups — same border, same radius,
   same neutral palette — but with a `<table>` inside so dense data fits.

   Selectors:
     .rvg-ic-block         wrapper (card)
     .rvg-ic-header        title + add button
     .rvg-ic-title         h3 + count badge
     .rvg-ic-add-btn       primary add button
     .rvg-ic-table-wrap    scroll container (mobile overflow)
     .rvg-ic-table         the grid table
       .rvg-ic-thead       header row
         .rvg-ic-th        header cell
         .rvg-ic-th-num    row-number column (narrow)
         .rvg-ic-th-total  running total column
         .rvg-ic-th-actions remove-button column (narrow)
       tbody              the row container (server + new rows)
         .rvg-ic-row             generic row (new OR existing)
         .rvg-ic-row-new         user-added row (live + removable)
         .rvg-ic-row-existing    DB-loaded row (read-only)
         .rvg-ic-cell            generic cell
         .rvg-ic-cell-num        row number cell
         .rvg-ic-cell-input      cell holding a form input
         .rvg-ic-cell-readonly   plain-text existing-row cell
         .rvg-ic-cell-total      live total cell
         .rvg-ic-cell-actions    remove-button cell
         .rvg-ic-empty           empty-state row (full-width message)
         .rvg-ic-empty-cell      its <td>
         .rvg-ic-empty-inner     icon + text wrapper
       .rvg-ic-tfoot       grand-total footer row
         .rvg-ic-tfoot-label    label cell (start-aligned, bold)
         .rvg-ic-tfoot-total    sum cell (accent-coloured)
     .rvg-ic-remove-btn     per-row remove icon button (X)
     .rvg-ic-pill           BoQ-awareness pill (inline next to lookup cell)
       .rvg-ic-pill-in        green: within BoQ
       .rvg-ic-pill-out       yellow: outside BoQ
       .rvg-ic-pill-checking  neutral grey: AJAX in flight
   ========================================================================== */

.rvg-ic-block {
    margin-top: var(--space-5);
    padding: var(--space-4);
    background: color-mix(in srgb, var(--color-accent) 3%, var(--color-bg));
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
}

.rvg-ic-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;        /* title may wrap above buttons on narrow viewports */
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
/* Header action cluster — keeps "فتح القائمة" + "+ إضافة بند" pinned
   side-by-side as one toolbar group, no matter how narrow the parent.
   `flex-wrap: nowrap` prevents the two buttons from stacking vertically
   when the title + buttons row gets squeezed. `flex-shrink: 0` keeps the
   buttons at their natural width so the *title* wraps to a new line on
   narrow viewports, not the action group. */
.rvg-ic-header-actions {
    display: inline-flex;
    align-items: center;
    flex-wrap: nowrap;
    flex-shrink: 0;
    gap: var(--space-2);
}
/* On narrow viewports, both buttons collapse to icon-only so they
   stay side-by-side instead of overflowing or stacking awkwardly.
   The title is still readable above; the user gets two compact
   square-ish buttons. The `title=...` attribute provides the
   tooltip / accessibility hint for the hidden label. */
@media (max-width: 560px) {
    .rvg-ic-header-actions .rvg-ic-add-btn > span:not(.revogen-icon),
    .rvg-ic-header-actions .rvg-ic-viewall-link > span:not(.revogen-icon) {
        display: none;
    }
    .rvg-ic-header-actions .rvg-ic-add-btn,
    .rvg-ic-header-actions .rvg-ic-viewall-link {
        padding: 0.4rem 0.7rem;
    }
}

.rvg-ic-title {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--color-text);
}

.rvg-ic-title .revogen-icon {
    width: 16px;
    height: 16px;
    color: var(--color-accent);
}

.rvg-ic-add-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0.4rem 0.85rem;
    background: var(--color-accent);
    color: #fff;
    border: 1px solid var(--color-accent);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 500;
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition);
}

.rvg-ic-add-btn:hover:not(:disabled) {
    background: var(--color-accent-hover);
    border-color: var(--color-accent-hover);
}

.rvg-ic-add-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.rvg-ic-add-btn .revogen-icon {
    width: 14px;
    height: 14px;
}

.rvg-ic-table-wrap {
    overflow-x: auto;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.rvg-ic-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}

.rvg-ic-thead {
    background: var(--color-bg-alt);
    border-bottom: 2px solid var(--color-accent-soft);
}

.rvg-ic-th {
    padding: var(--space-3) var(--space-3);
    text-align: start;
    font-weight: 600;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.025em;
    color: var(--color-text-muted);
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
}

.rvg-ic-th-num     { width: 40px; text-align: center; }
.rvg-ic-th-total   { width: 130px; text-align: end; }
.rvg-ic-th-actions { width: 44px; }

.rvg-ic-row {
    border-bottom: 1px solid var(--color-border);
    transition: background var(--transition);
}

.rvg-ic-row:last-child {
    border-bottom: none;
}

.rvg-ic-row-new:hover,
.rvg-ic-row-existing:hover {
    background: color-mix(in srgb, var(--color-accent) 4%, var(--color-bg));
}

.rvg-ic-cell {
    padding: var(--space-2) var(--space-3);
    vertical-align: middle;
    color: var(--color-text);
}

.rvg-ic-cell-num {
    text-align: center;
    font-size: 0.78rem;
    color: var(--color-text-soft);
    width: 40px;
}

.rvg-ic-cell-readonly {
    font-size: var(--text-sm);
    color: var(--color-text);
}

.rvg-ic-cell-input {
    padding: var(--space-1) var(--space-2);
}

/* The actual <input>/<select>/<textarea> inside a row cell — flat, fit
   the row height, no card-style padding. */
.rvg-ic-table .rvg-ic-cell input.rvg-ic-cell,
.rvg-ic-table .rvg-ic-cell select.rvg-ic-cell,
.rvg-ic-table .rvg-ic-cell textarea.rvg-ic-cell {
    width: 100%;
    padding: 0.4rem 0.55rem;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text);
    font-size: var(--text-sm);
    transition: border-color var(--transition), box-shadow var(--transition);
}

.rvg-ic-table .rvg-ic-cell input.rvg-ic-cell:focus,
.rvg-ic-table .rvg-ic-cell select.rvg-ic-cell:focus,
.rvg-ic-table .rvg-ic-cell textarea.rvg-ic-cell:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-accent) 22%, transparent);
}

.rvg-ic-cell-total {
    text-align: end;
    font-variant-numeric: tabular-nums;
    font-weight: 500;
    color: var(--color-text);
    white-space: nowrap;
}

.rvg-ic-cell-actions {
    text-align: center;
    width: 76px;
}
/* FR-110  existing-row action cluster (edit + delete on rvg-ic-row-existing).
   Sits next to the same column as the new-row remove (X) for layout parity. */
.rvg-ic-row-actions {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
}
.rvg-ic-row-edit-btn,
.rvg-ic-row-delete-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    background: transparent;
    color: var(--color-text-soft);
    border: 1px solid transparent;
    border-radius: 6px;
    cursor: pointer;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.rvg-ic-row-edit-btn:hover {
    background: color-mix(in srgb, var(--color-accent) 12%, var(--color-bg));
    color: var(--color-accent);
    border-color: color-mix(in srgb, var(--color-accent) 25%, transparent);
}
.rvg-ic-row-delete-btn:hover {
    background: color-mix(in srgb, var(--color-danger) 12%, var(--color-bg));
    color: var(--color-danger);
    border-color: color-mix(in srgb, var(--color-danger) 25%, transparent);
}
.rvg-ic-row-edit-btn .revogen-icon,
.rvg-ic-row-delete-btn .revogen-icon {
    width: 15px;
    height: 15px;
}

.rvg-ic-remove-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    background: transparent;
    color: var(--color-text-soft);
    border: 1px solid transparent;
    border-radius: 50%;
    cursor: pointer;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.rvg-ic-remove-btn:hover {
    background: color-mix(in srgb, var(--color-danger) 12%, var(--color-bg));
    color: var(--color-danger);
    border-color: color-mix(in srgb, var(--color-danger) 25%, transparent);
}

.rvg-ic-remove-btn .revogen-icon {
    width: 16px;
    height: 16px;
}

/* Empty state — full-width message inside the tbody. */
.rvg-ic-empty-cell {
    padding: var(--space-6) var(--space-4);
    text-align: center;
    color: var(--color-text-soft);
    background: var(--color-bg);
}

.rvg-ic-empty-inner {
    display: inline-flex;
    align-items: center;
    flex-direction: column;
    gap: var(--space-2);
    font-size: var(--text-sm);
}

.rvg-ic-empty-inner .revogen-icon {
    width: 32px;
    height: 32px;
    color: var(--color-text-soft);
    opacity: 0.7;
}

/* Footer — grand total. Accent-tinted background, bold sum. */
.rvg-ic-tfoot {
    background: color-mix(in srgb, var(--color-accent) 6%, var(--color-bg-alt));
    border-top: 2px solid var(--color-accent-soft);
}

.rvg-ic-tfoot-label {
    padding: var(--space-3) var(--space-3);
    text-align: end;
    font-weight: 600;
    color: var(--color-text);
    font-size: var(--text-sm);
}

.rvg-ic-tfoot-total {
    padding: var(--space-3) var(--space-3);
    text-align: end;
    font-weight: 700;
    color: var(--color-accent);
    font-size: var(--text-base);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.rvg-ic-tfoot-actions {
    width: 44px;
}

/* BoQ-awareness pill — inline next to the picker cell. Tiny, not loud.
   Positioned absolute when there's space; otherwise wraps under the input. */
/* FR-136 (توجيه المالك): الشارة كانت block تحت السلكت فترفع ارتفاع
   السطر وتكسر المحاذاة. صارت نقطة مدمجة صغيرة فوق زاوية الخليّة —
   صفر أثر على الـlayout، والنصّ الكامل في tooltip (title موجود أصلاً).
   الخليّة الحاضنة position:relative عبر .rvg-ic-cell أدناه. */
.rvg-ic-cell { position: relative; }
.rvg-ic-pill {
    position: absolute;
    top: 2px;
    inset-inline-end: 2px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    padding: 0;
    border-radius: 999px;
    font-size: 10px;
    line-height: 1;
    cursor: help;
    border: 1px solid transparent;
    z-index: 2;
}
/* النصّ يختفي بصريّاً — يبقى للـtooltip/قارئ الشاشة. */
.rvg-ic-pill-text {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
}

.rvg-ic-pill-icon {
    font-size: 0.85rem;
    line-height: 1;
}

.rvg-ic-pill-in {
    background: color-mix(in srgb, var(--color-success) 12%, var(--color-bg));
    border-color: color-mix(in srgb, var(--color-success) 35%, transparent);
    color: var(--color-success);
}

.rvg-ic-pill-out {
    background: color-mix(in srgb, var(--color-warning) 14%, var(--color-bg));
    border-color: color-mix(in srgb, var(--color-warning) 40%, transparent);
    color: var(--color-warning);
}

.rvg-ic-pill-checking {
    background: var(--color-bg-alt);
    border-color: var(--color-border);
    color: var(--color-text-soft);
}

/* Mobile (≤768px) — stack each row as a card. The <thead> becomes
   visually hidden (still in the DOM for accessibility); each <td> shows
   its column label via the `data-rvg-mobile-label` attribute. */
/* Inline grid mobile rules — KEEP table layout, switch to compact +
   horizontal scroll. Card-stacking (display:block) was originally used
   here but proved unusable for invoices with 10+ items (one row took
   ~7 vertical cells × 10 items = scroll forever). A horizontal table
   that pans sideways keeps 10 items in 10 rows, scannable. */
@media (max-width: 768px) {
    .rvg-ic-table-wrap {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .rvg-ic-table {
        min-width: 640px;       /* preserve horizontal table layout */
        font-size: 12px;
    }
    .rvg-ic-table thead.rvg-ic-thead th,
    .rvg-ic-table .rvg-ic-th,
    .rvg-ic-table tbody td,
    .rvg-ic-table .rvg-ic-cell {
        padding: 6px 8px;
    }
    /* Make the inputs slightly tighter so each row stays compact. */
    .rvg-ic-cell input,
    .rvg-ic-cell select,
    .rvg-ic-cell textarea,
    .rvg-ic-cell .rvg-lines-input,
    .rvg-ic-cell .rvg-lines-select,
    .rvg-ic-cell .rvg-lines-textarea {
        padding: 4px 6px;
        font-size: 12px;
    }
    .rvg-ic-cell-num {
        font-weight: 600;
        color: var(--color-text-muted);
        min-width: 28px;
        text-align: center;
    }
}

/* Even tighter at 380px — fonts shrink, but layout stays horizontal. */
@media (max-width: 380px) {
    .rvg-ic-table { min-width: 560px; font-size: 11px; }
    .rvg-ic-cell input,
    .rvg-ic-cell select,
    .rvg-ic-cell textarea {
        padding: 3px 5px;
        font-size: 11px;
    }
}

/* ─────────────────────────────────────────────────────────────────────
 * FR-100 — Live computed info panel (AJAX-driven)
 *
 * Card placeholder rendered on CREATE/EDIT forms when dna declares
 * `ui.live_panels`. The Alpine factory `rvgLivePanel` paints values into
 * `[data-rvg-live-panel-field]` cells on every AJAX response.
 *
 * Tokens reused (no new variables introduced):
 *   --color-bg, --color-bg-alt, --color-border, --color-text,
 *   --color-text-muted, --color-accent, --color-accent-soft,
 *   --color-success, --color-warning, --color-danger,
 *   --radius-md, --space-2/3/4
 * ───────────────────────────────────────────────────────────────────── */
.rvg-lp-card {
    background: color-mix(in srgb, var(--color-accent) 4%, var(--color-bg));
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.rvg-lp-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}
.rvg-lp-title {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--color-text);
}
.rvg-lp-title svg {
    width: 1em;
    height: 1em;
    flex-shrink: 0;
}
.rvg-lp-status {
    font-size: 0.75rem;
    color: var(--color-text-muted);
    font-style: italic;
}
.rvg-lp-status-error {
    color: var(--color-danger);
    font-style: normal;
    font-weight: 600;
}
.rvg-lp-empty {
    color: var(--color-text-muted);
    font-size: 0.8rem;
    text-align: center;
    padding: var(--space-2) 0;
}
.rvg-lp-grid {
    display: grid;
    grid-template-columns: repeat(var(--rvg-lp-cols, 3), minmax(0, 1fr));
    gap: var(--space-3);
}
/* Discrete column-count classes — Twig writes `rvg-lp-cols-N` so we can
 * scale from 1 to 6 without inline styles. */
.rvg-lp-cols-1 .rvg-lp-grid { grid-template-columns: 1fr; }
.rvg-lp-cols-2 .rvg-lp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.rvg-lp-cols-3 .rvg-lp-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.rvg-lp-cols-4 .rvg-lp-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.rvg-lp-cols-5 .rvg-lp-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.rvg-lp-cols-6 .rvg-lp-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }

/* FR-102 — polish: border + hover + RTL-friendly value alignment + icons.
   Card lays out HORIZONTALLY now: big icon on the start side (right in
   RTL), label + value stacked on the end side. The icon claims ~1/4 of
   the card's width so each card reads as an "iconographic stat" rather
   than a label-only chip. */
.rvg-lp-field {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3);
    background: var(--color-bg);
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    transition: border-color 120ms ease;
    min-height: 84px;
}
.rvg-lp-field:hover {
    border-color: color-mix(in srgb, var(--color-accent) 30%, var(--color-border));
}
.rvg-lp-field-icon {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    /* `flex-end` in RTL flow = visually LEFT (the icon is the last child
       in DOM order). Combined with `flex: 0 0 auto` the column no longer
       reserves a quarter of the row — the SVG sits flush against the
       outer edge with no empty gutter to its left. */
    justify-content: flex-end;
    align-self: stretch;
    color: var(--color-accent);
    background: transparent;
}
.rvg-lp-field-icon svg,
.rvg-lp-field-icon .bi {
    width: 48px;
    height: 48px;
    opacity: 0.85;
}
.rvg-lp-field-body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0; /* allow value to ellipsis if too long */
}
.rvg-lp-field-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.78rem;
    color: var(--color-text-muted);
    font-weight: 600;
}
.rvg-lp-field-label svg,
.rvg-lp-field-label .bi {
    /* Legacy inline-icon path (when card has no icon column). Kept so
       templates that still emit an icon inside the label render cleanly. */
    width: 14px;
    height: 14px;
    color: var(--color-accent);
    opacity: 0.85;
    flex-shrink: 0;
}
.rvg-lp-field-value {
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--color-text);
    /* No forced direction — inherit page direction so "55,683.42 ر.س"
       renders amount-first then currency in Arabic (RTL), and "$ 55,683"
       renders symbol-first in English (LTR). */
    text-align: start;
    min-height: 1.4em;
}
/* Sign-based colouring — JS applies one of these classes to the value
   cell when the field opts into `color_by_sign` in dna. Negative goes
   red (over-budget warning), zero or positive goes green. */
.rvg-lp-field-value.is-negative { color: var(--color-danger); }
.rvg-lp-field-value.is-positive { color: var(--color-success); }
/* Highlight variants — picked by `field.highlight` on dna. */
.rvg-lp-field-h-accent .rvg-lp-field-value   { color: var(--color-accent); }
.rvg-lp-field-h-success .rvg-lp-field-value  { color: var(--color-success); }
.rvg-lp-field-h-warning .rvg-lp-field-value  { color: var(--color-warning); }
.rvg-lp-field-h-danger  .rvg-lp-field-value  { color: var(--color-danger); }

/* Dynamic alert — toggled by JS when the field's `highlight_when`
   expression returns a strictly-positive value on the server. The
   whole field card lights up red so the alert is visible from the
   corner of the eye, not just in the value text. */
.rvg-lp-field.rvg-lp-field-h-active {
    background: color-mix(in srgb, var(--color-danger) 8%, var(--color-bg));
    border: 1px solid color-mix(in srgb, var(--color-danger) 35%, transparent);
    box-shadow: 0 1px 4px color-mix(in srgb, var(--color-danger) 18%, transparent);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    animation: rvg-lp-pulse 1.4s ease-in-out 1;
}
.rvg-lp-field.rvg-lp-field-h-active .rvg-lp-field-value {
    color: var(--color-danger);
    font-weight: 700;
}
.rvg-lp-field.rvg-lp-field-h-active .rvg-lp-field-label {
    color: var(--color-danger);
}
@keyframes rvg-lp-pulse {
    0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-danger) 35%, transparent); }
    50%  { box-shadow: 0 0 0 6px color-mix(in srgb, var(--color-danger) 0%,  transparent); }
    100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-danger) 0%,  transparent); }
}

/* Loading skeleton — semi-transparent shimmer over the value text. */
.rvg-lp-skeleton {
    position: relative;
    color: transparent !important;
}
.rvg-lp-skeleton::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 4px;
    background: linear-gradient(
        90deg,
        var(--color-bg-alt) 0%,
        color-mix(in srgb, var(--color-accent) 18%, var(--color-bg-alt)) 50%,
        var(--color-bg-alt) 100%
    );
    background-size: 200% 100%;
    animation: rvg-lp-shimmer 1.2s ease-in-out infinite;
}
@keyframes rvg-lp-shimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* Mobile — stack into single column at ≤640px. */
@media (max-width: 640px) {
    .rvg-lp-cols-2 .rvg-lp-grid,
    .rvg-lp-cols-3 .rvg-lp-grid,
    .rvg-lp-cols-4 .rvg-lp-grid,
    .rvg-lp-cols-5 .rvg-lp-grid,
    .rvg-lp-cols-6 .rvg-lp-grid {
        grid-template-columns: 1fr;
    }
}


/* ==========================================================================
   OP-45 (2026-06-11 theme-polish): generic 40px touch targets on phones.
   Icon-sized framework buttons get a minimum 40x40 hit area at <=768px.
   NOTE: being last in the file, the min-width here intentionally
   supersedes OP-52a's 30px slimming of +/eye at <=480px — a 30px target
   is hardest to hit exactly on the smallest phones (a11y floor wins over
   ~20px of reclaimed select width). Padding/colors untouched.
   REVERT: delete this whole media block (OP-52a then re-applies fully).
   ========================================================================== */
@media (max-width: 768px) {
    .rvg-icon-btn,
    .rvg-bell-btn,
    .rvg-quick-create-btn,
    .rvg-quick-edit-btn,
    .rvg-rmeta-btn {
        min-width: 40px;
        min-height: 40px;
    }
}

/* OP-77 (2026-06-11) — الشريط الشبحي أعلى الجداول العريضة.
   OP-77b: تصميمه نسخة حرفيّة من سكرولبار الجدول السفلي
   (list.twig ~سطر 1070): ارتفاع 8px، مسار شفّاف، إبهام border
   بزوايا 4px يغمق عند الـhover — قاعدة UI_MAP: حاكِ القياسي. */
.rvg-topscroll {
    overflow-x: auto;
    overflow-y: hidden;
    height: 8px;            /* نفس ارتفاع سكرولبار الجدول السفلي حرفيّاً */
    margin-bottom: 4px;
}
.rvg-topscroll::-webkit-scrollbar { height: 8px; }
.rvg-topscroll::-webkit-scrollbar:vertical { display: none; }
.rvg-topscroll::-webkit-scrollbar-track { background: transparent; }
.rvg-topscroll::-webkit-scrollbar-thumb {
    background: var(--color-border);
    border-radius: 4px;
}
.rvg-topscroll::-webkit-scrollbar-thumb:hover {
    background: var(--color-text-soft);
}
.rvg-topscroll { scrollbar-width: thin; scrollbar-color: var(--color-border) transparent; }
.rvg-topscroll-spacer { height: 1px; }

/* FR-136 P1 (2026-06-11) — the rich lines modal: toolbar + pager + print. */
.rvg-lines-modal-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}
.rvg-lines-modal-search-wrap {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: 1 1 220px;
    max-width: 340px;
    padding: 0 10px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md, 6px);
    background: var(--color-bg);
    color: var(--color-text-soft);
}
.rvg-lines-modal-search-wrap .revogen-icon { width: 14px; height: 14px; flex: 0 0 auto; }
.rvg-lines-modal-search {
    border: 0;
    outline: none;
    background: transparent;
    color: var(--color-text);
    font: inherit;
    font-size: 13px;
    min-height: 34px;
    width: 100%;
    min-width: 0;
}
.rvg-lines-modal-toolbar-spacer { flex: 1 1 auto; }
.rvg-lines-modal-tool-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 34px;
    padding: 0 12px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md, 6px);
    background: var(--color-bg);
    color: var(--color-text);
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
}
.rvg-lines-modal-tool-btn:hover { background: var(--color-bg-hover, var(--color-bg-alt)); }
.rvg-lines-modal-tool-btn .revogen-icon { width: 14px; height: 14px; }
.rvg-lines-modal-pager {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: wrap;
    margin-top: 10px;
}
.rvg-lines-modal-page-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 30px;
    min-height: 30px;
    padding: 0 8px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md, 6px);
    color: var(--color-text);
    text-decoration: none;
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
}
a.rvg-lines-modal-page-link:hover { background: var(--color-bg-hover, var(--color-bg-alt)); }
.rvg-lines-modal-page-link.is-current {
    background: var(--color-accent);
    color: var(--color-accent-fg, white);
    border-color: var(--color-accent);
    font-weight: 600;
}
.rvg-lines-modal-page-link.is-disabled { opacity: 0.35; pointer-events: none; }
.rvg-lines-modal-page-gap { color: var(--color-text-soft); padding: 0 2px; }
.rvg-lines-modal-pager-info {
    margin-inline-start: auto;
    color: var(--color-text-soft);
    font-size: 12px;
}
@media (max-width: 640px) {
    .rvg-lines-modal-search-wrap { flex-basis: 100%; max-width: none; }
    .rvg-lines-modal-tool-btn { min-height: 40px; }
    .rvg-lines-modal-page-link { min-width: 40px; min-height: 40px; }
    .rvg-lines-modal-pager-info { flex-basis: 100%; margin-inline-start: 0; }
}
/* Print: only the modal's table area. */
@media print {
    body.rvg-lines-printing > *:not(#rvg-lines-modal-dialog) { display: none !important; }
    body.rvg-lines-printing #rvg-lines-modal-dialog {
        position: static !important;
        width: 100% !important;
        max-width: none !important;
        height: auto !important;
        max-height: none !important;
        border: 0 !important;
        box-shadow: none !important;
        padding: 0 !important;
        margin: 0 !important;
    }
    body.rvg-lines-printing #rvg-lines-modal-dialog::backdrop { display: none; }
    body.rvg-lines-printing .rvg-lines-modal-toolbar,
    body.rvg-lines-printing .rvg-lines-modal-pager,
    body.rvg-lines-printing .rvg-lines-modal-close { display: none !important; }
    body.rvg-lines-printing .rvg-lines-modal-body { max-height: none !important; overflow: visible !important; }
    body.rvg-lines-printing .rvg-lines-scroll,
    body.rvg-lines-printing [class*="-scroll"] { overflow: visible !important; }
}

/* FR-136 — dialog chrome للمودال (كان inline في form.twig فقط → عارٍ من
   باقي الصفحات). نفس عائلة rvg-modal: راديوس 12، ظلّ عميق، رأس فاصل. */
.rvg-lines-modal-dialog {
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 0;
    width: min(960px, calc(100vw - 32px));
    max-height: min(82vh, 900px);
    background: var(--color-bg);
    color: var(--color-text);
    box-shadow: 0 24px 64px rgb(0 0 0 / 0.28);
}
.rvg-lines-modal-dialog::backdrop { background: var(--rvg-modal-backdrop-bg, rgb(0 0 0 / 0.45)); }
.rvg-lines-modal-frame { display: flex; flex-direction: column; max-height: inherit; }
.rvg-lines-modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--color-border);
}
.rvg-lines-modal-headline { margin: 0; font-size: 15px; font-weight: 700; }
.rvg-lines-modal-close {
    border: 0; background: transparent; cursor: pointer;
    width: 40px; height: 40px; border-radius: 8px;
    color: var(--color-text-soft); font-size: 15px;
}
.rvg-lines-modal-close:hover { background: var(--color-bg-hover, var(--color-bg-alt)); color: var(--color-text); }
.rvg-lines-modal-body { padding: 14px 18px 18px; overflow: auto; }
.rvg-lines-modal-parent { color: var(--color-text-soft); font-size: 12.5px; margin-bottom: 8px; }
.rvg-lines-modal-empty { padding: 28px 0; text-align: center; color: var(--color-text-soft); }
@media (max-width: 640px) {
    .rvg-lines-modal-dialog { width: calc(100vw - 16px); max-height: 90vh; }
}

/* FR-136 — روابط الفرز في رؤوس جدول المودال كانت بأزرق المتصفّح الخام. */
.rvg-lines-sort-link {
    color: inherit;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.rvg-lines-sort-link:hover { color: var(--color-accent); }

/* FR-136 — حقول الشبكة المدمجة كانت ترث مقاسات الفورم الكبيرة (ارتفاعات
   44px+) فتبدو غير منطقيّة داخل سطر جدول. مقاس مضغوط موحَّد 32px. */
.rvg-ic-table .rvg-ic-cell input:not([type="checkbox"]):not([type="radio"]),
.rvg-ic-table .rvg-ic-cell select,
.rvg-ic-table .rvg-ic-cell textarea {
    min-height: 32px;
    height: 32px;
    padding: 2px 8px;
    font-size: 12.5px;
    border-radius: 6px;
}
.rvg-ic-table .rvg-ic-cell textarea { height: auto; min-height: 32px; max-height: 64px; }
.rvg-ic-table .rvg-ic-cell .rvg-sel__btn {
    min-height: 32px;
    padding: 2px 8px;
    font-size: 12.5px;
    border-radius: 6px;
}
.rvg-ic-table .rvg-ic-cell .rvg-sel { min-width: 0; }
.rvg-ic-table .rvg-ic-cell { padding: 4px 6px; }

/* تكافؤ الأبناء (توجيه المالك 2026-06-12) — نفس سلوك القوائم الأساسية:
   توسيط المحتوى، أوّل عمود بيانات start، وtextarea باتجاه اللغة.
   rvg-al-* (محاذاة admin لكلّ عمود) آخر القواعد فتغلب الجميع. */
.rvg-children-table thead th,
.rvg-children-table tbody td { text-align: center; }
.rvg-children-table td[data-type="textarea"] { text-align: start; }
.rvg-children-table thead th.rvg-first-data-col,
.rvg-children-table tbody td.rvg-first-data-col { text-align: start; }
.rvg-children-table thead th.rvg-al-right,
.rvg-children-table tbody td.rvg-al-right  { text-align: right; }
.rvg-children-table thead th.rvg-al-center,
.rvg-children-table tbody td.rvg-al-center { text-align: center; }
.rvg-children-table thead th.rvg-al-left,
.rvg-children-table tbody td.rvg-al-left   { text-align: left; }

/* FR-136 — فرز لوحة الأبناء: مؤشّر يد + سهم على العمود النشط فقط. */
.rvg-children-table thead th:not(.rvg-children-seq-col):not(.rvg-children-action) {
    cursor: pointer;
    user-select: none;
}
.rvg-children-table thead th.is-sorted-asc::after { content: " ▲"; font-size: 9px; color: var(--color-accent); }
.rvg-children-table thead th.is-sorted-desc::after { content: " ▼"; font-size: 9px; color: var(--color-accent); }

/* FR-136 — فرز الشبكة المدمجة. */
.rvg-ic-table thead th:not(.rvg-ic-th-actions):not(:first-child) { cursor: pointer; user-select: none; }
.rvg-ic-table thead th.is-sorted-asc::after { content: " ▲"; font-size: 9px; color: var(--color-accent); }
.rvg-ic-table thead th.is-sorted-desc::after { content: " ▼"; font-size: 9px; color: var(--color-accent); }

/* FR-136 (قاعدة المالك 2026-06-11): أيّ سكرول أفقي لجدول — في كلّ النظام
   بجميع الأنواع — لا يظهر شكله إلا عند مرور الماوس. الوظيفة تبقى دائماً. */
[class$="-scroll"],
[class*="-table-wrap"],
.rvg-topscroll,
.rvg-lines-modal-body {
    scrollbar-color: transparent transparent;
}
[class$="-scroll"]:hover,
[class*="-table-wrap"]:hover,
.rvg-topscroll:hover,
.rvg-lines-modal-body:hover {
    scrollbar-color: var(--color-border) transparent;
}
[class$="-scroll"]::-webkit-scrollbar-thumb,
[class*="-table-wrap"]::-webkit-scrollbar-thumb,
.rvg-topscroll::-webkit-scrollbar-thumb,
.rvg-lines-modal-body::-webkit-scrollbar-thumb {
    background: transparent;
}
[class$="-scroll"]:hover::-webkit-scrollbar-thumb,
[class*="-table-wrap"]:hover::-webkit-scrollbar-thumb,
.rvg-topscroll:hover::-webkit-scrollbar-thumb,
.rvg-lines-modal-body:hover::-webkit-scrollbar-thumb {
    background: var(--color-border);
}
[class$="-scroll"]:hover::-webkit-scrollbar-thumb:hover,
.rvg-topscroll:hover::-webkit-scrollbar-thumb:hover {
    background: var(--color-text-soft);
}

/* FR-136 — شريط إضافة بند أسفل الشبكة (تكملة طبيعيّة للسطور). */
.rvg-ic-add-inline {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    min-height: 34px;
    margin-top: 4px;
    background: transparent;
    border: 1px dashed var(--color-border);
    border-radius: var(--radius-md, 6px);
    color: var(--color-text-soft);
    font: inherit;
    font-size: 12.5px;
    cursor: pointer;
}
.rvg-ic-add-inline:hover {
    color: var(--color-accent);
    border-color: var(--color-accent);
    background: color-mix(in srgb, var(--color-accent) 5%, transparent);
}
.rvg-ic-add-inline .revogen-icon { width: 13px; height: 13px; }
.rvg-ic-row-existing { cursor: default; }
.rvg-ic-row-existing:not(.is-editing):hover td { background: color-mix(in srgb, var(--color-accent) 5%, var(--color-bg)); }


/* آليّة «الأب وحقله الثاني»: سطر ثانٍ تحت قيمة الـlookup —
   عادي = رمادي هادئ بلا تلوين؛ accent = وصفة وقت التدقيق حرفيّاً
   (مونو + soft) فيأخذ «لون الساعة» في كلّ ثيم. */
/* لغة المحاذاة لشبكة الإدخال الإنلاين (توجيه المالك: الشبكة كانت تتجاهل
   التوسيط والمحاذاة كلّيّاً). توسيط افتراضيّ + المدخلات تتبع خليّتها +
   rvg-al-* من اللوحة آخر الكلام (thead/tbody ترفع التخصيص فوق العائلة). */
.rvg-ic-table .rvg-ic-th,
.rvg-ic-table .rvg-ic-cell { text-align: center; }
.rvg-ic-table .rvg-ic-cell textarea,
.rvg-ic-table .rvg-ic-cell[data-type="textarea"] { text-align: start; }
.rvg-ic-table .rvg-ic-cell input,
.rvg-ic-table .rvg-ic-cell select { text-align: inherit; }
.rvg-ic-table thead th.rvg-al-right, .rvg-ic-table tbody td.rvg-al-right { text-align: right; }
.rvg-ic-table thead th.rvg-al-center, .rvg-ic-table tbody td.rvg-al-center { text-align: center; }
.rvg-ic-table thead th.rvg-al-left, .rvg-ic-table tbody td.rvg-al-left { text-align: left; }

/* محاذاة الأعمدة في جداول lines (مودال سجلّات الإبن + كلّ سطوح FR-114) —
   آخر القواعد منطقيّاً فتغلب الافتراضات؛ نفس عائلة قواعد القوائم. */
.rvg-lines-table thead th.rvg-al-right, .rvg-lines-table tbody td.rvg-al-right { text-align: right; }
.rvg-lines-table thead th.rvg-al-center, .rvg-lines-table tbody td.rvg-al-center { text-align: center; }
.rvg-lines-table thead th.rvg-al-left, .rvg-lines-table tbody td.rvg-al-left { text-align: left; }

.rvg-lines-lookup-stack {
    display: inline-flex;
    flex-direction: column;
    line-height: 1.3;
    gap: 1px;
    min-width: 0;
}
.rvg-lines-lookup-sub {
    /* توجيه المالك (2026-06-12): سطر قابل للتخصيص الكامل — اللون من
       باليتة توكنات الثيم، والحجم sm..xl، والخطّ نظام/مونو. */
    font-size: 12px;
    color: var(--color-text-soft);
}
.rvg-lsub-c--default { color: var(--color-text-soft); }
.rvg-lsub-c--accent  { color: var(--color-accent); }
.rvg-lsub-c--success { color: var(--color-success); }
.rvg-lsub-c--info    { color: var(--color-info); }
.rvg-lsub-c--warning { color: var(--color-warning); }
.rvg-lsub-c--danger  { color: var(--color-danger); }
.rvg-lsub-c--muted   { color: var(--color-text-muted); }
.rvg-lsub-c--dark    { color: var(--color-text); }
.rvg-lsub-s--sm { font-size: 10.5px; }
.rvg-lsub-s--md { font-size: 12px; }
.rvg-lsub-s--lg { font-size: 13.5px; }
.rvg-lsub-s--xl { font-size: 15px; }
.rvg-lsub--mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
/* طريقة «نفس السطر»: جدة | البوادي — الفاصل خامد والمحاذاة baseline */
.rvg-lines-lookup-stack.is-inline {
    flex-direction: row;
    align-items: baseline;
    gap: 5px;
}
.rvg-lsub-sep { color: var(--color-text-soft); opacity: 0.7; }

/* ============================================================
   Smooth hover for data tables — system-wide (owner 2026-06-16)
   Fade the cell background on row/cell hover instead of an instant
   flip. Covers the main list (.rvg-list-card), inline/modal lines
   (.rvg-lines-table) and FR-143 colored rows/cells (whose hover
   intensifies the tint). background-color only → cheap, no layout
   touch. Initial paint isn't animated (transitions fire on change,
   and paginate/sort/AJAX swap fresh DOM nodes).
   ============================================================ */
/* hover bg lands on the TD in the main list, but on the TR in lines tables —
   so transition BOTH (a no-op on whichever element's bg doesn't change). */
.rvg-list-card tbody tr,
.rvg-list-card tbody td,
.rvg-lines-table tbody tr,
.rvg-lines-table tbody td,
tbody tr[class*="rvg-fmt-row"] td,
tbody td[class*="rvg-fmt-"]{transition:background-color 90ms ease-out}
@media(prefers-reduced-motion:reduce){
  .rvg-list-card tbody tr,
  .rvg-list-card tbody td,
  .rvg-lines-table tbody tr,
  .rvg-lines-table tbody td,
  tbody tr[class*="rvg-fmt-row"] td,
  tbody td[class*="rvg-fmt-"]{transition:none}
}

/* ============================================================
   FR-143 — Conditional table formatting (rvg-fmt-*)
   Applied by TableFormatEngine across list-render surfaces.
   `!important` + tbody scope deliberately beat list.twig's own
   `.list-{t} tbody tr.is-clickable:hover td` (0,3,3) hover/zebra rule,
   which would otherwise COVER these tints (root cause of "hover غير فعال").
   Row tint targets the row's TD cells (not the TR) so opaque cell
   backgrounds can't hide it. Cell rules come AFTER row rules so a
   specific cell color wins over the row tint on conflict. Rest + HOVER
   (hover INTENSIFIES, never replaces). Tokens only — zero raw hex.
   ============================================================ */
/* ---- ROW background tint (on cells) + hover intensify ---- */
tbody tr.rvg-fmt-row-accent td{background:color-mix(in srgb,var(--color-accent) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-accent:hover td{background:color-mix(in srgb,var(--color-accent) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-success td{background:color-mix(in srgb,var(--color-success) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-success:hover td{background:color-mix(in srgb,var(--color-success) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-info td{background:color-mix(in srgb,var(--color-info) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-info:hover td{background:color-mix(in srgb,var(--color-info) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-warning td{background:color-mix(in srgb,var(--color-warning) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-warning:hover td{background:color-mix(in srgb,var(--color-warning) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-danger td{background:color-mix(in srgb,var(--color-danger) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-danger:hover td{background:color-mix(in srgb,var(--color-danger) 26%,var(--color-bg)) !important}
/* ---- ROW side-stripe (leading cell) ---- */
tbody tr.rvg-fmt-rowstripe-accent td:first-child{box-shadow:inset 4px 0 0 var(--color-accent)}
tbody tr.rvg-fmt-rowstripe-success td:first-child{box-shadow:inset 4px 0 0 var(--color-success)}
tbody tr.rvg-fmt-rowstripe-info td:first-child{box-shadow:inset 4px 0 0 var(--color-info)}
tbody tr.rvg-fmt-rowstripe-warning td:first-child{box-shadow:inset 4px 0 0 var(--color-warning)}
tbody tr.rvg-fmt-rowstripe-danger td:first-child{box-shadow:inset 4px 0 0 var(--color-danger)}
/* ---- CELL background tint + hover intensify (after row → wins ties).
   CASE 1 (owner 2026-06-15): the hover rule MUST use the CHILD combinator
   `tr:hover > td` — NOT descendant. The list table is nested inside an outer
   `table.rvg-print-frame` whose row is `:hover` whenever the cursor is
   anywhere in the list; a descendant `tr:hover td` then matched EVERY colored
   cell and lit the whole COLUMN. `> td` restricts the match to a direct child
   of the actually-hovered data row, so only that one cell intensifies.
   (Proven live on /orders: hover row 1 → row 1 cell 28%, row 4 cell stays 14%.) ---- */
td.rvg-fmt-bg-accent{background:color-mix(in srgb,var(--color-accent) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-accent{background:color-mix(in srgb,var(--color-accent) 28%,var(--color-bg)) !important}
td.rvg-fmt-bg-success{background:color-mix(in srgb,var(--color-success) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-success{background:color-mix(in srgb,var(--color-success) 28%,var(--color-bg)) !important}
td.rvg-fmt-bg-info{background:color-mix(in srgb,var(--color-info) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-info{background:color-mix(in srgb,var(--color-info) 28%,var(--color-bg)) !important}
td.rvg-fmt-bg-warning{background:color-mix(in srgb,var(--color-warning) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-warning{background:color-mix(in srgb,var(--color-warning) 28%,var(--color-bg)) !important}
td.rvg-fmt-bg-danger{background:color-mix(in srgb,var(--color-danger) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-danger{background:color-mix(in srgb,var(--color-danger) 28%,var(--color-bg)) !important}
/* ---- CELL text color ---- */
td.rvg-fmt-tx-accent{color:var(--color-accent) !important;font-weight:700}
td.rvg-fmt-tx-success{color:var(--color-success) !important;font-weight:700}
td.rvg-fmt-tx-info{color:var(--color-info) !important;font-weight:700}
td.rvg-fmt-tx-warning{color:var(--color-warning) !important;font-weight:700}
td.rvg-fmt-tx-danger{color:var(--color-danger) !important;font-weight:700}
/* ---- CELL side-stripe ---- */
td.rvg-fmt-stripe-accent{box-shadow:inset 4px 0 0 var(--color-accent)}
td.rvg-fmt-stripe-success{box-shadow:inset 4px 0 0 var(--color-success)}
td.rvg-fmt-stripe-info{box-shadow:inset 4px 0 0 var(--color-info)}
td.rvg-fmt-stripe-warning{box-shadow:inset 4px 0 0 var(--color-warning)}
td.rvg-fmt-stripe-danger{box-shadow:inset 4px 0 0 var(--color-danger)}
/* ---- CELL leading dot ---- */
tbody td.rvg-fmt-dot-accent::before,tbody td.rvg-fmt-dot-success::before,tbody td.rvg-fmt-dot-info::before,tbody td.rvg-fmt-dot-warning::before,tbody td.rvg-fmt-dot-danger::before{content:"";display:inline-block;width:8px;height:8px;border-radius:50%;margin-inline-end:6px;vertical-align:middle}
tbody td.rvg-fmt-dot-accent::before{background:var(--color-accent)}
tbody td.rvg-fmt-dot-success::before{background:var(--color-success)}
tbody td.rvg-fmt-dot-info::before{background:var(--color-info)}
tbody td.rvg-fmt-dot-warning::before{background:var(--color-warning)}
tbody td.rvg-fmt-dot-danger::before{background:var(--color-danger)}
/* ---- CASE 1 (owner 2026-06-15): a row may carry SEVERAL colored columns
   (e.g. one red + one green). On row hover the WHOLE row reacts, but each
   cell intensifies its OWN color in place — the red cell deepens red, the
   green cell deepens green (rules above: bg 14%→28%), and a plain cell with
   no rule takes the neutral list hover (accent ~9%, list.twig). No single
   color floods the row — every cell keeps its own meaning. (No extra CSS is
   needed: the per-cell `tr:hover > td.rvg-fmt-bg-*` rules above already do it;
   the earlier whole-row flood was wrong and has been removed.) ---- */

/* FR-143 extended palette (owner 2026-06-15) — 7 added hues, same pattern
   as the 5 semantic ones above but via the --rvg-fmt-* tokens. Theme-aware.
   row 13%/26% · cell 14%/28% (child-combinator hover) · text · stripe · dot. */
tbody td.rvg-fmt-dot-purple::before,tbody td.rvg-fmt-dot-teal::before,tbody td.rvg-fmt-dot-pink::before,tbody td.rvg-fmt-dot-orange::before,tbody td.rvg-fmt-dot-lime::before,tbody td.rvg-fmt-dot-brown::before,tbody td.rvg-fmt-dot-slate::before{content:"";display:inline-block;width:8px;height:8px;border-radius:50%;margin-inline-end:6px;vertical-align:middle}
tbody tr.rvg-fmt-row-purple td{background:color-mix(in srgb,var(--rvg-fmt-purple) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-purple:hover td{background:color-mix(in srgb,var(--rvg-fmt-purple) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-rowstripe-purple td:first-child{box-shadow:inset 4px 0 0 var(--rvg-fmt-purple)}
td.rvg-fmt-bg-purple{background:color-mix(in srgb,var(--rvg-fmt-purple) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-purple{background:color-mix(in srgb,var(--rvg-fmt-purple) 28%,var(--color-bg)) !important}
td.rvg-fmt-tx-purple{color:var(--rvg-fmt-purple) !important;font-weight:700}
td.rvg-fmt-stripe-purple{box-shadow:inset 4px 0 0 var(--rvg-fmt-purple)}
tbody td.rvg-fmt-dot-purple::before{background:var(--rvg-fmt-purple)}
tbody tr.rvg-fmt-row-teal td{background:color-mix(in srgb,var(--rvg-fmt-teal) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-teal:hover td{background:color-mix(in srgb,var(--rvg-fmt-teal) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-rowstripe-teal td:first-child{box-shadow:inset 4px 0 0 var(--rvg-fmt-teal)}
td.rvg-fmt-bg-teal{background:color-mix(in srgb,var(--rvg-fmt-teal) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-teal{background:color-mix(in srgb,var(--rvg-fmt-teal) 28%,var(--color-bg)) !important}
td.rvg-fmt-tx-teal{color:var(--rvg-fmt-teal) !important;font-weight:700}
td.rvg-fmt-stripe-teal{box-shadow:inset 4px 0 0 var(--rvg-fmt-teal)}
tbody td.rvg-fmt-dot-teal::before{background:var(--rvg-fmt-teal)}
tbody tr.rvg-fmt-row-pink td{background:color-mix(in srgb,var(--rvg-fmt-pink) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-pink:hover td{background:color-mix(in srgb,var(--rvg-fmt-pink) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-rowstripe-pink td:first-child{box-shadow:inset 4px 0 0 var(--rvg-fmt-pink)}
td.rvg-fmt-bg-pink{background:color-mix(in srgb,var(--rvg-fmt-pink) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-pink{background:color-mix(in srgb,var(--rvg-fmt-pink) 28%,var(--color-bg)) !important}
td.rvg-fmt-tx-pink{color:var(--rvg-fmt-pink) !important;font-weight:700}
td.rvg-fmt-stripe-pink{box-shadow:inset 4px 0 0 var(--rvg-fmt-pink)}
tbody td.rvg-fmt-dot-pink::before{background:var(--rvg-fmt-pink)}
tbody tr.rvg-fmt-row-orange td{background:color-mix(in srgb,var(--rvg-fmt-orange) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-orange:hover td{background:color-mix(in srgb,var(--rvg-fmt-orange) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-rowstripe-orange td:first-child{box-shadow:inset 4px 0 0 var(--rvg-fmt-orange)}
td.rvg-fmt-bg-orange{background:color-mix(in srgb,var(--rvg-fmt-orange) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-orange{background:color-mix(in srgb,var(--rvg-fmt-orange) 28%,var(--color-bg)) !important}
td.rvg-fmt-tx-orange{color:var(--rvg-fmt-orange) !important;font-weight:700}
td.rvg-fmt-stripe-orange{box-shadow:inset 4px 0 0 var(--rvg-fmt-orange)}
tbody td.rvg-fmt-dot-orange::before{background:var(--rvg-fmt-orange)}
tbody tr.rvg-fmt-row-lime td{background:color-mix(in srgb,var(--rvg-fmt-lime) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-lime:hover td{background:color-mix(in srgb,var(--rvg-fmt-lime) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-rowstripe-lime td:first-child{box-shadow:inset 4px 0 0 var(--rvg-fmt-lime)}
td.rvg-fmt-bg-lime{background:color-mix(in srgb,var(--rvg-fmt-lime) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-lime{background:color-mix(in srgb,var(--rvg-fmt-lime) 28%,var(--color-bg)) !important}
td.rvg-fmt-tx-lime{color:var(--rvg-fmt-lime) !important;font-weight:700}
td.rvg-fmt-stripe-lime{box-shadow:inset 4px 0 0 var(--rvg-fmt-lime)}
tbody td.rvg-fmt-dot-lime::before{background:var(--rvg-fmt-lime)}
tbody tr.rvg-fmt-row-brown td{background:color-mix(in srgb,var(--rvg-fmt-brown) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-brown:hover td{background:color-mix(in srgb,var(--rvg-fmt-brown) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-rowstripe-brown td:first-child{box-shadow:inset 4px 0 0 var(--rvg-fmt-brown)}
td.rvg-fmt-bg-brown{background:color-mix(in srgb,var(--rvg-fmt-brown) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-brown{background:color-mix(in srgb,var(--rvg-fmt-brown) 28%,var(--color-bg)) !important}
td.rvg-fmt-tx-brown{color:var(--rvg-fmt-brown) !important;font-weight:700}
td.rvg-fmt-stripe-brown{box-shadow:inset 4px 0 0 var(--rvg-fmt-brown)}
tbody td.rvg-fmt-dot-brown::before{background:var(--rvg-fmt-brown)}
tbody tr.rvg-fmt-row-slate td{background:color-mix(in srgb,var(--rvg-fmt-slate) 13%,var(--color-bg)) !important}
tbody tr.rvg-fmt-row-slate:hover td{background:color-mix(in srgb,var(--rvg-fmt-slate) 26%,var(--color-bg)) !important}
tbody tr.rvg-fmt-rowstripe-slate td:first-child{box-shadow:inset 4px 0 0 var(--rvg-fmt-slate)}
td.rvg-fmt-bg-slate{background:color-mix(in srgb,var(--rvg-fmt-slate) 14%,var(--color-bg)) !important}
tbody tr:hover > td.rvg-fmt-bg-slate{background:color-mix(in srgb,var(--rvg-fmt-slate) 28%,var(--color-bg)) !important}
td.rvg-fmt-tx-slate{color:var(--rvg-fmt-slate) !important;font-weight:700}
td.rvg-fmt-stripe-slate{box-shadow:inset 4px 0 0 var(--rvg-fmt-slate)}
tbody td.rvg-fmt-dot-slate::before{background:var(--rvg-fmt-slate)}

/* FR-143 GLOW dot (owner 2026-06-15) — pulsing halo where_part, mimics
   alrifai .rpt-dot--overdrawn. Per-color --glow-c drives the ring color. */
@keyframes rvg-fmt-glow{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--glow-c) 80%,transparent)}100%{box-shadow:0 0 0 8px color-mix(in srgb,var(--glow-c) 0%,transparent)}}
tbody td[class*="rvg-fmt-glow-"]::before{content:"";display:inline-block;width:9px;height:9px;border-radius:50%;margin-inline-end:6px;vertical-align:middle;background:var(--glow-c);animation:rvg-fmt-glow 1.6s ease-out infinite}
@media(prefers-reduced-motion:reduce){tbody td[class*="rvg-fmt-glow-"]::before{animation:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--glow-c) 35%,transparent)}}
tbody td.rvg-fmt-glow-accent{--glow-c:var(--rvg-fmt-accent)}
tbody td.rvg-fmt-glow-success{--glow-c:var(--rvg-fmt-success)}
tbody td.rvg-fmt-glow-info{--glow-c:var(--rvg-fmt-info)}
tbody td.rvg-fmt-glow-warning{--glow-c:var(--rvg-fmt-warning)}
tbody td.rvg-fmt-glow-danger{--glow-c:var(--rvg-fmt-danger)}
tbody td.rvg-fmt-glow-purple{--glow-c:var(--rvg-fmt-purple)}
tbody td.rvg-fmt-glow-teal{--glow-c:var(--rvg-fmt-teal)}
tbody td.rvg-fmt-glow-pink{--glow-c:var(--rvg-fmt-pink)}
tbody td.rvg-fmt-glow-orange{--glow-c:var(--rvg-fmt-orange)}
tbody td.rvg-fmt-glow-lime{--glow-c:var(--rvg-fmt-lime)}
tbody td.rvg-fmt-glow-brown{--glow-c:var(--rvg-fmt-brown)}
tbody td.rvg-fmt-glow-slate{--glow-c:var(--rvg-fmt-slate)}

/* FR-143/144 — keep conditional colors when PRINTING (browsers strip
   backgrounds by default). `td` (not `tbody td`) so it covers the column
   TOTALS (tfoot) too, and the reports' client-built print zone (`.pz-table`)
   whose FR-144 classes are mirrored on by rvgDecoratePrintZone. Covers list +
   lines-modal + report print, body + totals — ONE generic rule. */
@media print{
  tr[class*="rvg-fmt-row"] td, td[class*="rvg-fmt-bg-"], td[class*="rvg-fmt-stripe-"], td[class*="rvg-fmt-glow-"]::before{
    -webkit-print-color-adjust:exact;print-color-adjust:exact;}
}

/* FR-144 — color legend below a table; entries derived from the rules engine.
   Swatch mirrors the rule's where-part (bg / text / stripe / dot / glow). */
.rvg-fmt-legend{display:flex;flex-wrap:wrap;align-items:center;gap:14px;padding:10px 14px;margin-top:8px;border-top:1px solid var(--color-border);background:var(--color-bg-alt);border-radius:0 0 var(--radius-md) var(--radius-md);font-size:12px}
.rvg-fmt-legend-ttl{font-weight:700;color:var(--color-text-muted)}
.rvg-fmt-legend-item{display:inline-flex;align-items:center;gap:6px;color:var(--color-text)}
.rvg-fmt-legend-sw{width:16px;height:16px;border-radius:4px;border:1px solid var(--color-border);flex-shrink:0;position:relative;display:inline-block}
.rvg-fmt-legend-sw.is-background{background:color-mix(in srgb,var(--c) 16%,var(--color-bg));border-color:color-mix(in srgb,var(--c) 34%,var(--color-border))}
.rvg-fmt-legend-sw.is-text{color:var(--c);font-weight:800;font-size:11px;line-height:14px;text-align:center}
.rvg-fmt-legend-sw.is-text::before{content:"A"}
.rvg-fmt-legend-sw.is-stripe{box-shadow:inset 4px 0 0 var(--c)}
.rvg-fmt-legend-sw.is-dot::before,.rvg-fmt-legend-sw.is-glow::before{content:"";position:absolute;inset:0;margin:auto;width:8px;height:8px;border-radius:50%;background:var(--c)}
.rvg-fmt-legend-sw.is-glow::before{animation:rvg-fmt-glow 1.6s ease-out infinite}
@media(prefers-reduced-motion:reduce){.rvg-fmt-legend-sw.is-glow::before{animation:none}}
@media print{.rvg-fmt-legend{break-inside:avoid}.rvg-fmt-legend-sw{-webkit-print-color-adjust:exact;print-color-adjust:exact}}
