/* zerb.az — site styles
   Stage 1: header + hero only. Sections 2–13 land in Stages 2–3.

   Motion contract for this file:
   - EVERY animation, looping or not, animates transform and/or opacity
     only. There are no exceptions. (There used to be one — a one-shot
     stroke-dashoffset trace reveal — but the draw/erase cycle replaced
     it, since the line writing itself is already the entry animation.)
   - Every looping duration is var(--pulse-period) or a calc() off it.
     No hand-typed seconds. One clock, one spine.
*/

/* ============================================================
   RESET / BASE
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  font-family: 'IBM Plex Sans', 'IBM Plex Sans Fallback', system-ui, sans-serif;
  background: var(--ds-page-bg);
  color: var(--ds-text-primary);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, p, ul, ol, figure { margin: 0; }
ul { padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; }

/* Visible focus everywhere. The product has an accessibility
   discipline; the site does not get to be the exception. */
:focus-visible {
  outline: 3px solid var(--ds-text-on-gradient);
  outline-offset: 3px;
  border-radius: var(--ds-radius-sm);
}
.hero :focus-visible { outline-color: #FFFFFF; }

.skip-link {
  position: absolute;
  left: var(--ds-space-4);
  top: var(--ds-space-4);
  z-index: 100;
  padding: var(--ds-space-3) var(--ds-space-5);
  background: var(--ds-surface);
  color: var(--ds-brand-tint-text);
  font-weight: 600;
  border-radius: var(--ds-radius-control);
  box-shadow: var(--ds-shadow-overlay);
  transform: translateY(-150%);
  transition: transform var(--ds-duration-base) var(--ds-ease-decelerate);
}
.skip-link:focus { transform: translateY(0); }

.u-visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.shell {
  width: 100%;
  max-width: 1160px;
  margin: 0 auto;
  padding-inline: var(--ds-space-5);
}
@media (min-width: 720px) {
  .shell { padding-inline: var(--ds-space-8); }
}

/* ============================================================
   HERO SHELL
   The hero owns the app's one sanctioned gradient, full-bleed.
   Same two stops as the product's Home hero card, so a visitor who
   later opens the app recognises the surface.
   ============================================================ */
/* ALWAYS DARK, in both themes (owner amendment 2026-07-27). The hero is
   the site's dramatic opening, not a theme state — so it does not read
   the theme at all, and there is no dark variant of it to maintain.
   A deep indigo field with the pulse trace as the light source in it. */
.hero {
  position: relative;
  isolation: isolate;
  background: var(--hero-field);
  color: var(--ds-text-on-gradient);
  overflow: hidden;
  padding-bottom: var(--ds-space-8);
}

/* The light the trace throws back into the field. Sits BEHIND the
   content, centred low where the trace runs, so the line reads as the
   source rather than as a shape painted on a dark rectangle. Static —
   it does not animate; the trace moving through it is the motion. */
.hero::before {
  content: '';
  position: absolute;
  inset: auto -10% -10% -10%;
  height: 85%;
  background: radial-gradient(58% 78% at 50% 78%, var(--hero-glow), rgba(150,122,255,0) 72%);
  pointer-events: none;
  z-index: 0;
}
.hero > * { position: relative; z-index: 1; }

/* ---- Nav ---- */
.site-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-4);
  padding-block: var(--ds-space-5);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--ds-space-3);
  text-decoration: none;
  min-width: 0;
}
.brand__glyph {
  flex: none;
  width: 34px; height: 34px;
  display: grid;
  place-items: center;
  border-radius: var(--ds-radius-md);
  background: rgba(255,255,255,.14);
  border: 1px solid rgba(255,255,255,.22);
}
/* The mark reads at 24 inside the 34px tile (~71%), not the 20 it started
   at (~59%) — at the smaller size the pulse looked like a stray hairline
   rather than the logo it is. */
.brand__glyph svg { width: 24px; height: 24px; }
.brand__text { display: flex; flex-direction: column; min-width: 0; }
.brand__name {
  /* The wordmark is set in its own face; the tagline under it stays IBM
     Plex, which is what a display-plus-text lockup is. Tracking goes to 0:
     the -.015em here was tuned for Plex, and a slab needs its serifs to
     keep their room. */
  font-family: 'Zerb Wordmark', 'IBM Plex Sans', 'IBM Plex Sans Fallback', system-ui, sans-serif;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.1;
}
.brand__tag {
  font-size: 11.5px;
  font-weight: 400;
  color: var(--ds-text-on-gradient-secondary);
  letter-spacing: .01em;
  line-height: 1.3;
}

/* ---- Language switcher ---- */
.lang {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.2);
  border-radius: var(--ds-radius-pill);
}
.lang__btn {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--ds-text-on-gradient-secondary);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .02em;
  padding: 6px 12px;
  min-height: 32px;
  border-radius: var(--ds-radius-pill);
  /* Anchors the ::after that carries the touch target on phones — see the
     touch-target block at the end of this section. */
  position: relative;
  /* Four of the five chips are <a href> and only the current one is a
     <span>, so without this the switcher shipped with RU/EN/TR/DE
     underlined and AZ not — for the ten days between the site's first
     commit and the measurement that found it. The rest of this rule is a
     <button> reset (appearance, border, background) written when these
     were buttons; buttons carry no underline, anchors do, and this sheet
     has no blanket `a { text-decoration: none }` — only `a { color:
     inherit }`. Every other anchor component here resets it on its own
     (.brand, .btn); this one was the miss. */
  text-decoration: none;
  cursor: pointer;
  transition: background var(--ds-duration-fast) var(--ds-ease-standard),
              color var(--ds-duration-fast) var(--ds-ease-standard);
}
/* This read `:hover:not(:disabled)` until it was measured. :disabled matches
   neither <a> nor <span>, so the guard filtered nothing — but it still cost a
   class-level unit, which put the rule at (0,3,0) against the (0,2,0) of
   .lang__btn[aria-current] below. So hovering the CURRENT language repainted
   its white pill to rgba(255,255,255,.14): the "you are here" mark vanished
   under the cursor that was pointing at it. Dropping the guard drops the rule
   to (0,2,0) — a tie that source order hands to [aria-current], which is why
   this rule must stay ABOVE it.
   The lesson is the reason this comment is long: an inert selector is not a
   free one. It was called dead code and it was changing what people saw. */
.lang__btn:hover { background: rgba(255,255,255,.14); color: #fff; }
/* The current language is a <span aria-current="page"> rather than the
   inert <button> it used to be (DL-284), so both selectors are kept:
   aria-current for the meaning, the class for the styling hook. */
.lang__btn--on,
.lang__btn[aria-current] {
  background: #fff;
  /* Same fixed-white-on-the-hero-field case as .btn--primary above. */
  color: var(--hero-btn-text);
  cursor: default;
}

/* ---- Theme toggle ----
   The site reads prefers-color-scheme and lets the visitor override it,
   exactly like the app (same `data-theme` attribute, same localStorage
   key). It never picks a theme from the clock or from a location: that
   would overrule a choice the visitor already made, and it would make
   every screenshot and test depend on when it ran. */
.theme-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  /* Same reason as .lang__btn: the phone touch target is an ::after. */
  position: relative;
  width: 38px; height: 38px;
  border-radius: var(--ds-radius-pill);
  background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.22);
  color: #fff;
  cursor: pointer;
  transition: background var(--ds-duration-fast) var(--ds-ease-standard);
}
.theme-btn:hover { background: rgba(255,255,255,.2); }
.theme-btn svg { width: 18px; height: 18px; }
/* One icon is shown at a time — whichever theme the press would switch
   TO, which is the convention the app uses and the one users read
   correctly. Both live in the DOM so nothing has to be re-rendered. */
.theme-btn .icon-dark { display: none; }
html[data-theme="dark"] .theme-btn .icon-dark,
.theme-btn[aria-pressed="true"] .icon-dark { display: block; }
html[data-theme="dark"] .theme-btn .icon-light,
.theme-btn[aria-pressed="true"] .icon-light { display: none; }

.site-nav__controls {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
}

/* ---- Touch targets (DL-284) ----
   Measured at 375px: the five language chips were 40x32 and sat shoulder
   to shoulder, and the theme toggle 38x38 — all over the 24px WCAG 2.2
   floor, all under the 44px every phone platform asks for, on the
   controls a five-language site is most used through. The chips keep
   their look; only the tappable area grows.

   THAT LAST SENTENCE WAS NOT TRUE UNTIL IT WAS MEASURED. The first
   version grew `min-height` to 44px, and a chip whose text is two capitals
   is about 44px wide — so at 375px the five chips measured 44.4x44.0,
   ratio 1.01. The pill became a CIRCLE, and the white current-language
   chip read as an avatar badge rather than as one segment of a control.
   Desktop, untouched, stayed 40.4x32.0 at ratio 1.26. A rule whose own
   comment promised the look would not change was changing it.

   So the box that the finger hits is now separated from the box that gets
   painted: the chip keeps its 32px height, and an EMPTY ::after carries
   the 44px target. It has no background, so it changes nothing visible;
   it belongs to the element, so it is the same tap.

   The vertical-only inset on .lang__btn is deliberate. The chips sit 2px
   apart, so growing the target sideways would make each pair of
   neighbours overlap by 2px and a tap in the seam would land on whichever
   one paints last — a wrong language is worse than a small target. The
   width instead comes from padding-inline, which every chip pays without
   ever reaching its neighbour. The theme toggle stands alone (51.7px of
   clear space beside it, measured), so it may grow in both directions.

   THIS BLOCK MUST STAY BELOW .theme-btn AND .more__tab. It first sat up
   beside .lang__btn, where it matched on specificity and lost on source
   order, so the toggle stayed 38px and the measurement said so. */
@media (hover: none), (max-width: 720px) {
  .lang__btn { padding-inline: 14px; }
  .lang__btn::after {
    content: "";
    position: absolute;
    inset-block: -6px;   /* 6 + 32 + 6 = 44 */
    inset-inline: 0;     /* never past the 2px gap to the next chip */
  }
  .theme-btn::after {
    content: "";
    position: absolute;
    /* -4, not -3. An absolutely positioned child is placed against its
       ancestor's PADDING box, and .theme-btn has a 1px border — so its
       padding box is 36px, not the 38px the rect reports. -3px was written
       first and measured 42x42; the arithmetic that produced it was right
       about everything except which box it was counting from. */
    inset: -4px;         /* 4 + 36 + 4 = 44, both axes */
  }
  /* .more__tab is raised at the END of this file — its own rule is
     declared ~1400 lines below here and would win over this one. */
}

/* Five languages stop fitting beside the brand on a phone. Measured at
   375px rather than guessed: the switcher pill is 219px, the theme button
   38px, and the Russian tagline «Пульс вашего бизнеса» is 145px on its
   own — 512px of demand. At three languages this row fit; at five it does
   not, and the brand was being crushed to 54px with the tagline wrapping
   onto four lines behind the pill.
   The controls therefore take a row of their own. The alternative was
   tightening the buttons until they fit, which needs 8px of horizontal
   padding — that squeaks into 375px with 5px to spare and then overflows
   the 360px Androids that are still everywhere, while making each target
   33px wide. A second row costs one row of hero space and keeps both the
   tagline and a thumb-sized target. */
@media (max-width: 619px) {
  .site-nav { flex-wrap: wrap; row-gap: var(--ds-space-3); }
  .site-nav__controls { width: 100%; justify-content: space-between; }
}

/* ============================================================
   HERO CONTENT
   ============================================================ */
.hero__content {
  padding-top: var(--ds-space-7);
  max-width: 660px;
}

.hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--ds-space-2);
  padding: 6px 14px 6px 10px;
  border-radius: var(--ds-radius-pill);
  background: rgba(255,255,255,.13);
  border: 1px solid rgba(255,255,255,.22);
  font-size: 12.5px;
  font-weight: 500;
  color: #fff;
  line-height: 1.4;
}
/* The eyebrow's dot is the smallest member of the pulse family —
   it beats on the same clock as everything else. */
.hero__eyebrow-dot {
  flex: none;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #fff;
  animation: pulse-dot var(--pulse-period) var(--ds-ease-standard) infinite;
}

