﻿/* Cascade layer `core` (UX-361) — the shared design system. Layer order: App.razor <head>.
   Everything in this file sits inside this block; see the end of the file. */
@layer core {

:root {
    --core-primary: var(--ds-primary);
    --core-primary-dark: var(--ds-primary-strong);
    --core-primary-soft: var(--ds-primary-soft);
    --core-accent: var(--ds-accent);
    --core-bg: var(--ds-bg);
    --core-border: var(--ds-border);
    --core-border-soft: var(--ds-border-soft);
    --core-text: var(--ds-text);
    --core-muted: var(--ds-muted);
    --core-shadow: var(--ds-shadow);
    /* UX-353: named by component CSS but until now only defined inside a few scoped .razor.css files. */
    --core-shadow-strong: var(--ds-shadow-lg);
    --core-shadow-hover: var(--ds-shadow-lg);
    --core-surface: var(--ds-surface);
    --core-surface-soft: var(--ds-surface-2);

    /* Data-grid box (UX-355). On :root, not on .core-data-grid, so a grid in a dialog (outside .core-page)
       reads exactly the same numbers as one on a page. Full explanation at the grid rules below. */
    --core-grid-rows: 10;
    --core-grid-head-h: 51px;
    --core-grid-row-h: 51px;
    --core-grid-hscroll: 10px;

    /* UX-338 — font weights. Vazir ships only 100/300/400/500/700; any 600–1000 snapped to 700, so
       grid body, column headers and page titles all rendered identically. Three weights only:
       data/body text regular, headers/labels/buttons/chips medium, titles/headings/key figures bold. */
    --ds-fw-regular: 400;
    --ds-fw-medium: 500;
    --ds-fw-bold: 700;

    /* UX-339 — type scale. Nothing below 12px (Persian glyphs and dots blur under it); grid body and
       inputs use sm (13px) or larger. */
    --ds-fs-xs: 12px;
    --ds-fs-sm: 13px;
    --ds-fs-md: 14px;
    --ds-fs-lg: 16px;
    --ds-fs-xl: 20px;
    --ds-fs-2xl: 24px;
    --ds-fs-3xl: 30px;
}

/* =========================================================================================
   Breakpoints (UX-357) — MudBlazor's, and only these. Every width query in core.css, app-ui.css, mobile.css
   and app.css uses one of them, so the layout changes at four widths instead of a dozen.

     xs  <  600      max-width: 599.95px   |  min-width: 600px
     sm  600 – 959   max-width: 959.95px   |  min-width: 960px   <- desktop starts here
     md  960 – 1279  max-width: 1279.95px  |  min-width: 1280px
     lg  1280 – 1919 max-width: 1919.95px  |  min-width: 1920px
     xl  >= 1920

   The .95 keeps max/min pairs from both matching at a fractional width (zoom, scaled displays).
   JavaScript uses the same numbers (CrudDataGrid.razor.js, theme.js).

   One deliberate exception: MudBlazor 9.5 switches a Breakpoint.Sm table to cards with
   `@media (max-width: 960px)` — inclusive. The rules that style those cards (app-ui.css) use the same
   query so they never disagree with MudBlazor by the one pixel at exactly 960.
   (mobile.css also keeps a 390px narrow-phone tweak, below every MudBlazor breakpoint.)
   ========================================================================================= */

/* Page and dialog share ONE layer (UX-356). The values below used to be split between this file and
   `body .core-page.core-page …` overrides in app-ui.css, so the same grid, button or card looked different
   in a dialog (outside .core-page) than on a page. The final values now live here; app-ui.css keeps only
   the shell and the mobile overrides. */
.core-page {
    width: 100%;
    max-width: 1580px;
    margin-inline: auto;
    padding: 12px 20px 20px;
    direction: inherit;
    color: var(--ds-text);
}

/* UX-379: the entrance plays on the first page of a load only; theme.js puts .ug-loaded on <html> when
   this animation ends (it listens for the name ug-page-in - keep the name). Later navigations show the
   data at once. Opacity only, <=150ms. (Reduced motion: app-ui.css sets animation: none.) */
html:not(.ug-loaded) .core-page {
    animation: ug-page-in var(--ds-dur-fast) var(--ds-ease-out) both;
}

/* A page component nested in another page (tabs that host a whole list page) adds no second gutter. */
.core-page > .core-page {
    padding: 0;
}

.core-page-header {
    min-height: 0;
    padding: 0 0 2px;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    overflow: visible;
}

.core-page-header::before,
.core-page-header::after {
    display: none;
}

.core-page-title {
    margin: 0;
    color: var(--ds-text);
    font-size: var(--ds-fs-2xl);
    font-weight: var(--ds-fw-bold);
    line-height: 1.3;
    letter-spacing: 0; /* UX-348: negative tracking broke Persian joins */
    text-align: start;
}

.core-breadcrumb {
    order: -1;
    margin: 0 0 7px;
    padding: 0;
    direction: inherit;
}

.core-breadcrumb .mud-breadcrumb-item,
.core-breadcrumb .mud-breadcrumb-separator {
    color: var(--ds-faint);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
}

.core-page-actions {
    flex-wrap: wrap;
}

/* (UX-377: a `.core-page-actions / .core-filter-actions .mud-button-root` rule stood here with the same
   height, radius and weight as the surface button rule below, which always won — both bars sit in a page.) */

/*
   Every `.mud-button-root` rule below excludes `.mud-switch-base`, and must keep doing so.

   MudBlazor builds a switch out of three pieces: a fixed-height track, and over it an
   absolutely positioned thumb holder that is itself an icon button — it carries
   `mud-button-root mud-icon-button mud-switch-base`. So a plain `.mud-button-root` rule
   reaches the thumb, and button styling breaks a switch in two ways:

     - `min-height` — the holder is `position:absolute; top:0` inside a 38px track box, so a
       taller box grows downward rather than recentring. 42px (now --ds-control-h) on a medium switch dropped the
       thumb 2px below the line; on a small switch (24px box) it dropped it 9px, which is what
       made the toggles look detached from their track.
     - `transform` — the checked thumb is held in its "on" position by
       `transform: translateX(20px)`. transform is one property, not a list, so a hover lift
       (`translateY(-2px)`) or a `transform: none` reset replaces it and the thumb snaps back
       to the off position while the pointer is over it.

   Checkbox and radio share the icon-button element but sit in normal flow, so they only gain
   symmetric padding and are left alone. The `:focus-visible` ring below is deliberately NOT
   excluded — a keyboard focus halo on a toggle is wanted, and it follows the border radius.
*/

/*
   Buttons on the app surfaces — a page and the form/confirm dialogs — one look (UX-356; these were
   `body .core-page.core-page .mud-button-root` in app-ui.css, so dialog buttons kept a different size,
   radius and a hover lift that pages had cancelled).

   No hover lift any more: pages already cancelled it and dialogs now match. Should one come back, it
   must use `translate`, never `transform` — transform is one property, so a lift written into it
   replaces MudBlazor's own orientation transforms (`.mud-flip-x-rtl` pager arrows flip the wrong way,
   `.mud-switch-base.mud-checked` thumb snaps to "off").
*/
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root:not(.mud-switch-base) {
    min-height: var(--ds-control-h); /* UX-363: the same 40px as the fields beside it (was 42) */
    border-radius: 11px;
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-medium);
    letter-spacing: 0;
    transition: box-shadow var(--ds-dur-fast) var(--ds-ease),
                background-color var(--ds-dur-fast) var(--ds-ease),
                border-color var(--ds-dur-fast) var(--ds-ease),
                color var(--ds-dur-fast) var(--ds-ease);
}

:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-filled-primary {
    box-shadow: var(--ds-shadow-primary);
}

.core-summary-card,
.core-filter-card,
.core-grid-card,
.core-hero-card,
.core-details-card,
.core-side-card,
.core-details-loading {
    border: 1px solid var(--ds-border);
    border-radius: 16px;
    background: var(--ds-surface);
    box-shadow: var(--ds-shadow-sm);
}

/* UX-356: final values of the KPI card (was split with app-ui.css).
   The transition is on `translate`, not `transform` (see the button note above): only a clickable card
   lifts, and it does so with the individual property (UX-377/378). */
.core-summary-card {
    position: relative;
    min-height: 72px;
    padding: 8px 12px;
    overflow: hidden;
    isolation: isolate;
    transition: translate var(--ds-dur) var(--ds-ease),
                box-shadow var(--ds-dur) var(--ds-ease),
                border-color var(--ds-dur) var(--ds-ease);
}

.core-summary-card > .mud-stack-root {
    min-height: 52px;
    direction: inherit;
}

.core-summary-copy {
    align-items: flex-start;
    justify-content: center;
    min-width: 0;
    text-align: start;
}

/* کارتِ خلاصه‌ای که نمای گرید را عوض می‌کند. دکمه است، پس ارثِ دکمه را باید خنثی کرد:
   عرضِ کامل، متنِ راست‌چین، و بدون ظاهرِ پیش‌فرضِ مرورگر. */
button.core-summary-card {
    display: block;
    width: 100%;
    font: inherit;
    color: inherit;
    text-align: start;
    -webkit-appearance: none;
    appearance: none;
}

/* Accent bar along the top edge. */
.core-summary-card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    display: block;
    height: 3px;
    border-radius: 0;
    background: var(--summary-accent, var(--ds-primary));
}

/* UX-378: only a card that filters the grid (a <button>, .is-clickable) lifts and shows the hand; a plain
   KPI card used to lift too and then did nothing when clicked. */
.core-summary-card.is-clickable {
    cursor: pointer;
}

.core-summary-card.is-clickable:hover {
    translate: 0 -2px;
    box-shadow: var(--ds-shadow);
}

.core-summary-card.is-clickable:focus-visible {
    outline: 2px solid var(--core-primary);
    outline-offset: 2px;
}

/* کارتِ فعال باید از یک نگاه پیدا باشد، چون تنها نشانهٔ اینکه جدولِ پایین فیلتر شده همین است.
   Out-specifies the base card rule above; no !important needed since the cascade layers (UX-361). */
.core-summary-card.is-active,
.core-summary-card.is-active:hover {
    border-color: var(--core-primary);
    box-shadow: 0 0 0 2px var(--core-primary) inset;
}

/*
   Variants (UX-352): accent = the top bar (a fill), soft = the icon well, ink = the number and the icon.
   Ink is always the *-strong text token, so the figure stays ≥ 4.5:1 — the fills as text measured
   success 3.30, warning 2.15 and the old orange secondary 3.39 on white. Orange is the brand only:
   is-warning is amber, and is-secondary (every «inactive / archived» card) is neutral grey.
*/
.core-summary-card.is-primary { --summary-accent: var(--ds-primary); --summary-soft: var(--ds-primary-soft); --summary-ink: var(--ds-primary-strong); }
.core-summary-card.is-success { --summary-accent: var(--ds-success); --summary-soft: var(--ds-success-soft); --summary-ink: var(--ds-success-strong); }
.core-summary-card.is-info { --summary-accent: var(--ds-info); --summary-soft: var(--ds-info-soft); --summary-ink: var(--ds-info-strong); }
.core-summary-card.is-warning { --summary-accent: var(--ds-warning); --summary-soft: var(--ds-warning-soft); --summary-ink: var(--ds-warning-strong); }
.core-summary-card.is-error { --summary-accent: var(--ds-error); --summary-soft: var(--ds-error-soft); --summary-ink: var(--ds-error-strong); }
.core-summary-card:is(.is-secondary, .is-neutral) { --summary-accent: var(--ds-neutral); --summary-soft: var(--ds-neutral-soft); --summary-ink: var(--ds-neutral-strong); }

.core-summary-copy .mud-typography-body2,
.core-summary-copy .mud-typography-h4,
.core-summary-copy .mud-typography-caption {
    width: 100%;
    text-align: start;
}

.core-summary-copy .mud-typography-body2 {
    color: var(--ds-text-3);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
}

.core-summary-copy .mud-typography-h4 {
    margin-top: 0;
    color: var(--summary-ink, var(--ds-primary-strong));
    font-size: var(--ds-fs-xl);
    font-weight: var(--ds-fw-bold);
    line-height: 1.1;
}

.core-summary-copy .mud-typography-caption {
    color: var(--ds-faint);
    font-size: var(--ds-fs-xs);
}

/* UX-374: the flex basis is the width in a row — it was 44px against width/height 34px, so the avatar
   rendered ~44×34. Basis, width and height now agree. */
.core-summary-icon {
    flex: 0 0 34px;
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: 13px;
    background: var(--summary-soft, var(--ds-primary-soft));
    color: var(--summary-ink, var(--ds-primary-strong));
    box-shadow: none;
}

/* KPI row gutters. */
.core-summary-grid {
    margin: 0 -6px;
}

/* (UX-379: no staggered entrance for the KPI row any more — the cards show with the data.) */
.core-summary-grid > .mud-grid-item {
    padding: 6px;
}

.core-filter-card {
    padding: 12px 14px;
}

/* (UX-363: the filter card's own 38px field height is gone — every field is --ds-control-h, 40px, so a filter
   bar and a form no longer differ by 8px, and the !important that held 38px against the 46px rule went with it.) */

.core-filter-card .core-field-label {
    font-size: var(--ds-fs-xs);
    line-height: 1.3;
}

.core-filter-card .core-card-subtitle {
    display: none;
}

.core-card-heading {
    min-height: 0;
    margin: 0 0 2px;
    padding: 0 0 8px;
    border-bottom: 1px solid var(--ds-border-soft);
}

/* سرصفحه‌ی کارت فیلتر یک <button> واقعی است تا با کلید هم کار کند؛ این قواعد ظاهر دکمه‌ای
   مرورگر را پاک می‌کنند و همان چیدمان سرصفحه‌ی کارت را نگه می‌دارند. */
/* :where - zero specificity, so .core-card-heading (margin, padding, divider) on the same button wins, as it
   used to through !important. */
:where(.core-filter-toggle) {
    width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: start;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.core-filter-toggle-copy {
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
}

.core-filter-toggle-icons {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 2px;
}

.core-filter-toggle-arrow {
    color: var(--ds-text-3);
    transition: color var(--ds-dur-fast) var(--ds-ease);
}

.core-filter-toggle:hover .core-filter-toggle-arrow {
    color: var(--ds-primary);
}

.core-filter-toggle:focus-visible {
    outline: 2px solid var(--ds-primary);
    outline-offset: 2px;
    border-radius: 10px;
    box-shadow: none;
}

/* جمع‌شده: خط جداکننده و فاصله‌ی زیر سرصفحه بی‌معنا می‌شوند چون چیزی زیرش نمانده.
   UX-361: wins over .core-card-heading on specificity; the scoped page rules it once had to beat are gone. */
.core-filter-card.is-collapsed .core-card-heading {
    margin: 0;
    padding: 0;
    border-bottom: 0;
}

.core-card-title {
    color: var(--ds-text);
    font-size: var(--ds-fs-md);
    font-weight: var(--ds-fw-bold);
}

.core-card-subtitle {
    margin-top: 2px;
    color: var(--ds-faint);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
    line-height: 1.6;
}

.core-field {
    width: 100%;
    gap: 7px;
    direction: inherit;
}

/* Labels medium (500), typed values regular (400) — UX-363. */
.core-field-label {
    width: 100%;
    min-height: 18px;
    padding-inline: 3px;
    color: var(--ds-text-2);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
    line-height: 1.45;
    text-align: start;
}

/* آیکونِ «اطلاعات» کنارِ برچسب، با جزئیات در تولتیپ (UX-149). */
.core-label-info {
    margin-inline-start: 4px;
    vertical-align: middle;
    color: var(--ds-text-2);
    cursor: help;
}

/* فهرستِ خالیِ autocomplete: به‌جای پاپ‌آپِ خالی، «نتیجه‌ای پیدا نشد» (UX-139). */
.core-lookup-empty {
    padding: 10px 14px;
    color: var(--ds-text-2);
}

/* زیرعنوانِ دیالوگ: روی کدام سند کار می‌کند (UX-137). */
.core-dialog-subject {
    display: block;
    color: var(--ds-text-2);
}

.core-dialog-subject-label {
    margin-inline-end: 4px;
}

/* نشانِ اجباری: یک شکل و قرمز، نه ستارهٔ خاکستریِ گم در برچسبِ پررنگ (UX-115). */
.core-required-mark {
    margin-inline-start: 3px;
    color: var(--mud-palette-error);
    font-weight: var(--ds-fw-bold);
}

/* ردیفِ جدولِ دیالوگ که ورودی‌اش مشکل دارد (UX-112/119). !important: over the selected-row tint (UX-361). */
.core-row-invalid > td {
    background: color-mix(in srgb, var(--mud-palette-error) 8%, transparent) !important;
}

.core-dialog-table-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 4px 0;
}

