/* EPIC-002: desktop profile data and low-height Home spacing extend the original adaptive-only layer below. */
/* ═══════════════════════════════════════════════════════════════════════════
   components/home.responsive.css — r88 (owner-approved mockups v10, D-01…D-18).
   ADDITIVE layer for Home only. Every rule sits inside max-width:1023.98px
   media queries: the desktop render stays byte-identical (D-01). Hand-authored
   (not build-r38 output); linked after bundles/home.css on index.html and the
   es/ + it/ mirrors. Copy variants live in components/bl-responsive-copy.js;
   post-commit personalization in components/bl-phone-live.js (D-07/D-17).
   ═══════════════════════════════════════════════════════════════════════════ */

#blPhoneIdent{display:none} /* r88 base: inert outside the adaptive layer */

/* ============ SHARED <=1023 ============ */
@media (max-width:1023.98px){
  /* ── the ONE anchor every phone-relative offset derives from ───────────────
     The input bar is 44 px tall wherever it sits, so its offset is NOT a fixed
     share of the phone — it has to be measured. With the section's row-gap flat
     (14 px, below) both breakpoint branches collapse to ONE relation:
         bar top = 21.38%·H + 14.1 px      (H = phone height = --p × 1.8201)
     Least-squares over 12 widths, 320–1010 px, residual ≤0.05 px on every one —
     mobile 320/360/390/412/480/599 and tablet 620/700/768/850/924/1010.
     From that single line:
       --cut0/--cut  the image's fade, ending 30 px INSIDE the 44 px bar, so the
                     phone's termination is occluded rather than drawn;
       --cardtop     the forecast text, 12 px below the bar.
     They live HERE, once, on purpose. They were per-branch fits until r88's
     review round, and a later row-gap change moved the bar without moving them:
     at 924 px the fade crossed 2 px BELOW the bar and exposed a sliver of the
     phone — the same visible-cut defect the owner had already rejected. One
     anchor shared by both branches cannot drift out of sync with itself. */
  #statsBlock{--cut0:calc(21.4% + 30px);--cut:calc(21.4% + 44px);--cardtop:calc(21.4% + 70px)}
  /* r88 a11y (axe serious): the stat labels my layer surfaces at ≤1023 kept the
     desktop tint (≈3.2:1). Adaptive-only darkening to ≥4.5:1; desktop untouched.
     EXECUTOR FIX (r88): shipped outside the media query, so it also tinted the
     ≥1024 render and broke the round's own D-01 "desktop byte-stable" clause.
     Moved inside the adaptive layer; Self-test S8's grep still matches. */
  #statsBlock .bl-statnow__l, #statsBlock .bl-statbig__l{color:#5F5870}
  /* D-12 tiles — the reservation release belongs to the SHARED branch, because
     both reflows below need it: bundles/home.css reserves
     `.bl-defer--tiles{contain-intrinsic-size:auto 410px}`, a height measured for
     the DESKTOP 3-column grid, and r88 reflows that grid to 2 columns at
     ≥600px and to 1 column below it. No fixed length can be right for either —
     measured content is 507px at 924px, 540px at 600px and 1038px at 360px,
     since the reflow moves both the row count and the row heights. Reserving
     too little overlapped the next H2; too much snapped the page upward on
     first render. So this ONE below-fold section opts out of the skip entirely
     and takes its height from real content at every width. bundles/home.css is
     untouched: desktop keeps its skip, as do bl-marquee and bl-reviews.
     r109d — MOVED to the all-width release at the end of this file, together
     with .bl-reviews. The clause above ("desktop keeps its skip") is what came
     back to bite: the r109 type raise made the 410px desktop reservation wrong
     too, exactly as the 2-column one had been. Same lesson, wider scope. */
  /* D-03 — a QUIET mock profile, not a frosted feature (owner review, twice).
     First it was too weak: the band started at 18.6%, leaving the asset's baked
     row — "instagram_handle", 1,487 Posts / 898 Followers / 1,310 Following at
     8.2–18.6% — perfectly crisp, so the loudest numbers in the hero were the fake
     ones. Then it was too strong: blur(5px) over a 42% white veil turned the
     phone's screen into a bright frosted panel, which is itself an attention
     magnet — the opposite of the goal.
     What actually makes placeholder content recede is losing DETAIL and COLOUR
     while staying quiet in value: blur(2.5px) with saturate(.55) and a light 26%
     veil. The numbers are unreadable at a glance, nothing glows, and the eye goes
     to the one high-contrast element left — the input. Verified against the
     alternative of deleting the mock content: a blurred profile still says "your
     Instagram goes here", which is the mockup's whole job.
     The notch and status bar (0–7.4%) stay crisp so it still reads as a phone,
     and #blPhoneIdent paints ABOVE this band, so the visitor's own numbers are
     never affected. */
  /* The band starts at 8.5%, ABOVE the asset's red notification badge (measured
     y8.7–10.34%, x63.67–66.67%), and cuts a notch around the dynamic island
     (measured x44.36–64.63%, y1.98–10.14%) so the camera is never touched.
     Notch in the band's own coordinates: the band is x20.5–88.4% and starts at
     8.5%, so the island maps to 34.5%–65.0% horizontally, and 11% of the band's
     height clears 10.14% at every width --cut can produce (19–21% tall → the cut
     lands at 10.6–10.8%). */
  /* Starts at 10.2%, below everything the asset bakes into its status area, so
     the camera is the ASSET's own and can never be clipped or redrawn wrongly.
     The baked username and the red badge are no longer this band's problem: they
     are not in the image any more (D-19 below). */
  /* r90c — the default band used the vdom's own left/width (20.14% / 68.82%),
     which is 0.12% wider than the screen's measured straight edge on the left:
     ~1px of frost outside the bezel on this crop (owner screenshot 3). It now
     takes the SAME measured inset the live state already uses (20.5% / 67.9%),
     so both states sit inside the glass. Nothing else about the band changes. */
  .bl-phone>div[style*="backdrop-filter"]{top:10.2%!important;height:calc(var(--cut) - 10.2%)!important;
    left:20.5%!important;width:67.9%!important;
    border-radius:0!important;background:rgba(255,255,255,.26)!important;
    -webkit-backdrop-filter:blur(2.5px) saturate(.55)!important;
    backdrop-filter:blur(2.5px) saturate(.55)!important;
    -webkit-mask-image:linear-gradient(transparent 0,#000 10px);
    mask-image:linear-gradient(transparent 0,#000 10px)}
  /* D-04 — the phone slides BEHIND the input bar; it is not chopped off.
     Owner review: a fade that dies in open space reads as a broken image, and
     both earlier attempts did exactly that. 36/42% left the story-highlight
     circles' top arcs showing below the bar (the two grey stubs in the review
     shot); 30/33% was a FIXED percentage, and the bar's own offset is not a
     fixed percentage — the bar is 44 px tall wherever it sits, so as the phone
     grows the bar covers a smaller share of it. Measured: the bar's bottom is at
     33.5% of the phone at 360 px but 31.1% at 1000 px, so one hard-coded 33%
     fade is inside the bar on a small phone and 8 px BELOW it on a large one —
     which is the stub the owner circled at tablet width.
     So the cut is now anchored to the bar itself: --cut is per-branch
     `<a>% + <b>px`, fitted to the measured bar geometry (mobile bar top =
     22.22%·H + 13.4 px, tablet = 28.74%·H − 26 px, both r² ≈ 1 across the whole
     range each branch can produce), and set to land 30 px INTO the 44 px bar.
     The bar is opaque and always at least as wide as the phone from 360 px up,
     so the termination is occluded at every width instead of being drawn —
     nothing is visibly cut, and the story circles (ink resumes at 33.25%) are
     always below the line. Desktop is untouched and keeps the full device with
     its circles: that crop is wide enough for them to read as context.
     Purely visual — the <img> box is still 100% high, so no layout, negative
     margin or CTA offset moves. */
  /* D-19 (r90) — the baked Instagram header is REMOVED FROM THE PIXELS, not
     covered. Three rounds of band tops, clip-path notches, dark chips and a
     redrawn island all failed for the same reason, and it was not geometry: the
     numbers this layer was reasoning with were wrong. Re-scanned pixel by pixel
     on the asset itself (834×1518; ink boxes, not guesses):
         dynamic island, ink        x 365–544, y  73–124   (4.81%–8.17%)
         BAKED USERNAME, ink        x 352–519, y 136–157   (8.96%–10.34%)
         RED BADGE, ink             x 530–557, y 131–158   (8.63%–10.41%)
         story ring, ink starts     y 175      (11.53%)
         screen white               #FCFCFC
     The island's ink ends at 8.24% and the username's begins at 8.96% — 10 clear
     rows between them, and nothing overlaps anything. The "island ends at 10.14%,
     username starts at 10.08%, therefore unsolvable" reading was a measurement
     error; and it is why a band top of 10.2% (= y 155) looked like it should work
     while covering only the last two rows of a word that starts at y 136.
     So the fix is one image, not one more overlay: the same PNG with x 336–574,
     y 129–167 painted out in the screen's own #FCFCFC, saved as WebP (72 KB, 8 KB
     LIGHTER than the PNG it replaces on this breakpoint). The camera, the clock
     and the status icons are the asset's own pixels — untouched, because nothing
     is drawn over them. Swapped with `content:` so no markup changes: the <img>
     tag lives in generated output (bundles/home.bundle.js) and no build runs here.
     Desktop keeps the original file: this rule is inside the adaptive query, and
     the mock header is deliberate context at that size. url() resolves against
     THIS stylesheet, so /es/ and /it/ get the same file with no path lifting. */
  #statsBlock .bl-phone>img{content:url("assets/phone-screen-clean-834x1518.webp");
    -webkit-mask-image:linear-gradient(#000 var(--cut0),transparent var(--cut));
    mask-image:linear-gradient(#000 var(--cut0),transparent var(--cut))}
  /* D-05 — the icon circle belongs to the desktop card (D-17) */
  #blPhoneCard>div:first-of-type{display:none}
  /* D-05/D-18 — NO pink panel on the adaptive crop (owner review).
     On desktop this element is a card lying on the phone's screen, and its pale
     pink gradient reads correctly there. On the adaptive crop the phone ends at
     the bar, so the same gradient became a free-floating 52%-wide pink rectangle
     with hard edges, sitting directly behind a pink gradient CTA — a panel
     competing with the one control it is supposed to promote. It is now a plain
     transparent text block spanning the full width, anchored 12 px under the bar
     (--cardtop, fitted the same way as --cut), so the CTA's gradient is the only
     pink in the zone and the two lines centre on the same axis as the bar and
     the button. Fixed 46 px box: the CTA below FLOWS, so a px-stable text box is
     what keeps the rhythm identical at every width. */
  #blPhoneCard{left:0!important;width:100%!important;top:var(--cardtop)!important;
    height:auto!important;background:none!important;box-shadow:none!important;
    border-radius:0!important;-webkit-backdrop-filter:none!important;backdrop-filter:none!important}
  #blPhoneCard>div:last-of-type{position:static!important;left:auto!important;top:auto!important;
    width:100%!important;height:46px;display:flex;flex-direction:column;align-items:center;
    justify-content:center;gap:4px;font-size:0!important}
  #blPhoneCard #blPhoneL1{display:block;font-size:clamp(14px,1.9vw,16px)!important;
    font-weight:700;line-height:1.25;text-align:center}
  #blPhoneCard #blPhoneL2{display:block;min-height:0;font-size:clamp(13px,1.8vw,14px)!important;
    font-weight:500;line-height:1.45;margin-top:0;color:#3A3344;text-align:center}
  /* D-09 — pill badges duplicate on-screen claims on <=1023 */
  [data-bl-island="hero-pill"] .bl-pill-badges{display:none!important}
  /* owner review — the hero pill's controls were 30 px tall: below every touch
     minimum, and the reason the row read as cramped. 44 px, and the primary CTA
     is allowed to take the space it needs. */
  /* r109 — the 14px literal here beat the raised --fl-cta-txt token. These are
     the two above-the-fold controls on every phone; measured at 390 the pair
     needs ~305px of the 358 available at 16px, so the size was never the
     constraint — the literal was just older than the token. */
  [data-bl-island="hero-pill"] .bl-cta{min-height:44px!important;height:44px;
    font-size:var(--fl-cta-txt)!important;padding:0 16px!important;display:inline-flex;
    align-items:center;justify-content:center}

  /* forecast section: single-column stack (D-02, D-04) */
  #statsBlock{display:grid!important;grid-template-columns:100%!important;row-gap:14px!important}
  #statsBlock>div:first-child{display:contents}
  #statsBlock>div:first-child>h2{order:1;max-width:none!important;text-align:center;justify-self:center}
  /* translateX(-4.32%) — the DEVICE is not centred in its own asset (owner
     review: "the input sticks out further on the left"). Measured on
     phone-screen-834x1518.png: 124 px of transparent padding on the left against
     51 px on the right, so the device's centre sits at 54.32% of the image box.
     Centring the BOX therefore pushed the device 4.32% right, and the input bar —
     correctly centred, 14 px of overhang each side — read as lopsided against it.
     The transform re-centres the device itself; it does not touch layout, and the
     identity overlays are positioned inside this box so they travel with it.

     The whole negative margin now lives HERE (−0.786 = the old −0.435/−0.448 plus
     the wrapper's −0.351/−0.338) and the wrapper's own margin-top is 0. Same bar
     position, but the wrapper's grid row is no longer a negative margin box that
     the grid clamps to zero height — which is what left a dead band of empty page
     between the free-note and the forecast cards (measured 32 px at 390, 71 px at
     768) and pushed the forecast out of the first screen. */
  #statsBlock .bl-phone{order:2;justify-self:center;width:var(--p)!important;margin-top:8px;
    transform:translateX(-4.32%);
    margin-bottom:calc(var(--p)*1.8201*-0.786)}
  /* r90b — THE CTA GOES BELOW THE FORECAST on this crop (owner: "чтобы юзер сперва
     видел прогноз и ниже уже нажимал на кнопку продвижения"). #blForecastCta is not a
     forecast trigger — submitEstimate() is the funnel's front door (it commits the
     handle and navigates), so reading the numbers first and pressing it after is
     the right order on a small screen, and the black trial link below it becomes a
     second door to the same place.
     `order` only speaks to a grid's CHILDREN and the button is nested two wrappers
     deep, so the wrappers become display:contents and their contents join
     #statsBlock's grid directly. Same node, same handler, later row — nothing is
     duplicated and no JS moves anything. The pill takes over the z-index the
     wrapper carried: it is what has to paint above the phone's negative margin. */
  #statsBlock>div:first-child>div[style*="margin-top:40px"],
  #statsBlock>div:first-child>div[style*="margin-top: 40px"],
  #statsBlock>div:first-child>div[style*="margin-top:40px"]>div,
  #statsBlock>div:first-child>div[style*="margin-top: 40px"]>div,
  #statsBlock div:has(>[data-bl-orbit="input"]){display:contents!important}
  /* Everything those two wrappers lift becomes a grid ITEM, and an item with no
     `order` sorts to 0 — ahead of the H2. Measured after the first attempt: the
     suggestions island and the inline field error both jumped to the top of the
     section. So every lifted node defaults to the field's own slot, in :where()
     so it carries zero specificity and each named rule below still wins. */
  :where(#statsBlock>div:first-child>div[style*="margin-top:40px"])>*,
  :where(#statsBlock>div:first-child>div[style*="margin-top: 40px"])>*,
  :where(#statsBlock>div:first-child>div[style*="margin-top:40px"]>div)>*,
  :where(#statsBlock>div:first-child>div[style*="margin-top: 40px"]>div)>*,
  :where(#statsBlock div:has(>[data-bl-orbit="input"]))>*{
    order:4;justify-self:center;width:var(--bw);max-width:100%}
  [data-bl-orbit="input"]{order:3;position:relative;z-index:5;justify-self:center;
    width:var(--bw)!important;flex:1 1 100%!important}
  [data-bl-orbit="input"] input{font-size:16px!important}
  /* r90 — THE NOTE MUST BE ABOVE THE PHONE, AND ALONE UNDER THE FIELD.
     Two defects from the owner's 403 screenshots, one cause each:
     · the retention note's own buttons were not clickable — measured
       elementFromPoint at both button centres returned the phone's <img>. The
       phone carries translateX(), which puts it in the positioned paint layer,
       so it covers any STATIC sibling that follows it however far down the
       column. The field wrapper already had this fix (z-index:5 above); the
       note needs the same, one step higher so it also clears the field.
     · the note printed straight through the phone's forecast hint (measured
       overlap: note 377–606, hint 375–421). The hint is absolutely positioned
       under the bar and cannot move, so while there IS something to say the
       marketing line stands down — the same opacity dance the live state uses. */
  #blApiNote{order:4;justify-self:center;width:var(--bw);position:relative;z-index:6}
  #statsBlock:has(#blApiNote:not(:empty)) #blPhoneCard{opacity:0;pointer-events:none}
  /* r90b — THE CARD UNDER THE BAR IS THE IDLE HINT, NEVER AN IDENTITY.
     Two owner screenshots, one cause: bl-suggest writes the committed handle into
     #blPhoneL1, and the card only fades when `.is-live` lands — a demo delay
     later — so the login sat under the field for ~2s (screenshot 1); the same
     node also printed its dark hint through the field-error box (screenshot 8).
     One state test settles both, and keeps the hint the owner wants on this crop:
     the hint exists exactly while the field is EMPTY, which is when its own
     words ("type your @username") are true. Desktop keeps the card and its
     identity paint — this whole block is ≤1023.98px. */
  #statsBlock:has([data-bl-orbit="input"] input:not(:placeholder-shown)) #blPhoneCard,
  #statsBlock:has(.bl-ferr.is-on) #blPhoneCard{opacity:0!important;pointer-events:none}
  /* r90b — the award wall: five 120px badges in one nowrap flex row with a 40px
     gap cannot fit a phone, so they were squeezed to unreadable slivers (owner
     screenshot 4). A wrapping wall with equal thirds reads as a deliberate 3+2
     block — the second row centres itself, which is why this is flex and not a
     grid.
     r109 — the WRAP was right; the SIZE was the defect the owner is pointing at.
     Each badge is a 120x56 SVG carrying two lines of type inside it ("Capterra /
     Shortlist 2026"), and max-height:42px (38px below 600) forced
     object-fit:contain to letterbox it: a 171px-wide box drew a 90px logo with
     41px of dead air on either side, and the caption stayed at ~6px. The cap is
     lifted and aspect-ratio now governs the box, so the badge fills the share of
     the row the flex basis already gave it. Opacity goes to 1: at this size the
     caption is meant to be READ, and .9 kept it under 4.5:1. */
  div:has(>img[src*="award-"]){display:flex;flex-wrap:wrap;justify-content:center;
    align-items:center;gap:clamp(14px,2.6vw,22px)!important;margin-top:clamp(22px,3vw,32px)!important;opacity:1!important}
  div:has(>img[src*="award-"])>img{flex:0 0 calc(33.333% - 12px);width:auto!important;
    height:auto!important;max-width:180px;max-height:none!important;
    aspect-ratio:120/56;object-fit:contain}
  /* r109e — the section label moved OUT of this media query to the all-width
     block at the end of the file: the owner's desktop screenshot carries the
     same complaint, and one owner beats two. */
  /* r90c — THE MEGAPHONE IS AN EASTER EGG THAT PAYS (five presses open the 10%
     offer), so on the crop where it wrapped onto its own line under the CTA it
     read as a stray sticker (owner screenshot 5) and nobody would press it. It
     stays in the CTA's row instead: the row stops wrapping, the button takes the
     space it needs and the megaphone sits right beside it, which is both the
     most-looked-at point of the section and where its hearts should fly from.
     Desktop already has exactly this arrangement — same markup, same row. */
  #root div:has(>#megaZone){flex-wrap:nowrap!important;gap:12px!important;align-items:center}
  #root div:has(>#megaZone)>a.bl-cta{flex:1 1 auto;min-width:0}
  #megaZone{flex:0 0 clamp(56px,15vw,88px)!important;width:clamp(56px,15vw,88px)!important;
    align-self:center;margin:0!important}
  /* The suggestions panel is mounted in an absolutely-positioned box whose
     containing block WAS the field wrapper — the very wrapper this layer
     dissolves, which left the menu pinned to the top-left of the hero (measured:
     233px above the field, 97px to its left). Rather than invent a new anchor,
     the mount becomes a grid item in its own right, directly under the field: it
     cannot be mis-anchored, it cannot be clipped by the phone above it, and it
     collapses again the moment a row is picked. Inline styles set position, top,
     left and width, so each one is overridden explicitly. */
  #statsBlock div:has(>.bl-sugpanel){position:static!important;top:auto!important;
    left:auto!important;right:auto!important;width:var(--bw)!important;max-width:100%;
    order:4;justify-self:center;margin-top:0}
  /* D-06 — the CTA and the free-note FLOW under the bar (owner review: the
     spacing looked crooked). Both were absolutely positioned at a PERCENTAGE of
     the phone's height while being px-tall themselves, so the rhythm could not
     hold: measured at 300 px the 48 px CTA is 11.3% of the phone but only 8.0%
     at 442 px, which put the CTA's top 2.1% ABOVE the subtitle's baseline on one
     width (a real overlap) and left a 27 px hole on another. In flow they cannot
     collide by construction, and every gap is a px: bar → 12 → text(46) → 16 →
     CTA(48) → 12 → note. The 64 px margin plus the row's own 10 px row-gap is
     that 16 px gap; auto side margins keep the button centred. */
  /* r109e — THE BUTTON WAS NOT CLICKABLE BELOW 1024, and this file already wrote
     the diagnosis for it 70 lines up: «the phone carries translateX(), which puts
     it in the positioned paint layer, so it covers any STATIC sibling that
     follows it however far down the column». The phone also carries a large
     NEGATIVE bottom margin (line ~196), which is what pulls the rest of the
     column up underneath it. Two siblings were given the remedy — the field
     wrapper (z-index:5) and #blApiNote (z-index:6) — and this one, the funnel's
     front door, was left position:static with no z-index. So the press landed on
     the phone image and nothing happened; on desktop the CTA is positioned, so
     it always worked — exactly the difference the owner reports.
     position:relative with all four offsets already auto changes no geometry; it
     only creates the paint layer its own sibling above it already has. */
  #blForecastCta{position:relative;left:auto;right:auto;top:auto;transform:none;order:7;
    z-index:7;
    justify-self:center;margin:2px auto 0;min-height:48px;font-size:var(--fl-cta-txt)!important;
    padding:4px 26px!important;white-space:nowrap;width:max-content;max-width:92%}
  /* live state: the 46 px text box above is hidden (D-07 hands the stage to the
     phone's own identity), so the reserved space became a 74 px hole between the
     field and the button — the owner's "громадные отступы". It collapses to a
     24 px gap the moment an identity paints, transitioned so the button glides
     rather than jumps under the thumb. `:has()` rather than a sibling combinator:
     the form wrapper PRECEDES the phone in the DOM (r88 reorders them visually
     with `order`), so `~` never matched — measured, the gap stayed 74 px. `:has`
     is already used in this file, so support is not a new assumption. */
  #statsBlock:has(.bl-phone.is-live) #blForecastCta{margin-top:2px}
  #statsBlock>div:first-child>div[style*="margin-top:40px"]>div>div[style*="margin-top:12px"],
  #statsBlock>div:first-child>div[style*="margin-top: 40px"]>div>div[style*="margin-top: 12px"]{
    order:8;position:static;margin:10px 0 0!important;text-align:center;
    /* r110f — 12px for the line that answers «what does pressing this cost me?»
       («Free — no password needed. Starts in 24h.»). It sits directly under the
       funnel's front door, so it is read at the moment of deciding — the last
       sub-14px string left on this page's critical path. */
    font-size:var(--fl-t14)!important}
  /* the phone's own forecast hint (#blPhoneCard) is absolutely positioned 12px
     under the bar and is 46px tall. With the CTA out of that slot the forecast
     row moved up underneath it, so the row reserves the band — and gives it back
     the moment an identity lands, because the hint is opacity:0 in the live state
     (same dance the CTA used to do, same easing). */
  #statsBlock .bl-statrow{order:5;position:relative;z-index:2;
    margin-top:40px!important;transition:margin-top .35s ease}
  #statsBlock:has(.bl-phone.is-live) .bl-statrow{margin-top:0!important}
  #statsBlock #blStatLive{order:6}
  /* the black "Start 7-day free trial" link is the same door as the CTA above it,
     and on this crop it now sits directly under it (owner crossed it out on the
     review shot). One call to action per screen. */
  #statsBlock>div:first-child>div[style*="margin-top:48px"],
  #statsBlock>div:first-child>div[style*="margin-top: 48px"]{display:none!important}

  /* D-07 — live state: card yields the stage, blur dismissed on the compositor */
  #blPhoneIdent{position:absolute;inset:0;display:none;pointer-events:none}
  .bl-phone.is-live #blPhoneIdent{display:block}
  .bl-phone.is-live #blPhoneCard{opacity:0;transition:opacity .4s ease-out}
  /* r89d — in the LIVE state this band is OPAQUE, not frosted. Two reasons, both
     measured: a 93%-white frost still let the baked "instagram_handle" read
     through under our own handle (owner review), and backdrop-filter is the most
     expensive thing on this screen — it forces a composited layer and re-samples
     the backdrop on every paint. Going opaque in the state that needs the
     coverage removes both problems at once: the baked header is gone, and the
     filter stops running exactly when the phone is busiest, which is the right
     trade for Web Vitals. The default state keeps the light frost, which is what
     makes the mock profile recede without erasing it.
     It cannot leak past the bezel: this is the ASSET's own element, positioned by
     the page's vdom, and its box IS the screen (measured x20.1–89.0%). */
  .bl-phone.is-live>div[style*="backdrop-filter"]{opacity:1!important;
    background:#FFF!important;
    /* the screen's straight edges are x20.26%–88.61% (measured off the asset at
       every height from 9% down); the band's own inline box is 20.14–88.96%, so it
       overhung the bezel on BOTH sides and butted hard against it — which is what
       read as a white plug climbing onto the phone's left edge. Inset just inside
       the glass, and rounded at the top so it follows the screen's corner instead
       of squaring it off. */
    left:20.5%!important;width:67.9%!important;
    border-top-left-radius:10px!important;border-top-right-radius:10px!important;
    -webkit-backdrop-filter:none!important;backdrop-filter:none!important;
    -webkit-mask-image:none;mask-image:none}
  /* the asset's story ring sits inside that opaque band, so the live state draws
     its own: one conic gradient around the avatar — generic geometry, not a copy
     of anyone's artwork, and no extra request. */
  .bl-phone.is-live #blIdRing{background:conic-gradient(from 210deg,#F58529,#DD2A7B,#8134AF,#515BD4,#F58529);
    padding:2px;box-sizing:border-box}
  .bl-phone.is-live::after{content:"";position:absolute;top:0;bottom:58%;left:-30%;width:34%;
    background:linear-gradient(105deg,transparent 0,rgba(255,255,255,.65) 50%,transparent 100%);
    transform:translateX(-100%);animation:blSheen .8s ease-out 1 both;pointer-events:none}
  /* the sheen is a desktop flourish and stays there. On the adaptive crop it
     parked a pale vertical band across the phone's left edge after a handle was
     committed (owner review, screenshot 1): the element is 34% wide at left:-30%
     with `animation-fill-mode:both`, so whichever keyframe it holds is painted
     permanently over a phone that is now only 30% tall. A one-off gleam is not
     worth a permanent artefact next to the visitor's own numbers. */
  .bl-phone.is-live::after{display:none!important}
  @media (prefers-reduced-motion:reduce){
    .bl-phone.is-live::after{animation:none;display:none}
    .bl-phone.is-live #blPhoneCard,.bl-phone.is-live>div[style*="backdrop-filter"]{transition:none}
  }
  /* ── the identity header, drawn as VECTOR over the asset ──────────────────
     Every number below is measured off components/assets/phone-screen-834x1518.png
     (834×1518, ratio 1.8201), not guessed: the baked story ring sits at L21.7%
     W16.4% with its centre at y16.3%, and the baked "handle / 1,487 Posts · 898
     Followers · 1,310 Following" block occupies x40–82%, y8.2–18.6%.
     Two things were wrong before: the avatar box (L11.3% W26.2%) was far larger
     than the ring and offset left, so the ring's pale interior and gradient arc
     showed around it; and a single chip was laid over the MIDDLE baked number,
     at a different size and baseline than the two baked ones either side — which
     is what read as crooked. Aligning DOM to baked pixels can only ever be
     approximately right, so the baked block is patched out and redrawn in real
     text instead. Type scales off --p, the phone's own width, so it stays
     proportional at every width instead of tracking the viewport. */
  /* The patch sits BETWEEN the asset's story ring and the screen's right edge, so
     the ring's gradient arc stays the asset's own (no brand artwork is redrawn).
     Its left and bottom edges are masked to nothing: a hard-edged opaque
     rectangle read as a pasted white box against the blur band that starts at
     18.6%, and softening the two edges that meet content is what makes it read
     as the phone's own header instead.
     The bottom fade starts at 89%, not 78%: the asset's baked label row
     ("Posts / Followers / Following") sits at 16.6-17.4%, which fell inside the
     old fade and bled through underneath the vector labels. 89% of the patch's
     11.4% height puts the first transparent pixel at 17.8% — below the baked
     labels, above the blur band. */
  /* r89d — NO white rectangles over the asset. The three patch bands were laid out
     in the phone's BOX coordinates, but that box carries the asset's transparent
     padding (124 px left, 51 px right of 834) and this layer also shifts it with
     translateX(-4.32%): the bands stuck out past the bezel as white slabs and
     broke the device (owner review). Percentages of a box whose art is inset can
     never be trusted for opaque fills.
     The fix is to stop introducing geometry and reuse the ONE element that is
     already inset to the screen correctly — the asset's own frosted band, whose
     box comes from the page's vdom. In the live state it is simply not dismissed:
     it stays, denser, and the baked header is frosted rather than erased, while
     our crisp handle and numbers paint above it. Nothing can leak outside the
     phone because nothing new is positioned. */
  /* the 51 px of blank white under the numbers is exactly where Instagram shows the
     display name, so it is FILLED rather than trimmed: the retired patch span is
     reused as that line (no markup change), fed from the same account record. */
  /* The usable zone ends at the input BAR, not at the band. The bar's top is the
     same anchor this layer already fitted (21.38%·H + 14.1px ≈ 23.2%), and the
     wrapper carries z-index:5 while #blPhoneIdent is z-index:auto — so a line
     placed by the band's bottom alone had its lower third sliced off by the opaque
     white pill. Between the ring's bottom (20.53%) and the bar there are ~2.7%
     ≈ 21px: the line sits at 20.95% with a 2.2% box, ending near 22.9%, clear of
     the bar. The 11px floor buys the last pixel. */
  /* the badge overlaps the island's bottom-right corner, so the part inside the
     notch cannot be reached by the band. It is covered with the island's OWN
     colour (sampled from the asset: rgb(9,10,10)) rather than white, so the pill's
     silhouette stays unbroken. Both states, hence .bl-phone and not #blPhoneIdent. */
  #blIdPatch{position:absolute;left:22.2%;width:66%;top:20.95%;height:2.1%;
    display:flex;align-items:center;
    font-size:max(11px,calc(var(--p)*0.030));font-weight:600;line-height:1.1;
    color:#160E28;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* The handle is BACK inside the phone, but where Instagram actually puts it:
     the profile screen's nav title, centred at the top of the screen — which is
     also exactly where the asset bakes "instagram_handle". It was removed in the
     previous round as a duplicate of the input; the owner's call is that the
     phone should read like a real Instagram profile, and a profile without its
     username does not. The verified badge sits inline right after it, the way
     Instagram shows it, and comes from the shared badge owner
     (components/bl-verified.js → env VERIFIED.ICON) — never a second icon.
     Geometry is measured, not guessed: the asset's dynamic island (camera
     included) runs to 9.95% of the phone's height and the baked username ink
     starts at 10.08%, so everything this layer paints starts at 10% — the island
     stays whole, which it was not while the blur began at 7.4%. */
  /* ONE axis for the header's text column. The handle used to centre on the screen
     (left:20%;width:66%) while the numbers centred at 62.75% of the phone — 41 px
     apart, which is the "кривизна" the owner kept pointing at. Both now share the
     stats block's box, so the username sits directly above its own numbers and the
     avatar reads as the left column of a two-column header.
     Vertically the pair is centred on the RING (centre 16.3%): handle 12.1–14.7%,
     numbers from 15.9%, group centre ≈16.3% — the alignment Instagram uses.
     Type has a px FLOOR: --p can fall to 294 px at a 390 px viewport, where the old
     multiplier gave 11.5 px values and 7.9 px labels. */
  /* r90 — THE HANDLE IS THE NAV TITLE (owner review: "логин инстаграмма — верно ли
     располагается? кажется плохие отступы"). It used to sit at 12.65%, on the stats
     block's axis, because the asset's baked "instagram_handle" occupied the nav slot
     and the only free room was beside the ring. r90 erased that ink, so the slot the
     username belongs in — the profile screen's centred nav title, x 20.5–88.4%,
     y 8.7–11.6%, between the island (ends 8.17%) and the story ring (starts 12.07%) —
     is now empty, and this is what Instagram itself does. Two things follow: the
     handle stops competing with the numbers for one optical axis, and the counts can
     centre on the AVATAR (below) the way a real profile header does.
     The verified badge stays inline right after it, from the shared badge owner
     (components/bl-verified.js → env VERIFIED.ICON) — never a second icon. */
  #blIdHandle{position:absolute;left:20.5%;width:67.9%;top:8.7%;height:2.9%;
    display:flex;align-items:center;justify-content:center;gap:.34em;
    font-size:max(13px,calc(var(--p)*0.040));font-weight:600;line-height:1;color:#160E28;
    white-space:nowrap;overflow:hidden}
  #blIdHandle [data-bl-verified]{position:static;flex:0 0 auto;
    width:calc(var(--p)*0.040);height:calc(var(--p)*0.040)}
  /* the asset also bakes a "Name / Bio" placeholder under the avatar. It sits
     inside the frosted band's range (10% → --cut), so the band handles it in both
     states — no extra element, nothing to leak. */
  /* the avatar fills the asset's ring exactly: interior = ring inset by its own
     ~0.5% stroke, so the gradient arc stays visible and nothing haloes */
  #blIdRing{position:absolute;left:22.2%;top:12.07%;width:15.4%;aspect-ratio:1;
    border-radius:50%;overflow:hidden;background:#EFEBF3}
  #blIdRing img{width:100%;height:100%;object-fit:cover;object-position:center;display:block;
    border-radius:50%}
  /* The stats take the whole width between the ring and the screen edge — the
     asset's baked trio was crammed into x43–79% because its own type was ~5px
     tall; real text needs the room, and at 42% the labels truncated to
     "Follow… / Engag…". Type scales off --p so the whole block stays
     proportional to the phone at every width. */
  /* the block takes every pixel between the ring (right edge 37.6%) and the band's
     inner edge (88.39%), with no column gap: at a 390 px viewport "Followers" and
     "Following" at the 11 px floor need ~50 px and were clipping in 44.7 px
     columns. Equal thirds of 49.9% give 50.6 px, and −0.02em tracking covers the
     last hair. Widening beats shrinking: the floor is what keeps them readable. */
  /* r90 — the counts now CENTRE ON THE AVATAR (ring centre 16.30%), which is the
     alignment a profile header uses, and which only became possible when the handle
     moved to the nav slot above. Measured: the block is 29px tall at H=535, so
     top 13.6% puts its centre at 16.3%. */
  #blIdStats{position:absolute;left:38.4%;width:49.9%;top:13.95%;
    display:grid;grid-template-columns:repeat(3,1fr);align-items:start;gap:0}
  #blIdStats>span{display:flex;flex-direction:column;align-items:center;
    gap:calc(var(--p)*0.005);min-width:0}
  #blIdStats b{font-weight:700;font-size:max(15px,calc(var(--p)*0.042));line-height:1.05;
    letter-spacing:-0.015em;color:#160E28;white-space:nowrap;padding:0 2px;
    max-width:100%;overflow:hidden;text-overflow:ellipsis;
    font-variant-numeric:tabular-nums}
  #blIdStats i{font-style:normal;font-weight:400;font-size:max(11px,calc(var(--p)*0.030));
    line-height:1.1;letter-spacing:-0.02em;color:#3A3344;white-space:nowrap;
    max-width:100%;overflow:hidden;text-overflow:ellipsis}
  /* r90 — LOADING STATE (owner review: "когда загружается новый аккаунт нет скелетона").
     The shimmer itself is the site's ONE skeleton system, `.sk` in bundles/shared.css,
     put on and taken off by bl-phone-live.js; these rules only give the three empty
     nodes a BOX, because `.sk` on an element with no content has no size of its own.
     Nothing here paints unless that module added the class, so the committed state is
     untouched. */
  #blIdStats b.sk{display:block;width:74%;margin:0 auto;
    height:max(15px,calc(var(--p)*0.042));border-radius:5px;padding:0}
  #blIdPatch.sk{width:42%;height:max(11px,calc(var(--p)*0.030));border-radius:5px}
  #blIdRing.sk{background:#EFEBF3}
  /* the conic story ring is the LIVE identity's frame; while the photo is still a
     skeleton it would read as a finished avatar, so it waits for the data too. */
  .bl-phone.is-live #blIdRing.sk{background:#EFEBF3;padding:0}
}

