/* ═══════════════════════════════════════════════════════════════════════════
   system.css — the design system for مرکز نوآوری بالینی یاس
   ───────────────────────────────────────────────────────────────────────────
   WHAT THIS IS NOT: an extraction of site.css. The old palette, radii and
   shadows are a prototype's accidents, not decisions, and none of them are
   inherited here. site.css keeps running the pages that have not migrated.

   OPTING IN: nothing in this file applies until an element carries
   data-surface. Load it anywhere; a page changes only when you write
   <html data-surface="paper"> or <body data-surface="dark">. That is what
   makes migrating one page at a time safe.

   SURFACE, NOT THEME. This product has two grounds and they are not a user
   preference — they are what the surface IS. Dark: landing, marketing, the
   projector. Paper: canvases, print, long reading. A canvas is on paper
   because it gets photocopied, not because someone likes light mode.

   ADDING TO THIS FILE — the rule that matters most:
   New work is born here. When you design a component that does not exist
   yet, write it in this file from the start; do not build it inside a page
   and promise to extract it later. What must NOT happen is the reverse —
   an old pattern climbing in just because it exists. Old patterns re-earn
   their place or stay where they are.
   A component enters on its SECOND real use, never the first, never
   speculatively. One use is a page's business.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Vazirmatn carries every word that is not a display heading, so it belongs
   here beside Lalezar rather than in one page's <style> block. It lived only in
   index.html and site.css, which meant advisor3 -- which loads the design system
   and nothing else -- had Lalezar for its headings and TAHOMA for every line of
   body text, on every visit, for as long as it has existed. Nothing reports a
   missing @font-face; the page simply renders in the fallback and looks
   subtly, unplaceably wrong. The pages that still carry their own copies are
   harmless duplicates, but this is the definition. */
@font-face{
  font-family:'Vazirmatn RD';
  src:url('/assets/fonts/Vazirmatn-RD-Light.woff2') format('woff2');
  font-weight:300;font-display:swap;
}
@font-face{
  font-family:'Vazirmatn RD';
  src:url('/assets/fonts/Vazirmatn-RD-Regular.woff2') format('woff2');
  font-weight:400;font-display:swap;
}
@font-face{
  font-family:'Vazirmatn RD';
  src:url('/assets/fonts/Vazirmatn-RD-Medium.woff2') format('woff2');
  font-weight:500;font-display:swap;
}
@font-face{
  font-family:'Vazirmatn RD';
  src:url('/assets/fonts/Vazirmatn-RD-Bold.woff2') format('woff2');
  font-weight:700;font-display:swap;
}

/* Lalezar carries every display size. It is woff, not woff2 like the Vazirmatn
   files — 113KB against roughly 80 — because no converter was on hand. Swap in
   a woff2 from Google Fonts when convenient and add it before this line.
   font-display:swap means it never blocks a render either way. */
@font-face{
  font-family:'Lalezar';
  src:url('/assets/fonts/Lalezar-Regular.woff') format('woff');
  font-weight:400;font-display:swap;
}