.core-input,
.core-input .mud-input-control,
.core-input .mud-input-control-input-container,
.core-input .mud-input,
.core-input .mud-select,
.core-input input,
.core-input textarea {
    width: 100%;
    direction: inherit;
    text-align: start;
}

/* UX-356: radius 11 and a surface fill everywhere (was page-only in app-ui.css; inputs in a dialog section
   showed the section's inset grey through them). Disabled/readonly grey further down still wins. */
.core-input .mud-input,
.core-input .mud-select {
    border-radius: 11px;
    background: var(--ds-surface);
}

.core-input .mud-input-outlined-border {
    border-color: var(--ds-border-strong);
    border-radius: 11px;
    transition: border-color var(--ds-dur-fast) var(--ds-ease),
                box-shadow var(--ds-dur-fast) var(--ds-ease);
}

.core-input:hover .mud-input-outlined-border {
    border-color: var(--core-primary);
}

.core-input .mud-input.mud-input-outlined:focus-within .mud-input-outlined-border {
    border-color: var(--core-primary);
    border-width: 1.5px;
    box-shadow: 0 0 0 3px var(--ds-primary-soft);
}


.core-input .mud-input-slot,
.core-input .mud-select-input,
.core-input input,
.core-input textarea {
    color: var(--ds-text);
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-regular);
}

.core-input input::placeholder,
.core-input textarea::placeholder {
    color: var(--ds-faint);
    opacity: 1;
}

/*
   National id, code, e-mail, phone, URL: typed and shown left-to-right (UX-344); before, these fields were
   typed RTL and the neutral characters moved («+98 912…» showed as «98 912…+»). `:root` and the class
   inside :is() lift this to (0,3,0) so it beats app.css's `[dir="rtl"]` input alignment rules whatever
   order the sheets load in. Only the <input>/<textarea> turns:
   the label, helper text and adornments keep the page direction and position. The unused
   `.uni-ltr-field` / `.uni-ltr-value` duplicates of this rule were removed.
*/
:root .core-ltr-input :is(input, textarea, .mud-input-slot) {
    direction: ltr;
    text-align: left;
}

/* ----------------------------------------------------------------------------------------------
   کلیدی که فقط از روی خودِ کلید عوض می‌شود.

   MudSwitch کل عنصر <label> — یعنی کلید به‌همراه متنش — را کلیک‌پذیر می‌کند؛ رفتار استاندارد
   HTML است. ولی در فرم‌هایی که متنِ کنار کلید بلند است، کاربر روی متن کلیک می‌کند و بی‌آنکه
   بخواهد مقدار را عوض می‌کند.

   به‌جای هدف‌گرفتن کلاسِ متن — که نسخه‌به‌نسخهٔ MudBlazor عوض می‌شود — کلِ برچسب از کلیک
   بی‌بهره می‌شود و فقط خانهٔ خودِ کلید دوباره فعال می‌گردد. صفحه‌کلید دست‌نخورده می‌ماند،
   چون pointer-events روی فوکوس و Space اثری ندارد.
   ---------------------------------------------------------------------------------------------- */
.core-switch-control-only {
    pointer-events: none;
    cursor: default;
}

.core-switch-control-only .mud-switch-span {
    pointer-events: auto;
    cursor: pointer;
}

/* ----------------------------------------------------------------------------------------------
   فیلدی که نمی‌شود عوضش کرد، باید همان‌طور هم دیده شود.

   MudBlazor فیلد غیرفعال را فقط کمی کم‌رنگ می‌کند و فیلدِ فقط‌خواندنی را اصلاً؛ نتیجه این بود که
   کاربر روی «مقدار ارسالی» کلیک می‌کرد و منتظر می‌ماند چیزی تایپ شود. اینجا هر دو حالت یک زمینهٔ
   طوسی و مکان‌نمای «ممنوع» می‌گیرند تا از روی ظاهر معلوم باشد.

   هاور هم خنثی می‌شود: قاب آبی روی فیلدی که ورودی نمی‌پذیرد، وعدهٔ بی‌عمل است.
   ---------------------------------------------------------------------------------------------- */
/* سلکت از این قاعده بیرون است: ورودی داخلی‌اش همیشه readonly است چون از فهرست انتخاب
   می‌شود و تایپ نمی‌شود. سلکت فقط وقتی طوسی می‌شود که واقعاً غیرفعال باشد — وگرنه فیلدِ
   اجباریِ «دلیل رد» هم طوسی می‌ماند و کاربر فکر می‌کند نمی‌شود پُرش کرد. */
.core-input .mud-input.mud-disabled,
.core-input .mud-input:not(.mud-select-input):has(input[readonly]),
.core-input .mud-input:not(.mud-select-input):has(textarea[readonly]) {
    background: var(--ds-surface-2);
    cursor: not-allowed;
}

.core-input .mud-input.mud-disabled .mud-input-outlined-border,
.core-input .mud-input:not(.mud-select-input):has(input[readonly]) .mud-input-outlined-border,
.core-input .mud-input:not(.mud-select-input):has(textarea[readonly]) .mud-input-outlined-border {
    border-color: var(--ds-border-soft);
    border-style: dashed;
}

.core-input:hover .mud-input.mud-disabled .mud-input-outlined-border,
.core-input:hover .mud-input:not(.mud-select-input):has(input[readonly]) .mud-input-outlined-border,
.core-input:hover .mud-input:not(.mud-select-input):has(textarea[readonly]) .mud-input-outlined-border {
    border-color: var(--ds-border-soft);
}

/* فیلدِ خطادار قرمز می‌ماند — عادی، زیرِ ماوس، در فوکوس و حتی فقط‌خواندنی (فیلدِ انتخابِ راننده). قاعده‌های
   بالا رنگِ خطِ دور را با !important ثابت می‌کردند و قاعدهٔ خودِ MudBlazor برای خطا هرگز دیده نمی‌شد
   (UX-117). Since UX-361 MudBlazor's own error border (!important, lowest layer) wins in every state anyway. */
.core-input .mud-input.mud-input-outlined.mud-input-error .mud-input-outlined-border,
.core-input:hover .mud-input.mud-input-outlined.mud-input-error .mud-input-outlined-border,
.core-input:hover .mud-input.mud-input-outlined.mud-input-error:not(.mud-select-input):has(input[readonly]) .mud-input-outlined-border,
.core-input .mud-input.mud-input-outlined.mud-input-error:focus-within .mud-input-outlined-border {
    border-color: var(--mud-palette-error);
}

.core-input .mud-input.mud-input-outlined.mud-input-error:focus-within .mud-input-outlined-border {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mud-palette-error) 18%, transparent);
}

.core-input .mud-input.mud-disabled input,
.core-input .mud-input.mud-disabled textarea,
.core-input .mud-input.mud-disabled .mud-input-slot,
.core-input .mud-input.mud-disabled .mud-select-input,
.core-input .mud-input:not(.mud-select-input) input[readonly],
.core-input .mud-input:not(.mud-select-input) textarea[readonly] {
    color: var(--ds-text-3);
    cursor: not-allowed;
}

.core-filter-footer {
    min-height: 44px;
    padding-top: 12px;
    border-top: 1px solid var(--ds-border-soft);
    gap: 14px;
    flex-wrap: wrap;
}

.core-filter-actions {
    flex-wrap: wrap;
}

.core-grid-card {
    overflow: hidden;
}

.core-data-grid {
    width: 100%;
    direction: inherit;
}

.core-data-grid .mud-table-toolbar {
    min-height: 56px;
    padding: 10px 16px;
    gap: 12px;
    border-bottom: 1px solid var(--ds-border-soft);
    background: var(--ds-surface);
}

/*
   The grid is a fixed box that scrolls inside itself — the page does not grow with
   the data, the way D365 tables behave.

   Four variables on :root (top of this file) are the single source of truth for that box:
   --core-grid-rows, --core-grid-head-h, --core-grid-row-h and --core-grid-hscroll. The head-
   and body-cell rules below read the same variables, so the container's height and the rows
   it is sized to can never drift apart — on a page and in a dialog alike (UX-355: the cell
   rules used to carry literal 54px/58px heights that only app-ui.css's page-scoped rules
   replaced, so a grid in a dialog showed ~8.5 rows and a clipped one in a box sized for ten).
   Override --core-grid-rows on a single grid to give it a taller or shorter box.

   max-height, not height: a grid with three rows stays three rows tall instead of
   padding itself out with empty space.

   These are OUTER heights — they include each row's 1px bottom border, because that
   border is what the container has to fit. The cell rules subtract it again. Getting
   this wrong is how a box "sized for ten rows" ends up showing nine and a half.

   --core-grid-hscroll is room for the horizontal scrollbar. These grids are wider than the
   screen, so the scrollbar sits inside the same box and eats from the row area; without it the
   box sized for ten rows shows nine and a bit. A grid with no sideways overflow shows a sliver
   of the next row instead, which reads as "there is more below".
*/
.core-data-grid .mud-table-container {
    width: 100%;
    max-height: calc(var(--core-grid-head-h) + (var(--core-grid-row-h) * var(--core-grid-rows)) + var(--core-grid-hscroll));
    overflow: auto;
    scrollbar-width: thin !important;
    scrollbar-color: var(--ds-border-strong) transparent !important;
}

.core-data-grid .mud-table-container::-webkit-scrollbar {
    width: 8px !important;
    height: 8px !important;
}

.core-data-grid .mud-table-container::-webkit-scrollbar-thumb {
    border-radius: 999px !important;
    background: var(--ds-border-strong) !important;
}

/*
   Ten rows is the target, not a promise the window can always keep. A list page spends
   roughly 220px above the grid on the KPI cards and the filter card, plus the toolbar and
   the pager below it; on a 768px-tall laptop that leaves room for about seven rows. Holding
   ten there would push the page into scrolling, which is the thing this box exists to stop.
   So the row count steps down with the viewport instead.
*/
@media (max-height: 900px) {
    :root {
        --core-grid-rows: 8;
    }
}

@media (max-height: 800px) {
    :root {
        --core-grid-rows: 7;
    }
}

@media (max-height: 700px) {
    :root {
        --core-grid-rows: 5;
    }
}

/*
   A row is only as short as the tallest control in it, and MudBlazor's checkbox and
   row-action menu are 42px each — with the old padding that made every row 63px, so a
   box sized for ten rows actually showed eight and a half. These bring the controls
   under the row height so the count is honest.

   Coarse pointers get the full-size controls back below: on a touch screen a 32px
   target is too small to hit, and there the taller row is the right trade.
*/
.core-data-grid .mud-table-cell .mud-checkbox .mud-button-root,
.core-data-grid .mud-table-cell .mud-menu .mud-icon-button {
    width: 32px;
    height: 32px;
    min-width: 0;
    min-height: 0;
    padding: 0;
}

/* The header's sort and filter buttons do the same thing to the header row. */
.core-data-grid .mud-table-head .mud-table-cell .mud-icon-button {
    width: 26px;
    height: 26px;
    min-width: 0;
    min-height: 0;
    padding: 0;
}

.core-data-grid .mud-table-cell .mud-checkbox {
    margin: 0;
}

@media (pointer: coarse) {
    :root {
        --core-grid-row-h: 62px;
    }

    .core-data-grid .mud-table-cell .mud-checkbox .mud-button-root,
    .core-data-grid .mud-table-cell .mud-menu .mud-icon-button {
        width: 42px;
        height: 42px;
    }
}

/* جدول همیشه کلِ عرضِ کارت را می‌گیرد و فقط وقتی ستون‌ها واقعاً جا نمی‌شوند اسکرول افقی می‌خورد؛ حداقلِ ثابتِ
   ۱۱۸۰ پیکسل جدولِ سه‌ستونی را هم روی لپ‌تاپ اسکرولی می‌کرد (UX-069). */
.core-data-grid .mud-table-root {
    width: 100%;
    table-layout: auto;
}

/*
   Cell heights come from the same variables as the container (minus the 1px bottom border) — never a
   literal, or the box and its rows drift apart (UX-355).

   Sticky table header: the whole top row stays put while the rows scroll under it. The scroll happens
   inside .mud-table-container, so that box is the sticky ancestor and the cells only need top: 0. It is
   the cells that stick, not the row — position: sticky does nothing on a <tr> in most engines, which is
   why this pins <th>. The separating line survives the scroll because MudBlazor never sets
   border-collapse on .mud-table-root (border-spacing: 0, default "separate"), so the bottom border
   belongs to the cell and travels with it. z-index has to clear the pinned checkbox column (2 on body
   cells), or a scrolled row's checkbox would ride over the header; the corner cell, pinned on both axes,
   takes 5. Sticky is also a containing block, so the column-resize handle needs no position: relative —
   a relative here once quietly unpinned the header (UX-377: these properties used to be a second rule
   for the same selector far down the file).
*/
.core-data-grid .mud-table-head .mud-table-cell {
    position: sticky;
    top: 0;
    z-index: 4;
    height: calc(var(--core-grid-head-h) - 1px);
    padding: 4px 12px;
    background: var(--ds-surface-2) !important;
    color: var(--ds-text-3);
    /* ۱۲ پیکسل؛ ۱۰٫۵ با وزیر برای سرستون خوانا نبود (UX-070). */
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
    border-bottom: 1px solid var(--ds-border);
    white-space: nowrap;
    vertical-align: middle;
}

.core-data-grid .mud-table-body .mud-table-cell {
    height: calc(var(--core-grid-row-h) - 1px);
    padding: 4px 12px;
    background: transparent;
    color: var(--ds-text-2);
    /* ۱۳ پیکسل برای شیفتِ کاریِ طولانی؛ ۱۱٫۵ ریز بود (UX-070). */
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-regular);
    border-bottom: 1px solid var(--ds-border-soft);
    white-space: nowrap;
    vertical-align: middle;
    /* متنِ آزادِ بلند (خطای سرویس، متنِ اعلان، نشانی، دلیل) دیگر ستون را صدها پیکسل پهن نمی‌کند؛ متنِ کامل
       در تولتیپ (theme.js) — UX-069. */
    max-width: 28rem;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: background-color var(--ds-dur-fast) var(--ds-ease);
}

.core-data-grid .mud-table-row-selected .mud-table-cell {
    background: var(--ds-surface-selected) !important;
}

.core-data-grid .mud-table-pagination-toolbar {
    min-height: 48px;
    padding: 10px 18px;
    direction: inherit;
    border-top: 1px solid var(--core-border-soft);
    background: var(--ds-surface);
    color: var(--ds-text-3);
}

.core-data-grid .mud-table-pagination-actions {
    direction: inherit;
}

