/* FaraDars public site — FaraJob design system v3 "Balanced Professional"
   Shared public-site styles and design tokens.
   Near-white warm-gray foundation, white content cards, one equal-weight
   accent family per content category, ONE brand blue for every action
   (search, buttons, links) so brand color = "what you can do" and category
   color = "what you are looking at". Vazirmatn everywhere, short functional
   motion.

   Category color plumbing: templates put the type's whole family on a wrapper
   via the `cat_style` filter (--type-color + --c-dark/-panel/-tile/-wash/-on/
   -border/-chip/-shadow). :root carries the neutral ink/gray family, so
   anything outside a category scope stays neutral. */

@import url('fonts.css');

@counter-style fa-decimal {
  system: numeric;
  symbols: '۰' '۱' '۲' '۳' '۴' '۵' '۶' '۷' '۸' '۹';
  suffix: '. ';
}

:root {
  /* Sticky-bar clearance (F52): the logged-in admin bar publishes its
     measured height here (assets/adminbar.js; 0 for normal visitors — and
     the draft-preview indicator is a pill INSIDE the bar, F53, so this one
     variable covers everything sticky). Every anchor scroll-margin and the
     TOC scroll-spy add it so content never lands underneath the bar. */
  --admin-bar-h: 0px;
  --sticky-bars: var(--admin-bar-h);
  /* neutrals — re-anchored to the app's cool navy-blue family (2026-08-25
     unification): each step keeps the lightness this ramp was tuned at
     (contrast relationships stay intact) but interpolates hue/saturation
     between the app's own --ink/--muted/--field-line/--line/--paper tokens,
     so the CMS's public pages and the app read as one palette rather than a
     warm-gray site living beside a cool-blue one. */
  --paper: #f6f8fb;
  --surface: #ffffff;
  --sand: #eff2f7;
  --line: #c9d7ec;
  --line-strong: #aebedb;
  --line-input: var(--line-strong);
  --line-soft: #e2e8f0;
  /* inks — primary / body / secondary / subtle */
  --ink: #131d32;
  --ink-2: #3b4c6b;
  --ink-3: #4b5c7a;
  --ink-4: #637695;
  --ink-body: #263552;
  --ink-placeholder: #526380;
  --chev: var(--ink-4);
  /* the site's ONE action color — search, buttons, links, focus. Category
     hues never drive actions; the app's own brand blue, so a button reads
     identically whether it sits on a CMS page or the application. */
  --brand: #1b5e9c;
  --brand-dark: #173f5f;
  --brand-ring: rgba(27, 94, 156, 0.16);
  --focus: #1b5e9c;
  /* neutral category family (overridden per scope by cat_style) */
  --type-color: #131d32;
  --c-dark: #090e18;
  --c-panel: #eff2f7;
  --c-tile: #e2e8f0;
  --c-wash: #f3f5f9;
  --c-on: #f6f8fb;
  --c-border: #c9d7ec;
  --c-chip: #b6c5e0;
  --c-shadow: rgba(19, 29, 50, 0.1);
}

* { box-sizing: border-box; }

/* F157: ONE typeface everywhere — form controls and buttons do not inherit
   the document font by default, which let UA fonts leak into button labels
   and (via ::after) the injected tooltips. */
button, input, select, textarea { font: inherit; }

html {
  -webkit-text-size-adjust: 100%;
  scrollbar-gutter: stable;
  /* F141: the body backstop alone still let the ROOT scroll horizontally
     when something overflowed — clip here too (clip ≠ hidden: no scroll
     container, sticky descendants unaffected). */
  overflow-x: clip;
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  font-family: 'Vazirmatn', 'Segoe UI', Tahoma, Arial, sans-serif;
  font-size: 1.03125rem; /* 16.5px */
  line-height: 1.85;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  /* F139: any stray min-content overflow (long LTR tokens, a wide chrome
     element) must never widen the page into a horizontal pan on phones.
     `clip` — not `hidden` — so no scroll container is created and
     position: sticky descendants keep working. */
  overflow-x: clip;
}

/* Code: Vazir Code (fonts.css) pairs Latin code glyphs with real Persian
   forms — the OS monospace Arabic fallback stretches glyphs. */
code, kbd, samp, pre { font-family: 'Vazir Code', ui-monospace, Consolas, monospace; }

::selection { background: #cde4f4; color: var(--ink); }
/* Ellipsis so a placeholder longer than the box fades out as «…» instead of
   hard-clipping mid-word (the hero placeholder at phone widths). */
input::placeholder { color: var(--ink-placeholder); opacity: 1; text-overflow: ellipsis; }

/* No underlines anywhere (they cross Persian descenders); links signal with
   the brand blue and answer hover with the darker step. */
a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-dark); }

/* One consistent, always-visible keyboard focus ring, everywhere. */
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Skip link (base.njk renders it first in <body>): parked above the viewport
   until keyboard focus reveals it; must sit over the admin bar too. */
.skip-link {
  position: fixed;
  inset-block-start: -100px;
  inset-inline-start: 16px;
  z-index: 210;
  padding: 10px 18px;
  border-radius: 12px;
  background: var(--brand);
  color: #fff;
  font-weight: 700;
  transition: none;
}
.skip-link:focus-visible { inset-block-start: calc(var(--sticky-bars) + 8px); outline-offset: 2px; }
/* The skip link moves focus to <main tabindex="-1">; a page-wide focus ring
   around the whole content column is noise, not orientation. */
main:focus { outline: none; }

h1, h2, h3, h4, h5, h6 { line-height: 1.45; color: var(--ink); }
h1 { font-size: 2rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.45; margin-block: 0.5rem 0.75rem; }
h2 { font-size: 1.375rem; font-weight: 800; margin-block: 0 1rem; }
h3 { font-size: 1.03125rem; font-weight: 800; margin-block: 0 0.5rem; line-height: 1.6; }
/* F99: the h4 tier exists now that the outline is strict (section h2 → field
   h3 → item/content h4) — one visual notch under h3. */
h4 { font-size: 0.97rem; font-weight: 800; margin-block: 0 0.5rem; line-height: 1.6; }
/* Deep-nested authored prose only: shiftHeadings (F99) can push a richtext
   fragment's outline down to h5/h6. One notch under h4, never browser
   defaults. */
h5, h6 { font-size: 0.93rem; font-weight: 800; margin-block: 0 0.5rem; line-height: 1.6; }

p { margin-block: 0 1rem; }

ul, ol { padding-inline-start: 1.5rem; margin-block: 0 1rem; }
li { margin-block-end: 0.35rem; }
ol { list-style-type: fa-decimal; }

img { max-width: 100%; height: auto; }

/* The content column. `main` is already capped to --page-w (assets/masir.css)
   and centered, so this only needs to match that same width — no inline
   padding of its own, or its content would sit inset from the shared
   header/footer content, which is flush against that same page-w box. */
.container {
  width: 100%;
  max-width: 1160px;
  margin-inline: auto;
}

/* Full-width surface band (hero / page head); pages put a .container inside.
   No fill of its own (2026-08-25): `main` is capped to --page-w, not the
   viewport, so a background here reads as a floating white slab against the
   page's own --paper tone rather than a true full-bleed section — the
   hairline below is enough of a break from the content underneath. */
.band {
  border-block-end: 1px solid var(--line);
}

main { flex: 1; width: 100%; }
main > .container { padding-block: 24px 8px; }

/* Public glyph sizing default. */
.crumbs svg { width: 10px; height: 10px; }

/* --- Reading progress (F113, injected by site.js) ------------------------
   A fixed hairline over the brandbar line; fills inline-start → inline-end
   (physical right → left on this RTL site). Inside a .cat-scope it inherits
   the post type's accent; elsewhere the brand blue. Sits BELOW the sticky
   admin bar when one is mounted (--admin-bar-h, 0 for visitors) — the admin
   bar must never cover any piece of the site design. */
.read-progress {
  position: fixed;
  inset-block-start: var(--admin-bar-h);
  inset-inline: 0;
  height: 3px;
  z-index: 60;
  background: var(--brand);
  transform: scaleX(0);
  transform-origin: right;
  pointer-events: none;
}
.cat-scope .read-progress { background: var(--type-color); }

/* --- Header & footer -----------------------------------------------------
   Retired 2026-08-25: this stylesheet no longer draws its own header/footer.
   Both are shared markup with the application (templates/partials/
   site-header.njk, site-footer.njk) and styled entirely by assets/masir.css,
   which base.njk now also loads — one header, one footer, one stylesheet
   deciding how each looks, on every page either system serves. What used to
   live here (site-nav, the phone hamburger, footer-columns/social/enamad)
   was CMS-only chrome with no reader ever configuring most of it; the
   settings it read (footer link_columns, social_links, enamad_html) stay in
   the schema, just unconsumed by any template now. */

/* --- Buttons & chips ---------------------------------------------------- */

/* Primary button — ALWAYS the brand blue (v3): actions never wear category
   color, so "blue = something you can do" stays learnable. */
.search-btn {
  font: inherit;
  font-size: 15.5px;
  font-weight: 700;
  background: var(--brand);
  color: #ffffff;
  border: none;
  border-radius: 14px;
  padding: 12px 28px;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(25, 87, 127, 0.2);
  transition: background-color 0.18s ease;
}
.search-btn:hover { background: var(--brand-dark); }
.search-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* F107/F146: icon-only variant — «جست‌وجو» was too long for a button; the
   name rides on aria-label instead. SQUARE: the flex row stretches the
   height to the input; the width is pinned to match (aspect-ratio does not
   transfer through stretched flex heights in Blink). */
.search-btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  width: 50px;
  flex: none;
}
.search-btn-icon svg { display: block; width: 19px; height: 19px; }

/* Quiet chip — «همه», copy-link, secondary actions. */
.quiet-chip,
.see-all {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  border: 1px solid var(--c-chip);
  padding: 9px 16px;
  border-radius: 999px;
  color: var(--type-color);
  font-weight: 700;
  font-size: 14px;
  white-space: nowrap;
  transition: border-color 0.18s ease;
}
.quiet-chip:hover,
.see-all:hover { border-color: var(--type-color); color: var(--type-color); }
.quiet-chip svg,
.see-all svg { width: 14px; height: 14px; }

/* --- Search field ------------------------------------------------------- */

.search-form {
  display: flex;
  gap: 10px;
  max-width: 620px;
  position: relative; /* anchors the suggest dropdown */
}
.search-form input[type='search'] {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 16px;
  color: var(--ink);
  background: var(--surface);
  border: 1.5px solid var(--line-input);
  border-radius: var(--radius-control);
  /* Fixed height (F146): the icon submit button stretches to the row, so a
     known height is what makes its pinned width a true square. */
  height: var(--control-h);
  padding: 0 18px;
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
/* Focus is immediate and unmistakable: brand border + soft brand halo.
   (In-category search stays brand too — search is an action, v3.) */
.search-form input[type='search']:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-ring);
}

/* --- Breadcrumb ---------------------------------------------------------- */

/* A flex row (not just the inner <ol>) so the copy-link pill toc.js appends
   after the list lands on the SAME row, pushed to the far inline-end by its
   own margin-inline-start:auto, instead of wrapping onto its own line. */
.crumbs { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 14px; font-size: 13.5px; margin: 0; }
.crumbs-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
}
.crumbs-list li { display: flex; align-items: center; gap: 8px; margin: 0; }
.crumbs a { color: var(--ink-3); transition: color 0.18s ease; }
.crumbs a:hover { color: var(--type-color); }
.crumbs svg { color: var(--chev); flex: none; }
.crumbs .crumbs-current { color: var(--ink); font-weight: 700; }

/* --- Hero (home) --------------------------------------------------------- */

.hero .container { padding-block: 46px 40px; }
.hero-eyebrow { font-size: 13px; font-weight: 800; letter-spacing: 0.12em; color: var(--brand); }
.hero h1 { font-size: 2.25rem; line-height: 1.4; margin: 12px 0; }
.hero-sub { font-size: 18px; color: var(--ink-3); max-width: 620px; margin: 0 0 26px; }
/* Richtext hero subtitle (F70): inner paragraphs must not double the block gap. */
.hero-sub p { margin: 0 0 0.5em; }
.hero-sub p:last-child { margin-block-end: 0; }

