/*
 * Component styles for the "Меридиан" WordPress templates.
 * Ported 1:1 (same values, same class names) from the Astro reference at
 * _migration-reference/site/src/components/*.astro — extended step by step
 * as each PHP template is built, not all at once.
 *
 * Currently covers: site-nav, byline (expert), marks (dot/ring), pills,
 * stages timeline, method-list, price-list, related-links, in-progress
 * notice. Homepage / archive / form pieces are added in later steps.
 */

/* site footer (redesigned 2026-07-13) — solid jade fill, 3 columns. Jade
   itself doesn't shift between light/dark themes (only paper/ink/line do —
   see the :root[data-theme] overrides at the top of style.css), so footer
   text is hardcoded #fff/rgba(255,255,255,x) here rather than var(--paper)
   — same reasoning .btn-primary/.site-nav__cta already use hardcoded #fff
   on a jade background instead of a theme variable, because var(--paper)
   flips to a DARK tone in dark mode and would go illegible against jade. */
.site-footer {
  padding: 40px;
  background: var(--jade);
  border: none;
  border-radius: 16px;
  margin-top: 28px;
}
.site-footer__grid { display: grid; grid-template-columns: 1.1fr 1fr 1fr 1fr; gap: 28px; }
.site-footer__logo { font-family: var(--font-display); font-size: 20px; color: #fff; margin-bottom: 8px; }
.site-footer__tagline { font-size: 13px; color: rgba(255, 255, 255, 0.75); max-width: 38ch; margin: 0 0 14px; }
.site-footer__col-title { display: block; font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: rgba(255, 255, 255, 0.6); margin: 0 0 10px; }
.site-footer__col-title--spaced { margin-top: 18px; }
.site-footer__col { display: flex; flex-direction: column; gap: 8px; }
.site-footer__col a { font-size: 13.5px; color: #fff; text-decoration: none; opacity: .9; }
.site-footer__col a:hover { opacity: 1; text-decoration: underline; }
.site-footer__socials { display: flex; gap: 10px; margin-bottom: 6px; }
.site-footer__social {
  box-sizing: border-box;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
}
.site-footer__social svg { width: 17px; height: 17px; }
.site-footer__social:hover { background: rgba(255, 255, 255, 0.14); }
.site-footer__disclaimer p { font-size: 12.5px; color: rgba(255, 255, 255, 0.75); margin: 0 0 10px; line-height: 1.5; }
.site-footer__address, .site-footer__email { font-size: 12px !important; color: rgba(255, 255, 255, 0.55) !important; }
.site-footer__bottom {
  margin-top: 28px;
  padding-top: 18px;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  font-size: 12px;
  color: rgba(255, 255, 255, 0.6);
}
@media (max-width: 760px) {
  .site-footer__grid { grid-template-columns: 1fr; gap: 24px; }
}
@media (max-width: 640px) {
  .site-footer { padding: 28px 20px; }
}

.not-found { text-align: center; padding: 64px 40px; }
.not-found h1 { margin: 8px 0 12px; }
.not-found .intro { margin: 0 auto 26px; }
.not-found__actions { display: flex; justify-content: center; gap: 14px; flex-wrap: wrap; }
@media (max-width: 640px) { .not-found { padding: 40px 20px; } }

/* site nav (ported from SiteNav.astro) — sticky (2026-07-13): stays pinned
   to the top of the viewport while scrolling. The hairline border-bottom
   alone reads as too thin once the nav sits on top of scrolling content
   with the same background — .is-stuck (toggled by a scroll listener
   below) deepens the shadow past the first few pixels of scroll so the
   nav still reads as "resting on the page" at scrollTop 0.
   Flat, un-carded, fluid-gutter treatment (2026-07-17) is now the sole,
   unconditional style: every template on the site runs the wide-layout
   system (either body.home or body.uses-wide-layout — verified via a
   grep across every body_class() call in the theme, zero exceptions
   left), so there's no template left that needs the old --paper-card/
   border-radius/920px-constrained "boxed card" look this rule used to
   have as its base, overridden separately by body.home AND body.uses-
   wide-layout (two copies of the same override, which is exactly how
   they drifted — see the link-centering rule below). */
.site-nav {
  display: flex;
  gap: 4px;
  padding: 14px clamp(20px, 4vw, 64px);
  background: var(--paper);
  border: none;
  border-radius: 0;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 40;
  box-shadow: 0 1px 0 var(--line);
  transition: box-shadow .2s ease;
}
.site-nav.is-stuck {
  box-shadow: 0 6px 18px rgba(31, 42, 51, 0.14), 0 1px 0 var(--line);
}
/* Links center in the space between the nav's left edge and the CTA
   button — used to be a homepage-only behaviour (left-aligned
   everywhere else), which read as visibly inconsistent once every
   other template adopted the same wide frame the homepage already had.
   Same reasoning as the parent rule above: one unconditional style now,
   not a per-template opt-in. */
.site-nav__links { display: flex; flex: 1; flex-wrap: wrap; gap: 4px; justify-content: center; }
.site-nav a {
  font-family: var(--font-body);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 8px 14px;
  border-radius: 6px;
}
.site-nav a:hover, .site-nav a:focus-visible {
  background: var(--jade-soft);
  color: var(--jade);
}
@media (max-width: 640px) {
  .site-nav { padding: 12px 16px; flex-wrap: wrap; }
}

/* Nav CTA — sized to the nav bar's own proportions (not .btn-primary's
   48px-tall version, which is built for hero/section contexts), but same
   jade-fill treatment so it still reads as *the* action among plain nav
   links. Pushed to the far right via margin-left:auto; on narrow screens
   it drops to its own full-width row instead of fighting the wrapped links
   for space. */
.site-nav__cta {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 8px 16px;
  background: var(--jade);
  color: #fff;
  border: none;
  border-radius: 6px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 13.5px;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.site-nav__cta:hover { opacity: .9; }
@media (max-width: 640px) {
  /* Also bumps padding/min-height to a proper >=44px tap target — the
     desktop 8px/13.5px sizing reads fine next to text nav links on a
     mouse, but is too short to comfortably tap once it drops to its own
     full-width row on mobile. */
  .site-nav__cta { margin-left: 0; width: 100%; order: 10; padding: 13px 16px; min-height: 44px; }
}

/* Astra parent theme's built-in "scroll to top" button defaults to
   Astra's own blue accent, which isn't in the Меридиан palette at all —
   re-skin it to jade/ink to match everything else. */
#ast-scroll-top {
  background-color: var(--jade) !important;
}
#ast-scroll-top:hover {
  background-color: var(--jade-soft) !important;
}
#ast-scroll-top .ast-scroll-top-icon {
  color: var(--paper) !important;
}
#ast-scroll-top:hover .ast-scroll-top-icon {
  color: var(--jade) !important;
}

/* -------------------------------------------------------------------
 * Expert Review re-skin — the plugin defaults to a "purple-1" preset
 * (generic lavender gradient + violet avatar circle) that has nothing to
 * do with "Меридиан". It exposes its whole palette as CSS custom
 * properties on the .expert-review wrapper (see wp-content/plugins/
 * expert-review/assets/public/css/styles.min.css), so re-skinning it is a
 * few token overrides, not a rewrite of its markup. !important is needed
 * because the plugin's own .expert-review--color-purple-1 rule sets the
 * same custom properties later in its stylesheet.
 * ------------------------------------------------------------------ */
.expert-review {
  --expert-review-main-color: var(--gold) !important;
  --expert-review-main-color-gradient: var(--jade) !important;
  --expert-review-main-bg: var(--paper) !important;
  --expert-review-text-color: var(--ink) !important;
  --expert-review-text-color-light: var(--ink-soft) !important;
}
.expert-review-expert {
  background: var(--paper) !important;
  border: 1px solid var(--line) !important;
  border-radius: 8px !important;
}

/* napravlenie/metod detail header — icon + eyebrow/h1, see
   inc/helpers.php:spina_group_diagram() and assets/animations.css for the
   icon's own line-draw/pulse/hover behaviour. */
.napr-header { display: flex; align-items: flex-start; gap: 22px; }
.napr-header__icon { width: 56px; flex-shrink: 0; margin-top: 2px; }
.napr-header__text { flex: 1; min-width: 0; }
.group-diagram--plain { width: 100%; height: 100%; color: var(--ink-soft); }
@media (max-width: 640px) {
  .napr-header { gap: 14px; }
  .napr-header__icon { width: 42px; }
}

/* Клиника has no group/icon concept (not part of napravlenie_group/
   metod_group), so it doesn't get a .napr-header diagram — a simple jade
   accent rule gives the text column presence on its own; the header block
   as a whole now reuses .gorod-hero (photo left, text right) once a
   featured image is set — see single-klinika.php. */
.klinika-header {
  border-left: 4px solid var(--jade);
  padding-left: 18px;
}
/* No featured photo yet (every klinika right now) — .gorod-hero's grid
   still expects two columns, so without media the text would be squeezed
   into the narrower (1fr) column with a dead gap beside it. Let it span
   both columns instead until a photo is added. */
.gorod-hero--no-photo {
  grid-template-columns: 1fr;
}

/* Contact info (address/phone) — separate from .rx-card on purpose; see
   spina_contact_card() in inc/helpers.php for why.
   2026-07-17: background was var(--paper) — the exact same tone as the
   page itself, so the "card" had zero contrast against its surroundings
   and just read as plain text with a barely-visible hairline (found by
   comparing computed background-color against the page's own, not
   assumed from the class name). Switched to var(--paper-card), the
   tone every other card-shaped component on the site actually uses to
   stand out from the page. Whole-block border removed in favour of a
   hairline divider BETWEEN items only — a border around the whole card
   plus a card-colored background reads as "boxed in", not the light
   "resting on the page" look used elsewhere. */
.contact-card {
  background: var(--paper-card);
  border-radius: 8px;
  padding: 16px 20px;
  display: grid;
  gap: 12px;
}
.contact-card__item + .contact-card__item {
  padding-top: 12px;
  border-top: 1px solid var(--line);
}
.contact-card__item { display: flex; align-items: baseline; gap: 12px; }
.contact-card__label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--slate);
  min-width: 72px;
  flex-shrink: 0;
}
.contact-card__value { font-size: 14.5px; color: var(--ink); }
/* Bracketed placeholder values ([КОНТАКТНЫЙ ТЕЛЕФОН] etc.) — deliberately
   unfilled, real data doesn't exist yet (project convention: never invent
   it). Styled to read unmistakably as "not final data" rather than a
   layout bug — muted + italic, same visual language as .in-progress /
   .note use elsewhere for "this isn't done yet" content. */
.ph { color: var(--slate); font-style: italic; }

/* Light-background counterpart to .site-footer__social (2026-07-14, /kontakty/)
   — same spina_social_icon() SVGs, own jade styling since the footer's
   version is hardcoded white for its dark jade background.
   2026-07-17: was a permanently jade-soft-filled circle — jade-soft is
   close enough in lightness to the page background that it read as a
   plain grey button, not a jade accent (confirmed via the same
   before/after contrast comparison as .contact-card above). Matched
   to the footer's own established interaction pattern instead: an
   outline ring at rest (bold and unmistakably jade, not a pale fill),
   filling in only on hover — the same "ring first, fill on interaction"
   language, just adapted for a light background instead of the
   footer's dark one. */
/* 14px above / 20px below — the row used to carry no bottom margin at
   all and sat flush against the disclaimer box under it (2026-07-18 bug
   report). 20px matches the block's own internal rhythm: .contact-card
   padding is 16/20px and the disclaimer's dashed .note box reads as the
   next item in that stack. */
.contact-socials { display: flex; gap: 10px; margin: 14px 0 20px; }
.contact-socials__link {
  box-sizing: border-box;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1.5px solid var(--jade);
  background: transparent;
  color: var(--jade);
  display: flex;
  align-items: center;
  justify-content: center;
}
.contact-socials__link svg { width: 17px; height: 17px; }
.contact-socials__link:hover { background: var(--jade-soft); }

/* Map + office-info card (2026-07-19, /kontakty/ rebuild). Map on the
   left, socials/address/hours on the right — deliberately mirrored from
   the design reference (which had them swapped), per instruction.
   aspect-ratio: 560/400 matches the Yandex widget's own native
   width/height attributes exactly, so the responsive box has the same
   proportions the widget was designed for — just scaled, not cropped. */
.contact-map-card {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  align-items: start;
}
.contact-map-card__map-embed {
  position: relative;
  overflow: hidden;
  border-radius: 8px;
  aspect-ratio: 560 / 400;
  background: var(--paper-card);
}
.contact-map-card__map-embed iframe { display: block; }
.contact-map-card__info { display: flex; flex-direction: column; gap: 14px; }
/* Margin replaced by the flex column's own gap here — the base
   .contact-socials rule's 14px/20px margin was tuned for sitting above
   a full-width .note block (see that rule's own comment); doubling up
   with the gap here would read as an oversized jump before the address
   card. */
.contact-map-card__info .contact-socials { margin: 0; }
@media (max-width: 768px) {
  .contact-map-card { grid-template-columns: 1fr; }
}

