/* ===========================================================================
   پایهٔ سیستمِ طراحیِ فروشگاه — فاز ۵۹.۱
   ===========================================================================

   این فایل روی **هر صفحهٔ فروشگاه** بار می‌شود، در هر چهار قالب، پیش از
   `theme-design.css`ِ خودِ آن قالب.

   دو چیز می‌دهد و بیشتر از این نمی‌دهد:

     ۱. **مقیاس‌ها** — تایپوگرافی، فاصله، عمق، سرعتِ حرکت. اعداد یک بار
        اینجا تصمیم گرفته می‌شوند و همه‌جا از همین‌جا خوانده می‌شوند.
     ۲. **حالت‌ها** — hover، focus، disabled، loading. چیزی که یک رابط را
        «کارکرده» نشان می‌دهد و نبودش را کسی نمی‌تواند نام ببرد ولی
        همه حس می‌کنند.

   ── قاعده‌ای که این فایل نمی‌شکند ─────────────────────────────────────

   **هیچ انتخابگرِ عنصری ندارد.** نه `button`، نه `.card`، نه `a`. فقط
   `:root` و کلاس‌هایی که با `ds-` شروع می‌شوند.

   دلیلش این است که این فایل کنارِ چند هزار خط CSSِ قالب‌های خریداری‌شده
   می‌نشیند. یک `button { padding: … }` بی‌گناه، در چهار قالب چهار جای
   نامربوط را جابه‌جا می‌کند و هیچ‌کس نمی‌فهمد از کجاست.

   تنها استثنا `:focus-visible` است، که پایین توضیح داده شده و عمدی است.

   ── چرا `--ds-` و نه `--theme-` ────────────────────────────────────────

   `--theme-*` از دیتابیس می‌آید: چیزی که **فروشنده** در پنل تعیین می‌کند.
   `--ds-*` از همین فایل می‌آید: چیزی که **طراحیِ سامانه** تعیین می‌کند و
   فروشنده کاری با آن ندارد.

   مقیاسِ پیمانه‌ای یک تصمیمِ زیبایی‌شناسی نیست، مهندسیِ خوانایی است؛
   گذاشتنش در پنل یعنی دادنِ اهرمی به کسی که با آن فقط می‌تواند صفحه‌اش
   را بدتر کند. در عوض هر `--ds-*` روی `--theme-*` سوار است، پس عوض کردنِ
   «تراکم» یا «عمق سایه» در پنل کلِ مقیاس را با هم جابه‌جا می‌کند.

   ── نقاطِ شکست، یک بار ─────────────────────────────────────────────────

   CSS اجازه نمی‌دهد `var()` داخلِ `@media` بیاید، پس نقاطِ شکست نمی‌توانند
   توکن باشند. جایشان اینجاست تا حداقل **نوشته** شده باشند:

       ≥  576px   موبایلِ افقی
       ≥  768px   تبلت
       ≥  992px   دسکتاپ        ← جایی که `--theme-columns` معنا پیدا می‌کند
       ≥ 1200px   دسکتاپِ عریض
       ≥ 1400px   نمایشگرِ بزرگ

   همان اعدادِ بوت‌استرپ‌اند و عمداً: هر چهار قالب رویش نوشته شده‌اند و
   یک مجموعهٔ دومِ کمی متفاوت یعنی دو ردیفی که در ۹۹۱px با هم نمی‌خوانند.
   =========================================================================== */

