
@font-face{font-family:'Cormorant Garamond';font-style:normal;font-weight:600;font-display:swap;src:url("/assets/fonts/0e47c4b6.woff2") format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:'Cormorant Garamond';font-style:normal;font-weight:600;font-display:swap;src:url("/assets/fonts/087778c2.woff2") format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122;}
@font-face{font-family:'Cormorant Garamond';font-style:normal;font-weight:700;font-display:swap;src:url("/assets/fonts/0e47c4b6.woff2") format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:'Cormorant Garamond';font-style:normal;font-weight:700;font-display:swap;src:url("/assets/fonts/087778c2.woff2") format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122;}
@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url("/assets/fonts/8f9657f9.woff2") format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url("/assets/fonts/dc732831.woff2") format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122;}
@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url("/assets/fonts/8f9657f9.woff2") format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}
@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url("/assets/fonts/dc732831.woff2") format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122;}
:root{--bg:#0A1F1A;--bg-2:#0E2A24;--bg-3:#10302A;--gold:#D4AF6A;--gold-soft:#C8A24B;--text:#F3F1EC;--text-2:#A8A49C;--text-3:#6F7570;--line:rgba(212,175,106,.20);--line-soft:rgba(243,241,236,.08);}
*{box-sizing:border-box;}
/* Clip horizontal overflow from off-canvas fixed menus/drawers so mobile
   never gets a stray horizontal scroll. overflow-x:hidden (not clip) keeps
   position:sticky and the slide-in nav working; verified on iOS 390px. */
html{overflow-x:hidden;}
body{margin:0;background:var(--bg);color:var(--text);font-family:'Inter',system-ui,sans-serif;font-size:17px;line-height:1.7;-webkit-font-smoothing:antialiased;}
a{color:var(--gold);text-decoration:none;}a:hover{text-decoration:underline;}
/* Guaranteed visible keyboard focus (WCAG 2.4.7). Only on keyboard nav
   via :focus-visible, so mouse/touch users are unaffected. */
:focus-visible{outline:2px solid var(--gold);outline-offset:2px;border-radius:2px;}
/* Round initial-letter avatar placeholder (used by nav.js when a person/
   partner photo is missing). Inherits width/height from the avatar class. */
.avatar-ph{display:inline-flex!important;align-items:center;justify-content:center;box-sizing:border-box;font-family:'Cormorant Garamond',Georgia,serif;font-weight:600;font-size:2rem;line-height:1;color:var(--gold);background:linear-gradient(160deg,var(--bg-3,#10302A),var(--bg-2,#0E2A24));border:2px solid var(--gold);border-radius:50%;overflow:hidden;flex:0 0 auto;}
.bwrap{max-width:760px;margin:0 auto;padding:0 22px;}
/* .bhead / .bbrand moved to assets/header.css (2026-07-17). They could not stay here:
   the two landings inline their whole stylesheet and cannot link blog.css (it restyles
   bare body/a/table/h1 and would repaint them), so the header was written a second time
   by hand over there and the two drifted. See the top of assets/header.css. */
.btg{font-size:13.5px;font-weight:600;color:var(--text);border:1px solid var(--line);border-radius:2px;padding:9px 15px;}
.btg:hover{color:var(--gold);border-color:var(--gold);text-decoration:none;}
.bcrumbs{font-size:12.5px;color:var(--text-3);margin:28px 0 6px;}
.bcrumbs a{color:var(--text-3);}
.bcrumbs a:hover{color:var(--gold);}
/* Hub and project headlines were never given a rule of their own, so they fell
   through to the browser default and inherited body line-height:1.7 in Inter —
   on a phone the catalogue title took three lines with a blank line between
   each. They are the same kind of heading as an article's, so they get the same
   type. The margins set later for .hub-hero h1 and .pj-top h1 still win. */
article h1,.hub-hero h1,.pj-top h1{font-family:'Cormorant Garamond',Georgia,serif;font-size:clamp(30px,5.4vw,46px);font-weight:700;line-height:1.12;letter-spacing:-.01em;margin:10px 0 14px;}
.bmeta{font-size:13px;color:#c9d4d4;margin-bottom:30px;padding-bottom:22px;border-bottom:1px solid var(--line-soft);}
.bmeta.has-byline{margin-bottom:14px;padding-bottom:0;border-bottom:0;}
.article-byline{font-size:13.5px;color:var(--text-2);margin:0 0 30px;padding-bottom:22px;border-bottom:1px solid var(--line-soft);}
.article-byline a{color:var(--gold);}
.article-byline .abrev{display:block;font-size:13px;color:var(--text-3);margin-top:4px;}
.bhero{margin:0 0 30px;border-radius:4px;overflow:hidden;border:1px solid var(--line-soft);background:var(--bg-3);}
.bhero img{display:block;width:100%;height:auto;aspect-ratio:1200/630;object-fit:cover;}
.prose{font-size:15.5px;line-height:1.62;}
.prose h2{font-family:'Cormorant Garamond',Georgia,serif;font-size:clamp(25px,3vw,30px);font-weight:600;line-height:1.2;color:var(--gold);margin:46px 0 10px;padding-top:8px;}
.prose h2::before{content:"";display:block;width:34px;height:3px;background:var(--gold);border-radius:2px;margin:0 0 12px;}
.prose h3{font-family:'Inter',system-ui,sans-serif;font-size:17.5px;font-weight:700;line-height:1.32;color:#f0e4cf;margin:28px 0 9px;}
.prose p,.prose li{font-size:15.5px;line-height:1.62;color:#D7DED9;}
.prose p{margin:0 0 15px;max-width:68ch;}
.prose li{margin-bottom:9px;}
.prose strong{color:var(--text);}
.prose .lead{font-size:17px;color:#dfe6e1;line-height:1.58;max-width:64ch;}
article:not(.prose) h2{font-family:'Cormorant Garamond',Georgia,serif;font-size:clamp(24px,3.6vw,32px);font-weight:600;line-height:1.18;margin:44px 0 14px;}
article:not(.prose) h3{font-family:'Cormorant Garamond',Georgia,serif;font-size:22px;font-weight:600;margin:32px 0 10px;}
article:not(.prose) p,article:not(.prose) li{color:#DCD9D2;}
article:not(.prose) li{margin-bottom:8px;}
article:not(.prose) strong{color:var(--text);}
article:not(.prose) .lead{font-size:19px;color:var(--text);line-height:1.6;}
.gold-num{color:var(--gold);font-weight:600;}
table{width:100%;border-collapse:collapse;font-size:15px;margin:18px 0;}
/* Mobile-first: wide article tables scroll inside themselves instead of
   squishing into unreadable slivers. The inner overflow is independent of
   html{overflow-x:hidden}, so the page never gets a stray horizontal scroll. */
@media(max-width:600px){
  /* width:100% on a display:block element makes the table shrink to the phone
     instead of scrolling: columns squash to two words per line and the scroll
     never triggers. max-content lets it keep its natural width; min-width:100%
     stops narrow tables from collapsing to the left. */
  .bwrap table{display:block;width:max-content;min-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;
    /* Two fixed gradients pinned to the scroll box and two that travel with the
       content. When the content edge sits under a fixed shadow the shadow is
       covered, so the fade only shows on the side where more table remains —
       the classic Roman Komarov trick, no wrapper element and no JS. */
    background:
      linear-gradient(to right,var(--bg) 30%,rgba(11,26,23,0)) left center/28px 100% no-repeat local,
      linear-gradient(to left,var(--bg) 30%,rgba(11,26,23,0)) right center/28px 100% no-repeat local,
      radial-gradient(farthest-side at 0 50%,rgba(0,0,0,.7),rgba(0,0,0,0)) left center/22px 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%,rgba(0,0,0,.7),rgba(0,0,0,0)) right center/22px 100% no-repeat scroll;
    /* The shadow sits behind the cells, so on its own a reader still sees a
       column chopped mid-word. The mask fades the actual content out at the
       edge, which is what reads as "there is more to the right". Both edges are
       masked and the fade is narrow, so nothing is ever hidden — scrolling one
       swipe brings it back. */
    -webkit-mask-image:linear-gradient(to right,transparent 0,#000 18px,#000 calc(100% - 18px),transparent 100%);
    mask-image:linear-gradient(to right,transparent 0,#000 18px,#000 calc(100% - 18px),transparent 100%);
  }
  /* NOTE (2026-07-20): the card layout that used these data-label attributes is
     reverted for now. On the live site it left the table as a grid while its
     borders disappeared, so the result was worse than the scrolling version, and
     a phone screenshot is not enough to tell a CSS parse failure from a
     specificity problem. The build still writes data-label (see
     _build/label-table-cells.js) — the attributes are inert without CSS — so the
     layout can be reintroduced once it can be tested properly in a device
     emulator rather than diagnosed from screenshots. */

  /* A two-column table always fits, and masking it would fade the first and
     last letters of every row for no reason. */
  .bwrap table:not(:has(tr > *:nth-child(3))){-webkit-mask-image:none;mask-image:none;background:none;width:100%;}
  /* Three columns of Russian prose at 15px leave four or five characters per
     line; a step down buys a whole word without hurting legibility. */
  .bwrap table:has(tr > *:nth-child(3)){font-size:14px;}
  /* A table that scrolls has to say so; on a phone a cut-off column just looks
     like a broken layout. */
  .bwrap th,.bwrap td{padding:10px 12px;}
  .bwrap table:has(td[data-label]){display:block;width:100%;max-width:100%;min-width:0!important;overflow:visible;background:none;-webkit-mask-image:none;mask-image:none;border-collapse:separate;border-spacing:0;}
  .bwrap table:has(td[data-label]) thead,
  .bwrap table:has(td[data-label]) tbody,
  .bwrap table:has(td[data-label]) tr,
  .bwrap table:has(td[data-label]) td,
  .bwrap table:has(td[data-label]) tbody th{display:block;width:100%;box-sizing:border-box;}
  .bwrap table:has(td[data-label]) thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;}
  .bwrap table:has(td[data-label]) tr:has(> th):not(:has(> td)){position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;}
  .bwrap table:has(td[data-label]) tr{background:#FBF6EC;border:1px solid #ece3d4;border-radius:16px;padding:14px 16px;margin:0 0 12px;color:#0A1F1A;}
  .bwrap table:has(td[data-label]) td,
  .bwrap table:has(td[data-label]) tbody th{border:0;border-bottom:1px solid #ece3d4;padding:7px 0;background:transparent;color:#0A1F1A;font-size:14px;line-height:1.4;text-align:left;white-space:normal;}
  .bwrap table:has(td[data-label]) td:last-child{border-bottom:0;}
  .bwrap table:has(td[data-label]) td:first-child,
  .bwrap table:has(td[data-label]) tbody th:first-child{font-family:'Cormorant Garamond',Georgia,serif;font-size:17px;font-weight:600;line-height:1.25;color:#0A1F1A;padding:0 0 10px;}
  .bwrap table:has(td[data-label]) td:first-child::before,
  .bwrap table:has(td[data-label]) tbody th:first-child::before{content:none;}
  .bwrap table:has(td[data-label]) td:not(:first-child){display:flex;justify-content:space-between;gap:14px;align-items:baseline;}
  .bwrap table:has(td[data-label]) td:not(:first-child)::before{content:attr(data-label);flex:0 0 42%;font-weight:500;color:rgba(10,31,26,.66);font-size:13px;line-height:1.35;}
  .bwrap table:has(td[data-label]) td:nth-child(2){color:#7a5f1a;font-weight:700;text-align:right;}
  .bwrap table:has(td[data-label]) td:nth-child(n+3){font-weight:600;text-align:right;}
}
/* Long unbroken tokens (URLs, codes, place names) must wrap, never clip or overflow. */
.bwrap,.bwrap p,.bwrap li,.bwrap td,.bwrap th,.bwrap h1,.bwrap h2,.bwrap h3,.bwrap h4,.bwrap a{overflow-wrap:break-word;}
/* Mobile tap targets (R8 probe_04): interactive pill/button controls reach 44px;
   header CTAs and footer links get a comfortable touch area. */
@media(max-width:1024px){
  .pg-btn,.pg-num,.pf-btn,.pf-chip,.cmp-chip,.cmp-goal,.cmp-pick-x,.cnc-chip,.hubnav-i,.rgn-chip,.zh-btn,.nv-ask,.bnav-tg,.bnav-wa,.btg,.pcard-cta .ask{min-height:44px;display:inline-flex;align-items:center;justify-content:center;}
  .bfoot a{display:inline-block;padding:8px 0;min-height:24px;}
  .related a{padding-top:10px;padding-bottom:10px;}
}
.pf-chip,.pf-btn,.pcard-cta .ask{min-height:44px;display:inline-flex;align-items:center;justify-content:center;}
th,td{padding:11px 12px;border:1px solid var(--line-soft);text-align:left;vertical-align:top;}
th{background:var(--bg-3);color:var(--gold);font-weight:600;font-size:13px;letter-spacing:.04em;}
td{color:#DCD9D2;}
.cta{margin:40px 0;padding:30px 28px;border:1px solid var(--line);border-radius:3px;background:radial-gradient(120% 140% at 50% 0%,rgba(212,175,106,.10),rgba(212,175,106,0) 70%),var(--bg-3);}
.cta p{margin:0 0 18px;color:var(--text);font-size:16.5px;}
.cta-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:48px;background:linear-gradient(180deg,var(--gold),var(--gold-soft));color:#1B130A;font-weight:700;font-size:15px;padding:0 26px;border-radius:999px;text-decoration:none;}
.cta-btn:hover{text-decoration:none;filter:brightness(1.05);}
.cta .alt-link{display:inline-flex;align-items:center;gap:7px;min-height:48px;margin-left:14px;color:var(--gold);font-size:14.5px;font-weight:700;}
.cta .alt-link::before{content:"→";font-size:16px;}
.note{border-left:2px solid var(--gold);padding:4px 0 4px 16px;font-size:14.5px;color:var(--text-2);margin:24px 0;}

/* ---- Mobile-first reading pass (2026-07-20) ----
   The site is read on a phone far more often than on a desktop, and the long
   editorial pages we shipped this week are where that shows: heading gaps sized
   for a wide screen, a call-to-action whose second link wrapped under the
   button, list items packed tight enough to blur together. None of this needs a
   markup change — the pages are already semantic, they were just being laid out
   for the wrong screen. */
@media(max-width:600px){
  /* 22px of side padding on a 360px screen costs a sixth of the line. */
  .bwrap{padding:0 18px;}
  /* Vertical rhythm scaled to the viewport: a 44px gap above every h2 is a
     third of a phone screen spent on emptiness. */
  .prose h2{margin:38px 0 9px;}
  .prose h3{margin:25px 0 8px;}
  .prose li{margin-bottom:10px;}
  .prose .lead{font-size:16.5px;}
  .mth-prose>h2,.mth-prose :is(.mth-sec:not(.mth-corr),.bp-sec,.bd-sec,.gl-sec,.lt-sec,.pgup-sec,.related,.any-proj)>h2{margin:38px 0 9px;}
  .mth-prose h3{margin:25px 0 8px;}
  .mth-prose li{margin-bottom:10px;}
  article:not(.prose) h2{margin:34px 0 12px;}
  article:not(.prose) h3{margin:26px 0 9px;}
  article:not(.prose) li{margin-bottom:10px;}
  article:not(.prose) .lead{font-size:18px;}
  /* Full-width tap target instead of a button the thumb has to aim at, and the
     secondary links below it rather than trailing off the right edge. */
  .cta{padding:24px 20px;margin:32px 0;}
  .cta-btn{display:flex;width:100%;min-height:50px;text-align:center;padding:0 20px;}
  .cta .alt-link{display:inline-flex;margin:10px 0 0;min-height:48px;}
  /* The contents block is navigation, not reading matter: it should not push
     the article itself below the fold. */
  .btoc{margin-bottom:26px;}
  .btoc li{margin-bottom:6px;}
}
/* ---- .bfoot — SUPERSEDED by /assets/footer.css (.nsfoot) ----
   The footer is one component for the whole site now: markup from _build/footer.js,
   rules in assets/footer.css, stamped onto hand-made pages by _build/sync-footer.js.
   These rules are kept, not deleted, on purpose: they style pages that still carry the
   old markup, so the site degrades gracefully if sync-footer.js has not been run yet or
   if it skipped a page (it skips any page with more than one <footer> rather than guess).
   Once `grep -rl 'class="bfoot"' website/` is empty, this block and the .fcols block
   below are dead and can go. Do not add to them. */
.bfoot{margin-top:64px;border-top:1px solid var(--line-soft);padding:36px 0 44px;}
.bfoot .disc{font-size:11.5px;line-height:1.65;color:var(--text-3);}
.bfoot .row{display:flex;flex-wrap:wrap;gap:10px 26px;font-size:13.5px;margin-bottom:18px;}
.related{margin:48px 0 0;}
.related h2{margin-top:0;}
.related a{display:block;padding:16px 18px;border:1px solid var(--line-soft);border-radius:2px;margin-bottom:10px;color:var(--text);font-weight:600;font-size:15.5px;}
.related a:hover{border-color:var(--gold);color:var(--gold);text-decoration:none;}
/* auto table of contents (long articles) */
.btoc{margin:22px 0 34px;padding:16px 18px;border:1px solid var(--line-soft);border-radius:16px;background:#102A22;}
.btoc-h{margin:0 0 12px;font-size:11.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--gold);}
.btoc ul{list-style:none;margin:0;padding:0;display:grid;gap:0;counter-reset:btoc;}
.btoc li{counter-increment:btoc;font-size:15px;line-height:1.4;padding:0;position:relative;margin:0;}
.btoc li::before{content:none;}
.btoc a{display:flex;gap:11px;align-items:baseline;padding:9px 0;border-bottom:1px solid var(--line-soft);color:#e7ede9;text-decoration:none;}
.btoc li:last-child a{border-bottom:0;}
.btoc a::before{content:counter(btoc,decimal-leading-zero);color:var(--gold);font-weight:700;font-size:12.5px;min-width:22px;}
.btoc a:hover{color:var(--gold);text-decoration:none;}
html{scroll-behavior:smooth;}
:target{scroll-margin-top:80px;}

/* Long-page navigation: reading progress, mobile sections sheet and back-to-top.
   Injected by assets/js/nav.js only on pages that already have nav.btoc. */
.lp-progress{position:fixed;z-index:1200;left:0;right:0;top:0;height:3px;background:rgba(243,241,236,.08);pointer-events:none;}
.lp-progress__bar{display:block;width:100%;height:100%;transform:scaleX(0);transform-origin:left center;background:linear-gradient(90deg,#D4AF6A,#E7C988);box-shadow:0 0 14px rgba(212,175,106,.34);}
.lp-stack{position:fixed!important;z-index:1050;left:calc(16px + env(safe-area-inset-left));bottom:calc(18px + env(safe-area-inset-bottom));display:flex;flex-direction:column;align-items:flex-start;gap:10px;pointer-events:none;}
.lp-top,.lp-sections{pointer-events:auto;appearance:none;border:1px solid rgba(212,175,106,.45);background:#102A22;color:#F3F1EC;box-shadow:0 12px 30px rgba(0,0,0,.28);font-family:'Inter',system-ui,sans-serif;cursor:pointer;transition:opacity .22s ease,transform .22s ease,border-color .18s ease,background .18s ease;}
.lp-top{width:46px;height:46px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;color:#D4AF6A;font-size:21px;line-height:1;opacity:0;transform:translateY(8px);pointer-events:none;}
.lp-top.is-visible{opacity:1;transform:translateY(0);pointer-events:auto;}
.lp-top:hover,.lp-sections:hover{border-color:#D4AF6A;background:#123328;text-decoration:none;}
.lp-sections{min-height:48px;border-radius:999px;display:inline-flex;align-items:center;gap:9px;padding:0 16px 0 14px;font-size:14px;font-weight:700;letter-spacing:.01em;}
.lp-sections__icon{color:#D4AF6A;font-size:16px;line-height:1;}
.lp-sheet{position:fixed!important;z-index:1300;inset:0;display:none!important;}
.lp-sheet.is-open{display:block!important;}
.lp-sheet__shade{position:absolute;inset:0;background:rgba(0,0,0,.52);opacity:0;transition:opacity .22s ease;}
.lp-sheet.is-open .lp-sheet__shade{opacity:1;}
.lp-sheet__panel{position:absolute;left:0;right:0;bottom:0;max-height:min(78vh,620px);padding:10px 18px calc(18px + env(safe-area-inset-bottom));border:1px solid rgba(243,241,236,.12);border-bottom:0;border-radius:22px 22px 0 0;background:#102A22;box-shadow:0 -22px 60px rgba(0,0,0,.42);transform:translateY(102%);transition:transform .26s cubic-bezier(.2,.8,.2,1);}
.lp-sheet.is-open .lp-sheet__panel{transform:translateY(0);}
.lp-sheet__handle{width:42px;height:4px;border-radius:999px;background:rgba(243,241,236,.22);margin:0 auto 14px;}
.lp-sheet__head{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:0 0 10px;border-bottom:1px solid rgba(243,241,236,.12);}
.lp-sheet__title{margin:0;font-family:'Cormorant Garamond',Georgia,serif;font-size:24px;line-height:1.15;font-weight:700;color:#F3F1EC;}
.lp-sheet__close{appearance:none;border:1px solid rgba(212,175,106,.38);border-radius:999px;width:42px;height:42px;background:#0A1F1A;color:#D4AF6A;font-size:24px;line-height:1;cursor:pointer;}
.lp-sheet__list{list-style:none;margin:0;padding:6px 0 0;max-height:calc(min(78vh,620px) - 98px);overflow:auto;-webkit-overflow-scrolling:touch;counter-reset:lpnav;}
.lp-sheet__list li{counter-increment:lpnav;margin:0;}
.lp-sheet__list a{display:flex;align-items:center;gap:12px;min-height:48px;padding:12px 2px;border-bottom:1px solid rgba(243,241,236,.10);color:#e7ede9;text-decoration:none;font-size:15px;line-height:1.35;}
.lp-sheet__list li:last-child a{border-bottom:0;}
.lp-sheet__list a::before{content:counter(lpnav,decimal-leading-zero);flex:0 0 28px;color:#D4AF6A;font-weight:800;font-size:12.5px;letter-spacing:.02em;}
.lp-sheet__list a:hover{color:#D4AF6A;text-decoration:none;}
body.lpnav-open{overflow:hidden;}
@media(min-width:900px){
  .lp-sections{display:none;}
  .lp-stack{bottom:calc(24px + env(safe-area-inset-bottom));}
}
@media(max-width:520px){
  .lp-stack{bottom:calc(12px + env(safe-area-inset-bottom));}
}
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  .lp-progress__bar,.lp-top,.lp-sections,.lp-sheet__shade,.lp-sheet__panel{transition:none!important;}
}
/* Sections control — same dark-panel / gold-ring language as the AI assistant.
   It remains a real button and the sheet stays a keyboard-operable dialog. */
.lp-sections{border-color:rgba(212,175,106,.45);background:linear-gradient(180deg,#123328,#102A22);box-shadow:0 10px 28px rgba(0,0,0,.38);}
.lp-sections:hover{border-color:#D4AF6A;background:#15382c;color:#F3F1EC;}
.lp-sections:focus-visible,.lp-top:focus-visible,.lp-sheet__close:focus-visible{outline:2px solid #E7C988;outline-offset:3px;}
.lp-sheet__panel{border-color:rgba(212,175,106,.34);background:linear-gradient(180deg,#102A22,#0A1F1A);}
.lp-sheet__handle{background:rgba(212,175,106,.55);}
.lp-sheet__close{border-color:rgba(212,175,106,.48);background:#0A1F1A;color:#D4AF6A;}
.lp-sheet__list a:hover{background:rgba(212,175,106,.07);}
/* 12T blog discovery: evidence note + on-page filter */
.bevidence{font-size:13.5px;line-height:1.6;color:var(--text-2);margin:0 0 22px;padding:14px 16px;border:1px solid var(--line-soft);border-radius:3px;background:var(--bg-3);}
.bevidence a{color:var(--gold);}
.bfind{margin:0 0 26px;}
.bfind-in{width:100%;box-sizing:border-box;font-family:inherit;font-size:15px;color:var(--text);background:var(--bg-2);border:1px solid var(--line-soft);border-radius:3px;padding:13px 16px;min-height:44px;transition:border-color .2s;}
.bfind-in:focus{outline:none;border-color:var(--gold);}
.bfind-in::placeholder{color:var(--text-3);}
.bfind-hint{margin:8px 2px 0;font-size:12.5px;color:var(--text-3);}
.bfind-empty,.bfind-status{margin:10px 2px 0;font-size:13.5px;color:var(--text-2);}
/* index list */
.bgrid{display:grid;gap:14px;margin:34px 0 60px;}
.bcard{display:block;border:1px solid var(--line-soft);border-radius:3px;padding:26px 26px 24px;color:var(--text);transition:border-color .3s;}
.bcard:hover{border-color:var(--gold);text-decoration:none;}
.bcard h2{margin:0 0 10px;font-size:24px;}
.bcard p{margin:0;color:var(--text-2);font-size:15px;line-height:1.6;}
@media(max-width:640px){.bcard p{font-size:16px;}}
.bcard .tag{display:inline-block;font-size:11px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--gold);margin-bottom:12px;}
.bpager{display:flex;align-items:center;justify-content:center;gap:22px;margin:18px 0 60px;font-size:14.5px;}
.bpager a{color:var(--gold);font-weight:600;}
.bpager span{color:var(--text-3);}
/* topic filter chips */
.bchips{display:flex;flex-wrap:wrap;gap:9px;margin:30px 0 4px;}
.bchip{appearance:none;cursor:pointer;font-family:inherit;font-size:13.5px;font-weight:500;color:var(--text-2);background:var(--bg-2);border:1px solid var(--line-soft);border-radius:999px;padding:8px 16px;white-space:nowrap;transition:border-color .2s,color .2s,background .2s;}
.bchip:hover{color:var(--gold);border-color:var(--line);}
.bchip.is-on{color:#1B130A;background:linear-gradient(180deg,var(--gold),var(--gold-soft));border-color:var(--gold-soft);font-weight:600;}
@media(max-width:560px){
  .bchips{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;margin-left:-22px;margin-right:-22px;padding:0 22px 4px;}
  .bchips::-webkit-scrollbar{display:none;}
  .bchip{flex:0 0 auto;}
}

/* topic rubric links (real hub URLs, replaces JS chips) */
.brubs{display:flex;flex-wrap:wrap;gap:9px;margin:30px 0 4px;}
.brubs a,.brubs span{font-size:13.5px;font-weight:500;color:var(--text-2);background:var(--bg-2);border:1px solid var(--line-soft);border-radius:999px;padding:8px 16px;white-space:nowrap;transition:border-color .2s,color .2s,background .2s;}
.brubs a:hover{color:var(--gold);border-color:var(--line);text-decoration:none;}
.brubs span.is-on{color:#1B130A;background:linear-gradient(180deg,var(--gold),var(--gold-soft));border-color:var(--gold-soft);font-weight:600;}
@media(max-width:560px){
  .brubs{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;margin-left:-22px;margin-right:-22px;padding:0 22px 4px;}
  .brubs::-webkit-scrollbar{display:none;}
  .brubs a,.brubs span{flex:0 0 auto;}
}

/* ============ NAVIGATION ============
   Moved in full to assets/header.css on 2026-07-17, together with the markup that
   went to _build/header.js. Everything that was here — .bhead, .bnav, .navlink,
   .navitem, .dropdown, .d-sub, .bnav-tg, .bnav-wa, .burger, .nav-backdrop and the
   drawer media query — is defined there once, for both design systems, and reads no
   variable from this file. Do not re-add a header rule here: a rule here reaches the
   ~1000 pages that link blog.css and silently misses index.html and en/index.html,
   which is precisely how the site ended up with two different menus.
   ==================================== */
/* footer 4-col */
.bfoot .fcols{display:flex;flex-wrap:wrap;gap:30px 46px;margin-bottom:30px;align-items:flex-start;}
.bfoot .fcols>div{flex:1 1 150px;min-width:130px;}
.bfoot .fcols>div:first-child{flex:1 1 250px;max-width:330px;}
.bfoot .fcols>div:nth-child(3){flex:1.9 1 300px;columns:2;column-gap:38px;}
.bfoot .fcols>div:nth-child(3) h4{column-span:all;}
.bfoot .fcols>div:nth-child(3) a{break-inside:avoid;}
.bfoot .fcols h4{font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--gold);margin:0 0 14px;font-weight:600;}
.bfoot .fcols a{display:block;color:var(--text-2);font-size:14px;margin-bottom:9px;}
.bfoot .fcols a:hover{color:var(--gold);text-decoration:none;}
/* Mobile footer. Two flex columns left a short group (Legal, 5 links) next to a
   long one (Information, 11) — the long column ran on while a big empty block sat
   beside it. Stack the groups full width instead and let a long list use two
   internal columns. Also drop the link margin: the 8px tap padding above already
   spaces them, and stacking both made every link ~45px tall. */
@media(max-width:640px){
  .bfoot .fcols{flex-direction:column;gap:24px;}
  .bfoot .fcols>div,
  .bfoot .fcols>div:first-child,
  .bfoot .fcols>div:nth-child(3){flex:1 1 auto;min-width:0;max-width:none;columns:auto;}
  .bfoot .fcols>div:nth-child(3){columns:2;column-gap:22px;}
  .bfoot .fcols>div:nth-child(3) h4{column-span:all;}
  .bfoot .fcols a{margin-bottom:0;break-inside:avoid;}
  .bfoot .fcols h4{margin-bottom:8px;}
}
.bfoot .fbrand{display:flex;align-items:center;gap:10px;margin-bottom:12px;}
.bfoot .fbrand img{height:34px;}
.bfoot .fbrand b{font-family:'Cormorant Garamond',Georgia,serif;font-size:19px;font-weight:600;color:var(--text);}
.bfoot .fbrand b span{color:var(--gold);}
.bfoot .fabout{font-size:13.5px;color:var(--text-2);line-height:1.6;margin:0;}
.bfoot .fwrap{max-width:1100px;margin:0 auto;padding:0 22px;}
@media(max-width:640px){.bfoot .fcols{gap:22px 28px;}.bfoot .fcols>div,.bfoot .fcols>div:first-child,.bfoot .fcols>div:nth-child(3){flex:1 1 44%;max-width:none;}.bfoot .fcols>div:nth-child(3){columns:1;}}
@media(max-width:420px){.bfoot .fcols>div,.bfoot .fcols>div:first-child,.bfoot .fcols>div:nth-child(3){flex:1 1 100%;}}
/* office address block */
.office-addr{font-style:normal;line-height:1.7;color:var(--text);background:var(--bg-2);border:1px solid var(--line);border-left:3px solid var(--gold);border-radius:8px;padding:16px 18px;margin:14px 0 18px;font-size:15px;}
.office-addr strong{color:var(--text);}

/* ============ FAVOURITES + RECENTLY VIEWED ============ */
.fav-btn{display:inline-flex;align-items:center;gap:7px;cursor:pointer;font-family:inherit;font-size:13.5px;font-weight:600;color:var(--text-2);background:var(--bg-2);border:1px solid var(--line-soft);border-radius:999px;padding:8px 15px;transition:color .2s,border-color .2s,background .2s;}
.fav-btn:hover{color:var(--gold);border-color:var(--line);}
.fav-btn .fav-ic{font-size:14px;line-height:1;}
.fav-btn.is-saved{color:#1B130A;background:linear-gradient(180deg,var(--gold),var(--gold-soft));border-color:var(--gold-soft);}
/* card-corner variant: absolute pill over a project card */
.pcard{position:relative;}
.fav-btn.fav-corner{position:absolute;top:12px;right:12px;z-index:3;background:rgba(10,31,26,.72);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);border-color:rgba(243,241,236,.18);}
.fav-btn.fav-corner:hover{background:rgba(10,31,26,.85);}
.fav-btn.fav-corner.is-saved{background:linear-gradient(180deg,var(--gold),var(--gold-soft));}

/* floating launcher */
/* The chat launcher (.nsc-l in assets/js/chat.js) is also fixed at right:18px
   bottom:18px and is 58px across, so the favourites pill landed underneath it
   and the two overlapped each other and the card below. Stack it above instead.
   It only appears once something is saved, which is exactly when a buyer is
   comparing and least wants controls covering the card. */
.fav-launcher{position:fixed;right:18px;bottom:88px;z-index:60;display:none;align-items:center;gap:8px;cursor:pointer;font-family:inherit;font-size:14px;font-weight:600;color:var(--text);background:var(--bg-2);border:1px solid var(--line);border-radius:999px;padding:11px 17px;box-shadow:0 10px 30px rgba(0,0,0,.4);}
.fav-launcher.has-items{display:inline-flex;}
.fav-launcher:hover{border-color:var(--gold);color:var(--gold);}
.fav-launcher .fav-star{color:var(--gold);font-size:13px;}
.fav-launcher .fav-count{min-width:20px;height:20px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;background:var(--gold);color:#1B130A;border-radius:999px;}

/* drawer + backdrop */
.fav-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.5);opacity:0;visibility:hidden;transition:.25s;z-index:65;}
body.fav-open .fav-backdrop{opacity:1;visibility:visible;}
.fav-drawer{position:fixed;top:0;right:0;bottom:0;width:min(90vw,380px);background:var(--bg-2);border-left:1px solid var(--line);z-index:70;transform:translateX(100%);transition:transform .28s ease;overflow-y:auto;padding:18px 18px 30px;}
body.fav-open .fav-drawer{transform:translateX(0);}
.fav-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;font-family:'Cormorant Garamond',Georgia,serif;font-size:22px;font-weight:600;color:var(--text);}
.fav-close,.fav-rm{cursor:pointer;background:none;border:0;color:var(--text-3);font-size:22px;line-height:1;padding:2px 6px;border-radius:4px;}
.fav-close:hover,.fav-rm:hover{color:var(--gold);}
.fav-sub{margin:24px 0 10px;font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--gold);font-weight:600;}
.fav-empty{color:var(--text-2);font-size:14.5px;line-height:1.6;}
.fav-list{display:flex;flex-direction:column;gap:8px;}
.fav-row{display:flex;align-items:stretch;gap:6px;}
.fav-link{flex:1;display:flex;align-items:center;gap:12px;padding:9px 10px;border:1px solid var(--line-soft);border-radius:8px;color:var(--text);}
.fav-link:hover{border-color:var(--gold);text-decoration:none;}
.fav-link img{width:52px;height:52px;object-fit:cover;border-radius:6px;flex:0 0 auto;}
.fav-txt{display:flex;flex-direction:column;gap:3px;min-width:0;}
.fav-txt b{font-size:14.5px;font-weight:600;line-height:1.3;}
.fav-txt i{font-style:normal;font-size:12.5px;color:var(--text-3);}
.fav-rm{align-self:center;}
.fav-item{display:flex;flex-direction:column;gap:6px;}
.fav-note{width:100%;box-sizing:border-box;font:inherit;font-size:12.5px;color:var(--text-2);background:var(--bg-3);border:1px solid var(--line-soft);border-radius:4px;padding:7px 9px;resize:vertical;min-height:40px;}
.fav-note:focus{outline:none;border-color:var(--gold);}
.fav-note::placeholder{color:var(--text-3);}
.fav-cta{display:block;margin-top:14px;text-align:center;background:linear-gradient(180deg,var(--gold),var(--gold-soft));color:#1B130A;font-weight:600;font-size:14.5px;padding:13px 16px;border-radius:2px;}
.fav-cta:hover{filter:brightness(1.05);text-decoration:none;}
.fav-btn-card{font-size:12.5px;padding:8px 12px;white-space:nowrap;flex:0 0 auto;}
.fav-memo{display:block;width:100%;margin-top:12px;cursor:pointer;font-family:inherit;font-size:14px;font-weight:600;color:var(--text);background:var(--bg-3);border:1px solid var(--line);border-radius:2px;padding:12px 16px;transition:border-color .2s,color .2s;}
.fav-memo:hover{border-color:var(--gold);color:var(--gold);}
@media(max-width:560px){
  /* Same stacking as the desktop rule above: the chat bubble owns the corner,
     favourites sits on top of it. Without this the mobile override put the pill
     straight back under the bubble. */
  .fav-launcher{right:12px;bottom:84px;padding:10px 15px;font-size:13.5px;}
}

/* ============ STICKY MOBILE CTA (subpages) — REMOVED ============ */
/* The bottom WhatsApp/Telegram bar is retired (owner, 2026-07-16). Its rules lived here.
   Nothing emits `.scta` any more (assets/js/sticky-cta.js is an empty no-op), so these
   selectors could never match and are deleted rather than left as dead paint. */

/* ============================================================
   V5 HONESTY UI — source coverage / evidence / uncertainty
   Shared primitive for hubs (R1), mega-pages (R9) and trust surfaces.
   States map to schema enums (source_coverage_state, price_state, ...).
   Never a quality rating; unknown is a visible state, not "no".
   ============================================================ */
.src-label{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;line-height:1;padding:5px 9px;border-radius:999px;border:1px solid var(--line);color:var(--text-2);background:var(--bg-2);white-space:nowrap;}
.src-label .dot{width:7px;height:7px;border-radius:50%;background:var(--text-3);flex:none;}
.src-label.is-confirmed{color:#8fe3b0;border-color:rgba(37,211,102,.35);} .src-label.is-confirmed .dot{background:#25D366;}
.src-label.is-probable{color:#e6c98a;border-color:rgba(212,175,106,.4);} .src-label.is-probable .dot{background:var(--gold);}
/* is-secondary sits between is-probable and is-unknown: a real source exists, so the border
   stays solid (not the dashed "unknown" treatment), but the gold is muted toward grey
   because that source is single and secondary. */
.src-label.is-secondary{color:#c4b58e;border-color:rgba(180,162,120,.32);} .src-label.is-secondary .dot{background:#9a8f6a;}
.src-label.is-unverified,.src-label.is-unknown{color:var(--text-3);border-style:dashed;} .src-label.is-unknown .dot{background:var(--text-3);}
.src-label.is-byrequest{color:#9ec2e6;border-color:rgba(120,170,220,.4);} .src-label.is-byrequest .dot{background:#6aa3dd;}
.src-label.is-conflict{color:#e6a08a;border-color:rgba(220,110,90,.45);} .src-label.is-conflict .dot{background:#d9694a;}
.src-label.is-stale{color:#e0b48a;border-color:rgba(220,150,80,.4);} .src-label.is-stale .dot{background:#e0973f;}
.freshness{font-size:12px;color:var(--text-3);margin-top:6px;}
.freshness b{color:var(--text-2);font-weight:600;}
.kut{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:18px 0;}
.kut-col{border:1px solid var(--line);border-radius:6px;padding:14px 16px;background:var(--bg-2);}
.kut-col h5{margin:0 0 8px;font-size:12px;letter-spacing:.08em;text-transform:uppercase;font-weight:600;color:var(--text-3);}
.kut-col.k h5{color:#8fe3b0;} .kut-col.t h5{color:#e6c98a;}
.kut-col ul{margin:0;padding-left:16px;} .kut-col li{font-size:14px;margin:0 0 5px;color:var(--text-2);}
.kut-col li.muted{color:var(--text-3);}
@media(max-width:640px){ .kut{grid-template-columns:1fr;} }

/* Registry-driven project/entity card — R1 hubs + R9 mega-page related.
   Unknown-first: shows price STATE + source-coverage label, never invented numbers. */
.pgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(270px,100%),1fr));gap:16px;margin:18px 0;}
@media(max-width:640px){.pgrid{grid-template-columns:minmax(0,1fr);}}
.pcard{min-width:0;border:1px solid var(--line);border-radius:10px;background:var(--bg-2);display:flex;flex-direction:column;overflow:hidden;transition:border-color .2s;}
.pcard:hover{border-color:var(--gold);}
.pcard-ph{height:120px;background:linear-gradient(135deg,#123a30,#0c2a22);display:flex;align-items:flex-end;padding:10px 14px;color:#d5dfdf;font-size:12px;border-bottom:1px solid var(--line-soft);}
.pcard-img{position:relative;aspect-ratio:3/2;overflow:hidden;background:#0c2a22;border-bottom:1px solid var(--line-soft);}
.pcard-img img{width:100%;height:100%;object-fit:cover;object-position:center;display:block;transition:transform .3s;}
.pcard:hover .pcard-img img{transform:scale(1.04);}
.pcard-badge{position:absolute;top:8px;left:8px;background:rgba(0,0,0,.62);color:#fff;font-size:10px;letter-spacing:.06em;text-transform:uppercase;padding:2px 7px;border-radius:3px;}
.pcard-cred{position:absolute;bottom:0;right:0;background:rgba(0,0,0,.55);color:rgba(255,255,255,.85);font-size:10px;padding:2px 7px;border-top-left-radius:4px;}
.pcard-top{padding:14px 15px 0;}
.pcard-cat{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:#c9d4d4;font-weight:600;}
.pcard h3{margin:4px 0 2px;font-size:17px;line-height:1.2;}
.pcard .loc{font-size:13px;color:var(--text-2);}
.pcard .loc .tc{color:#c9d4d4;}
.pcard .dev{font-size:12.5px;color:#c9d4d4;margin-top:3px;}
.pcard-mid{padding:12px 15px 0;}
.pcard-body{padding:12px 15px 15px;margin-top:auto;}
.pcard-price{font-size:13.5px;color:var(--text-2);margin:10px 0 0;}
.pcard-cta{display:flex;gap:8px;margin-top:13px;}
.pcard-cta a{flex:1;text-align:center;font-size:13px;font-weight:600;padding:9px;border-radius:3px;}
.pcard-cta .ask{background:var(--gold);color:#1B130A;}
.pcard-cta .open{border:1px solid var(--line);color:var(--text);}
.pcard-stage{display:inline-flex;align-items:center;font-size:11.5px;font-weight:600;color:var(--gold);border:1px solid var(--line-soft);border-radius:999px;padding:3px 9px;margin-left:6px;background:var(--bg-3);white-space:nowrap;}

/* Hub page chrome — hero, filters, CTA (R1 /projects/ etc.) */
.hub-hero{margin:8px 0 22px;}
.hub-hero h1{margin:0 0 10px;}
.hub-lead{color:var(--text-2);font-size:16px;line-height:1.6;max-width:70ch;}
.hub-meta{margin:14px 0;font-size:13.5px;color:var(--text-3);}
.hub-meta b{color:var(--text-2);}
.hub-cta{display:flex;gap:10px;flex-wrap:wrap;margin-top:10px;}
.hubnav{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;margin:0 0 22px;padding:0 0 16px;border-bottom:1px solid var(--line-soft);}
.hubnav-h{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--text-3);margin-right:4px;}
.hubnav-i{font-size:13.5px;color:var(--text-2);border:1px solid var(--line);border-radius:999px;padding:6px 14px;transition:border-color .15s,color .15s;}
.hubnav-i:hover{border-color:var(--gold);color:var(--gold);text-decoration:none;}
.hubnav-i.is-on{background:var(--gold);border-color:var(--gold);color:#1B130A;font-weight:600;}
.hub-cta a{display:inline-flex;align-items:center;justify-content:center;gap:7px;min-height:48px;font-size:14px;font-weight:700;padding:0 20px;border-radius:999px;text-decoration:none;}
.hub-cta .btn-ask{background:linear-gradient(180deg,var(--gold),var(--gold-soft));color:#1B130A;}
.hub-cta .btn-open{color:var(--gold);border:1px solid var(--line);background:transparent;}
.hub-cta .btn-open:hover{border-color:var(--gold);color:#f0d295;}
/* Information hubs carry a small page-local baseline; these shared overrides
   keep their headings and final actions in the same gold, touch-safe system as
   the rest of the site. */
.ih-page .ih-sec>h2,.ih-page .ih-cta>h2{font-family:'Cormorant Garamond',Georgia,serif;font-size:clamp(25px,3vw,30px);font-weight:600;line-height:1.2;color:var(--gold);}
.ih-page .ih-sec>h3{font-family:'Inter',system-ui,sans-serif;font-size:17.5px;font-weight:700;line-height:1.32;color:#f0e4cf;}
/* Information-hub contrast contract: cream is a content surface, never a pale-text
   surface. The selectors cover the generated cards and every text-bearing descendant,
   including links nested in prose, source metadata and comparison tables. */
.ih-page :is(.ih-card,.ih-scn,.ih-source,.ih-scroll th,.ih-scroll td){color:#0A1F1A;}
.ih-page :is(.ih-card,.ih-scn,.ih-source,.ih-scroll th,.ih-scroll td) :is(h2,h3,p,li,span,a,strong,dt,dd){color:#0A1F1A;}
.ih-page :is(.ih-card,.ih-scn,.ih-source,.ih-scroll th,.ih-scroll td) :is(p,li,dt,dd,.ih-scn-d,.ih-source-pub){color:rgba(10,31,26,.66);}
.ih-page :is(.ih-card,.ih-scn,.ih-source,.ih-scroll th,.ih-scroll td) a{color:#5f4811;text-decoration-color:#D4AF6A;}
.ih-page :is(.ih-card,.ih-scn,.ih-source,.ih-scroll th,.ih-scroll td) a:hover{color:#0A1F1A;}
/* Long link and source lists stay compact until a visitor asks for them. Native
   details/summary provides keyboard operation without retaining UI state. */
.ih-page .ih-accordion{border:1px solid rgba(212,175,106,.34);border-radius:16px;background:#102A22;overflow:hidden;}
.ih-page .ih-accordion::before{display:none;}
.ih-page .ih-accordion>summary{display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:56px;padding:14px 18px;cursor:pointer;color:var(--gold);font-family:'Cormorant Garamond',Georgia,serif;font-size:clamp(25px,3vw,30px);font-weight:600;line-height:1.2;list-style:none;}
.ih-page .ih-accordion>summary::-webkit-details-marker{display:none;}
.ih-page .ih-accordion>summary:focus-visible{outline:2px solid var(--gold);outline-offset:-4px;}
.ih-page .ih-accordion-chevron{width:10px;height:10px;flex:0 0 auto;border-right:2px solid var(--gold);border-bottom:2px solid var(--gold);transform:rotate(45deg) translateY(-3px);transition:transform .18s ease;}
.ih-page .ih-accordion[open] .ih-accordion-chevron{transform:rotate(225deg) translate(-3px,-3px);}
.ih-page .ih-accordion-body{padding:0 18px 18px;}
.ih-page .ih-accordion .ih-linkgrid,.ih-page .ih-accordion .ih-sourcegrid{margin-top:0;}
/* Materials are deliberately light cards in a dark accordion: the contrast rules
   above make their titles, labels and arrows readable on every viewport. */
.ih-page .ih-materials .ih-mat{background:#FBF6EC;border-color:#ece3d4;color:#0A1F1A;min-height:52px;}
.ih-page .ih-materials .ih-mat :is(span,a){color:#0A1F1A;}
.ih-page .ih-materials .ih-mat .ih-mat-tag,.ih-page .ih-materials .ih-mat .ih-mat-go{color:#5f4811;}
@media(max-width:640px){.ih-page .ih-accordion>summary{min-height:52px;padding:13px 14px;}.ih-page .ih-accordion-body{padding:0 14px 14px;}.ih-page .ih-materials .ih-mat{padding:13px 14px;}}
.ih-page .ih-cta-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px 16px;}
.ih-page .ih-cta-primary{display:inline-flex;align-items:center;justify-content:center;gap:9px;min-height:48px;padding:0 22px;border-radius:999px;background:linear-gradient(180deg,var(--gold),var(--gold-soft));color:#1B130A;font-size:15px;font-weight:800;text-decoration:none;}
.ih-page .ih-cta-primary:hover{filter:brightness(1.06);text-decoration:none;}
.ih-page .ih-cta-secondary{display:inline-flex;align-items:center;gap:7px;min-height:48px;color:var(--gold);font-size:14px;font-weight:700;text-decoration:none;}
.ih-page .ih-cta-secondary:hover{color:#f0d295;text-decoration:underline;}
@media(max-width:640px){.ih-page .ih-cta-actions{align-items:stretch;}.ih-page .ih-cta-primary{width:100%;min-height:50px;}.ih-page .ih-cta-secondary{width:max-content;min-height:48px;}}
.pfilters{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:18px 0;}
.pf-label{font-size:13px;color:var(--text-3);margin-right:4px;}
.pf-btn{font-size:13px;font-weight:600;padding:7px 13px;border-radius:999px;border:1px solid var(--line);background:var(--bg-2);color:var(--text-2);cursor:pointer;transition:.15s;}
.pf-btn:hover{border-color:var(--gold);color:var(--text);}
.pf-btn.is-on{background:var(--gold);color:#1B130A;border-color:var(--gold);}
/* Slice size on the button. Muted, never louder than the label it qualifies. */
.pf-n{margin-left:6px;font-size:11.5px;font-weight:600;color:var(--text-3);}
.pf-btn.is-on .pf-n{color:#1B130A;opacity:.62;}
/* Filter drawer (/projects/) — same native <details> as .pj-gal-x / .pj-ov-x on a project page.
   Closed by default so the catalogue is the first thing under the hub nav. */
.pf-drawer{margin:16px 0 6px;}
.pf-sum{display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:9px 18px;border:1px solid var(--line);border-radius:999px;background:var(--bg-2);color:var(--text-2);font-size:13.5px;font-weight:600;cursor:pointer;list-style:none;transition:.15s;}
.pf-sum::-webkit-details-marker{display:none;}
.pf-sum::before{content:"\25b8";color:var(--gold);display:inline-block;transition:transform .15s;}
.pf-drawer[open] .pf-sum::before{transform:rotate(90deg);}
.pf-sum:hover{border-color:var(--gold);color:var(--text);}
.pf-drawer[open] .pf-sum{border-color:var(--gold);color:var(--text);}
/* Active-filter badge: gold, because it is the one thing the closed drawer must not hide. */
.pf-sum-n{display:inline-flex;align-items:center;justify-content:center;min-width:19px;height:19px;padding:0 5px;border-radius:999px;background:var(--gold);color:#1B130A;font-size:11.5px;font-weight:700;}
.pf-sum-n[hidden]{display:none;}
.pf-body{margin:4px 0 0;padding:4px 2px 2px;}
.pf-body .pfilters{margin:12px 0;}
/* Owner asked for mobile by name: the closed drawer becomes one full-width bar to tap. */
@media(max-width:600px){.pf-sum{width:100%;justify-content:center;}.pf-body .pfilters{margin:14px 0;}}
.pf-intent{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:16px 0 4px;}
.pf-chip{font-size:13px;font-weight:600;padding:8px 14px;border-radius:999px;border:1px solid var(--gold);background:transparent;color:var(--text);cursor:pointer;transition:.15s;}
.pf-chip:hover{background:var(--bg-3);}
.pf-chip.is-on{background:var(--gold);color:#1B130A;}
.pexplain{font-size:13px;color:var(--text-3);margin:6px 0 0;letter-spacing:.01em;}
.pexplain:empty{display:none;}
.meth-drawer{border:1px solid var(--line-soft);border-radius:10px;background:var(--bg-2);margin:0 0 20px;font-size:14px;}
.meth-drawer summary{cursor:pointer;padding:12px 16px;font-weight:600;color:var(--text);list-style:none;}
.meth-drawer summary::-webkit-details-marker{display:none;}
.meth-drawer summary::before{content:"\25b8";color:var(--gold);margin-right:9px;display:inline-block;transition:transform .15s;}
.meth-drawer[open] summary::before{transform:rotate(90deg);}
.meth-body{padding:0 16px 14px;color:var(--text-2);line-height:1.55;}
.meth-body p{margin:0 0 10px;}
.meth-list{list-style:none;padding:0;margin:0 0 10px;}
.meth-list li{margin:0 0 8px;font-size:13.5px;line-height:1.5;}
.meth-list .src-label{margin-right:4px;}
.meth-body a{color:var(--gold);font-weight:600;}
.fresh-panel{display:flex;flex-wrap:wrap;align-items:center;gap:10px 20px;margin:0 0 16px;padding:13px 16px;border:1px solid var(--line-soft);border-radius:10px;background:var(--bg-2);}
.fresh-h{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--text-3);font-weight:600;}
.fresh-item{font-size:13px;color:var(--text-2);}
.fresh-item b{color:var(--gold);font-weight:700;font-size:15px;margin-right:3px;}
.nv-board{margin:36px 0 8px;padding-top:26px;border-top:1px solid var(--line-soft);}
.nv-h{font-size:19px;margin:0 0 6px;color:var(--text);}
.nv-sub{font-size:14px;color:var(--text-2);line-height:1.55;margin:0 0 16px;max-width:680px;}
.nv-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:10px;}
.nv-item{display:flex;flex-direction:column;align-items:flex-start;gap:6px;border:1px solid var(--line-soft);border-radius:10px;padding:13px 14px;background:var(--bg-2);}
.nv-label{font-size:13.5px;color:var(--text);font-weight:600;line-height:1.35;}
.nv-ask{font-size:12.5px;font-weight:600;color:var(--gold);white-space:nowrap;margin-top:auto;}
.nv-ask:hover{text-decoration:underline;}
.zero-handoff{border:1px solid var(--line-soft);border-radius:12px;padding:20px 22px;margin:18px 0;background:var(--bg-2);}
.zero-handoff .zh-t{font-size:16px;font-weight:600;color:var(--text);margin:0 0 6px;}
.zero-handoff .zh-s{font-size:14px;color:var(--text-2);line-height:1.55;margin:0 0 14px;}
.zh-acts{display:flex;flex-wrap:wrap;gap:9px;}
.zh-btn{font-size:13.5px;font-weight:600;padding:9px 15px;border-radius:8px;border:1px solid var(--line);color:var(--text);}
.zh-btn:hover{border-color:var(--gold);text-decoration:none;}
.zh-btn.primary{background:var(--gold);color:#1B130A;border-color:var(--gold);}
.pzero{color:var(--text-2);font-size:15px;margin:18px 0;}
.pzero a{color:var(--gold);}
/* ---- pagination (status hub & scalable card grids) ---- */
.pcount{font-size:12.5px;color:var(--text-3);margin:2px 0 0;letter-spacing:.01em;}
.pcount:empty{display:none;}
.ppager{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:6px;margin:28px 0 6px;}
.ppager:empty{display:none;}
.pg-btn,.pg-num{font-size:13px;font-weight:600;min-width:38px;height:38px;padding:0 12px;border-radius:8px;border:1px solid var(--line);background:var(--bg-2);color:var(--text-2);cursor:pointer;transition:.15s;display:inline-flex;align-items:center;justify-content:center;}
.pg-btn:hover:not([disabled]),.pg-num:hover{border-color:var(--gold);color:var(--text);}
.pg-num.is-on{background:var(--gold);color:#1B130A;border-color:var(--gold);cursor:default;}
.pg-btn[disabled]{opacity:.4;cursor:default;}
.pg-gap{min-width:24px;text-align:center;color:var(--text-3);user-select:none;}
/* The catalogue pager is now server-rendered as real <a href> links (/projects/page/N/), so the
   same pills have to look identical whether they are a button or an anchor: kill the global
   a:hover underline, and let the current page read as a label rather than a target. */
a.pg-num:hover,a.pg-btn:hover{text-decoration:none;}
span.pg-num.is-on{cursor:default;}
@media(max-width:520px){.pg-btn,.pg-num{min-width:44px;height:44px;padding:0 9px;font-size:12.5px;}}
/* ---- hub → guide/tool cross-links ---- */
.hub-guides{margin:34px 0 8px;padding-top:22px;border-top:1px solid var(--line-soft);}
.hub-guides h2{font-size:15px;letter-spacing:.02em;color:var(--text-2);margin:0 0 12px;}
/* margin-top, added 2026-07-17 (owner, with screenshots). .hg-links started life inside
   .hub-guides, where the <h2> above it carried the spacing. It is now also used twice on the
   project page with a paragraph directly above it — under the map's «Круг показывает примерную
   зону...» caption, and under the last item of «Что проверить до брони» — and there it sat flush
   against the text, reading as part of the sentence rather than as an action.
   Set here rather than at each call site: a chip row after prose always wants air. .hub-guides
   opts out below, because its heading already provides it. */
.hg-links{display:flex;flex-wrap:wrap;gap:10px;margin-top:18px;}
.hub-guides .hg-links{margin-top:0;}
.hg-links a{font-size:13.5px;font-weight:600;color:var(--text);border:1px solid var(--line-soft);border-radius:999px;padding:8px 14px;}
.hg-links a:hover{border-color:var(--gold);color:var(--gold);text-decoration:none;}
.pcard .loc a{color:inherit;border-bottom:1px dotted var(--line);}
.pcard .loc a:hover{color:var(--gold);border-color:var(--gold);text-decoration:none;}
.pcard-sum,.rcard .pcard-sum{font-size:13px;line-height:1.5;color:var(--text-2);margin:0 0 10px;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;}
.pcard-facts{font-size:12.5px;color:#c9d4d4;margin:0 0 8px;line-height:1.5;}
.pcard-ev{margin:6px 0 2px;border-top:1px solid var(--line-soft);padding-top:8px;}
.pcard-ev summary{cursor:pointer;font-size:12px;font-weight:600;color:#c9d4d4;list-style:none;}
.pcard-ev summary::-webkit-details-marker{display:none;}
.pcard-ev summary::before{content:"\25b8";color:var(--gold);margin-right:6px;font-size:10px;}
.pcard-ev[open] summary::before{content:"\25be";}
.pcard-ev ul{list-style:none;padding:8px 0 0;margin:0;}
.pcard-ev li{display:flex;justify-content:space-between;gap:8px;font-size:12px;padding:3px 0;color:#c9d4d4;}
.pcard-ev li b{color:var(--text-2);font-weight:600;}
.pj-treat{display:inline-block;font-size:11.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--gold);border:1px solid var(--line);border-radius:999px;padding:5px 12px;margin:0 0 12px;}
/* "At a glance". Modelled on the portals' Project Overview: an icon, a small label and the value,
   packed tight enough to read in one pass. 180px (was 200px) because the cards are now three
   columns of short values rather than two of long ones; auto-fill still gives a single column on a
   360px phone without a media query. */
.qf-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(180px,100%),1fr));gap:8px;margin:14px 0 6px;}
.qf-card{display:flex;align-items:flex-start;gap:10px;border:1px solid var(--line-soft);border-radius:10px;
  padding:11px 13px;background:var(--bg-2);min-width:0;}
.qf-card .pj-ico{color:var(--gold);margin-top:1px;opacity:.85;}
/* min-width:0 on the text column, or a long unbroken value would push the icon out of the card. */
.qf-b{display:block;min-width:0;}
.qf-k{display:block;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:#c9d4d4;font-weight:600;margin-bottom:3px;}
.qf-v{display:block;font-size:14px;color:var(--text);line-height:1.4;overflow-wrap:anywhere;}
/* Optional fourth line: the qualifier a value needs to be actionable ("3,3 м на этажах 8–23…").
   Only some cards carry one, and .qf-cards is a grid, so a card with a note grows its own row and
   the cards beside it stretch to match — the grid never reflows and nothing below it moves. */
.qf-n{display:block;font-size:12px;color:#c9d4d4;line-height:1.45;margin-top:4px;overflow-wrap:anywhere;}
.dg-h{font-size:13px;letter-spacing:.06em;text-transform:uppercase;color:var(--gold);font-weight:600;margin:22px 0 10px;}
.pj-faq{border:1px solid var(--line-soft);border-radius:10px;background:var(--bg-2);margin:0 0 10px;overflow:hidden;}
.pj-faq>summary{cursor:pointer;list-style:none;padding:14px 16px;font-weight:600;font-size:15px;color:var(--text);position:relative;padding-right:40px;}
.pj-faq>summary::-webkit-details-marker{display:none;}
.pj-faq>summary::after{content:"+";position:absolute;right:16px;top:50%;transform:translateY(-50%);font-size:20px;color:var(--gold);font-weight:400;}
.pj-faq[open]>summary::after{content:"\2212";}
.pj-faq>div{padding:0 16px 14px;}
.pj-faq p{margin:0 0 8px;font-size:14px;line-height:1.55;color:var(--text-2);}
.pj-faq a{color:var(--gold);}
/* ---- "Читайте также" (projectReadAlso in build-hubs.js) ----
   Deliberately NOT .hg-links: those are pill chips, and an article title is a sentence — "BKK1 для
   жизни и аренды: микрозоны, цены и кто там арендует" set in a 999px pill wraps into a lozenge.
   Rows instead, with the registry's own cluster as a kicker above the title, so the reader can
   scan four topics down the left edge and read the one they want. Two columns where there is room,
   one on a phone; the grid takes any 2–4 items without leaving a hole. */
.pj-ra{list-style:none;margin:0;padding:0;display:grid;gap:10px;grid-template-columns:1fr;}
@media (min-width:700px){.pj-ra{grid-template-columns:1fr 1fr;}}
.pj-ra a{display:block;height:100%;padding:12px 14px;border:1px solid var(--line-soft);border-radius:10px;
  background:var(--bg-2);text-decoration:none;transition:border-color .2s var(--ease,ease);}
.pj-ra a:hover{border-color:var(--gold);text-decoration:none;}
.pj-ra-k{display:block;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--text-3);margin-bottom:4px;}
.pj-ra-t{display:block;font-size:14px;font-weight:600;line-height:1.45;color:var(--text);}
.pj-ra a:hover .pj-ra-t{color:var(--gold);}
@media (prefers-reduced-motion:reduce){.pj-ra a{transition:none;}}
.vf-ctas{display:flex;flex-wrap:wrap;gap:8px;margin:12px 0 4px;}
.vf-cta{display:inline-flex;align-items:center;min-height:44px;padding:8px 14px;border:1px solid var(--line-soft);border-radius:999px;background:var(--bg-2);color:var(--text);font-size:14px;font-weight:600;text-decoration:none;line-height:1.3;}
.vf-cta:hover{border-color:var(--gold);color:var(--gold);}
/* Analytics opt-out switch on the cookie policy (we run no consent banner) */
.ns-opt{border:1px solid var(--line);border-left:3px solid var(--gold);border-radius:12px;background:var(--bg-2);padding:16px 18px;margin:14px 0 22px;}
.ns-opt-row{display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.ns-opt-row>div{flex:1 1 240px;}
.ns-opt-row b{font-size:15px;color:var(--text);}
.ns-opt-s{font-size:13.5px;line-height:1.5;color:var(--text-2);margin:4px 0 0;}
.ns-opt-btn{flex:0 0 auto;min-height:44px;padding:10px 20px;border-radius:8px;cursor:pointer;font-family:inherit;font-size:14px;font-weight:600;
  color:#1B130A;background:linear-gradient(180deg,var(--gold),var(--gold-soft));border:1px solid transparent;}
.ns-opt-btn[aria-pressed="true"]{color:var(--text);background:transparent;border-color:var(--line);}
.ns-opt-btn:hover{filter:brightness(1.05);}
.ns-opt-btn:disabled{opacity:.5;cursor:default;}
.ns-opt-n{font-size:12.5px;line-height:1.5;color:var(--text-3);margin:12px 0 0;}
.vs-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;}
.vs-table{min-width:560px;}
.vs-table td,.vs-table th{font-size:13.5px;line-height:1.5;vertical-align:top;}
.vs-table .vs-dim{font-weight:600;color:var(--text);white-space:nowrap;}
/* Mobile: stack the 3-column comparison into cards instead of a scrolling table */
@media(max-width:760px){
  .vs-scroll{overflow:visible;}
  .vs-table{min-width:0;display:block;}
  .vs-table thead{display:none;}
  .vs-table tbody,.vs-table tr,.vs-table td{display:block;width:100%;box-sizing:border-box;}
  .vs-table tr{border:0;border-top:1px solid var(--line-soft);padding:13px 0;}
  .vs-table tbody tr:first-child{border-top:0;padding-top:0;}
  .vs-table td{border:0;padding:5px 0;display:flex;gap:12px;align-items:baseline;}
  .vs-table td.vs-dim{white-space:normal;display:block;padding:0 0 8px;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);width:auto;}
  .vs-table td::before{content:attr(data-p);flex:0 0 38%;font-weight:600;color:var(--gold);font-size:13px;line-height:1.4;}
  .vs-table td.vs-dim::before{content:none;}
}
.vs-src{margin:6px 0 0;padding-left:20px;}
.vs-src li{margin:0 0 6px;font-size:13.5px;}
.vs-src a{color:var(--gold);overflow-wrap:break-word;}
/* Дата источника: YMYL-правила меняются ежегодно, и ссылка без даты не даёт читателю
   понять, насколько она свежая. Приглушаем, чтобы не спорить с названием источника. */
.vs-src-d{color:var(--text-2);}
/* Домен источника. Внешних ссылок на сайте нет — источник назван текстом, и домен рядом
   отвечает на «где это лежит», не уводя читателя с сайта. Приглушён так же, как дата. */
.vs-src-h{color:var(--text-3);overflow-wrap:break-word;}
/* FAQ на хабах сравнения. <details> вместо всегда раскрытого списка: вопросов много,
   развёрнутыми они превращают конец страницы в стену текста. */
.mth-faq{border-top:1px solid var(--line);padding:12px 0;}
.mth-faq:last-of-type{border-bottom:1px solid var(--line);}
.mth-faq summary{cursor:pointer;font-weight:600;list-style:none;}
.mth-faq summary::-webkit-details-marker{display:none;}
.mth-faq summary::before{content:"+";color:var(--gold);margin-right:9px;font-weight:700;}
.mth-faq[open] summary::before{content:"\2013";}
.mth-faq p{margin:9px 0 0 21px;color:var(--text-2);}
/* Landed/borey notice. Gold left rule rather than a red alarm box: this is a constraint the
   buyer must know, not a scare — structures exist and it is a lawyer's call, not ours. */
.pj-landed{border:1px solid var(--line);border-left:3px solid var(--gold);border-radius:0 12px 12px 0;
  background:var(--bg-2);padding:18px 20px;margin:26px 0;}
.pj-landed h2{font-size:19px;margin:0 0 10px;}
.pj-landed p{font-size:15px;line-height:1.65;color:var(--text-2);margin:0 0 12px;}
.pj-landed p:last-of-type{margin-bottom:14px;}
@media print{.pj-landed{border-color:#ccc;background:none;}}

/* project page media (cover + gallery from project_media.json) — mobile-first.
   aspect-ratio is doing real work here: the registry carries no width/height, so without a
   reserved box every image would land as a layout shift. 16/10 + object-fit:cover crops
   rather than distorts, whatever the source proportions turn out to be. */
.pj-hero{position:relative;margin:22px 0 26px;border-radius:14px;overflow:hidden;border:1px solid var(--line);background:var(--bg-2);}
.pj-hero img{display:block;width:100%;height:auto;aspect-ratio:16/10;object-fit:cover;object-position:center;}
/* Inside the hero grid the figure sets its own rhythm: on a phone it sits between the facts and the
   price, on a desktop it is the right column and must not push itself away from the H1.
   The 16/10 box above is the default; a record whose cover is a portrait tower render overrides it
   per image (see media.cover_aspect in build-hubs.js) rather than by slug in here. */
.pj-top-media .pj-hero{margin:18px 0 6px;}
@media (min-width:860px){.pj-top-media .pj-hero{margin:0;}}
.pj-badge{position:absolute;top:12px;left:12px;font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  font-weight:700;color:#14222b;background:var(--gold);border-radius:20px;padding:4px 11px;}
.pj-cred{font-size:12px;color:var(--text-3);padding:9px 14px;line-height:1.45;background:var(--bg-2);}
/* min() so a long-word caption or a narrow phone never forces a horizontal scroll */
.pj-gal{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px;margin-top:12px;}
.pj-gi{margin:0;border-radius:12px;overflow:hidden;border:1px solid var(--line);background:var(--bg-2);}
.pj-gi img{display:block;width:100%;height:auto;aspect-ratio:3/2;object-fit:cover;object-position:center;transition:transform .45s var(--ease,ease);}
.pj-gi:hover img{transform:scale(1.04);}
/* The thumbnail is a link now (see the lightbox note in build-hubs.js). It must fill the figure and
   say so on hover — a zoom cursor is the only affordance telling the reader the shot opens. */
.pj-gi .pj-lb{display:block;cursor:zoom-in;}
@media (prefers-reduced-motion:reduce){.pj-gi img{transition:none;}.pj-gi:hover img{transform:none;}}
/* ---- gallery "показать ещё" (owner: 10–15 shots per project, not 5) ----
   A <details>, so this is the whole implementation: no JS, and the collapsed frames stay in the
   DOM for search, for print and for a reader with scripts off. Only emitted when a gallery is long
   enough to need it (see build-hubs.js), so the 2–5 shot records never load-bear any of this. */
.pj-gal-x{margin-top:12px;}
.pj-gal-x>.pj-gal{margin-top:12px;}
.pj-gal-b,.pj-ov-b{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:9px;
  /* 44px of tappable height: this is the one control on the page a thumb reaches for. */
  min-height:44px;padding:9px 18px;border:1px solid var(--line);border-radius:999px;
  font-size:13.5px;font-weight:600;color:var(--text);background:var(--bg-2);
  transition:border-color .2s var(--ease,ease),color .2s var(--ease,ease);}
.pj-gal-b::-webkit-details-marker,.pj-ov-b::-webkit-details-marker{display:none;}
/* The plus the owner asked for, doing the work of an icon without shipping one. */
.pj-gal-b::before{content:'+';font-size:19px;font-weight:400;line-height:1;color:var(--gold);}
.pj-gal-x[open]>.pj-gal-b::before{content:'\2212';}
.pj-gal-b:hover,.pj-ov-b:hover{border-color:var(--gold);color:var(--gold);}
.pj-gal-b2,.pj-gal-x[open]>.pj-gal-b>.pj-gal-b1{display:none;}
.pj-gal-x[open]>.pj-gal-b>.pj-gal-b2{display:inline;}
@media (prefers-reduced-motion:reduce){.pj-gal-b,.pj-ov-b{transition:none;}}
/* Unchanged rule, plus the new control: print already drops the gallery, and a "показать ещё"
   button on paper is a button that cannot be pressed. */
@media print{.pj-gal,.pj-gal-b{display:none;}.pj-hero{border-color:#ccc;}}

/* ---- gallery lightbox (assets/js/lightbox.js) ----
   Built only when a reader opens a photo, so these rules idle on every page without a gallery.
   z-index 90 clears the sticky header (45), the nav drawer (50) and the chat launcher; the viewer
   is modal, so nothing may sit on top of it. */
.pj-lbx{position:fixed;inset:0;z-index:90;display:flex;align-items:center;justify-content:center;
  gap:6px;padding:16px;background:rgba(4,12,10,.94);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);}
.pj-lbx[hidden]{display:none;}
/* The page behind must not scroll under the overlay. */
html.pj-lbx-on,body.pj-lbx-on{overflow:hidden;overscroll-behavior:none;}
.pj-lbx-f{margin:0;min-width:0;display:flex;flex-direction:column;align-items:center;gap:10px;}
/* The whole point: the image gets the viewport, and contain (never cover) means a floor plan is
   shown whole rather than cropped to a pretty box. */
.pj-lbx-i{display:block;max-width:100%;max-height:calc(100vh - 96px);width:auto;height:auto;
  object-fit:contain;border-radius:8px;background:var(--bg-2);}
/* svh, second, as a progressive override. On a phone browser with a retracting URL bar, 100vh is
   the LARGE viewport while the position:fixed overlay is only ever the small one — so 100vh-96px
   let the image grow taller than the box holding it, and the caption and the arrows went off the
   bottom of the screen with no way to scroll to them. svh is that small viewport. Kept as a second
   declaration rather than a replacement so a browser without svh keeps the vh value it understands. */
.pj-lbx-i{max-height:calc(100svh - 96px);}
.pj-lbx-c{font-size:13px;line-height:1.5;color:var(--text-2);text-align:center;max-width:70ch;}
.pj-lbx-n{color:var(--text-3);white-space:nowrap;}
.pj-lbx-x,.pj-lbx-p,.pj-lbx-nx{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;border:1px solid var(--line);border-radius:999px;cursor:pointer;
  background:rgba(14,42,36,.9);color:var(--text);font-size:26px;line-height:1;padding:0;}
.pj-lbx-x:hover,.pj-lbx-p:hover,.pj-lbx-nx:hover{border-color:var(--gold);color:var(--gold);}
.pj-lbx-x[hidden],.pj-lbx-p[hidden],.pj-lbx-nx[hidden]{display:none;}
.pj-lbx-x{position:absolute;top:12px;right:12px;font-size:22px;}
/* Phone: the arrows would eat the image's width, so they sit at the bottom as thumb-reachable
   controls and swiping does the same job. */
@media (max-width:600px){
  .pj-lbx{flex-wrap:wrap;padding:12px;}
  .pj-lbx-f{order:1;flex:1 0 100%;}
  .pj-lbx-p{order:2;}
  .pj-lbx-nx{order:3;}
  .pj-lbx-i{max-height:calc(100vh - 150px);}
  .pj-lbx-i{max-height:calc(100svh - 150px);}
}
@media print{.pj-lbx{display:none!important;}}

/* ---- classified project media viewer (assets/js/lightbox.js) ---- */
.pj-media-launch{display:flex;flex-wrap:wrap;gap:10px;margin:12px 0 2px;}
.pj-media-previews{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:12px 0 14px;max-width:660px;}
.pj-media-preview{position:relative;display:block;min-width:0;padding:0;overflow:hidden;aspect-ratio:4/3;border:1px solid var(--line);border-radius:12px;background:var(--bg-2);cursor:pointer;isolation:isolate;}
.pj-media-preview img{display:block;width:100%;height:100%;object-fit:cover;transition:transform .25s ease;}
.pj-media-preview::after{content:"";position:absolute;inset:40% 0 0;background:linear-gradient(transparent,rgba(4,12,10,.82));z-index:1;pointer-events:none;}
.pj-media-preview span{position:absolute;z-index:2;right:9px;bottom:8px;color:#fff;font-size:12px;font-weight:700;text-shadow:0 1px 2px rgba(0,0,0,.5);}
.pj-media-preview:hover,.pj-media-preview:focus-visible{border-color:var(--gold);}.pj-media-preview:hover img,.pj-media-preview:focus-visible img{transform:scale(1.04);}
.pj-media-open{display:inline-flex;align-items:center;justify-content:center;gap:10px;min-height:48px;padding:10px 16px;border:1px solid var(--line);border-radius:999px;background:var(--bg-2);color:var(--text);font:inherit;font-size:14px;font-weight:700;cursor:pointer;}
.pj-media-open:hover,.pj-media-open:focus-visible{border-color:var(--gold);color:var(--gold);}
.pj-media-open-main{background:linear-gradient(180deg,var(--gold),var(--gold-soft));border-color:var(--gold);color:#1b130a;}
.pj-media-open-main:hover,.pj-media-open-main:focus-visible{color:#1b130a;filter:brightness(1.05);}
.pj-media-open b{display:inline-flex;align-items:center;justify-content:center;min-width:24px;height:24px;padding:0 7px;border-radius:999px;background:rgba(10,31,26,.14);font-size:12px;}
.pj-media-open:not(.pj-media-open-main) b{background:rgba(212,175,106,.15);color:var(--gold);}
.pj-lbx{position:fixed;inset:0;z-index:90;display:grid;place-items:center;gap:0;padding:18px;background:rgba(4,12,10,.94);-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);}
.pj-lbx-panel{width:min(1180px,100%);height:min(820px,calc(100svh - 36px));display:flex;flex-direction:column;overflow:hidden;border:1px solid rgba(212,175,106,.32);border-radius:18px;background:#0a1f1a;box-shadow:0 24px 80px rgba(0,0,0,.45);}
.pj-lbx-head{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:58px;padding:0 14px 0 20px;border-bottom:1px solid var(--line);}
.pj-lbx-title{margin:0;color:var(--text);font-size:15px;font-weight:700;}
.pj-lbx-x,.pj-lbx-p,.pj-lbx-nx{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;border:1px solid var(--line);border-radius:999px;cursor:pointer;background:rgba(14,42,36,.94);color:var(--text);font-size:28px;line-height:1;padding:0;}
.pj-lbx-x{position:static;font-size:28px;}.pj-lbx-x:hover,.pj-lbx-p:hover,.pj-lbx-nx:hover,.pj-lbx-thumb:hover,.pj-lbx-thumb:focus-visible{border-color:var(--gold);}
.pj-lbx-tabs{display:flex;gap:8px;overflow-x:auto;padding:12px 20px 0;border-bottom:1px solid var(--line);scrollbar-width:thin;}
.pj-lbx-tabs[hidden]{display:none;}.pj-lbx-tab{flex:0 0 auto;min-height:38px;padding:7px 13px;border:1px solid var(--line);border-radius:999px;background:transparent;color:var(--text-2);font:inherit;font-size:13px;font-weight:700;cursor:pointer;}
.pj-lbx-tab.is-on{border-color:var(--gold);background:rgba(212,175,106,.13);color:var(--gold);}
.pj-lbx-layout{display:grid;grid-template-columns:minmax(0,1fr) 272px;min-height:0;flex:1;}
.pj-lbx-stage{position:relative;display:flex;align-items:center;justify-content:center;min-width:0;padding:22px 62px;background:rgba(0,0,0,.16);}
.pj-lbx-f{margin:0;min-width:0;display:flex;flex-direction:column;align-items:center;gap:10px;}.pj-lbx-i{display:block;max-width:100%;max-height:calc(100svh - 190px);width:auto;height:auto;object-fit:contain;border-radius:8px;background:var(--bg-2);}
.pj-lbx-c{display:flex;flex-wrap:wrap;justify-content:center;gap:4px 10px;font-size:13px;line-height:1.45;color:var(--text-2);text-align:center;max-width:68ch;}.pj-lbx-n{color:var(--text-3);white-space:nowrap;}
.pj-lbx-p,.pj-lbx-nx{position:absolute;top:50%;transform:translateY(-50%);background:rgba(4,12,10,.78);}.pj-lbx-p{left:14px;}.pj-lbx-nx{right:14px;}
.pj-lbx-side{min-width:0;border-left:1px solid var(--line);overflow:auto;padding:12px;background:rgba(3,11,9,.34);scrollbar-width:thin;scrollbar-color:rgba(212,175,106,.55) #0a1f1a;}.pj-lbx-side::-webkit-scrollbar{width:8px;}.pj-lbx-side::-webkit-scrollbar-thumb{border-radius:99px;background:rgba(212,175,106,.55);}.pj-lbx-side::-webkit-scrollbar-track{background:#0a1f1a;}
.pj-lbx-thumbs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;}.pj-lbx-thumb{display:block;min-width:0;padding:0;overflow:hidden;border:2px solid transparent;border-radius:7px;background:var(--bg-2);cursor:pointer;}.pj-lbx-thumb.is-on{border-color:var(--gold);}.pj-lbx-thumb img{display:block;width:100%;aspect-ratio:3/2;object-fit:cover;}
@media(max-width:700px){.pj-lbx{padding:8px;overscroll-behavior:contain;}.pj-lbx-panel{height:calc(100svh - 16px);border-radius:14px;overscroll-behavior:contain;}.pj-lbx-head{min-height:54px;padding-left:14px;}.pj-lbx-tabs{padding:9px 12px 0;}.pj-lbx-layout{grid-template-columns:1fr;grid-template-rows:minmax(0,1fr) 126px;}.pj-lbx-stage{padding:10px 18px 8px;}.pj-lbx-f{width:100%;}.pj-lbx-i{width:100%;max-height:calc(100svh - 242px);}.pj-lbx-side{border-top:1px solid var(--line);border-left:0;overflow-x:auto;overflow-y:hidden;padding:10px 12px;}.pj-lbx-thumbs{grid-template-columns:repeat(18,88px);gap:8px;}.pj-lbx-thumb img{height:72px;aspect-ratio:auto;}.pj-lbx-p{left:7px;}.pj-lbx-nx{right:7px;}.pj-lbx-c{font-size:12px;}}

/* ---- project hero (final control spec §4.1) ----

   Mobile-first, and the DOM order IS the mobile order the spec asks for: name and short facts
   (.pj-top-a), then the image (.pj-top-media), then the price anchor and the CTAs (.pj-top-b).
   No JS, no duplicated markup, no order:-1 hacks.

   On a wide screen the same three blocks become the two-column composition the spec asks for: a/b
   stack in the left column, the media spans both rows on the right. 860px is where .bwrap's 760px
   content box stops being able to hold two readable columns; below it the single column is correct
   rather than a compromise. .has-media, because a project with no cover has no right column and a
   grid would only squeeze the text next to a column of nothing. */
.pj-top{margin:8px 0 26px;}
.pj-top h1{margin:0 0 8px;}
@media (min-width:860px){
  .pj-top.has-media{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);column-gap:28px;align-items:start;}
  .pj-top.has-media .pj-top-a{grid-column:1;grid-row:1;}
  .pj-top.has-media .pj-top-b{grid-column:1;grid-row:2;}
  /* THE DEAD SPACE (owner, 2026-07-16: "на десктопе есть вот там квадрат пустой").
     This used to be align-self:start. The media spans rows 1+2, but `start` sized it to the cover's
     own 16/10 box and left it there — so whenever the text column (name + tagline + facts + price +
     CTAs) came out taller than the cover, the difference was a hole under the image, with the left
     column still running beside it. That is the empty square: the middle of the three columns a
     project page shows on a wide screen (facts | cover | form) simply stopped early.

     `stretch` + a flexed figure keeps the cover and its optional map in one desktop column.
     The hero image itself retains its intrinsic height here: an actual photo must not lose its
     top or bottom just to fill a decorative 16/10 box. This is a layout fix, not a content fix —
     it holds with or without coordinates, which matters
     because most records will never have any. When projectMap() does get coordinates it can be
     appended inside .pj-top-media and it will land exactly in the space that used to be the hole,
     sharing the column with the cover; nothing here has to change for that to work.
     min-height keeps a short record (thin page, few facts) from squashing the cover to a strip. */
  /* FIX 2026-07-26 (owner: главное фото проекта должно быть ВЕРТИКАЛЬНЫМ и хорошо видимым, а слева от
     него — факты + цена + CTA). The media spans both text rows on the right and stretches to the left
     column's height; the image fills that box with object-fit:cover, so a landscape source is shown as
     a tall portrait crop matching the text height — no empty field, photo well visible. The earlier
     contain/aspect-auto version letterboxed a short landscape into a full-height box and left the empty
     green field; the 16/10 landscape attempt made it horizontal and pushed price/CTA off the left —
     both wrong. min-height keeps the hero tall on short records. */
  .pj-top.has-media .pj-top-media{grid-column:2;grid-row:1 / span 2;align-self:stretch;}
  .pj-top.has-media .pj-top-media .pj-hero{height:100%;min-height:460px;}
  .pj-top.has-media .pj-top-media .pj-hero img{width:100%;height:100%;object-fit:cover;object-position:center;}
}
/* The one commercial line under the name. Bigger than body copy and not grey: it is the sentence
   that has to make the reader want to keep reading. */
.pj-tag{margin:0 0 12px;font-size:17.5px;line-height:1.4;color:var(--text);font-weight:500;}
.pj-loc{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0 0 14px;font-size:14px;color:var(--text-2);}
.pj-loc .pj-ico{color:var(--gold);flex:0 0 18px;}
/* 4–6 strong facts, one per line. Not a bulleted list: these are specifications, and a disc marker
   makes them read as prose points. Hairline rules do the separating instead. */
.pj-hl{list-style:none;margin:0;padding:0;border-top:1px solid var(--line-soft);}
.pj-hl li{padding:8px 0;border-bottom:1px solid var(--line-soft);font-size:15px;line-height:1.45;color:var(--text);}
.pj-price-hero{margin:16px 0 14px;}
.pj-price-hero b{display:block;font-size:20px;line-height:1.3;font-weight:600;color:var(--gold);margin:0 0 4px;overflow-wrap:anywhere;}
.pj-price-hero span{display:block;font-size:13.5px;line-height:1.5;color:var(--text-2);}
/* CTA row. One primary, one secondary — §7 and §2: no wall of channel buttons. min-height 44px is
   the tap target; flex:1 1 auto lets them share a phone row rather than each taking a full line. */
.pj-cta-row{display:flex;flex-wrap:wrap;gap:10px;margin:0 0 4px;}
.btn-lead,.btn-lead2{display:inline-flex;align-items:center;justify-content:center;min-height:46px;
  flex:1 1 auto;padding:10px 20px;border-radius:8px;font-size:14.5px;font-weight:600;line-height:1.3;
  text-align:center;text-decoration:none;}
.btn-lead{background:linear-gradient(180deg,var(--gold),var(--gold-soft));color:#1B130A;border:1px solid transparent;}
.btn-lead:hover{filter:brightness(1.05);text-decoration:none;}
.btn-lead2{border:1px solid var(--line);color:var(--text);background:transparent;}
.btn-lead2:hover{border-color:var(--gold);color:var(--gold);text-decoration:none;}
@media print{.btn-lead,.btn-lead2{display:none;}}
.pj-hero-note{margin:10px 0 0;font-size:12.5px;line-height:1.5;color:var(--text-3);}

/* "Почему проект интересен" (§4.2). Short cards, readable on a phone in one pass. */
.pj-why-w{display:grid;grid-template-columns:1fr;gap:10px;margin-top:4px;}
@media (min-width:560px){.pj-why-w{grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));}}
.pj-why-c{border:1px solid var(--line-soft);border-radius:10px;background:var(--bg-2);padding:14px 16px;min-width:0;}
.pj-why-c h3{margin:0 0 6px;font-size:15px;font-weight:600;color:var(--gold);line-height:1.35;}
.pj-why-c p{margin:0;font-size:14px;line-height:1.55;color:var(--text-2);}

/* Location bullets (§4.6): what the district gives you and what it costs you, in one list. */
.pj-loc-l{list-style:none;margin:0 0 14px;padding:0;}
.pj-loc-l li{position:relative;padding:6px 0 6px 18px;font-size:15px;line-height:1.55;color:var(--text-2);}
.pj-loc-l li::before{content:"";position:absolute;left:0;top:14px;width:6px;height:6px;border-radius:50%;background:var(--gold);}

/* "Кому подходит" (§4.8). Two columns where the record has both lists, one where it has one. The
   second list is a qualifier, not an alarm — same card, muted marker, no red. */
.pj-aud-w{display:grid;grid-template-columns:1fr;gap:12px;margin-top:4px;}
@media (min-width:640px){.pj-aud-w{grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr));}}
.pj-aud{border:1px solid var(--line-soft);border-radius:10px;background:var(--bg-2);padding:14px 16px;min-width:0;}
.pj-aud h3{margin:0 0 8px;font-size:13px;letter-spacing:.06em;text-transform:uppercase;font-weight:600;}
.pj-aud.is-yes h3{color:var(--gold);}
.pj-aud.is-no h3{color:var(--text-3);}
.pj-aud ul{list-style:none;margin:0;padding:0;}
.pj-aud li{position:relative;padding:5px 0 5px 16px;font-size:14px;line-height:1.5;color:var(--text-2);}
.pj-aud li::before{position:absolute;left:0;top:5px;font-weight:700;}
.pj-aud.is-yes li::before{content:"+";color:var(--gold);}
.pj-aud.is-no li::before{content:"\2013";color:var(--text-3);}
@media print{.pj-why-c,.pj-aud{border-color:#ccc;background:none;}.pj-why-c h3,.pj-aud.is-yes h3{color:#000;}}

/* Address / landmark in the Location block. Flex-column first: on a phone the label above the
   value beats a two-column row that would wrap a long street address mid-word. */
.pj-addr{display:flex;flex-direction:column;gap:2px;margin:10px 0 14px;padding:11px 14px;
  border:1px solid var(--line-soft);border-left:2px solid var(--gold);border-radius:0 8px 8px 0;background:var(--bg-2);}
.pj-addr-k{font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--text-3);font-weight:600;}
.pj-addr-v{font-size:15px;line-height:1.5;color:var(--text);overflow-wrap:anywhere;}

/* Map facade in the Location block (see projectMap() in _build/build-hubs.js).

   Nothing here loads a map: this is the poster the reader taps. Leaflet is ~43 KB gzip of JS plus
   200-300 KB of tiles, and on a project page the map is a detail, not the content — most readers
   came for the flats and the price and will never press this. So, unlike /projects/map/ (where the
   map IS the page and auto-loads on desktop), this one loads on click only, at every width.

   The box is sized in CSS and reserved before anything loads, so the map appearing cannot shift the
   page. Height is mobile-first and modest: a taller box would push the price block, which is what
   the reader actually scrolled for, further down. */
.pj-map-w{margin:4px 0 14px;}
/* The block ships hidden and its own script un-hides it, so no-JS readers never meet a dead
   button. Explicit, so that adding a display rule to .pj-map-w later cannot defeat the attribute. */
.pj-map-w[hidden]{display:none;}
.pj-map-shell{position:relative;height:280px;border:1px solid var(--line-soft);border-radius:10px;
  overflow:hidden;background:var(--bg-2);}
@media (min-width:860px){.pj-map-shell{height:360px;}}
.pj-map{width:100%;height:100%;}
.pj-map-ph{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:12px;text-align:center;padding:20px;color:var(--text-2);font-size:14px;line-height:1.55;}
.pj-map-ph p{margin:0;max-width:34em;}
.pj-map-ph button{font-size:15px;font-weight:600;color:var(--text);border:1px solid var(--line);
  border-radius:4px;padding:11px 20px;background:var(--bg-3);cursor:pointer;transition:border-color .3s,color .3s;}
.pj-map-ph button:hover{border-color:var(--gold);color:var(--gold);}
.pj-map-n{font-size:12.5px;color:var(--text-3);margin:8px 2px 0;line-height:1.5;}
/* Leaflet's popup is white with dark text whatever the site theme is, so the popup title is set
   against the popup, not against the page — do not swap these for var(--text). */
.pj-map-t{font-family:'Cormorant Garamond',Georgia,serif;font-size:17px;font-weight:600;color:#1a1a1a;}
/* Print and reduced-motion: a tile map is neither printable nor useful as a static box. */
@media print{.pj-map-w{display:none;}}

/* "Рядом с проектом" — the landmark list that follows Location (projectNearby() in
   _build/build-hubs.js). The component is lifted from the hand-made /projects/odom-tower/, which
   keeps its own inline copy of these rules: that page is not generated, and nothing here reaches it.

   Odom's row is name + category. This one carries a third value — the distance — and that is the
   only reason the markup is not byte-identical: the metre figure is the most useful thing in the
   block, and it has to survive a 320px phone sitting next to "международная школа".

   So the row wraps by design. Below 560px the name takes the whole width and the distance and the
   category share the line under it; above it the row is one line, the name elastic, the two values
   pinned right. Neither value is guaranteed — the registry may hold a landmark with no distance, or
   no category — and each is a separate element, so a row missing one simply loses it and flex
   closes the gap. The block cannot go ragged on a record with a different mix of slots. */
.nrby{margin:14px 0 4px;border:1px solid var(--line-soft);border-radius:10px;overflow:hidden;}
.nrby-row{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px;padding:10px 14px;
  border-top:1px solid var(--line-soft);}
.nrby-row:first-child{border-top:0;}
.nrby-name{flex:1 1 100%;min-width:0;color:var(--text);font-size:14px;line-height:1.45;}
/* tabular-nums so 84 / 111 / 684 stack as a column instead of dancing under each other. */
.nrby-d{flex:0 1 auto;font-size:12.5px;color:var(--text-3);font-variant-numeric:tabular-nums;}
/* margin-left:auto keeps the gold category hard right on the wrapped phone row even when the
   distance is missing and there is nothing before it to push it there. On the desktop row the name
   already absorbs the free space, so it is inert rather than a second alignment mechanism. */
.nrby-cat{flex:0 0 auto;margin-left:auto;font-size:11px;font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;color:var(--gold);}
@media (min-width:560px){
  .nrby-row{flex-wrap:nowrap;}
  .nrby-name{flex:1 1 auto;}
  /* Fixed, right-aligned box: this is what makes the gold category column start at the same x on
     every row whether the figure reads 84 or 684. */
  .nrby-d{flex:0 0 auto;min-width:56px;text-align:right;}
}
@media print{.nrby,.nrby-row{border-color:#bbb;}.nrby-cat{color:#000;}}

/* Sources block. No anchors by design (owner rule: no outbound links) — a source is named, not
   linked — so this is styled as evidence rows rather than as a link list like .vs-src. */
.pj-src{margin:14px 0 0;padding:0 0 0 22px;list-style:decimal;}
.pj-src li::marker{color:var(--text-3);font-size:12px;}
.pj-src-i{margin:0 0 12px;padding:0 0 12px;border-bottom:1px solid var(--line-soft);}
.pj-src-i:last-child{border-bottom:0;margin-bottom:0;padding-bottom:0;}
.pj-src-own{display:block;font-size:14.5px;font-weight:600;color:var(--text);line-height:1.45;overflow-wrap:anywhere;}
.pj-src-t{display:block;font-size:14px;color:var(--text-2);line-height:1.5;margin-top:2px;overflow-wrap:anywhere;}
.pj-src-m{display:block;font-size:12.5px;color:var(--text-3);line-height:1.5;margin-top:4px;}
/* Collapsed "Источники" drawer on project pages (owner 2026-07-26): a subtle, findable toggle rather
   than a full gold h2 — the legal citation list stays one click away without dominating the page. */
.src-drawer{border-top:1px solid var(--line-soft);padding-top:16px;}
.src-drawer>summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:12px;font-size:17px;font-weight:600;letter-spacing:.01em;color:var(--gold);padding:11px 18px;border:1px solid var(--line);border-radius:999px;background:transparent;transition:border-color .2s,color .2s;}
.src-drawer>summary:hover{border-color:var(--gold);color:#f0d295;}
.src-drawer>summary::-webkit-details-marker{display:none;}
.src-drawer>summary::after{content:"+";font-size:20px;line-height:1;}
.src-drawer[open]>summary::after{content:"\2212";}
.src-drawer[open]>summary{margin-bottom:8px;}
.src-drawer .mth-note{margin-top:10px;}
@media print{.src-drawer[open] .pj-src,.src-drawer .mth-note{display:block;}.pj-addr{border-color:#ccc;background:none;}}

/* ---- CX-3 reference-page blocks: unit mix, facilities ---- */

/* Inline SVG icons. The sprite itself must stay in the layout but occupy nothing — display:none is
   the one thing that can stop <use> resolving, so it is collapsed to a zero box instead.
   .pj-ico carries the stroke presentation for every icon: stroke/fill/stroke-width are inherited
   CSS properties, so the symbol content needs no attributes of its own and an icon simply takes the
   colour of whatever text it sits beside. Width/height are fixed in px (never a %), so an icon
   reserves its box before paint and nothing reflows when the sprite resolves. */
.pj-sprite{position:absolute;width:0;height:0;overflow:hidden;}
.pj-ico{width:18px;height:18px;flex:0 0 18px;fill:none;stroke:currentColor;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;overflow:visible;}

/* A counted headline for a block ("24 удобства"). The number is counted from the rendered data, so
   it is a summary of what is below it, not a claim we authored. */
.pj-stat{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 12px;padding:0;list-style:none;}
.pj-stat-i{font-size:12.5px;color:var(--text-3);border:1px solid var(--line-soft);border-radius:999px;
  padding:4px 11px;background:var(--bg-2);white-space:nowrap;}
.pj-stat-i b{color:var(--gold);font-weight:700;}

/* Unit mix. Cards, not a table: the reader's question is "what do I get for which size", and the
   area is the answer — in a two-column table it was the same 14px as everything else. One column on
   a phone, two once there is room; the grid is stable at 1 card and at 30. */
.pj-um-w{display:grid;grid-template-columns:1fr;gap:10px;margin-top:12px;}
@media (min-width:560px){.pj-um-w{grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));}}
.pj-um-c{border:1px solid var(--line-soft);border-radius:10px;background:var(--bg-2);padding:13px 15px;min-width:0;}
.pj-um-h{display:flex;align-items:center;gap:8px;color:var(--text);font-size:14px;min-width:0;}
.pj-um-h b{font-weight:600;overflow-wrap:anywhere;}
.pj-um-h .pj-ico{color:var(--text-3);}
/* The number the page exists for. A card whose size is unpublished simply has no .pj-um-a — the
   spec forbids the "Площадь не опубликована" card, so there is no muted variant to style. */
.pj-um-a{font-size:21px;line-height:1.25;font-weight:600;color:var(--gold);margin:8px 0 0;overflow-wrap:anywhere;}
/* gross/net. The gross figure keeps the 21px gold slot it has always had and only gains a tag; the
   net figure is a second, quieter measurement under it — not a correction of the first, and not
   styled as a warning. Both tags are inline-block with their own baseline, so a card with a net
   line is exactly one 17px row taller than one without, and cards in the same grid row stretch to
   match rather than shifting anything. Records with no net figure render neither element. */
.pj-um-ab,.pj-um-n span{display:inline-block;margin-left:6px;font-size:10.5px;font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;color:var(--text-3);vertical-align:middle;}
.pj-um-n{margin-top:3px;font-size:14px;line-height:1.35;font-weight:600;color:var(--text-2);overflow-wrap:anywhere;}
.pj-um-b{display:flex;align-items:center;gap:8px;margin-top:7px;font-size:13.5px;color:var(--text-2);}
.pj-um-b .pj-ico{color:var(--text-3);}
/* The one short reason to want this format (§4.4). */
.pj-um-d{margin:9px 0 0;font-size:13.5px;line-height:1.5;color:var(--text-2);}
.pj-um-th{margin-top:9px;padding-top:9px;border-top:1px solid var(--line-soft);
  font-size:12.5px;line-height:1.45;color:var(--text-3);overflow-wrap:anywhere;}
/* Price state + the card's own CTA. Muted text and a text-link CTA on purpose: three gold buttons
   stacked down the unit grid would compete with the hero's primary ask instead of feeding it. */
.pj-um-p{margin-top:9px;font-size:13.5px;line-height:1.45;color:var(--text);font-weight:600;overflow-wrap:anywhere;}
.pj-um-cta{display:inline-flex;align-items:center;min-height:40px;margin-top:8px;font-size:13.5px;
  font-weight:600;color:var(--gold);line-height:1.35;}
.pj-um-cta::after{content:" \2192";}
.pj-um-cta:hover{text-decoration:underline;}
@media print{.pj-um-cta{display:none;}}

/* Facilities grouped by use case (§4.5). The group cards stack full-width and the AMENITIES inside
   them run two-up on a desktop, one-up on a phone (owner's brief, and it matches how the portals
   show the same list). Groups are not put side by side: squeezing two into one row would push each
   item list into a ~120px strip where every label wraps. */
.pj-fz-w{display:grid;grid-template-columns:1fr;gap:12px;margin-top:12px;}
.pj-fz{border:1px solid var(--line-soft);border-radius:10px;background:var(--bg-2);padding:14px 16px;}
.pj-fz-h{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px;margin:0 0 10px;font-size:15px;font-weight:600;color:var(--text);}
.pj-fz-l{display:grid;grid-template-columns:1fr;gap:2px 14px;margin:0;padding:0;list-style:none;}
@media (min-width:560px){.pj-fz-l{grid-template-columns:1fr 1fr;}}
/* Fixed min-height + align-items:start keeps a one-line and a two-line item on the same baseline
   grid, so the two columns stay visually aligned instead of drifting apart down the list. */
.pj-fz-i{display:flex;align-items:flex-start;gap:9px;min-height:30px;padding:4px 0;
  font-size:14px;line-height:1.45;color:var(--text-2);min-width:0;}
.pj-fz-i .pj-ico{color:var(--gold);margin-top:1px;opacity:.85;}
.pj-fz-i span{min-width:0;overflow-wrap:anywhere;}

/* A slot INSIDE a section (the payment timeline in "Цена", the floor stack in "Инфраструктура").
   h3 rather than a second h2 on purpose: these are parts of the block they sit in, and giving them
   their own h2 would put them in the section rail as if they were peers of Price and Location. */
.pj-sub-h{margin:24px 0 0;font-size:15px;font-weight:600;color:var(--text);}

/* Payment timeline. Lifted verbatim from /projects/odom-tower/'s inline <style> (owner: reuse it,
   do not invent a second one), so the hand-made page and the 98 generated ones render the same
   object. That page keeps its own copy of these rules inline; being later in the cascade at equal
   specificity, its copy still wins there and it is untouched by this.
   The build caps the list at six steps — see projectPaySchedule() — which is what keeps the ≥640px
   row layout honest: flex:1 on seven steps would be a column of wrapped syllables. */
.pay-timeline{--pt-gap:10px;list-style:none;margin:12px 0 4px;padding:0;display:flex;flex-direction:column;gap:var(--pt-gap);counter-reset:pt;}
.pay-timeline .pt-step{position:relative;padding:12px 14px 12px 46px;border:1px solid var(--line-soft);border-radius:8px;background:var(--bg-2);min-width:0;}
.pay-timeline .pt-step::before{counter-increment:pt;content:counter(pt);position:absolute;left:12px;top:12px;width:24px;height:24px;border-radius:50%;background:linear-gradient(180deg,var(--gold),var(--gold-soft));color:#1B130A;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:center;}
.pay-timeline .pt-h{font-weight:600;color:var(--text);font-size:14.5px;overflow-wrap:anywhere;}
.pay-timeline .pt-sub{color:var(--text-2);font-size:13px;margin-top:2px;overflow-wrap:anywhere;}
@media(min-width:640px){.pay-timeline{flex-direction:row;gap:0;}.pay-timeline .pt-step{flex:1;padding:40px 12px 12px;text-align:center;border-radius:0;border-left:0;}.pay-timeline .pt-step:first-child{border-left:1px solid var(--line-soft);border-radius:8px 0 0 8px;}.pay-timeline .pt-step:last-child{border-radius:0 8px 8px 0;}.pay-timeline .pt-step::before{left:50%;transform:translateX(-50%);top:10px;}}

/* Floor stack. Two fixed columns — the level on the left, what is on it on the right — so a
   nine-row tower and a three-row one read as the same object at different lengths. The level
   column is a fixed 66px basis rather than auto: auto would let "R1–R3" and "8–23" set different
   widths per row and the labels would step in and out down the list. */
.pj-fs{list-style:none;margin:10px 0 0;padding:0;border:1px solid var(--line-soft);border-radius:10px;overflow:hidden;}
.pj-fs-i{display:flex;align-items:baseline;gap:12px;padding:9px 14px;border-top:1px solid var(--line-soft);}
.pj-fs-i:first-child{border-top:0;}
.pj-fs-f{flex:0 0 66px;font-size:12px;font-weight:700;letter-spacing:.04em;color:var(--gold);overflow-wrap:anywhere;}
.pj-fs-l{flex:1;min-width:0;font-size:14px;line-height:1.45;color:var(--text-2);overflow-wrap:anywhere;}

/* .pj-cf-* (source conflicts) and .pj-ed-* (the "О проекте" article) are gone with the blocks they
   styled — see the REMOVED note in build-hubs.js for why. */
@media print{.pj-fz,.pj-um-c,.pj-fs,.pay-timeline .pt-step{border-color:#ccc;background:none;}
  .pay-timeline .pt-step::before{background:#eee;color:#000;}
  .pj-fs-f,.pj-sub-h,.pj-um-n{color:#000;}
  .pj-stat-i{border-color:#999;background:none;color:#000;}
  .pj-um-a,.pj-stat-i b{color:#000;}
  /* Icons survive print as thin grey line art rather than gold-on-white. */
  .pj-ico{stroke:#666;}}

/* The developer name in the facts grid is the one linked value there (its dossier). */
.qf-v a{color:var(--gold);border-bottom:1px solid transparent;}
.qf-v a:hover{border-bottom-color:var(--gold);text-decoration:none;}

/* ---- selling copy (§4, "О проекте") ----
   Plain prose at reading size. No card, no border, no accent rail: it is the one block on the page
   that is meant to be read rather than scanned, and boxing it would say otherwise. */
.pj-ov p{font-size:16px;line-height:1.75;color:var(--text-2);margin:0 0 14px;}
.pj-ov p:last-child{margin-bottom:0;}

/* ---- selling copy: "Читать далее" (owner, 2026-07-16) ----
   The same device as the gallery fold above: a <details>, so this is the whole implementation —
   no JS, native in every browser, and every paragraph stays in the DOM open or shut. That last
   part is the point for this block specifically: it is the copy that sells and the copy that
   ranks, so it may be moved off screen but never out of the document.
   Emitted only when there is a real tail to fold (see projectOverview() in build-hubs.js), so a
   two-paragraph record renders the same bare <p>s it renders today — no wrapper, no fade, no
   control to press.
   display:flex is here to put the control AFTER the prose once it opens (summary is order:2).
   The gallery can leave its summary on top, because a grid of photos below a button still reads
   as a grid of photos; a "Свернуть" wedged between paragraph 2 and paragraph 3 would cut the
   sentence the reader is in. If a browser ignores the flex, the button lands above the tail:
   ugly, still working. */
.pj-ov-x{position:relative;display:flex;flex-direction:column;}
.pj-ov-x>.pj-ov-b{order:2;}
/* The fade belongs over the LAST SHOWN paragraph, not inside the fold, which is why it hangs off
   this element at bottom:100% — "the strip the reader is about to stop reading". Absolutely
   positioned, so it is not a flex item, and pointer-events:none, so it never eats a tap or a
   text selection.
   The colour is the page's own background variable rather than a literal black: this block sits
   straight on body{background:var(--bg)} with no card underneath it, and #000 would read as a
   smudge against the emerald. --pj-ov-fade is the seam if the copy is ever dropped on a panel. */
.pj-ov-x:not([open])::before{content:'';position:absolute;left:0;right:0;bottom:100%;height:104px;
  background:linear-gradient(to bottom,transparent,var(--pj-ov-fade,var(--bg)));pointer-events:none;}
/* Centred, unlike the gallery's left-aligned twin: the reader leaves the text at the middle of
   the measure, not at its left edge. width:fit-content is what makes the auto margins bite. */
.pj-ov-b{display:flex;width:fit-content;margin:18px auto 0;}
/* Chevron, as the owner asked — and, like the gallery's plus, a glyph rather than an icon file. */
.pj-ov-b::before{content:'\25BE';font-size:12px;line-height:1;color:var(--gold);}
.pj-ov-x[open]>.pj-ov-b::before{content:'\25B4';}
.pj-ov-b2,.pj-ov-x[open]>.pj-ov-b>.pj-ov-b1{display:none;}
.pj-ov-x[open]>.pj-ov-b>.pj-ov-b2{display:inline;}
/* The tail fades in rather than snapping in. Only opacity and a 4px lift are animated: the height
   change is native and instant either way, and animating it is what would make the sections below
   jump around under the reader's thumb. */
.pj-ov-x[open]>.pj-ov-more{animation:pj-ov-in .28s var(--ease,ease);}
@keyframes pj-ov-in{from{opacity:0;transform:translateY(-4px);}to{opacity:1;transform:none;}}
/* Shorter fade on a phone: 104px is a third of the viewport there, and this fold matters most on
   a phone, where the un-folded copy is the reason the reader never reaches the price. */
@media(max-width:600px){.pj-ov-x:not([open])::before{height:80px;}}
@media (prefers-reduced-motion:reduce){.pj-ov-x[open]>.pj-ov-more{animation:none;}}
/* On paper there is nothing to press and nothing to fade into. */
@media print{.pj-ov-b{display:none;}.pj-ov-x:not([open])::before{display:none;}}

/* ---- section rail (all project pages) ----

   A sticky jump list, no JS. It sits inside .pj-col-a, and that is deliberate rather than a
   limitation to work around: .pj-col-a is the reading column (hero → price), so the rail travels
   for exactly as long as the reader is reading and lets go at the lead form, which is where we want
   their attention anyway. Every anchor still resolves after that — an <a href="#id"> does not care
   which box the link is in.

   Why it cannot simply span the whole page: at ≥1080px .pj-shell is a grid and any child of it is
   a grid item whose sticky travel is its own grid area. A rail that spans both rows would have to
   be a grid item in a spanning area, i.e. a third column — which is the form's job.

   Horizontal scroll, not wrap: a wrapping rail is 1 row on a full record and 3 on a fuller one, and
   its height would then depend on how many slots the record happens to fill — which is the one
   thing this page must not do. One row, always, at every count. */
.pj-rail{position:sticky;top:0;z-index:12;margin:0 0 8px;padding:8px 0 7px;background:var(--bg);}
/* The hairline is a pseudo-element, not a border: a border would be part of the sticky box's height
   and the 1px would show as a seam against the hero above it before the rail engages. */
.pj-rail::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:var(--line-soft);}
/* The "there is more →" fade. Sits over the right edge of the scrolling row and dissolves the last
   chip into the page background instead of guillotining it. Harmless when the row does NOT
   overflow: it is a gradient of --bg over --bg, i.e. nothing. That is why it needs no JS and no
   overflow measurement — the honest signal costs one pseudo-element.
   pointer-events:none, or it would eat clicks on the last chip it is drawn over. */
.pj-rail::before{content:"";position:absolute;top:8px;bottom:5px;right:0;width:46px;z-index:2;
  pointer-events:none;background:linear-gradient(90deg,rgba(10,31,26,0) 0%,var(--bg) 82%);}
/* SCROLLABLE, AND IT HAS TO LOOK IT (owner, 2026-07-17: «все кнопки не помещаются и там как будто
   можно скролить но скорола нет»). The rail hid its scrollbar outright — scrollbar-width:none plus
   ::-webkit-scrollbar{display:none} — so on any record with more than ~6 slots the last chips sat
   off-screen with nothing on the page admitting they existed. A row that is cut off mid-chip reads
   as a rendering bug, not as an invitation to swipe.

   Two affordances, because neither is enough alone:
   - a real scrollbar, thin and dim, so a desktop reader can grab it. It appears only when the row
     overflows (overflow-x:auto), so short records are unaffected;
   - the fade on the right edge below, which is the only signal that survives macOS/iOS overlay
     scrollbars — those are invisible until you are already scrolling, i.e. exactly too late. */
.pj-rail ul{display:flex;gap:6px;margin:0;padding:0 0 4px;list-style:none;overflow-x:auto;
  -webkit-overflow-scrolling:touch;scrollbar-width:thin;scrollbar-color:var(--line) transparent;
  /* Chips land flush instead of half-cut when the reader lets go. */
  scroll-snap-type:x proximity;}
.pj-rail li{scroll-snap-align:start;}
.pj-rail ul::-webkit-scrollbar{height:4px;}
.pj-rail ul::-webkit-scrollbar-track{background:transparent;}
.pj-rail ul::-webkit-scrollbar-thumb{background:var(--line);border-radius:999px;}
.pj-rail ul:hover::-webkit-scrollbar-thumb{background:var(--gold-soft);}
.pj-rail li{flex:0 0 auto;}
.pj-rail a{display:inline-flex;align-items:center;min-height:32px;padding:4px 12px;border-radius:999px;
  border:1px solid var(--line-soft);background:var(--bg-2);color:var(--text-2);
  font-size:12.5px;font-weight:600;line-height:1.3;white-space:nowrap;}
.pj-rail a:hover{border-color:var(--gold);color:var(--gold);text-decoration:none;}
/* ≤960px the .bhead is itself sticky at top:0 (see the NAVIGATION block above) and is ~77px tall,
   so the rail parks under it instead of behind it. Above 960px the header is position:relative and
   the rail takes the top of the viewport. z-index stays below the header's 45. */
@media(max-width:960px){.pj-rail{top:76px;}}
/* Anchor landing has to clear whatever is sticky above it: header + rail on a phone, rail alone on
   a desktop. Scoped to .pj-shell so no other hub's sections gain a scroll offset. */
.pj-shell section[id]{scroll-margin-top:132px;}
@media(min-width:961px){.pj-shell section[id]{scroll-margin-top:60px;}}
@media print{.pj-rail{display:none;}}

/* ============ PROJECT LEAD FORM (§7) + the page shell it needs ============

   Mobile first, and on a phone there is nothing to do: .pj-ask is a normal card sitting in the flow
   between the price block and "Кому подходит". No sticky, no fixed, no overlay — the mobile bottom
   bar (assets/js/sticky-cta.js) already owns the bottom of a phone screen and a second floating
   thing would fight it.

   Sizing note: every input stays at font-size:16px. Below 16px iOS zooms the viewport on focus and
   the reader lands on a page they then have to pinch back out of. */
.pj-ask{border:1px solid var(--line);border-radius:14px;background:var(--bg-2);padding:16px 16px 18px;margin:26px 0;}
.pj-ask-h{margin:0 0 6px;font-size:16px;font-weight:600;color:var(--text);line-height:1.35;}
.pj-ask-s{margin:0 0 13px;font-size:13px;line-height:1.55;color:var(--text-2);}
.pj-ask-r{display:flex;flex-direction:column;gap:5px;margin:0 0 10px;}
.pj-ask-f label{font-size:12.5px;font-weight:600;color:var(--text-2);line-height:1.4;}
.pj-ask-f input[type=text],.pj-ask-f select,.pj-ask-f textarea{font-size:16px;padding:9px 11px;
  border:1px solid var(--line);border-radius:8px;background:var(--bg-3);color:var(--text);
  width:100%;box-sizing:border-box;font-family:inherit;line-height:1.4;}
.pj-ask-f textarea{resize:vertical;min-height:74px;}
/* Same gold chevron the /contacts/ form uses. assets/js/select.js (which replaces the OS popup on
   desktop) is not loaded on generated project pages, so this is the native control, styled. */
.pj-ask-f select{appearance:none;-webkit-appearance:none;-moz-appearance:none;cursor:pointer;padding-right:36px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23c9a24b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;background-size:11px 7px;}
.pj-ask-f select:hover{border-color:rgba(201,162,75,.5);}
.pj-ask-f input:focus,.pj-ask-f select:focus,.pj-ask-f textarea:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 3px rgba(201,162,75,.14);}
.pj-ask-f option{background:#0b1219;color:#eef3f6;}
.pj-ask-f option:checked,.pj-ask-f option:hover{background:#16232e;color:#e8c98a;}
.pj-ask-k{display:flex;gap:8px;align-items:flex-start;margin:2px 0 13px;}
.pj-ask-k input{margin-top:2px;min-width:17px;min-height:17px;flex:0 0 17px;accent-color:var(--gold);}
.pj-ask-k label{font-size:11.5px;line-height:1.5;color:var(--text-3);font-weight:400;}
.pj-ask-k a{color:var(--text-2);text-decoration:underline;}
.pj-ask-k a:hover{color:var(--gold);}
/* The one primary action on the panel. Full width, unlike the .btn-lead pair in the hero, because
   here there is nothing to share the row with — and that is the point (§7). */
.pj-ask-btn{width:100%;cursor:pointer;}
.pj-ask-st{font-size:12.5px;line-height:1.5;color:var(--gold);margin:10px 0 0;min-height:1em;}
.pj-ask-st a{color:var(--gold);text-decoration:underline;}
/* Honeypot. Selector deliberately more specific than `.pj-ask-f input[type=text]` above, or that
   rule's width:100% would win and stretch this to the width of the initial containing block. */
.pj-ask-f input.pj-ask-hp{position:absolute;left:-9999px;width:1px;height:1px;padding:0;border:0;}
.pj-ask-note{margin:12px 0 0;font-size:11.5px;line-height:1.5;color:var(--text-3);}
/* Fallback channels. Small muted chips under a lead-in line, never four gold buttons: §2 bans
   "четыре равнозначные CTA WhatsApp / Telegram / форма / email", so these have to read as the
   second-best way to reach us, which is what they are. */
.pj-ask-alt{margin:14px 0 8px;padding-top:13px;border-top:1px solid var(--line-soft);
  font-size:12px;color:var(--text-3);}
.pj-ask-alts{display:flex;flex-wrap:wrap;gap:7px;}
.pj-ask-c{display:inline-flex;align-items:center;min-height:34px;padding:5px 13px;border-radius:999px;
  border:1px solid var(--line-soft);background:var(--bg-3);color:var(--text-2);font-size:12.5px;font-weight:500;}
.pj-ask-c:hover{border-color:var(--gold);color:var(--gold);text-decoration:none;}

/* Desktop: the page shifts left and the form takes a sticky right column (owner, 2026-07-16).
   1080px is the threshold because below it the reading column would have to give up more width than
   it can spare; 1100px max-width is not arbitrary either — it is exactly .bhead's own rail, so the
   content column now starts on the same line as the logo instead of 170px inside it. */
@media (min-width:1080px){
  /* The form column went 316px -> 380px (owner, 2026-07-16: "расширить контактную форму").
     max-width stays 1100px on purpose: it is exactly .bhead's own rail, so the content column and
     the logo start on the same line. Widening the shell instead would have bought the form its
     64px at the cost of the page no longer lining up with its own header. The content column
     therefore absorbs the difference — 1100 - 44 (.bwrap padding) - 380 - 32 = 644px of reading
     width, still wider than a phone and only ~14% down from before. */
  .bwrap.pj-shell{max-width:1100px;display:grid;grid-template-columns:minmax(0,1fr) 380px;
    column-gap:32px;align-items:start;}
  .pj-shell .pj-col-a{grid-column:1;grid-row:1;min-width:0;}
  .pj-shell .pj-col-b{grid-column:1;grid-row:2;min-width:0;}
  /* FIX 2026-07-26: page-upgrade sections are appended as direct children of the .pj-shell grid
     (after the reading column and the sticky rail), with no grid placement — so they auto-flowed
     into column 2 / trailing rows and "escaped" to the bottom-right (owner screenshot). Pin them to
     the reading column so they continue the article below .pj-col-b; the sticky rail keeps col 2. */
  .pj-shell>.pgup-sec{grid-column:1;grid-row:auto;min-width:0;}
  /* grid-row 1/span 2 gives the sticky box the whole page height to travel through.
     align-self:start is not optional: a stretched grid item is already as tall as its area, and a
     sticky element that fills its containing block has nowhere to stick to and simply scrolls away.

     max-height + overflow-y are GONE (owner, 2026-07-16: "то что там два ползунка — этого точно не
     должно быть"). They were the outer of the two scrollbars. They existed to stop a tall panel
     losing its submit button off the bottom, but the panel is no longer tall: dropping the lede,
     the note and half the consent line, and turning "Что прислать" from a pre-filled textarea into
     a one-line <select>, takes it to roughly 550px — it fits a 900px laptop window whole, with the
     button visible, which is what the constraint was actually protecting. Nothing clips it now, so
     if a future edit grows the panel past the viewport it will push the page rather than hide the
     button — a visible failure instead of a silent one. */
  .pj-shell .pj-ask{grid-column:2;grid-row:1 / span 2;align-self:start;position:sticky;top:20px;
    margin:10px 0 0;}
  /* The generated hub footer is a .bwrap too (see footer() in _build/build-hubs.js), so at 760px it
     would close a 1100px page 170px to the right of where the content starts. Sibling-scoped off
     .pj-shell: only the project pages widen it, every other hub footer is untouched. */
  .pj-shell ~ .bfoot .bwrap{max-width:1100px;}
}
/* A4 landscape is ~1123px, so the grid above CAN match in print. Undo it: with the form hidden the
   second column is 350px of blank paper down the side of every page. */
@media print{.pj-ask{display:none;}.bwrap.pj-shell{display:block;max-width:100%;}}

/* project-line hub (/projects/<line>/) — a disambiguation table, mobile-first */
.pl-lede{font-size:16px;line-height:1.7;color:var(--text-2);margin:0 0 14px;}
.pl-honest{font-size:14.5px;line-height:1.65;color:var(--text-2);border-left:3px solid var(--gold);
  background:var(--bg-2);border-radius:0 8px 8px 0;padding:12px 16px;margin:0 0 26px;}
.pl-honest a{color:var(--gold);font-weight:600;}
.pl-table{margin:26px 0;}
.pl-table h2{font-size:20px;margin:0 0 12px;}
.pl-grid{width:100%;border-collapse:collapse;font-size:15px;}
.pl-grid th{text-align:left;font-size:12px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--text-3);font-weight:600;padding:0 10px 8px 0;border-bottom:1px solid var(--line);}
/* word-break: several rows carry two or three alternative names and would otherwise
   push the table into a horizontal scroll on a phone. */
.pl-grid td{padding:11px 10px 11px 0;border-bottom:1px solid var(--line);color:var(--text-2);
  line-height:1.5;overflow-wrap:anywhere;}
.pl-grid td a{color:var(--gold);font-weight:600;}
.pl-ord{width:2.5em;color:var(--text-3);font-variant-numeric:tabular-nums;}
.pl-nopage{display:inline-block;font-size:11.5px;letter-spacing:.04em;color:var(--text-3);
  border:1px solid var(--line);border-radius:20px;padding:1px 9px;margin-left:6px;white-space:nowrap;}
.pl-conflict{border:1px solid var(--line);border-radius:12px;padding:16px 18px;margin:26px 0;background:var(--bg-2);}
.pl-conflict h2{font-size:17px;margin:0 0 8px;}
.pl-conflict ul{margin:0;padding-left:18px;}
.pl-conflict li{font-size:14.5px;line-height:1.6;color:var(--text-2);}
@media print{.pl-honest,.pl-conflict{border-color:#ccc;background:none;}}

/* Named contact card — the person who handles the enquiry, shown above the channel list at the foot
   of every generated project page (contactCard() in _build/build-hubs.js). Was inlined on the
   hand-made /projects/odom-tower/ page; those nine flagships keep their own copy of these rules. */
.contact-card{display:flex;gap:14px;align-items:flex-start;border:1px solid var(--line);border-radius:10px;padding:16px;margin:22px 0;background:radial-gradient(120% 140% at 0% 0%,rgba(212,175,106,.08),rgba(212,175,106,0) 60%),var(--bg-3);}
/* 56px at 320px leaves ~215px of text column next to it; the 64px of the original would not. */
.contact-card img{width:56px;height:56px;border-radius:50%;object-fit:cover;flex:0 0 auto;}
/* min-width:0 lets the flex item shrink below its content width — without it a long role line
   forces the card wider than the viewport instead of wrapping. */
.contact-card .cc-body{flex:1;min-width:0;}
.contact-card .cc-name{font-family:'Cormorant Garamond',Georgia,serif;font-size:20px;font-weight:600;color:var(--text);margin:0 0 2px;}
.contact-card .cc-role{font-size:13px;color:var(--text-2);margin:0 0 10px;line-height:1.5;}
/* 44px tap target, matching .reg-links a — it was a bare inline link on odom-tower. */
.contact-card .cc-btn{display:inline-flex;align-items:center;min-height:44px;font-size:14px;font-weight:600;color:var(--gold);}
@media(min-width:480px){.contact-card{gap:16px;padding:18px 20px;}.contact-card img{width:64px;height:64px;}}
/* On paper the reader cannot tap a Telegram link, and the card is there to name the person. */
@media print{.contact-card{border-color:#ccc;background:none;}.contact-card .cc-name{color:#000;}.contact-card .cc-btn{display:none;}}

.any-proj{border:1px solid var(--line);border-left:3px solid var(--gold);border-radius:12px;background:radial-gradient(130% 150% at 0% 0%,rgba(212,175,106,.08),rgba(212,175,106,0) 55%),var(--bg-2);padding:20px 22px;margin:26px 0;}
/* Regional decision cards (/rynok-kambodzhi/): choosing a region, not listing projects */
.reg-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));gap:14px;margin:18px 0 8px;}
.reg-card{border:1px solid var(--line-soft);border-radius:14px;background:var(--bg-2);padding:18px 20px;display:flex;flex-direction:column;}
.reg-card h2{font-size:19px;margin:0 0 8px;color:var(--gold);}
.reg-card h2 .rcount{font-size:12px;font-weight:600;color:var(--text-3);background:var(--bg-3);border:1px solid var(--line-soft);border-radius:999px;padding:1px 8px;vertical-align:middle;}
.reg-what{font-size:14.5px;line-height:1.6;color:var(--text-2);margin:0 0 14px;}
.reg-f{margin:0 0 11px;}
.reg-k{display:block;font-size:11.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-3);margin:0 0 3px;}
.reg-f p{font-size:14px;line-height:1.55;color:var(--text-2);margin:0;}
.reg-links{display:flex;flex-wrap:wrap;gap:8px;margin-top:auto;padding-top:12px;}
.reg-links a{font-size:13px;font-weight:600;color:var(--text);border:1px solid var(--line);border-radius:8px;padding:8px 13px;min-height:44px;display:inline-flex;align-items:center;}
.reg-links a:hover{border-color:var(--gold);color:var(--gold);text-decoration:none;}
.reg-links .reg-go{color:#1B130A;background:linear-gradient(180deg,var(--gold),var(--gold-soft));border-color:transparent;}
.any-proj h2{font-size:20px;margin:0 0 8px;color:var(--text);}
.any-proj p{font-size:15px;line-height:1.65;color:var(--text-2);margin:0 0 14px;}
/* Email shown as a copyable address instead of a mailto button (no mail client needed) */
.mail-chip{display:inline-flex;align-items:center;gap:9px;min-height:48px;padding:0 18px;border:1px solid var(--line);border-radius:999px;background:transparent;color:var(--text);font-family:inherit;font-size:14px;font-weight:600;cursor:pointer;line-height:1.2;vertical-align:middle;}
.mail-chip::after{content:"\29C9";color:var(--gold);font-size:14px;opacity:.8;}
.mail-chip:hover{border-color:var(--gold);color:var(--gold);}
.mail-chip:focus-visible{outline:2px solid var(--gold);outline-offset:2px;}
.mail-chip.is-copied{border-color:var(--gold);color:var(--gold);}
.mail-chip.is-copied::after{content:"\2713";opacity:1;}
@media(max-width:560px){.mail-chip{width:100%;justify-content:center;}}
/* ---- comparison workbench (/projects/compare/) ---- */
/* One panel for "choose what to compare": presets, search, its answers, the shortlist. */
.cmp-pick{border:1px solid var(--line-soft);border-radius:12px;background:var(--bg-2);padding:14px 16px;margin:18px 0 16px;}
.cmp-controls{display:flex;gap:14px;flex-wrap:wrap;align-items:center;margin:0;}
.cmp-search{flex:1;min-width:220px;box-sizing:border-box;font-family:inherit;font-size:16px;color:var(--text);background:var(--bg-2);border:1px solid var(--line-soft);border-radius:3px;padding:12px 15px;min-height:44px;}
.cmp-search:focus{outline:none;border-color:var(--gold);}
.cmp-diff-lbl{font-size:13.5px;color:var(--text-2);display:inline-flex;align-items:center;gap:7px;cursor:pointer;white-space:nowrap;}
.cmp-diff-lbl input{accent-color:var(--gold);width:16px;height:16px;}
.cmp-copy{font-size:13px;font-weight:600;padding:8px 14px;border-radius:8px;border:1px solid var(--line);background:var(--bg-2);color:var(--text-2);cursor:pointer;transition:.15s;min-height:44px;}
.cmp-copy:hover{border-color:var(--gold);color:var(--text);}
.cmp-goals{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0 0 12px;}
.cmp-goals-h{font-size:12px;letter-spacing:.04em;text-transform:uppercase;color:var(--text-3);font-weight:600;margin-right:2px;}
.cmp-goal{font-size:13px;font-weight:600;padding:8px 14px;border-radius:999px;border:1px solid var(--line);background:var(--bg-3);color:var(--text-2);cursor:pointer;transition:.15s;}
.cmp-goal:hover{border-color:var(--gold);color:var(--text);}
/* Search answers. No max-height and no overflow by design — the JS caps the list at 8, so this
   box can never grow its own scrollbar again. That scrollbar is what the owner cut. */
.cmp-sel{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:12px 0 0;}
.cmp-sel[hidden],.cmp-picked[hidden]{display:none;}
.cmp-hint{font-size:12.5px;color:var(--text-3);}
/* The shortlist: the only place a chosen project can be seen and taken off. */
.cmp-picked{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:12px 0 0;padding:12px 0 0;border-top:1px solid var(--line-soft);}
.cmp-picked-h{font-size:12px;letter-spacing:.04em;text-transform:uppercase;color:var(--text-3);font-weight:600;}
.cmp-pick-x{display:inline-flex;align-items:center;gap:8px;min-height:36px;font-size:12.5px;font-weight:600;padding:6px 10px 6px 13px;border-radius:999px;border:1px solid var(--gold);background:var(--gold);color:#1B130A;cursor:pointer;transition:.15s;}
.cmp-pick-x:hover{background:transparent;color:var(--text);}
.cmp-x{font-size:15px;line-height:1;opacity:.7;}
.cmp-pick-x:hover .cmp-x{opacity:1;color:var(--gold);}
/* Actions on a finished comparison, so they sit under the table rather than in front of it. */
.cmp-acts{display:flex;gap:10px;flex-wrap:wrap;margin:4px 0 6px;}
@media(max-width:600px){
  .cmp-pick{padding:12px 13px;}
  .cmp-search{flex:1 1 100%;min-width:0;}
  .cmp-acts .cmp-copy{flex:1 1 100%;}
}
.cmp-chip{font-size:12.5px;font-weight:600;padding:7px 12px;border-radius:999px;border:1px solid var(--line);background:var(--bg-2);color:var(--text-2);cursor:pointer;transition:.15s;}
.cmp-chip:hover{border-color:var(--gold);color:var(--text);}
.cmp-chip.is-on{background:var(--gold);color:#1B130A;border-color:var(--gold);}
.cmp-empty{color:var(--text-2);font-size:15.5px;margin:20px 0;padding:22px;border:1px dashed var(--line-soft);border-radius:4px;text-align:center;}
.cmp-notes{margin:22px 0 6px;}
.cmp-notes:empty{display:none;}
.cmp-notes-h{font-size:16px;color:var(--text-2);margin:0 0 12px;font-weight:600;}
.cmp-notes-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(260px,100%),1fr));gap:14px;}
.cmp-note{border:1px solid var(--line-soft);border-radius:12px;padding:16px 18px;background:var(--bg-2);}
.cmp-note-n{font-size:15px;font-weight:600;color:var(--gold);margin:0 0 8px;}
.cmp-note p{font-size:13px;line-height:1.5;color:var(--text-2);margin:0 0 7px;}
.cmp-note p b{color:var(--text);}
.cmp-note-open{display:inline-block;margin-top:4px;font-size:12.5px;font-weight:600;color:var(--gold);}
.cmp-scroll{overflow-x:auto;margin:8px 0 6px;-webkit-overflow-scrolling:touch;}
.cmp-table{border-collapse:collapse;width:100%;min-width:520px;font-size:14px;}
.cmp-table th,.cmp-table td{border:1px solid var(--line-soft);padding:11px 13px;text-align:left;vertical-align:top;}
.cmp-table thead th{background:var(--bg-3);}
.cmp-th .cmp-name{color:var(--gold);font-weight:600;font-size:14.5px;margin-bottom:6px;}
.cmp-th .src-label{margin:0 0 4px;}
.cmp-th .cmp-open{display:inline-block;margin-top:6px;font-size:12.5px;font-weight:600;}
.cmp-row{background:var(--bg-3);color:var(--text-2);font-weight:600;font-size:13px;letter-spacing:.02em;white-space:nowrap;position:sticky;left:0;z-index:1;}
.cmp-table td{color:var(--text);}
.cmp-tc{color:var(--text-3);font-style:italic;font-size:13px;}
@media(max-width:600px){.cmp-row{white-space:normal;}}
/* Compare UX: collapsible groups (desktop) + stacked cards instead of a wide table (mobile) */
.cmp-grp{border:1px solid var(--line-soft);border-radius:12px;background:var(--bg-2);margin:0 0 12px;overflow:hidden;}
.cmp-grp>summary{cursor:pointer;list-style:none;padding:13px 16px;font-weight:600;font-size:15px;color:var(--text);display:flex;align-items:center;gap:10px;}
.cmp-grp>summary::-webkit-details-marker{display:none;}
.cmp-grp>summary::after{content:"+";color:var(--gold);font-size:19px;font-weight:400;line-height:1;}
.cmp-grp[open]>summary::after{content:"\2212";}
.cmp-grp>summary:hover{color:var(--gold);}
.cmp-grp-n{margin-left:auto;font-size:12px;font-weight:600;color:var(--text-3);background:var(--bg-3);border:1px solid var(--line-soft);border-radius:999px;padding:1px 8px;}
.cmp-grp .cmp-scroll{margin:0;}
.cmp-grp .cmp-table{border-top:1px solid var(--line-soft);}
.cmp-legend{display:none;}
@media(max-width:760px){
  .cmp-legend{display:grid;grid-template-columns:1fr;gap:8px;margin:0 0 14px;}
  .cmp-lg{border:1px solid var(--line-soft);border-radius:10px;background:var(--bg-2);padding:10px 12px;display:flex;flex-wrap:wrap;align-items:center;gap:8px;}
  .cmp-lg b{color:var(--gold);font-size:14.5px;}
  .cmp-lg a{margin-left:auto;font-size:12.5px;font-weight:600;color:var(--gold);}
  .cmp-scroll{overflow:visible;}
  .cmp-table{min-width:0;display:block;font-size:14.5px;}
  .cmp-table thead{display:none;}
  .cmp-table tbody,.cmp-table tr,.cmp-table td,.cmp-table th{display:block;width:100%;box-sizing:border-box;}
  .cmp-table tr{border:0;border-top:1px solid var(--line-soft);padding:12px 14px;}
  .cmp-table tbody tr:first-child{border-top:0;}
  .cmp-table th.cmp-row{position:static;background:transparent;border:0;padding:0 0 8px;font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);white-space:normal;}
  .cmp-table td{border:0;padding:5px 0;display:flex;gap:12px;align-items:baseline;text-align:left;}
  .cmp-table.cmp-ev-on td{text-align:left;}
  .cmp-table td::before{content:attr(data-p);flex:0 0 40%;font-weight:600;color:var(--text-2);font-size:13px;line-height:1.4;}
}
/* ---- methodology page (/kak-my-proveryaem/) ---- */
.mth-sec{margin:34px 0;min-width:0;}
.mth-sec p,.mth-boundary,.hub-lead{overflow-wrap:anywhere;word-break:normal;}
.mth-sec h2{font-size:20px;color:var(--text);margin:0 0 12px;}
.mth-lead{color:var(--text-2);font-size:15.5px;margin:0 0 16px;}
.mth-ev{display:flex;flex-direction:column;gap:14px;}
.mth-ev-item{padding:14px 16px;border:1px solid var(--line-soft);border-radius:4px;background:var(--bg-3);}
.mth-ev-item .src-label{margin-bottom:6px;}
.mth-ev-item p{margin:0;color:var(--text-2);font-size:14.5px;line-height:1.6;}
.mth-table{border-collapse:collapse;width:100%;font-size:14.5px;}
.mth-table th,.mth-table td{border:1px solid var(--line-soft);padding:11px 13px;text-align:left;vertical-align:top;}
.mth-table thead th{background:var(--bg-3);color:var(--gold);font-weight:600;}
.mth-table td:first-child{color:var(--gold);font-weight:600;width:64px;}
.mth-note{color:var(--text-3);font-size:13px;}
.mth-steps{margin:0;padding-left:0;list-style:none;counter-reset:mth;}
.mth-steps li{position:relative;padding:10px 0 10px 42px;border-bottom:1px solid var(--line-soft);color:var(--text);font-size:15px;counter-increment:mth;}
.mth-steps li::before{content:counter(mth,decimal-leading-zero);position:absolute;left:0;top:10px;font-size:13px;font-weight:600;color:var(--gold);}
.mth-boundary{color:var(--text-2);font-size:14.5px;line-height:1.7;padding:14px 16px;border-left:2px solid var(--gold);background:var(--bg-3);border-radius:0 3px 3px 0;}
.mth-corr{display:block;margin-top:36px;padding:26px 24px;border:1px solid var(--line);border-radius:3px;background:radial-gradient(120% 140% at 50% 0%,rgba(212,175,106,.09),rgba(212,175,106,0) 70%),var(--bg-3);}
.mth-corr h2{margin:0 0 8px;font-size:19px;color:var(--text);}
.mth-corr p{margin:0 0 16px;color:var(--text-2);font-size:15px;}
.mth-corr a{display:inline-flex;align-items:center;justify-content:center;gap:7px;min-height:48px;font-size:14px;font-weight:700;padding:0 20px;border-radius:999px;margin:0 10px 8px 0;text-decoration:none;}
.mth-corr .btn-ask{background:linear-gradient(180deg,var(--gold),var(--gold-soft));color:#1B130A;}
.mth-corr .btn-open{color:var(--gold);border:1px solid var(--line);background:transparent;}
.mth-corr .btn-open:hover{border-color:var(--gold);color:#f0d295;}
.mth-prose{font-size:15.5px;line-height:1.62;}
.mth-prose :is(.mth-sec,.bp-sec,.bd-sec,.gl-sec,.lt-sec,.pgup-sec){margin:42px 0;}
.mth-prose>h2,.mth-prose :is(.mth-sec:not(.mth-corr),.bp-sec,.bd-sec,.gl-sec,.lt-sec,.pgup-sec,.related,.any-proj)>h2{font-family:'Cormorant Garamond',Georgia,serif;font-size:clamp(25px,3vw,30px);font-weight:600;line-height:1.2;color:var(--gold);margin:46px 0 10px;padding-top:8px;}
.mth-prose>h2::before,.mth-prose :is(.mth-sec:not(.mth-corr),.bp-sec,.bd-sec,.gl-sec,.lt-sec,.pgup-sec,.related,.any-proj)>h2::before{content:"";display:block;width:34px;height:3px;background:var(--gold);border-radius:2px;margin:0 0 12px;}
.mth-prose h3{font-family:'Inter',system-ui,sans-serif;font-size:17.5px;font-weight:700;line-height:1.32;color:#f0e4cf;margin:28px 0 9px;}
.mth-prose p,.mth-prose li{font-size:15.5px;line-height:1.62;}
.mth-prose p{max-width:68ch;}
.mth-prose .mth-lead{font-size:15.5px;line-height:1.62;color:#d7ded9;}
.mth-prose .mth-corr{margin-top:38px;}
.mth-prose .mth-corr>h2{font-family:'Cormorant Garamond',Georgia,serif;font-size:20px;line-height:1.2;color:var(--text);margin:0 0 8px;padding-top:0;}
.mth-prose .mth-corr>h2::before{content:none;}
/* ---- regional market-context showcase (/rynok-kambodzhi/) ---- */
.rbanner{margin:6px 0 22px;padding:14px 16px;border:1px solid var(--line);border-left:3px solid var(--gold);border-radius:0 3px 3px 0;background:var(--bg-3);color:var(--text-2);font-size:14px;line-height:1.6;}
.rcount{color:var(--text-3);font-weight:400;font-size:15px;}
.rcard{display:flex;flex-direction:column;border:1px solid var(--line-soft);border-radius:6px;padding:16px 16px 14px;background:var(--bg-2);}
.rcard .pcard-cat{font-size:11.5px;letter-spacing:.04em;text-transform:uppercase;color:var(--text-3);margin-bottom:6px;}
.rcard h3{margin:0 0 4px;font-size:16.5px;color:var(--text);}
.rcard .loc{font-size:13.5px;color:var(--text-2);margin-bottom:8px;}
.rcard .pcard-mid{margin:2px 0 8px;}
.rcard-note{font-size:12.5px;color:var(--text-3);font-style:italic;margin:0 0 12px;line-height:1.5;}
.rcard .pcard-cta{margin-top:auto;}
.rcard .ask{display:inline-flex;align-items:center;justify-content:center;min-height:44px;font-size:13.5px;font-weight:700;padding:0 16px;border-radius:999px;background:linear-gradient(180deg,var(--gold),var(--gold-soft));color:#1B130A;}
/* ---- buyer tools + calculators ---- */
.tool-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(260px,100%),1fr));gap:14px;margin:18px 0;}
.tool-card{display:block;border:1px solid var(--line-soft);border-radius:6px;padding:18px;background:var(--bg-2);color:var(--text);}
.tool-card:hover{border-color:var(--gold);text-decoration:none;}
.tool-card h3{margin:0 0 8px;font-size:17px;color:var(--gold);}
.tool-card p{margin:0;font-size:14px;color:var(--text-2);line-height:1.55;}
.calc-disc{margin:6px 0 20px;padding:14px 16px;border:1px solid var(--line);border-left:3px solid var(--gold);border-radius:0 3px 3px 0;background:var(--bg-3);color:var(--text-2);font-size:13.5px;line-height:1.6;}
.calc-form{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(240px,100%),1fr));gap:14px;margin:8px 0 18px;}
.calc-field{display:flex;flex-direction:column;gap:6px;}
.calc-field label{font-size:13px;color:var(--text-2);}
.calc-field input,.calc-field select{box-sizing:border-box;font-family:inherit;font-size:15px;color:var(--text);background:var(--bg-2);border:1px solid var(--line-soft);border-radius:3px;padding:11px 13px;min-height:44px;}
.calc-field input:focus,.calc-field select:focus{outline:none;border-color:var(--gold);}
.calc-go{font-size:15px;font-weight:600;padding:13px 26px;border-radius:3px;border:none;cursor:pointer;background:linear-gradient(180deg,var(--gold),var(--gold-soft));color:#1B130A;}
.calc-out{margin:22px 0 8px;}
.calc-res{border-collapse:collapse;width:100%;font-size:15px;}
.calc-res th,.calc-res td{border:1px solid var(--line-soft);padding:12px 14px;text-align:left;}
.calc-res th{background:var(--bg-3);color:var(--text-2);font-weight:600;width:55%;}
.calc-res td{color:var(--text);font-weight:600;}
.calc-warn{margin:16px 0 0;padding:14px 16px;border:1px solid var(--line);border-left:3px solid var(--gold);border-radius:0 3px 3px 0;background:var(--bg-3);font-size:13.5px;color:var(--text-2);}
.calc-warn ul{margin:8px 0 0;padding-left:18px;} .calc-warn li{margin:0 0 4px;}
/* ---- buyer checklist ---- */
.ck-out{position:sticky;top:0;background:var(--bg);padding:12px 0 10px;z-index:2;margin-bottom:8px;}
.ck-bar{height:8px;border-radius:999px;background:var(--bg-3);overflow:hidden;}
.ck-bar span{display:block;height:100%;background:linear-gradient(90deg,var(--gold-soft),var(--gold));transition:width .2s;}
.ck-stat{margin:8px 0 6px;font-size:14px;color:var(--text-2);font-weight:600;}
.ck-gate{margin:0;font-size:13.5px;padding:8px 12px;border-radius:3px;}
.ck-gate.blocked{color:#f0b8b8;background:rgba(200,80,80,.10);border:1px solid rgba(200,80,80,.25);}
.ck-gate.ok{color:#8fe3b0;background:rgba(80,180,120,.10);border:1px solid rgba(80,180,120,.22);}
.ck-gh{font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--text-3);margin:20px 0 8px;}
.ck-item{display:flex;gap:10px;align-items:flex-start;padding:10px 0;border-bottom:1px solid var(--line-soft);font-size:15px;color:var(--text);cursor:pointer;}
.ck-item input{margin-top:3px;accent-color:var(--gold);width:17px;height:17px;flex:0 0 auto;}
.ck-crit{font-size:11px;font-weight:600;letter-spacing:.03em;color:var(--gold);text-transform:uppercase;}
/* ---- consultation questions ---- */
.q-actions{margin:8px 0 12px;}
.q-list{margin:0;padding-left:22px;}
.q-list li{font-size:15.5px;color:var(--text);margin:0 0 10px;line-height:1.5;}
/* The mobile bottom CTA bar (.scta) is retired (owner, 2026-07-16): it covered ~81px of every
   phone screen and Google treats a page-wide fixed overlay as an interstitial. The rules that
   revealed it lived here; assets/js/sticky-cta.js no longer injects the bar or the
   body.has-sticky-cta flag, so the .fav-launcher lift that dodged it is unnecessary too and the
   launcher returns to its own bottom offset. Contact routes on mobile are unaffected: the nav
   drawer and the footer both keep WhatsApp + Telegram. */

/* ============ PROJECT FACT TAGS ============ */
/* Factual, non-evaluative chips sourced from FACTS.md. Never use
   promotional/absolute labels ("Best investment", "Zero risk").
   Developer-conditional facts (GRR, buyback) are marked as such. */
.ptags{display:flex;flex-wrap:wrap;gap:7px;margin:0 0 6px;}
.ptag-chip{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;line-height:1;letter-spacing:.01em;color:#0a1f1a;background:#f3f1ec;border:1px solid #f3f1ec;border-radius:999px;padding:6px 11px;white-space:nowrap;}
.ptag-chip.is-gold{color:#0a1f1a;border-color:var(--gold);background:var(--gold);}
.ptag-chip .ptag-dot{font-size:9px;opacity:.7;}
/* updated-on line under the tag row */
.ptags-date{font-size:11.5px;color:#c9d4d4;margin:8px 0 0;}
/* on listing cards the tag row sits tighter */
.pcard .ptags{margin-top:2px;}

/* ============ "COMING SOON" TOPIC BADGE ============ */
/* Small inline chip for guide-hub topics that are planned as full
   cornerstone pages but not yet published. Non-promotional, muted. */
.tag-soon{display:inline-flex;align-items:center;font-size:11px;font-weight:600;line-height:1;letter-spacing:.02em;text-transform:uppercase;color:var(--text-3);background:rgba(243,241,236,.04);border:1px solid var(--line-soft);border-radius:999px;padding:5px 10px;margin-left:8px;vertical-align:middle;white-space:nowrap;}

/* ============ ASK-FOR-CURRENT-PRICE ============ */
/* Inline link next to a price. Prices on site are developer
   promo figures that change, so we invite a fresh quote rather
   than presenting the number as fixed. */
.price-ask{display:inline-flex;align-items:center;gap:6px;font-size:13px;font-weight:600;color:var(--gold);border:1px solid var(--line);border-radius:999px;padding:6px 13px;margin-left:4px;transition:background .2s,border-color .2s;vertical-align:middle;}
.price-ask:hover{background:rgba(212,175,106,.08);border-color:var(--gold);text-decoration:none;}
.price-ask .pa-ic{font-size:12px;}
/* a block-level variant that sits under a price table or hero price */
.price-ask-row{margin:14px 0 4px;font-size:14px;color:#c9d4d4;display:flex;flex-wrap:wrap;align-items:center;gap:10px;}

/* ============ WIDE COMPARISON TABLE ============ */
/* Comparison tables with many project columns must scroll
   horizontally on narrow screens instead of squeezing cells into
   unreadable slivers. The wrapper keeps overflow-x:auto; the table
   gets a min-width so columns stay legible and the scroll engages. */
.tbl-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:18px 0;}
.tbl-scroll>table{margin:0;min-width:880px;}
/* Mobile: bare in-article tables become their own horizontal scroll box
   (instead of overflowing the page or being clipped by html overflow-x).
   Wrapped tables (.pvt/.osrm live inside overflow-x:auto divs) are excluded. */
@media(max-width:640px){.bwrap article table:not(.pvt):not(.osrm){display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;}}
.tbl-scroll>table th,.tbl-scroll>table td{white-space:normal;}
.tbl-hint{font-size:12px;color:var(--text-3);margin:6px 0 0;display:none;}
@media(max-width:760px){.tbl-hint{display:block;}}
@media(max-width:600px){
  .bwrap .tbl-scroll:has(table td[data-label]){overflow:visible;max-width:100%;-webkit-overflow-scrolling:auto;}
  .bwrap article table:has(td[data-label]):not(.pvt):not(.osrm),
  .bwrap .tbl-scroll>table:has(td[data-label]){display:block;width:100%;max-width:100%;min-width:0!important;overflow:visible;-webkit-overflow-scrolling:auto;}
}

/* ============ DEVELOPER TRACK-RECORD TIMELINE ============ */
/* Vertical, dated milestone list for developer profile pages.
   Only verified, sourced milestones belong here. Each row carries a
   source label; undated/claim-only history goes in .dev-tl-note, never
   as a fake dated milestone. Never imply reliability ("on time",
   "trusted") without evidence. */
.dev-tl{list-style:none;margin:16px 0 6px;padding:0;position:relative;}
.dev-tl::before{content:"";position:absolute;left:7px;top:6px;bottom:6px;width:2px;background:var(--line-soft);}
.dev-tl-item{position:relative;padding:0 0 18px 30px;}
.dev-tl-item:last-child{padding-bottom:0;}
.dev-tl-item::before{content:"";position:absolute;left:2px;top:5px;width:12px;height:12px;border-radius:50%;background:var(--bg-2);border:2px solid var(--gold);box-sizing:border-box;}
.dev-tl-item.is-current::before{background:var(--gold);}
.dev-tl-year{font-family:'Cormorant Garamond',Georgia,serif;font-size:17px;font-weight:600;color:var(--gold);line-height:1.2;}
.dev-tl-event{color:var(--text);font-size:14.5px;line-height:1.5;margin:2px 0 0;}
.dev-tl-src{display:block;font-size:11.5px;color:var(--text-3);margin-top:3px;}
.dev-tl-note{font-size:13px;color:var(--text-3);line-height:1.6;margin:8px 0 0;padding-left:2px;}
@media print{.dev-tl::before{background:#bbb!important;}.dev-tl-item::before{background:#fff!important;border-color:#888!important;}.dev-tl-item.is-current::before{background:#888!important;}.dev-tl-year{color:#000!important;}}

/* ============ ANCHOR SCROLL OFFSET (sticky mobile header) ============ */
/* On mobile the .bhead is position:sticky (see NAVIGATION block above,
   ~76px tall). Without a scroll offset, jumping to an in-page anchor
   (#reservation, #ownership, hub "choose your situation" links, etc.)
   lands the target heading UNDER the header. scroll-margin-top pushes
   the target down by header height + a small gap. Scoped to the mobile
   breakpoint where the header is actually sticky; desktop header is
   position:relative and needs no offset. */
@media(max-width:860px){
  article :is(h2,h3,h4)[id],
  main [id]{scroll-margin-top:88px;}
}

/* ============================================================
   12E - DOWNLOADABLE PDF / PRINT SUPPORT
   "Скачать PDF" triggers the browser Save-as-PDF of a
   print-optimised view of the live canonical page, so the file
   never goes stale (it is always generated from current data).
   ============================================================ */
.pdf-only{display:none;}
.pdf-actions{display:flex;flex-wrap:wrap;gap:10px;margin:16px 0;}
.pdf-btn{display:inline-flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600;color:var(--text);background:transparent;border:1px solid var(--gold);border-radius:2px;padding:10px 18px;cursor:pointer;}
.pdf-btn:hover{color:var(--gold);}
.pdf-meta{border:1px solid var(--line-soft);border-radius:10px;padding:14px 16px;margin:14px 0;font-size:12.5px;color:var(--text-2);line-height:1.5;}
.pdf-meta strong{color:var(--text);}

@media print{
  html,body{background:#fff !important;color:#111 !important;}
  .bhead,.nav-backdrop,.bnav,.burger,.head-burger,.bnav-tg,.bnav-wa,.scta,.pdf-actions,.srch-box,.anchor-row,.fav-drawer,.fav-btn,.fav-launcher,.nsc-w,.nsc-p,video,.brand-intro,form button,.cta-btn,.alt-link{display:none !important;}
  /* The email chip carries the actual address — print it as plain text, not a button. */
  .mail-chip{border:0 !important;background:none !important;padding:0 !important;color:#111 !important;min-height:0 !important;font-weight:400 !important;}
  .mail-chip::after{content:"" !important;}
  .cta,.related{border:0 !important;padding:0 !important;margin:10px 0 !important;}
  .bfoot{background:none !important;border:0 !important;margin-top:18px;}
  .bfoot .fcols{display:none !important;}
  .bfoot .disc{display:block !important;color:#333 !important;font-size:9.5px;}
  .bwrap,article,main{max-width:100% !important;margin:0 !important;padding:0 !important;}
  a{color:#111 !important;text-decoration:none !important;}
  a[href^="http"]::after{content:" (" attr(href) ")";font-size:9px;color:#666;word-break:break-all;}
  .pdf-only{display:block !important;}
  .pdf-meta{border:1px solid #bbb !important;color:#333 !important;}
  h1,h2,h3{color:#111 !important;page-break-after:avoid;}
  table,figure,.pdf-meta,.exp-contact{page-break-inside:avoid;}
  img{max-width:100% !important;}
  @page{margin:16mm 14mm;}
}

/* ============================================================
   12S.13B - ADAPTIVE ARTICLE MODULE LIBRARY (callouts)
   Emitted by the blog builder from :::key / :::note / :::warn /
   :::evidence blocks as <aside class="m-callout m-TYPE">. One
   restrained family: a coloured left rule + subtle tint, no loud
   badges. Density is the author's responsibility (use sparingly).
   ============================================================ */
.m-callout{border:1px solid var(--line-soft);border-left:3px solid var(--gold);border-radius:10px;padding:14px 16px;margin:18px 0;background:var(--bg-2);font-size:15px;line-height:1.6;}
.m-callout>p{margin:0;}
.m-callout>p+p{margin-top:10px;}
.m-callout a{font-weight:600;}
.m-key{border-left-color:var(--gold);}
.m-note{border-left-color:#5B9A86;}
.m-warn{border-left-color:#C6603E;background:rgba(198,96,62,.07);}
.m-evidence{border-left-color:var(--text-3);}
@media print{.m-callout{break-inside:avoid;background:none !important;border:1px solid #bbb !important;border-left:3px solid #888 !important;}}

/* ============================================================
   YouTube facade (assets/js/yt.js)

   Nothing here loads a video: this is the poster the reader taps, and it is
   the third use of the pattern already behind the project map and the gallery
   lightbox — markup that works as a link, upgraded on click.

   The poster is a LOCAL .webp (/assets/img/video/<id>.webp), not i.ytimg.com:
   that is what keeps img-src off Google's hosts. The play button below is
   drawn, not fetched, for the same reason. Google is contacted exactly once,
   by the reader who presses play.

   aspect-ratio on the shell reserves the box before the poster decodes, so
   neither the image nor the iframe replacing it can shift the page.
   ============================================================ */
.yt{margin:22px 0 24px;}
.yt-shell{position:relative;aspect-ratio:16/9;border-radius:12px;overflow:hidden;
  border:1px solid var(--line);background:var(--bg-2);}
.yt-a{display:block;position:absolute;inset:0;cursor:pointer;}
.yt-a:hover{text-decoration:none;}
/* The shell clips, so the global :focus-visible outline would be cut in half
   sitting on the edge. Pull it inside instead of turning it off. */
.yt-a:focus-visible{outline:2px solid var(--gold);outline-offset:-4px;border-radius:12px;}
.yt-a img{display:block;width:100%;height:100%;object-fit:cover;}
/* Scrim: YouTube titles are burned into most maxres thumbnails, and the chip
   and button below need to survive a pale frame either way. */
.yt-a::after{content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(4,12,10,.10) 0%,rgba(4,12,10,0) 38%,rgba(4,12,10,.42) 100%);
  transition:background .3s var(--ease,ease);}
.yt-a:hover::after{background:linear-gradient(180deg,rgba(4,12,10,.04) 0%,rgba(4,12,10,0) 44%,rgba(4,12,10,.34) 100%);}
/* The YouTube play button, drawn: 68x48 rounded rect + triangle. Red on hover
   is the convention and it is doing a job here — it names the destination
   before the reader commits to loading it. */
/* z-index: the scrim above is an ::after, i.e. the anchor's LAST child, so
   without this it would paint over the button and tint the chip. */
.yt-btn{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1;
  width:68px;height:48px;border-radius:14px;background:rgba(18,18,18,.78);
  display:flex;align-items:center;justify-content:center;pointer-events:none;
  transition:background .25s var(--ease,ease),transform .25s var(--ease,ease);}
.yt-btn svg{width:26px;height:26px;fill:#fff;margin-left:3px;}
.yt-a:hover .yt-btn,.yt-a:focus-visible .yt-btn{background:#f00;transform:translate(-50%,-50%) scale(1.06);}
@media (min-width:860px){.yt-btn{width:82px;height:58px;border-radius:16px;}.yt-btn svg{width:31px;height:31px;}}
/* Duration chip, bottom-right, as on a YouTube thumbnail. Static text from the
   JSON-LD duration — nothing queries an API for it. */
.yt-dur{position:absolute;right:9px;bottom:9px;z-index:1;pointer-events:none;
  font-size:12px;font-weight:600;line-height:1;color:#fff;font-variant-numeric:tabular-nums;
  background:rgba(0,0,0,.78);border-radius:4px;padding:4px 5px;letter-spacing:.02em;}
/* The iframe yt.js builds. Fills the reserved box; no border, no shift. */
.yt-f{position:absolute;inset:0;width:100%;height:100%;border:0;display:block;}
/* The anchor's accessible name is an aria-label, not a hidden span: it overrides
   the inner content outright, so a reader hears one clean "Смотреть видео «…», 25
   минут 14 секунд" instead of the poster's alt and the duration chip read back to
   back. The <img> keeps a descriptive alt for search and for a failed load. */
.yt-cap{font-size:13px;line-height:1.55;color:var(--text-3);margin:9px 2px 0;}
.yt-cap b{color:var(--text-2);font-weight:600;}
@media (prefers-reduced-motion:reduce){
  .yt-btn,.yt-a::after{transition:none;}
  .yt-a:hover .yt-btn,.yt-a:focus-visible .yt-btn{transform:translate(-50%,-50%);}
}
/* On paper a play button is a button that cannot be pressed — but the caption
   says what the video is, so that one stays. */
@media print{.yt-shell{display:none;}.yt-cap{color:#333;}}

/* ============================================================
   Comparison directory (.vsg-*) — build-hubs.js §4.9
   Added 2026-07-21. The cluster grew to 38 markets and the flat
   .hg-links pill row stopped being readable: 38 chips on the market
   hub, 37 on each of the 76 vs-pages. Own namespace on purpose —
   .hg-links is used by ~15 other blocks and must not change.
   Mobile-first: one column, cards at least 44px tall (touch target),
   two columns from 620px, three from 980px. No JS, no accordion.
   ============================================================ */
.vsg-groups{margin-top:14px;}
.vsg-g+.vsg-g{margin-top:22px;}
.vsg-h{font-size:13px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  color:var(--text-2);margin:0 0 10px;padding-bottom:7px;border-bottom:1px solid var(--line-soft);}
.vsg-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:8px;margin-top:12px;}
.vsg-g .vsg-grid{margin-top:0;}
.vsg-grid a{display:flex;align-items:center;gap:10px;min-height:44px;padding:9px 14px;
  border:1px solid var(--line-soft);border-radius:10px;
  font-size:14px;font-weight:600;line-height:1.35;color:var(--text);}
.vsg-grid a:hover{border-color:var(--gold);color:var(--gold);text-decoration:none;}
.vsg-ar{margin-left:auto;flex:0 0 auto;color:var(--text-3);}
.vsg-grid a:hover .vsg-ar{color:var(--gold);}
.vsg-more{margin:14px 0 0;font-size:14px;font-weight:600;}
.vsg-more a{display:inline-flex;align-items:center;min-height:44px;}
@media (min-width:620px){.vsg-grid{grid-template-columns:repeat(2,minmax(0,1fr));}}
@media (min-width:980px){.vsg-grid{grid-template-columns:repeat(3,minmax(0,1fr));}}
@media print{.vsg-grid a{border-color:#ccc;}.vsg-h{border-bottom-color:#ccc;}}
