/* مستر تتر — پوسته‌ی راست‌به‌چپ. بدون CDN، همه‌چیز محلی. */

@font-face {
  font-family: "Vazirmatn";
  src: url("/static/fonts/Vazirmatn-Regular.woff2") format("woff2");
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: "Vazirmatn";
  src: url("/static/fonts/Vazirmatn-Medium.woff2") format("woff2");
  font-weight: 500; font-display: swap;
}
@font-face {
  font-family: "Vazirmatn";
  src: url("/static/fonts/Vazirmatn-Bold.woff2") format("woff2");
  font-weight: 700; font-display: swap;
}

:root {
  /* روشن، ولی نه سفیدِ خیره‌کننده. یک طوسیِ ملایم که چشم را در ساعت‌های
     طولانیِ کار با عدد اذیت نکند؛ کارت‌ها کمی روشن‌تر از زمینه تا لبه‌ها
     بدون خط هم دیده شوند. */
  --bg:        #e8eaee;
  --surface:   #f4f5f7;
  --surface-2: #dfe2e7;
  --border:    #cfd4db;
  --text:      #1a1f27;
  --muted:     #5d6673;
  --faint:     #8b939f;
  --accent:    #0f7b6c;
  --accent-2:  #0a5f53;
  --accent-bg: #d9ebe7;
  --pos:       #0d6b37;
  --pos-bg:    #dcecE1;
  --neg:       #a81f26;
  --neg-bg:    #f4dedf;
  --warn:      #7d5100;
  --warn-bg:   #f2e6cd;
  --radius:    12px;
  --shadow:    0 1px 2px rgba(16,22,28,.06), 0 4px 14px rgba(16,22,28,.05);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:        #0e1116;
    --surface:   #161b22;
    --surface-2: #1c2330;
    --border:    #262e3a;
    --text:      #e7ecf2;
    --muted:     #93a0b0;
    --faint:     #6a7788;
    --accent:    #3fbfa9;
    --accent-2:  #7bd8c6;
    --accent-bg: #12312c;
    --pos:       #4ec97e;
    --pos-bg:    #12301f;
    --neg:       #f0757c;
    --neg-bg:    #341a1c;
    --warn:      #e0b155;
    --warn-bg:   #33280f;
    --shadow:    0 1px 2px rgba(0,0,0,.4), 0 4px 16px rgba(0,0,0,.25);
  }
}

* { box-sizing: border-box; }

html { font-size: 15px; }

body {
  margin: 0;
  font-family: "Vazirmatn", "Segoe UI", Tahoma, "Iranian Sans", sans-serif;
  background: var(--bg);
  color: var(--text);
  direction: rtl;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ─── چیدمان ─── */

.shell { display: flex; min-height: 100vh; }

.sidebar {
  width: 232px; flex: 0 0 232px;
  background: var(--surface);
  border-inline-start: 1px solid var(--border);
  padding: 20px 14px;
  display: flex; flex-direction: column; gap: 4px;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}

/* نشان، و در عینِ حال درِ صفحه‌ی معرفی. رنگ و بی‌خط‌بودنش صریح است تا
   با پیوند اشتباه گرفته نشود؛ فقط زیرِ نشانگر کمی روشن می‌شود. */
.logo {
  font-weight: 700; font-size: 1.18rem; color: var(--text);
  padding: 6px 10px 18px; display: flex; align-items: center; gap: 9px;
}
a.logo:hover { text-decoration: none; color: var(--accent); }
.logo .dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 4px var(--accent-bg);
}

.navlink {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: 9px;
  color: var(--muted); font-weight: 500; font-size: .94rem;
}
.navlink:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.navlink.active { background: var(--accent-bg); color: var(--accent-2); }
.navlink svg { width: 17px; height: 17px; flex: 0 0 17px; }

.sidebar-foot { margin-top: auto; padding-top: 14px; border-top: 1px solid var(--border); }

.main { flex: 1; min-width: 0; padding: 22px 26px 56px; }

.page-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 18px;
}
.page-head h1 { font-size: 1.4rem; margin: 0; font-weight: 700; letter-spacing: -.01em; }
.page-head .sub { color: var(--muted); font-size: .88rem; }

/* ─── کارت‌ها ─── */

.grid { display: grid; gap: 14px; }
.grid.k4 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.grid.k3 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid.k2 { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }

.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px 18px; box-shadow: var(--shadow);
}
.card h2 {
  font-size: .82rem; text-transform: none; color: var(--muted);
  margin: 0 0 12px; font-weight: 500; letter-spacing: .01em;
}
.card.tight { padding: 14px 16px; }

.stat .label { color: var(--muted); font-size: .82rem; margin-bottom: 6px; }
.stat .value { font-size: 1.62rem; font-weight: 700; letter-spacing: -.02em; line-height: 1.2; }
.stat .unit  { font-size: .78rem; color: var(--faint); font-weight: 400; margin-inline-start: 4px; }
.stat .foot  { font-size: .8rem; color: var(--muted); margin-top: 6px; }

.pos { color: var(--pos); }
.neg { color: var(--neg); }
.dim { color: var(--muted); }

.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: 999px;
  font-size: .76rem; font-weight: 500; white-space: nowrap;
}
.pill.buy  { background: var(--pos-bg); color: var(--pos); }
.pill.sell { background: var(--neg-bg); color: var(--neg); }
.pill.recv { background: var(--accent-bg); color: var(--accent-2); }
.pill.pay  { background: var(--warn-bg); color: var(--warn); }
.pill.void { background: var(--surface-2); color: var(--faint); }
.pill.due  { background: var(--warn-bg); color: var(--warn); }

/* ─── جدول ─── */

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: .9rem; }
th {
  text-align: right; font-weight: 500; color: var(--muted);
  font-size: .8rem; padding: 8px 10px; border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
td { padding: 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--surface-2); }
td.num, th.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
tr.voided td { opacity: .48; text-decoration: line-through; }

.empty { text-align: center; color: var(--faint); padding: 34px 10px; font-size: .9rem; }

/* ─── فرم ─── */

input, select, textarea, button {
  font-family: inherit; font-size: .92rem; color: var(--text);
}
/* `time` هم اینجاست: بدونش کنارِ فیلدِ تاریخِ آراسته، یک کنترلِ خامِ
   مرورگر می‌نشست — قابِ روشن، اندازه‌ی دیگر، و آشکارا وصله. */
input[type="text"], input[type="password"], input[type="number"],
input[type="datetime-local"], input[type="time"], select, textarea {
  width: 100%; padding: 8px 11px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 9px; outline: none;
}
input:focus, select:focus, textarea:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg);
}
label { display: block; font-size: .82rem; color: var(--muted); margin-bottom: 4px; }
/* `min-width` صفر، وگرنه فیلد به اندازه‌ی *بلندترین گزینه‌ی* انتخابگرش
   پهن می‌شود و کوچک هم نمی‌شود: پیش‌فرضِ فلکس‌باکس برای کمینه‌ی یک آیتم،
   عرضِ محتوایش است. یک مشتری به نام «شرکت بازرگانی آریا تجارت پارس» در
   فهرستِ «مالِ کدام حساب مقصد» کافی بود تا فرمِ مستندات روی گوشی ۱۰۰
   پیکسل از کارت بیرون بزند و کلِ صفحه را کنار براند. */
.field { margin-bottom: 11px; min-width: 0; }
.row { display: flex; gap: 10px; flex-wrap: wrap; }
.row > * { flex: 1 1 150px; }
/* ردیفِ فیلتر. دو قالب `class="filters"` می‌نوشتند و هیچ قاعده‌ای نداشت:
   فیلدها بلوکِ ساده می‌ماندند و روی دسکتاپ هم زیرِ هم می‌افتادند. */
.filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
/* «کف‌چین» — برای فرمی که دکمه‌اش باید هم‌ترازِ پایینِ ورودی‌ها بنشیند.
   کلاس است و نه `style=` روی خودِ عنصر، چون سبکِ درون‌خطی را هیچ قاعده‌ی
   موبایلی نمی‌تواند پس بگیرد. */
.row-end { align-items: flex-end; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 16px; border-radius: 9px; border: 1px solid transparent;
  background: var(--accent); color: #fff; font-weight: 500;
  cursor: pointer; white-space: nowrap;
}
.btn:hover { background: var(--accent-2); text-decoration: none; }
.btn.ghost { background: transparent; border-color: var(--border); color: var(--text); }
.btn.ghost:hover { background: var(--surface-2); }
.btn.sm { padding: 5px 11px; font-size: .84rem; }

/* «خطرناک» دو حالت دارد و قاطی‌شدنشان متن را ناپیدا می‌کرد: نسخه‌ی پُر
   (قرمزِ تخت با متن سفید) و نسخه‌ی شبح (متن قرمز روی زمینه‌ی خالی).
   ghost باید همیشه برنده شود، چون دکمه‌ی کنارِ هر ردیف است نه دکمه‌ی اصلی. */
