/*
 * Public website styling (docs/public-site-and-seo.md).
 *
 * Same brand as the portal — the gold ramp, champagne text and near-black
 * navy shell from web-client/src/index.css — so the two read as one product.
 * Deliberately a single hand-written file: no build step, no framework, no
 * Node in production for what is a handful of content pages.
 *
 * RTL-first like the rest of the project: logical properties only
 * (.claude/rules/frontend-conventions.md), never left/right.
 */

/* Vazirmatn, self-hosted — the project's only typeface (CLAUDE.md), and the
 * same variable file the portal ships. Self-hosted rather than loaded from a
 * font CDN for three reasons: the CSP here is `font-src 'self'`, Iranian
 * visitors often can't reach Google Fonts, and a third-party font request
 * would leak visitor IPs. Copied from the `vazirmatn` npm package; the
 * upstream filename `Vazirmatn[wght].woff2` is renamed because the brackets
 * need percent-encoding in a URL. */
@font-face {
  font-family: "Vazirmatn";
  src: url("fonts/Vazirmatn-Variable.f6d31671339d.woff2") format("woff2 supports variations"),
       url("fonts/Vazirmatn-Variable.f6d31671339d.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  /* Show fallback text immediately, swap when the font lands — never a blank
   * page while a crawler or a slow connection waits. */
  font-display: swap;
}

:root {
  color-scheme: dark;

  --bg: #050b12;
  --bg-2: #0a1b2c;
  --surface: rgb(24 42 64 / 0.55);
  --raised: rgb(32 52 78 / 0.6);
  --line: rgb(228 199 101 / 0.16);
  --line-strong: rgb(228 199 101 / 0.35);

  --text: #f4e7ce;
  --text-dim: #a9b4be;
  --text-faint: #6e7278;

  /* The portal's buy/sell pair, same names and same values
     (web-client/src/index.css), because the trend chart here is a port of the
     portal's and shares its stylesheet rules verbatim.

     On the chart these name the direction of a candle's move — green up, red
     down — not a side of the book: this chart draws the ask alone (trend.js).
     The *-text pair is the readable-on-a-surface variant, used by the change
     figure; the *-solid pair is the fill. */
  --buy-solid: #0f9d63;
  --sell-solid: #d33f4d;
  --buy-text: #3ecb92;
  --sell-text: #ff7b88;

  --gold: #c9a227;
  --gold-text: #e4c765;
  --gold-metal: linear-gradient(135deg, #f2dd9a, #d9ae3e 45%, #b8871f);
  --on-gold: #1b1404;

  /* The price board's caption band and the chart's plot well. */
  --well: rgb(4 10 18 / 0.55);
  --radius: 1.1rem;

  --font: "Vazirmatn", "Segoe UI", Tahoma, system-ui, sans-serif;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* The phone may not enlarge text on its own. Chrome on Android "boosts" the
   font of wide text blocks, and iOS resizes on rotation; either one grew the
   board's figures past their cells. The visitor's own zoom still works —
   this only stops the browser deciding sizes for them. */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font);
  line-height: 1.9;
  color: var(--text);
  background-color: var(--bg);
  background-image:
    radial-gradient(1100px 620px at 50% -8%, rgb(201 162 39 / 0.16), transparent 62%),
    radial-gradient(900px 560px at 102% 105%, rgb(201 162 39 / 0.1), transparent 60%),
    linear-gradient(175deg, var(--bg-2), var(--bg) 60%);
  background-attachment: fixed;
}

.wrap {
  max-inline-size: 68rem;
  margin-inline: auto;
  padding-inline: 1.15rem;
}

/* Keyboard users get out of the header without tabbing the whole nav. */
.skip-link {
  position: absolute;
  inset-block-start: -3rem;
  inset-inline-start: 1rem;
  background: var(--gold-metal);
  color: var(--on-gold);
  padding: 0.5rem 1rem;
  border-radius: 0 0 0.6rem 0.6rem;
  z-index: 20;
  transition: inset-block-start 150ms ease;
}

.skip-link:focus {
  inset-block-start: 0;
}

a {
  color: var(--gold-text);
}

h1,
h2,
h3 {
  line-height: 1.35;
  margin-block: 0 0.6rem;
}

h1 {
  font-size: clamp(1.7rem, 4vw, 2.5rem);
  font-weight: 800;
}

h2 {
  font-size: clamp(1.3rem, 2.6vw, 1.7rem);
  font-weight: 700;
}

/* ---------- header ---------- */

.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: 10;
  background: rgb(5 11 18 / 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-block-end: 1px solid var(--line);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-block: 0.8rem;
  flex-wrap: wrap;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--text);
  font-weight: 800;
  margin-inline-end: auto;
}

/* The mark's lettering is pale ivory, drawn for a dark backdrop, and its own
 * background is transparent — so it carries a fixed dark backing and a gold
 * ring of its own, exactly as in the portal (web-client/src/index.css). */
.brand-mark {
  inline-size: 2.5rem;
  block-size: 2.5rem;
  border-radius: 50%;
  background: var(--bg-2);
  padding: 4px;
  border: 1px solid rgb(201 162 39 / 0.45);
  box-shadow: 0 8px 18px -10px rgb(0 0 0 / 0.6);
  object-fit: contain;
  flex: 0 0 auto;
}

.hero-logo {
  display: inline-flex;
  border-radius: 50%;
  background: var(--bg-2);
  padding: 0.6rem;
  margin-block-end: 1.1rem;
  border: 1px solid rgb(201 162 39 / 0.45);
  box-shadow:
    0 18px 36px -14px rgb(0 0 0 / 0.65),
    0 0 30px -8px rgb(201 162 39 / 0.35);
}

.hero-logo img {
  inline-size: clamp(5rem, 14vw, 7.5rem);
  block-size: auto;
  object-fit: contain;
  display: block;
}

.site-nav {
  display: flex;
  gap: 0.35rem;
  flex-wrap: wrap;
}

.site-nav a {
  color: var(--text-dim);
  text-decoration: none;
  padding: 0.4rem 0.75rem;
  border-radius: 0.7rem;
  font-size: 0.95rem;
}

.site-nav a:hover,
.site-nav a[aria-current="page"] {
  color: var(--text);
  background: rgb(201 162 39 / 0.12);
}

.btn-portal,
.btn-primary {
  display: inline-block;
  background: var(--gold-metal);
  color: var(--on-gold);
  font-weight: 700;
  text-decoration: none;
  padding: 0.6rem 1.3rem;
  border-radius: 2rem;
  box-shadow: 0 12px 24px -12px rgb(201 162 39 / 0.6);
}

.btn-ghost {
  display: inline-block;
  color: var(--text);
  text-decoration: none;
  padding: 0.6rem 1.3rem;
  border-radius: 2rem;
  border: 1px solid var(--line-strong);
}

/* A phone: the header on one row (owner, 2026-10-19). It wrapped the portal
   button onto a second line, which doubled the sticky bar's height over every
   page. Smaller nav words and a smaller button, and the shop's name gives
   way to the mark alone — there is no width for it beside three links and the
   button, and an ellipsised name is worse than none. The mark's alt text
   still names the shop, so the home link keeps its label. */