/* Category entry tiles under the hero search — F126: ONE shared responsive
   grid for the homepage groups (hero entry tiles AND the explorer's preview
   card grid): 3 columns at desktop, 2 on tablets, 1 on phones. The preview
   grid is written as the compound .card-grid.cat-exp-grid so these fixed
   column counts outrank the generic .card-grid auto-fill columns (defined
   further down) regardless of source order — a bare single-class selector
   ties with .card-grid and silently loses to it (that bug shipped 4 desktop
   columns once, on the retired spotlight grid). */
.cat-tiles,
.card-grid.cat-exp-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.cat-tiles { margin-block-start: 24px; }
@media (max-width: 860px) { .cat-tiles, .card-grid.cat-exp-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 540px) { .cat-tiles, .card-grid.cat-exp-grid { grid-template-columns: 1fr; } }
.cat-tile {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 11px 16px;
  color: var(--ink);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.cat-tile:hover {
  color: var(--ink);
  transform: translateY(-2px);
  border-color: var(--c-chip);
  box-shadow: 0 8px 20px var(--c-shadow);
}
/* Icon containers are one system: 44px, 12px radius, accent fill, near-white
   glyph (24px) — identical in the hero tiles and the section heads. */
.cat-tile-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  /* F74: tinted tile + accent glyph (the dashboard type-card treatment) —
     the solid accent fill put a white stroke icon on dark hues that don't
     all carry it well. Same swap on every icon tile below. */
  background: var(--c-tile);
  color: var(--type-color);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.cat-tile-icon svg { width: 24px; height: 24px; }
.cat-tile-text { flex: 1; min-width: 0; }
/* F126: medium weight, ONE line — overflow ellipsizes (site.js surfaces the
   full text via tooltip only when truncation really happens). */
.cat-tile-name {
  display: block;
  font-size: 15.5px;
  font-weight: 500;
  color: var(--ink);
  line-height: 1.7;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* (.cat-tile-count retired with F110 — homepage tiles carry no item counts.) */
.cat-tile-chevron { width: 16px; height: 16px; flex: none; color: var(--type-color); }

/* --- Category explorer (partials/category-explorer.njk) ------------------ */
/* Inline category exploration inside a section panel: count-ordered selector
   BUTTONS (a TAB strip on desktop — no chevron; the CLAUDE.md chevron rule
   excepts tab-style selectors) + preview PANELS of shared item cards. The
   DOM is button,panel,button,panel… (right for AT, no-JS and phones); on
   wider screens CSS `order` floats every panel below the button grid, so the
   one open panel reads as a single shared full-width preview area — buttons
   keep their rows, nothing shifts inside the grid. The panel's own TITLE
   (category name + count) provides the context and the separation from the
   selector grid. The server ships the first category active, the rest
   hidden; site.js only wires the one-open switching. */
.cat-explorer { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.cat-exp-btn {
  order: 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 11px 16px;
  font: inherit;
  text-align: start;
  color: var(--ink);
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease, box-shadow 0.18s ease;
}
.cat-exp-btn:hover { border-color: var(--c-chip); box-shadow: 0 8px 20px var(--c-shadow); }
/* Selected (active-tab) state never rides on color alone: accent border +
   tinted fill + the BOLD name all mark it. */
.cat-exp-btn[aria-expanded="true"] {
  background: var(--c-wash);
  border-color: var(--type-color);
  box-shadow: none;
}
.cat-exp-btn[aria-expanded="true"] .cat-exp-name { font-weight: 700; }
.cat-exp-name {
  flex: 1;
  min-width: 0;
  font-size: 15px;
  font-weight: 500;
  line-height: 1.7;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* (Counts live ONLY in the view-all tile's label — tabs and the panel title
   carry the bare category name.) */
.cat-exp-panel { order: 1; grid-column: 1 / -1; margin-block-start: 18px; }
.cat-exp-panel[hidden] { display: none; }
/* Panel title: the selected category's name right above its items — the
   context AND the visual separation from the selector grid. */
.cat-exp-title {
  margin: 0 0 12px;
  font-size: 16px;
  font-weight: 800;
  color: var(--ink);
  line-height: 1.6;
}
@media (max-width: 860px) { .cat-explorer { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 540px) {
  .cat-explorer { grid-template-columns: 1fr; }
  /* True accordion on phones: source order puts each panel under its button —
     the button directly above already names the category, so no panel title. */
  .cat-exp-btn, .cat-exp-panel { order: initial; }
  .cat-exp-panel { margin-block-start: 0; }
  .cat-exp-title { display: none; }
}

/* --- Category panel + content cards (home & listings) -------------------- */

.home-section { margin-block-end: 20px; }
.home-section:target { scroll-margin-block-start: calc(16px + var(--sticky-bars)); }

/* White card everywhere (home sections and listing pages alike) — a tinted
   panel on just one section/page read as a different, heavier design than
   the rest of the system, so every category panel now shares one flat,
   white, bordered surface. */
.category-panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 24px;
  padding: 26px;
}

.panel-head { display: flex; align-items: center; gap: 14px; margin-block-end: 18px; }
.panel-head-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--c-tile);
  color: var(--type-color);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.panel-head-icon svg { width: 24px; height: 24px; }
.panel-head-text { flex: 1; min-width: 0; }
.panel-head h2 { margin: 0; line-height: 1.45; }
.panel-sub { display: block; font-size: 14px; color: var(--ink-2); line-height: 1.7; }

/* Taxonomy term descriptions (F68): under the section heading on grouped
   overviews, and under the title block on a term's own filter page. */
.panel-desc { margin: -8px 0 16px; max-width: 70ch; font-size: 14.5px; color: var(--ink-2); }
.panel-desc p, .listing-desc p { margin: 0 0 0.5em; }
.panel-desc p:last-child, .listing-desc p:last-child { margin-block-end: 0; }
.listing-desc { margin-block-start: 10px; max-width: 70ch; font-size: 15px; color: var(--ink-2); line-height: 1.9; }

/* The trailing "uncategorized" bucket is a content gap (a doc missing its
   grouping field), not a real category — dashed border + neutral ink icon
   (never the type's own accent color) so it reads as "needs attention"
   rather than sitting as an equally legitimate section next to real ones. */
.category-panel--uncategorized { border: 1px dashed var(--line-strong); }
.panel-head-icon--muted { background: var(--sand); color: var(--ink-3); }

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
  gap: 12px;
}
/* (The homepage explorer grid's column counts live beside .cat-tiles above,
   as .card-grid.cat-exp-grid — the compound outranks this auto-fill rule so
   the homepage keeps its fixed 3/2/1 columns. A duplicate rule HERE once
   overrode the 860/540px overrides and forced three squeezed columns on
   phones, F141. Never restate them below the queries.) */

/* Grouped listing overviews (the /skills/-style top-level pages): fixed TWO
   columns on desktop, one on phones (owner decision 2026-08-04 — was the
   auto-fill ≈3 beside the filter sidebar). Pairs with sectionPreview's 7/10
   listing numbers (listing.ts): a full 7-item preview + the view-all tile
   close the grid as a clean 2×4. Descendant selector so it outranks the
   auto-fill base above regardless of source order (same specificity lesson
   as .card-grid.cat-exp-grid); breakpoint matches the explorer's 2→1. */
.listing-main .card-grid { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 540px) { .listing-main .card-grid { grid-template-columns: 1fr; } }
/* F141: one-line (nowrap) card titles must never dictate the column width —
   grid items default to min-width:auto, which let a long title push the
   whole grid past the viewport on phones. */
.card-grid > *, .cat-tiles > * { min-width: 0; }

/* Trailing view-all TILE — shared by every grouped listing overview section
   AND the homepage explorer panels: the card grid's LAST cell, so a full
   preview closes the desktop grid without an empty slot (explorer: 8 + tile
   = 3×3; listing overview: 7 + tile = 2×4); on narrower column counts it
   simply ends the list. Dashed border + accent text keep it "meta" next to
   the solid content cards. */
.card-grid .see-all-card {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px dashed var(--c-chip);
  border-radius: 14px;
  padding: 12px 16px;
  font-size: 14.5px;
  font-weight: 700;
  color: var(--type-color);
  transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.card-grid .see-all-card:hover { background: var(--c-wash); border-color: var(--type-color); color: var(--type-color); }
.card-grid .see-all-card svg { width: 15px; height: 15px; flex: none; }

/* Content card — the workhorse doorway card. */
.card-grid .relation-card,
.listing .relation-card {
  display: flex;
  flex-direction: column;
  gap: 7px;
  background: var(--surface);
  border: 1px solid var(--c-border);
  border-radius: 14px;
  padding: 17px 18px 13px;
  color: var(--ink);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease,
    color 0.18s ease, background-color 0.18s ease;
}
/* F126: the slim doorway card is ONE horizontal row — title and chevron on
   the same line, vertically centered; no bottom-corner chevron, no second
   line. Shared by the homepage explorer previews and every listing grid.
   (Doubled class keeps it above the `.card-grid .relation-card` column
   rule.) */
.relation-card.relation-card-slim { flex-direction: row; align-items: center; gap: 10px; padding: 12px 16px; }
.relation-card-slim .relation-card-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: 15.5px;
  font-weight: 500;
  line-height: 1.7;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.relation-card-slim .relation-card-chevron { flex: none; }
/* Hover = clearer tinted border + gentle lift; the text stays ink (v3: no
   dramatic color flips) and only the chevron carries the accent. */
.relation-card:hover {
  border-color: var(--c-chip);
  box-shadow: 0 8px 20px var(--c-shadow);
  transform: translateY(-2px);
  color: var(--ink);
}
.relation-card-head { min-width: 0; }
.relation-card-title { display: block; font-weight: 800; font-size: 16.5px; line-height: 1.5; margin: 0; color: inherit; }
.relation-card-summary {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  /* F78: quieter than before (was 14px/--ink-3, 3 lines) — the summary is a
     scent, not the content; it must not compete with the card title. */
  color: var(--ink-4);
  font-size: 13px;
  line-height: 1.7;
}
/* The POST-shaped card (guides) gets a third line. The excerpt the generator
   writes is 160 characters cut on a word boundary with its own «…», and that
   needs three lines at this size — so at two, every single card was being cut
   a SECOND time by the clamp, mid-word and with no say in where. Three lines
   fits ~164 characters even on the narrowest card, which makes the server's
   cut the only one and leaves the clamp as a backstop that never fires.
   F78's two-line rule still governs every other relation-card: there the
   summary is a scent under a directory entry, here it is the point. */
.relation-card-post .relation-card-summary {
  -webkit-line-clamp: 3;
  line-clamp: 3;
}

.relation-card-foot { display: flex; align-items: center; gap: 4px; justify-content: flex-end; margin-block-start: auto; padding-block-start: 4px; }
.relation-card-readmore { font-size: 12.5px; font-weight: 700; color: var(--type-color); }
.relation-card-chevron { width: 14px; height: 14px; color: var(--type-color); }

/* Screen-reader-only text (the tooltip summary's accessible copy). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* (The custom black data-tip bubble on cards was retired 2026-08-03 — cards
   are title-only; the summary stays as sr-only text for screen readers, and
   a truncated title falls back to the native title tooltip via site.js.) */

/* --- Listing page --------------------------------------------------------- */

.listing-head .container { padding-block: 24px 30px; }
.listing-title-row { display: flex; align-items: center; gap: 16px; margin-block-start: 20px; }
.listing-icon {
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: var(--c-tile);
  color: var(--type-color);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.listing-icon svg { width: 25px; height: 25px; }
.listing-title-text { flex: 1; min-width: 0; }
.listing-title-line { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.listing-head h1 { font-size: 30px; margin: 0; }
/* How much is in this listing, said at the size of a claim rather than of a
   tag (owner, 2026-09-07). The size of this library is the product's own
   advantage, and at 13px beside a 30px heading it read as a piece of metadata
   somebody might check — «۴۹۱ دانشگاه» is worth stating, and repeating it on
   the home page as well is a feature, not a duplication. */
.count-chip {
  background: var(--c-tile);
  color: var(--type-color);
  border-radius: 999px;
  padding: 5px 16px;
  font-size: 17px;
  font-weight: 800;
  white-space: nowrap;
}
.listing-section { margin-block-end: 20px; }
.listing-section:last-child { margin-block-end: 0; }
.listing-main { min-width: 0; }
.listing-section .panel-head h2 { font-size: 20px; }

/* F108: search + filters live in the listing sidebar now — one quiet card
   sharing the doc-sidebar chrome (sticky on desktop, drawer on phones). */
/* Sidebar head (explore): overline + ONE quiet reset action on a single row
   — replaces the stacked clear links that used to sit between the search box
   and the filter accordions. */
.listing-tools-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.filters-reset { flex: none; font-size: 12px; font-weight: 700; color: var(--ink-3); padding-block-end: 8px; }
.filters-reset:hover { color: var(--type-color); }

.listing-tools .search-form { margin-block-start: 2px; }
/* Inline padding stays with the .search-box rules (room for the prepended
   magnifier / appended ✕) — this higher-specificity rule once reset it to
   14px and ran the text under the icon. */
.listing-tools .search-form input[type='search'] { height: 44px; padding-block: 0; font-size: 14.5px; }
.listing-tools .search-btn-icon { width: 44px; border-radius: 12px; }
.listing-tools .search-btn-icon svg { width: 16px; height: 16px; }

/* Filter bar (per-field value listings). */
.filter-groups { display: flex; flex-direction: column; gap: 8px; margin-block-start: 18px; }
.filter-group { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* Sidebar variant (F130): accordion groups separated by hairlines. */
.filter-groups-sidebar { margin-block-start: 10px; gap: 0; }
.filter-groups-sidebar .filter-group {
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  border-block-start: 1px solid var(--line-soft);
}
.filter-groups-sidebar .filter-options {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  padding-block-end: 12px;
}
.filter-options[hidden] { display: none; }
/* Accordion header: a real button — label, active count, closed-state-down
   chevron; whole row is the hit target. */
.filter-acc-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 11px 2px;
  background: none;
  border: none;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-2);
  cursor: pointer;
  text-align: start;
}
.filter-acc-btn:hover { color: var(--ink); }
.filter-acc-label { flex: 1; min-width: 0; }
.filter-acc-count {
  flex: none;
  min-width: 19px;
  height: 19px;
  padding-inline: 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--c-tile);
  color: var(--type-color);
  font-size: 11.5px;
  font-weight: 800;
  line-height: 1;
}
.filter-acc-chevron { width: 13px; height: 13px; flex: none; color: var(--chev); transition: transform 0.18s ease; }
.filter-acc.open .filter-acc-chevron { transform: rotate(180deg); }
/* F129: the primary clear-everything action — a real labeled control, shown
   only while something is filtered. */
.filter-clear-all {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-block-start: 12px;
  padding: 7px 14px;
  border: 1px dashed var(--line-strong);
  border-radius: 999px;
  align-self: flex-start;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 700;
  transition: color 0.18s ease, border-color 0.18s ease;
}
.filter-clear-all:hover { color: var(--type-color); border-color: var(--type-color); }
/* Compact «نمایش بیشتر» inside a filter group (shares .list-more-btn). */
.list-more-btn-sm { margin-block-start: 2px; padding: 4px 12px; font-size: 12.5px; }
.filter-pill[hidden] { display: none; }
.filter-label { font-size: 13.5px; font-weight: 700; color: var(--ink-3); margin-inline-end: 2px; }
.filter-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 14px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-3);
  font-size: 13.5px;
  font-weight: 700;
  transition: color 0.18s ease, border-color 0.18s ease;
}
.filter-pill:hover { color: var(--type-color); border-color: var(--type-color); }
.filter-pill.active { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.filter-pill.active:hover { color: var(--paper); }
/* No opacity and ≥11.5px: counts inherit the pill's ink-3, which is the
   lightest ink that still clears WCAG AA on surface. */
/* (.filter-count retired 2026-08-03 — filter pills carry no result counts.) */
.filter-clear { border-style: dashed; }

/* --- Pagination ----------------------------------------------------------- */

.pager, .search-pagination {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-block-start: 24px;
}
.pager a, .pager span, .search-pagination a, .search-pagination span {
  min-width: 38px;
  height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding-inline: 8px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
}
.pager a, .search-pagination a {
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink-3);
  transition: color 0.18s ease, border-color 0.18s ease;
}
.pager a:hover, .search-pagination a:hover { color: var(--type-color); border-color: var(--type-color); }
.pager .pager-cur { background: var(--ink); border: 1px solid var(--ink); color: var(--paper); }
.pager .pager-gap { color: var(--ink-4); min-width: auto; padding-inline: 4px; }
.pager svg, .search-pagination svg { width: 13px; height: 13px; }

/* --- Document (detail) pages ---------------------------------------------- */

.doc-head .container { padding-block: 24px 30px; }

.doc-title-row { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; margin-block-start: 14px; }
.doc-title-text { flex: 1; min-width: 0; }
/* Slightly under the global 2rem h1 — the content H1 shares the band with
   breadcrumbs and the logo, so it reads calmer a notch smaller. */
.doc-head h1.doc-title { margin: 0; font-size: 1.8rem; }
/* Full container width — the sidebar column only exists below, in the grid. */

/* Share button (F102, injected by site.js on the breadcrumb row, pushed to
   the far inline-end — the physical LEFT on this RTL site — on every page
   template that shares crumbs.njk: content pages and listing pages alike).
   Icon-only; the success feedback is the ::after bubble below. */
.doc-share-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: var(--surface);
  border: 1px solid var(--c-chip);
  border-radius: 999px;
  color: var(--type-color);
  cursor: pointer;
  transition: border-color 0.18s ease;
}
.doc-share-btn:hover { border-color: var(--type-color); }
/* display:block kills the inline-svg baseline slack that nudged the glyph
   off-center inside the circle (F143). */
