/* ═══════════════════════════════════════════════════════════════════════
   دکتر سایه حسینی — practice website
   Hand-authored, no build step. Persian / RTL is the primary direction.

   Two typography rules govern this file and must not be relaxed:
     1. No letter-spacing on Persian text, anywhere. The script is cursive;
        tracking breaks the letter joins. Hierarchy comes from weight, size
        and colour only.
     2. Body line-height stays near 2. Persian needs more leading than Latin.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Fonts ───────────────────────────────────────────────────────────────
   Sahel, self-hosted from this app's own /static. Third-party CDNs are
   unreliable on Iranian networks, so nothing here may reference an external
   host.

   Sahel (Saber Rastikerdar, SIL OFL 1.1 — the licence ships alongside the
   files at /static/sahel-OFL.txt) replaced two faces at once: IRANSans for
   body, which is commercial and licensed per-domain, and Amiri for display.
   One family across the whole page is the reason it now reads as one
   document rather than two typefaces sharing a stylesheet, and the
   display/body distinction it used to get from a second family it now gets
   from weight — 300 at the large sizes, 400 for reading, 500/600 for
   anything that has to lead a block.

   Sahel has no 500, so the SemiBold face claims the 500–600 range: every
   `font-weight:500` in this file (buttons, summaries, small headings) lands
   on a real cut instead of silently falling back to 400, which is what CSS
   font matching would otherwise do.
   ─────────────────────────────────────────────────────────────────────── */
@font-face { font-family:'Sahel'; font-weight:300; font-display:swap;
             src:url('/static/sahel-300.woff2') format('woff2'); }
@font-face { font-family:'Sahel'; font-weight:400; font-display:swap;
             src:url('/static/sahel-400.woff2') format('woff2'); }
@font-face { font-family:'Sahel'; font-weight:500 600; font-display:swap;
             src:url('/static/sahel-600.woff2') format('woff2'); }
@font-face { font-family:'Sahel'; font-weight:700; font-display:swap;
             src:url('/static/sahel-700.woff2') format('woff2'); }

/* ── Tokens ──────────────────────────────────────────────────────────────
   Sampled from the practice logo: muted forest monogram, sage leaves, warm
   off-white. The neutrals are deliberately green-biased rather than grey —
   a true grey against this accent reads as unconsidered.

   Components style through tokens only. Never write a colour inside the
   dark-mode blocks below.
   ─────────────────────────────────────────────────────────────────────── */
:root {
  --paper:#f7f4ec;       --paper-2:#f1ede0;     --surface:#fffdf8;
  --ink:#23301c;         --ink-2:#4d5c42;       --ink-3:#5f6e53;
  --line:#e4dfd0;        --line-soft:#ede9dc;
  /* --line is for separating things and is deliberately faint; it measures
     1.27:1 against the card ground, which is fine for a hairline and fails
     WCAG 1.4.11 for anything a person is meant to operate. Every control
     border — inputs, selects, textareas, slot chips, the scale options, the
     icon buttons, the ghost button — takes --field-line instead, which
     clears 3:1 against all three grounds in both themes. Dark mode is where
     this mattered most: the callback form's fields were effectively
     invisible on the surface behind them. */
  --field-line:#7c8b68;
  --forest:#4e6b3c;      --forest-deep:#3a5129;
  --sage:#9ba98c;        --sage-tint:#e6ebdd;   --on-forest:#f8f7ef;
  --band:#3a4d2c;        --band-2:#2e3e23;      --on-band:#eff2e6;
  --on-band-2:#b3c2a0;   --band-line:#4d6339;
  --danger:#8f3222;      --danger-tint:#f8ebe6;

  --shadow-card:0 30px 60px -30px rgba(35,48,28,.26);
  --shadow-lift:0 18px 30px -16px rgba(78,107,60,.50);
  --grain-blend:multiply; --grain-opacity:.035;

  /* One family, two roles. --display exists so the weight and tracking of a
     heading stay a single decision, not one repeated at every call site. */
  --font:'Sahel',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Noto Sans Arabic',Tahoma,sans-serif;
  --display:var(--font);
  --ease:cubic-bezier(.22,.61,.36,1);
  --wrap:min(100% - 2.5rem, 66rem);
  --header-h:4.75rem;
  /* The header shrinks once the page moves. Anything that sticks *below* it
     has to line up with this height, not the resting one. */
  --header-h-scrolled:4.05rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper:#171d14;       --paper-2:#1d241a;     --surface:#232b1f;
    --ink:#eaeee1;         --ink-2:#adb9a0;       --ink-3:#8a9680;
    --line:#2f3828;        --line-soft:#262e21;
    --field-line:#6f7d5e;
    --forest:#a3bd8e;      --forest-deep:#c0d4ac;
    --sage:#9fb58b;        --sage-tint:#262f1f;   --on-forest:#141a10;
    --band:#12180f;        --band-2:#1a2115;      --on-band:#eaeee1;
    --on-band-2:#9aa88a;   --band-line:#2b351f;
    --danger:#e0917f;      --danger-tint:#2c1a14;

    --shadow-card:0 30px 70px -30px rgba(0,0,0,.7);
    --shadow-lift:0 18px 30px -16px rgba(0,0,0,.62);
    --grain-blend:overlay; --grain-opacity:.045;
  }
}

/* An explicit toggle must beat the OS preference in both directions, so both
   themes are restated under a data-theme selector. */
:root[data-theme="dark"] {
  --paper:#171d14;       --paper-2:#1d241a;     --surface:#232b1f;
  --ink:#eaeee1;         --ink-2:#adb9a0;       --ink-3:#8a9680;
  --line:#2f3828;        --line-soft:#262e21;
  --field-line:#6f7d5e;
  --forest:#a3bd8e;      --forest-deep:#c0d4ac;
  --sage:#9fb58b;        --sage-tint:#262f1f;   --on-forest:#141a10;
  --band:#12180f;        --band-2:#1a2115;      --on-band:#eaeee1;
  --on-band-2:#9aa88a;   --band-line:#2b351f;
  --danger:#e0917f;      --danger-tint:#2c1a14;

  --shadow-card:0 30px 70px -30px rgba(0,0,0,.7);
  --shadow-lift:0 18px 30px -16px rgba(0,0,0,.62);
  --grain-blend:overlay; --grain-opacity:.045;
}

:root[data-theme="light"] {
  --paper:#f7f4ec;       --paper-2:#f1ede0;     --surface:#fffdf8;
  --ink:#23301c;         --ink-2:#4d5c42;       --ink-3:#5f6e53;
  --line:#e4dfd0;        --line-soft:#ede9dc;
  --field-line:#7c8b68;
  --forest:#4e6b3c;      --forest-deep:#3a5129;
  --sage:#9ba98c;        --sage-tint:#e6ebdd;   --on-forest:#f8f7ef;
  --band:#3a4d2c;        --band-2:#2e3e23;      --on-band:#eff2e6;
  --on-band-2:#b3c2a0;   --band-line:#4d6339;
  --danger:#8f3222;      --danger-tint:#f8ebe6;

  --shadow-card:0 30px 60px -30px rgba(35,48,28,.26);
  --shadow-lift:0 18px 30px -16px rgba(78,107,60,.50);
  --grain-blend:multiply; --grain-opacity:.035;
}

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

/* Several components below set an explicit `display`, which silently beats
   the `hidden` attribute. Everything toggled from JS uses `hidden`, so this
   has to win. */
[hidden] { display:none !important; }

html {
  scroll-behavior:smooth;
  /* Sticky header would otherwise cover the top of every anchored section. */
  scroll-padding-top:6.5rem;
  -webkit-text-size-adjust:100%;
}

body {
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--font);
  font-size:1.0625rem;
  line-height:2;
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  text-wrap:pretty;
  /* The page body must never scroll sideways at any width; wide content
     scrolls inside its own container instead. */
  overflow-x:hidden;
  transition:background-color .3s ease, color .3s ease;
}

/* Paper grain, plus a soft vignette at the far corners — one fixed
   composited layer for both. A second body::after rule would not stack
   with this one; pseudo-elements are singular per element, so a later
   rule of the same selector replaces this background instead of layering
   over it. The vignette's own colour stop is full-strength (rgba(...,1));
   --grain-opacity does the restraint work for both layers at once, which
   is also why there is no separate dark-mode override here — the
   light/dark values already set for --grain-opacity and --grain-blend
   retheme the vignette along with the grain. */
