@charset "UTF-8";
/* ============================================================
   حساب لند — سیستم طراحی
   جهت هنری: «دفتر فلز گران‌بها» — زغالی و طلایی، برگرفته از
   خود آیکن اپ. مبلغ قهرمان صفحه است؛ بقیه چیزها آرام می‌مانند.
   ============================================================ */

/* ---------- فونت (محلی؛ اگر نبود، فونت سیستم) ----------
   یک فایل variable به‌جای سه فایل ثابت:
     سه فایل ثابت  → ۱۵۳ کیلوبایت در ۳ درخواست
     variable subset → ۸۵ کیلوبایت در ۱ درخواست
   subset شامل لاتین، بلوک عربی/فارسی، فرم‌های نمایشی، نیم‌فاصله و
   نشانه‌گذاری است. همه‌ی ویژگی‌های OpenType نگه داشته شده‌اند —
   به‌ویژه tnum که این فایل در ۱۱ جا برای هم‌ترازی مبالغ صدایش می‌زند،
   و kern که نبودش فاصله‌ی حروف را خراب می‌کند.
   با font-weight: 100 900 همه‌ی وزن‌ها از همین یک فایل می‌آیند.

   مسیر فونت '../fonts/…' است: مرورگر خودِ این فایل را از
   assets/css/ می‌گیرد، پس مبدأ آدرس‌های نسبی همان پوشه است. */
@font-face {
    font-family: 'Vazirmatn';
    /* نسبت به همین فایل: assets/css/ → assets/fonts/ */
    src: url('../fonts/Vazirmatn.woff2') format('woff2');
    font-weight: 100 900; font-style: normal; font-display: swap;
}

/* ============================================================
   ۱. توکن‌ها
   ============================================================ */
:root {
    /* جوهر */
    --ink:        #15171c;
    --ink-soft:   #2a2e36;
    --muted:      #6f7580;
    --muted-2:    #9aa0ab;
    --line:       #e6e7ea;
    --line-soft:  #f0f1f3;
    --surface:    #ffffff;
    --paper:      #f5f5f3;

    /* برند — این‌ها هرگز در حالت شب معکوس نمی‌شوند */
    --brand:      #15171c;   /* سطح زغالی (کارت مانده، دکمه اصلی، چیپ فعال) */
    --brand-on:   #ffffff;   /* متن روی سطح زغالی */

    /* طلا — از آیکن خود اپ */
    --gold:       #b8862f;
    --gold-lift:  #d9a441;
    --gold-wash:  #fbf3e2;

    /* معنایی */
    --in:         #16794f;
    --in-wash:    #e8f6ef;
    --out:        #c33c3c;
    --out-wash:   #fdeded;
    --warn-wash:  #fef4e2;
    --warn-ink:   #94620d;

    /* شکل */
    --r-sm: 10px;
    --r:    14px;
    --r-lg: 18px;
    --r-pill: 999px;

    --sh:    0 1px 2px rgba(21,23,28,.05), 0 1px 8px rgba(21,23,28,.04);
    --sh-lg: 0 8px 28px rgba(21,23,28,.12);

    --sidebar-w: 250px;

    /* سازگاری با نام‌های قدیمی که هنوز در قالب‌ها هستند */
    --color-black: var(--ink);
    --color-dark: var(--ink-soft);
    --color-gray-900: var(--ink-soft);
    --color-gray-700: #4d525c;
    --color-gray-500: var(--muted);
    --color-gray-300: var(--line);
    --color-gray-100: var(--line-soft);
    --color-white: var(--surface);
    --color-accent: var(--gold);
    --color-accent-dark: var(--gold);
    --color-income: var(--in);
    --color-income-bg: var(--in-wash);
    --color-expense: var(--out);
    --color-expense-bg: var(--out-wash);
    --radius: var(--r);
    --radius-sm: var(--r-sm);
    --shadow-sm: var(--sh);
    --shadow-md: var(--sh-lg);
}

/* ---------- حالت شب ---------- */
html[data-theme="dark"] {
    --ink:        #eceef1;
    --ink-soft:   #cdd1d8;
    --muted:      #8d939e;
    --muted-2:    #6d737e;
    --line:       #2b3037;
    --line-soft:  #23272d;
    --surface:    #191c21;
    --paper:      #101216;

    /* در حالت شب سطح برند کمی روشن‌تر از پس‌زمینه تا دیده شود */
    --brand:      #23272e;
    --brand-on:   #f3f4f6;

    --gold:       #dcab52;
    --gold-lift:  #eec777;
    --gold-wash:  #2a2317;

    --in:         #4ec98a;
    --in-wash:    #16301f;
    --out:        #f07070;
    --out-wash:   #34191b;
    --warn-wash:  #322715;
    --warn-ink:   #e0b45f;

    --sh:    none;
    --sh-lg: 0 10px 30px rgba(0,0,0,.5);
}

/* ============================================================
   ۲. پایه
   ============================================================ */
* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
    font-family: 'Vazirmatn', -apple-system, BlinkMacSystemFont, 'Segoe UI', Tahoma, sans-serif;
    background: var(--paper);
    color: var(--ink);
    font-size: 15px;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    -webkit-text-size-adjust: 100%;
}

button, input, select, textarea { font-family: inherit; }
button { cursor: pointer; }
a { color: inherit; }

/* هر عددی: هم‌عرض، تا ستون مبلغ‌ها تکان نخورد */
.tx-row-amount, .mc-value, .stats-value, .debt-amount, .tx-day-total,
.cat-breakdown-amount, .cat-detail-amount, .summary-box .value, .amount-cell {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    direction: ltr;
}

:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
    * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ============================================================
   ۳. چیدمان
   ============================================================ */
.app-shell { display: flex; min-height: 100vh; }
.main-content { flex: 1; min-width: 0; }

.topbar {
    display: flex;
    align-items: center;
    gap: 12px;
    /* حاشیه‌ی امنِ بالا به padding اضافه می‌شود، وگرنه در حالت نصب‌شده
       روی آیفون، عنوان صفحه زیر ناچ / Dynamic Island می‌رود.
       دلیلش apple-mobile-web-app-status-bar-style=black-translucent است
       که عمداً گذاشته شده تا نوار وضعیت هم‌رنگ اپ باشد — ولی همان باعث
       می‌شود وب‌ویو تا بالای صفحه کشیده شود. */
    padding: calc(13px + env(safe-area-inset-top)) 16px 13px;
    background: var(--surface);
    border-bottom: 1px solid var(--line-soft);
    /* ⛔ چسبندگی روی موبایل هم لازم است، نه فقط دسکتاپ.
       در مرورگر، نوارِ خودِ سافاری بالای صفحه است و محتوا هرگز زیر
       ساعت نمی‌رود. ولی در حالت **نصب‌شده** (`apple-mobile-web-app-capable`
       + `status-bar-style=black-translucent`) وب‌ویو تا بالای صفحه کشیده
       می‌شود و هیچ نوارِ مرورگری نیست: با اولین اسکرول، همین نوار بالا
       می‌رفت و کارت و عنوان می‌رفتند **زیر Dynamic Island**، جایی که iOS
       ساعت و باتری را روی صفحه می‌کشد. یعنی باگ فقط روی گوشیِ نصب‌شده
       دیده می‌شد و در وب هرگز.
       حالا نوار می‌ماند و padding بالایش (که حاشیه‌ی امن را دارد) همیشه
       پشتِ ساعت یک پس‌زمینه‌ی مات می‌گذارد. */
    position: sticky;
    top: 0;
    z-index: 100;
}
.page-title { font-size: 17px; font-weight: 700; letter-spacing: -.2px; flex: 1; }
.topbar-user { display: flex; align-items: center; gap: 9px; }
.user-name { font-size: 13px; color: var(--muted); }

.user-role-badge {
    font-size: 10.5px;
    font-weight: 700;
    padding: 3px 9px;
    border-radius: var(--r-pill);
}
.badge-admin { background: var(--gold-wash); color: var(--gold); }
.badge-user  { background: var(--line-soft); color: var(--muted); }

.menu-toggle {
    background: none; border: none; color: var(--ink);
    display: none; padding: 4px; line-height: 0;
}

.page-content { padding: 16px; max-width: 720px; margin: 0 auto; }
/* ⛔ ۷۲۰ پیکسل عرضِ **خواندن** است و برای همه‌ی صفحه‌های این اپ درست
   است، ولی یک جدولِ هفت‌ستونه را روی دسکتاپ در نصفِ صفحه له می‌کند —
   در حالی که ۴۵۰ پیکسل کنارش خالی مانده. صفحه‌ای که جدولِ پهن دارد با
   `$pageWide = true` پیش از `header.php` این را باز می‌کند.
   ⚠ روی موبایل بی‌اثر است (عرضِ پنجره از هر دو کمتر است)، پس چیزی در
     نمای گوشی عوض نمی‌شود. */
.page-content.is-wide { max-width: 1120px; }

.theme-toggle {
    background: none; border: none; padding: 7px;
    color: var(--muted); border-radius: var(--r-sm); line-height: 0;
}
.theme-icon-sun { display: none; }
html[data-theme="dark"] .theme-icon-moon { display: none; }
html[data-theme="dark"] .theme-icon-sun  { display: block; }

/* ============================================================
   ۴. منوی کناری (فقط دسکتاپ)
   ============================================================ */
.sidebar {
    width: var(--sidebar-w);
    flex-shrink: 0;
    background: #15171c;
    color: #e9eaed;
    display: flex;
    flex-direction: column;
    padding: 20px 12px;
    position: sticky;
    top: 0;
    height: 100vh;
}
.sidebar-brand {
    display: flex; align-items: center; gap: 10px;
    padding: 0 8px 20px;
    font-weight: 700; font-size: 16px;
    flex-shrink: 0;   /* عنوان و خروج نباید له شوند تا فهرست جا باز کند */
}
.brand-icon { font-size: 20px; }

/* ⛔ `min-height: 0` اینجا اختیاری نیست و کلِ رفعِ باگ همین است.

   `.sidebar` ارتفاعش به `100vh` قفل است ولی فهرستِ منو با آمدنِ هر بخشِ
   تازه بلندتر شد — تا **۱۲۰۱ پیکسل** برای یک مدیر. نتیجه‌اش این بود که
   آخرین گزینه‌ها (سررسیدها، کاربران، ورود و پیامک) روی **هر** پنجره‌ی
   دسکتاپی بیرون می‌افتادند و **هیچ راهی برای رسیدن به آن‌ها نبود**:
   نه اسکرول، نه بریدگی — فقط نبودند. اندازه‌گیری شد، حدس زده نشد.

   ⚠ و افزودنِ `overflow-y: auto` به‌تنهایی **هیچ کاری نمی‌کرد**: یک
     فرزندِ فلکس پیش‌فرض `min-height: auto` دارد، یعنی حاضر نیست کوتاه‌تر
     از محتوایش شود. پس `flex: 1` هرگز فشرده نمی‌شد، ارتفاعِ واقعی برابرِ
     محتوا می‌ماند و `overflow` هرگز فعال نمی‌شد. (در همان اندازه‌گیری
     دیده شد: `clientHeight` و `scrollHeight` هر دو ۱۰۳۱ بودند.)

   ⚠ `overscroll-behavior` هم لازم است، وگرنه رسیدن به ته منو اسکرول را
     به خودِ صفحه زنجیر می‌کند و کاربر جای محتوا را گم می‌کند. */
.sidebar-nav {
    list-style: none;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* نوارِ اسکرول روی زمینه‌ی تیره: نازک و کم‌رنگ. بدونِ این، کروم نوارِ
   روشنِ پیش‌فرضش را می‌کشد که کنارِ منوی تیره شبیهِ یک خطای رندر است. */
.sidebar-nav::-webkit-scrollbar { width: 6px; }
.sidebar-nav::-webkit-scrollbar-track { background: transparent; }
.sidebar-nav::-webkit-scrollbar-thumb {
    background: rgba(255,255,255,.14);
    border-radius: 3px;
}
.sidebar-nav:hover::-webkit-scrollbar-thumb { background: rgba(255,255,255,.24); }
.sidebar-nav { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.18) transparent; }
.sidebar-nav li { margin-bottom: 2px; }
/* دکمه‌ی «ثبت تراکنش» دقیقاً مثل بقیه‌ی ردیف‌های منو دیده می‌شود —
   کاربر نباید بفهمد یکی‌شان دکمه است و بقیه لینک. `width:100%` و
   `text-align:start` لازم‌اند چون `<button>` پیش‌فرضِ خودش را دارد. */
.sidebar-nav a,
.sidebar-nav .sidebar-action {
    display: flex; align-items: center; gap: 11px;
    padding: 11px 12px;
    border-radius: var(--r-sm);
    color: #a9aeb8;
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
}
.sidebar-nav .sidebar-action {
    width: 100%; text-align: start;
    background: var(--brand); border: none;
    color: #fff; font-family: inherit; cursor: pointer;
    font-weight: 600; margin-bottom: 6px;
}
.sidebar-nav a:hover,
.sidebar-nav .sidebar-action:hover { background: rgba(255,255,255,.06); color: #fff; }
.sidebar-nav .sidebar-action:hover { background: var(--brand); filter: brightness(1.15); }
.sidebar-nav a.active { background: var(--gold); color: #15171c; font-weight: 700; }
.nav-divider {
    font-size: 10.5px; color: #6a707a;
    padding: 16px 12px 6px; letter-spacing: .4px;
}
.nav-badge {
    background: var(--out); color: #fff;
    font-size: 10.5px; font-weight: 700;
    border-radius: var(--r-pill);
    padding: 1px 7px; margin-inline-start: auto;
}
.sidebar-footer {
    padding-top: 12px;
    border-top: 1px solid rgba(255,255,255,.08);
    flex-shrink: 0;   /* «خروج از حساب» همیشه دمِ دست بماند، حتی با منوی بلند */
}
.logout-link {
    display: flex; align-items: center; gap: 11px;
    padding: 11px 12px; color: #a9aeb8;
    text-decoration: none; font-size: 14px;
}
.logout-link:hover { color: var(--out); }
.sidebar-overlay {
    display: none; position: fixed; inset: 0;
    background: rgba(0,0,0,.45); z-index: 150;
}

/* ============================================================
   ۵. کارت
   ============================================================ */
.card {
    background: var(--surface);
    border-radius: var(--r-lg);
    padding: 16px;
    margin-bottom: 14px;
    box-shadow: var(--sh);
}
html[data-theme="dark"] .card { border: 1px solid var(--line); }

.card-title { font-size: 15px; font-weight: 700; margin-bottom: 14px; letter-spacing: -.2px; }
.card-header-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; margin-bottom: 14px; flex-wrap: wrap;
}
.card-header-row .card-title { margin-bottom: 0; }
.link-more { font-size: 12.5px; color: var(--gold); text-decoration: none; font-weight: 600; }

/* ============================================================
   ۶. عنصر امضا — نوار مانده (زغالی و طلایی، مثل آیکن اپ)
   ============================================================ */
.balance-ribbon {
    background: var(--brand);
    border-radius: var(--r-lg);
    padding: 20px;
    margin-bottom: 12px;
}
/* بدون تزئین اضافه. عدد طلایی روی زغالی، خودش امضای کارت است. */
.balance-label {
    font-size: 11.5px;
    color: #8d939e;
    letter-spacing: .4px;
    margin-bottom: 7px;
}
/* عدد و واحد جدا نگه داشته می‌شوند تا در چیدمان راست‌به‌چپ به‌هم نریزند.
   ⛔ `row` است نه `row-reverse`، و این تنها چیزی است که عددِ درشتِ نوار
   را چپ‌چین نگه می‌دارد. `.balance-value` در فهرستِ `.ltr-num` است، پس
   `direction: ltr` دارد؛ با `row-reverse` محورِ اصلی راست‌به‌چپ می‌شد و
   `flex-start` یعنی لبه‌ی **راست** — اندازه‌گیری شد: عدد روی
   `gapL = ۱۶۶` و `gapR = ۰` می‌نشست، یعنی چسبیده به راست. حالا عدد چپ
   است و واحد بلافاصله راستِ آن، هم‌تراز با «دریافتی/پرداختی» زیرش. */
.balance-value {
    display: flex;
    align-items: baseline;
    gap: 7px;
    flex-direction: row;
    justify-content: flex-start;
    margin-top: 2px;
}
/* ⚠ `direction: ltr` اینجا **دوباره نوشته نمی‌شود**: `.bv-num` به فهرستِ
   `.ltr-num` پیوست. قاعده‌ی پروژه همین است — کلاسِ عددیِ تازه یک نامِ
   تازه در آن فهرست می‌گیرد، نه یک `direction: ltr` تازه جای دیگر. */
.bv-num {
    font-size: 30px;
    font-weight: 700;
    color: var(--gold-lift);
    letter-spacing: -.5px;
    line-height: 1.2;
}
.bv-unit { font-size: 13px; color: #8d939e; }
.balance-split {
    display: flex;
    gap: 22px;
    margin-top: 15px;
    padding-top: 14px;
    border-top: 1px solid rgba(255,255,255,.10);
}
.balance-split div { flex: 1; }
.balance-split .bs-label { font-size: 11px; color: #8d939e; margin-bottom: 3px; }
.balance-split .bs-value {
    font-size: 14.5px; font-weight: 700;
    direction: ltr; text-align: left;
    font-variant-numeric: tabular-nums;
}
.bs-in  { color: #4ec98a; }
.bs-out { color: #f07070; }

.money-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 11px; margin-bottom: 14px; }

.money-card {
    border-radius: var(--r-lg);
    padding: 17px 18px;
    box-shadow: var(--sh);
}
.money-card .mc-label { font-size: 12px; margin-bottom: 6px; color: var(--muted); }
.money-card .mc-value { font-size: 19px; font-weight: 700; text-align: left; }
.money-card .mc-value small { font-size: 11px; font-weight: 400; opacity: .75; }

/* دو کارت آرام: درآمد و هزینه */
.money-card-income  { background: var(--in-wash); }
.money-card-income .mc-value  { color: var(--in); }
.money-card-expense { background: var(--out-wash); }
.money-card-expense .mc-value { color: var(--out); }

/* ============================================================
   ۷. آمار
   ============================================================ */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
    margin-bottom: 14px;
}
.stats-card {
    background: var(--surface);
    border-radius: var(--r-lg);
    padding: 16px;
    box-shadow: var(--sh);
}
html[data-theme="dark"] .stats-card { border: 1px solid var(--line); }
.stats-card-title {
    font-size: 11.5px; font-weight: 700; color: var(--muted);
    margin-bottom: 10px; letter-spacing: .3px;
}
.stats-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; padding: 5px 0;
}
.stats-label { font-size: 13px; color: var(--muted); }
.stats-value { font-size: 14px; font-weight: 700; }
.stats-value small { font-size: 10.5px; font-weight: 400; color: var(--muted); }
.stats-net-row { margin-top: 5px; padding-top: 9px; border-top: 1px dashed var(--line); }
.stats-income { color: var(--in); }
.stats-expense { color: var(--out); }
.stats-net-positive { color: var(--in); }
.stats-net-negative { color: var(--out); }

.summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 11px;
    margin-bottom: 14px;
}
.summary-box {
    background: var(--surface);
    border-radius: var(--r);
    padding: 13px;
    box-shadow: var(--sh);
}
html[data-theme="dark"] .summary-box { border: 1px solid var(--line); }
.summary-box .label { font-size: 11.5px; color: var(--muted); margin-bottom: 5px; }
.summary-box .value { font-size: 15.5px; font-weight: 700; }

/* ============================================================
   ۸. فرم
   ============================================================ */
.form-group { margin-bottom: 13px; }
.form-group label {
    display: block; font-size: 12.5px; font-weight: 600;
    color: var(--muted); margin-bottom: 6px;
}
.form-row { display: flex; gap: 11px; }
.form-row .form-group { flex: 1; min-width: 0; }

/* ⛔ `tel` و `search` یک بار از این فهرست جا افتاده بودند و نتیجه‌اش
   **بی‌صدا** بود: آن فیلدها هیچ استایلی نمی‌گرفتند و مرورگر جعبه‌ی
   پیش‌فرضِ خودش را می‌کشید — کوچک، با حاشیه‌ی آبی، کاملاً بیگانه با
   بقیه‌ی اپ. روی صفحه‌ی «ورود با پیامک» که تنها فیلدش `tel` است، کلِ
   صفحه شکسته به نظر می‌رسید. نوعِ تازه‌ای که اضافه می‌کنید هم باید
   همین‌جا بیاید. */
input[type="text"], input[type="password"], input[type="email"],
input[type="number"], input[type="date"], input[type="color"],
input[type="tel"], input[type="search"],
select, textarea {
    width: 100%;
    padding: 11px 13px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--ink);
    font-size: 14px;
    transition: border-color .15s;
}

/* ⛔ `<select>` و `<option>` باید جهت را **روی خودشان** داشته باشند، نه
   از ارث.
   `<html dir="rtl">` هست و در کرومیوم `direction` روی هر دو `rtl`
   محاسبه می‌شود (اندازه‌گیری شد)، پس روی دسکتاپ همه چیز درست بود. ولی
   پاپ‌آپِ بازشده‌ی `<select>` روی iOS **کرومِ خودِ سیستم است، نه جعبه‌ای
   که ما رندر می‌کنیم**: وب‌کیت متنِ هر گزینه را به یک منوی بومی می‌دهد و
   آن منو زنجیره‌ی ارث را نمی‌پیماید — پس گزینه‌ها **چپ‌چین** دیده
   می‌شدند، با اینکه کلِ صفحه راست‌به‌چپ است. در اسکرین‌شاتِ گوشی دیده
   شد و در مرورگرِ دسکتاپ اصلاً بازتولید نمی‌شود — قرینه‌ی همان درسِ
   `env(safe-area-inset-*)`.

   ⚠ و `text-align: right` عمداً فیزیکی است، نه `start`: مقدارِ منطقی
     نسبت به **جهتِ پایه‌ی همان رندرکننده** حل می‌شود و همان چیزی است که
     اینجا غلط از آب درمی‌آید. مقدارِ فیزیکی دوباره حل نمی‌شود.

   ⚠ روی کرومیوم این دو خط هیچ چیزی را عوض نمی‌کنند (از قبل همان مقدار
     محاسبه می‌شد) — یعنی هزینه‌ی صفر و فقط بستنِ همان یک درز. */
select, select option {
    direction: rtl;
    text-align: right;
}

/* ⛔ `input[type="color"]` نباید از قاعده‌ی بالا padding بگیرد.
   مرورگر نمونه‌ی رنگ را داخلِ **جعبه‌ی محتوا** می‌کشد، پس ۱۱ پیکسل
   padding از بالا و پایین یعنی از ۲۷ پیکسل ارتفاع فقط **۵ پیکسل** برای
   خودِ رنگ می‌ماند: یک خطِ نازک وسطِ یک کادرِ سفید. کاربر می‌دید «کادر
   رنگ خالی است» ولی رنگ **ذخیره و اعمال می‌شد** — یعنی خرابیِ کاملاً
   بی‌صدا: هیچ خطایی نبود، فقط انتخابگر کار نمی‌کرد.
   اندازه‌گیری شد، حدس زده نشد: ۲۰۳×۲۷ با ۲۲ پیکسل padding.

   ⚠ ارتفاع با بقیه‌ی فیلدها یکی می‌ماند (۴۴px) تا در `.form-row` کنارِ
     فیلدِ مبلغ هم‌تراز بنشیند؛ قبلاً کوتاه‌تر بود و ردیف شکسته می‌شد. */
input[type="color"] {
    padding: 4px;
    height: 44px;
    cursor: pointer;
}
input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
input[type="color"]::-webkit-color-swatch { border: none; border-radius: 6px; }
input[type="color"]::-moz-color-swatch { border: none; border-radius: 6px; }

input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--gold);
}
input::placeholder, textarea::placeholder { color: var(--muted-2); }
textarea { resize: vertical; }
.req { color: var(--out); }

/* ⛔ برچسبِ یک کنترل هرگز وسطِ خودش نمی‌شکند.
   فارسی «نیم‌فاصله» دارد و مرورگر آن را **جای شکستن** می‌شناسد، پس
   «غیرفعال‌سازی» به «غیرفعال‌» و «سازی» می‌شکند و در یک ستونِ تنگ به
   شکلِ «غیرفعال‌ساز» دیده می‌شود — یعنی دکمه‌ای که برچسبش دروغ می‌گوید.
   بدتر از آن: چون کمترین عرضِ لازمِ ستون به همان تکه‌ی کوچک می‌رسد،
   جدول آن ستون را می‌فشارد و باقیِ عرض را به ستون‌های دیگر می‌دهد.
   با `nowrap` کمترین عرضِ ستون همان عرضِ واقعیِ دکمه‌هاست و اگر جا نشد
   `.table-wrapper` اسکرول می‌دهد — که دیدنی است، برخلافِ متنِ بریده. */
.btn {
    display: inline-flex; align-items: center; justify-content: center;
    gap: 7px;
    padding: 11px 18px;
    border: 1px solid transparent;
    border-radius: var(--r-sm);
    font-size: 14px; font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
    transition: opacity .15s, transform .1s;
}
.btn:active { transform: scale(.985); }
.btn-primary { background: var(--brand); color: var(--brand-on); }
.btn-secondary { background: var(--line-soft); color: var(--ink); border-color: var(--line); }
.btn-block { width: 100%; }
.btn-large { padding: 15px; font-size: 15px; border-radius: var(--r); }
.btn-sm { padding: 8px 13px; font-size: 12.5px; }
.btn:disabled { opacity: .55; }

/* ---------- کارِ برگشت‌ناپذیر ----------
   عمداً پر و قرمز است، نه یک دکمه‌ی معمولی با متنِ ترسناک: کاری که
   بازگشت ندارد باید *پیش از* خوانده شدنِ متن هم فرق داشته باشد. */
.btn-danger { background: var(--out); color: #fff; border-color: var(--out); }
.btn-danger:hover { filter: brightness(.94); }

.danger-zone {
    margin-top: 18px; padding-top: 16px;
    border-top: 1px solid var(--line);
}
.danger-title { font-size: 14px; font-weight: 700; color: var(--out); margin-bottom: 6px; }
.danger-zone .btn { margin-top: 12px; }

.version-line { margin-top: 16px; text-align: center; font-size: 11.5px; }
.privacy-p { font-size: 13.5px; line-height: 2; color: var(--ink-soft); margin-bottom: 12px; }

/* پوسته‌ی صفحه‌ی حریم خصوصی برای بازدیدکننده‌ی واردنشده (بازبینِ فروشگاه
   یا کسی که هنوز حساب نساخته). عمداً نه منو دارد نه نوار پایین: آن‌ها به
   نشستِ کاربر بندند و اینجا نشستی در کار نیست. عرض همان عرضِ خواندنِ
   `.page-content` است تا متن در هر دو حالت یک شکل خوانده شود. */
.privacy-shell {
    max-width: 720px;
    margin: 0 auto;
    padding: calc(20px + env(safe-area-inset-top)) 16px calc(24px + env(safe-area-inset-bottom));
}
.privacy-title { font-size: 17px; font-weight: 700; margin-bottom: 16px; text-align: center; }

/* ورودیِ کدِ پیامکی. `direction: ltr` عمدی است: کد یک عددِ لاتین است و
   در صفحه‌ی راست‌به‌راست، رقم‌ها از سمتِ اشتباه پر می‌شدند. */
.otp-input {
    direction: ltr;
    text-align: center;
    font-size: 26px;
    font-weight: 700;
    letter-spacing: 0.5em;
    padding-inline-start: 0.5em;   /* جبرانِ فاصله‌ی آخرین رقم */
    font-variant-numeric: tabular-nums;
}

/* شماره موبایل هم عدد است، پس مثل کدِ ورود چپ‌به‌راست و وسط‌چین —
   قاعده‌ی «متنِ فارسی راست‌چین، عدد چپ‌چین». دو مرحله‌ی همین صفحه
   (شماره و کد) حالا یک شکل‌اند و پرش بصری بینشان نیست. */
.phone-input {
    direction: ltr;
    text-align: center;
    font-size: 21px !important;
    font-weight: 600;
    letter-spacing: 0.10em;
    padding: 15px 13px !important;
    font-variant-numeric: tabular-nums;
}
.phone-input::placeholder { font-weight: 400; letter-spacing: 0.06em; opacity: .45; }

/* ---------- اعلان و یادآور ---------- */

.notif-bell { position: relative; }
/* نشانِ نخوانده روی زنگ. عدد است نه نقطه، چون «۳ تا خبر داری» با
   «یک خبری هست» فرق دارد — و کاربری که عدد را ببیند بازش می‌کند. */
.notif-badge {
    position: absolute; top: -3px; inset-inline-end: -3px;
    min-width: 16px; height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--out); color: #fff;
    font-size: 10px; font-weight: 700; line-height: 16px;
    text-align: center;
    box-shadow: 0 0 0 2px var(--surface);
}

.notif-list, .reminder-list { list-style: none; margin: 0; padding: 0; }
.notif-row, .reminder-row {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 12px 0;
    border-bottom: 1px solid var(--line);
}
.notif-row:last-child, .reminder-row:last-child { border-bottom: none; }
.notif-row.is-fresh { background: color-mix(in srgb, var(--gold) 7%, transparent); }

.notif-dot {
    flex: 0 0 auto; width: 8px; height: 8px; margin-top: 6px;
    border-radius: 50%; background: var(--muted);
}
.notif-reminder { background: var(--gold); }
.notif-due      { background: var(--out); }
.notif-payment  { background: var(--in); }
/* ⚠ کهربایی است نه قرمز: پشتیبان نگرفتن یک **خطر** است ولی سررسیدِ
   امروز نیست. با قرمز، این جمله در فهرست هم‌وزنِ چکِ برگشتی دیده می‌شد. */
.notif-backup   { background: var(--warn-ink); }
/* ⚠ قرمز، نه کهربایی: خطای برنامه یعنی همین حالا کاربری صفحه‌ی خراب
   دیده — هم‌وزنِ سررسیدِ امروز است، نه هم‌وزنِ «پشتیبان نگرفته‌اید». */
.notif-apperr   { background: var(--out); }

.notif-main, .reminder-main { flex: 1 1 auto; min-width: 0; }
.notif-title, .reminder-title { font-size: 13.5px; font-weight: 700; }
.notif-body, .reminder-note { font-size: 12.5px; color: var(--muted); margin-top: 3px; }
.notif-time { font-size: 11px; color: var(--muted); margin-top: 4px; }
.notif-go { color: var(--muted); flex: 0 0 auto; padding-top: 4px; }

.reminder-meta {
    display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
    font-size: 12px; color: var(--muted); margin-top: 4px;
}
.reminder-meta .is-late  { color: var(--out); font-weight: 700; }
.reminder-meta .is-today { color: var(--gold); font-weight: 700; }
.reminder-amount { font-weight: 600; }
.reminder-actions { display: flex; gap: 6px; flex: 0 0 auto; }
/* انجام‌شده کم‌رنگ می‌شود ولی پاک نمی‌شود — تاریخچه‌ی خودِ کاربر است. */
.reminder-row.is-done { opacity: .5; }
.reminder-row.is-done .reminder-title { text-decoration: line-through; }

.card-head-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; margin-bottom: 8px;
}
.card-head-row .card-title { margin-bottom: 0; }

/* نوارِ بخش‌های پنل مدیریت. روی موبایل افقی اسکرول می‌شود تا هیچ‌وقت
   به خطِ دوم نرود و ارتفاعِ صفحه را نخورد؛ نوارِ اسکرول پنهان است. */
.admin-tabs {
    display: flex; gap: 6px;
    overflow-x: auto;
    scrollbar-width: none;
    margin-bottom: 14px;
    padding-bottom: 2px;
}
.admin-tabs::-webkit-scrollbar { display: none; }
.admin-tab {
    flex: 0 0 auto;
    padding: 8px 14px;
    border-radius: 999px;
    font-size: 12.5px; font-weight: 600;
    color: var(--muted);
    background: var(--surface);
    border: 1px solid var(--line);
    text-decoration: none;
    white-space: nowrap;
    transition: background .15s, color .15s, border-color .15s;
}
.admin-tab:hover { color: var(--ink); }
.admin-tab.is-active {
    background: var(--brand); color: #fff; border-color: var(--brand);
}

/* ⛔ نشانِ خطای رسیدگی‌نشده روی نوارِ مدیر — «اطلاع‌رسانی» نیمه‌ی اولش
   همین است. با صفر اصلاً رندر نمی‌شود (در `admin/_nav.php`)، چون نشانِ
   «۰» فقط آدم را عادت می‌دهد نگاهش نکند.
   ⚠ رنگش قرمز است نه کهربایی: خطای برنامه یعنی همین حالا کاربری یک
   صفحه‌ی خراب دیده، نه یک ریسکِ آینده. */
.admin-tab-badge {
    display: inline-block;
    min-width: 18px;
    margin-inline-start: 6px;
    padding: 1px 5px;
    border-radius: 999px;
    font-size: 10.5px; font-weight: 800;
    text-align: center;
    color: #fff;
    background: var(--out);
}
.admin-tab.is-active .admin-tab-badge {
    color: var(--out); background: #fff;
}

/* نشانِ «ثبت شده» کنارِ برچسبِ کلید و رمز. فیلدِ خالی بعد از ذخیره
   شبیهِ «ذخیره نشد» است؛ این نشان و جای‌نگهدارِ ماسک‌شده با هم ابهام
   را برمی‌دارند. */
.saved-chip {
    display: inline-block;
    font-size: 10.5px; font-weight: 700;
    color: var(--in);
    background: color-mix(in srgb, var(--in) 14%, transparent);
    border-radius: 999px;
    padding: 2px 8px;
    vertical-align: 1px;
}
/* نشانِ تلاشِ ناموفقِ ورود، کنارِ نام کاربری در پنل مدیر.
   ⚠ رنگِ هشدار `--warn-ink` است نه `--gold`: پالتِ دومِ style.css
     مقدارِ `--gold` را به آبی بازتعریف می‌کند، پس نشانِ «هشدار» با آن
     دقیقاً مثل نشانِ «اطلاع» دیده می‌شد. */
.lock-chip {
    display: inline-block;
    font-size: 10.5px; font-weight: 700;
    color: var(--warn-ink);
    background: color-mix(in srgb, var(--warn-ink) 14%, transparent);
    border-radius: 999px;
    padding: 2px 8px;
    margin-inline-start: 6px;
    vertical-align: 1px;
    white-space: nowrap;
}
/* قفلِ کامل قرمز است: با هم‌رنگ بودن، مدیر «۲ تلاش» و «قفل شده» را از
   هم تشخیص نمی‌داد و همان تفاوت است که تصمیمش را عوض می‌کند. */
.lock-chip.is-locked {
    color: var(--out);
    background: color-mix(in srgb, var(--out) 14%, transparent);
}

.privacy-p:last-child { margin-bottom: 0; }
.privacy-p a { color: var(--gold); }

/* ---------- اشتراک ---------- */
.plan-state { font-size: 16px; font-weight: 700; }
.plan-state-on { color: var(--in); }
.pay-card {
    background: var(--line-soft); border-radius: var(--r);
    padding: 14px; text-align: center;
}
.pay-number {
    font-size: 18px; font-weight: 700; letter-spacing: 1px;
    direction: ltr; unicode-bidi: isolate;
}
.pay-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; padding: 11px 0;
    border-bottom: 1px solid var(--line-soft);
}
.pay-row:last-child { border-bottom: none; }

/* ---------- بازگرداندن از فایل ---------- */

/* ⚠ رنگ از `--warn-ink` می‌آید نه `--gold`: پالتِ دومِ همین فایل
   `--gold` را آبی بازتعریف می‌کند، و آن‌وقت هشدارِ «داده‌ات پاک می‌شود»
   دقیقاً شبیهِ یک نوارِ اطلاع دیده می‌شد. */
.restore-warn {
    background: var(--warn-wash);
    color: var(--warn-ink);
    border-inline-start: 3px solid var(--warn-ink);
    border-radius: 10px;
    padding: 12px 14px;
    line-height: 1.9;
    font-size: 13px;
    margin-bottom: 14px;
}

.restore-list {
    list-style: none;
    margin: 0 0 4px;
    padding: 0;
    /* ⚠ با ده‌ها جدول این فهرست بلند می‌شود؛ دو ستون نگهش می‌دارد.
       `min(190px,100%)` نه `1fr` خام — آیتمِ گرید پیش‌فرض
       `min-width: auto` دارد و حاضر نیست از محتوایش کوتاه‌تر شود. */
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(190px, 100%), 1fr));
    gap: 2px 16px;
}
.restore-list li {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: 13px;
    color: var(--muted);
    padding: 3px 0;
}

.restore-preview {
    background: var(--in-wash);
    border-radius: 10px;
    padding: 10px 12px;
    font-size: 13px;
    line-height: 1.9;
    margin-bottom: 14px;
}
/* ⛔ بدونِ این خط ویژگیِ `hidden` بی‌اثر است: آن یک قاعده‌ی UA است و
   هر `display` ساده بر آن غلبه می‌کند (قاعده ۱۸). */