/* Breakout to the sitewide wide container (2026-07-19): this is a
   widget/showcase block (map + contacts), not reading prose, so — same
   reasoning as the homepage's own wide bands vs. its narrow text — it
   uses var(--page-w) (~1400px) instead of the page's 780px text column.
   Only THIS card breaks out; everything else on /kontakty/ (intro text,
   "По каким вопросам", the old Контакты block, legal sections) stays in
   the 780px column untouched.
   The math: .page-shell > .section is centered at max-width:780px with
   its own 40px side padding (border-box), so the card's un-shifted left
   edge sits at (section's own centered offset) + 40px. To re-center the
   card on the FULL VIEWPORT at width var(--page-w) instead, the required
   margin-left collapses to a viewport-independent constant:
     (780px − page-w)/2 − 40px
   — both the section's centering and the desired centering scale
   identically with viewport width, so that term cancels out. Verified
   empirically (getComputedStyle) at 1280/1920/3440 before shipping — a
   fixed viewport-relative offset, not a coincidence at one width.
   Desktop-only: below 768px the card already stacks to a single column
   at near-full width, so there's no meaningful gap between 780px and
   page-w to reclaim. */
@media (min-width: 861px) {
  body.page .contact-map-card {
    width: var(--page-w);
    margin-left: calc((780px - var(--page-w)) / 2 - 40px);
  }

  /* The info column is now roughly 2× wider than before (~340px →
     ~680px at 1400px page-w) — icons and the address/hours card are
     enlarged to match, so the right column doesn't read as sparse next
     to the now much taller map. Scoped to .contact-map-card__info only:
     the phone/email card in the old "Контакты" block and "Юридические
     данные" further down the page keep their original compact size. */
  .contact-map-card__info .contact-socials { gap: 16px; }
  .contact-map-card__info .contact-socials__link { width: 56px; height: 56px; }
  .contact-map-card__info .contact-socials__link svg { width: 26px; height: 26px; }
  .contact-map-card__info .contact-card { padding: 24px 28px; gap: 18px; }
  .contact-map-card__info .contact-card__item + .contact-card__item { padding-top: 18px; }
  .contact-map-card__info .contact-card__label { font-size: 12px; min-width: 92px; }
  .contact-map-card__info .contact-card__value { font-size: 18px; }
}

/* doctor / expert byline (ported from Napravlenie.astro).
   Prefixed .spina-byline (not plain .byline): Astra's own frontend.min.css
   ships ".single .byline{display:inline}" for its post-author byline,
   specificity (0,2,0) — that silently beat our (0,1,0) .byline{display:flex}
   on every single-klinika.php page (body has the .single class), collapsing
   the doctor card's flex layout without any error or console warning.
   Found via a real screenshot, not code review — worth remembering to
   prefix custom component classes going forward. */
.expert-section { padding-top: 0; }
.spina-byline {
  display: flex; gap: 16px; align-items: center;
  background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 14px 18px;
}
.spina-byline-mark {
  width: 46px; height: 46px; border-radius: 50%;
  border: 1.5px solid var(--gold);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-size: 20px; color: var(--gold);
  flex-shrink: 0;
}
.expert-name { font-weight: 700; font-size: 14.5px; }
.expert-pos { font-size: 12.5px; color: var(--ink-soft); }

/* marks: solid jade dot (indications) / hollow cinnabar ring (contraindications) */
.marks { list-style: none; margin: 0 0 6px; padding: 0; display: grid; gap: 9px; }
.marks--two-col { grid-template-columns: 1fr 1fr; gap: 8px 24px; }
@media (max-width: 640px) {
  .marks--two-col { grid-template-columns: 1fr; }
}
.marks li { display: flex; align-items: flex-start; gap: 10px; font-size: 14.5px; }
.mark-dot::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--jade); margin-top: 6px; flex-shrink: 0; }
.mark-ring::before { content: ""; width: 9px; height: 9px; border-radius: 50%; border: 1.5px solid var(--seal); margin-top: 5px; flex-shrink: 0; }

/* pills (diagnostics tags etc.) */
.pills { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 4px; }
.pill { font-size: 12.5px; font-family: var(--font-mono); padding: 5px 11px; border-radius: 14px; background: var(--jade-soft); color: var(--jade); }

/* staged treatment timeline */
.stages { list-style: none; margin: 0; padding: 0; border-left: 2px solid var(--line); margin-left: 6px; }
.stages li { position: relative; padding: 0 0 22px 26px; }
.stages li:last-child { padding-bottom: 0; }
.stages li::before {
  content: ""; position: absolute; left: -7px; top: 3px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--paper-card); border: 2px solid var(--jade);
}
.stage-label {
  font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--jade); display: block; margin-bottom: 4px;
}

/* {name, body} groups: conservative/tcm/surgical methods, sizes, types */
.method-list { display: grid; gap: 16px; margin-top: 14px; }
.method-item strong { display: block; font-size: 14.5px; margin-bottom: 4px; }
.method-item p { margin: 0 0 8px; font-size: 14px; color: var(--ink-soft); }

/* diagnostics price list (gryzha-style, with placeholder pricing) — also
   reused as-is for single-klinika.php's "Прайс-лист" block (methods +
   extra services), not a duplicated component. */
.price-list { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 8px; }
/* min-width:0 on both the li (a grid item) and the name span (a flex
   item) — grid/flex items default to min-width:auto, which forbids
   shrinking below their content's min size. Found live (2026-07-17,
   375px, dalian-tunzhentang): one clinic's price column holds a long
   text value ("своя фабрика лекарств на территории") which, combined
   with strong's nowrap below, made every row's min-content wider than
   the mobile container — the grid track sized to it and the whole page
   scrolled horizontally. */
.price-list li { display: flex; justify-content: space-between; gap: 12px; font-size: 14px; border-bottom: 1px solid var(--line); padding-bottom: 8px; min-width: 0; }
/* Deliberately NO min-width:0 / overflow-wrap:anywhere on the name span:
   tried both first, and a real 375px screenshot showed the name being
   squeezed below its longest word and breaking mid-word ("Фитотерапи-я").
   The name keeps its natural flex floor (its longest word) and wraps
   between words only; all the shrinking happens in the price column,
   whose mobile wrap rule below is what actually resolves the overflow. */
.price-list strong { font-family: var(--font-mono); color: var(--jade); white-space: nowrap; font-weight: 600; }
/* nowrap keeps real prices ("650 ¥", "85–170¥") from breaking across
   lines — correct on desktop where there's room even for the long
   prose-style values. On phones a long value physically cannot fit on
   one line, so nowrap there IS the overflow: let it wrap, right-aligned
   so wrapped lines stay visually in the price column. Short prices are
   single tokens (no space to break at) and render identically. */
@media (max-width: 640px) {
  .price-list strong { white-space: normal; text-align: right; }
}
.price-list-group + .price-list-group { margin-top: 20px; }

/* "смотрите также" resolved cross-links */
.related-links { display: flex; flex-wrap: wrap; gap: 8px; }
.related-links a { font-size: 13px; padding: 7px 14px; border-radius: 14px; background: var(--jade-soft); color: var(--jade); text-decoration: none; }

/* prescription-style facts grid (procedure duration/efficacy/price...) */
.rx-card {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 20px 22px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
@media (max-width: 640px) {
  .rx-card { grid-template-columns: 1fr 1fr; }
}
/* Seal-stamp corner mark ("方" = "formula/prescription") — leans into the
   card's own "prescription" metaphor instead of reading as a generic
   stat-tile grid. A translucent rotated chop stamp, same visual family as
   the doctor spina-byline-mark's gold-ringed circle, just cinnabar + square. */
.rx-card::after {
  content: '方';
  position: absolute;
  top: -12px;
  right: 16px;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 18px;
  line-height: 1;
  color: var(--seal);
  border: 1.5px solid var(--seal);
  border-radius: 4px;
  background: var(--paper-card);
  opacity: .6;
  transform: rotate(-8deg);
  pointer-events: none;
}
.rx-item small {
  display: block;
  font-family: var(--font-mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--slate);
  margin-bottom: 4px;
}
.rx-item strong { font-family: var(--font-mono); font-size: 17px; color: var(--ink); }

/* photo strip (method photos, ported from Filmstrip.astro) */
.filmstrip { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 16px; margin-top: 16px; }
.filmstrip figure { margin: 0; position: relative; transition: transform .3s ease; }
.filmstrip img { border-radius: 4px; border: 1px solid var(--line); width: 100%; }
.filmstrip .clip { position: absolute; top: -6px; left: 14px; width: 26px; height: 11px; background: var(--slate); border-radius: 2px; opacity: .5; }
/* A light, static "clipped to a board" tilt rather than another entrance
   animation stacked on top of the section's own scroll-reveal fade —
   restraint on purpose (see chat: too many simultaneous animations on one
   page reads as noise). Straightens back out on hover as the one bit of
   interactivity. */
.filmstrip figure:nth-child(odd) { transform: rotate(-1.5deg); }
.filmstrip figure:nth-child(even) { transform: rotate(1.5deg); }
.filmstrip figure:hover { transform: rotate(0deg) scale(1.03); z-index: 1; }

/* small pill-style links to a related clinic/direction/method (клиника card_links) */
.card-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.card-link {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; padding: 7px 13px; border-radius: 8px;
  background: var(--jade-soft); color: var(--jade); text-decoration: none;
}

/* Klinika "Заболевания клиники"/"Методы клиники" cross-links (2026-07-14) —
   reuses .body-link--confirmed (solid jade underline, same "confirmed by
   source text" convention already used for inline cross-links on
   napravlenie/metod pages) instead of the filled .card-link pill above,
   per explicit instruction. Wider gap than the plain .card-links default:
   underlined text needs more breathing room than a filled pill did, since
   there's no background box to visually separate adjacent links. */
.card-links--confirmed { gap: 8px 20px; row-gap: 12px; }
.card-links--confirmed .body-link--confirmed { font-size: 14px; }

/* The /kliniki/ archive card (formerly .card-link--klinika, a small
   fixed-size pill) was replaced 2026-07-17 by the .idx-card/.idx-card--
   city photo-card grid below (see archive-klinika.php) — removed
   entirely rather than left as dead code. */

/* placeholder / in-progress notice */
.in-progress {
  margin-top: 12px;
  padding: 16px 18px;
  border: 1.5px dashed var(--seal);
  background: rgba(178, 58, 46, 0.04);
  border-radius: 8px;
  color: var(--seal-dark);
  font-size: 14px;
}
.in-progress p { margin: 0; max-width: 60ch; }

/* -------------------------------------------------------------------
 * Catalog cards/grids — ported 1:1 from the Astro reference at
 * _migration-reference/site/src/components/{Card,CatalogGroups,CityCard}.astro
 * and pages/goroda/index.astro (same class names, same values).
 * ------------------------------------------------------------------ */
/* 16px matches the homepage hero subtitle (.hero .subtitle) — same
   "intro line under the page title" role, same size (2026-07-18 audit;
   was 14px). Mobile drop mirrors the subtitle's own 14.5px. */
.intro { font-size: 16px; color: var(--ink-soft); max-width: 65ch; }
@media (max-width: 640px) {
  .intro { font-size: 14.5px; }
}

.idx-grid { display: grid; gap: 14px; margin-top: 14px; }
/* auto-fit (not auto-fill): auto-fill reserves empty column tracks when a
   row has fewer items than would fit, which pins the real cards to their
   minimum width instead of growing them — invisible on archives with
   many items per group (napravlenie/metod, 9-13 each), but very visible
   on /kliniki/ where each city group is only 2-4 cards (found 2026-07-17
   checking a real ultrawide screen, not just a screenshot at "normal"
   zoom — a city's row left most of the container empty instead of its
   few cards growing to fill it). auto-fit collapses the empty tracks so
   the real items share the full row regardless of count. */
.idx-grid--flow { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.idx-grid--3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 640px) { .idx-grid--3 { grid-template-columns: 1fr; } }

/* Catalog card grid (2026-07-17) — /napravleniya/ and /metody/ archives
   only. At 9-13 items per taxonomy group, .idx-grid--flow's auto-fit
   already fills every column, so on an ultrawide monitor it mostly just
   ADDS more ~200px columns as the container grows rather than making
   individual cards bigger — cards read as tiny relative to how much
   free space is actually on screen. Two isolated, catalog-only classes
   fix this without touching the shared .idx-grid--flow / .idx-card that
   /kliniki/ and everything else still rely on:
   - .wide-container--catalog widens just the groups section's own cap
     (1800px instead of the sitewide --page-w's 1400px) — the page's own
     H1/breadcrumb/.intro block is a separate .wide-container instance
     above this one and keeps the standard 1400px cap, untouched.
   - .idx-grid--catalog raises the minmax() floor from 180px to 240px,
     so growing the container actually grows each card meaningfully
     instead of just adding more same-size columns, plus a modest
     clamp() on the title/icon so the card's own content scales a little
     alongside it rather than staying frozen at a fixed px size. */
/* Compound selector (.wide-container.wide-container--catalog), not just
   .wide-container--catalog alone — the base .wide-container rule lives
   much later in this file (it's part of the original Stage 1 "wide
   layout" system, appended near the end), so a same-specificity single-
   class override placed here would silently lose the cascade tie on
   source order alone. Two classes beats one regardless of position —
   found this exact bug live via getComputedStyle before trusting it. */
.wide-container.wide-container--catalog { max-width: min(94vw, 1800px); }
.idx-grid--catalog {
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: clamp(14px, 1.2vw, 20px);
}
.idx-grid--catalog .idx-title { font-size: clamp(14.5px, 1vw, 17px); }
.idx-grid--catalog .idx-card-icon { width: clamp(26px, 2vw, 34px); height: clamp(26px, 2vw, 34px); }

.idx-group { margin-bottom: 22px; }
.idx-group:last-child { margin-bottom: 0; }
.idx-group-title {
  font-family: var(--font-display);
  /* 17px + full-ink — matched to the homepage's .cat-column__head h3
     (same "catalog group heading" role, 2026-07-18 audit; was 16px
     ink-soft, the 1px + muted-color drift read as a different style). */
  font-size: 17px;
  font-weight: 400;
  color: var(--ink);
  margin: 0 0 12px;
}
.idx-group-count {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--slate);
  vertical-align: middle;
}
.idx-group-count::before { content: '\00b7\0020'; }

