/* TradeLab — layout.css : هدر، فوتر، سایدبار، اپ‌شل، بخش‌های سایت */

/* ============ برند ============ */
.brand{display:flex;align-items:center;gap:10px;text-decoration:none}
/* ⚠️ نشانِ برند — لوگوی رسمیِ کارفرما (خواسته‌ی ۱ از پیامِ «لوگو هس
   میتونی استفاده کنی»). پیش‌تر اینجا دو حرفِ «TL» تایپوگرافی می‌شد.

   چرا `mask-image` و نه `<img>`؟ چهار نقطه‌ی صدازدنِ `brand-mark` در
   کد هست (`login.html:57` و `ui.js` خطوطِ ۱۶۳/۱۹۶/۳۲۲). اگر تگِ
   تصویر بگذارم باید هر چهار جا را دست بزنم و هر جایی که از قلم
   بیفتد «TL» می‌ماند. با ماسک، **یک** قاعده‌ی CSS همه را می‌پوشاند و
   متنِ «TL» داخلِ تگ هم به‌طور خودکار ناپیدا می‌شود (رنگِ شفاف).

   مزیتِ دومِ ماسک: نشان رنگش را از `currentColor` می‌گیرد، پس در
   پس‌زمینه‌ی روشن/تیره و در حالتِ hover خودبه‌خود درست می‌ماند —
   کاری که PNGِ رنگی نمی‌تواند. */
.brand-mark{width:38px;height:38px;border-radius:11px;background:var(--brand-grad);
  color:transparent;font-size:0;line-height:0;
  display:grid;place-items:center;position:relative;
  box-shadow:0 6px 18px rgba(139,92,246,.32)}
.brand-mark::after{content:'';position:absolute;inset:19%;
  background:#fff;
  -webkit-mask:url('/media/logo_mark_white') center/contain no-repeat;
          mask:url('/media/logo_mark_white') center/contain no-repeat}
.brand.sm .brand-mark{width:32px;height:32px;border-radius:9px}
.brand-txt{display:flex;flex-direction:column;line-height:1.1;color:var(--tx-1);font-weight:800;font-size:16px}
.brand-txt small{font-size:10px;font-weight:500;color:var(--tx-3);letter-spacing:1.4px}
/* خواسته‌ی ۹ — شعارِ داخلِ لوگو. `letter-spacing` را صفر می‌کنم
   چون قاعده‌ی بالا برای واژه‌ی لاتینِ «TradeLab» نوشته شده بود و
   فاصله‌ی حروف در فارسی، واژه را از هم می‌پاشد. */
.brand-slog{letter-spacing:0 !important;font-size:9.5px !important;
  max-width:150px;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;direction:rtl}

/* ============ هدر عمومی ============ */
/* ══════════ اصلاحِ ۴ — ثابت‌ماندنِ منوی بالا هنگامِ اسکرول ══════════
   کارفرما: «منوی بالای صفحهٔ لندینگ موقعِ اسکرول کردن صفحه ثابت بماند.»

   ⚠️ ریشهٔ ایراد (سنجیده با مرورگرِ واقعی، نه حدس): `position:sticky`
      از پیش همین‌جا نوشته شده بود و به همین دلیل با grep همه‌چیز سالم
      به‌نظر می‌رسید. ولی `sticky` نسبت به **نزدیک‌ترین نیای اسکرول‌شونده**
      می‌چسبد، و هدر داخلِ `<div id="site-header">` تزریق می‌شود
      (`renderPublicHeader`). آن wrapper ارتفاعش به اندازهٔ خودِ هدر است،
      پس محدودهٔ چسبندگی صفر می‌شود و هدر با صفحه بالا می‌رود.
      سنجهٔ `tools/vsticky.py` پیش از اصلاح در هر ۸ صفحه `top=-1400`
      می‌داد؛ یعنی هدر کاملاً از دید خارج می‌شد.

   ⚠️ چرا wrapper را `sticky` کردم و نه خودِ `.hdr` را `fixed`؟
      `fixed` هدر را از جریانِ صفحه بیرون می‌بَرد و محتوای زیرش به
      اندازهٔ ارتفاعِ هدر بالا می‌پرد؛ آن‌وقت باید به همهٔ صفحه‌ها
      `padding-top` دستی بدهم — یعنی ۸ صفحه ریسکِ جابه‌جاییِ چیدمان.
      `sticky` روی wrapper جا را نگه می‌دارد و صفر تغییرِ چیدمان دارد. */
#site-header{position:sticky;top:0;z-index:var(--z-hdr,60)}
.hdr{position:sticky;top:0;z-index:var(--z-hdr,60);background:color-mix(in srgb,var(--bg-1) 86%,transparent);
  backdrop-filter:saturate(160%) blur(14px);border-bottom:1px solid var(--ln-1)}
.hdr-in{height:var(--header-h);display:flex;align-items:center;gap:18px}
.hdr-nav{display:flex;align-items:center;gap:2px;margin-inline-start:14px;flex:1}
.hdr-nav .nv,.mob-nav .nv{padding:8px 13px;border-radius:var(--r-md);color:var(--tx-2);text-decoration:none;
  font-size:14px;font-weight:500;transition:all var(--t-fast)}
.hdr-nav .nv:hover{color:var(--tx-1);background:var(--bg-3)}
.hdr-nav .nv.act{color:var(--brand-1);background:color-mix(in srgb,var(--brand-1) 12%,transparent);font-weight:700}
.hdr-act{display:flex;align-items:center;gap:8px}
.mob-nav{display:none;flex-direction:column;padding:8px 16px 16px;border-top:1px solid var(--ln-1);background:var(--bg-2)}
.mob-nav.open{display:flex}
.mob-only{display:none!important}
@media(max-width:900px){
  .hdr-nav{display:none}
  .mob-only{display:inline-flex!important}
}