.core-data-grid .mud-table-sort-label {
    justify-content: flex-start;
    gap: 4px;
}

.core-grid-header-right,
.core-grid-cell-right {
    text-align: start;
}

.core-grid-header-left,
.core-grid-cell-left {
    direction: ltr;
    text-align: left;
}

.core-grid-header-center,
.core-grid-cell-center {
    text-align: center;
}

/*
   Latin values (codes, numbers, dates, URLs) inside RTL text — everywhere (UX-359).

   The class used to be honoured only inside `.core-table` and `.core-data-grid`, so the same
   «PO-1403/12» in a detail page's hero title, a dialog subject or a hero subtitle was laid out
   by the bidi algorithm as RTL text and its segments could appear in the wrong order.
   Isolation, not just direction, is what fixes that.

   direction: ltr on a BLOCK (a MudText <p>/<h2>) would also flip its `start` alignment to the
   left, so outside table cells the block keeps the alignment of the document direction it sits in
   — the value stays where the RTL layout put it, only its characters run left-to-right. :dir()
   reads the dir attribute (the page's direction), not the CSS direction set here, which is exactly
   the "start" the element had before. (text-align: match-parent would say this in one line, but
   Chromium does not implement it.) Table cells, and anything inside them, keep the alignment they
   always had (a td.ltr-value is left-aligned).

   `:root` lifts the direction rule to (0,2,0): component classes on the same element that write
   `direction: inherit` (.core-hero-subtitle, …) would otherwise win on source order.
*/
:root .ltr-value {
    direction: ltr;
    unicode-bidi: isolate;
}

.ltr-value:not(td, th, :is(td, th) *):dir(rtl) {
    text-align: right;
}

.ltr-value:not(td, th, :is(td, th) *):dir(ltr) {
    text-align: left;
}

/*
   The row-selector column stays put while the grid scrolls sideways.

   These grids are wider than the viewport — `.mud-table-root` carries a min-width and the
   container scrolls — so the first column used to travel off screen with everything else:
   the moment you scrolled right to read the value you were deciding on, the checkbox you
   wanted to tick was gone, and you had to scroll back to select the row.

   Keyed on `:first-child:has(.mud-checkbox)` rather than a class added at each call site,
   because MudBlazor's SelectColumn renders as an ordinary `mud-table-cell` with no class of
   its own — there is nothing else to aim at. The `:has()` test is what keeps this honest:
   a grid with no selector column keeps its first column scrolling like any other.

   Body cells are transparent at rest, so the pinned one needs a background of its own or the
   columns sliding beneath would show through it. The row-hover and selected-row rules further
   down this file out-specify the background below and still repaint it — deliberately, since
   otherwise the pinned cell would be the one cell in the row that ignores hover.
*/
.core-data-grid .mud-table-head th:first-child:has(.mud-checkbox),
.core-data-grid .mud-table-body td:first-child:has(.mud-checkbox) {
    position: sticky;
    inset-inline-start: 0;
    border-inline-end: 1px solid var(--ds-border-soft);
    z-index: 2;
}

/*
   The corner cell: pinned to the start edge by the rule above and to the top by the sticky
   header rule further down this file, so it has to clear both the body cells sliding under
   it (2) and the rest of the header sliding past it sideways (4).
*/
.core-data-grid .mud-table-head th:first-child:has(.mud-checkbox) {
    z-index: 5;
}

/*
   The pinned cell needs an opaque background of its own: the body-cell rule above sets every
   cell to `background: transparent`, so without this the text of the columns sliding underneath
   would read straight through the checkbox.

   It out-specifies that transparent rule (five classes vs three) and still follows row hover,
   column hover and selection, because those rules further down are !important — so the pinned
   cell is never the one cell in the row that ignores hover.
*/
.core-data-grid .mud-table-body .mud-table-cell:first-child:has(.mud-checkbox) {
    background: var(--ds-surface);
}

.core-grid-primary-text {
    color: var(--ds-text);
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-medium);
}

.core-grid-secondary-text {
    color: var(--ds-faint);
    font-size: var(--ds-fs-xs);
}

/* Radius (11px) and font size come from the surface button rule above. The second selector ties with that rule
   and comes later, so the compact 28px height wins on pages and in dialogs too. */
.core-code-button,
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-code-button {
    min-width: 0;
    min-height: 28px;
    padding: 3px 7px;
    background: transparent;
    color: var(--ds-primary-strong);
    font-weight: var(--ds-fw-medium);
}

.core-neutral-chip {
    background: var(--ds-surface-2);
    color: var(--ds-text-3);
    font-weight: var(--ds-fw-medium);
}

.core-grid-state {
    min-height: 310px;
    width: 100%;
    color: var(--ds-muted);
}

.core-empty-title {
    color: var(--ds-text-2);
    font-weight: var(--ds-fw-bold);
}

/* DataGrid menus and filters */
.mud-popover,
.mud-menu,
.mud-list,
.mud-data-grid-filter,
.mud-picker-container {
    direction: inherit;
}

.mud-data-grid-filter .mud-input-control,
.mud-data-grid-filter input,
.mud-data-grid-filter .mud-select-input {
    direction: inherit;
    text-align: start;
}

/* Dialogs — final values (UX-356: radius, padding and fills used to be overridden again by
   `body .core-form-dialog …` rules in app-ui.css). */
.core-form-dialog,
.core-confirm-dialog {
    direction: inherit;
    border: 1px solid var(--ds-border);
    border-radius: 18px;
    background: var(--ds-surface);
    box-shadow: var(--ds-shadow-lg);
    overflow: hidden;
    animation: core-pop-in var(--ds-dur) var(--ds-ease-out);
}

.core-form-dialog .mud-dialog-title,
.core-confirm-dialog .mud-dialog-title {
    padding: 18px 22px;
    border-bottom: 1px solid var(--ds-border-soft);
    background: var(--ds-surface);
}

.core-form-dialog .mud-dialog-content,
.core-confirm-dialog .mud-dialog-content {
    direction: inherit;
    text-align: start;
    max-height: min(70vh, 720px);
    overflow-y: auto;
    padding: 20px 22px;
    background: var(--ds-surface);
}

.core-form-dialog .mud-dialog-actions,
.core-confirm-dialog .mud-dialog-actions {
    padding: 15px 22px;
    border-top: 1px solid var(--ds-border-soft);
    background: var(--ds-surface-2);
}

/*
    دیالوگی که چند حکم دارد، دکمه‌هایش در یک ردیف جا نمی‌شوند. به‌جای بزرگ‌شدن و شکستنِ عنوان
    داخل خودِ دکمه، ردیف مرتب می‌شکند و دکمه‌ها هم‌قد می‌مانند.
    نوار به پایینِ دیالوگ می‌چسبد تا در فرمِ بلند همیشه دیده شود.
*/
.core-form-dialog .mud-dialog-actions {
    position: sticky;
    bottom: 0;
    z-index: 2;
    flex-wrap: wrap;
    gap: 8px;
    box-shadow: var(--ds-shadow-up); /* UX-367: theme token (the fixed light rgba vanished on the dark dialog) */
}

.core-form-dialog .mud-dialog-actions > .mud-button-root {
    margin: 0;
    white-space: nowrap;
}

.core-dialog-titlebar {
    width: 100%;
}

.core-dialog-title-icon {
    width: 44px;
    height: 44px;
}

.core-dialog-title {
    color: var(--core-text);
    font-weight: var(--ds-fw-bold);
}

.core-dialog-subtitle,
.core-dialog-section-subtitle {
    color: var(--ds-faint);
    line-height: 1.7;
}

.core-dialog-form {
    width: 100%;
}

.core-dialog-readonly-fieldset {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.core-dialog-section {
    padding: 15px;
    border: 1px solid var(--ds-border);
    border-radius: 13px;
    background: var(--ds-surface-inset);
}

.core-dialog-section-header {
    margin-bottom: 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--core-border-soft);
}

.core-dialog-section-title {
    color: var(--ds-text);
    font-weight: var(--ds-fw-bold);
}

/* UniToggle (Field variant): switch pinned to the far end of the row, title/description
   on the other. A flex row is direction-agnostic by construction — flipping to RTL
   reverses start/end on its own, no ltr/rtl override needed. */
.core-switch-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    height: 100%;
    min-height: 78px;
    padding: 12px 14px;
    border: 1px solid var(--ds-border);
    border-radius: 12px;
    background: var(--ds-primary-softer);
    direction: inherit;
}

/*
   A plain bordered container sharing the switch card's box treatment but none of its layout.
   .core-switch-card is a flex row because a toggle sits opposite its label; a card that stacks block
   children - the workflow step editor, for instance - needs the box without the row, and reusing the
   switch class for that silently laid its children side by side.
*/
.core-step-card {
    height: 100%;
    padding: 12px 14px;
    border: 1px solid var(--ds-border);
    border-radius: 12px;
    background: var(--ds-primary-softer);
}

.core-switch-title {
    color: var(--ds-text-2);
    font-weight: var(--ds-fw-medium);
}

.core-dialog-actions {
    width: 100%;
}

.core-dialog-actions .mud-button-root:not(.mud-switch-base) {
    min-height: var(--ds-control-h);
    border-radius: 11px;
    font-weight: var(--ds-fw-medium);
}

.core-button-progress {
    margin-inline-start: 8px;
}

.core-confirm-alert {
    margin-top: 8px;
    line-height: 2;
}