:root {
    /* ---------------------------------------------------------------------
       مقیاسِ تایپوگرافی — پیمانه‌ای ۱٫۲۵ روی پایهٔ ۱rem
       ---------------------------------------------------------------------
       اندازه‌های دلبخواه همان چیزی است که یک صفحه را شلوغ نشان می‌دهد
       بدونِ اینکه بشود گفت چرا. با یک مقیاس، هر اندازه نسبتِ مشخصی با
       بغل‌دستی‌اش دارد. */
    --ds-text-xs: 0.8rem;
    --ds-text-sm: 0.9rem;
    --ds-text-base: 1rem;
    --ds-text-lg: 1.125rem;
    --ds-text-xl: 1.4rem;
    --ds-text-2xl: 1.75rem;
    --ds-text-3xl: 2.1rem;

    /* قلمِ تک‌عرض — فاز ۶۷.
       جایی لازم می‌شود که کاراکترها را باید **یکی‌یکی** رونویسی کرد:
       کدِ بازیابیِ عاملِ دوم، کلیدِ دستیِ Authenticator، شمارهٔ پیگیری.
       در قلمِ معمولی `l` و `1` و `I` یک شکل‌اند، و کاربری که کدِ
       بازیابی را اشتباه رونویسی کند تازه شبی می‌فهمد که گوشی‌اش گم
       شده. این یکی از آن چیزهاست که هر قالبی لازمش دارد و هیچ قالبی
       چیزِ متفاوتی از آن نمی‌خواهد — پس اینجاست و نه در قالب‌ها. */
    --ds-font-mono: ui-monospace, 'Cascadia Mono', 'Segoe UI Mono',
                    'Roboto Mono', Menlo, Consolas, monospace;

    /* ارتفاعِ خط: هرچه متن درشت‌تر، خط فشرده‌تر. یک عددِ ثابت برای هر دو،
       یا تیترها را باز می‌کند یا پاراگراف‌ها را خفه. */
    --ds-leading-tight: 1.25;
    --ds-leading-snug: 1.5;
    --ds-leading-normal: 1.75;
    --ds-leading-loose: 1.9;

    /* ---------------------------------------------------------------------
       مقیاسِ فاصله — از `--theme-density` که یک تنظیمِ قالب است
       ---------------------------------------------------------------------
       یعنی فروشنده‌ای که «فشرده‌تر» می‌خواهد یک عدد را عوض می‌کند و کلِ
       ریتمِ صفحه با هم جابه‌جا می‌شود. */
    --ds-space-1: calc(var(--theme-density, 16px) * 0.25);
    --ds-space-2: calc(var(--theme-density, 16px) * 0.5);
    --ds-space-3: var(--theme-density, 16px);
    --ds-space-4: calc(var(--theme-density, 16px) * 1.5);
    --ds-space-5: calc(var(--theme-density, 16px) * 2.5);
    --ds-space-6: calc(var(--theme-density, 16px) * 4);

    /* ---------------------------------------------------------------------
       حرکت
       ---------------------------------------------------------------------
       سه سرعت و یک منحنی. `--ds-ease` بیرون‌رو است (`ease-out`): چیزی که
       سریع شروع و آرام تمام می‌شود، پاسخ‌گو حس می‌شود؛ `ease-in` تنبل. */
    --ds-fast: 120ms;
    --ds-normal: 220ms;
    --ds-slow: 380ms;
    --ds-ease: cubic-bezier(0.2, 0, 0.2, 1);

    /* ---------------------------------------------------------------------
       عرضِ محتوا
       ---------------------------------------------------------------------
       `min()` یعنی روی صفحهٔ باریک حاشیهٔ ۱rem می‌ماند و روی صفحهٔ بزرگ
       متن بی‌نهایت پهن نمی‌شود. */
    --ds-container: min(100% - 2rem, 1600px);
    --ds-container-narrow: min(100% - 2rem, 1100px);
    /* طولِ خطِ خوانا. بیش از ۷۵ نویسه در هر خط، چشم را موقعِ برگشتن گم
       می‌کند. */
    --ds-measure: 70ch;

    /* ---------------------------------------------------------------------
       حلقهٔ focus
       --------------------------------------------------------------------- */
    --ds-ring: 2px;
    --ds-ring-offset: 2px;
}