/* ============ TABLET 600–1023 ============ */
@media (max-width:1023.98px) and (min-width:600px){
  /* --p only: the geometry anchor is shared, see the top of the <=1023 block */
  #statsBlock{--p:clamp(340px,46vw,432px);--bw:calc(var(--p)*1.08)}
  #statsBlock .bl-statrow{width:100%;max-width:860px;justify-self:center}
  #statsBlock>div:first-child>div[style*="margin-top:48px"],
  #statsBlock>div:first-child>div[style*="margin-top: 48px"]{display:flex;justify-content:center}
  .bl-defer--tiles>div{grid-template-columns:repeat(2,1fr)!important}
}

/* ============ MOBILE <=599 ============ */
@media (max-width:599.98px){
  :root{--fl-inset:16px;--fl-hero-pad:clamp(16px,5vw,24px);
    --fl-heromark:clamp(26px,7.5vw,34px);--fl-sec:56px}
  /* bar top = 22.22%·H + 13.4 px on this branch (phone 454–601 px tall).
     --p is additionally capped at 100vw − 96px so the phone is never WIDER than
     the input bar: the bar is what occludes the phone's termination, and below
     395 px the old min(78vw,330px) made the phone 8 px wider than the bar, which
     left a 4 px sliver of the cut visible down each side — the same stub defect
     in miniature. Measured: 360 px → phone 264 vs bar 273. */
  #statsBlock{--p:min(78vw,calc(100vw - 96px),330px);--bw:100%}
  #statsBlock .bl-phone{margin-bottom:calc(var(--p)*1.8201*-0.786)!important}
  /* r112 — THE FORCED TWO-ROW PILL IS GONE (owner: the mobile header is crooked).
     r109x retired the forced stack site-wide and put the pill back on progressive
     degradation: one row that sheds badges, then Login, keeping the primary action.
     That retirement never reached HOME, because this copy is scoped to
     [data-bl-island="hero-pill"] instead of .bl-pill, so components/site.responsive.css
     could not overwrite it. Measured before removal, 360-532px: home pill 120-123px
     tall in two full-width rows with the dark CTA stretched to 248-408px at 15.0px,
     while pricing at the same widths is one 60px row with a 126px CTA at 14px — the
     same component, two behaviours, and the stretched CTA is what draws over the
     lockup. Removing the block hands Home the shared behaviour; nothing is added. */
  /* the scroll-in bar keeps ONE row and one job: brand + the primary action.
     Its "Pricing" link is the only item that can go — the same link sits in the
     footer of every page, and a 133 px two-row fixed bar on a 360 px phone costs
     more than it carries. */
  .bl-sticky>div{flex-wrap:nowrap;gap:8px;padding:8px 12px!important;min-height:0!important}
  .bl-sticky .bl-stickynav{display:none}
  /* r90c — the scroll-in bar overflowed the screen in every locale (owner
     screenshot 4): logo + Login + a 34-character trial CTA cannot share 360px.
     Login goes: it is the one control here that sells nothing (the same link
     sits in the footer and in the hero pill), and the bar's whole job is the
     primary action. The CTA then takes what is left and carries the compact
     label bl-responsive-copy swaps in below 600px. */
  .bl-sticky .bl-cta--ghost{display:none}
  .bl-sticky>div{justify-content:space-between}
  .bl-sticky .bl-cta--dark{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis}
  .bl-sticky .bl-logo-lockup{width:112px;height:auto}
  /* r109c — the sticky-bar button rule lives in components/site.responsive.css
     ONLY (search "r109c"). A twin here lost the cascade to it and made the
     button look unreachable; one owner, in the file that wins. */
  /* r109i — margin-top MOVED to the single ≤1023 owner at the end of this file.
     It was dead here: both rules are (0,1,1) with !important, and the appended
     one wins on source order, so the phone silently got 32px. Only font-size
     stays in this branch. */
  #root h1{font-size:clamp(27px,8.4vw,36px)!important}
  #root h1+div p{max-width:none!important}
  [data-bl-island="hero-pill"]{min-height:0!important}
  /* r109 — two up; the cap that squeezed it is gone with the <=1023 one above */
  div:has(>img[src*="award-"])>img{flex:0 0 calc(50% - 9px);max-width:190px}
  [data-bl-island="hero-pill"]>*{flex-wrap:wrap!important;height:auto!important;min-height:0!important;row-gap:6px;justify-content:center}
  .bl-trust{flex-wrap:wrap;min-height:0;padding-top:8px;padding-bottom:8px;border-radius:24px;row-gap:6px}
  /* D-12 — unified compact forecast panel */
  #statsBlock .bl-statrow{display:grid!important;grid-template-columns:1fr;gap:10px;
    background:#FFF;border:1px solid #F3D9EC;border-radius:20px;padding:14px;
    box-shadow:0 10px 30px rgba(219,97,221,.10)}
  #statsBlock .bl-statcol{display:grid!important;grid-template-columns:1fr;row-gap:8px;
    padding:10px 12px!important;text-align:left}
  #statsBlock .bl-statcol__h{text-align:left;font-size:13.5px!important}
  #statsBlock .bl-statstack{display:grid!important;grid-template-columns:1fr 1fr;gap:8px}
  #statsBlock .bl-statnow{min-height:48px;justify-content:flex-start;padding:0 10px}
  #statsBlock .bl-statbig{min-height:48px;padding:8px 10px!important;gap:4px}
  #statsBlock .bl-statbig__v{font-size:clamp(17px,5.2vw,21px)!important}
  #statsBlock>div:first-child>div[style*="margin-top:48px"] .bl-cta,
  #statsBlock>div:first-child>div[style*="margin-top: 48px"] .bl-cta{width:100%}
  /* r109h — the AI card gets the treatment the feature tiles already got: the
     56px mark and the "OUR AI ENGINE" eyebrow share row one, the headline and
     the paragraph take the full card width below. Stacking them cost a whole row
     to a 26px-tall badge and pushed the headline down the card.
     The badge is not a sibling of the mark — it lives inside the text column —
     so that column becomes display:contents and its children join this grid
     directly. Nothing moves in the DOM: same nodes, same #aiCardMark listener,
     so the easter egg still fires. */
  div:has(>#aiCardMark){display:grid!important;flex-direction:row;
    grid-template-columns:auto minmax(0,1fr);
    column-gap:clamp(10px,2.6vw,14px)!important;row-gap:0!important;
    align-items:center!important}
  div:has(>#aiCardMark)>#aiCardMark{grid-area:1/1;align-self:center}
  div:has(>#aiCardMark)>div{display:contents}
  div:has(>#aiCardMark)>div>*{grid-column:1/-1}
  div:has(>#aiCardMark)>div>div:first-child{grid-area:1/2;justify-self:start}
  div:has(>#aiCardMark)>div>h2{margin-top:clamp(14px,3.4vw,20px)!important}
  /* one column → six rows; the skip opt-out comes from the ≤1023 block */
  .bl-defer--tiles>div{grid-template-columns:1fr!important}
  .bl-revslide{grid-template-columns:1fr!important}
  /* r109 — the awards wall is now sized and wrapped by the READABILITY block
     at the end of this file (one rule for the whole <=1023 range). */
  /* r109 — `html` prefix, and nothing else changes. Home is the one page with a
     DESIGNED phone footer (two columns, brand across the top). The site-wide
     adaptive layer now stands the r38.2 narrow-desktop footer grid down below
     600px (BUG-011: it pushed the Support column off a 390px screen), and that
     layer loads AFTER this file — at equal specificity it would have taken
     Home's two columns with it. One extra element in the selector settles the
     order question permanently instead of relying on load sequence. */
  html .bl-foot .bl-foot__cols{display:grid;grid-template-columns:1fr 1fr;gap:24px}
  html .bl-foot .bl-foot__brand{grid-column:1/-1;grid-row:auto}
}
@media (max-width:359.98px){
  #root h1{font-size:25px!important}
  #statsBlock .bl-statstack{grid-template-columns:1fr}
  /* the field's own font-size stays 16px (anything smaller makes iOS zoom the
     page on focus); only the PLACEHOLDER shrinks, and only here — measured at
     320 px the sentence needs 180 px against 177 px of room, so it would clip by
     three pixels. ::placeholder is not part of the accname or the typed text. */
  [data-bl-orbit="input"] input::placeholder{font-size:14px}
}


/* ═══════════════════════════════════════════════════════════════════════════
   r109 — HOME READABILITY PASS (owner: «шрифты мелковаты, порой еле читаемы»)
   Home only, appended last so it wins over bundles/home.css without editing a
   single generated file. Nothing is re-laid-out except the two blocks the owner
   named: the feature tiles and the awards wall.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1. THE TYPE LADDER ────────────────────────────────────────────────────
   THE ACTUAL DEFECT was never the maxima — 14/17/19 px at 1440 are fine. It
   was the SHAPE of the expression. Every step was clamp(min, N vw, max):

       --fl-t14: clamp(11px, 1vw, 14px)

   A pure-vw middle term collapses onto the FLOOR as soon as the viewport is
   narrow, and these floors were chosen to keep 1440 proportions rather than to
   stay readable. On a 390 px phone the page therefore rendered:

       card body 11px · card title 13.5px · «Rated & recognised» 11px
       footer legal 9.5px · CTA label 11.5px

   — which is what the owner is seeing. Two changes, both best practice:

   (a) FLOORS are raised to real minimums instead of scaled-down desktop ones.
       Body copy lands at 16px on a phone (Material body-1, iOS HIG, and the
       size below which Safari zooms a focused field); supporting copy >=13.5px;
       legal >=12px, the accepted floor for legally-required small print.
       Nothing on the page is below 11px any more.
   (b) The middle term gains a rem component (A rem + B vw). A pure-vw font size
       IGNORES the reader own browser font setting — a 200 % text-size
       preference does nothing at all, which fails WCAG 1.4.4 outright. With a
       rem term the ladder scales with the reader and stays fluid. For «не у
       всех хорошее зрение» this is the most important line of the pass: it is
       what lets a long-sighted visitor fix the page themselves.

   Maxima are unchanged to the pixel, so the >=1400 desktop render is identical;
   the ramp simply reaches them by ~1280 instead of ~1900. */
:root{
  --fl-t11: clamp(0.688rem, 0.664rem + 0.10vw, 0.75rem);      /* 11   -> 12   */
  --fl-t12: clamp(0.75rem,  0.727rem + 0.10vw, 0.813rem);     /* 12   -> 13   */
  --fl-t13: clamp(0.781rem, 0.746rem + 0.14vw, 0.875rem);     /* 12.5 -> 14   */
  --fl-t14: clamp(0.844rem, 0.798rem + 0.19vw, 0.969rem);     /* 13.5 -> 15.5 */
  --fl-t15: clamp(0.875rem, 0.817rem + 0.24vw, 1.031rem);     /* 14   -> 16.5 */
  --fl-t16: clamp(1rem,     0.965rem + 0.14vw, 1.094rem);     /* 16   -> 17.5 */
  --fl-t17: clamp(1rem,     0.942rem + 0.24vw, 1.156rem);     /* 16   -> 18.5 */
  --fl-t18: clamp(1.031rem, 0.962rem + 0.29vw, 1.219rem);     /* 16.5 -> 19.5 */
  --fl-t19: clamp(1.063rem, 0.969rem + 0.38vw, 1.313rem);     /* 17   -> 21   */
  --fl-t20: clamp(1.094rem, 0.989rem + 0.43vw, 1.375rem);     /* 17.5 -> 22   */
  --fl-t22: clamp(1.125rem, 0.986rem + 0.57vw, 1.5rem);       /* 18   -> 24   */
  --fl-t24: clamp(1.188rem, 1.025rem + 0.67vw, 1.625rem);     /* 19   -> 26   */
  --fl-t26: clamp(1.25rem,  1.064rem + 0.76vw, 1.75rem);      /* 20   -> 28   */
  --fl-t28: clamp(1.313rem, 1.104rem + 0.86vw, 1.875rem);     /* 21   -> 30   */
  --fl-t32: clamp(1.438rem, 1.182rem + 1.05vw, 2.125rem);     /* 23   -> 34   */
  /* r109b — THE MAXIMA, which the first pass deliberately froze «so the desktop
     render is identical». The owner's answer to that: desktop is small too. It
     was — 14px body copy and a 17px lead are the 2019 marketing-page scale;
     current practice for a SaaS landing page is 16-18px body with the lead a
     step above, because a desktop reader sits 60-70cm back, further than a phone
     reader. Raised one step (roughly +10%), no more: «НЕ ПЕРЕБОРЩИ» is the
     brief, so nothing gains a size class — 14→15.5, 17→18.5, 19→21, and the
     display steps move least because they were never the complaint.
     Floors are untouched, so every phone measurement already verified holds. */

  /* CONTROLS AND THE FIELD MOVE WITH THE TEXT, and they do it through the same
     two tokens — this is the part the previous pass left inconsistent (bigger
     labels in unchanged pills). The hero field is not a special case either:
     src/pages/home.static.gen.js gives its wrapper height:var(--fl-cta-h) and
     its <input> font-size:var(--fl-cta-txt), so the field, its placeholder, its
     typed text and every button on the page are one system. Raising the pair
     grows all of them together and keeps the field flush with the button beside
     it — which is why the owner saw the input text as smaller than the rest. */
  --fl-cta-txt:  clamp(1rem,     0.942rem + 0.24vw, 1.156rem);   /* 16 -> 18.5 */
  --fl-cta-txts: clamp(0.938rem, 0.884rem + 0.22vw, 1.063rem);   /* 15 -> 17   */
  --fl-cta-h:    clamp(48px, 4.2vw, 64px);                       /* 44/60 -> 48/64 */
  --fl-cta-hs:   clamp(44px, 3.4vw, 54px);                       /* 44/48 -> 44/54 */
  --fl-cta-pad:  clamp(16px, 1.95vw, 32px);                      /* 14/28 -> 16/32 */
  /* «место есть» — the feature icons were 20px on a phone against a 28px cap. */
  --fl-featico:  clamp(1.625rem, 1.393rem + 0.95vw, 2.25rem);    /* 26 -> 36 */
  /* r109g — the UI icon token, raised at the TOKEN and not at the element:
     bundles/shared.css already sets .bl-wapill img / .bl-tgpill img to
     var(--fl-uiico), so an !important copy of the same value changed nothing.
     18px was the floor until ~1372px, i.e. an 18px glyph inside a 44px pill
     beside a 16px label — the chat and Telegram icons ARE the control on those
     two, so they carry the same weight as the words. Lifts the SSL and
     money-back marks in the trust row by the same step. */
  --fl-uiico:    clamp(1.375rem, 1.293rem + 0.33vw, 1.625rem);   /* 18 -> 22-26 */
  --fl-uiico-sm: clamp(1.125rem, 1.043rem + 0.33vw, 1.313rem);   /* 14 -> 18-21 */
}

/* ── 2. FEATURE TILES — the icon and the title share the first line ─────────
   Owner screenshots 1 and 3: the icon sat alone on its own row with 18px of air
   under it, so the card real headline started a third of the way down and the
   eye had to hunt for it. Pairing the icon with the title turns the icon into a
   bullet for the heading it belongs to, recovers that vertical space, and pays
   for a larger title at no cost in card height.

   The tiles are inline-styled generated nodes with no class of their own, so
   the layer addresses them structurally and has to out-rank inline style.
   Nothing in the generated tree, the bundle, the prerendered shells or the
   frozen skeletons is touched. */
.bl-defer--tiles>div>div{
  display:grid;
  grid-template-columns:auto minmax(0,1fr);
  column-gap:clamp(11px,1.1vw,15px);
  align-items:center;
}
.bl-defer--tiles>div>div>img{grid-area:1/1}
.bl-defer--tiles>div>div>div:nth-of-type(1){
  grid-area:1/2;
  margin-top:0!important;
  font-size:var(--fl-t20)!important;   /* was t19: 13.5px on a phone -> 17.5px */
  line-height:1.25;
  text-wrap:balance;
}
.bl-defer--tiles>div>div>div:nth-of-type(2){
  grid-area:2/1/auto/-1;               /* full card width: the body reads as a
                                          paragraph, not as a narrow column
                                          indented past the icon */
  margin-top:clamp(12px,1.2vw,16px)!important;
  font-size:var(--fl-t16)!important;   /* was t14: 11px on a phone -> 16px */
  line-height:1.55!important;          /* WCAG 1.4.12 — body copy >=1.5 */
  text-wrap:pretty;
}

/* ── 3. AWARDS WALL — «улучши читаемость и АДАПТИВ» ─────────────────────────
   Fixed IN PLACE in the r90b block above (search "r109 — the WRAP was right"),
   not layered on top of it: a second rule set owning the same element would
   have left gap / margin / opacity / flex decided by source order alone, and
   the pre-existing max-height cap — the actual defect — would have survived
   untouched underneath it.
   Only the desktop veil is set below, because r90b lives inside a <=1023 media
   query and the >=1024 row, which keeps its 5-in-a-row 120x56 layout, has none:
   .85 still reads as a quiet trust row, but the captions clear 4.5:1. */
/* r109e — DESKTOP: the badges were still the 120x56 asset at native size, which
   the owner's screenshot shows as a row of slivers under a 56px headline. Each is
   an SVG, so its own dimensions are not a ceiling — the row is. Five badges plus
   four gaps at 168px need ~1000px; the content box is 918px at 1024 and 1216px at
   1440, so the width RAMPS rather than jumping: 120px at 1024 (760px used), 158px
   at 1440, 168px from ~1750 up. aspect-ratio carries the height so nothing
   distorts, and the wall never wraps at any desktop width. */
@media (min-width:1024px){
  div:has(>img[src*="award-"]){opacity:.85!important;gap:clamp(28px,3vw,48px)!important}
  div:has(>img[src*="award-"])>img{width:clamp(120px,11vw,168px)!important;
    height:auto!important;aspect-ratio:120/56;object-fit:contain}
}
/* one owner, every width: a 15px all-caps line under a 56px H2 needs the size
   AND the tracking — uppercase throws away the word-shape cue. */
div:has(+div>img[src*="award-"]){font-size:var(--fl-t16)!important;
  letter-spacing:0.08em!important;color:#3D3748!important}

/* ── 8. THE HEADER LOCKUP — r109e ──────────────────────────────────────────
   bundles/home.css pins --fl-logo and --fl-logo-sticky at a flat 28px, and says
   why: «The logo must never exceed the CTA beside it (44px) — 24 and 28 both
   clear it.» That reasoning is still right; its input changed. This round took
   the control to 48px on a phone and 64px on desktop, so 28px is now 44% of the
   pill beside it instead of 64%, and the brand mark reads as an afterthought next
   to the button — which is what the owner is pointing at.
   A header wordmark normally sits at 55-65% of the adjacent control's height, so
   the token becomes a ramp with the old 28px as its FLOOR: nothing shrinks
   anywhere, phones keep exactly the verified 28px, and desktop reaches 38px
   against a 64px control (59%). The pill's own ≤1023 override
   (clamp(18px,2.73vw,28px), bundles/shared.css:434) is untouched — that is the
   measured two-row layout, and it stays as verified. */
:root{
  --fl-logo:        clamp(28px, 1.4rem + 0.90vw, 38px);
  --fl-logo-sticky: clamp(28px, 1.4rem + 0.90vw, 38px);
}


/* ── 4. THE FORECAST PANEL — the block the ladder could not reach ───────────
   Raising the tokens fixed the page and missed #statsBlock entirely, because
   every size in that panel is a LITERAL, not var(--fl-*): the base rules in
   bundles/home.css (.bl-statcol__h, .bl-statnow__l, .bl-statbig__l) carry their
   own clamps, and its r38.2 <=1023 branch hardcodes 9.5px / 11px / 12px. So the
   densest text on the home page — the one the owner photographs first — was
   still rendering a 9.5px label after the pass. Worth saying plainly: it also
   made the earlier claim "nothing on the page is below 11px" untrue.

   These four declarations are the ONLY owner of those sizes now: each is
   !important, so nothing is left to source order, and each names the rule it
   supersedes. They are not re-pointed at the ladder wholesale — this is a data
   panel with nowrap labels in 48px cells, and t14/t16 would overflow the two-up
   grid at 360px. Measured at 390 (cell 141px of content box) the values below
   leave ~50px of slack; going further needs the panel's own layout pass, which
   is a separate decision and not something to slip into a type change.

   supersedes  bundles/home.css @<=1023.98:
     .bl-statrow .bl-statnow__l  9.5px · .bl-statnow__v 12px
     .bl-statrow .bl-statcol__h   11px · .bl-fchip      11px
   and the two base clamps (10.5px floor) at bundles/home.css:167 / :171. */
#statsBlock .bl-statnow__l,#statsBlock .bl-statbig__l{font-size:var(--fl-t14)!important}
#statsBlock .bl-statcol__h{font-size:var(--fl-t16)!important}
@media (max-width:1023.98px){
  #statsBlock .bl-statrow .bl-statnow__l{font-size:13px!important}
  #statsBlock .bl-statrow .bl-statnow__v{font-size:15px!important}
  #statsBlock .bl-statrow .bl-statcol__h{font-size:15px!important}
  #statsBlock .bl-statrow .bl-fchip{font-size:12px!important;height:22px}
}

/* ── 5. THE SCOPED TOKEN BLOCKS — why the ladder kept missing ───────────────
   ROOT CAUSE, and the reason three passes did not converge: bundles/shared.css
   does not keep the type tokens in one place. Line 434 re-declares the WHOLE
   set a second time, scoped to .bl-pill, inside @media (max-width:1023.98px):

     .bl-pill{ --fl-cta-txt:clamp(9px,1.12vw,11.5px);
               --fl-btxt:clamp(8px,0.93vw,9.5px);
               --fl-bsub:clamp(7px,0.78vw,8px); … }

   Custom properties inherit, so everything inside the hero pill resolved
   against THAT block, not :root. Raising :root could never reach it — and
   pointing the hero CTA at var(--fl-cta-txt) actually made it SMALLER than the
   14px literal it replaced (10.35px measured). The trust cluster has the same
   shape: --fl-more-txt / --fl-cap / --fl-score are their own tokens with 9-12px
   floors, which is why "111K" rendered at 9px and the caption at 10px.

   One edit at the cause: re-declare the scoped tokens where they are scoped,
   instead of chasing each element that reads them. Nothing selects an element
   here — only the two token blocks change, so every label, badge and control
   inside the pill and the trust row moves together and stays proportional.
   (components/site.responsive.css already patches this same .bl-pill block for
   --fl-cta-h, so the pattern is the project's own, not a new assumption.)

   Fit check at 390: the pill row is logo + ghost(min-width:86px) + primary.
   "Login" at 15px ≈ 38px + 32 padding = 86px, the primary ≈ 175px + 32 = 207px,
   total ≈ 305px inside 358px of content box — the literal was never holding a
   layout together, it was just older than the tokens. */
:root{
  --fl-more-txt: clamp(0.75rem, 0.715rem + 0.14vw, 0.875rem);  /*  9  -> 12-14 */
  --fl-cap:      clamp(0.781rem, 0.746rem + 0.14vw, 0.875rem); /* 10  -> 12.5-14 */
  --fl-score:    clamp(0.875rem, 0.798rem + 0.31vw, 1.094rem); /* 12  -> 14-17.5 */
}
/* …and the pill block needs !important, because it is not only a stylesheet
   rule. components/bl-header.js re-injects a byte-identical copy of the same
   .bl-pill token block at runtime as <style id="bl-header-css">, the LAST
   <style> in <head>. An injected <style> sorts after every <link rel=stylesheet>,
   so at equal specificity (.bl-pill = 0,1,0) the runtime copy wins whatever
   order the linked files load in — no linked stylesheet can out-order it.
   Custom properties do accept !important, and components/site.responsive.css
   already relies on exactly this to win --fl-cta-h on this same selector. */
@media (max-width:1023.98px){
  .bl-pill{
    --fl-cta-txt:  clamp(0.938rem, 0.910rem + 0.11vw, 1rem)!important;    /* 11.5 -> 15-16 */
    --fl-cta-txts: clamp(0.875rem, 0.848rem + 0.11vw, 0.938rem)!important;/* 11   -> 14-15 */
    --fl-btxt:     clamp(0.75rem,  0.696rem + 0.22vw, 0.844rem)!important;/*  9.5 -> 12-13.5 */
    --fl-bsub:     clamp(0.688rem, 0.660rem + 0.11vw, 0.75rem)!important; /*  8   -> 11-12 */
    --fl-bico:     clamp(0.875rem, 0.793rem + 0.33vw, 1.125rem)!important;/* 14   -> 14-18 */
  }
}

/* ── 6. REVIEW CARDS — the testimonial is the page's evidence ───────────────
   .bl-card__q was clamp(12px,1vw,14px) and .bl-card__name clamp(13px,1.05vw,16px),
   so a phone read the actual social proof at 12px under a 13px name — smaller
   than the feature-card body it sits below. A testimonial is not a caption; it
   is the longest continuous sentence a visitor reads on the page and the one
   they weigh before paying, so it belongs on the body step of the ladder.
   Name goes one step above the quote and keeps its weight: same-size name and
   quote would flatten the attribution into the sentence.

   The straight " " wrapped around every quote is gone (src/ui/reviewsCarousel.js,
   the reviewsPanel twin in the shared bundle, the baked island tree, and reg3's
   own wall, which used curly quotes for the same job). Two reasons beyond the
   owner asking: straight quotes are inch marks, never quotation marks — and the
   card already carries the attribution, so avatar + name + stars + a ruled line
   IS the quotation frame. The glyphs only added visual noise to it. */
.bl-card__q{font-size:var(--fl-t17)!important;line-height:1.55!important}
.bl-card__name{font-size:var(--fl-t18)!important;font-weight:600!important}

/* ── 7. THE PIXEL RESERVATIONS — r109d ─────────────────────────────────────
   The type raise broke a layout, and it broke it the way this project has
   already documented once (DEVIATION_LOG DEV-r88-5): a section whose height was
   RESERVED as a literal now contains more than it reserved.

     bundles/home.css / shared.css:  .bl-defer.bl-reviews{contain-intrinsic-size:auto 484px}
                                     .bl-defer--tiles    {contain-intrinsic-size:auto 410px}

   With content-visibility:auto that length IS the box height until the section
   first renders, so the section below is positioned against the short box.
   Measured at 924px after the raise: the reviews wall's box was 527px against
   594px of real content — 67px spilling out — and «Show all 6 reviews» ended up
   25px inside the next H2's first line. Two elements literally on top of each
   other.

   The fix is NOT a new number. r88 tried that first for the tiles and traded the
   overlap for its mirror image: over-reserve, and the page renders too low and
   snaps upward on first paint (133px at 924px, per the log). Any literal chosen
   today is wrong again the next time the scale, the locale or the card count
   moves — and this round moved the scale, which is precisely how a reservation
   from r88 became a broken layout in r109.

   So both sections opt out of the skip at EVERY width and take their height from
   real content. r88 released the tiles only ≤1023 and left the desktop literal
   standing; that leftover is what failed today. Cost: two below-fold sections
   lose a paint optimisation. That trade was already accepted for the tiles in
   r88; correctness of a layout the visitor sees outranks it.
   .bl-marquee (auto 148px) and the .bl-defer base (auto 600px) are left alone:
   both were re-measured this round and spill 0 — the marquee holds fixed-height
   logos with no type in the flow, so the raise cannot reach it. */
.bl-defer.bl-reviews,
.bl-defer--tiles{content-visibility:visible;contain-intrinsic-size:none}

/* ── 9. THE HERO ROW — r109f ───────────────────────────────────────────────
   Owner: «перебор с формой». Correct — but not the sizes. The row is
   flex-wrap:wrap holding [field][error note][button], and .bl-ferr is injected
   BETWEEN them with a full-width basis. While the note is hidden the row is two
   items and fits; the moment it appears it breaks the line, so the button falls
   to a third row and the field looks stranded. Bigger controls only made the
   break arrive sooner — the ordering was always wrong.
   Fixed by ORDER, not by shrinking anything back: the note is the last item in
   the row's own layout while staying where it is in the DOM (so the screen
   reader still hears it right after the field it describes), and the field and
   the button keep line one. A little headroom on the row's 620px literal too —
   that number was measured against the pre-r109 control scale. */
@media (min-width:1024px){
  div:has(>div>[data-bl-orbit="input"]){width:min(680px,100%)!important}
  div:has(>[data-bl-orbit="input"])>[data-bl-orbit="input"]{order:1}
  div:has(>[data-bl-orbit="input"])>#blForecastCta{order:2}
  div:has(>[data-bl-orbit="input"])>.bl-ferr{order:3;flex:1 1 100%}
}

/* ── 10. THE FOOTER — r109f ────────────────────────────────────────────────
   The footer was the last block still on the old scale, and it is the block the
   product can least afford to whisper: PRODUCT_LOGIC puts the support channels
   here, so «Contact us», live chat and Telegram ARE the page's answer to a
   visitor who has a question and no other route. A 13px column heading over 14px
   links is a legal-footer treatment applied to a support surface.
   Every value below is the ladder, one step up, nothing invented:
     .bl-foot__h    13 → t15   the three column headings
     .bl-navlink    14 → t16   every footer link, incl. Contact us / Cancel
     .bl-foot__legal 13 → t14  the disclaimer — small print, but readable
     trust row      13 → t14   «Secure payment», SSL, money-back
   The support chips get the control treatment rather than the text treatment:
   a 44px hit box, a label on the button step, and an icon sized against that
   label instead of a fixed 18px — an icon that is the point of the control
   («Live chat», «Telegram») has to read as a target, not as decoration. */
.bl-foot__h{font-size:var(--fl-t15)!important;letter-spacing:.05em!important}
.bl-foot .bl-navlink{font-size:var(--fl-t16)!important}
.bl-foot__legal{font-size:var(--fl-t14)!important;line-height:1.5!important;color:#6E687A!important}
.bl-foot__trust span{font-size:var(--fl-t14)!important}
/* r109g — the two lines the owner's arrows point at, by their REAL class names.
   The previous attempt guessed b/strong and matched nothing: the block holds
   .bl-suplabel / .bl-suprow / .bl-wapill / .bl-tgpill / .bl-supcap. Base rules
   are var(--fl-t13) in bundles/shared.css, so they were the last two strings in
   the footer still on the old scale, sitting next to 16.7px links. */
.bl-suplabel{font-size:var(--fl-t15)!important}
.bl-supcap{font-size:var(--fl-t14)!important;line-height:1.5!important}
.bl-wapill,.bl-tgpill{min-height:44px;font-size:var(--fl-cta-txts)!important}
/* r109g — THE ERROR MESSAGE WAS THE SMALLEST TEXT ON THE PAGE, at 11px, from
   clamp(11px,0.92vw,13px) in bundles/shared.css. An error is the highest-priority
   string on a form: it is read under stress, it is the only thing standing
   between the visitor and the funnel, and here it sat at two thirds the size of
   the body copy beside it. Last round moved this element (order:3) without
   looking at its size — the same literal-under-a-token pattern as the awards cap
   and the sticky-bar label. */
.bl-ferr{font-size:var(--fl-t14)!important;line-height:1.5!important}
.bl-ferr__ic{width:var(--fl-uiico-sm)!important;height:var(--fl-uiico-sm)!important;flex:0 0 auto}

/* ── 11. THE DEAD BAND ABOVE THE HEADLINE — r109i ──────────────────────────
   The h1's top margin is a GENERATED INLINE style (margin:80px 0 0 in the static
   tree), so only the ≤599 branch — which uses !important — ever moved it. Every
   tablet width kept the full 80px, and since the h1 has no previous sibling that
   margin IS the empty band the owner photographed.
   A proof row and the headline it introduces are one rhythm unit; 80px on an
   800px-tall viewport spends a tenth of the screen on nothing.
   ONE owner for this property, at every width below 1024 — a second copy in the
   ≤599 branch would only be shadowed by whichever sits later in the file, which
   is exactly how the phone quietly ended up with 32px instead of the 24px that
   branch asked for. The ramp carries both intents instead: 24px through 428,
   32px by ~570, 44px at 1023, desktop untouched at ≥1024. */
@media (max-width:1023.98px){
  #root h1{margin-top:clamp(24px,5.6vw,44px)!important}
}

/* ── 12. TWO PILLS THAT MUST NEVER WRAP — r109j ────────────────────────────
   A control with border-radius:100px and a fixed 44px height IS a single-line
   object: wrap it and the text leaves the pill. Neither declared white-space, so
   both inherited normal and both broke on a label that grew by ~2px —
   «Status: live» missed one line by 3px, «See plans & pricing →» by 21px.

   The fix is the CONSTRAINT, not the type. Declaring nowrap makes each pill's
   min-content its real one-line width, and a flex/grid item is not shrunk below
   min-content — so the track grows to fit instead of the label breaking. That is
   what makes this locale-proof: «Ver planes y precios →» and «Vedi piani e
   prezzi →» simply ask their column for more room, with nothing tuned to the
   English string. Shrinking the font to fit English would have wrapped in es/it
   on the next pass.
   flex-shrink:0 on the status chip because it sits in a wrapping gap:10px row
   inside .bl-foot__brand, where a flexible item would still be squeezed.
   Below 600 the footer is two columns of ~155px, too narrow for a 200px pill at
   any size, so the column holding it takes the full width — one row for the
   product CTA reads as deliberate, a pill with its label hanging out does not.

   r109k — AND THE TRACK HAS TO BE ALLOWED TO GROW. nowrap alone was not enough,
   and the paragraph above was wrong about why: .bl-foot__col carries an explicit
   min-width:132px (bundles/home.css:438), and an explicit min-width REPLACES the
   automatic minimum size. So the 1fr track resolved to 132px rather than the
   pill's ~201px min-content, and the unbreakable label overflowed its own
   padding box instead — 6.4px of clearance left in EN, 1.8px in ES, i.e. one
   glyph from sitting outside a border-radius:100px background.
   min-content restores the automatic minimum for this ONE column, so the track
   resolves to at least the pill's real width and the authored 16.76px padding
   survives in all three locales. Same rule covers the ≥1024 flex branch, which
   carries the identical min-width. This is the locale-proof half of the fix: the
   alternative — trimming font or padding until English fits — is what would have
   broken Spanish on the next pass. */
.bl-foot__go,[data-bl-status]{white-space:nowrap!important}
[data-bl-status]{flex-shrink:0}
.bl-foot .bl-foot__col:has(>.bl-foot__go){min-width:min-content}
@media (max-width:599.98px){
  .bl-foot .bl-foot__col:has(>.bl-foot__go){grid-column:1/-1}
}

/* ── 13. THE PILL LOGO ON PHONE AND TABLET — r109l ─────────────────────────
   r109e ramped --fl-logo at :root and explicitly left the pill's ≤1023 override
   (clamp(18px,2.73vw,28px), bundles/shared.css:434) as verified. That override
   is what a phone actually reads, so the mark stayed at its 18px floor while the
   control beside it is held at 44-48px by site.responsive.css — 38% of the pill,
   against the 55-65% a header lockup normally sits at. Hence «логотип очень
   маленький» on exactly the two widths the raise never reached.
   26px floor → 32px at 1023 puts it back at ~57%. !important because
   components/bl-header.js re-injects this same block at runtime as the last
   <style> in <head>, so no linked sheet can out-order it. */
@media (max-width:1023.98px){
  .bl-pill{--fl-logo:clamp(26px, 1.3rem + 0.70vw, 32px)!important}
}

/* ── 13. MOBILE FOOTER COPY — the size was the fix, not the word count ──────
   Owner ask (r109): shorten the two long footer lines on the phone, in three
   languages, without losing meaning. Measured first, and the honest answer is
   that truncation is the wrong instrument here:

     · the brand tagline compacts ~12 % in EN («powered by AI» → «by AI») but
       only ~2 % in ES/IT — «Crecimiento real en Instagram con IA…» has no
       padding to remove. Cutting it further means dropping one of the five
       promises it carries (real growth · Instagram · AI · no bots · no
       passwords · cancel anytime), which IS a loss of meaning;
     · the second line is a LEGAL disclaimer (independence + non-affiliation +
       non-endorsement re Instagram/Meta). Fine print is not shortened for
       layout; a dropped clause changes what the sentence warrants. Owner call.

   What the phone actually needed was legibility and measure, and both are in
   place: §12 above raised the whole footer one ladder step (headings t15,
   links t16, disclaimer t14 at line-height 1.5, trust row t14), the grid is
   two ~155px columns with the CTA column spanning full width, and both pills
   are nowrap so no label can break out of its radius. A 3–4 line tagline at
   15px is a tagline reading normally — not eye strain.

   The swap mechanism is ready if the owner still wants the cut: swapText() in
   components/bl-responsive-copy.js parks the canonical string in
   data-bl-fulltx and restores it above 599.98px, and i18n/r88.extra.js is the
   hand-keyed home for mobile-only tiers in en/es/it with NO gen-langs run
   needed. It takes three approved strings, not a code change. */


/* ── 14. THE FORECAST CARDS ON A BIG SCREEN — r114 ─────────────────────────
   Owner (ФР, screenshots 1-2, full HD): «плохое позиционирование, плохие
   отступы… на меньшем разрешении с отступами всё ок».

   Measured first (dev/probes/r114-fullhd.html, EN, cold load):

     viewport   .bl-statrow   one column   "Now" row: box / content
      1280 px      724 px       228 px         170 / 184  → 14 px OVER
      1440 px      728 px       228 px         166 / 202  → 36 px OVER
      1920 px      686 px       214 px         150 / 202  → 52 px OVER
      2560 px      643 px       200 px         136 / 202  → 66 px OVER

   THE CAUSE, and why the phone looks right while a 27" monitor does not: every
   size inside this panel is a clamp on **vw**, but the panel's WIDTH is capped.
   The left half of #statsBlock stops at max-width:728px, so a column stops
   growing at ~228px around 1400px of viewport — and then keeps SHRINKING,
   because --fl-inset (→112px) and the row gap (→80px) and the phone (→417px)
   all keep growing out of the same line. Meanwhile the paddings and type keep
   climbing to their vw maxima: .bl-statcol 18px, .bl-statbig 28px, the value
   38px. At 1920 that is 62px of horizontal padding inside a 214px card — 29% of
   the card spent on air — and the three-item "Now" row (label · bar · number),
   whose bar is a FIXED clamp(38px,5.9vw,84px), cannot fit and bursts out of its
   own pill. "+5,000" at 38px needs ~124px against 122px of content box, which
   is the clipped number in screenshot 1. Below 1024 none of this shows because
   the branch above restructures the panel into a two-up grid with its own
   literal padding — hence "on the smaller screen it's fine".

   THE FIX IS THE MEASUREMENT, NOT NEW NUMBERS. A card is sized by its own box
   from here on: .bl-statcol becomes a container, and everything inside it that
   was a share of the VIEWPORT becomes a share of the CARD (cqw). So the same
   rule holds at 1024, at 1920, at 4K and in es/it, where every label is longer
   than the English one — no width gets its own literal, and there is nothing
   left to re-tune the next time the inset or the phone grows.

   Three structural corrections come with it, each removing an overflow that no
   padding value could have fixed:
     · the "Now" bar is the FLEXIBLE item now (flex:1 1 auto, min 16px) instead
       of a fixed clamp: label and number are content and must never be pushed
       out, a decorative rule is what should absorb the slack. Label left,
       number right (space-between) reads as a row rather than a cramped
       cluster, and it is what the <=1023 branch already does;
     · the big value is capped against the card as well as the viewport
       (min(…, 20cqw)), so no locale and no five-digit forecast can clip;
     · the three headings occupy the same box. "Your followers" is one line and
       "Average likes on post" is two at >=1920 (measured), so the stacks under
       them started at different heights — that is the "позиционирование" half
       of the ФР. Where the browser has subgrid the whole panel aligns on three
       shared rows (heading · Now · In 1 month) in every locale; without it the
       reserved two-line heading box keeps EN/IT aligned. Both paths are here,
       the richer one behind @supports.
   Desktop only: <=1023.98 is owned by the branch above and is not touched. */
@media (min-width:1024px){
  #statsBlock .bl-statcol{
    container-type:inline-size;
    padding:clamp(11px,1.05vw,15px) clamp(11px,1.05vw,15px) clamp(12px,1.15vw,17px);
    gap:clamp(9px,0.85vw,14px)}
  #statsBlock .bl-statrow{gap:clamp(10px,1.15vw,18px)}
  #statsBlock .bl-statcol__h{
    min-height:calc(2em * 1.15);
    display:flex;align-items:center;justify-content:center;
    text-wrap:balance}
  #statsBlock .bl-statstack{gap:clamp(6px,0.55vw,9px)}
  /* the row is label · rule · number — only the rule may be squeezed */
  #statsBlock .bl-statnow{
    min-height:clamp(46px,3.6vw,58px);
    justify-content:space-between;
    gap:clamp(5px,3cqw,10px);
    padding:0 clamp(8px,5cqw,13px)}
  #statsBlock .bl-statnow__b{flex:1 1 auto;width:auto;min-width:16px;max-width:84px}
  #statsBlock .bl-statbig{
    min-height:clamp(84px,8.4vw,124px);
    padding:clamp(10px,8cqw,16px);
    gap:clamp(5px,3cqw,9px)}
  #statsBlock .bl-statbig__v{font-size:min(clamp(23px,2.65vw,38px),20cqw)}
  @supports (grid-template-rows:subgrid){
    #statsBlock .bl-statrow{
      display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
      grid-template-rows:auto auto auto}
    #statsBlock .bl-statcol{
      display:grid;grid-template-rows:subgrid;grid-row:span 3;
      grid-template-columns:minmax(0,1fr);justify-items:center}
    #statsBlock .bl-statcol__h{min-height:0}
    #statsBlock .bl-statstack{
      display:grid;grid-template-rows:subgrid;grid-row:span 2;
      grid-template-columns:minmax(0,1fr)}
  }
}