@media (max-width: 40rem) {
  .header-inner {
    flex-wrap: nowrap;
    gap: min(0.5rem, 1.6vw);
    padding-block: 0.55rem;
  }

  /* The page gutter, capped by the screen too, for the same reason as the
     header's text below: an enlarged system font must not eat a 320px
     screen's width in padding. */
  .wrap {
    padding-inline: min(1.15rem, 5vw);
  }

  /* The mark keeps its size; the name is hidden below, so the link is the
     mark alone and must never be the thing that shrinks. */
  .brand {
    flex: 0 0 auto;
    gap: 0.45rem;
    font-size: 0.92rem;
  }

  .brand-mark {
    inline-size: min(2.35rem, 10.5vw);
    block-size: min(2.35rem, 10.5vw);
  }

  .site-nav {
    flex-wrap: nowrap;
    gap: 0.1rem;
  }

  /* Sized back up once the button became «ورود» (2026-10-19): the width it
     gave up goes to the links, which are what people tap here. */
  /* Capped by the screen's width as well as set in rem: a phone whose own
     font setting enlarges text (Android's font scale) pushed this nowrap row
     10px past a 360px screen, and one overflowing row widens the whole page —
     it then opens zoomed in (2026-10-20). Paddings are in em so they shrink
     with the text. */
  .site-nav a {
    padding: 0.47em 0.63em;
    font-size: min(0.95rem, 4.2vw);
    white-space: nowrap;
  }

  .btn-portal {
    flex: 0 0 auto;
    padding: 0.49em 1.14em;
    font-size: min(0.92rem, 4.1vw);
    white-space: nowrap;
    box-shadow: 0 8px 16px -10px rgb(201 162 39 / 0.6);
  }

  .brand-name {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
}

/* The narrowest phones (320px): one step down, so the row still fits whole. */
@media (max-width: 22rem) {
  .header-inner {
    gap: min(0.35rem, 1.2vw);
  }

  .site-nav a {
    padding-inline: 0.45em;
    font-size: min(0.88rem, 4.1vw);
  }

  .btn-portal {
    padding-inline: 0.9em;
    font-size: min(0.86rem, 4vw);
  }

  .brand-mark {
    inline-size: 2.1rem;
    block-size: 2.1rem;
  }
}

/* ---------- hero ---------- */

.hero {
  padding-block: clamp(2.5rem, 7vw, 5rem);
  text-align: center;
}

.hero-lead {
  color: var(--text-dim);
  max-inline-size: 40rem;
  margin-inline: auto;
  font-size: 1.05rem;
}

.hero-actions {
  display: flex;
  gap: 0.75rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-block: 1.5rem 0.75rem;
}

.hero-note,
.lead {
  color: var(--text-faint);
  font-size: 0.9rem;
}

.lead {
  font-size: 1rem;
  color: var(--text-dim);
  margin-block-end: 1.25rem;
}

/* ---------- sections ---------- */

.section {
  padding-block: clamp(1.75rem, 4vw, 3rem);
}

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-block-end: 1rem;
}

.link-more {
  text-decoration: none;
  font-weight: 600;
  font-size: 0.95rem;
}

.feature-grid,
.card-grid {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  gap: 1rem;
}

.feature-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}

.feature {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 1.1rem;
  padding: 1.2rem 1.3rem;
}

.feature h3 {
  font-size: 1.05rem;
  color: var(--gold-text);
}

.feature p {
  margin: 0;
  color: var(--text-dim);
  font-size: 0.95rem;
}

/* ---------- cards ---------- */

.card-grid {
  grid-template-columns: repeat(auto-fill, minmax(min(12rem, 100%), 1fr));
}

.card a {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 1.1rem;
  overflow: hidden;
  block-size: 100%;
  transition: border-color 150ms ease, transform 150ms ease;
}

.card a:hover {
  border-color: var(--line-strong);
  transform: translateY(-2px);
}

.card-media {
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  background: repeating-linear-gradient(
    135deg,
    rgb(201 162 39 / 0.1) 0 10px,
    rgb(255 255 255 / 0.02) 10px 20px
  );
}

.card-media img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* An item with no photo yet gets the shop's medallion, matching web-admin's
   empty catalog slot — literally the same image, since its /brand-mark.png is
   a byte-for-byte copy of this favicon-512.

   favicon-512 rather than logo.png: the logo's lettering is pale ivory on
   transparency and disappears without a dark backing, while this variant
   carries its own navy disc and gold ring.

   Selectors are container-qualified because `.card-media img` / `.detail-media
   img` already set cover-and-fill, and a bare `.card-mark` would lose to them
   on specificity. Contained, not cropped: the mark keeps its ring instead of
   being trimmed to the card's square.

   The templates carry width/height attributes, and they are load-bearing here
   rather than a nicety: with `inline-size: auto` an image that has not arrived
   yet has no intrinsic width, so it lays out zero pixels wide, and a
   zero-area `loading="lazy"` image never enters the viewport as far as the
   browser is concerned — it was never fetched at all. The attributes give it
   an aspect ratio up front, which also keeps the grid from shifting on load. */
/* Sized from the width, which is definite, and never from the height, which is
   not. `.card-media` derives its height from `aspect-ratio: 1`, so a
   percentage *height* here is circular: it resolved to 70% of the width before
   the image arrived, then to 70% of the loaded image's own 512px once it did —
   stretching the card from 196px tall to 512px the moment the mark appeared.
   web-admin can use a percentage height for the same mark because its
   `.img-ph` box has a fixed height; the declaration is not portable between
   the two. */
.card-media .card-mark {
  inline-size: 70%;
  block-size: auto;
  object-fit: contain;
}

.detail-media .card-mark {
  /* No aspect-ratio box here, so a percentage height would have nothing to
     resolve against — size from the width and let the height follow. */
  inline-size: min(60%, 16rem);
  block-size: auto;
  object-fit: contain;
  margin-block: 2rem;
}

.card-body {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.8rem 0.9rem;
}

.card-cat {
  font-size: 0.72rem;
  color: var(--text-faint);
}

.card-name {
  font-weight: 700;
  font-size: 0.95rem;
}

/* A piece's published price on its card — only ever rendered when both
   publish flags allow it (apps.public_site.views.catalog). */
.card-price {
  margin-block-start: 0.2rem;
  color: var(--gold-text);
  font-weight: 700;
  font-size: 0.92rem;
  font-variant-numeric: tabular-nums;
}

.card-price small {
  color: var(--text-faint);
  font-weight: 400;
  font-size: 0.72rem;
}

/* ---------- price range and sort ----------

   A toolbar, not a panel: one hairline-ruled band under the category chips.
   Sort is a row of words — the chosen one in gold with a small mark under it —
   because a native <select> is drawn by the phone and cannot be made to
   belong here. Price is a short sentence, «قیمت از … تا …», with underlined
   bounds. Both work with JavaScript off; catalog-filter.js only groups the
   digits as they are typed. */
.catalog-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem 2rem;
  padding-block: 0.7rem;
  border-block: 1px solid var(--line);
  margin-block-end: 0.5rem;
}

.tools-cap {
  font-size: 0.78rem;
  color: var(--text-faint);
}

.tools-sort {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  overflow-x: auto;
  scrollbar-width: none;
}

.tools-sort::-webkit-scrollbar {
  display: none;
}

.tools-sort-opt {
  position: relative;
  flex: 0 0 auto;
  padding-block: 0.35rem;
  font-size: 0.88rem;
  color: var(--text-dim);
  text-decoration: none;
  transition: color 150ms ease;
}

.tools-sort-opt:hover {
  color: var(--text);
}

.tools-sort-opt.on {
  color: var(--gold-text);
  font-weight: 700;
}

/* The direction of the chosen price or weight order: a small chevron, up for
   low-to-high, down for high-to-low. Drawn with borders so it inherits the
   gold text colour and needs no icon font. */