.doc-share-btn svg { display: block; width: 15px; height: 15px; }
/* F157: share + copy travel as ONE group at the far inline-end — their own
   6px gap, immune to the crumbs row's gap and wrapping. */
.doc-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-inline-start: auto;
}
/* Hover hint + copy feedback share one bubble (same pattern as the heading
   anchors); .copied swaps the text and pins it visible. */
.doc-share-btn::after {
  content: attr(data-tipword);
  position: absolute;
  top: calc(100% + 7px);
  inset-inline-start: 50%;
  translate: 50% 0; /* RTL page: physical +x shift centers the bubble */
  background: var(--ink);
  color: var(--paper);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  padding: 6px 10px;
  border-radius: 7px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.15s ease 0.15s;
  z-index: 5;
}
.doc-share-btn.copied::after { content: 'لینک صفحه کپی شد'; }
@media (hover: hover) {
  .doc-share-btn:hover::after,
  .doc-share-btn:focus-visible::after { opacity: 1; visibility: visible; }
}
.doc-share-btn.copied::after { opacity: 1; visibility: visible; }

/* Grid: 280px sticky sidebar (right, in RTL) + article. */
.doc-layout {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 26px;
  align-items: start;
  padding-block: 26px 8px;
}
.doc-layout.no-sidebar { grid-template-columns: minmax(0, 1fr); }

/* Tool logo beside the title. */
.doc-logo { margin: 6px 0 0; flex: none; }
.doc-logo img { max-height: 72px; width: auto; border-radius: 13px; display: block; background: var(--surface); }

/* Sidebar type scale (T2): one tier set for every sidebar component —
   values/TOC links 14 · labels/badges/EN title 12.5 · notes/overline 12;
   the card title (15) is the single deliberate step up. New sidebar
   components take a variable instead of hand-picking a size. */
.doc-sidebar {
  --sb-value: 14px;
  --sb-label: 12.5px;
  --sb-note: 12px;
  --sb-title: 15px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}
@media (min-width: 64rem) {
  .doc-sidebar {
    position: sticky;
    /* Stick BELOW the logged-in admin bar (F52): without the offset the
       sidebar's top slid underneath the sticky bar while scrolling. The
       height cap shrinks by the same amount so the bottom stays on-screen. */
    top: calc(24px + var(--sticky-bars));
    max-height: calc(100dvh - 48px - var(--sticky-bars));
    overflow-y: auto;
    /* F148: sticky forms a stacking context in Blink — without an explicit
       level, the results column painted OVER the suggestion panel. */
    z-index: 10;
  }
  /* F79: scrolling the WHOLE column cut the TOC card (and its bottom border)
     at the viewport cap. Instead the cards keep their natural height and the
     TOC's LIST scrolls inside its own bordered card: min-height:0 lets the
     card compress within the flex column, the ul takes the scrollbar. The
     container's overflow-y:auto stays only as a fallback for the extreme
     case of a glance card alone exceeding the viewport. */
  .doc-sidebar > * { flex: none; }
  .doc-sidebar > .doc-toc { flex: 0 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .doc-sidebar > .doc-toc > * { flex: none; }
  .doc-sidebar > .doc-toc > ul { flex: 0 1 auto; min-height: 0; overflow-y: auto; }
  /* LISTING/SEARCH sidebars are never an inner scroll container (F130: the
     page scrolls, accordions keep the column short) — a capped overflow here
     also CLIPPED the suggestion panel at the card edge (F128) and grew a
     stray horizontal scrollbar under the sidebar. */
  .doc-sidebar.listing-sidebar { max-height: none; overflow: visible; }
}

/* Sidebar fact card (alternative names, learning time, tool facts). */
.glance {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 16px 19px;
}
.glance-rows { margin-block-start: 0; }
/* F163: label and value(s) share one wrapping line — the label leads, badges
   flow after it and wrap to full-width lines when a row carries many. Gap
   replaces the old per-value margins. */
.glance-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 10px;
  row-gap: 4px;
  border-block-start: 1px solid var(--line-soft);
  padding-block: 10px;
}
.glance-row:first-child { border-block-start: 0; padding-block-start: 2px; }
/* F206: a row CONTINUING its group (presentation.glance_groups) drops the
   rule and the lead-in, so the group reads as one block and the rule marks
   only the boundary between groups. */
.glance-row.glance-row-cont { border-block-start: 0; padding-block-start: 0; }
.glance-row:last-child { padding-block-end: 2px; }
/* F164: the outward-links block (official site …) sits apart from the fact
   rows above it. Only the first links row gets the extra lead-in. */
.glance-row:not(.glance-row-links) + .glance-row-links { padding-block-start: 18px; }
.glance-label { flex: none; font-size: var(--sb-label); font-weight: 700; color: var(--ink-3); }
.glance-value { font-size: var(--sb-value); font-weight: 700; color: var(--ink); }
.glance-value.glance-latin { text-align: left; letter-spacing: 0.01em; }
/* An emphasized numeric value (learning hours, …) is a STAT, not a link, so
   it takes the category accent inside a tinted pill rather than plain
   colored text — plain accent text next to real `<a>` pills in this same
   sidebar reads as another link. Linked values are actions → brand blue (v3). */
.glance-value-pill {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  padding: 3px 12px;
  border-radius: 999px;
  background: var(--c-tile);
  color: var(--type-color);
  font-size: var(--sb-value);
  font-weight: 800;
}
.glance-value a { color: var(--brand); }
/* GlanceTag: plain inline text, one value per line — the sidebar's own
   role for a multi-value fact (alternative names, platform list), distinct
   from the filled pill `.badge` wears in the article body, so one class
   name doesn't carry two unrelated looks depending on where it lands. */
.glance-tag { display: inline; }
a.glance-tag { color: var(--brand); }
a.glance-tag:hover { color: var(--brand-dark); }