/* ── brand constants — the same on every surface ────────────────────────── */
:root{
  /* the two brand colours. Everything else is a ground or a neutral. */
  --y-orange:#E95F23;        /* screen */
  --y-orange-print:#B34515;  /* on paper, where #E95F23 measures 3.4:1 as text */

  /* The teal is the design system's own -- it is the «درک» phase colour and it
     is what «سبزآبی» means here. Two values for the same reason the orange has
     two: white on #1F8FA0 measures 3.82:1, which is under the floor for a
     button label, so anything carrying white text takes the darker one.
     Use --y-teal for a fill, a mark or a rule; --y-teal-ink when a word sits
     on top of it.
     The ink went from #17808F to #15788A on 2026-09-04: as the label of the
     profile sheet's «خرید اعتبار» button it measured 4.49 against --y-raise,
     which is a failure by a hundredth and reads exactly like a pass. Nothing
     but walking the rendered text and measuring it finds that one. 4.97 now. */
  --y-teal:#1F8FA0;
  /* --y-teal-ink is NOT a constant and is declared per surface below. It was
     here, and #15788A is tuned to clear 4.5:1 on paper -- on the dark sheet it
     measures 3.4, which is what «خرید اعتبار» became the moment that sheet went
     dark. A colour named "ink" is a relationship with a ground, not a brand
     value; --y-teal, the fill, is the constant. */

  /* Reserved for the one thing on this site that is genuinely time-critical:
     the checkout button once a session is nearly over. White holds 5.17:1. */
  --y-danger:#C2402B;

  /* the route rule. The five-step bar, the canvas navigator, the icon set and
     the background tile all derive from these four numbers — change one and
     every one of them moves. */
  --y-u:28px;                /* grid unit */
  --y-stroke:var(--y-u);     /* stroke width equals the unit, always */
  --y-turn:calc(var(--y-u) / 2);   /* corner radius */
  --y-gate:calc(var(--y-u) * 0.75);/* gate dot diameter */

  /* spacing — a scale, not a set of guesses */
  --y-1:4px; --y-2:8px; --y-3:12px; --y-4:16px; --y-5:24px;
  --y-6:32px; --y-7:48px; --y-8:72px; --y-9:112px;

  /* Persian needs the line-height. This is not a preference either. */
  --y-lh-body:1.85;
  --y-lh-tight:1.15;

  --y-sans:'Vazirmatn RD','Vazirmatn',Tahoma,sans-serif;
  --y-display:'Lalezar','Vazirmatn RD','Vazirmatn',Tahoma,sans-serif;

  /* Back to what the brand book actually draws (Figma «۱۳ · اجزای رابط کاربری»).
     This was squared on 2026-09-01 with the reasoning that a pill next to square
     panels and square fields was the only rounded thing on the page, so
     consistency beat the reference. That was the wrong half to give up: the
     answer to one rounded thing among squares is to round the others, not to
     square the one. Squared, the whole product read as «زمخت» rather than
     modern — Amin's word, and he is right.
     Three shapes, and they are the book's: a pill for anything you press, a
     generous corner for a card, a smaller one for a field. */
  --y-radius:14px;        /* cards, panels, sheets — the default */
  --y-radius-sm:10px;     /* fields, chips, anything small and boxy */
  --y-radius-btn:999px;   /* buttons are pills */

  /* Two marks, drawn rather than typed. They were the characters "⚠" and "✓",
     and ⚠ (U+26A0) is in the emoji block: a good half of platforms substitute
     the colour emoji ⚠️ for it, so an error in a Persian sentence arrived
     wearing a yellow cartoon triangle that took none of the surface's colours
     and turned to a grey smudge on a photocopy. Applied through `mask` with
     `background:currentColor`, they inherit colour like text and have no font
     to disagree with them. Use --y-mark, which sets everything but the shape. */
  --y-mk-warn:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3.2 22.3 21H1.7L12 3.2Zm0 4.4a1.15 1.15 0 0 0-1.15 1.22l.35 5.3a.8.8 0 0 0 1.6 0l.35-5.3A1.15 1.15 0 0 0 12 7.6Zm0 8.5a1.25 1.25 0 1 0 0 2.5 1.25 1.25 0 0 0 0-2.5Z'/%3E%3C/svg%3E");
  --y-mk-tick:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9.6 16.4 4.9 11.7a1.1 1.1 0 0 1 1.55-1.55l3.15 3.15 7.95-7.95A1.1 1.1 0 0 1 19.1 6.9l-9.5 9.5Z'/%3E%3C/svg%3E");
}

/* The shared half of a drawn mark: everything but which shape. */
.y-mark,[class].y-mark{display:inline-block;inline-size:1em;block-size:1em;
  vertical-align:-.16em;background:currentColor;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-size:contain;mask-size:contain;}

/* ── surfaces ───────────────────────────────────────────────────────────── */
[data-surface="dark"]{
  --y-teal-ink:#4FC3D4;   /* 8.4:1 on the dark panel */
  /* COOLER GROUNDS, WARM INK (2026-09-04). Every neutral here was red-shifted --
     #231616 is R35 G22 B22 -- and the whole product read as brown. These are the
     same tones at the SAME RELATIVE LUMINANCE, hue-rotated to a near-neutral
     cool: ΔL is under 0.004 everywhere, so every contrast measurement taken
     against the old set still holds.

     The TEXT tokens below are deliberately left warm. Amin asked for cooler
     backgrounds and boxes, not cooler words, and the cream is the brand's --
     warm ink on a cool ground is a better pairing than either on its own. */
  --y-ground:#101214;
  --y-raise:#181A1D;
  --y-panel:#171A1C;
  --y-rule:#313539;        /* divider — decorative, no contrast floor */
  --y-rule-2:#43484F;      /* heavier divider, still decorative */
  --y-control:#6D737B;     /* the visible boundary of an input or a button: 3:1 */
  --y-text:#F6F0EA;
  --y-text-2:#D3C9C1;
  --y-muted:#A69C94;
  --y-accent:var(--y-orange);
  --y-on-accent:#141110;
  --y-on-accent-2:#2E170B;
  --y-field:#181A1D;
  --y-placeholder:#948B82;
  --y-veil:rgba(16,18,20,.72);
  /* A card lifts off the ground with a little translucency and a hairline of
     light along its edge, instead of being one more flat rectangle. No
     backdrop-filter: a blur behind every card costs a mid-range Android real
     frames, and the effect here comes from the two layers, not from blurring
     what is under them. */
  --y-glass:rgba(255,255,255,.045);
  --y-glass-edge:rgba(255,255,255,.075);
}
[data-surface="paper"]{
  --y-teal-ink:#15788A;   /* 4.97:1 on the paper raise */
  --y-ground:#EBECEF;
  --y-raise:#FBFBFC;
  --y-panel:#FFFFFF;
  --y-rule:#D2D5DA;        /* divider — decorative, no contrast floor */
  --y-rule-2:#B9BEC5;      /* heavier divider, still decorative */
  --y-control:#79818A;     /* the visible boundary of an input or a button: 3:1 */
  --y-text:#241F1D;
  --y-text-2:#3E3733;
  --y-muted:#6B6259;
  --y-accent:var(--y-orange-print);
  --y-on-accent:#FFF8F5;
  --y-on-accent-2:#FFE2D6;
  --y-field:#FFFFFF;
  --y-placeholder:#7C7269;
  --y-veil:rgba(242,235,227,.74);
  --y-glass:rgba(255,255,255,.55);
  --y-glass-edge:rgba(255,255,255,.8);
}