/* Details */
.core-details-loading {
    min-height: 320px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.core-hero-card {
    padding: 20px;
    overflow: hidden;
}

.core-hero-card::before,
.core-hero-card::after {
    display: none;
}

.core-hero-content {
    gap: 18px;
    flex-wrap: wrap;
}

.core-hero-icon {
    width: 58px;
    height: 58px;
    border-radius: 15px;
    background: var(--ds-primary-soft);
    color: var(--ds-primary);
}

/* UX-352: was the brand orange (--core-accent) outside .core-page; a kicker is a label, not the brand. */
.core-hero-kicker {
    color: var(--ds-faint);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
    letter-spacing: 0; /* UX-348: Persian kicker; Typo.overline's tracking pulled the letters apart */
}

.core-hero-title {
    color: var(--ds-text);
    font-size: var(--ds-fs-xl);
    font-weight: var(--ds-fw-bold);
}

.core-hero-subtitle {
    color: var(--ds-muted);
    direction: inherit;
    text-align: start;
}

.core-hero-badges {
    flex-wrap: wrap;
}

.core-details-card,
.core-side-card {
    padding: 18px;
    overflow: hidden;
}

/*
    کارت گرید در صفحه‌های جزئیات میزبان بخش‌هایی مثل «ردیف‌های لود» است، نه فقط گرید داده.
    بی این فاصله، عنوان و توضیح بخش به لبه و بالای کارت می‌چسبید در حالی که جدولِ زیرش از
    فاصله‌ی سلول‌هایش تورفتگی داشت. کارتی که خودِ گرید داده را در بر دارد با کلاس flush
    استثنا می‌شود.
*/
.core-grid-card:not(.core-grid-card-flush) {
    padding: 18px;
}

.core-details-section-header {
    margin-bottom: 14px;
}

.core-info-grid {
    margin-top: 2px;
}

/*
   Fact cards in detail views deliberately use a stable two-column rhythm. Individual pages
   historically chose md=3, md=4 or md=6 for the same type of data, which made adjacent
   fields look unrelated. core-info-grid is the shared, explicit marker for these fields.
   همه‌جا دوستونه — صفحه، دیالوگ و کارت‌های مشترک (UX-173، تصمیم مالک). mobile.css's narrow-screen
   100% rule is in a later layer and wins where it applies (UX-361).
*/
.core-info-grid > .mud-grid-item {
    flex-basis: 50%;
    max-width: 50%;
}

.core-info-box {
    min-height: 76px;
    padding: 12px 13px;
    border: 1px solid var(--ds-border);
    border-radius: 12px;
    background: var(--ds-surface-inset);
    transition: border-color var(--ds-dur-fast) var(--ds-ease),
                background-color var(--ds-dur-fast) var(--ds-ease);
}

.core-info-copy {
    min-width: 0;
    text-align: start;
}

/* فقط جعبهٔ پیوند‌دار/قابلِ کلیک زیرِ ماوس رنگ می‌گیرد؛ جعبهٔ ثابت ثابت می‌ماند (UX-189).
   (On pages this used to tie with app-ui.css's `body .core-page.core-page .core-info-box` and lose on
   load order, so the hover only ever showed in dialogs; it now wins everywhere — UX-356.) */
.core-info-box.is-interactive:hover {
    border-color: var(--core-primary);
    background: var(--ds-primary-soft);
}

.core-info-open {
    font-size: .95em;
    margin-inline-start: 4px;
    vertical-align: -2px;
    opacity: .7;
}

.core-info-label {
    color: var(--ds-text-2);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
    line-height: 1.5;
}

.core-info-value {
    color: var(--ds-text);
    font-size: var(--ds-fs-md);
    font-weight: var(--ds-fw-medium);
    line-height: 1.7;
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.core-info-icon {
    flex: 0 0 auto;
}

/* کلیدِ داخل باکسِ اطلاعات. MudSwitch حاشیهٔ خودش را دارد و بدون این، باکس از بقیهٔ شبکه
   بلندتر می‌شد و ردیف هدر ناهموار می‌ماند. برچسبش هم‌وزنِ مقدارِ بقیهٔ باکس‌ها می‌شود. */
.core-info-switch {
    /* UX-376: logical, not `margin: -2px 0 0 -8px` — a physical left margin pulled the switch the wrong way
       in RTL and off the edge the neighbouring boxes align to. */
    margin-block: -2px 0;
    margin-inline: -8px 0;
}

/* کارتِ لوگو در صفحهٔ شرکت. ارتفاعِ ثابت ندارد چون دکمه‌هایش از یک خطِ متن بلندترند. */
.core-logo-box {
    min-height: 96px;
}

.core-logo-preview {
    width: 56px;
    height: 56px;
    object-fit: contain;
    border-radius: 10px;
    border: 1px solid var(--ds-border);
    background: var(--ds-surface);
    flex: 0 0 auto;
}

/* لوگوی شرکت در هدر. اندازه‌اش با نشانِ پیش‌فرضِ MudIcon یکی است تا جابه‌جا شدنِ شرکت،
   ارتفاع کارت را نپراند؛ و contain است نه cover، چون لوگو نباید بریده شود. */
.uni-company-logo {
    width: 22px;
    height: 22px;
    object-fit: contain;
    border-radius: 5px;
    flex: 0 0 auto;
}

.core-info-switch .mud-switch-label {
    color: var(--ds-text);
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-medium);
}

.core-side-actions {
    margin-top: 14px;
}

/* :where keeps this below the surface-button rule (11px radius) on pages and in dialogs, where that rule used
   to win through !important; elsewhere it still applies. */
:where(.core-side-actions) .mud-button-root:not(.mud-switch-base) {
    min-height: var(--ds-control-h);
    border-radius: 10px;
    font-weight: var(--ds-fw-medium);
}

@media screen and (max-width: 959.95px) {
    .core-page-actions {
        width: 100%;
    }

    .core-page-actions .mud-button-root:not(.mud-switch-base) {
        flex: 1;
    }
}

/* (UX-356: the card radius/padding and dialog-content padding this block used to set are gone — the
   mobile.css's ≤959.95px overrides, a later layer, set the small-screen values.) */
@media screen and (max-width: 599.95px) {
    .core-grid-card:not(.core-grid-card-flush) {
        padding: 14px;
    }

    .core-filter-actions {
        width: 100%;
    }

    .core-filter-actions .mud-button-root:not(.mud-switch-base) {
        flex: 1;
    }
}

/* ===== Reviewed enterprise refinements =====
   (UX-377: the summary-card, field, field-label, grid-container and table-root values this block used to
   restate are merged into their first rules above; only rules with no earlier twin remain here.) */
.core-page > .mud-stack-root {
    width: 100%;
    gap: 12px;
}

/* محتوای <button> به‌طور پیش‌فرض اندازهٔ خودش را می‌گیرد (shrink-to-fit)، پس در کارتِ قابل‌کلیک ردیفِ
   space-between جمع می‌شد و آیکن کنار عدد می‌چسبید. ردیف باید تمام عرض کارت را بگیرد تا مثل کارتِ ساده
   متن یک طرف و آیکن طرف دیگر باشد. */
button.core-summary-card > .mud-stack-root {
    width: 100%;
}

.core-filter-card > .mud-stack-root > .mud-grid-root {
    margin-top: 2px;
}

/* Reserve a full 48px touch target for menu-based action columns. */
.core-data-grid .mud-table-body .mud-table-cell.core-grid-cell-center:has(.mud-menu) {
    width: 64px;
    min-width: 64px;
}

.core-data-grid .mud-table-cell-content {
    width: 100%;
    min-width: 0;
}

/* Keep the title, sort state and menu mark in one row, including intrinsic sizing. */
.core-data-grid .column-header {
    display: flex;
    align-items: center;
    gap: 4px;
    width: 100%;
    min-width: max-content;
}

/*
   A column header is never narrower than its own title.

   The title used to be `flex: 0 1 auto; min-width: 0` with `overflow: hidden` and an ellipsis,
   so whenever the header row was tight it gave way and the title was cut — the column stayed
   narrow and the label lost its end. Sizing should work the other way round: the title is part
   of the column's content, so it sets the column's minimum width like any cell value does.

   `flex-shrink: 0` plus `min-width: max-content` makes the title incompressible, which feeds
   its full width into the cell's min-content and therefore into the table's column width. The
   table is auto-layout inside a scrolling container, so columns grow to fit and the grid
   scrolls sideways rather than truncating anything.
*/
.core-data-grid.mud-data-grid .mud-table-cell .column-header .sortable-column-header {
    width: auto;
    flex: 0 0 auto;
    min-width: max-content;
    white-space: nowrap;
}

/* The custom title menu owns filtering; keep native controls available to JS only. */
.core-data-grid .mud-table-head .column-options .filter-button,
.core-data-grid .mud-table-head .column-options .mud-menu,
.core-data-grid .mud-table-head .column-options .sort-direction-icon:not(.mud-direction-asc):not(.mud-direction-desc) {
    display: none;
}

/*
   MudBlazor's grab handle. It only ever appears on hover and duplicates an affordance the
   header already has — the whole header cell is the drag source, so reordering still works
   without it. Dropping it also buys back the width it was reserving next to the title.
*/
.core-data-grid .drag-icon-options {
    display: none;
}

/*
   Everything inside `.column-options` is hidden except the arrow on the one sorted column,
   yet the empty box still claimed ~11px next to every title — enough to push the title past
   the cell edge, since the column is sized from the title alone. Collapse it when it has
   nothing to show.
*/
.core-data-grid .mud-table-head .column-options:not(:has(.sort-direction-icon.mud-direction-asc)):not(:has(.sort-direction-icon.mud-direction-desc)) {
    display: none;
}

/* The menu mark participates in layout so titles cannot run underneath it.
   Auto margin keeps it at the trailing edge in both RTL and LTR; the fixed flex
   basis reserves its width even for narrow or user-resized columns. */
.core-data-grid .mud-table-head .mud-table-cell:has(.sort-direction-icon) .column-header::after,
.core-data-grid .mud-table-head .mud-table-cell:has(.filter-button) .column-header::after {
    content: "";
    position: static;
    flex: 0 0 16px;
    margin-inline-start: auto;
    width: 16px;
    height: 16px;
    background-color: var(--ds-faint);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='black'%3E%3Ccircle cx='12' cy='5' r='2'/%3E%3Ccircle cx='12' cy='12' r='2'/%3E%3Ccircle cx='12' cy='19' r='2'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='black'%3E%3Ccircle cx='12' cy='5' r='2'/%3E%3Ccircle cx='12' cy='12' r='2'/%3E%3Ccircle cx='12' cy='19' r='2'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
}

.core-data-grid .mud-table-head .mud-table-cell[data-core-grid-interactive] {
    cursor: pointer;
}

/* The whole header opens the menu; keep its hover target clear of the resize strip. */
.core-data-grid .mud-table-head .mud-table-cell[data-core-grid-interactive]:hover {
    background: color-mix(in srgb, var(--ds-primary) 10%, var(--ds-surface-2)) !important;
}

/* The menu mark darkens with its cell. */
.core-data-grid .mud-table-head .mud-table-cell[data-core-grid-interactive]:hover .column-header::after {
    background-color: var(--ds-muted);
}

/* Dragging a column edge is not hovering the header; the tint would follow the pointer
   across every column the drag passes over. */
.core-data-grid .mud-table-head .mud-table-cell:has(.core-grid-resizer.is-dragging):hover {
    background: revert;
}

.core-data-grid .mud-table-head .mud-table-cell.core-grid-header-menu-open,
.core-data-grid .mud-table-head .mud-table-cell:has(.filter-button.filtered) {
    background: color-mix(in srgb, var(--ds-primary) 10%, var(--ds-surface-2)) !important;
    color: var(--ds-primary-strong);
}

.core-grid-header-right .column-header .sortable-column-header,
.core-grid-header-right .column-header .mud-table-sort-label,
.core-grid-header-right .mud-table-cell-content,
.core-grid-cell-right .mud-table-cell-content {
    display: flex;
    justify-content: flex-start;
    text-align: start;
}

.core-grid-header-right .column-header {
    justify-content: flex-start;
}

html[dir="ltr"] .core-grid-header-right .column-header {
    direction: ltr;
}

html[dir="rtl"] .core-grid-header-right .column-header {
    direction: rtl;
}

.core-grid-header-left .column-header .sortable-column-header,
.core-grid-header-left .column-header .mud-table-sort-label,
.core-grid-header-left .mud-table-cell-content {
    display: flex;
    text-align: left;
}

html[dir="ltr"] .core-grid-header-left .column-header .sortable-column-header,
html[dir="ltr"] .core-grid-header-left .column-header .mud-table-sort-label,
html[dir="ltr"] .core-grid-header-left .mud-table-cell-content {
    justify-content: flex-start;
}

html[dir="ltr"] .core-grid-header-left .column-header {
    justify-content: flex-start;
}

html[dir="rtl"] .core-grid-header-left .column-header .sortable-column-header,
html[dir="rtl"] .core-grid-header-left .column-header .mud-table-sort-label,
html[dir="rtl"] .core-grid-header-left .mud-table-cell-content {
    justify-content: flex-end;
}

html[dir="rtl"] .core-grid-header-left .column-header {
    justify-content: flex-end;
}

.core-grid-cell-left .mud-table-cell-content {
    display: flex;
    direction: ltr;
    justify-content: flex-start;
    text-align: left;
}

html[dir="ltr"] .core-grid-header-center .column-header {
    direction: ltr;
}

html[dir="rtl"] .core-grid-header-center .column-header {
    direction: rtl;
}

.core-grid-header-center .column-header {
    justify-content: center;
}

.core-grid-header-center .column-header .sortable-column-header,
.core-grid-header-center .column-header .mud-table-sort-label,
.core-grid-header-center .mud-table-cell-content,
.core-grid-cell-center .mud-table-cell-content {
    display: flex;
    justify-content: center;
    text-align: center;
}

.core-grid-header-center .column-header .sortable-column-header {
    flex: 0 1 auto;
}

/* ---------------------------------------------------------------------------
   Row vs. column hover: the row under the cursor should read stronger than
   the column it happens to share, so the primary-tinted tier moves to the
   row and the column keeps only a pass-through tint.

   MudBlazor's own ".mud-table-row:hover" only paints the <tr>; every cell
   already carries its own opaque background (mud-table-cell, or
   ds-surface-selected below), so that <tr> background never showed through
   on its own - the two "row hover" rules just below are what actually make
   the row visible, by repainting each cell directly.

   All of these backgrounds keep !important (UX-361): the pinned checkbox cell
   above out-specifies them, and the head-cell and selected-row backgrounds
   they repaint are !important too. Among the tiers, specificity and then
   source order decide — keep the order.

   The column tier is set by CrudDataGrid.razor.js and only in table layout;
   in MudBlazor's card layout (≤ 960px) cellIndex no longer means "column".
--------------------------------------------------------------------------- */
.core-data-grid .mud-table-head .mud-table-cell.core-grid-column-hover {
    background: color-mix(in srgb, var(--ds-primary) 7%, var(--ds-surface-2)) !important;
}

.core-data-grid .mud-table-body .mud-table-cell.core-grid-column-hover {
    background: color-mix(in srgb, var(--ds-primary) 5%, var(--ds-surface)) !important;
}

.core-data-grid .mud-table-row-selected .mud-table-cell.core-grid-column-hover {
    background: color-mix(in srgb, var(--ds-primary) 9%, var(--ds-surface-selected)) !important;
}

/* Row (horizontal) - the one the cursor is actually on, so the stronger tint. */
.core-data-grid .mud-table-body .mud-table-row:hover .mud-table-cell {
    background: color-mix(in srgb, var(--ds-primary) 13%, var(--ds-surface)) !important;
}

.core-data-grid .mud-table-body .mud-table-row-selected:hover .mud-table-cell {
    background: color-mix(in srgb, var(--ds-primary) 20%, var(--ds-surface-selected)) !important;
}

/* The one cell that is in both the hovered row and the hovered column gets
   its own, stronger tier so it reads as the focused cell instead of just
   whichever of the two rules above happened to lose. */
.core-data-grid .mud-table-body .mud-table-row:hover .mud-table-cell.core-grid-column-hover {
    background: color-mix(in srgb, var(--ds-primary) 18%, var(--ds-surface)) !important;
}

.core-data-grid .mud-table-body .mud-table-row-selected:hover .mud-table-cell.core-grid-column-hover {
    background: color-mix(in srgb, var(--ds-primary) 26%, var(--ds-surface-selected)) !important;
}

.core-grid-column-menu {
    position: fixed;
    z-index: 1400;
    min-width: 236px;
    padding: 6px;
    border: 1px solid var(--ds-border);
    border-radius: 8px;
    background: var(--ds-surface);
    box-shadow: var(--ds-shadow-md);
    color: var(--ds-text);
}

.core-grid-column-menu__action {
    display: flex;
    align-items: center;
    width: 100%;
    min-height: 36px;
    gap: 10px;
    padding: 8px 10px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: inherit;
    font: inherit;
    font-weight: var(--ds-fw-medium);
    text-align: start;
    cursor: pointer;
}

.core-grid-column-menu__action:hover,
.core-grid-column-menu__action:focus-visible {
    background: var(--ds-surface-hover); /* + the global keyboard ring (UX-345) on focus */
}

.core-grid-column-menu__action.is-selected {
    background: var(--ds-primary-softer);
    color: var(--ds-primary-strong);
}

.core-grid-column-menu__icon {
    display: inline-grid;
    flex: 0 0 18px;
    width: 18px;
    height: 18px;
    place-items: center;
    color: var(--ds-primary-strong); /* an 18px SVG only (UX-381) — no glyph font-size/line-height */
}

.core-grid-column-menu__divider {
    height: 1px;
    margin: 6px 4px;
    background: var(--ds-border);
}

.core-grid-column-menu__title {
    padding: 6px 10px 4px;
    color: var(--ds-text);
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-bold);
}

.core-data-grid .mud-table-pagination-caption,
.core-data-grid .mud-table-pagination-select,
.core-data-grid .mud-table-pagination-information {
    font-size: var(--ds-fs-sm) !important; /* over app-ui.css's small-screen 10.5px (UX-339 floor, UX-361) */
    font-weight: var(--ds-fw-medium);
}

/* (Grid icon buttons take the 11px radius of the surface button rule — UX-356; the 10px override here
   only ever showed in dialogs.) */

.core-data-grid .mud-chip {
    font-weight: var(--ds-fw-medium);
}


/* ===== Loading skeletons (shimmer) — UX-380 =====
   A placeholder has the shape of what it stands for, so nothing jumps when the data arrives:
   - grid: CrudDataGrid's LoadingContent draws rows of --core-grid-row-h (the real row height, 1px border
     included) with one bar per visible column, the selection column as a checkbox-sized square;
   - details: DetailsState draws the hero card (icon, kicker, title, subtitle, badges) and an info grid of
     boxes that are real .core-info-box frames with a label and a value bar.
   (Replaces SkeletonRow's avatar / two lines / pill / circle row, ~70px tall against a 51px grid row.) */
.core-skeleton {
    display: block;
    position: relative;
    overflow: hidden;
    height: 12px;
    background: var(--ds-border-soft);
    background-image: linear-gradient(90deg,
            transparent 0,
            color-mix(in srgb, var(--ds-text) 8%, transparent) 50%,
            transparent 100%);
    background-size: 200% 100%;
    background-repeat: no-repeat;
    border-radius: var(--ds-radius-pill);
    animation: core-shimmer 1.4s ease-in-out infinite;
}

.core-skeleton-w-25 { width: 25%; }
.core-skeleton-w-40 { width: 40%; }
.core-skeleton-w-60 { width: 60%; }
.core-skeleton-w-80 { width: 80%; }

/* Grid: the LoadingContent sits in MudDataGrid's one full-width empty-row cell (th.mud-table-empty-row >
   div.my-3). The cell gives up its padding, fixed row height and 28rem cap, and the my-3 margin is zeroed in
   mud.overrides at the end of this file, so the placeholder rows start right under the header. */
.core-data-grid :is(td, th).mud-table-empty-row:has(.core-grid-skeleton) {
    height: auto;
    max-width: none;
    padding: 0;
    border-bottom: 0;
}

/* Never taller than the grid box: --core-grid-rows rows at most (the markup renders the largest count). */
.core-grid-skeleton {
    max-height: calc(var(--core-grid-row-h) * var(--core-grid-rows));
    overflow: hidden;
}

.core-grid-skeleton-row {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    height: var(--core-grid-row-h);
    border-bottom: 1px solid var(--ds-border-soft);
}

.core-grid-skeleton-cell {
    flex: 1 1 0;
    min-width: 0;
    padding: 4px 12px; /* = the body cell padding */
}

.core-grid-skeleton-cell > .core-skeleton {
    width: 72%;
}

/* A little variety, so the block reads as rows of data rather than a striped pattern. */
.core-grid-skeleton-row:nth-child(odd) .core-grid-skeleton-cell:nth-child(3n + 2) > .core-skeleton { width: 48%; }
.core-grid-skeleton-row:nth-child(even) .core-grid-skeleton-cell:nth-child(3n) > .core-skeleton { width: 56%; }
.core-grid-skeleton-row:nth-child(3n) .core-grid-skeleton-cell:nth-child(2n + 1) > .core-skeleton { width: 86%; }

.core-grid-skeleton-cell.is-select {
    flex: 0 0 auto;
}

.core-grid-skeleton-cell.is-select > .core-skeleton {
    width: 18px;
    height: 18px;
    border-radius: 4px;
}