.idx-card {
  position: relative;
  display: block;
  text-decoration: none;
  color: inherit;
  background: var(--paper);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line);
  /* 8px — unified content-card radius, matched to the homepage's
     .usp-card (2026-07-18 audit; was 6px). Card radius tiers now:
     8px content cards, 10px large accent cards (.article-cta,
     .quiz-section, .cta-banner — bigger mass, proportionally bigger
     radius), 6px stays only on small interactive controls (buttons,
     nav pills). */
  border-radius: 8px;
  padding: 18px 16px 16px;
}
.idx-card .idx-title { font-weight: 700; font-size: 14.5px; }
.idx-card--napr { border-left-color: var(--jade); }
.idx-card--metod { border-left-color: var(--gold); }
.idx-card-icon { width: 26px; height: 26px; margin-bottom: 10px; color: var(--ink-soft); }
.idx-card-icon svg { width: 100%; height: 100%; }
.idx-card--placeholder .idx-title { color: var(--ink-soft); font-weight: 600; }
.idx-placeholder-tag {
  position: absolute;
  top: 8px;
  right: 8px;
  font-family: var(--font-mono);
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--slate);
  background: var(--paper-card);
  border: 1px dashed var(--line);
  padding: 2px 6px;
  border-radius: 10px;
  white-space: nowrap;
}

.idx-card--city {
  display: block;
  text-decoration: none;
  color: inherit;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px; /* content-card tier — see .idx-card note */
  padding: 0;
  overflow: hidden;
  border-top: 3px solid var(--jade);
}
.idx-card-photo { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; }
.idx-card-body { padding: 12px 14px; }
.idx-card--city .idx-title { font-weight: 700; font-size: 14.5px; margin-bottom: 4px; }
.idx-meta { font-size: 12px; font-family: var(--font-mono); color: var(--slate); }
/* /kliniki/ archive (2026-07-17) — was a small flex-wrap pill list
   (.card-link--klinika, fixed 40px thumb / 280px max-width, never grew
   past that no matter how wide the surrounding wide-layout frame got —
   caught on a real screen, not visible from a screenshot at a "normal"
   zoom level). Converted to the same .idx-card/.idx-card--city photo-
   card + .idx-grid--flow adaptive grid every other catalog on the site
   already uses (Города, homepage) — cards now size in fr/percentage
   terms via the grid, not a fixed px cap, so they actually fill the
   available width of whatever frame they're in. All 18 klinika posts
   have a real photo today, but the placeholder path is kept for
   whenever a future one doesn't. */
.idx-card-photo--placeholder {
  aspect-ratio: 4/3;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--paper-card);
  color: var(--slate);
}
.idx-card-photo--placeholder svg { width: 32px; height: 32px; }

/* -------------------------------------------------------------------
 * Application-form CTA button + the My Popup content (see
 * inc/popup-form.php / assets/popup-form.js / _migration-reference/
 * setup-mypopup-once.php). My Popup itself only supplies the modal
 * chrome (overlay, close button) — these are the "Меридиан" styles for
 * our own trigger button and the form markup inside .mypopup-body.
 * ------------------------------------------------------------------ */
.cta-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 14.5px;
  color: #fff;
  background: var(--seal);
  border: none;
  border-radius: 8px;
  padding: 14px 26px;
  cursor: pointer;
  text-decoration: none;
}
.cta-button:hover, .cta-button:focus-visible { background: var(--seal-dark); }

/* -------------------------------------------------------------------
 * Popup application form rebuild (2026-07-11) — visual only, same field
 * names/ids/required attributes and the same assets/popup-form.js gating
 * logic as before. Previously there was a *different*, unused CSS block
 * here (`.spina-popup-form ...`) that never matched anything: the real
 * <form> only ever carried `id="spina-popup-form"`, never that class, so
 * every rule silently no-opped and the form rendered with 100% browser-
 * default styling ("form from 2002"). Scoped by #id this time — the id is
 * unique to this one form on the site, no class needed.
 * ------------------------------------------------------------------ */
.mypopup-modal-content {
  border-radius: 14px;
  box-shadow: 0 20px 60px rgba(31, 42, 51, 0.22);
}
/* .popup-form added 2026-07-13 alongside the #spina-popup-form id so the
   same visual rules cover the inline "Связаться с нами" copy of the form
   on the homepage (see template-parts/contact-form.php) — two forms can't
   share one id (invalid HTML, breaks label/for once both exist on a page
   at once), but they can share this class. */
#spina-popup-form, .popup-form {
  font-family: var(--font-body);
  padding: 6px;
}
#spina-popup-form h3, .popup-form h3 {
  margin: 0 0 22px;
  font-size: 21px;
  color: var(--ink);
}
.popup-form__group {
  padding: 18px 0;
  border-top: 1px solid var(--line);
}
.popup-form__group:first-of-type { padding-top: 0; border-top: none; }
.popup-form__group-title { display: block; margin-bottom: 12px; }
.popup-form__field { margin-bottom: 14px; }
.popup-form__field:last-child { margin-bottom: 0; }
#spina-popup-form label, .popup-form label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
  margin-bottom: 6px;
}
#spina-popup-form input[type="text"], .popup-form input[type="text"],
#spina-popup-form input[type="tel"], .popup-form input[type="tel"],
#spina-popup-form input[type="email"], .popup-form input[type="email"],
#spina-popup-form textarea, .popup-form textarea {
  width: 100%;
  box-sizing: border-box;
  font-family: var(--font-body);
  font-size: 14.5px;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  color: var(--ink);
  box-shadow: inset 0 1px 2px rgba(31, 42, 51, 0.05);
  transition: border-color .15s ease, box-shadow .15s ease;
}
#spina-popup-form input[type="text"]:focus, .popup-form input[type="text"]:focus,
#spina-popup-form input[type="tel"]:focus, .popup-form input[type="tel"]:focus,
#spina-popup-form input[type="email"]:focus, .popup-form input[type="email"]:focus,
#spina-popup-form textarea:focus, .popup-form textarea:focus {
  outline: none;
  border-color: var(--jade);
  box-shadow: 0 0 0 3px var(--jade-soft);
}
#spina-popup-form textarea, .popup-form textarea { min-height: 80px; resize: vertical; }

#spina-popup-form input[type="file"], .popup-form input[type="file"] {
  width: 100%;
  box-sizing: border-box;
  font-size: 13px;
  color: var(--ink-soft);
  padding: 10px 0;
}
#spina-popup-form input[type="file"]::file-selector-button, .popup-form input[type="file"]::file-selector-button {
  -webkit-appearance: none;
  appearance: none;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 13px;
  color: var(--jade);
  background: var(--jade-soft);
  border: none;
  border-radius: 6px;
  padding: 9px 16px;
  margin-right: 12px;
  cursor: pointer;
  transition: opacity .15s ease;
}
#spina-popup-form input[type="file"]::file-selector-button:hover, .popup-form input[type="file"]::file-selector-button:hover { opacity: .8; }

.spina-consent { margin: 4px 0 20px; }
.spina-consent label { display: flex; align-items: flex-start; gap: 8px; font-size: 12.5px; font-weight: 400; color: var(--ink-soft); line-height: 1.5; }
.spina-consent input[type="checkbox"] { flex: none; margin-top: 3px; width: 15px; height: 15px; accent-color: var(--jade); cursor: pointer; }
.spina-consent a { color: var(--jade); }

.popup-form__submit {
  /* Missing box-sizing meant width:100% (content-box) + this padding added
     44px on top of the parent's content width — the button's right edge
     rendered past the rounded card's own boundary. Same recurring trap as
     the carousel-nav/lightbox buttons fixed earlier this project: any
     fixed/100%-width <button> on this site needs explicit border-box. */
  box-sizing: border-box;
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 15px;
  color: #fff;
  background: var(--jade);
  border: none;
  border-radius: 8px;
  padding: 13px 22px;
  min-height: 48px;
  cursor: pointer;
  transition: opacity .15s ease;
}
.popup-form__submit:hover:not(:disabled) { opacity: .9; }
.popup-form__submit:disabled { opacity: .45; cursor: not-allowed; }

.spina-popup-message { display: block; margin-top: 12px; font-size: 13.5px; text-align: center; }
.spina-popup-message--success { color: var(--jade); }
.spina-popup-message--error { color: var(--seal); }

/* -------------------------------------------------------------------
 * Desktop 2-column layout for the My Popup modal (2026-07-14) — every
 * .js-open-application-popup trigger site-wide (nav, napravlenie/metod/
 * klinika CTAs, the "Отправить снимок" banner) opens this SAME modal, so
 * one change here covers all of them automatically.
 *
 * Scoped to #spina-popup-form specifically, NOT the shared .popup-form
 * class: the homepage's inline "Связаться с нами" copy (spina_contact_form(),
 * #home-contact-form) also carries .popup-form but has a DIFFERENT internal
 * structure — all 5 fields in one single .popup-form__group, not 3 separate
 * groups — so these nth-of-type-based column rules would misfire on it if
 * applied broadly. That form is untouched by this change (out of scope —
 * it's not one of the .js-open-application-popup entry points).
 *
 * .mypopup-modal is the PLUGIN's own outer container (My Popup, not ours) —
 * it hardcodes width:350px with no media query, which is the real cause of
 * the narrow modal in the original screenshot; overridden here rather than
 * in the plugin itself so it survives plugin updates.
 *
 * Mobile (< 768px) is untouched: no media query below this width, so the
 * original single-column stacked layout (already correct) is unaffected.
 * ------------------------------------------------------------------ */
@media (min-width: 768px) {
  .mypopup-modal { width: 680px; }

  #spina-popup-form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 32px;
  }
  #spina-popup-form h3 { grid-column: 1 / -1; }
  /* 1st .popup-form__group = contact fields (Имя/Телефон/Email) → left column,
     explicitly spanning the same 2 rows the right column's groups occupy —
     without this, implicit row auto-placement syncs row 2's height to
     whichever column is taller there (usually the 3-field contact group),
     leaving a large dead gap in the right column before "Снимок/скан"
     starts on row 3. */
  #spina-popup-form .popup-form__group:nth-of-type(1) { grid-column: 1; grid-row: 2 / span 2; }
  /* 2nd = comment, 3rd = scan upload → right column, each its own row */
  #spina-popup-form .popup-form__group:nth-of-type(2) { grid-column: 2; grid-row: 2; }
  #spina-popup-form .popup-form__group:nth-of-type(3) { grid-column: 2; grid-row: 3; }
  #spina-popup-form .popup-form__group:nth-of-type(2) textarea { min-height: 150px; }
  /* consent + submit + status message → full width, below both columns */
  #spina-popup-form .spina-consent,
  #spina-popup-form .popup-form__submit,
  #spina-popup-form .spina-popup-message {
    grid-column: 1 / -1;
  }
}

/* -------------------------------------------------------------------
 * front-page.php — ported 1:1 from the Astro reference at
 * src/pages/index.astro and src/components/{StatsPlaque,SearchWidget,
 * HowItWorks,Guarantees,SpineIllustration}.astro (same class names,
 * same values).
 * ------------------------------------------------------------------ */
.hero {
  padding: 22px 40px 30px;
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 28px;
  align-items: center;
  border-bottom: 1px solid var(--line);
}
/* 34px/1.1 — the documented exception to the sitewide 36px/1.4 H1 (see
   style.css): this is the homepage banner composition, tuned to sit
   with the subtitle/search block, not a document title. Confirmed as a
   deliberate exception in the 2026-07-18 consistency audit. */
.hero h1 { font-size: 34px; line-height: 1.1; margin: 0 0 10px; }
.hero .subtitle { font-size: 16px; color: var(--ink-soft); margin: 0 0 16px; max-width: 46ch; }
@media (max-width: 640px) {
  .hero { grid-template-columns: 1fr; padding: 18px 16px 22px; gap: 20px; }
  .hero h1 { font-size: 25px; }
  .hero .subtitle { font-size: 14.5px; }
}