/* HTML's own `hidden` LOSES TO ANY DISPLAY A RULE GIVES THE ELEMENT.
   The UA stylesheet says [hidden]{display:none}, which is a single element
   selector -- so `#boot{display:grid}` or `.badge{display:inline-flex}` beats
   it, and `el.hidden = true` then does nothing at all while reading as though
   it did. The library's loading mark was told to hide on every load since the
   page was written and never once went away; the notification badge had the
   same fault and was fixed locally. This is the fix for the class rather than
   for each instance, and it is what every modern reset carries. */
[hidden]{display:none !important}

/* ── base ───────────────────────────────────────────────────────────────────
   data-surface declares a TOKEN CONTEXT. .y-page PAINTS the ground. They are
   two decisions and must stay separable: the account chip mounts inside a
   header this system does not own, so it needs the tokens and must not paint
   anything behind itself. A whole page carries both.
   Nesting works — a light panel inside a dark page declares its own surface
   and the tokens resolve to the nearest one. */
[data-surface]{
  color:var(--y-text);
  font-family:var(--y-sans);
  line-height:var(--y-lh-body);
  -webkit-font-smoothing:antialiased;
}
[data-surface].y-page{
  /* the ground is painted on the ROOT, not here: a z-index:-1 layer inside the
     page would otherwise render under this box and disappear entirely */
  background:transparent;
  font-size:16px;
  direction:rtl;
  text-align:right;
}
[data-surface] *{box-sizing:border-box;}
[data-surface] :focus-visible{outline:3px solid var(--y-accent);outline-offset:3px;}

/* Latin inside a Persian run must not flip the line. */
[data-surface] .y-ltr{direction:ltr;unicode-bidi:isolate;}

/* ── type ───────────────────────────────────────────────────────────────── */
[data-surface] .y-display{
  font-family:var(--y-display);font-weight:400;line-height:var(--y-lh-tight);
  margin:0;text-wrap:balance;
}
[data-surface] .y-d1{font-size:clamp(44px,9vw,132px);}
[data-surface] .y-d2{font-size:clamp(30px,5vw,64px);}
[data-surface] .y-d3{font-size:clamp(22px,3vw,38px);}
[data-surface] .y-lead{font-size:17px;color:var(--y-muted);max-width:62ch;}
[data-surface] .y-small{font-size:13.5px;color:var(--y-muted);}

/* the section label. Two real uses today: landing and the canvas navigator. */
[data-surface] .y-eyebrow{
  display:flex;align-items:center;gap:var(--y-3);
  font-size:11.5px;letter-spacing:.2em;font-weight:700;color:var(--y-muted);
}
[data-surface] .y-eyebrow::before{
  content:"";inline-size:4px;block-size:20px;background:var(--y-accent);flex:0 0 auto;
}

/* ── layout ─────────────────────────────────────────────────────────────── */
[data-surface] .y-wrap{max-width:1320px;margin-inline:auto;padding-inline:clamp(16px,4vw,52px);}
[data-surface] .y-stack{display:flex;flex-direction:column;gap:var(--y-4);}
[data-surface] .y-row{display:flex;flex-wrap:wrap;gap:var(--y-3);align-items:center;}

/* A divider and a control boundary are not the same thing. --y-rule is
   decoration and may be faint; --y-control is what tells a person where an
   input ends, so it holds 3:1 against every ground it sits on. Collapsing
   the two is how a form becomes invisible in a bright ward. */

/* ── panel ──────────────────────────────────────────────────────────────── */
[data-surface] .y-panel{
  background:var(--y-panel);border:1px solid var(--y-rule);
  border-radius:var(--y-radius);padding:clamp(18px,2.6vw,30px);
}