/* Details: hero + info grid. */
.core-details-skeleton {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.core-details-skeleton-hero {
    display: flex;
    align-items: center;
    gap: 18px;
}

.core-details-skeleton-icon {
    flex: 0 0 58px;
    width: 58px;
    height: 58px;
    border-radius: 15px;
}

.core-details-skeleton-lines {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}

.core-details-skeleton-title {
    height: 20px;
}

.core-details-skeleton-badges {
    display: flex;
    gap: 8px;
}

.core-details-skeleton-badges > .core-skeleton {
    width: 72px;
    height: 24px;
}

.core-details-skeleton .core-info-box {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 10px;
}

.core-details-skeleton .core-info-box > .core-skeleton:first-child {
    width: 30%;
}

/* Reduced motion: a still placeholder, no sweep (the global reduced-motion rule only shortens it). */
@media (prefers-reduced-motion: reduce) {
    .core-skeleton {
        animation: none;
        background-image: none;
    }
}

/* ===== Keyframes ===== */
@keyframes core-pop-in {
    from { opacity: 0; transform: scale(.97); }
    to { opacity: 1; transform: scale(1); }
}

@keyframes core-shimmer {
    from { background-position: 200% 0; }
    to { background-position: -200% 0; }
}

/* Page entrance (moved from app-ui.css with the .core-page rule, UX-356); opacity only since UX-379. */
@keyframes ug-page-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

@media screen and (max-width: 1279.95px) {
    .core-data-grid .mud-table-root {
        min-width: 1100px;
    }
}

/* (UX-356: the page-title, KPI-card, filter-card and toolbar sizes this file used to set below 960/600px
   were dead — the page layer overrode them — and are gone; mobile.css's ≤959.95px block sets them.) */
@media screen and (max-width: 959.95px) {
    .core-page-header {
        gap: 16px;
    }
}

@media screen and (max-width: 599.95px) {
    .core-card-heading {
        align-items: flex-start;
    }

    .core-data-grid .mud-table-toolbar {
        flex-wrap: wrap;
    }
}

/* ===== Respect reduced-motion ===== */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
}

/* =========================================================
   Design-fidelity primitives (Phase C): focus ring, control height,
   status chip, active icon, row menu, tabs slider, loading
   skeletons. All var(--ds-*) — theme-aware, no hardcoded hex.
   ========================================================= */

/*
   Keyboard focus ring — UX-345. The old ring was a 3px --ds-primary-soft halo (#e7f1ff on white,
   ~1.1:1: invisible) and only inside .core-page / dialogs; MudBlazor itself sets outline:0 on buttons,
   chips, tabs and list items. Now one ring everywhere, the nav rail's: 2px --ds-primary outline, 2px
   off the control — 5.51:1 on white, 5.82 on the dark surface. :focus-visible only, so a mouse click
   never shows it. A checkbox, radio or switch focuses its hidden <input>, so the ring goes on the
   icon-button around it (MudBlazor's own :has() pattern); outline follows border-radius, so it is a
   circle there. Component rules that inset the ring (rail, flyout, grid tabs, menu rows) are more
   specific or later and keep their offset.
*/
:is(.mud-button-root, .mud-chip, .mud-tab, .mud-list-item, .mud-menu-item, .mud-nav-link, .mud-link,
    .mud-expand-panel-header, a[href], button, summary, [role="button"], [role="tab"], [role="menuitem"]):focus-visible,
.mud-icon-button:has(> input:focus-visible),
.mud-icon-button:has(.mud-switch-input:focus-visible) {
    outline: 2px solid var(--ds-primary);
    outline-offset: 2px;
}

/* Menu/list rows fill their popover edge to edge and tabs sit in an overflow-hidden tab bar: inset the
   ring there so the clipping box does not cut it off. */
:is(.mud-list-item, .mud-menu-item, [role="menuitem"], .mud-tab, [role="tab"]):focus-visible {
    outline-offset: -2px;
}

/*
   Control height — UX-363. One height for every field (--ds-control-h, 40px; theme-tokens.css), not 38px in
   the filter card and 46px everywhere else. app.css sizes MudBlazor's input/select/adornment boxes from the
   same token, so a container that wants compact fields only re-points the token (below), never re-sizes
   the MudBlazor parts itself.
*/
.core-input .mud-input-control,
.core-field .mud-input-control {
    min-height: var(--ds-control-h);
}

/*
   Compact controls (--ds-control-h-sm, 32px) where a field lives inside dense data: the grid's column
   filter row, the pager's rows-per-page select (both sat at 46px in a 51px row) and the month/year
   selects of the Persian calendar header.
*/
.core-data-grid .mud-table-head .filter-header-cell,
.core-data-grid .mud-table-pagination-toolbar,
.persian-calendar-popover :is(.persian-month-select, .persian-year-select) {
    --ds-control-h: var(--ds-control-h-sm);
}

/* (UX-377: the sticky-header properties that stood here are merged into the head-cell rule near the top of
   the grid section, with their explanation.) */

/*
   With the filter row showing, thead has two rows and the second parks under the first.
   MudBlazor's own sticky header hardcodes 59px here; ours reads the variable that sizes the
   header row, so the two cannot drift apart.
*/
.core-data-grid .mud-table-head .mud-table-cell.filter-header-cell {
    top: var(--core-grid-head-h);
}

/* Record-status chip (StatusChip) */
.core-status-chip {
    font-weight: var(--ds-fw-medium);
}

/*
   Coloured chips are soft chips — UX-341. MudBlazor fills a Filled chip with the palette colour and writes
   white on it (light: success 3.30, warning 2.15, secondary 3.39; dark: success 1.92, warning 1.67,
   info 2.54, error 2.77, tertiary 1.87), and an Outlined/Text chip writes the palette colour itself as
   text (light warning 2.15 on white). Every coloured chip — StatusChip and the hand-built ones in grids,
   heroes and dialogs — now takes a *-soft tint with the same hue's *-strong text (ratios in
   theme-tokens.css: ≥ 5.0 light, ≥ 6.0 dark). Outlined keeps its transparent background and border so
   «غیرفعال»-style chips still read as the lighter variant.

   Primary is left alone: white on #0062df is 5.51 and #0d1117 on the dark #4d94ff is 6.30, and the
   filled primary chip is the «selected» look of MudChipSet. Default (grey) chips are already 14:1+.

   Specificity: each selector is one class above MudBlazor's (`.mud-chip-filled.mud-chip-color-x` and
   `….mud-clickable:hover:not(.mud-disabled)`), so no !important is needed and a page that styles its
   own chip with !important still wins.
*/
.mud-chip.mud-chip-color-success {
    --uni-chip-fg: var(--ds-success-strong);
    --uni-chip-bg: var(--ds-success-soft);
}

.mud-chip.mud-chip-color-warning {
    --uni-chip-fg: var(--ds-warning-strong);
    --uni-chip-bg: var(--ds-warning-soft);
}

.mud-chip.mud-chip-color-error {
    --uni-chip-fg: var(--ds-error-strong);
    --uni-chip-bg: var(--ds-error-soft);
}

.mud-chip.mud-chip-color-info {
    --uni-chip-fg: var(--ds-info-strong);
    --uni-chip-bg: var(--ds-info-soft);
}

/* UX-352: Secondary is the archived / inactive / «also» status (StatusChip Archived, record counts,
   «پیش‌فرض», «به‌روزرسانی» rows) — neutral grey, not the brand orange. */
.mud-chip.mud-chip-color-secondary {
    --uni-chip-fg: var(--ds-neutral-strong);
    --uni-chip-bg: var(--ds-neutral-soft);
}

.mud-chip.mud-chip-color-tertiary {
    --uni-chip-fg: var(--ds-primary-strong);
    --uni-chip-bg: var(--ds-primary-soft);
}

.mud-chip:is(.mud-chip-filled, .mud-chip-text):is(.mud-chip-color-success, .mud-chip-color-warning, .mud-chip-color-error, .mud-chip-color-info, .mud-chip-color-secondary, .mud-chip-color-tertiary) {
    background-color: var(--uni-chip-bg);
    color: var(--uni-chip-fg);
}

.mud-chip.mud-chip-outlined:is(.mud-chip-color-success, .mud-chip-color-warning, .mud-chip-color-error, .mud-chip-color-info, .mud-chip-color-secondary, .mud-chip-color-tertiary) {
    border-color: color-mix(in srgb, var(--uni-chip-fg) 45%, transparent);
    color: var(--uni-chip-fg);
}

/* Hover/press on a clickable chip: 8% of the text hue over the tint — text stays ≥ 4.64 light, ≥ 5.18 dark. */
.mud-chip.mud-clickable:is(.mud-chip-filled, .mud-chip-text, .mud-chip-outlined):is(.mud-chip-color-success, .mud-chip-color-warning, .mud-chip-color-error, .mud-chip-color-info, .mud-chip-color-secondary, .mud-chip-color-tertiary):is(:hover, :focus-visible, :active):not(.mud-disabled) {
    background-color: color-mix(in srgb, var(--uni-chip-fg) 8%, var(--uni-chip-bg));
}

/*
   Warning alerts (UX-352): one warning colour — amber — on pages and in dialogs. MudBlazor writes
   --mud-palette-warning-darken as text on the warning hover tint, which does not reach 4.5:1 for the
   amber #F59E0B; the same soft-tint / strong-text pair as the warning chip does (light 5.37, dark 7.4).
   A filled warning alert keeps the amber fill but takes dark ink: MudBlazor's default white on it is 2.15:1;
   #121820 is 8.31 on #F59E0B and 11+ on the dark theme's #FBBF24.
*/
.mud-alert.mud-alert-filled-warning {
    color: #121820;
}

.mud-alert.mud-alert-filled-warning .mud-alert-icon {
    color: inherit;
}

.mud-alert.mud-alert-text-warning {
    background-color: var(--ds-warning-soft);
    color: var(--ds-warning-strong);
}

.mud-alert.mud-alert-outlined-warning {
    border-color: color-mix(in srgb, var(--ds-warning) 60%, transparent);
    color: var(--ds-warning-strong);
}

.mud-alert:is(.mud-alert-text-warning, .mud-alert-outlined-warning) .mud-alert-icon {
    color: var(--ds-warning-strong);
}

/* Active/inactive icon (ActiveIcon) — UX-351: solid --ds-faint, no extra opacity on an already-muted colour. */
.core-active-icon-faint {
    color: var(--ds-faint);
}

/* Row-action menu popover (design: rounded 16, soft hover, error-soft delete) */
.core-row-menu.mud-list {
    padding: 7px;
    border-radius: 16px;
}
.core-row-menu .mud-list-item {
    min-height: 38px;
    border-radius: 10px;
    font-weight: var(--ds-fw-medium);
}
.core-row-menu .mud-list-item:hover {
    background: var(--ds-primary-soft);
    color: var(--ds-primary-strong);
}
.core-row-menu .core-menu-danger:hover {
    background: var(--ds-error-soft);
    color: var(--ds-error-strong); /* UX-341: base error on its tint 4.17, strong 5.59 */
}

/* Tabs — 3px brand underline under the active tab (design: tabs) */
.core-tabs .mud-tab-slider {
    height: 3px;
    border-radius: 3px 3px 0 0;
    background: var(--ds-primary);
}

/* =========================================================
   Mobile polish (shared) — cascades to every page built on the
   core-* scaffold: tighter page gutters, single-column filters &
   dialog fields, full-bleed dialogs, dense tables that scroll.
   ========================================================= */
/* UX-357: was 768px — a fifth width of its own. It now switches together with the app shell, the
   bottom-sheet dialogs (mobile.css, ≤959.95px) and the card grids (app-ui.css, ≤960px). The page gutter, near-full-screen
   dialog and info-grid rules it used to carry were already overridden by mobile.css at those widths and
   were removed. */
@media screen and (max-width: 959.95px) {
    /* Filter fields stack full width on phones */
    .core-filter-card .mud-grid-item {
        flex-basis: 100%;
        max-width: 100%;
    }

    /* Dialog section field grids collapse to one column */
    .core-form-dialog .mud-grid-item {
        flex-basis: 100%;
        max-width: 100%;
    }

    /* (Hero badges already wrap at every width — base rule; the column direction of .core-hero-content is in
       mud.overrides below. UX-377 removed the copy that stood here.) */

    /* Detail tabs scroll instead of squashing */
    .core-details-card .mud-tabs-toolbar {
        overflow-x: auto;
    }
}

@media screen and (max-width: 599.95px) {
    /* Dense tables keep their columns and scroll horizontally (less extreme on tiny screens) */
    .core-data-grid .mud-table-root {
        min-width: 640px;
    }
}

/* Metadata / sanitized error details: wrap long text instead of clipping it. */
.uni-error-details {
    direction: ltr;
    text-align: left;
    unicode-bidi: plaintext;
    white-space: pre-wrap;
    word-break: break-word;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--ds-fs-sm);
    line-height: 1.6;
}

/* ---------------------------------------------------------------------------
   دکمه‌های عملیاتیِ نوار گرید — خروجی اکسل و هر کاری که با انتخابِ ردیف روشن می‌شود.

   قاعده‌ی سراسریِ دکمه‌های صفحه و دیالوگ (`:is(.core-page, …) .mud-button-root`، بالای همین فایل)
   ارتفاع ۴۲px و radius/font را تحمیل می‌کند؛ انتخابگرِ این دکمه‌ها هم‌وزنِ آن است و بعد از آن
   می‌آید، پس برنده می‌شود (UX-361). هدف: هم‌اندازه شدن با چیپ کنارشان (MudChip Small = 26px).
   UX-356: همین دکمه در دیالوگ هم همین شکل را دارد (پیش‌تر فقط داخلِ .core-page).
--------------------------------------------------------------------------- */
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button {
    min-height: 26px;
    height: 26px;
    padding-block: 0;
    /* در حالت جمع باید گرد بماند، نه کپسولِ پهن؛ عرضِ اضافه را خودِ برچسب می‌آورد.
       MudBlazor به هر دکمه min-width: 64px می‌دهد و بدون صفرکردنش، دکمهٔ جمع‌شده
       همچنان یک کپسولِ ۶۴ پیکسلی با نشانِ وسط می‌ماند. */
    min-width: 0;
    padding-inline: 6px;
    border-radius: 999px;
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
    line-height: 1;
    white-space: nowrap;
    text-transform: none;
    background-color: transparent;
    transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}

:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button .mud-button-label {
    /* فاصله را خودِ برچسب با margin می‌سازد، وگرنه در حالت جمع هم یک شکافِ بی‌دلیل می‌ماند. */
    gap: 0;
    line-height: 1;
}

/* MudBlazor به نشانِ ابتدای دکمه margin می‌دهد؛ در حالت جمع باید صفر باشد. */
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button .mud-button-icon-start {
    margin: 0;
}

/* ---------------------------------------------------------------------------
   عنوانِ دکمه فقط با هاور باز می‌شود.

   انیمیشن روی max-width است نه width، چون عرضِ واقعیِ متن از قبل معلوم نیست و
   width: auto قابل ترنزیشن نیست. مقدارِ سقف از بلندترین ترجمه بیشتر است تا
   هیچ زبانی نصفه نماند.
--------------------------------------------------------------------------- */
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button .core-action-label {
    display: inline-block;
    max-width: 0;
    opacity: 0;
    overflow: hidden;
    /* سقفِ عرض یعنی یک عنوانِ خیلی بلند بریده می‌شود؛ سه‌نقطه می‌گوید بریده شده. */
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1.6;
    margin-inline-start: 0;
    transition: max-width 180ms ease, opacity 140ms ease, margin-inline-start 180ms ease;
}

:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button:hover:not(:disabled) .core-action-label,
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button:focus-visible:not(:disabled) .core-action-label,
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button .core-action-label.is-open {
    max-width: 14rem;
    opacity: 1;
    margin-inline-start: 5px;
}

/* کسی که انیمیشن را خاموش کرده، بازشدنِ ناگهانی ببیند نه لغزش. */
@media (prefers-reduced-motion: reduce) {
    :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button .core-action-label {
        transition: none;
    }
}