/* ── 15. r115 — NINE OWNER ITEMS, MEASURED FIRST ───────────────────────────
   Probe: dev/probes/r115-mobile.html (360/390/430/768/1440, en+es).
   Owner's standing constraint for this round, quoted: «ЗАПРЕЩЕНО менять UI
   блоков в любом пункте этого запроса» — so nothing below adds, removes or
   re-proportions a block. What changes is dead space, text alignment, text
   size, and one ring that desktop was missing.

   ── 15a · THE AVATAR RING ON DESKTOP (screenshots 1 + 3) ─────────────────
   ФР: the phone's live avatar wears the Instagram story ring below 1024px and
   nothing above it. Cause is scope, not intent: the ring was authored in the
   r88 adaptive identity (`#blIdRing`, this file's ≤1023 branch) and desktop
   keeps the OTHER identity surface — the avatar that loads into the pink
   card's icon circle (`#blPhoneAv`, D-17). Two surfaces, one of them dressed.
   ОР: desktop gets the same ring, at the same moment — when the photo arrives
   from the backend (`[src]`), or when a 403 leaves the first-character glyph
   (`[data-bl-avph]`, the same signal bl-avatar.js writes). The ring is the
   ≤1023 gradient verbatim, so the two surfaces cannot drift.
   Geometry note: the circle is `position:absolute` and the avatar inside it is
   `inset:0`, which resolves against its PADDING box — so padding on the circle
   insets the photo and the gradient shows as an annulus. No box moves.

   ── 15b · THE DEAD BAND ABOVE THE MOBILE HEADER (screenshot 2) ───────────
   ФР measured at 360 and 390: the header pill starts 80px down the page, and
   all 80px are empty — 28px of shell padding + 20px of hero-card margin + 32px
   of hero-card padding, three desktop values stacked. Above 600px they are the
   design; on a 640px-tall phone screen they spend an eighth of the first screen
   on nothing before the logo.
   ОР: 24px total (8+8+8), mobile only. Desktop and tablet keep all three.

   ── 15c · AND THE SPACE GOES BACK INTO THE RHYTHM (screenshot 4) ─────────
   ФР: «нет отступов совершенно нигде на первом экране мобильной версии».
   Measured: pill → H1 24px, H1 → sub 16px, CTA → trust row 22px. A 124px-tall
   header pill, a 36px headline and a 48px button separated by 22-24px read as
   one mass — the gaps are smaller than the objects they separate.
   ОР: an 8pt rhythm where the step is proportional to what it separates, and
   the 56px freed in 15b pays for it: pill → H1 32px, H1 → sub 20px, sub →
   campaign line 20px, → CTA 28px, → trust row 32px. Nothing is resized.

   ── 15d · THE FORECAST BLOCK IS LEFT-ALIGNED (new screenshot 1) ──────────
   ФР: «выравнивание должно быть по левому краю всех данных в блоке». The three
   headings were centred while every value under them is left-aligned, and the
   centring is also what made the columns disagree: "Media de «me gusta» por
   publicación" wraps to two lines and pushed its own «Ahora» row 17px below
   the other two. The ≤599 branch already left-aligns this block, so this is
   also the range 600-1023 catching up with the phone.
   ОР: headings left, and §14's shared-row alignment applies from 600px up, not
   only from 1024px. Text alignment only — no card, gap or size changes.

   ── 15e · A "Now" ROW THAT CANNOT BURST (with 15f) ──────────────────────
   §14 made the decorative rule the flexible item above 1024px. An 11-digit
   account number needs the same room at every width, so the rule is flexible
   everywhere now. It is the one element in the row that carries no
   information — the label and the number are content and may not be pushed
   out of their own pill. */