.tools-dir {
  display: inline-block;
  inline-size: 0.38em;
  block-size: 0.38em;
  margin-inline-start: 0.4em;
  /* Physical sides on purpose: this is a glyph, and "up" must not mirror in
     RTL the way a layout edge does. */
  border-left: 1.6px solid currentColor;
  border-top: 1.6px solid currentColor;
  vertical-align: 0.12em;
  transform: rotate(45deg);
}

.tools-dir.desc {
  vertical-align: 0.3em;
  transform: rotate(225deg);
}

/* The mark under the chosen order: a short gold rule, centred. */
.tools-sort-opt.on::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline: 30%;
  block-size: 2px;
  border-radius: 2px;
  background: var(--gold);
}

.tools-price {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin: 0;
}

.tools-bound {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.82rem;
  color: var(--text-dim);
}

/* Underlined, not boxed: two bounds in a sentence, not two form fields. */
.tools-bound input {
  inline-size: 9rem;
  padding-block: 0.3rem;
  padding-inline: 0.1rem;
  border: none;
  border-block-end: 1px solid var(--line-strong);
  border-radius: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
  transition: border-color 150ms ease;
}

.tools-bound input:focus {
  outline: none;
  border-block-end-color: var(--gold);
}

.tools-apply {
  padding-block: 0.35rem;
  padding-inline: 1rem;
  border: 1px solid var(--gold);
  border-radius: 2rem;
  background: transparent;
  color: var(--gold-text);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  transition: background-color 150ms ease;
}

.tools-apply:hover {
  background: rgb(201 162 39 / 0.14);
}

.tools-clear {
  font-size: 0.8rem;
  color: var(--text-faint);
}

.tools-clear:hover {
  color: var(--text);
}

.catalog-priced-at {
  margin-block: 0 1.4rem;
  font-size: 0.74rem;
  color: var(--text-faint);
}

/* A phone: the sort words on one line (scrolling sideways if they must), the
   price sentence on the next, its two bounds sharing the width. */
@media (max-width: 40rem) {
  .catalog-tools {
    flex-direction: column;
    align-items: stretch;
    gap: 0.55rem;
  }

  .tools-price {
    gap: 0.55rem;
  }

  .tools-bound {
    flex: 1 1 0;
    min-inline-size: 0;
  }

  .tools-bound input {
    inline-size: 100%;
    min-inline-size: 0;
  }
}

/* ---------- chips ---------- */

.chips {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-block-end: 1.25rem;
}

.chip {
  text-decoration: none;
  border: 1px solid var(--line-strong);
  border-radius: 2rem;
  color: var(--text-dim);
  padding: 0.35rem 0.9rem;
  font-size: 0.88rem;
}

.chip.on,
.chip:hover {
  color: var(--gold-text);
  background: rgb(201 162 39 / 0.14);
  border-color: var(--gold);
}

/* ---------- pager ---------- */

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-block-start: 2rem;
}

.pager-btn {
  text-decoration: none;
  border: 1px solid var(--line-strong);
  border-radius: 2rem;
  color: var(--text-dim);
  padding: 0.4rem 1.1rem;
  font-size: 0.9rem;
}

.pager-btn:hover {
  color: var(--gold-text);
  border-color: var(--gold);
}

/* Kept in the flow rather than removed, so the row does not reflow between
   the first page and the rest. */
.pager-btn.disabled {
  opacity: 0.4;
  pointer-events: none;
}

.pager-status {
  color: var(--text-dim);
  font-size: 0.9rem;
}

/* ---------- detail ---------- */

.breadcrumb {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  color: var(--text-faint);
  font-size: 0.88rem;
  margin-block-end: 1rem;
}

.breadcrumb a {
  text-decoration: none;
}

.detail {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: 1fr;
  margin-block-end: 2.5rem;
}

@media (min-width: 48rem) {
  .detail {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
  }
}

.detail-media {
  display: grid;
  gap: 0.75rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 1.1rem;
  padding: 0.75rem;
  place-items: center;
}

.detail-media img {
  inline-size: 100%;
  border-radius: 0.8rem;
  display: block;
}

.detail-cat {
  color: var(--text-faint);
  margin-block: 0 0.75rem;
}

.spec {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.3rem 1rem;
  margin-block: 0 1rem;
}

.spec dt {
  color: var(--text-faint);
  font-size: 0.9rem;
}

.spec dd {
  margin: 0;
}

.detail-desc {
  color: var(--text-dim);
}

/* ---------- catalog price, and the CTA that stands in for it ----------
   Only one of these ever renders. The price appears when the shop published
   both the master switch and the piece's source product; otherwise the CTA
   does, because a listed piece with no price and no explanation reads as a
   broken page (docs/public-site-and-seo.md). Logical properties throughout —
   this site is RTL (.claude/rules/frontend-conventions.md). */

.detail-price {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  margin-block: 1.25rem 0.2rem;
}

.detail-price-value {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.2;
}

.detail-price-unit {
  color: var(--text-faint);
}

.detail-price-stamp {
  color: var(--text-faint);
  font-size: 0.85rem;
  margin-block: 0 0.75rem;
}

.detail-price-note {
  color: var(--text-dim);
  font-size: 0.9rem;
  margin-block: 0 1rem;
}

.detail-cta {
  margin-block-start: 1.5rem;
  padding: 1.1rem 1.25rem;
  border: 1px solid var(--line);
  border-radius: 0.8rem;
  background: var(--surface);
}

.detail-cta-lead {
  margin-block: 0 0.4rem;
  font-weight: 600;
}

.detail-cta-body {
  margin-block: 0 1rem;
  color: var(--text-dim);
}

.detail-cta-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

/* ---------- contact ---------- */

/* The contact page (templates/public_site/contact.html): channels, then
   branches, then membership — each block a grid that balances itself for
   however many items the shop has entered. */
.contact-page {
  display: grid;
  gap: clamp(1.75rem, 4vw, 2.75rem);
}

.contact-head .lead {
  max-inline-size: 40rem;
  margin-block-end: 0;
}

/* Plain section titles: weight and space separate the blocks, not ornament. */
.contact-section-title {
  font-size: 1.2rem;
  margin-block-end: 1rem;
}

/* ---- channels: the call panel and the directory list ----

   Two columns on a wide screen — the call panel narrow on the start side, the
   list taking the rest — stacked on a phone, call first. */
.channels {
  display: grid;
  gap: 1rem;
  /* The call panel takes the list's height, so the two columns end on one
     line however many channels the list holds. */
  align-items: stretch;
}

@media (min-width: 52rem) {
  .channels.split {
    grid-template-columns: minmax(16rem, 20rem) minmax(0, 1fr);
  }

  /* Phones only: the call panel alone, at a comfortable width rather than
     stretched across the page. */
  .channels:not(.split) .channel-call {
    max-inline-size: 26rem;
  }
}

.channel-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  inline-size: 2.5rem;
  block-size: 2.5rem;
  border-radius: 50%;
  color: var(--gold-text);
  background: color-mix(in srgb, var(--gold) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--gold) 30%, transparent);
}

/* The voice line: the number set large, its note, one button. */
.channel-call {
  display: grid;
  justify-items: start;
  align-content: center;
  gap: 0.35rem;
  padding: 1.35rem 1.4rem 1.4rem;
  border-radius: var(--radius, 1.1rem);
  border: 1px solid var(--line);
  background: var(--raised);
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--gold) 45%, transparent);
}

.channel-call .channel-icon {
  margin-block-end: 0.5rem;
}

.channel-call-cap {
  margin: 0;
  font-size: 0.85rem;
  color: var(--text-dim);
}