.btn-primary {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 12px 22px; min-height: 48px;
  background: var(--jade); color: #fff; border: none; border-radius: 8px;
  font-family: var(--font-body); font-weight: 600; font-size: 15px;
  text-decoration: none; cursor: pointer;
}
.btn-primary:hover { opacity: .9; }
@media (max-width: 640px) { .btn-primary { width: 100%; } }

.btn-secondary {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 11px 22px; min-height: 44px;
  background: none; color: var(--jade); border: 1.5px solid var(--jade); border-radius: 8px;
  font-family: var(--font-body); font-weight: 600; font-size: 14px;
  text-decoration: none; cursor: pointer;
}
.btn-secondary:hover { background: var(--jade-soft); }
.more-link { text-align: center; margin-top: 18px; }

.idx-grid--highlight { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
@media (max-width: 640px) { .idx-grid--highlight { grid-template-columns: 1fr; } }

.hero-illustration {
  aspect-ratio: 4/3;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 50% 42%, var(--jade-soft) 0%, transparent 68%);
  border-radius: 12px;
}
.hero-illustration svg { width: 56%; height: auto; max-height: 88%; }

.stats-plaque { display: flex; gap: 0; padding: 0 40px 8px; }
.stat-item { flex: 1; padding: 14px 20px 14px 0; border-right: 1px solid var(--line); margin-right: 20px; }
.stat-item:last-child { border-right: none; margin-right: 0; }
.stat-item strong { display: block; font-family: var(--font-mono); font-size: 30px; color: var(--ink); line-height: 1; }
.stat-item span { font-size: 12.5px; color: var(--ink-soft); display: block; margin-top: 6px; }
.stat-sub { display: block; font-size: 10.5px; color: var(--jade); margin-top: 3px; }
.stats-note { padding: 0 40px 20px; }
.stats-note .note { margin-top: 0; }
@media (max-width: 640px) {
  .stats-plaque { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 16px; padding: 4px 16px 14px; }
  .stat-item { border-right: none; margin-right: 0; padding: 10px 0; border-bottom: 1px solid var(--line); }
  .stat-item:nth-child(3) { grid-column: 1 / -1; border-bottom: none; }
  .stat-item strong { font-size: 26px; }
  .stats-note { padding: 0 16px 20px; }
}