@media (min-width:1024px){
  #blPhoneCard>div:has(>#blPhoneAv[src]),
  #blPhoneCard>div:has(>[data-bl-avph]){
    background:conic-gradient(from 210deg,#F58529,#DD2A7B,#8134AF,#515BD4,#F58529)!important;
    padding:clamp(2px,0.24vw,4px);box-sizing:border-box}
}

/* 15d — the alignment half of §14, from 600px up */
@media (min-width:600px){
  #statsBlock .bl-statcol{align-items:stretch}
  #statsBlock .bl-statcol__h{text-align:left;justify-content:flex-start}
  @supports (grid-template-rows:subgrid){
    #statsBlock .bl-statrow{
      display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
      grid-template-rows:auto auto auto}
    /* minmax(0,1fr) is not optional: a subgrid item with no explicit column
       gets ONE implicit `auto` track, which takes max-content from a nowrap
       11-digit readout — measured 254.8px of row inside a 231.6px card. */
    #statsBlock .bl-statcol{
      display:grid;grid-template-rows:subgrid;grid-row:span 3;
      grid-template-columns:minmax(0,1fr);justify-items:stretch}
    #statsBlock .bl-statcol__h{min-height:0;height:30px}
    #statsBlock .bl-statstack{display:grid;grid-template-rows:subgrid;grid-row:span 2;
      grid-template-columns:minmax(0,1fr)}
  }
}