/* ── button ─────────────────────────────────────────────────────────────── */
[data-surface] .y-btn{
  display:inline-flex;align-items:center;gap:var(--y-3);
  font-family:inherit;font-weight:800;font-size:15px;line-height:1.6;
  padding:13px 26px;border:1px solid transparent;border-radius:var(--y-radius-btn);
  background:var(--y-accent);color:var(--y-on-accent);
  text-decoration:none;cursor:pointer;
}
[data-surface] .y-btn:hover{filter:brightness(1.08);}
[data-surface] .y-btn[disabled],[data-surface] .y-btn[aria-disabled="true"]{
  opacity:.55;pointer-events:none;
}
[data-surface] .y-btn.quiet{
  background:transparent;color:var(--y-text);border-color:var(--y-control);
}
[data-surface] .y-btn.quiet:hover{border-color:var(--y-accent);filter:none;}
/* pressed is a state, and a state is never colour alone */
[data-surface] .y-btn[aria-pressed="true"]{
  background:var(--y-text);color:var(--y-ground);border-color:var(--y-text);
}

/* ── field — sized for a phone held one-handed in a corridor ────────────── */
[data-surface] .y-field{
  inline-size:100%;background:var(--y-field);color:var(--y-text);
  border:1px solid var(--y-control);border-radius:var(--y-radius-sm);
  font-family:inherit;font-size:16px;line-height:1.8;padding:13px 15px;
  min-block-size:48px;
}
[data-surface] textarea.y-field{min-block-size:96px;resize:vertical;}
[data-surface] .y-field::placeholder{color:var(--y-placeholder);}
[data-surface] .y-field:focus{border-color:var(--y-accent);}
/* format hints go UNDER the field. A grey sample inside the box is read as a
   value already entered — that cost us a queue at the door. */
[data-surface] .y-help{font-size:12.5px;color:var(--y-muted);margin-block-start:var(--y-2);}
[data-surface] .y-help.err{color:var(--y-accent);}

/* ── the route — the one motif, shared by the journey bar and the canvas
      navigator. States are told apart by FORM so a colour-blind reader can
      read them: filled square, ringed dot, hollow dot, dashed line. ─────── */
[data-surface] .y-route{fill:none;stroke:var(--y-text);stroke-linejoin:round;stroke-linecap:butt;}
[data-surface] .y-route.is-done{stroke:var(--y-text);}
[data-surface] .y-route.is-now{stroke:var(--y-accent);}
[data-surface] .y-route.is-next{stroke:var(--y-control);stroke-dasharray:4 9;}
[data-surface] .y-gate-dot{fill:var(--y-accent);}
[data-surface] .y-gate-ring{fill:none;stroke:var(--y-accent);}
[data-surface] .y-gate-open{fill:var(--y-ground);stroke:var(--y-text);}

/* ── motion is optional, and the design is complete without it ──────────── */
@media (prefers-reduced-motion:no-preference){
  [data-surface] .y-btn,
  [data-surface] .y-field{transition:background .16s ease,border-color .16s ease,filter .16s ease;}
}

/* ═══════════════════════════════════════════════════════════════════════════
   NOT IN THE SYSTEM YET, deliberately — each has exactly one use today:
     the sticky note (canvas)      the ghost word (landing)
     the rotated card rail (landing)   the projector mode (canvas)
     the teaching drawer (canvas)      the score panel (canvas)
   They live in their own page until a second surface genuinely needs them.
   Promoting a one-use pattern is how a system fills with furniture nobody
   ordered.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── the grid, and traffic on it ─────────────────────────────────────────────
   The one moment of motion in the system. Routes travel the grid the way the
   progress bar travels a case: right to left, turning only at 90 degrees,
   pausing at a gate. It is CSS on an inline SVG — a dash sliding along a path
   — so there is no library, no canvas and nothing to load.

   It earns its place by being STRUCTURAL: the same rule that draws the journey
   bar and the canvas navigator, moving. Ambient decoration would not.

   Kept faint on purpose. This sits behind a headline someone is reading and
   behind a door someone uses for four seconds at eight in the morning; if it
   competes with either, it has failed. Motion off leaves the grid, which is
   the texture — the page is complete without a single frame of this.
   ────────────────────────────────────────────────────────────────────────── */