.restore-preview[hidden] { display: none; }

/* ---------- فهرستِ توری و صفحه‌بندی ---------- */

/* ⛔ توری با `auto-fill` و `minmax`، نه تعدادِ ستونِ ثابت: با عددِ ثابت
   اولین عرضی که پیش‌بینی نکرده‌ایم کارت‌ها را له می‌کند. روی موبایل
   خودبه‌خود یک ستون می‌شود چون `230px` از عرضِ در دسترس بزرگ‌تر است.
   ⚠ `minmax(0, 1fr)` نه `1fr`: آیتمِ گرید پیش‌فرض `min-width: auto`
   دارد و حاضر نیست از محتوایش کوتاه‌تر شود — همان چیزی که یک بار
   منوی کناری را از اسکرول شدن انداخت. بدونِ آن، یک نامِ بلند کلِ
   ستون را پهن می‌کند و صفحه افقی اسکرول می‌شود. */
.grid-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(230px, 100%), 1fr));
    gap: 10px;
    margin-top: 12px;
}
/* زمینه عمداً ندارد: `html[data-theme="dark"] .card` با وزنِ بیشتر
   `background` را بازنویسی می‌کند و همان درسِ `.start-card` است —
   «داشتنِ مقدار در فایل کافی نیست، قاعده‌ای که برنده می‌شود باید
   داشته باشدش». مرز از `--line` می‌آید که خودش تم‌آگاه است. */
.grid-card {
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 11px 13px;
    min-width: 0;
}
.grid-card-head {
    display: flex; align-items: center; gap: 6px;
    flex-wrap: wrap; margin-bottom: 4px;
}
/* ⚠ `overflow-wrap: anywhere` لازم است: نامِ کاربر را خودش می‌نویسد و
   یک رشته‌ی بی‌فاصله‌ی بلند از کارت بیرون می‌زد. */
.grid-card-name { font-weight: 700; min-width: 0; overflow-wrap: anywhere; }
.grid-card-sub  { display: block; line-height: 1.9; }

/* ---------- کارت‌های تاشوی کاربران (admin/users.php) ----------
   ⛔ زمینه عمداً ندارد — همان درسِ `.grid-card` و `.start-card`:
   `html[data-theme="dark"] .card` با وزنِ بیشتر `background` را
   بازنویسی می‌کند. مرز از `--line` می‌آید که خودش تم‌آگاه است. */
.ucards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr));
    gap: 8px;
    /* ⛔ `start` اجباری است: بدونش باز کردنِ یک کارت، هم‌ردیف‌هایش را هم
       به همان قد می‌کشد و صفحه پر از کارتِ بلندِ خالی می‌شود. */
    align-items: start;
    margin-top: 12px;
}
.ucards-empty { grid-column: 1 / -1; text-align: center; margin: 14px 0; }

.ucard {
    border: 1px solid var(--line);
    border-radius: 12px;
    min-width: 0;
}
/* کارتی که کاری می‌خواهد باید از دور هم دیده شود، نه فقط از روی نشانش:
   با صد کارتِ بسته، چشم مرزِ رنگی را زودتر از متن پیدا می‌کند. */
.ucard.is-flagged { border-color: color-mix(in srgb, var(--warn-ink) 45%, var(--line)); }

.ucard-head {
    display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
    padding: 10px 12px;
    cursor: pointer;
    font-size: 13.5px;
    /* مثلثِ پیش‌فرض: فایرفاکس با `list-style`، وبکیت با شبه‌عنصرِ خودش. */
    list-style: none;
}
.ucard-head::-webkit-details-marker { display: none; }
/* ⚠ `overflow-wrap: anywhere` لازم است: نام را خودِ کاربر می‌نویسد و یک
   رشته‌ی بی‌فاصله‌ی بلند از کارت بیرون می‌زد (درسِ `.grid-card-name`). */
.ucard-name { font-weight: 700; min-width: 0; overflow-wrap: anywhere; flex: 1; }
/* نشانگرِ باز/بسته، جای همان مثلثِ برداشته‌شده.
   ⚠ مرزها عمداً فیزیکی‌اند نه منطقی: این یک شکل است نه متن، و مقدارِ
     منطقی در راست‌به‌چپ آینه می‌شد. */
.ucard-head::after {
    content: '';
    width: 7px; height: 7px; flex: 0 0 auto;
    border-right: 2px solid var(--muted);
    border-bottom: 2px solid var(--muted);
    transform: rotate(45deg);
    transition: transform .15s ease;
    margin-bottom: 3px;
}
.ucard[open] > .ucard-head::after { transform: rotate(-135deg); margin-bottom: -3px; }
.ucard[open] > .ucard-head { border-bottom: 1px solid var(--line-soft); }

.ucard-body { padding: 8px 12px 12px; font-size: 13px; }
.ucard-row { display: flex; justify-content: space-between; gap: 12px; padding: 5px 0; }
.ucard-k { color: var(--muted); font-size: 12px; font-weight: 600; flex: 0 0 auto; }
.ucard-v { min-width: 0; text-align: left; overflow-wrap: anywhere; }
/* ⚠ اینجا `wrap` درست است، برخلافِ ستونِ عملیاتِ جدول در قاعده ۳۱: کارت
   باریک است و ردیفِ دکمه‌ها باید بشکند، نه اینکه از کارت بیرون بزند. */
.ucard-actions {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
    margin-top: 8px; padding-top: 8px;
    border-top: 1px solid var(--line-soft);
}
.ucard-actions form { display: inline-flex; margin: 0; }
.ucard-actions .self-note { font-size: 12px; color: var(--muted); white-space: nowrap; }
/* منوی نوعِ حساب کنارِ دکمه‌اش، هم‌قدِ دکمه‌های کوچکِ کارت */
.ucard-actions .ucard-type-form { flex-basis: 100%; gap: 6px; align-items: center; }
.ucard-actions .ucard-type-form select { width: auto; flex: 1 1 auto; min-width: 0; padding: 6px 10px; font-size: 13px; }

.pager {
    display: flex; align-items: center; justify-content: center;
    gap: 6px; flex-wrap: wrap; margin-top: 14px;
}
/* ⛔ `nowrap` اجباری است — همان درسِ قاعده ۳۱: «صفحه‌بندی» نیم‌فاصله
   دارد و مرورگر آن را **جای شکستن** می‌شناسد، پس برچسبِ یک کنترل
   وسطِ خودش دو خط می‌شد. */
.pager-link {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 32px; padding: 0 12px; border-radius: 9px;
    border: 1px solid var(--line); background: transparent;
    color: var(--brand-fg); font-size: 12.5px; font-weight: 600;
    text-decoration: none; white-space: nowrap; cursor: pointer;
}
.pager-link:hover { border-color: var(--brand-fg); }
.pager-link.is-off { color: var(--muted); opacity: .55; cursor: default; }
.pager-link.is-off:hover { border-color: var(--line); }
.pager-info { font-size: 12px; color: var(--muted); white-space: nowrap; }

/* ⛔ شماره‌ی صفحه — با چهل صفحه، «قبلی/بعدی» تنها یعنی سی‌وشش تپ تا
   رسیدن به صفحه‌ی ۳۷. ظرف `nowrap` است تا خودِ ردیفِ شماره‌ها وسطِ
   خودش نشکند؛ سرریزش اسکرول می‌شود (همان الگوی `.cat-grid`). */
.pager-nums {
    display: inline-flex; align-items: center; gap: 4px;
    flex-wrap: nowrap; overflow-x: auto; max-width: 100%;
    padding: 2px; margin-inline: -2px;
}
.pager-num {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 32px; min-height: 32px; padding: 0 7px; border-radius: 9px;
    border: 1px solid var(--line); background: transparent;
    color: var(--brand-fg); font-size: 12.5px; font-weight: 600;
    text-decoration: none; white-space: nowrap; flex: 0 0 auto;
}
.pager-num:hover { border-color: var(--brand-fg); }
.pager-num.is-current {
    background: var(--brand); border-color: var(--brand); color: #fff; cursor: default;
}
.pager-gap { color: var(--muted); font-size: 12px; padding: 0 2px; flex: 0 0 auto; }

/* ---------- مدیریت کاربران در مقیاس ---------- */

/* ⚠ چهار چیپِ خلاصه که خودشان صافی هم هستند. `auto-fit` با کفِ ۱۰۴
   پیکسل: روی موبایلِ ۳۹۰ دوتا در هر ردیف، روی دسکتاپ هر چهار در یک
   ردیف — بدونِ هیچ `@media` تازه‌ای. */
.user-stats {
    display: grid; gap: 8px; margin-bottom: 12px;
    grid-template-columns: repeat(auto-fit, minmax(min(104px, 100%), 1fr));
}
/* ⚠ زمینه عمداً از `--line-soft` می‌آید نه `--card`: قاعده‌ی
   `html[data-theme="dark"] .card` با وزنِ بیشتر `background` را
   بازنویسی می‌کند — همان درسِ `.start-card` و `.grid-card`. */
.user-stat {
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    padding: 10px 6px; border-radius: 12px; border: 1px solid var(--line);
    text-decoration: none; color: inherit; min-width: 0;
}
.user-stat:hover { border-color: var(--brand-fg); }
.user-stat.is-current { border-color: var(--brand-fg); box-shadow: inset 0 0 0 1px var(--brand-fg); }
.user-stat-num { font-size: 18px; font-weight: 800; }
.user-stat-label { font-size: 11.5px; color: var(--muted); white-space: nowrap; }
.user-stat.is-warn .user-stat-num { color: var(--warn-ink); }

.user-filters {
    display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 10px;
}
/* ⚠ `flex: 1 1 200px` با `min-width: 0`: بدونِ دومی، فیلدِ جست‌وجو
   حاضر نیست از placeholder اش کوتاه‌تر شود و ردیف روی موبایل سرریز
   می‌کرد — همان چیزی که یک بار منوی کناری را از اسکرول انداخت. */
.user-filters .user-filter-q { flex: 1 1 200px; min-width: 0; }
.user-filters select { flex: 0 1 auto; width: auto; min-width: 0; }
.user-filter-note { margin: -4px 0 10px; }
.user-filters input[type="date"] { flex: 0 1 auto; width: auto; min-width: 0; }

/* ---------- پشتیبانی: مرکز راهنما و تیکت ---------- */

.sup-flash {
    padding: 11px 14px; border-radius: 12px; margin-bottom: 12px;
    border: 1px solid var(--line); font-size: .93rem; line-height: 1.8;
}
/* ⚠ زمینه‌ی صریح لازم است: `html[data-theme="dark"] .card` با وزنِ
   بیشتر هر زمینه‌ای را بازنویسی می‌کند — همان درسِ `.start-card`. این
   عنصر `.card` نیست، ولی متغیرها تم‌آگاه‌اند و همان کار را می‌کنند. */
.sup-flash-ok  { background: var(--in-wash);   border-color: var(--in);   color: var(--in); }
.sup-flash-err { background: var(--warn-wash); border-color: var(--warn-ink); color: var(--warn-ink); }

.sup-empty { text-align: center; padding: 26px 16px; }
.sup-empty h2 { margin: 0 0 8px; font-size: 1.02rem; }
.sup-empty p { margin: 0 0 14px; color: var(--ink-soft); line-height: 1.9; }

.sup-note { margin: 0 0 10px; color: var(--ink-soft); font-size: .9rem; line-height: 1.9; }
.sup-cat-title { margin: 0 0 10px; font-size: 1rem; }
.sup-cat-card + .sup-cat-card { margin-top: 12px; }

.sup-search-label { display: block; margin-bottom: 6px; font-size: .9rem; color: var(--ink-soft); }
.sup-search-row { display: flex; gap: 8px; align-items: center; }
/* ⚠ `min-width: 0` کنارِ `flex: 1`: بدونش فیلد حاضر نیست از
   placeholder اش کوتاه‌تر شود و ردیف روی موبایل سرریز می‌کند. */
.sup-search-row input[type="search"] { flex: 1 1 auto; min-width: 0; }

.sup-article { border-top: 1px solid var(--line); padding: 10px 0; }
.sup-article:first-of-type { border-top: 0; }
.sup-article summary {
    cursor: pointer; font-weight: 600; font-size: .95rem; line-height: 1.8;
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.sup-article summary::-webkit-details-marker { display: none; }
.sup-article-body { margin-top: 8px; color: var(--ink-soft); line-height: 2; font-size: .92rem; }
.sup-cat-tag {
    font-size: .74rem; padding: 2px 8px; border-radius: 999px;
    background: var(--chip-bg); color: var(--ink-soft); font-weight: 500;
}

.sup-pick { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr)); gap: 8px; }
.sup-pick-item {
    display: block; padding: 13px 14px; border: 1px solid var(--line);
    border-radius: 12px; font-size: .93rem; color: inherit; text-decoration: none;
}
.sup-pick-item:hover { border-color: var(--brand-fg); }

.sup-gate { display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }
.sup-still { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; justify-content: space-between; }
.sup-still p { margin: 0; color: var(--ink-soft); }
.sup-close-form { margin-top: 10px; text-align: center; }
.sup-meta-note { margin-top: -4px; }

.sup-ticket-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.sup-no { font-weight: 700; }
.sup-subject { margin: 0 0 8px; font-size: 1.05rem; line-height: 1.7; }
.sup-meta { margin: 0; display: flex; gap: 10px; flex-wrap: wrap; font-size: .84rem; color: var(--ink-soft); }
.sup-tech { margin: 8px 0 0; font-size: .78rem; color: var(--ink-soft); opacity: .75; word-break: break-all; }

/* ⚠ `white-space: nowrap` لازم است — همان درسِ نیم‌فاصله در قاعده ۳۱:
   «پاسخ داده شد» جای شکستن دارد و نشان را دو خط می‌کرد. */
.sup-status, .sup-prio {
    font-size: .76rem; padding: 3px 9px; border-radius: 999px;
    font-weight: 600; white-space: nowrap;
}
.sup-status-new      { background: var(--in-wash);   color: var(--in); }
.sup-status-review   { background: var(--warn-wash); color: var(--warn-ink); }
/* ⚠ «پاسخ داده شد» عمداً رنگِ هشدار نمی‌گیرد: چیزی خراب نشده. و
   `--gold` هم به کار نمی‌رود — پالتِ دومِ همین فایل آن را به آبی
   بازتعریف می‌کند و نشان با نشانِ «اطلاع» یکی دیده می‌شد. */
.sup-status-answered { background: var(--chip-bg); color: var(--brand-fg); }
.sup-status-closed   { background: var(--chip-bg);   color: var(--ink-soft); }
.sup-prio-low    { background: var(--chip-bg);   color: var(--ink-soft); }
.sup-prio-normal { background: var(--chip-bg);   color: var(--ink-soft); }
.sup-prio-high   { background: var(--out-wash);  color: var(--out); }

.sup-thread { display: flex; flex-direction: column; gap: 12px; }
.sup-msg { border: 1px solid var(--line); border-radius: 12px; padding: 11px 13px; }
.sup-msg-admin { border-color: var(--brand-fg); }
.sup-msg-who {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    font-size: .82rem; font-weight: 600; color: var(--ink-soft); margin-bottom: 6px;
}
.sup-msg-time { font-weight: 400; opacity: .8; }
.sup-msg-body { line-height: 2; font-size: .93rem; white-space: pre-wrap; }
.sup-file {
    display: inline-flex; align-items: center; gap: 6px; margin-top: 8px;
    font-size: .84rem; color: var(--brand-fg); text-decoration: none;
}

.sup-row {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 11px 0; border-top: 1px solid var(--line); color: inherit; text-decoration: none;
}
.sup-row:first-of-type { border-top: 0; }
.sup-row-main { min-width: 0; }
.sup-row-title { display: block; font-weight: 600; font-size: .94rem; }
.sup-row-sub { display: block; font-size: .8rem; color: var(--ink-soft); margin-top: 3px; }
.sup-row-side { display: flex; align-items: center; gap: 8px; flex: none; }
.sup-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--out); display: inline-block; }
.sup-wait { color: var(--out); font-weight: 900; }

.sup-badge {
    display: inline-block; min-width: 17px; padding: 1px 5px; margin-inline-start: 5px;
    border-radius: 999px; background: var(--out); color: #fff;
    font-size: .7rem; font-weight: 700; text-align: center;
}

.sup-admin-ops { display: flex; gap: 18px; flex-wrap: wrap; align-items: flex-end; }
.sup-op-form { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.sup-op-form label { font-size: .86rem; color: var(--ink-soft); }
.sup-op-form select { width: auto; min-width: 0; }

/* ---------- کد تخفیف ---------- */

/* ⚠ کد لاتین است و باید چپ‌به‌راست خوانده شود، ولی عمداً به فهرستِ
   `.ltr-num` **نپیوسته**: آن فهرست برای عدد است (`tabular-nums` و
   تراز شدنِ ستون‌ها)، و اینجا به `text-transform` و فاصله‌ی حروف نیاز
   داریم که برای عدد بی‌معنا است. */
.code-input {
    direction: ltr;
    text-align: left;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    font-weight: 700;
}
.code-form {
    display: flex; gap: 8px; align-items: stretch;
}
.code-form .code-input { flex: 1; min-width: 0; }
.code-form .btn { flex: 0 0 auto; }

.code-tag {
    display: inline-block;
    direction: ltr; unicode-bidi: isolate;
    font-weight: 700; letter-spacing: 1px;
    background: var(--line-soft);
    border-radius: var(--r-sm, 8px);
    padding: 3px 9px;
}
.code-tag-sm { font-size: 11px; padding: 1px 6px; letter-spacing: .5px; }

.code-applied {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap;
    background: color-mix(in srgb, var(--in) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--in) 30%, transparent);
    border-radius: var(--r);
    padding: 11px 13px;
}
.code-applied .code-tag { background: var(--surface); color: var(--in); }
.code-applied-text { font-size: 13px; font-weight: 600; color: var(--in); margin-inline-start: 6px; }

/* ردیفِ کد در پنل مدیر */
.dcode-list { margin-bottom: 18px; }
.dcode-row {
    padding: 12px 0;
    border-bottom: 1px solid var(--line-soft);
}
.dcode-row:last-child { border-bottom: none; }
.dcode-head {
    display: flex; align-items: center; gap: 8px;
    flex-wrap: wrap; margin-bottom: 6px;
}
.dcode-meta { font-size: 12px; color: var(--muted); margin: 0 0 8px; }
.dcode-foot {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap;
}
.dcode-count { font-size: 12.5px; font-weight: 600; color: var(--muted); }
.dcode-form-title {
    font-size: 13px; font-weight: 700; color: var(--muted);
    margin: 0 0 12px;
    padding-top: 14px;
    border-top: 1px solid var(--line-soft);
}

/* ---------- ردیف‌های آمار مدیر ---------- */
.funnel-row { margin-bottom: 13px; }
.funnel-row:last-child { margin-bottom: 0; }
.funnel-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 10px; margin-bottom: 5px; font-size: 13px;
}
.version-line a { color: var(--muted); text-decoration: underline; }

.delete-btn {
    background: none; border: none;
    color: var(--out); font-size: 12.5px; font-weight: 600;
    padding: 8px 10px; border-radius: var(--r-sm);
    white-space: nowrap;   /* همان قاعده‌ی `.btn` — برچسب نمی‌شکند */
}
.delete-btn:hover { background: var(--out-wash); }

.form-message {
    margin-top: 11px; padding: 10px 13px;
    border-radius: var(--r-sm); font-size: 13px;
}
.form-message.success { background: var(--in-wash); color: var(--in); }
.form-message.error   { background: var(--out-wash); color: var(--out); }

.alert {
    padding: 11px 14px; border-radius: var(--r-sm);
    font-size: 13.5px; margin-bottom: 14px;
}
.alert-success { background: var(--in-wash); color: var(--in); }
.alert-error   { background: var(--out-wash); color: var(--out); }
.alert-info    { background: var(--warn-wash); color: var(--warn-ink); }

/* ---------- «از پیامک بانک» ----------
   یک دکمه‌ی کوچکِ کم‌رنگ زیرِ عنوانِ شیت، نه یک بخشِ تازه: مسیرِ اصلیِ
   ثبت همان فرم است و این میان‌بر نباید با آن رقابت کند. جعبه‌اش با
   grid-template-rows از ۰fr باز می‌شود (همان الگوی .stay-choices)، و
   دقیقاً **یک** فرزندِ صریح دارد — دو تا بشود، دومی در ردیفِ ضمنیِ
   auto می‌افتد و جعبه در حالت بسته هم جا می‌گیرد. */
.sms-paste-btn {
    display: inline-flex; align-items: center; gap: 6px;
    margin: -4px 0 12px;
    padding: 7px 11px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    font-family: inherit; font-size: 12.5px; font-weight: 600;
    cursor: pointer;
    transition: color .15s, border-color .15s, background .15s;
}
.sms-paste-btn:hover,
.sms-paste-btn.active { color: var(--brand-fg); border-color: var(--brand-fg); }
.sms-paste-btn.active { background: var(--line-soft); }

.sms-paste {
    display: grid; grid-template-rows: 0fr;
    opacity: 0;
    transition: grid-template-rows .22s ease, opacity .18s ease, margin .22s ease;
    margin-bottom: 0;
}
.sms-paste.open { grid-template-rows: 1fr; opacity: 1; margin-bottom: 14px; }
.sms-paste-inner { overflow: hidden; min-height: 0; }
.sms-paste textarea {
    width: 100%; resize: vertical;
    padding: 10px 12px;
    border: 1px solid var(--line); border-radius: var(--r-sm);
    background: var(--bg); color: var(--text);
    font-family: inherit; font-size: 13px; line-height: 1.8;
}
.sms-paste-actions {
    display: flex; align-items: center; gap: 10px;
    margin-top: 8px; flex-wrap: wrap;
}
.sms-paste-msg { font-size: 12px; color: var(--muted); flex: 1; min-width: 0; }
.sms-paste-msg.ok   { color: var(--in); }
.sms-paste-msg.warn { color: var(--warn-ink); }