/* 15e/15f — the rule yields, and a readout never wraps (it is scaled to fit by
   components/bl-text-fit.js instead, which needs a single line to measure) */
#statsBlock .bl-statnow__b{flex:1 1 auto;width:auto;min-width:14px;max-width:84px}
/* nowrap so components/bl-text-fit.js has a single line to measure; the two
   containment properties are the LAST resort behind it — at the 62%/12px floor
   a readout can still be wider than its card (an account with a 19-digit
   number), and the owner's rule is that the block may not change, so the text
   is clipped inside its own card rather than allowed to run over the neighbour.
   In practice the scaler reaches the floor only past ~15 characters. */
/* Keep the complete number line in the subgrid's intrinsic height. With
   overflow:hidden, flex's automatic minimum can collapse to zero: at 1280px
   a 34px readout was squeezed into 16px. Inter also needs ascent/descent room
   beyond line-height:1. Horizontal fitting remains owned by bl-text-fit.js. */
#statsBlock .bl-statbig__v{white-space:nowrap;max-width:100%;overflow:hidden;
  line-height:1.25;min-height:1.25em;flex-shrink:0}
/* The landed state adds a growth chip. Let that full content set the minimum
   subgrid row height instead of forcing it into the pre-chip height floor. */
#statsBlock .bl-statbig.is-forecast{min-height:max-content}
/* Inline-size containment on desktop columns cannot size a shared subgrid
   row from the landed contents reliably. Keep equal-height columns, but let
   each stack contribute its full intrinsic height to the outer row. */