/* ---------------------------------------------------------------------------
   دیده‌شدنِ focus — تنها انتخابگرِ غیرِ `ds-` این فایل
   ---------------------------------------------------------------------------

   هر سه قالبِ خریداری‌شده جایی `outline: none` نوشته‌اند. این کار روی
   `:focus` رایج است و نتیجه‌اش یک صفحه است که با صفحه‌کلید **قابلِ
   ناوبری نیست**: مکان‌نما حرکت می‌کند و هیچ‌جا دیده نمی‌شود.

   `:focus-visible` — و نه `:focus` — یعنی این حلقه فقط وقتی می‌آید که
   مرورگر تشخیص بدهد کاربر با صفحه‌کلید ناوبری می‌کند، پس کلیکِ ماوس
   حلقه‌ای روی دکمه نمی‌گذارد و همان چیزی که آن `outline: none` می‌خواست
   حل کند، حل می‌ماند.

   (ui-ux-pro-max ← Accessibility / Focus Visible)
   --------------------------------------------------------------------------- */
body :is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: var(--ds-ring) solid var(--theme-accent, #0da487);
    outline-offset: var(--ds-ring-offset);
    border-radius: var(--theme-radius-sm, 4px);
}

/* ---------------------------------------------------------------------------
   دکمه
   --------------------------------------------------------------------------- */

.ds-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ds-space-2);
    /* ۴۴px کف‌ترین هدفِ لمسیِ قابلِ اتکاست. کوچک‌تر از آن روی موبایل
       خطای کلیک می‌سازد. (ui-ux-pro-max ← Touch Target Size) */
    min-height: 44px;
    padding: var(--ds-space-2) var(--ds-space-4);
    border: 1px solid transparent;
    border-radius: var(--theme-radius-sm, 4px);
    background: var(--theme-accent, #0da487);
    color: #fff;
    font: inherit;
    font-size: var(--ds-text-sm);
    font-weight: 700;
    line-height: var(--ds-leading-tight);
    text-decoration: none;
    cursor: pointer;
    transition: background var(--ds-fast) var(--ds-ease),
                border-color var(--ds-fast) var(--ds-ease),
                transform var(--ds-fast) var(--ds-ease);
}