/* PageToc — «در این صفحه» (scroll-spy adds .active) */
.doc-toc {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 14px 12px;
}
.doc-toc-overline {
  font-size: var(--sb-note);
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--ink-3);
  padding: 0 7px 8px;
  margin: 0;
}
.doc-toc ul { list-style: none; padding-inline-start: 0; margin: 0; display: flex; flex-direction: column; gap: 2px; }
.doc-toc li { margin: 0; }
.doc-toc a {
  display: block;
  padding: 8px 13px;
  border-radius: 9px;
  font-size: var(--sb-value);
  line-height: 1.6;
  color: var(--ink-3);
  transition: color 0.18s ease, background-color 0.18s ease;
  /* F134: one line per entry, always — short labels come from the framing
     engine; anything still longer ellipsizes instead of wrapping. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.doc-toc a:hover { color: var(--type-color); }
.doc-toc a.active { background: var(--c-panel); color: var(--type-color); font-weight: 700; }
/* Nested entries come from headings the author wrote INSIDE a section body,
   so there is no short label to fall back on the way a section has
   sec_toc_title — a one-line clamp would just lie about what the subsection
   says. They wrap to two lines instead. The section entries above them keep
   the one-line rule, because those DO carry an authored label. */
.doc-toc .toc-sub a {
  padding-inline-start: 26px;
  font-size: 13px;
  white-space: normal;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

/* Entity identity at the top of the FIRST sidebar card: the type pill as an
   eyebrow, the short content title under it at full card width, the English
   name last — always visible (the H1 carries the descriptive SEO title
   instead). column-reverse: the pill is LAST in the shared markup but reads
   first; a side-by-side layout crushed long guide titles against the pill. */
.sidebar-id {
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-start;
  gap: 7px;
  border-block-end: 1px solid var(--line-soft);
  padding-block-end: 10px;
  margin-block-end: 8px;
}
.sidebar-id:last-child { border-block-end: 0; padding-block-end: 2px; margin-block-end: 0; }
.doc-toc .sidebar-id { padding-inline: 7px; }
.sidebar-id-text { min-width: 0; align-self: stretch; }
.sidebar-title { font-size: var(--sb-title); font-weight: 800; color: var(--ink); line-height: 1.6; margin: 0; }
/* Right-aligned: in the identity block there are only the two titles (fa + en),
   so the English one hugs the same edge as the Persian title. (The career
   page's multi-name English list uses .glance-latin and stays left-aligned.) */
.sidebar-title-en {
  font-size: var(--sb-label);
  font-weight: 400;
  color: var(--ink-3);
  letter-spacing: 0.02em;
  text-align: right;
  line-height: 1.6;
  margin: 2px 0 0;
}
/* Content-type pill: the eyebrow above the title (see .sidebar-id). */
.sidebar-type {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--c-tile);
  color: var(--type-color);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 11.5px;
  font-weight: 800;
  line-height: 1.8;
  white-space: nowrap;
}
.sidebar-type-icon { width: 1.05em; height: 1.05em; flex: none; }
/* F162: the chip links to its type's listing; hover follows a.badge (tile
   pill deepens its text, no underline). */
a.sidebar-type { transition: color 0.18s ease; }
a.sidebar-type:hover { color: var(--c-dark); }

/* Article column */
.doc { display: flex; flex-direction: column; gap: 18px; min-width: 0; }

.doc-section {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 24px;
  padding: 26px 30px 28px;
  scroll-margin-block-start: calc(16px + var(--sticky-bars));
}

/* SectionTitle: 5×26 accent bar + h2.
   The second selector is the article-body panel (a type whose page is ONE
   authored body — guides): there the AUTHOR's own top-level headings are the
   sections, so they wear the same title. They sit one level deeper, inside the
   .richtext wrapper, which is why the rule is restated rather than loosened —
   `.doc-section > h2` stays direct-child on purpose, so an h2 inside a
   repeater item can never help itself to the accent bar. */
.doc-section > h2,
.doc-article-body .richtext > h2 {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 14px;
}
.doc-section > h2::before,
.doc-article-body .richtext > h2::before {
  content: '';
  width: 5px;
  height: 26px;
  border-radius: 3px;
  background: var(--type-color);
  flex: none;
}
.doc-section > h2, .doc-section > h3,
.doc-article-body .richtext > :is(h2, h3) { scroll-margin-block-start: calc(16px + var(--sticky-bars)); }

.doc-section > h3 { font-size: 16.5px; margin: 0 0 10px; }
.doc-section > * + h3 { margin-block-start: 20px; }

/* Every heading but the first opens a new block mid-panel, so it needs the
   space a section's own top padding gives the first one. (.richtext's
   :first-child rule already zeroes the top of the fragment.) */
.doc-article-body .richtext > * + h2 { margin-block-start: 34px; }

.doc-section p { font-size: 15.5px; color: var(--ink-body); line-height: 1.95; }

.richtext {
  font-size: 15.5px;
  color: var(--ink-body);
  line-height: 1.95;
  /* Contains the floated figures below. Without it a figure taller than the
     text beside it hangs out of the bottom of this box, and the panel's own
     border and background cut straight across the picture. Different fix from
     the `clear` on headings further down: that stops a float sliding under a
     heading INSIDE the prose, this stops it escaping the prose altogether. */
  display: flow-root;
}
.richtext :first-child { margin-block-start: 0; }
.richtext :last-child { margin-block-end: 0; }
/* An authored embed from a trusted FaraDars host (owner, 2026-09-08). The
   snippet the player hands an author already carries width="100%" and a pixel
   height, so this is not sizing it — it is stopping an embed pasted with a
   fixed pixel width from pushing the whole article sideways on a phone, which
   is the one way a third party's box can break this layout. */
.richtext iframe { display: block; max-width: 100%; border: 0; border-radius: 10px; }
/* Authored-prose subsections (owner 2026-08-04): a heading opens a new
   subsection, so it carries extra space ABOVE the 16px paragraph rhythm and
   stays tight to its own content below. All levels — the outline normalizer
   (shiftHeadings, F99) renders authored h2–h4 anywhere from h3 to h6
   depending on render depth. The :first-child rule above already zeroes the
   space at the top of a fragment. */
.richtext h2, .richtext h3, .richtext h4, .richtext h5, .richtext h6 { margin-block-start: 1.7em; }
/* F206: a 'blocks' richtext field (حوزه‌ها و رشته‌های تحصیلی …) — the authored
   headings are real subsection openers, so each takes the category marker and
   a hairline above it and stays tight to its own prose. The field reads as
   scannable blocks instead of one wall of text, and a value with no headings
   simply renders as ordinary prose. Levels h3–h5: shiftHeadings (F99)
   renumbers authored headings by render depth, so the same stored value can
   land on any of them. */
.richtext-blocks > :is(h3, h4, h5) {
  position: relative;
  margin-block: 0 6px;
  padding-inline-start: 15px;
  font-size: 15px;
  color: var(--ink);
}
.richtext-blocks > :is(h3, h4, h5)::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  inset-block: 0.22em 0.22em;
  width: 4px;
  border-radius: 999px;
  background: var(--type-color);
}
/* Every block after the first opens with a rule; the marker keeps hugging the
   TEXT, so it starts below that rule rather than spanning the gap. */
.richtext-blocks > * + :is(h3, h4, h5) { margin-block-start: 20px; padding-block-start: 20px; }
.richtext-blocks > * + :is(h3, h4, h5)::before { inset-block-start: calc(20px + 0.22em); }
.richtext-blocks > * + :is(h3, h4, h5)::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  inset-block-start: 0;
  height: 1px;
  background: var(--line-soft);
}

/* Inline prose links are ACTIONS → brand blue (v3), never category-colored. */
/* --- Authored images (owner, 2026-09-06) --------------------------------
   Stored as one flat <img>; the figure is built at render time by
   lib/html.ts renderRichtextImages. Centre is the DEFAULT and carries no
   modifier class, so the common case needs no rule beyond this one. */
.richtext .rt-figure {
  margin-block: 1.6em;
  /* The browser's own stylesheet gives <figure> `margin: 1em 40px`, and
     nothing here ever reset the inline half of it (owner, 2026-09-08). It went
     unseen for as long as the figure was shrink-to-fit: 40px of margin on each
     side merely made a natural-size picture narrower than the column, which
     looked like a deliberate inset. It stopped being invisible the moment the
     box was given a width — 100% plus two 40px margins is 80px wider than the
     column, so the figure slid off the end edge and left the gap it had taken
     from the start edge, which is what a phone showed as an image pushed off
     one side of the card.

     Reset here rather than at the breakpoint: the inset was never designed,
     and a picture at «اندازه اصلی» should meet the same edges the text does at
     every width. The `margin-inline: auto` further down still wins for a
     narrowed box, because that is a later rule at higher specificity. */
  margin-inline: 0;
  /* The figure is its own block; the image inside decides the width, so a
     portrait and a landscape both sit centred without a wrapper width. */
  display: flex;
  flex-direction: column;
  align-items: center;
}
.richtext .rt-figure img {
  max-width: 100%;
  height: auto;
  border-radius: 12px;
  display: block;
}
.richtext .rt-figure figcaption {
  margin-block-start: 0.7em;
  font-size: 13.5px;
  line-height: 1.75;
  color: var(--ink-3);
  text-align: center;
  /* A caption is a sentence about the picture, not a column of prose. */
  max-width: 56ch;
}

/* Alignment is stored LOGICALLY: on this RTL page «start» is the right edge,
   which is why the stored value is never left/right — the same document read
   in an LTR context would otherwise flip its layout silently. */
.richtext .rt-align-start,
.richtext .rt-align-end {
  max-width: 50%;
  margin-block: 0.4em;
}
.richtext .rt-align-start { float: inline-start; margin-inline-end: 1.4em; }
.richtext .rt-align-end { float: inline-end; margin-inline-start: 1.4em; }
.richtext .rt-align-start figcaption,
.richtext .rt-align-end figcaption { text-align: start; }
/* --- Display width: how wide the picture is DRAWN ------------------------
   A share of the text column, from the closed vocabulary in
   shared/image-display.ts. A CLASS and not an inline style, because the
   product surface serves `style-src 'self'` with no 'unsafe-inline' and would
   drop the attribute in silence.

   Written three classes deep so an explicit width beats the 50% a float sets
   for itself two classes up — otherwise asking for a quarter-width floated
   image would quietly get you half. */
.richtext .rt-figure.rt-w-25 { max-width: 25%; }
.richtext .rt-figure.rt-w-50 { max-width: 50%; }
.richtext .rt-figure.rt-w-75 { max-width: 75%; }
.richtext .rt-figure.rt-w-100 { max-width: 100%; }
/* The BOX is what narrowed; the image has to follow it or it overflows the
   box it was just told to fit in. */
.richtext .rt-figure[class*="rt-w-"] img { width: 100%; }
/* A narrowed block box sits at the start edge on its own — `align-items` only
   centres the contents WITHIN the box, which is invisible until a width class
   makes the box narrower than the column. Not for a floated figure: there the
   auto margin would compute to zero anyway, but it would first overwrite the
   1.4em gutter the float sets against the text. */
.richtext .rt-figure[class*="rt-w-"]:not(.rt-align-start):not(.rt-align-end) {
  margin-inline: auto;
}

/* A float has no height, so a short paragraph beside a tall image would let
   the next heading ride up alongside it. */
.richtext h2, .richtext h3, .richtext h4, .richtext h5, .richtext h6 { clear: both; }

/* A floated image in a phone-width column leaves a 2-word text gutter, which
   reads as broken rather than as a layout. Below the breakpoint every image
   is full width and centred — the alignment is a desktop refinement, not a
   promise. (mobile-first: checked at 400px) */
@media (max-width: 640px) {
  .richtext .rt-align-start,
  .richtext .rt-align-end {
    float: none;
    max-width: 100%;
    margin-inline: 0;
    align-items: center;
  }
  .richtext .rt-align-start figcaption,
  .richtext .rt-align-end figcaption { text-align: center; }
  /* And a quarter-width picture on a phone is a thumbnail nobody can see, so
     the width steps collapse with the floats.
     `[class*="rt-w-"]` is not decoration here: the per-step rules above are
     (0,3,0), so a plainer selector would lose to them and the step would
     survive the breakpoint.
     (mobile-first: checked at 400px) */
  .richtext .rt-figure,
  .richtext .rt-figure[class*="rt-w-"] { max-width: 100%; width: 100%; }
  /* Every content image fills the column, whatever width it was given —
     including «اندازه اصلی», which stores nothing and is therefore the common
     case (owner, 2026-09-08). Measured at a 390px viewport: the column is
     298px and a figure with no step rendered at its source's own 218px,
     leaving a margin down one side that reads as a mistake rather than as a
     layout. The steps already collapsed here; the DEFAULT did not.

     `width` and not just `max-width`, because the gap is an image SMALLER
     than the column, and only `width` grows it. The cost is that a genuinely
     tiny source is now scaled up and will look soft — on a phone a picture
     that does not reach the edges reads as broken, and that was the call. */
  .richtext .rt-figure img,
  .doc-cover img,
  .field-figure img { width: 100%; height: auto; }
}