/* ---------- تاگل درآمد/هزینه ---------- */
.type-toggle {
    display: flex; gap: 4px;
    background: var(--line-soft);
    border-radius: var(--r);
    padding: 4px;
    margin-bottom: 15px;
}
.type-btn {
    flex: 1; padding: 11px;
    border: none; background: transparent;
    border-radius: var(--r-sm);
    font-weight: 700; font-size: 14px;
    color: var(--muted);
    transition: background .15s, color .15s;
}
.type-btn.active.type-btn-income,
.type-btn.active.type-btn-receivable { background: var(--in); color: #fff; }
.type-btn.active.type-btn-expense,
.type-btn.active.type-btn-payable   { background: var(--out); color: #fff; }
/* حالت خنثی (مثل «موجودی واقعی» در تعدیل موجودی) — نه درآمد است نه هزینه،
   پس رنگ معنادار نمی‌گیرد ولی باید معلوم باشد کدام انتخاب شده. */
.type-btn.active.type-btn-neutral   { background: var(--brand); color: var(--brand-on); }

/* ============================================================
   ۹. ردیف تراکنش
   ============================================================ */
.tx-day-group { margin-bottom: 4px; }
.tx-day-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 12px 2px 6px;
}
.tx-day-date { font-size: 11.5px; font-weight: 700; color: var(--muted); letter-spacing: .2px; }
.tx-day-total { font-size: 12.5px; font-weight: 700; }

.tx-row { padding: 3px 0; }
.tx-row-summary {
    display: flex; align-items: center; gap: 11px;
    min-height: 56px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.tx-row-summary:active { opacity: .65; }
.tx-row-icon-wrap { display: flex; align-items: center; gap: 11px; flex: 1; min-width: 0; }
.tx-row-texts { flex: 1; min-width: 0; }
.tx-row-title {
    display: block;
    font-size: 14.5px; font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tx-row-cat { display: block; font-size: 11.5px; color: var(--muted-2); margin-top: 1px; }
/* ثبتِ دارایی: عنوان = توضیحِ نوشته‌شده، زیرش نوع و مقدار؛ و «شامل: …» در کارتِ نرخِ روز */
.asset-rate-items { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; overflow-wrap: anywhere; }
.tx-row-amount { font-size: 15px; font-weight: 700; white-space: nowrap; letter-spacing: -.2px; }
.tx-row-chevron { display: none; }
.tx-row.expanded .tx-row-chevron { transform: rotate(180deg); }
/* ⛔ ردیفِ باز عنوانِ کامل را نشان می‌دهد: بسته، `ellipsis` در متنِ راست‌به‌چپ
      ابتدای نامِ لاتین را می‌برد («…e 12 Pro» به‌جای «iPhone 12 Pro») و در
      جزئیات هم جای دیگری برای خواندنش نبود. */
.tx-row.expanded .tx-row-title { white-space: normal; overflow: visible; overflow-wrap: anywhere; }

.tx-row-details {
    display: none;
    margin: 4px 0 10px;
    padding: 11px 13px;
    background: var(--line-soft);
    border-radius: var(--r);
    font-size: 13px;
}
.tx-row.expanded .tx-row-details { display: block; }
.tx-row-details-line {
    display: flex; justify-content: space-between; gap: 10px;
    padding: 4px 0; color: var(--muted);
}
.tx-row-details-line span:last-child { color: var(--ink); font-weight: 500; text-align: left; }
.tx-row-actions { display: flex; gap: 7px; margin-top: 10px; flex-wrap: wrap; }

/* انضباط رنگ: رنگ فقط در سطرهای جمع‌بندی معنا دارد.
   در تک‌تک ردیف‌ها، علامت + و − جهت پول را می‌گوید و آیکن رنگی دسته را. */
.tx-row-amount.amount-income,
.tx-row-amount.amount-expense { color: var(--ink); }
.amount-income  { color: var(--in); }
.amount-expense { color: var(--out); }
.amount-cell { font-weight: 700; text-align: left; }

/* آیکن دسته‌بندی */
.cat-icon {
    width: 40px; height: 40px;
    border-radius: 12px;
    display: inline-flex; align-items: center; justify-content: center;
    flex-shrink: 0;
}
.cat-icon svg { display: block; }
.cat-icon-sm { width: 28px; height: 28px; border-radius: 8px; }

.type-tag {
    display: inline-block;
    font-size: 11px; font-weight: 700;
    padding: 3px 9px; border-radius: var(--r-pill);
}
.type-tag-income  { background: var(--in-wash); color: var(--in); }
.type-tag-expense { background: var(--out-wash); color: var(--out); }

.status-badge { font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: var(--r-pill); }
.status-active   { background: var(--in-wash); color: var(--in); }
.status-inactive { background: var(--line-soft); color: var(--muted); }
.debt-badge-overdue { background: var(--out-wash); color: var(--out); }
.debt-badge-pending { background: var(--warn-wash); color: var(--warn-ink); }
/* چکِ خرج‌شده: از جریان خارج شده ولی نه پاس شده نه برگشتی — پس نه سبز
   نه قرمز. خاکستریِ خنثی. */
.status-badge-muted { background: var(--line-soft); color: var(--muted); }

/* ⛔ سه حالتِ نشانِ «سلامت» در پنل مدیر. `status-badge-in`/`-out` از قبل
   در `admin/insights.php` نوشته شده بودند ولی **هیچ قاعده‌ای نداشتند**،
   پس هر دو یک شکلِ بی‌رنگ دیده می‌شدند — یعنی «درست» و «رسیدگی» از هم
   تشخیص داده نمی‌شدند و کارتِ سلامت عملاً چیزی نمی‌گفت.
   ⚠ رنگِ حالتِ میانی `--warn-ink` است نه `--gold`: پالتِ دوم `--gold` را
   آبی بازتعریف می‌کند و آن‌وقت «هشدار» دقیقاً مثل «اطلاع» دیده می‌شود. */
.status-badge-in   { background: var(--in-wash);   color: var(--in); }
.status-badge-out  { background: var(--out-wash);  color: var(--out); }
.status-badge-warn { background: var(--warn-wash); color: var(--warn-ink); }

/* نشانِ وضعیتِ چک دکمه است (جایِ عوض کردنِ وضعیت)، ولی باید دقیقاً مثلِ
   نشانِ معمولی دیده شود — وگرنه دو شکلِ متفاوت برای یک چیز می‌شد.
   ⚠ هدفِ لمس با padding منفی بزرگ می‌شود، نه با بزرگ کردنِ خودِ نشان. */
button.status-badge {
    border: none;
    font-family: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    padding: 9px 10px;
    margin: -6px 0;
}
button.status-badge:active { transform: scale(.96); }

.empty-row {
    text-align: center; color: var(--muted-2);
    padding: 28px 12px; font-size: 13.5px;
}

/* ============================================================
   ۱۰. فیلترها
   ============================================================ */
/* یک نوار افقی که کشیده می‌شود — به‌جای شکستن به چند ردیف و بلعیدن صفحه */
.filter-bar {
    display: flex;
    gap: 7px;
    flex-wrap: nowrap;
    overflow-x: auto;
    margin: 0 -14px 9px;
    padding: 0 14px 2px;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.filter-bar::-webkit-scrollbar { display: none; }
.filter-chip {
    padding: 8px 14px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    background: var(--surface);
    font-size: 12.5px; font-weight: 600;
    color: var(--muted);
    cursor: pointer; text-decoration: none;
    white-space: nowrap;
}
.filter-chip.active { background: var(--brand); color: var(--brand-on); border-color: var(--brand); }
.filter-search { flex: 1; min-width: 150px; }
.report-form { display: flex; gap: 11px; align-items: flex-end; flex-wrap: wrap; margin-bottom: 14px; }
.report-form .form-group { flex: 1; min-width: 130px; margin-bottom: 0; }

.chart-range-tabs { display: flex; gap: 7px; margin: 4px 0 15px; }
.chart-range-tab {
    flex: 1; padding: 9px;
    border: 1px solid var(--line);
    background: var(--surface);
    border-radius: var(--r-sm);
    font-size: 13px; font-weight: 600; color: var(--muted);
}
.chart-range-tab.active { background: var(--brand); color: var(--brand-on); border-color: var(--brand); }

.chart-container { position: relative; height: 270px; margin: 0 auto; }

/* ============================================================
   ۱۱. جدول (فقط صفحات مدیریت)
   ============================================================ */
/* روی موبایل جدول‌ها کارتی می‌شوند، پس اسکرول افقی لازم نیست.
   نبودِ ظرف اسکرول، اسکرول عمودی صفحه را محسوس روان‌تر می‌کند. */
.table-wrapper { }
.data-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.data-table th {
    text-align: right; padding: 10px;
    background: var(--line-soft);
    color: var(--muted);
    font-size: 12px; font-weight: 700;
    white-space: nowrap;
}
.data-table th:first-child { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
.data-table th:last-child  { border-radius: var(--r-sm) 0 0 var(--r-sm); }
.data-table td { padding: 11px 10px; border-bottom: 1px solid var(--line-soft); }
.data-table tr:last-child td { border-bottom: none; }

/* ⛔ ستونِ «عملیات» عرضِ **خودش** را می‌گیرد، نه باقی‌ماندهٔ عرض را.
   `width: 1%` در جدولِ خودکار یعنی «کمترین عرضِ لازم»، پس فشار روی
   ستون‌هایی می‌افتد که متنشان واقعاً می‌تواند بشکند (نام، ایمیل) نه روی
   ردیفی از دکمه‌ها. بدونِ این، دکمه‌ها زیرِ هم می‌افتادند و ارتفاعِ هر
   ردیف از ۴۸ به **۲۱۱** پیکسل می‌رسید — اندازه‌گیری شد، حدس زده نشد. */
.data-table th.actions-cell, .data-table td.actions-cell { width: 1%; }
.table-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.table-actions form { display: inline-flex; margin: 0; }
.table-actions .self-note { font-size: 12px; color: var(--muted); white-space: nowrap; }

/* ============================================================
   ۱۲. مودال
   ============================================================ */
/* ⛔ حاشیه‌ی امن اینجا هم لازم است، نه فقط در نوار بالا و پایین.
   شیت‌ها از قبل `env(safe-area-inset-bottom)` داشتند ولی مودال‌ها نه —
   و مودال روی گوشیِ نصب‌شده تا لبه‌ی صفحه می‌رفت، پس ردیفِ دکمه‌ها زیرِ
   خطِ خانه می‌افتاد و سرآیند زیرِ ناچ. در مرورگر بی‌عیب بود چون آنجا
   `env(...)` صفر است — همان دامی که قاعده‌ی ۱۳ برایش نوشته شد. */
.modal-overlay {
    position: fixed; inset: 0;
    background: rgba(21,23,28,.5);
    z-index: 300;
    display: none;
    align-items: center; justify-content: center;
    padding: calc(16px + env(safe-area-inset-top)) 16px
             calc(16px + env(safe-area-inset-bottom));
    /* اگر مودالی از فضای امن هم بلندتر شد، خودِ لایه اسکرول شود.
       با `align-items: center` تنها، بالای مودالِ بلند بیرون از لایه
       می‌افتد و **قابل اسکرول هم نیست** — یعنی سرآیند و دکمه‌ی بستن
       برای همیشه از دسترس خارج می‌شوند. */
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}
.modal-overlay.show { display: flex; }
.modal-box {
    background: var(--surface);
    border-radius: var(--r-lg);
    padding: 18px;
    width: 100%; max-width: 430px;
    /* ⚠ `88vh` نه: `vh` روی iOS کلِ صفحه را می‌شمارد، هم فضای ناچ هم
       نوارِ مرورگر. `100%` یعنی جعبه‌ی محتوای همین لایه — که حاشیه‌ی
       امن و padding از آن کم شده — پس عددِ جادویی لازم نیست و روی هر
       گوشی‌ای درست درمی‌آید. */
    max-height: 100%; overflow-y: auto;
    box-shadow: var(--sh-lg);
    flex-shrink: 0;
}
.modal-header {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 15px;
}
.modal-header h3 { font-size: 16px; font-weight: 700; }
.modal-close {
    background: none; border: none;
    font-size: 25px; line-height: 1;
    color: var(--muted); padding: 0 4px;
}
.modal-actions { display: flex; gap: 9px; margin-top: 17px; }
.modal-actions .btn { flex: 1; }

/* ============================================================
   ۱۳. ناوبری پایین (موبایل)
   ============================================================ */
.bottom-nav {
    position: fixed; bottom: 0; left: 0; right: 0;
    height: 60px;
    background: var(--surface);
    border-top: 1px solid var(--line);
    display: flex; align-items: center;
    z-index: 200;
    padding-bottom: env(safe-area-inset-bottom);
}
.bottom-nav-item {
    flex: 1;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 3px;
    height: 100%;
    background: none; border: none;
    font-size: 10px; font-weight: 600;
    color: var(--muted-2);
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
}
.bottom-nav-item.active { color: var(--gold); }
.bottom-nav-item:active { opacity: .6; }
.bottom-nav-center {
    flex: 1; display: flex;
    align-items: center; justify-content: center;
    height: 100%; text-decoration: none;
    background: none;          /* بدون این، مرورگر مربع خاکستری دکمه را می‌کشد */
    border: none;
    padding: 0;
    -webkit-appearance: none;
    appearance: none;
    -webkit-tap-highlight-color: transparent;
}
.bottom-nav-fab {
    width: 50px; height: 50px;
    border-radius: 50%;
    background: var(--brand);
    color: var(--gold-lift);
    display: flex; align-items: center; justify-content: center;
    margin-top: -20px;
    border: 4px solid var(--surface);
    box-shadow: 0 4px 14px rgba(21,23,28,.28);
}
.bottom-nav-center:active .bottom-nav-fab { transform: scale(.93); }

/* ---------- شیت ثبت تراکنش ---------- */
.sheet-overlay {
    position: fixed; inset: 0;
    background: rgba(21,23,28,.45);
    z-index: 260;
    display: none;
    align-items: flex-end;
}
.sheet-overlay.show { display: flex; }
.sheet {
    background: var(--surface);
    width: 100%;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    padding: 9px 16px calc(20px + env(safe-area-inset-bottom));
    max-height: 90vh;
    max-height: 90dvh;   /* iOS: vh نوارِ مرورگر را نادیده می‌گیرد */
    overflow-y: auto;
    animation: sheetUp .2s ease-out;
}
.sheet-head {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 14px;
}

/* مبلغ، قهرمانِ فرم ثبت است */
.amount-input {
    font-size: 24px !important;
    font-weight: 700;
    letter-spacing: -.4px;
    text-align: center;
    padding: 14px 13px !important;
    font-variant-numeric: tabular-nums;
}
@media (min-width: 901px) {
    .sheet-overlay { align-items: center; padding: 20px; }
    .sheet { max-width: 430px; border-radius: var(--r-lg); }
}

/* ---------- شیت ابزارها ---------- */
.more-sheet-overlay {
    position: fixed; inset: 0;
    background: rgba(21,23,28,.45);
    z-index: 250; display: none; align-items: flex-end;
}
.more-sheet-overlay.show { display: flex; }
.more-sheet {
    background: var(--surface);
    width: 100%;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    padding: 9px 16px calc(22px + env(safe-area-inset-bottom));
    max-height: 82vh;
    max-height: 82dvh;   /* iOS: vh نوارِ مرورگر را نادیده می‌گیرد */
    overflow-y: auto;
    animation: sheetUp .2s ease-out;
}
@keyframes sheetUp { from { transform: translateY(18px); opacity: 0; } to { transform: none; opacity: 1; } }
.more-sheet-handle {
    width: 38px; height: 4px;
    background: var(--line);
    border-radius: 3px; margin: 4px auto 14px;
}
.more-sheet-title { font-size: 14px; font-weight: 700; margin-bottom: 13px; }

.tools-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.tool-card {
    display: flex; flex-direction: column;
    align-items: flex-start; justify-content: space-between;
    gap: 13px;
    --tool-card-h: 90px;
    min-height: var(--tool-card-h);
    padding: 14px;
    border-radius: var(--r);
    background: var(--line-soft);
    color: var(--ink);
    text-decoration: none;
    font-size: 13px; font-weight: 700;
}
.tool-card svg { color: var(--tc1, var(--gold)); }
.tool-card:active { transform: scale(.975); }

/* ============================================================
   ۱۴. طلب و بدهی / چک
   ============================================================ */
.debt-card {
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: 14px;
    margin-bottom: 11px;
}
.debt-card-main { display: flex; align-items: flex-start; gap: 11px; }
.debt-check { flex-shrink: 0; cursor: pointer; padding-top: 2px; }
.debt-check input { display: none; }
.debt-check-mark {
    display: block; width: 25px; height: 25px;
    border-radius: 50%;
    border: 2px solid var(--line);
    background: var(--surface);
    position: relative;
}
.debt-check input:checked + .debt-check-mark { background: var(--in); border-color: var(--in); }
.debt-check input:checked + .debt-check-mark::after {
    content: ''; position: absolute;
    top: 50%; left: 50%;
    width: 6px; height: 11px;
    border: solid #fff; border-width: 0 2px 2px 0;
    transform: translate(-50%,-60%) rotate(45deg);
}
.debt-info { flex: 1; min-width: 0; }
.debt-name { font-weight: 700; font-size: 14.5px; margin-bottom: 3px; }
.debt-dates { font-size: 11.5px; color: var(--muted); }
/* کلیدِ «بدون سررسید» زیرِ تاریخ‌گزینِ طلب/بدهی */
.debt-no-due { display: flex; align-items: center; gap: 6px; margin-top: 6px; font-size: 12.5px; color: var(--muted); cursor: pointer; }
.debt-no-due input { width: auto; margin: 0; }
.jdp-display:disabled { opacity: .5; cursor: not-allowed; }
.debt-note { font-size: 12.5px; color: var(--muted); margin-top: 4px; }
.debt-amount { font-weight: 700; font-size: 14.5px; white-space: nowrap; }
.debt-amount small { font-size: 10.5px; font-weight: 400; color: var(--muted); }
/* ارزشِ امروزِ چک (`chequePresentValue()`) زیرِ مبلغِ اسمی، و روشش زیرِ تاریخ */
.cheque-today-value { display: block; margin-top: 2px; font-size: 11px; font-weight: 600; color: var(--in); text-align: end; }
.cheque-value-caption { color: var(--muted-2); }
.summary-box .summary-sub { margin-top: 3px; font-size: 11px; color: var(--muted); }
.cheque-value-preview {
    margin: 4px 0 12px; padding: 10px 12px; border-radius: 12px;
    background: color-mix(in srgb, var(--in) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--in) 22%, transparent);
    font-size: 12.5px; line-height: 1.9; color: var(--ink);
}
.cheque-value-preview b { font-weight: 700; }
.cheque-value-preview.is-error { background: none; border-color: var(--line); color: var(--muted); }
.debt-card-footer {
    display: flex; align-items: center; justify-content: space-between;
    gap: 9px; flex-wrap: wrap;
    margin-top: 12px; padding-top: 11px;
    border-top: 1px dashed var(--line);
}
.debt-actions { display: flex; gap: 7px; }
.debt-overdue { border-color: var(--out); }
.debt-settled { opacity: .58; }
.debt-settled .debt-name { text-decoration: line-through; }
.debt-search-bar input { width: 100%; }

/* ============================================================
   ۱۵. گزارش دسته‌بندی
   ============================================================ */
.category-breakdown-list { display: flex; flex-direction: column; gap: 15px; }
.cat-breakdown-summary { display: flex; align-items: center; gap: 9px; }
.cat-breakdown-summary.js-cat-toggle { cursor: pointer; }
/* رنگ نقطه و نوار از دو متغیر می‌آید که PHP کنارشان می‌نویسد: مقدار
   روشن و مقدار شب. این‌طور همان HTML در هر دو حالت درست است و لازم
   نیست صفحه دوباره ساخته شود. */
.cat-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; background: var(--dot-l); }
[data-theme="dark"] .cat-dot { background: var(--dot-d, var(--dot-l)); }
.cat-breakdown-name {
    flex: 1; font-size: 13.5px; font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cat-breakdown-pct { font-size: 11.5px; color: var(--muted); flex-shrink: 0; }
.cat-breakdown-amount { font-size: 13.5px; font-weight: 700; white-space: nowrap; flex-shrink: 0; }
.cat-breakdown-bar-track {
    height: 5px; background: var(--line-soft);
    border-radius: 3px; overflow: hidden; margin-top: 7px;
    /* میله‌ی پیشرفت همیشه از چپ پر می‌شود، حتی در صفحه‌ی راست‌به‌چپ.
       بدون این، بچه‌ی بلاکیِ داخل ترک از لبه‌ی راست شروع می‌کرد و
       «۳۰٪ پیشرفت» به شکل ۳۰٪ سمتِ راست دیده می‌شد — خلافِ چیزی که
       چشم از یک نوار پیشرفت انتظار دارد. */
    direction: ltr;
}
.cat-breakdown-bar { height: 100%; border-radius: 3px; background: var(--dot-l); }
[data-theme="dark"] .cat-breakdown-bar { background: var(--dot-d, var(--dot-l)); }
.cat-breakdown-detail {
    margin-top: 10px; padding: 10px 12px;
    background: var(--line-soft); border-radius: var(--r-sm);
}
.cat-detail-row { display: flex; align-items: center; gap: 9px; padding: 6px 0; font-size: 12.5px; }
.cat-detail-row + .cat-detail-row { border-top: 1px solid var(--line); }
.cat-detail-date { color: var(--muted); flex-shrink: 0; }
.cat-detail-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-detail-amount { font-weight: 700; flex-shrink: 0; }
.cat-detail-note { font-size: 11.5px; color: var(--muted); margin-top: -3px; padding-bottom: 5px; }

/* ============================================================
   ۱۶. لیست‌های مرجع (بانک‌ها / انواع دارایی)
   ============================================================ */
.ref-manager { margin-bottom: 20px; }
.ref-manager:last-child { margin-bottom: 0; }
.ref-manager-title { font-size: 13px; font-weight: 700; margin-bottom: 9px; color: var(--muted); }
/* ردیفِ «دسته‌های پیشنهادی» — فقط تا وقتی که چیزی کم است دیده می‌شود،
   بعد از زدن خودش ناپدید می‌شود. پس نباید مثل یک بخشِ دائمی به نظر
   برسد؛ همان کارت با یک ردیفِ کم‌ارتفاع. */
.ref-suggest {
    display: flex; align-items: center; gap: 12px;
    flex-wrap: wrap;
}
.ref-suggest-text {
    flex: 1; min-width: 180px; margin: 0;
    font-size: 12.5px; line-height: 1.8; color: var(--muted);
}
.ref-suggest-text strong { color: var(--ink); font-weight: 700; }

/* چیپِ نوعِ دارایی وقتی نرخ دارد: نام، نرخ، حذف — همه در یک چیپ.
   بخشِ جدا برای «نرخ‌ها» یعنی کارتِ هفتم در صفحه‌ای که برای کم کردنِ
   شلوغی ساخته شده. */
.ref-chip-priced { gap: 7px; }
.ref-price-btn {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    color: var(--gold);
    font-family: inherit; font-size: 11.5px; font-weight: 700;
    padding: 3px 9px; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.ref-price-btn:active { transform: scale(.96); }

/* ---------- وام و قسط ---------- */
/* همان مکانیزمِ باز شدنِ نرمِ «ماندن در حساب» — یک فرزند، وگرنه
   0fr جمعش نمی‌کند (دلیلش بالاتر توضیح داده شده). */
.inst-fields {
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    transition: grid-template-rows .28s ease, opacity .2s ease, margin-top .28s ease;
    margin-top: 0;
}
.inst-fields-inner { overflow: hidden; min-height: 0; }
.inst-fields.is-open { grid-template-rows: 1fr; opacity: 1; margin-top: 12px; }

.debt-inst-line {
    margin: 7px 0 0;
    font-size: 12.5px; line-height: 1.8; color: var(--muted);
}
.debt-inst-line strong { color: var(--ink); font-weight: 700; }

/* تاریخچه‌ی پرداخت — جمع‌شونده تا کارت شلوغ نشود */
.debt-pay-log { margin-top: 8px; }
.debt-pay-log summary {
    font-size: 12px; color: var(--muted); cursor: pointer;
    list-style: none; padding: 3px 0;
    -webkit-tap-highlight-color: transparent;
}
.debt-pay-log summary::-webkit-details-marker { display: none; }
.debt-pay-log summary::before { content: '▾ '; }
.debt-pay-log[open] summary::before { content: '▴ '; }
.debt-pay-row {
    display: flex; align-items: center; gap: 10px;
    padding: 6px 0; font-size: 12.5px; color: var(--muted);
}
.debt-pay-row + .debt-pay-row { border-top: 1px solid var(--line-soft); }
.debt-pay-row span:first-child { min-width: 84px; }
.debt-pay-row span:nth-child(2) { flex: 1; }
.debt-pay-row b { color: var(--ink); font-variant-numeric: tabular-nums; }

/* روندِ خالص دارایی */
.nw-delta { margin: 6px 0 0; font-size: 12.5px; font-weight: 700; }
.nw-spark { margin: 10px 0 2px; height: 46px; }

.ref-add-row { display: flex; gap: 7px; margin-bottom: 11px; flex-wrap: wrap; }
.ref-add-row input { flex: 1; min-width: 110px; }
.ref-chip-list { display: flex; flex-wrap: wrap; gap: 6px; }
.ref-chip {
    display: inline-flex; align-items: center; gap: 5px;
    background: var(--line-soft);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    padding: 5px 6px 5px 12px;
    font-size: 12.5px;
}
.ref-chip-x {
    background: none; border: none;
    color: var(--muted); font-size: 16px; line-height: 1;
    padding: 0 4px; border-radius: 50%;
}
.ref-chip-x:hover { color: var(--out); }
/* ادغام — فقط کنارِ دسته‌ی شخصی رندر می‌شود (مبدأ حذف می‌شود، و حذفِ
   یک پیش‌فرض کارِ پنل مدیر است). */
/* پینِ دسته‌بندی روی فرمِ ثبت — کنارِ نامِ همان دسته، نه یک فهرستِ دوم */
.ref-chip-pin {
    display: inline-flex; align-items: center;
    background: none; border: none; cursor: pointer;
    color: var(--muted-2);
    padding: 0 2px; line-height: 0;
    -webkit-tap-highlight-color: transparent;
}
.ref-chip-pin svg { display: block; }
.ref-chip-pin.is-on { color: var(--brand-fg); }
/* ⚠ چیپِ پین‌شده باید در **یک نگاه** از بقیه جدا باشد، وگرنه کاربر در
   فهرستی با ۲۰ دسته نمی‌فهمد کدام‌ها را انتخاب کرده و آیکونِ کوچک را
   تک‌تک نگاه می‌کند. */
.ref-chip:has(.ref-chip-pin.is-on) {
    background: color-mix(in srgb, var(--brand) 12%, var(--surface));
    border-color: var(--brand-fg);
}
.ref-empty { font-size: 12.5px; color: var(--muted-2); }
.ref-unit-input { max-width: 110px; }

/* ---------- صفحه‌ی «فهرست‌های من» ----------
   هر فهرست یک کارت با آیکن رنگی و یک خط توضیح که می‌گوید کجای اپ به
   کار می‌آید — وگرنه «بانک‌های من» و «بانک‌های طرف مقابل» از هم قابل
   تشخیص نبودند. */
.ref-page-intro {
    font-size: 12.5px; color: var(--muted); line-height: 1.85;
    margin: 0 0 14px; padding: 0 2px;
}
.ref-card-head {
    display: flex; align-items: flex-start; gap: 11px;
    margin-bottom: 14px;
}
.ref-card-icon {
    width: 38px; height: 38px; flex: none;
    border-radius: 11px;
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(140deg, var(--rc1), var(--rc2));
    color: #fff;
}
.ref-card-title { font-size: 15px; font-weight: 700; margin: 1px 0 3px; }
.ref-card-sub { font-size: 12px; color: var(--muted); line-height: 1.75; margin: 0; }
.ref-link-row { margin: 0 0 16px; padding: 0 2px; }

/* دسته‌های پیش‌فرض برنامه — دیده می‌شوند ولی دکمه‌ی حذف ندارند، پس باید
   از چیپ‌های خودِ کاربر قابل تشخیص باشند. */
.ref-locked-title {
    font-size: 11.5px; color: var(--muted-2);
    margin: 14px 0 8px;
}
.ref-chip-locked {
    padding: 5px 12px;
    background: transparent;
    border-style: dashed;
    color: var(--muted);
}

/* ---------- دکمه‌ی بازگشت بالای صفحه‌های فرعی ---------- */
.page-back {
    display: inline-flex; align-items: center; gap: 6px;
    margin: 0 0 12px;
    padding: 7px 13px 7px 11px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    background: var(--surface);
    color: var(--ink-soft);
    font-size: 12.5px; font-weight: 600;
    text-decoration: none;
}
.page-back svg { flex: none; }
.page-back:active { background: var(--line-soft); }

/* ---------- زبانه‌های سطحِ صفحه ----------
   ⛔ عمداً «زیرخط» است نه «قرص»، چون `.due-filter` و `.filter-chip` هر دو
      قرص‌اند: با یک شکلِ مشترک، صافیِ داخلِ یک زبانه و خودِ زبانه‌ها هم‌وزن
      دیده می‌شدند و سلسله‌مراتب صاف می‌شد. حالا زبانه بالاست و قرص‌ها
      زیرش — یک نگاه کافی است تا معلوم شود کدام کدام است.

   زبانه‌ها **لینک**اند نه جاوااسکریپت: هر زبانه آدرسِ خودش را دارد، پس
   دکمه‌ی بازگشتِ مرورگر کار می‌کند و فقط محتوای همان زبانه از سرور
   می‌آید — نه هر سه با هم. */
.page-tabs {
    display: flex; gap: 4px;
    margin: 0 0 16px;
    border-bottom: 1px solid var(--line);
    overflow-x: auto;
    scrollbar-width: none;
}
.page-tabs::-webkit-scrollbar { display: none; }
.page-tab {
    flex: 0 0 auto;
    display: inline-flex; align-items: center; gap: 7px;
    padding: 11px 14px;
    margin-bottom: -1px;                 /* روی خودِ خطِ پایین می‌نشیند */
    border-bottom: 2px solid transparent;
    color: var(--muted);
    font-size: 13.5px; font-weight: 600;
    text-decoration: none; white-space: nowrap;
    -webkit-tap-highlight-color: transparent;
}
.page-tab svg { flex: none; opacity: .8; }
.page-tab:hover { color: var(--ink-soft); }
.page-tab.is-active { color: var(--brand-fg); border-bottom-color: var(--brand-fg); }
.page-tab.is-active svg { opacity: 1; }
/* شمارنده‌ی کنارِ زبانه — فقط وقتی چیزی هست. */
.page-tab-n {
    background: color-mix(in srgb, currentColor 15%, transparent);
    border-radius: 999px; padding: 1px 6px; font-size: 11px; font-weight: 700;
}

/* راهِ رسیدن به صفحه‌ای که زبانه نشد (تراکنش دوره‌ای). عمداً یک ردیفِ
   آرام است نه یک کارتِ دیگر: کارت با کارت‌های بالای صفحه هم‌وزن می‌شد و
   دوباره همان شلوغی را می‌ساخت. */
.due-more-link {
    display: flex; align-items: center; gap: 10px;
    margin-top: 16px; padding: 13px 15px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-sm);
    color: var(--ink-soft); font-size: 12.5px; font-weight: 600;
    text-decoration: none;
}
.due-more-link svg { flex: none; color: var(--muted); }
.due-more-link span { flex: 1; }
.due-more-link:active { background: var(--line-soft); }

/* ============================================================
   ۱۷. کارت جمع‌شونده
   ============================================================ */
.collapsible-header {
    display: flex; align-items: center; justify-content: space-between;
    cursor: pointer; user-select: none;
}
.collapse-chevron { color: var(--muted-2); font-size: 12px; transition: transform .18s; }
.collapsible-card.collapsed .collapse-chevron { transform: rotate(-90deg); }
.collapsible-body { margin-top: 14px; }
.collapsible-card.collapsed .collapsible-body { display: none; }

/* ============================================================
   ۱۸. تقویم شمسی
   ============================================================ */
.jdp-field { position: relative; cursor: pointer; }
.jdp-display { cursor: pointer; padding-left: 34px !important; pointer-events: none; }
.jdp-icon {
    position: absolute; left: 11px; top: 50%;
    transform: translateY(-50%);
    font-size: 14px; opacity: .5; pointer-events: none;
}
.jdp-overlay {
    position: fixed; inset: 0;
    background: rgba(21,23,28,.5);
    display: flex; align-items: center; justify-content: center;
    z-index: 400; padding: 16px;
}
.jdp-box {
    background: var(--surface);
    border-radius: var(--r-lg);
    padding: 15px;
    width: 100%; max-width: 320px;
    box-shadow: var(--sh-lg);
}
.jdp-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 11px; }
.jdp-nav {
    background: var(--line-soft); border: none;
    width: 33px; height: 33px; border-radius: 50%;
    font-size: 17px; font-weight: 700; color: var(--ink);
}
.jdp-title { font-size: 14px; font-weight: 700; }
.jdp-weekdays { display: grid; grid-template-columns: repeat(7,1fr); text-align: center; margin-bottom: 5px; }
.jdp-weekdays span { font-size: 10.5px; color: var(--muted); font-weight: 600; padding: 4px 0; }
.jdp-grid { display: grid; grid-template-columns: repeat(7,1fr); gap: 2px; }
.jdp-day {
    aspect-ratio: 1; min-height: 38px;
    border: none; background: transparent;
    border-radius: var(--r-sm);
    font-size: 13px; color: var(--ink);
}
.jdp-day:hover { background: var(--line-soft); }
.jdp-day-empty { pointer-events: none; }
.jdp-today { border: 1px solid var(--gold); font-weight: 700; }
.jdp-selected { background: var(--brand); color: var(--brand-on); font-weight: 700; }
.jdp-footer { margin-top: 9px; text-align: center; }
.jdp-today-btn {
    background: none; border: none;
    color: var(--gold); font-size: 12.5px; font-weight: 600; padding: 8px;
}

/* ============================================================
   ۱۹. صفحات ورود
   ============================================================ */
.auth-body {
    display: flex; align-items: center; justify-content: center;
    min-height: 100vh; padding: 20px;
    background: var(--paper);
}
.auth-box {
    background: var(--surface);
    border-radius: var(--r-lg);
    padding: 30px 24px;
    width: 100%; max-width: 380px;
    box-shadow: var(--sh-lg);
}
.auth-box-wide { max-width: 440px; }
.auth-logo { text-align: center; margin-bottom: 22px; }
.auth-logo .brand-icon { font-size: 34px; display: block; margin-bottom: 9px; }

/* آیکن خود اپ به‌جای ایموجی. گوشه‌ها گرد است چون خودِ فایل مربع است
   و در iOS/اندروید هم با همان انحنا نشان داده می‌شود. */
.brand-icon-img {
    display: block;
    object-fit: contain;
    border-radius: 22%;
}
.auth-logo .brand-icon-img { margin: 0 auto 11px; width: 64px; height: 64px; }

/* قاب گرد صفحه‌ی ورود — همان قابی که عکس پروفایل در بقیه‌ی اپ دارد.
   اگر دستگاه کاربری را به خاطر داشته باشد عکس خودش می‌نشیند، وگرنه
   آیکن برنامه؛ ولی شکل قاب در هر دو حالت یکی است. */
.auth-avatar {
    display: block; margin: 0 auto 12px;
    width: 76px; height: 76px;
    border-radius: 50%;
    object-fit: cover;
    border: 3px solid var(--surface);
    box-shadow: 0 6px 18px -8px rgba(0,0,0,.45);
    background: var(--brand);
}
/* آیکن برنامه مربع است و طرحش تا لبه می‌رود؛ کمی تو رفتگی لازم دارد
   تا داخل دایره بریده به نظر نرسد. */
.auth-avatar-app { object-fit: contain; padding: 6px; }
.sidebar-brand .brand-icon-img { width: 24px; height: 24px; border-radius: 26%; }
.auth-logo h1 { font-size: 21px; font-weight: 700; }
.auth-subtitle { font-size: 12.5px; color: var(--muted); margin-top: 4px; }
.auth-form { margin-top: 6px; }

/* شناسه‌ی ورود در مرحله‌ی سوم ثبت‌نام با شماره — یک مقدارِ خواندنی، نه
   یک فیلد: فیلدِ غیرفعال شبیهِ چیزی است که کاربر باید پرش کند.
   ⚠ جهتش از `.ltr-num` می‌آید (در همان فهرست، روی خودِ عنصر)، نه یک
     `direction: ltr` تازه — وگرنه نسخه‌ی دومِ آن قاعده می‌شد. */
.idcard {
    font-size: 17px; font-weight: 700;
    padding: 11px 13px; border-radius: 12px;
    border: 1px solid var(--line); background: var(--gold-wash);
}
.link-back {
    background: none; border: none;
    color: var(--gold); font-size: 12.5px;
    padding: 0 0 13px; display: block;
    text-align: right; width: 100%; text-decoration: none;
}

/* ============================================================
   ۲۰. واکنش‌گرایی
   ============================================================ */
@media (max-width: 900px) {
    /* منوی کناری کنار می‌رود؛ ناوبری پایین جایگزین آن است */
    .sidebar, .sidebar-overlay, .menu-toggle { display: none !important; }
    /* ⛔ کفِ صفحه باید از **سرِ** نوارِ شناور بگذرد، و حاشیه‌ی امن هم
       در آن حساب شود. نوار از کفِ پنجره این‌قدر بالا می‌ایستد:
           14px (فاصله از کف) + env(safe-area-inset-bottom) + 62px (ارتفاع)
       در مرورگر حاشیه‌ی امن صفر است ⇒ ۷۶px، و ۹۶پیکسلِ قبلی کافی بود.
       روی آیفونِ نصب‌شده حاشیه ۳۴px است ⇒ ۱۱۰px، و همان ۹۶ یعنی
       **۱۴ پیکسل از آخرین ردیف زیر نوار گیر می‌کرد**. دقیقاً به همین دلیل
       «در وب درست بود ولی در اپ نه». اندازه‌گیری شده. */
    .page-content { padding: 14px 14px calc(96px + env(safe-area-inset-bottom)); }
    .topbar { padding: calc(12px + env(safe-area-inset-top)) 14px 12px; }

    /* جلوگیری از زوم خودکار iOS: فونت ورودی حداقل ۱۶px */
    input[type="text"], input[type="password"], input[type="email"],
    input[type="number"], input[type="date"],
    input[type="tel"], input[type="search"], select, textarea {
        font-size: 16px; padding: 12px 13px;
    }

    .btn { min-height: 44px; }
    .btn-sm { min-height: 36px; }
    .stats-grid { grid-template-columns: 1fr; }
    .report-form { flex-direction: column; align-items: stretch; }
    .report-form .form-group { min-width: 0; }
    .chart-container { height: 230px; }
    .modal-box { max-width: 100%; }
    .jdp-day { min-height: 42px; font-size: 14px; }

    /* جدول‌های مدیریت روی موبایل کارتی می‌شوند */
    .data-table, .data-table tbody, .data-table tr, .data-table td { display: block; width: 100%; }
    .data-table thead { display: none; }
    .data-table tr {
        border: 1px solid var(--line);
        border-radius: var(--r);
        padding: 11px; margin-bottom: 10px;
    }
    .data-table td {
        display: flex; justify-content: space-between; gap: 12px;
        padding: 6px 0; border: none; text-align: left;
    }
    .data-table td::before {
        content: attr(data-label);
        font-weight: 600; color: var(--muted);
        font-size: 12px; text-align: right;
    }
    .data-table td.empty-row { display: block; text-align: center; }
    .data-table td.empty-row::before { content: none; }
}

/* ---------- تنظیماتِ پیامک ---------- */
/* ⛔ `.card` یک `display` دارد و با ویژگیِ `hidden` هم‌وزن است، پس هر
   کدام دیرتر بیاید برنده می‌شود — یعنی `hidden` بی‌اثر می‌ماند و کارت
   با اینکه پنهان علامت خورده دیده می‌شود. این را در مرورگر دیدم، نه
   با خواندنِ کد. یک قاعده‌ی صریح جلویش را می‌گیرد. */
/* ⚠ ویژگیِ hidden با هر قاعده‌ای که display بدهد هم‌وزن است، پس کارتِ
   «پنهان» دیده می‌شد. برای فیلدهای نوعِ حسابِ ملی‌پیامک هم صریح لازم است. */
.sms-conn[hidden] { display: none; }
.mp-console[hidden], .mp-panel[hidden] { display: none; }

.req { color: var(--out); font-weight: 700; }
.sms-test {
    margin-top: 18px; padding-top: 16px;
    border-top: 1px dashed var(--line);
}
.sms-test-row { display: flex; gap: 8px; align-items: stretch; }
.sms-test-row input { flex: 1; }
.sms-test-row .btn { white-space: nowrap; }

/* ---------- گیتِ اشتراک ---------- */
/* ⛔ قفل، نه پنهان‌سازی. کاربری که نمی‌داند چیزی هست هرگز برایش پول
   نمی‌دهد؛ آنچه می‌فروشد دیدنِ همان چیزی است که ندارد. */
.lock-badge { font-size: 11px; opacity: .75; margin-inline-start: 4px; }

/* ⛔ نوارِ «فقط خواندنی» — جای صفحه‌ی قفلِ قبلی که کلِ محتوا را
   برمی‌داشت. رنگش کهربایی است نه قرمز: داده‌ی کاربر سرِ جایش است و
   چیزی خراب نشده، فقط یک در بسته است. با قرمز، کاربر فکر می‌کرد
   اطلاعاتش رفته. */
.plan-ro {
    display: flex; align-items: flex-start; gap: 11px; flex-wrap: wrap;
    padding: 13px 15px; margin-bottom: 16px;
    border-radius: 14px;
    background: var(--warn-wash);
    color: var(--warn-ink);
    font-size: 13px; line-height: 1.95;
}
.plan-ro-icon { flex-shrink: 0; margin-top: 3px; }
.plan-ro-body { flex: 1; min-width: 200px; }
.plan-ro-body strong { font-weight: 700; }
.plan-ro-body em { font-style: normal; font-weight: 700; }
.plan-ro-cta { flex-shrink: 0; align-self: center; }

/* ---------- پیشنهادِ نصبِ اپ اندروید ---------- */
/* ⛔ هیچ `position: fixed` ای اینجا نیست و نباید بیاید: نوارِ شناور با
   `.bottom-nav` و `env(safe-area-inset-bottom)` درگیر می‌شود و آن دسته
   خرابی فقط روی گوشیِ نصب‌شده دیده می‌شود. این یک کارتِ معمولی است.
   ⚠ `[hidden]` صریح لازم است (قاعده ۱۸): `display: flex` بر قاعده‌ی UA
   غلبه می‌کند و نوار **پیش از** تصمیمِ جاوااسکریپت یک لحظه دیده می‌شد. */
.apk-bar {
    display: flex; align-items: flex-start; gap: 11px; flex-wrap: wrap;
    padding: 13px 15px; margin-bottom: 16px;
    border-radius: 14px;
    background: var(--gold-wash);
    color: var(--ink);
    font-size: 13px; line-height: 1.95;
    position: relative;
}
/* ⚠ رنگش همان رنگِ «دعوت» است که `.start-card` هم دارد (`--gold`، که
   پالتِ دوم آبی‌اش می‌کند) نه رنگِ هشدار: این یک پیشنهاد است، نه اخطار. */
.apk-bar[hidden] { display: none !important; }
.apk-bar-icon { flex-shrink: 0; margin-top: 3px; color: var(--gold); }
.apk-bar-body { flex: 1; min-width: 190px; }
.apk-bar-body strong { display: block; font-weight: 700; }
.apk-bar-cta { flex-shrink: 0; align-self: center; }
/* ⚠ دکمه‌ی بستن گوشه است نه داخلِ ردیف: با `flex-wrap` وسطِ متن و دکمه
   می‌افتاد و شبیهِ یک تکه‌ی جامانده دیده می‌شد. */
.apk-bar-x {
    position: absolute; inset-inline-end: 6px; inset-block-start: 4px;
    background: none; border: 0; cursor: pointer;
    font-size: 19px; line-height: 1; padding: 2px 6px;
    color: var(--muted);
}

/* نامِ فایلِ بکاپ — قبل از زدنِ دکمه دیده می‌شود تا کاربر بداند دنبالِ
   چه فایلی در فهرستِ دانلود بگردد. `ltr` چون نامِ فایل لاتین است. */
.backup-file {
    display: flex; align-items: center; gap: 10px;
    background: var(--bg); border: 1px dashed var(--line);
    border-radius: var(--r-md); padding: 13px 15px;
    color: var(--ink-soft);
}
.backup-file-name {
    direction: ltr; font-weight: 700; font-size: 15px;
    color: var(--ink); letter-spacing: .2px;
}

/* ⛔ قفلِ اسکرول وقتی لایه‌ای باز است.
   عمداً هیچ `position`، `top` یا `height`ی عوض نمی‌شود: هر تغییرِ
   چیدمانی روی `body` روی آیفون نوارِ پایینِ شناور را جابه‌جا می‌کرد.
   `overscroll-behavior` جلوی «کشیدنِ زنجیره‌ای» را می‌گیرد تا رسیدن به
   ته شیت، صفحه‌ی زیرش را نلغزاند. */
html.is-locked, html.is-locked body {
    overflow: hidden;
    overscroll-behavior: none;
}

@media (min-width: 901px) {
    .bottom-nav, .more-sheet-overlay { display: none !important; }
    .table-wrapper { overflow-x: auto; }

    /* ⛔ نیمه‌ی دومِ رفعِ ستونِ «عملیات»، و بدونش `width: 1%` بی‌اثر است:
       تا وقتی ردیفِ دکمه‌ها `flex-wrap: wrap` باشد، کمترین عرضِ لازمش
       فقط **یک** دکمه است — پس جدول ستون را روی ۱۳۹ پیکسل می‌بندد و
       چهار دکمه زیرِ هم می‌افتند (ارتفاعِ ردیف ۱۹۱ پیکسل، اندازه‌گیری
       شد). با `nowrap` کمترین عرض همان مجموعِ دکمه‌هاست و اگر جا نشد
       `.table-wrapper` اسکرول می‌دهد.
       ⚠ فقط روی دسکتاپ: زیرِ ۹۰۱ پیکسل جدول کارتی می‌شود و آنجا شکستنِ
         ردیفِ دکمه‌ها دقیقاً همان چیزی است که باید بشود. */
    .table-actions { flex-wrap: nowrap; }

    /* ⛔ روی دسکتاپ شیت باید **وسط** باز شود، نه چسبیده به لبه.
       `.sheet` یک الگوی موبایلی است: تمام‌عرض، چسبیده به کف، و
       گردیِ فقط بالا. روی عرضِ ۱۴۰۰ پیکسل همان یعنی یک نوارِ دراز
       در لبه‌ی پایین که هیچ‌کس آن را «پنجره‌ی ثبت تراکنش» نمی‌خواند.
       اینجا همان نشانه‌گذاری بدونِ تغییر، به یک مودالِ وسط تبدیل
       می‌شود — پس هیچ صفحه‌ای دو نسخه‌ی HTML لازم ندارد. */
    .sheet-overlay { align-items: center; justify-content: center; padding: 24px; }
    .sheet {
        width: min(560px, 100%);
        border-radius: var(--r-lg);
        padding: 16px 20px 20px;
        max-height: 86vh;
        box-shadow: 0 24px 60px -20px rgba(21,23,28,.5);
        animation: sheetPop .16s ease-out;
    }
}

@keyframes sheetPop {
    from { opacity: 0; transform: scale(.97); }
    to   { opacity: 1; transform: scale(1); }
}

@media (max-width: 420px) {
    .tools-grid { gap: 9px; }
    .tool-card { font-size: 12.5px; }
}

/* ============================================================
   ۲۱. پرداخت نهایی
   ============================================================ */

/* نوار مانده: عمق واقعی، نه سایه‌ی تخت */
.balance-ribbon {
    box-shadow: 0 10px 24px -12px rgba(21,23,28,.45);
}

/* ردیف تراکنش: خط جداکننده‌ی مویی بین ردیف‌ها، نه دور تا دور */
.tx-row + .tx-row .tx-row-summary { border-top: 1px solid var(--line-soft); }
.tx-day-group + .tx-day-group { margin-top: 2px; }

/* سربرگ روز: خط کوچک قبل از تاریخ، مثل دفترهای حسابداری */
.tx-day-date::before {
    content: '';
    display: inline-block;
    width: 14px; height: 1px;
    background: var(--line);
    vertical-align: middle;
    margin-left: 7px;
}

/* آیکن دسته: فقط زمینه‌ی کم‌رنگ. حلقه‌ی پررنگ ردیف را شبیه هشدار می‌کرد. */
.cat-icon svg { opacity: .9; }

/* دکمه‌ی اصلی: بازخورد لمسی محسوس */
.btn-primary:active { opacity: .88; }

/* دکمه‌ی شناور: حلقه‌ی طلایی نازک، امضای برند */
.bottom-nav-fab { box-shadow: 0 0 0 1px rgba(217,164,65,.35), 0 6px 16px -6px rgba(21,23,28,.55); }

/* ناوبری پایین: تاکید فعال با یک نقطه، نه فقط رنگ */
.bottom-nav-item { position: relative; }
.bottom-nav-item.active::before {
    content: '';
    position: absolute;
    top: 7px;
    width: 4px; height: 4px;
    border-radius: 50%;
    background: var(--gold);
}

/* تراز اعداد در سطرهای جمع‌بندی */
.tx-day-total, .bs-value { letter-spacing: -.2px; }

/* حالت شب: کارت‌ها با کنتراست ملایم‌تر از هم جدا شوند */
html[data-theme="dark"] .card,
html[data-theme="dark"] .stats-card,
html[data-theme="dark"] .summary-box { background: var(--surface); }
html[data-theme="dark"] .balance-ribbon { box-shadow: none; }

/* اسکرول روان‌تر و بدون کشسانی مزاحم داخل شیت‌ها */
.sheet, .more-sheet { overscroll-behavior: contain; }

/* ⛔ شیت هرگز بلندتر از لایه‌اش نیست. با کیبوردِ باز، `fitOverlaysToKeyboard()`
   لایه را به اندازه‌ی viewport دیداری کوتاه می‌کند؛ بی‌این، شیت با همان ۹۰dvh
   از بالای لایه بیرون می‌زد و پایینش زیرِ کیبورد می‌ماند (اندروید). */
@media (max-width: 900px) {
    .sheet-overlay > .sheet { max-height: min(90dvh, 100%); }
    .more-sheet-overlay > .more-sheet { max-height: min(82dvh, 100%); }
}

/* جلوگیری از پرش چیدمان وقتی نوار اسکرول ظاهر می‌شود */
html { scrollbar-gutter: stable; }

/* ============================================================
   ۲۲. تنظیم ریتم و کنتراست
   ============================================================ */

/* مبلغ و عنوان به هم نزدیک‌تر؛ فاصله‌ی بی‌مورد وسط ردیف حذف شد */
.tx-row-summary { gap: 12px; min-height: 58px; }
.tx-row-amount { min-width: 0; }

/* عنوان کمی درشت‌تر، نام دسته کم‌رنگ‌تر — سلسله‌مراتب روشن‌تر */
.tx-row-title { font-size: 15px; }
.tx-row-cat { font-size: 11px; opacity: .85; }

/* حالت شب: کارت‌ها باید از پس‌زمینه جدا شوند */
html[data-theme="dark"] {
    --paper: #0d0f12;
    --surface: #16191e;
}
html[data-theme="dark"] .card,
html[data-theme="dark"] .stats-card,
html[data-theme="dark"] .summary-box { background: var(--surface); border-color: var(--line); }
html[data-theme="dark"] .balance-ribbon { background: #0a0b0d; }

/* حالت روز: کارت مانده کمی نرم‌تر از سیاه مطلق */
.balance-ribbon { background: #16181d; }

/* نوار پایین: جدایی تمیزتر از محتوا */
.bottom-nav { box-shadow: 0 -1px 0 var(--line); border-top: none; }

/* لبه‌ی کارت‌ها در حالت روز: خط مویی به‌جای سایه‌ی پخش */
.card, .stats-card, .summary-box {
    box-shadow: 0 1px 2px rgba(21,23,28,.04);
    border: 1px solid rgba(21,23,28,.06);
}
html[data-theme="dark"] .card,
html[data-theme="dark"] .stats-card,
html[data-theme="dark"] .summary-box { box-shadow: none; }


/* ============================================================
   ۲۳. اصلاح ایرادهای دیده‌شده در تست واقعی
   ============================================================ */

/* دکمه + : در هر دو حالت طلایی — همیشه دیده می‌شود و امضای برند است */
.bottom-nav-fab {
    background: linear-gradient(160deg, var(--gold-lift), var(--gold));
    color: #15171c;
    border: none;
    box-shadow: 0 0 0 4px var(--surface), 0 5px 14px -5px rgba(184,134,47,.6);
}
html[data-theme="dark"] .bottom-nav-fab {
    box-shadow: 0 0 0 4px var(--surface);
}

/* عدد مانده کمی کوچک‌تر تا در عرض موبایل جا شود و «تومان» له نشود */
.bv-num { font-size: 27px; }
@media (max-width: 380px) { .bv-num { font-size: 23px; } }

/* خط جداکننده‌ی داخل کارت مانده کم‌رنگ‌تر */
.balance-split { border-top-color: rgba(255,255,255,.07); }


/* ============================================================
   ۲۴. فیلتر فشرده (نوع + جستجو در یک ردیف)
   ============================================================ */
.filter-row { display: flex; gap: 8px; align-items: stretch; }

/* کنترل بخش‌بندی‌شده — سه حالت در یک قاب، کم‌جا و واضح */
.seg {
    display: flex;
    background: var(--line-soft);
    border-radius: var(--r-sm);
    padding: 3px;
    flex-shrink: 0;
}
.seg-item {
    padding: 6px 11px;
    border-radius: 7px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--muted);
    cursor: pointer;
    white-space: nowrap;
    -webkit-tap-highlight-color: transparent;
}
.seg-item.active { background: var(--surface); color: var(--ink); box-shadow: 0 1px 2px rgba(21,23,28,.08); }
html[data-theme="dark"] .seg-item.active { background: #2b3037; color: var(--ink); box-shadow: none; }

/* جستجو با آیکن داخل کادر — دکمه‌ی جداگانه لازم نیست، Enter کافی است */
.search-inline {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 7px;
    background: var(--line-soft);
    border-radius: var(--r-sm);
    padding: 0 11px;
}
.search-inline svg { color: var(--muted-2); flex-shrink: 0; }
.search-inline input {
    border: none;
    background: none;
    padding: 9px 0;
    font-size: 13.5px;
    min-width: 0;
}
.search-inline input:focus { outline: none; }

/* دکمه‌ی خروجی CSV — زیرِ نوارِ صافی، هم‌تراز با لبه‌ی راستِ کارت.
   ⚠ `display`/`gap`/`nowrap` عمداً تکرار نشده‌اند: `.btn` هر سه را
   دارد (`nowrap` را قاعده ۳۱ نگه می‌دارد). قاعده‌ای که چیزی را عوض
   نمی‌کند فقط دیف را بزرگ‌تر می‌کند. */
.tx-export {
    display: flex;
    justify-content: flex-end;
    margin-top: 10px;
}

/* روی موبایل فیلتر نوع و جستجو زیر هم بهتر جا می‌شوند */
@media (max-width: 400px) {
    .filter-row { flex-direction: column; }
    .seg { justify-content: space-between; }
    .seg-item { flex: 1; text-align: center; }
}

/* ============================================================
   ۲۵. حساب‌ها و انتقال
   ============================================================ */
.wallet-row {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 11px 0;
}
.wallet-row + .wallet-row { border-top: 1px solid var(--line-soft); }
.wallet-off { opacity: .5; }

.wallet-chip {
    width: 40px; height: 40px;
    border-radius: 12px;
    display: inline-flex;
    align-items: center; justify-content: center;
    flex-shrink: 0;
}
.wallet-meta { flex: 1; min-width: 0; }
.wallet-name {
    font-size: 14.5px; font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wallet-sub { font-size: 11px; color: var(--muted-2); margin-top: 1px; }
.wallet-bal {
    font-size: 14.5px; font-weight: 700;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    direction: ltr;
}
.wallet-menu {
    background: none; border: none;
    color: var(--muted-2);
    padding: 6px; border-radius: 8px;
    flex-shrink: 0; line-height: 0;
}
.wallet-menu:active { background: var(--line-soft); }

.transfer-row {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 11px 0;
    flex-wrap: wrap;
}
.transfer-row + .transfer-row { border-top: 1px solid var(--line-soft); }
.transfer-path {
    display: flex; align-items: center; gap: 7px;
    flex: 1; min-width: 140px;
    font-size: 13.5px; font-weight: 600;
}
.transfer-path svg { color: var(--muted-2); flex-shrink: 0; }
.tp-from, .tp-to { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.transfer-side { text-align: left; flex-shrink: 0; }
.transfer-amount {
    font-size: 14px; font-weight: 700;
    font-variant-numeric: tabular-nums; direction: ltr;
}
.transfer-date { font-size: 11px; color: var(--muted-2); }
.transfer-actions { display: flex; gap: 6px; }

/* ============================================================
   کلید دو حالته — یک شکل برای همه‌ی گزینه‌های روشن/خاموش اپ.
   قبلاً هر صفحه چک‌باکس خام مرورگر را نشان می‌داد و هر مرورگر
   شکل خودش را می‌کشید؛ حالا همه‌جا همین است.
   ============================================================ */
/* کلیدِ «منفی»ِ موجودیِ اولیه زیرِ همان فیلد (`wallets.php`).
   ⚠ `.form-group label` (block، با کلاس + عنصر) از `.switch` قوی‌تر است و کلید را
   زیرِ متن می‌شکست — پس داخلِ فرم دوباره flex. */
.form-group .switch { display: flex; margin-bottom: 0; font-weight: 400; }
.wallet-neg-switch { margin-top: 8px; font-size: 12.5px; }

.switch {
    display: flex; align-items: center; gap: 10px;
    cursor: pointer; font-size: 13.5px; line-height: 1.5;
    user-select: none;
}
.switch input {
    position: absolute; opacity: 0; width: 0; height: 0;
}
.switch-track {
    width: 42px; height: 24px; flex: none;
    border-radius: 999px;
    background: var(--line);
    position: relative;
    transition: background .18s ease;
}
.switch-knob {
    position: absolute; top: 3px; inset-inline-start: 3px;
    width: 18px; height: 18px; border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0,0,0,.28);
    transition: transform .18s ease;
}
.switch input:checked + .switch-track { background: var(--in); }
/* راست‌به‌چپ: حالت روشن یعنی دستگیره به سمت چپ می‌رود */
.switch input:checked + .switch-track .switch-knob { transform: translateX(-18px); }
.switch input:focus-visible + .switch-track {
    outline: 2px solid var(--brand-fg); outline-offset: 2px;
}
.switch input:disabled + .switch-track { opacity: .5; }
.switch-text { flex: 1; min-width: 0; }
.switch[hidden] { display: none !important; }

/* نسخه‌ی جمع‌وجور برای کنار ردیف‌های فهرست */
.switch-sm .switch-track { width: 34px; height: 20px; }
.switch-sm .switch-knob { width: 14px; height: 14px; top: 3px; }
.switch-sm input:checked + .switch-track .switch-knob { transform: translateX(-14px); }

.wallet-extra {
    display: flex; align-items: center; justify-content: space-between;
    gap: 9px; margin-top: 14px; padding-top: 13px;
    border-top: 1px dashed var(--line);
}

.hint { font-size: 11.5px; color: var(--muted); line-height: 1.7; margin-top: 4px; }
.ribbon-link {
    display: inline-block;
    margin-top: 13px;
    font-size: 12px;
    color: var(--gold-lift);
    text-decoration: none;
    font-weight: 600;
}

/* ============================================================
   ۲۶. بودجه‌بندی
   ============================================================ */
.budget-item { padding: 13px 0; }
.budget-item + .budget-item { border-top: 1px solid var(--line-soft); }
.budget-head { display: flex; align-items: center; gap: 10px; margin-bottom: 9px; }
.budget-meta { flex: 1; min-width: 0; }
.budget-name { font-size: 14px; font-weight: 600; }
.budget-period { font-size: 10.5px; color: var(--muted-2); }

.budget-bar-track {
    height: 7px;
    background: var(--line-soft);
    border-radius: 4px;
    overflow: hidden;
    margin-bottom: 7px;
    direction: ltr;   /* پر شدن از چپ — توضیح کامل کنار .cat-breakdown-bar-track */
}
.budget-bar { height: 100%; border-radius: 4px; transition: width .3s; }
.budget-bar-good { background: var(--in); }
.budget-bar-warn { background: #d97706; }
.budget-bar-over { background: var(--out); }

.budget-numbers { display: flex; align-items: baseline; justify-content: space-between; }
.budget-spent { font-size: 13.5px; font-weight: 700; font-variant-numeric: tabular-nums; }
.budget-of { font-size: 11.5px; font-weight: 400; color: var(--muted-2); }
.budget-pct { font-size: 12.5px; font-weight: 700; }
.budget-pct-good { color: var(--in); }
.budget-pct-warn { color: #d97706; }
.budget-pct-over { color: var(--out); }
.budget-note { font-size: 11px; color: var(--muted-2); margin-top: 4px; }
.budget-note-over { color: var(--out); }

/* ============================================================
   ۲۷. اهداف پس‌انداز
   ============================================================ */
.goal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.goal-title { font-size: 15px; font-weight: 700; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.goal-done { font-size: 11px; font-weight: 600; color: var(--in); }
.goal-date { font-size: 11.5px; color: var(--muted-2); margin-top: 2px; }
.goal-actions { display: flex; gap: 7px; margin-top: 12px; flex-wrap: wrap; }
.goal-history {
    margin-top: 11px;
    padding: 4px 12px;
    background: var(--line-soft);
    border-radius: var(--r-sm);
}
/* پرداختِ جزئی — حلقه‌ی پیشرفت به‌جای نوارِ خطی.
   ⛔ ردیفِ `.debt-progress` هم‌قد یا کوتاه‌ترِ نوار + جمله‌ی قبلی است (۳۹ در برابرِ
      ~۴۰)، پس کارت بلندتر نمی‌شود. حلقه عمداً کنارِ عددِ درشتِ بالا
      نیست: روی موبایل ستونِ نام را می‌فشرد (اندازه‌گیری شد).
   ⛔ رنگ از `--ring-h` می‌آید که `debtPaidRing()` می‌دهد (۰ قرمز → ۱۲۰
      سبز)؛ روشنایی در شب جدا است، وگرنه روی زمینه‌ی تیره گم می‌شد.
      حلقه از بالا و ساعت‌گرد پر می‌شود و `direction: ltr` دارد تا در
      صفحه‌ی راست‌به‌چپ برعکس نشود (قاعده‌ی میله‌های پیشرفت). */
.debt-amount-stack { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.35; flex-shrink: 0; }
.debt-amount-was { font-size: 10.5px; color: var(--muted); white-space: nowrap; }
/* هم‌خط با ستونِ نام (۲۵ دکمه‌ی تیک + ۱۱ فاصله) */
.debt-progress { display: flex; align-items: center; gap: 10px; margin-top: 5px; padding-inline-start: 36px; }
.debt-partial-note {
    display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
    font-size: 11px; color: var(--muted); line-height: 1.4; min-width: 0;
}
.debt-partial-paid { white-space: nowrap; }
.debt-ring {
    width: 34px; height: 34px; flex-shrink: 0; display: block;
    direction: ltr; overflow: visible;
    --ring-c: hsl(var(--ring-h, 0) 72% 44%);
}
.debt-ring circle { fill: none; stroke-width: 3.6; }
.debt-ring-track { stroke: var(--line); }
.debt-ring-fill {
    stroke: var(--ring-c); stroke-linecap: round;
    transform: rotate(-90deg); transform-origin: 18px 18px;
    transition: stroke-dasharray .5s ease;
}
.debt-ring-pct {
    fill: var(--ring-c); font-size: 9.5px; font-weight: 700;
    text-anchor: middle; dominant-baseline: central;
    font-variant-numeric: tabular-nums;
}
html[data-theme="dark"] .debt-ring { --ring-c: hsl(var(--ring-h, 0) 65% 60%); }

/* ============================================================
   ۲۸. تراکنش دوره‌ای
   ============================================================ */
.recur-row { display: flex; align-items: center; gap: 10px; padding: 12px 0; }
.recur-row + .recur-row { border-top: 1px solid var(--line-soft); }
.recur-info { flex: 1; min-width: 0; }
.recur-title { font-size: 14px; font-weight: 600; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.recur-sub { font-size: 11px; color: var(--muted-2); margin-top: 2px; line-height: 1.6; }
.recur-amount { font-size: 13.5px; font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; direction: ltr; }

.recur-attention-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; padding: 11px 0; flex-wrap: wrap;
}
.recur-attention-row + .recur-attention-row { border-top: 1px solid var(--line-soft); }
.recur-attention-title { font-size: 13.5px; font-weight: 600; }
.recur-attention-sub { font-size: 11px; color: var(--muted-2); margin-top: 2px; }
.recur-attention-actions { display: flex; gap: 7px; flex-wrap: wrap; }

/* ============================================================
   ۲۹. آینده مالی و تقویم
   ============================================================ */
.event-row {
    display: flex; align-items: center; gap: 10px;
    padding: 11px 0; text-decoration: none; color: inherit;
}
.event-row + .event-row { border-top: 1px solid var(--line-soft); }
.event-row:active { opacity: .6; }
.event-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.event-dot-in { background: var(--in); }
.event-dot-out { background: var(--out); }
.event-body { flex: 1; min-width: 0; }
.event-title {
    display: block; font-size: 14px; font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.event-meta { display: block; font-size: 11px; color: var(--muted-2); margin-top: 1px; }
.event-amount {
    font-size: 14px; font-weight: 700; white-space: nowrap;
    font-variant-numeric: tabular-nums; direction: ltr;
}
.event-when {
    font-size: 11px; font-weight: 700; flex-shrink: 0;
    min-width: 62px;
}
.event-overdue { color: var(--out); }
.event-daybreak {
    font-size: 11.5px; font-weight: 700; color: var(--muted);
    padding: 13px 0 4px;
}
.event-daybreak:first-child { padding-top: 2px; }

/* ---------- تقویم (`includes/home_calendar.php`) ----------
   ⛔ یک کارت، دو جا: روی گوشی بالای «گزارش» (`dashboard.php`؛ کاربر
      می‌تواند به نوارِ هفته جمعش کند — `.is-week`)، روی دسکتاپ زیرِ
      «آخرین تراکنش‌ها» در ستونِ اصلیِ خانه (همیشه ماهِ کامل — `.is-desk`).
   ⛔ «پهن» با container query سنجیده می‌شود نه عرضِ پنجره: همان کارت در
      ستونِ اصلیِ دسکتاپ مبلغِ هر روز و نامِ کاملِ روزها را نشان می‌دهد و
      روی گوشی نه — بی‌آنکه رندرکننده بداند کجاست.
   ⚠ زمینه‌ی تزئینی روی `::before` است نه `background` خودِ کارت: قاعده‌ی
     حالتِ شبِ `.card` وزنِ بیشتری دارد و گرادیان را پاک می‌کرد (درسِ
     `.start-card`).
   ⚠ روزِ ماهِ قبل/بعد `is-adj` است، نه `is-out` — `is-out` رنگِ پرداخت
     است (`.hcal-dot.is-out`) و یک نام برای دو معنا اولین تغییر را
     می‌شکست. */
.hcal { position: relative; overflow: hidden; padding: 16px 14px 12px; container-type: inline-size; }
.hcal::before {
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background: radial-gradient(120% 70% at 100% 0%, color-mix(in srgb, var(--gold) 11%, transparent), transparent 65%);
}
.hcal-inner { position: relative; transition: opacity .15s ease; }
.hcal-inner.is-loading { opacity: .55; }
.hcal-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.hcal-title { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.hcal-kicker { font-size: 11.5px; font-weight: 600; color: var(--muted); }
.hcal-title strong { font-size: 17px; font-weight: 800; letter-spacing: -.2px; white-space: nowrap; }
.hcal-tools { display: flex; align-items: center; gap: 6px; flex: none; }
.hcal-nav {
    width: 34px; height: 34px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--line-soft); color: var(--ink); text-decoration: none;
    transition: background .15s ease;
}
.hcal-nav:hover { background: var(--line); }
.hcal-now {
    font-size: 12px; font-weight: 700; white-space: nowrap;
    padding: 6px 12px; border-radius: var(--r-pill);
    background: var(--gold-wash); color: var(--gold); text-decoration: none;
}
.hcal-week { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; margin-bottom: 4px; }
.hcal-week span { font-size: 11px; font-weight: 700; color: var(--muted-2); }
.hcal-week .is-fri { color: var(--out); opacity: .8; }
.hcal-week i { font-style: normal; }
.hcal-wd-l, .hcal-amt { display: none; }
.hcal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
.hcal-d {
    appearance: none; -webkit-appearance: none; border: 0; padding: 0; margin: 0;
    background: transparent; font: inherit; color: var(--ink);
    height: 46px; border-radius: 12px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
    cursor: pointer; position: relative;
    transition: background .15s ease, transform .1s ease;
    -webkit-tap-highlight-color: transparent;
}
.hcal-n { font-size: 14px; font-weight: 600; line-height: 1; }
.hcal-d.is-fri .hcal-n { color: var(--out); }
.hcal-d.has-any { background: var(--line-soft); }
.hcal-d:not(.is-adj):hover { background: var(--line); }
.hcal-d:not(.is-adj):active { transform: scale(.94); }
.hcal-d.is-adj { cursor: default; }
.hcal-d.is-adj .hcal-n { color: var(--muted-2); opacity: .55; font-weight: 500; }
.hcal-d.is-today, .hcal-d.is-today:hover {
    background: var(--brand); color: var(--brand-on);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--brand) 32%, transparent);
}
.hcal-d.is-today .hcal-n { color: var(--brand-on); font-weight: 800; }
.hcal-d.is-today .hcal-dot { box-shadow: 0 0 0 1.5px var(--brand); }
/* ⚠ شب: `--brand` تقریباً هم‌رنگِ کارت است و «امروز» گم می‌شد. */
html[data-theme="dark"] .hcal-d.is-today { background: color-mix(in srgb, var(--gold) 38%, var(--surface)); }
html[data-theme="dark"] .hcal-d.is-today .hcal-dot { box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--gold) 38%, var(--surface)); }
.hcal-d.is-sel { box-shadow: inset 0 0 0 2px var(--gold); }
.hcal-d.is-today.is-sel { box-shadow: inset 0 0 0 2px var(--gold), 0 4px 12px color-mix(in srgb, var(--brand) 32%, transparent); }
.hcal-dots { display: flex; gap: 3px; height: 5px; }
.hcal-dot { width: 5px; height: 5px; border-radius: 50%; display: inline-block; flex: none; }
.hcal-dot.is-in   { background: var(--in); }
.hcal-dot.is-out  { background: var(--out); }
.hcal-dot.is-late { background: #d97706; }
.hcal-dot.is-due  { background: var(--gold); }

/* کارتِ پهن (ستونِ اصلیِ دسکتاپ، یا «گزارش» روی صفحه‌ی بزرگ) */
@container (min-width: 560px) {
    .hcal-week { margin-bottom: 6px; }
    .hcal-week span { font-size: 12px; }
    .hcal-wd-s { display: none; }
    .hcal-wd-l { display: inline; }
    .hcal-grid { gap: 6px; }
    .hcal-d { height: 78px; gap: 4px; border-radius: 14px; }
    .hcal-n { font-size: 15px; }
    .hcal-amt {
        display: flex; flex-direction: column; align-items: center;
        font-size: 10.5px; font-weight: 700; line-height: 1.3; white-space: nowrap;
    }
    .hcal-amt b { font-weight: 700; }
    .hcal-amt .is-in  { color: var(--in); }
    .hcal-amt .is-out { color: var(--out); }
    .hcal-d.is-today .hcal-amt b { color: var(--brand-on); }
}

/* نوارِ هفته: فقط ردیفِ امروز */
.hcal.is-week .hcal-d:not(.is-wk) { display: none; }

.hcal-foot {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
    margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--line);
}
.hcal-chip {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 12px; font-weight: 600; color: var(--ink-soft);
    padding: 5px 10px; border-radius: var(--r-pill);
    background: var(--line-soft); text-decoration: none; white-space: nowrap;
}
.hcal-chip b { font-weight: 800; color: var(--ink); }
.hcal-chip.is-in b  { color: var(--in); }
.hcal-chip.is-out b { color: var(--out); }
.hcal-chip.is-late { background: var(--warn-wash); color: var(--warn-ink); }
.hcal-chip.is-due  { background: var(--gold-wash); color: var(--gold); }
.hcal-chip.is-wait { min-width: 150px; opacity: .6; }
.hcal-toggle {
    appearance: none; -webkit-appearance: none; border: 0; background: transparent;
    font: inherit; font-size: 12.5px; font-weight: 700; color: var(--gold);
    display: inline-flex; align-items: center; gap: 4px;
    margin-inline-start: auto; padding: 5px 2px; cursor: pointer; white-space: nowrap;
}
.hcal-toggle svg { transition: transform .2s ease; }
.hcal:not(.is-week) .hcal-toggle svg { transform: rotate(180deg); }
.hcal.is-week .hcal-toggle-less, .hcal:not(.is-week) .hcal-toggle-more { display: none; }
.hcal.is-desk .hcal-toggle { display: none; }

/* جزئیاتِ روز — داخلِ همان کارت، نه کارتِ دوم پایینِ صفحه */
.hcal-day {
    position: relative; margin-top: 12px; padding: 12px;
    border-radius: var(--r); background: var(--paper); border: 1px solid var(--line-soft);
    animation: hcalIn .18s ease;
    scroll-margin-bottom: 96px;   /* زیرِ `.bottom-nav` نرود */
}
.hcal-day[hidden] { display: none; }
.hcal-day-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.hcal-day-title { font-size: 13.5px; font-weight: 800; }
.hcal-day-x {
    appearance: none; -webkit-appearance: none; border: 0; cursor: pointer; flex: none;
    width: 28px; height: 28px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--line-soft); color: var(--muted);
}
@keyframes hcalIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .hcal-day { animation: none; } .hcal-inner, .hcal-toggle svg { transition: none; } }
.day-section-title {
    font-size: 12.5px; font-weight: 700; color: var(--muted);
    margin: 12px 0 6px;
}
.day-section-title:first-child { margin-top: 0; }

/* ============================================================
   ۳۰. جستجو و ورود اطلاعات
   ============================================================ */
.search-page-form { display: flex; gap: 8px; align-items: stretch; }

.import-help { margin-top: 18px; padding-top: 15px; border-top: 1px dashed var(--line); }
.map-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 11px;
    margin-bottom: 14px;
}
.import-summary { margin: 16px 0 12px; }
.import-errors {
    background: var(--warn-wash); color: var(--warn-ink);
    border-radius: var(--r-sm); padding: 10px 12px;
    font-size: 12px; margin-bottom: 12px;
}
.import-errors summary { cursor: pointer; font-weight: 700; }
.import-error-row { padding: 3px 0; }

input[type="file"] {
    width: 100%; padding: 11px;
    border: 1px dashed var(--line);
    border-radius: var(--r-sm);
    background: var(--line-soft);
    font-size: 13px;
}

/* ============================================================
   ۳۱. پیوست رسید
   ============================================================ */
.attach-box {
    margin-top: 10px; padding: 10px 12px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
}
.attach-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 8px; padding: 6px 0; font-size: 12.5px;
}
.attach-row + .attach-row { border-top: 1px solid var(--line-soft); }
.attach-link {
    color: var(--ink); text-decoration: none; flex: 1;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.attach-link small { color: var(--muted-2); font-weight: 400; }
.attach-add {
    display: block; text-align: center;
    margin-top: 8px; padding: 9px;
    border: 1px dashed var(--line);
    border-radius: var(--r-sm);
    font-size: 12px; color: var(--gold);
    cursor: pointer;
}
.attach-add:active { opacity: .6; }

/* ---------- گزارش مقایسه‌ای ---------- */
.compare-row {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 0;
}
.compare-row + .compare-row { border-top: 1px solid var(--line-soft); }
.compare-label { font-size: 12.5px; font-weight: 700; color: var(--muted); min-width: 42px; }
.compare-bars { flex: 1; min-width: 0; }
.compare-line { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px; padding: 2px 0; }
.compare-name { color: var(--muted-2); }
.compare-val { font-weight: 700; font-variant-numeric: tabular-nums; direction: ltr; }
.compare-delta { font-size: 12px; font-weight: 700; flex-shrink: 0; }
/* خلاصه‌ی همیشه‌پیدا زیر سرِ کارتِ جمع‌شونده */
.compare-summary {
    margin: 0; padding: 10px 0 2px;
    font-size: 12.5px; line-height: 1.9; color: var(--muted);
}
.compare-summary strong { color: var(--ink); font-weight: 700; }
.compare-summary-delta { font-weight: 700; }
.delta-up { color: var(--in); }
.delta-down { color: var(--out); }
.insight-block { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--line); }

/* ============================================================
   ۳۲. حساب کاربری من
   ============================================================ */
.profile-head { display: flex; align-items: center; gap: 13px; }
.profile-avatar {
    width: 52px; height: 52px;
    border-radius: 50%;
    background: var(--brand);
    color: var(--gold-lift);
    display: flex; align-items: center; justify-content: center;
    font-size: 22px; font-weight: 700;
    flex-shrink: 0;
}
.profile-name { font-size: 16px; font-weight: 700; }
.profile-sub { font-size: 12px; color: var(--muted-2); margin-top: 2px; }

.devices-block { margin-top: 20px; padding-top: 16px; border-top: 1px dashed var(--line); }
.device-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; padding: 10px 0;
}
.device-row + .device-row { border-top: 1px solid var(--line-soft); }
.device-info { flex: 1; min-width: 0; }
.device-name { font-size: 13.5px; font-weight: 600; }
.device-meta { font-size: 11px; color: var(--muted-2); margin-top: 1px; }

/* ---------- صفحه‌بندی ---------- */
.pager {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; margin-top: 16px; padding-top: 14px;
    border-top: 1px solid var(--line-soft);
}
.pager-btn {
    padding: 9px 16px;
    border-radius: var(--r-sm);
    background: var(--line-soft);
    color: var(--ink);
    text-decoration: none;
    font-size: 13px; font-weight: 600;
    white-space: nowrap;
}
.pager-btn:active { opacity: .6; }
.pager-off { opacity: .35; }
.pager-info { font-size: 12px; color: var(--muted); text-align: center; }
.pager-info small { display: block; font-size: 11px; color: var(--muted-2); }

/* ============================================================
   ۳۳. تم Finmori
   برگرفته از طرح Finmori (Zoey Do) — سرمه‌ای عمیق، آبی روشن،
   کارت‌های سفید با خط مویی، و ناوبری شناور قرص‌شکل.
   ============================================================ */
:root {
    --ink:        #1b2559;   /* سرمه‌ای عمیق — متن و عنوان */
    --ink-soft:   #2a3563;
    --muted:      #6e7ba0;   /* متن ثانویه */
    --muted-2:    #9aa3c0;
    --line:       #e8ebf5;
    --line-soft:  #f2f4fa;
    --surface:    #ffffff;
    --paper:      #f6f7fb;

    --brand:      #2a3563;   /* دکمه اصلی و منوی پایین */
    --brand-on:   #ffffff;

    /* آبی = تعامل (لینک، حالت فعال) */
    --gold:       #2563eb;
    --gold-lift:  #3b82f6;
    --gold-wash:  #eaf1fe;

    --in:         #16a34a;
    --in-wash:    #e9f8ef;
    --out:        #e5484d;
    --out-wash:   #fdeeee;
    --warn-wash:  #fef6e7;
    --warn-ink:   #b45309;

    --r-sm: 12px;
    --r:    16px;
    --r-lg: 20px;

    --sh:    0 1px 2px rgba(27,37,89,.04);
    --sh-lg: 0 12px 32px rgba(27,37,89,.16);
}

html[data-theme="dark"] {
    --ink:        #eef1fa;
    --ink-soft:   #d5dbec;
    --muted:      #8e98bb;
    --muted-2:    #6c7699;
    --line:       #262c47;
    --line-soft:  #1e2338;
    --surface:    #161a2c;
    --paper:      #0e101b;   /* رنگ رسمی برند Finmori */

    --brand:      #232a47;
    --brand-on:   #ffffff;

    --gold:       #6f9bff;
    --gold-lift:  #8db2ff;
    --gold-wash:  #1b2540;

    --in:         #3ddc84;
    --in-wash:    #12301f;
    --out:        #ff6b70;
    --out-wash:   #331b1d;
    --warn-wash:  #33280f;
    --warn-ink:   #e5b45f;
}

/* ---------- کارت‌ها: خط مویی به‌جای سایه ---------- */
.card, .stats-card, .summary-box {
    border: 1px solid var(--line);
    box-shadow: none;
    border-radius: var(--r-lg);
}
html[data-theme="dark"] .card,
html[data-theme="dark"] .stats-card,
html[data-theme="dark"] .summary-box { border-color: var(--line); }

/* ---------- عنوان بخش‌ها: ریز، کم‌رنگ، با فاصله‌ی حروف ---------- */
.tx-day-date, .day-section-title, .ref-manager-title, .stats-card-title {
    text-transform: none;
    letter-spacing: .6px;
    font-size: 11px;
    font-weight: 700;
    color: var(--muted);
}
.tx-day-date::before { display: none; }

/* ---------- کارت مانده: روشن با عدد سرمه‌ای ---------- */
.balance-ribbon {
    background: linear-gradient(160deg, #eef2ff 0%, #f7f9ff 45%, var(--surface) 100%);
    border: 1px solid var(--line);
    box-shadow: none;
    padding: 22px 20px;
}
html[data-theme="dark"] .balance-ribbon {
    background: linear-gradient(160deg, #1c2340 0%, #171b2e 60%, var(--surface) 100%);
}
.balance-label { color: var(--muted); font-weight: 600; }
.bv-num { color: var(--ink); font-weight: 800; letter-spacing: -1px; }
.bv-unit { color: var(--muted); }
.balance-split { border-top-color: var(--line); }
.balance-split .bs-label { color: var(--muted); }
.bs-in  { color: var(--in); }
.bs-out { color: var(--out); }
.ribbon-link { color: var(--gold); }

/* ---------- کارت‌های آماری: پس‌زمینه‌ی خیلی کم‌رنگ ---------- */
.money-card { border: none; }
.money-card-income  { background: var(--in-wash); }
.money-card-expense { background: var(--out-wash); }
.summary-box { background: var(--surface); }

/* ---------- ناوبری پایین: شناور و قرص‌شکل ---------- */
.bottom-nav {
    left: 14px; right: 14px;
    /* ⚠ حاشیه‌ی امن در خودِ `bottom` است، نه در `margin-bottom`.
       هر دو یک نتیجه می‌دهند، ولی `margin-bottom` روی عنصرِ `fixed`ی که
       با `bottom` جای‌گذاری شده رفتارِ بدیهی ندارد و خواندنِ موقعیتِ
       واقعی را سخت می‌کند — و همین‌جا بود که باید عیب‌یابی می‌شد. */
    bottom: calc(14px + env(safe-area-inset-bottom));
    max-width: 460px;
    margin: 0 auto;
    height: 62px;
    background: var(--brand);
    border: none;
    border-radius: var(--r-pill);
    box-shadow: 0 10px 28px -8px rgba(27,37,89,.5);
    padding-bottom: 0;
}
.bottom-nav-item { color: rgba(255,255,255,.55); font-size: 10px; }
.bottom-nav-item.active { color: #fff; }
.bottom-nav-item.active::before { display: none; }
.bottom-nav-fab {
    width: 46px; height: 46px;
    margin-top: 0;
    border: none;
    background: linear-gradient(160deg, #dfe6ff, #b9c6ff);
    color: var(--brand);
    box-shadow: 0 4px 12px -3px rgba(27,37,89,.45);
}
html[data-theme="dark"] .bottom-nav-fab {
    background: linear-gradient(160deg, #8db2ff, #6f9bff);
    color: #0e101b;
}
/* ⚠ اینجا پیش از این `.page-content { padding-bottom: 96px }` بود و چون
   **بعد از** قاعده‌ی موبایل می‌آمد، هر مقداری که آنجا نوشته می‌شد را
   خنثی می‌کرد — بی‌آنکه معلوم باشد. فاصله‌ی کف حالا فقط یک جا تعریف
   می‌شود: داخل @media (max-width:900px)، همان‌جا که نوار شناور هست.
   روی دسکتاپ نوار `display:none` است، پس آنجا این فاصله فقط جای خالی
   می‌گرفت. */

/* ---------- چیپ فیلتر: فعال = آبی کم‌رنگ ---------- */
.filter-chip {
    border-radius: var(--r-pill);
    border-color: var(--line);
    color: var(--muted);
    background: var(--surface);
}
.filter-chip.active {
    background: var(--gold-wash);
    border-color: var(--gold);
    color: var(--gold);
}

/* ---------- کنترل بخش‌بندی‌شده ---------- */
.seg { background: var(--line-soft); border-radius: var(--r-sm); }
.seg-item.active {
    background: var(--surface);
    color: var(--ink);
    box-shadow: 0 1px 3px rgba(27,37,89,.10);
}
html[data-theme="dark"] .seg-item.active { background: var(--brand); color: #fff; }

/* ---------- دکمه‌ها ---------- */
.btn { border-radius: var(--r-sm); }
.btn-primary { background: var(--brand); color: #fff; }
.btn-large { border-radius: var(--r); padding: 16px; }
.btn-secondary { background: var(--line-soft); border-color: var(--line); color: var(--ink); }
.link-more, .attach-add { color: var(--gold); }

/* ---------- آیکن دسته: دایره‌ی سفید با حلقه‌ی نازک ---------- */
.cat-icon {
    border-radius: 50%;
    background: var(--surface) !important;
    box-shadow: inset 0 0 0 1px var(--line);
}
.cat-icon-sm { border-radius: 50%; }
.wallet-chip { border-radius: 50%; }

/* ---------- ردیف تراکنش ---------- */
.tx-row-summary { min-height: 62px; }
.tx-row-title { font-weight: 600; color: var(--ink); }
.tx-row-cat { color: var(--muted-2); }
.tx-row-amount { font-weight: 700; }
.tx-row-amount.amount-income  { color: var(--in); }
.tx-row-amount.amount-expense { color: var(--out); }
.tx-row + .tx-row .tx-row-summary { border-top-color: var(--line-soft); }

/* ---------- نوار پیشرفت: سبز روشن با دستگیره ---------- */
.budget-bar-track { background: var(--line-soft); height: 8px; border-radius: var(--r-pill); }
.budget-bar { border-radius: var(--r-pill); }
.budget-bar-good { background: #3ddc84; }
.budget-bar-warn { background: #f5a524; }
.budget-bar-over { background: var(--out); }

/* ---------- ورودی‌ها ---------- */
input[type="text"], input[type="password"], input[type="email"],
input[type="number"], input[type="date"], select, textarea {
    border-radius: var(--r-sm);
    border-color: var(--line);
    background: var(--surface);
}
input:focus, select:focus, textarea:focus {
    border-color: var(--gold);
    box-shadow: 0 0 0 3px var(--gold-wash);
}
.search-inline { background: var(--line-soft); border-radius: var(--r-sm); }

/* مبلغ در فرم ثبت: بزرگ و سرمه‌ای، مثل Finmori */
.amount-input {
    color: var(--ink);
    font-size: 30px !important;
    letter-spacing: -1px;
    border: none;
    background: none;
}
.amount-input:focus { box-shadow: none; }

/* ---------- نوار بالا و منوی کناری ---------- */
.topbar { border-bottom-color: var(--line-soft); }
.page-title { color: var(--ink); font-weight: 700; }
.sidebar { background: var(--brand); }
.sidebar-nav a.active { background: var(--gold); color: #fff; }
.badge-admin { background: var(--gold-wash); color: var(--gold); }

.jdp-selected { background: var(--gold); color: #fff; }
.jdp-today { border-color: var(--gold); }

/* ---------- مودال و شیت ---------- */
.modal-box, .sheet, .more-sheet { border-radius: var(--r-lg); }
.sheet, .more-sheet { border-radius: var(--r-lg) var(--r-lg) 0 0; }
.tool-card { border-radius: var(--r); }

/* ---------- کارت‌های طلب/بدهی و چک ---------- */
.debt-card { border-radius: var(--r); border-color: var(--line); }
.debt-check-mark { border-color: var(--line); }
.debt-check input:checked + .debt-check-mark { background: var(--in); border-color: var(--in); }

/* ---------- صفحه‌بندی ---------- */
.pager-btn { background: var(--line-soft); border-radius: var(--r-pill); }

/* ---------- رفع سرریز فیلد جستجو ----------
   قانون عمومی input عرض ۱۰۰٪ می‌دهد؛ داخل ظرف flex این یعنی
   «۱۰۰٪ ظرف + فضای آیکن» و فیلد از کادر بیرون می‌زند. */
.search-inline {
    overflow: hidden;
    min-height: 42px;
}
.search-inline input {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
    max-width: 100%;
}
.search-page-form { align-items: stretch; flex-wrap: nowrap; }
.search-page-form .btn { flex-shrink: 0; white-space: nowrap; }

/* نوار جستجوی صفحه‌ی چک و طلب/بدهی هم همین مشکل را داشت */
.debt-search-bar { display: flex; gap: 8px; align-items: stretch; }
.debt-search-bar input { flex: 1 1 auto; width: auto; min-width: 0; }
.debt-search-bar .btn { flex-shrink: 0; white-space: nowrap; }

/* نوار فیلتر: چیپ‌ها نباید فشرده شوند */
.filter-bar .filter-chip { flex-shrink: 0; }

/* ============================================================
   ۳۴. رنگ‌های زنده — گرادیان‌های Finmori
   ============================================================ */

/* ---------- کارت مانده: گرادیان بنفش عمیق، مثل کارت بانکی طرح ---------- */
.balance-ribbon {
    background: linear-gradient(135deg, #3b2f8f 0%, #4a3fb5 38%, #2f2a6b 100%);
    border: none;
    color: #fff;
    position: relative;
    overflow: hidden;
    box-shadow: 0 14px 30px -14px rgba(58,44,150,.65);
}
/* حلقه‌های محو گوشه — همان بافت کارت بانکی طرح */
.balance-ribbon::after {
    content: '';
    position: absolute;
    top: -30px; left: -30px;
    width: 190px; height: 190px;
    border-radius: 50%;
    background: rgba(255,255,255,.07);
    pointer-events: none;
}
.balance-ribbon::before {
    content: '';
    position: absolute;
    top: 24px; left: 60px;
    width: 120px; height: 120px;
    border-radius: 50%;
    background: rgba(255,255,255,.05);
    pointer-events: none;
}
.balance-ribbon > * { position: relative; z-index: 1; }
.balance-label { color: rgba(255,255,255,.72); }
.bv-num  { color: #fff; }
.bv-unit { color: rgba(255,255,255,.65); }
.balance-split { border-top-color: rgba(255,255,255,.16); }
.balance-split .bs-label { color: rgba(255,255,255,.6); }
.bs-in  { color: #6ee7a8; }
.bs-out { color: #ff9b9e; }
.ribbon-link { color: #c9c2ff; }
.balance-ribbon .hint { color: rgba(255,255,255,.6) !important; }

html[data-theme="dark"] .balance-ribbon {
    background: linear-gradient(135deg, #2b2270 0%, #3a318f 40%, #1e1a4d 100%);
}

/* ---------- هدر گرادیانتی: صورتی → یاسی → سفید ---------- */
.profile-head {
    position: relative;
    margin: -16px -16px 4px;
    padding: 26px 16px 18px;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    background: linear-gradient(170deg, #ffd9e8 0%, #e3dcff 45%, var(--surface) 100%);
}
html[data-theme="dark"] .profile-head {
    background: linear-gradient(170deg, #3a2140 0%, #262452 48%, var(--surface) 100%);
}
.profile-avatar {
    background: linear-gradient(150deg, #6d5ce7, #3b2f8f);
    color: #fff;
    box-shadow: 0 6px 16px -6px rgba(61,47,143,.55);
    border: 3px solid rgba(255,255,255,.75);
}

/* ---------- کارت هدف: نوار رنگین بالای کارت ---------- */
.goal-card { position: relative; overflow: hidden; }
.goal-card::before {
    content: '';
    position: absolute;
    top: 0; right: 0; left: 0;
    height: 4px;
    background: linear-gradient(90deg, #ff9ec4, #a78bfa, #60a5fa, #34d399);
}

/* ---------- کارت‌های ابزار: سطح شیشه‌ای، رنگ فقط در آیکن ----------
   نسخه‌ی قبل هر کارت را یک گرادیان تمام‌رنگ می‌کرد. ده کارت کنار هم
   یعنی ده رنگ اشباع که با بقیه‌ی اپ (سفید/زغالی/طلایی) بیگانه بود و
   چشم نمی‌دانست کجا را نگاه کند.

   حالا خودِ کارت یک سطح نیمه‌شفاف هم‌رنگ تم است و رنگِ اختصاصی هر
   ابزار (--tc1) فقط در دو جا می‌ماند: آیکن، و یک لایه‌ی ته‌رنگ بسیار
   کم‌جان روی کارت. تشخیص ابزارها حفظ می‌شود، سروصدا نه.

   ته‌رنگ با یک لایه‌ی ::before و opacity ساخته می‌شود نه با color-mix،
   تا روی مرورگرهای قدیمی‌تر هم همان‌طور دربیاید. */
.tool-card {
    position: relative;
    overflow: hidden;
    background: var(--tool-glass);
    -webkit-backdrop-filter: blur(12px) saturate(140%);
    backdrop-filter: blur(12px) saturate(140%);
    border: 1px solid var(--tool-edge);
    color: var(--ink);
    box-shadow: var(--sh);
}
.tool-card::before {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--tc1, var(--gold));
    opacity: var(--tool-tint);
    pointer-events: none;
}
/* آیکن و متن باید روی لایه‌ی ته‌رنگ بنشینند */
.tool-card > * { position: relative; z-index: 1; }

.tool-card svg {
    color: var(--tc1, var(--gold));
    flex: none;
}
.tool-card:active {
    transform: scale(.975);
    background: var(--tool-glass-press);
}

:root {
    --tool-glass:       rgba(255, 255, 255, .66);
    --tool-glass-press: rgba(255, 255, 255, .86);
    --tool-edge:        var(--line);
    --tool-tint:        .05;
}
html[data-theme="dark"] {
    --tool-glass:       rgba(255, 255, 255, .045);
    --tool-glass-press: rgba(255, 255, 255, .085);
    --tool-edge:        var(--line);
    --tool-tint:        .085;
}
/* رنگ‌های --tc1 برای زمینه‌ی روشن انتخاب شده‌اند و روی کارت تیره
   کدر می‌شوند؛ کمی روشنشان می‌کنیم تا آیکن خوانا بماند. */
html[data-theme="dark"] .tool-card svg { filter: brightness(1.3) saturate(.85); }

/* ---------- کارت‌های آماری: تیره‌تر و خواناتر روی زمینه‌ی کم‌رنگ ---------- */
.money-card-income  { background: linear-gradient(140deg, #e6f9ee, #d8f5e6); }
.money-card-expense { background: linear-gradient(140deg, #ffeced, #ffe1e3); }
html[data-theme="dark"] .money-card-income  { background: linear-gradient(140deg, #13301f, #10281a); }
html[data-theme="dark"] .money-card-expense { background: linear-gradient(140deg, #331b1d, #2a1618); }

/* ---------- دکمه شناور +: گرادیان یاسی روشن ---------- */
.bottom-nav-fab {
    background: linear-gradient(150deg, #e9e4ff, #bcb2ff);
    color: #33297a;
}

/* ---------- نوار پیشرفت بودجه و هدف ---------- */
.budget-bar-good { background: linear-gradient(90deg, #34d399, #6ee7a8); }
.budget-bar-warn { background: linear-gradient(90deg, #f59e0b, #fbbf24); }
.budget-bar-over { background: linear-gradient(90deg, #ef4444, #fb7185); }

/* ---------- بنر یادآوری: زنده‌تر ---------- */
.card[style*="--color-expense"], .card[style*="#d97706"] { border-width: 1px; }

/* اعداد داخل کارت بنفش باید سفید باشند، نه سرمه‌ای */
.balance-ribbon .bs-value { color: #fff; }
.balance-ribbon .bs-value.bs-in  { color: #6ee7a8; }
.balance-ribbon .bs-value.bs-out { color: #ff9b9e; }

/* ============================================================
   ۳۵. عکس پروفایل
   ============================================================ */
.profile-head { text-align: center; display: block; }
.avatar-wrap {
    position: relative;
    width: 96px; height: 96px;
    margin: 0 auto 12px;
}
.profile-avatar {
    width: 96px; height: 96px;
    border-radius: 50%;
    font-size: 36px;
    display: flex; align-items: center; justify-content: center;
}
.profile-avatar-img { object-fit: cover; display: block; }
.avatar-camera {
    position: absolute;
    bottom: 0; left: 0;
    width: 32px; height: 32px;
    border-radius: 50%;
    background: var(--gold);
    color: #fff;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    border: 3px solid var(--surface);
    box-shadow: 0 2px 8px -2px rgba(27,37,89,.4);
}
.avatar-camera:active { opacity: .8; }
.profile-name { font-size: 17px; font-weight: 700; }
.profile-sub { font-size: 12.5px; color: var(--muted); margin-top: 3px; }
.profile-head .form-message { text-align: center; margin-top: 10px; }

/* ============================================================
   تنظیم تصویر پروفایل (برش دایره‌ای)
   ============================================================ */
.avatar-crop-box { max-width: 380px; }

/* صحنه مربع است و بوم دقیقاً همان اندازه را پر می‌کند؛ ماسک فقط
   نشان می‌دهد چه چیزی داخل دایره می‌ماند. برش واقعی روی بوم انجام
   می‌شود، نه با CSS — پس چیزی که دیده می‌شود همانی است که ذخیره می‌شود. */
.crop-stage {
    position: relative;
    width: 100%;
    aspect-ratio: 1 / 1;
    background: #101216;
    border-radius: var(--r);
    overflow: hidden;
    touch-action: none;          /* تا کشیدن انگشت صفحه را اسکرول نکند */
    cursor: grab;
    user-select: none;
}
.crop-stage:active { cursor: grabbing; }
.crop-stage canvas { display: block; width: 100%; height: 100%; }

/* بیرونِ دایره تیره می‌شود تا مرز برش پیدا باشد */
.crop-mask {
    position: absolute; inset: 0;
    pointer-events: none;
    background: rgba(16, 18, 22, .58);
    -webkit-mask-image: radial-gradient(circle at 50% 50%,
        transparent 0, transparent 49.5%, #000 50%);
            mask-image: radial-gradient(circle at 50% 50%,
        transparent 0, transparent 49.5%, #000 50%);
}
/* مرورگری که mask ندارد: به‌جای تیرگیِ اشتباه، فقط یک حلقه‌ی راهنما */
@supports not ((-webkit-mask-image: radial-gradient(#000, #000)) or (mask-image: radial-gradient(#000, #000))) {
    .crop-mask {
        background: none;
        border-radius: 50%;
        box-shadow: 0 0 0 2px rgba(255,255,255,.85) inset;
    }
}

.crop-hint { margin: 10px 2px 12px; text-align: center; }

/* این ردیف عمداً چپ‌به‌راست است. جهت نوار بزرگ‌نمایی فضایی است نه
   زبانی: «−» باید سمت کم و «+» سمت زیاد باشد. در RTL دسته‌ی نوار در
   کمترین مقدار به راست می‌چسبید و مثل «حداکثر» خوانده می‌شد. */
.crop-controls {
    display: flex; align-items: center; gap: 10px;
    margin-bottom: 14px;
    direction: ltr;
}
.crop-controls input[type="range"] {
    flex: 1; min-width: 0;
    accent-color: var(--gold);
}
.crop-zoom-btn {
    flex: none;
    width: 34px; height: 34px;
    border: 1px solid var(--line);
    background: var(--line-soft);
    color: var(--ink);
    border-radius: var(--r-pill);
    font-size: 19px; line-height: 1;
}
.crop-zoom-btn:active { transform: scale(.94); }

.crop-actions { display: flex; align-items: center; gap: 9px; }
.crop-actions .btn-block { margin: 0; flex: 1; }
/* «از نو» کوتاه است ولی در ستون باریک دو خطی می‌شد */
.crop-actions #cropReset { flex: none; white-space: nowrap; }

/* ============================================================
   صفحه‌ی «ایمیل را ببینید» — بعد از درخواست بازیابی رمز
   ============================================================ */
.check-mail { text-align: center; padding: 4px 0 2px; }
.check-mail-icon {
    width: 62px; height: 62px;
    margin: 0 auto 13px;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: var(--gold-wash);
    color: var(--gold);
}
.check-mail-title { font-size: 17px; font-weight: 700; margin-bottom: 7px; }
.check-mail-text  { font-size: 13.5px; color: var(--muted); line-height: 2; }
.check-mail-text b { color: var(--ink); word-break: break-all; }

.check-mail-notes {
    list-style: none;
    margin: 15px 0 13px;
    padding: 13px 14px;
    background: var(--line-soft);
    border-radius: var(--r);
    font-size: 12.5px; color: var(--muted); line-height: 1.95;
}
.check-mail-notes li { position: relative; padding-inline-start: 15px; }
.check-mail-notes li::before {
    content: '';
    position: absolute; inset-inline-start: 0; top: 11px;
    width: 5px; height: 5px; border-radius: 50%;
    background: var(--muted-2);
}
.check-mail-notes b { color: var(--ink-soft); }

/* دکمه‌ی در حال کار: باید بی‌درنگ دیده شود که زدن دوباره بی‌فایده است */
.btn:disabled { opacity: .6; cursor: default; }

/* .link-back مقدار display دارد و همان بر [hidden] پیش‌فرض مرورگر غلبه
   می‌کند؛ بدون این خط، لینک «دوباره درخواست می‌دهم» از همان ثانیه‌ی اول
   دیده می‌شد و شمارش معکوس بی‌اثر بود. */
.link-back[hidden] { display: none; }

/* ============================================================
   معاملات (خرید و فروش)
   ============================================================ */
.form-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

/* مبلغ در فرم معامله: هم‌قد بقیه‌ی فیلدها، فقط با ارقام هم‌عرض.
   کلاس amount-input برای «قهرمانِ» شیت ثبت تراکنش است و اینجا فرم را
   نامتقارن و درشت می‌کرد. */
.amount-input-sm {
    font-variant-numeric: tabular-nums;
    letter-spacing: -.2px;
}

.trade-toolbar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px;
    margin-top: 12px;
}
.view-switch {
    display: flex; flex: none;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    overflow: hidden;
}
.view-switch-btn {
    display: flex; align-items: center; justify-content: center;
    width: 34px; height: 30px;
    background: var(--surface);
    border: none; color: var(--muted);
}
.view-switch-btn.active { background: var(--line-soft); color: var(--ink); }

/* ---------- حالت فهرستی: هر معامله یک ردیف فشرده ----------
   جزئیات با لمس ردیف باز می‌شود (کلاس expanded) — برای وقتی کالاها
   زیاد شدند و کاربر فقط می‌خواهد فهرست را مرور کند. */
#tradesWrap.view-list .trade-card { padding: 11px 14px; margin-bottom: 7px; cursor: pointer; }
#tradesWrap.view-list .trade-card .trade-figures,
#tradesWrap.view-list .trade-card .trade-sales,
#tradesWrap.view-list .trade-card .trade-notes,
#tradesWrap.view-list .trade-card .trade-remaining,
#tradesWrap.view-list .trade-card .trade-actions { display: none; }
#tradesWrap.view-list .trade-card .trade-meta { margin-top: 1px; }
#tradesWrap.view-list .trade-card .list-profit {
    display: inline-block;
    font-size: 12.5px; font-weight: 700;
    margin-inline-start: 8px;
}
#tradesWrap.view-list .trade-card.expanded { cursor: default; }
#tradesWrap.view-list .trade-card.expanded .trade-figures,
#tradesWrap.view-list .trade-card.expanded .trade-sales,
#tradesWrap.view-list .trade-card.expanded .trade-notes,
#tradesWrap.view-list .trade-card.expanded .trade-remaining,
#tradesWrap.view-list .trade-card.expanded .trade-actions { display: flex; }
#tradesWrap.view-list .trade-card.expanded .trade-notes,
#tradesWrap.view-list .trade-card.expanded .trade-remaining { display: block; }
#tradesWrap:not(.view-list) .trade-card .list-profit { display: none; }



.trade-summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.trade-sum-item { text-align: center; }
.trade-sum-label { display: block; font-size: 11.5px; color: var(--muted); margin-bottom: 5px; }
.trade-sum-value { font-size: 15px; }
.trade-sum-value small { font-size: 10px; font-weight: 400; color: var(--muted); }

.trade-card { padding: 15px; }
.trade-closed { opacity: .78; }
.trade-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.trade-title { font-size: 14.5px; font-weight: 700; }
.trade-meta { font-size: 11.5px; color: var(--muted); margin-top: 3px; }
.trade-status {
    flex: none;
    font-size: 11px; font-weight: 700;
    padding: 3px 10px; border-radius: var(--r-pill);
}
.trade-status.is-open   { background: var(--gold-wash); color: var(--warn-ink); }
.trade-status.is-closed { background: var(--line-soft); color: var(--muted); }

.trade-figures {
    display: flex; flex-wrap: wrap; gap: 6px 18px;
    margin-top: 12px;
    padding-top: 11px;
    border-top: 1px dashed var(--line);
}
.trade-fig span { display: block; font-size: 11px; color: var(--muted); margin-bottom: 2px; }
.trade-fig b { font-size: 13.5px; }
.is-in  { color: var(--in); }
.is-out { color: var(--out); }

.trade-remaining { font-size: 12px; color: var(--warn-ink); margin-top: 9px; }
.trade-notes { font-size: 12.5px; color: var(--muted); margin-top: 9px; line-height: 1.9; }

.trade-sales { margin-top: 11px; border-top: 1px dashed var(--line); }
.trade-sale-row {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    padding: 9px 0;
    border-bottom: 1px solid var(--line-soft);
}
.trade-sale-row:last-child { border-bottom: none; }
.trade-sale-info b { font-size: 13px; }
.trade-sale-meta { display: block; font-size: 11px; color: var(--muted); margin-top: 2px; }
/* امانی/نسیه — نشانِ آرام کنارِ متا: پولی هنوز جابه‌جا نشده و در
   «طلب و بدهی» نشسته. رنگِ هشدار نیست (چیزی خراب نیست)، فقط متمایز. */
.trade-credit-tag {
    display: inline-block; padding: 0 6px; border-radius: 6px;
    background: var(--gold-wash); color: var(--brand-fg);
    font-weight: 600; white-space: nowrap;
}

.trade-actions { display: flex; gap: 7px; margin-top: 13px; flex-wrap: wrap; }

/* ---------- سربرگ شیت: دستگیره‌ی قابل لمس و دکمه‌ی بستن ----------
   دستگیره قبلاً فقط یک خط تزئینی بود. حالا ناحیه‌ی لمسی دارد (کشیدن
   به پایین یا زدنش، شیت را می‌بندد) چون با شیتِ بلند، نوار باریکِ
   بالای آن عملاً تنها راه بستن بود. */
.more-sheet-grab {
    padding: 6px 0 2px;
    margin: -3px 0 0;
    cursor: pointer;
    touch-action: none;
}
.more-sheet-head {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 13px;
}
.more-sheet-head .more-sheet-title { margin-bottom: 0; }

/* کارت پهن معاملات: تمام‌عرض ولی دقیقاً هم‌ضخامتِ بقیه‌ی کارت‌ها.
   ارتفاع از یک متغیر مشترک می‌آید تا دو جا از هم جدا نیفتند. */
.tool-card-wide {
    grid-column: 1 / -1;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 10px;
    text-align: center;
    /* چون چیدمانش افقی است، محتوایش کوتاه‌تر از کارت‌های ستونی است و
       بدون این خط، دو پیکسل کوتاه‌تر می‌نشست. */
    min-height: var(--tool-card-h);
    height: var(--tool-card-h);
}
.tool-card-wide span { flex: none; }

/* ============================================================
   کارت بانکی
   ============================================================ */
/* ============================================================
   ⛔ استانداردِ جهت: **متنِ فارسی راست‌چین، عدد چپ‌چین**
   ============================================================

   صفحه راست‌به‌چپ است و برچسب‌ها باید همان‌طور بمانند، ولی عدد
   ذاتاً چپ‌به‌راست است. وقتی مبلغ در جریانِ راست‌به‌چپ رها شود سه
   چیز خراب می‌شود و هیچ‌کدام خطا نمی‌دهد:

     ۱. جداکننده‌ی سه‌رقمی و علامتِ منفی سرِ جای اشتباه می‌نشینند.
     ۲. ارقامِ هم‌مرتبه در ستون‌های زیرِ هم تراز نمی‌شوند، پس چشم
        نمی‌تواند «۱٬۲۰۰٬۰۰۰» را از «۱۲۰٬۰۰۰» در یک نگاه جدا کند —
        و این دقیقاً کارِ یک دفترِ مالی است.
     ۳. واحدِ پول («تومان») گاهی این‌طرف عدد می‌افتد و گاهی آن‌طرف.

   ⛔ این قاعده **یک جا** تعریف می‌شود و همه‌ی کلاس‌های عددی به همین
      یک قاعده می‌پیوندند. اگر جای دیگری `direction: ltr` بنویسید،
      نسخه‌ی دومی می‌شود که دیر یا زود از این عقب می‌افتد.
      کلاسِ عددیِ تازه = یک نامِ تازه در همین فهرست.

   ⚠ عمداً فقط روی خودِ **مقدار** است، نه روی ظرفش: ظرف‌هایی مثل
     `.money-card` یا `.balance-ribbon` برچسبِ فارسی هم دارند و
     چپ‌چین کردنشان چیدمانِ برچسب را خراب می‌کند.
   ============================================================ */
.ltr-num,
.stats-value, .balance-value, .bv-num,
.wallet-bal, .wallet-line-bal, .wallet-line-total,
.tx-row-amount, .tx-day-total,
.debt-amount, .event-amount, .recur-amount, .transfer-amount,
.cat-breakdown-amount, .cat-detail-amount, .breakdown-cta-amount,
.asset-total-value, .asset-item-qty, .trade-sum-value,
.bank-card-balance, .bank-card-row-value, .bank-card-number,
.pay-number, .amount-cell,
.store-own-stat b, .store-row-own,
.amount-income, .amount-expense, .asset-amount-neg,
.amount-input, .amount-input-sm {
    direction: ltr;
    text-align: left;
    font-variant-numeric: tabular-nums;
}
.ltr-num, .bank-card-number, .pay-number { letter-spacing: .5px; }

/* ⚠ در جدول‌ها، سرستونِ عدد هم باید با خودِ عدد یکی باشد وگرنه
   عنوان راست می‌نشیند و مقدارها چپ. */
.data-table th.amount-cell { text-align: left; }

.iban-field { display: flex; align-items: stretch; gap: 0; direction: ltr; }
.iban-prefix {
    display: flex; align-items: center;
    padding: 0 11px;
    background: var(--line-soft);
    border: 1px solid var(--line);
    border-inline-end: none;
    border-radius: var(--r-sm) 0 0 var(--r-sm);
    font-weight: 700; font-size: 13px; color: var(--muted);
}
.iban-field input { border-radius: 0 var(--r-sm) var(--r-sm) 0 !important; flex: 1; min-width: 0; }

.js-show-card { cursor: pointer; }

.bank-card-box { max-width: 400px; }
.bank-card {
    position: relative;
    overflow: hidden;
    border-radius: 16px;
    padding: 17px 18px 15px;
    aspect-ratio: 1.586 / 1;      /* نسبت واقعی کارت بانکی */
    display: flex; flex-direction: column; justify-content: space-between;
    color: #fff;
    background: linear-gradient(135deg, var(--bc1, #475569), var(--bc2, #2f3b4a));
    box-shadow: 0 10px 26px rgba(21,23,28,.28);
    direction: rtl;
}
/* درخشش مورب — به‌جای تصویر، طرح خودمان */
.bank-card-shine {
    position: absolute; inset: 0;
    pointer-events: none;
    background:
        radial-gradient(120% 80% at 85% -10%, rgba(255,255,255,.22), transparent 60%),
        radial-gradient(90% 70% at -10% 110%, rgba(255,255,255,.10), transparent 55%);
}
.bank-card > *:not(.bank-card-shine) { position: relative; z-index: 1; }

.bank-card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.bank-card-bank { font-size: 14px; font-weight: 700; }
.bank-card-kind {
    font-size: 10.5px; opacity: .85;
    background: rgba(255,255,255,.18);
    padding: 3px 9px; border-radius: var(--r-pill);
    white-space: nowrap;
}
.bank-card-chip {
    width: 38px; height: 28px; border-radius: 6px;
    background: linear-gradient(140deg, #f0d68a, #c8a44e 55%, #e5c877);
    box-shadow: inset 0 0 0 1px rgba(0,0,0,.13);
}
.bank-card-number {
    direction: ltr; text-align: left;
    font-size: 17px; font-weight: 700;
    letter-spacing: 1.5px;
    font-variant-numeric: tabular-nums;
    text-shadow: 0 1px 2px rgba(0,0,0,.25);
}
.bank-card-number:empty::before { content: '•••• •••• •••• ••••'; opacity: .45; }
.bank-card-bottom { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; }
.bank-card-label { display: block; font-size: 9.5px; opacity: .75; margin-bottom: 2px; }
.bank-card-owner { font-size: 12.5px; font-weight: 700; }
.bank-card-balance-wrap { text-align: left; }
.bank-card-balance { font-size: 13.5px; font-weight: 700; font-variant-numeric: tabular-nums; }

.bank-card-rows { margin-top: 15px; }
.bank-card-actions {
    display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
    margin-top: 14px;
}
.bank-card-actions .btn { text-align: center; text-decoration: none; }
.bank-card-actions-wide { grid-column: 1 / -1; }
.bank-card-row {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 10px 0;
    border-bottom: 1px solid var(--line-soft);
}
.bank-card-row:last-child { border-bottom: none; }
.bank-card-row-label { font-size: 12px; color: var(--muted); flex: none; }
.bank-card-row-value {
    font-size: 13px; font-weight: 700;
    direction: ltr; text-align: left;
    word-break: break-all;
    font-variant-numeric: tabular-nums;
}
.bank-card-copy {
    flex: none;
    background: var(--line-soft); border: none;
    color: var(--muted); border-radius: var(--r-sm);
    padding: 5px 9px; font-size: 11px;
}
.bank-card-copy.done { background: var(--in-wash); color: var(--in); }

/* ---------- نوار پایین بالای شیت ابزارها می‌ماند ----------
   شیت با inset:0 تمام صفحه را می‌پوشاند و دکمه‌ی «بیشتر» زیرش گم
   می‌شد؛ یعنی همان دکمه‌ای که شیت را باز کرده، برای بستنش قابل زدن
   نبود. حالا نوار بالاتر می‌نشیند و «بیشتر» ضامن واقعی است. */
.bottom-nav { z-index: 260; }

/* ⛔ کیبورد که باز است، نوار کنار می‌رود — وگرنه وسطِ صفحه شناور می‌ماند.
   `position: fixed` نسبت به viewport **چیدمان** است و کیبوردِ مجازی آن
   را کوچک نمی‌کند (فقط viewport دیداری کوچک می‌شود)، پس کفِ چیدمان جایی
   وسطِ صفحه‌ی دیداری می‌افتد و نوار همان‌جا روی محتوا می‌ماند. توضیحِ
   کامل و دلیلِ «برداشتن به‌جای جبران‌سازی» کنارِ `keyboardAwareNav()` در
   `app.js` است.
   ⚠ وزنِ این انتخابگر (۰,۲,۰) از خودِ `.bottom-nav` بیشتر است، پس به
   `!important` نیازی نیست و قاعده‌ی دسکتاپ هم دست‌نخورده می‌ماند. */
html.kb-open .bottom-nav { display: none; }
/* شیت پشت نوار پنهان نشود و کارت آخر به آن نچسبد.
   نوار شناور است: ۶۲ ارتفاع + ۱۴ فاصله از پایین. روی آن ۱۸ پیکسل هوا
   می‌گذاریم — کمی بیشتر از فاصله‌ی ۱۰ پیکسلی بین خود کارت‌ها. */
.more-sheet { padding-bottom: calc(62px + 14px + 18px + env(safe-area-inset-bottom)); }

/* ============================================================
   نمای کلی دارایی‌ها
   ============================================================ */
.asset-total-row {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 10px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--line-soft);
}
.asset-total-label { font-size: 13px; color: var(--muted); }
.asset-total-value { font-size: 18px; font-weight: 700; }
.asset-total-value small { font-size: 11px; font-weight: 400; color: var(--muted); }

.asset-search-wrap { margin-bottom: 12px; }
.asset-search {
    width: 100%;
    padding: 9px 12px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--ink);
    font-size: 13px; font-family: inherit;
}
.asset-empty-filter { text-align: center; color: var(--muted); font-size: 13px; padding: 14px 0; }

.asset-item-qty {
    font-size: 11.5px; color: var(--muted);
    margin: 2px 0 6px;
    padding-inline-start: 18px;   /* هم‌تراز با متن، بعد از نقطه‌ی رنگی */
}
.asset-noprice { color: var(--muted-2); }
.asset-tag {
    font-size: 9.5px; font-weight: 700;
    background: var(--gold-wash); color: var(--warn-ink);
    padding: 2px 6px; border-radius: var(--r-pill);
    margin-inline-start: 5px;
    vertical-align: middle;
}
/* اگر .cat-breakdown-item مقدار display داشته باشد، بر [hidden] پیش‌فرض
   مرورگر غلبه می‌کند و فیلتر بی‌اثر می‌شود — همان دامی که یک بار با
   .link-back خوردیم. */
.asset-item[hidden] { display: none !important; }
.chart-container[hidden] { display: none !important; }

.asset-tag-wallet { background: var(--in-wash); color: var(--in); }

/* کلید اعمال/عدم اعمال هر قلم در جمع و نمودار */
.asset-toggle { flex: none; margin-inline-start: 8px; }
.asset-item-off .cat-breakdown-name,
.asset-item-off .cat-breakdown-amount,
.asset-item-off .asset-item-qty { opacity: .42; }
.asset-item-off .cat-dot { opacity: .3; }
.asset-item-off .cat-breakdown-bar-track { opacity: .35; }
.asset-total-note { margin-top: 8px; }

/* ---------- انتخابگر شخص ----------
   سمت (همکار / مشتری / …) کنارِ عنوانِ «نام طرف حساب» می‌نشیند، نه داخل
   منو. داخل منو نامِ بلند را می‌برید و فهرست را شلوغ می‌کرد. */
.person-label-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.person-label-row label { margin: 0; }
/* همان زبانِ برچسب‌های صفحه‌ی دارایی (.asset-tag) تا اپ یک‌دست بماند.
   رنگِ «تعامل» عمداً استفاده نمی‌شود: کنارِ عنوانِ آبی، نشان شبیهِ
   ادامه‌ی خودِ عنوان دیده می‌شد و به نظر می‌رسید بشود رویش زد. */
.person-role-badge {
    font-size: 10px;
    font-weight: 700;
    color: var(--warn-ink);
    background: var(--gold-wash);
    padding: 2px 8px;
    border-radius: var(--r-pill);
    white-space: nowrap;
}

/* خالصِ منفی (چکِ صادره بیشتر از دریافتی، یا بدهی بیشتر از طلب) با رنگ
   هزینه می‌آید تا در یک نگاه معلوم باشد از جمع کم می‌کند. */
.asset-amount-neg { color: var(--out); }

/* نامِ ردیف‌های جمع‌شده («مجموع دارایی‌های بخش معاملات») از عرض یک خط
   بلندتر است و با ellipsisِ مشترک، نصفه دیده می‌شد. اینجا — برخلاف
   گزارش دسته‌بندی که ده‌ها ردیف دارد — تعداد ردیف‌ها کم است، پس رفتن
   به خط دوم بهتر از بریدن نام است. */
.asset-item .cat-breakdown-name {
    white-space: normal;
    overflow: visible;
    line-height: 1.55;
}

/* ---------- دکمه‌های ورود به گزارش دسته‌بندی (داشبورد) ----------
   رنگ همان رنگی است که در خودِ گزارش می‌بیند: هزینه گرم، درآمد سبز. */
.breakdown-cta { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.breakdown-cta-period {
    font-size: 11.5px; color: var(--muted);
    background: var(--line-soft);
    padding: 3px 9px; border-radius: var(--r-pill);
}
.breakdown-cta-btn {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 13px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: inherit; text-decoration: none;
    transition: border-color .15s, background .15s;
}
.breakdown-cta-btn:active { background: var(--line-soft); }
.breakdown-cta-icon {
    width: 34px; height: 34px; flex: none;
    border-radius: 10px;
    display: flex; align-items: center; justify-content: center;
}
.breakdown-cta-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.breakdown-cta-title { font-size: 13px; font-weight: 700; }
.breakdown-cta-amount {
    font-size: 12px; font-weight: 700; direction: ltr; text-align: start;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.breakdown-cta-out .breakdown-cta-icon { background: var(--out-wash); color: var(--out); }
.breakdown-cta-out .breakdown-cta-amount { color: var(--out); }
.breakdown-cta-out:hover { border-color: var(--out); }
.breakdown-cta-in  .breakdown-cta-icon { background: var(--in-wash);  color: var(--in); }
.breakdown-cta-in  .breakdown-cta-amount { color: var(--in); }
.breakdown-cta-in:hover { border-color: var(--in); }

/* ---------- تفکیک موجودی حساب‌ها (داشبورد) ---------- */
.wallet-line {
    display: flex; align-items: center; gap: 9px;
    padding: 10px 0;
    border-bottom: 1px solid var(--line-soft);
    color: inherit; text-decoration: none;
}
.wallet-line:last-child { border-bottom: none; }
.wallet-line-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.wallet-line-name { flex: 1; font-size: 13.5px; }
.wallet-line-bal { font-size: 13.5px; font-weight: 700; direction: ltr; }
.wallet-line-total {
    border-top: 1px solid var(--line);
    border-bottom: none;
    margin-top: 4px; padding-top: 12px;
}
.wallet-line-total .wallet-line-name { font-weight: 700; }
.wallet-line-total .wallet-line-bal { font-size: 15px; }

/* ==========================================================================
   صفحه‌ای که هنوز جان ندارد
   ==========================================================================
   `<html class="js-loading">` در header.php گذاشته می‌شود و app.js اولین
   کاری که می‌کند برداشتنش است. پس تا وقتی این کلاس هست یعنی اسکریپت هنوز
   نرسیده — و صفحه با اینکه کامل و خوش‌ظاهر رندر شده، هیچ دکمه‌ای ندارد.

   این حالت واقعاً پیش می‌آمد: بعد از هر deploy آدرس app.js عوض می‌شود و
   باید از شبکه بیاید؛ اگر روی اینترنت موبایل گیر می‌کرد، کاربر صفحه را
   می‌دید، اسکرول می‌کرد، دکمه می‌زد و هیچ اتفاقی نمی‌افتاد — بی‌هیچ
   نشانه‌ای. حالا دست‌کم پیداست که چیزی هنوز آماده نیست.

   ⏱ با تأخیر ۹۰۰ میلی‌ثانیه: بارگذاری عادی چند ده میلی‌ثانیه است و نباید
   هیچ‌وقت این حالت را ببیند. animation فقط برای همان تأخیر است. */
@keyframes js-loading-hint { to { opacity: .45; } }

.js-loading button:not([type="submit"]),
.js-loading .tool-card,
.js-loading [class*="js-"] {
    opacity: 1;
    animation: js-loading-hint .2s linear .9s forwards;
    cursor: progress;
}

/* ============================================================
   ماندن در حساب — کلید + چیپ
   ============================================================
   منوی کشویی با ده گزینه روی گوشی شلوغ بود و کاربر برای دیدنِ
   انتخاب‌ها باید یک لایه باز می‌کرد. حالا بیشترِ کاربران فقط یک کلید
   می‌بینند؛ چیپ‌ها وقتی ظاهر می‌شوند که کسی واقعاً مهلت بخواهد. */

.stay-hero {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.stay-hero-text  { flex: 1; min-width: 0; }
.stay-hero-title { display: block; font-weight: 700; font-size: 14.5px; color: var(--ink); }
.stay-hero-sub   { display: block; margin-top: 4px; font-size: 12.5px; color: var(--muted); line-height: 1.7; }
/* کلید هم‌تراز با **عنوان** بنشیند، نه با وسطِ بلوکِ متن. با
   align-items:center کلید کنارِ خطِ دومِ توضیح می‌افتاد و انگار به آن
   خط مربوط بود. */
.stay-hero-switch { flex-shrink: 0; margin-top: 1px; }

/* بازشدن نرم به‌جای ظاهر شدنِ ناگهانی. grid-template-rows تنها راهی
   است که ارتفاعِ نامعلوم را بدون عددِ جادویی انیمیت می‌کند.
   ⚠ فرزند باید **یکی** باشد (`.stay-choices-inner`): فرزندِ دوم به ردیفِ
   ضمنیِ auto می‌رفت و 0fr جمعش نمی‌کرد. */
.stay-choices {
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    transition: grid-template-rows .28s ease, opacity .2s ease, margin-top .28s ease;
    margin-top: 0;
}
.stay-choices-inner { overflow: hidden; min-height: 0; }
.stay-choices.is-open {
    grid-template-rows: 1fr;
    opacity: 1;
    margin-top: 18px;
}

/* یادآوری سررسید — همان مکانیزمِ باز شدن، پس همان قاعده‌ها.
   ⚠ فرزند باید یکی باشد؛ دلیلش بالا توضیح داده شده. */
.remind-days {
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    transition: grid-template-rows .28s ease, opacity .2s ease, margin-top .28s ease;
    margin-top: 0;
}
.remind-days-inner { overflow: hidden; min-height: 0; }
.remind-days.is-open { grid-template-rows: 1fr; opacity: 1; margin-top: 16px; }
/* چهار بازه باید در یک ردیف جا شوند. `.stay-chip` پایه `min-width:78px`
   دارد که برای ۹ چیپِ «ماندن در حساب» درست است، ولی اینجا چیپِ چهارم را
   به خطِ دوم می‌انداخت و تک‌افتاده تمامِ عرض را می‌گرفت. */
.remind-days .stay-chip { min-width: 0; padding: 10px 6px; }

.stay-choices-label {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--muted);
    margin-bottom: 10px;
}

.stay-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.stay-chip {
    flex: 1 1 auto;
    min-width: 78px;
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--ink-soft);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background .15s ease, color .15s ease, border-color .15s ease, transform .1s ease;
}
.stay-chip:active { transform: scale(.96); }
.stay-chip.active {
    background: var(--brand);
    border-color: var(--brand-fg);
    color: var(--brand-on);
}
html[data-theme="dark"] .stay-chip.active { box-shadow: none; }

/* فرمِ یادآور: همان زبانِ چیپ، ولی داخلِ یک فرم و نه یک کارتِ تنظیمات.
   ⛔ کلاسِ تازه‌ای برای *ظاهرِ* چیپ ساخته نمی‌شود — فقط چیدمانِ داخلِ فرم
      تنظیم می‌شود. با یک ظاهرِ دوم، رنگِ فعالِ اینجا و پروفایل دیر یا زود
      از هم دور می‌افتادند. */
/* ⛔ هر کلاسی که `display` دارد بر `[hidden]`ِ پیش‌فرضِ مرورگر غلبه
      می‌کند — قاعده‌ی UA ضعیف‌ترین قاعده‌ی ممکن است. یعنی عنصری که در
      HTML `hidden` نوشته شده **دیده می‌شود**، بی‌هیچ خطایی.

      این تا امروز پنج بار زده (`.sms-conn`, `.asset-item`,
      `.chart-container`, و حالا این چهار تا). خرابی‌هایی که با همین
      یک خط بسته می‌شوند:

      • `.stay-chips` — چیپ‌های «مبلغ هر قسط / جمع کل» که فقط برای
        تعهدِ چندقسطی معنا دارند، همیشه دیده می‌شدند.
      • `.btn` — دکمه‌ی «انصراف از ویرایش» در صفحه‌ی یادآور همیشه بود،
        در حالی که فقط هنگام ویرایش معنا دارد؛ و **دکمه‌ی «چسباندن و
        خواندن»** پیامک بانک که طبق قاعده‌ی خودش فقط با
        `navigator.clipboard` و `isSecureContext` باید رندر شود — روی
        http دیده می‌شد و زدنش هیچ کاری نمی‌کرد. دکمه‌ی بی‌کار از
        نبودنش بدتر است.
      • `.form-row` — «بازه‌ی دلخواه» بودجه همیشه باز بود.
      • `.wallet-extra` — کارهای اضافیِ حساب و بودجه همیشه دیده می‌شدند.

      ⚠ `!important` لازم است: بعضی از این کلاس‌ها داخلِ `@media` هم
        `display` می‌گیرند و بدونِ آن، قاعده‌ی بعدی دوباره برنده می‌شد.
      قاعده ۱۸ در `test_api_contract.php` این را می‌سنجد. */
.stay-chips[hidden],
.btn[hidden],
.form-row[hidden],
.wallet-extra[hidden] { display: none !important; }

/* حکمِ قیفِ شروع در پنل مدیر — یک تشخیص و یک قدمِ بعدی.
   نوارِ رنگی سمتِ **شروع** است (`border-inline-start`) نه سمتِ چپِ
   فیزیکی، وگرنه در صفحه‌ی راست‌به‌چپ می‌افتد آن‌طرفِ متن. */
.verdict {
    margin-top: 18px; padding: 13px 15px;
    background: var(--line-soft);
    border-inline-start: 3px solid var(--muted-2);
    border-radius: var(--r-sm);
}
.verdict-head { font-weight: 700; font-size: 13.5px; color: var(--ink); margin-bottom: 5px; }
.verdict-body { font-size: 12.5px; line-height: 1.9; color: var(--muted); }
/* نوارِ «از پیامک بانک خودکار ثبت شد» — بالای محتوای هر صفحه، با راهِ
   برگشت. عمداً در جاوااسکریپت ساخته می‌شود (نه در PHP)، پس قاعده‌ی
   `[hidden]` لازم ندارد: هیچ‌وقت پنهان رندر نمی‌شود، یا هست یا نیست. */
.undo-bar {
    display: flex; align-items: center; gap: 10px;
    margin-bottom: 14px; padding: 11px 14px;
    background: var(--warn-wash); color: var(--warn-ink);
    border-radius: var(--r-sm);
    font-size: 12.5px; line-height: 1.8;
}
.undo-bar-text { flex: 1; }
/* ⚠ رنگِ متن `--warn-wash` است نه `#fff`: در حالتِ شب، `--warn-ink`
   خودش **روشن** می‌شود (کهربایی کم‌رنگ) و سفید رویش عملاً خوانده
   نمی‌شود. اندازه‌گیری شد: #e5b45f با متنِ سفید. با این جفت، متن در هر
   دو حالت وارونه‌ی زمینه‌اش است و کنتراست حفظ می‌شود. */
.undo-bar-undo {
    flex-shrink: 0;
    background: var(--warn-ink); color: var(--warn-wash); border: 0;
    padding: 6px 16px; border-radius: var(--r-sm);
    font: inherit; font-weight: 700; cursor: pointer;
}
.undo-bar-undo[disabled] { opacity: .55; cursor: default; }
.undo-bar-close {
    flex-shrink: 0;
    background: none; border: 0; color: inherit;
    font-size: 19px; line-height: 1; cursor: pointer; padding: 0 4px;
}

.verdict-bad  { border-inline-start-color: var(--out); }
/* ⚠ `--warn-ink` است نه `--gold`: آن متغیر با پالتِ دومِ همین فایل به
   **آبی** (#2563eb) بازتعریف شده، پس نوارِ «هشدار» دقیقاً مثل نوارِ
   «اطلاع» دیده می‌شد و تفاوتِ دو حکم از بین می‌رفت. `--warn-ink` همان
   کهربایی است که بقیه‌ی اپ برای هشدار به کار می‌برد (`.debt-badge-pending`،
   نشانِ «کم‌فعال»، و همین صفحه در سرآیندِ «بیش از ۱۴ روز»). */
.verdict-warn { border-inline-start-color: var(--warn-ink); }
.verdict-good { border-inline-start-color: var(--in); }

/* ⛔ کارتِ جمله‌های بینش — تنها جایی که اپ حرف می‌زند.
   عمداً padding کارت را صفر می‌کند و هر جمله خودش یک ردیفِ کامل و
   قابلِ زدن است: جمله‌ای که «۴۰٪ بیشتر خرجِ خوراک» می‌گوید باید همان‌جا
   به گزارشِ همان دسته ببرد، وگرنه کاربر خبر را می‌خواند و کاری نمی‌تواند
   بکند — و خبری که به اقدام نرسد دفعه‌ی بعد خوانده نمی‌شود. */
.insight-card { padding: 0; overflow: hidden; }
.insight-row {
    display: flex; align-items: center; gap: 10px;
    padding: 13px 15px;
    color: var(--ink); text-decoration: none;
    font-size: 13.5px; line-height: 1.75;
    border-bottom: 1px solid var(--line-soft);
}
.insight-row:last-child { border-bottom: none; }
.insight-row:hover { background: var(--line-soft); }
.insight-text { flex: 1; min-width: 0; }
/* ⚠ فلشِ راهنما رو به **چپ** است چون صفحه راست‌به‌چپ است؛ همان جهتی که
   بقیه‌ی «مشاهده همه»های اپ دارند. */
.insight-go { color: var(--muted-2); flex-shrink: 0; }
.insight-dot {
    width: 8px; height: 8px; border-radius: 50%;
    flex-shrink: 0; background: var(--muted-2);
}
/* رنگ اینجا **معنا** دارد نه تزئین:
     • قرمز (`--out`) فقط برای چیزی که **همین حالا** هزینه دارد —
       سررسیدِ گذشته و بودجه‌ی ردشده.
     • سبز (`--in`) برای خبرِ خوب.
     • رنگِ تأکید برای خبرِ خنثی («بیشتر خرج شده») — عمداً قرمز نیست،
       وگرنه کارت یک دیوارِ قرمز می‌شد و آن‌وقت هشدارِ واقعی هم دیده
       نمی‌شد. همان درسِ «هشدارِ همیشگی بدتر از نبودنش است».

   ⚠ `--gold` دیگر طلایی نیست: پالتِ بعدیِ همین فایل (خطِ ~۲۲۱۴) آن را
     به آبیِ تأکید (`#2563eb`) عوض کرده و نامش جا مانده. اگر روزی دنبالِ
     رنگِ طلایی گشتید، اینجا پیدایش نمی‌کنید. */
.insight-warn .insight-dot { background: var(--out); }
.insight-up   .insight-dot { background: var(--gold); }
.insight-down .insight-dot,
.insight-good .insight-dot { background: var(--in); }

/* ---------- اسلایدرِ خانه: «مانده این ماه» + حساب‌های پین‌شده ----------
   ⛔ یک نوار است، نه دو تا. اسلاید اول همان نوارِ ماه است و کارت‌های
     حساب پشتِ سرش می‌آیند — نه زیرش. با نوارِ جدا، هر چیزی که پایین‌تر
     است ۱۲۰ پیکسل پایین می‌رفت.

   ⛔ هیچ عرض و ارتفاعِ ثابتی اینجا نیست و نباید باشد: عرضِ هر اسلاید
     `100%` است (یعنی دقیقاً عرضِ نوارِ ماه) و ارتفاعش را
     `align-items: stretch`ِ پیش‌فرض از بلندترین اسلاید می‌گیرد. عددِ
     ثابت یعنی هر بار که محتوای نوار عوض شود، کارت‌ها بی‌صدا از قدِ آن
     می‌افتند. */
/* ⚠ ‎−۱۴ پیکسل چون `.home-slides` زیرِ خودش ۲۶ پیکسل padding دارد (توضیحش
   پایین‌تر): جمعشان همان ۱۲ پیکسلی می‌شود که نوارِ ماه همیشه داشت، پس
   صفحه‌ی خانه‌ی کسی که هیچ حسابی پین نکرده **مو نمی‌زند**. */
.home-carousel { margin-bottom: -14px; }

.home-slides {
    display: flex;
    /* ⛔ فاصله‌ی اسلایدها از padding افقیِ پایین **کمتر نباشد**، وگرنه
       لبه‌ی اسلایدِ بعدی داخلِ همان ۱۴ پیکسل «سرک می‌کشد»: یک نوارِ
       باریکِ رنگی کنارِ صفحه که شبیهِ خرابیِ رندر دیده می‌شود، نه شبیهِ
       نشانه‌ی کشیدنی بودن. آن نشانه کارِ نقطه‌هاست. */
    gap: 28px;
    flex-wrap: nowrap;
    overflow-x: auto;
    /* ⛔ `overflow-x: auto` مقدارِ `overflow-y` را هم به `auto` می‌برد، پس
       جعبه‌ی برش دقیقاً روی لبه‌ی اسلایدها می‌افتد و **سایه بریده
       می‌شود** — نه محو، بلکه با یک لبه‌ی صافِ دیدنی. اندازه‌گیری شد:
       ۸ پیکسل زیرِ کارت هنوز `#D5D3E9` بود و ۱۲ پیکسل زیرش ناگهان
       `#F6F7FB`ِ زمینه. این padding جا برای همان سایه است و اندازه‌اش
       هم اندازه‌گیری شده، نه حدس: با ۱۶ پیکسل لبه هنوز دیده می‌شد.
       ⚠ و حاشیه‌ی منفیِ قرینه‌اش اجباری است: با padding تنها، عرضِ
       اسلاید (که `100%`ِ جعبه‌ی محتواست) ۲۸ پیکسل کم می‌شد و دیگر
       «دقیقاً به اندازه‌ی نوارِ ماه» نبود. ۱۴ از paddingِ خودِ صفحه هم
       بیشتر نیست، پس چیزی از لبه بیرون نمی‌زند. */
    padding: 0 14px 26px;
    margin: 0 -14px;
    scroll-snap-type: x mandatory;
    /* ⛔ نیمه‌ی دومِ همان رفع: بدونِ این، اسنپ لبه‌ی اسلاید را به لبه‌ی
       **جعبه‌ی padding** می‌چسباند و همان ۱۴ پیکسل بالا را خنثی می‌کند —
       مرورگر خودش ۱۴ پیکسل اسکرول می‌کند و اسلاید ۱۴ پیکسل بیرون‌تر از
       بقیه‌ی کارت‌های صفحه می‌ایستد. یک بار واقعاً همین شد. */
    scroll-padding-inline: 14px;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
}
.home-slides::-webkit-scrollbar { display: none; }

.home-slides > * {
    flex: 0 0 100%;
    /* ⛔ `start` است نه `center`: با `center` و `scroll-snap-type:
       mandatory`، مرورگر همان هنگامِ چیدمان اسلایدِ **دوم** را وسط
       می‌آورد و کاربر اصلاً نوارِ ماه را نمی‌دید. یک بار واقعاً همین شد
       و در اسکرین‌شات دیده شد، نه در بازبینی. */
    scroll-snap-align: start;
}

/* ⛔ حاشیه‌ی پایینِ خودِ نوار داخلِ اسلایدر صفر می‌شود. نه فقط برای
   فاصله: حاشیه‌ی یک آیتمِ فلکس در `stretch` از ارتفاعِ جعبه‌اش کم
   می‌شود، پس بدونِ این خط نوارِ ماه ۱۲ پیکسل **کوتاه‌تر** از کارت‌های
   کنارش می‌شد. */
.home-slides .balance-ribbon { margin-bottom: 0; }

/* نقطه‌های نشانگر — جایگزینِ «سرک کشیدنِ» کارتِ بعدی. */
.home-dots { display: flex; justify-content: center; gap: 2px; padding-bottom: 8px; }
.home-dot {
    width: 22px; height: 18px; padding: 0; border: 0;
    background: none; cursor: pointer; position: relative;
}
.home-dot::before {
    content: '';
    position: absolute; inset: 0; margin: auto;
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--line);
    transition: width .18s ease, background-color .18s ease;
}
.home-dot.is-on::before { width: 16px; border-radius: 3px; background: var(--muted-2); }

/* ---------- کارتِ حسابِ پین‌شده روی خانه ----------
   ⛔ خودِ `.bank-card`ِ صفحه‌ی حساب‌هاست و اینجا فقط سه چیز عوض می‌شود.
     طرحِ دوم ننویسید: با دو طرح، کاربر بسته به اینکه کارت را از خانه
     باز کرده یا از فهرست حساب‌ها، دو چیزِ متفاوت می‌بیند. */
.home-card {
    /* ⛔ `aspect-ratio` باید برداشته شود. `.bank-card` نسبتِ واقعیِ کارت
       بانکی (۱.۵۸۶) را دارد و آن با «هم‌قدِ نوارِ ماه» در تضاد است: روی
       موبایل ۲۱۹ پیکسل می‌شد و روی دسکتاپ **۴۳۴**، در برابر ۱۷۷ِ نوار.
       ارتفاع را همان `stretch`ِ اسلایدر می‌دهد. */
    aspect-ratio: auto;
    /* گردی و padding از نوارِ ماه می‌آید، نه از کارتِ داخلِ مودال:
       دو اسلایدِ هم‌اندازه با دو گردیِ متفاوت کنارِ هم غلط دیده می‌شوند. */
    border-radius: var(--r-lg);
    padding: 22px 20px;
    box-shadow: 0 10px 24px -12px rgba(21, 23, 28, .45);
    cursor: pointer;
}
/* ⚠ چیپِ طلایی در ارتفاعِ کمترِ خانه جا را می‌گیرد و شماره‌ی کارت را
   می‌فشارد؛ کوچک‌تر می‌شود، نه حذف — همان چیزی است که کارت را «کارت»
   نشان می‌دهد. */
.home-card .bank-card-chip { width: 32px; height: 23px; }
.home-card .bank-card-bank { font-size: 15px; }
.home-card .bank-card-number { font-size: 18px; }
.home-card .bank-card-balance { font-size: 17px; }
.home-card:focus-visible { outline: 2px solid #fff; outline-offset: -4px; }

/* دکمه‌ی پین در فهرست حساب‌ها */
.wallet-pin {
    background: none; border: 0; padding: 6px;
    color: var(--muted-2); cursor: pointer;
    flex-shrink: 0; line-height: 0; border-radius: 8px;
}
.wallet-pin:hover { color: var(--ink); background: var(--line-soft); }
.wallet-pin.is-on { color: var(--gold); }
.wallet-pin.is-on svg { fill: color-mix(in srgb, var(--gold) 22%, transparent); }
.wallet-pin:disabled { opacity: .5; cursor: default; }

/* ---------- «دقیقه‌ی اول»: کارتِ موجودی اولیه ----------
   ⚠ رنگش آبیِ تعامل است (`--gold`/`--gold-wash`) نه کهربایی: این یک
     **دعوت** است نه هشدار. با رنگِ هشدار، اولین چیزی که کاربرِ تازه
     می‌بیند یک اخطار می‌شد — و آن‌وقت رنگِ هشدار در بقیه‌ی اپ هم بی‌اثر
     می‌شود. همان درسِ «هشدارِ همیشگی بدتر از نبودنش است». */
/* ============================================================
   معرفیِ اولیه — تورِ نورافکنی روی خودِ صفحه
   ============================================================
   ⛔ لایه‌ی تازه‌ای ساخته نشد: `.intro-overlay` همچنان روی همان
      `.modal-overlay` می‌نشیند، چون سه چیز از آنجا می‌آید که نسخه‌ی
      دومشان دیر یا زود از اصل دور می‌افتد — `display: none`ِ پیش‌فرض
      (پس هیچ `hidden` ای رندر نمی‌شود و قاعده ۱۸ موضوعیت ندارد)،
      قفلِ بدنه در `watchOverlays()`، و همان `z-index`.

   ⛔ ولی `padding`ِ حاشیه‌ی امنِ آن کلاس اینجا **صفر می‌شود** —
      تمام‌صفحه یعنی تمام‌صفحه — پس `env(safe-area-inset-*)` به خودِ
      کارت منتقل شده است. بدونِ آن انتقال، دقیقاً همان خرابی برمی‌گردد
      که قاعده ۱۳ برای گرفتنش نوشته شد، و چون سلکتورش `.intro-overlay`
      است آن قاعده هم نمی‌گیردش. قاعده ۴۷ این یکی را جدا می‌سنجد.

   ⛔ تاریکیِ صفحه از `box-shadow`ِ خودِ `.intro-spot` می‌آید، نه از
      زمینه‌ی لایه. یک مکانیزم برای هر دو حالت: با هدف، حفره اندازه‌ی
      هدف است؛ بی‌هدف، حفره صفر می‌ماند و همان سایه کلِ صفحه را تیره
      می‌کند. با دو مکانیزمِ جدا (زمینه‌ی لایه + حفره) لبه‌ی بینشان در
      جابه‌جاییِ اسلایدها یک لحظه دیده می‌شد.

   ⚠ جای حفره با `top`/`left`ِ **فیزیکی** نوشته می‌شود، نه
     `inset-inline-start`: مقدارِ منطقی در صفحه‌ی راست‌به‌چپ به `right`
     نگاشت می‌شود و کنارِ `left`ی که جاوااسکریپت می‌نویسد جعبه را
     بیش‌ازحد مقید می‌کند و `left` **بی‌صدا** نادیده می‌ماند — همان
     چیزی که یک بار سرِ `optionPicker()` افتاد. و
     `getBoundingClientRect()` هم فیزیکی می‌دهد. */
.intro-overlay {
    padding: 0;
    background: transparent;
    align-items: stretch;
    justify-content: stretch;
    overflow: hidden;
}
.intro-spot {
    position: absolute;
    top: 50%; left: 50%;
    width: 0; height: 0;
    border-radius: 18px;
    box-shadow: 0 0 0 9999px rgba(12, 14, 20, .74);
    pointer-events: none;
    transition: top .2s ease, left .2s ease, width .2s ease, height .2s ease;
}
/* ⛔ رنگِ حلقه **ثابت** است، نه یک توکنِ تم — و این عمدی است: این حلقه
   همیشه روی همان سایه‌ی تیره‌ی بالا می‌نشیند، نه روی سطحِ صفحه. یک
   توکنِ تم (مثل `--brand`) در حالت شب زغالی می‌ماند و روی همان تیرگی
   **ناپدید** می‌شود — یعنی نورافکن بی‌حلقه، بی‌هیچ خطایی.
   ⚠ و نسخه‌ی اول `var(--accent)` داشت که در این فایل **اصلاً تعریف
     نشده**: مرورگر کلِ اعلانِ `outline` را دور می‌ریزد، پس حلقه هرگز
     کشیده نمی‌شد. در اسکرین‌شات دیده شد، نه در بازبینی. */
.intro-spot.has-target {
    outline: 2px solid rgba(255, 255, 255, .92);
    outline-offset: 0;
}

/* کارتِ چسبیده به حفره. جای دقیقش را جاوااسکریپت می‌نویسد؛ این‌جا فقط
   حالتِ پیش‌فرض و عرض است. */
.intro-card {
    position: absolute;
    left: 14px; right: 14px; bottom: 14px;
    background: var(--surface);
    border-radius: var(--r-lg);
    padding: 18px;
    box-shadow: var(--sh-lg);
    max-height: 72%;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}
/* ⛔ همان «مستطیلی که صفحه را در بر می‌گیرد»: اسلایدِ بی‌هدف.
   ⚠ و تنها حالتی که کارت به لبه‌ی صفحه می‌چسبد، پس `env(...)` اینجا
     لازم است — `.intro-overlay` همان padding را از `.modal-overlay`
     برداشته و قاعده ۱۳ سلکتورِ تازه را نمی‌بیند. قاعده ۴۷ می‌سنجدش. */
.intro-card.is-full {
    top: 0; bottom: 0; left: 0; right: 0;
    width: auto;
    border-radius: 0;
    max-height: none;
    padding: calc(28px + env(safe-area-inset-top)) 22px
             calc(24px + env(safe-area-inset-bottom));
    display: flex; flex-direction: column; justify-content: center;
}
.intro-card.is-full .intro-icon { font-size: 52px; margin-bottom: 20px; }
.intro-card.is-full .intro-title { font-size: 20px; }
.intro-card.is-full .intro-actions { margin-top: 26px; }

.intro-close {
    position: absolute;
    top: 8px; inset-inline-end: 10px;
    background: none; border: none;
    font-size: 25px; line-height: 1;
    color: var(--muted); padding: 0 4px;
    z-index: 2;
}
.intro-card.is-full .intro-close { top: calc(14px + env(safe-area-inset-top)); }

/* نوکِ اشاره به سمتِ عنصرِ نورافکن‌شده.
   ⚠ نام‌ها **فیزیکی**اند (`is-left` یعنی کارت سمتِ چپِ حفره است)، نه
     منطقی: مختصاتِ `getBoundingClientRect()` هم فیزیکی است و مقدارِ
     منطقی در صفحه‌ی راست‌به‌چپ دقیقاً برعکس می‌نشیند — همان چیزی که یک
     بار سرِ `optionPicker()` افتاد. */
.intro-beak {
    position: absolute;
    width: 15px; height: 15px;
    background: var(--surface);
    transform: rotate(45deg);
    display: none;
}
.intro-card.is-under .intro-beak { top: -7px; display: block; }
.intro-card.is-over  .intro-beak { bottom: -7px; display: block; }
.intro-card.is-right .intro-beak { left: -7px; display: block; }
.intro-card.is-left  .intro-beak { right: -7px; display: block; }

.intro-slide { display: none; text-align: center; padding: 6px 2px 2px; }
.intro-slide.is-on { display: block; }
.intro-icon { font-size: 40px; line-height: 1; margin-bottom: 12px; }
.intro-title { font-size: 16px; font-weight: 700; margin-bottom: 8px; }
.intro-body { font-size: 14px; line-height: 1.9; color: var(--muted); }
.intro-dots {
    display: flex; justify-content: center; gap: 7px;
    margin-top: 16px;
}
.intro-dot {
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--line);
    transition: background .15s, width .15s;
}
/* ⚠ `--ink` است نه یک توکنِ برند: نقطه روی سطحِ `--surface` می‌نشیند و
   `--ink` تنها چیزی است که در **هر دو** پالت با آن سطح تضاد دارد. */
.intro-dot.is-on { width: 18px; border-radius: 4px; background: var(--ink); }

/* ⛔ روی دسکتاپ کارتِ تمام‌عرض یک نوارِ درازِ لبه‌ی صفحه می‌شود — همان
   چیزی که `.sheet` را روی عرضِ بزرگ خراب می‌کرد. فقط کارتِ چسبیده به
   نورافکن جمع می‌شود؛ اسلایدِ تمام‌صفحه عمداً تمام‌صفحه می‌ماند.
   ⚠ و هیچ `transform` ای اینجا نیست: جای افقیِ کارت را جاوااسکریپت با
     `left` می‌نویسد تا هم‌مرکزِ حفره بنشیند. یک `translateX(-50%)`ِ
     جامانده آن را **بی‌صدا** ۲۳۰ پیکسل جابه‌جا می‌کرد و نوکِ اشاره از
     لبه‌ی کارت بیرون می‌افتاد — با اندازه‌گیری دیده شد، نه با نگاه. */
@media (min-width: 901px) {
    .intro-card {
        right: auto;
        width: min(460px, 92vw);
    }
    .intro-card.is-full { left: 0; right: 0; width: auto; }
}

.start-card {
    border-inline-start: 3px solid var(--gold);
    background: linear-gradient(180deg, var(--gold-wash) 0%, var(--surface) 62%);
}
/* ⛔ حالت شب **باید** جدا نوشته شود، وگرنه بی‌صدا از بین می‌رود:
   `html[data-theme="dark"] .card { background: #16191e }` (خطِ ~۱۷۵۵)
   وزنِ بیشتری از `.start-card` دارد، پس شورتهندِ `background` آن،
   گرادیانِ بالا را کاملاً پاک می‌کند. در روز بی‌عیب بود و فقط در شب
   دیده می‌شد — همان درسِ «قاعده‌ای که *برنده می‌شود* باید مقدار را
   داشته باشد» که یک بار سرِ `env(safe-area-inset-*)` گفته شد.
   با اندازه‌گیری پیدا شد (`backgroundImage: none`)، نه با نگاه. */
html[data-theme="dark"] .start-card {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--gold) 16%, var(--surface)) 0%,
        var(--surface) 62%);
    /* ⚠ و خطِ رنگیِ کنار هم همین‌طور: `html[data-theme="dark"] .card
       { border-color: var(--line) }` (خطِ ~۲۳۲۰) وزنش بیشتر است، پس
       نوارِ آبی در شب خاکستری می‌شد. اندازه‌گیری شد: rgb(38,44,71). */
    border-inline-start-color: var(--gold);
}
.start-head { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.start-step {
    background: var(--gold); color: var(--brand-on);
    font-size: 11px; font-weight: 700;
    padding: 3px 9px; border-radius: 999px;
    flex-shrink: 0;
}
.start-title { font-size: 15.5px; font-weight: 800; color: var(--ink); margin: 0; }
.start-why {
    font-size: 13px; line-height: 1.9; color: var(--muted);
    margin: 9px 0 14px;
}
.start-label {
    display: block;
    font-size: 12.5px; font-weight: 600; color: var(--ink-soft);
    margin-bottom: 6px;
}
/* ورودی و دکمه در یک ردیف: قدمِ اول باید یک عدد و یک تپ باشد، نه یک فرم. */
.start-row { display: flex; gap: 8px; align-items: stretch; }
/* ⚠ فاصله‌ی عمودیِ کمتر از فیلدِ مبلغِ شیتِ ثبت. `.amount-input` با
   `font-size: 30px !important` ساخته شده و با padding پیش‌فرض ۷۷px
   ارتفاع می‌گیرد؛ در یک کارتِ کوچکِ راهنما آن ارتفاع، دکمه‌ی کنارش را
   به یک تخته‌ی ۶۰×۷۷ تبدیل می‌کرد. اندازه‌گیری شد، حدس زده نشد. */
/* ⚠ `!important` اینجا ناچاری است نه سلیقه: خودِ `.amount-input` با
   `font-size: …!important` و `padding: …!important` نوشته شده، پس بدونِ
   آن این قاعده **بی‌صدا** بی‌اثر می‌ماند. اولین تلاش دقیقاً همین شد و
   با اندازه‌گیری معلوم شد (`paddingTop` همچنان ۱۴px بود)، نه با نگاه. */
.start-row .amount-input {
    flex: 1; min-width: 0;
    font-size: 26px !important;
    padding: 10px 13px !important;
}
/* دکمه پهنای معقول می‌گیرد وگرنه با دو حرفِ «ثبت» یک مربعِ باریک می‌شود. */
.start-row .btn { flex-shrink: 0; min-width: 92px; }
.start-foot {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; margin-top: 12px;
    font-size: 12.5px;
}
.start-foot a { color: var(--gold); text-decoration: none; }
/* «نیازی نیست» عمداً کم‌رنگ و بی‌کادر است: راهِ فرار باید باز باشد ولی
   نباید هم‌وزنِ خودِ کار دیده شود. */
.start-skip {
    background: none; border: 0; padding: 0;
    color: var(--muted-2); font: inherit; cursor: pointer;
    text-decoration: underline; text-underline-offset: 3px;
    margin-inline-start: auto;
}
.start-skip:hover { color: var(--ink); }

/* ⛔ راهِ ثبتِ اولین تراکنش باید **دکمه** باشد، نه جمله‌ای که به دکمه‌ی
   نوارِ پایین اشاره کند: آن نوار بالای ۹۰۰px اصلاً رندر نمی‌شود. */
.empty-cta { text-align: center; padding: 0 12px 26px; margin: -14px 0 0; }

/* پیش‌نمایشِ زنده‌ی هدفِ پس‌انداز — همان اجزای کارتِ واقعی، تا آنچه
   کاربر می‌بیند با آنچه بعد از ذخیره می‌گیرد یکی باشد. */
.goal-preview {
    margin-top: 4px; padding: 12px 13px;
    background: var(--line-soft);
    border-radius: var(--r-sm);
}
.goal-preview-title { font-size: 13.5px; font-weight: 700; color: var(--ink); margin-bottom: 9px; }
.goal-preview-foot {
    display: flex; justify-content: space-between; align-items: center;
    margin-top: 7px; font-size: 12px; color: var(--muted);
}

.rm-chips { margin-top: 2px; }
.rm-chips .stay-chip { min-width: 0; flex: 0 1 auto; padding: 9px 12px; font-size: 12.5px; }

/* «دلخواه»: عدد و واحد کنارِ هم، چون با هم یک جمله‌اند («هر ۴ ماه»).
   زیرِ هم گذاشتنشان دو تصمیمِ جدا به نظر می‌رسید. */
.rm-custom { margin-top: 12px; }
.rm-custom-row { display: flex; gap: 8px; align-items: center; }
.rm-custom-row input { flex: 0 0 92px; }
.rm-custom-row select { flex: 0 0 auto; width: auto; }

/* خلاصه‌ی زنده — کاربر بدون ذخیره کردن می‌بیند انتخابش یعنی چه */
.stay-note {
    margin: 14px 0 0;
    padding: 10px 12px;
    background: var(--line-soft);
    border-radius: var(--r-sm);
    font-size: 12.5px;
    line-height: 1.8;
    color: var(--muted);
}
.stay-note strong { color: var(--ink); font-weight: 700; }

/* دکمه‌های ذخیره/تستِ کارتِ اتصالِ پیامک، و خطِ وضعیتِ بالای کارت. */
.sms-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.sms-actions .btn { flex: 1 1 auto; }
.conn-state {
    font-size: 12.5px; color: var(--muted);
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 9px 11px; margin-bottom: 14px;
}
.conn-state strong { color: var(--ink); }
.sms-test-inline { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line); }

/* نسخه‌ی مستقرشده، زیرِ نوارِ بخش‌های مدیریت. عمداً کم‌رنگ و ریز است:
   جواب دادنِ «آیا deploy نشست؟» مهم است، ولی هر روز خوانده نمی‌شود. */
.deploy-stamp {
    font-size: 11px; color: var(--muted);
    margin: -8px 0 14px; text-align: left;
}

/* ---------- صفحه‌ی سررسیدها ---------- */
.due-filters {
    display: flex; gap: 6px; overflow-x: auto;
    scrollbar-width: none; margin-bottom: 14px; padding-bottom: 2px;
}
.due-filters::-webkit-scrollbar { display: none; }
.due-filter {
    flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 14px; border-radius: 999px;
    font-size: 12.5px; font-weight: 600;
    color: var(--muted); background: var(--surface);
    border: 1px solid var(--line); text-decoration: none; white-space: nowrap;
}
.due-filter.is-active { background: var(--brand); color: #fff; border-color: var(--brand); }
.due-count {
    background: color-mix(in srgb, currentColor 18%, transparent);
    border-radius: 999px; padding: 1px 6px; font-size: 11px;
}

.due-list { list-style: none; margin: 0; padding: 0; }
.due-row {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 12px 0; border-bottom: 1px solid var(--line);
}
.due-row:last-child { border-bottom: none; }
/* رنگِ نوع — همان معنایی که در بقیه‌ی اپ دارند. */
.due-dot { flex: 0 0 auto; width: 8px; height: 8px; margin-top: 6px; border-radius: 50%; }
.due-cheque    { background: var(--gold); }
.due-debt      { background: var(--out); }
.due-recurring { background: var(--in); }
.due-custom    { background: var(--muted); }

.due-main { flex: 1 1 auto; min-width: 0; text-decoration: none; color: inherit; }
.due-title { font-size: 13.5px; font-weight: 700; }
.due-meta {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    font-size: 12px; color: var(--muted); margin-top: 4px;
}
.due-meta .is-late  { color: var(--out); font-weight: 700; }
.due-meta .is-today { color: var(--gold); font-weight: 700; }
.due-type {
    background: var(--paper); border: 1px solid var(--line);
    border-radius: 999px; padding: 1px 7px; font-size: 11px;
}
/* ⛔ `margin-right: auto` مبلغ را به لبه‌ی **چپِ** ردیف می‌برد، و عمداً
   فیزیکی است نه `margin-inline-*`: مقدارِ منطقی در این ردیفِ راست‌به‌چپ
   دوباره حل می‌شود و دقیقاً برعکس می‌نشیند. اندازه‌گیری شد: پیش از این
   `.due-meta` با `flex-wrap: wrap` مبلغ را به خطِ دوم می‌برد و آنجا
   `gapL = ۱۵۱` و `gapR = ۰` می‌شد — یعنی چسبیده به راست. حالا چه خط
   بشکند چه نشکند، مبلغ همان‌جای چپ می‌ماند. */
.due-amount { font-weight: 600; margin-right: auto; }

.due-actions { display: flex; gap: 4px; flex: 0 0 auto; }
.due-btn {
    width: 30px; height: 30px; display: grid; place-items: center;
    border-radius: 8px; border: 1px solid var(--line);
    background: var(--surface); color: var(--muted); cursor: pointer;
}
.due-btn-ok   { color: var(--in); }
.due-btn-mute { color: var(--out); }
.due-btn:hover { background: var(--paper); }

/* ⛔ شبکه‌ی چیپ‌های دسته‌بندی در شیتِ ثبت تراکنش.
   ⚠ جایگزینِ `<select>` نیست؛ بالای آن می‌نشیند و فقط مقدارش را
   می‌نویسد. دلیلش در `includes/add_tx_sheet.php` نوشته شده.
   ⚠ `:empty` به‌جای `[hidden]` عمدی است: ظرف خالی از سرور می‌آید و
   `app.js` پرش می‌کند، پس هیچ‌جا ویژگیِ `hidden` روی این کلاس رندر
   نمی‌شود و قاعده ۱۸ موضوعیت ندارد. بدونِ این خط، ظرفِ خالی همان
   `margin-bottom` را می‌گرفت و زیرِ برچسب یک فاصله‌ی بی‌دلیل می‌ماند. */
/* ⛔ یک خطِ افقی، نه شبکه‌ی چندردیفی — خواسته‌ی صریحِ مالکِ نصب.
   با `wrap`، هشت چیپ روی عرضِ گوشی سه ردیف می‌شد و کلِ فرمِ ثبت را
   پایین می‌برد؛ همان شلوغی‌ای که گزارش شد. حالا `nowrap` + اسکرولِ
   افقی، و انتخابِ اینکه چه چیزی اینجا بیاید دستِ خودِ کاربر است
   (`categoriesForGrid()`)، پس معمولاً اصلاً اسکرول لازم نمی‌شود. */
.cat-grid {
    display: flex;
    flex-wrap: nowrap;
    gap: 6px;
    margin-bottom: 8px;
    overflow-x: auto;
    /* ⚠ `overflow-x: auto` مقدارِ `overflow-y` را هم به `auto` می‌برد و
       `:active { transform: scale(.96) }` را لبه‌ی برش می‌گرفت — همان
       درسِ سایه‌ی کارت‌های خانه. padding + حاشیه‌ی منفیِ قرینه، تا نه
       چیزی بریده شود نه ردیف از بقیه‌ی فرم تورفته بیفتد. */
    padding: 3px;
    margin-inline: -3px;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
}
.cat-grid::-webkit-scrollbar { display: none; }
.cat-grid:empty { display: none; }
/* ⛔ چیپ در یک ردیفِ فلکس نباید فشرده شود: بدونِ این، مرورگر همه را در
   عرضِ موجود جا می‌دهد و نام‌ها با «…» بریده می‌شوند — یعنی `nowrap`
   بالا بی‌اثر می‌شد. */
.cat-grid .cat-chip { flex: 0 0 auto; }

.cat-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 10px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--ink-soft);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    /* ⛔ برچسبِ یک کنترل هرگز وسطِ خودش نمی‌شکند — همان درسِ نیم‌فاصله
       در قاعده ۳۱: «خوراکی‌ها» با U+200C جای شکستن دارد و چیپ را به دو
       خط می‌بُرد. */
    white-space: nowrap;
}
.cat-chip:active { transform: scale(.96); }
.cat-chip-icon {
    display: inline-flex;
    color: var(--cc, #64748b);
}
.cat-chip-icon svg { display: block; width: 16px; height: 16px; }

/* ⚠ رنگِ خودِ دسته روی حالتِ فعال می‌نشیند، نه `--brand`: کاربر همان
   رنگ را در فهرست تراکنش‌ها و نمودارها هم می‌بیند. */
.cat-chip.active {
    background: color-mix(in srgb, var(--cc, #64748b) 14%, var(--surface));
    border-color: var(--cc, #64748b);
    color: var(--ink);
}
.cat-chip.active .cat-chip-icon { color: var(--cc, #64748b); }

/* ---------------------------------------------------------------
   صفحه‌ی «خطاهای برنامه» (`admin/errors.php`)

   ⛔ هر ردیف یک اقدام دارد، نه فقط یک متن — کلِ خواسته همین بود:
      «بتونم راحت برطرفش کنم». دکمه در ستونِ **آخر** و با عرضِ کمینه
      می‌نشیند تا متنِ خطا فشرده نشود (همان درسِ `.actions-cell`).
   --------------------------------------------------------------- */
.err-list { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }

.err-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
}
/* ⚠ ردیفِ رسیدگی‌شده کم‌رنگ می‌شود ولی **خوانا** می‌ماند: پنهان کردنش
   یعنی همان «سقفِ بی‌صدا» که این پروژه جای دیگری ممنوعش کرده. */
.err-row.is-resolved { opacity: .62; }

.err-main { flex: 1; min-width: 0; }

.err-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* ⚠ مسیرِ فایل چپ‌به‌راست است و جای شکستن ندارد، پس روی عرضِ موبایل
   باید بتواند بشکند — وگرنه کارت اسکرولِ افقی می‌گیرد. */
.err-where {
    font-size: 12px; font-weight: 700;
    color: var(--ink-soft);
    overflow-wrap: anywhere;
}

.err-msg {
    margin-top: 4px;
    font-size: 12.5px;
    color: var(--ink);
    overflow-wrap: anywhere;
}

.err-meta { margin-top: 4px; font-size: 11.5px; }

/* ⛔ «کمترین عرضِ لازم» — بدونِ آن، ستونِ دکمه از متنِ خطا عرض می‌گرفت
   و برچسبِ «برطرف شد» (که نیم‌فاصله دارد) دو خط می‌شد؛ همان خرابیِ
   ستونِ «عملیات» در `admin/users.php` — قاعده ۳۱. */
.err-act { flex: 0 0 auto; }

.err-tools {
    display: flex; flex-wrap: wrap; gap: 8px;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--line);
}

.err-howto { margin: 6px 0 0; padding-inline-start: 18px; }
.err-howto li { margin-bottom: 4px; }


/* ============================================================
   کالاهای فروشگاه — کارتِ کوچکِ صفحه‌ی دارایی و صفحه‌ی خودش

   ⛔ اعدادِ `.store-own-stat b` و `.store-row-own` به فهرستِ `.ltr-num`
      بالا **پیوسته‌اند**، نه اینکه `direction: ltr` تازه‌ای اینجا
      بگیرند — قاعده‌ی پروژه: کلاسِ عددیِ تازه = یک نامِ تازه در همان
      یک فهرست، وگرنه نسخه‌ی دومی می‌شود که دیر یا زود عقب می‌افتد.
   ============================================================ */

/* ⚠ `auto-fit` با `minmax` تا روی ۳۹۰ پیکسل دو ستون بماند و روی
     دسکتاپ کش بیاید. `min(…,100%)` لازم است چون آیتمِ گرید پیش‌فرض
     `min-width: auto` دارد و حاضر نیست از محتوایش کوتاه‌تر شود —
     همان چیزی که یک بار منوی کناری را از اسکرول انداخت. */
.store-own-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(130px, 100%), 1fr));
    gap: 10px;
    margin: 12px 0 4px;
}
.store-own-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: 12px;
}
/* ⚠ عمداً `background` ندارد: `html[data-theme="dark"] .card` با وزنِ
     بیشتر بازنویسی‌اش می‌کند — همان درسِ `.start-card` و `.grid-card`.
     مرز از `--line` می‌آید که خودش تم‌آگاه است. */
.store-own-label {
    font-size: .78rem;
    color: var(--color-gray-500);
}
.store-own-stat b { font-size: .98rem; }
/* مانده‌ی نقدی: همان کارت، با نوارِ کنارِ رنگِ درآمد — پولی است که
   مالِ اوست و فقط هنوز به دستش نرسیده. رنگ روی مرز است نه زمینه (درسِ
   `.start-card`: زمینه در حالت شب بازنویسی می‌شود). */
.store-own-cash { border-inline-start: 3px solid var(--in); }
.store-own-total b { font-size: .95rem; }
/* گوشیِ نه در انبار نه فروخته (ثبت‌شده، بایگانی، مرجوع) — آرام، نه هشدار. */
.store-row-out { color: var(--color-gray-500); }
.store-own-stat small {
    font-size: .72rem;
    color: var(--color-gray-500);
}

/* دکمه‌ی ورود: تمام‌عرض تا روی گوشی هدفِ لمسِ درستی باشد. */
.store-enter {
    display: block;
    width: 100%;
    margin-top: 14px;
    text-align: center;
    text-decoration: none;
}

.store-cat-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px;
    margin: 16px 0 6px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--line);
}
.store-cat-name { font-weight: 700; font-size: .95rem; }
.store-cat-meta {
    font-size: .78rem;
    color: var(--color-gray-500);
    margin-right: auto;
}
/* ⚠ فیزیکی است نه `margin-inline-*`: مقدارِ منطقی نسبت به جهتِ همان
     ردیفِ راست‌به‌چپ دوباره حل می‌شود و **دقیقاً برعکس** می‌نشیند —
     همان دلیلِ `text-align: right`ِ فیزیکی روی `<select>`. */

.store-row-own {
    display: block;
    font-size: .74rem;
    font-weight: 400;
    color: var(--color-gray-500);
}

.store-asset-search {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 10px;
}
.store-asset-search .input { flex: 1; min-width: 0; }

/* ============================================================
   کارتِ سالانه‌ی چهارفصل (dashboard.php)

   ⛔ رنگِ فصل «نشانه» است نه پس‌زمینه‌ی پُررنگ: یک wash کم‌رنگ و یک
      نوارِ باریکِ کنار. عددها رنگِ خودشان (--in/--out) را نگه می‌دارند،
      وگرنه سبزِ بهار با سبزِ «درآمد» یکی خوانده می‌شد.
   ⚠ `.season-card` عمداً `.card` نیست: `html[data-theme="dark"] .card`
     با وزنِ بیشتر `background` را بازنویسی می‌کند (درسِ `.start-card`).
   ============================================================ */
:root {
    --season-spring: #2f9e62; --season-spring-wash: #eef8f1;
    --season-summer: #2f7fd6; --season-summer-wash: #edf4fc;
    --season-autumn: #d9822b; --season-autumn-wash: #fcf3ea;
    --season-winter: #8a94ad; --season-winter-wash: #ffffff;
}
html[data-theme="dark"] {
    --season-spring-wash: rgba(47,158,98,.10);
    --season-summer-wash: rgba(47,127,214,.10);
    --season-autumn-wash: rgba(217,130,43,.10);
    --season-winter-wash: rgba(255,255,255,.04);
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --season-spring-wash: rgba(47,158,98,.10);
        --season-summer-wash: rgba(47,127,214,.10);
        --season-autumn-wash: rgba(217,130,43,.10);
        --season-winter-wash: rgba(255,255,255,.04);
    }
}
.year-report-head {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    margin-bottom: 10px;
}
.year-title { font-size: 17px; font-weight: 800; color: var(--ink); text-decoration: none; }
.year-nav {
    min-width: 64px; font-size: 13px; color: var(--muted); text-decoration: none;
    white-space: nowrap;
}
.year-nav:last-child { text-align: left; }
.year-nav.is-off { visibility: hidden; }
.year-totals {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px;
    padding: 10px 0 12px; border-bottom: 1px dashed var(--line); margin-bottom: 12px;
}
.year-totals > div { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.year-totals .stats-value { font-size: 14.5px; overflow-wrap: anywhere; }
/* ⛔ ۱ یا ۲ ستون، نه auto-fit: با auto-fit روی عرضِ ۷۲۰ سه فصل در یک ردیف
      و زمستان تنها در ردیفِ دوم می‌نشست — سال شبیهِ «۳+۱» خوانده می‌شد. */
.season-grid { display: grid; gap: 10px; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 600px) {
    .season-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.season-card {
    border: 1px solid var(--line); border-radius: var(--r-lg, 14px);
    border-inline-start: 4px solid var(--season-c);
    background: var(--season-w); padding: 10px 12px; min-width: 0;
}
.season-spring { --season-c: var(--season-spring); --season-w: var(--season-spring-wash); }
.season-summer { --season-c: var(--season-summer); --season-w: var(--season-summer-wash); }
.season-autumn { --season-c: var(--season-autumn); --season-w: var(--season-autumn-wash); }
.season-winter { --season-c: var(--season-winter); --season-w: var(--season-winter-wash); }
.season-card.is-current { box-shadow: 0 0 0 2px var(--season-c); }
.season-card.is-future { opacity: .55; }
.season-head {
    display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
    text-decoration: none; color: inherit;
}
.season-name { font-weight: 800; font-size: 14.5px; color: var(--season-c); }
.season-net { font-weight: 800; font-size: 14px; }
.season-sub {
    display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 10px;
    font-size: 11.5px; color: var(--muted); margin: 4px 0 8px;
}
.season-sub b { font-weight: 700; }
.season-month {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    padding: 6px 4px; border-top: 1px solid var(--line);
    text-decoration: none; color: var(--ink); font-size: 13px;
}
.season-month.is-current .season-month-name { font-weight: 800; }
.season-month.is-current .season-month-name::after { content: " •"; color: var(--season-c); }
.season-month.is-future { opacity: .55; }
.season-month-val { font-size: 12.5px; font-weight: 700; }
.year-hint { margin: 10px 0 0; }

/* ---------- تاریخِ امروز روی خانه ----------
   ⚠ زمینه ندارد و کارت نیست: یک خطِ کوچکِ اطلاعی است، نه یک بخش؛ با
     کارت، اولین چیزی که روی خانه دیده می‌شد وزنِ «مانده این ماه» را
     می‌گرفت. */
.home-date {
    display: inline-flex; align-items: center; gap: 6px;
    margin: 0 2px 10px;
    color: var(--ink-soft);
    font-size: 13px; font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}
.home-date svg { flex: none; color: var(--muted); }
.home-date:active { opacity: .7; }

/* ---------- لوگوی رسمیِ بانک ----------
   ⛔ لوگو همیشه روی یک پایه‌ی **سفید** می‌نشیند، نه مستقیم روی گرادیانِ
      کارت: رنگِ کارت را کاربر انتخاب می‌کند و لوگوی آبیِ سپه روی کارتِ
      آبیِ تیره، یا لوگوی قرمزِ ملت روی کارتِ قرمز، اصلاً دیده نمی‌شد. */
.bank-logo {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; flex: none;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0,0,0,.18);
    vertical-align: middle;
}
.bank-logo img { width: 22px; height: 22px; object-fit: contain; display: block; }
.bank-logo[hidden] { display: none; }
.bank-card-top .bank-card-bank { display: inline-flex; align-items: center; gap: 8px; }

.wallet-chip-logo {
    background: #fff;
    border: 1px solid var(--line);
}
.wallet-chip-logo img { width: 26px; height: 26px; object-fit: contain; display: block; }

.bank-pick-row { display: flex; align-items: center; gap: 8px; }
.bank-pick-row select { flex: 1; min-width: 0; }
.bank-pick-logo {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; flex: none;
    border-radius: 12px; background: #fff; border: 1px solid var(--line);
}
.bank-pick-logo img { width: 30px; height: 30px; object-fit: contain; display: block; }
.bank-pick-logo[hidden] { display: none; }

/* ============================================================
   ۴۰. برندِ «حساب لند» — پیش‌فرضِ همه: نیلی

   ⛔ خواسته‌ی مالکِ نصب: «پیش‌فرض رنگ و تم نیلی باشه برای همه». پس نیلی
      خودِ `:root` است نه یک `data-palette` — تا صفحه‌های پیش از ورود
      (`login.php` و …، که سرآیندِ خودشان را دارند)، مانیفست، نوارِ وضعیتِ
      اپِ اندروید و مرورگرِ بی‌جاوااسکریپت هم همان رنگ را داشته باشند.
      زمرد (سبزِ آیکون) حالا یک پالتِ عادی در بخشِ ۴۱ است.

   ⛔ این بخش **آخرین** بخشِ فایل است و باید بماند: توکن‌ها چند بار در
      این فایل بازتعریف شده‌اند (زغالی، Finmori سرمه‌ای، …) و آخرینِ هم‌وزن
      برنده است. رنگِ برند فقط **اینجا** تعریف می‌شود — این «نیلی»ِ
      پیش‌فرض است؛ پالت‌های دیگر فقط همین توکن‌ها را در بخشِ ۴۱
      بازتعریف می‌کنند.
   ⛔ سه جای دیگر همین رنگ را دارند و باید با هم عوض شوند (قاعده ۵۷):
      `theme_color` در `assets/manifest.php`، هر `<meta name="theme-color">`،
      و `colorPrimary` در `mobile/…/values/colors.xml`. با یکی، نوارِ
      وضعیتِ گوشی با خودِ صفحه نمی‌خواند.
   ⚠ `--in`/`--out` عمداً دست نخوردند: آن‌ها **معنا** دارند (درآمد و
     هزینه)، نه برند. سبزِ برند روی **سطح** می‌نشیند (نوار، دکمه، کارتِ
     ماه) و سبزِ درآمد روی **عدد** — پس با هم اشتباه خوانده نمی‌شوند.
   ⚠ نامِ `--gold*` جا ماند و دیگر نه طلایی است نه آبی: «رنگِ تعامل»
     است (لینک، چیپِ فعال). عوض کردنِ نامش صدها مصرف‌کننده را می‌شکست.
   ============================================================ */
:root {
    /* پیش‌فرضِ همه: نیلی. نشانِ ثابت برای تست‌ها (رنگ ندارد). */
    --palette-default: indigo;
    --ink:        #1b2559;
    --ink-soft:   #2a3563;
    --muted:      #6e7ba0;
    --muted-2:    #9aa3c0;
    --line:       #e8ebf5;
    --line-soft:  #f2f4fa;
    --surface:    #ffffff;
    --paper:      #f6f7fb;

    --brand:      #2a3563;   /* نوار پایین، منوی کناری، دکمه‌ی اصلی */
    --brand-deep: #1b2044;
    --brand-on:   #ffffff;
    /* برند به‌عنوان **متن یا خط** (زبانه‌ی فعال، حاشیه‌ی انتخاب). در شب
       خودِ --brand سطحِ تیره است و متنِ هم‌رنگش روی زمینه‌ی تیره گم
       می‌شد — زبانه‌ی فعالِ «سررسیدها» عملاً نامرئی بود. */
    --brand-fg:   #2a3563;

    --gold:       #2563eb;   /* تعامل */
    --gold-lift:  #3b82f6;
    --gold-wash:  #eaf1fe;

    --sh:    0 1px 2px rgba(27,37,89,.04);
    --sh-lg: 0 14px 34px -10px rgba(27,37,89,.28);
    --sh-card: 0 1px 2px rgba(27,37,89,.04), 0 4px 14px -8px rgba(27,37,89,.10);
    /* طیفِ رنگیِ پالت (بخشِ ۴۱): کارتِ ماه، دکمه‌ی +، سرِ پروفایل */
    --tint:     42,36,120;
    --rb1: #3b2f8f; --rb2: #4a3fb5; --rb3: #2f2a6b;
    --rb-in: #6ee7a8; --rb-out: #ff9b9e; --rb-link: #c9c2ff; --rb-fill: #e3dcff;
    --nav-mark: #a5b4fc;
    --fab1: #eef0ff; --fab2: #c7c9ff; --fab-ink: #2a3563;
    --ph1: #ffd9e8; --ph2: #e3dcff;
    --av1: #6d5ce7; --av2: #3b2f8f;
}
html[data-theme="dark"] {
    --ink:        #eef1fa;
    --ink-soft:   #d5dbec;
    --muted:      #8e98bb;
    --muted-2:    #6c7699;
    --line:       #262c47;
    --line-soft:  #1e2338;
    --surface:    #161a2c;
    --paper:      #0e101b;

    --brand:      #232a47;
    --brand-deep: #141830;
    --brand-on:   #ffffff;
    --brand-fg:   #8db2ff;

    --gold:       #6f9bff;
    --gold-lift:  #8db2ff;
    --gold-wash:  #1b2540;

    --sh:    none;
    --sh-lg: 0 14px 34px -10px rgba(0,0,0,.6);
    --sh-card: none;

    --rb1: #2b2270; --rb2: #3a318f; --rb3: #1e1a4d;
    --fab1: #8db2ff; --fab2: #6f7cf0; --fab-ink: #0b1030;
    --ph1: #3a2140; --ph2: #262452;
}

/* ---------- کارت‌ها: یک شعاع، یک سایه، یک خط ---------- */
.card, .stats-card, .summary-box {
    border-radius: var(--r-lg);
    border: 1px solid var(--line);
    box-shadow: var(--sh-card);
}

/* ---------- منوی کناری ---------- */
.sidebar { background: linear-gradient(180deg, var(--brand) 0%, var(--brand-deep) 100%); }
.sidebar-nav a.active { background: rgba(255,255,255,.94); color: var(--brand-fg); font-weight: 700; }
html[data-theme="dark"] .sidebar-nav a.active { background: rgba(255,255,255,.1); color: var(--gold-lift); }

/* ---------- کارتِ «مانده این ماه» ---------- */
.balance-ribbon {
    background: linear-gradient(135deg, var(--rb1) 0%, var(--rb2) 46%, var(--rb3) 100%);
    box-shadow: 0 16px 32px -16px rgba(var(--tint),.75);
}
/* ⛔ پس‌زمینه در شب هم **تکرار** می‌شود: بخشِ ۳۴ یک
   `html[data-theme="dark"] .balance-ribbon` بنفش دارد (۰،۲،۱) که بر
   `.balance-ribbon` تنها می‌برد — و در شب هر پنج پالت بنفش می‌شدند. */
html[data-theme="dark"] .balance-ribbon {
    background: linear-gradient(135deg, var(--rb1) 0%, var(--rb2) 46%, var(--rb3) 100%);
    box-shadow: none;
}
.balance-ribbon .bs-value.bs-in,  .balance-ribbon .bs-in  { color: var(--rb-in); }
.balance-ribbon .bs-value.bs-out, .balance-ribbon .bs-out { color: var(--rb-out); }
.ribbon-link { color: var(--rb-link); }

/* ⛔ دریافتی/پرداختی: برچسب راست، عدد چپ، **روی یک خط**. نسخه‌ی قبلی
   دو ستون بود و در هر ستون برچسب راست‌چین و عدد چپ‌چین می‌نشست، پس
   «پرداختی» وسطِ کارت بود و عددش لبه‌ی چپ — دو چیزی که به هم تعلق
   دارند دورترین فاصله را داشتند. ردیفِ کلید/مقدار همان قاعده‌ی «عدد
   چپ‌چین» را نگه می‌دارد و جفت را کنارِ هم می‌گذارد. هر سه مصرف‌کننده
   (خانه، حساب‌ها، پول قابل خرج) با همین یک قاعده عوض می‌شوند. */
.balance-split { flex-direction: column; gap: 7px; }
.balance-split > div {
    display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
}
.balance-split .bs-label { margin-bottom: 0; font-size: 12px; display: inline-flex; align-items: center; gap: 7px; }
.balance-split .bs-label::before {
    content: ''; width: 7px; height: 7px; border-radius: 50%;
    background: currentColor; opacity: .55; flex: none;
}
.balance-split .bs-in-row .bs-label::before  { background: var(--rb-in); opacity: 1; }
.balance-split .bs-out-row .bs-label::before { background: var(--rb-out); opacity: 1; }

/* نوارِ «چقدر از دریافتی خرج شد» — ⛔ `direction: ltr` روی ترک، مثل هر
   میله‌ی پیشرفتِ دیگرِ اپ: از چپ پر می‌شود. */
.month-meter { margin-top: 14px; }
.month-meter-track {
    direction: ltr;
    height: 6px; border-radius: var(--r-pill);
    background: rgba(255,255,255,.16);
    overflow: hidden;
}
.month-meter-fill {
    height: 100%; border-radius: var(--r-pill);
    background: var(--rb-fill);
    transition: width .5s ease;
}
.month-meter.is-warn .month-meter-fill { background: #fcd679; }
.month-meter.is-over .month-meter-fill { background: #ff9b9e; }
.month-meter-caption {
    margin-top: 6px;
    font-size: 11.5px; color: rgba(255,255,255,.72);
}
.month-compare {
    margin-top: 11px;
    display: flex; align-items: center; gap: 6px;
    font-size: 11.5px; color: rgba(255,255,255,.72);
}
.month-compare svg { flex: none; }
.month-compare.is-up   svg { color: var(--rb-out); }
.month-compare.is-down svg { color: var(--rb-in); }

/* ---------- نوار پایین ---------- */
.bottom-nav {
    background: var(--brand);
    box-shadow: 0 12px 30px -10px rgba(var(--tint),.55);
}
html[data-theme="dark"] .bottom-nav { box-shadow: 0 0 0 1px var(--line), 0 12px 30px -10px rgba(0,0,0,.7); }
.bottom-nav-item { color: rgba(255,255,255,.58); position: relative; }
.bottom-nav-item.active { color: #fff; }
.bottom-nav-item svg { transition: transform .2s ease; }
.bottom-nav-item.active svg { transform: translateY(-1px); }
/* ⛔ نشانگرِ فعال یک خطِ کوتاه زیرِ برچسب است، نه فقط رنگ: روی نوارِ
   تیره تفاوتِ «سفید» و «سفیدِ کم‌رنگ» در آفتاب دیده نمی‌شود. */
.bottom-nav-item.active::after {
    content: '';
    position: absolute; bottom: 7px; left: 50%;
    width: 16px; height: 3px; margin-left: -8px;
    border-radius: var(--r-pill);
    background: var(--nav-mark);
}
.bottom-nav-fab {
    background: linear-gradient(150deg, var(--fab1), var(--fab2));
    color: var(--fab-ink);
    box-shadow: 0 5px 14px -4px rgba(var(--tint),.55);
}
html[data-theme="dark"] .bottom-nav-fab {
    background: linear-gradient(150deg, var(--fab1), var(--fab2));
    color: var(--fab-ink);
    box-shadow: 0 5px 14px -4px rgba(0,0,0,.6);
}

/* ---------- سرِ پروفایل ---------- */
.profile-head { background: linear-gradient(170deg, var(--ph1) 0%, var(--ph2) 46%, var(--surface) 100%); }
.profile-avatar {
    background: linear-gradient(150deg, var(--av1), var(--av2));
    box-shadow: 0 6px 16px -6px rgba(var(--tint),.55);
}

/* ---------- کنترلِ بخش‌بندی‌شده و چیپِ فعال ---------- */
.seg-item.active { box-shadow: 0 1px 3px rgba(var(--tint),.12); }
html[data-theme="dark"] .seg-item.active { background: var(--brand); color: #fff; }

/* ---------- آیکونِ دسته: دایره‌ی رنگیِ کم‌جان ----------
   ⛔ رنگ از خودِ دسته می‌آید (`--cat-bg`، که `renderTransactionRow()`
   می‌گذارد)، نه یک پالتِ دوم. Finmori آن را با `!important` سفید کرده
   بود و فهرستِ ده تراکنش ده دایره‌ی سفیدِ یکسان می‌شد؛ چشم باید از
   روی رنگ دسته را بشناسد، نه با خواندنِ زیرعنوان. */
.cat-icon[style*="--cat-bg"] {
    background: var(--cat-bg) !important;
    box-shadow: none;
}

/* ---------- سرِ روز در فهرستِ تراکنش‌ها ---------- */
.tx-day-header { padding-top: 14px; }
.tx-day-date { color: var(--ink-soft); font-size: 12px; letter-spacing: 0; }
.tx-day-date .tx-day-rel { color: var(--gold); font-weight: 800; margin-left: 6px; }
.tx-day-total { font-size: 12px; font-weight: 700; opacity: .9; }

/* ---------- شیت‌ها: باز شدنِ نرم‌تر ----------
   فقط منحنی و مدت عوض شد، نه خودِ حرکت: همان `sheetUp` با شتابِ
   «ease-out» تند، که شیت را سریع می‌آورد و آرام می‌نشاند. پرده هم محو
   می‌شود، نه اینکه یک‌باره سیاه شود. */
.sheet, .more-sheet { animation: sheetUp .28s cubic-bezier(.2,.8,.25,1); }
.sheet-overlay.show, .more-sheet-overlay.show { animation: overlayIn .2s ease-out; }
@keyframes overlayIn { from { background-color: rgba(0,0,0,0); } }
@media (prefers-reduced-motion: reduce) {
    .sheet, .more-sheet, .sheet-overlay.show, .more-sheet-overlay.show { animation: none; }
}

/* ---------- حالتِ خالی: یک نشانِ آرام بالای جمله ----------
   ⛔ فقط روی `p.empty-row`، نه `td.empty-row`: داخلِ جدول، نشانِ ۵۶
   پیکسلی ردیف را بی‌تناسب بلند می‌کرد. کارتِ خالی بدونِ نشان شبیهِ
   «صفحه درست بار نشد» دیده می‌شود؛ با نشان، شبیهِ «هنوز چیزی نیست».
   ⚠ آیکن یک data URI است (CSP: `img-src 'self' data:`)، و رنگِ خطش
   در شب جدا نوشته شده چون داخلِ data URI متغیرِ CSS کار نمی‌کند. */
p.empty-row { position: relative; }
p.empty-row::before {
    content: '';
    display: block;
    width: 54px; height: 54px;
    margin: 0 auto 12px;
    border-radius: 18px;
    background: var(--gold-wash);
}
/* ⛔ خودِ آیکن یک ماسک است که رنگش را از `--gold` می‌گیرد، نه یک data
   URI با رنگِ سخت‌کد: داخلِ data URI متغیرِ CSS کار نمی‌کند، پس با هر
   پالت (بخشِ ۴۱) یک نسخه‌ی تازه لازم می‌شد و اولین پالتِ فراموش‌شده
   آیکنِ سبز روی زمینه‌ی نارنجی می‌گذاشت. `top` همان padding-top
   پایه‌ی `.empty-row` به‌علاوه‌ی نصفِ اختلافِ جعبه و آیکن است. */
p.empty-row::after {
    content: '';
    position: absolute;
    top: calc(28px + 14px); left: 50%;
    width: 26px; height: 26px; margin-left: -13px;
    background: var(--gold);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 12h-6l-2 3h-4l-2-3H2'/%3E%3Cpath d='M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z'/%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' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 12h-6l-2 3h-4l-2-3H2'/%3E%3Cpath d='M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z'/%3E%3C/svg%3E") center / contain no-repeat;
    pointer-events: none;
}
/* اندپوینتی که padding خودش را درون‌خطی می‌دهد (savings_history) */
p.empty-row[style*="padding:14px"]::after { top: calc(14px + 14px); }
p.empty-row { color: var(--muted); line-height: 1.9; }

/* ---------- اسکلتِ بارگذاری (`window.skeletonHtml`) ---------- */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skel { padding: 6px 0; }
.skel-row { display: flex; align-items: center; gap: 12px; padding: 9px 0; }
.skel-dot, .skel-line, .skel-amt {
    background: linear-gradient(90deg, var(--line-soft) 0%, var(--line) 50%, var(--line-soft) 100%);
    background-size: 200% 100%;
    animation: skelShine 1.2s ease-in-out infinite;
}
.skel-dot { width: 36px; height: 36px; border-radius: 50%; flex: none; }
.skel-lines { flex: 1; display: flex; flex-direction: column; gap: 7px; }
.skel-line { height: 10px; border-radius: 6px; width: 62%; }
.skel-line.is-short { width: 34%; }
.skel-amt { width: 70px; height: 12px; border-radius: 6px; flex: none; }
@keyframes skelShine { from { background-position: 100% 0; } to { background-position: -100% 0; } }
@media (prefers-reduced-motion: reduce) { .skel-dot, .skel-line, .skel-amt { animation: none; } }

/* ============================================================
   ۴۱. پالت‌های رنگ (انتخابِ کاربر در پروفایل → «نمایش»)

   ⛔ «نیلی» پیش‌فرض است و **هیچ ویژگی‌ای** نمی‌گیرد: توکن‌هایش همان
      `:root` بخشِ ۴۰ است (اولین کلیدِ `UI_PALETTES`). پس رنگِ
      `theme-color`ِ ایستا (قاعده ۵۷) همان برندِ پیش‌فرض است.
   ⛔ هر پالت **کلِ** مجموعه را بازتعریف می‌کند — روز و شب جدا — نه فقط
      برند. پالتی که فقط `--brand` را عوض کند، کنارِ خاکستری‌های
      ته‌رنگِ پالتِ پیش‌فرض می‌نشست و «دو برنامه‌ی
      چسبیده به هم» دیده می‌شد.
   ⛔ وزن‌ها عمدی‌اند: `html[data-palette]` (۰،۱،۱) بر `:root` می‌برد و
      `html[data-theme="dark"][data-palette]` (۰،۲،۱) بر هر دو. پالت
      شب را از زمرد نمی‌گیرد.
   ⛔ فهرستِ پالت‌ها در PHP فقط `UI_PALETTES` است (functions.php)؛
      اسکریپتِ سرآیند هم هر نامی را که آنجا نیست نادیده می‌گیرد.
   ⚠ `--in`/`--out`/`--warn-*` در هیچ پالتی نیستند: معنا دارند نه سلیقه.
   ============================================================ */

/* ---------- زمرد — سبزِ هم‌خانواده با آیکون (پیش‌فرضِ قبلی) ---------- */
html[data-palette="emerald"] {
    --ink: #13211a;
    --ink-soft: #26372e;
    --muted: #637168;
    --muted-2: #97a49c;
    --line: #e2eae5;
    --line-soft: #eff4f1;
    --surface: #ffffff;
    --paper: #f4f7f5;
    --brand: #0b5d41;
    --brand-deep: #073f2c;
    --brand-fg: #0b5d41;
    --gold: #0a8154;
    --gold-lift: #11a36b;
    --gold-wash: #e5f5ed;
    --sh: 0 1px 2px rgba(10,48,33,.04);
    --sh-lg: 0 14px 34px -10px rgba(10,48,33,.28);
    --sh-card: 0 1px 2px rgba(10,48,33,.04), 0 4px 14px -8px rgba(10,48,33,.10);
    --tint: 10,48,33;
    --rb1: #0f7550;
    --rb2: #0b5d41;
    --rb3: #073f2c;
    --rb-in: #b7f4d2;
    --rb-out: #ffc0c2;
    --rb-link: #c8f5de;
    --rb-fill: #d9fbe9;
    --nav-mark: #7fe2bd;
    --fab1: #e4f8ee;
    --fab2: #aeeacd;
    --fab-ink: #0b5d41;
    --ph1: #dcf5e8;
    --ph2: #eef8f3;
    --av1: #11a36b;
    --av2: #0b5d41;
}
html[data-theme="dark"][data-palette="emerald"] {
    --ink: #e7efea;
    --ink-soft: #cbd7d0;
    --muted: #8b9c93;
    --muted-2: #677870;
    --line: #22302a;
    --line-soft: #1a2520;
    --surface: #131b17;
    --paper: #0b100e;
    --brand: #17583f;
    --brand-deep: #0c2e22;
    --brand-fg: #4fd1a0;
    --gold: #4fd1a0;
    --gold-lift: #7fe2bd;
    --gold-wash: #12291f;
    --sh: none;
    --sh-lg: 0 14px 34px -10px rgba(0,0,0,.6);
    --sh-card: none;
    --rb1: #145a41;
    --rb2: #0f4130;
    --rb3: #0a2c20;
    --fab1: #7fe2bd;
    --fab2: #3fbf8c;
    --fab-ink: #06251a;
    --ph1: #143a2b;
    --ph2: #12251d;
}

/* ---------- اقیانوس — فیروزه‌ای به آبیِ عمیق ---------- */
html[data-palette="ocean"] {
    --ink: #10212e; --ink-soft: #223847; --muted: #5f7482; --muted-2: #93a5b1;
    --line: #e0e9ef; --line-soft: #eef4f7; --surface: #ffffff; --paper: #f3f7fa;
    --brand: #0c4a6e; --brand-deep: #082f49; --brand-fg: #0c4a6e;
    --gold: #0369a1; --gold-lift: #0284c7; --gold-wash: #e3f2fb;
    --sh: 0 1px 2px rgba(8,47,73,.04); --sh-lg: 0 14px 34px -10px rgba(8,47,73,.28);
    --sh-card: 0 1px 2px rgba(8,47,73,.04), 0 4px 14px -8px rgba(8,47,73,.10);
    --tint: 8,47,73;
    --rb1: #0891b2; --rb2: #0369a1; --rb3: #1e3a8a;
    --rb-in: #a7f3d0; --rb-out: #fecdd3; --rb-link: #bae6fd; --rb-fill: #e0f7ff;
    --nav-mark: #7dd3fc;
    --fab1: #e0f7ff; --fab2: #9fdcf5; --fab-ink: #0c4a6e;
    --ph1: #d3f0fb; --ph2: #e7f4fb;
    --av1: #0ea5e9; --av2: #0c4a6e;
}
html[data-theme="dark"][data-palette="ocean"] {
    --ink: #e6eef3; --ink-soft: #c9d7e0; --muted: #8a9dab; --muted-2: #667985;
    --line: #1f2e38; --line-soft: #17232b; --surface: #111a21; --paper: #0a1016;
    --brand: #0f4a6b; --brand-deep: #0a2a3d; --brand-fg: #5cc8f0;
    --gold: #5cc8f0; --gold-lift: #8adbf7; --gold-wash: #0f2533;
    --sh: none; --sh-lg: 0 14px 34px -10px rgba(0,0,0,.6); --sh-card: none;
    --rb1: #0b6f86; --rb2: #0a4f7a; --rb3: #152a66;
    --fab1: #8adbf7; --fab2: #38bdf8; --fab-ink: #04202e;
    --ph1: #0f3346; --ph2: #11222c;
}

/* ---------- غروب — نارنجی به تمشکی ---------- */
html[data-palette="sunset"] {
    --ink: #2a1a17; --ink-soft: #3d2723; --muted: #7c6660; --muted-2: #ad9993;
    --line: #f0e4df; --line-soft: #f8f1ee; --surface: #ffffff; --paper: #fbf6f3;
    --brand: #9d2449; --brand-deep: #6b1532; --brand-fg: #9d2449;
    --gold: #c2410c; --gold-lift: #ea580c; --gold-wash: #fdeee4;
    --sh: 0 1px 2px rgba(90,30,20,.04); --sh-lg: 0 14px 34px -10px rgba(90,30,20,.28);
    --sh-card: 0 1px 2px rgba(90,30,20,.04), 0 4px 14px -8px rgba(90,30,20,.10);
    --tint: 110,30,40;
    --rb1: #f97316; --rb2: #e2445c; --rb3: #9d174d;
    --rb-in: #d1fae5; --rb-out: #ffe4e6; --rb-link: #ffe4d6; --rb-fill: #fff1e6;
    --nav-mark: #ffc8a8;
    --fab1: #fff1e6; --fab2: #ffc9a8; --fab-ink: #9d2449;
    --ph1: #ffe1d2; --ph2: #fbe6ee;
    --av1: #f97316; --av2: #9d174d;
}
html[data-theme="dark"][data-palette="sunset"] {
    --ink: #f5ebe7; --ink-soft: #e0d0ca; --muted: #a8938c; --muted-2: #7f6c66;
    --line: #33241f; --line-soft: #281c18; --surface: #1c1412; --paper: #120c0b;
    --brand: #6e1d38; --brand-deep: #3d0f1f; --brand-fg: #ff9e7a;
    --gold: #ff9e7a; --gold-lift: #ffbd9f; --gold-wash: #33201a;
    --sh: none; --sh-lg: 0 14px 34px -10px rgba(0,0,0,.6); --sh-card: none;
    --rb1: #b4520f; --rb2: #a8304a; --rb3: #5e0f33;
    --fab1: #ffbd9f; --fab2: #ff8a65; --fab-ink: #3a0d05;
    --ph1: #4a1f18; --ph2: #2a1618;
}

/* ---------- شب — زغالی با طلایی ---------- */
html[data-palette="graphite"] {
    --ink: #16181d; --ink-soft: #2b2f36; --muted: #6b7079; --muted-2: #9da1a8;
    --line: #e5e6e9; --line-soft: #f1f2f4; --surface: #ffffff; --paper: #f5f5f6;
    --brand: #1c1f25; --brand-deep: #0e1013; --brand-fg: #1c1f25;
    --gold: #a16207; --gold-lift: #ca8a04; --gold-wash: #fbf3e2;
    --sh: 0 1px 2px rgba(20,22,26,.05); --sh-lg: 0 14px 34px -10px rgba(20,22,26,.3);
    --sh-card: 0 1px 2px rgba(20,22,26,.05), 0 4px 14px -8px rgba(20,22,26,.12);
    --tint: 20,22,26;
    --rb1: #3a3f4a; --rb2: #22262d; --rb3: #0e1013;
    --rb-in: #b7f4d2; --rb-out: #ffc0c2; --rb-link: #f6d58c; --rb-fill: #f6d58c;
    --nav-mark: #f0c05a;
    --fab1: #fbeecb; --fab2: #f0c05a; --fab-ink: #1c1f25;
    --ph1: #ececee; --ph2: #f4f4f5;
    --av1: #4a4f5a; --av2: #1c1f25;
}
html[data-theme="dark"][data-palette="graphite"] {
    --ink: #eceef1; --ink-soft: #d0d3d8; --muted: #8f949c; --muted-2: #6a6f77;
    --line: #282b31; --line-soft: #1e2025; --surface: #16181c; --paper: #0c0d0f;
    --brand: #22252b; --brand-deep: #121417; --brand-fg: #f0c05a;
    --gold: #f0c05a; --gold-lift: #f6d58c; --gold-wash: #2a2414;
    --sh: none; --sh-lg: 0 14px 34px -10px rgba(0,0,0,.6); --sh-card: none;
    --rb1: #2f333b; --rb2: #1c1f24; --rb3: #0a0b0d;
    --fab1: #f6d58c; --fab2: #f0c05a; --fab-ink: #1c1f25;
    --ph1: #2a2c31; --ph2: #1c1d21;
}

/* ---------- یاس — ارغوانی به بنفشِ عمیق ---------- */
html[data-palette="lilac"] {
    --ink: #221630; --ink-soft: #35264a; --muted: #72658a; --muted-2: #a598b8;
    --line: #ebe4f3; --line-soft: #f5f1fa; --surface: #ffffff; --paper: #f8f5fc;
    --brand: #5b2196; --brand-deep: #3b1466; --brand-fg: #5b2196;
    --gold: #8b2fd8; --gold-lift: #a855f7; --gold-wash: #f3eafd;
    --sh: 0 1px 2px rgba(59,20,102,.04); --sh-lg: 0 14px 34px -10px rgba(59,20,102,.28);
    --sh-card: 0 1px 2px rgba(59,20,102,.04), 0 4px 14px -8px rgba(59,20,102,.10);
    --tint: 70,24,120;
    --rb1: #d946ef; --rb2: #9333ea; --rb3: #4c1d95;
    --rb-in: #bbf7d0; --rb-out: #ffe4e6; --rb-link: #f5d0fe; --rb-fill: #fae8ff;
    --nav-mark: #e9b5ff;
    --fab1: #fbeaff; --fab2: #e4c2ff; --fab-ink: #5b2196;
    --ph1: #fbe0f6; --ph2: #efe4fd;
    --av1: #c026d3; --av2: #5b2196;
}
html[data-theme="dark"][data-palette="lilac"] {
    --ink: #f1eaf8; --ink-soft: #dacfe8; --muted: #9d90b3; --muted-2: #74688a;
    --line: #2d2340; --line-soft: #231b32; --surface: #1a1424; --paper: #100c17;
    --brand: #4a1d7a; --brand-deep: #2a0f47; --brand-fg: #d8a8ff;
    --gold: #d8a8ff; --gold-lift: #e9c9ff; --gold-wash: #2a1c3d;
    --sh: none; --sh-lg: 0 14px 34px -10px rgba(0,0,0,.6); --sh-card: none;
    --rb1: #a21caf; --rb2: #6d28d9; --rb3: #3b0d6e;
    --fab1: #e9c9ff; --fab2: #c084fc; --fab-ink: #22093d;
    --ph1: #3d1a45; --ph2: #26193d;
}

/* ---------- انتخابگرِ پالت در پروفایل ----------
   هر نمونه طیفِ **روزِ** همان پالت را نشان می‌دهد، مستقل از پالتِ فعلی
   و از حالت شب — نمونه‌ای که با پالتِ جاری عوض شود، دیگر نمونه نیست. */
.palette-title { margin-top: 18px; font-size: 13px; font-weight: 700; color: var(--ink-soft); }
.palette-picker {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(96px, 100%), 1fr));
    gap: 10px;
    margin-top: 10px;
}
.palette-opt { position: relative; cursor: pointer; display: block; }
.palette-opt input { position: absolute; opacity: 0; pointer-events: none; }
.palette-swatch {
    display: block;
    height: 58px;
    border-radius: 14px;
    border: 2px solid transparent;
    box-shadow: 0 6px 14px -8px rgba(0,0,0,.45), inset 0 0 0 1px rgba(255,255,255,.12);
    position: relative; overflow: hidden;
    transition: transform .15s ease, border-color .15s ease;
}
.palette-swatch::after {   /* همان حلقه‌ی محوِ گوشه‌ی کارتِ ماه */
    content: ''; position: absolute; top: -18px; left: -18px;
    width: 64px; height: 64px; border-radius: 50%;
    background: rgba(255,255,255,.12);
}
.palette-opt:active .palette-swatch { transform: scale(.96); }
.palette-opt input:checked + .palette-swatch {
    border-color: var(--surface);
    box-shadow: 0 0 0 2px var(--gold), 0 8px 18px -8px rgba(0,0,0,.5);
}
.palette-opt input:focus-visible + .palette-swatch { outline: 2px solid var(--gold); outline-offset: 3px; }
.palette-check {
    position: absolute; bottom: 7px; right: 7px;
    width: 20px; height: 20px; border-radius: 50%;
    background: #fff; color: #111;
    display: none; align-items: center; justify-content: center;
    z-index: 1;
}
.palette-opt input:checked + .palette-swatch .palette-check { display: flex; }
.palette-name {
    display: block; text-align: center;
    margin-top: 6px;
    font-size: 12px; font-weight: 700; color: var(--ink-soft);
    white-space: nowrap;
}
.palette-swatch[data-pal="emerald"]  { background: linear-gradient(135deg, #0f7550, #0b5d41 50%, #073f2c); }
.palette-swatch[data-pal="indigo"]   { background: linear-gradient(135deg, #3b2f8f, #4a3fb5 45%, #2f2a6b); }
.palette-swatch[data-pal="ocean"]    { background: linear-gradient(135deg, #0891b2, #0369a1 50%, #1e3a8a); }
.palette-swatch[data-pal="sunset"]   { background: linear-gradient(135deg, #f97316, #e2445c 50%, #9d174d); }
.palette-swatch[data-pal="lilac"]    { background: linear-gradient(135deg, #d946ef, #9333ea 50%, #4c1d95); }
.palette-swatch[data-pal="graphite"] { background: linear-gradient(135deg, #3a3f4a, #22262d 50%, #0e1013); }

/* ---------- اعلان روی گوشی (پروفایل) ---------- */
.push-state { margin: 0 0 12px; font-size: 13px; line-height: 1.8; color: var(--ink-soft); }
.push-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 4px; }
.push-actions:empty { display: none; }

/* ---------- صفحه‌ی خانه: روشن/خاموشِ قلم‌ها (پروفایل) ----------
   فهرستِ گروه‌بندی‌شده مثلِ تنظیماتِ گوشی: متن سمتِ راست، کلید سمتِ
   چپ. ⚠ `order: -1` روی متن است نه جابه‌جا کردنِ HTML: قاعده‌ی
   `.switch input:checked + .switch-track` می‌خواهد ترک **درست بعد از**
   input باشد، وگرنه کلید روشن‌شده رنگ نمی‌گرفت — بی‌هیچ خطایی. */
.hw-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.hw-count {
    flex: none; font-size: 12px; font-weight: 700;
    color: var(--muted); background: var(--line-soft);
    padding: 3px 10px; border-radius: 999px; white-space: nowrap;
}
.hw-group-title {
    margin: 16px 2px 7px; font-size: 12px; font-weight: 700;
    color: var(--muted); letter-spacing: .2px;
}
.hw-list {
    border: 1px solid var(--line);
    border-radius: 14px;
    overflow: hidden;
}
.hw-row { padding: 11px 14px; gap: 12px; margin: 0; }
.hw-row + .hw-row { border-top: 1px solid var(--line-soft); }
.hw-row .switch-text { order: -1; display: flex; flex-direction: column; gap: 2px; }
.hw-row .switch-track { order: 0; }
.hw-label { font-size: 13.5px; font-weight: 700; color: var(--ink); }
.hw-hint  { font-size: 11.5px; color: var(--muted); line-height: 1.6; }
.hw-row:active { background: var(--line-soft); }
.hw-foot { margin-top: 12px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.hw-foot .form-message { align-self: stretch; margin: 0; }

/* ---------- پیامکِ بانکی برای بررسی (خانه) ----------
   ⚠ کارت است نه مودال: هیچ چیزی را نمی‌پوشاند و کاربر هر وقت خواست
   تکلیفش را روشن می‌کند. زمینه ندارد (درسِ `.start-card`): حالتِ شبِ
   `.card` با وزنِ بیشتر بازنویسی می‌کند، پس مرز از `--line` می‌آید. */
.sms-review {
    margin-bottom: 14px; padding: 12px 14px;
    border: 1px solid var(--line); border-inline-start: 3px solid var(--brand-fg);
    border-radius: var(--r-sm);
}
.sms-review-head { font-size: 12.5px; color: var(--muted); }
.sms-review-body { font-size: 14px; font-weight: 700; margin: 4px 0 10px; }
.sms-review-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sms-review-actions .undo-bar-close { margin-inline-start: auto; color: var(--muted); }

/* ---------- نمای دسکتاپِ خانه: داشبوردِ کلی ----------
   **خواسته‌ی مالکِ نصب:** «در دسکتاپ فضا اصلاً متناسب نیست… وقتی اپ
   باز میشه در دسکتاپ باید داشبورد با مانده حساب‌ها و دارایی و کلیات
   باز بشه.» روی ۱۴۴۰ پیکسل ستونِ ۷۲۰پیکسلی ۴۷۰ پیکسل (۴۰٪) خالی
   می‌گذاشت.

   ⛔ همه‌ی این بلوک‌ها فقط وقتی در HTML هستند که `deskView()` درست باشد،
      و همین‌جا هم پشتِ همان `DESK_MIN_PX` (۱۱۰۰) پنهان‌اند. پس نمای
      گوشی — و پنجره‌ی کوچکِ دسکتاپ — همان قبلی است.
   ⚠ `.desk-card` عمداً زمینه‌ی خودش را ندارد و از `.card` می‌گیرد، تا
     قاعده‌ی حالتِ شبِ `.card` برنده بماند (درسِ `.start-card`). */
.desk-only { display: none; }

@media (min-width: 1100px) {
    .page-content.is-desk { max-width: 1240px; }
    .desk-only { display: block; }

    .desk-kpis.desk-only {
        display: grid;
        /* هر تعداد کاشی (۳ یا ۴ — «خالص دارایی» و «پول قابل خرج» شرطی‌اند)
           هم‌عرض در یک ردیف. */
        grid-auto-flow: column;
        grid-auto-columns: minmax(0, 1fr);
        gap: 14px;
        margin-bottom: 16px;
    }
    /* ⚠ `min-width: 0` روی ستون‌ها: آیتمِ گرید پیش‌فرض `min-width: auto`
       دارد و نامِ بلندِ یک حساب کلِ ستون را پهن می‌کرد (درسِ منوی کناری). */
    .home-desk {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 380px);
        gap: 18px;
        align-items: start;
    }
    .home-main, .home-side { min-width: 0; }
    .home-side .card { margin-bottom: 14px; }

    /* ⛔ ادامه‌ی خانه = داشبورد (`includes/dash_parts.php`). کارتِ سالانه
       تمام‌عرض؛ زیرش روند (پهن) و دسته‌بندی/مقایسه (باریک) کنارِ هم. */
    .home-desk-more.desk-only { margin-top: 4px; }
    .desk-more-grid {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 380px);
        gap: 18px;
        align-items: start;
    }
    .desk-more-main, .desk-more-side { min-width: 0; }
}

.desk-kpi {
    display: flex; flex-direction: column; gap: 6px;
    padding: 16px 18px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg, 16px);
    box-shadow: var(--sh-card, none);
    color: var(--ink);
    text-decoration: none;
    min-width: 0;
    transition: border-color .15s ease, transform .15s ease;
}
.desk-kpi:hover { border-color: var(--brand-fg); transform: translateY(-1px); }
.desk-kpi.is-warn { border-color: var(--warn-ink); }
.desk-kpi-label { font-size: 12.5px; color: var(--muted); font-weight: 600; }
.desk-kpi-label small { font-weight: 400; }
.desk-kpi-value {
    font-size: 22px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    /* ⛔ عدد چپ‌چین (قاعده‌ی «متنِ فارسی راست‌چین، عدد چپ‌چین»): در ستونِ
       فلکسِ راست‌به‌چپ، `flex-end` یعنی لبه‌ی **چپ** — و `ltr` واحد را
       همان سمتی می‌نشاند که روی کارتِ ماه است. `test_number_align` گرفتش. */
    align-self: flex-end; max-width: 100%; direction: ltr;
}
.desk-kpi-value small { font-size: 12px; font-weight: 500; color: var(--muted); }
.desk-kpi-sub { font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.desk-kpi.is-warn .desk-kpi-sub { color: var(--warn-ink); }

.desk-list { display: flex; flex-direction: column; }
.desk-row {
    display: flex; align-items: center; gap: 10px;
    padding: 9px 2px;
    border-bottom: 1px solid var(--line);
    color: var(--ink); text-decoration: none;
    min-width: 0;
}
.desk-list > :last-child { border-bottom: 0; }
a.desk-row:hover .desk-row-name { color: var(--brand-fg); }
.desk-row-mark {
    flex: 0 0 auto; width: 28px; height: 28px; border-radius: 50%;
    background: var(--wc, var(--line));
    display: inline-flex; align-items: center; justify-content: center;
}
/* ⛔ لوگو همیشه روی پایه‌ی سفید — همان قاعده‌ی `.bank-logo`. */
.desk-row-mark img { background: #fff; border-radius: 50%; padding: 2px; box-sizing: content-box; }
.desk-row-name {
    flex: 1 1 auto; min-width: 0;
    font-size: 13.5px; font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.desk-row-name small { display: block; font-size: 11.5px; font-weight: 400; color: var(--muted); }
.desk-row-amount { flex: 0 0 auto; font-size: 13.5px; font-weight: 700; white-space: nowrap; }
.desk-row-amount.is-neg, .desk-kpi-value .is-neg, .desk-row-amount.is-out { color: var(--out); }
.desk-row-amount.is-in { color: var(--in); }
.desk-due-date { flex: 0 0 auto; font-size: 11.5px; color: var(--muted); min-width: 64px; }
.desk-due-date.is-past { color: var(--warn-ink); font-weight: 700; }

.desk-comp { padding: 8px 2px; border-bottom: 1px solid var(--line); }
.desk-comp-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; min-width: 0; }
.desk-comp .cat-breakdown-bar-track { margin: 0; }

/* ============================================================
   ۴۲ — Ramp × Mercury × Linear
   ============================================================
   **خواسته‌ی مالکِ نصب:** «از این فورمول برای ساختِ ظاهر: Ramp × Mercury ×
   Linear.» سه اصل، از هر کدام یکی:
   - **Linear — پایه:** بومِ خنثی، پنلِ سفید، **خطِ مو به‌جای سایه**، منوی
     کناریِ روشن و بی‌رنگ با قلمِ فعالِ «کارت‌مانند»، تایپِ ریز و دقیق.
   - **Mercury — عدد:** عددِ پولیِ قهرمان درشت و آرام (وزنِ ۶۰۰، فشرده)،
     برچسب کوچک و خاکستری؛ رنگ فقط روی کارتِ ماه.
   - **Ramp — ابزار:** دکمه و فیلدِ ۸ پیکسلیِ تخت، فهرستِ ردیف‌به‌ردیف با
     جداکننده‌ی مو، و رنگ **فقط برای معنا** (درآمد/هزینه/هشدار).

   ⛔ پایه‌ی خنثی (`--paper/--surface/--line/--ink/--muted`) برای **هر شش
      پالت یکی است** و بعد از بخشِ ۴۱ می‌نشیند؛ پالت فقط لهجه را رنگ
      می‌کند: `--brand`/`--brand-fg`، کارتِ ماه (`--rb*`)، دکمه‌ی +
      (`--fab*`)، نشانگرِ نوارِ پایین. پس سه جای «رنگِ برند» (مانیفست،
      `theme-color`، APK — قاعده ۵۷) و طیفِ کارتِ ماه (`test_palette`)
      دست نخوردند.
   ⚠ وزن‌ها عمدی‌اند: روز `html:not([data-theme="dark"])` (۰،۱،۱) بعد از
     `html[data-palette]` (۰،۱،۱) است، پس با ترتیب می‌برد؛ شب
     `html[data-theme="dark"][data-theme]` (۰،۲،۱) — ویژگیِ تکراری فقط
     برای رسیدن به وزنِ `html[data-theme="dark"][data-palette="x"]`.
   ============================================================ */
html:not([data-theme="dark"]) {
    --paper: #f6f7f9; --surface: #ffffff; --line: #e6e8ec; --line-soft: #f1f2f5;
    --ink: #0f1115; --ink-soft: #2b2f38; --muted: #697080; --muted-2: #9aa0ab;
    --rml-hover: rgba(15,17,21,.045); --rml-ring: rgba(15,17,21,.06);
}
html[data-theme="dark"][data-theme] {
    --paper: #0b0c0e; --surface: #131418; --line: #24262c; --line-soft: #1a1b20;
    --ink: #eceef1; --ink-soft: #c8ccd3; --muted: #8e939d; --muted-2: #646a75;
    --rml-hover: rgba(255,255,255,.045); --rml-ring: rgba(0,0,0,.4);
}

/* ---------- سطح: خطِ مو، بی‌سایه، ۱۲ پیکسل ---------- */
.card, .stats-card, .summary-box, .desk-kpi {
    border: 1px solid var(--line); box-shadow: none; border-radius: 12px;
}
.card-title { font-size: 13.5px; font-weight: 600; letter-spacing: -.1px; margin-bottom: 12px; }
.desk-kpi:hover { transform: none; border-color: var(--muted-2); }

/* ---------- سرآیند: شیشه‌ای، عنوانِ ریز ---------- */
.topbar {
    background: color-mix(in srgb, var(--surface) 88%, transparent);
    -webkit-backdrop-filter: saturate(1.4) blur(14px); backdrop-filter: saturate(1.4) blur(14px);
    border-bottom: 1px solid var(--line);
}
.page-title { font-size: 15px; font-weight: 600; letter-spacing: -.2px; }

/* ---------- منوی کناری: طیفِ همان پالت ----------
   ⛔ رنگ از `--rb1..3` می‌آید — همان سه رنگی که کارتِ ماه را می‌سازند —
   پس با عوض شدنِ پالت، منو هم عوض می‌شود و هیچ پالتی قاعده‌ی جدا ندارد.
   پایه `--rb2 (۵۵٪) → --rb3` زیرِ یک پرده‌ی تیره‌ی ۱۰٪ است و `--rb1` فقط
   یک درخششِ نرم پشتِ نامِ برنامه: `--rb1` در «غروب» نارنجیِ روشن است و
   متنِ سفید رویش خوانده نمی‌شد. با این اعداد تضادِ متنِ منو (سفیدِ ۸۴٪)
   در بدترین پالت («غروب»ِ روز) ۴٫۹ است — `test_palette` می‌سنجدش.
   ⚠ بخشِ ۴۲ توکن تعریف نمی‌کند (قاعده ۵۸)، فقط مصرف می‌کند. */
.sidebar,
html[data-theme="dark"] .sidebar {
    background:
        radial-gradient(120% 34% at 100% 0%, color-mix(in srgb, var(--rb1) 55%, transparent) 0%, transparent 70%),
        linear-gradient(180deg, rgba(0,0,0,.1) 0%, rgba(0,0,0,.1) 45%, rgba(0,0,0,.26) 100%),
        linear-gradient(172deg, color-mix(in srgb, var(--rb2) 55%, var(--rb3)) 0%, var(--rb3) 100%);
    color: #fff; border-inline-end: 0; padding: 14px 10px;
    box-shadow: inset 1px 0 0 rgba(255,255,255,.06);
}
.sidebar-brand { color: #fff; font-size: 14.5px; padding: 2px 8px 14px; }
.sidebar-nav a, .logout-link {
    color: rgba(255,255,255,.84); font-size: 13.5px; font-weight: 500;
    padding: 7px 10px; border-radius: 8px; gap: 10px;
}
.sidebar-nav a svg, .logout-link svg { width: 17px; height: 17px; }
.sidebar-nav a:hover, .logout-link:hover { background: rgba(255,255,255,.09); color: #fff; }
.sidebar-nav a.active,
html[data-theme="dark"] .sidebar-nav a.active {
    background: rgba(255,255,255,.17); color: #fff; font-weight: 600;
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.2), 0 6px 14px -8px rgba(0,0,0,.45);
}
.sidebar-nav .sidebar-action,
.sidebar-nav .sidebar-action:hover {
    background: rgba(255,255,255,.96); color: var(--rb3); filter: none; font-weight: 600;
    box-shadow: 0 8px 18px -10px rgba(0,0,0,.55);
    padding: 8px 10px; margin-bottom: 12px; font-size: 13.5px;
}
.sidebar-nav .sidebar-action:hover { background: #fff; box-shadow: 0 10px 22px -10px rgba(0,0,0,.6); }
.sidebar-nav .sidebar-action svg { color: var(--rb2); }
.nav-divider { color: rgba(255,255,255,.52); font-size: 11px; font-weight: 600; padding: 14px 10px 4px; letter-spacing: 0; }
.sidebar .lock-badge { opacity: .7; }
.sidebar .nav-badge { box-shadow: 0 0 0 2px rgba(255,255,255,.18); }
.sidebar-footer { border-top-color: rgba(255,255,255,.14); }
.sidebar-nav::-webkit-scrollbar-thumb, .sidebar-nav:hover::-webkit-scrollbar-thumb { background: rgba(255,255,255,.22); }
.sidebar-nav { scrollbar-color: rgba(255,255,255,.22) transparent; }

/* ---------- عدد: Mercury ---------- */
.ltr-num:not(.bank-card-number):not(.pay-number) { letter-spacing: -.2px; }
.bv-num { font-size: 38px; font-weight: 600; letter-spacing: -1.2px; font-variant-numeric: proportional-nums; }
.desk-kpi-value, .desk-kpi-value .ltr-num { font-size: 24px; font-weight: 600; letter-spacing: -.8px; font-variant-numeric: proportional-nums; }
.desk-kpi-label { font-size: 12.5px; font-weight: 500; color: var(--muted); }

/* ---------- ابزار: Ramp ---------- */
.btn { border-radius: 8px; font-weight: 600; }
.btn-secondary { background: var(--surface); border: 1px solid var(--line); color: var(--ink); }
.btn-secondary:hover { border-color: var(--muted-2); }
input[type="text"], input[type="password"], input[type="email"], input[type="number"], input[type="date"],
input[type="tel"], input[type="search"], select, textarea {
    border-radius: 8px; border-color: var(--line); background: var(--surface);
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
    border-color: var(--brand-fg); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-fg) 16%, transparent); outline: none;
}
/* فهرستِ تراکنش: آیکونِ گوشه‌گردِ کوچک‌تر، جداکننده‌ی مو */
.cat-icon { width: 34px; height: 34px; border-radius: 9px; }
.cat-icon svg { width: 17px; height: 17px; }

/* ---------- کارتِ سالانه: فصل یک نشانه است، نه یک رنگِ تمام‌کارت ---------- */
.season-card { background: var(--surface); border: 1px solid var(--line); border-inline-start: 1px solid var(--line); }
.season-card .season-name::before {
    content: ''; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
    background: var(--season-c); margin-inline-end: 7px; vertical-align: middle;
}
.season-card .season-name { color: var(--ink); }
.season-card.is-current { box-shadow: none; border-color: var(--season-c); }

/* ============================================================
   ۴۳. درگاهِ «حسابداری فروشگاه» — فقط حسابِ «شخصی + فروشگاه»
   (`Biz::personalGateway()`). ⛔ هیچ توکنِ رنگی تعریف نمی‌شود و هیچ کلاسِ
   `st-` نیست (قاعده ۷۰/۵۸): لهجه همان پالتِ حساب لند است و فقط لوگوی
   فروشگاه رنگِ خودش را دارد — تا معلوم باشد به محصولِ دیگری می‌رود.
   ============================================================ */
.store-gate-ico { border-radius: 6px; flex-shrink: 0; display: block; }
.sidebar-footer .store-gate-nav { margin-bottom: 2px; }
.store-gate-tool { flex-direction: row; align-items: center; justify-content: flex-start; min-height: 0; }
.store-gate-tool .store-gate-ico { border-radius: 8px; }

/* ============================================================
   ۴۴. نرخِ ارز، طلا و سکه (`includes/rates.php`)
   — صفحه‌ی مدیر (`admin/rates.php`) و نشانِ نرخ کنارِ نوعِ دارایی.
   ============================================================ */
.alert-warning { background: var(--warn-wash); color: var(--warn-ink); }
.rates-list { display: flex; flex-direction: column; }
.rates-row {
    display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1.4fr) minmax(0, 1.5fr);
    gap: 12px; align-items: center; padding: 11px 0; border-top: 1px solid var(--line-soft);
}
.rates-row:first-child { border-top: 0; }
.rates-name b { display: block; font-size: 14px; }
.rates-name small, .rates-val small { display: block; font-size: 11.5px; color: var(--muted); }
.rates-price { font-size: 15px; font-weight: 800; }
.rates-chg { font-size: 11.5px; font-weight: 700; margin-inline-start: 6px; }
.rates-chg.is-up { color: var(--in); }
.rates-chg.is-down { color: var(--out); }
.rates-row.is-stale .rates-price { color: var(--muted); }
.rates-old { color: var(--warn-ink); }
.rates-edit { display: flex; gap: 6px; align-items: center; justify-content: flex-end; flex-wrap: wrap; }
.rates-edit input { width: 150px; min-width: 0; }
.rate-src { border: 1px solid var(--line); border-radius: var(--r); padding: 14px; margin-bottom: 12px; }
.rate-src-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.rate-src-state { display: inline-flex; align-items: center; gap: 8px; }
.rate-src-state small { color: var(--muted); font-size: 11.5px; }
.rate-src-err { margin: 8px 0 0; color: var(--out); }
.rate-src-grid { display: grid; grid-template-columns: 90px minmax(0, 1fr) minmax(0, 1.4fr); gap: 10px; margin-top: 12px; }
.rate-src-grid .form-group { margin-bottom: 0; display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; }
.rate-src-grid .form-group small { color: var(--muted); font-weight: 400; }
.rate-src-clear { font-size: 11.5px; color: var(--muted); display: inline-flex; gap: 5px; align-items: center; }
.rate-src-foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.rate-src-rial { font-size: 12.5px; color: var(--ink-soft); display: inline-flex; gap: 6px; align-items: center; }
.rate-paths-box { margin-top: 10px; }
.rate-paths-box > summary { cursor: pointer; font-size: 13px; font-weight: 700; }
.rate-paths { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 8px; }
.rate-paths label { display: flex; flex-direction: column; gap: 3px; font-size: 12px; color: var(--ink-soft); }
@media (max-width: 760px) {
    .rates-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .rates-edit { grid-column: 1 / -1; justify-content: flex-start; }
    .rates-edit input { flex: 1; width: auto; }
    .rate-src-grid { grid-template-columns: minmax(0, 1fr); }
}

/* نوعِ داراییِ وصل به نرخِ خودکار */
.ref-rate-tag {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: 10.5px; font-weight: 700; padding: 1px 7px; border-radius: var(--r-pill);
    background: var(--in-wash); color: var(--in); margin-inline-start: 4px;
}
.asset-rate-hint { margin-top: 6px; }
/* ⚠ قاعده ۱۸: خانه‌ی دستیِ نرخ با `hidden` کنار می‌رود (نرخِ خودکار). */
.form-group[hidden], .hint[hidden] { display: none; }

/* ارزش به نرخِ روز (`my-assets.php`) */
.asset-rate-list { display: flex; flex-direction: column; }
.asset-rate-row {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 12px;
    align-items: center; padding: 12px 0; border-top: 1px solid var(--line-soft);
}
.asset-rate-row:first-child { border-top: 0; padding-top: 2px; }
.asset-rate-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.asset-rate-main b { font-size: 14.5px; }
.asset-rate-main small { font-size: 12px; color: var(--muted); }
.asset-rate-src { color: var(--in) !important; }
.asset-rate-src.is-stale { color: var(--warn-ink) !important; }
.asset-rate-value { font-size: 15.5px; font-weight: 800; white-space: nowrap; }
.asset-rate-pick { grid-column: 1 / -1; }
.asset-rate-pick select { width: 100%; font-size: 12.5px; padding: 7px 10px; }
@media (min-width: 760px) {
    .asset-rate-row { grid-template-columns: minmax(0, 1fr) minmax(0, 260px) auto; }
    .asset-rate-pick { grid-column: auto; order: 2; }
    .asset-rate-value { order: 3; }
}
.asset-live-value {
    margin: -4px 0 12px; padding: 9px 12px; border-radius: var(--r-sm);
    background: var(--in-wash); color: var(--in); font-size: 13px; font-weight: 700;
}
.asset-live-value[hidden] { display: none; }

/* ---------- ⛔ نشانِ «سهامِ فروشگاه» — لوگوی SL روی ردیفِ سودِ همگام‌شده ----------
   (`storeShareMarkSvg()`). دایره‌ی تیره‌ی همان اندازه‌ی آیکنِ دسته، با لوگوی سفید؛
   در حالتِ شب حلقه‌ی روشن تا روی زمینه‌ی تیره گم نشود. */
.cat-icon.cat-icon-store {
    background: #141414 !important;
    color: #fff;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14), 0 1px 2px rgba(0, 0, 0, .18);
}
.cat-icon.cat-icon-store svg { opacity: 1; }
.store-mark-chip {
    display: inline-flex; align-items: center; justify-content: center;
    width: 20px; height: 20px; border-radius: 50%;
    background: #141414; color: #fff; vertical-align: middle;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14);
}
.tx-store-src { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.tx-store-tag { font-weight: 600; color: var(--ink); }

/* ⛔ «وصول و پرداخت» در فهرستِ تراکنش (`renderMoneyMoveRow()`): پول جابه‌جا شده
   ولی درآمد/هزینه نیست — آیکنِ خنثی و برچسبِ صریح تا با تراکنش اشتباه نشود. */
.cat-icon-move { --cat-bg: var(--line-soft); background: var(--line-soft); color: var(--muted); }
.tx-move-tag {
    display: inline-block; padding: 0 7px; border-radius: 999px;
    background: var(--line-soft); color: var(--ink); font-size: 11px; font-weight: 600;
}

/* ============================================================
   کارتِ «مانده این ماه»: ماه‌های قبل با کشیدن به بالا
   ⛔ منطق در `setupMonthStack()` (`app.js`)؛ این‌جا فقط نما.
   ============================================================ */
/* ⛔ `pan-x`: کشیدنِ افقی همان اسلایدرِ بومی می‌ماند (کارت‌های حساب)، و کشیدنِ
   عمودی **روی همین کارت** صفحه را اسکرول نمی‌کند و به جاوااسکریپت می‌رسد. بقیه‌ی
   صفحه مثلِ همیشه اسکرول می‌شود. */
.month-stack { touch-action: pan-x; cursor: grab; outline: none; }
.month-stack:focus-visible { box-shadow: 0 0 0 3px rgba(255,255,255,.55); }
.month-stack .ms-past {
    position: absolute;
    inset: 0;
    padding: inherit;
    z-index: 2;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    display: flex;
    flex-direction: column;
}
.month-stack.is-past .ms-past { opacity: 1; visibility: visible; pointer-events: auto; }
/* لایه‌ی ماهِ جاری در زمانِ «ماهِ قبل» دیده نمی‌شود ولی جایش را نگه می‌دارد،
   تا قدِ کارت با عوض شدنِ ماه نپرد. */
.month-stack.is-past > :not(.ms-past):not(.ms-rail):not(.ms-grab) { visibility: hidden; }
.month-stack .ms-ago {
    margin-inline-start: 8px;
    padding: 1px 8px;
    border-radius: 999px;
    background: rgba(255,255,255,.16);
    font-size: 10.5px;
}
.month-stack .ms-past .balance-label { display: flex; align-items: center; }
/* لینکِ تراکنش‌های همان ماه در ردیفِ بالا، نه پایینِ کارت: کارت قدِ ماهِ جاری را
   دارد و هر ردیفِ اضافه در پایین بریده می‌شد (در عکس دیده شد). */
.month-stack .ms-open {
    margin-inline-start: auto;
    padding: 2px 10px;
    border-radius: 999px;
    background: rgba(255,255,255,.14);
    color: #fff;
    font-size: 11px; font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

/* ورود از پایین (ماهِ قدیمی‌تر) یا از بالا (ماهِ تازه‌تر) */
@keyframes ms-from-below { from { transform: translateY(38%); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes ms-from-above { from { transform: translateY(-38%); opacity: 0; } to { transform: none; opacity: 1; } }
.month-stack .ms-anim-up   { animation: ms-from-below .32s cubic-bezier(.2,.8,.2,1) both; }
.month-stack .ms-anim-down { animation: ms-from-above .32s cubic-bezier(.2,.8,.2,1) both; }
@media (prefers-reduced-motion: reduce) {
    .month-stack .ms-anim-up, .month-stack .ms-anim-down { animation-duration: .01s; }
}

/* نشانگرِ ماه‌ها: ستونی از نقطه در لبه‌ی چپ (پایانِ خط در راست‌به‌چپ)؛ بالایی = ماهِ جاری */
.month-stack .ms-rail {
    position: absolute;
    left: 7px; top: 50%;
    transform: translateY(-50%);
    z-index: 3;
    display: flex; flex-direction: column; gap: 4px;
    pointer-events: none;
}
.month-stack .ms-rail i {
    width: 3px; height: 4px; border-radius: 2px;
    background: rgba(255,255,255,.32);
    transition: height .2s, background .2s;
}
.month-stack .ms-rail i.is-on { height: 12px; background: #fff; }

/* دستگیره: تنها نشانه‌ی «این کارت بالا کشیده می‌شود» */
.month-stack .ms-grab {
    position: absolute;
    bottom: 6px; left: 50%;
    width: 34px; height: 4px; margin-left: -17px;
    border-radius: 2px;
    background: rgba(255,255,255,.28);
    z-index: 3;
    pointer-events: none;
}
.month-stack.is-empty .ms-grab, .month-stack.is-empty .ms-rail { display: none; }