.channel-call-number {
  margin: 0;
  display: grid;
  font-size: 1.45rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
}

.channel-call-note {
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--text-faint);
}

.channel-call-btn {
  margin-block-start: 0.85rem;
}

/* The directory: one bordered surface, a hairline between rows. */
.channel-list {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  border-radius: var(--radius, 1.1rem);
  border: 1px solid var(--line);
  background: var(--surface);
  overflow: hidden;
}

.channel-list > li + li {
  border-block-start: 1px solid var(--line);
}

/* icon · name · value · action, on one line; on a phone the value drops
   under the name and the action becomes the row's end. */
.channel-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  grid-template-areas: "icon name value action";
  align-items: center;
  column-gap: 0.9rem;
  padding: 0.85rem 1.15rem;
  color: var(--text);
  text-decoration: none;
  transition: background-color 150ms ease;
}

a.channel-row:hover,
a.channel-row:focus-visible {
  background: color-mix(in srgb, var(--gold) 5%, transparent);
}

.channel-row .channel-icon { grid-area: icon; }

.channel-name {
  grid-area: name;
  display: grid;
  min-inline-size: 0;
  line-height: 1.55;
}

.channel-title {
  font-weight: 700;
  font-size: 0.98rem;
}

.channel-subtitle {
  font-size: 0.8rem;
  color: var(--text-faint);
}

.channel-value {
  grid-area: value;
  font-size: 0.98rem;
  font-weight: 600;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* What tapping does, in words — «گفتگو», «مشاهده صفحه» — as a quiet outline
   pill that turns gold with the row. */
.channel-action {
  grid-area: action;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--gold-text);
  border: 1px solid color-mix(in srgb, var(--gold) 35%, transparent);
  border-radius: 999px;
  padding: 0.15rem 0.75rem;
  white-space: nowrap;
  transition: background-color 150ms ease;
}

a.channel-row:hover .channel-action {
  background: color-mix(in srgb, var(--gold) 14%, transparent);
}

/* A phone: the value drops under the name, and the action pill gives its
   width to the value — a 22-character handle beside a pill did not fit. The
   row is still the link; a small chevron says so. */
@media (max-width: 40rem) {
  .channel-row {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "icon name go"
      "icon value go";
    row-gap: 0.1rem;
    padding: 0.8rem 0.95rem;
  }

  .channel-action {
    display: none;
  }

  /* Physical borders on purpose: a glyph, pointed by its rotation towards
     the inline end; RTL is this site's only direction. */
  a.channel-row::after {
    content: "";
    grid-area: go;
    inline-size: 0.45rem;
    block-size: 0.45rem;
    border-left: 1.6px solid var(--text-faint);
    border-bottom: 1.6px solid var(--text-faint);
    transform: rotate(45deg);
  }

  .channel-value {
    justify-self: start;
    font-size: 0.92rem;
    overflow-x: auto;
    max-inline-size: 100%;
    scrollbar-width: none;
  }
}

/* ---- branches: a card each, sharing a row's height ---- */

.branch-cards {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
}

.branch-card {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 1.25rem 1.35rem;
  border-radius: var(--radius, 1.1rem);
  border: 1px solid var(--line);
  background: var(--surface);
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--gold) 40%, transparent);
}

.branch-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.branch-card-head h3 {
  margin: 0;
  font-size: 1.1rem;
  color: var(--gold-text);
}

.branch-city {
  font-size: 0.82rem;
  color: var(--text-faint);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding-inline: 0.6rem;
}

.branch-address {
  margin: 0;
  font-weight: 600;
  line-height: 1.8;
}

.branch-parking {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  margin: 0;
  font-size: 0.88rem;
  color: var(--text-dim);
  line-height: 1.8;
}

/* A drawn «P», not the 🅿 emoji: an emoji renders in the phone's own colours
   and size, and on some fonts not at all. */
.branch-parking-mark {
  flex: 0 0 auto;
  display: inline-grid;
  place-items: center;
  inline-size: 1.15rem;
  block-size: 1.15rem;
  border-radius: 0.3rem;
  border: 1px solid var(--line-strong);
  color: var(--gold-text);
  font-size: 0.7rem;
  font-weight: 800;
  line-height: 1;
}

.branch-contacts {
  display: grid;
  gap: 0.35rem;
  padding-block-start: 0.6rem;
  border-block-start: 1px solid var(--line);
}

.branch-contacts:empty {
  display: none;
}

.branch-contact {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.branch-contact a {
  font-weight: 700;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}

.branch-contact a:hover {
  text-decoration: underline;
  text-underline-offset: 0.3em;
}

/* Pushed to the card's foot, so across a row of branches the map buttons sit
   on one line whatever each address above them holds. */
.branch-map {
  margin-block-start: auto;
  align-self: flex-start;
  font-size: 0.9rem;
  padding: 0.45rem 1rem;
}

.empty {
  color: var(--text-faint);
}

/* ---------- positioning chips (hero) ---------- */

.chips {
  list-style: none;
  padding-inline-start: 0;
  margin-block: 1.25rem 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
}

.chips li {
  border: 1px solid var(--line-strong);
  border-radius: 2rem;
  padding: 0.35rem 0.9rem;
  font-size: 0.88rem;
  color: var(--text-dim);
  background: var(--surface);
}

/* ---------- trust band ---------- */

.trust-grid {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}

.trust {
  display: grid;
  gap: 0.3rem;
  padding: 1.1rem 1.2rem;
  border-radius: 1.1rem;
  border: 1px solid var(--line);
  background: var(--raised);
  text-align: center;
}

.trust-head {
  font-weight: 700;
  color: var(--gold-text);
  font-size: 1.02rem;
}

.trust-body {
  color: var(--text-dim);
  font-size: 0.92rem;
}

/* ---------- checkmark list ---------- */

.check-grid {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  gap: 0.6rem;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
}

.check-grid li {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  color: var(--text-dim);
}

/* The tick is decoration, so it is generated rather than typed into the
   markup — a screen reader reading "✓" before every item adds nothing. */
.check-grid li::before {
  content: "✓";
  color: var(--gold-text);
  font-weight: 700;
  flex-shrink: 0;
}

/* ---------- membership ---------- */

/* Breathing room on both sides: the page <h1> above and the contact panels
   below were both crowding this block. */
/* Membership closes the contact page as one framed band — a gold hairline
   along its top — rather than a heading floating between the title and the
   panels. */
.membership {
  padding: clamp(1.25rem, 3vw, 1.75rem);
  border-radius: var(--radius, 1.1rem);
  border: 1px solid var(--line);
  background: var(--raised);
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--gold) 55%, transparent);
}

.membership h2 {
  margin-block: 0 1rem;
  font-size: 1.15rem;
}

.benefit-grid {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  gap: 0.75rem;
  /* min() so the track can shrink below its ideal on a narrow phone instead
     of forcing the page into a sideways scroll. */
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}

.benefit {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.95rem 1.15rem;
  border-radius: 1rem;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font-weight: 600;
  font-size: 0.95rem;
}

/* The only tick on the page. Generated, not typed into the markup — see the
   template comment: a literal character there doubles up with the list's own
   bullet if this stylesheet ever fails to load. */
.benefit::before {
  content: "✓";
  color: var(--gold-text);
  font-weight: 700;
  flex-shrink: 0;
}

.join-note {
  margin-block: 1.25rem 0;
  color: var(--text-faint);
  font-size: 0.95rem;
  max-inline-size: 44rem;
}

/* ---------- long-form prose (the SEO body) ---------- */

.section-intro {
  color: var(--text-dim);
  margin-block: -0.5rem 1.25rem;
}