/* ---------------------------------------------------------------------------
   تو-خالی است و با هاور پر می‌شود.

   پس‌زمینه currentColor است، یعنی همان رنگی که خودِ دکمه دارد — سبزِ خروجی، آبیِ
   ثبت، قرمزِ حذف. پس هیچ رنگی قاعده‌ی جداگانه لازم ندارد و دکمه‌ی رنگِ تازه هم
   خودبه‌خود درست درمی‌آید. سفیدشدنِ متن روی برچسب می‌نشیند نه روی خودِ دکمه، وگرنه
   currentColor هم سفید می‌شد و پس‌زمینه سفید روی سفید می‌افتاد.

   UX-377: the hover/focus rules themselves live once, at the CoreActionButton section near the end of this
   file (fill var(--core-action-fill, currentColor), ink var(--core-action-ink, #fff)); the eight-selector
   copy that stood here with plain currentColor/#fff always lost to them.
--------------------------------------------------------------------------- */

.core-export-spinner {
    width: 13px;
    height: 13px;
    margin-inline-end: 4px;
}

/* ---------------------------------------------------------------------------
   ردیفِ کارها در کارتِ هویتِ سند (صفحه‌های جزئیات).

   کارهای یک سند کنار وضعیتش می‌نشینند، نه در کارتِ جداگانه‌ی «عملیات» و نه بالای
   صفحه کنار «بازگشت». همان‌جایی که کاربر وضعیت را می‌خواند، کاری هم که می‌تواند
   بکند همان‌جاست. بالای صفحه فقط ناوبری می‌ماند: بازگشت و به‌روزرسانی.
--------------------------------------------------------------------------- */
.core-details-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 6px;
}

/*
   نوار عملیات، همان ظرف برای لیست و جزئیات است. در حالت عادی عنوان هر دکمه باز است؛
   این انتخاب عمدی است تا دو یا سه عملِ موجود پشت نشان‌های بی‌نام پنهان نشوند. فقط
   نوارهایی که صراحتاً پرتعدادند یک کلید جمع/باز دارند.
*/
.core-action-toolbar {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

.core-action-toolbar.is-collapsible {
    flex-wrap: nowrap;
}

.core-action-toolbar-toggle {
    flex: 0 0 auto;
    border: 1px solid var(--core-border);
    border-radius: 999px;
}

@media screen and (max-width: 599.95px) {
    .core-action-toolbar,
    .core-action-toolbar.is-collapsible {
        width: 100%;
    }

    .core-action-toolbar.is-collapsible {
        flex-wrap: wrap;
    }
}

/* ---------------------------------------------------------------------------
   نوار تبِ گرید.

   تب‌ها داخل نوار ابزارِ خودِ گریدند و تمام‌عرض، پس به خط دوم می‌شکنند و درست بالای
   سرستون‌ها می‌نشینند — جایی که معنی‌شان روشن است: این جدول، این نما. برای همین
   نوار ابزار فقط وقتی تب دارد اجازهٔ شکستن می‌گیرد.
--------------------------------------------------------------------------- */
/* padding-bottom keeps !important: app-ui.css's small-screen toolbar padding is !important in a later
   layer, and among !important declarations the earlier layer (core) wins (UX-361). */
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .core-data-grid-tabbed .mud-table-toolbar {
    flex-wrap: wrap;
    row-gap: 10px;
    padding-bottom: 0 !important;
    /* MudBlazor به نوار ابزار ارتفاعِ ثابت می‌دهد؛ بدون auto، ردیفِ دومِ تب‌ها از کادر
       بیرون می‌زد و زیرِ سرستون‌ها پنهان می‌شد. */
    height: auto;
}

.core-grid-tabs {
    display: flex;
    align-items: stretch;
    flex-wrap: wrap;
    gap: 4px;
    flex-basis: 100%;
    /* آخرین عضوِ نوار ابزار: وگرنه دکمهٔ تنظیمِ ستون‌ها که MudBlazor خودش بعد از محتوای ما
       می‌گذارد، به خطِ سومِ تنهایی می‌افتاد. */
    order: 1;
    margin-block-start: 2px;
    padding-inline: 2px;
    border-bottom: 1px solid var(--ds-border-soft);
}

.core-grid-tab {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 9px 16px;
    border: 0;
    border-radius: 10px 10px 0 0;
    background: transparent;
    color: var(--mud-palette-text-secondary);
    font: inherit;
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-medium);
    line-height: 1.4;
    white-space: nowrap;
    cursor: pointer;
    transition: color 140ms ease, background-color 140ms ease;
}

/* خطِ زیرِ تب روی ::after است نه border، تا فعال‌شدن ارتفاع تب را جابه‌جا نکند. */
.core-grid-tab::after {
    content: "";
    position: absolute;
    inset-inline: 14px;
    bottom: -1px;
    height: 2px;
    border-radius: 2px 2px 0 0;
    background: transparent;
    transition: background-color 140ms ease, inset-inline 160ms ease;
}

.core-grid-tab .mud-icon-root {
    font-size: 1rem;
    opacity: .85;
}

.core-grid-tab:hover:not(.is-active) {
    color: var(--mud-palette-primary);
    background: var(--ds-primary-softer);
}

.core-grid-tab.is-active {
    color: var(--mud-palette-primary);
    background: var(--ds-primary-softer);
}

.core-grid-tab.is-active::after {
    inset-inline: 8px;
    background: var(--mud-palette-primary);
}

.core-grid-tab.is-active .mud-icon-root {
    opacity: 1;
}

.core-grid-tab:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -3px;
}

/* شمارشِ کنارِ عنوان: روی تبِ فعال پررنگ می‌شود تا نمای جاری از یک نگاه معلوم باشد. */
.core-grid-tab-count {
    min-width: 22px;
    padding: 2px 7px;
    border-radius: 999px;
    background: var(--ds-border-soft);
    color: var(--mud-palette-text-secondary);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
    line-height: 1.5;
    text-align: center;
    transition: background-color 140ms ease, color 140ms ease;
}

.core-grid-tab.is-active .core-grid-tab-count {
    background: var(--mud-palette-primary);
    color: var(--mud-palette-primary-text);
}

@media (prefers-reduced-motion: reduce) {
    .core-grid-tab,
    .core-grid-tab::after,
    .core-grid-tab-count {
        transition: none;
    }
}

@media screen and (max-width: 599.95px) {
    .core-grid-tab {
        padding: 8px 11px;
        font-size: 0.79rem;
    }
}

/* ---------------------------------------------------------------------------
   گزینه‌های انتخابگرِ گروهی (بچ، انبار مبدأ، مقصد تحویل).

   عنوان و توضیح هم‌وزن نیستند: عنوان همان چیزی است که گزینه را می‌شناساند و
   توضیح فقط کمک می‌کند. در نشانیِ مشتری این تفاوت حیاتی است، چون Description
   همهٔ نشانی‌ها یک متنِ تکراری است و آنچه واقعاً جدایشان می‌کند خیابان است.
--------------------------------------------------------------------------- */
.core-pick-option {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
    padding-block: 2px;
}

.core-pick-option-title {
    font-weight: var(--ds-fw-medium);
    line-height: 1.5;
}

.core-pick-option-detail {
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-regular);
    line-height: 1.5;
    color: var(--mud-palette-text-secondary);
    /* نشانی بلند است؛ بریدنش یعنی همان چیزی که گزینه‌ها را جدا می‌کند دیده نشود. */
    white-space: normal;
    overflow-wrap: anywhere;
}

/* نوارِ کارهای گرید: در تنگی می‌شکند تا دکمه‌ها از کارت بیرون نزنند. */
.core-grid-actions {
    display: flex;
    align-items: center;
    align-content: flex-start;
    flex-wrap: wrap;
    gap: 6px;
}

/* ---------------------------------------------------------------------------
   بازشدنِ عنوانِ یک دکمه نباید چیدمانِ نوار را به‌هم بریزد.

   با هاور، دکمه چند ده پیکسل پهن‌تر می‌شود و اگر جا کم بیاید آخرین دکمه به خط
   بعد می‌پرد — درست همان لحظه‌ای که کاربر دارد نشانه می‌رود. پس روی نمایشگرِ
   بزرگ نوار نمی‌شکند و به‌جایش عنوانِ گرید کوتاه می‌شود؛ در عرضِ کم همان
   شکستنِ قبلی می‌ماند چون آنجا واقعاً جا نیست.
--------------------------------------------------------------------------- */
.core-grid-toolbar-title {
    /* پایهٔ صفر، نه auto — و همین یک خط است که مسئله را حل می‌کند.

       در یک ظرفِ wrap، مرورگر برای جا باز کردن اول آخرین عضو را به خط بعد
       می‌اندازد و تنها وقتی سراغ کوچک‌کردنِ عنوان می‌رود که راهِ دیگری نمانده
       باشد. نتیجه‌اش این بود: با هاور، دکمه حدود ۱۵۰ پیکسل پهن می‌شد، عنوانِ
       ۲۵۰پیکسلی دست‌نخورده می‌ماند و دکمهٔ تنظیمِ ستون‌ها تنها به خط بعد
       می‌افتاد؛ نوار از ۱۰۶ به ۱۵۸ پیکسل می‌پرید و با کنار رفتنِ نشانگر
       برمی‌گشت — یعنی درست همان لحظه‌ای که کاربر دارد نشانه می‌رود.

       با flex-basis صفر، عنوان در محاسبهٔ شکستن اصلاً شرکت نمی‌کند و فقط
       فضای باقی‌مانده را می‌گیرد. پس بازشدنِ دکمه عنوان را کوتاه می‌کند — که
       با سه‌نقطه پیداست و برگشت‌پذیر است — نه اینکه چیدمان را بشکند. */
    flex: 1 1 0;
    /* کفِ عنوان: صفر شدنش یعنی ناپدید شدنِ نامِ جدول. این اندازه برای چند نویسه
       به‌علاوهٔ سه‌نقطه بس است و آن‌قدر کوچک هست که خودش باعث شکستن نشود. */
    min-width: 3.5rem;
    overflow: hidden;
}

.core-grid-toolbar-title .core-card-title,
.core-grid-toolbar-title .core-card-subtitle {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (min-width: 960px) {
    .core-grid-actions {
        flex-wrap: nowrap;
    }
}

/* اگر با همهٔ اینها باز هم شکست (نمایشگرِ تنگ)، دست‌کم مرتب بشکند: ردیف‌ها
   نچسبند و ردیفِ ناقصِ دکمه‌ها از همان لبه‌ای شروع شود که بقیه شروع می‌شوند. */
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .core-data-grid .mud-table-toolbar {
    row-gap: 10px;
}

/* ---------------------------------------------------------------------------
   جدول‌های داخل تب و کارت جزئیات (.core-table).
   این کلاس در ۱۰ صفحه استفاده می‌شد اما هیچ استایلی نداشت، پس جدول‌ها خام دیده
   می‌شدند. الگوی واحد: سرستون مشخص و چسبان، فاصله‌ی کافی، جداکننده‌ی ملایم بین
   سطرها، و هاور. هر تب جدیدی هم باید همین کلاس را بگیرد.
--------------------------------------------------------------------------- */
.core-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background-color: var(--ds-surface);
    border: 1px solid var(--ds-border-soft);
    border-radius: 12px;
    overflow: hidden;
}

/* سرستون: پس‌زمینه‌ی متمایز، حروف کمی درشت‌تر، و خط پایه‌ی پررنگ‌تر تا از بدنه جدا شود. */
.core-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background-color: var(--ds-surface-inset);
    color: var(--ds-text-2);
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-medium);
    white-space: nowrap;
    padding: 12px 16px;
    border-bottom: 1px solid var(--ds-border);
    text-align: start;
}

.core-table tbody td {
    padding: 12px 16px;
    font-size: var(--ds-fs-sm);
    /* body2 در پوسته ۱٫۷ است (UX-347)؛ خانهٔ جدول متراکم‌تر می‌ماند تا ردیف‌های چندخطی بلند نشوند. */
    line-height: 1.5;
    color: var(--ds-text);
    border-bottom: 1px solid var(--ds-border-soft);
    vertical-align: middle;
}

.core-table tbody tr:last-child td {
    border-bottom: none;
}

.core-table tbody tr {
    transition: background-color var(--ds-dur-fast) var(--ds-ease-out);
}

.core-table tbody tr:hover {
    background-color: var(--ds-surface-hover);
}

/* ستون‌های وضعیت/نشانگر معمولاً باریک و وسط‌چین‌اند. */
/* سطری که دیده می‌شود ولی انتخاب‌شدنی نیست — مثل رانندهٔ بی‌خودرو در پنجرهٔ انتخاب.
   کم‌رنگ می‌شود، نه پنهان: حذفش یعنی کاربر فکر کند اصلاً وجود ندارد. */
/* UX-351: was opacity .55 — text #121820 fell to 3.97:1 and muted text to 2.19:1. The muted
   text colour instead (light 6.07 on white / 5.60 on --ds-bg, dark 6.0+; UX-368); chips keep their own colours. */
.core-table tbody tr.is-muted > td {
    color: var(--ds-muted);
}

.core-table .core-table-center {
    text-align: center;
}

/* ستونِ شمارهٔ ردیف، تیکِ انتخاب و عملیاتِ آیکونی: به اندازهٔ محتوا (UX-192). */
.core-table .core-table-narrow {
    width: 1%;
    white-space: nowrap;
}

/* مقدارهای لاتین (کد، شبا، تاریخ) در چیدمان راست‌به‌چپ LTR می‌مانند — قاعدهٔ سراسریِ .ltr-value (UX-359). */

/* سلول کد/شماره که به صفحه‌ی جزئیات پیوند دارد. */
.core-table .core-table-link {
    min-height: 0;
    padding: 0 4px;
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-medium);
    text-transform: none;
}

/* ---------------------------------------------------------------------------
   MudSimpleTable با Dense قاعده‌ی خودش را دارد:
     .mud-simple-table.mud-table-dense * tr th { padding: 6px 16px }
   که specificity بالاتری از `.core-table thead th` داشت، پس فاصله‌ها و ضخامت قلم
   اعمال نمی‌شد. UX-361: core.css حالا در لایه‌ای بالاتر از MudBlazor است، پس دیگر لازم
   نیست کلاس برای بالا بردنِ ویژگی‌مندی تکرار شود.
--------------------------------------------------------------------------- */
.core-table table * tr th {
    padding: 12px 16px;
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-medium);
    color: var(--ds-text-2);
    background-color: var(--ds-surface-inset);
    border-bottom: 1px solid var(--ds-border);
}

.core-table table * tr td {
    padding: 12px 16px;
    font-size: var(--ds-fs-sm);
    border-bottom: 1px solid var(--ds-border-soft);
}

.core-table table * tr:last-child td {
    border-bottom: none;
}

/* ---------------------------------------------------------------------------
   اندازهٔ ستون در جدول‌های جزئیات و گزارش‌ها (MudSimpleTable).

   جدول به‌جای فشرده‌شدن در عرضِ کارت، به عرضِ محتوای خودش باز می‌شود و اگر از کارت بزرگ‌تر بود،
   اسکرول افقی می‌گیرد (مثل فهرست‌ها). پیش‌تر ستون‌ها تا کمینهٔ عرضِ محتوا فشرده می‌شدند و در
   جدولِ ردیف‌های گزارش (۱۵ ستون و بیشتر) متن‌ها کلمه‌به‌کلمه زیر هم می‌شکستند.
   - width: max-content ستون را به اندازهٔ محتوا نگه می‌دارد، min-width: 100% جدول‌های کوچک را تمام‌عرض.
   - min-width سلول جلوی ستونِ باریکِ بی‌خواناییِ ستون‌های عددی/کد را می‌گیرد.
   - max-width سلول فقط متنِ خیلی بلند (توضیح، نام کالا) را می‌شکند تا یک ستون جدول را نکشد.
--------------------------------------------------------------------------- */
.mud-simple-table table {
    width: max-content;
    min-width: 100%;
}