.btn.danger { background: var(--neg); color: #fff; border-color: var(--neg); }
.btn.danger:hover { background: var(--neg); filter: brightness(.92); }
.btn.ghost.danger {
  background: transparent; color: var(--neg); border-color: var(--border);
}
.btn.ghost.danger:hover {
  background: var(--neg-bg); border-color: var(--neg); color: var(--neg);
}

/* ─── نوار ثبت سریع ─── */

.quickbar {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 12px 14px; margin-bottom: 18px;
  box-shadow: var(--shadow);
}
.quickbar form { display: flex; gap: 9px; align-items: center; }
.quickbar input[type="text"] {
  font-size: 1rem; padding: 11px 14px; background: var(--bg);
}
.quickbar .hint { color: var(--faint); font-size: .78rem; margin-top: 7px; }
.quickbar .hint code {
  background: var(--surface-2); padding: 1px 6px; border-radius: 5px;
  font-family: inherit; color: var(--muted);
}

/* ─── نمودار ─── */

.chart { width: 100%; height: auto; display: block; }
.chart .axis { fill: var(--faint); font-size: 11px; }
.chart .axis.y { text-anchor: end; }
.chart .axis.x { dominant-baseline: alphabetic; }
/* عمداً اینجا text-anchor نمی‌گذاریم: CSS بر صفتِ روی خودِ عنصر غلبه
   می‌کند و لنگرِ حساب‌شده‌ی هر برچسب را بی‌اثر می‌کرد — نتیجه، بیرون‌زدنِ
   برچسبِ اول و آخر از کادر. */
.chart .tickline { stroke: var(--border); stroke-width: 1; stroke-dasharray: 3 4; }
/* مرزِ سود و زیان است، نه یک خطِ راهنمای دیگر — پس ممتد و پررنگ‌تر. */
.chart .zeroline { stroke: var(--muted); stroke-width: 1; }
.chart .grid-line { stroke: var(--border); stroke-width: 1; }
.chart .bar   { fill: var(--accent); opacity: .82; }
.chart .bar.pos { fill: var(--pos); }
.chart .bar.neg { fill: var(--neg); }
/* میله‌ی زیرِ موس پررنگ می‌شود تا معلوم باشد تولتیپ مالِ کدام روز است. */
.chart .barslot:hover .bar { opacity: 1; }
/* متنِ محور نباید موس را از میله بدزدد. */
.chart .axis { pointer-events: none; }
/* در RTL، text-anchor=start یعنی راست و end یعنی چپ — یعنی دقیقاً برعکسِ
   مختصاتی که در پایتون حساب شده، و برچسبِ اول و آخر از کادر بیرون می‌زنند.
   محتوای محور عدد و تاریخ است، پس LTR کردنش هم درست‌تر است هم مسئله را حل
   می‌کند. */
.chart text   { fill: var(--faint); font-size: 10px; font-family: inherit;
                direction: ltr; unicode-bidi: isolate; }

/* ─── متفرقه ─── */

.banner {
  padding: 10px 14px; border-radius: 9px; margin-bottom: 14px; font-size: .88rem;
  border: 1px solid transparent;
}
.banner.ok   { background: var(--pos-bg); color: var(--pos); border-color: var(--pos); }
.banner.warn { background: var(--warn-bg); color: var(--warn); border-color: var(--warn); }
.banner.err  { background: var(--neg-bg); color: var(--neg); border-color: var(--neg); }

.kv { display: grid; grid-template-columns: auto 1fr; gap: 7px 16px; font-size: .9rem; }
.kv dt { color: var(--muted); }
/* ستونِ `1fr` پیش‌فرض زیرِ عرضِ محتوایش نمی‌رود؛ یک شبا یا TXIDِ نشکن
   در `dd` کلِ گرید را باز می‌کند. */
.kv dd {
  margin: 0; font-variant-numeric: tabular-nums;
  min-width: 0; overflow-wrap: anywhere;
}

.section-gap { margin-top: 20px; }

details.inline summary {
  cursor: pointer; color: var(--accent); font-size: .88rem;
  list-style: none; user-select: none;
}
details.inline summary::-webkit-details-marker { display: none; }
details.inline[open] summary { margin-bottom: 11px; }

/* ─── ورود ───
   تنها صفحه‌ای که آدم پیش از دیدن هیچ عددی می‌بیند؛ پس کمی خرجِ ظاهر دارد.
   متغیرها محلی‌اند تا بقیه‌ی پوسته دست‌نخورده بماند، و هر سه حالتِ تم
   (پیش‌فرض، سلیقه‌ی سیستم، انتخابِ صریح) جداگانه پوشش داده شده‌اند. */

.login-page {
  --lg-base:   #dde1e8;
  --lg-top:    #eef0f4;
  --lg-glow-1: rgba(15,123,108,.32);
  --lg-glow-2: rgba(32,94,150,.20);
  --lg-glow-3: rgba(15,123,108,.16);
  --lg-grid:   rgba(26,31,39,.06);
  --lg-card:   rgba(252,253,254,.74);
  --lg-edge:   rgba(255,255,255,.85);
  --lg-field:  rgba(255,255,255,.70);
  --lg-line:   rgba(15,123,108,.55);
  --lg-line-2: rgba(32,94,150,.26);
  --lg-fill:   rgba(15,123,108,.10);
  --lg-shadow: 0 26px 60px -24px rgba(14,22,30,.42), 0 2px 10px rgba(14,22,30,.08);

  margin: 0;
  min-height: 100vh; min-height: 100dvh;
  /* فقط افقی. اگر عمودی را هم ببندیم، روی صفحه‌ی کوتاه (موبایلِ خوابیده)
     بالای کارت زیر لبه گیر می‌کند و دیگر قابل رسیدن نیست. */
  overflow-x: hidden;
  background: radial-gradient(125% 95% at 50% -12%, var(--lg-top), var(--lg-base) 62%);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .login-page {
    --lg-base:   #080b11;
    --lg-top:    #101725;
    --lg-glow-1: rgba(63,191,169,.24);
    --lg-glow-2: rgba(56,118,196,.18);
    --lg-glow-3: rgba(63,191,169,.12);
    --lg-grid:   rgba(231,236,242,.055);
    --lg-card:   rgba(20,26,34,.70);
    --lg-edge:   rgba(255,255,255,.10);
    --lg-field:  rgba(255,255,255,.05);
    --lg-line:   rgba(63,191,169,.62);
    --lg-line-2: rgba(96,150,220,.30);
    --lg-fill:   rgba(63,191,169,.13);
    --lg-shadow: 0 30px 70px -26px rgba(0,0,0,.75), 0 2px 10px rgba(0,0,0,.4);
  }
}
:root[data-theme="dark"] .login-page {
  --lg-base:   #080b11;
  --lg-top:    #101725;
  --lg-glow-1: rgba(63,191,169,.24);
  --lg-glow-2: rgba(56,118,196,.18);
  --lg-glow-3: rgba(63,191,169,.12);
  --lg-grid:   rgba(231,236,242,.055);
  --lg-card:   rgba(20,26,34,.70);
  --lg-edge:   rgba(255,255,255,.10);
  --lg-field:  rgba(255,255,255,.05);
  --lg-line:   rgba(63,191,169,.62);
  --lg-line-2: rgba(96,150,220,.30);
  --lg-fill:   rgba(63,191,169,.13);
  --lg-shadow: 0 30px 70px -26px rgba(0,0,0,.75), 0 2px 10px rgba(0,0,0,.4);
}

.login-bg { position: fixed; inset: 0; pointer-events: none; overflow: hidden; }

/* هاله‌ها با گرادیانِ شعاعی ساخته شده‌اند نه filter: blur — همان نرمی را
   می‌دهد بی‌آنکه موبایل را برای یک تصویرِ ثابت عرق بریزد. */
.login-bg .orb { position: absolute; border-radius: 50%; will-change: transform; }
.login-bg .orb-1 {
  width: 58vmax; height: 58vmax; top: -22vmax; right: -16vmax;
  background: radial-gradient(circle, var(--lg-glow-1), transparent 66%);
  animation: lg-drift-a 24s ease-in-out infinite alternate;
}
.login-bg .orb-2 {
  width: 48vmax; height: 48vmax; bottom: -20vmax; left: -14vmax;
  background: radial-gradient(circle, var(--lg-glow-2), transparent 66%);
  animation: lg-drift-b 29s ease-in-out infinite alternate;
}
.login-bg .orb-3 {
  width: 34vmax; height: 34vmax; top: 30%; left: 26%;
  background: radial-gradient(circle, var(--lg-glow-3), transparent 70%);
  animation: lg-drift-c 34s ease-in-out infinite alternate;
}
@keyframes lg-drift-a {
  from { transform: translate3d(0,0,0) scale(1); }
  to   { transform: translate3d(-3vmax, 3vmax, 0) scale(1.08); }
}
@keyframes lg-drift-b {
  from { transform: translate3d(0,0,0) scale(1); }
  to   { transform: translate3d(3vmax, -2vmax, 0) scale(1.06); }
}
@keyframes lg-drift-c {
  from { transform: translate3d(0,0,0); opacity: .55; }
  to   { transform: translate3d(2vmax, 2vmax, 0); opacity: 1; }
}

/* شبکه‌ی نازک، مثل کاغذِ پشتِ نمودار. با ماسک از لبه‌ها محو می‌شود تا
   قاب نگیرد و توجه را از کارت نبرد. */
.login-bg .mesh {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right,  var(--lg-grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--lg-grid) 1px, transparent 1px);
  background-size: 46px 46px;
  -webkit-mask-image: radial-gradient(ellipse 72% 62% at 50% 40%, #000 22%, transparent 78%);
          mask-image: radial-gradient(ellipse 72% 62% at 50% 40%, #000 22%, transparent 78%);
}

.login-bg .skyline {
  position: absolute; left: 0; right: 0; bottom: 0;
  width: 100%; height: min(44vh, 360px); display: block;
}
.login-bg .skyline .ln {
  fill: none; stroke: var(--lg-line); stroke-width: 2.4;
  stroke-linecap: round; stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 2600; stroke-dashoffset: 2600;
  animation: lg-draw 2.2s cubic-bezier(.22,.75,.3,1) .15s forwards;
}
.login-bg .skyline .ln2 {
  stroke: var(--lg-line-2); stroke-width: 1.4;
  animation-duration: 2.9s; animation-delay: .4s;
}
.login-bg .skyline .fill {
  fill: var(--lg-fill); stroke: none;
  opacity: 0; animation: lg-fade 1.6s ease-out 1s forwards;
}
@keyframes lg-draw { to { stroke-dashoffset: 0; } }
@keyframes lg-fade { to { opacity: 1; } }

.login-wrap {
  position: relative; z-index: 1;
  min-height: 100vh; min-height: 100dvh;
  display: grid; place-items: center; padding: 24px 20px 36px;
}
.login-box { width: 100%; max-width: 372px; }

/* «login-page» جلو را می‌گیرد: بلوکِ موبایل پایین‌تر یک «.card { padding: 14px }»
   دارد که با هم‌وزن بودن و پایین‌تر بودن، فاصله‌های این کارت را می‌بلعید. */
.login-page .login-card {
  position: relative; overflow: hidden;
  background: var(--lg-card);
  border: 1px solid var(--lg-edge);
  border-radius: 18px;
  padding: 30px 26px 26px;
  box-shadow: var(--lg-shadow);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
          backdrop-filter: blur(16px) saturate(140%);
  animation: lg-rise .5s cubic-bezier(.2,.7,.3,1) both;
}
/* لبه‌ی شیشه: خطِ نوری بالای کارت که آن را از پس‌زمینه جدا می‌کند. */
.login-page .login-card::before {
  content: ""; position: absolute; left: 14%; right: 14%; top: 0; height: 1px;
  background: linear-gradient(to left, transparent, var(--accent), transparent);
  opacity: .55;
}
@keyframes lg-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

.login-brand { text-align: center; margin-bottom: 22px; }
.login-mark {
  width: 54px; height: 54px; margin: 0 auto 12px;
  border-radius: 17px; display: grid; place-items: center; color: #fff;
  background: linear-gradient(145deg, var(--accent), var(--accent-2));
  box-shadow: 0 12px 26px -12px var(--accent), inset 0 1px 0 rgba(255,255,255,.35);
}
.login-mark svg { width: 27px; height: 27px; }
.login-brand h1 { margin: 0; font-size: 1.34rem; font-weight: 700; letter-spacing: -.01em; }
.login-brand .sub { color: var(--muted); font-size: .85rem; margin-top: 2px; }

.login-card input[type="text"], .login-card input[type="password"] {
  background: var(--lg-field); border-color: var(--lg-edge);
  padding: 11px 13px; border-radius: 11px; font-size: .98rem;
}
.login-card .field { margin-bottom: 14px; }
.login-card .btn.block {
  width: 100%; padding: 12px; border-radius: 11px;
  font-size: 1rem; font-weight: 600; margin-top: 4px;
  box-shadow: 0 12px 24px -14px var(--accent);
}
.login-foot {
  text-align: center; color: var(--faint);
  font-size: .78rem; margin-top: 16px;
}

/* ویرایشِ یک سطرِ صف — بسته می‌ماند تا جدول شلوغ نشود. */
.rowedit > summary {
  cursor: pointer; font-size: .78rem; color: var(--muted);
  list-style: none; padding: 3px 0;
}
.rowedit > summary::-webkit-details-marker { display: none; }
.rowedit > summary:hover { color: var(--accent); }
.editform { display: grid; gap: 6px; margin-top: 6px; }
.editform label {
  display: flex; align-items: center; gap: 6px;
  font-size: .76rem; color: var(--muted);
}
.editform label > input, .editform label > select { flex: 1; min-width: 0; }
.editform input[readonly] { opacity: .6; cursor: not-allowed; }
.editform .field { flex: 1 1 auto; }

/* فیلدی که خطا داشته، خودش را نشان می‌دهد — نه فقط بنرِ بالای فرم. */
input[aria-invalid="true"], select[aria-invalid="true"] {
  border-color: var(--neg);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--neg) 18%, transparent);
}