@media (min-width:600px){
  @supports (grid-template-rows:subgrid){
    #statsBlock .bl-statrow{grid-template-rows:auto}
    #statsBlock .bl-statcol{grid-template-rows:auto 1fr;grid-row:auto}
    #statsBlock .bl-statstack{grid-template-rows:auto 1fr;grid-row:auto}
  }
}
/* r115e — the "Now" value gets max-width but NOT overflow:hidden, and the
   distinction is the point: this element is the direct parent of .bl-nowv,
   which runs blNowPop (scale 0.82 → 1.12 → 1) the moment the visitor's real
   number lands — the one frame of this panel the product most cares about
   (PRODUCT_LOGIC / SC-03). An ancestor's overflow:hidden clips a transformed
   descendant, and this parent is sized to its own content, so the 1.12
   overshoot was shaving ~5.7px off each end of the number for 460ms.
   It needs no backstop anyway: the row absorbs width through the flexible rule
   above and the value is nowrap, so bl-text-fit.js already measures against a
   correct box. .bl-statbig__v above is safe to clip because climb.land()
   animates that element ITSELF, not a child, and appends its shock ring to
   .bl-statbig — both outside the clip. */
#statsBlock .bl-statnow__v{max-width:100%}

/* 15b + 15c — mobile only. The three selectors are structural on purpose: the
   values they beat are GENERATED inline styles, and a [style*=…] match breaks
   the moment React re-serialises the same declaration with a space in it. */