.hero__title {
  margin-top: var(--ds-space-5);
  font-size: clamp(2rem, 1.35rem + 2.9vw, 3.7rem);
  line-height: 1.08;
  letter-spacing: -.032em;
  font-weight: 600;
  text-wrap: balance;
}
.hero__title em {
  /* The operative word used to carry a hairline underline. The owner read
     it as clutter on the finished hero, so the emphasis is now semantic
     only — no rule here may reintroduce a visible treatment. The
     font-style reset stays: without it the browser italicises `<em>`. */
  font-style: normal;
}

.hero__lede {
  margin-top: var(--ds-space-5);
  font-size: clamp(1rem, .95rem + .35vw, 1.19rem);
  line-height: 1.6;
  color: var(--ds-text-on-gradient-secondary);
  max-width: 52ch;
  text-wrap: pretty;
}

/* ---- CTAs ---- */
.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ds-space-3);
  margin-top: var(--ds-space-7);
}
/* Below 520px the two CTAs go full-width rather than sitting at two
   different intrinsic widths — a ragged pair reads as an accident on a
   375px screen, and full-width gives the thumb a proper target. */
@media (max-width: 519px) {
  .hero__cta .btn { flex: 1 0 100%; }
}

.btn {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ds-space-2);
  min-height: 52px;
  padding: 0 var(--ds-space-7);
  border: 1px solid transparent;
  border-radius: var(--ds-radius-control);
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -.005em;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: transform var(--ds-duration-fast) var(--ds-ease-standard),
              background var(--ds-duration-fast) var(--ds-ease-standard),
              box-shadow var(--ds-duration-base) var(--ds-ease-standard);
}
/* Interaction ripple — the pulse metaphor at its smallest scale: a
   press sends one beat outward. Animates transform + opacity on a
   pseudo-element (NOT custom properties, which would need @property
   registration to interpolate and would otherwise jump discretely). */
.btn::after {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 240px; height: 240px;
  margin: -120px 0 0 -120px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0;
  transform: scale(0);
  pointer-events: none;
}
.btn:active { transform: translateY(1px); }
.btn.is-rippling::after { animation: pulse-ripple var(--ds-duration-slow) var(--ds-ease-decelerate); }