.search-widget { padding: 0 40px 8px; }
.search-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.search-tab {
  font-family: var(--font-body); font-size: 13px; font-weight: 600;
  padding: 10px 16px; min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 20px; border: 1px solid var(--line);
  background: var(--paper); color: var(--ink-soft); cursor: pointer;
}
.search-tab[aria-selected="true"] { background: var(--jade); border-color: var(--jade); color: #fff; }
.search-tab:focus-visible { outline: 2px solid var(--jade); outline-offset: 1px; }
.search-options { display: flex; flex-wrap: wrap; gap: 8px; padding: 16px; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; }
.search-options[hidden] { display: none; }
.search-opt { font-size: 13px; padding: 7px 14px; border-radius: 14px; background: var(--jade-soft); color: var(--jade); text-decoration: none; }
@media (max-width: 640px) { .search-widget { padding: 0 16px 8px; } }

.hiw-grid { display: flex; align-items: flex-start; gap: 4px; margin-top: 18px; }
.hiw-step { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; text-align: center; }
/* A seal-stamp (chop) rather than a bare numbered circle — same family as
   the "方" corner mark on .rx-card, so the numbering reads as part of the
   site's own visual vocabulary instead of a generic numbered-badge
   template. Alternating rotation (odd/even step) so the four stamps don't
   look machine-uniform, as if each was actually pressed by hand. */
.hiw-badge {
  width: 48px; height: 48px; border-radius: 6px; border: 2px solid var(--seal); color: var(--seal);
  background: rgba(178, 58, 46, 0.04);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-size: 20px; margin-bottom: 10px; flex-shrink: 0;
  transform: rotate(-4deg);
}
.hiw-badge--alt { transform: rotate(3deg); }
.hiw-icon { width: 24px; height: 24px; margin-bottom: 8px; color: var(--ink-soft); }
.hiw-icon svg { width: 100%; height: 100%; }
.hiw-label { font-weight: 700; font-size: 13.5px; margin-bottom: 4px; }
.hiw-text { font-size: 12.5px; color: var(--ink-soft); max-width: 19ch; }
.hiw-arrow { flex: 0 0 auto; width: 20px; height: 20px; margin-top: 16px; color: var(--line); }
.hiw-arrow svg { width: 100%; height: 100%; }
@media (max-width: 640px) {
  .hiw-grid { flex-direction: column; align-items: stretch; }
  .hiw-step { align-items: center; }
  .hiw-arrow { align-self: center; transform: rotate(90deg); margin: 2px 0; }
}

.guarantee-row { display: flex; align-items: flex-start; gap: 12px; padding: 10px 0; border-top: 1px solid var(--line); }
.guarantee-row:first-child { border-top: none; padding-top: 0; }
.guarantee-row strong { display: block; font-size: 14.5px; margin-bottom: 2px; }
.guarantee-row span { font-size: 13.5px; color: var(--ink-soft); }
.guarantee-icon {
  width: 40px; height: 40px; border-radius: 50%; border: 1.5px solid var(--jade); color: var(--jade);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.guarantee-icon svg { width: 20px; height: 20px; }

/* Homepage-only modifier: 3 items laid out as a horizontal row of columns
   instead of a narrow stacked list, so the block uses the full band width.
   Kept as a modifier class (not a rewrite of .guarantee-row/.marks
   themselves) since both are plain, unscoped classes usable elsewhere. */
.marks--guarantees { grid-template-columns: repeat(3, 1fr); gap: 28px; }
@media (max-width: 860px) { .marks--guarantees { grid-template-columns: 1fr; } }
.marks--guarantees .guarantee-row {
  flex-direction: column;
  align-items: center;
  text-align: center;
  border-top: none;
  padding: 0;
  gap: 12px;
}
.marks--guarantees .guarantee-icon { width: 48px; height: 48px; }
.marks--guarantees .guarantee-icon svg { width: 22px; height: 22px; }

/* Small jade arrow-link — "Подробнее →" / "Все методы →" / etc. Reused
   across the homepage restructure (2026-07-13) instead of a one-off class
   per block. */
.text-link { display: inline-flex; align-items: center; gap: 4px; font-size: 14px; font-weight: 600; color: var(--jade); text-decoration: none; }
.text-link:hover { text-decoration: underline; }

/* -------------------------------------------------------------------
 * "Методы лечения" / "Направления лечения" homepage blocks (2026-07-13
 * restructure) — 2 columns by taxonomy group (ТКМ/Современная медицина,
 * Позвоночник/Суставы), each a short link list under one category-level
 * icon rather than the archive page's full per-item idx-card grid — the
 * homepage only needs to point at each group, not catalog it.
 * ------------------------------------------------------------------ */
.cat-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 36px; margin-top: 16px; }
@media (max-width: 640px) { .cat-columns { grid-template-columns: 1fr; gap: 26px; } }
.cat-column__head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.cat-column__icon {
  width: 40px; height: 40px; border-radius: 50%; border: 1.5px solid var(--jade); color: var(--jade);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.cat-column__icon svg { width: 22px; height: 22px; }
.cat-column__head h3 { font-family: var(--font-display); font-weight: 400; font-size: 17px; margin: 0; }
.cat-column__list { list-style: none; margin: 0 0 14px; padding: 0; }
.cat-column__list li { border-top: 1px solid var(--line); }
.cat-column__list li:first-child { border-top: none; }
.cat-column__list a {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 1px; font-size: 14px; color: var(--ink-soft); text-decoration: none;
}
.cat-column__list a:hover { color: var(--jade); }
.cat-column__soon {
  flex-shrink: 0; font-family: var(--font-mono); font-size: 9px; text-transform: uppercase;
  letter-spacing: .03em; color: var(--slate); white-space: nowrap;
}

/* -------------------------------------------------------------------
 * "Связаться с нами" homepage block (2026-07-13) — collapsible inline
 * copy of the application form (see template-parts/contact-form.php),
 * native <details>/<summary> rather than a JS-driven accordion: no state
 * to manage, works with JS disabled, and the marker is trivially themed.
 * ------------------------------------------------------------------ */
.contact-reveal { border: 1px solid var(--line); border-radius: 10px; background: var(--paper); }
.contact-reveal summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 20px;
  font-weight: 600;
  font-size: 15px;
  color: var(--ink);
}
.contact-reveal summary::-webkit-details-marker { display: none; }
.contact-reveal summary .chev { width: 18px; height: 18px; color: var(--jade); flex-shrink: 0; transition: transform .18s ease; }
.contact-reveal[open] summary .chev { transform: rotate(180deg); }
.contact-reveal__body { padding: 4px 20px 20px; border-top: 1px solid var(--line); }

/* -------------------------------------------------------------------
 * Homepage grid rework (2026-07-16) — replaces the earlier "floating
 * cards" pass (every block its own bordered/rounded/margin-gapped card,
 * all still capped by .page-shell's sitewide max-width:920px). That
 * combination read as a narrow mockup with dead margins on wide screens
 * and a stack of disconnected boxes, not an adaptive site — see chat for
 * the full brief (ui-ux-pro-max skill consulted: a full-bleed section
 * background with an inner max-width "container" is the standard
 * technique for this, not a hack).
 *
 * Structure: .home-band (full-bleed background, no max-width) wraps
 * .home-container (max-width: var(--home-w), centred, fluid padding).
 * .page-shell is neutralised below — background/border/radius AND
 * max-width all reset to none — so it contributes nothing on the
 * homepage anymore; it stays in front-page.php's markup only because
 * every other template still needs the real, untouched .page-shell.
 *
 * Width: min(94vw, 1400px) — fluid up to the cap, not a fixed pixel
 * gutter, so margins grow proportionally on very wide screens. At
 * 1280px viewport this already uses ~94% of the width (was a fixed
 * 920px regardless of viewport before); at 1920px it caps at 1400px
 * with ~14%-each-side margins, instead of the old ~26%-each-side dead
 * space from a flat 920px column.
 *
 * Connecting blocks: no margin-bottom, no border-radius, no shadow, no
 * gap — bands sit flush. Separation comes from EITHER a background
 * color change (the existing paper/jade-soft tint alternation, kept) OR,
 * where two adjacent bands share a background, a single hairline
 * border-top (var(--line)) — the same "just a rule, no card" separator
 * every OTHER template already uses between its own .section blocks
 * (napravlenie/metod/klinika articles use plain border-bottom hairlines,
 * never cards). This makes the homepage consistent with the rest of the
 * site instead of the odd one out.
 * ------------------------------------------------------------------ */
body.home { --home-w: min(94vw, 1400px); }
body.home .home-band { width: 100%; }
/* Breathing room between bands (2026-07-16, third revision) — real
   feedback from an actual ultrawide (3440px) monitor flagged two things
   the earlier passes got wrong:
   1. Full-bleed color bands (jade-soft/paper alternation stretched to
      the viewport edge) read as flat, linear stripes at ultrawide —
      removed entirely as a technique. .home-band--tint is no longer
      applied anywhere in front-page.php (kept below, harmless/unused, in
      case a future page-shaped need for a genuine full-bleed accent band
      comes up — but it is NOT how ordinary section rhythm works anymore).
      Separation between EVERY band is now via .home-divider (a plain
      hairline, aligned to the same home-w edge as every heading) plus a
      real margin gap — uniformly, since there is no color difference
      left to lean on anywhere.
   2. A real CSS bug: `.home-container` and `.section` sit on the SAME
      element on every content band, both at specificity (0,0,2,1) under
      body.home — whichever rule came LATER in the file won on the
      shared `padding` property, and `.section`'s reset (`padding: 0`)
      was declared after `.home-container`'s own `padding: 64px ...`,
      silently zeroing it out almost everywhere (confirmed via
      getComputedStyle before writing this fix, not assumed). Fixed by
      folding `border-bottom: none` directly into `.home-container` and
      deleting the separate `.section` padding override — one rule now
      owns the box model for these elements, not two competing ones. */
body.home .home-band + .home-band { margin-top: 40px; }
@media (max-width: 640px) {
  body.home .home-band + .home-band { margin-top: 24px; }
}
body.home .home-band--tint { background: var(--jade-soft); } /* unused on the homepage now, kept for a possible future genuine accent band */
/* Uniform separator between every band — no color difference to lean on
   anymore, so every junction gets the same treatment: a hairline at the
   same home-w edge as every heading, sitting in a real margin gap. */
body.home .home-divider {
  max-width: var(--home-w);
  margin: 32px auto;
  border-top: 1px solid var(--line);
}
@media (max-width: 640px) { body.home .home-divider { margin: 20px auto; } }
body.home .home-container {
  max-width: var(--home-w);
  margin: 0 auto;
  /* Top/bottom split (2026-07-16, sixth revision — the fourth revision's
     24px/16px numbers were confirmed live via getComputedStyle to be
     correctly applied, but the user reported no visible change across
     two follow-up screenshots, so the gap is widened much further this
     time rather than nudged: the divider's own 32px+32px margin plus a
     bigger 48px of this container's own top padding now put ~112px
     between the previous block and the heading, against an 8px
     heading-to-content gap below (~14x, not ~5x) — big enough to read
     at a glance, not just measure. BOTTOM padding stays the full 64px
     (the previous section's own trailing space, untouched — still the
     "breathing room" fix from the third revision).
     2026-07-18 (seventh revision): 48/64 → 40/56 — user judged the
     total inter-band gap slightly too airy after living with it; a
     modest trim (16px less per gap incl. the 32+32 divider margins),
     not a rework. Same values applied to .wide-container and the
     article outer blocks below to keep the one-rhythm unification. */
  padding: 40px clamp(20px, 4vw, 64px) 56px;
  border-bottom: none;
}
@media (max-width: 640px) {
  body.home .home-container { padding: 32px clamp(20px, 5vw, 40px) 40px; }
}
/* Headings center horizontally across the page (2026-07-16, seventh
   revision) — the content below a heading (cards, grids, forms) stays
   at its existing left/grid alignment; only the heading text itself
   (and its subtitle, if any) is centered. Margin-bottom set to an exact
   32px (eighth revision) — 8px read as visually "glued" against a 30px
   serif heading; this is a fixed value applied identically at every
   width, not a relative/mobile-scaled one, per explicit instruction. */
body.home .section h2 { font-size: 30px; margin: 0 0 32px; text-align: center; }
@media (max-width: 640px) {
  body.home .section h2 { font-size: 24px; }
}
/* Each of these is the first content element right after an H2 on the
   homepage — zeroed so the heading's own margin-bottom above is the only
   source of "gap below heading", deterministically, rather than leaning
   on margin-collapse picking whichever value happens to be larger. */
body.home .idx-grid,
body.home .clinic-carousel,
body.home .hiw-grid { margin-top: 0; }
/* Методы/Заболевания — the 2-column grid used to just stretch edge to
   edge (1fr/1fr across the full ~1400px container), which technically
   filled the width but left each column's actual short list looking
   stranded against a lot of trailing space on the right, while the
   (centered) heading above sat on a different visual axis entirely.
   Capped to the same 1100px "long-form content" width the about-project
   grid already uses and centered as one unit — symmetric margins on
   both sides now, matching the centered heading above it. */
body.home .cat-columns { margin-top: 0; max-width: 1100px; margin-left: auto; margin-right: auto; }

/* Hero gains a secondary action next to the existing primary CTA — a
   lower-commitment "browse first" path alongside "Оставить заявку". */
body.home .hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
@media (max-width: 640px) { body.home .hero-actions { flex-direction: column; } }

/* "Почему выбирают нас" USP block — 4 icon cards, sits on the tinted
   section right after the hero. Cards use var(--paper) (lighter than the
   section's jade-soft tint) so they read as distinct cards, same
   figure/ground logic as .idx-card sitting on .page-shell's paper-card. */
body.home .usp-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 0; }
@media (max-width: 900px) { body.home .usp-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { body.home .usp-grid { grid-template-columns: 1fr; } }
body.home .usp-card { background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 24px 20px; text-align: center; }
body.home .usp-icon { width: 40px; height: 40px; margin: 0 auto 14px; color: var(--jade); }
body.home .usp-icon svg { width: 100%; height: 100%; }
body.home .usp-title { font-weight: 700; font-size: 14.5px; margin-bottom: 6px; }
body.home .usp-text { font-size: 13px; color: var(--ink-soft); line-height: 1.45; }

/* More "air" in the recommended-clinics carousel + methods/directions
   columns, per the new rhythm (only on the homepage — gorod/klinika pages
   reuse the same carousel markup at its original, tighter padding). */
body.home .carousel-card__body { padding: 18px 18px 20px; }
body.home .cat-column__list a { padding: 13px 2px; }

/* Page-shell no longer contributes any box/width on the homepage — see
   the big comment above. */
body.home .page-shell { max-width: none; background: none; border: none; border-radius: 0; }

/* Nav's flat/fluid/centered treatment is unconditional now (see the base
   .site-nav/.site-nav__links rules) — this used to be a body.home-only
   override (2026-07-16), then also duplicated for body.uses-wide-layout
   (2026-07-16, Stage 1), which is exactly how the two rulesets drifted:
   the wide-layout copy got the background/border fix but nobody
   remembered to also copy the link-centering rule, so archive/single
   pages had fluid padding but LEFT-aligned links while home had both —
   a visible inconsistency across the site (caught 2026-07-17). Removed
   both duplicates; nothing homepage-specific belongs here anymore. */


/* Contact form — same narrower-tool treatment and same left-alignment
   rule as the search widget; a form stretched to the full 1400px band
   reads badly, and the popup modal it mirrors is already tuned to a
   similar ~680px width. */
body.home .contact-reveal { max-width: 640px; margin: 0; }
/* This one block is a deliberate exception to the shared-left-edge rule
   above: the "Связаться с нами" form is a standalone destination, not a
   compact tool sitting beside other content, so it centers within its
   own band instead of hugging the common left axis. */
body.home #zayavka .contact-reveal { margin: 0 auto; }

/* Hero + search — ONE card (2026-07-16, sixth revision, superseding the
   fifth revision's "two paired cards"): the user explicitly asked for a
   single frame/background/width, hero on top, search widget below it,
   inside the same box — not two separate rounded rectangles sitting
   close together. .hero-search-card is the only element that owns a
   background/border/radius now; .hero and .search-widget are plain
   layout wrappers inside it with no box of their own. */
body.home .hero-search-card {
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 48px clamp(24px, 4vw, 56px);
}
body.home .hero { padding: 0; border-bottom: none; min-height: 420px; }
/* Real gap between the nav's bottom hairline and the hero card — it used
   to sit flush against the nav, no breathing room at all. */
body.home #home-hero-band { margin-top: 40px; }
@media (max-width: 640px) { body.home #home-hero-band { margin-top: 24px; } }
body.home .hero-illustration { min-height: 320px; }
body.home .hero-illustration img { width: 100%; height: 100%; object-fit: cover; border-radius: 12px; display: block; }
@media (max-width: 640px) {
  body.home .hero-search-card { padding: 28px 20px; }
  body.home .hero { min-height: 0; }
  body.home .hero-illustration { min-height: 220px; }
}

/* Search widget — sits directly below the hero row, inside the SAME
   card (no width/frame of its own anymore — max-width:none, no
   background/border/radius). Its own top margin is the only thing
   separating it from the hero row above — plain spacing, deliberately
   no hairline/border, since the user asked for no second internal
   frame at all, not even a subtle rule. */
body.home .search-widget { max-width: none; margin: 32px 0 0; padding: 0; }
@media (max-width: 640px) { body.home .search-widget { margin-top: 24px; } }
/* Only ONE frame for the whole hero+search card — the tabs/pills used to
   nest their own second border (.search-options) around just the pill
   row; stripped so pills sit directly on the card's own background. */
body.home .search-options { padding: 0; background: none; border: none; border-radius: 0; }
/* Inactive tabs read as "thin outline, no fill" against the card's own
   background; transparent (not the shared var(--paper) the base rule
   uses) is what actually delivers "no fill" now that the surrounding
   card is var(--paper-card), a different tone from var(--paper). */
body.home .search-tab { background: transparent; }
body.home .search-tab[aria-selected="true"] { background: var(--jade); border-color: var(--jade); color: #fff; }

/* "О проекте" two-column — its own, narrower max-width even within the
   wide home-w band: long-form text reads worse stretched past ~1100px
   regardless of how wide the container around it is allowed to get.
   Deliberately NOT .home-band--tint (see front-page.php): the WPRemark
   accent card in the aside already carries the jade-soft tone, and a
   jade-soft BAND behind an also-jade-soft card would make the card
   vanish into its background. Centered via margin:0 auto (eighth
   revision, 2026-07-16) — the heading+subtitle above are centered
   across the full ~1400px container, but this grid had no auto margins
   of its own, so it sat flush against the container's left edge instead
   of sharing the heading's center — the two read as unrelated elements
   living on different axes. align-items:start already puts both
   columns on the same top line; centering the grid as a whole was the
   missing piece. */
body.home .about-project { display: grid; grid-template-columns: 1.3fr 1fr; gap: 32px; align-items: start; max-width: 1100px; margin: 0 auto; }
/* margin:0 auto (not just 0 0 14px) is load-bearing here, found during
   the audit pass, not assumed: style.css's shared `.section p { max-
   width: 70ch }` rule (class+tag, (0,0,1,1)) beats this class-only rule
   ((0,0,1,0)) on the max-width property, so this paragraph gets capped
   to ~622px regardless — without auto side margins it sat flush against
   the container's left edge, its own text centered inside that narrow,
   off-center box, while every other heading centers across the FULL
   ~1400px container. Auto margins center the box itself, matching them. */
body.home .about-project__subtitle { font-size: 16px; font-weight: 600; color: var(--ink-soft); margin: 0 auto 14px; text-align: center; }
body.home .about-project__aside .wpremark { margin: 0; }
@media (max-width: 760px) { body.home .about-project { grid-template-columns: 1fr; } }

/* Footer — already full-bleed jade sitewide via .site-footer; on home it
   drops its own rounded-card corners, gets the same breathing-room gap
   as every other band transition, and its inner grid/bottom row get the
   same home-w cap + centering as every other band (its own 40px padding
   already provides a safe edge inset outside that; the footer's own grid
   genuinely spans the full home-w, so centering vs. left-aligning it is
   a non-issue — same result either way). */
body.home .site-footer { border-radius: 0; margin-top: 40px; }
body.home .site-footer__grid,
body.home .site-footer__bottom { max-width: var(--home-w); margin-left: auto; margin-right: auto; }
@media (max-width: 640px) { body.home .site-footer { margin-top: 24px; } }

/* -------------------------------------------------------------------
 * Страница города — самостоятельная шапка (не .section/.eyebrow-архив),
 * карточки клиник (реальные + заглушки) и обёртка квиза Quizle.
 * См. template-parts/gorod-hero.php, gorod-clinics.php, gorod-quiz.php.
 * ------------------------------------------------------------------ */
.gorod-hero {
  display: grid;
  grid-template-columns: 1fr 1.3fr; /* photo left (narrower), text right (wider) */
  gap: 28px;
  align-items: center;
  padding: 22px 40px 30px;
  border-bottom: 1px solid var(--line);
}
.gorod-hero__subtitle { font-size: 16px; color: var(--ink-soft); margin: 0 0 16px; max-width: 46ch; }
.gorod-hero__facts { display: flex; gap: 0; flex-wrap: wrap; }
.gorod-hero__fact {
  flex: 1;
  min-width: 130px;
  padding: 12px 18px 12px 0;
  border-right: 1px solid var(--line);
  margin-right: 18px;
}
.gorod-hero__fact:last-child { border-right: none; margin-right: 0; }
.gorod-hero__fact strong { display: block; font-family: var(--font-mono); font-size: 22px; color: var(--ink); line-height: 1.1; }
.gorod-hero__fact span { font-size: 12px; color: var(--ink-soft); display: block; margin-top: 4px; }
.gorod-hero__media { position: relative; }
.gorod-hero__photo { width: 100%; border-radius: 10px; border: 1px solid var(--line); display: block; aspect-ratio: 4/3; object-fit: cover; }
.gorod-hero__photo-credit { font-size: 11.5px; color: var(--slate); margin-top: 6px; }
@media (max-width: 640px) {
  .gorod-hero { grid-template-columns: 1fr; padding: 18px 16px 22px; gap: 20px; }
  .gorod-hero__facts { gap: 8px 0; }
  .gorod-hero__fact { min-width: 45%; border-right: none; margin-right: 0; padding: 8px 0; border-bottom: 1px solid var(--line); }
}

.clinic-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 14px; margin-top: 14px; }
.clinic-card {
  position: relative;
  display: block;
  text-decoration: none;
  color: inherit;
  background: var(--paper);
  border: 1px solid var(--line);
  border-left: 3px solid var(--jade);
  border-radius: 8px; /* content-card tier — see .idx-card note */
  padding: 16px 16px 14px;
}
.clinic-card__title { font-weight: 700; font-size: 14.5px; }
.clinic-card__meta { font-size: 12.5px; color: var(--ink-soft); margin-top: 4px; }
.clinic-card--placeholder {
  border-left-style: dashed;
  border-left-color: var(--slate);
  cursor: default;
}
.clinic-card--placeholder .clinic-card__title { color: var(--ink-soft); font-weight: 600; }

/* Distinct from .idx-placeholder-tag (dashed slate pill — "written content
   not authored yet"). A clinic-not-yet-profiled is a different kind of
   placeholder — a place/person, not a page — so it gets a softer, filled
   jade tag with a small dot instead of a dashed outline. */
.clinic-placeholder-tag {
  position: absolute;
  top: 10px;
  right: 10px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--jade);
  background: var(--jade-soft);
  padding: 3px 9px 3px 7px;
  border-radius: 10px;
  white-space: nowrap;
}
.clinic-placeholder-tag::before {
  content: '';
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--jade);
}