body::after {
  content:'';
  position:fixed; inset:0; z-index:100;
  pointer-events:none;
  opacity:var(--grain-opacity);
  mix-blend-mode:var(--grain-blend);
  background-image:
    radial-gradient(ellipse farthest-corner at center, transparent 55%, rgba(0,20,10,1) 100%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

::selection { background:var(--sage-tint); color:var(--ink); }

a { color:var(--forest); text-underline-offset:6px; }
a:hover { color:var(--forest-deep); }

img { max-width:100%; display:block; }

:focus-visible {
  outline:3px solid var(--sage);
  outline-offset:2px;
  border-radius:4px;
}

.wrap { width:var(--wrap); margin-inline:auto; }
.sr-only {
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

.skip-link {
  position:absolute; inset-inline-start:1rem; top:-5rem; z-index:200;
  background:var(--forest); color:var(--on-forest);
  padding:.75rem 1.25rem; border-radius:10px; text-decoration:none;
  font-size:.9rem; transition:top .2s var(--ease);
}
.skip-link:focus-visible { top:.75rem; color:var(--on-forest); }

/* ── Type ────────────────────────────────────────────────────────────────
   Sizes are set for Sahel, whose x-height runs well above the Amiri that
   used to hold these slots — the old clamps rendered about a step too large
   in the new face, so each one came down roughly a tenth. Weight 300 is
   what keeps a heading this size calm rather than loud, which on a therapy
   site is the whole point.
   ─────────────────────────────────────────────────────────────────────── */
.display {
  font-family:var(--display);
  font-weight:300;
  line-height:1.62;
  margin:0;
  color:var(--ink);
  text-wrap:balance;
}
h1.display { font-size:clamp(1.85rem,4.1vw,2.8rem); line-height:1.55; }
h2.display { font-size:clamp(1.4rem,2.8vw,1.8rem); }
/* Card and list headings (.post h2, .pub-title, .episode-title h2,
   .article-body h2, .q-* h2) sit too small for the 300 to read as
   deliberate — below about 1.4rem thin just reads as faint. They take 500
   instead, and that inversion is the system: size and weight trade off. */
h3 { font-size:1rem; font-weight:500; margin:0; color:var(--ink); }

.lead { font-size:1.075rem; line-height:2; color:var(--ink-2); margin:0; max-width:33rem; }
.prose { color:var(--ink-2); margin:0; max-width:36rem; line-height:2; }
.meta { font-size:.84rem; color:var(--ink-3); line-height:1.9; }
.num { font-variant-numeric:tabular-nums; }

/* The eyebrow: a short sage rule then a quiet label. Repeats across the page
   as the one recurring ornament, which is what makes it read as a system. */
.eyebrow { display:flex; align-items:center; gap:.7rem; font-size:.86rem; color:var(--ink-2); }
.eyebrow::before { content:''; width:22px; height:1px; background:var(--sage); flex:none; }

/* ── Header ────────────────────────────────────────────────────────────── */
.site-header {
  position:sticky; top:0; z-index:50;
  background:color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter:blur(12px);
  -webkit-backdrop-filter:blur(12px);
  border-bottom:1px solid transparent;
  transition:border-color .25s ease, box-shadow .25s ease, background-color .3s ease;
}
.site-header.is-scrolled {
  border-bottom-color:var(--line);
  box-shadow:0 10px 30px -26px rgba(35,48,28,.42);
}

.header-inner {
  width:var(--wrap); margin-inline:auto;
  display:flex; align-items:center; justify-content:space-between; gap:1.5rem;
  height:var(--header-h);
  transition:height .28s var(--ease);
}
.site-header.is-scrolled .header-inner { height:var(--header-h-scrolled); }

/* The mark now ships with its ground knocked out, in two colourways, so it
   sits directly on the header instead of inside a framed tile. The tile was
   forced by the old files: both rasters baked in an opaque cream square,
   which on the dark theme lit up as a chip floating in the header, and no
   filter fixes it — invert() swings green line art magenta, and the strokes
   and the leaves need to move by different amounts anyway. Two files, chosen
   the same way the theme toggle chooses its own glyph. */
.brand { display:flex; align-items:center; gap:.7rem; text-decoration:none; color:inherit; flex:none; }
.brand img {
  height:40px; width:40px; object-fit:contain;
  transition:height .28s var(--ease), width .28s var(--ease);
}
.site-header.is-scrolled .brand img { height:32px; width:32px; }

/* Paired theme assets: default to the light one, swap on an explicit dark
   choice, and follow the OS only while no choice has been made. Mirrors the
   .icon-moon/.icon-sun rules below — a <picture> with prefers-color-scheme
   cannot see the site's own toggle, so it would strand anyone who set it. */
.theme-dark-only { display:none; }
:root[data-theme="dark"] .theme-light-only { display:none; }
:root[data-theme="dark"] .theme-dark-only { display:block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .theme-light-only { display:none; }
  :root:not([data-theme]) .theme-dark-only { display:block; }
}
.brand-text { display:flex; flex-direction:column; gap:.1rem; white-space:nowrap; }
.brand-name { font-family:var(--display); font-weight:500; font-size:1.02rem; line-height:1.4; }
.brand-role { font-size:.79rem; line-height:1.2; color:var(--ink-3); }

.nav { display:flex; align-items:center; gap:1.5rem; }
.nav a {
  color:var(--ink-2); text-decoration:none; font-size:.92rem; padding:.4rem 0;
  border-bottom:1px solid transparent;
  transition:color .2s ease, border-color .2s ease;
}
.nav a:hover { color:var(--ink); border-bottom-color:var(--sage); }

.header-actions { display:flex; align-items:center; gap:.6rem; flex:none; }

/* ── Language switch ─────────────────────────────────────────────────────
   Two anchors, not a button and a script. Each one is the counterpart URL
   of the page it sits on, so it works with scripting off, a crawler follows
   it into the other language, and the choice survives as a URL someone can
   send to somebody else. Nothing here stores a preference: a visitor who
   wanted English asked for English by opening the link, and second-guessing
   that on their next visit is how people end up stuck in a language they
   cannot read their way out of.

   The pill is forced LTR in both directions. It is a pair of two-letter
   language tags, not prose, and letting it mirror puts FA on the side the
   Persian reader's eye leaves rather than the side it arrives at.
   ─────────────────────────────────────────────────────────────────────── */
.lang-switch {
  display:flex; align-items:center; flex:none; direction:ltr;
  padding:2px; border-radius:12px;
  background:color-mix(in srgb, var(--ink) 6%, transparent);
}
.lang-opt {
  display:flex; align-items:center; justify-content:center;
  min-width:2rem; height:2rem; padding:0 .45rem;
  border-radius:10px;
  font-size:.78rem; font-weight:500; line-height:1;
  color:var(--ink-3); text-decoration:none;
  transition:color .2s ease, background-color .2s ease;
}
.lang-opt:hover { color:var(--ink); }
.lang-opt.is-current {
  background:var(--surface); color:var(--ink);
  box-shadow:0 1px 2px rgba(0,0,0,.06);
}
/* The current language is a link to the page you are already on. Keeping it
   focusable but inert stops a tab-through from reloading the page, and
   `aria-current` is what actually announces the state. */
.lang-opt.is-current { pointer-events:none; }

/* Below 620 the pair costs more header than there is. The current-language
   chip is the one that goes: it is the only element in the header that tells
   the visitor something they already know. What is left is a single chip
   naming the language you can switch *to*, which is the older and smaller
   pattern and still an ordinary link to a real URL. */
@media (max-width: 620px) {
  .lang-switch { padding:0; background:none; }
  .lang-opt.is-current { display:none; }
  .lang-opt {
    height:2.5rem; min-width:2.5rem; border-radius:14px;
    background:color-mix(in srgb, var(--ink) 6%, transparent);
    color:var(--ink);
  }
}

/* Circles with a hairline outline, which at 40px read as two empty rings
   parked next to the logo — the ring competed with the glyph instead of
   containing it. A soft chip instead: no border, a tint that sits a step off
   the header ground, and the icon carrying its own contrast (which is what
   WCAG 1.4.11 actually asks of an icon button — the ring was never the part
   that had to be visible). */
.icon-btn {
  position:relative;
  width:2.5rem; height:2.5rem; flex:none;
  display:flex; align-items:center; justify-content:center;
  background:color-mix(in srgb, var(--ink) 6%, transparent);
  border:none; border-radius:14px;
  color:var(--ink); cursor:pointer; padding:0;
  transition:color .2s ease, background-color .2s ease;
}
.icon-btn:hover { color:var(--forest-deep); background:color-mix(in srgb, var(--sage) 34%, transparent); }
/* The visible circle stays 40px to match the header logo's height, but a
   40px tap target is under the 44px mobile baseline. Grow the hit area, not
   the circle. */
.icon-btn::before { content:''; position:absolute; inset:-2px; }
.icon-btn svg { width:17px; height:17px; }
/* The toggle shows the theme it switches *to*, not the one in force. */
.theme-toggle .icon-sun { display:none; }
.theme-toggle .icon-moon { display:block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display:none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display:block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .theme-toggle .icon-moon { display:none; }
  :root:not([data-theme]) .theme-toggle .icon-sun { display:block; }
}

/* Reading-progress hairline, pinned to the header's bottom edge. */
.progress-track {
  position:absolute; inset-inline:0; bottom:-1px; height:2px;
  overflow:hidden; pointer-events:none;
}
/* Anchored at the reading edge so it grows the way the page is read, and the
   gradient's own direction is flipped to match — `to left` is physical and
   would run the fade backwards on the English pages. */
.progress-fill {
  position:absolute; inset-block:0; inset-inline-start:0; width:0;
  background:linear-gradient(to left, var(--forest), var(--sage));
}
[dir="ltr"] .progress-fill {
  background:linear-gradient(to right, var(--forest), var(--sage));
}

/* Three bars of two different lengths, right-aligned, and no open state
   beyond the short one growing — it read as a misaligned stack rather than a
   control, and once the menu was open nothing in the header said so. Two
   even bars that cross into an X: the geometry is symmetrical at rest, the
   open state is unmistakable, and the whole thing animates on `transform`,
   which composites. */
.menu-btn { display:none; }
.menu-btn span {
  position:absolute; left:50%; top:50%;
  width:18px; height:1.5px; margin:-1px 0 0 -9px;
  background:currentColor; border-radius:2px;
  transition:transform .24s var(--ease);
}
.menu-btn span:nth-child(1) { transform:translateY(-3.5px); }
.menu-btn span:nth-child(2) { transform:translateY(3.5px); }
.menu-btn[aria-expanded="true"] span:nth-child(1) { transform:rotate(45deg); }
.menu-btn[aria-expanded="true"] span:nth-child(2) { transform:rotate(-45deg); }

/* Nine links and a booking button run to about 680px. On a phone held in
   one hand that is taller than the viewport left under the header, and the
   button — the one thing the menu is open for — was the item falling off
   the bottom with nothing to scroll. The menu carries its own scroll, and
   `dvh` measures against the collapsed browser chrome so the cap is honest
   on mobile Safari. `overscroll-behavior` keeps the flick from chaining
   into the page underneath once the list bottoms out. */
.mobile-menu {
  display:none; flex-direction:column;
  width:var(--wrap); margin-inline:auto;
  padding-bottom:1.25rem; border-top:1px solid var(--line-soft);
  max-height:calc(100vh - var(--header-h) - 1px);
  max-height:calc(100dvh - var(--header-h) - 1px);
  overflow-y:auto; overscroll-behavior:contain;
}
.mobile-menu.is-open { display:flex; }
.mobile-menu a {
  color:var(--ink); text-decoration:none; font-size:1rem;
  /* Still a 56px row — comfortably over the 44px floor — and eight of them
     fit a 667px phone where the 1rem original did not. */
  padding:.8rem 0; border-bottom:1px solid var(--line-soft); flex:none;
}
.mobile-menu .btn { margin-top:1rem; border-bottom:none; flex:none; }

/* ── Buttons ───────────────────────────────────────────────────────────── */
/* `white-space:nowrap` keeps the pills from breaking mid-label, but a button
   cannot be allowed to set the page's minimum width: the PDF link on /writing
   is wide enough to push a 360px phone into horizontal scroll and drag the
   whole layout off-centre. `max-width:100%` caps it at the column, and the
   flex wrap lets a label that still will not fit break onto a second line
   rather than overflow. */
.btn {
  display:inline-flex; align-items:center; justify-content:center; gap:.5rem;
  flex-wrap:wrap; max-width:100%;
  font-family:inherit; font-size:1rem; font-weight:500; line-height:1.5;
  padding:1rem 2rem; border-radius:999px; border:1px solid transparent;
  text-decoration:none; cursor:pointer; white-space:nowrap;
  transition:background-color .22s ease, color .22s ease, border-color .22s ease,
             box-shadow .28s ease, transform .2s var(--ease);
}
.btn-primary {
  background:var(--forest); color:var(--on-forest);
  box-shadow:var(--shadow-lift);
}
.btn-primary:hover { background:var(--forest-deep); color:var(--on-forest); transform:translateY(-1px); }
.btn-primary:active { transform:translateY(0); }
.btn-primary[disabled] { opacity:.55; cursor:not-allowed; transform:none; }

.btn-ghost {
  background:transparent; color:var(--ink); border-color:var(--field-line);
}
.btn-ghost:hover { border-color:var(--sage); background:var(--paper-2); color:var(--ink); }

.btn-sm { font-size:.9rem; padding:.72rem 1.4rem; }
.btn-block { display:flex; width:100%; }

.link-quiet {
  color:var(--ink-2); font-size:.98rem; text-decoration:underline;
  text-decoration-thickness:1px; text-decoration-color:var(--line);
  transition:color .2s ease, text-decoration-color .2s ease;
}
.link-quiet:hover { color:var(--ink); text-decoration-color:var(--sage); }

/* ── Section scaffolding ───────────────────────────────────────────────── */
.section { border-top:1px solid var(--line-soft); }
.section > .wrap { padding-block:clamp(3.5rem,6.5vw,5.5rem); }

/* Heading in a narrow column on the RTL reading edge, content running out
   beside it. A single right-aligned column on a wide screen leaves a dead
   half; this turns that into content. */
.split { display:grid; grid-template-columns:17rem minmax(0,1fr); gap:3.5rem; }
.split-head { position:sticky; top:6.5rem; align-self:start; }
/* The numeral plus a short rule is the page's spine: it recurs at every
   section and is what makes the whole thing read as one document rather than
   a stack of unrelated blocks. */
.sec-index {
  display:flex; align-items:center; gap:.65rem;
  font-family:var(--display); font-weight:500; font-size:.92rem;
  /* Sage would be the obvious accent here and fails AA at this size against
     paper (2.2:1). Forest carries the same family at 6.4:1. */
  color:var(--forest); font-variant-numeric:tabular-nums;
  margin-bottom:.9rem;
}
.sec-index::after { content:''; height:1px; width:2.25rem; background:var(--line); flex:none; }
.band .sec-index { color:var(--on-band-2); }
.band .sec-index::after { background:var(--band-line); }
.sec-note { margin:.85rem 0 0; font-size:.86rem; color:var(--ink-3); line-height:1.9; }

/* ── Hero ──────────────────────────────────────────────────────────────── */
.hero { position:relative; overflow:hidden; }
.hero > .wrap {
  position:relative; z-index:1;
  padding-block:clamp(3rem,7vw,6rem) clamp(2.5rem,5vw,4rem);
}
.hero-halo {
  position:absolute; top:-26%; inset-inline-end:-16%;
  width:min(56rem,110%); aspect-ratio:1; border-radius:999px;
  pointer-events:none; z-index:0;
  /* Long, uneven falloff. A tidy two-stop gradient leaves a visible ring at
     the last stop, which is exactly the artefact this is meant to avoid. */
  background:radial-gradient(circle at 55% 45%,
    color-mix(in srgb, var(--sage) 50%, transparent) 0%,
    color-mix(in srgb, var(--sage) 26%, transparent) 34%,
    color-mix(in srgb, var(--sage) 8%, transparent) 58%,
    transparent 85%);
  animation:breathe 15s ease-in-out infinite;
}
.hero-halo-2 {
  position:absolute; bottom:-34%; inset-inline-start:-12%;
  width:min(40rem,88%); aspect-ratio:1; border-radius:999px;
  pointer-events:none; z-index:0;
  background:radial-gradient(circle,
    color-mix(in srgb, var(--forest) 26%, transparent), transparent 66%);
  animation:breathe 19s ease-in-out infinite reverse;
}

.hero-grid {
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,23rem);
  gap:4rem; align-items:center;
}
.hero-copy { display:flex; flex-direction:column; gap:1.5rem; min-width:0; }
.hero-actions { display:flex; flex-wrap:wrap; align-items:center; gap:1.5rem; margin-top:.5rem; }

/* Portrait plate. The arch is the one shape on the page that isn't a
   rectangle or a pill — it carries the "consulting room" reference without
   a single decorative image. */
.portrait { margin:0; display:flex; flex-direction:column; gap:.8rem; }
.portrait-frame {
  position:relative; width:100%; aspect-ratio:4/5;
  border-radius:14rem 14rem 20px 20px;
  overflow:hidden; background:var(--paper-2);
  border:1px solid var(--line);
}
.portrait-frame::after {
  /* Engraved inner rule, inset from the edge — a framing convention borrowed
     from print, and the cheapest way to make a plate look deliberate. */
  content:''; position:absolute; inset:10px; pointer-events:none;
  border:1px solid color-mix(in srgb, var(--sage) 45%, transparent);
  border-radius:13rem 13rem 12px 12px;
}
/* The prototype's eighth animation, and the only one the original build could
   not use: it is a slow drift across the portrait, and there was no portrait.
   Twenty-six seconds for five percent of scale is below the threshold where
   the eye reads it as movement — it just stops the plate from looking like a
   printed panel. The reduced-motion block at the foot of this file disables
   it along with everything else. */
@keyframes kenburns { from { transform:scale(1); } to { transform:scale(1.05); } }
.portrait-frame img.portrait-photo {
  width:100%; height:100%; object-fit:cover;
  animation:kenburns 26s ease-in-out infinite alternate;
}
.portrait-placeholder {
  position:absolute; inset:0;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1rem;
  background:
    repeating-linear-gradient(135deg,
      transparent, transparent 9px,
      color-mix(in srgb, var(--sage) 9%, transparent) 9px,
      color-mix(in srgb, var(--sage) 9%, transparent) 18px);
  text-align:center; padding:2rem;
}
.portrait-placeholder img { width:56px; opacity:.5; }
.portrait-placeholder span { font-size:.8rem; color:var(--ink-3); line-height:1.8; }
.portrait figcaption { font-size:.79rem; color:var(--ink-3); line-height:1.8; }

/* Credentials strip. This is the professionalism signal doing the most work
   on the page — it sits above the fold on desktop and is all fact, no claim. */
.creds {
  display:grid; grid-template-columns:repeat(4,minmax(0,1fr));
  gap:0;
  border-top:1px solid var(--line); border-bottom:1px solid var(--line);
  margin-top:clamp(2.5rem,5vw,3.5rem);
}
.cred { padding:1.4rem 1.5rem; border-inline-start:1px solid var(--line-soft); }
.cred:first-child { border-inline-start:none; padding-inline-start:0; }
.cred:last-child { padding-inline-end:0; }
.cred-label { display:block; font-size:.76rem; color:var(--ink-3); line-height:1.7; }
.cred-value { display:block; font-size:.94rem; color:var(--ink); line-height:1.8; margin-top:.2rem; }

/* ── About ─────────────────────────────────────────────────────────────── */
.about-grid { display:grid; grid-template-columns:17rem minmax(0,1fr); gap:3.5rem; align-items:start; }
.about-copy { display:flex; flex-direction:column; gap:1.2rem; min-width:0; }

/* ── Rows (facts, areas) ───────────────────────────────────────────────── */
.fact-row {
  display:flex; gap:1.5rem; padding:1.35rem 0;
  border-bottom:1px solid var(--line-soft);
}
.fact-row:last-child { border-bottom:none; }
.fact-row h3 { width:9rem; flex:none; }
.fact-row p { margin:0; color:var(--ink-2); font-size:.96rem; }

.areas { display:grid; grid-template-columns:1fr 1fr; column-gap:3rem; }
.areas li {
  list-style:none; padding:.95rem 0; border-bottom:1px solid var(--line-soft);
  font-size:.98rem; color:var(--ink);
}
.areas { margin:0; padding:0; }

/* ── Process steps ─────────────────────────────────────────────────────── */
.steps { position:relative; display:flex; flex-direction:column; }
/* 1.15rem is half the 2.3rem marker, so the rail runs down the centre of the
   marker column. The markers are the first item in each `.step` flex row, so
   that column is the inline *start* — `inset-inline-end` put the rail against
   the opposite margin, ~820px from the circles it is supposed to thread, and
   it read as a stray vertical line beside the section. */
.step-rail, .step-rail-fill {
  position:absolute; inset-inline-start:1.15rem; width:1px; pointer-events:none;
}
.step-rail { top:2.45rem; bottom:2.45rem; background:var(--line); }
.step-rail-fill {
  top:2.45rem; height:0; max-height:calc(100% - 4.9rem);
  background:var(--sage); transition:height .15s linear;
}
.step { display:flex; gap:1.1rem; align-items:flex-start; padding:1.35rem 0; }
.step-marker {
  width:2.3rem; height:2.3rem; flex:none; border-radius:999px;
  display:flex; align-items:center; justify-content:center;
  position:relative; z-index:1;
  font-family:var(--display); font-weight:500; font-size:.95rem;
  font-variant-numeric:tabular-nums;
  background:var(--paper-2); border:1px solid var(--line); color:var(--ink-3);
  transition:background-color .4s ease, border-color .4s ease, color .4s ease;
}
.step.is-passed .step-marker {
  background:var(--forest); border-color:var(--forest); color:var(--on-forest);
}
.step p { margin:.45rem 0 0; color:var(--ink-2); font-size:.96rem; }

/* ── Availability band ─────────────────────────────────────────────────────
   Moved out of the hero and given its own full-bleed section. It is the
   thesis of the page, so it gets the only inverted ground and the heaviest
   shadow — everywhere else separates with hairlines.
   ─────────────────────────────────────────────────────────────────────── */
.band {
  position:relative; overflow:hidden;
  background:var(--band); color:var(--on-band);
  border-top:1px solid var(--line-soft);
}
.band > .wrap { position:relative; z-index:1; padding-block:clamp(3.5rem,7vw,5.5rem); }
.band::before {
  /* Depth in the ground, not a shape. An earlier version used a hard-edged
     arch here and the edge read as a rendering fault rather than a decision. */
  content:''; position:absolute; inset:0; z-index:0; pointer-events:none;
  background:
    radial-gradient(55rem 34rem at 82% 0%,
      color-mix(in srgb, var(--sage) 15%, transparent), transparent 62%),
    radial-gradient(45rem 40rem at 5% 105%,
      color-mix(in srgb, #000 30%, transparent), transparent 66%);
}
.band .display, .band h2, .band h3 { color:var(--on-band); }
.band .eyebrow { color:var(--on-band-2); }
.band .sec-index, .band .sec-note { color:var(--on-band-2); }

.band-grid { display:grid; grid-template-columns:17rem minmax(0,1fr); gap:3.5rem; align-items:start; }
.band-head { align-self:start; }
.band-head .band-fine {
  margin-top:1.75rem; padding-top:1.5rem;
  border-top:1px solid var(--band-line);
  font-size:.82rem; color:var(--on-band-2); line-height:1.95;
}

.avail-card {
  background:var(--surface); border:1px solid var(--line);
  border-radius:22px; box-shadow:var(--shadow-card);
  padding:1.6rem; min-width:0;
}
.avail-head {
  display:flex; align-items:baseline; justify-content:space-between; gap:.75rem;
  padding-bottom:1rem; border-bottom:1px solid var(--line-soft);
}
.avail-title { display:flex; align-items:center; gap:.55rem; font-weight:500; font-size:1.05rem; color:var(--ink); }
.avail-fresh { font-size:.79rem; color:var(--ink-3); }

.pulse { position:relative; display:inline-flex; width:7px; height:7px; flex:none; }
.pulse-dot {
  width:7px; height:7px; border-radius:999px; background:var(--sage);
  animation:pulse 2.4s ease-in-out infinite;
}
.pulse-ring {
  position:absolute; inset:0; border-radius:999px; border:1px solid var(--sage);
  animation:ring 2.8s ease-out infinite;
}

/* One opening per row, full width and tappable end to end.
 *
 * This replaced a week grid of every free hour with the taken ones showing as
 * gaps. Two things were wrong with that. It published when she has a client —
 * her working hours minus the free ones — to anyone who looked. And on a
 * practice that is still filling, a wall of empty slots is the loudest thing
 * on the page, and what it says about her is not true.
 *
 * A short list says neither. Every row is a real opening; how many there are
 * in total is simply not in the payload. */
.opening {
  width:100%; display:flex; align-items:center; justify-content:space-between;
  gap:1rem; text-align:start;
  font-family:inherit; font-size:.9rem;
  /* Comfortably past the 44px touch floor: this is the page's primary action
     and the row is the whole target, not a chip inside it. */
  min-height:56px; padding:.7rem .95rem; margin-bottom:.4rem;
  border-radius:12px; border:1px solid var(--field-line);
  background:var(--paper-2); color:var(--forest-deep); cursor:pointer;
  transition:background-color .18s ease, border-color .18s ease,
             color .18s ease, transform .18s var(--ease), box-shadow .22s ease;
}
.opening:last-of-type { margin-bottom:0; }
.opening:hover {
  border-color:var(--sage); background:var(--sage-tint); transform:translateY(-1px);
}
.opening[aria-pressed="true"] {
  background:var(--forest); border-color:var(--forest); color:var(--on-forest);
  transform:translateY(-1px);
  box-shadow:0 8px 16px -10px rgba(58,81,41,.8);
}
.opening-when { display:flex; flex-direction:column; gap:.1rem; }
.opening-when b { font-size:.92rem; font-weight:500; }
.opening-when span {
  font-size:.8rem; opacity:.72; font-variant-numeric:tabular-nums;
}
.opening-time {
  font-size:1.02rem; font-weight:500; font-variant-numeric:tabular-nums;
}
.opening-more {
  margin:.85rem 0 0; text-align:center;
  font-size:.8rem; color:var(--ink-3);
}

.avail-foot {
  border-top:1px solid var(--line-soft); margin-top:1.1rem; padding-top:1.1rem;
  display:flex; flex-direction:column; gap:.75rem;
}
.avail-note { font-size:.82rem; color:var(--ink-3); line-height:1.85; margin:0; }
.avail-note.is-selection { color:var(--forest-deep); animation:answer .4s var(--ease) both; }
.avail-fine { font-size:.78rem; color:var(--ink-3); text-align:center; margin:0; }

/* Availability card states */
.skeleton-row {
  height:48px; border-radius:10px; margin-bottom:.55rem;
  background:linear-gradient(90deg, var(--paper-2) 25%, var(--line-soft) 37%, var(--paper-2) 63%);
  background-size:400% 100%;
  animation:shimmer 1.6s ease-in-out infinite;
}
.card-state {
  display:flex; flex-direction:column; align-items:center; text-align:center;
  gap:.9rem; padding:2.5rem 1rem;
}
.card-state p { margin:0; color:var(--ink-2); font-size:.94rem; max-width:20rem; }
.card-state-icon {
  width:38px; height:38px; border-radius:999px; border:1px solid var(--field-line);
  color:var(--ink-2); display:flex; align-items:center; justify-content:center; font-size:1.1rem;
}

/* ── FAQ ───────────────────────────────────────────────────────────────── */
.faq details { border-bottom:1px solid var(--line-soft); }
.faq summary {
  display:flex; align-items:center; justify-content:space-between; gap:1.5rem;
  cursor:pointer; list-style:none; padding:1.15rem 0;
  font-weight:500; font-size:.99rem; color:var(--ink);
}
.faq summary::-webkit-details-marker { display:none; }
.faq summary:hover { color:var(--forest-deep); }
/* Physical borders + rotation, not logical properties — logical properties
   flip under RTL and produce a sideways arrow. */
.chevron {
  width:7px; height:7px; flex:none; margin-bottom:3px;
  border-right:1.5px solid var(--ink-3); border-bottom:1.5px solid var(--ink-3);
  transform:rotate(45deg); transition:transform .2s ease, margin .2s ease;
}
.faq details[open] .chevron { transform:rotate(-135deg); margin-bottom:-3px; }
.faq details p {
  margin:0 0 1.25rem; color:var(--ink-2); font-size:.96rem; max-width:36rem;
  animation:answer .38s var(--ease) both;
}

/* ── Manifesto ───────────────────────────────────────────────────────────
   Was a tall arch-shaped tint with the quote floating centred inside it.
   The arch is the page's one non-rectangular shape and it already carries
   the portrait; using it a second time as a background blob behind text
   made the section read as decoration with a caption rather than as the
   page's one moment of voice — and the blob's edges did not agree with the
   quote's own shape at any width.

   The replacement is an editorial pull-quote: a tinted panel sitting in the
   measure, opened by a heavy sage bar on the reading edge. It borrows its
   geometry from the cards the rest of the page already uses, so it reads as
   part of the document, and it holds its proportions at every width instead
   of being a fixed aspect-ratio shape text has to fit inside.
   ─────────────────────────────────────────────────────────────────────── */
.manifesto {
  background:var(--sage-tint);
  border-block:1px solid color-mix(in srgb, var(--sage) 42%, transparent);
}
.manifesto > .wrap { padding-block:clamp(3.25rem,6.5vw,5rem); }

/* Reading-edge aligned, not centred. Centred text at this size floats — it
   has no edge to start from, so each line begins somewhere different and the
   eye has to find it. Against the wrap's own edge the quote reads as
   something written rather than something displayed. */
.manifesto-panel {
  max-width:40rem;
  display:flex; flex-direction:column; gap:1.5rem;
}
.manifesto blockquote {
  margin:0;
  font-family:var(--display); font-weight:300;
  font-size:clamp(1.3rem,2.9vw,1.85rem); line-height:1.85; color:var(--ink);
  text-wrap:balance;
}
/* Short, forest, and three pixels tall rather than one — at 1px on this tint
   it disappeared, and this is the section's only ornament. */
.manifesto .rule {
  width:38px; height:3px; border-radius:2px;
  background:var(--forest); flex:none;
}

/* ── Contact form ──────────────────────────────────────────────────────── */
.contact { background:var(--paper-2); }
.form-card {
  max-width:31rem; margin-inline:auto;
  background:var(--surface); border:1px solid var(--line);
  border-radius:22px; padding:clamp(1.6rem,4vw,2.4rem);
}
.form-card h2 { text-align:center; }
.form-card > p { text-align:center; margin:.9rem 0 1.6rem; font-size:.92rem; color:var(--ink-2); }
/* The error line is positioned out of flow over reserved space. Letting it
   push the layout means a blur-triggered message moves the submit button
   between press and release, and the person's first tap does nothing. */
.field {
  position:relative; display:flex; flex-direction:column; gap:.45rem;
  padding-bottom:1.25rem;
}
.field label { font-size:.84rem; color:var(--ink-2); }
.field input, .field select, .field textarea {
  font-family:inherit; font-size:.95rem; color:var(--ink);
  background:var(--surface); border:1px solid var(--field-line); border-radius:12px;
  padding:.85rem 1rem; width:100%;
  transition:border-color .2s ease;
}
.field input:hover, .field select:hover, .field textarea:hover { border-color:var(--sage); }
.field textarea { resize:vertical; min-height:5.5rem; line-height:1.9; }
.field .num-input { font-variant-numeric:tabular-nums; }
.field[data-invalid="true"] input,
.field[data-invalid="true"] textarea { border-color:var(--danger); }
.field-error {
  position:absolute; inset-inline:0; bottom:0;
  font-size:.78rem; color:var(--danger); line-height:1.6;
}
form { display:flex; flex-direction:column; gap:.4rem; }
form .btn { margin-top:.75rem; }
.form-status {
  display:flex; flex-direction:column; align-items:center; gap:.9rem;
  padding:1.5rem 0; text-align:center;
}
.form-status .tick {
  width:44px; height:44px; border-radius:999px;
  background:var(--sage-tint); color:var(--forest-deep);
  display:flex; align-items:center; justify-content:center; font-size:1.25rem;
  animation:pop .45s var(--ease) both;
}
.form-status p { margin:0; font-size:.98rem; color:var(--ink); max-width:22rem; }
.form-error {
  font-size:.85rem; color:var(--danger); background:var(--danger-tint);
  border-radius:10px; padding:.75rem 1rem; margin:0; line-height:1.9;
}

/* ── Closing + footer ──────────────────────────────────────────────────── */
.closing { border-top:1px solid var(--line); }
.closing > .wrap {
  padding-block:clamp(3rem,6vw,4.5rem);
  display:flex; flex-direction:column; align-items:center; gap:1.4rem; text-align:center;
}

.site-footer { border-top:1px solid var(--line); background:var(--paper-2); }
.site-footer > .wrap { padding-block:clamp(2.5rem,5vw,3.5rem) 2rem; }
.footer-grid { display:grid; grid-template-columns:1.4fr 1fr 1fr; gap:3rem; }
.footer-col { display:flex; flex-direction:column; gap:.7rem; }
.footer-col h3 { font-size:.78rem; color:var(--ink-3); font-weight:400; margin-bottom:.2rem; }
.footer-col a, .footer-col span { color:var(--ink-2); font-size:.9rem; text-decoration:none; }
.footer-col a:hover { color:var(--ink); text-decoration:underline; }
.footer-logo {
  height:112px; width:112px; align-self:flex-start;
  object-fit:contain;
}

/* ── Social links ─────────────────────────────────────────────────────────
   The platform marks stand in for their names: at this size the glyph is
   read faster than the word, and it leaves the handle — the part that is
   actually hers and worth reading — as the only text on the row. Monochrome
   on purpose. Three brand colours in the corner of a page built on one
   green would be the loudest thing on it, and they would each need a second
   value to survive the dark theme.

   The handle is isolated as an LTR run: `@` is bidi-neutral, so inside the
   Persian footer "@dr.sayeh.hoseini" otherwise renders with its `@` stranded
   on the far end. */
.social { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:.1rem; }
.social-link {
  display:flex; align-items:center; gap:.6rem;
  padding-block:.45rem;
  color:var(--ink-2); font-size:.9rem; text-decoration:none;
}
.social-link svg {
  width:18px; height:18px; flex:none; fill:currentColor;
  color:var(--ink-3); transition:color .2s ease;
}
.footer-col .social-link:hover { color:var(--ink); text-decoration:none; }
.social-link:hover svg { color:var(--forest); }
.social-link bdi { text-underline-offset:4px; }
.footer-col .social-link:hover bdi { text-decoration:underline; }

/* The menu copy drops the handles: it is a row of three marks under the
   links, not a second contact list. */
.social-compact { flex-direction:row; gap:.35rem; margin-top:.9rem; }
.social-compact .social-link {
  width:2.75rem; height:2.75rem; justify-content:center; gap:0;
  border-radius:14px; background:color-mix(in srgb, var(--ink) 5%, transparent);
}
.social-compact .social-link svg { width:20px; height:20px; }
.footer-bottom {
  border-top:1px solid var(--line); margin-top:2.5rem; padding-top:1.2rem;
  display:flex; justify-content:space-between; flex-wrap:wrap; gap:.6rem;
  font-size:.8rem; color:var(--ink-3);
}

/* ── Mobile booking bar ───────────────────────────────────────────────────
   On a phone the hero fills the screen and the header CTA is behind the menu
   button, which leaves the page's whole purpose two scrolls away. This puts
   it back one tap — and retreats once the availability card is on screen,
   where it would only be covering the thing it points at.
   ─────────────────────────────────────────────────────────────────────── */
.mobile-cta {
  position:fixed; inset-inline:0; bottom:0; z-index:60;
  padding:.7rem 1.25rem calc(.7rem + env(safe-area-inset-bottom, 0px));
  background:color-mix(in srgb, var(--paper) 90%, transparent);
  backdrop-filter:blur(12px);
  -webkit-backdrop-filter:blur(12px);
  border-top:1px solid var(--line);
  transform:translateY(130%);
  transition:transform .32s var(--ease);
}
.mobile-cta.is-visible { transform:none; }
@media (min-width: 1000px) { .mobile-cta { display:none; } }
/* The bar is fixed, so it takes no flow space and parks itself over the last
   two lines of the footer — the crisis note among them, which is the one
   line on the page that must never be half-covered. The footer buys back the
   bar's own height wherever the bar can appear. */
@media (max-width: 999px) {
  .site-footer > .wrap {
    padding-bottom:calc(5.5rem + env(safe-area-inset-bottom, 0px));
  }
}

/* ── Motion ────────────────────────────────────────────────────────────── */
@keyframes pulse   { 0%,100% { opacity:1; transform:scale(1); } 50% { opacity:.35; transform:scale(1.5); } }
@keyframes ring    { 0% { transform:scale(1); opacity:.45; } 70%,100% { transform:scale(3.2); opacity:0; } }
@keyframes shimmer { 0% { background-position:-200% 0; } 100% { background-position:200% 0; } }
@keyframes answer  { from { opacity:0; transform:translateY(-6px); } to { opacity:1; transform:none; } }
@keyframes pop     { 0% { opacity:0; transform:scale(.82); } 60% { transform:scale(1.04); } 100% { opacity:1; transform:scale(1); } }
@keyframes breathe { 0%,100% { transform:scale(1); opacity:.55; } 50% { transform:scale(1.09); opacity:.9; } }
@keyframes slotIn  { from { opacity:0; transform:translateY(5px); } to { opacity:1; transform:none; } }

.opening { animation:slotIn .42s var(--ease) both; }

/* Scoped to .js, which the inline head script sets. Unscoped, a page loaded
   with scripting disabled would render as a blank sheet. */
.js [data-reveal] {
  opacity:0; transform:translateY(18px);
  transition:opacity .8s var(--ease), transform .8s var(--ease);
  transition-delay:calc(var(--reveal-i, 0) * 80ms);
}
.js [data-reveal].is-in { opacity:1; transform:none; }

/* ═══════════════════════════════════════════════════════════════════════
   Sub-pages — /writing, /writing/<slug>, /podcast

   The home page is one long scroll with its own section rhythm. These pages
   are read, not scanned, so they open on a quieter head instead of a hero
   and hand the whole measure to a single column of text.
   ═══════════════════════════════════════════════════════════════════════ */

.nav a.is-current { color:var(--ink); border-bottom-color:var(--sage); }

/* ── Page head ─────────────────────────────────────────────────────────── */
/* The header is sticky, so it already occupies flow space — this needs the
   hero's own padding, not an extra header's worth on top of it. */
.page-head > .wrap {
  padding-block:clamp(2.75rem,6vw,4.5rem) clamp(1.75rem,3.5vw,2.5rem);
  display:flex; flex-direction:column; gap:1.1rem;
}
.page-head .display { max-width:34rem; }

.crumb { display:flex; align-items:center; gap:.5rem; font-size:.82rem; color:var(--ink-3); }
.crumb a { color:var(--ink-3); text-decoration:none; }
.crumb a:hover { color:var(--ink-2); text-decoration:underline; }
.crumb span[aria-hidden] { color:var(--line); }

/* ── Post list (/writing) ──────────────────────────────────────────────── */
.post-list { display:flex; flex-direction:column; }
.post {
  display:flex; flex-direction:column; gap:.55rem;
  padding:1.6rem 0; text-decoration:none; color:inherit;
  border-bottom:1px solid var(--line-soft);
  transition:padding-inline-start .25s var(--ease);
}
.post:first-child { padding-top:0; }
.post:last-child { border-bottom:none; }
.post:hover { padding-inline-start:.6rem; }
.post h2 {
  font-family:var(--display); font-weight:500; font-size:1.16rem;
  line-height:1.8; margin:0; max-width:32rem;
}
.post:hover h2 { color:var(--forest); }
.post p { margin:0; color:var(--ink-2); font-size:.95rem; line-height:1.95; max-width:34rem; }
.post-meta { font-size:.8rem; color:var(--ink-3); }

/* ── Publication card (/writing) ───────────────────────────────────────── */
.publication {
  display:flex; flex-direction:column; gap:1rem; align-items:flex-start;
  padding:1.9rem; border:1px solid var(--line); border-radius:22px;
  background:var(--surface);
}
.pub-badge {
  font-size:.76rem; color:var(--forest-deep);
  background:var(--sage-tint); border-radius:999px; padding:.3rem .8rem;
}
/* The title and subtitle are the book's own English; they set their own
   direction so the Latin text does not reflow inside the RTL column. */
.pub-title { font-family:var(--display); font-weight:500; font-size:1.2rem; line-height:1.65; margin:0; }
.pub-sub { font-size:.88rem; color:var(--ink-3); line-height:1.75; margin:0; }
.pub-facts { display:flex; flex-wrap:wrap; gap:2rem; margin:.4rem 0 .2rem; }
.pub-facts div { display:flex; flex-direction:column; gap:.15rem; }
.pub-facts dt { font-size:.76rem; color:var(--ink-3); }
.pub-facts dd { margin:0; font-size:.92rem; color:var(--ink); }
.publication .btn .meta { margin-inline-start:.4rem; }

/* ── Episodes (/podcast) ───────────────────────────────────────────────── */
.episode {
  display:flex; flex-direction:column; gap:1.1rem;
  padding:1.9rem; border:1px solid var(--line); border-radius:22px;
  background:var(--surface);
}
.episode-head { display:flex; align-items:flex-start; gap:1.1rem; }
.episode-num {
  flex:none; display:flex; align-items:center; justify-content:center;
  width:2.6rem; height:2.6rem; border-radius:999px;
  background:var(--sage-tint); color:var(--forest-deep); font-size:.9rem;
}
.episode-title { min-width:0; }
.episode-title h2 { font-family:var(--display); font-weight:500; font-size:1.16rem; line-height:1.8; margin:0; }
.episode-meta {
  display:flex; flex-wrap:wrap; align-items:center; gap:.5rem;
  margin:.35rem 0 0; font-size:.82rem; color:var(--ink-3);
}
/* The native control is left alone — a hand-built player would have to
   re-earn keyboard support, scrubbing and screen-reader labels that the
   browser already ships. It is only sized and given the page's radius. */
.player { width:100%; height:2.75rem; border-radius:999px; }
.episode-foot { margin:0; font-size:.86rem; }

/* ── Article ───────────────────────────────────────────────────────────── */
.article-body {
  display:flex; flex-direction:column; gap:1.5rem;
  padding-bottom:clamp(2.5rem,5vw,4rem);
  max-width:min(100% - 2.5rem, 40rem); margin-inline:auto;
}
.article-meta { margin:0; font-size:.82rem; color:var(--ink-3); }
.article-body h2 {
  font-family:var(--display); font-weight:500; font-size:1.2rem;
  line-height:1.8; margin:1.6rem 0 -.4rem; max-width:32rem;
}
.article-body .prose { max-width:none; }

.prose-list { margin:0; padding-inline-start:1.2rem; display:flex; flex-direction:column; gap:.9rem; }
.prose-list li { color:var(--ink-2); line-height:2; }
.prose-list li::marker { color:var(--sage); }
.prose-list strong { color:var(--ink); font-weight:500; }

/* The one boxed aside in the articles. Reserved for the crisis note — if a
   second style of callout ever appears, this stops being a signal. */
/* The radius has to follow the bar. A physical `0 12px 12px 0` is right in
   LTR and inside-out in RTL — it squared the corners away from the bar and
   rounded the ones the bar runs along. Logical corner properties track the
   direction the same way the border does. */
.callout {
  border-inline-start:2px solid var(--sage);
  background:var(--paper-2);
  border-radius:12px;
  border-start-start-radius:0; border-end-start-radius:0;
  padding:1.1rem 1.3rem; margin:.6rem 0;
}
.callout p { margin:0; color:var(--ink-2); font-size:.93rem; line-height:1.95; }

.article-source {
  margin:1.4rem 0 0; padding-top:1.4rem; border-top:1px solid var(--line-soft);
  font-size:.85rem; color:var(--ink-3); line-height:1.95;
}

/* ── Questionnaire ─────────────────────────────────────────────────────
   Seventy-five items on a phone is the hard case: six columns per row, and
   a reader who has lost track of what ۴ meant. The legend is therefore
   sticky under the header, and the options are numerals with the wording
   kept above rather than repeated 75 times.
   ─────────────────────────────────────────────────────────────────── */
.q-wrap { max-width:min(100% - 2.5rem, 44rem); margin-inline:auto; }

.q-intro {
  display:flex; flex-direction:column; gap:1.2rem; align-items:flex-start;
  padding:1.9rem; border:1px solid var(--line); border-radius:22px;
  background:var(--surface);
}
.q-intro h2 { font-family:var(--display); font-weight:500; font-size:1.2rem; margin:0; }
.q-intro .callout { margin:0; align-self:stretch; }

#q-form { display:flex; flex-direction:column; gap:1.1rem; }

.q-legend {
  /* Measured against the *scrolled* header, and overlapping it slightly: at
     the resting height there was a two-pixel channel between the two bars
     where question text slid past in a thin bright strip. */
  position:sticky; top:calc(var(--header-h-scrolled) - .35rem); z-index:20;
  display:grid; grid-template-columns:repeat(6,1fr); gap:.4rem;
  padding:.7rem .6rem; border:1px solid var(--line); border-radius:14px;
  background:color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  font-size:.7rem; color:var(--ink-3); text-align:center; line-height:1.5;
}
.q-legend span { display:flex; flex-direction:column; gap:.15rem; }
.q-legend .num { color:var(--ink-2); font-size:.82rem; }

.q-progress { display:flex; align-items:center; gap:.8rem; }
.q-progress-track {
  flex:1; height:4px; border-radius:999px; background:var(--line-soft); overflow:hidden;
}
.q-progress-fill {
  height:100%; width:0; border-radius:999px; background:var(--sage);
  transition:width .3s var(--ease);
}

.q-item {
  border:none; border-bottom:1px solid var(--line-soft);
  margin:0; padding:1.15rem 0; display:flex; flex-direction:column; gap:.9rem;
}
.q-item legend {
  float:right; width:100%; padding:0;
  color:var(--ink-2); line-height:1.95; font-size:.96rem;
}
.q-item.is-missing legend { color:var(--danger); }
.q-num { color:var(--ink-3); font-size:.82rem; margin-inline-end:.35rem; }

.q-scale { display:grid; grid-template-columns:repeat(6,1fr); gap:.4rem; clear:both; }
.q-opt { position:relative; display:flex; }
.q-opt input {
  position:absolute; inset:0; width:100%; height:100%; margin:0;
  opacity:0; cursor:pointer;
}
.q-opt span {
  flex:1; display:flex; align-items:center; justify-content:center;
  min-height:2.6rem; border:1px solid var(--field-line); border-radius:10px;
  background:var(--surface); color:var(--ink-3); font-size:.92rem;
  transition:background-color .18s ease, border-color .18s ease, color .18s ease;
}
.q-opt input:hover + span { border-color:var(--sage); }
.q-opt input:focus-visible + span { outline:2px solid var(--forest); outline-offset:2px; }
.q-opt input:checked + span {
  background:var(--forest); border-color:var(--forest); color:var(--on-forest);
}
.q-item.is-missing .q-opt span { border-color:color-mix(in srgb, var(--danger) 45%, transparent); }

.q-nav { display:flex; align-items:center; gap:.8rem; padding-top:.4rem; }

.q-done {
  display:flex; flex-direction:column; gap:1rem; align-items:flex-start;
  padding:1.9rem; border:1px solid var(--line); border-radius:22px;
  background:var(--surface);
}
.q-done h2 { font-family:var(--display); font-weight:500; font-size:1.2rem; margin:0; }
.q-done:focus { outline:none; }

/* ── Responsive ────────────────────────────────────────────────────────── */
/* Seven items now, with /questionnaire alongside /writing and /podcast.
   Tighten the gap before it wraps. */
@media (max-width: 1080px) {
  .nav { gap:1.05rem; }
}

/* Even at the tightened gap the seven labels need about 850px beside the
   brand and the actions, so between here and 760px the nav wrapped onto a
   second row and pushed the header wider than the screen. The burger takes
   over early rather than the row breaking — the mobile menu holds the same
   links with room to spare. The header's booking button goes with the nav,
   so the sticky bottom CTA has to start covering for it at the same width. */
@media (max-width: 999px) {
  .nav, .header-actions .btn { display:none; }
  .menu-btn { display:flex; }
}

@media (max-width: 1000px) {
  .hero-grid { grid-template-columns:1fr; gap:2.75rem; }
  /* Capped but not centred, so once the hero stacked the plate sat hard
     against the reading edge with all the slack on the other side and read
     as a layout that had come apart. */
  .portrait { max-width:22rem; margin-inline:auto; }
}

@media (max-width: 900px) {
  .split, .about-grid, .band-grid { grid-template-columns:1fr; gap:1.75rem; }
  .split-head, .band-head { position:static; }
  /* Two columns holds down to about 620px: the brand block wants the full
     measure, so it spans and the two link lists sit beside each other rather
     than becoming a single 500px-tall stack of nine identical rows. */
  .footer-grid { grid-template-columns:1fr 1fr; gap:2rem 2.5rem; }
  .footer-col:first-child { grid-column:1 / -1; }
  .creds { grid-template-columns:1fr 1fr; }
  .cred { padding-inline:0 1.5rem; border-inline-start:none; }
  .cred:nth-child(n+3) { border-top:1px solid var(--line-soft); }
}

@media (max-width: 760px) {
  html { scroll-padding-top:5.5rem; }
  .areas { grid-template-columns:1fr; }
  .fact-row { flex-direction:column; gap:.5rem; }
  .fact-row h3 { width:auto; }
  /* The row already stacks its own two halves; nothing to reflow. */
  /* The card title and its freshness stamp are a two-item baseline row that
     stops fitting once «به‌روزرسانی ۱۲ دقیقه پیش» is the second half of it;
     without the wrap the stamp squeezes the title into a second line inside
     a flex item that was never sized for one. */
  .avail-head { flex-wrap:wrap; gap:.15rem .75rem; }
  .footer-bottom { flex-direction:column; }
  .avail-card { padding:1.25rem; }
  .band::before { display:none; }
  .episode, .publication { padding:1.35rem; }
  .episode-head { gap:.85rem; }
  .pub-facts { gap:1.25rem; }
  .faq summary { gap:1rem; }
  .post h2, .episode-title h2, .article-body h2, .pub-title { font-size:1.1rem; }
  .q-intro, .q-done { padding:1.35rem; }
  /* Six labelled columns will not fit a phone. The wording drops to the
     two anchors and the numerals carry the rest — the sticky legend is
     still on screen, so the scale is never more than a glance away. */
  .q-legend { grid-template-columns:repeat(6,1fr); gap:.25rem; font-size:0; padding:.55rem .4rem; }
  .q-legend span:not(:first-child):not(:last-child) { font-size:0; }
  .q-legend .num { font-size:.8rem; }
  .q-legend span:first-child, .q-legend span:last-child { font-size:.62rem; }
  .q-scale { gap:.3rem; }
  .q-opt span { min-height:2.9rem; font-size:.88rem; }
  .q-item legend { font-size:.94rem; }
  .q-nav { flex-direction:column-reverse; align-items:stretch; }
  .q-nav .btn { justify-content:center; }
}

/* ── Phone ────────────────────────────────────────────────────────────────
   Most visitors arrive here. Everything below is about the two things a
   narrow screen gets wrong on its own: rows built for a wide viewport that
   turn into tall stacks, and controls that were sized against a mouse.
   ─────────────────────────────────────────────────────────────────────── */
@media (max-width: 620px) {
  .footer-grid { grid-template-columns:1fr; gap:1.75rem; }
  .footer-col:first-child { grid-column:auto; }
  /* The link lists become the footer's bulk once stacked, so they get a
     hairline each — without one the three groups read as a single
     eighteen-item list with two stray headings in it. */
  .footer-col + .footer-col { border-top:1px solid var(--line-soft); padding-top:1.5rem; }
  .footer-logo { height:88px; width:88px; }

  /* The primary action stops sharing a row with the quiet link: side by side
     at this width the button takes the measure and the link is left with a
     sliver, and the link's own tap target was only its text box. */
  .hero-actions { flex-direction:column; align-items:stretch; gap:.35rem; }
  .hero-actions .btn { width:100%; }
  .hero-actions .link-quiet {
    display:flex; align-items:center; justify-content:center; min-height:44px;
  }

  /* Four label-over-value blocks is 300px of scroll for four facts. As rows
     they are the same four facts in a third of the height, and they read as
     what they are — a spec table for the practice. */
  .creds { grid-template-columns:1fr; }
  .cred {
    display:flex; align-items:baseline; justify-content:space-between; gap:1.25rem;
    padding:.95rem 0; border-inline-start:none;
  }
  .cred + .cred { border-top:1px solid var(--line-soft); }
  .cred-label { flex:1 1 auto; min-width:0; }
  .cred-value { flex:none; text-align:end; margin-top:0; }

  .form-card { border-radius:18px; }
  .publication .btn, .q-nav .btn { width:100%; }

  /* Stacked footer links and the availability card's "show more" come out at
     29px and 37px — clear of the 24px AA floor, but tight for a thumb in a
     list of seven near-identical labels. Padding, not `display:flex` and a
     min-height: the contact links are «اینستاگرام — <bdi>@handle</bdi>», and
     flex makes the label and the bdi separate flex items, which drops the
     whitespace around the dash and renders «اینستاگرام—@handle». */
  .footer-col { gap:.15rem; }
  .footer-col a { padding-block:.5rem; }
}

/* The header is a fixed set of controls and a name, and below about 480 the
   name is what stops fitting — «دکتر سایه حسینی» and "Dr Sayeh Hosseini" are
   both wider than the space left once the language switch, the theme toggle
   and the burger have taken theirs. The monogram carries the identity on its
   own here, and the page's own h1 says the name two lines further down.

   `.sr-only`, not `display:none`: hiding it outright would leave the brand
   link with no accessible name at all, since the logo's alt is empty by
   design (it is decorative next to the text it sits beside). */
@media (max-width: 480px) {
  .brand-text {
    position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
  }
}

@media (max-width: 420px) {
  .brand-role { display:none; }
  .btn { padding:.95rem 1.5rem; }
  .cred { gap:1rem; }
  .cred-label { font-size:.74rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior:auto; }
  *, *::before, *::after {
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
  .js [data-reveal] { opacity:1; transform:none; }
  .step-rail-fill { transition:none; }
}

@media print {
  .site-header, .hero-halo, .hero-halo-2, body::after, .menu-btn { display:none; }
  body { background:#fff; color:#000; }
}


/* ═══════════════════════════════════════════════════════════════════════
   REDESIGN LAYER — August 2026
   Appended, not merged, so the diff against the shipped sheet stays legible.
   Five changes, in the order they matter:
     0. Shipped at intensity ۳ of the three densities reviewed: display
        weight 700, leading 1.14–1.24, section padding ~3.6rem.
     1. The weight ladder inverts at display sizes. 300 at 2.8rem read faint
        rather than calm — that single value is what made the page feel
        lifeless. Display goes to 700 and leading tightens from 1.55 to 1.16.
     2. Sections sit closer together. The vertical rhythm was loose enough
        that each block read as isolated.
     3. Section numerals become oversized ghost figures — the page's spine,
        now visible from across the room.
     4. Practice areas become a hairline grid of cells instead of a bare
        list, so the section is built rather than typed.
     5. The manifesto quote is staged: labelled rule, two clauses, revealed
        in sequence when it enters view.
   Everything still styles through tokens, so dark mode follows for free.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1. Weight ladder ──────────────────────────────────────────────────── */
.display { font-weight:700; line-height:1.16; }
.hero .display {
  font-size:clamp(2.5rem,5.4vw,4.1rem);
  line-height:1.14;
  max-width:20ch;
}
/* One phrase in accent so the headline has an internal turn. */
.hero .display .accent { color:var(--forest); }
h2.display { font-size:clamp(1.6rem,3vw,2.35rem); line-height:1.24; }
.lead { font-size:1.09rem; }

/* ── 2. Vertical rhythm ────────────────────────────────────────────────── */
.section > .wrap { padding-block:clamp(2.5rem,4.2vw,3.6rem); }
.band > .wrap { padding-block:clamp(2.75rem,4.8vw,4rem); }
.split { gap:clamp(2rem,4vw,3rem); }

/* ── 3. Ghost section numerals ─────────────────────────────────────────── */
.sec-index {
  display:block;
  font-size:clamp(2.7rem,5.4vw,4.1rem);
  font-weight:700;
  line-height:.9;
  color:color-mix(in srgb, var(--sage) 42%, var(--paper));
  margin-bottom:1rem;
}
.sec-index::after { display:none; }
.band .sec-index { color:color-mix(in srgb, var(--on-band) 22%, transparent); }

/* ── 4. Practice areas as a hairline grid ──────────────────────────────── */
.areas {
  display:grid; grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));
  gap:1px; column-gap:1px;
  background:var(--line); border:1px solid var(--line);
}
.areas li {
  display:flex; align-items:center; gap:.65rem;
  background:var(--paper); border-bottom:none;
  padding:1rem 1.1rem;
  transition:background .22s var(--ease);
}
.areas li::before {
  content:''; flex:none; width:5px; height:5px; border-radius:999px;
  background:var(--sage);
}
.areas li:hover { background:var(--sage-tint); }

/* The session facts and process steps get the same small physical response
   on hover — the page answers the cursor everywhere now. */
.fact-row {
  padding:1.15rem 0;
  transition:padding-inline-start .25s var(--ease);
}
.fact-row:hover { padding-inline-start:.5rem; }
.step { transition:padding-inline-start .25s var(--ease); }
.step:hover { padding-inline-start:.5rem; }

/* ── 5. The manifesto, staged ──────────────────────────────────────────── */
.manifesto > .wrap { padding-block:clamp(3.25rem,6vw,4.75rem); }
.manifesto { position:relative; overflow:hidden; }
/* Two slow washes in the ground so the section is lit rather than filled.
   26s+ cycles, per the ambient-motion rule. */
.manifesto::before, .manifesto::after {
  content:''; position:absolute; border-radius:999px; pointer-events:none;
}
.manifesto::before {
  top:-40%; inset-inline-end:8%; width:38vw; height:38vw;
  background:radial-gradient(circle at 50% 50%,
    color-mix(in srgb, var(--surface) 88%, transparent), transparent 68%);
  animation:manifesto-drift 27s ease-in-out infinite;
}
.manifesto::after {
  bottom:-45%; inset-inline-start:2%; width:34vw; height:34vw;
  background:radial-gradient(circle at 50% 50%,
    color-mix(in srgb, var(--forest) 14%, transparent), transparent 70%);
  animation:manifesto-drift 34s ease-in-out infinite reverse;
}
@keyframes manifesto-drift {
  0%,100% { transform:translate3d(0,0,0) scale(1); }
  50%     { transform:translate3d(-3%,2%,0) scale(1.1); }
}

.manifesto-panel { position:relative; max-width:none; gap:clamp(1.6rem,2.5vw,2.5rem); }

/* The rule becomes a labelled divider: the label is the ::before, the line
   that sweeps out is the ::after. No extra markup. */
.manifesto .rule {
  width:100%; height:auto; background:none; border-radius:0;
  display:flex; align-items:center; gap:.85rem;
  font-size:.8rem; font-weight:500; color:var(--forest);
}
.manifesto .rule::before {
  content:'اصل کار'; white-space:nowrap;
  padding-inline-start:calc(28px + .85rem);
  background:linear-gradient(to left, var(--sage) 28px, transparent 28px) no-repeat;
  background-position:right center; background-size:28px 1px;
}
html[lang='en'] .manifesto .rule::before { content:'The principle'; }
.manifesto .rule::after {
  content:''; flex:1; height:1px;
  background:color-mix(in srgb, var(--sage) 62%, transparent);
  transform:scaleX(0); transform-origin:right;
  transition:transform 1.1s .1s var(--ease);
}
.manifesto-panel.is-in .rule::after { transform:scaleX(1); }
:root:not(.js) .manifesto .rule::after { transform:scaleX(1); }

.manifesto blockquote {
  font-weight:700;
  font-size:clamp(1.7rem,4.2vw,2.85rem);
  line-height:1.3;
  max-width:47rem;
  color:var(--ink);
}
/* Second clause in accent and revealed after the first — the sentence has a
   turn in it, so the reveal has one too. */
.manifesto blockquote .q-b { display:block; margin-top:.35em; color:var(--forest); }
.js .manifesto blockquote .q-a,
.js .manifesto blockquote .q-b { opacity:0; }
.manifesto-panel.is-in blockquote .q-a { animation:manifesto-line .95s .2s var(--ease) both; }
.manifesto-panel.is-in blockquote .q-b { animation:manifesto-line .95s .56s var(--ease) both; }
@keyframes manifesto-line {
  from { opacity:0; transform:translateY(16px); }
  to   { opacity:1; transform:none; }
}

@media (prefers-reduced-motion: reduce) {
  .manifesto::before, .manifesto::after { animation:none; }
  .manifesto .rule::after { transform:scaleX(1); transition:none; }
  .js .manifesto blockquote .q-a,
  .js .manifesto blockquote .q-b { opacity:1; animation:none; }
}

@media (max-width: 620px) {
  .sec-index { font-size:2.5rem; }
  .areas { grid-template-columns:1fr; }
}


/* ── 6. Inner pages ──────────────────────────────────────────────────────
   /writing, /podcast, /questionnaire and the article pages inherit
   everything above (weight ladder, rhythm, ghost numerals). These are the
   set pieces that only exist on those pages, brought to the same density.
   ─────────────────────────────────────────────────────────────────────── */

/* Page heads sit closer and land heavier, matching the homepage hero. */
.page-head > .wrap { padding-block:clamp(2.5rem,5vw,4rem) clamp(1.75rem,3vw,2.5rem); }
.page-head .display { font-size:clamp(2.2rem,4.8vw,3.5rem); line-height:1.16; }

/* Post rows become cells in a hairline stack — the same cell treatment the
   practice-areas grid gets, so the two pages read as one system. */
.post-list { border:1px solid var(--line); background:var(--line); gap:1px; }
.post {
  background:var(--paper);
  padding:1.5rem 1.4rem;
  border-bottom:none;
  gap:.5rem;
}
.post:first-child { padding-top:1.5rem; }
.post:hover { background:var(--surface); padding-inline-start:1.9rem; }
.post h2 { font-weight:600; font-size:1.2rem; line-height:1.55; }
.post p { line-height:1.9; }

/* Publication card: hairline, per the Two-Shadow Rule, but denser inside
   and with the facts row gridded rather than floating. */
.publication { padding:clamp(1.5rem,3vw,2.1rem); }
.pub-title { font-weight:600; line-height:1.35; }
.pub-facts {
  display:grid; grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));
  gap:1px; background:var(--line);
  border:1px solid var(--line); margin-top:1.5rem;
}
.pub-facts > div { background:var(--paper); padding:.9rem 1rem; margin:0; }
.pub-facts dt { font-size:.76rem; color:var(--ink-3); }
.pub-facts dd { margin:.2rem 0 0; font-size:.94rem; font-weight:500; color:var(--ink); }

/* Episodes: same cell rhythm as posts, with the episode numeral picking up
   the ghost-figure treatment at a smaller scale. */
.episode-head { align-items:baseline; }
.episode-num {
  font-size:1.9rem; font-weight:700; line-height:1;
  color:color-mix(in srgb, var(--sage) 52%, var(--paper));
}
.episode-title h2 { font-weight:600; font-size:1.18rem; line-height:1.55; }

/* Questionnaire: the scale options are the one thing a person operates
   twenty times in a row, so they get the strongest hover response on the
   site. Items sit tighter; the legend stays sticky. */
.q-item { padding-block:1.15rem; }
.q-item legend { font-weight:400; line-height:1.85; }
.q-num {
  font-weight:700; color:color-mix(in srgb, var(--sage) 62%, var(--ink));
}
.q-opt { transition:background .18s var(--ease), transform .18s var(--ease); }
.q-opt:hover { background:var(--sage-tint); transform:translateY(-1px); }
.q-intro { padding:clamp(1.4rem,3vw,2rem); }
.q-intro h2 { font-weight:600; font-size:1.18rem; }

/* Article body: the reading measure was already right — only the headings
   change, to match the new ladder. */
.article-body h2 { font-weight:600; font-size:clamp(1.3rem,2.4vw,1.6rem); line-height:1.45; }
.article-body h3 { font-weight:600; font-size:1.06rem; }
.article-meta { font-size:.84rem; color:var(--ink-3); }

/* The closing line on every page gets the display ladder too. */
.closing .display { font-size:clamp(1.75rem,3.8vw,2.6rem); line-height:1.2; }

@media (max-width: 620px) {
  .post { padding-inline:1.1rem; }
  .post:hover { padding-inline-start:1.4rem; }
}