.btn--primary {
  background: #fff;
  /* Fixed, not --ds-brand-tint-text: the fill is white in both themes
     (the hero field is), so a theme-flipping colour breaks here. */
  color: var(--hero-btn-text);
  box-shadow: 0 1px 2px rgba(20,18,31,.16), 0 8px 24px rgba(20,18,31,.20);
}
.btn--primary:hover { background: #F7F5FE; }

.btn--ghost {
  background: rgba(255,255,255,.1);
  border-color: rgba(255,255,255,.36);
  color: #fff;
}
.btn--ghost:hover { background: rgba(255,255,255,.18); }

.hero__micro {
  margin-top: var(--ds-space-4);
  font-size: 13.5px;
  color: var(--ds-text-on-gradient-secondary);
}

/* ============================================================
   THE PULSE TRACE — the hero's signature
   ------------------------------------------------------------
   This is not decoration. Each of the four beats is one real moment
   in a shop's day, in the order they happen. The trace is the
   argument: your shop already has a pulse, you just cannot see it.

   preserveAspectRatio="none" + vector-effect="non-scaling-stroke"
   lets the band be any height at any width without the stroke
   thinning or the spikes distorting. The cost of that non-uniform
   scale is that y stretches relative to x by 6·height/width — which
   is why the brand mark spliced into the trace had to be widened by
   hand; see the `d` in the markup.

   The four beats carry no labels: they had chips on desktop and a
   legend on mobile, both removed by owner call 2026-07-27. Nothing on
   screen names them now, so the band is decorative outright and stays
   aria-hidden with no text alternative.
   ============================================================ */
.pulse {
  position: relative;
  margin-top: var(--ds-space-8);
}
/* The desktop override that used to sit here (margin-top: 56px) bought
   clearance for the chips rising above the band. The chips are gone, so
   the extra air had nothing left to clear and went with them — one
   spacing rule for both widths now. */

.pulse__band {
  position: relative;
  height: 120px;
  /* Fades the trace out at both ends so it reads as continuous —
     the day did not start at the left edge of your screen. The solid
     window must clear the outermost beats (15% and 90%) with room to
     spare, or the 4th beat lands in the fade and reads as missing. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 95%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 95%, transparent);
}
@media (min-width: 720px) {
  .pulse__band { height: 190px; }
}

.pulse__svg {
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Ghost of the whole day — faint, static, never animated. It keeps the
   hero from looking empty at the loop seam and tells the eye where the
   line is going. All the life comes from the hot layer drawn over it. */
.pulse__trace {
  fill: none;
  stroke: rgba(255,255,255,.15);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* Phosphor under-glow of the whole trace — a blurred copy in a light
   periwinkle-white, so the line reads as lit from within rather than
   printed on. The FILTER is static; only opacity animates: it fades in
   after the one-shot draw lands (draw 1.4s → glow from 1.15s), so the
   line arrives crisp first, then warms up. */
.pulse__trace-glow {
  fill: none;
  stroke: rgba(214,201,255,.10);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* NOTE: the old one-shot stroke-dashoffset reveal is gone. With the
   draw/erase loop, the hot layer writing itself IS the entry
   animation — a separate reveal would just be the same gesture twice.
   That removes the last non-transform animation on this site, so the
   motion budget is now transform/opacity with NO exceptions at all. */

/* Each beat's QRS complex, drawn bright on top of the dim trace and
   flashed as the sweep reaches it. Opacity only. */
.pulse__beat {
  fill: none;
  stroke: #fff;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  animation: pulse-flash var(--pulse-period) var(--ds-ease-standard) infinite;
}
.pulse__beat--1 { animation-delay: var(--pulse-beat-1); }
.pulse__beat--2 { animation-delay: var(--pulse-beat-2); }
.pulse__beat--3 { animation-delay: var(--pulse-beat-3); }
.pulse__beat--4 { animation-delay: var(--pulse-beat-4); }

/* Halo behind each flashing QRS — same clock, same delays, wider and
   blurred, so the flash has body instead of being a bare line. */
.pulse__beat-glow {
  fill: none;
  stroke: rgba(226,216,255,.6);
  stroke-width: 7;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  animation: pulse-flash var(--pulse-period) var(--ds-ease-standard) infinite;
}
.pulse__beat-glow--1 { animation-delay: var(--pulse-beat-1); }
.pulse__beat-glow--2 { animation-delay: var(--pulse-beat-2); }
.pulse__beat-glow--3 { animation-delay: var(--pulse-beat-3); }
.pulse__beat-glow--4 { animation-delay: var(--pulse-beat-4); }

/* Echo ring — one circle expanding from the spike's apex as its beat
   fires: the pulse propagating outward. Transform + opacity only.
   Centre = the apex (x at the beat fraction, y at 26/200 = 13%). */
.pulse__echo {
  position: absolute;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  border: 1.5px solid rgba(255,255,255,.55);
  border-radius: 50%;
  opacity: 0;
  transform: scale(.2);
  pointer-events: none;
  animation: pulse-echo var(--pulse-period) var(--ds-ease-decelerate) infinite;
}
.pulse__echo--1 { left: 15%; top: 31%; animation-delay: var(--pulse-beat-1); }
.pulse__echo--2 { left: 40%; top: 17%; animation-delay: var(--pulse-beat-2); }
.pulse__echo--3 { left: 65%; top: 24%; animation-delay: var(--pulse-beat-3); }
.pulse__echo--4 { left: 90%; top: 11%; animation-delay: var(--pulse-beat-4); }

/* The sweep — a soft light that travels the band once per period,
   exactly like a monitor's refresh head.

   The element spans the full band and centres its glow at its OWN 50%,
   then travels translateX(-50%) → translateX(50%). Because a percentage
   translate resolves against the element's own width, and that width IS
   the band, the glow's centre lands at exactly `elapsed fraction × band`
   — so the sweep stays in phase with the beat flashes at any viewport
   width. A fixed px or vw distance would drift the moment the shell
   hits its 1160px max-width.

   Both radii must stay INSIDE the box: the gradient is painted within
   the element's own bounds, so anchoring at 0% (or using a vertical
   radius over 50%) clips the ellipse and it renders as a hard-edged
   rectangle rather than a glow. 46% keeps it clear of the top and
   bottom at both band heights. */
.pulse__sweep {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* Comet, not lamp: a bright head hugging the baseline (y = 110/200 =
     55%) plus a longer, dimmer periwinkle tail TRAILING it (centred
     left of the head, %-sized so it scales with the band). Both layers
     ride the same single transform. */
  /* No background of its own. The element is just a moving anchor
     whose RIGHT edge is the pen tip; both visible parts hang off that
     edge as pseudo-elements CENTRED on it.

     They must not be painted as a background on this element: a
     gradient anchored `at 100%` has half its ellipse outside the box
     and gets clipped into a hard vertical edge — the same clipping
     trap that made the very first sweep render as a rectangle. */
  opacity: 0;
  animation: pulse-head var(--pulse-period) var(--ds-ease-linear) infinite;
  will-change: transform;
}

/* The write head: a small, HARD-EDGED dot riding the baseline
   (y = 110/200 = 55%). The soft gradients above give atmosphere but
   nothing the eye can lock onto — this dot is what makes the motion
   legible as "the line is being drawn right now". It sits at the
   sweep's own 50%, so it inherits the sweep's phase for free. */
/* Soft halo around the pen tip — its own box, centred on the head, so
   the ellipse is never clipped. */
.pulse__sweep::before {
  content: '';
  position: absolute;
  left: 100%;
  top: 55%;
  width: 190px;
  height: 116px;
  margin: -58px 0 0 -95px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(214,201,255,.34), rgba(214,201,255,0) 100%);
}
/* The pen tip itself. */
.pulse__sweep::after {
  content: '';
  position: absolute;
  left: 100%;
  top: 55%;
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 10px 3px rgba(214,201,255,.85);
}

/* ============================================================
   PHOSPHOR PERSISTENCE TRAIL
   ------------------------------------------------------------
   The single biggest "alive" upgrade. A hot copy of the trace,
   revealed through a travelling window whose mask is bright at the
   leading edge and fades over a long tail behind it — a real monitor's
   afterglow. The line is no longer a static graphic that occasionally
   blinks; there is always a lit region moving along it.

   The counter-translate pair is the whole trick:
     .pulse__hot        translateX(-50% → 50%)   ← carries the mask
     .pulse__hot-inner  translateX( 50% → -50%)  ← cancels it out
   Net content displacement is zero, so the trace stays put while the
   window sweeps. Both halves are plain transforms, so this stays
   inside the transform/opacity budget and needs no JS.

   Phase note: the outer's travel is identical to .pulse__sweep's, so
   the head, the write dot and the beat flashes all stay locked to the
   same fractions of --pulse-period.
   ============================================================ */
.pulse__hot {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* The mask is a solid block exactly the width of the band, with a
     soft trailing edge (the ink fading as it is wiped) and a crisp
     leading edge (the pen tip). mask-repeat MUST be no-repeat, or the
     block tiles and the window never ends.

     Geometry of the illusion: the window is one band wide, so as it
     slides from translateX(-100%) to translateX(100%) its intersection
     with the band grows 0 → full (drawing) and then shrinks full → 0
     from the left (erasing). One linear translate produces both halves
     of the cycle — no width animation, no dash offset. */
  -webkit-mask-image: linear-gradient(90deg,
    transparent 0%, rgba(0,0,0,.45) 5%, #000 13%, #000 100%);
          mask-image: linear-gradient(90deg,
    transparent 0%, rgba(0,0,0,.45) 5%, #000 13%, #000 100%);
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  animation: pulse-hot-window var(--pulse-period) var(--ds-ease-linear) infinite;
  will-change: transform;
}
.pulse__hot-inner {
  position: absolute;
  inset: 0;
  animation: pulse-hot-counter var(--pulse-period) var(--ds-ease-linear) infinite;
  will-change: transform;
}
.pulse__hot-inner .pulse__svg { width: 100%; height: 100%; }

.pulse__hot-line {
  fill: none;
  stroke: #fff;
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.pulse__hot-glow {
  fill: none;
  stroke: rgba(206,190,255,.75);
  stroke-width: 7;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* Every beat LABEL used to live here — the desktop chips (with their
   stems, per-apex positions and lift animation) and the mobile legend
   below them. All removed by owner call, 2026-07-27: the trace is a
   rhythm, and a rhythm does not come with a key. The reveal/lift
   keyframes and the reduced-motion overrides they needed went too, so
   nothing here styles an element that no longer exists. See the markup
   for why the screen-reader list went as well. */

/* ============================================================
   HONEST FACT STRIP
   Shop-owner-facing facts only. The engineering proof (test count,
   decision count) belongs to section 8, for the other audience.
   ============================================================ */
.hero__facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ds-space-2) var(--ds-space-5);
  margin-top: var(--ds-space-7);
  padding-top: var(--ds-space-5);
  border-top: 1px solid rgba(255,255,255,.16);
}
.hero__facts li {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  font-size: 13.5px;
  color: var(--ds-text-on-gradient-secondary);
}
.hero__facts svg {
  flex: none;
  width: 16px; height: 16px;
  opacity: .85;
}
/* Below 720px the strip is a STACK, not a wrapping row — one fact per
   line, every language. Same reasoning as the hero CTA above: three
   items of unequal width wrapping freely produce a ragged shape that
   reads as an accident rather than a layout.

   The failure was real and locale-specific (owner report, az + tr,
   2026-07-27). On a 375px screen the middle fact is too wide to sit
   beside the first, so it starts line 2 — and az/tr's third fact is
   the short "5 dil", narrow enough to then tuck in beside it. Result:
   one item stranded out on the right with empty space under line 1.
   en/ru/de escaped only because "5 languages"/"5 языков"/"5 Sprachen"
   are wide enough to be pushed down to their own line. That is luck of
   translation, not a layout, and it would break again for any future
   language with a short third fact.

   720px is where it stops mattering. Measured at that width, the shell
   offers 656px of content and the widest locale (de) asks for 580 —
   every language holds all three facts on one line, with room. It is
   also where the shell switches to its wide padding, so the strip
   changes shape on a breakpoint the layout already observes. Above it
   the strip is one honest row, below it three left-aligned lines, and
   the ragged in-between cannot occur in any language. */
@media (max-width: 719px) {
  .hero__facts { row-gap: var(--ds-space-3); }
  .hero__facts li { flex: 1 0 100%; }
}

/* ============================================================
   KEYFRAMES — transform/opacity only, without exception
   ============================================================ */
/* ---- The draw / erase cycle ----------------------------------
   Three animations, one shared shape: -100% → 0% over the first 70%
   (drawing), then 0% → 100% over the last 30% (erasing, faster).
   Keep these three in lockstep — if one changes, all three change. */

/* The masked window. */
@keyframes pulse-hot-window {
  0%   { transform: translateX(-100%); }
  70%  { transform: translateX(0); }
  100% { transform: translateX(100%); }
}
/* Its exact inverse, so the trace itself never moves. */
@keyframes pulse-hot-counter {
  0%   { transform: translateX(100%); }
  70%  { transform: translateX(0); }
  100% { transform: translateX(-100%); }
}
/* The pen tip. Rides the window, then fades the instant the writing
   finishes — during the erase half there is no head, only a tail. */
@keyframes pulse-head {
  0%   { transform: translateX(-100%); opacity: 0; }
  4%   { opacity: 1; }
  66%  { opacity: 1; }
  70%  { transform: translateX(0); opacity: 0; }
  100% { transform: translateX(100%); opacity: 0; }
}

/* The sweep crosses the full band width plus its own overhang.
   Percentages are of the element's own width, so the +/-100px
   overhang is expressed against the band via left/margin above. */
/* Linear 0%→100% of the band, so elapsed fraction == horizontal
   position. That identity is what lets the beat delays be plain
   fractions of --pulse-period (.15/.40/.65/.90) and still land exactly
   on their spikes. Do not ease this one. */

@keyframes pulse-flash {
  0%, 100% { opacity: 0; }
  3%       { opacity: 1; }
  14%      { opacity: .55; }
  30%      { opacity: 0; }
}

@keyframes pulse-dot {
  0%, 100% { transform: scale(1);   opacity: .75; }
  8%       { transform: scale(1.5); opacity: 1; }
  22%      { transform: scale(1);   opacity: .75; }
}

@keyframes pulse-ripple {
  from { transform: scale(0); opacity: .22; }
  to   { transform: scale(1); opacity: 0; }
}

/* The apex echo: appears the instant its beat fires, expands, gone.
   Percentages are of the 6s period — the ring lives ~0.7s. */
@keyframes pulse-echo {
  0%   { transform: scale(.2); opacity: 0; }
  1.5% {                       opacity: .55; }
  11%  { transform: scale(1);  opacity: 0; }
  100% { transform: scale(1);  opacity: 0; }
}

/* ============================================================
   BÖLMƏ 3 — «BİR GÜNÜ YAŞA» SİMULYASİYASI
   ------------------------------------------------------------
   A replica of the product's Sales Mode / Kassa surfaces. Every
   colour here is a --ds-* token; there is not one literal hex in
   this block, because the whole point is that the site and the app
   look like one family. If something needs a colour that is not
   here, it gets added to the app first (see tokens.css's header).

   This is also the site's FIRST content below the fold, so it is the
   first thing that has to survive dark mode — hence the dark token
   block that Stage 2 added to tokens.css.

   Motion contract still holds without exception: transform/opacity
   only, and the one looping animation (the target ring) runs on
   var(--pulse-period) like everything else on this site.
   ============================================================ */
.sim {
  padding-block: clamp(48px, 4vw + 32px, 88px);
}

.sim__intro { max-width: 640px; }

.sim__heading {
  font-size: clamp(1.75rem, 1.2rem + 2.2vw, 2.6rem);
  line-height: 1.12;
  letter-spacing: -.028em;
  font-weight: 600;
  text-wrap: balance;
}
.sim__sub {
  margin-top: var(--ds-space-2);
  font-size: clamp(1.05rem, 1rem + .4vw, 1.3rem);
  font-weight: 500;
  color: var(--ds-brand);
}
.sim__lede {
  margin-top: var(--ds-space-4);
  color: var(--ds-text-secondary);
  max-width: 62ch;
  text-wrap: pretty;
}

/* ============================================================
   THE DAY→NIGHT ARC — applied
   ------------------------------------------------------------
   `.sim__field` is the sky: the one surface in this section with no
   text on it, which is exactly why it is the surface allowed to
   animate. Its two colours interpolate over --arc-duration; the till
   inside it switches palette instantly (see tokens.css for why).

   The section INTRO deliberately sits outside the field, on the stable
   page background. If the heading rode the sky, no single text colour
   could clear AA against both the morning sky (#FFF1DC) and the night
   sky (#171043), and the arc would have to be fought instead of used.
   ============================================================ */
.sim__field {
  margin-top: var(--ds-space-7);
  padding: clamp(12px, 2.2vw, 34px);
  border-radius: var(--ds-radius-card);
  background: linear-gradient(168deg, var(--arc-sky-from) 0%, var(--arc-sky-to) 100%);
  transition: --arc-sky-from var(--arc-duration) var(--ds-ease-standard),
              --arc-sky-to   var(--arc-duration) var(--ds-ease-standard);

  /* NOT redundant, and the arc is broken without it. `body` sets
     `color: var(--ds-text-primary)` — that declaration resolves against
     BODY's value of the token, so re-pointing the token further down the
     tree cannot reach back and change it. Every element inside the till
     that does not name its own colour was still inheriting body's dark
     ink; at the night stop that put #0F1514 text on a #1A1636 surface
     and measured 1.07:1 — invisible. Re-declaring `color` here makes the
     subtree resolve the token again. Measured, not reasoned about. */
  color: var(--ds-text-primary);
}

/* One frame with descendant transitions off, so the till's palette
   lands all at once. Without it a control's own 120ms background
   transition lags behind its instantly-switched text colour and the
   pair measures 1.79:1 while it catches up. Descendants only — the
   sky's transition lives on .sim__field itself and must survive. */
.sim__field.is-arc-switch * {
  transition: none !important;
}

/* Scroll's whole job: engage the arc inside the section, and give the
   page back its ordinary theme on the way out. No scroll-jacking, no
   pinning, nothing that can trap the viewport — the class is toggled by
   an IntersectionObserver and the section scrolls like any other. */
.sim__field:not(.is-arc-on) {
  --arc-sky-from: var(--ds-page-bg);
  --arc-sky-to: var(--ds-page-bg);
}

.sim__field.is-arc-on[data-arc="morning"] {
  --arc-sky-from: var(--arc-morning-sky-from);
  --arc-sky-to: var(--arc-morning-sky-to);
}
.sim__field.is-arc-on[data-arc="midday"] {
  --arc-sky-from: var(--arc-midday-sky-from);
  --arc-sky-to: var(--arc-midday-sky-to);
}
.sim__field.is-arc-on[data-arc="afternoon"] {
  --arc-sky-from: var(--arc-afternoon-sky-from);
  --arc-sky-to: var(--arc-afternoon-sky-to);
}
.sim__field.is-arc-on[data-arc="evening"] {
  --arc-sky-from: var(--arc-evening-sky-from);
  --arc-sky-to: var(--arc-evening-sky-to);
}
.sim__field.is-arc-on[data-arc="night"] {
  --arc-sky-from: var(--arc-night-sky-from);
  --arc-sky-to: var(--arc-night-sky-to);
}

/* The till's own surface. Re-pointing --ds-surface here means all ~80
   existing rules inside the simulation follow the arc without a single
   one of them being edited — the token is already what they read. */
.sim__field[data-arc="morning"]   { --ds-surface: var(--arc-morning-surface); }
.sim__field[data-arc="midday"]    { --ds-surface: var(--arc-midday-surface); }
.sim__field[data-arc="afternoon"] { --ds-surface: var(--arc-afternoon-surface); }
.sim__field[data-arc="evening"]   { --ds-surface: var(--arc-evening-surface); }

/* NIGHT — the till switches to a night palette in one step, never
   interpolated. Values are the app's own dark tokens, so this is the
   product's real night mode rather than a new palette invented for a
   sunset. In an already-dark theme this changes almost nothing, which
   is correct: the room was already dark. */
.sim__field[data-arc="night"] {
  --ds-surface: #1A1636;
  --ds-page-bg: #100C28;
  --ds-text-primary: #EEF3F3;
  --ds-text-secondary: #BFCBC9;
  --ds-text-tertiary: #A6B2B0;
  --ds-text-quiet: #92A09D;
  --ds-text-placeholder: #56605E;
  --ds-border: #2E2856;
  --ds-border-strong: #3D3568;
  --ds-neutral-badge-bg: #241F45;
  --ds-brand: #0DA58C;
  --ds-brand-tint: #1B3733;
  --ds-brand-tint-text: #62CBB9;
  --ds-brand-tint-hover: #24443F;
  --ds-text-on-brand: #0F1514;
  --ds-success: #6CD079;
  --ds-success-tint: #213D25;
  --ds-success-text: #6CD079;
  --ds-error: #E5766F;
  --ds-error-tint: #3A2422;
  --ds-error-text: #E5766F;
  --ds-warning: #D4A24C;
  --ds-warning-tint: #332818;
  --ds-warning-text: #D4A24C;
  --ds-commerce: #54A7E3;
  --ds-commerce-tint: #1C3242;
  --ds-shadow-card: 0 1px 2px rgba(0,0,0,.4), 0 4px 14px rgba(0,0,0,.5);
  --ds-shadow-hero: 0 2px 4px rgba(0,0,0,.4), 0 10px 34px rgba(0,0,0,.55);
}

/* «the kəsir figure is the only lit element». Everything else on the
   Z-report is legible but quiet; the shortfall is the one thing giving
   off light. The glow is a box-shadow on a static element — no
   animation, so the motion contract is untouched. */
.sim__field[data-arc="night"] .sim-zdiff--short {
  background: #40201F;
  color: #FFC9C4;
  box-shadow: 0 0 0 1px rgba(229,118,111,.45),
              0 0 34px rgba(229,118,111,.42),
              0 0 90px rgba(229,118,111,.18);
}
.sim__field[data-arc="night"] .sim-zdiff__value { color: #FFE2DF; }
.sim__field[data-arc="night"] .sim-zgroup { opacity: .82; }

/* ---- The frame: one object, the app's card language ---- */
.sim__frame {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-card);
  box-shadow: var(--ds-shadow-hero);
  overflow: hidden;
}

/* Never small print, never dismissible, never below the fold of the
   frame. It is the first line inside the box for a reason. */
.sim__disclaimer {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  padding: var(--ds-space-3) var(--ds-space-5);
  background: var(--ds-warning-tint);
  color: var(--ds-warning-text);
  font-size: 13.5px;
  font-weight: 600;
  border-bottom: 1px solid var(--ds-border);
}
.sim__disclaimer svg { flex: none; width: 17px; height: 17px; }

/* ---- Chrome ---- */
.sim__chrome {
  display: flex;
  align-items: center;
  gap: var(--ds-space-3);
  flex-wrap: wrap;
  padding: var(--ds-space-3) var(--ds-space-5);
  border-bottom: 1px solid var(--ds-border);
  background: var(--ds-neutral-badge-bg);
}
.sim__chrome-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--ds-space-2);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ds-commerce);
  margin-inline-end: auto;
}
.sim__chrome-brand svg { width: 17px; height: 17px; }

.sim-chip {
  display: inline-flex;
  align-items: center;
  padding: 4px 11px;
  border-radius: var(--ds-radius-pill);
  background: var(--ds-surface);
  border: 1px solid var(--ds-border-strong);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ds-text-tertiary);
  font-variant-numeric: tabular-nums;
}
.sim-chip--ok {
  background: var(--ds-success-tint);
  border-color: transparent;
  color: var(--ds-success-text);
}
.sim-chip--count {
  background: var(--ds-brand-tint);
  border-color: transparent;
  color: var(--ds-brand-tint-text);
}

.sim-net {
  display: inline-flex;
  align-items: center;
  gap: var(--ds-space-2);
  padding: 5px 12px;
  min-height: 32px;
  border-radius: var(--ds-radius-pill);
  border: 1px solid var(--ds-border-strong);
  background: var(--ds-surface);
  color: var(--ds-text-tertiary);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.sim-net__dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--ds-success);
}
.sim-net--off {
  background: var(--ds-warning-tint);
  border-color: transparent;
  color: var(--ds-warning-text);
}
.sim-net--off .sim-net__dot { background: var(--ds-warning); }