.quiz-section .quizle-container { margin-top: 14px; }

/* Quiz is the single most conversion-relevant element on a gorod page —
   give it a distinct jade-soft "card" treatment so it doesn't read as just
   another text section (same tokens as everything else, just inverted
   emphasis: filled instead of outlined).
   Deliberately NOT sharing the generic ".section" class (this used to be
   `class="section quiz-section"`): this card sits inside .article-layout's
   grid (see single-gorod.php), and `.article-layout .section` — two
   classes, higher specificity than `.quiz-section` alone — was silently
   overriding this rule's own `padding` shorthand down to top/left/right:0,
   leaving only the 26px bottom value. That's the exact cause of the
   "Быстрая заявка" eyebrow reading as pinned into the top-left corner and
   every side but the bottom sitting flush against the border — not
   something Quizle's own footer/contacts fixes below could ever touch,
   since those only reposition content *inside* this box. Two rounds of
   patching those symptoms without finding this is why the bug kept coming
   back in a new shape. Standalone card now: one padding declaration nothing
   else can collide with, plus its own h2 rule (`.section h2` no longer
   applies once the shared class is gone) and an explicit entry in
   scroll-reveal.js's selector list (it also no longer matches `.section`
   there, so it needs to opt back in by name to keep its fade-in). */
.quiz-section {
  background: var(--jade-soft);
  border: 1.5px solid var(--jade);
  border-radius: 10px;
  /* No side margins (2026-07-18, was 26px 40px): the 40px inset made
     the quiz a narrower floating card (524px) inside the text column —
     now it spans the column's full width like the CTA cards do. */
  margin: 26px 0;
  padding: 36px;
}
.quiz-section h2 { font-size: 26px; margin: 0 0 14px; } /* size follows the unified 26px inner-H2 scale; tight card-internal margin stays */
@media (max-width: 640px) {
  .quiz-section { margin: 20px 16px; padding: 24px; }
}

/* End-of-article CTA (napravlenie/metod, after "Смотрите также") — same
   self-contained-card discipline as .quiz-section above (own padding, own
   h2 rule, no shared ".section" class to collide with .article-layout's
   ancestor-scoped rule). Centered text/button, not a form, so no inner
   __layout wrapper needed. */
.article-cta {
  background: var(--jade-soft);
  border: 1.5px solid var(--jade);
  border-radius: 10px;
  margin: 26px 40px;
  padding: 36px;
  text-align: center;
}
.article-cta h2 { font-size: 26px; margin: 0 0 8px; } /* size follows the unified 26px inner-H2 scale; tight card-internal margin stays */
.article-cta p { margin: 0 0 20px; color: var(--ink-soft); }
@media (max-width: 640px) {
  .article-cta { margin: 20px 16px; padding: 24px; }
}

/* "Отправить снимок" dark CTA banner (template-parts/cta-banner-scan.php)
   — the one deliberately dark card on the site. --cta-ink is a LOCAL,
   fixed value (not var(--ink), which flips to a light tone in dark mode —
   see style.css's :root[data-theme="dark"]): this card stays dark
   regardless of site theme, an intentional one-off exception, not a bug.
   No horizontal margin: lives inside .article-body (single-napravlenie.php's
   spina_render_article() $inject_after, between "Диагностика" and "Лечение"
   on kifoz), which already sits inset via .article-layout's own padding —
   an extra side margin here would double-indent it against the surrounding
   prose. Only margin-bottom, matching .article-layout .section's own
   26px rhythm between sections. */
.cta-banner {
  --cta-ink: #1F2A33;
  background: var(--cta-ink);
  color: #EDEFEA;
  border-radius: 10px;
  margin: 0 0 26px;
  padding: 40px;
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 36px;
  align-items: center;
}
.cta-banner__heading {
  font-family: var(--font-display);
  font-size: 26px;
  line-height: 1.3;
  color: #fff;
  margin: 0 0 18px;
  max-width: 30ch;
}
.cta-banner .checklist { margin-top: 0; }
.cta-banner .checklist__icon { color: #8FCDB0; } /* lighter jade tint — var(--jade) itself is too close in value to --cta-ink to read clearly */
.cta-banner .checklist__text { color: #C9D2CE; }
.cta-banner .btn-primary { margin-top: 24px; }
.cta-banner__photo {
  border-radius: 8px;
  overflow: hidden;
  aspect-ratio: 4/5;
}
.cta-banner__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 760px) {
  .cta-banner {
    grid-template-columns: 1fr;
    margin: 0 0 20px;
    padding: 28px;
    gap: 22px;
  }
  .cta-banner__heading { max-width: none; }
  .cta-banner__photo { max-width: 280px; margin: 0 auto; }
}

/* -------------------------------------------------------------------
 * Long-form narrative article layout (napravlenie/metod "sections_json"
 * format + gorod — see single-napravlenie.php / spina_render_article()).
 * Reference page: Остеохондроз.
 *
 * Redesigned 2026-07-18 (user screenshot showed the asymmetry): the TOC
 * no longer occupies a grid column next to the text — that grid pushed
 * the whole reading column left of the page's center and left dead
 * space on the right. Now the article column stands alone on the page's
 * single centered axis, and the TOC exists in two mutually exclusive
 * forms:
 *   ≥1440px — .article-toc: floating FIXED panel to the right of the
 *             centered column, out of the document flow entirely; faded
 *             in/out by assets/toc-float.js only while the reader is
 *             actually inside the article (hidden at the top of the
 *             page and again past the article's end, so it never
 *             hovers over the CTA/footer).
 *   ≤1439px — .article-toc-inline: a plain static block in the normal
 *             flow right before the article body — no sticky, no
 *             animation, scrolls away with the content (explicit user
 *             decision: one continuous behavior from mobile up to the
 *             width where the floating panel physically fits).
 * 1440 is not arbitrary (was 1280 for the 604px column): the centered
 * 780px column + 40px gap + 260px panel + ≥24px viewport margin needs
 * ≈1428px minimum — 1440 is the first standard breakpoint above that.
 * ------------------------------------------------------------------ */
.article-layout { display: block; padding: 26px 40px; }
.article-layout .article-body { min-width: 0; }
.article-layout .section {
  padding: 0 0 26px;
  margin-bottom: 26px;
  border-bottom: 1px solid var(--line);
}
.article-layout .section:last-child { padding-bottom: 0; margin-bottom: 0; border-bottom: none; }

/* Floating panel. left: calc(50% + 430px) anchors it to the COLUMN, not
   the viewport edge: 430 = half the 780px article column + one 40px gap
   — so on ultrawide it sits right next to the text instead of drifting
   to the far screen edge. Hidden state is opacity+visibility (not
   display) so the fade can run; .is-visible is toggled by
   assets/toc-float.js. z-index stays under .site-nav's 40.
   (2026-07-18 column widening: 342→430 and breakpoint 1280→1440 — the
   780px column + 40 gap + 260 panel + ≥24px margin needs ≥1428px.) */
.article-toc { display: none; }
@media (min-width: 1440px) {
  .article-toc {
    display: block;
    position: fixed;
    top: 110px;
    left: calc(50% + 430px);
    width: 260px;
    max-height: calc(100vh - 134px);
    overflow-y: auto;
    z-index: 30;
    opacity: 0;
    visibility: hidden;
    transform: translateX(10px);
    transition: opacity .25s ease, transform .25s ease, visibility 0s linear .25s;
  }
  .article-toc.is-visible {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: opacity .25s ease, transform .25s ease;
  }
}
@media (prefers-reduced-motion: reduce) {
  .article-toc { transition: none; transform: none; }
}
.article-toc__sticky { border-left: 2px solid var(--jade); padding-left: 16px; }
.article-toc__list { display: flex; flex-direction: column; gap: 2px; margin-top: 10px; }
.article-toc__list a {
  font-size: 13px;
  line-height: 1.4;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 5px 0;
}
.article-toc__list a:hover { color: var(--jade); }

/* In-flow TOC block (mobile / tablet / narrow desktop). Same 70ch cap
   and auto-centering as .article-body so it reads as the first block of
   the same column. Replaced the old collapsed <details> menu — the list
   is simply open, ordinary content. */
.article-toc-inline {
  max-width: 780px; /* synced with .article-body (2026-07-18 widening) */
  margin: 0 auto 26px;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px 18px 12px;
}
.article-toc-inline .article-toc__list { margin-top: 8px; }
@media (min-width: 1440px) {
  .article-toc-inline { display: none; }
}
@media (max-width: 860px) {
  .article-layout { padding: 22px 40px; }
}
@media (max-width: 640px) {
  .article-layout { padding: 18px 16px; }
  .article-toc-inline { margin-bottom: 18px; }
}

/* Anchor targets vs the sticky nav (2026-07-18 mobile bug). TOC links DID
   scroll (hash changed, scrollY moved — verified with real clicks), but
   the target heading landed at viewport top:0 — i.e. UNDER the sticky
   .site-nav, which is 151px tall on phones (nav wraps to 3 rows) — so on
   a real device it read as "click does nothing": you saw a section's
   prose with its heading hidden behind the header. scroll-margin-top
   reserves the nav's height on every in-page anchor target ([id] is
   deliberately universal — the property only matters during anchor/
   scrollIntoView navigation, it's inert otherwise, and gorod's targets
   are .section divs, not h2s, so element-scoping would miss them).
   The +32px cushion is not padding taste alone: scroll-reveal's
   translateY(18px) is still applied to a not-yet-revealed section at
   the moment the browser computes the jump, so the final settled
   position is up to ~18px higher than targeted — 32px absorbs that
   drift with visible room to spare. The var's static fallbacks mirror
   the nav's measured wrap heights (66px one-row ≥641px / 151px worst
   case ≤640px); toc-float.js refines it to the exact measured height
   on load/resize. */
:root { --sticky-nav-h: 66px; }
@media (max-width: 640px) {
  :root { --sticky-nav-h: 151px; }
}
[id] { scroll-margin-top: calc(var(--sticky-nav-h) + 32px); }

/* Reading-progress line (assets/reading-progress.js). Injected by JS into
   the sticky .site-nav ONLY on pages with a TOC'd article, so it rides the
   nav for free — no separate fixed element, no nav-height math in CSS, and
   it stays glued to the nav's bottom edge even when the mobile nav wraps
   to two rows. bottom:-1px overlays the nav's 1px hairline border, so the
   jade fill visually replaces the hairline as it grows. The fill scales
   via transform (set from JS each scroll frame) — no layout work. */
.reading-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 3px;
  pointer-events: none;
}
.reading-progress__bar {
  height: 100%;
  background: var(--jade);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

/* Inline cross-links inside article prose — solid jade underline marks a
   connection the content itself confirms. */
.body-link--confirmed {
  color: inherit;
  text-decoration: none;
  border-bottom: 2px solid var(--jade);
}
.body-link--confirmed:hover { color: var(--jade); }

/* Dashed cinnabar counterpart — a cross-link WE added where the source
   only implied the connection but never marked it (marked_in_source:
   false in cross_links_json/the old napravlenie fields). Locked-in
   convention from the pre-sections_json pages (Спондилез, Грыжа и
   протрузия) carried over here: permanent origin marker, not a
   "pending/unfinished" indicator — don't merge with .body-link--confirmed
   or drop the trailing tag later without asking. */
.body-link--added {
  color: inherit;
  text-decoration: none;
  border-bottom: 2px dashed var(--seal);
}
.body-link--added:hover { color: var(--seal-dark); }
.body-link--added-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--seal-dark);
  background: rgba(178, 58, 46, 0.08);
  padding: 1px 7px;
  border-radius: 9px;
  margin-left: 4px;
  white-space: nowrap;
  vertical-align: 2px;
}

/* Inline body photo — real photo (once attached) or an explicit
   placeholder, same "flag it, don't fake it" rule as clinic/city photos.
   Deliberately distinct from .in-progress (cinnabar/seal = "text missing")
   — this is jade/slate, a neutral "image pending" marker, not a warning. */
.body-photo {
  width: 100%;
  border-radius: 10px;
  border: 1px solid var(--line);
  display: block;
}
.body-photo-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 44px 24px;
  border: 1.5px dashed var(--line);
  border-radius: 10px;
  background: var(--paper);
  text-align: center;
}
.body-photo-placeholder svg { width: 34px; height: 34px; color: var(--slate); }
.body-photo-placeholder p { margin: 0; max-width: 42ch; font-size: 13.5px; color: var(--ink-soft); }
.body-photo-placeholder span {
  font-family: var(--font-mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--slate);
  border: 1px dashed var(--line);
  padding: 3px 9px;
  border-radius: 10px;
}

/* -------------------------------------------------------------------
 * Cookie banner — bottom-left floating card (not a full-width bar) so it
 * never sits over the main content column or the popup form; deliberately
 * compact, same paper/ink/jade tokens as everything else.
 * ------------------------------------------------------------------ */
.cookie-banner {
  position: fixed;
  left: 20px;
  bottom: 20px;
  z-index: 9999;
  max-width: 380px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14);
  padding: 16px 18px;
}
.cookie-banner[hidden] { display: none; }
.cookie-banner p { margin: 0 0 12px; font-size: 13.5px; color: var(--ink-soft); }
.cookie-banner a { color: var(--jade); }