.richtext a { color: var(--brand); font-weight: 700; }
.richtext a:hover { color: var(--brand-dark); }

.doc-cover { margin: 14px 0 0; }
.doc-cover img { border-radius: 16px; display: block; }

/* --- Item lists ------------------------------------------------------------
   The general titled-point component (duties, highlights, applications, key
   features, use cases, …): a 7px accent dot, a bold title, a quiet body.
   Column layout comes from a modifier: .cols-2 / .cols-3 (default: one
   column); all collapse to one column on narrow viewports. */
.item-list {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px 26px;
}
.item-list.cols-2 { grid-template-columns: 1fr 1fr; }
.item-list.cols-3 { grid-template-columns: 1fr 1fr 1fr; }
@media (max-width: 48rem) {
  .item-list.cols-2, .item-list.cols-3 { grid-template-columns: 1fr; }
}
.doc-section > * + .item-list { margin-block-start: 16px; }
.item-list .item {
  position: relative;
  min-width: 0;
  padding-inline-start: 17px;
  margin: 0;
  font-size: 14.5px;
  color: var(--ink-body);
  line-height: 1.85;
}
.item-list .item::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 10px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--type-color);
}
.item-title { font-size: 15.5px; font-weight: 800; margin: 0; line-height: 1.6; }
.item-body { font-size: 14px; color: var(--ink-3); margin: 2px 0 0; line-height: 1.85; }

/* Generic field-renderer content inside an .item (field.njk's object_list
   dispatch emits a plain p.item-title/p/.richtext, not real headings — a
   repeated bullet title is a list-item label, not a document subsection, so
   it stays out of the heading outline. Same visual weight as the
   hand-authored item-title/item-body classes, so a generic and a bespoke
   dot-list are indistinguishable. Scoped to the item-list-generic marker
   (not bare .item-list) so it can never out-specificity .item-title/
   .item-body on the hand-authored dot-lists. */
.item-list-generic .item .item-title { margin: 0 0 4px; }
.item-list-generic .item p, .item-list-generic .item .richtext { font-size: 14px; color: var(--ink-3); line-height: 1.85; }
.item-list-generic .item > :last-child { margin-block-end: 0; }
/* Real sub-heading item labels (h3/h4 with .item-heading — the ordered rail
   and the 'titled' presentation, F99/F120). */
.item-list .item .item-heading { font-size: 15.5px; font-weight: 800; margin: 0 0 4px; line-height: 1.6; }
/* 'titled' lists (گرایش‌ها …): the title IS the point — one notch larger,
   with the body kept quiet under it. */
.item-list-titled { gap: 16px 26px; }
.item-list-titled .item .item-heading { font-size: 16.5px; }
.item-list-titled .item p { font-size: 14.5px; }

/* 'cards' lists (دانشکده‌ها …): a ROSTER of named units — the names are what
   the reader scans, so the items become a self-sizing card grid instead of
   one tall bullet column. The card replaces the bullet dot; the family tint
   ties the roster to the type without repeating the accent 20 times. An item
   that carries only a name still reads as a complete card. */
.item-list-cards {
  grid-template-columns: repeat(auto-fit, minmax(238px, 1fr));
  gap: 12px;
}
.item-list-cards .item {
  padding: 13px 15px 14px;
  background: var(--c-wash);
  border: 1px solid var(--c-border);
  border-radius: 14px;
}
.item-list-cards .item::before { content: none; }
.item-list-cards .item .item-heading { font-size: 15px; line-height: 1.65; }
.item-list-cards .item p { margin: 5px 0 0; font-size: 13.5px; line-height: 1.8; color: var(--ink-3); }

/* 'counterpoint' lists (نکاتی که باید بسنجید …): the SECOND of two sibling
   lists in one section, which otherwise wear identical dots under different
   headings. The list sits in a tinted block — the same two-sided reading the
   deck gets from its compare columns, in one column — instead of a marker
   tweak that vanishes at 7px. A tint, not a ✓/✗ pair: these are points to
   weigh, not defects. */
.item-list-counterpoint {
  background: var(--c-wash);
  border: 1px solid var(--c-border);
  border-radius: 16px;
  padding: 15px 18px 16px;
}

/* Plain string bullets (سایر پیش‌نیازها …) share the dot treatment. */
.prereq-list {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.prereq-list li {
  position: relative;
  padding-inline-start: 17px;
  margin: 0;
  font-size: 14.5px;
  color: var(--ink-body);
  line-height: 1.85;
}
.prereq-list li::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 11px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--type-color);
}

/* Checklists (single-text repeaters) — ✓ marks, no ordering implied. */
.checklist {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.checklist li {
  position: relative;
  padding-inline-start: 26px;
  margin: 0;
  font-size: 15px;
  color: var(--ink-body);
  line-height: 1.85;
}
.checklist li::before {
  content: '✓';
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0;
  font-weight: 800;
  color: var(--type-color, var(--brand));
}

/* Small label over a badge/list group inside repeater items (e.g. per-stage
   skills vs tools) — distinguishes adjacent same-shaped groups. */
.field-mini-label {
  margin: 10px 0 4px;
  font-size: 12.5px;
  font-weight: 800;
  color: var(--ink-3);
}
.learning-step .field-mini-label:first-child { margin-block-start: 0; }

/* Muted one-line intro directly under a section heading (learning-hours
   hint, legacy panel-questions intro). */
.section-intro {
  margin: -2px 0 14px;
  font-size: 14px;
  color: var(--ink-3);
  line-height: 1.9;
}
/* F124: section LEAD — the connective sentence between a section heading and
   its structured contents (framing engine + owner-authored intros). Same
   type family as body prose, visually subordinate to the h2, readable
   measure, no cards/icons/decoration. */
.section-lead {
  margin: -4px 0 16px;
  font-size: 14.5px;
  color: var(--ink-2);
  line-height: 1.95;
  max-width: 70ch;
}
/* F81: checklist lead-in sits mid-section, so it drops the pull-up margin. */
.checklist-intro { margin: 0 0 12px; }
/* F87: alternative-names block inside #sec-intro (career pages). */
.alt-names-lead { margin-block-start: 14px; }
.alt-names-list { margin-block-start: 10px; }

/* Fact tiles (generic renderer key data). */
.fact {
  display: inline-flex;
  flex-direction: column;
  vertical-align: top;
  padding: 8px 16px 9px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  margin-inline-end: 10px;
  margin-block-end: 12px;
}
.fact-row { display: flex; flex-wrap: wrap; gap: 10px; margin-block-end: 18px; }
/* Learning-path closing total (glance goal 2026-08-04): the timeline's
   terminal node — same marker/card/header anatomy as the steps above it, a
   clock in the marker instead of a step number, the qualifier sentence as
   the card body at full width. The emphasized time chip marks it as the
   summary of the per-step chips. */
.learning-path-total { position: relative; padding-inline-start: 58px; margin-block-start: 28px; }
.learning-path-total .learning-step-marker { inset-block-start: 12px; }
.learning-total-icon { width: 20px; height: 20px; }
.learning-total-title { margin: 0; color: var(--ink); font-size: 16px; font-weight: 900; line-height: 1.55; }
.learning-path-total .learning-step-time {
  background: transparent;
  border-color: var(--c-chip);
  color: var(--type-color);
  font-size: 13px;
  font-weight: 800;
}
.learning-hours-note { margin: 0; font-size: 13.5px; color: var(--ink-3); line-height: 1.9; }
/* The rail runs on from the last step into the total node (progressive
   enhancement — without :has() the rail simply ends at the last step). */
.doc-section:has(.learning-path-total) .learning-path-unified .learning-step:last-child::after {
  display: block;
  inset-block-end: -40px;
}
.fact-row .fact { margin: 0; }
.fact-label { font-size: 12.5px; line-height: 1.7; color: var(--ink-3); }
.fact-value { font-size: 15.5px; line-height: 1.7; font-weight: 700; color: var(--ink); }
.fact-value a { color: var(--brand); }

/* Steps — accent-filled number discs on a vertical rail. */
.learning-steps {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  counter-reset: learning-step;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.learning-step {
  counter-increment: learning-step;
  position: relative;
  padding-inline-start: 46px;
  margin: 0;
}
.learning-step::before {
  content: counter(learning-step, fa-decimal);
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 2px;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--type-color);
  color: var(--c-on);
  font-weight: 800;
  font-size: 14px;
  line-height: 1;
  box-shadow: 0 0 0 3px var(--c-panel);
}
/* The rail connecting each disc to the next (spans the flex gap). */
.learning-step::after {
  content: '';
  position: absolute;
  inset-inline-start: 15px;
  inset-block-start: 40px;
  inset-block-end: -15px;
  width: 2px;
  border-radius: 999px;
  background: var(--c-border);
}
.learning-step:last-child::after { display: none; }
/* h3 OR h4 — the item heading level follows the outline (F99). */
.learning-step h3, .learning-step h4 { font-size: 15.5px; font-weight: 800; margin: 0 0 4px; line-height: 1.6; }
.learning-step p, .learning-step .richtext { font-size: 14px; color: var(--ink-3); line-height: 1.85; }
.learning-step > :last-child { margin-block-end: 0; }

/* Hours chip on the step title row: a quiet outlined pill in the family. */
.step-hours-chip {
  display: inline-block;
  margin-inline-start: 8px;
  padding: 0 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.9;
  background: var(--surface);
  border: 1px solid var(--c-border);
  color: var(--c-dark);
  vertical-align: 0.12em;
  white-space: nowrap;
}
p.step-hours-chip { margin: 0 0 4px; }

.section-meta { color: var(--ink-3); font-size: 14px; margin: -6px 0 16px; }

/* --- Related groups: destination-colored panels of compact cards ---------- */

.relation-group {
  background: var(--c-panel);
  border-radius: 18px;
  padding: 14px;
}
.doc-section .relation-group + .relation-group,
.doc-section * + .relation-group { margin-block-start: 12px; }
.relation-group-head { display: flex; align-items: center; gap: 10px; margin-block-end: 10px; }
.relation-group-icon {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: var(--c-tile);
  color: var(--type-color);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.relation-group-icon svg { width: 18px; height: 18px; }
.relation-group-title { font-size: 16px; font-weight: 800; color: var(--ink); margin: 0; line-height: 1.6; }

.relation-cards {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(13rem, 100%), 1fr));
  gap: 10px;
}
.relation-cards li { margin: 0; }
.relation-cards .relation-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  height: 100%;
  background: var(--surface);
  border: 1px solid var(--c-border);
  border-radius: 12px;
  padding: 12px 14px;
  color: var(--ink);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.relation-cards .relation-card:hover {
  border-color: var(--c-chip);
  box-shadow: 0 8px 18px var(--c-shadow);
  transform: translateY(-2px);
  color: var(--ink);
  background: var(--surface);
}
.relation-cards .relation-card-title { font-size: 15px; font-weight: 800; line-height: 1.5; }
.relation-cards .relation-card-summary { font-size: 12.5px; }
.relation-card-kind {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  font-weight: 800;
  line-height: 1.6;
  color: var(--type-color);
}
.relation-card-kind-icon { width: 14px; height: 14px; flex: none; }

/* Mixed lists (backlinks): each row carries its own category family — a soft
   tile icon (`c-tile` fill + `type-color` glyph, unlike the solid-fill tiles
   above) plus a stacked kind/title/latin text block.
   F135: a responsive GRID (two columns on desktop article widths, one on
   narrow screens) — a single full-width column wasted half the line. */