/* ---- Coach strip ---- */
.sim__coach {
  display: grid;
  gap: var(--ds-space-4);
  padding: var(--ds-space-5);
  border-bottom: 1px solid var(--ds-border);
  background: var(--ds-brand-tint);
}
@media (min-width: 860px) {
  .sim__coach {
    grid-template-columns: 1fr auto;
    align-items: center;
  }
  .sim__dots { grid-column: 1 / -1; }
}

/* Seven beats — the same motif as the hero, counting a different
   thing. The current one breathes on the shared clock. */
/* The base reset only strips markers from `ul`; this is an `ol` because
   the seven steps are genuinely ordered, so it has to strip its own —
   otherwise the decimal markers print «1. 2. 3.» under the bars. Found
   live, not reasoned about. `.sim-fallback ol` keeps its numbers on
   purpose, which is why this is scoped rather than added to the reset. */
.sim__dots {
  display: flex;
  gap: var(--ds-space-2);
  list-style: none;
  padding: 0;
}
.sim-dot {
  width: 100%;
  max-width: 46px;
  height: 4px;
  border-radius: var(--ds-radius-pill);
  background: var(--ds-brand-tint-hover);
}
.sim-dot.is-done { background: var(--ds-brand); }
.sim-dot.is-now {
  background: var(--ds-brand);
  animation: pulse-dot var(--pulse-period) var(--ds-ease-standard) infinite;
}

.sim__coach-step,
.sim__coach-body .sim-coach__step {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ds-brand-tint-text);
}
.sim-coach__title {
  margin-top: var(--ds-space-1);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: -.015em;
  color: var(--ds-text-primary);
}
.sim-coach__why {
  margin-top: 2px;
  font-size: 14px;
  color: var(--ds-text-secondary);
  max-width: 60ch;
}
.sim-coach__hint {
  margin-top: var(--ds-space-3);
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ds-brand-tint-text);
  max-width: 60ch;
}

.sim__controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ds-space-2);
}
.sim-ctl {
  appearance: none;
  min-height: 44px;
  padding: 0 var(--ds-space-4);
  border-radius: var(--ds-radius-control);
  border: 1px solid var(--ds-border-strong);
  background: var(--ds-surface);
  color: var(--ds-text-secondary);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--ds-duration-fast) var(--ds-ease-standard);
}
.sim-ctl:hover { background: var(--ds-neutral-badge-bg); }
.sim-ctl--next {
  background: var(--ds-brand);
  border-color: transparent;
  color: var(--ds-text-on-brand);
}
.sim-ctl--next:hover { background: var(--ds-brand-hover); }

/* ---- Stage ---- */
.sim__stage { padding: var(--ds-space-5); }

.sim-fallback { color: var(--ds-text-secondary); font-size: 15px; }
.sim-fallback ol {
  list-style: decimal;
  padding-inline-start: var(--ds-space-6);
  margin-top: var(--ds-space-3);
  display: grid;
  gap: var(--ds-space-2);
}
.sim-fallback strong { color: var(--ds-text-primary); }

.sim-pane--center { max-width: 520px; margin-inline: auto; }
.sim-pane--pos {
  display: grid;
  gap: var(--ds-space-5);
}
/* DL-286 — 860px -> 900px. Not a taste change: this is the app's own
   cutoff (`.sm-layout`, DL-263), and the two-pane/drawer decision now
   has to be the same number on both sides or the replica shows a
   layout at some width where the product shows the other one. */
@media (min-width: 900px) {
  .sim-pane--pos { grid-template-columns: minmax(0, 1fr) minmax(0, 340px); }
}
/* Below 900px the pane is a single implicit `auto` track, and an auto
   track's floor is the item's min-content size — so one unshrinkable
   child silently widened the whole column past the frame, which clips
   at `overflow-x: hidden` and shows no scrollbar to admit it. Measured
   on a 375px phone: pane 289px, column 315px, 26px of the flash, the
   tiles, the crosslink and the cart bar cut off at the right edge.
   `minmax(0, …)` is already how the desktop track says this; the
   columns say it for the implicit track. */
.sim-col { min-width: 0; }

/* ---- Buttons inside the till ---- */
.sim-btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ds-space-2);
  min-height: 44px;
  padding: 0 var(--ds-space-5);
  border-radius: var(--ds-radius-control);
  border: 1px solid var(--ds-border-strong);
  background: var(--ds-surface);
  color: var(--ds-text-primary);
  font: inherit;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--ds-duration-fast) var(--ds-ease-standard);
}
.sim-btn--primary,
.sim-btn--scan {
  background: var(--ds-brand);
  border-color: transparent;
  color: var(--ds-text-on-brand);
}
.sim-btn--pay {
  width: 100%;
  min-height: 52px;
  margin-top: var(--ds-space-3);
  font-size: 16px;
  border-color: transparent;
  background: var(--ds-gradient-hero);
  color: var(--ds-text-on-gradient);
}
.sim-btn--quiet {
  background: var(--ds-surface);
  color: var(--ds-text-secondary);
  min-height: 40px;
  font-size: 13.5px;
}

/* Inert, not broken: the screen keeps its shape and its numbers, it
   simply cannot be driven off the scripted day. Kept legible rather
   than ghosted — a shopkeeper is here to read the till, not to click
   every button on it. */
/* Two exclusions, one rule: a control that is currently REPORTING state
   rather than offering an action must not be dimmed. The chosen payment
   method (.is-on) and the switched-off network pill (.sim-net--off) both
   read as "unavailable" when faded — caught on screen, not in review. */
.sim__frame button:disabled:not(.is-on):not(.sim-net--off) {
  opacity: .45;
  cursor: default;
}
.sim__frame button:disabled { cursor: default; }

/* The one control the step is waiting for. A ring on the shared clock —
   the pulse metaphor doing an actual job: "here, now". */
.sim__frame .is-target:not(:disabled) {
  position: relative;
  box-shadow: 0 0 0 3px var(--ds-brand-tint), 0 0 0 4px var(--ds-brand);
}
.sim__frame .is-target::before {
  content: '';
  position: absolute;
  inset: -4px;
  border-radius: inherit;
  border: 2px solid var(--ds-brand);
  opacity: 0;
  transform: scale(1);
  pointer-events: none;
  animation: sim-target var(--pulse-period) var(--ds-ease-decelerate) infinite;
}

/* ---- Kassa aç / bağla / qaytarma panels ---- */
.sim-open, .sim-return, .sim-z {
  display: grid;
  gap: var(--ds-space-4);
  padding: var(--ds-space-5);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  background: var(--ds-surface);
  box-shadow: var(--ds-shadow-card);
}
.sim-open__title {
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: -.015em;
}
.sim-open__note {
  margin-top: -8px;
  font-size: 14px;
  color: var(--ds-text-secondary);
}

.sim-field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-4);
  padding: var(--ds-space-3) var(--ds-space-4);
  border-radius: var(--ds-radius-md);
  background: var(--ds-neutral-badge-bg);
}
.sim-field__label { font-size: 13.5px; color: var(--ds-text-secondary); }
.sim-field__value {
  font-size: 1.1rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* ---- Scan row + catalogue ---- */
.sim-scan {
  display: flex;
  gap: var(--ds-space-3);
  flex-wrap: wrap;
}
.sim-scan__field {
  flex: 1 1 200px;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--ds-space-3);
  padding: 0 var(--ds-space-4);
  min-height: 44px;
  border: 1px solid var(--ds-border-strong);
  border-radius: var(--ds-radius-control);
  background: var(--ds-surface);
  color: var(--ds-text-quiet);
}
.sim-scan__field svg { flex: none; width: 19px; height: 19px; }
/* `min-width: 0` is what lets the ellipsis below ever fire: as a flex
   item its automatic minimum is its min-content size, and `nowrap` makes
   that the whole placeholder (250px of «Barkodu skan edin və ya məhsul
   axtarın…», more in RU/DE). That was the single child pushing the POS
   column past the phone. Truncating is also what the product does — its
   scan row is a real `<input>` (main.py, `#scan-input`), and a native
   placeholder clips rather than wraps. */
.sim-scan__code {
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sim-tiles {
  margin-top: var(--ds-space-4);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--ds-space-3);
}
.sim-tile {
  display: grid;
  gap: 2px;
  padding: var(--ds-space-3);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  background: var(--ds-surface);
}
.sim-tile__name { font-size: 13px; font-weight: 600; line-height: 1.3; }
.sim-tile__price {
  font-size: 14px;
  font-weight: 600;
  color: var(--ds-commerce);
  font-variant-numeric: tabular-nums;
}
.sim-tile__stock { font-size: 11.5px; color: var(--ds-text-quiet); }
.sim-tile__stock--low { color: var(--ds-warning-text); font-weight: 600; }

.sim-crosslink { margin-top: var(--ds-space-4); }

/* ---- Cart ---- */
.sim-cart {
  padding: var(--ds-space-4);
  border: 1px solid var(--ds-border);
  border-top: 3px solid var(--ds-commerce);
  border-radius: var(--ds-radius-lg);
  background: var(--ds-surface);
  box-shadow: var(--ds-shadow-card);
}
.sim-cart__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-3);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ds-text-quiet);
}
.sim-cart__table {
  width: 100%;
  border-collapse: collapse;
  margin-top: var(--ds-space-3);
  font-size: 13.5px;
}
.sim-cart__table th {
  text-align: start;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ds-text-quiet);
  padding-bottom: var(--ds-space-2);
  border-bottom: 1px solid var(--ds-border);
}
.sim-cart__table td {
  padding-block: var(--ds-space-2);
  border-bottom: 1px solid var(--ds-border);
}
.sim-cart__table .num { text-align: end; font-variant-numeric: tabular-nums; }
.sim-cart__empty {
  color: var(--ds-text-quiet);
  font-size: 13px;
  padding-block: var(--ds-space-5) !important;
}
.sim-cart__total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--ds-space-4);
  padding-top: var(--ds-space-3);
  font-size: 1.05rem;
  font-weight: 600;
}
.sim-cart__total .num { font-variant-numeric: tabular-nums; }