.cookie-banner__actions { display: flex; gap: 8px; }
.cookie-banner__accept, .cookie-banner__settings-btn, .cookie-banner__save {
  font-family: var(--font-mono);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .04em;
  border-radius: 6px;
  padding: 8px 16px;
  cursor: pointer;
  border: none;
}
.cookie-banner__accept { background: var(--jade); color: var(--paper); flex: 1; }
.cookie-banner__accept:hover { opacity: .9; }
.cookie-banner__settings-btn { background: none; color: var(--ink-soft); border: 1px solid var(--line); }
.cookie-banner__settings-btn:hover { border-color: var(--jade); color: var(--jade); }
.cookie-banner__settings-btn[aria-expanded="true"] { border-color: var(--jade); color: var(--jade); }

/* Category toggles ("Настройки" panel) — hidden by default, shown by
   assets/cookie-banner.js when .cookie-banner__settings-btn is clicked. */
.cookie-banner__settings { margin-bottom: 12px; padding-top: 2px; border-top: 1px solid var(--line); }
.cookie-banner__settings[hidden] { display: none; }
.cookie-cat { display: block; padding: 10px 0; border-bottom: 1px solid var(--line); cursor: default; }
.cookie-cat:last-of-type { border-bottom: none; }
.cookie-cat__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.cookie-cat__title { font-size: 13px; font-weight: 600; color: var(--ink); }
.cookie-cat__head input[type="checkbox"] { flex-shrink: 0; width: 15px; height: 15px; accent-color: var(--jade); cursor: pointer; }
.cookie-cat__head input[type="checkbox"]:disabled { cursor: not-allowed; opacity: .55; }
.cookie-cat__desc { display: block; margin-top: 3px; font-size: 12px; color: var(--ink-soft); line-height: 1.4; }
.cookie-banner__save { display: block; width: 100%; margin-top: 12px; background: var(--jade-soft); color: var(--jade); }
.cookie-banner__save:hover { opacity: .85; }

@media (max-width: 640px) {
  .cookie-banner { left: 12px; right: 12px; bottom: 12px; max-width: none; }
}

/* -------------------------------------------------------------------
 * Gorod page redesign (2026-07-10 — Хэйхэ as the reference template for
 * the other 5 cities). Reuses .article-layout/.article-toc (originally
 * built for napravlenie/metod's sections_json format) for the sticky
 * sidebar — gorod's sections are a fixed list, not JSON-driven, but the
 * grid/TOC styling is identical so no need for a parallel set of rules.
 * ------------------------------------------------------------------ */

/* "Подробнее о городе" — native <details>, no JS. */
.about-more { margin-top: 14px; }
.about-more summary {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--jade);
  list-style: none;
}
.about-more summary::-webkit-details-marker { display: none; }
.about-more summary::before { content: '+'; font-family: var(--font-body); font-size: 15px; line-height: 1; }
.about-more[open] summary::before { content: '−'; }
.about-more__body { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }

/* ---------- Clinic carousel ---------- */
.clinic-carousel { position: relative; margin-top: 14px; display: flex; align-items: center; gap: 12px; }
/* /kliniki/ archive (2026-07-19): each city group's .wide-container is
   ~1400px — much wider than 3 fixed-card-width cards need, so the
   carousel's own flex:1 viewport would stretch to fill that space and
   happily fit a 4th/5th card with room to spare instead of genuinely
   overflowing (the whole point of the arrow). max-width below = exactly
   3 slides + their 2 inter-slide gaps + this component's own gap to the
   arrow + the arrow itself — the same confinement the narrower ~780px
   article/gorod contexts already get "for free" from their own width,
   reproduced explicitly here since this container is wider than that.
   margin-inline:auto centers the (now width-capped) carousel under the
   group heading above it, which .wide-container h2 already centers via
   text-align — without this the carousel sat flush against the wide
   container's left edge while its own heading centered, a visible
   two-axis mismatch (2026-07-19, later: user screenshot caught it).
   2026-07-19 (later still): 240px read too small against this ~1400px
   wide container next to the rest of the site's wide-band cards, so the
   card itself is enlarged to 288px HERE ONLY (.klinika-archive-group
   .clinic-carousel__slide below) — the shared base .clinic-carousel__slide
   rule (240px) still governs every other usage (the napravlenie/metod/
   gorod "Клиники, где лечат X" carousels, all in the narrower ~780px
   column) untouched. max-width recomputed with the same formula for the
   new width: 3×288 + 2×14 (track gaps) + 12 (carousel-to-arrow gap) +
   40 (arrow) = 944px. */
.klinika-archive-group .clinic-carousel { max-width: 944px; margin-inline: auto; }
.klinika-archive-group .clinic-carousel__slide { flex-basis: 288px; }
.clinic-carousel__viewport { overflow: hidden; flex: 1; min-width: 0; }
.clinic-carousel__track {
  display: flex;
  gap: 14px;
  list-style: none;
  margin: 0;
  padding: 0;
  will-change: transform;
}
.clinic-carousel__track.is-animating { transition: transform .35s ease; }
/* 240px FIXED — one card size everywhere (2026-07-18, user bug report):
   the old calc((100% − 28px) / 3) made the card a function of its
   container AND of the slide count — groups of exactly 3 (no arrow)
   rendered wider cards than groups of 4+ (the 40px arrow + 12px gap
   shrink the viewport), and home's wide container produced ~390px cards
   vs ~190px in the article column. A fixed basis makes every clinic
   card identical on every page at every count; extra cards simply sit
   beyond the viewport edge (overflow:hidden) and rotate in via the
   arrow. 240px matches the catalog card floor (.idx-grid--catalog's
   minmax). The arrow hides itself via JS when all slides already fit
   (.clinic-carousel__nav--hidden below). */
.clinic-carousel__slide { flex: 0 0 240px; min-width: 0; }
.carousel-card {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  text-decoration: none;
  color: inherit;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  transition: border-color .15s ease;
}
.carousel-card:hover { border-color: var(--jade); }
.carousel-card__photo {
  aspect-ratio: 4/3;
  background: var(--jade-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--slate);
}
.carousel-card__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.carousel-card__photo svg { width: 30px; height: 30px; }
.carousel-card__body { padding: 12px 14px 14px; }
.carousel-card__title { font-weight: 700; font-size: 14.5px; }
.carousel-card__address { font-size: 12.5px; color: var(--ink-soft); margin-top: 4px; }
.carousel-card--placeholder .carousel-card__title { color: var(--ink-soft); font-weight: 600; }
.clinic-carousel__nav {
  flex: none;
  box-sizing: border-box;
  padding: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.clinic-carousel__nav:hover { background: var(--jade); color: #fff; border-color: var(--jade); }
.clinic-carousel__nav:focus-visible { outline: 2px solid var(--jade); outline-offset: 2px; }
.clinic-carousel__nav svg { width: 18px; height: 18px; }
/* Toggled by gorod-interactions.js when every slide already fits inside
   the viewport (few slides / very wide container) — a rotate arrow with
   nothing hidden behind the edge is a lie. Server renders the arrow for
   any 2+ slides; the JS measurement decides. */
.clinic-carousel__nav--hidden { display: none; }

/* ---------- Quiz illustration ---------- */
/* align-items:center (not flex-start) is deliberate: Quizle's steps vary a
   lot in height (a 4-option radio step vs. the file-upload step with its
   extra description/dropzone/progress-bar text), so a fixed-size
   illustration pinned to the top would sit flush with short steps but
   look stranded with a big empty gap below it on tall ones. Centering
   keeps the same visual relationship — illustration vertically centered
   against whatever height the current step happens to be — on every step. */
/* flex-start + a fixed margin (not center-alignment) is deliberate: a
   centered illustration's absolute position shifts with every step's
   content height, which reads as "jumping around" between steps even
   though it's centered relative to each one individually. A fixed
   top/bottom margin keeps the illustration's position and the gap above
   it identical on every question step — the only thing that varies is
   how much blank space trails below it on shorter steps, which is far
   less noticeable than the illustration itself moving. The contacts step
   (name/phone/consent/submit) hides the illustration entirely instead —
   see assets/gorod-interactions.js — it's Quizle's own two-column layout
   and needs the full card width, not a fixed-margin decorative aside. */
.quiz-section__layout { display: flex; gap: 28px; align-items: flex-start; }
.quiz-section__illustration { flex: none; width: 130px; margin: 20px 0; }
.quiz-section__illustration svg { width: 100%; height: auto; color: var(--ink); }
.quiz-illustration__checkmark {
  stroke-dasharray: 26;
  stroke-dashoffset: 26;
}
.quiz-illustration.is-drawn .quiz-illustration__checkmark {
  animation: spina-draw-checkmark .5s ease forwards;
}
@keyframes spina-draw-checkmark {
  to { stroke-dashoffset: 0; }
}
.quiz-section__quiz { flex: 1; min-width: 0; }
/*
 * Quizle's own stylesheet switches .quizle-contacts from column to a
 * side-by-side row layout at `@media (min-width:768px)` — a viewport
 * check, not a container query. Our .quiz-section sits in a narrow
 * content column (page-shell minus the sticky TOC sidebar, ~500-600px)
 * that's well under 768px even on a wide desktop viewport, so Quizle's
 * row layout kept triggering anyway and squeezed the consent-checkbox
 * text into a sliver-width column — tall enough that Quizle's own step
 * height calculation didn't account for it, so the progress bar/buttons
 * rendered on top of the wrapped text. Force column layout here
 * regardless of viewport width, since that's what actually fits this
 * container. !important because this overrides a plugin's own
 * media-query-scoped rule, not fighting our own CSS.
 */
.quiz-section .quizle-contacts { flex-direction: column !important; }
/*
 * Quizle pins its progress-bar/buttons footer (.quizle-footer) via
 * position:absolute against a container height it computes once via JS
 * (assuming its own default row layout for the contacts step). Forcing
 * column layout above changes the actual content height, but doesn't
 * change that JS-computed number, so the absolutely-positioned footer
 * stayed at the old (shorter) offset and rendered on top of the now-
 * taller wrapped consent text. Taking the footer out of absolute
 * positioning entirely sidesteps the stale height number — it just
 * flows after the real content instead of trusting a number nothing
 * here recalculates.
 */
.quiz-section .quizle-footer { position: static !important; margin-top: 20px !important; }
.quiz-section .js-quizle-questions { padding-bottom: 0 !important; }
@media (max-width: 700px) {
  .quiz-section__layout { flex-direction: column; }
  .quiz-section__illustration { width: 90px; }
}

/* ---------- "Как добраться" transport cards ---------- */
.transport-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 14px; margin-top: 14px; }
.transport-card {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 16px 16px 14px;
}
.transport-card__icon { width: 30px; height: 30px; color: var(--jade); margin-bottom: 10px; }
.transport-card__title { font-weight: 700; font-size: 14.5px; margin-bottom: 6px; }
.transport-card__meta { font-size: 12.5px; color: var(--ink-soft); }
.transport-card__meta div { margin-top: 2px; }
.transport-card__when { font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--slate); margin-bottom: 6px; }
.transport-card--upcoming { border-style: dashed; border-color: var(--seal); }
.transport-card--upcoming .transport-card__icon { color: var(--seal); }
.transport-card__upcoming-tag {
  display: inline-block;
  margin-top: 8px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--seal-dark);
  background: rgba(178, 58, 46, 0.08);
  border: 1px solid var(--seal);
  border-radius: 10px;
  padding: 3px 10px;
}
.transport-card__link {
  display: inline-block;
  margin-top: 8px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--jade);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.transport-card__link:hover { color: var(--ink); }