.relation-rows {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(21rem, 100%), 1fr));
  gap: 12px;
}
.relation-rows li { margin: 0; }
.relation-row {
  display: flex;
  align-items: center;
  gap: 14px;
  background: var(--surface);
  border: 1px solid var(--c-border);
  border-radius: 16px;
  padding: 14px 20px;
  color: var(--ink);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.relation-row:hover {
  border-color: var(--c-chip);
  box-shadow: 0 8px 18px var(--c-shadow);
  transform: translateY(-2px);
  color: var(--ink);
}
/* F149/F151: the shared TYPE CHIP in the leading slot — one identity
   component for relation rows, related items and explore results. ICON
   only (F151: visible names disrupted rows); the type name rides as sr-only
   text + a native title tooltip. */
.type-chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 12px;
  background: var(--c-tile);
  color: var(--type-color);
}
.type-chip-icon { display: block; width: 20px; height: 20px; flex: none; }

.relation-row-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.relation-row-title { font-size: 15.5px; font-weight: 700; line-height: 1.6; color: var(--ink); }
.relation-row-latin { align-self: stretch; font-size: 13px; font-weight: 400; color: var(--ink-3); letter-spacing: 0.02em; text-align: right; }
/* F100 (2026-08-02): the Latin title stays OFF (the markup still ships it —
   restoring it is deleting this line). The kind label returned inside the
   type chip (F149). */
.relation-row-latin { display: none; }
.relation-row-chevron { width: 17px; height: 17px; flex: none; color: var(--chev); }

/* --- External reference / resource cards ----------------------------------- */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(14.5rem, 100%), 1fr));
  gap: 10px;
}
ul.cards { list-style: none; padding-inline-start: 0; margin: 0; }
.cards > li { margin: 0; }

.card, .ref-card {
  display: block;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 14px;
  color: var(--ink);
  transition: border-color 0.18s ease, box-shadow 0.18s ease, color 0.18s ease;
}
a.card:hover, a.ref-card:hover {
  border-color: var(--c-chip);
  box-shadow: 0 8px 18px var(--c-shadow);
  color: var(--ink);
}
.ref-card { display: flex; align-items: center; gap: 12px; }
.ref-card-thumb { inline-size: 72px; block-size: auto; border-radius: 8px; flex-shrink: 0; }
.ref-card-title { font-weight: 700; font-size: 14.5px; line-height: 1.7; }

/* Resource rows: kind icon in the category tile, title over a quiet meta line
   (kind · domain), external-link mark at the inline-end. */
.resource-list {
  list-style: none;
  padding-inline-start: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr));
  gap: 10px;
}
.resource-list > li { margin: 0; }
.resource-card {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 100%;
  padding: 10px 14px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 12px;
  color: var(--ink);
  transition: border-color 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease;
}
a.resource-card:hover {
  color: var(--ink);
  border-color: var(--c-chip);
  background: var(--c-wash);
  box-shadow: 0 8px 18px var(--c-shadow);
}
.resource-icon {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--c-tile);
  color: var(--type-color);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.resource-icon svg { width: 17px; height: 17px; }
/* Featured image of the linked page, in the same leading slot as the icon
   tile. F105/F194: EVERY link thumbnail renders square (1:1, CSS crop) —
   external resources match the FaraDars rows; row height stays text-driven. */
.resource-thumb {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  object-fit: cover;
  background: var(--c-tile);
  flex: none;
}
.resource-text { flex: 1; min-width: 0; }
.resource-card-title {
  display: block;
  font-weight: 700;
  font-size: 14.5px;
  line-height: 1.7;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
a.resource-card:hover .resource-card-title { color: var(--type-color); }
.resource-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  line-height: 1.7;
  color: var(--ink-3);
  min-width: 0;
}
.resource-meta > * + *::before { content: '·'; margin-inline-end: 6px; color: var(--ink-4); }
.resource-kind { flex: none; }
.resource-domain { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; letter-spacing: 0.01em; }
.resource-ext-icon {
  inline-size: 15px;
  block-size: 15px;
  flex: none;
  color: var(--ink-4);
  transition: color 0.18s ease;
}
a.resource-card:hover .resource-ext-icon { color: var(--type-color); }

/* --- Badges ---------------------------------------------------------------- */

.badges { display: flex; flex-wrap: wrap; gap: 8px; margin-block-end: 14px; }
.badges:last-child { margin-block-end: 0; }
.badges + .badges { margin-block-start: -6px; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  font-weight: 800;
  line-height: 1.8;
  padding: 3px 12px;
  border-radius: 999px;
  background: var(--c-tile);
  color: var(--type-color);
  max-width: 100%;
}
.badge-icon { width: 0.95em; height: 0.95em; flex: none; }
/* F183: the icon a linkified raw URL carries (lib/html.ts linkifyUrls via
   the `linkify` filter) — trails the compact host text inside prose. */
.linkified-ext-icon { width: 0.8em; height: 0.8em; vertical-align: -0.08em; margin-inline-start: 4px; }

.badge-neutral { background: var(--sand); color: var(--ink-2); }

/* Tiered scales run low → high; the hue carries the meaning (v3 families:
   green / blue / terracotta working accents on their tile tints). */