/* ============================================================
   DL-286 — THE TILL ON A PHONE
   ============================================================
   Two faults, one root, measured at 375x812 on the live site.

   ROOT: the replica was handing the till 269px of a 375px screen.
   The chain was .shell 20+20, .sim__field 12+12, .sim__stage 20+20 —
   86px, 24% of the phone, spent on the replica's own nesting. The
   product itself gives its catalogue ~355px (body padding 10+10).

   FAULT 1, honesty. At 269px `minmax(140px, 1fr)` cannot fit two
   columns (140+140+12 = 292), so six tiles stacked into ONE column
   578px tall. The app's own grid is `minmax(150px, 1fr)` and at its
   real 355px it lays out TWO. The replica was not showing a narrower
   screen; it was showing a layout the product does not have.

   FAULT 2, the scroll. Those 578px sat between «Barkodu oxut» and the
   cart it fills — and the catalogue tiles are deliberately inert, so
   it was 578px of scenery. The first scan pushed the button 248px off
   the top (`nextTargetVisible:false`): press, see nothing, press
   again. The founder reported it as «bug kimi görünür».

   THE FIX IS THE PRODUCT'S OWN. Below 900px — the app's cutoff, not a
   new one — the app hides the cart column and floats a summary bar
   (DL-263), which raises the cart as a sheet (DL-138). The replica now
   does the same, and gets its width back on the way.

   The tile minimum drops 140px -> 118px here rather than copying the
   app's 150px, because the frame is a frame: it will always be
   narrower than a full app on the same phone. What has to match is the
   OUTCOME the shopkeeper sees — two columns — not the threshold.
   ============================================================ */
/* BASE FIRST, PHONE QUERY SECOND — and it has to be this way round.
   Written the other way (query above, `display:none` below) the two
   rules tie on specificity, the later one wins, and the bar is
   `display:none` at EVERY width. Caught by measuring: the bar existed
   in the DOM with the right label and a 0x0 box. */
/* Three labels on one 289px row, and the two longest locales are the
   ones that decide the sizing. Measured at 375px with two items in the
   cart: German «Warenkorb · 2 / 2.40 AZN / Öffnen ▲» needs 266px and
   Russian «Корзина · 2 / 2.40 AZN / Открыть ▲» 265px — so the tightest
   of the five clears by ~23px. Nothing is clipped today.

   The 8px gap and the shrink rules below are headroom, not a repair: a
   bar that fits only because the current five translations happen to be
   short is a bar that breaks on the sixth. If something must give, it is
   the COUNT — the total may never shrink or ellipsis, because it is the
   number the visitor is checking. */
.sim-cart-bar {
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-2);
  width: 100%;
  min-height: 48px;
  margin-top: var(--ds-space-4);
  padding: var(--ds-space-3) var(--ds-space-4);
  border: none;
  border-radius: 14px;
  background: var(--ds-commerce);
  color: #FFFFFF;
  font: inherit;
  font-size: 14.5px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: var(--ds-shadow-card);
}
/* Only the count gives way. `min-width:0` is the part that actually does
   the work — without it a flex item refuses to shrink below its content
   and `text-overflow` never fires.

   (Do not test this row with `el.scrollWidth > el.clientWidth`. On a
   `justify-content: space-between` flex container that reads 293 vs 289
   with 23px of room to spare; it cost a round trip here. Compare each
   child's rect against the parent's padding box instead.) */
.sim-cart-bar > :first-child {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sim-cart-bar .num { flex: none; font-variant-numeric: tabular-nums; }
.sim-cart-bar__hint {
  flex: none;
  display: inline-flex;
  gap: 4px;
  font-size: 12.5px;
  opacity: .9;
}

.sim-scrim { display: none; }

/* The ✕ belongs to the sheet. Above 900px the cart is a permanent
   column and a column cannot be closed, so the button is not merely
   invisible there — `display:none` keeps it off the Tab order too. */
.sim-cart__close { display: none; }

@media (max-width: 899px) {
  /* Give the phone back what the nesting was taking. */
  .sim__field { padding: 10px; }
  .sim__stage { padding: var(--ds-space-3); }
  .sim-tiles { grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); }

  /* The cart stops being a column and becomes a sheet. */
  .sim-col--right { display: none; }
  .is-cart-open .sim-col--right { display: block; }

  .sim-cart-bar { display: flex; }

  /* Not floating, and that is deliberate. The app's bar floats because
     its catalogue is hundreds of products long; this one is six and
     fits, so a bar pinned to the viewport would only be an animation of
     a problem the replica does not have. It also must not escape the
     frame onto the marketing page around it. Resting at the bottom of a
     screen that fits looks the same and lies about nothing. */
  .is-cart-open .sim-cart-bar { visibility: hidden; }

  .sim-cart__close {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-inline-start: auto;
    min-width: 44px;
    min-height: 44px;
    border: none;
    border-radius: 8px;
    background: var(--ds-neutral-badge-bg);
    color: var(--ds-text-primary);
    font-size: 1rem;
    cursor: pointer;
  }

  .is-cart-open .sim-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 119;
    background: rgba(20, 18, 31, .45);
  }
  .is-cart-open .sim-cart {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: 0;
    width: calc(100% - 20px);
    max-width: 520px;
    max-height: 75dvh;
    overflow-y: auto;
    z-index: 120;
    border-radius: 16px 16px 0 0;
    box-shadow: var(--ds-shadow-overlay);
    background: var(--ds-surface);
  }
}

.sim-methods {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--ds-space-2);
  margin-top: var(--ds-space-4);
}
.sim-pay {
  appearance: none;
  min-height: 44px;
  padding: 0 var(--ds-space-2);
  border: 1px solid var(--ds-border-strong);
  border-radius: var(--ds-radius-control);
  background: var(--ds-surface);
  color: var(--ds-text-secondary);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}
.sim-pay.is-on {
  background: var(--ds-brand);
  border-color: transparent;
  color: var(--ds-text-on-brand);
}

/* Three of five need two rows, and this is measured rather than guessed.
   At 375px each of the four buttons is 51px wide, ~43px of that usable
   for text. Widest payment label per language, measured against the real
   computed font (600 13.5px IBM Plex Sans):

       az «Bölmə»       40.0px   fits
       en «Credit»      38.3px   fits
       tr «Veresiye»    53.4px   clipped
       ru «Разделить»   69.4px   clipped
       de «Anschreiben» 78.7px   clipped

   This rule used to name Russian alone, on the reasoning that German and
   Turkish were narrower than the Azerbaijani baseline, so a container
   holding az held them too. That was true and is now false: DL-280 gave
   each language its own word for nisyə, and «Veresiye»/«Anschreiben»
   replaced a 5-letter label with an 8- and an 11-letter one. The lesson
   is that this list is a function of the DICTIONARY, not of the language
   count — re-measure it whenever a payment label changes, not only when
   a language is added. A content-driven rule (flex-wrap with
   `min-width: max-content`) would end the class, but wraps 3+1 ragged
   instead of 2×2; the neat two rows are worth the measurement. */
[lang="ru"] .sim-methods,
[lang="tr"] .sim-methods,
[lang="de"] .sim-methods { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* …except a demo cart that declares one of the two languages that DO fit
   four across. The five-language chapter must show each language's real
   layout even when the page around it is Russian, German or Turkish, or
   it stops being a demonstration. Written as a positive list so it
   cannot drift out of step with the rule above. */
.m-cartdemo[lang="az"] .sim-methods,
.m-cartdemo[lang="en"] .sim-methods {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.sim-sub {
  display: grid;
  gap: var(--ds-space-2);
  margin-top: var(--ds-space-3);
  padding: var(--ds-space-3);
  border-radius: var(--ds-radius-md);
  background: var(--ds-neutral-badge-bg);
}
.sim-sub__label {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--ds-text-quiet);
}
.sim-sub__picked {
  font-size: 14px;
  font-weight: 600;
  color: var(--ds-brand-tint-text);
}
.sim-sub__ok { font-size: 13px; font-weight: 600; color: var(--ds-success-text); }
.sim-sub__hint { font-size: 12.5px; color: var(--ds-text-quiet); align-self: center; }

.sim-leg {
  display: flex;
  justify-content: space-between;
  gap: var(--ds-space-3);
  font-size: 13.5px;
  font-weight: 600;
}
.sim-leg .num { font-variant-numeric: tabular-nums; }
.sim-quick { display: flex; flex-wrap: wrap; gap: var(--ds-space-2); }

.sim-flash {
  margin-bottom: var(--ds-space-4);
  padding: var(--ds-space-3) var(--ds-space-4);
  border-radius: var(--ds-radius-md);
  background: var(--ds-success-tint);
  color: var(--ds-success-text);
  font-size: 13.5px;
  font-weight: 600;
}
.sim-flash--offline {
  background: var(--ds-warning-tint);
  color: var(--ds-warning-text);
}

/* ---- Return ---- */
.sim-rlines { display: grid; gap: var(--ds-space-2); }
.sim-rline {
  display: flex;
  align-items: center;
  gap: var(--ds-space-3);
  padding: var(--ds-space-3);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
}
.sim-rline__name { flex: 1 1 auto; font-size: 13.5px; font-weight: 600; }
.sim-rline__meta { font-size: 12.5px; color: var(--ds-text-quiet); }

.sim-rpanel {
  display: grid;
  gap: var(--ds-space-3);
  padding: var(--ds-space-4);
  border-radius: var(--ds-radius-md);
  background: var(--ds-brand-tint);
}
.sim-rpanel__title { font-size: 15px; font-weight: 600; }
.sim-rpanel__sub { font-size: 13px; color: var(--ds-text-secondary); }
.sim-rpanel__check { font-size: 13px; font-weight: 600; color: var(--ds-success-text); }

/* ---- Z-Hesabat ---- */
.sim-zgroup {
  display: grid;
  gap: var(--ds-space-1);
  padding: var(--ds-space-3) var(--ds-space-4);
  border-radius: var(--ds-radius-md);
  background: var(--ds-neutral-badge-bg);
}
.sim-zrow {
  display: flex;
  justify-content: space-between;
  gap: var(--ds-space-4);
  font-size: 13.5px;
  color: var(--ds-text-secondary);
}
.sim-zrow .num { font-variant-numeric: tabular-nums; }
.sim-zrow--sum {
  margin-top: var(--ds-space-2);
  padding-top: var(--ds-space-2);
  border-top: 1px solid var(--ds-border-strong);
  font-weight: 600;
  color: var(--ds-text-primary);
}

/* The kəsir is the loudest thing on the last frame. That is the
   whole argument: Zerb does not remove it, it refuses to hide it. */
.sim-zdiff {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--ds-space-4);
  padding: var(--ds-space-4);
  border-radius: var(--ds-radius-md);
  background: var(--ds-success-tint);
  color: var(--ds-success-text);
}
.sim-zdiff--short {
  background: var(--ds-error-tint);
  color: var(--ds-error-text);
}
.sim-zdiff__label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.sim-zdiff__value {
  font-size: 1.35rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.sim-z__truth {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ds-text-secondary);
}
.sim-z__truth strong { color: var(--ds-text-primary); }

.sim__foot {
  margin-top: var(--ds-space-4);
  font-size: 13px;
  color: var(--ds-text-quiet);
  max-width: 62ch;
}

/* ============================================================
   SHARED SECTION FURNITURE
   Every below-fold section uses the same heading rhythm, so the
   page reads as one document rather than a stack of components.
   ============================================================ */
.sec__intro { max-width: 640px; }
.sec__heading {
  font-size: clamp(1.6rem, 1.15rem + 1.9vw, 2.4rem);
  line-height: 1.14;
  letter-spacing: -.026em;
  font-weight: 600;
  text-wrap: balance;
}
.sec__lede {
  margin-top: var(--ds-space-3);
  color: var(--ds-text-secondary);
  max-width: 62ch;
  text-wrap: pretty;
}