@media (max-width:599.98px){
  /* the shell is NOT a child of #root — there is one more wrapper between them
     (measured: #root > div > div[padding-top:28px] > hero card), so a child
     combinator here matched the wrapper and left all 28px standing. */
  #root div:has(>div>div>[data-bl-island="hero-pill"]){padding-top:8px!important}
  div:has(>div>[data-bl-island="hero-pill"]){margin-top:8px!important}
  div:has(>[data-bl-island="hero-pill"]){padding-top:8px!important}
  #root h1{margin-top:32px!important}
  #root h1+div p,#root h1~div>p:first-of-type{margin-top:20px!important}
  #root h1~div [data-bl-campaign],#root h1~div>div:has(>[data-bl-campaign]){margin-top:20px!important}
  #root h1~div>a.bl-cta--dark,#root h1~div .bl-cta--dark{margin-top:28px!important}
  #root .bl-trust{margin-top:32px!important}
}

/* EPIC-002: the identity header is a phone-only adaptive overlay. The desktop
   geometry below remains inert while the shared selectors stay co-located. */
@media (min-width:1024px){
  .bl-phone.is-live #blPhoneIdent::before{content:"";position:absolute;left:20.5%;width:67.9%;top:8.7%;height:15.4%;background:#fff}
  #blIdHandle{position:absolute;left:20.5%;width:67.9%;top:8.7%;height:2.9%;display:flex;align-items:center;justify-content:center;gap:.34em;font-size:clamp(12px,1vw,16px);font-weight:600;color:#160E28;white-space:nowrap}
  #blIdHandle [data-bl-verified]{position:static;flex:0 0 auto;width:1em;height:1em}
  #blIdRing{position:absolute;left:22.2%;top:12.07%;width:15.4%;aspect-ratio:1;border-radius:50%;overflow:hidden;background:#EFEBF3}
  #blIdRing img{width:100%;height:100%;object-fit:cover;border-radius:50%}
  #blIdPatch{position:absolute;left:22.2%;width:66%;top:20.95%;display:block;font-size:clamp(11px,.85vw,14px);font-weight:600;line-height:1.1;color:#160E28;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #blIdStats{position:absolute;left:38.4%;width:49.9%;top:13.95%;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));align-items:start;container-type:inline-size}
  #blIdStats>span{display:flex;flex-direction:column;align-items:center;min-width:0;gap:2px}
  #blIdStats b{font-size:9cqw;font-weight:700;line-height:1.1;color:#160E28;font-variant-numeric:tabular-nums;white-space:nowrap}
  #blIdStats i{font-size:7cqw;font-style:normal;line-height:1.1;color:#3A3344;white-space:nowrap}
}