.mud-simple-table table * tr th,
.mud-simple-table table * tr td {
    min-width: 110px;
}

.mud-simple-table table * tr td {
    max-width: 340px;
    overflow-wrap: anywhere;
}

/* ستونِ شمارهٔ ردیف و ستونِ عملیاتِ آیکونی عمداً باریک می‌مانند. کلاس فقط روی سرستون است؛ خانه‌های همان
   ستون با :has پیدا می‌شوند — ستون‌های شرطی شمارهٔ ستون را در زمانِ اجرا جابه‌جا می‌کنند، پس شمارهٔ ثابت
   در markup کار نمی‌کرد (UX-192). */
.mud-simple-table table * tr th.core-table-narrow,
.mud-simple-table table * tr td.core-table-narrow,
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(1)) tbody tr > td:nth-child(1),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(2)) tbody tr > td:nth-child(2),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(3)) tbody tr > td:nth-child(3),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(4)) tbody tr > td:nth-child(4),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(5)) tbody tr > td:nth-child(5),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(6)) tbody tr > td:nth-child(6),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(7)) tbody tr > td:nth-child(7),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(8)) tbody tr > td:nth-child(8),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(9)) tbody tr > td:nth-child(9),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(10)) tbody tr > td:nth-child(10),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(11)) tbody tr > td:nth-child(11),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(12)) tbody tr > td:nth-child(12),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(13)) tbody tr > td:nth-child(13),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(14)) tbody tr > td:nth-child(14),
.mud-simple-table table:has(thead th.core-table-narrow:nth-child(15)) tbody tr > td:nth-child(15) {
    min-width: 0;
}

/* جای‌نگهدارِ «مقدار ندارد» تا ستون‌های نشانگر خالی به‌نظر نرسند. */
.core-table .core-table-dash {
    color: var(--ds-faint);
}

/* ---------------------------------------------------------------------------
   قاب جدول داخل تب. جدول به لبه‌ی کارت نمی‌چسبد: از هر طرف فاصله می‌گیرد و
   جدول عریض خودش اسکرول می‌شود، نه اینکه صفحه را افقی بکشد.
--------------------------------------------------------------------------- */
.core-table-scroll {
    width: auto;
    overflow-x: auto;
    margin: 4px 16px 20px;
    border-radius: 12px;
}

/*
    فاصله‌ی افقی بالا برای کارتی بود که خودش فاصله‌ی داخلی نداشت. حالا که بخش‌های جزئیات
    فاصله دارند، این دو روی هم جمع می‌شدند و جدول بیش از عنوانِ بالای خودش تورفتگی می‌گرفت.
*/
.core-grid-card:not(.core-grid-card-flush) > .core-table-scroll {
    margin-inline: 0;
}

/* اسکرول‌بار افقی باریک و کم‌رنگ، تا وجودش جدول را شلوغ نکند. */
.core-table-scroll::-webkit-scrollbar {
    height: 8px !important;
}

.core-table-scroll::-webkit-scrollbar-thumb {
    background-color: var(--ds-border-strong) !important;
    border-radius: 999px !important;
}

.core-table-scroll::-webkit-scrollbar-track {
    background-color: transparent !important;
}

/* داخل قاب، سایه‌ی ملایم به جدول عمق می‌دهد و از پس‌زمینه‌ی کارت جدایش می‌کند. */
.core-table-scroll > .core-table {
    box-shadow: var(--ds-shadow-sm); /* UX-367 */
}

/* پیام «رکوردی نیست» هم باید همان فاصله‌ی جدول را داشته باشد، وگرنه تب ناهم‌تراز می‌شود. */
.core-details-tabs .mud-alert {
    margin: 4px 16px 20px;
}

/* ورودی مقدار در جدول ردیف‌های بار: عریض‌تر از ورودی معمولی، چون عدد تا چهار رقم اعشار دارد. */
.core-quantity-input {
    min-width: 190px;
}

/* ---------------------------------------------------------------------------
   Column resize handle (see CrudDataGrid.razor.js).

   The grid resizes itself rather than using MudBlazor's resizer, which computes
   width from a raw pointer delta and has no notion of writing direction - under
   RTL its drag runs backwards. Positioning uses inset-inline-end so the handle
   lands on the column's end edge in both directions without a direction-specific
   rule: the right edge in LTR, the left edge in RTL.
--------------------------------------------------------------------------- */
/*
   No position: relative here. It used to sit on this selector to give the absolutely
   positioned handle a containing block, but being the last rule in the file for that
   selector it also overrode the sticky header above and quietly unpinned it. The sticky
   header establishes a containing block just as well, so the handle still lands correctly.
*/
.core-grid-resizer {
    position: absolute;
    inset-block: 0;
    inset-inline-end: 0;
    width: 6px;
    cursor: col-resize;
    user-select: none;
    touch-action: none;
    z-index: 2;
}

/*
   The divider is painted at rest, not only on hover.

   It used to be transparent until the pointer happened to land inside the 8px strip, and the grid
   draws no column separators of its own — so there was nothing on screen to suggest a column edge
   could be dragged at all, and the feature went unfound. A faint mark costs almost nothing
   visually and is the only thing advertising it.

   Every column in the header row carries one, the row selector and the action column included.
   The handle used to be installed only where the header had a sort icon or a filter button, which
   meant the divider quietly doubled as a map of which columns happened to be sortable — columns
   that are neither showed no edge at all, and the grid read as half-resizable.
*/
.core-grid-resizer::after {
    content: "";
    position: absolute;
    inset-block: 25%;
    inset-inline-end: 3px;
    width: 2px;
    border-radius: 1px;
    background: var(--ds-border);
    transition: background-color var(--ds-dur-fast) var(--ds-ease);
}

/*
   `is-dragging` is set by the JS module for the length of the drag. Hover alone is not enough:
   the handle takes pointer capture on pointerdown, so the cursor leaves the 8px strip on the
   first pixel of movement and `:hover` stops matching — the divider would fade out exactly while
   being used.
*/
.core-grid-resizer:hover::after,
.core-grid-resizer.is-dragging::after {
    background: var(--ds-primary);
}

/* UX-369: the handle is a focusable separator; arrows resize. Ring inset so the header cell does not clip it. */
.core-grid-resizer:focus-visible {
    outline: 2px solid var(--ds-primary);
    outline-offset: -2px;
    border-radius: 2px;
}

.core-grid-resizer:focus-visible::after {
    background: var(--ds-primary);
}

/* UX-378: the hand only where a plain click on the row does something — a grid opts in with
   .core-data-grid--row-clickable (today the two picker dialogs with SelectOnRowClick). CrudDataGrid does not:
   its RowHref answers Ctrl/⌘+click only (new tab) and a plain click deliberately does nothing (UX-057, owner
   decision), so a hand there would be the very promise this row removes. Every other grid row is plain; the
   row tint on hover stays, it is a reading aid. (The unused .core-row-activatable that stood here is gone.) */
.core-data-grid--row-clickable .mud-table-body .mud-table-row {
    cursor: pointer;
}

/* ---------------------------------------------------------------------------
   واژه‌های انگلیسی همه‌جا به شکلِ جمله نوشته می‌شوند، نه با حروف بزرگ.

   UnigateTheme.Button.TextTransform این را برای دکمه‌ها خاموش می‌کند، ولی MudBlazor
   دو جا uppercase را مستقیم در CSS خودش گذاشته و از آن متغیرِ تایپوگرافی رد نمی‌شود:
   برچسبِ تب‌ها و دکمه‌ی پنجره‌ی اتصالِ دوباره‌ی Blazor. پس همان دو تا اینجا برداشته
   می‌شوند. core.css بعد از MudBlazor.min.css بار می‌شود (App.razor)، و گزیننده‌ها
   عیناً همان‌هایند، پس ترتیب کافی است و !important لازم نیست.
   --------------------------------------------------------------------------- */
.mud-tab,
#components-reconnect-modal button {
    text-transform: none;
}

/* ---------------------------------------------------------------------------
   نشانِ پیوست و کامنت روی سربرگِ سند.

   با بقیهٔ دکمه‌های عملیاتی یک شکل‌اند (همان کپسولِ جمع‌شونده) ولی پُر و کم‌رنگ‌اند
   نه تو خالی: این دو «کارِ سند» نیستند، همیشه هستند و روی هر سندی تکرار می‌شوند.
   اگر مثل حذف و ارسال خط‌دار بودند، نوارِ سربرگ پر می‌شد از قاب‌های هم‌وزن و چشم
   دیگر کارِ اصلی را پیدا نمی‌کرد.
--------------------------------------------------------------------------- */
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.core-notes-button {
    border-color: transparent;
    background-color: color-mix(in srgb, currentColor 10%, transparent);
}

/* هاور عمداً دست‌نخورده می‌ماند: قانونِ پایه دکمه را با رنگِ خودش پر می‌کند و نشان را
   سفید می‌کند. اگر اینجا پس‌زمینه را کم‌رنگ نگه می‌داشتیم، آن «سفیدِ» اجباری روی زمینهٔ
   روشن می‌نشست و نشان محو می‌شد — همان چیزی که دیده شد. پس فقط حالتِ عادی نرم است و
   رفتارِ هاور با بقیهٔ دکمه‌های نوار یکی می‌ماند. */

/* شمارندهٔ کنارِ نشان.

   عدد همیشه نوشته می‌شود، حتی صفر — پس کوچک و کم‌وزن می‌ماند تا کنارِ نشان بنشیند نه
   اینکه به آن غلبه کند. صفر خاکستری است و فقط عددهای واقعی رنگ می‌گیرند. */
.core-notes-badge {
    margin-inline-start: 2px;
}

.core-notes-badge .mud-badge.mud-badge-dot,
.core-notes-badge .mud-badge {
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-bold);
    /* 18px (was 15px): the count is 12px now (UX-339) and needs the room. */
    min-width: 18px;
    height: 18px;
    padding-inline: 4px;
}

/* ===========================================================================
   تقویم شمسی (PersianDatePicker) — قاعده‌هایی که پیش‌تر در PersianDatePicker.razor.css بودند.

   آن‌جا روی ریشه‌ی MudStack/MudText/MudTextField/MudPaper/MudSelect می‌نشستند و چون Blazor نشانِ
   scope را روی ریشه‌ی کامپوننت‌ها نمی‌گذارد، هرگز اجرا نمی‌شدند. حالا سراسری‌اند و برای همین هر
   انتخابگر زیرِ یک ریشه‌ی مخصوصِ خودش است. پاپ‌اور خارج از درختِ DOMِ فیلد رندر می‌شود (MudPopoverProvider)،
   پس پنل و اجزایش زیرِ .persian-calendar-popover‌اند نه .persian-date-picker. مقدارها بی‌تغییر آمده‌اند؛
   direction: rtl ِ ریشه عمداً نیامده، چون attributeِ dir همان را (و در زبان دیگر چیزِ درست را) می‌دهد.
   =========================================================================== */
.persian-date-picker {
    width: 100%;
}

.persian-date-picker .persian-date-label {
    display: block;
    width: 100%;
    padding: 0 3px;
    color: var(--ds-text);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
    text-align: start; /* UX-376: was right — wrong edge when the picker renders in an LTR page */
}

.persian-date-picker .persian-date-input {
    width: 100%;
}

/* UX-375: follows the document direction (the dir attribute), no forced rtl/right. */
.persian-date-picker .persian-date-input .mud-input-control,
.persian-date-picker .persian-date-input .mud-input,
.persian-date-picker .persian-date-input input {
    direction: inherit;
    text-align: start;
}

.persian-date-picker .persian-date-input .mud-input-root {
    min-height: var(--ds-control-h); /* UX-363 */
    border-radius: 12px;
    background: var(--ds-surface);
}

.persian-date-picker .persian-date-input .mud-input-outlined-border {
    border-color: var(--ds-border-strong);
    border-radius: 12px;
}

/* خطای فیلد (اجباری، تاریخِ نادرست یا بیرون از بازه) باید خطا دیده شود: قاعدهٔ بالا قابِ قرمزِ MudBlazor را
   می‌پوشاند و فیلدِ خطادار با فیلدِ خالیِ placeholder‌دار یکی می‌شد (UX-130). */
.persian-date-picker .persian-date-input .mud-input-error .mud-input-outlined-border,
.persian-date-picker .persian-date-input:hover .mud-input-error .mud-input-outlined-border,
.persian-date-picker .persian-date-input .mud-input-error:focus-within .mud-input-outlined-border {
    border-color: var(--mud-palette-error);
}

/* «فقط از تقویم» (Editable=false): ورودی readonly است ولی غیرفعال نیست؛ ظاهرِ طوسی و «ممنوع» ِ core-input
   نباید بگیرد، چون کلیک تقویم را باز می‌کند (UX-130). */
.persian-date-picker .is-pick-only .mud-input:has(input[readonly]),
.persian-date-picker .is-pick-only .mud-input input[readonly] {
    background: var(--ds-surface);
    cursor: pointer;
}

.persian-date-picker .is-pick-only .mud-input:has(input[readonly]) .mud-input-outlined-border {
    border-color: var(--ds-border-strong);
    border-style: solid;
}

.persian-calendar-popover .persian-calendar-panel {
    width: 336px;
    padding: 12px;
    border: 1px solid var(--ds-border);
    border-radius: 18px;
    background: var(--ds-surface);
    box-shadow: var(--ds-shadow-lg);
}

.persian-calendar-popover .persian-calendar-toolbar {
    min-height: 42px;
    padding-bottom: 8px;
}

.persian-calendar-popover .persian-calendar-title-row {
    min-width: 0;
}

.persian-calendar-popover .persian-month-select,
.persian-calendar-popover .persian-year-select {
    min-width: 96px;
}

.persian-calendar-popover .persian-month-select .mud-input-root,
.persian-calendar-popover .persian-year-select .mud-input-root {
    font-size: var(--ds-fs-sm);
    font-weight: var(--ds-fw-medium);
    color: var(--ds-text);
}

.persian-calendar-popover .persian-weekday {
    height: 24px;
    display: grid;
    place-items: center;
    color: var(--ds-faint);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
}

.persian-calendar-popover .persian-calendar-actions {
    padding-top: 10px;
}

.persian-calendar-popover .persian-calendar-actions .mud-button-root:not(.mud-switch-base) {
    border-radius: 10px;
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
}

/* ===========================================================================
   نگهبانِ صفحه — جایگاهِ ثابتِ «در حال بارگذاری» تا ناحیهٔ محتوا هنگامِ خواندنِ مجوزها فرو نریزد.
   =========================================================================== */
.screen-guard-pending {
    min-height: 50vh;
}