/* Alternating canvas: surface / page-bg down the page, so adjacent
   sections separate without a rule line between every one of them. */
.pain, .feat, .obj { background: var(--ds-surface); }
.pain, .more, .feat, .biz, .obj, .built, .wait {
  padding-block: clamp(48px, 4vw + 32px, 84px);
}

/* ============================================================
   BÖLMƏ 2 — AĞRI
   ============================================================ */
.pain__grid {
  margin-top: var(--ds-space-7);
  display: grid;
  gap: var(--ds-space-4);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.pain__card {
  padding: var(--ds-space-5);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  background: var(--ds-page-bg);
}
.pain__quote {
  display: block;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -.015em;
  color: var(--ds-error-text);
  margin-bottom: var(--ds-space-2);
}
.pain__card p { font-size: 14.5px; color: var(--ds-text-secondary); }
.pain__turn {
  margin-top: var(--ds-space-6);
  padding: var(--ds-space-5);
  border-radius: var(--ds-radius-lg);
  background: var(--ds-brand-tint);
  color: var(--ds-text-primary);
  font-size: clamp(1rem, .95rem + .35vw, 1.15rem);
  max-width: 62ch;
}
.pain__turn em { font-style: normal; color: var(--ds-text-quiet); }

/* ============================================================
   BÖLMƏ 3b — DAHA NƏ VAR? (explorer)
   Deliberately the SAME frame language as the simulation: it is
   the same product, just without a rail.
   ============================================================ */
.more__frame {
  margin-top: var(--ds-space-7);
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-card);
  box-shadow: var(--ds-shadow-hero);
  overflow: hidden;
}
.more__tabs {
  display: flex;
  gap: var(--ds-space-2);
  padding: var(--ds-space-3) var(--ds-space-4);
  border-bottom: 1px solid var(--ds-border);
  background: var(--ds-neutral-badge-bg);
  overflow-x: auto;
  /* Five chapter names do not fit on a 375px screen and never will.
     Scrolling the strip is right; wrapping it into three ragged rows
     is not. The container scrolls, the page does not. */
  scrollbar-width: thin;
}
.more__tab {
  appearance: none;
  flex: 0 0 auto;
  min-height: 40px;
  padding: 0 var(--ds-space-4);
  border-radius: var(--ds-radius-pill);
  border: 1px solid var(--ds-border-strong);
  background: var(--ds-surface);
  color: var(--ds-text-secondary);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--ds-duration-fast) var(--ds-ease-standard);
}
.more__tab:hover { background: var(--ds-brand-tint); }
.more__tab.is-on {
  background: var(--ds-brand);
  border-color: transparent;
  color: var(--ds-text-on-brand);
}
.more__stage { padding: var(--ds-space-5); }
.more__stage:focus-visible { outline-offset: -3px; }

.m-title { font-size: 1.15rem; font-weight: 600; letter-spacing: -.015em; }
.m-sub {
  margin-top: var(--ds-space-2);
  font-size: 14px;
  color: var(--ds-text-secondary);
  max-width: 68ch;
}
.m-sub em { font-style: italic; color: var(--ds-text-quiet); }
.m-act { margin-top: var(--ds-space-4); }
.m-hint {
  margin-top: var(--ds-space-2);
  font-size: 12.5px;
  color: var(--ds-text-quiet);
}

/* Wide tables scroll inside their own box — the page never does. */
.m-tablewrap { margin-top: var(--ds-space-4); overflow-x: auto; }
.m-table {
  width: 100%;
  min-width: 520px;
  border-collapse: collapse;
  font-size: 13.5px;
}
.m-table th {
  text-align: start;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ds-text-quiet);
  padding: 0 var(--ds-space-3) var(--ds-space-2) 0;
  border-bottom: 1px solid var(--ds-border-strong);
  white-space: nowrap;
}
.m-table td {
  padding: var(--ds-space-2) var(--ds-space-3) var(--ds-space-2) 0;
  border-bottom: 1px solid var(--ds-border);
}
.m-table .num { text-align: end; font-variant-numeric: tabular-nums; }
.m-table tfoot td {
  font-weight: 600;
  border-bottom: 0;
  border-top: 2px solid var(--ds-border-strong);
  color: var(--ds-text-primary);
}
.m-profit { color: var(--ds-success-text); font-weight: 600; }

.m-state {
  display: inline-block;
  padding: 2px 9px;
  border-radius: var(--ds-radius-pill);
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
}
.m-state--full    { background: var(--ds-success-tint); color: var(--ds-success-text); }
.m-state--partial { background: var(--ds-warning-tint); color: var(--ds-warning-text); }
.m-state--none    { background: var(--ds-error-tint);   color: var(--ds-error-text); }
.m-state--wait    { background: var(--ds-neutral-badge-bg); color: var(--ds-text-quiet); }

.m-split {
  margin-top: var(--ds-space-4);
  display: grid;
  gap: var(--ds-space-4);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
/* The roles view lost its second panel — the product card demonstrated a gate
   the product does not have (cost price is readable by any operator), so it
   came out. auto-fit would stretch the six-item menu that is left across the
   whole shell; hold it to a card's width so it still reads as a panel. */
.m-split--single { grid-template-columns: minmax(240px, 420px); }
.m-panel {
  padding: var(--ds-space-4);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  background: var(--ds-page-bg);
}
.m-panel h4 {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--ds-text-quiet);
  margin-bottom: var(--ds-space-3);
}
.m-panel--ok   { background: var(--ds-success-tint); border-color: transparent; }
.m-panel--warn { background: var(--ds-warning-tint); border-color: transparent; }
.m-panel--msg  { background: var(--ds-brand-tint);   border-color: transparent;
                 margin-top: var(--ds-space-4); }
.m-panel__note {
  margin-top: var(--ds-space-3);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ds-text-secondary);
}
.m-msg {
  padding: var(--ds-space-3);
  border-radius: var(--ds-radius-sm);
  background: var(--ds-surface);
  font-size: 14px;
  line-height: 1.6;
}

.m-kv {
  display: flex;
  justify-content: space-between;
  gap: var(--ds-space-4);
  padding-block: 5px;
  font-size: 13.5px;
}
.m-kv .num { font-variant-numeric: tabular-nums; }
/* The mask itself — a row of dots carrying no information, so its
   contrast is incidental. The label beside it is NOT dimmed. */
.m-masked { color: var(--ds-text-placeholder); letter-spacing: .12em; }

/* ---- Debt ageing ---- */
.m-buckets {
  margin-top: var(--ds-space-4);
  display: grid;
  gap: var(--ds-space-3);
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.m-bucket {
  display: grid;
  gap: 4px;
  padding: var(--ds-space-3);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
}
.m-bucket--hot { border-color: var(--ds-error); background: var(--ds-error-tint); }
.m-bucket__label { font-size: 11.5px; font-weight: 600; color: var(--ds-text-quiet); }
.m-bucket__val { font-size: 1rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.m-bucket__bar {
  height: 4px;
  border-radius: var(--ds-radius-pill);
  background: var(--ds-border-strong);
  overflow: hidden;
}
.m-bucket__bar i { display: block; height: 100%; background: var(--ds-brand); }
.m-bucket--hot .m-bucket__bar i { background: var(--ds-error); }

.m-debts { margin-top: var(--ds-space-4); display: grid; gap: var(--ds-space-2); }
.m-debt {
  appearance: none;
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  align-items: center;
  gap: var(--ds-space-3);
  width: 100%;
  min-height: 48px;
  padding: 0 var(--ds-space-4);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  background: var(--ds-surface);
  color: inherit;
  font: inherit;
  font-size: 13.5px;
  text-align: start;
  cursor: pointer;
}
.m-debt:hover { background: var(--ds-neutral-badge-bg); }
.m-debt.is-on { border-color: var(--ds-brand); background: var(--ds-brand-tint); }
.m-debt__name { font-weight: 600; }
.m-debt__age { font-size: 12px; color: var(--ds-text-quiet); white-space: nowrap; }
.m-debt__age--old { color: var(--ds-error-text); font-weight: 600; }
.m-debt__amt { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.m-debt__wa {
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: var(--ds-radius-pill);
  background: var(--ds-success-tint);
  color: var(--ds-success-text);
  white-space: nowrap;
}
@media (max-width: 559px) {
  /* Four columns cannot survive 375px. Name+amount on top, age and the
     WhatsApp pill beneath — nothing is dropped, only re-stacked. */
  .m-debt {
    grid-template-columns: 1fr auto;
    padding-block: var(--ds-space-3);
  }
  .m-debt__age { grid-row: 2; }
  .m-debt__wa  { grid-row: 2; justify-self: end; }
}

/* ---- Roles ---- */
.m-roleswitch, .m-langpick {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ds-space-2);
  margin-top: var(--ds-space-4);
}
.m-roleswitch .sim-pay, .m-langpick .sim-pay { flex: 0 0 auto; padding: 0 var(--ds-space-4); }
.m-menu { display: grid; gap: 6px; font-size: 13.5px; }
.m-menu li { display: flex; align-items: center; gap: var(--ds-space-2); }
/* Struck through and pilled, but READABLE: the point of this list is
   that the owner can see which screens the cashier loses. Placeholder
   grey measured 2.93:1 — the strike-through and the «gizlədilib» pill
   carry the state, so the colour does not have to disappear too. */
.m-menu .is-hidden { color: var(--ds-text-quiet); text-decoration: line-through; }
.m-lock {
  font-size: 10.5px;
  font-weight: 600;
  text-decoration: none;
  padding: 2px 7px;
  border-radius: var(--ds-radius-pill);
  background: var(--ds-neutral-badge-bg);
  color: var(--ds-text-quiet);
}

/* ---- Report ---- */
.m-summary {
  margin-top: var(--ds-space-4);
  display: grid;
  gap: var(--ds-space-3);
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
}
.m-sum {
  display: grid;
  gap: 2px;
  padding: var(--ds-space-3);
  border-radius: var(--ds-radius-md);
  background: var(--ds-neutral-badge-bg);
}
.m-sum span { font-size: 11.5px; font-weight: 600; color: var(--ds-text-quiet); }
.m-sum strong { font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.m-sum--profit { background: var(--ds-success-tint); }
.m-sum--profit strong { color: var(--ds-success-text); }

.m-exports {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--ds-space-2) var(--ds-space-3);
  margin-top: var(--ds-space-4);
}
.m-exports__label { font-size: 13px; font-weight: 600; }
.m-exports__note { font-size: 12px; color: var(--ds-text-quiet); }
.m-badge {
  padding: 4px 12px;
  border-radius: var(--ds-radius-pill);
  border: 1px solid var(--ds-border-strong);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ds-text-secondary);
}

/* ---- Languages ---- */
.m-cartdemo { margin-top: var(--ds-space-4); max-width: 380px; }
.m-cartdemo .sim-btn--pay { opacity: 1; }
/* The one word that is the same in all five — it earns a mark. */
.m-credit {
  border-color: var(--ds-brand) !important;
  color: var(--ds-brand-tint-text) !important;
  opacity: 1 !important;
}

/* ============================================================
   BÖLMƏ 5 — NƏ EDİR
   ============================================================ */
.feat__grid {
  margin-top: var(--ds-space-7);
  display: grid;
  gap: var(--ds-space-4);
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
}
.feat__card {
  position: relative;
  padding: var(--ds-space-5);
  padding-top: var(--ds-space-6);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  background: var(--ds-page-bg);
}
.feat__n {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .1em;
  color: var(--ds-brand);
  font-variant-numeric: tabular-nums;
}
.feat__card h3 {
  margin-top: var(--ds-space-1);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -.015em;
}
.feat__card p {
  margin-top: var(--ds-space-2);
  font-size: 14px;
  color: var(--ds-text-secondary);
}
.feat__card strong { color: var(--ds-text-primary); }

/* ============================================================
   BÖLMƏ 6 — BİZNES TİPLƏRİ
   The «TEZLİKLƏ» rows must be impossible to mistake for the ready
   one — dashed border, flat canvas, muted text, clock icon. A
   footnote would not be enough; the shape of the row carries it.
   ============================================================ */
.biz__list {
  margin-top: var(--ds-space-7);
  display: grid;
  gap: var(--ds-space-3);
}
.biz__row {
  display: flex;
  align-items: flex-start;
  gap: var(--ds-space-4);
  padding: var(--ds-space-5);
  border: 2px dashed var(--ds-border-strong);
  border-radius: var(--ds-radius-lg);
  background: transparent;
}
.biz__row--ready {
  border-style: solid;
  border-color: transparent;
  background: var(--ds-surface);
  box-shadow: var(--ds-shadow-card);
}
.biz__badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  padding: 5px 12px;
  border-radius: var(--ds-radius-pill);
  background: var(--ds-neutral-badge-bg);
  color: var(--ds-text-quiet);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .06em;
  white-space: nowrap;
}
.biz__badge svg { width: 14px; height: 14px; }
.biz__badge--ready { background: var(--ds-success-tint); color: var(--ds-success-text); }
.biz__body h3 { font-size: 1.05rem; font-weight: 600; letter-spacing: -.015em; }
.biz__body p {
  margin-top: 4px;
  font-size: 14px;
  color: var(--ds-text-secondary);
}
.biz__row:not(.biz__row--ready) .biz__body h3 { color: var(--ds-text-tertiary); }
@media (max-width: 559px) {
  .biz__row { flex-direction: column; gap: var(--ds-space-3); }
}