/* «رمزت را یادت رفته؟» — بسته، تا فرمِ ورود شلوغ نشود. */
.recover { margin-top: 16px; border-top: 1px solid var(--border); padding-top: 12px; }
.recover > summary {
  cursor: pointer; color: var(--muted); font-size: .82rem;
  text-align: center; list-style: none;
}
.recover > summary::-webkit-details-marker { display: none; }
.recover > summary:hover { color: var(--accent); }
.recover form { margin-top: 14px; }
.recover .hint { color: var(--faint); font-size: .76rem; line-height: 1.75; margin: 10px 0 0; }

@media (max-width: 560px) {
  .login-page .login-card { padding: 24px 18px 22px; border-radius: 16px; }
  .login-bg .skyline { height: 32vh; }
  .login-bg .orb-3 { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .login-bg .orb, .login-page .login-card { animation: none; }
  .login-bg .skyline .ln { stroke-dashoffset: 0; animation: none; }
  .login-bg .skyline .fill { opacity: 1; animation: none; }
}

/* ─── تم صریح ───
   بلوک بالا فقط prefers-color-scheme را پوشش می‌دهد. این یکی برای وقتی است
   که آدم خودش انتخاب کرده — باید بر سلیقه‌ی سیستم بچربد، در هر دو جهت. */

:root[data-theme="dark"] {
  --bg:        #0e1116;
  --surface:   #161b22;
  --surface-2: #1c2330;
  --border:    #262e3a;
  --text:      #e7ecf2;
  --muted:     #93a0b0;
  --faint:     #6a7788;
  --accent:    #3fbfa9;
  --accent-2:  #7bd8c6;
  --accent-bg: #12312c;
  --pos:       #4ec97e;
  --pos-bg:    #12301f;
  --neg:       #f0757c;
  --neg-bg:    #341a1c;
  --warn:      #e0b155;
  --warn-bg:   #33280f;
  --shadow:    0 1px 2px rgba(0,0,0,.4), 0 4px 16px rgba(0,0,0,.25);
}

:root[data-theme="dark"] .ic-sun,
:root:not([data-theme="light"]) .ic-sun { display: none; }
:root[data-theme="dark"] .ic-moon,
:root:not([data-theme="light"]) .ic-moon { display: block; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .ic-sun { display: block; }
  :root:not([data-theme="dark"]) .ic-moon { display: none; }
}
:root[data-theme="light"] .ic-sun { display: block; }
:root[data-theme="light"] .ic-moon { display: none; }

.theme-btn {
  background: none; border: 0; width: 100%; cursor: pointer;
  font: inherit; text-align: start;
}

.nav-sep { height: 1px; background: var(--border); margin: 9px 4px; }

/* ─── نوار بالا و پایینِ موبایل (روی دسکتاپ پنهان) ─── */

.topbar, .tabbar { display: none; }

.iconbtn {
  display: grid; place-items: center; width: 38px; height: 38px;
  border-radius: 10px; border: 1px solid var(--border);
  background: var(--surface); color: var(--muted); cursor: pointer;
}
.iconbtn:hover { color: var(--text); }
.iconbtn svg { width: 19px; height: 19px; }

/* ─── صفحه‌بندی ─── */

.pager {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding-top: 13px; margin-top: 13px; border-top: 1px solid var(--border);
  font-size: .88rem;
}
.pager-count { color: var(--muted); }
/* `wrap` لازم است: دکمه‌ها `min-width: 34px` دارند و نه کوچک می‌شوند
   نه به خط بعد می‌روند. پنجره‌ی کاملِ صفحه‌بندی یازده تاست و روی
   گوشه از هر دو طرفِ کارت می‌زند بیرون. */
.pager-pages, .pager-size {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
}
.pager-size { margin-inline-start: auto; color: var(--muted); }

.pg {
  min-width: 34px; height: 34px; padding: 0 9px;
  display: inline-grid; place-items: center;
  border: 1px solid var(--border); border-radius: 9px;
  color: var(--muted); background: var(--surface); font-size: .86rem;
}
.pg:hover { color: var(--text); border-color: var(--accent); text-decoration: none; }
.pg.on { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
.pg.off { opacity: .35; pointer-events: none; }
.pg.dots { border: 0; min-width: 18px; pointer-events: none; }

/* ─── نوار ابزار جدول: فیلتر + خروجی ─── */

.toolbar {
  display: flex; gap: 9px; align-items: end; flex-wrap: wrap;
}
.toolbar .field { margin: 0; }
.toolbar .grow { flex: 1 1 170px; }
.btn.export { background: var(--pos-bg); color: var(--pos); border-color: transparent; }
.btn.export:hover { filter: brightness(.96); }

.editbox {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 13px; margin-top: 9px; background: var(--surface-2);
}
.row-off { opacity: .55; }

.banner.info { background: var(--accent-bg); color: var(--accent-2); }


/* ─── نوار قیمت ─── */

/* نوار قیمت هرگز افقی اسکرول نمی‌شود: نرخی که باید کشیده شود تا دیده شود،
   دیده نمی‌شود. با زیاد شدن ارزها، به خط بعد می‌رود. */
.ticker {
  display: flex; align-items: center; gap: 4px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 7px 10px; margin-bottom: 15px;
}
.ticker-rows { display: flex; flex-wrap: wrap; gap: 4px 2px; flex: 1; min-width: 0; }
.tick {
  display: flex; align-items: baseline; gap: 6px; white-space: nowrap;
  padding: 3px 11px; border-radius: 8px; font-size: .84rem;
}
/* جداکننده‌ی خطی با شکستنِ سطر بد می‌افتد (اولِ هر خط یک خطِ بی‌معنی).
   به‌جایش هر قلم قابِ ملایمِ خودش را دارد. */
.tick { background: var(--bg); border: 1px solid transparent; }
.tick:hover { border-color: var(--border); }
.t-label { color: var(--muted); }
.t-value { font-weight: 700; font-variant-numeric: tabular-nums; }
.t-unit  { color: var(--faint); font-size: .74rem; }
.t-chg   { font-size: .75rem; font-weight: 600; }
.t-chg.up { color: var(--pos); }
.t-chg.down { color: var(--neg); }
.t-at    { color: var(--faint); font-size: .72rem; margin-inline-start: 3px; }
.ticker-refresh {
  flex: 0 0 auto; border: 0; background: none; cursor: pointer;
  color: var(--muted); font-size: 1rem; padding: 2px 6px; border-radius: 7px;
}
.ticker-refresh:hover { background: var(--surface-2); color: var(--text); }

/* ─── پنل ثبت (بسته‌شونده) ─── */

.entry { padding: 0; overflow: hidden; }
.entry > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 13px 16px; cursor: pointer; list-style: none; user-select: none;
}
.entry > summary::-webkit-details-marker { display: none; }
.entry > summary:hover { background: var(--surface-2); }
.entry[open] > summary { border-bottom: 1px solid var(--border); }
.entry-title { font-weight: 600; display: flex; align-items: center; gap: 8px; }
.entry-title .plus {
  display: inline-grid; place-items: center; width: 21px; height: 21px;
  border-radius: 7px; background: var(--accent); color: #fff;
  font-size: 1rem; line-height: 1;
}
.entry-hint { font-size: .83rem; }
.entry-body { padding: 15px 16px 16px; }
.entry-note { font-size: .82rem; margin-top: 8px; line-height: 1.9; }

.ai-form { display: flex; gap: 8px; }
.ai-form input { flex: 1; }

/* ─── زبانه ─── */

.tabs { display: flex; gap: 5px; margin-bottom: 13px; flex-wrap: wrap; }
.tab-btn {
  border: 1px solid var(--border); background: var(--surface);
  color: var(--muted); border-radius: 9px; padding: 7px 15px;
  font: inherit; font-size: .88rem; cursor: pointer;
}
.tab-btn:hover { color: var(--text); text-decoration: none; }
.tab-btn.on {
  background: var(--accent-bg); color: var(--accent-2);
  border-color: var(--accent); font-weight: 600;
}
.pagetabs { margin-bottom: 16px; }
.badge {
  display: inline-block; min-width: 19px; padding: 0 5px; margin-inline-start: 5px;
  border-radius: 20px; background: var(--surface-2); color: var(--muted);
  font-size: .74rem; font-weight: 600;
}
.tab-btn.on .badge { background: var(--accent); color: #fff; }
.pane { display: none; }
.pane.on { display: block; }

/* ─── نوار آمارِ بالای جدول ─── */

.statstrip {
  display: flex; gap: 0; flex-wrap: wrap; margin-bottom: 14px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden;
}
.statcell {
  flex: 1 1 130px; padding: 11px 15px; display: flex;
  flex-direction: column; gap: 2px;
}
.statcell + .statcell { border-inline-start: 1px solid var(--border); }
.statcell .label { color: var(--muted); font-size: .78rem; }
.statcell .value { font-weight: 700; font-size: 1.08rem; font-variant-numeric: tabular-nums; }
.statcell .value.neg { color: var(--neg); }
.statcell .value.dim { color: var(--faint); font-weight: 500; }

/* ─── ابزار و فرم ─── */

.toolbar-actions { display: flex; gap: 7px; align-items: end; flex: 0 0 auto; }
.rowtight { gap: 7px; align-items: center; flex-wrap: wrap; }
.cellactions { display: flex; gap: 6px; justify-content: flex-end; align-items: center; }
.cellactions form { margin: 0; }
.inline-form { display: flex; gap: 6px; align-items: center; }
.inline-form input { max-width: 145px; }
.checkrow { display: flex; gap: 18px; flex-wrap: wrap; }
.checkrow label {
  display: flex; align-items: center; gap: 7px; cursor: pointer;
  font-weight: 500; color: var(--text);
}
.checkrow input { width: auto; }

/* ─── تولتیپ نمودار ─── */

.card-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 11px;
}
.card-head h2 { margin: 0; }
.card-head .dim { font-size: .82rem; }

.chartbox { position: relative; }
.chart .hot { fill: transparent; cursor: crosshair; }
.chart .dot {
  fill: var(--accent); stroke: var(--surface); stroke-width: 2;
  pointer-events: none; opacity: 0; transition: opacity .12s;
}
.chart .dot.on { opacity: 1; }
.charttip {
  position: absolute; transform: translate(-50%, -125%);
  background: var(--text); color: var(--bg);
  padding: 5px 9px; border-radius: 8px; font-size: .76rem;
  white-space: nowrap; pointer-events: none; z-index: 5;
  box-shadow: 0 3px 12px rgba(0,0,0,.22); line-height: 1.5;
}
.charttip b { display: block; font-weight: 700; }
.charttip span { opacity: .78; font-size: .72rem; }
.chart-foot { font-size: .82rem; margin-top: 6px; }

/* ─── بخش بسته‌شونده (فیلتر و مانندش) ─── */

.foldable > summary {
  display: flex; align-items: center; justify-content: space-between;
  cursor: pointer; list-style: none; font-weight: 600; font-size: .92rem;
}
.foldable > summary::-webkit-details-marker { display: none; }
.foldable > summary::after {
  content: "▾"; color: var(--muted); transition: transform .15s;
}
.foldable[open] > summary::after { transform: rotate(180deg); }
.foldable[open] > summary { margin-bottom: 12px; }
.fold-count {
  font-weight: 500; font-size: .8rem; color: var(--accent-2);
  background: var(--accent-bg); border-radius: 20px; padding: 1px 9px;
  margin-inline-start: 7px;
}

/* ═══════════════════ موبایل ═══════════════════
   بیشترِ کاربرها از موبایل می‌آیند، پس این «حالت کوچک‌شده‌ی دسکتاپ» نیست:
   ناوبری می‌رود پایینِ صفحه که دستِ شست به آن برسد، و جدول‌ها به کارت
   تبدیل می‌شوند چون جدولِ افقیِ اسکرول‌شونده روی موبایل عملاً خوانده نمی‌شود. */

@media (max-width: 860px) {
  html { font-size: 15.5px; }

  .sidebar { display: none; }
  .shell { flex-direction: column; min-height: 100dvh; }

  .topbar {
    display: flex; align-items: center; justify-content: space-between;
    padding: 10px 14px; background: var(--surface);
    border-bottom: 1px solid var(--border);
    position: sticky; top: 0; z-index: 30;
    padding-top: calc(10px + env(safe-area-inset-top));
  }
  .topbar .logo { font-size: 1.05rem; padding: 0; }
  .topbar-actions { display: flex; gap: 8px; }

  .main { padding: 15px 13px calc(78px + env(safe-area-inset-bottom)); }

  .tabbar {
    display: flex; position: fixed; inset-inline: 0; bottom: 0; z-index: 40;
    background: var(--surface); border-top: 1px solid var(--border);
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
    box-shadow: 0 -2px 14px rgba(0,0,0,.06);
  }
  .tab {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
    padding: 6px 2px; color: var(--muted); font-size: .68rem; border-radius: 10px;
    -webkit-tap-highlight-color: transparent;
  }
  .tab svg { width: 21px; height: 21px; }
  .tab.on { color: var(--accent); }
  .tab:hover { text-decoration: none; }
  .tab-more { position: relative; list-style: none; }
  .tab-more > summary {
    list-style: none; display: flex; flex-direction: column; align-items: center;
    gap: 2px; cursor: pointer; color: var(--muted); font-size: .68rem;
  }
  .tab-more > summary::-webkit-details-marker { display: none; }
  .more-sheet {
    position: absolute; bottom: calc(100% + 10px); inset-inline-end: 0;
    min-width: 190px; background: var(--surface); border: 1px solid var(--border);
    border-radius: 14px; box-shadow: var(--shadow); padding: 7px;
  }

  /* عنوان صفحه فشرده‌تر */
  .page-head { flex-direction: column; align-items: stretch; gap: 9px; }
  .page-head h1 { font-size: 1.3rem; }

  /* کارت‌های آمار: دوتا در هر سطر، نه چهارتا */
  .grid.k4 { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .grid.k2, .grid.k3 { grid-template-columns: 1fr; }
  .card { padding: 14px; }
  .card.stat .value { font-size: 1.34rem; }

  /* فرم‌ها یک‌ستونه، و ورودی ۱۶px تا سافاری روی فوکوس زوم نکند */
  .row, .filters { flex-direction: column; align-items: stretch; gap: 10px; }
  .field { flex: none !important; }
  input, select, textarea { font-size: 16px !important; }
  .btn { padding: 11px 16px; }

  /* جدول → کارت.
     پیش از این هر خانه یک ردیفِ فلکس بود: برچسب چسبیده به راست، مقدار
     چسبیده به چپ، و یک `auto` وسطشان. یعنی هرچه صفحه پهن‌تر، دره‌ی خالیِ
     وسط بزرگ‌تر — و چشم باید در هر سطر از رویش می‌پرید تا برچسب را به
     مقدارش وصل کند. روی کارتی با شش خانه، همین شد ستونی از هیچ.

     حالا برچسب یک ستونِ باریکِ ثابت است و مقدار بلافاصله کنارش شروع
     می‌شود. برچسب `absolute` است تا مقدارِ چندخطی زیرِ *خودش* بشکند نه
     زیرِ برچسب، و خانه‌ای که چند تکه محتوا دارد — نام و نشان و بانک —
     همان‌طور کنار هم بماند که در جدول بود. */
  table.stack thead { display: none; }
  table.stack, table.stack tbody, table.stack tr, table.stack td { display: block; width: 100%; }
  table.stack tr {
    border: 1px solid var(--border); border-radius: var(--radius);
    padding: 10px 12px; margin-bottom: 8px; background: var(--surface);
  }
  table.stack td {
    position: relative; border: 0; text-align: start;
    padding: 3px 0; padding-inline-start: 5.9rem; min-height: 1.4em;
  }
  table.stack td::before {
    content: attr(data-label);
    position: absolute; inset-inline-start: 0; top: 3px; width: 5.4rem;
    color: var(--faint); font-size: .76rem; line-height: 1.75;
    overflow-wrap: anywhere;
  }
  table.stack td[data-label=""]::before { content: none; }
  table.stack td[data-label=""] { padding-inline-start: 0; }

  /* سرِ کارت — همان چیزی که کارت *درباره‌ی* آن است: نام مشتری، شرحِ
     معامله، صاحبِ حساب. برچسب نمی‌خواهد، و نباید هم‌وزنِ بقیه دیده شود؛
     وگرنه آدم باید شش سطر را بخواند تا بفهمد این کارت مالِ کیست. */
  table.stack td[data-head] {
    padding-inline-start: 0; padding-bottom: 7px; margin-bottom: 4px;
    border-bottom: 1px solid var(--border);
    font-size: 1.02rem; font-weight: 600; line-height: 1.7;
  }
  table.stack td[data-head]::before { content: none; }
  table.stack td[data-head] .dim,
  table.stack td[data-head] .pill { font-weight: 400; }

  /* فقط جدولی که واقعاً کارت شده. جدولِ ستونیِ داخلِ همین قاب — داشبورد،
     صفحه‌ی یک تراکنش — هنوز از عرضِ گوشی پهن‌تر است و باید بلغزد. بدونِ
     این شرط، پهنایش کلِ صفحه را کنار می‌راند: نوارِ افقی روی *سند* و
     عنوانِ صفحه نصفه. اگر مرورگری `:has` نداشته باشد، قاعده کنار می‌رود
     و همان `overflow-x: auto`ِ بالا می‌مانَد — یعنی درست، فقط کم‌ظرافت. */
  .table-wrap:has(table.stack) { overflow: visible; }

  /* عدد در کارت چپ‌چین نمی‌شود: ستونی در کار نیست که با آن تراز شود، و
     چپ‌چینِ تنها فقط همان دره‌ی خالی را برمی‌گرداند. */
  table.stack td.num { white-space: normal; text-align: start; }

  .ticker { padding: 6px 8px; margin-bottom: 12px; }
  .tick { padding: 3px 8px; font-size: .79rem; }
  .t-at { display: none; }            /* روی موبایل جا نیست؛ روی دسکتاپ هست */
  .statstrip { flex-direction: row; }
  .statcell { flex: 1 1 50%; padding: 9px 12px; }
  .statcell:nth-child(2n) { border-inline-start: 1px solid var(--border); }
  .entry > summary { padding: 12px 13px; }
  .entry-hint { display: none; }
  .entry-body { padding: 13px; }
  .ai-form { flex-direction: column; }
  .toolbar-actions { width: 100%; }
  .toolbar-actions .btn { flex: 1; text-align: center; }
  .inline-form { width: 100%; }
  .inline-form input { max-width: none; flex: 1; }
  /* ولی نه داخلِ سطرِ سهم: آنجا دکمه‌ها کنارِ نامِ خریدارند و تمام‌عرض‌شدنشان
     هر سهم را سه خط می‌کند. */
  .partrow .inline-form { width: auto; }

  /* روی موبایل هر بخشِ فرمی جمع می‌شود تا فهرست بالا بیاید */
  .foldable > summary { padding: 2px 0; }
  /* ستون کنش در حالت کارتی: دکمه‌ها ته کارت، کنار هم */
  table.stack td[data-label=""] { padding-top: 8px; }
  .cellactions { width: 100%; justify-content: stretch; }
  .cellactions .btn, .cellactions form { flex: 1; }
  .cellactions .btn { width: 100%; }
  .chart .axis { font-size: 13px; }     /* نمودار کوچک‌تر می‌شود، متن باید بماند */
  .charttip { font-size: .8rem; }

  .pager { justify-content: center; }
  .pager-size { margin-inline-start: 0; width: 100%; justify-content: center; }
  /* `!important` چون `.field { flex: none !important }` بالاتر است و
     بدون آن این خط اجرا نمی‌شود — جعبه‌ی جستجو روی گوشی باریک می‌ماند. */
  .toolbar .grow { flex: 1 1 100% !important; }
}

/* صفحه‌های خیلی باریک */
@media (max-width: 380px) {
  .grid.k4 { grid-template-columns: 1fr; }
  .tab span { font-size: .62rem; }
}

/* ─── انتخاب ارزهای نوار قیمت ─── */

.tickerpick { display: flex; flex-wrap: wrap; gap: 8px; }
.pickbox {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 12px; border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); cursor: pointer; font-size: .88rem;
  user-select: none;
}
.pickbox:hover { border-color: var(--accent); }
.pickbox input { width: auto; margin: 0; accent-color: var(--accent); }
.pickbox:has(input:checked) {
  background: var(--accent-bg); border-color: var(--accent); color: var(--accent-2);
}
.pickbox .dim { font-size: .76rem; }

/* ─── تیکت پشتیبانی ─── */

.nav-badge {
  margin-inline-start: auto; min-width: 19px; height: 19px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 5px; border-radius: 999px;
  background: var(--neg); color: #fff; font-size: .72rem; font-weight: 700;
}

.thread { display: flex; flex-direction: column; gap: 12px; }
.msg {
  border: 1px solid var(--border); border-radius: 12px;
  padding: 10px 13px; max-width: 88%;
}
/* پیام خودم سمت شروع، پیام طرف مقابل سمت پایان — چشم بدون خواندن هم
   می‌فهمد نوبتِ کیست. */
.msg.mine   { align-self: flex-start; background: var(--accent-bg); border-color: var(--accent); }
.msg.theirs { align-self: flex-end;   background: var(--surface-2); }
.msg-head {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  font-size: .82rem; margin-bottom: 6px;
}
.msg-head .dim { font-size: .76rem; }
/* `pre-wrap` فقط سرِ فاصله می‌شکند. تیکت از آدم می‌خواهد آنچه دیده را
   بچسباند، و یک TXID شصت‌واندی‌کاراکتری هیچ فاصله‌ای ندارد: از حباب
   می‌زند بیرون و صفحه را افقی می‌لغزاند. `anywhere` مثل `.docval`. */
.msg-body {
  white-space: pre-wrap; overflow-wrap: anywhere;
  line-height: 1.7; font-size: .93rem;
}

textarea { min-height: 70px; resize: vertical; line-height: 1.7; }

@media (max-width: 560px) { .msg { max-width: 100%; } }

/* ── هشدار ثبت تکراری ──
   فهرست داخل بنر می‌نشیند، پس نباید تورفتگی و نقطه‌ی پیش‌فرضِ ul را داشته
   باشد: در بنرِ باریکِ موبایل، تورفتگی متن را به لبه می‌چسباند. */
.duplist { list-style: none; margin: 9px 0 0; padding: 0; }
.duplist > li {
  padding: 8px 0;
  border-top: 1px solid color-mix(in srgb, currentColor 22%, transparent);
}
.duprow { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.duprow strong { flex: 1 1 200px; }

/* ── انتخابگر تاریخ ──
   یک ظاهر برای شمسی و میلادی: تفاوتشان فقط در داده‌ای است که سرور می‌دهد. */
.jdate { position: relative; display: flex; gap: 6px; align-items: center; }
.jdate .jdate-show { flex: 1 1 110px; min-width: 0; }
.jdate .jdate-time { flex: 0 1 96px; min-width: 0; }

/* `fixed` و نه `absolute`: پنلِ ثبت `overflow: hidden` دارد (برای اینکه
   گوشه‌های گردش محتوا را ببرد) و تقویمی که داخلش باز شود از پایین بریده
   می‌شود — روزهای ۲۱ تا ۳۱ و دکمه‌ی «امروز» ناپدید. جای‌گیری‌اش در
   jdate.js حساب می‌شود، پس اینجا نه `top` دارد نه `inset`. */
.jdate-pop {
  position: fixed; z-index: 60;
  width: 268px; padding: 10px;
  /* سقفِ ارتفاع را جای‌گیرِ jdate.js می‌گذارد، چون فقط او خبر دارد کیبورد
     چقدر از صفحه را خورده. `100vh` روی موبایل کیبورد را نمی‌بیند. */
  max-height: calc(100vh - 16px); overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; box-shadow: 0 12px 34px rgba(0, 0, 0, .28);
}
.jdate-pop[hidden] { display: none; }

.jdate-head {
  display: flex; align-items: center; gap: 4px; margin-bottom: 8px;
}
.jdate-title { flex: 1; text-align: center; font-weight: 600; font-size: .92rem; }
.jdate-nav {
  background: transparent; border: 1px solid transparent; color: var(--text);
  border-radius: 8px; cursor: pointer; padding: 3px 8px; font-size: .95rem;
  line-height: 1.6;
}
.jdate-nav:hover { background: var(--surface-2); }
.jdate-nav.wide { width: 100%; border-color: var(--border); font-size: .86rem; }

.jdate-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.jdate-wd {
  text-align: center; font-size: .72rem; color: var(--faint);
  padding-bottom: 4px;
}
.jdate-day {
  background: transparent; border: 1px solid transparent; color: var(--text);
  border-radius: 8px; cursor: pointer; padding: 6px 0; font-size: .86rem;
}
.jdate-day:hover { background: var(--surface-2); }
/* امروز فقط حاشیه دارد و انتخاب‌شده پُر است: دو حالتِ متفاوت که نباید
   شبیه هم دیده شوند، وگرنه آدم فکر می‌کند روزی را انتخاب کرده که نکرده. */
.jdate-day.is-today { border-color: var(--accent); }
.jdate-day.is-picked { background: var(--accent); color: #fff; border-color: var(--accent); }
.jdate-foot { margin-top: 8px; }
.jdate-err { font-size: .84rem; color: var(--neg); padding: 6px; }

/* جای‌گیریِ افقی در jdate.js است، نه اینجا: عرضِ صفحه تنها متغیر نیست،
   جای خودِ فیلد در ردیف هم هست — و CSS آن را نمی‌داند. */

/* ── صفحه‌ی یک تراکنش ──
   سه لایه: این چیست / چه می‌گوید / چه می‌شود کرد. کارهای روی رکورد یک
   فهرستِ تاشو هستند نه کارت‌های هم‌وزن — «ابطال» نباید هم‌اندازه‌ی
   «لینک به بک‌تو‌بک» دیده شود. */
.txhead h1 { line-height: 1.5; }
.txhead .sub { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }

/* منبع رکورد، جدا از خودِ اعداد */
.kv-foot {
  margin-top: 13px; padding-top: 11px; border-top: 1px solid var(--border);
  color: var(--faint); font-size: .8rem; display: flex; flex-wrap: wrap; gap: 5px;
}
.kv-foot .rawline {
  flex: 1 1 100%; margin-top: 5px; color: var(--muted);
  background: var(--surface-2); border-radius: 8px; padding: 5px 9px;
  overflow-wrap: anywhere;
}

/* دو سمتِ تسویه، کنار هم و هم‌اندازه */
.sides { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 11px; }
.side {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 12px; display: flex; flex-direction: column; gap: 9px;
  align-items: flex-start; background: var(--surface-2);
}
.side-label { font-size: .92rem; }
.side.is-done { opacity: .72; }

/* فهرستِ کارها */
.actions details.act { border-top: 1px solid var(--border); }
.actions details.act:first-of-type { border-top: 0; }
.actions details.act > summary {
  cursor: pointer; list-style: none; user-select: none;
  padding: 12px 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
}
.actions details.act > summary::-webkit-details-marker { display: none; }
.actions details.act > summary::before {
  content: "›"; color: var(--faint); font-size: 1.05rem; line-height: 1;
  transition: transform .15s;
}
.actions details.act[open] > summary::before { transform: rotate(-90deg); }
.actions details.act > summary:hover .act-name { color: var(--accent); }
.act-name { font-weight: 600; font-size: .95rem; }
.act-hint { color: var(--faint); font-size: .82rem; flex: 1 1 240px; }
.actions details.act.danger .act-name { color: var(--neg); }
.act-body {
  padding: 4px 0 16px;
  animation: actin .16s ease-out;
}
@keyframes actin { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; } }

/* فرم‌های تک‌خطیِ پیوند و ابطال */
.linkform { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start; }
/* همان دلیلِ `.docform`: تعریفِ بالا بعد از بلوکِ ۸۶۰ می‌آید، پس قاعده‌ی
   موبایل باید همین‌جا و بعد از آن بنشیند وگرنه پس گرفته می‌شود. */
@media (max-width: 860px) {
  .linkform { flex-direction: column; align-items: stretch; gap: 10px; }
}
.linkform + .linkform { margin-top: 14px; padding-top: 14px; border-top: 1px dashed var(--border); }

@media (max-width: 560px) {
  .act-hint { flex-basis: 100%; }
}
.headactions { display: flex; flex: 0 0 auto; gap: 8px; align-items: center; }

/* ── بایگانیِ مدرک ──
   فیش را باید *دید*، نه اینکه هر بار دانلودش کرد. */
.doclist { list-style: none; margin: 0 0 16px; padding: 0; }
.doclist > li {
  padding: 11px 0;
  border-top: 1px solid var(--border);
}
.doclist > li:first-child { border-top: 0; }
.docrow { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.docval {
  background: var(--surface-2); border-radius: 6px; padding: 3px 8px;
  font-size: .82rem; overflow-wrap: anywhere; max-width: 100%;
}
.docnote { font-size: .84rem; margin-top: 5px; }
.docmeta { font-size: .76rem; margin-top: 5px; }
/* چرا دکمه‌ی افزودن نیست: دو دسترسی، به تفکیک. */
.docwhy { font-size: .84rem; margin-top: 10px; line-height: 2.1; }
.docthumb {
  display: block; margin-top: 8px; max-width: 220px; max-height: 160px;
  border-radius: 10px; border: 1px solid var(--border); object-fit: cover;
}
.docform { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start; }
/* `width` لازم است چون ورودیِ فایل در فهرستِ «عرض ۱۰۰٪»ِ بالا نیست و
   عرضِ ذاتی‌اش (دکمه + نام فایل) از قابِ گوشیِ باریک بیشتر است. */
.docform input[type="file"] {
  padding: 6px; font-size: .84rem; width: 100%; max-width: 100%;
}

/* روی گوشی یک‌ستونه، مثل هر فرم دیگر.
   اینجا نوشته شده و نه کنارِ `.row` در بلوکِ ۸۶۰، چون `.docform`ِ بالا
   با همان وزن و پایین‌تر می‌آید و `align-items: flex-start` را پس
   می‌گیرد — و بی‌stretch، فیلد به اندازه‌ی محتوایش می‌ماند:
   ورودیِ فایل روی صفحه‌ی ۳۲۰ پیکسلی ۳۱۸ پیکسل عرض می‌گیرد و بیرون
   می‌زند. قاعده‌ای که جای اشتباه بنشیند، هست ولی کار نمی‌کند. */
@media (max-width: 860px) {
  .docform { flex-direction: column; align-items: stretch; gap: 10px; }
}
.btn.has-docs { color: var(--accent); border-color: var(--accent); }


/* ─── صفِ حساب‌ها ─── */

/* نوارِ پیشرفت: «۲۰۰ از ۵۰۰» را با یک نگاه می‌گوید. دو رنگ دارد چون سه
   چیز متفاوت‌اند — رسیده، سپرده‌شده‌ی نرسیده، و آزاد. */
.bar {
  display: flex; height: 6px; border-radius: 3px; overflow: hidden;
  background: var(--surface-2); margin: 5px 0 3px;
}
.bar-done { background: var(--pos); }
.bar-held { background: var(--warn); opacity: .65; }

.partrow {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 3px 0; font-size: .84rem;
}
.partrow + .partrow { border-top: 1px dashed var(--border); }
.partform {
  display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
  margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border);
}
.partform select { flex: 1 1 110px; min-width: 0; }
.partform input { flex: 0 1 110px; min-width: 0; }
/* درصد، نه فقط رقم: سؤالِ واقعی «چقدرش را به او داده‌ام» است و جوابش را
   از «۲۹۵٬۰۰۰٬۰۰۰» نمی‌شود یک‌نگاهی گرفت. */
.partpct {
  font-variant-numeric: tabular-nums; font-weight: 600;
  color: var(--accent); font-size: .8rem;
}
/* راهنما تمامِ عرضِ فرم را می‌گیرد تا زیرِ فیلدها بنشیند، نه کنارشان. */
.parthint { flex: 1 1 100%; color: var(--faint); font-size: .76rem; line-height: 1.8; }

/* ═══════════════ نقش‌ها ═══════════════
 *
 * فرمِ ویرایش پیش از این داخلِ خانه‌ی یک جدول بود، پس عرضش را جدول تعیین
 * می‌کرد و نه محتوا: ستونی باریک، گزینه‌ها روی هم، و سه‌چهارمِ کارت خالی.
 * حالا هر نقش یک کارتِ تاشوی تمام‌عرض است.
 */

.rolelead { font-size: .88rem; margin-bottom: 14px; max-width: 72ch; }
.rolelist { display: flex; flex-direction: column; gap: 8px; }

.rolecard {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.rolecard > summary {
  display: flex; align-items: center; gap: 8px 16px; flex-wrap: wrap;
  padding: 12px 15px; cursor: pointer; list-style: none; user-select: none;
}
.rolecard > summary::-webkit-details-marker { display: none; }
.rolecard > summary:hover { background: var(--surface-2); }
.rolecard[open] > summary { border-bottom: 1px solid var(--border); }
.rolecard[open] { background: var(--surface-2); }

.rolename {
  display: inline-flex; align-items: center; gap: 7px;
  flex: 0 0 auto; font-weight: 600; font-size: .95rem;
}
/* خلاصه‌ی دسترسی‌ها فضای باقی‌مانده را می‌گیرد و در یک خط می‌مانَد: کارتِ
   بسته باید یک نگاه باشد، نه یک پاراگراف. */
.rolegrants {
  flex: 1 1 240px; min-width: 0; font-size: .8rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rolecount { flex: 0 0 auto; font-size: .82rem; }
.roleopen { flex: 0 0 auto; color: var(--accent); font-size: .86rem; }

.rolebody { padding: 15px; }
.rolename-field { max-width: 320px; }
.roleactions {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 14px;
}
.roleactions .dim { font-size: .8rem; }
.roledelete {
  margin-top: 14px; padding-top: 13px; border-top: 1px dashed var(--border);
}
.rolecard-new { margin-top: 10px; border-style: dashed; }

/* ─── ماتریسِ دسترسی ───
   سرستون‌ها یک بار بالا می‌آیند و معنیِ هر ستون را می‌گویند. پیش از این
   سه گزینه هشت بار تکرار می‌شدند و هیچ‌بار عنوان نداشتند — و «—» هم
   هیچ نمی‌گفت. */
/* عرضِ بیشینه دارد و کشیده نمی‌شود: روی نمایشگرِ پهن، جدولی که تا ته
   کارت باز شود نامِ بخش را در یک سرِ صفحه و گزینه‌ها را در سرِ دیگر
   می‌گذارد و چشم باید بینشان سفر کند. ماتریسِ جمع‌وجور خواناتر است. */
.permtable { width: 100%; max-width: 780px; border-collapse: collapse; }
.permtable thead th {
  font-size: .79rem; font-weight: 500; color: var(--muted);
  padding: 4px 10px 9px; text-align: center; white-space: nowrap;
  border-bottom: 1px solid var(--border);
}
.permtable th.permhead-name { text-align: start; }
/* `white-space: normal` لازم است: قاعده‌ی سراسریِ `th` نویسه‌شکنی را
   می‌بندد، و آن‌وقت ستونِ نام به اندازه‌ی بلندترین توضیح پهن می‌شود،
   جدول از قابش می‌زند بیرون و خودِ نام‌ها از دید خارج می‌شوند. */
.permtable tbody th.permhead-name {
  font-weight: 400; padding: 9px 10px; white-space: normal;
  border-bottom: 1px solid var(--border);
}
.permname { display: block; font-size: .92rem; }
.permhint {
  display: block; font-size: .76rem; color: var(--faint);
  margin-top: 2px; line-height: 1.6;
}
.permtable td {
  width: 122px; padding: 0; text-align: center;
  border-bottom: 1px solid var(--border);
}
.permtable tbody tr:last-child th,
.permtable tbody tr:last-child td { border-bottom: 0; }
.permtable tbody tr:hover th,
.permtable tbody tr:hover td { background: var(--surface); }

/* سبز یعنی «داده شده». ستونِ بی‌دسترسی عمداً بی‌رنگ می‌ماند، وگرنه یک
   نقشِ خالی هشت خانه‌ی سبز نشان می‌داد و رنگ معنایش را از دست می‌داد. */
.permtable td:nth-child(n+3):has(input:checked) {
  background: color-mix(in srgb, var(--accent) 9%, transparent);
}

.permpick {
  display: flex; align-items: center; justify-content: center;
  padding: 15px 6px; margin: 0; cursor: pointer;
}
.permpick input[type="radio"] { width: auto; margin: 0; accent-color: var(--accent); }
.permpick input:disabled { cursor: default; }
.permna {
  display: block; padding: 15px 6px; font-size: .75rem; color: var(--faint);
}

@media (max-width: 760px) {
  .permtable thead { display: none; }
  .permtable, .permtable tbody { display: block; }
  .permtable tr {
    display: flex; flex-wrap: wrap; align-items: stretch;
    border: 1px solid var(--border); border-radius: var(--radius);
    padding: 10px 12px 6px; margin-bottom: 8px; background: var(--surface);
  }
  .permtable tbody th.permhead-name {
    flex: 1 1 100%; padding: 0 0 8px; border: 0;
  }
  .permtable td {
    flex: 1 1 0; width: auto; border: 0; border-radius: 9px;
    display: flex; flex-direction: column-reverse; justify-content: flex-end;
  }
  /* برچسبِ ستون کنارِ خودِ گزینه می‌آید، چون سرستون‌ها اینجا نیستند. */
  .permtable td::before {
    content: attr(data-label); display: block; font-size: .72rem;
    color: var(--muted); text-align: center; padding: 0 2px 7px;
  }
  .permpick { padding: 7px 4px 3px; }
  .permna { padding: 7px 4px 3px; }
  .rolegrants { flex-basis: 100%; white-space: normal; }
}

/* ─── جدولِ گزارش فعالیت ───
 *
 * `table-layout: fixed` با درصدهای صریح، به‌جای گذاشتنِ تقسیم به عهده‌ی
 * مرورگر. چیدمانِ خودکار عرض را از *محتوا* می‌گیرد و نه از معنا، و نتیجه
 * هر بار یک‌جور بد است: یک‌بار «دفتر مستر تتر» دو خط می‌شود، یک‌بار نامِ
 * کاربر می‌شکند و هر سطر دوخطی می‌شود.
 *
 * با درصد، نسبت‌ها در هر عرضی همان می‌مانند و همه‌چیز داخلِ خانه‌ی خودش
 * می‌شکند — نه بیرون می‌زند و نه جدول را پهن می‌کند.
 *
 * فقط روی دسکتاپ: پایین‌تر از ۸۶۰ جدول کارت می‌شود و هر خانه یک بلوکِ
 * تمام‌عرض است.
 */
@media (min-width: 861px) {
  .logtable { table-layout: fixed; }
  .logtable th:nth-child(1), .logtable td:nth-child(1) { width: 15%; }
  .logtable th:nth-child(2), .logtable td:nth-child(2) { width: 12%; }
  .logtable th:nth-child(3), .logtable td:nth-child(3) { width: 12%; }
  .logtable th:nth-child(4), .logtable td:nth-child(4) { width: 14%; }
  .logtable th:nth-child(5), .logtable td:nth-child(5) { width: 39%; }
  /* «سایت»/«ربات» کوتاه‌اند ولی نمی‌شکنند: با ۶٪ روی لپ‌تاپِ کوچک از
     خانه بیرون می‌زدند. کمی پهن‌تر، و با حاشیه‌ی جمع‌وجورتر. */
  .logtable th:nth-child(6), .logtable td:nth-child(6) {
    width: 8%; padding-inline: 6px;
  }

  /* با عرضِ ثابت، «نشکن» یعنی «بزن بیرون». پس همه‌جا اجازه‌ی شکستن —
     برچسبِ کار هم، که `.pill` بی‌قید نشکن است و روی لپ‌تاپِ کوچک
     («بازسازی دفتر معامله» در ستونی ۸۴ پیکسلی) از خانه بیرون می‌زد. */
  .logtable th, .logtable td { white-space: normal; }
  .logtable .pill { white-space: normal; }
  .logtable td { vertical-align: top; }
}

/* شکستنِ رشته‌ی نشکن، در هر عرضی: شرحِ یک مدرک می‌تواند آدرسِ کاملِ
   بلاک‌اکسپلورر یا یک TXID شصت‌ودوکاراکتری باشد و هیچ فاصله‌ای ندارد. */
.logtable td:nth-child(5) { overflow-wrap: anywhere; }

/* روی گوشی، «شرح» دو ستون است نه یک ردیفِ فلکس.
 *
 * با فلکس، مقدارِ بلند به خط بعد می‌رفت و برچسب تنها روی خطِ خودش
 * می‌ماند — کارت‌ها ناهموار می‌شدند. بردنِ همیشگیِ متن به خطِ بعد هم
 * یکنواخت بود ولی ریتمِ بقیه‌ی سطرها را می‌شکست: همه «برچسب راست، مقدار
 * کنارش»، و این یکی «برچسب تنها، مقدار زیرش».
 *
 * گرید هر دو را حل می‌کند: برچسب سرِ جای همیشگی‌اش می‌ماند و متن در ستونِ
 * خودش می‌شکند — کوتاه باشد یا سه‌خطی. متنِ آزادِ فارسی هم از لبه‌ی شروعِ
 * همان ستون خوانده می‌شود، نه چسبیده به لبه‌ی مخالف. */
@media (max-width: 860px) {
  .logtable td:nth-child(5) {
    display: grid; grid-template-columns: max-content 1fr; gap: 0 12px;
    text-align: start;
  }
  .logtable td:nth-child(5)::before { margin: 0; }
}

/* ─── نمودار خطی ───
   خط پررنگ است و سطحِ زیرش کم‌رنگ: چشم باید مسیر را دنبال کند، نه سطح را.
   نقطه‌ها کوچک‌اند تا در سی‌روزه به هم نچسبند. */
.lineplot {
  fill: none; stroke: var(--accent); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round;
}
.linearea { fill: var(--accent-bg); stroke: none; }
.linedot { fill: var(--accent); opacity: .55; }
.barslot:hover .linedot { opacity: 1; r: 3.2; }

/* ─── کلیدهای ربات بله (تنظیمات) ───
   چک‌باکس و متن باید *یک* هدف کلیک باشند: روی گوشی، زدنِ دقیقِ یک مربعِ
   ۱۳ پیکسلی کارِ سختی است و آدم فکر می‌کند کلید خراب است. */
.balerow {
  display: grid; grid-template-columns: auto 1fr; gap: 10px;
  align-items: start; cursor: pointer;
  border: 1px solid var(--border); border-radius: 10px;
  padding: 11px 13px; background: var(--surface);
}
.balerow:hover { border-color: var(--accent); }
.balerow input { margin-top: 4px; }
.balerow strong { font-weight: 600; margin-inline-end: 6px; }
.balerow em { display: block; color: var(--muted); font-style: normal;
              font-size: .82rem; margin-top: 3px; }
.balerow:has(input:not(:checked)) { opacity: .62; }
.balerow:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ─── کرکره‌ی جست‌وجوپذیر ───
   خودِ `select` اینجاست، فقط دیده نمی‌شود — با `opacity` و نه با
   `display: none`. پنج‌تا از این کرکره‌ها `required`اند و کروم برای نشان‌دادنِ
   خطا باید بتواند رویشان فوکوس کند؛ عنصرِ `display: none` فوکوس‌پذیر نیست و
   فرم آن‌وقت **بی هیچ پیامی** ثبت نمی‌شود. اینجا `select` جای واقعی دارد
   (هم‌اندازه‌ی کادر، درست زیرِ آن)، پس حبابِ خطای مرورگر هم سرِ جای درست
   می‌نشیند. */
.pick { position: relative; display: block; width: 100%; min-width: 0; }
.pick > select {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; pointer-events: none;
}
/* `relative` تا روی `select`ِ مطلق بنشیند، نه زیرش. */
.pick > .pick-show { position: relative; cursor: text; }
/* فلکس‌آیتم حالا این قاب است، نه `select`ِ داخلش. */
.partform .pick { flex: 1 1 110px; }

/* `fixed` و زیرِ `body`: پنلِ ثبت `overflow: hidden` دارد و فهرستی که
   داخلش باز شود بریده می‌شود — همان دردِ تقویم. جای‌گیری در pick.js است،
   پس اینجا نه `top` دارد نه `inset`. */
.pick-pop {
  position: fixed; z-index: 60;
  padding: 5px; display: flex; flex-direction: column;
  max-height: calc(100vh - 16px); overflow: hidden;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; box-shadow: 0 12px 34px rgba(0, 0, 0, .28);
}
.pick-pop[hidden] { display: none; }
.pick-list { overflow-y: auto; min-height: 0; }
.pick-item {
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  font-size: .89rem; line-height: 1.7;
}
.pick-item[hidden] { display: none; }
/* `on` همان چیزی است که Enter انتخابش می‌کند؛ باید از `hover` پررنگ‌تر
   نباشد ولی همیشه دیده شود، چون روی کیبورد ماوسی در کار نیست. */
.pick-item:hover { background: var(--surface-2); }
.pick-item.on { background: var(--accent-bg); color: var(--accent); }
/* گزینه‌ی نشدنی پاک نمی‌شود: دلیلِ نشدنش کنارِ نامش نوشته شده و همان
   دلیل، جوابِ سؤالی است که کاربر از نبودنِ نام می‌پرسید. */
.pick-item.is-off { color: var(--faint); cursor: not-allowed; }
.pick-item.is-off:hover { background: transparent; }
.pick-none { padding: 10px; font-size: .84rem; color: var(--faint); text-align: center; }

/* ─── پوششِ انتظار ───
   سامانه POST-و-ریدایرکت است؛ در فاصله‌ی ثبت تا صفحه‌ی بعد هیچ نشانه‌ای
   نبود و آدم دوباره کلیک می‌کرد. روی `/quick` که تا شصت ثانیه هم طول
   می‌کشد، نتیجه‌اش دو رکوردِ یکسان بود. */
.busy {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  animation: busy-in .18s ease-out;
}
.busy[hidden] { display: none; }
.busy-box {
  position: relative; display: flex; flex-direction: column;
  align-items: center; gap: 13px;
}
.busy-mark {
  /* بالای هاله، وگرنه آن مربعِ رنگی روی نشان می‌افتد: عنصرِ `absolute`
     همیشه بالای همسایه‌ی بی‌موقعیتش کشیده می‌شود. */
  position: relative; z-index: 1;
  width: 58px; height: 58px; display: block;
}
.busy-word { font-size: .88rem; color: var(--muted); }

/* هاله‌ی نبض‌دار پشتِ نشان. فقط `transform` و `opacity` — یعنی روی کارتِ
   گرافیک، بی‌آنکه صفحه دوباره چیده شود. */
.busy-halo {
  position: absolute; top: -9px; left: calc(50% - 38px); width: 76px; height: 76px;
  border-radius: 19px; background: var(--accent);
  animation: busy-halo 1.8s ease-out infinite;
}
/* خطِ صعودی خودش را می‌کشد. ۵۲ کمی بلندتر از طولِ واقعیِ مسیر (~۵۱) است
   تا در انتها سرِ خط تمیز بسته شود. */
.busy-line {
  stroke-dasharray: 52; stroke-dashoffset: 52;
  animation: busy-draw 1.8s ease-in-out infinite;
}
.busy-tip { opacity: 0; animation: busy-tip 1.8s ease-in-out infinite; }

@keyframes busy-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes busy-halo {
  0%   { transform: scale(.85); opacity: .30; }
  70%  { transform: scale(1.18); opacity: 0; }
  100% { transform: scale(1.18); opacity: 0; }
}
@keyframes busy-draw {
  0%   { stroke-dashoffset: 52; }
  45%  { stroke-dashoffset: 0; }
  78%  { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: 52; }
}
@keyframes busy-tip {
  0%, 42%   { opacity: 0; }
  55%, 78%  { opacity: 1; }
  100%      { opacity: 0; }
}

/* حرکت برای همه خوشایند نیست — و برای بعضی‌ها سرگیجه‌آور است. پیام باقی
   می‌ماند، نشان کامل و ساکن. */
@media (prefers-reduced-motion: reduce) {
  .busy { animation: none; }
  .busy-halo { display: none; }
  .busy-line { stroke-dashoffset: 0; animation: none; }
  .busy-tip { opacity: 1; animation: none; }
}