.badge-tone-good { background: #d1f1e3; color: #16775a; }
.badge-tone-mid { background: #d2ecff; color: #1a6d9e; }
.badge-tone-attn { background: #ffe0d7; color: #a74932; }
a.badge-tone-good:hover { color: #066148; }
a.badge-tone-mid:hover { color: #0c5983; }
a.badge-tone-attn:hover { color: #8b3925; }

.badge-outline { background: transparent; color: var(--ink-3); border: 1px solid var(--line-strong); font-weight: 700; }

a.badge { transition: color 0.18s ease, background-color 0.18s ease; }
a.badge:hover { color: var(--c-dark); }

.badge-link {
  background: var(--surface);
  border: 1px solid var(--c-chip);
  color: var(--type-color);
  font-weight: 700;
  transition: border-color 0.18s ease;
}
.badge-link:hover { border-color: var(--type-color); color: var(--type-color); }

.badge-hours { background: var(--c-tile); color: var(--type-color); }

/* CategoryChip on search rows & suggest items — a flat tile pill, no dot. */
.badge-type {
  background: var(--c-tile);
  color: var(--type-color);
  font-size: 11.5px;
  padding: 2px 10px;
  flex: none;
}

/* --- Search page ------------------------------------------------------------ */

.search-head .container { padding-block: 26px; }
.search-head h1 { font-size: 26px; letter-spacing: -0.01em; margin: 0; }

/* F153: buttonless sidebar query box — Enter submits. The decorative
   magnifier is PREPENDED at the inline START (physical RIGHT on this RTL
   site); the functional ✕ is APPENDED at the inline end — the two never
   share a corner. The input's own WebKit cancel button is suppressed (it
   rendered at the same end as the ✕ and collided with it). */
.search-box { position: relative; }
.search-box input[type='search'] {
  /* The clearance the prepended magnifier and the appended clear control
     need, said as the shared field-padding tokens (assets/masir.css) —
     that sheet loads last and owns field geometry, and its generic rule
     is more specific than this selector, so a plain padding here never
     survived and both glyphs sat on top of the reader's own text. */
  --field-pad-start: 40px;
  --field-pad-end: 38px;
}
.search-box input[type='search']::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.search-box-icon {
  position: absolute;
  inset-inline-start: 13px;
  inset-block-start: 50%;
  translate: 0 -50%;
  display: inline-flex;
  color: var(--ink-4);
  pointer-events: none;
}
.search-box-icon svg { width: 16px; height: 16px; }
/* The ✕ clears the query and keeps the filter state (explore sidebar);
   hover turns red — it reads as the small destructive action it is. */
.search-box-clear {
  position: absolute;
  inset-inline-end: 13px;
  inset-block-start: 50%;
  translate: 0 -50%;
  display: inline-flex;
  padding: 4px;
  color: var(--ink-3);
  transition: color 0.18s ease;
}
.search-box-clear:hover { color: #b5473c; }
.search-box-clear svg { width: 14px; height: 14px; }
/* (The search-meta count LINE retired 2026-08-03 — the state-driven h1
   names the query/scope; the same day's UI audit (C1) put the total back as
   the shared F127 count-chip beside the h1, matching the static listing
   heads. FilterTabs retired with F132 — the type facet lives in the shared
   filter sidebar as multi-select pills.) */

/* F129: secondary clear-query action under the primary clear-all. */
.filter-clear-query {
  display: inline-flex;
  align-items: center;
  margin-block-start: 8px;
  align-self: flex-start;
  color: var(--ink-3);
  font-size: 12.5px;
  font-weight: 700;
  transition: color 0.18s ease;
}
.filter-clear-query:hover { color: var(--ink); }

/* F132: pagination centers under the RESULTS column (search + listings). */
.listing-main .pager { justify-content: center; }
.listing-main .pager, .listing-main .search-pagination { margin-block-end: 8px; }

/* F145: even container inset all around; each row is ONE flex line — chip ·
   stacked text · chevron — with the chevron centered against the whole row.
   Rows breathe around the hairline: 4px padding + 4px margin on each side of
   every separator, so the rounded hover highlight floats clear of the lines
   instead of touching them; the highlight itself is the row type's wash tint
   (data-cat family), not a flat neutral. */
.search-results {
  list-style: none;
  padding: 8px;
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
}
.search-result { margin: 0; }
.search-result + .search-result {
  margin-block-start: 4px;
  padding-block-start: 4px;
  border-block-start: 1px solid var(--line-soft);
}
.search-result-link {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px;
  border-radius: 12px;
  color: inherit;
  transition: background-color 0.15s ease;
}
.search-result-link:hover { background: var(--c-wash); color: inherit; }
.search-result-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
/* F132: quieter row — the chip identifies, the title carries, the snippet
   stays plain text (no highlight fragments). */
.search-result-title { font-size: 15.5px; font-weight: 700; color: var(--ink); line-height: 1.6; }
.search-result-chevron { width: 13px; height: 13px; flex: none; color: var(--chev); }
.search-snippet {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin: 0;
  color: var(--ink-3);
  font-size: 13.5px;
  line-height: 1.8;
  max-width: 920px;
}

/* Empty state — always offers a next step. */
.empty-state {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 36px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  text-align: center;
}
.empty-icon {
  width: 58px;
  height: 58px;
  border-radius: 50%;
  background: var(--sand);
  color: var(--ink-4);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.empty-icon svg { width: 24px; height: 24px; }
.empty-title { font-size: 17.5px; font-weight: 800; color: var(--ink); }
.empty-body { font-size: 14px; color: var(--ink-3); max-width: 420px; line-height: 1.85; }
.empty-links { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: center; margin-block-start: 6px; }
.empty-links-label { font-size: 13px; color: var(--ink-3); }
.empty-links a {
  background: var(--paper);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 13.5px;
  color: var(--ink-body);
  transition: color 0.18s ease, border-color 0.18s ease;
}
.empty-links a:hover { border-color: var(--type-color); color: var(--type-color); }

/* --- Search suggest dropdown (site.js) -------------------------------------- */

/* F128: a proper suggestion PANEL — wider than its input when the viewport
   allows (site.js clamps it inside the viewport), quiet separated rows,
   scrolling list, full-width footer action. Anchored at the input's
   inline-start edge and growing toward inline-end. */
.search-suggest {
  position: absolute;
  inset-block-start: calc(100% + 10px);
  inset-inline-start: 0;
  width: min(33rem, calc(100vw - 24px));
  min-width: 100%;
  z-index: 60; /* F148: above result lists and sticky chrome */
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  box-shadow: 0 28px 60px rgba(36, 35, 33, 0.14);
  padding: 8px;
}
@media (max-width: 48rem) {
  /* Phones (and the filter drawer): span the form — the form itself is
     near-full-width there. */
  .search-suggest { width: 100%; }
}
.search-suggest ul { list-style: none; margin: 0; padding: 0; max-height: min(24rem, 60vh); overflow-y: auto; }
.search-suggest li { margin: 0; }

.suggest-item a {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 12px;
  border-radius: 11px;
  color: var(--ink);
  transition: background-color 0.15s ease;
}
.suggest-item a:hover, .suggest-item a.active { background: var(--c-wash); color: var(--ink); }
/* Hairline separators between rows (F128) — cheap to scan. */
.suggest-item + .suggest-item a { border-start-start-radius: 0; border-start-end-radius: 0; }
.suggest-item + .suggest-item { border-block-start: 1px solid var(--line-soft); }

/* The Persian type badge leads the row (no icons, F128). */
.suggest-type { flex: none; }

.suggest-text { flex: 1; min-width: 0; }
.suggest-title {
  display: block;
  font-weight: 700;
  font-size: 15px;
  line-height: 1.6;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.suggest-summary {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12.5px;
  line-height: 1.8;
  color: var(--ink-3);
}
.suggest-chevron { width: 12px; height: 12px; flex: none; color: var(--chev); }

.suggest-empty { padding: 12px 14px; color: var(--ink-3); font-size: 14px; }

.suggest-item .suggest-footer {
  display: flex;
  align-items: center;
  justify-content: center; /* F128: one clear, full-width closing action */
  gap: 8px;
  padding: 12px 14px 9px;
  margin-block-start: 6px;
  border-block-start: 1px solid var(--line);
  border-radius: 0 0 10px 10px;
  color: var(--brand);
  font-weight: 700;
  font-size: 14px;
  transition: background-color 0.15s ease;
}
.suggest-item .suggest-footer:hover, .suggest-item .suggest-footer.active { background: var(--sand); color: var(--brand); }

/* --- Empty listing / generic states ---------------------------------------- */

.empty-note { color: var(--ink-3); text-align: center; padding-block: 40px; }

/* --- Error pages (404/410) --------------------------------------------------- */

.error-page {
  max-width: 560px;
  margin-inline: auto;
  text-align: center;
  padding-block: 56px 40px;
}
.error-code { font-size: 56px; font-weight: 800; color: var(--type-color); margin: 0; line-height: 1.2; }
.error-page h1 { font-size: 26px; margin-block: 8px 10px; }
.error-page p { color: var(--ink-3); }

/* --- Heading anchors (toc.js) ------------------------------------------------ */

.heading-anchor {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4em;
  height: 1.4em;
  margin-inline-start: 4px;
  vertical-align: middle;
  color: var(--ink-4);
  border-radius: 7px;
  opacity: 0;
  transition: opacity 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}
/* Inside the flex section heading the 12px gap already separates it — pull it
   back so the anchor sits right beside the text. */
.doc-section > h2 > .heading-anchor,
.doc-article-body .richtext > h2 > .heading-anchor { margin-inline-start: -8px; }
.doc-section > h2:hover .heading-anchor,
.doc-section > h3:hover .heading-anchor,
.doc-article-body .richtext > h2:hover .heading-anchor,
.doc-article-body .richtext > h3:hover .heading-anchor,
.heading-anchor:focus-visible { opacity: 0.7; }
.heading-anchor:hover { opacity: 1; color: var(--type-color); background: var(--c-wash); }
.heading-anchor svg { width: 0.75em; height: 0.75em; }
.heading-anchor.copied { opacity: 1; color: var(--type-color); }
/* Hover tooltip: tells the reader the anchor copies the section link.
   Pure CSS (::after over the anchor), so it needs no JS and never blocks
   the click. Hidden again while .copied so it does not fight the feedback
   state, and suppressed on touch-only devices where hover is sticky. */
.heading-anchor { position: relative; }
.heading-anchor::after {
  content: 'کپی لینک این بخش';
  position: absolute;
  bottom: calc(100% + 7px);
  inset-inline-start: 50%;
  translate: 50% 0; /* RTL page: physical +x shift centers the bubble */
  background: var(--ink);
  color: var(--paper);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  padding: 6px 10px;
  border-radius: 7px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.15s ease 0.15s;
  z-index: 5;
}
.heading-anchor.copied::after { content: 'کپی شد!'; }
@media (hover: hover) {
  .heading-anchor:hover::after,
  .heading-anchor:focus-visible::after,
  .heading-anchor.copied::after { opacity: 1; visibility: visible; }
}

/* --- Return-to-top (site.js) -------------------------------------------------- */

.to-top {
  position: fixed;
  inset-block-end: 20px;
  inset-inline-end: 20px;
  z-index: 40;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-3);
  box-shadow: 0 6px 20px rgba(36, 35, 33, 0.12);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s 0.2s;
}
.to-top.visible { opacity: 1; visibility: visible; transform: none; transition: opacity 0.2s ease, transform 0.2s ease; }
.to-top:hover { border-color: var(--brand); color: var(--brand); }
.to-top svg { width: 20px; height: 20px; }

/* --- Generic field renderer leftovers ---------------------------------------- */

.field-row { margin-block: 0 0.5rem; }
.field-label { color: var(--ink-3); font-weight: 700; margin-inline-end: 0.25rem; }

.obj-group {
  border-inline-start: 3px solid var(--line-strong);
  padding-inline-start: 1rem;
  margin-block: 0.75rem 1rem;
}
.obj-group > :last-child { margin-block-end: 0; }

.swatch {
  display: inline-block;
  inline-size: 1em;
  block-size: 1em;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  vertical-align: -0.15em;
  margin-inline-end: 0.25rem;
}

.field-figure { margin: 0 0 1rem; }
.field-figure img { border-radius: 12px; display: block; }
.field-figure figcaption { color: var(--ink-3); font-size: 0.85rem; margin-block-start: 0.35rem; }
.field-video video { width: 100%; height: auto; border-radius: 12px; display: block; background: #000; }

.gallery { margin-block-end: 1rem; }
.gallery .field-figure { margin: 0; }
.gallery img { inline-size: 100%; object-fit: cover; }

.embed-frame { aspect-ratio: 16 / 9; margin-block-end: 1rem; border-radius: 12px; overflow: hidden; background: var(--ink); }
.embed-frame iframe { inline-size: 100%; block-size: 100%; border: 0; display: block; }
.embed-caption { color: var(--ink-3); font-size: 0.9rem; margin-block: -0.5rem 1rem; }

.field-file .file-link { font-weight: 700; color: var(--brand); }
.file-size { color: var(--ink-3); font-size: 0.85rem; }

/* Unified content patterns ------------------------------------------------ */

/* Authored tables (F159) — bordered, tinted header, zebra body, in the same
   soft-rounded language as the rest of the system. The .table-scroll wrapper
   is added at render time (wrap_tables filter) so a wide table scrolls
   inside its own box instead of clipping or panning the page. */
.table-scroll {
  margin: 18px 0;
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
}
.richtext table {
  width: 100%;
  margin: 0;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 14px;
  line-height: 1.85;
}
.richtext th,
.richtext td {
  padding: 10px 14px;
  text-align: start;
  vertical-align: top;
  min-width: 9rem;
  border-block-start: 1px solid var(--line-soft);
}
.richtext th + th,
.richtext td + td { border-inline-start: 1px solid var(--line-soft); }
/* Header row: the type's tile tint — the same accent family the page wears. */
.richtext thead th {
  background: var(--c-tile);
  color: var(--c-dark);
  font-weight: 700;
  border-block-start: 0;
  white-space: nowrap;
}
.richtext tbody tr:first-child > * { border-block-start: 0; }
.richtext thead + tbody tr:first-child > * { border-block-start: 1px solid var(--line-soft); }
/* Zebra rows keep long comparison tables scannable. */
.richtext tbody tr:nth-child(even) { background: var(--c-wash); }
.richtext td p, .richtext th p { margin: 0; }

/* A plain emphasis box, not a quotation — flat solid background, one plain
   border, no accent bar, no shadow, no quote mark. */
.richtext blockquote {
  margin: 20px 0;
  padding: 16px 20px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 14px;
  color: var(--ink-body);
}
.richtext blockquote > :last-child { margin-block-end: 0; }

.checklist { gap: 10px; }
.checklist li {
  padding: 12px 46px 12px 16px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 14px;
}
.checklist li::before {
  inset-inline-start: 14px;
  inset-block-start: 13px;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  background: var(--c-tile);
  font-size: 13px;
}

.doc-section > .relation-rows + .prereq-list,
.doc-section > .relation-rows + .badges { margin-block-start: 26px; }

.learning-path-unified { gap: 22px; }
.learning-path-unified .learning-step {
  position: relative;
  padding: 0;
  padding-inline-start: 58px;
  background: transparent;
  border: 0;
  border-radius: 0;
}
.learning-path-unified .learning-step::before { content: none; display: none; }
.learning-path-unified .learning-step::after {
  inset-inline-start: 19px;
  inset-block-start: 58px;
  inset-block-end: -28px;
  width: 2px;
  background: var(--c-border);
}
/* The circled number is the ONLY step indicator — no repeated "step N" text
   alongside it, and no shadow at rest (flat, in line with the rest of the
   system); only a plain ring keeps it legible against the card edge. */
.learning-step-marker {
  position: absolute;
  z-index: 2;
  inset-inline-start: 0;
  inset-block-start: 17px;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 4px solid var(--paper);
  border-radius: 50%;
  background: var(--type-color);
  color: var(--c-on);
  box-shadow: 0 0 0 3px var(--c-panel);
  font-size: 14px;
  font-weight: 900;
  line-height: 1;
}
.learning-step-card {
  overflow: hidden;
  border: 1px solid var(--c-border);
  border-radius: 20px;
  background: var(--surface);
  transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}
.learning-step-card:hover {
  border-color: var(--c-chip);
  box-shadow: 0 8px 20px var(--c-shadow);
  transform: translateY(-2px);
}
.learning-step-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 20px 14px;
  border-block-end: 1px solid var(--c-border);
}
.learning-step-heading { min-width: 0; }
.learning-path-unified .learning-step h3,
.learning-path-unified .learning-step h4 {
  margin: 0;
  color: var(--ink);
  font-size: 17px;
  font-weight: 900;
  line-height: 1.55;
}
.learning-step-time {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  flex: none;
  padding: 5px 11px;
  border: 1px solid var(--c-border);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-3);
  font-size: 12px;
  white-space: nowrap;
}
.learning-step-content { padding: 16px 20px 18px; }
.learning-step-content > :first-child { margin-block-start: 0; }
.learning-step-content > :last-child { margin-block-end: 0; }
.learning-step-content .richtext { color: var(--ink-body); }
.learning-step-content .field-mini-label {
  margin-block: 14px 5px;
  color: var(--ink-2);
  font-size: 12.5px;
}
.learning-step-content .relation-pills { margin-block: 4px 10px; }

.relation-pills { display: flex; flex-wrap: wrap; gap: 7px; margin-block: 8px 12px; }
.relation-pill {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  padding: 3px 10px;
  border: 1px solid var(--c-border);
  border-radius: 999px;
  background: var(--c-tile);
  color: var(--type-color);
  font-size: 12.5px;
  font-weight: 800;
}
.relation-pill:hover { background: var(--c-panel); color: var(--c-dark); }

/* F79: inside the learning rail, pills and badges go OUTLINE — a step that
   lists many skills/tools turns filled tiles into a wall of color that
   competes with the content. */
.learning-path-unified .relation-pill,
.learning-path-unified .badge {
  background: transparent;
  border: 1px solid var(--c-chip);
  color: var(--type-color);
}
.learning-path-unified .relation-pill:hover { background: var(--c-tile); color: var(--c-dark); }
.learning-path-unified .learning-step-time { background: transparent; }

.direct-relation-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border: 1px solid var(--c-border);
  border-radius: 999px;
  background: var(--c-tile);
  /* Size inherits the sidebar value tier via .glance-value (--sb-value). */
  font-weight: 800;
  transition: border-color 0.18s ease;
}
/* Beats `.glance-value a { color: var(--brand) }` (two classes vs one) so the
   pill keeps its own type's accent at rest instead of falling back to the
   brand link blue. */
.glance-value .direct-relation-pill,
.glance-value .direct-relation-pill:hover { color: var(--type-color); }
.glance-value .direct-relation-pill:hover { border-color: var(--type-color); }
.direct-relation-pill-icon { width: 14px; height: 14px; flex: none; }
/* Same fix, same reason: a linked multiselect glance badge (categories, T:
   category taxonomy) is an `<a>` too, so `.glance-value a { color: var(--brand) }`
   otherwise wins over `.badge-link`'s own color at rest (equal class count,
   but the plain rule's trailing element selector loses on source order only
   AFTER a class-count tie — `.glance-value .badge-link` has one more class,
   so it wins outright). Without this the pill's text renders generic brand
   blue instead of its type's accent. */
.glance-value .badge-link,
.glance-value .badge-link:hover { color: var(--type-color); }
/* F163 (supersedes the one-per-line rule): tag lists ride the shared label
   line and wrap; the wider column gap keeps distinct values scannable. */
.glance-badges { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 12px; row-gap: 4px; }

@media (max-width: 36rem) {
  .learning-path-unified .learning-step { padding-inline-start: 48px; }
  .learning-step-marker { width: 34px; height: 34px; inset-block-start: 18px; border-width: 3px; }
  .learning-path-unified .learning-step::after { inset-inline-start: 16px; inset-block-start: 55px; }
  .learning-step-header { align-items: flex-start; flex-direction: column; gap: 9px; }
  .learning-step-time { align-self: flex-start; }
  .learning-path-total { padding-inline-start: 48px; }
  .learning-path-total .learning-step-marker { inset-block-start: 14px; }
}

.item-list-routes { gap: 14px; }
.item-list-routes .item {
  padding: 18px 20px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 16px;
}
.item-list-routes .item::before { display: none; }
.item-list-routes .field-labeled:last-child {
  display: inline-flex;
  margin-block-start: 8px;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--c-tile);
  color: var(--c-dark);
  font-size: 12.5px;
}

.item-list-questions .item {
  padding: 18px 20px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 16px;
}
.item-list-questions .item::before { display: none; }
.item-list-questions .fact { inline-size: fit-content; margin-block-end: 12px; }
.item-list-questions .field-mini-label {
  margin-block: 14px 5px;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 800;
}
.item-list-questions .field-key-answer-guidance,
.item-list-questions .field-key-model-answer {
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
}
.item-list-questions .field-key-model-answer {
  border-color: var(--c-border);
  background: var(--c-wash);
}
.legacy-question-list > ul {
  display: grid;
  gap: 9px;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}
.legacy-question-list > ul > li {
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
}
.legacy-question-list > ul > li::before { display: none; }
.legacy-question-list em {
  display: block;
  margin-block-start: 8px;
  color: var(--ink-3);
  font-style: normal;
}

/* Interview question cards: category → question → short caption stay in
   view; the longer answer guidance / model answer fold into a native
   <details> disclosure so a list of questions doesn't read as a wall of
   text. Flat, no resting shadow. */
.qa-list { list-style: none; padding-inline-start: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; }
.qa-item { padding: 16px 18px; background: var(--paper); border: 1px solid var(--line); border-radius: 14px; }
.qa-item-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* F85: the category is orientation, not content — outline + muted so the
   question itself carries the row. */
.qa-category {
  flex: none;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-3);
  font-weight: 600;
}
.qa-question { flex: 1; min-width: 0; margin: 0; font-size: 15.5px; font-weight: 800; color: var(--ink); line-height: 1.7; }
.qa-caption { margin: 6px 0 0; font-size: 13.5px; color: var(--ink-3); line-height: 1.8; }
/* The toggle is an ACTION (expand/collapse), so it takes the brand action
   color, not the page's category accent (v3: category color = what you're
   looking at, brand blue = what you can do). */
.qa-details { margin-block-start: 10px; }
.qa-details summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  list-style: none;
  cursor: pointer;
  padding: 4px 2px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--brand);
}
.qa-details summary:hover { color: var(--brand-dark); }
.qa-details summary::-webkit-details-marker { display: none; }
.qa-details summary::after { content: none; }
.qa-details summary::before {
  content: '';
  width: 7px;
  height: 7px;
  flex: none;
  border-inline-end: 2px solid currentColor;
  border-block-end: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.18s ease;
}
.qa-details[open] summary::before { transform: rotate(45deg); }
.qa-details-body { margin-block-start: 8px; padding: 12px 14px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; }
/* Accordion parts (answer guidance / model answer) carry no mini-labels —
   the <summary> names them (T10); a hairline separates the two. */
.qa-detail-part + .qa-detail-part {
  border-block-start: 1px solid var(--line-soft);
  margin-block-start: 12px;
  padding-block-start: 12px;
}
/* Question level badge (T9) — neutral, so the colored category badge stays
   the primary scent. */

/* FAQ accordion (T16): reuses the qa-details disclosure (chevron caret,
   hidden marker, folding body). Unlike the qa toggle, the summary here IS
   the question — content, not an action — so it reads ink-colored at body
   size and only takes the brand color on hover/open. */
.faq-list { display: flex; flex-direction: column; gap: 10px; }
.faq-item.qa-details { margin-block-start: 0; background: var(--paper); border: 1px solid var(--line); border-radius: 14px; }
.faq-item summary { display: flex; width: 100%; padding: 12px 16px; font-size: 15px; color: var(--ink); }
/* F97: the caret sits at the inline-end (LEFT in RTL) of the FAQ header —
   the question reads first, the affordance closes the row. */
.faq-item summary::before { order: 2; margin-inline-start: auto; }
.faq-item summary:hover, .faq-item[open] summary { color: var(--brand); }
.faq-item .qa-details-body { margin: 0 16px 14px; }
.faq-item .qa-details-body p { margin: 0; line-height: 1.9; }

/* External resources deliberately use one neutral visual family. */
.resource-card, .ref-card { --resource-accent: #637695; }
.resource-icon { background: #e2e8f0; color: var(--resource-accent); }
a.resource-card:hover, a.ref-card:hover { border-color: #aebedb; background: #eff2f7; box-shadow: 0 8px 18px rgba(19, 29, 50, 0.08); }
a.resource-card:hover .resource-card-title,
a.resource-card:hover .resource-ext-icon { color: var(--resource-accent); }

/* Static (URL-less) resource entries carry no click affordance, so they must
   not wear the same solid card chrome as a real link — a dashed, unfilled
   treatment signals "reference only" before a reader tries to click it. */
.resource-card-static { border-style: dashed; background: transparent; }
.resource-card-static .resource-icon { background: transparent; color: var(--ink-3); border: 1px solid var(--line); }

.related-filters { display: flex; flex-wrap: wrap; gap: 7px; margin-block-end: 14px; }
.related-filter {
  appearance: none;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-3);
  padding: 5px 12px;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
.related-filter:hover { border-color: var(--ink-3); color: var(--ink); }
.related-filter.active { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.related-items-list > li[hidden],
.resource-list > li[hidden],
.faradars-list > li[hidden] { display: none; }

/* «نمایش بیشتر…» ↔ «نمایش کمتر» under collapsible lists (F104, toc.js).
   Quiet-chip look; the chevron flips while expanded (disclosure contract). */
.list-more-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-block-start: 12px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 700;
  background: var(--surface);
  border: 1px solid var(--c-chip);
  padding: 7px 15px;
  border-radius: 999px;
  color: var(--type-color);
  cursor: pointer;
  transition: border-color 0.18s ease;
}
.list-more-btn:hover { border-color: var(--type-color); }
.list-more-chevron { display: inline-flex; }
.list-more-chevron svg { width: 13px; height: 13px; transition: transform 0.18s ease; }
.list-more-btn.expanded .list-more-chevron svg { transform: rotate(180deg); }

.doc-tag-list { display: flex; flex-wrap: wrap; gap: 7px; }
.doc-tag {
  padding: 3px 9px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-3);
  font-size: 12px;
}
.doc-tag:hover { border-color: var(--line-strong); color: var(--ink); }

/* --- Motion & responsiveness -------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .relation-card:hover, .cat-tile:hover, .relation-cards .relation-card:hover, .relation-row:hover { transform: none; }
}

/* Floating sidebar button (site.js): phone-only (the 63.99rem block below
   turns it on — this base rule must stay ABOVE that block so the media rule
   wins, F140), accent-filled, above the drawer so it doubles as its close
   toggle. Sits at the inline-START edge — the physical RIGHT on this RTL
   site — leaving the to-top button its inline-end corner. */
.sidebar-fab {
  display: none;
  position: fixed;
  z-index: 56;
  inset-block-end: 20px;
  inset-inline-start: 20px;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: none;
  border-radius: 999px;
  background: var(--type-color, var(--brand));
  color: var(--c-on, #fff);
  box-shadow: 0 8px 24px rgba(36, 35, 33, 0.3);
  cursor: pointer;
}
.sidebar-fab svg { width: 22px; height: 22px; }
/* Active-filter count badge on the drawer button (F131) — site.js copies it
   from the sidebar's data-active-filters attribute. */
.sidebar-fab-count {
  position: absolute;
  inset-block-start: -4px;
  inset-inline-end: -4px;
  min-width: 20px;
  height: 20px;
  padding-inline: 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1;
}

/* Must complement the sticky-sidebar query above (min-width: 64rem) exactly —
   an overlap would leave the STACKED sidebar sticky and viewport-capped. */
@media (max-width: 63.99rem) {
  .doc-layout { grid-template-columns: 1fr; gap: 18px; }
  /* Content before chrome: on phones/tablets the article renders first and
     the at-a-glance/TOC sidebar follows, instead of forcing a scroll past
     both cards before any real content appears. (No-JS fallback — with JS
     the sidebar folds into the drawer below instead.) */
  .doc-layout > .doc-sidebar { order: 2; }
  .doc-layout > .doc { order: 1; }

  /* F101/F108: with site.js present (body.sidebar-collapsible) the sidebar
     leaves the flow entirely and opens as a bottom-sheet drawer from the
     floating button. */
  body.sidebar-collapsible .doc-layout > .doc-sidebar { display: none; }
  body.sidebar-collapsible.sidebar-open .doc-layout > .doc-sidebar {
    display: flex;
    position: fixed;
    z-index: 55;
    inset-inline: 0;
    inset-block-end: 0;
    max-height: 78dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
    margin: 0;
    background: var(--paper);
    border-block-start: 1px solid var(--line-strong);
    border-start-start-radius: 20px;
    border-start-end-radius: 20px;
    /* Bottom clearance = FAB footprint (20px inset + 48px button + breathing
       room): the floating button stays visible over the open sheet and used
       to sit ON the sheet's last row (last filter group / last TOC entry). */
    padding: 16px 16px calc(84px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -18px 50px rgba(36, 35, 33, 0.28);
  }
  body.sidebar-open { overflow: hidden; }
  /* AFTER the base rule below in the cascade? No — media rules must WIN, so
     the base .sidebar-fab { display:none } is authored ABOVE this block.
     (F140: it originally sat below and the button never appeared.) */
  .sidebar-fab { display: inline-flex; }
}
.sidebar-backdrop {
  position: fixed;
  inset: 0;
  z-index: 54;
  background: rgba(36, 35, 33, 0.45);
}
.sidebar-backdrop[hidden] { display: none; }

@media (max-width: 48rem) {
  h1 { font-size: 1.75rem; }
  .doc-head h1.doc-title { font-size: 1.6rem; }
  .hero h1 { font-size: 1.85rem; }
  .listing-head h1 { font-size: 1.75rem; }
  .hero .container { padding-block: 30px 26px; }
  .category-panel { padding: 18px; border-radius: 20px; }
  .doc-section { padding: 18px 20px 20px; border-radius: 18px; }
  /* Follows the panel's own tighter padding — see the desktop rule. */
  .doc-article-body .richtext > * + h2 { margin-block-start: 26px; }
  .relation-row { gap: 12px; padding: 12px 14px; border-radius: 14px; }
  .relation-row-icon { width: 38px; height: 38px; border-radius: 11px; }
  .relation-row-icon svg { width: 19px; height: 19px; }
  .relation-row-title { font-size: 15px; }
  .site-nav { order: 3; flex-basis: 100%; margin-inline-start: 0; }
  .listing-icon { width: 44px; height: 44px; }
  .listing-icon svg { width: 23px; height: 23px; }
}

/* --- Touch ergonomics ---------------------------------------------------- */

@media (pointer: coarse) {
  /* iOS Safari zooms the page onto any focused input under 16px; the sidebar
     boxes were 14.5px (the hero was already 16px). Desktop keeps its denser
     size — this only follows the primary coarse pointer. */
  .listing-tools .search-form input[type='search'] { font-size: 16px; }
  /* Small inline links that double as primary navigation on phones
     (breadcrumbs, sidebar utility links): grow the tap slab without moving
     a pixel of layout (padding paid back by margin). */
  .crumbs a,
  .filter-clear-query,
  .filters-reset {
    padding-block: 8px;
    margin-block: -8px;
  }
}