/* ============================================================
   BÖLMƏ 7 — ETİRAZLAR
   ============================================================ */
.obj__list {
  margin-top: var(--ds-space-7);
  display: grid;
  gap: var(--ds-space-2);
  max-width: 780px;
}
.obj__item {
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  background: var(--ds-page-bg);
  overflow: hidden;
}
.obj__item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-4);
  padding: var(--ds-space-4) var(--ds-space-5);
  min-height: 56px;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.obj__item summary::-webkit-details-marker { display: none; }

/* A plus that becomes a minus — its own element, carrying two bars.
   The obvious one-pseudo-element version (paint a plus, rotate it 90°
   on open) is WRONG and looked it: rotating a horizontal bar by 90°
   just stands it up, so an open row showed «|» instead of «−». Caught
   on screen. Collapsing the vertical bar via background-size would fix
   it but would be the site's first animation of something other than
   transform/opacity, so the bars are two pseudo-elements and the
   vertical one is scaled to nothing. Contract intact. */
.obj__plus {
  position: relative;
  flex: none;
  width: 13px; height: 13px;
  color: var(--ds-brand);
}
.obj__plus::before,
.obj__plus::after {
  content: '';
  position: absolute;
  inset: 50% 0 auto 0;
  height: 2px;
  margin-top: -1px;
  border-radius: 1px;
  background: currentColor;
  transition: transform var(--ds-duration-base) var(--ds-ease-standard);
}
.obj__plus::after { transform: rotate(90deg); }
.obj__item[open] .obj__plus::after { transform: rotate(90deg) scaleX(0); }
.obj__answer { padding: 0 var(--ds-space-5) var(--ds-space-5); }
.obj__answer p { font-size: 14.5px; color: var(--ds-text-secondary); max-width: 66ch; }
.obj__answer p + p { margin-top: var(--ds-space-3); }
.obj__answer strong { color: var(--ds-text-primary); }
.obj__note {
  padding: var(--ds-space-3) var(--ds-space-4);
  border-radius: var(--ds-radius-md);
  background: var(--ds-warning-tint);
  color: var(--ds-warning-text) !important;
  font-size: 13px !important;
}
.obj__note strong { color: inherit !important; }

/* ============================================================
   BÖLMƏ 8 — NECƏ QURULUB
   ============================================================ */
.built { background: var(--ds-gradient-hero); color: var(--ds-text-on-gradient); }
.built .sec__lede { color: var(--ds-text-on-gradient-secondary); }
.built__facts {
  margin-top: var(--ds-space-7);
  display: grid;
  gap: var(--ds-space-4);
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.built__fact {
  display: grid;
  gap: 2px;
  padding: var(--ds-space-5);
  border-radius: var(--ds-radius-lg);
  background: rgba(255,255,255,.1);
  border: 1px solid rgba(255,255,255,.2);
}
.fact__num {
  font-size: clamp(1.9rem, 1.4rem + 1.8vw, 2.6rem);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}
.fact__label { font-size: 14px; font-weight: 600; }
.fact__src { font-size: 12px; color: var(--ds-text-on-gradient-secondary); }

.built__points {
  margin-top: var(--ds-space-6);
  display: grid;
  gap: var(--ds-space-3);
  max-width: 70ch;
}
.built__points li {
  position: relative;
  padding-inline-start: var(--ds-space-5);
  font-size: 14.5px;
  color: var(--ds-text-on-gradient-secondary);
}
.built__points li::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  top: .62em;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: #fff;
}
.built__points strong { color: #fff; }
.built__note {
  margin-top: var(--ds-space-6);
  padding-top: var(--ds-space-4);
  border-top: 1px solid rgba(255,255,255,.18);
  font-size: 13px;
  color: var(--ds-text-on-gradient-secondary);
  max-width: 66ch;
}
.built__note strong { color: #fff; }
.built code, .built__note code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .92em;
  padding: 1px 6px;
  border-radius: var(--ds-radius-sm);
  background: rgba(255,255,255,.14);
}

/* ============================================================
   BÖLMƏ 11 — SİYAHIYA YAZIL
   ------------------------------------------------------------
   The only form on the site, and it lands right after «Necə
   qurulub» — i.e. straight off the gradient. It therefore sits on
   --ds-page-bg with the card in --ds-surface, so the eye reads
   "the argument ended, now it is your turn" as a change of
   material rather than as another band of the same colour.

   Nothing here animates. A form is the one place on this page
   where motion would read as the page doing something to your
   data, and the one-clock rule has no third state to spend on it.
   ============================================================ */
.wait__form {
  margin-top: var(--ds-space-7);
  padding: clamp(20px, 1.5vw + 14px, 32px);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  background: var(--ds-surface);
  box-shadow: var(--ds-shadow-card);
  max-width: 780px;
}

/* Off-screen rather than display:none — a bot that only skips
   hidden inputs still fills this one, which is the entire point. */
.wait__pot {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Two columns, stated rather than auto-fit: at this card's width
   auto-fit resolved to THREE 230px columns, which is narrower than a
   phone number wants and left a hole mid-form. A form is a sequence,
   not a tile wall. */
.wait__grid {
  display: grid;
  gap: var(--ds-space-4);
  grid-template-columns: 1fr;
}
@media (min-width: 620px) {
  .wait__grid { grid-template-columns: 1fr 1fr; }
}
.wait__field { display: grid; gap: 6px; }
.wait__field--wide { grid-column: 1 / -1; }

.wait__label {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ds-text-secondary);
}

.wait__input {
  width: 100%;
  min-height: 46px;
  padding: 0 var(--ds-space-4);
  border: 1px solid var(--ds-border-strong);
  border-radius: var(--ds-radius-control);
  background: var(--ds-page-bg);
  color: var(--ds-text-primary);
  font: inherit;
  font-size: 16px;   /* < 16px makes iOS Safari zoom on focus */
  transition: border-color var(--ds-duration-fast) var(--ds-ease-standard),
              background var(--ds-duration-fast) var(--ds-ease-standard);
}
.wait__input:hover { border-color: var(--ds-brand); }
.wait__input:focus { background: var(--ds-surface); border-color: var(--ds-brand); }
.wait__note {
  min-height: 0;
  padding: var(--ds-space-3) var(--ds-space-4);
  resize: vertical;
  line-height: 1.5;
}

/* The native arrow is drawn by the OS and ignores the theme, so the
   control draws its own and keeps the click target native. */
.wait__select {
  appearance: none;
  padding-inline-end: var(--ds-space-7);
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 20px center, right 14px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  cursor: pointer;
}
.wait__select:invalid { color: var(--ds-text-quiet); }

.wait__consent {
  margin-top: var(--ds-space-5);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--ds-space-3);
  align-items: start;
}
.wait__consent input {
  width: 20px; height: 20px;
  margin-top: 1px;
  accent-color: var(--ds-brand);
  cursor: pointer;
}
.wait__consent label {
  font-size: 14px;
  color: var(--ds-text-secondary);
  cursor: pointer;
}

.wait__actions {
  margin-top: var(--ds-space-6);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ds-space-4);
}
/* NOT .btn--primary: that one is white-on-gradient for the hero and
   would be an invisible white slab on this light surface. */
.wait__submit {
  background: var(--ds-brand);
  color: var(--ds-text-on-brand);
}
.wait__submit:hover:not(:disabled) { background: var(--ds-brand-hover); }
.wait__submit:disabled { opacity: .6; cursor: progress; }
.wait__micro { font-size: 13px; color: var(--ds-text-quiet); max-width: 34ch; }

.wait__status {
  margin-top: var(--ds-space-4);
  padding: var(--ds-space-3) var(--ds-space-4);
  border-radius: var(--ds-radius-control);
  font-size: 14px;
}
.wait__status--error {
  background: var(--ds-error-tint);
  color: var(--ds-error-text);
}

/* The reply. Same footprint as the form it replaces, so the page
   does not jump under the reader at the moment they are looking
   for the queue number. */
.wait__done {
  margin-top: var(--ds-space-7);
  padding: clamp(24px, 2vw + 16px, 40px);
  border: 1px solid var(--ds-success);
  border-radius: var(--ds-radius-lg);
  background: var(--ds-success-tint);
  max-width: 780px;
}
.wait__done:focus { outline: none; }
.wait__done-title {
  display: flex;
  align-items: baseline;
  gap: var(--ds-space-3);
  font-size: clamp(1.25rem, 1rem + 1vw, 1.6rem);
  font-weight: 600;
  letter-spacing: -.02em;
  color: var(--ds-success-text);
}
.wait__tick { font-size: 1.1em; }
.wait__done-queue {
  margin-top: var(--ds-space-4);
  font-size: clamp(1rem, .95rem + .4vw, 1.2rem);
  color: var(--ds-text-primary);
}
.wait__done-queue strong {
  font-variant-numeric: tabular-nums;
  font-size: 1.35em;
  font-weight: 600;
  letter-spacing: -.02em;
}
.wait__done-note {
  margin-top: var(--ds-space-2);
  font-size: 14.5px;
  color: var(--ds-text-secondary);
}

/* One looping animation, on the shared clock like everything else. */
@keyframes sim-target {
  0%   { transform: scale(1);    opacity: .8; }
  12%  { transform: scale(1.14); opacity: 0; }
  100% { transform: scale(1.14); opacity: 0; }
}

/* ============================================================
   REDUCED MOTION
   The product respects prefers-reduced-motion, so the site does too.
   Nothing is hidden and nothing is left mid-animation: the trace is
   fully drawn, every beat is lit, every marker and legend item is at
   its resting visible state. The page loses the motion, not the
   meaning.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  /* No draw/erase cycle: the day is simply shown, fully written.
     The hot layer stays, unmasked and parked, so the line keeps its
     full brightness instead of collapsing to the faint ghost. */
  .pulse__hot {
    -webkit-mask-image: none;
            mask-image: none;
    transform: none;
    animation: none;
  }
  .pulse__hot-inner { transform: none; animation: none; }
  .pulse__beat   { opacity: .9; animation: none; }
  /* Glow layers stay, statically — they are part of how the trace
     LOOKS, not of how it moves. The echo rings and sweep are pure
     motion, so they go entirely. */
  .pulse__trace-glow { animation: none; }
  .pulse__beat-glow  { opacity: .45; animation: none; }
  .pulse__echo   { display: none; }
  .pulse__sweep  { display: none; }
  .hero__eyebrow-dot { animation: none; opacity: 1; }
  .btn::after { animation: none !important; }

  /* The simulation loses its two loops and nothing else. The current
     step's dot stays filled and the awaited control keeps its solid
     ring (a box-shadow, never animated), so "you are here" and "click
     this" are both still said — in colour and position rather than in
     motion. */
  .sim-dot.is-now { animation: none; }
  .sim__frame .is-target::before { display: none; }

  /* THE ARC, REDUCED: two states, no scrubbing. The three middle stops
     collapse into morning, so the light changes exactly once — when the
     till closes and the Z-report appears. That keeps the one thing the
     arc is actually saying (the day ended, look at the shortfall) and
     drops the part that is only atmosphere. Nothing interpolates. */
  .sim__field {
    transition: none !important;
  }
  .sim__field.is-arc-on[data-arc="midday"],
  .sim__field.is-arc-on[data-arc="afternoon"],
  .sim__field.is-arc-on[data-arc="evening"] {
    --arc-sky-from: var(--arc-morning-sky-from);
    --arc-sky-to: var(--arc-morning-sky-to);
  }
  .sim__field[data-arc="midday"],
  .sim__field[data-arc="afternoon"],
  .sim__field[data-arc="evening"] {
    --ds-surface: var(--arc-morning-surface);
  }
}