/* Two columns from ~52rem up. The cards are text-heavy, so they need a wider
   breakpoint than the picture grids — squeezed into 20rem each, the Persian
   paragraphs break into ragged four-word lines.

   `min(24rem, 100%)` rather than a bare `24rem`: a bare minimum larger than
   the viewport cannot shrink, so on a 375px phone the track stayed 384px wide
   and pushed the whole page into a sideways scroll. The min() lets the track
   fall back to the container width when there is less room than the ideal. */
.guide-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(24rem, 100%), 1fr));
}

.guide-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 1.1rem;
  padding: 1.35rem 1.5rem;
}

.prose h3 {
  margin-block: 0 0.7rem;
  font-size: 1.05rem;
  color: var(--gold-text);
}

.prose p {
  color: var(--text-dim);
  margin-block: 0 0.85rem;
  line-height: 2;
}

.prose p:last-child {
  margin-block-end: 0;
}

.prose strong {
  color: var(--text);
  font-weight: 700;
}

/* ---------- branches ---------- */

.branch-grid {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
}

.branch {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 1.1rem;
  padding: 1.1rem 1.25rem;
}

.branch-label {
  font-weight: 700;
  color: var(--gold-text);
  margin-block-end: 0.35rem;
}

.branch-line {
  color: var(--text-dim);
  font-size: 0.95rem;
}

.branch-note {
  margin-block-start: 0.5rem;
  color: var(--text-faint);
  font-size: 0.88rem;
}

/* ---------- cta band ---------- */

.cta-band {
  text-align: center;
  border-block-start: 1px solid var(--line);
}

.cta-band p {
  color: var(--text-dim);
  margin-block-end: 1.25rem;
  max-inline-size: 42rem;
  margin-inline: auto;
}

.cta-contacts {
  display: flex;
  gap: 0.75rem;
  justify-content: center;
  flex-wrap: wrap;
}

/* ---------- published price strip ---------- */

/* One board, not a stack of cards: a single surface with hairline rows and
   the two column captions once, at the top, so the list is read *down* a
   column — every buy price against every buy price — the way the portal's
   market board reads (web-client MarketScreen). Each row is a three-column
   grid sharing the caption row's tracks, so the figures line up exactly.

   The per-cell «خرید»/«فروش» captions stay in the markup for screen readers
   (the caption row is aria-hidden) and are hidden visually. */
.price-grid {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  /* `minmax(0, 1fr)`, not the implicit `auto`: an auto column sizes to its
     max-content, so the moment a row contains something that does not wrap —
     the trend's one-line metrics header — the column grows past the viewport
     and takes the whole page into a horizontal scroll. The 0 minimum is what
     lets that line scroll inside its own box instead. */
  grid-template-columns: minmax(0, 1fr);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--gold) 45%, transparent);
  overflow: hidden;
  /* Name a little wider than each price, and the figures centred in their
     tracks: right-aligned names and left-aligned prices left a gulf across
     the middle of a desktop-wide board. */
  --price-cols: minmax(0, 1.25fr) minmax(7rem, 1fr) minmax(7rem, 1fr);
}

.price-head,
.price-row {
  display: grid;
  grid-template-columns: var(--price-cols);
  column-gap: clamp(0.6rem, 3vw, 2rem);
  align-items: center;
  min-inline-size: 0;
  padding-block: 0.85rem;
  padding-inline: clamp(0.9rem, 3vw, 1.6rem);
}

.price-head {
  padding-block: 0.6rem;
  background: var(--well);
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-faint);
}

.price-head span:not(:first-child) {
  text-align: center;
}

.price-row {
  border-block-start: 1px solid var(--line);
  transition: background-color 150ms ease;
}

.price-head + .price-row {
  border-block-start: none;
}

/* The product whose chart is open (owner, 2026-10-20): a faint gold wash
   over the row and its chart together, fading downward, inside a gold
   hairline — so the chart is read as belonging to the row above it, not to
   the one below. Light enough that the figures keep their own colours. */
.price-row.open {
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--gold) 11%, transparent),
    color-mix(in srgb, var(--gold) 4%, transparent) 70%
  );
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--gold) 32%, transparent);
}

.price-row.open button.price-name {
  color: var(--gold-text);
}

.price-row:not(.open):hover {
  background: color-mix(in srgb, var(--gold) 4%, transparent);
}

.price-name {
  font-weight: 700;
  color: var(--text);
  min-inline-size: 0;
  /* Every name starts at the same indent, with or without a chart: the
     triangle (when there is one) sits in this space, so a board mixing the
     two still reads as one straight column of names. */
  padding-inline-start: 1.15rem;
}

.price-unit {
  display: block;
  font-weight: 400;
  font-size: 0.78rem;
  color: var(--text-faint);
}

/* The pair takes the row's two price tracks itself. */
.price-pair {
  display: contents;
}

.price-cell {
  display: block;
  text-align: center;
  min-inline-size: 0;
}