/* ---------- "Что взять с собой" checklist ---------- */
.checklist { list-style: none; margin: 14px 0 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.checklist__item { display: flex; gap: 12px; align-items: flex-start; }
.checklist__icon { flex: none; width: 22px; height: 22px; color: var(--jade); margin-top: 1px; }
.checklist__text { font-size: 14.5px; line-height: 1.5; }
.checklist__text a { color: var(--jade); }

/* ---------- Photo gallery + lightbox ---------- */
/* Carousel behaviour (viewport/track/nav) is the same .clinic-carousel__*
   component used by spina_render_clinic_carousel() — see gorod-gallery.php
   for why. .photo-gallery__track only adds its own gap/will-change/
   is-animating on top since it doesn't reuse .clinic-carousel__track
   itself (item sizing here is fixed-width, not the 3-up percentage split
   clinic slides use). Native scroll (overflow-x:auto + scroll-snap) that
   produced the grey scrollbar is gone as of 2026-07-14. */
.photo-gallery { margin-top: 14px; }
.photo-gallery__track {
  display: flex;
  gap: 14px;
  will-change: transform;
}
.photo-gallery__track.is-animating { transition: transform .35s ease; }
.photo-gallery__item {
  flex: 0 0 auto;
  width: min(280px, 70vw);
  aspect-ratio: 4/3;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--line);
  cursor: pointer;
  padding: 0;
  background: var(--jade-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--slate);
}
.photo-gallery__item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-gallery__item svg { width: 32px; height: 32px; }
.photo-gallery__item:focus-visible { outline: 2px solid var(--jade); outline-offset: 2px; }

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background: rgba(22, 29, 34, 0.88);
  display: flex;
  align-items: center;
  justify-content: center;
}
.lightbox[hidden] { display: none; }
.lightbox__figure { position: relative; max-width: min(90vw, 900px); max-height: 85vh; }
.lightbox__image-wrap {
  aspect-ratio: 4/3;
  width: min(90vw, 900px);
  background: var(--paper);
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--slate);
  overflow: hidden;
}
.lightbox__image-wrap img { width: 100%; height: 100%; object-fit: contain; }
.lightbox__image-wrap svg { width: 44px; height: 44px; }
.lightbox__caption { color: var(--paper); text-align: center; margin-top: 12px; font-size: 13.5px; }
.lightbox__close, .lightbox__prev, .lightbox__next {
  position: absolute;
  box-sizing: border-box;
  padding: 0;
  border: none;
  background: rgba(238, 241, 236, 0.14);
  color: var(--paper);
  border-radius: 50%;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.lightbox__close:hover, .lightbox__prev:hover, .lightbox__next:hover { background: rgba(238, 241, 236, 0.28); }
.lightbox__close:focus-visible, .lightbox__prev:focus-visible, .lightbox__next:focus-visible { outline: 2px solid var(--paper); outline-offset: 2px; }
.lightbox__close { top: -50px; right: 0; }
.lightbox__prev { left: -56px; top: 50%; transform: translateY(-50%); }
.lightbox__next { right: -56px; top: 50%; transform: translateY(-50%); }
.lightbox__close svg, .lightbox__prev svg, .lightbox__next svg { width: 20px; height: 20px; }
@media (max-width: 700px) {
  .lightbox__prev { left: 4px; }
  .lightbox__next { right: 4px; }
  .lightbox__close { top: 4px; right: 4px; }
}

/* -------------------------------------------------------------------
 * Sitewide "wide layout" system (2026-07-16, Stage 1 of rolling the
 * homepage's grid system out to other templates) — .wide-band/
 * .wide-container/.wide-divider mirror .home-band/.home-container/
 * .home-divider (front-page.php, body.home-scoped) in every measurement:
 * same --*-w formula, same 48px/64px top/bottom split, same 32px
 * divider margins, same centered-heading-with-32px-gap-to-content rule.
 * Deliberately a SEPARATE set of classes, not a rename of the homepage's
 * own — home-band/home-container/home-divider are already tested and
 * approved; duplicating a few rules here is safer than touching that
 * working code to rename it. Opt in per-template via body_class(
 * 'uses-wide-layout') — see archive-napravlenie.php for the first use.
 * ------------------------------------------------------------------ */
:root { --page-w: min(94vw, 1400px); }
.wide-band { width: 100%; }
.wide-container {
  max-width: var(--page-w);
  margin: 0 auto;
  padding: 40px clamp(20px, 4vw, 64px) 56px; /* 2026-07-18: 48/64→40/56, synced with .home-container's seventh revision */
}
@media (max-width: 640px) {
  .wide-container { padding: 32px clamp(20px, 5vw, 40px) 40px; }
}
.wide-divider {
  max-width: var(--page-w);
  margin: 32px auto;
  border-top: 1px solid var(--line);
}
@media (max-width: 640px) { .wide-divider { margin: 20px auto; } }
/* Heading + intro center across the full container, with a fixed 32px
   gap to whatever content follows — same numbers as the homepage's
   .section h2 rule. Full `margin: 0 0 32px` (not just margin-bottom) so
   margin-top is deterministically 0 regardless of what a nested
   element's own rule (e.g. .idx-group-title) already declares — same
   "one rule owns the box model" reasoning as the homepage's own fix. */
.wide-container h1,
.wide-container h2 { text-align: center; margin: 0 0 32px; }
/* .intro already caps at 65ch (base rule in components.css) for
   readability — that rule sets no margin at all, so centering it needs
   an explicit auto margin, not just text-align, or the box sits flush
   left with only its text centered inside (the exact bug the homepage
   audit caught on .about-project__subtitle last round). */
.wide-container .intro { text-align: center; margin: 0 auto 32px; }

/* Page-shell loses its boxed-card look on templates using the wide
   layout, same as the homepage (.site-nav's own flat/fluid treatment is
   unconditional now — see the base rule — so it no longer needs its own
   copy here). .crumb gets the same fluid gutter so its left edge lines
   up with .wide-container's own edge. */
body.uses-wide-layout .page-shell { max-width: none; background: none; border: none; border-radius: 0; }
body.uses-wide-layout .crumb { max-width: var(--page-w); margin: 0 auto; padding: 18px clamp(20px, 4vw, 64px) 0; }

/* -------------------------------------------------------------------
 * Stage 2 (2026-07-17): single-napravlenie.php / single-metod.php.
 * Explicit constraint from the user, confirmed after two clarifying
 * questions (see spina-site-status.md memory for the full reasoning):
 * the FRAME widens (header/hero, the side gutters and TOC gap of the
 * text+TOC grid) but the actual reading column stays capped at ~70ch
 * — it must NOT stretch just because the page around it got wider.
 * The "Отправить снимок" CTA banner (template-parts/cta-banner-scan.php)
 * stays at text width too (no bleed) — it has no width rule of its own,
 * it's simply 100% of .article-body, so capping .article-body already
 * covers it with zero extra code.
 *
 * Gated to min-width:861px — matches .article-layout's own existing
 * grid-to-block collapse breakpoint (see its @media (max-width:860px)
 * rule above). Below that, none of this applies; the page already
 * reverts to the simple stacked mobile layout these rules would only
 * fight with (mobile's own .article-cta margin, in particular, must
 * stay in full control below 640px — nothing here should out-specificity
 * it by accident).
 * ------------------------------------------------------------------ */
@media (min-width: 861px) {
  /* Header/hero — shared .gorod-hero/.napr-header markup with single-
     gorod.php/single-klinika.php (Stage 3, not yet touched) — scoped to
     body.uses-wide-layout so Stage 3 pages (no such class yet) are
     completely unaffected. Just gets more breathing room; internal
     photo/text grid ratio (1fr/1.3fr) is untouched. */
  body.uses-wide-layout .gorod-hero { max-width: var(--page-w); margin: 0 auto; padding: 22px clamp(20px, 4vw, 64px) 30px; }

  /* Article column — this rule has now flipped twice, so the history
     matters. Originally justify-content:center on a text+TOC GRID —
     wrong, because centering the (column+TOC) pair put the text's left
     edge off the hero's content edge (fixed 2026-07-17 to grid-start,
     per the "shared left edge" rule). 2026-07-18 redesign changed the
     composition itself: the TOC left the flow entirely (fixed floating
     panel / in-flow block before the article — see .article-toc rules),
     so there is no grid pair anymore, and the user-confirmed target for
     TOC'd article pages became ONE CENTERED axis for everything between
     hero and footer: the hero band is a centered box, the article
     column centers inside the same symmetric-padding container (margin
     auto = viewport center), and the .page-shell sections below the
     article re-center too via the has-toc-article override further
     down. The old left-edge rule still stands where nothing changed:
     klinika and old-format (no-TOC) pages. */
  body.uses-wide-layout .article-layout {
    max-width: var(--page-w);
    margin: 0 auto;
    /* Homepage band rhythm (.home-container's own padding), applied to
       article pages' outer composition in the 2026-07-18 consistency
       audit (was 26/40 — article pages read ~2× denser than every other
       page type). Intra-article 26px between subsections is untouched:
       that's reading typography (Stage 2), not band rhythm.
       2026-07-18 (later): 48/64→40/56 with the sitewide rhythm trim. */
    padding: 40px clamp(20px, 4vw, 64px) 56px;
  }
  /* Belt-and-suspenders cap directly on the text column itself — must
     hold independently of the container, per explicit instruction from
     the Stage-2 round. margin:auto is what puts the column on the
     centered axis now that .article-layout is a plain block.
     780px (2026-07-18, user-approved revision of the 70ch decision,
     confirmed on 1920px preview screenshots): the old 604px column left
     too much dead margin against the 1400px hero band. 780px ≈ 90ch in
     the body font — the agreed readability ceiling (~90 chars/line),
     deliberately NOT the hero width. */
  body.uses-wide-layout .article-body { max-width: 780px; margin-left: auto; margin-right: auto; }

  /* Everything that sits OUTSIDE .article-layout but still directly in
     .page-shell — expert-review widget, the old-format field-based
     sections (5 old-format metod pages, e.g. iglonozh), cross-links,
     related-clinics, and the closing "Остались вопросы?" CTA card — all
     used the implicit 920px page-shell cap before; now that page-shell
     itself has no cap, each needs its own, or they'd stretch edge to
     edge. Same 70ch reading width. The child combinator
     (.page-shell > .section) deliberately excludes .article-layout
     .section (each content sub-section inside the article, e.g.
     "Диагностика") — that already has its own unrelated rule and must
     keep filling .article-body's full (already-capped) width, not get
     double-capped.
     Centered (margin auto) as the BASE case — that's correct for the
     hero-less Page templates (legal pages, /kontakty/, whose centered
     look was explicitly reviewed and approved) and 404. */
  body.uses-wide-layout .page-shell > .section,
  body.uses-wide-layout .page-shell > .article-cta {
    /* 780px — synced with .article-body above (2026-07-18 widening):
       kontakty/legal, klinika and old-format pages share the same
       unified column, per the "no new divergences" instruction. */
    max-width: 780px;
    margin-left: auto;
    margin-right: auto;
  }

  /* Paragraph cap: style.css's base `.section p { max-width: 70ch }`
     predates the 780px column (2026-07-18) and would keep prose at
     604px inside the wider column — lift it ONLY where the unified
     column applies. The homepage is deliberately untouched: its
     .home-container sections are neither .article-body descendants nor
     .page-shell children, so home paragraphs keep the 70ch cap inside
     the wide bands. */
  body.uses-wide-layout .article-body .section p,
  body.uses-wide-layout .page-shell > .section p {
    max-width: none;
  }

  /* AXIS HISTORY (three revisions, kept so the next reader knows why
     there is no left-align rule here anymore):
     — 2026-07-17: single-post blocks were LEFT-aligned to the hero's
       content edge via a margin-left calc (the "shared left edge" rule),
       because back then the ARTICLE column itself was left-aligned too.
     — 2026-07-18 (TOC redesign): TOC'd pages (has-toc-article) moved to
       a CENTERED single axis; klinika/old-format kept the left-align.
     — 2026-07-18 (later, user bug report №4): that split itself became
       the defect — klinika/old-format pages read as "not matching the
       approved wide format" next to every other page type. The
       left-align calc rules were REMOVED entirely: the base rule above
       (max-width:780px + margin auto) now centers every page type on
       the same axis — articles, kontakty/legal, klinika, old-format,
       404. The hero band is a centered box, so hero and column share
       the center line everywhere. No separate has-toc margin override
       needed anymore either. */

  /* Band rhythm (48/64, as on the homepage) for the OUTER blocks of
     article pages — expert plaque, "Смотрите также", related clinics,
     the closing CTA (2026-07-18 audit; was 26/26 — see the
     .article-layout padding note above for the rationale). Scoped to
     has-toc-article: on old-format/klinika pages the same
     .page-shell > .section selector also matches the article-like
     subsections themselves (no .article-body wrapper there to tell
     them apart), so those pages deliberately keep the compact reading
     rhythm. Desktop-only (this media block): the ≤860px media rules
     own the mobile compact spacing and must keep winning. */
  body.uses-wide-layout.single.has-toc-article .page-shell > .section {
    padding-top: 40px; /* 48/64→40/56 (2026-07-18 sitewide rhythm trim) */
    padding-bottom: 56px;
  }
  body.uses-wide-layout.single.has-toc-article .page-shell > .article-cta {
    margin-top: 40px;
    margin-bottom: 56px;
  }
}

/* -------------------------------------------------------------------
 * Legal/kontakty pages (2026-07-17) — /kontakty/, /politika-
 * konfidencialnosti/, /polzovatelskoe-soglashenie/. All three are plain
 * WordPress "Page" posts rendered through page.php's single flat
 * `.section` (h1/h2/p/ul straight from post_content) — flowing prose
 * with subheadings, not the homepage/archive's centered "block titles",
 * so headings stay left-aligned here; only the vertical rhythm
 * (tight below, generous above) is brought in line with the rest of
 * the site's heading system.
 *
 * Scoped to body.page — WordPress's own automatic class for any Page
 * post type on the default template, added by core, not something we
 * put there ourselves. This is exactly what distinguishes these 3
 * pages from single-klinika.php/404.php, which reuse the identical
 * `.page-shell > .section` markup shape but are NOT Pages (klinika is
 * a custom post type, 404 has no post at all) — so this rule can't
 * leak onto them by accident.
 * ------------------------------------------------------------------ */
body.page .section h1 { margin: 0 0 32px; }
body.page .section h2 { margin: 80px 0 32px; }