/* =====================================================================
   FOOTER, PRIVACY, 404                                        (DL-284)
   =====================================================================
   The site had no footer and no page below the fold at all until it
   started collecting a name and a phone number in five languages. These
   three blocks are what that required: somewhere to say who holds the
   data, and a 404 of our own so Hostinger's — which loads Google
   Analytics, DoubleClick and an ad-audience pixel, and sets _ga cookies
   on this domain — is never served.

   All three sit on the always-dark hero field, so they inherit its text
   tokens rather than introducing a fourth surface. */

.hero--flat {
  /* The privacy and 404 pages have no pulse, no arc and nothing below
     them, so the hero stretches to the viewport instead of ending. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  padding-bottom: var(--ds-space-6);
}
.hero--flat > .shell {
  display: flex;
  flex-direction: column;
  flex: 1;
}

/* ---- Footer ---- */
.site-foot {
  background: var(--hero-field);
  color: var(--ds-text-on-gradient-secondary);
  border-top: 1px solid rgba(255,255,255,.12);
  padding-block: var(--ds-space-5);
}
.site-foot__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-3);
}
.site-foot__mark {
  /* Same word, same face as the nav — the subset only carries 600, so the
     footer drops from 700 rather than synthesising a bolder weight. The
     class was named __mark from the day the footer shipped and drew no mark
     at all; the pulse now sits beside the word (DL-368). */
  display: flex;
  align-items: center;
  gap: .5em;
  margin: 0;
  font-family: 'Zerb Wordmark', 'IBM Plex Sans', 'IBM Plex Sans Fallback', system-ui, sans-serif;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--ds-text-on-gradient);
}
.site-foot__glyph {
  /* Sized in em so it tracks the word rather than a fixed pixel value, and
     coloured by currentColor so it follows whatever the footer inherits. */
  width: 1.25em;
  height: 1.25em;
  flex-shrink: 0;
}
.site-foot__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ds-space-4);
}
.site-foot__links a {
  color: var(--ds-text-on-gradient-secondary);
  text-decoration: underline;
  text-underline-offset: 3px;
  /* 44px of tappable height without 44px of visible chrome. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.site-foot__links a:hover { color: var(--ds-text-on-gradient); }

/* ---- Privacy ---- */
.prose {
  flex: 1;
  max-width: 42rem;
  padding-block: var(--ds-space-7) var(--ds-space-8);
}
.prose__title {
  margin: 0 0 var(--ds-space-3);
  font-size: clamp(2rem, 1.4rem + 2.6vw, 3rem);
  line-height: 1.1;
  letter-spacing: -.02em;
  color: var(--ds-text-on-gradient);
}
.prose__lede {
  margin: 0 0 var(--ds-space-6);
  font-size: 1.06rem;
  line-height: 1.6;
  color: var(--ds-text-on-gradient-secondary);
}
.prose__body h2 {
  margin: var(--ds-space-6) 0 var(--ds-space-2);
  font-size: 1.12rem;
  letter-spacing: -.005em;
  color: var(--ds-text-on-gradient);
}
.prose__body p {
  margin: 0 0 var(--ds-space-3);
  line-height: 1.65;
  color: var(--ds-text-on-gradient-secondary);
}
.prose__body strong { color: var(--ds-text-on-gradient); font-weight: 600; }
.prose__body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .92em;
  padding: 1px 5px;
  border-radius: var(--ds-radius-sm);
  background: rgba(255,255,255,.12);
}
.prose__contact a {
  color: var(--ds-text-on-gradient);
  font-weight: 600;
  text-underline-offset: 3px;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.prose__stamp {
  margin: var(--ds-space-6) 0 0;
  font-size: .86rem;
  color: var(--ds-text-on-gradient-secondary);
  opacity: .8;
}

/* ---- 404 ---- */
.notfound {
  flex: 1;
  max-width: 40rem;
  padding-block: var(--ds-space-8);
}
.notfound__title {
  margin: 0 0 var(--ds-space-3);
  font-size: clamp(1.9rem, 1.3rem + 2.4vw, 2.75rem);
  line-height: 1.12;
  letter-spacing: -.02em;
  color: var(--ds-text-on-gradient);
}
.notfound__lede {
  margin: 0 0 var(--ds-space-6);
  line-height: 1.6;
  color: var(--ds-text-on-gradient-secondary);
}
.notfound__pick {
  margin: 0 0 var(--ds-space-3);
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ds-text-on-gradient-secondary);
}
.notfound__langs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--ds-space-2);
}
.notfound__langs a {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--ds-space-1) var(--ds-space-3);
  min-height: 44px;
  padding: var(--ds-space-3) var(--ds-space-4);
  border: 1px solid rgba(255,255,255,.18);
  border-radius: var(--ds-radius-md);
  background: rgba(255,255,255,.06);
  color: var(--ds-text-on-gradient-secondary);
  text-decoration: none;
  transition: background var(--ds-duration-fast) var(--ds-ease-standard),
              border-color var(--ds-duration-fast) var(--ds-ease-standard);
}
.notfound__langs a:hover {
  background: rgba(255,255,255,.12);
  border-color: rgba(255,255,255,.3);
}
.notfound__lang {
  font-weight: 700;
  color: var(--ds-text-on-gradient);
  min-width: 6.5rem;
}
.notfound__say { font-size: .95rem; }

/* The "Daha nə var?" tab bar, raised to a 44px touch target (DL-284).
   It lives here rather than beside the other touch-target rules because
   .more__tab's own min-height:40px is declared after them and would win.
   The sim's chrome is deliberately NOT raised: those controls are a
   depiction of the app's own screen at the app's own scale, and growing
   them would make the picture stop matching the product. */
@media (hover: none), (max-width: 720px) {
  .more__tab { min-height: 44px; }
}

/* =====================================================================
   SIMULATION CONTROL AFFORDANCE                               (DL-285)
   =====================================================================
   Two findings from the mobile UX pass, both about a control not
   looking like what it is.

   1. «Onlayn» is a BUTTON that toggles the simulated connection, styled
      as a status pill. Nothing about it said it could be pressed, so the
      one step that demonstrates the product's headline claim — that the
      shop keeps selling when the internet drops — was reachable only by
      accident. It keeps the pill shape (it is still reporting a state)
      and gains the border and press feedback of a control.

   2. «Keç» sat directly beside «Növbəti addım →» at thumb size. It
      discards the rest of the walkthrough, and a destructive action one
      slip away from the primary action is a trap. It moves onto its own
      row with «Yenidən başla», where the two rewind/skip actions live
      together and the primary keeps the first row to itself. */

.sim-net {
  border: 1px solid var(--ds-border-strong);
  cursor: pointer;
  transition: background var(--ds-duration-fast) var(--ds-ease-standard),
              border-color var(--ds-duration-fast) var(--ds-ease-standard);
}
.sim-net:hover { border-color: var(--ds-text-secondary); }
.sim-net:active { transform: translateY(1px); }

/* The primary keeps row one; skip/restart wrap to row two. */
.sim__controls { flex-wrap: wrap; }
.sim__controls .sim-ctl--next { flex: 1 1 100%; }

@media (min-width: 720px) {
  /* On a pointer device the mis-tap risk is gone, so the original
     single row comes back. */
  .sim__controls .sim-ctl--next { flex: 0 0 auto; }
}

/* ============================================================
   BÖLMƏ 12 — HESAB SƏHİFƏLƏRİ (DP-013 §15)
   ============================================================
   Giriş, qeydiyyat, sıfırlama və hesab səhifələri saytın MÖVCUD
   forma lüğətini işlədir — .wait__form, .wait__input, .wait__submit
   hamısı olduğu kimi qalır. Burada yalnız o lüğətin əhatə etmədiyi
   dörd şey var: yalnız naviqasiyadan ibarət nazik başlıq zolağı,
   qısa səhifədə footer-i aşağıda saxlayan sütun, «və ya» ayırıcısı,
   və Google-un öz brendinq qaydalarına tabe olan düymə. */

.hero--bar { padding-bottom: 0; }

/* Giriş forması qısadır — bu olmasa footer səhifənin ortasında asılı
   qalır. min-height: 100svh, 100vh yox: mobil brauzerlərin ünvan
   zolağı 100vh-i ekrandan böyük edir və footer görünməz sürüşür. */
.auth-page { display: flex; flex-direction: column; min-height: 100svh; }
.auth__band { flex: 1; }

/* Bir sütunluq forma iki sütunluq şəbəkənin enini tələb etmir. */
.auth__form { max-width: 27rem; }

.auth__sep {
  max-width: 27rem;
  margin: var(--ds-space-5) 0 0;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--ds-space-4);
  color: var(--ds-text-quiet);
  font-size: 13px;
}
.auth__sep::before, .auth__sep::after {
  content: '';
  height: 1px;
  background: var(--ds-border);
}

.auth__google-wrap { max-width: 27rem; margin-top: var(--ds-space-4); }

/* Google-un brendinq qaydası: ağ dolğu, #747775 kontur, #1F1F1F mətn;
   qaranlıq temada #131314 / #8E918F / #E3E3E3. Rənglər qəsdən token
   DEYİL — bunlar bizim deyil, Google-un dəyərləridir və saytın teması
   dəyişəndə onlarla birlikdə sürüşməməlidir. «G» loqosu isə həmişə
   öz rəngli variantında və ağ üzərində qalır. */
.auth__google {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 52px;
  padding: 0 var(--ds-space-6);
  box-sizing: border-box;
  border: 1px solid #747775;
  border-radius: var(--ds-radius-control);
  background: #FFFFFF;
  color: #1F1F1F;
  font-size: 16px;
  font-weight: 600;
  text-decoration: none;
}
.auth__google:hover { background: #F7F8F8; }
.auth__google-mark { display: flex; padding: 2px; border-radius: 2px; background: #FFFFFF; }
.auth__google-mark svg { width: 20px; height: 20px; }

html[data-theme="dark"] .auth__google { background: #131314; border-color: #8E918F; color: #E3E3E3; }
html[data-theme="dark"] .auth__google:hover { background: #1E1F20; }
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) .auth__google {
    background: #131314; border-color: #8E918F; color: #E3E3E3;
  }
  html:not([data-theme="light"]) .auth__google:hover { background: #1E1F20; }
}

.auth__alt { margin-top: var(--ds-space-6); font-size: 15px; }

/* Hesab səhifəsinin blokları — forma kartı ilə eyni footprint. */
.auth__card {
  max-width: 27rem;
  margin-top: var(--ds-space-6);
  padding: clamp(20px, 1.5vw + 14px, 32px);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  background: var(--ds-surface);
  box-shadow: var(--ds-shadow-card);
}
.auth__card--danger { border-color: var(--ds-error-text); }
.auth__card-title { font-size: 17px; font-weight: 600; }
.auth__card-text { margin-top: var(--ds-space-3); font-size: 14px; color: var(--ds-text-secondary); }
.auth__state { margin-top: var(--ds-space-3); font-size: 14px; color: var(--ds-text-quiet); }
.auth__key { margin-top: var(--ds-space-3); }
.auth__key code {
  display: inline-block;
  padding: 8px 12px;
  border-radius: var(--ds-radius-control);
  background: var(--ds-page-bg);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 15px;
  letter-spacing: .04em;
}
.auth__inline { display: grid; gap: 6px; margin-top: var(--ds-space-4); }
.auth__inline .wait__submit { justify-self: start; }
.auth__signout { max-width: 27rem; }