/* Visually hidden, still read: the caption row carries them for sight. */
.price-cap {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.price-value {
  font-size: clamp(0.95rem, 2.4vw, 1.2rem);
  font-weight: 600;
  /* Tabular figures so a changing digit does not reflow the row on every
     poll — the numbers sit still and only their glyphs change. */
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The per-gram equivalent under a مثقال price — quiet, the مثقال figure above
   it is the price (docs/catalog-and-pricing.md, "مثقال products"). */
.price-sub {
  display: block;
  font-size: 0.72rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* «خرید» — what the shop pays — in gold; «فروش» in ivory. */
.price-value.buy {
  color: var(--gold-text);
}

.price-value.sell {
  color: var(--text);
}

.price-stamp {
  font-size: 0.85rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.price-actions {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: wrap;
  margin-block-start: 1.1rem;
}

.price-note {
  margin-block: 0.9rem 0;
  font-size: 0.9rem;
  color: var(--text-faint);
}

/* The figures as the portal's market board draws them (web-client
   index.css, `.market-side`): each price in a glass cell — its side's hue
   held at a fraction of its strength, a hairline of the same hue, one sweep
   of light across the top and a soft glow beneath.

   **Which side is green is decided by the number, not by the word.** This
   site labels from the shop's side («نرخ خرید، قیمتی که ما از شما
   می‌خریم») and the portal from the client's, so the same `sell_price` is
   «فروش» here and «خرید» there. Coloured the same in both places — green for
   the price a visitor pays, red for the price they are paid — the two boards
   read as one. The owner confirmed both choices on 2026-10-19: the website
   stays shop-perspective, and the colours follow the number. A word-for-colour
   swap was tried and reverted the same day. */
.price-head .sell,
.price-head .buy {
  font-weight: 700;
}

.price-head .sell { color: var(--buy-text); }
.price-head .buy { color: var(--sell-text); }

.price-head small {
  font-weight: 500;
  opacity: 0.8;
}

.price-cell.sell { --side: var(--buy-solid); --side-text: var(--buy-text); }
.price-cell.buy { --side: var(--sell-solid); --side-text: var(--sell-text); }

.price-cell.sell,
.price-cell.buy {
  justify-self: stretch;
  padding-block: 0.55rem;
  padding-inline: 0.5rem;
  border-radius: 0.7rem;
  border: 1px solid color-mix(in srgb, var(--side) 42%, transparent);
  background:
    linear-gradient(152deg, rgb(255 255 255 / 0.06), rgb(255 255 255 / 0) 46%),
    linear-gradient(
      180deg,
      color-mix(in srgb, var(--side) 20%, transparent),
      color-mix(in srgb, var(--side) 12%, transparent)
    );
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.12),
    0 1px 2px rgb(0 0 0 / 0.4),
    0 10px 20px -16px color-mix(in srgb, var(--side) 30%, transparent);
}

/* A phone: the name track gives up a little width to the two cells, and the
   figure is sized to the space the viewport leaves — a ten-digit price is
   never cut or wrapped (the same rule as the portal's board). */
@media (max-width: 40rem) {
  .price-grid {
    --price-cols: minmax(0, 0.8fr) minmax(0, 1fr) minmax(0, 1fr);
  }

  .price-head,
  .price-row {
    column-gap: 0.4rem;
    padding-inline: 0.6rem;
  }

  .price-cell.sell,
  .price-cell.buy {
    padding-inline: 0.2rem;
  }

  /* Each figure is sized to its own cell, never to the screen: the cell is a
     size container, and a figure takes the smaller of its normal size and
     "cell width ÷ its longest length" — 13 characters for a ten-digit price
     («۱٬۱۳۵٬۰۰۰٬۰۰۰», ~7.6em), 11 for the per-gram line under a مثقال price.
     Sized to the screen (vw) instead, it ran out of the cell whenever the
     cell was narrower than the screen implied — a 360px phone, or one whose
     own font setting enlarges text — and that overflow widened the whole
     page, which is what made it open zoomed in (owner, 2026-10-20). The
     figure is shrunk, never rounded or cut: a price is read to the Rial. */
  .price-cell.sell,
  .price-cell.buy {
    container-type: inline-size;
  }

  .price-cell .price-value {
    font-size: min(0.95rem, calc(100cqi / 8.3));
    letter-spacing: -0.01em;
  }

  /* «هر گرم» and its figure: the caption steps onto its own line when the
     two do not fit side by side, and the figure fits whatever is left. */
  .price-sub {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    column-gap: 0.25em;
    white-space: normal;
    line-height: 1.5;
    font-size: min(0.7rem, calc(100cqi / 7.4));
  }

  .price-sub > span {
    white-space: nowrap;
  }
}

/* The change tag over a price — the portal's market-board chip: a faint pill
   in the move's own colour, green up and red down whichever cell it sits in,
   with the arrow carrying the direction for anyone who cannot tell the two
   colours apart (web-client index.css, `.market-change`). */
.price-cell.sell,
.price-cell.buy {
  display: grid;
  justify-items: center;
  gap: 0.15rem;
}

.price-change {
  display: inline-flex;
  align-items: center;
  gap: 0.16rem;
  font-size: 0.68rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
  border-radius: 999px;
  padding-inline: 0.4rem;
  background: color-mix(in srgb, currentColor 14%, transparent);
  color: var(--text-dim);
}

.price-change.up { color: var(--buy-text); }
.price-change.down { color: var(--sell-text); }

.price-change.flat,
.price-change.none {
  background: none;
  font-weight: 600;
  opacity: 0.6;
}

.price-change-arrow {
  font-size: 0.78em;
  line-height: 1;
}

/* The figure in its side's colour, as on the portal. These override the
   gold/ivory pair the strip used before it had cells. */
.price-cell.sell .price-value,
.price-cell.buy .price-value {
  color: var(--side-text);
  font-weight: 700;
}

/* Set by prices.js when a poll fails: the last known numbers stay on screen,
   visibly dimmed, rather than being blanked out. A slightly old price is
   still true; an empty one reads as "this shop has no prices". */
.price-strip[data-price-stale] .price-value {
  opacity: 0.55;
}

/* ---------- published price trends (docs/price-history.md) ----------
 *
 * **A port of the portal's chart styling**, class for class and value for
 * value from `web-client/src/index.css`. The public chart is the same chart
 * (trend.js) and must not be a second look: a visitor who reads a trend here
 * and then signs up should meet what they already know. Only the wrapper rules
 * differ — `button.price-name`, its caret and `.price-trend-panel` — and those
 * are themselves ported from the portal's market row, which opens its trend the
 * same way.
 *
 * The layout lesson from the portal's version comes with it: every row of
 * figures is either a grid or a scroller that is *allowed to shrink*. A nowrap
 * row inside a flex or grid parent takes a max-content minimum, refuses to
 * shrink, and drags the whole page into a horizontal scroll on a phone rather
 * than scrolling inside its own box.
 */

/* The name is the control, as on the portal's market board — a button that has
   to shed every button default and read as the label it looks like
   (web-client/src/index.css, `button.market-name`). */
button.price-name {
  font-family: inherit;
  /* A button keeps its own font size and line height; inheriting both keeps a
     row with a chart exactly as tall as one without. */
  font-size: inherit;
  line-height: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
  text-align: start;
  padding: 0;
  position: relative;
  /* Room for the triangle (.price-trend-caret), which leads the name. */
  padding-inline-start: 1.15rem;
  /* Hug the name, so the caret sits beside it rather than at the far end of
     the name track. */
  justify-self: start;
}

button.price-name:hover,
button.price-name.on {
  color: var(--gold-text);
}

/* The "this opens a chart" mark: a small solid triangle in brushed gold
   (owner, 2026-10-20) — a metal ramp clipped to a triangle, with a soft
   glow, rather than the «▾» text glyph that read as a dot. Down when closed,
   up when open, read off the button's own `aria-expanded` so it can never
   disagree with the state a screen reader hears. The glyph is still in the
   markup (aria-hidden) and is simply not drawn. */
/* At the name's *start*, not its end (owner, 2026-10-20): after the name
   it landed wherever each name happened to end, a ragged column down the
   board; before it, every triangle sits on one line at the column's edge.
   Centred on the name's first line — the name's 1.9rem line box, less half the mark — in
   rem, because the mark's own font-size is 0 and an `em` here resolves to
   nothing (which is what lifted it above the text). */
.price-trend-caret {
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.6rem;
  inline-size: 0.7rem;
  block-size: 0.7rem;
  font-size: 0;
  line-height: 0;
}

.price-trend-caret::before {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  inline-size: 0.62rem;
  block-size: 0.42rem;
  background: linear-gradient(160deg, #f2dd9a, #d9ae3e 50%, #b8871f);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  filter: drop-shadow(0 0 3px color-mix(in srgb, var(--gold) 45%, transparent));
  transition: transform 180ms ease;
}

button.price-name[aria-expanded="true"] .price-trend-caret::before {
  transform: rotate(180deg);
}

/* The expanded panel, spanning all three tracks under the row's figures.
 *
 * Two boxes from trend.js: `.trend-side` (range, metrics, readout, help) and
 * `.trend-plot` (the chart). Stacked on a phone, in the portal's order. From
 * ~56rem they sit side by side — the figures in one column of their own, the
 * plot taking the rest — because spread across a thousand-pixel row the
 * metrics, the readout and the range buttons each landed in a different
 * corner and nothing read as belonging to anything. */
.price-trend-panel {
  grid-column: 1 / -1;
  display: grid;
  gap: 0.75rem;
  min-inline-size: 0;
  margin-block-start: 0.85rem;
  padding-block-start: 1rem;
  border-block-start: 1px solid var(--line);
}

.trend-side,
.trend-plot {
  min-inline-size: 0;
}

.trend-side {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

@media (min-width: 56rem) {
  .price-trend-panel {
    grid-template-columns: minmax(15rem, 18rem) minmax(0, 1fr);
    align-items: start;
    gap: 1.75rem;
  }

  /* The plot gets a well of its own, so the chart sits on a surface rather
     than floating in the row. */
  .trend-plot {
    background: var(--well);
    border: 1px solid var(--line);
    border-radius: 0.7rem;
    padding: 0.75rem 0.9rem 0.5rem;
  }

  /* The metrics line has a whole column here: a stacked label/figure list
     instead of a sideways scroller, and no fade at its edge. */
  .trend-side .trend-headline {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.35rem 1rem;
    overflow: visible;
    white-space: normal;
    mask-image: none;
  }

  .trend-side .trend-headline-item {
    display: contents;
  }

  .trend-side .trend-headline dd {
    text-align: end;
  }

  /* The selected candle's four figures, one per line — label at the start,
     figure at the end, the same shape as the metrics above them. Two to a
     line put four ten-digit numerals and four labels into a 17rem column. */
  .trend-side .trend-ohlc {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.2rem;
    padding-block-start: 0.5rem;
    border-block-start: 1px solid var(--line);
    font-size: 0.75rem;
  }

  .trend-side .trend-ohlc-figure {
    justify-content: space-between;
  }

  .trend-side .trend-readout-top {
    flex-direction: column;
    align-items: stretch;
  }

  .trend-side .money {
    align-items: start;
  }

  .trend-side .money-toman {
    text-align: start;
  }
}

.price-trend-panel[hidden] {
  display: none;
}

.trend-note {
  margin: 0.5rem 0 0;
  color: var(--text-faint);
  font-size: 0.85rem;
}

/* ---- from here down, the portal's rules ---- */

.trend-chart {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  inline-size: 100%;
  min-inline-size: 0;
  max-inline-size: 100%;
}

.trend-svg {
  display: block;
  inline-size: 100%;
  /* Probing the chart is a horizontal gesture; the page still scrolls
   * vertically through it. */
  touch-action: pan-y;
}

.trend-grid {
  stroke: var(--line);
  stroke-width: 1;
}

.trend-tick {
  fill: var(--text-faint);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
}

/* One candle: the wick spans high to low, the body open to close.
 *
 * A doji — a bucket in which the shop did not reprice — has a body of zero
 * height, floored to a hairline in trend.js. That flat mark is the whole point:
 * the price definitively stood there for the bucket, which is data, not a hole
 * (docs/price-history.md). */
.trend-candle .trend-wick {
  stroke-width: 1;
}

.trend-candle .trend-body {
  stroke-width: 1;
}

.trend-candle.up .trend-wick,
.trend-candle.up .trend-body { stroke: var(--buy-solid); }
.trend-candle.up .trend-body { fill: var(--buy-solid); }

.trend-candle.down .trend-wick,
.trend-candle.down .trend-body { stroke: var(--sell-solid); }
.trend-candle.down .trend-body { fill: var(--sell-solid); }

/* Unmoved: neither up nor down, so it borrows neither colour. */
.trend-candle.flat .trend-wick,
.trend-candle.flat .trend-body { stroke: var(--text-dim); }
.trend-candle.flat .trend-body { fill: var(--text-dim); }

/* Everything but the candle being read, while one is being read. */
.trend-candle.faded { opacity: 0.45; }

.trend-line {
  fill: none;
  stroke-width: 1.75;
  stroke-linejoin: miter;
  stroke-linecap: butt;
}

.trend-line.sell { stroke: var(--sell-solid); }

.trend-crosshair {
  stroke: var(--text-faint);
  stroke-width: 1;
  stroke-dasharray: 2 3;
}

/* What the chart is currently saying, in words — the full Rial-plus-Toman
 * treatment lives here rather than on the tick labels. */
.trend-readout {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-block-size: 1.6rem;
  min-inline-size: 0;
  max-inline-size: 100%;
}

.trend-readout-top {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.2rem 0.7rem;
  min-inline-size: 0;
}

.trend-readout-at {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35rem;
  font-size: 0.68rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  min-inline-size: 0;
}

.trend-readout-now {
  font-weight: 700;
  color: var(--gold-text);
}

.trend-readout-side {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
}

.trend-readout-figure {
  font-size: 0.82rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* The two-line money treatment, as the portal renders it (MoneyFigure). */
.money {
  display: inline-flex;
  flex-direction: column;
  align-items: end;
  gap: 0.1rem;
}

.money-toman {
  font-size: 0.78rem;
  font-weight: 400;
  line-height: 1.6;
  color: var(--text-dim);
  text-align: end;
  /* A spelled-out billion is a long phrase; let it wrap inside the block
     rather than widen the row it sits in. */
  text-wrap: pretty;
  overflow-wrap: anywhere;
}

/* One candle's O/H/L/C, under the figure it closed at.
 *
 * A grid, not a sideways scroller: four ten-digit Persian numerals do not fit
 * a phone's width, and a numeral clipped at a scroll edge reads as a different
 * number rather than as "there is more". Two columns on a phone, four when
 * there is room for them. */
.trend-ohlc {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.1rem 0.6rem;
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
  min-inline-size: 0;
  max-inline-size: 100%;
}

@media (min-width: 560px) {
  .trend-ohlc { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.trend-ohlc-figure {
  display: flex;
  gap: 0.2rem;
  align-items: baseline;
  min-inline-size: 0;
  white-space: nowrap;
}

/* Dotted underline: the affordance that says "there is an explanation behind
 * this word", and the `title` is that explanation on a pointer device. */
.trend-ohlc-label {
  color: var(--text-faint);
  border-block-end: 1px dotted var(--line-strong);
  cursor: help;
}

/* The «؟». Small, quiet, and beside the stamp rather than in the numerals. */
.trend-help {
  font-family: inherit;
  cursor: pointer;
  inline-size: 1.05rem;
  block-size: 1.05rem;
  padding: 0;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--text-dim);
  font-size: 0.62rem;
  line-height: 1;
  align-self: center;
  flex: 0 0 auto;
}

.trend-help.on {
  border-color: color-mix(in srgb, var(--gold) 45%, transparent);
  background: color-mix(in srgb, var(--gold) 16%, transparent);
  color: var(--gold-text);
}

/* Opens in flow, pushing the chart down — an overlay would need a physical
 * offset to be positioned, which is the one thing the RTL rules have no logical
 * property for (see trend.js). */
.trend-help-panel {
  border: 1px solid var(--line);
  border-radius: 0.6rem;
  padding: 0.6rem 0.7rem;
  background: color-mix(in srgb, var(--gold) 5%, transparent);
  font-size: 0.7rem;
  line-height: 1.7;
}

.trend-help-panel h4 {
  margin: 0 0 0.4rem;
  font-size: 0.75rem;
  color: var(--gold-text);
}

.trend-help-panel dl {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.5rem;
}

.trend-help-panel dt {
  font-weight: 700;
  color: var(--text-dim);
}

.trend-help-panel dd {
  margin: 0;
  color: var(--text-faint);
}

.trend-help-note {
  margin: 0.45rem 0 0;
  color: var(--text-faint);
}

/* The window the server actually served — never the range that was asked for,
 * which is clamped rather than refused. */
.trend-window {
  margin: 0;
  font-size: 0.68rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.trend-ranges {
  display: flex;
  gap: 0.35rem;
  margin-block-end: 0.6rem;
}

.trend-range {
  font-family: inherit;
  cursor: pointer;
  font-size: 0.75rem;
  font-weight: 600;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--text-dim);
  padding-block: 0.25rem;
  padding-inline: 0.7rem;
  transition: background-color 140ms ease, color 140ms ease;
}

.trend-range.on {
  background: color-mix(in srgb, var(--gold) 16%, transparent);
  border-color: color-mix(in srgb, var(--gold) 45%, transparent);
  color: var(--gold-text);
}

/* The metrics, as **one line** above the plot — the exchange convention the
 * shop pointed at, not a grid of cards beside the chart
 * (docs/price-history.md, "Where the metrics go").
 *
 * It scrolls sideways when it does not fit. On a narrow RTL screen the
 * alternative is three wrapped rows of Persian numerals, which is exactly the
 * clutter this line replaced. */
.trend-headline-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  margin-block-end: 0.5rem;
  min-inline-size: 0;
  max-inline-size: 100%;
}

.trend-headline {
  display: flex;
  gap: 0.9rem;
  margin: 0;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  scrollbar-width: none;
  white-space: nowrap;
  align-items: baseline;
  min-inline-size: 0;
  max-inline-size: 100%;
  /* One line that scrolls is what the shop asked for (docs/price-history.md),
     and a figure cut off dead straight at that edge reads as a smaller number
     rather than as "swipe for more" — so the last centimetre fades out.

     `to left` is physical, and there is no logical form of a gradient
     direction. It is correct here because this site renders RTL only: the line
     starts at the inline-start edge on the right and overflows leftwards. If a
     left-to-right locale is ever added, this is one of the few rules that has
     to be mirrored by hand. */
  mask-image: linear-gradient(to left, #000 calc(100% - 1.6rem), transparent);
}

.trend-headline::-webkit-scrollbar { display: none; }

.trend-headline-item {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  flex: 0 0 auto;
}

.trend-headline dt {
  font-size: 0.68rem;
  color: var(--text-faint);
  border-block-end: 1px dotted var(--line-strong);
  cursor: help;
}

.trend-headline dd {
  margin: 0;
  font-size: 0.8rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Open-to-close over the window on screen. The arrow carries the direction,
   matching the market board's chip rather than inventing a second idiom. */
.trend-change {
  display: inline-flex;
  align-items: baseline;
  gap: 0.25rem;
  font-variant-numeric: tabular-nums;
}

.trend-change.up { color: var(--buy-text); }
.trend-change.down { color: var(--sell-text); }
.trend-change.flat { color: var(--text-dim); }

.trend-change-percent {
  font-size: 0.85em;
  opacity: 0.8;
}

/* ---------- not found ---------- */

/* The 404 keeps the site's shell and adds one composition inside it: a quiet
 * gold numeral, the sentence that actually explains the situation, and the way
 * out. Centred like the hero, and sharing its lead and action-row classes, so
 * the page reads as the same site rather than as a system page that happens to
 * be the same colour. */
.notfound {
  padding-block: clamp(3rem, 9vw, 6.5rem);
  text-align: center;
}

/* The one moment of personality on the page, and deliberately the only one.
 * Same metal as the primary button and the skip link, so it is the brand's
 * own gold rather than a second gold invented for an error page. */
.notfound-code {
  font-size: clamp(4.5rem, 16vw, 9rem);
  font-weight: 800;
  line-height: 1;
  /* Persian numerals, like every other figure on this site
   * (docs/i18n-rtl.md) — the digits are in the markup, this only sets how
   * they look. letter-spacing opens them up at display size, where «۴۰۴»
   * otherwise reads as one glyph. */
  letter-spacing: 0.08em;
  margin-block-end: 1.75rem;
  /* The gradient is painted through the glyphs. `color` is set first and
   * stays the answer anywhere background-clip is unsupported: a solid gold
   * numeral, not an invisible one. */
  color: var(--gold-text);
  background: var(--gold-metal);
  -webkit-background-clip: text;
  background-clip: text;
  /* Separate rule rather than `color: transparent` above, so the fallback
   * keeps its colour: a browser that ignores background-clip also ignores
   * -webkit-text-fill-color. */
  -webkit-text-fill-color: transparent;
  /* The glow the hero's logo disc has, borrowed as a soft pool of light
   * behind the numeral — enough to lift it off the background, not enough to
   * read as a graphic of its own. */
  filter: drop-shadow(0 18px 34px rgb(201 162 39 / 0.22));
}

/* A hairline under the numeral, fading out at both ends: the same gold line
 * the cards and the header use, drawn as a rule so the numeral sits on
 * something instead of floating. Symmetric, so it needs no RTL thought. */
.notfound-code::after {
  content: "";
  display: block;
  inline-size: min(14rem, 60%);
  block-size: 1px;
  margin-block: 1.5rem 0;
  margin-inline: auto;
  background: linear-gradient(90deg, transparent, var(--line-strong), transparent);
}

.notfound h1 {
  /* Keeps the heading from breaking into a long line and a two-word orphan.
   * Ignored where unsupported, which costs nothing. */
  text-wrap: balance;
}

.notfound .hero-lead {
  max-inline-size: 34rem;
  /* Three lines and «خودشان هستند.» alone on the fourth is how this reads
   * on a phone without it. */
  text-wrap: pretty;
}

.notfound-note {
  /* --text-dim, not the --text-faint this size of text usually takes here:
   * the phone number in this line is the most useful thing on the page for
   * someone who was looking for one specific piece, and faint grey on this
   * background sits just under the 4.5:1 it needs to be read comfortably. */
  color: var(--text-dim);
  font-size: 0.95rem;
  margin-block-start: 1.75rem;
  text-wrap: pretty;
}

.notfound-note a {
  text-decoration: none;
  border-block-end: 1px solid var(--line-strong);
  padding-block-end: 0.1rem;
}

/* ---------- footer ---------- */

.site-footer {
  border-block-start: 1px solid var(--line);
  margin-block-start: 2rem;
  padding-block: 1.75rem;
  color: var(--text-dim);
}

.footer-inner {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.footer-title {
  font-weight: 700;
  color: var(--text);
}

.footer-line {
  font-size: 0.9rem;
}

.footer-nav {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}

.footer-nav a {
  text-decoration: none;
  font-size: 0.92rem;
}

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

/* ---------- «مسیریابی»: which map app to open (_map_choose.html) ----------
   A <details> rather than a script: the summary is the button, the open body
   is a small menu of نشان، بلد and گوگل مپ under it. It keeps the card-foot
   placement .branch-map gives the button on the contact page. */
.map-choose {
  position: relative;
  margin-block-start: auto;
  align-self: flex-start;
}

.map-choose > summary {
  list-style: none;
  cursor: pointer;
}

.map-choose > summary::-webkit-details-marker {
  display: none;
}

.map-menu {
  position: absolute;
  inset-block-start: calc(100% + 0.35rem);
  inset-inline-start: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  min-inline-size: 10rem;
  padding: 0.35rem;
  border: 1px solid var(--line-strong);
  border-radius: 0.8rem;
  background: var(--bg);
  box-shadow: 0 12px 32px rgb(0 0 0 / 0.35);
}

.map-menu a {
  padding: 0.55rem 0.8rem;
  border-radius: 0.55rem;
  color: var(--text);
  text-decoration: none;
  font-size: 0.92rem;
}

.map-menu a:hover,
.map-menu a:focus-visible {
  background: var(--raised);
  color: var(--gold-text);
}

/* «کپی نشانی» in the map menu: a button dressed as the links beside it. */
.map-menu .map-copy {
  font: inherit;
  font-size: 0.92rem;
  text-align: start;
  padding: 0.55rem 0.8rem;
  border: none;
  border-block-start: 1px solid var(--line);
  border-radius: 0 0 0.55rem 0.55rem;
  background: none;
  color: var(--text-dim);
  cursor: pointer;
}

.map-menu .map-copy:hover,
.map-menu .map-copy:focus-visible {
  background: var(--raised);
  color: var(--gold-text);
}