/* ===========================================================================
   دکمهٔ عملیاتیِ نوار گرید (CoreActionButton) — رنگِ هاور و دستگاهِ لمسی.

   کنتراست: پرشدنِ هاور پیش‌تر همیشه currentColor با متنِ سفید بود. نسبتِ کنتراست (فرمول WCAG 2.x
   روی مقدارهای واقعیِ UnigateTheme) و مقدارِ تازه:
     روشن — متن سفید روی:
       primary   #0062DF ۵٫۵۱ — بی‌تغییر (UX-340: پیش‌تر #0472FF با ۴٫۳۲ بود و این‌جا تیره می‌شد؛ حالا
                 خودِ پالت از AA می‌گذرد و آن قاعده حذف شد)
       success   #16A34A ۳٫۳۰  ->  ۸۰٪ + ۲۰٪ سیاه          = #12823B  ۴٫۹۰
       secondary #626F82 ۵٫۱۰ — بی‌تغییر (UX-352: پیش‌تر نارنجیِ #F15927 با ۳٫۳۹ بود و تیره می‌شد)
       error     #DC2626 ۴٫۸۳, info #2563EB ۵٫۱۷, tertiary #0355BD ۶٫۹۱ — بی‌تغییر
       default   #121820 (text-primary) ۱۷٫۸۴ — بی‌تغییر
     روشن — متنِ تیره #121820 روی warning #F59E0B: ۲٫۱۵ (سفید) -> ۸٫۳۱
     تیره — رنگ‌های پالت روشن‌اند، پس متنِ #0D1117 روی: success #34D399 ۹٫۸۴، warning #FBBF24 ۱۱٫۳۴،
       error #F87171 ۶٫۸۴، info #60A5FA ۷٫۴۴، tertiary #8FC1FF ۱۰٫۱۳، default #F0F3F7 ۱۷٫۰۰.
       primary #4D94FF ۶٫۳۰ (UX-340: primaryِ تیره روشن شد و متنِ رویش تیره است).
       secondary #8F9BAA ۶٫۷۰ با همان متنِ تیره (UX-352).
   قاعده‌های پایه (بالاتر) دست نخورده‌اند؛ این‌ها فقط دو متغیر می‌دهند و قاعده‌ی هاور را با همان
   اولویت و بعد از آن‌ها دوباره می‌نویسند.
   =========================================================================== */
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.mud-button-outlined-success {
    --core-action-fill: color-mix(in srgb, currentColor 80%, #000);
}

:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.mud-button-outlined-warning {
    --core-action-ink: #121820;
}

html[data-theme="dark"] :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.mud-button-outlined-primary,
html[data-theme="dark"] :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.mud-button-outlined-success,
html[data-theme="dark"] :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.mud-button-outlined-secondary,
html[data-theme="dark"] :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.mud-button-outlined-warning,
html[data-theme="dark"] :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.mud-button-outlined-error,
html[data-theme="dark"] :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.mud-button-outlined-info,
html[data-theme="dark"] :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.mud-button-outlined-tertiary,
html[data-theme="dark"] :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.mud-button-outlined-default {
    --core-action-ink: #0D1117;
}

:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button:hover:not(:disabled),
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button:focus-visible:not(:disabled) {
    background-color: var(--core-action-fill, currentColor);
}

:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button:hover:not(:disabled) .mud-button-label,
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button:focus-visible:not(:disabled) .mud-button-label,
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button:hover:not(:disabled) .mud-icon-root,
:is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button:focus-visible:not(:disabled) .mud-icon-root {
    color: var(--core-action-ink, #fff);
}

/* دستگاهِ لمسی هاور ندارد: عنوان همیشه باز می‌ماند (دکمهٔ بی‌عنوان نداریم؛ :empty برای احتیاط) و
   دکمه ۴۰px می‌شود تا هدفِ لمس کوچک نماند. روی ماوس هیچ‌چیز عوض نمی‌شود. */
@media (hover: none), (pointer: coarse) {
    body :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button.core-action-button {
        min-height: 40px !important;
        height: 40px;
        min-width: 40px !important;
    }

    body :is(.core-page, .core-form-dialog, .core-confirm-dialog) .mud-button-root.core-action-button .core-action-label:not(:empty) {
        max-width: 14rem;
        opacity: 1;
        margin-inline-start: 5px;
    }
}

/* ===========================================================================
   پنلِ کامنت (CommentPanel) — جعبهٔ نوشتن و فهرستِ کارتیِ کامنت‌ها.
   اینجا و نه در CommentPanel.razor.css: CSS ایزوله به ریشهٔ کامپوننت‌های Mud نمی‌رسد و پنل
   هم در صفحه (.core-page) و هم در دیالوگ (بیرون از .core-page) می‌نشیند؛ پس قاعده‌ها به
   .core-page گره نخورده‌اند. همهٔ رنگ‌ها از توکن‌های --ds-* است تا حالتِ تیره خودبه‌خود درست باشد.
   =========================================================================== */
.core-comment-panel {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}

.core-comment-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.core-comment-count {
    padding: 2px 10px;
    border: 1px solid var(--ds-border-soft);
    border-radius: var(--ds-radius-pill);
    background: var(--ds-surface-2);
    color: var(--ds-muted);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
    white-space: nowrap;
}

/* جعبهٔ نوشتن: یک قاب که با فوکوسِ textarea رنگِ اصلی می‌گیرد. */
.core-comment-compose {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius-lg);
    background: var(--ds-surface-2);
    transition: border-color var(--ds-dur-fast) var(--ds-ease),
                box-shadow var(--ds-dur-fast) var(--ds-ease);
}

.core-comment-compose:focus-within {
    border-color: color-mix(in srgb, var(--ds-primary) 45%, var(--ds-border));
    box-shadow: 0 0 0 3px var(--ds-primary-softer);
}

/* متنِ کامنت نثر است، نه مقدارِ یک فیلد: وزنِ عادی و فاصلهٔ خطِ خوانا به‌جای ۷۰۰ و .8rem ورودی‌ها.
   (با گزینندهٔ دقیق‌ترش بر قاعدهٔ پایهٔ .core-input می‌نشیند.) */
.core-comment-compose .core-comment-input textarea {
    font-size: var(--ds-fs-md);
    font-weight: var(--ds-fw-regular); /* UX-363: typed text is regular, as the comment above always said */
    line-height: 1.8;
}

.core-comment-compose-footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 16px;
}

.core-comment-submit {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-inline-start: auto;
}

.core-comment-submit-meta {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    text-align: end;
}

.core-comment-counter {
    color: var(--ds-muted);
    font-size: var(--ds-fs-xs);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.core-comment-counter.is-near {
    color: var(--ds-warning-strong); /* UX-352: a warning, so amber — orange is the brand only */
    font-weight: var(--ds-fw-medium);
}

.core-comment-counter.is-over,
.core-comment-limit-error {
    color: var(--ds-error);
    font-weight: var(--ds-fw-medium);
}

.core-comment-limit-error {
    font-size: var(--ds-fs-xs);
}

.core-comment-shortcut {
    color: var(--ds-faint);
    font-size: var(--ds-fs-xs);
    white-space: nowrap;
}

/* نشانِ «ارسال» به راست اشاره می‌کند؛ در راست‌به‌چپ باید به سمتِ جریانِ متن (چپ) باشد. */
[dir="rtl"] .core-comment-send .mud-button-icon-start svg {
    transform: scaleX(-1);
}

/* فهرست: هر کامنت یک کارت — آواتار، نویسنده و زمان، متن، و دکمهٔ حذف در انتهای ردیف. */
.core-comment-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.core-comment-item {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 14px;
    border: 1px solid var(--ds-border-soft);
    border-radius: var(--ds-radius-lg);
    background: var(--ds-surface);
    box-shadow: var(--ds-shadow-sm);
}

/* کامنتِ خودِ کاربر: ته‌رنگِ ملایمِ رنگِ اصلی؛ برچسبِ «(شما)» کنارِ نام همین را بی‌رنگ هم می‌گوید. */
.core-comment-item.is-own {
    border-color: color-mix(in srgb, var(--ds-primary) 25%, var(--ds-border-soft));
    background: var(--ds-primary-softer);
}

.core-comment-avatar {
    display: inline-flex;
    flex: 0 0 36px;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--ds-primary-soft);
    color: var(--ds-primary-strong);
    font-size: var(--ds-fs-lg);
    font-weight: var(--ds-fw-bold);
    line-height: 1;
    user-select: none;
}

.core-comment-item.is-own .core-comment-avatar {
    background: var(--ds-primary);
    color: var(--ds-primary-contrast);
}

.core-comment-body {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.core-comment-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    min-width: 0;
}

.core-comment-author {
    color: var(--ds-text);
    font-size: var(--ds-fs-md);
    font-weight: var(--ds-fw-medium);
    overflow-wrap: anywhere;
}

.core-comment-you {
    color: var(--ds-primary-strong);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
}

/* کامنتی که یک فرایند (کنترل کیفیت، بازرسی و ...) ساخته؛ همان جای نشانِ «شما» می‌نشیند. */
.core-comment-process {
    padding: 1px 8px;
    border: 1px solid color-mix(in srgb, var(--ds-primary) 35%, transparent);
    border-radius: var(--ds-radius-pill);
    background: var(--ds-primary-softer);
    color: var(--ds-primary-strong);
    font-size: var(--ds-fs-xs);
    font-weight: var(--ds-fw-medium);
    line-height: 1.6;
}


.core-comment-time {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 6px;
    color: var(--ds-muted);
    font-size: var(--ds-fs-xs);
}

.core-comment-time-relative {
    color: var(--ds-faint);
}

.core-comment-time-relative::before {
    content: "·";
    margin-inline-end: 6px;
}

/* شکستنِ خطی که کاربر نوشته حفظ می‌شود و کلمهٔ بلند (نشانی، شماره) از کارت بیرون نمی‌زند. */
.core-comment-text {
    margin: 4px 0 0;
    color: var(--ds-text-2);
    font-size: var(--ds-fs-md);
    line-height: 1.85;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.core-comment-actions {
    flex: 0 0 auto;
    margin-inline-start: auto;
}

@media screen and (max-width: 599.95px) {
    .core-comment-item {
        gap: 10px;
        padding: 10px 12px;
    }

    .core-comment-submit {
        width: 100%;
        justify-content: space-between;
    }

    .core-comment-submit-meta {
        align-items: flex-start;
        text-align: start;
    }
}

/* ===== انتخابگرِ ماهِ شمسی (UX-099) ===== */
.persian-month-panel {
    min-width: 280px;
}

.persian-month-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 8px;
}

.persian-month-year {
    font-size: var(--ds-fs-lg);
    font-weight: var(--ds-fw-bold);
}

.persian-month-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 4px;
    padding: 4px 8px 8px;
}

.persian-month-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 8px;
}

/* فیلدِ فقط‌خواندنیِ انتخاب‌گر (راننده): کلِ فیلد دکمهٔ بازکردنِ جدولِ انتخاب است و تایپ نمی‌پذیرد. ورودی کلیک
   نمی‌گیرد تا فوکوس روی خودِ div بماند (UX-138). */
.core-picker-field {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    cursor: pointer;
    border-radius: 4px;
}

.core-picker-field .mud-input,
.core-picker-field input {
    cursor: pointer;
}

.core-picker-field input {
    pointer-events: none;
}

.core-picker-field:focus-visible {
    outline: 2px solid var(--ds-primary);
    outline-offset: 2px;
}

/* ردیفِ جدولِ انتخاب راننده: کلیک یا Enter روی ردیف انتخاب می‌کند؛ رانندهٔ فعلیِ فیلد پررنگ است (UX-138). */
.core-table tbody tr.core-picker-row {
    cursor: pointer;
}

.core-table tbody tr.core-picker-row:focus-visible {
    outline: 2px solid var(--ds-primary);
    outline-offset: -2px;
}

.core-table tbody tr.is-selected > td {
    background-color: var(--ds-primary-soft);
}

/* «به‌روزرسانی» صفحهٔ جزئیات: نوارِ نازک بالای محتوای قبلی، نه صفحهٔ خالی (UX-194). */
.core-details-refreshing {
    margin-bottom: -4px;
    border-radius: 4px;
}

/* چند خطای سرور (UX-319): هر خطا سطرِ خودش را دارد — در اعلان فهرستِ نشانه‌دار، زیرِ فیلد هر پیام یک سطر —
   نه یک جملهٔ به هم چسبیده. متن‌ها با شکستنِ سطر جدا شده‌اند و pre-line همان را نشان می‌دهد. */
.mud-snackbar .mud-snackbar-content-message,
.mud-input-helper-text.mud-input-error {
    white-space: pre-line;
}

/* متنِ چندسطریِ خطا (فهرستِ نشانه‌دارِ UX-319) داخلِ جعبهٔ خطای دیالوگ: شکستِ سطرها نگه داشته می‌شود. فقط روی
   همان span که متن را دارد، نه کلِ MudAlert — آن‌جا شکستِ سطرِ کدِ Razor هم دیده می‌شد. */
.core-pre-line {
    white-space: pre-line;
}

/* =========================================================
   UX-362: rules moved out of scoped CSS that never matched.
   Blazor CSS isolation stamps b-* only on plain HTML elements of its own .razor file, so a
   rule aimed at a component root (MudStack/MudIcon/...) in a .razor.css is dead code. These
   three were intended and are not provided anywhere else, so they live here under the
   component's own class.
   ========================================================= */

/* MyNotificationsPanel: the «open» chevron is ChevronLeft; in LTR it must point forward. */
html[dir="ltr"] .nx-chevron {
    transform: scaleX(-1);
}

/* ScreenPermissionTree: a framed, self-scrolling tree (its root is a MudStack). Used in the
   role permissions dialog and on the role details page. */
.permission-tree {
    max-height: 52vh;
    overflow-y: auto;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    padding: 0.25rem 0;
}

/* UserUpsertDialog: the outlined MudAvatar in each section header is tinted primary instead
   of the default grey outline. */
.core-dialog-section-icon {
    width: 42px;
    height: 42px;
    color: var(--ds-primary-strong);
    background: var(--ds-primary-soft);
    border-color: var(--ds-primary);
}

} /* end @layer core */

/* =========================================================================================
   mud.overrides (UX-361) - the only place that may beat a MudBlazor !important utility.

   MudBlazor sits in the lowest cascade layer, and among !important declarations the EARLIER layer
   wins, so its utility classes (.align-center, .flex-row, .d-flex, .mud-primary-text ...) beat every
   !important in core and app. A rule that has to win over a utility the markup puts on the same
   element therefore lives in mud.overrides, a sub-layer ordered before MudBlazor itself (App.razor).
   Only !important declarations belong here: a normal declaration in this layer loses to everything.
   ========================================================================================= */
@layer mud.overrides {
    /* MudStack AlignItems (Start on most pages, Center on some) - the page header always aligns to the top. */
    .core-page-header {
        align-items: flex-start !important;
    }

    /* MudLink adds .mud-primary-text; a link used as a document title or a value keeps the text colour of
       its slot, as it did before the layers (the link affordance is the underline on hover). */
    .core-hero-title.mud-link,
    .core-info-value.mud-link {
        color: var(--ds-text) !important;
    }

    .core-hero-subtitle.mud-link {
        color: var(--ds-muted) !important;
    }

    /* UX-380: MudDataGrid wraps LoadingContent in a .my-3 (12px !important margins); the skeleton rows sit flush
       under the header so they line up with where the data rows will be. */
    .core-data-grid .mud-table-empty-row > .my-3:has(> .core-grid-skeleton) {
        margin-block: 0 !important;
    }

    /* Soft status chips (UX-341): the ripple follows the chip ink, not MudBlazor's own !important ripple colour. */
    .mud-chip:is(.mud-chip-filled, .mud-chip-text, .mud-chip-outlined):is(.mud-chip-color-success, .mud-chip-color-warning, .mud-chip-color-error, .mud-chip-color-info, .mud-chip-color-secondary, .mud-chip-color-tertiary) {
        --mud-ripple-color: var(--uni-chip-fg) !important;
    }

    /* Small screens: these are MudStack Row="true" (.flex-row) and stack vertically. */
    @media screen and (max-width: 959.95px) {
        .core-page-header,
        .core-filter-footer {
            align-items: stretch !important;
            flex-direction: column !important;
        }

        .core-hero-content {
            align-items: flex-start !important;
            flex-direction: column !important;
        }
    }
}