.ds-button:hover { background: var(--theme-accent-strong, #0b8a71); }
.ds-button:active { transform: translateY(1px); }

.ds-button--outline {
    background: transparent;
    border-color: var(--theme-accent, #0da487);
    color: var(--theme-accent, #0da487);
}

.ds-button--outline:hover {
    background: var(--theme-accent-soft, #ecfdf5);
}

.ds-button--ghost {
    background: transparent;
    color: var(--theme-ink, #222);
    font-weight: 600;
}

.ds-button--ghost:hover {
    background: color-mix(in srgb, var(--theme-ink, #222) 6%, transparent);
}

.ds-button--small {
    min-height: 34px;
    padding: var(--ds-space-1) var(--ds-space-3);
    font-size: var(--ds-text-xs);
}

/* حالتِ غیرفعال، برای هر سه گونه. `pointer-events` برداشته نمی‌شود چون
   آن‌وقت مرورگر نشانگرِ «ممنوع» را هم نشان نمی‌دهد و کاربر فکر می‌کند
   دکمه خراب است. */
.ds-button:disabled,
.ds-button[aria-disabled='true'] {
    opacity: .55;
    cursor: not-allowed;
    transform: none;
}

.ds-button:disabled:hover,
.ds-button[aria-disabled='true']:hover {
    background: var(--theme-accent, #0da487);
}

/* ---------------------------------------------------------------------------
   حالتِ در حالِ کار
   ---------------------------------------------------------------------------

   `aria-busy` و نه یک کلاس، چون این حالت را صفحه‌خوان هم باید بشنود. متنِ
   دکمه سرِ جایش می‌ماند و فقط محو می‌شود؛ عوض کردنش با «صبر کنید» عرضِ
   دکمه را می‌پراند و صفحه را تکان می‌دهد.
   --------------------------------------------------------------------------- */
.ds-button[aria-busy='true'] {
    color: transparent;
    position: relative;
    pointer-events: none;
}

.ds-button[aria-busy='true']::after {
    content: '';
    position: absolute;
    /* `inset: 0` به‌علاوهٔ `margin: auto` یعنی دقیقاً وسطِ دکمه، هر
       اندازه‌ای که دکمه داشته باشد. بدونِ این، شمرنده جای متنِ محوشده
       می‌نشیند که در دکمهٔ چندخطی وسط نیست. */
    inset: 0;
    margin: auto;
    width: 1.1em;
    height: 1.1em;
    border: 2px solid currentColor;
    border-block-start-color: #fff;
    border-radius: 50%;
    animation: ds-spin .7s linear infinite;
    /* `currentColor` شفاف است، پس رنگِ حلقه از خودِ دکمه می‌آید. */
    color: #fff;
    opacity: .85;
}

.ds-button--outline[aria-busy='true']::after,
.ds-button--ghost[aria-busy='true']::after {
    border-block-start-color: var(--theme-accent, #0da487);
    color: var(--theme-accent, #0da487);
}

@keyframes ds-spin {
    to { transform: rotate(360deg); }
}

/* ---------------------------------------------------------------------------
   کارت
   --------------------------------------------------------------------------- */

.ds-card {
    display: flex;
    flex-direction: column;
    background: var(--theme-surface, #fff);
    border: 1px solid var(--theme-line, #e5e7eb);
    border-radius: var(--theme-radius, 8px);
    box-shadow: var(--theme-shadow-sm, none);
    overflow: hidden;
    transition: border-color var(--ds-normal) var(--ds-ease),
                box-shadow var(--ds-normal) var(--ds-ease),
                transform var(--ds-normal) var(--ds-ease);
}

/* بلند شدنِ کارت زیرِ اشاره‌گر. `:focus-within` هم هست تا همان بازخورد
   با صفحه‌کلید هم بیاید — کارتی که فقط با ماوس واکنش نشان بدهد، برای
   نیمی از کاربرها بی‌جان است. */
.ds-card:hover,
.ds-card:focus-within {
    border-color: var(--theme-accent, #0da487);
    box-shadow: var(--theme-shadow-md, none);
    transform: translateY(-2px);
}

.ds-card__body { padding: var(--ds-space-3); }

.ds-card__media {
    position: relative;
    display: block;
    aspect-ratio: 1 / 1;
    background: var(--theme-accent-soft, #f8fafc);
}

.ds-card__media img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* ---------------------------------------------------------------------------
   کادرِ ورودی
   --------------------------------------------------------------------------- */

.ds-input {
    width: 100%;
    min-height: 44px;
    padding: var(--ds-space-2) var(--ds-space-3);
    border: 1px solid var(--theme-line, #d1d5db);
    border-radius: var(--theme-radius-sm, 4px);
    background: var(--theme-surface, #fff);
    color: var(--theme-ink, #222);
    font: inherit;
    font-size: var(--ds-text-sm);
    transition: border-color var(--ds-fast) var(--ds-ease);
}

.ds-input:hover { border-color: var(--theme-ink-muted, #9ca3af); }
.ds-input:disabled { opacity: .6; cursor: not-allowed; }

/* خطا با رنگ **و** با متن. رنگ به‌تنهایی برای کسی که رنگ‌ها را متفاوت
   می‌بیند هیچ اطلاعاتی ندارد. (ui-ux-pro-max ← Color Is Not Information) */
.ds-input[aria-invalid='true'] { border-color: #dc2626; }

.ds-field__error {
    display: block;
    margin-block-start: var(--ds-space-1);
    font-size: var(--ds-text-xs);
    color: #dc2626;
}

.ds-field__hint {
    display: block;
    margin-block-start: var(--ds-space-1);
    font-size: var(--ds-text-xs);
    color: var(--theme-ink-muted, #6b7280);
}

/* ستارهٔ «اجباری». تا فاز ۶۶ هرجا لازم بود `style="color:red"` نوشته
   می‌شد — نودوچند بار در قالب‌ها — که نه از پنل عوض می‌شود و نه با
   Content-Security-Policyِ سخت‌گیر کنار می‌آید.
   `aria-hidden` نیست چون `required` روی خودِ ورودی نشسته و صفحه‌خوان
   آن را می‌خواند؛ این ستاره فقط نشانهٔ دیداری است. */
.ds-required {
    color: #dc2626;
    margin-inline-start: 2px;
}

/* ---------------------------------------------------------------------------
   ابزارها
   --------------------------------------------------------------------------- */

.ds-container { width: var(--ds-container); margin-inline: auto; }
.ds-container--narrow { width: var(--ds-container-narrow); margin-inline: auto; }

/* متنی که فقط صفحه‌خوان می‌خواندش. بوت‌استرپ `visually-hidden` را دارد
   ولی هر چهار قالب بوت‌استرپ ندارند، و این لایه در همه‌شان بار می‌شود. */
.ds-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* هر چیزِ کلیک‌شدنی‌ای که دکمه نیست ولی باید روی موبایل قابلِ زدن باشد —
   لینکِ «مشاهدهٔ همه»، آیکونِ بستن، برگهٔ یک تب. */
.ds-tap {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* بریدنِ متن بعد از n خط. بدونِ آن، نامِ بلندِ یک محصول ردیفِ کارت‌ها را
   نامرتب می‌کند. */
.ds-clamp-1,
.ds-clamp-2,
.ds-clamp-3 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ds-clamp-1 { -webkit-line-clamp: 1; }
.ds-clamp-2 { -webkit-line-clamp: 2; }
.ds-clamp-3 { -webkit-line-clamp: 3; }

/* اسکلتِ بارگذاری. ارتفاعِ رزروشده همان چیزی است که نمی‌گذارد صفحه
   موقعِ رسیدنِ محتوا بپرد. */
.ds-skeleton {
    border-radius: var(--theme-radius, 8px);
    background: linear-gradient(
        90deg,
        var(--theme-accent-soft, #f3f4f6) 25%,
        color-mix(in srgb, var(--theme-accent-soft, #f3f4f6) 60%, #fff) 50%,
        var(--theme-accent-soft, #f3f4f6) 75%);
    background-size: 200% 100%;
    animation: ds-shimmer 1.4s linear infinite;
}

@keyframes ds-shimmer {
    from { background-position: 200% 0; }
    to { background-position: -200% 0; }
}

/* ---------------------------------------------------------------------------
   ترجیحِ حرکتِ کمتر
   ---------------------------------------------------------------------------

   یک ترجیح است و نه یک سلیقه: بعضی‌ها با انیمیشن سرگیجه می‌گیرند. اینجا
   یک بار و برای کلِ لایه نوشته می‌شود، نه هر جا که یک `transition` هست.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    .ds-button,
    .ds-card,
    .ds-input {
        transition: none;
    }

    .ds-button:active,
    .ds-card:hover,
    .ds-card:focus-within {
        transform: none;
    }

    .ds-skeleton { animation: none; }

    /* شمرندهٔ دکمهٔ «در حالِ کار» می‌ماند: بازخوردِ لازم است و نه تزئین.
       ولی کندتر می‌چرخد. */
    .ds-button[aria-busy='true']::after { animation-duration: 2s; }
}

/* ── جایگاهِ تبلیغِ کناری — فاز ۶۴ (D57) ─────────────────────────────────
 *
 * لایهٔ `.ds-*` است و نه واژگانِ یک قالب، چون هر چهار قالب همین partial را
 * رندر می‌کنند و شکلِ یک بنرِ کناری تصمیمِ هویتیِ قالب نیست — اندازه‌اش را
 * ستونی که در آن نشسته تعیین می‌کند.
 *
 * قالبی که نظرِ دیگری داشته باشد همین انتخابگرها را در `theme-design.css`
 * خودش بازنویسی می‌کند؛ آن فایل بعد از این بار می‌شود.
 */

.ds-promo {
    margin-block-end: var(--ds-space-3, 16px);
}

.ds-promo__link {
    display: block;
    position: relative;
    overflow: hidden;
    border-radius: var(--theme-radius, 8px);
    text-decoration: none;
}

.ds-promo__image {
    display: block;
    width: 100%;
    height: auto;
    transition: transform var(--ds-slow, 380ms) var(--ds-ease, ease);
}

.ds-promo__link:hover .ds-promo__image {
    transform: scale(1.03);
}

.ds-promo__caption {
    position: absolute;
    inset-inline: 0;
    inset-block-end: 0;
    padding: var(--ds-space-3, 16px);
    font-size: var(--ds-text-sm, 0.9rem);
    line-height: var(--ds-leading-snug, 1.5);
    color: #fff;
    /* گرادیان و نه یک زمینهٔ تو‌پُر: متن باید خوانده شود بی آنکه نیمهٔ
       پایینیِ تصویر پوشانده شود. */
    background: linear-gradient(to top, rgba(0, 0, 0, 0.75), transparent);
}

/* ---------------------------------------------------------------------------
   پیام‌ها — فاز ۶۶

   `toast-messages.js` وقتی toastr نباشد این نشانه‌گذاری را می‌سازد.
   بیگ‌دیل تا فاز ۶۶ نسخهٔ خودش را با `style=`ِ درون‌خطی می‌ساخت.

   ساختار اینجاست و **رنگ از توکن می‌آید**، پس هر قالب همان‌طور که
   شکلِ خودش را دارد پیام هم به شکلِ خودش درمی‌آید — و می‌تواند این
   قاعده‌ها را بازنویسی کند.
   --------------------------------------------------------------------------- */

.ds-toast-region {
    position: fixed;
    inset-block-end: var(--ds-space-3, 16px);
    inset-inline-start: var(--ds-space-3, 16px);
    z-index: 2000;
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-2, 8px);
    max-width: min(92vw, 380px);
    /* ناحیه خودش کلیک را نمی‌گیرد؛ فقط خودِ پیام‌ها. وگرنه یک نوارِ
       نامرئی روی گوشهٔ صفحه می‌ماند و دکمهٔ زیرش کار نمی‌کند. */
    pointer-events: none;
}

.ds-toast {
    pointer-events: auto;
    padding: var(--ds-space-2, 8px) var(--ds-space-3, 16px);
    border-radius: var(--theme-radius-sm, 4px);
    border: 1px solid var(--theme-line, #d1d5db);
    background: var(--theme-surface, #fff);
    color: var(--theme-ink, #222);
    font-size: var(--ds-text-sm, 0.9rem);
    line-height: var(--ds-leading-snug, 1.5);
    box-shadow: var(--theme-shadow-md, 0 6px 18px rgb(0 0 0 / 12%));
    /* نوارِ رنگیِ کناری سطح را از رنگ جدا می‌کند: کسی که رنگ‌ها را
       متفاوت می‌بیند هم مرزِ پیام را می‌بیند. */
    border-inline-start-width: 3px;
}

.ds-toast--success { border-inline-start-color: #16a34a; }
.ds-toast--info    { border-inline-start-color: #2563eb; }
.ds-toast--warning { border-inline-start-color: #d97706; }
.ds-toast--error   { border-inline-start-color: #dc2626; }

/* ---------------------------------------------------------------------------
   قیمتِ خط‌خورده و قیمتِ تازه — فاز ۷۵
   ---------------------------------------------------------------------------

   کارتِ محصول این دو را پشتِ سرِ هم می‌گذارد و هیچ فاصله‌ای بینشان
   نبود. نتیجه‌اش روی کالای تخفیف‌دار یک رشتهٔ عددیِ به‌هم‌چسبیده بود —
   «۲,۸۷۳,۵۰۰۳,۹۹۱,۰۰۰» — که نه قیمتِ قبلی خوانده می‌شد و نه قیمتِ
   فعلی. با فاصله‌گذاری، دو عدد دوباره دو عدد می‌شوند.

   رنگ از توکن می‌آید و نه `style="color:red"`ِ درون‌خطی: قالبِ تیره
   قرمزِ خالص را نمی‌خواهد، و قاعده‌ای که در HTML نوشته شده باشد هیچ
   قالبی نمی‌تواند عوضش کند. */

.ds-price__was {
    margin-inline-end: var(--ds-space-2, 8px);
    color: var(--ds-price-was, #ef4444);
    font-weight: 500;
    opacity: .85;
    /* عددها هم‌عرض، تا دو قیمتِ کنارِ هم تکان نخورند. */
    font-variant-numeric: tabular-nums;
}

.ds-price__now {
    font-weight: 700;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