[data-surface] .y-grid{
  position:relative;
  background-image:
    linear-gradient(to right, rgba(233,95,35,.06) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(233,95,35,.06) 1px, transparent 1px);
  background-size:var(--y-u) var(--y-u);
}
[data-surface="paper"] .y-grid{
  background-image:
    linear-gradient(to right, rgba(36,31,29,.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(36,31,29,.05) 1px, transparent 1px);
}
/* Behind the whole document, and scrolling with it. Pinned to one block it
   reads as an effect ON that block; pinned to the viewport it slides under the
   content as you scroll, which is worse — it stops being ground and starts
   being a thing that moves independently. Absolute against the page body makes
   it the ground and nothing else. z-index:-1 puts it under every element
   without any of them needing a stacking context of their own. */
html:has([data-surface].y-grid),
html:has(body[data-surface]){background:var(--y-ground);}

/* A 2px horizontal overflow exists at 375: no element measures wider than the
   viewport, so it is sub-pixel at the rtl scroll origin from the decorative
   layers. DO NOT fix it with overflow-x on <html>.
   Tried on 2026-09-02 and it killed vertical scrolling on the whole site —
   `clip` on one axis forces the other out of `visible`, and on the root that
   is the viewport's own scroll container. scrollTop stayed 0, window.scrollTo
   did nothing, the page could not be scrolled at all, and it shipped.
   A 2px scrollbar is a blemish; an unscrollable page is the site being down.
   If it is worth fixing, fix it on the element that actually overflows, and
   verify by trying to scroll the page afterwards. */
[data-surface] .y-traffic{
  position:absolute;inset:0;inline-size:100%;block-size:100%;
  /* clip, do not let it out. preserveAspectRatio="slice" makes these paths far
     wider than the viewport, and overflow:visible let them push the document
     2px past the edge on a 375 screen — a horizontal scrollbar earned by
     decoration is the worst trade on the page. */
  pointer-events:none;overflow:hidden;z-index:-1;
}
[data-surface].y-grid{position:relative;}
[data-surface] .y-traffic path{
  fill:none;stroke:var(--y-accent);stroke-width:1.5;
  stroke-linecap:butt;stroke-linejoin:round;opacity:.2;
  stroke-dasharray:74 1600;stroke-dashoffset:1674;
}
[data-surface] .y-traffic circle{fill:var(--y-accent);opacity:0;}

@keyframes y-travel{
  0%   {stroke-dashoffset:1674;}
  100% {stroke-dashoffset:0;}
}
/* a gate lights only while the route is passing through it */
@keyframes y-gate{
  0%,72%   {opacity:0;transform:scale(.4);}
  78%,88%  {opacity:.34;transform:scale(1);}
  100%     {opacity:0;transform:scale(.4);}
}
@media (prefers-reduced-motion:no-preference){
  [data-surface] .y-traffic path{animation:y-travel var(--y-dur,44s) linear infinite;
    animation-delay:var(--y-lag,0s);}
  [data-surface] .y-traffic circle{
    animation:y-gate var(--y-dur,44s) linear infinite;animation-delay:var(--y-lag,0s);
    transform-box:fill-box;transform-origin:center;
  }
}
/* Motion off: the traffic layer goes entirely. A frozen dash reads as a
   rendering fault, not as restraint. The grid stays and carries the texture. */
@media (prefers-reduced-motion:reduce){
  [data-surface] .y-traffic{display:none;}
}

/* ═══ taken from the brand book ═════════════════════════════════════════════
   Patterns the Figma pages settled that the system had not: a bilingual
   section header, the full button state set, a tertiary that is text alone, an
   OTP row, a dashed card for what does not exist yet, and a banner for the
   error that is not one field's fault.
   ══════════════════════════════════════════════════════════════════════════ */

/* the header the brand book uses everywhere: Persian, then the English label */
[data-surface] .y-sect{border-block-end:1px solid var(--y-rule);padding-block-end:var(--y-3);
  margin-block:var(--y-7) var(--y-5);display:flex;align-items:baseline;
  justify-content:space-between;gap:var(--y-4);flex-wrap:wrap;}
[data-surface] .y-sect h2{font-family:var(--y-display);font-weight:400;margin:0;
/* The clamp FLOOR is the size a phone actually gets, and Lalezar's floor is
   28px. Auditing at 1180 hides this completely: every one of these read as
   compliant on a desktop and broke the scale at 390, which is the width
   this product is primarily used at. */
  font-size:clamp(28px,2.6vw,30px);line-height:1.15;color:var(--y-accent);}
[data-surface] .y-sect .en{font-size:12px;letter-spacing:.16em;color:var(--y-muted);
  direction:ltr;unicode-bidi:isolate;text-transform:uppercase;font-weight:600;}

/* the states the brand book draws, in the order it draws them */
[data-surface] .y-btn:active{filter:brightness(.92);}
[data-surface] .y-btn:focus-visible{outline:3px solid var(--y-text);outline-offset:3px;}
/* third level: no fill, no border — the brand book calls it شیشه‌ای */
[data-surface] .y-btn.glass{background:transparent;border-color:transparent;color:var(--y-accent);
  padding-inline:var(--y-3);}
[data-surface] .y-btn.glass:hover{background:var(--y-raise);filter:none;}

/* one code, six boxes, and it has to stay LTR inside a Persian page */
[data-surface] .y-otp{display:flex;gap:var(--y-2);direction:ltr;unicode-bidi:isolate;}
[data-surface] .y-otp input{
  inline-size:52px;block-size:60px;text-align:center;font-size:24px;font-weight:700;
  background:var(--y-field);color:var(--y-text);border:1px solid var(--y-control);
  border-radius:var(--y-radius-sm);font-variant-numeric:tabular-nums;
}
[data-surface] .y-otp input:focus{border-color:var(--y-accent);outline:2px solid var(--y-accent);outline-offset:-2px;}

/* a card for the thing that does not exist yet — dashed, so it reads as an
   invitation and never as a card that failed to load */
[data-surface] .y-card-new{background:transparent;border:1px dashed var(--y-control);
  border-radius:var(--y-radius);padding:clamp(18px,2.6vw,30px);}

/* the error nothing on the page can fix by being edited */
[data-surface] .y-banner{display:flex;gap:var(--y-3);align-items:flex-start;
  border:1px solid var(--y-accent);border-radius:var(--y-radius);
  padding:var(--y-4);font-size:14px;line-height:1.8;background:var(--y-raise);}
[data-surface] .y-banner::before{content:"";color:var(--y-accent);flex:0 0 auto;
  display:inline-block;inline-size:19px;block-size:19px;margin-block-start:2px;
  background:currentColor;-webkit-mask:var(--y-mk-warn) center/contain no-repeat;
  mask:var(--y-mk-warn) center/contain no-repeat;}

/* an empty state is a room with one door, not a message */
[data-surface] .y-empty{text-align:center;padding-block:clamp(30px,5vw,58px);}
[data-surface] .y-empty .ic{inline-size:64px;block-size:64px;margin-inline:auto;
  border:1px solid var(--y-control);border-radius:50%;display:grid;place-items:center;
  color:var(--y-muted);}
[data-surface] .y-empty h3{font-family:var(--y-display);font-weight:400;
  font-size:clamp(28px,2.2vw,28px);margin:var(--y-4) 0 var(--y-2);}
[data-surface] .y-empty p{color:var(--y-muted);max-inline-size:44ch;margin-inline:auto;font-size:14.5px;}

/* ═══ the wait ════════════════════════════════════════════════════════════════════════════
   A veil that blurs the page, and a lean canvas filling itself in behind it.

   WHY A CANVAS AND NOT A SPINNER. A spinner says only "wait". Every long wait
   in this product is the same wait — something is reading a canvas, or writing
   one — so the mark is a canvas: the lean canvas silhouette, which a room full
   of bootcamp teams recognises before they have read a single word.

   THE SILHOUETTE IS THE WHOLE ICON, so it has to be the real one. Three tall
   boxes on the outside and at the centre, two stacked pairs between them, two
   wide boxes along the bottom. Flatten it to an even 3×3 and it stops being a
   lean canvas and becomes a loading square. The nine grid-areas below are that
   shape and nothing else is; if you change one, check the silhouette, not the
   rule that produced it.

   NO TEXT, by request — which puts the whole message on the mark, so the mark
   has to carry it in both motion branches. That is the constraint driving
   everything in the reduced-motion block at the bottom. The only words are on
   .y-sr, which is for a screen reader and never painted.

   THE CONSUMER OWNS TWO THINGS this file cannot: keeping the page behind from
   scrolling, and keeping the keyboard out of it. Set `inert` on the content
   the veil covers; without it a Tab walks focus through a blurred form nobody
   can see.

   ═══════════════════════════════════════════════════════════════════════════════════════

   <div class="y-veil" role="status">
     <span class="y-sr">در حال پردازش…</span>
     <div class="y-wait" aria-hidden="true">
       <i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
     </div>
   </div>
   ═══════════════════════════════════════════════════════════════════════════════════════ */

/* Nothing else in this file needed one yet. A textless loader does: role and
   an animation are not a name, and a screen reader is owed the sentence the
   eye is getting from the mark. */
[data-surface] .y-sr{
  position:absolute;inline-size:1px;block-size:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0;padding:0;margin:-1px;
}

/* 100000, not a tidier number: the two canvas pages pin their "همهٔ ابزارها"
   link at 99999, and those pages are exactly where this veil appears. Below
   that number the link floats on top of the blur, unblurred and clickable. */
[data-surface] .y-veil{
  position:fixed;inset:0;z-index:100000;
  display:grid;place-items:center;padding:var(--y-5);
  background:var(--y-veil);
  -webkit-backdrop-filter:blur(7px) saturate(115%);
  backdrop-filter:blur(7px) saturate(115%);
}
/* Without the blur the tint alone is far too thin to separate the veil from
   the page — the reader sees a form they can still read and cannot touch.
   Where the filter is unsupported the ground goes opaque instead. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  [data-surface] .y-veil{background:var(--y-ground);}
}

/* Ten columns because the bottom two boxes split the canvas in half and the
   top five do not — halves and fifths only share a whole number at ten. The
   column is half a grid unit and the row is a whole one, which is what lands
   the mark on the background tile instead of floating over it.
   direction is declared and not inherited: the veil is usually mounted at the
   end of <body>, outside whatever set the page RTL. */
[data-surface] .y-wait{
  --y-col:calc(var(--y-u) * .5);
  --y-step:.6s;
  display:grid;direction:rtl;
  grid-template-columns:repeat(10,var(--y-col));
  grid-template-rows:repeat(3,var(--y-u));
  gap:3px;padding:3px;
  border:1px solid var(--y-control);
}
[data-surface] .y-wait i{position:relative;border:1px solid var(--y-rule-2);}
/* the fill is a pseudo-element, not the cell's own background: inset:-1px lets
   it cover the cell outline, so a filled box is a solid orange block and not
   an orange block in a grey frame. Nothing in the layout moves as it lights. */
[data-surface] .y-wait i::after{
  content:"";position:absolute;inset:-1px;background:var(--y-accent);
  opacity:0;transform:scale(.82);
}

/* the lean canvas, in the order Maurya draws it. row-start/col-start/row-end/
   col-end — and under RTL column line 1 is the right edge, which mirrors the
   whole thing to match the page. The silhouette is near symmetric, so it reads
   as the same canvas either way. */
[data-surface] .y-wait i:nth-child(1){grid-area:1/1/3/3;}   /* مسئله */
[data-surface] .y-wait i:nth-child(2){grid-area:1/3/2/5;}   /* راه‌حل */
[data-surface] .y-wait i:nth-child(3){grid-area:2/3/3/5;}   /* سنجه‌های کلیدی */
[data-surface] .y-wait i:nth-child(4){grid-area:1/5/3/7;}   /* ارزش پیشنهادی یکتا */
[data-surface] .y-wait i:nth-child(5){grid-area:1/7/2/9;}   /* مزیت ناعادلانه */
[data-surface] .y-wait i:nth-child(6){grid-area:2/7/3/9;}   /* کانال‌ها */
[data-surface] .y-wait i:nth-child(7){grid-area:1/9/3/11;}  /* بخش‌های مشتری */
[data-surface] .y-wait i:nth-child(8){grid-area:3/1/4/6;}   /* ساختار هزینه */
[data-surface] .y-wait i:nth-child(9){grid-area:3/6/4/11;}  /* جریان‌های درآمد */

/* SCATTERED, AND IT STAYS SCATTERED — the part worth reading before editing.

   Two dials do it, and neither needs a line of JavaScript. The DELAY scatters
   where the boxes are in the cycle at t=0: the order below is centre, bottom
   corner, far edge, and never two boxes that touch. The DURATION is what keeps
   it scattered — each box runs on its own period, so after the first pass they
   drift out of phase and the arrangement never comes back. Give all nine the
   same duration and it is a fixed shuffle: convincing for one cycle, and a
   recognisable little dance by the fourth, which is exactly the thing a long
   wait gives someone time to notice.

   HOW MANY ARE LIT AT ONCE is the number that decides whether this reads as
   calm or as chatter, and it falls out of two ratios. The step is a ninth of a
   cycle, so the nine starts sit evenly around the clock; the keyframes' 19%
   on-window is a bit under two of those steps wide. One or two alight, and the
   canvas is never crowded. The first version ran at 2.4s with a 58% window and
   put five boxes up at once, flashing over each other.

   THE SPREAD OF THE PERIODS IS A TRADE, and it is the subtle one. Wide spread
   scrambles the phases quickly — good for never repeating, bad for spacing,
   because once the starts bunch up you get four boxes at once and then a gap
   with nothing lit at all. A 13% spread measured exactly that: 27% of the time
   at three or more, and dark stretches of 1.6s. These sit inside 4%, so the
   even spacing survives about a minute — longer than almost any wait here —
   and decays gently rather than never holding in the first place.

   Awkward decimals on purpose. Round them to each other and the drift stops;
   round them apart and the spacing goes. */
[data-surface] .y-wait i:nth-child(4)::after{animation-delay:0s;                     animation-duration:5.41s;}
[data-surface] .y-wait i:nth-child(9)::after{animation-delay:calc(var(--y-step) * 1);animation-duration:5.47s;}
[data-surface] .y-wait i:nth-child(1)::after{animation-delay:calc(var(--y-step) * 2);animation-duration:5.33s;}
[data-surface] .y-wait i:nth-child(6)::after{animation-delay:calc(var(--y-step) * 3);animation-duration:5.53s;}
[data-surface] .y-wait i:nth-child(2)::after{animation-delay:calc(var(--y-step) * 4);animation-duration:5.38s;}
[data-surface] .y-wait i:nth-child(7)::after{animation-delay:calc(var(--y-step) * 5);animation-duration:5.44s;}
[data-surface] .y-wait i:nth-child(3)::after{animation-delay:calc(var(--y-step) * 6);animation-duration:5.31s;}
[data-surface] .y-wait i:nth-child(8)::after{animation-delay:calc(var(--y-step) * 7);animation-duration:5.50s;}
[data-surface] .y-wait i:nth-child(5)::after{animation-delay:calc(var(--y-step) * 8);animation-duration:5.36s;}

/* A box is dark for three quarters of its cycle, which is the whole reason
   only one or two are alight at a time. The ramps are long against the hold,
   so a box arrives and leaves instead of blinking, and the scale barely moves:
   .94 is a breath, where the .82 this started at was a pop. */
@keyframes y-wait-fill{
  0%,100%  {opacity:0;transform:scale(.94);}
  7%,11%   {opacity:1;transform:scale(1);}
  19%      {opacity:0;transform:scale(.94);}
}
/* Opacity alone, and it never reaches zero here: with no words on screen the
   cross-fade is the entire signal, and a box that empties completely leaves a
   gap a reader has to re-read the shape to explain. */
@keyframes y-wait-fade{
  0%,100%  {opacity:.1;}
  7%,11%   {opacity:1;}
  19%      {opacity:.1;}
}

@media (prefers-reduced-motion:no-preference){
  [data-surface] .y-wait i::after{animation-name:y-wait-fill;
    animation-timing-function:ease-in-out;animation-iteration-count:infinite;}
}

/* Motion off is NOT the traffic layer's rule, and this is the one place the
   two part company. The grid may vanish entirely because the page is complete
   without it; a loader that stops moving is a loader that is lying — a still
   canvas reads as finished or as broken, and it is neither. With the label
   gone there is nothing else left to say otherwise, so this branch carries
   the whole message on its own.

   What goes is the movement, not the signal: scale dropped, a floor under the
   fade, same nine boxes on the same scattered clocks. That leaves a cross-fade
   and nothing that travels, which is what reduced motion is actually asking
   for. */
@media (prefers-reduced-motion:reduce){
  [data-surface] .y-wait i::after{transform:none;animation-name:y-wait-fade;
    animation-timing-function:ease-in-out;animation-iteration-count:infinite;}
}

/* ---- .y-back : the way out of a tool -------------------------------------
   Four pages carried four versions of this: two bare links with no affordance
   at all ("ابزارهای تعاملی", "همهٔ ابزارها"), and two fixed white pills on the
   canvases still painted in the palette this site stopped using — #fff, #E6DDCE,
   #2E3256. One control now.

   It sits after a flex spacer, so on this rtl page it lands at the far LEFT of
   the bar, and the chevron goes on its outer edge pointing out: away from the
   page, in the direction the reader leaves. That is what makes it read as back
   rather than as another destination. It is a bordered control, not a link, for
   the same reason the contact asks are — a thing you can press should look like
   one. */
.y-back{
  display:inline-flex;align-items:center;gap:8px;
  min-block-size:40px;padding-inline:14px;
  background:transparent;border:1px solid var(--y-control);
  border-radius:var(--y-radius);
  color:var(--y-text);text-decoration:none;
  font:inherit;font-size:14px;font-weight:700;white-space:nowrap;cursor:pointer;
  /* It sits beside a brand lockup in a row that has to fit a phone. At 360 the
     library's topbar was brand + this button and the pair pushed the page 7px
     wide -- a nowrap label cannot shrink, so the padding and size give instead. */
  min-inline-size:0;
}
/* ::after, not ::before. On an rtl page ::before is the START edge, which is
   the RIGHT of the text — the chevron has to sit on the far side, at the outer
   left edge of the bar, pointing away from the page. */
.y-back::after{content:"\2039";font-size:19px;line-height:1;color:var(--y-accent);}
.y-back:hover{border-color:var(--y-accent);background:var(--y-raise);text-decoration:none;}
.y-back:focus-visible{outline:3px solid var(--y-accent);outline-offset:2px;}
/* on the canvases it floats over the board rather than sitting in a bar */
.y-back.fixed{
  position:fixed;inset-block-start:12px;inset-inline-end:12px;z-index:99999;
  background:var(--y-panel);
}
@media (prefers-reduced-motion:no-preference){
  .y-back{transition:border-color .16s ease,background .16s ease;}
}
/* Narrow screens: it may shrink, but a nowrap label in a shrunken box does not
   shrink -- it SPILLS, and the spill pushed the page 20px wide at 320 with the
   button's own box measuring only 60 against 101 of content. Letting the label
   wrap is what actually makes the control fit. */
@media (max-width:400px){
  .y-back{padding-inline:10px;font-size:13px;gap:6px;
    white-space:normal;text-align:center;line-height:1.35;}
}