/* ============ فوتر ============ */
.ftr{margin-top:80px;background:var(--bg-2);border-top:1px solid var(--ln-1);padding:52px 0 22px}
.ftr-grid{display:grid;grid-template-columns:2.2fr 1fr 1fr 1fr;gap:36px}
.ftr-brand p{color:var(--tx-3);font-size:13.5px;line-height:2;margin:14px 0 16px;max-width:380px}
.ftr-soc{display:flex;gap:9px}
.soc{width:36px;height:36px;border-radius:10px;background:var(--bg-3);border:1px solid var(--ln-1);
  display:grid;place-items:center;color:var(--tx-2);text-decoration:none;transition:all var(--t-fast)}
.soc:hover{background:var(--brand-1);color:#fff;border-color:transparent;transform:translateY(-2px)}
.ftr-col h3,.ftr-col h4{font-size:14px;margin-bottom:14px;color:var(--tx-1);font-weight:700;letter-spacing:0}
.ftr-col a{display:block;color:var(--tx-3);text-decoration:none;font-size:13.5px;padding:6px 0;transition:color var(--t-fast)}
.ftr-col a:hover{color:var(--brand-1)}
.ftr-btm{margin-top:38px;padding-top:20px;border-top:1px solid var(--ln-1);display:flex;
  justify-content:space-between;gap:20px;flex-wrap:wrap;color:var(--tx-4);font-size:12px}
.ftr-note{max-width:640px;line-height:1.9}
@media(max-width:860px){.ftr-grid{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.ftr-grid{grid-template-columns:1fr}}

/* ============ بخش‌های سایت ============ */
.sec{padding:74px 0}
.sec-sm{padding:48px 0}
.sec-head{text-align:center;max-width:720px;margin:0 auto 46px}
.sec-tag{display:inline-block;padding:5px 14px;border-radius:var(--r-full);font-size:12px;font-weight:700;
  background:color-mix(in srgb,var(--brand-1) 14%,transparent);color:var(--brand-1);margin-bottom:14px}
.sec-head h1,.sec-head h2{font-size:var(--fs-4xl);margin-bottom:14px;line-height:1.45;font-weight:800;letter-spacing:0}
.sec-head p{color:var(--tx-3);font-size:15.5px;line-height:2.1}

/* ============ هیرو ============ */
.hero{position:relative;padding:74px 0 60px;overflow:hidden}
/* هاله‌ی پشتِ هیرو: پیش‌تر دو گرادیانِ آبی/فیروزه‌ای بود. کارفرما
   بنفشِ بی‌گرادیان خواست، پس به یک هاله‌ی بنفشِ یکدستِ محو بدل شد
   (شفافیت + blur، نه تغییرِ رنگ در طولِ سطح). */
.hero::before{content:'';position:absolute;inset:-40% 10% auto -10%;height:620px;
  background:rgba(167,139,250,.13);
  border-radius:50%;filter:blur(90px);pointer-events:none;z-index:0}
.hero-in{position:relative;z-index:1;display:grid;grid-template-columns:1.05fr .95fr;gap:44px;align-items:center}
.hero h1{font-size:clamp(28px,4.2vw,50px);line-height:1.42;margin-bottom:20px;font-weight:900}
.hero .lead{font-size:17px;color:var(--tx-2);line-height:2.15;margin-bottom:26px;max-width:560px}
.hero-cta{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:24px}
.hero-trust{display:flex;gap:22px;flex-wrap:wrap;color:var(--tx-3);font-size:13px}
.hero-trust span{display:flex;align-items:center;gap:7px}
.hero-art{border-radius:var(--r-xl);border:1px solid var(--ln-2);background:var(--bg-2);overflow:hidden;
  box-shadow:0 30px 70px rgba(0,0,0,.36)}
@media(max-width:980px){.hero-in{grid-template-columns:1fr}.hero-art{order:-1}}

/* ============ کارت ویژگی ============ */
.feat{padding:26px;border-radius:var(--r-lg);border:1px solid var(--ln-1);background:var(--bg-2);
  transition:all var(--t)}
.feat:hover{border-color:color-mix(in srgb,var(--brand-1) 40%,transparent);transform:translateY(-4px);
  box-shadow:0 16px 40px rgba(0,0,0,.24)}
.feat .fi{width:48px;height:48px;border-radius:13px;display:grid;place-items:center;font-size:22px;
  background:color-mix(in srgb,var(--brand-1) 13%,transparent);margin-bottom:16px}
/* ══════════ بندِ ب۲ — آیکونِ کارتِ ویژگی ══════════
   ایموجی رنگِ خودش را همراه داشت؛ SVG رنگ را از `currentColor`
   می‌گیرد و در این کارت رنگِ ارثی خاکستریِ متن است، پس آیکون‌ها
   بی‌جان می‌شدند. رنگِ برند را می‌دهم — همان رنگی که پس‌زمینه‌ی
   ظرف از ۱۳٪ آن ساخته شده، پس چشم آن را یک مجموعه می‌بیند.
   اندازه لازم نبود دست بخورد: `svg.ic` از `1.15em` می‌آید و
   `font-size:22px`ِ همین ظرف اندازه‌اش را درست می‌کند. */
.feat .fi{color:var(--brand-1)}
.feat .fi svg.ic{width:24px;height:24px;vertical-align:0}
/* ══════════ خواسته‌ی ۲ + ۱۸ — آیکونِ تصویریِ کارت‌های امکانات ══════════
   این نُه کارت تصویرِ *معنایی* می‌گیرند نه آیکونِ رابط. تفاوت مهم است:
   آیکونِ رابط باید `currentColor` بگیرد (پس SVGِ درون‌خطی می‌ماند —
   سنجشِ پیکسلیِ درسِ ۲۵۰ ثابت کرد `<img src=svg>` رنگ‌پذیری را از دست
   می‌دهد)، ولی تصویرِ معنایی رنگِ خودش را دارد و باید از داشبورد
   تغییرپذیر باشد. پس این نُه‌تا `<img src="/media/feat_*">` هستند.

   ⚠️ دامِ AS — این قاعده‌ها **پس از** `.feat .fi{...}` نوشته شده‌اند.
      اگر بالاتر بودند، `width:48px` و `font-size:22px`ِ خطِ ۱۰۲ روی
      آن‌ها می‌چربید (هم‌ویژگی ⇒ دیرتر می‌برد) و هیچ خطایی هم دیده
      نمی‌شد. اندازه را در همان جعبه‌ی ۴۸ نگذاشتم چون تصویرِ معنایی
      در ۲۴ پیکسل ناخوانا می‌شود.
   ⚠️ دامِ AH — `font-size:22px` از دورانِ ایموجی مانده و روی `<img>`
      یک خطِ متنیِ خالی می‌سازد که ارتفاع اضافه می‌دهد. با
      `font-size:0` و `display:grid` (نه inline) بی‌اثرش می‌کنم. */
.feat .fi.fi-img{width:64px;height:64px;border-radius:16px;font-size:0;
  padding:9px;background:color-mix(in srgb,var(--brand-1) 11%,transparent);
  border:1px solid color-mix(in srgb,var(--brand-1) 22%,transparent)}
.feat .fi.fi-img img{width:100%;height:100%;object-fit:contain;display:block;
  /* تصویر پس‌زمینه‌ی تیرهٔ خودش را دارد؛ گوشه‌گردی تا با ظرف یکی شود */
  border-radius:9px}
.feat:hover .fi.fi-img{border-color:color-mix(in srgb,var(--brand-1) 45%,transparent)}

/* بندِ ب۲ — نشانِ فهرست‌ها. در فهرستی با `line-height:1.85`
   هم‌ترازیِ پیش‌فرضِ `-.16em` کجی‌اش دیده می‌شود. */
/* ⚠️ نامِ کلاس را نخست `.f-list` حدس زدم و grep نشان داد چنین کلاسی
   در پروژه **وجود ندارد**؛ نامِ واقعی `.fl` است. همان دامِ همیشگی:
   حدس‌زدنِ نامِ شناسه، قاعده‌ای می‌سازد که بی‌صدا هیچ‌کاری نمی‌کند. */
.plan li .ck svg.ic,.fl li .ck svg.ic{width:15px;height:15px;vertical-align:-.12em}
/* بندِ ب۲ — آیکونِ درونِ متن (نوارِ برجسته‌های صفحه‌ی خانه). */
.in-ic svg.ic{width:16px;height:16px;vertical-align:-.18em;color:var(--brand-1)}
.feat h3{font-size:17px;margin-bottom:9px}
.feat p{color:var(--tx-3);font-size:14px;line-height:2}

/* ============ آمار ============ */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
.stat{padding:22px;border-radius:var(--r-lg);border:1px solid var(--ln-1);background:var(--bg-2);text-align:center}
.stat b{display:block;font-size:30px;font-weight:900;background:var(--brand-grad);
  -webkit-background-clip:text;background-clip:text;color:transparent;margin-bottom:6px}
.stat span{color:var(--tx-3);font-size:13px}
@media(max-width:820px){.stats{grid-template-columns:repeat(2,1fr)}}

/* ============ تعرفه ============ */
.plans{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;align-items:stretch}
.plan{position:relative;padding:28px 24px;border-radius:var(--r-xl);border:1px solid var(--ln-1);
  background:var(--bg-2);display:flex;flex-direction:column;transition:all var(--t)}
.plan:hover{transform:translateY(-5px);box-shadow:0 20px 46px rgba(0,0,0,.26)}
.plan.pop{border-color:var(--brand-1);box-shadow:0 0 0 1px var(--brand-1),0 22px 50px rgba(139,92,246,.20)}
.plan-badge{position:absolute;top:-12px;inset-inline-start:50%;transform:translateX(50%);
  background:var(--brand-grad);color:#fff;font-size:11.5px;font-weight:800;padding:5px 15px;border-radius:var(--r-full)}
.plan h3{font-size:19px;margin-bottom:6px}
.plan .p-desc{color:var(--tx-3);font-size:13px;min-height:38px;line-height:1.9}
.plan .p-price{margin:16px 0 4px;font-size:30px;font-weight:900;color:var(--tx-1)}
.plan .p-price small{font-size:13px;font-weight:500;color:var(--tx-3)}
.plan .p-old{color:var(--tx-4);text-decoration:line-through;font-size:13px;margin-bottom:14px;min-height:18px}
.plan ul{list-style:none;margin:18px 0;flex:1;display:flex;flex-direction:column;gap:11px}
.plan li{display:flex;gap:9px;font-size:13.6px;color:var(--tx-2);line-height:1.85}
.plan li .ck{color:var(--up);flex-shrink:0;font-weight:800}
.plan li .nk{color:var(--tx-4);flex-shrink:0}
.plan li.off{color:var(--tx-4)}
@media(max-width:1050px){.plans{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.plans{grid-template-columns:1fr}}

/* ============ سایدبار اپ ============ */
/* ⚠️ و۵ — «سایدبار رو از چپ ببریم به راست».
   نقص یک واژه بود: `inset-inline-end`. در RTL، `inline-end` سمتِ **چپ**
   است، پس سایدبار در فارسی چپ می‌نشست در حالی که خودِ زبان از راست
   می‌آید و پنلِ مدیریت (که درست بود) راست می‌نشیند. دو صفحه‌ی یک
   محصول دو جور بودند.
   درمان: `inline-end` ⇒ `inline-start` (در RTL = راست). حاشیه هم
   قرینه شد: سایدبارِ راست، خطِ جداکننده‌اش روی لبه‌ی چپ است که در RTL
   همان `inline-end` است.
   چرا `inset-inline-*` و نه `right`/`left`: با نوشتنِ صریحِ `right:0`
   نسخه‌ی انگلیسیِ آینده‌ی سایت (dir=ltr) خراب می‌شد. توکنِ منطقی
   خودش با جهتِ سند می‌چرخد و همین قاعده هر دو زبان را می‌پوشاند. */
.app-body{--sb:var(--sidebar-w)}
.sb{position:fixed;inset-block:0;inset-inline-start:0;width:var(--sidebar-w);background:var(--bg-2);
  border-inline-end:1px solid var(--ln-1);display:flex;flex-direction:column;z-index:var(--z-sb,70);
  transition:transform var(--t)}
.sb-top{height:var(--header-h);display:flex;align-items:center;justify-content:space-between;
  padding:0 16px;border-bottom:1px solid var(--ln-1);flex-shrink:0}
.sb-nav{flex:1;overflow-y:auto;padding:14px 10px;scrollbar-width:thin}
.sb-grp{margin-bottom:16px}
.sb-gt{font-size:10.5px;font-weight:800;color:var(--tx-4);letter-spacing:1px;padding:0 10px 8px}
.sb-i{display:flex;align-items:center;gap:11px;padding:9px 11px;border-radius:var(--r-md);
  color:var(--tx-2);text-decoration:none;font-size:13.8px;font-weight:500;transition:all var(--t-fast);margin-bottom:2px}
.sb-i:hover{background:var(--bg-3);color:var(--tx-1)}
.sb-i.act{background:color-mix(in srgb,var(--brand-1) 14%,transparent);color:var(--brand-1);font-weight:700}
.sb-ic{width:22px;text-align:center;font-size:15px;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center}
/* و۶ — نقش‌ها از نویسه‌ی یونیکد به مسیرِ SVG رفتند (چراییِ کامل در
   ui.js بالای APP_NAV). سه نکته‌ی سنجیده در همین چند خط:
   • رنگ از `currentColor` می‌آید، پس حالتِ `.sb-i.act` و هر دو تم را
     خودبه‌خود ارث می‌برد و هیچ رنگِ سختی تکرار نمی‌شود؛
   • `fill:none` لازم است — پیش‌فرضِ SVG پرکردنِ سیاه است و مسیرهای
     بسته (مثلِ مربع‌های داشبورد) لکه‌ی توپُر می‌شدند؛
   • `stroke-linejoin/​cap: round` تا گوشه‌ها مثلِ فلشِ تقویم نرم باشد. */
.sb-ic svg{width:17px;height:17px;fill:none;stroke:currentColor;
  stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;display:block}
.sb-btm{padding:12px;border-top:1px solid var(--ln-1)}
.plan-card{padding:13px;border-radius:var(--r-md);background:var(--bg-3);border:1px solid var(--ln-1)}
.plan-row{display:flex;justify-content:space-between;font-size:12.5px;color:var(--tx-3);margin-bottom:10px}
.plan-row b{color:var(--brand-1)}
.sb-back{display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:calc(var(--z-sb,70) - 1)}
.sb-back.on{display:block}

.topbar{position:sticky;top:0;height:var(--header-h);display:flex;align-items:center;gap:12px;
  padding:0 22px;background:color-mix(in srgb,var(--bg-1) 88%,transparent);backdrop-filter:blur(12px);
  border-bottom:1px solid var(--ln-1);z-index:var(--z-hdr,60)}
.tb-title{flex:1;font-weight:800;font-size:16.5px;margin:0;line-height:1.6;letter-spacing:0}
.tb-act{display:flex;align-items:center;gap:7px}
.tb-act .dot{position:absolute;top:6px;inset-inline-end:6px;width:7px;height:7px;border-radius:50%;background:var(--down)}
/* ══ خواسته‌ی ۱۵ — تپشِ زنگ هنگامِ رسیدنِ اعلانِ نو ══
   رنگ از --brand-1 می‌آید نه از یک هکسِ تازه، تا در پوسته‌ی روشن و
   تیره هر دو درست بخواند. */
@keyframes notifPing{
  0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--brand-1) 55%,transparent)}
  70%{box-shadow:0 0 0 10px color-mix(in srgb,var(--brand-1) 0%,transparent)}
  100%{box-shadow:0 0 0 0 color-mix(in srgb,var(--brand-1) 0%,transparent)}
}
.notif-ping{animation:notifPing 1.3s ease-out 2;border-radius:50%}
/* کاربری که جنبش را خاموش کرده نباید تپش ببیند — ولی خبر هم نباید
   از دست برود، پس قابِ ثابت جایش را می‌گیرد. */
@media(prefers-reduced-motion:reduce){
  .notif-ping{animation:none;outline:2px solid var(--brand-1);outline-offset:2px}
}
.usr{display:flex;align-items:center;gap:9px;padding:5px 9px 5px 5px;border-radius:var(--r-full);
  background:var(--bg-3);border:1px solid var(--ln-1);cursor:pointer;color:var(--tx-1);font-size:13px;font-weight:600}
.usr:hover{border-color:var(--ln-2)}
.usr-n{max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media(max-width:700px){.usr-n{display:none}}

/* محتوای اصلی باید از همان سویی کنار بکشد که سایدبار رفته. با
   جابه‌جاییِ سایدبار به `inline-start`، این هم باید `start` شود؛
   وگرنه محتوا از یک سو فاصله می‌گیرد و از سوی دیگر زیرِ سایدبار
   می‌رود — یعنی منوی سمت راست روی متن می‌افتاد. */
.app-main{margin-inline-start:var(--sidebar-w);min-height:100vh;display:flex;flex-direction:column}
.app-content{padding:24px;flex:1}
@media(max-width:1000px){
  .app-main{margin-inline-start:0}
  /* در گوشی سایدبار پنهان می‌شود و باید به **بیرونِ همان لبه‌ای** بلغزد
     که رویش نشسته: در RTL لبه‌ی راست ⇒ ‎+100%‎؛ در LTR لبه‌ی چپ ⇒ ‎-100%‎.
     پیش‌تر این دو برعکس بود (چون سایدبار آن‌سو بود) و اگر دست نمی‌زدم،
     منو در گوشی از سمتِ اشتباه می‌آمد یا وسطِ صفحه گیر می‌کرد. */
  .sb{transform:translateX(-100%)}
  html[dir="rtl"] .sb{transform:translateX(100%)}
  .sb.open{transform:translateX(0)!important}
}

/* ============ گرید داشبورد ============ */
/* ⚠️ و۷ — «باکس‌های داشبورد جای خالی می‌ذارن، در یک ردیف مرتبشون کنیم».
   ریشه‌ی نقص: `grid-template-columns:repeat(auto-fit,minmax(190px,1fr))`.
   `auto-fit` شمارِ ستون را از **عرض** می‌گیرد و به **شمارِ کارت‌ها** کاری
   ندارد. سنجیدم: در ۱۴۴۰px پنج ستون می‌سازد و کارت‌ها ۸ تاست ⇒ ۵+۳ و
   دو خانه‌ی خالی در ردیفِ دوم. کارفرما همین حفره را دید.

   چرا «ستونِ ثابت» درمانش نیست: با ۴ ستون، ۸ کارت درست می‌شود ولی در
   عرضِ میانی که ۳ ستون می‌شود باز ۸٪۳=۲ حفره می‌مانَد. هر شمارِ ستونِ
   ثابتی برای بعضی شمارِ کارت‌ها حفره می‌سازد.

   درمانِ ریشه‌ای: از grid به **flex-wrap با رشد** می‌روم. `flex:1 1 190px`
   یعنی «کمینه ۱۹۰px، ولی جای خالیِ ردیف را بین خودتان پُر کنید». پس
   ردیفِ آخر هم مثل ردیف‌های دیگر **تا لبه** کشیده می‌شود و حفره — در هر
   عرض و با هر شمارِ کارت — ناممکن می‌شود، نه اینکه برای این یک صفحه
   وصله شود.
   بهایش: کارت‌های ردیفِ آخر کمی پهن‌تر از بالا می‌شوند. سنجیدم که در
   شمارهای واقعیِ این پروژه (۴، ۶، ۸) ردیف‌ها برابر درمی‌آیند، و دو
   لبه‌ی صاف از حفره‌ی وسط بسیار منظم‌تر دیده می‌شود. */
/* ⚠️ خواسته‌ی ۱۳ — «۸ باکس مساوی ۴تا۴تا در دو سطر».
   پیش‌تر `display:flex; flex-wrap:wrap` بود و شمارِ کارتِ هر ردیف به
   عرضِ دید بسته می‌شد (در ۱۵۰۰ پنج‌تا، در ۱۹۲۰ هشت‌تا در یک ردیف)، پس
   «۴+۴» هیچ‌گاه تضمین نبود و کارت‌های ردیفِ آخر پهن‌تر می‌افتادند.
   با `grid` و چهار ستونِ برابر، تقسیم ۴+۴ **قطعی** می‌شود.
   نکته‌ی دوم و مهم‌تر: در flex-wrap کشیدگیِ `stretch` تنها درونِ هر
   خط عمل می‌کند، ولی در grid ردیف‌ها با `grid-auto-rows:1fr` هم‌قدِ
   یکدیگر می‌شوند — یعنی ریشه‌ی ناهم‌قدیِ درسِ ۲۴۰ از بنیاد برداشته
   می‌شود. در عرض‌های کوچک‌تر ۲ ستون و در موبایل ۱ ستون. */
.kpis{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  grid-auto-rows:1fr;gap:14px;margin-bottom:20px}
.kpis>*{min-width:0}
/* ══ خواسته‌ی ۱۳ — «هشت جعبه باید ۴+۴ شوند» ══
   عکسِ کارفرما (پهنای ۱۰۲۴) شبکه را دوستونی نشان داد، چون نقطه‌شکن
   روی ۱۱۰۰px بود. آزمودم: با ۴ستونیِ اجباری، ستون ۱۷۱px می‌شود و
   «-$۲,۹۵۷» و «۴۲/۱۰۰» بریده می‌شوند (ایرادِ درسِ ۲۴۰). در ۱۱۰۰px
   ستون ۱۹۰px است و هیچ بریدگی نیست.
   پس: نقطه‌شکن به ۱۰۷۹ آمد و برای بازه‌ی ۱۰۸۰..۱۲۴۰ جعبه فشرده‌تر
   می‌شود تا ۴+۴ بی‌بریدگی برسد. زیرِ ۱۰۸۰ دو ستون می‌مانَد، چون
   آنجا ۴ستونی یعنی عددِ بریده — و عددِ بریده از دو ستون بدتر است. */
@media(max-width:1079px){.kpis{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:560px){.kpis{grid-template-columns:1fr}}
.kpi{padding:18px;border-radius:var(--r-lg);border:1px solid var(--ln-1);background:var(--bg-2);position:relative;overflow:hidden}
.kpi-t{font-size:12.5px;color:var(--tx-3);margin-bottom:9px;display:flex;align-items:center;gap:6px}
.kpi-v{font-size:25px;font-weight:900;line-height:1.2}
.kpi-s{font-size:12px;color:var(--tx-4);margin-top:6px}
.kpi.up .kpi-v{color:var(--up)} .kpi.down .kpi-v{color:var(--down)}
/* شکلِ بی‌کلاسِ کارت شاخص: `<div class="kpi"><small>برچسب</small><b>مقدار</b></div>`.
   پنج جا در چهار صفحه (calendar ۱۶۴ و ۲۵۵، dashboard ۲۱۲، referral، strategies)
   این شکل را می‌سازند، ولی قاعده‌ها فقط برای `.kpi-t`/`.kpi-v` نوشته شده بود.
   نتیجه: `small` و `b` هر دو inline می‌ماندند و **صفر پیکسل** فاصله
   می‌گرفتند، یعنی کاربر «تعداد معامله۲۲» سرهم می‌دید. اندازه‌گیری‌شده:
   `gapX=0` و هر دو روی یک خط، در هر چهار کارت.
   درمان را اینجا و یک‌بار می‌گذارم تا هر پنج جا و صفحه‌های آینده با هم
   حل شوند؛ سراغ تک‌تک قالب‌ها رفتن هم پرخطاست و هم تکرارشدنی. */
.kpi>small{display:block;font-size:12.5px;color:var(--tx-3);margin-bottom:9px}
.kpi>b{display:block;font-size:25px;font-weight:900;line-height:1.2}
.kpi>b.up{color:var(--up)} .kpi>b.down{color:var(--down)}
.kpi::after{content:'';position:absolute;inset-block-start:0;inset-inline-start:0;width:3px;height:100%;background:var(--brand-1);opacity:.7}
.kpi.up::after{background:var(--up)} .kpi.down::after{background:var(--down)}

.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.grid-2-1{display:grid;grid-template-columns:2fr 1fr;gap:16px}
@media(max-width:980px){.grid-2,.grid-3,.grid-2-1{grid-template-columns:1fr}}

/* ============ صفحه‌بندی ============ */
.pager{display:flex;align-items:center;gap:6px;margin-top:16px;flex-wrap:wrap}
/* ⚠️ درسِ ۲۴۱ — ارقامِ هم‌عرض برای شماره‌ی صفحه‌ها.
   `vnumfont` گرفت: این دکمه‌ها `font-variant-numeric:normal` داشتند و
   «۱» و «۲» پهنای متفاوت می‌گرفتند، پس با هر تغییرِ صفحه دکمه‌ها کمی
   می‌لرزیدند. چرا دیرتر گرفته شد؟ چون تا جلسه‌ها به بیش از یک صفحه
   نرسیده بودند، صفحه‌بند رندر نمی‌شد و ادعا به آن نمی‌رسید — پوششِ
   سنجه‌ای که روی داده‌ی زنده می‌گردد، خودش زنده است. */
.pg{min-width:34px;height:34px;padding:0 9px;border-radius:var(--r-md);border:1px solid var(--ln-1);
  background:var(--bg-2);color:var(--tx-2);cursor:pointer;font-size:13px;font-weight:600;
  font-variant-numeric:tabular-nums lining-nums;font-feature-settings:'tnum' 1}
.pg:hover:not(:disabled){border-color:var(--brand-1);color:var(--brand-1)}
.pg.act{background:var(--brand-1);color:#fff;border-color:var(--brand-1)}
.pg:disabled{opacity:.4;cursor:not-allowed}
.pg-info{margin-inline-start:auto;color:var(--tx-4);font-size:12.5px}

/* ============ ابزارک‌ها ============ */
.toolbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:16px}
.toolbar .grow{flex:1}
.chip{padding:5px 12px;border-radius:var(--r-full);border:1px solid var(--ln-1);background:var(--bg-2);
  font-size:12.5px;color:var(--tx-2);cursor:pointer;transition:all var(--t-fast)}
.chip:hover{border-color:var(--ln-2)}
.chip.act{background:var(--brand-1);color:#fff;border-color:var(--brand-1)}

/* ============ توست/مودال تکمیلی ============ */
.t-ic{width:20px;height:20px;border-radius:50%;display:grid;place-items:center;font-size:12px;
  font-weight:800;flex-shrink:0;background:rgba(255,255,255,.18)}
.t-msg{flex:1;line-height:1.8}
.t-x{background:none;border:0;color:inherit;opacity:.7;cursor:pointer;font-size:17px;line-height:1}
.t-x:hover{opacity:1}
.cm-msg{line-height:2.1;color:var(--tx-2);font-size:14.5px}
.modal-x{background:none;border:0;color:var(--tx-3);font-size:23px;cursor:pointer;line-height:1}
.modal-x:hover{color:var(--tx-1)}

/* ============ کمکی ============ */
.up{color:var(--up)!important} .down{color:var(--down)!important} .flat{color:var(--tx-3)!important}
.muted{color:var(--tx-3)}
.center{text-align:center}
.nowrap{white-space:nowrap}
.hidden,[hidden]{display:none!important}
.mt-0{margin-top:0} .mb-0{margin-bottom:0}
.sp-8{height:8px} .sp-16{height:16px} .sp-24{height:24px} .sp-40{height:40px}

/* --- اصلاحات تکمیلی --- */
.plan .p-price small{margin-inline-start:7px;display:inline-block}
.plan{position:relative;display:flex;flex-direction:column}
.lnk{color:var(--brand-1);cursor:pointer;font-weight:600;text-decoration:none}
.lnk:hover{text-decoration:underline}

/* ═══ بندِ ۳ — آیکونِ متناسب داخلِ ۸ باکسِ شاخصِ داشبورد ═══
   چرا `position:absolute` و نه یک ردیفِ flex در بالای کارت؟
   دو دلیلِ اندازه‌گیری‌شده:
   ۱) مقدارِ کارت (`.kpi-v`) ۲۵px و درشت است؛ اگر آیکون هم‌ردیفِ عنوان
      در جریانِ عادی بنشیند، ارتفاعِ کارت ۳۸px بلندتر می‌شود و چون
      `.kpis` از `flex-wrap` استفاده می‌کند، ردیف‌ها ناهم‌قد می‌شوند.
   ۲) عنوان‌ها طولِ متفاوت دارند («انتظار ریاضی» تا «طولانی‌ترین زنجیره باخت»)؛
      در جریانِ عادی آیکون هر کارت جای دیگری می‌افتاد. absolute همه را
      روی یک مختصاتِ ثابت قفل می‌کند.
   `inset-inline-end` است نه `right` تا در LTR هم درست بماند. */
/* ⚠️ درسِ ۲۴۰ — عددِ این فاصله را با خط‌کش تعیین کن، نه با احتیاطِ کلی.
   ۶۸px بودم و آیکن فقط ۵۶px می‌خواهد (عرضِ ۴۲ + فاصله‌ی ۱۴ از لبه)؛
   آن ۱۲px هرز، عرضِ سطرِ عنوان را می‌خورد و «سود/زیان خالص» — که با
   نشانِ روند هم‌سطر است — دقیقاً ۵px کم می‌آورد و «سود/زیان خال..»
   دیده می‌شد. هیچ‌یک از ۶۵ سنجه این را نگرفت چون همه‌شان «یک‌خطی
   ماندن» و «هم‌قدی» را می‌سنجیدند، و متنِ بریده هر دو شرط را برمی‌آورد.
   ۶۰px می‌گذارم: ۴px فاصله‌ی امن تا آیکن، و ۸px بازگشته به عنوان. */
/* ۱۴۰۵/۰۶/۱۶ — تنها کارتی که آیکون دارد جای آیکون را نگه می‌دارد.
   در استراتژی‌ها و تقویم کارت‌ها بی‌آیکون‌اند و این ۶۰px لبه‌ی چپِ
   هر کارت را خالی می‌گذاشت؛ کارفرما همین را «فاصله‌ی نامنظم» دید. */
.kpi:has(>.kpi-ic){padding-inline-end:60px}
.kpi-ic{position:absolute;top:14px;inset-inline-end:14px;pointer-events:none}
.kpi-ic .ic-box{width:42px;height:42px;border-radius:12px}
.kpi-ic .ic-box svg.ic{width:21px;height:21px}
/* رنگِ آیکون از وضعیتِ کارت پیروی می‌کند تا سود/زیان با یک نگاه خوانده شود */
.kpi.up   .kpi-ic .ic-box{color:var(--up);
  background:color-mix(in srgb,var(--up) 14%,transparent);
  border-color:color-mix(in srgb,var(--up) 30%,transparent)}
.kpi.down .kpi-ic .ic-box{color:var(--down);
  background:color-mix(in srgb,var(--down) 14%,transparent);
  border-color:color-mix(in srgb,var(--down) 30%,transparent)}
@media (max-width:560px){
  .kpi:has(>.kpi-ic){padding-inline-end:60px}
  .kpi-ic .ic-box{width:36px;height:36px}
  .kpi-ic .ic-box svg.ic{width:18px;height:18px}
}

/* ══════════ خواسته‌ی ۱۳ — فشردگیِ کارت تا «۴+۴» بی‌بریدگی برسد ══════════
   عکسِ کارفرما (پهنای ۱۰۲۴) شبکه را دوستونی نشان داد چون نقطه‌شکن
   روی ۱۱۰۰px بود. با آوردنش به ۱۰۷۹، شبکه از ۱۰۸۰px چهارستونی شد —
   ولی ستون ۱۸۵px می‌شود و عددِ «+$۲۸,۲۳۴» (پنج رقم + جداکننده +
   نشانه + دلار) در آن جا نمی‌شود.

   ⚠️ این قاعده‌ها **باید اینجا باشند، نه بالاتر.** نخست کنارِ
   `.kpis` نوشتم‌شان و بی‌اثر ماندند: `.kpi-v{font-size:25px}` و
   `.kpi{padding-inline-end:60px}` پایین‌ترند و در CSS با ویژگیِ
   یکسان، قاعده‌ی پسین می‌برد (media query ویژگی را بالا نمی‌برد).
   سنجه گرفتش — عنصر همچنان ۲۵px و ۶۰px داشت، هرچند من ۱۸px و ۳۴px
   نوشته بودم. خواهرِ درسِ ۲۴۵، با سرچشمه‌ی «ترتیبِ نوشتار» نه
   «محلِ نوشتار».

   دو پله، هر دو با اندازه‌گیری:
     ۱۲۴۱..۱۰۸۰ ⇒ کارتِ فشرده (ستونِ ۱۸۵..۲۲۵px)
     ۱۱۲۰..۱۰۸۰ ⇒ یک پله تنگ‌تر، چون ستونِ ۱۸۵px حتی با پله‌ی یکم
                   عددِ پنج‌رقمیِ علامت‌دار را می‌بُرید. */
@media(max-width:1240px) and (min-width:1080px){
  .kpi{padding:14px}
  .kpi:has(>.kpi-ic){padding-inline-end:44px}
  .kpi-t{font-size:11.6px;margin-bottom:7px}
  .kpi-v{font-size:20px}
  .kpi-ic{top:11px;inset-inline-end:11px}
  .kpi-ic .ic-box{width:34px;height:34px;border-radius:10px}
  .kpi-ic .ic-box svg.ic{width:17px;height:17px}
}
@media(max-width:1120px) and (min-width:1080px){
  .kpi{padding:12px}
  .kpi:has(>.kpi-ic){padding-inline-end:34px}
  .kpi-t{font-size:10.8px}
  .kpi-v{font-size:17px}
  .kpi-ic{top:9px;inset-inline-end:9px}
  .kpi-ic .ic-box{width:28px;height:28px;border-radius:9px}
  .kpi-ic .ic-box svg.ic{width:15px;height:15px}
}

/* بندِ ۳ (پیوست) — عنوانِ کارت باید **همیشه یک خط** بماند.
   سنجه‌ی vkpiic اندازه گرفت: با افزودنِ آیکون، عنوانِ دو کارتِ نخست
   (که `trendTag` هم دارند) می‌شکست — ارتفاعِ عنوان ۴۶px و ۳۱px شد در
   برابر ۲۳px بقیه — و چون `.kpis` از flex-wrap استفاده می‌کند، ردیفِ
   اول ۱۵۱px و ردیفِ دوم ۱۲۸px درآمد. راهِ درست «رزروِ دو خط» نیست
   (فضای هرز)، بلکه جلوگیری از شکستن است: عنوان در `.kpi-tl` بسته شد
   تا ellipsis بگیرد و نشانِ روند هرگز به خطِ دوم نرود. */
/* ⚠️ درسِ ۲۴۰ — `nowrap` مسئله را از «شکستنِ سطر» به «بریدنِ متن» جابه‌جا
   کرد، نه حل. اندازه‌گیری در ۱۴۴۰/۱۴۶۰/۱۵۰۰/۱۶۰۰/۱۹۲۰ نشان داد در
   عرض‌های پهن‌تر کارت‌ها **باریک‌تر** می‌شوند (چون `flex:1 1 190px` است و
   ردیف کارت‌های بیشتری می‌گیرد)، پس سطرِ ۱۱۱پیکسلی باید ۸۰px عنوان و
   ۶۰px نشان را با هم جا کند — نشدنی. اجازه می‌دهم نشان به خطِ دوم برود:
   عنوان کامل خوانده می‌شود و هم‌قدیِ کارت‌ها با `min-height` و کشیدگیِ
   flex حفظ می‌شود. خوانایی بر فشردگی مقدم است. */
/* ⚠️ درسِ ۲۴۰ (پایانی) — ۳۸px = رزروِ دو خط، آگاهانه.
   `.kpis` یک flex-wrap است و در flex-wrap کشیدگیِ stretch تنها درونِ
   هر خط عمل می‌کند؛ پس عنوانِ دوخطی، ردیفِ خودش را ۱۴px بلندتر می‌کرد
   ([۱۲۸, ۱۴۲]) و سنجه‌ی «ارتفاعِ همه‌ی کارت‌ها یکسان» گرفتش. با رزروِ
   ثابتِ دو خط، ارتفاعِ سطرِ عنوان از طولِ متن مستقل می‌شود و همه‌ی
   کارت‌ها — در هر ردیف و هر عرضِ دید — هم‌قد می‌مانند. */
.kpi-t{flex-wrap:wrap;overflow:hidden;min-height:38px;row-gap:2px;
  align-content:flex-start}
.kpi-tl{overflow:hidden;text-overflow:ellipsis;min-width:0;flex:1 1 100%;
  /* درسِ ۲۴۰ — عنوانِ بلند در کارتِ باریک باید بشکند، نه بریده شود؛
     هم‌قدیِ کارت‌ها را `min-height` و stretch نگه می‌دارد و سنجه‌ی
     «ارتفاعِ همه‌ی کارت‌ها یکسان» نگهبانِ همین گمان است. */
  overflow-wrap:anywhere}
.kpi-t > span:not(.kpi-tl){flex:none}

/* بندِ ۲۴ — آیکونِ درونِ نشانِ توست و نشان‌های شبکه‌ی اجتماعی */
.t-ic svg.ic{width:13px;height:13px;vertical-align:0}
.soc svg.ic{width:18px;height:18px;vertical-align:0}
/* دکمه‌ی بستنِ توست: نویسه‌ی «×» بود، حالا SVG */
.t-x svg.ic{width:13px;height:13px;vertical-align:0}

/* بندِ ۳ — نشانِ روند در عنوانِ کارت. `nowrap` و `line-height:1` واجب‌اند:
   بدونشان این span درونِ عنوان می‌شکست و ارتفاعِ عنوان از ۲۳ به ۳۱px
   می‌رفت، و چون `.kpis` از flex-wrap استفاده می‌کند، ردیفِ اولِ کارت‌ها
   ۸px بلندتر از ردیفِ دوم درمی‌آمد. */
.kpi-tr{font-size:11.5px;font-weight:700;white-space:nowrap;line-height:1;
  display:inline-flex;align-items:center;gap:3px;flex:none}
.kpi-tr svg.ic{vertical-align:0}

/* ══════════ خواسته‌ی ۱۸ — نوارِ بنرِ سربرگِ صفحه‌های عمومی ══════════
   کلاسِ نو است (شمارشِ ۰ پیش از نوشتن)، پس چیزی را بازنویسی نمی‌کند.
   `aspect-ratio` به‌جای `height` تا در هر پهنایی نسبت حفظ شود و
   جهشِ چیدمان (CLS) پیش نیاید؛ `width`/`height` روی خودِ `<img>` هم
   نوشته شده تا مرورگر پیش از رسیدنِ تصویر جا را رزرو کند. */
.hero-band{margin:26px auto 0;max-width:1080px;border-radius:var(--r-lg);
  overflow:hidden;border:1px solid var(--ln-1);background:var(--bg-3);
  aspect-ratio:1600/700;line-height:0}
.hero-band img{width:100%;height:100%;object-fit:cover;display:block}
@media(max-width:760px){.hero-band{margin-top:18px;border-radius:var(--r-md)}}

/* ══════════ خواسته‌ی ۱۸ — بنرِ سربرگِ صفحه‌های عمومی ══════════
   ⚠️ این کلاس پیش از نوشتن ۰ تعریف داشت (سنجیدم، حدس نزدم) — پس
      اگر تعریفش نمی‌کردم، `<div class="pg-hero">` هیچ اثری نداشت و
      تصویر با ابعادِ خامِ ۱۶۰۰ پیکسل بیرون می‌زد. همان دامِ «نامِ
      ساختگی خاموش است».

   `aspect-ratio` را از ابعادِ توصیه‌شده‌ی همین رسانه می‌گیرم تا حتی
   پیش از بارگذاریِ تصویر، جای آن رزرو شود و صفحه نپرد (CLS صفر). */
.pg-hero{margin:26px auto 0;max-width:1000px;border-radius:var(--r-lg);
  overflow:hidden;border:1px solid var(--ln-1);background:var(--bg-2);
  aspect-ratio:1600/700}
.pg-hero img{width:100%;height:100%;object-fit:cover;display:block}
@media(max-width:720px){.pg-hero{margin-top:18px;border-radius:var(--r-md)}}

/* ══════════ خواسته‌ی ۲ + ۱۸ — نشانِ تصویریِ بخش‌های صفحه‌ی امکانات ══════════
   چهار بخشِ اصلی (بازپخش، ژورنال، پراپ‌فرم، مربیِ هوشمند) نشانِ
   تصویریِ خودشان را می‌گیرند. این «آیکونِ صفحه‌ای» است — تصویرِ
   معناییِ بزرگ — نه آیکونِ رابط؛ پس تصویر بودنش درست است و از
   داشبورد هم تغییرپذیر می‌ماند.

   ⚠️ کلاسِ `.sec-ic` پیش از این ۰ تعریف داشت (سنجیدم). `aspect-ratio`
      مربع است تا پیش از بارگذاری هم جای تصویر رزرو شود. */
.sec-ic{width:56px;height:56px;border-radius:15px;padding:8px;margin-bottom:13px;
  background:color-mix(in srgb,var(--brand-1) 13%,transparent);aspect-ratio:1}
.sec-ic img{width:100%;height:100%;object-fit:contain;display:block}
