/* ═══════════════════════════════════════════════════════════════════════════
   components/site.responsive.css — r90. THE site-wide adaptive layer.

   Why one file: r88 gave Home an adaptive layer and r89 gave registration-3 a
   single rule; every other page — the whole registration/auth/payment flow and
   the pricing table — still rendered its DESKTOP layout on a phone (owner
   review, screenshot 1). Rather than a per-page stylesheet each with its own
   copy of the same idea, the shapes the generator actually emits are handled
   here once, and this file is linked by every shell.

   Contract, identical to the other two layers: every rule below sits inside a
   max-width query EXCEPT the reviews wall, which is a deliberate all-width
   change the owner asked for ("слайдер допотопная технология в 2026"), and the
   r109 sticky-bar typeface directly below.
   Hooks are the generated inline-style substrings (the pattern established in
   home.responsive.css), matched in both spellings — the prerendered HTML writes
   `flex:0 1 698px` and React's own re-render writes `flex: 0 1 698px`, so every
   hook is chosen to be a substring of both.
   ═══════════════════════════════════════════════════════════════════════════ */

/* r109 — THE STICKY BAR WAS RENDERING IN TIMES NEW ROMAN, on every shell.
   Nothing sets a font-family on <body>: this project applies Inter per
   component, on the outermost node of each page tree, as an inline style. The
   scroll-in bar is not inside that tree — it is injected as a sibling — so
   .bl-cta{font-family:inherit} inherited straight past it to the UA default.
   Two labels ("Login", "Start free trial →") drew as a serif, which is narrower
   and lighter than Inter at the same px, so the bar that is on screen for most
   of the page's scroll length read smaller than its own font-size — the exact
   complaint this round is about.
   The stack is copied verbatim from the page trees (bundles/home.bundle.js et
   al.), and it goes on .bl-sticky, never on .bl-cta: the button MUST keep
   inherit so it stays correct inside every other container. Outside a media
   query on purpose — a missing typeface is not a width problem. */
.bl-sticky{font-family:Inter,'Inter Fallback',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif}

/* ============ REVIEWS: a wall, not a carousel (all widths) ================
   The markup is ui/reviewsCarousel's: an overflow-hidden window, a
   `.bl-revtrack` that is translated sideways, one `.bl-revslide` per three
   cards, and two arrow buttons. Three of six reviews were reachable only by
   pressing an arrow, which is the 2010s pattern the owner called out: it hides
   half the social proof behind an interaction, it cannot be scanned, and on a
   phone the arrows are a 44px target for content that could simply be there.
   `display:contents` on the slides dissolves the slide boxes, so all six cards
   become one grid the track owns — no markup change, no JS, and the carousel's
   own transform is neutralised rather than fought. Card count per row is then
   just a column count, and the arrows are removed because nothing can move.

   r90 research (2023–2026): what is evidenced is NOT a magic number of
   testimonials — vendor guidance in that window ranges from 2–4 to 10–30, all
   Tier-3 and commercially interested — but that (a) content reachable only by
   operating a control is largely unseen (Notre Dame carousel measurement: ~1%
   of visitors clicked any slide, 84% of those the first; NN/g: people scroll
   past carousels and miss non-first frames) and (b) progressive disclosure is
   the right answer to "too much for one screen" (NN/g). So the first three
   reviews are the default at EVERY width — complete, scannable, no control
   needed — and the rest is revealed by the one labelled button
   components/bl-reviews-wall.js adds. */
.bl-revtrack{display:grid!important;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:var(--fl-revgap);transform:none!important;transition:none!important}
.bl-revslide{display:contents}
/* the nav row is the arrows' only content — the whole row goes, not just the
   buttons, so it leaves no 24px gap behind. */
div:has(>.bl-revnav){display:none!important}
/* deferred by default, revealed by the disclosure control (which sets the
   attribute on the section). Both rules name the same nodes, so nothing can
   half-open. */
.bl-revslide:nth-of-type(n+2){display:none}
[data-bl-revall="1"] .bl-revslide:nth-of-type(n+2){display:contents}

/* r108 (owner) — the plan step's own wall: its extra cards are deferred behind
   the same one control, so reg3 behaves like Home (three visible at every width,
   the rest one tap away). The grid itself is the page's own auto-fit grid; only
   visibility is touched. */
[data-bl-revwall] [data-bl-revextra]{display:none}
[data-bl-revwall][data-bl-revall="1"] [data-bl-revextra]{display:block}

@media (max-width:1023.98px){
  /* two columns keep the card's quote readable at tablet measure; six cards
     divide evenly, so no card is ever orphaned on its own row. */
  .bl-revtrack{grid-template-columns:repeat(2,minmax(0,1fr))}
  /* three-per-slide into two columns leaves a 2+1 row — the same orphan
     flow.responsive.css fixes on reg3. The third card takes the full row
     instead, so every slide reads as a deliberate 2+1 block at any state of
     the disclosure. */
  .bl-revslide .bl-card:nth-child(3){grid-column:1/-1}
}
@media (max-width:599.98px){
  .bl-revtrack{grid-template-columns:1fr}
}

/* ============ THE FLOW SHELL: two columns → one ==========================
   reg1, reg2, reg4t, login and forgot-password all render the same split: a
   form column (`flex:1 1 560px`, left padding up to 90px) beside a decorative
   panel (`flex:0 1 698px`, the reg-panel.svg art + a review + the trust stack).
   Below ~900px the flex basis ratio squeezes BOTH: measured at 617px the form
   was 265px wide and the panel 281px, which is the overlapping, unreadable
   screenshot the owner sent. Flex cannot solve it — 560+698 needs 1258px plus
   the gap — so the split becomes a stack, form first.
   The panel is kept rather than hidden: it carries the review, the rating and
   the "111K" stack, which is the page's only social proof, and dropping it on
   the smallest screens would make the weakest device show the weakest page. */
@media (max-width:899.98px){
  div:has(>div[style*="0 1 698px"]){flex-direction:column!important;
    gap:clamp(16px,3vw,28px)!important;padding-left:clamp(14px,4vw,24px)!important;
    padding-right:clamp(14px,4vw,24px)!important}
  div[style*="1 1 560px"]{flex:1 1 auto!important;padding-left:0!important;width:100%}
  div[style*="0 1 698px"]{flex:0 0 auto!important;width:100%;align-self:auto!important;
    border-radius:24px!important}
  /* the panel's art is an absolutely-positioned 698×804 SVG stretched to the
     box; once the box is wide and short it stretches badly, so it covers
     instead of distorting. */
  div[style*="0 1 698px"]>img{object-fit:cover;object-position:center top}
  /* the form column's own blocks are `width:min(440px,100%)`, so they stay a
     comfortable measure and simply centre once the column is the page — logo
     included, or the lockup would hang alone on the left of a centred form. */
  div[style*="1 1 560px"]>*{margin-left:auto;margin-right:auto}
}
@media (max-width:599.98px){
  /* the panel's inner padding is height-driven (clamp(24px,7.2vh,72px)); on a
     phone in portrait 7.2vh is ~58px of empty space above a review. These two
     variables are the panel's own and are read nowhere else. */
  :root{--fl-reg-pad-y:22px;--fl-reg-pad-x:18px}
  /* the floating 10%-off pill sits over the page's last line on a small screen
     (owner review, screenshot 1). Same pill, tighter, and clear of the edge. */
  /* r90d — the pill and the language plaque are both fixed to the bottom edge, so
     on a phone they fought for the same line whatever the pill's width (owner
     screenshots 1-2, both states). They stop sharing the line: the pill sits one
     row above the plaque. Copy is compacted separately (bl-responsive-copy). */
  /* r110f — the discount pill IS a button (it opens the reward), so its label
     takes the control step rather than a 13px literal. Its max-width already
     keeps it inside the viewport, and bl-responsive-copy compacts the copy
     separately, so the larger label cannot push it off-screen. */
  .bl-dpill{right:12px!important;bottom:68px!important;min-height:44px;padding:0 14px;
    font-size:var(--fl-cta-txts);max-width:calc(100vw - 24px)}
  .bl-dtoast{right:12px!important;left:12px!important;bottom:124px!important;max-width:none}
}

/* ============ PRICING: the closing "see real growth" block ===============
   `.bl-defer--demo` is a nowrap flex row: a round portrait (up to 276px) beside
   a text column, with 40px of padding and up to 71px of gap. At 360px that
   leaves the column ~150px, so the h2 broke to two words a line and the three
   numbered steps wrapped into a staircase (owner screenshot 11). Below 900px
   the portrait moves above the text and shrinks to a badge, which is the same
   move the flow shell makes. */
@media (max-width:899.98px){
  .bl-defer--demo{flex-direction:column!important;align-items:flex-start!important;
    gap:18px!important;padding:24px!important;margin:32px var(--fl-inset) 48px!important}
  .bl-defer--demo>img{width:88px!important;height:88px!important}
  .bl-defer--demo h2{font-size:clamp(21px,5.4vw,28px)!important;line-height:1.25!important}
}
@media (max-width:599.98px){
  /* r90b — reg3's billing toggle carried a 48px top margin on top of the 21px
     the flow rhythm already gives it: ~69px of white between the trust chips and
     the plan switch, which is the empty band the owner boxed (screenshot 6). The
     margin is a desktop breathing rule; on a phone the switch should follow the
     chips. Only this wrapper is touched. */
  #root div:has(>.bl-billing){margin-top:20px!important}
  .bl-defer--demo{padding:20px!important;border-radius:18px!important}
  .bl-defer--demo>img{width:72px!important;height:72px!important}
  /* the steps: the number keeps its 28px circle, the sentence takes the rest */
  .bl-defer--demo>div>div>div{align-items:flex-start!important;gap:10px!important}
}

/* ============ THE 403 RETENTION NOTE'S CONTROLS ==========================
   `.bl-apinote__cta` is rendered by components/bl-live-data.js and appears on
   Home, reg1 and payment. Its two `.bl-cta--sm` buttons are 210px + 171px: on a
   phone they add up to more than the note is wide, so they wrapped into a
   ragged stack with the ghost button hanging half-width. Below 600px they are
   one full-width column (primary first), 600–1023 they share the row and both
   keep the 44px touch minimum. Desktop is untouched. */
@media (max-width:1023.98px){
  .bl-apinote__cta>.bl-cta{min-height:44px;padding:8px 16px;justify-content:center}
}
@media (max-width:599.98px){
  .bl-apinote__cta{gap:8px}
  .bl-apinote__cta>.bl-cta{flex:1 1 100%;width:100%}
}

/* ============ PRICING: the comparison table on a phone ===================
   Four columns (1.6fr 1fr 1fr 1fr) inside a 16px-inset card leave ~55px per
   plan on a 360px screen: the ticks fall out of their column, the row
   backgrounds and the pink Pro band stop lining up, and the whole table reads
   as broken stripes (owner review, screenshot 2).
   The fix keeps every row a grid and every column in the same order — only the
   feature LABEL leaves the row and takes the line above its own three cells.
   Three equal columns then align across the sticky plan header, every feature
   row and the closing price row, so the Pro band is one continuous stripe
   again. `1.6fr 1fr 1fr 1fr` is the one hook all three shapes share. */
@media (max-width:599.98px){
  #root div[style*="1.6fr 1fr 1fr 1fr"]{grid-template-columns:repeat(3,minmax(0,1fr))!important;
    margin-left:-16px!important;margin-right:-16px!important;width:calc(100% + 32px)!important;
    padding-left:12px!important;padding-right:12px!important;box-sizing:border-box!important}
  /* the header and the closing price row open with an empty spacer cell; the
     feature rows open with the label, which stays and spans the row. */
  #root div[style*="1.6fr 1fr 1fr 1fr"]:not(.bl-cmp__row)>span:first-child{display:none}
  .bl-cmp__row{row-gap:8px;padding-top:12px!important;padding-bottom:14px!important;
    align-items:end!important}
  .bl-cmp__row>span:first-child{grid-column:1/-1;font-size:var(--fl-t13);line-height:1.35}
  /* the section captions ("SUPPORT & TOOLS") carry the same negative margin */
  #root div[style*="26px 24px 8px"]{margin-left:-16px!important;margin-right:-16px!important;
    width:calc(100% + 32px)!important;padding:18px 12px 6px!important}
  /* the table's own card: 48px of side padding is a third of a 360px screen */
  #root div[style*="40px 48px"]{padding:18px 16px!important;border-radius:18px!important}
  /* the sticky plan header clears the compact top bar, not the desktop one */
  .bl-cmp__stick{top:60px!important}
  /* r109c — 12px was below the 14px floor this project now holds control labels
     to. Kept as a literal, not the token: this is a 3-4-up row of buttons across
     a phone, so it gets the floor and not the full 15-17px ramp. */
  .bl-cmp__stick .bl-cta{width:100%;padding:0 6px!important;font-size:14px!important;
    min-height:44px}
  .bl-cmp__stick>div{padding:12px 4px 12px!important;gap:4px!important}
}

/* ============ HIDDEN UI MUST NOT HOLD KEYBOARD FOCUS =====================
   Two carried bug reports from the owner's test pass, same class of defect and
   the same one-property fix. Neither adds a control or changes a flow.

   BUG-001 — the scroll-revealed `.bl-sticky` is only translated out of view
   (`translateY(-130%)`), so its four links stayed in the tab order: on a page
   opened at the top the first four Tab presses landed on a bar above the
   viewport with no visible result. Reproduced 2/2 on Pricing and on Help.
   BUG-002 — reg1's inline e-mail step and the password step collapse with
   `max-height:0; opacity:0`, which also leaves their inputs focusable.

   `visibility:hidden` is the minimal correct answer: it removes descendants
   from sequential focus navigation without touching layout, transform or the
   animation. The transitions are re-declared byte-identical to the ones in
   bundles/shared.css and bundles/flow.css, with visibility switching at 0s —
   delayed on the way out so the slide/collapse still plays, immediate on the
   way in so the revealed bar is focusable the moment it starts moving. */
.bl-sticky{visibility:hidden;transition:transform .3s ease, visibility 0s linear .3s}
.bl-sticky.is-visible{visibility:visible;transition:transform .3s ease, visibility 0s}
.bl-r1-email,.bl-pwstep{visibility:hidden;
  transition:max-height .34s cubic-bezier(.22,1,.36,1), opacity .2s ease .06s,
    transform .3s cubic-bezier(.22,1,.36,1), visibility 0s linear .34s}
.bl-r1-email.is-on,.bl-pwstep.is-on{visibility:visible;
  transition:max-height .34s cubic-bezier(.22,1,.36,1), opacity .2s ease .06s,
    transform .3s cubic-bezier(.22,1,.36,1), visibility 0s}

/* ============ THE FLOATING DISCOUNT PILL ON A PHONE ======================
   The pill is fixed bottom-right and the language plaque is fixed bottom-left;
   at full length the pill spanned the screen and sat on top of the plaque
   (owner screenshot 2). Two halves of one fix: the label goes compact below
   600px (bl-responsive-copy.js), and the pill leaves the plaque's line entirely
   (bottom:68px, in the flow-page block above) instead of racing it for width. */
@media (max-width:599.98px){
  .bl-dpill{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
}

/* ============ THE BILLING TOGGLE FITS ITS OWN LABEL =======================
   Regression of a bug this project already fixed once (dev/tests/r76-checks.js
   §1, PRODUCT_LOGIC "A control whose width is a number and whose content is a
   sentence"): `.bl-billing__opt` carries `min-width:118px` + `padding:0 16px`
   + `white-space:nowrap`, and the row's own width is `max-content` capped at
   100%. English fits. "Annuale · RISPARMIA 50%" and "Anual · AHORRA 50%" do
   not, so the options overflow the capped row while the sliding thumb keeps
   using `50% - 6px` — the thumb ends up over the other option's text, which is
   exactly the owner's screenshot on reg3 and Pricing.
   The fix is to stop sizing a sentence in pixels: below 900px the option loses
   its pixel floor, and below 600px the chip drops under the word instead of
   beside it, so both halves are equal thirds of a full-width row and the thumb
   lines up with what it highlights again. The toggle's own stylesheet is
   injected at runtime by components/bl-pricing-cards.js, i.e. after this file,
   so these few declarations are !important on purpose. */
@media (max-width:899.98px){
  .bl-billing{width:100%!important;min-width:0!important;max-width:100%!important}
  .bl-billing__opt{min-width:0!important;padding:0 10px!important}
}
@media (max-width:599.98px){
  .bl-billing{height:auto!important;padding:5px!important}
  .bl-billing__opt{flex-direction:column;gap:2px!important;white-space:normal!important;
    line-height:1.12;font-size:14px!important;padding:6px 6px!important;min-height:48px}
  /* r109c — 10px on a chip that carries the discount is the smallest readable
     claim on any surface; 12px is the small-print floor used page-wide now. The
     r76 wrap guards above (column direction, white-space:normal, min-width:0)
     absorb the ~8% extra width in ES/IT. */
  .bl-billing__chip{height:auto!important;padding:1px 7px!important;font-size:12px!important}
  .bl-billing__thumb{width:calc(50% - 7px)!important;top:5px!important;bottom:5px!important;left:5px!important}
}

/* ============ THE BOOT PICTURE MAY NOT SCROLL THE PAGE SIDEWAYS ==========
   r92 (BUG-003). Measured on reg3.html: during `#bl-boot-shell` the document
   was 419px wide against a 390px viewport (+29; +39 at 360, and the same class
   of overflow at 375/412), and the page returned to 375px the moment the shell
   was dropped — so the overflow is the boot picture's, not the settled page's.
   The overflowing node is a placeholder line inside the third review card that
   the generator emitted with an em width (`width:14em`), which on a 360-390px
   phone is wider than its own grid column.

   SKELETON FREEZE LAW (r77, master/SKELETON_CONTRACT.md): `bundles/*.skeleton.js`
   is a human-approved picture and is NOT touched here. The width is bounded
   from the outside instead, scoped to the shell and to phone widths only: a
   placeholder bar may be as wide as its column and no wider, and the shell
   clips whatever still tries to leave it. Nothing about the settled page, the
   generator or the approved skeleton bytes changes. */
@media (max-width:1023.98px){
  #bl-boot-shell .sk{max-width:100%!important}
  #bl-boot-shell{overflow-x:clip}
}

/* ============ A TOUCH TARGET IS 44px, NOT 30 =============================
   r92, measured at 390×844 across the shells: the header pair on Pricing
   («Login» ghost + «Start 7-day free trial →») rendered **30px** tall, and the
   Spanish edition the same («Iniciar sesión» 30px, «Empieza la prueba» 35px) —
   the project already holds itself to 44 everywhere it thought about touch
   (`.bl-sticky .bl-cta`, `.bl-lang__row`), so these are the surfaces that were
   never measured on a phone, not a different intention.
   44px is the platform figure (iOS HIG / Material) and WCAG 2.5.5 (AAA); the AA
   floor of 2.5.8 is 24. Only the height floor is set — no padding, font or
   colour changes — so the label, the gradient and the desktop render are
   untouched (this whole block is inside the phone/tablet query).
   The billing note under the toggle is an INLINE link in a sentence (2.5.8
   exempts those), but at 22px it was under even the AA floor, so it gets the
   floor and nothing else. */
/* ── r99 — THE SCROLL-IN BAR ON A PHONE, ON EVERY PAGE ────────────────────────
   Owner screenshot (es/contact, 412px): logo + «Precios» + «Iniciar sesión» +
   the 30-character dark trial CTA in one fixed row — the CTA sliced by the right
   edge of the screen.

   Cause is scope, not layout. The phone treatment of `.bl-sticky` was written in
   r90c into `components/home.responsive.css`, and that file is loaded by ONE
   page. Every other shell — contact, pricing, help, cancel, the three legal
   pages, ×3 languages — carried the desktop row onto a 360–412px screen with no
   rule at all. It is not a regression of the bar; it is a rule that never
   reached 24 of the 25 pages.

   The decision (owner): on a phone the bar carries the brand and ONE control,
   and that control is Login — the visitor who scrolls a support or legal page is
   returning, not converting, and the trial CTA is one screen away in the hero
   pill and in the footer of every page. Pricing goes too: the same link sits in
   the footer.

   This file loads after home.responsive.css on the home page, so the same three
   declarations settle home as well — one behaviour everywhere, one place. */
@media (max-width:599.98px){
  .bl-sticky>div{flex-wrap:nowrap;gap:8px;padding:8px 12px!important;min-height:0!important;
    justify-content:space-between}
  .bl-sticky .bl-stickynav{display:none}
  .bl-sticky .bl-cta--dark{display:none}
  .bl-sticky .bl-cta--ghost{display:inline-flex;flex:0 0 auto;margin-left:0!important}
  .bl-sticky .bl-logo-lockup{width:112px;height:auto}
  /* r109c — THIS is the rule that actually paints the sticky-bar button below
     600px, not the twin that used to sit in home.responsive.css: both are
     (0,2,0) with !important, and this file is linked last, so it won. The twin
     is deleted rather than edited to match — two owners for one declaration is
     what hid the .bl-pill token block and the awards max-height for a round
     each, and it is not worth keeping for symmetry.
     All three values now come from the control tokens, so this button scales
     with every other control on the page instead of being frozen at 13.5px in a
     44px pill. min-height keeps its floor: --fl-cta-hs already bottoms out at
     44px (iOS HIG / Material touch target, WCAG 2.5.5), so the token cannot
     take the bar below what this file's own §touch block guarantees. */
  .bl-sticky .bl-cta{min-height:var(--fl-cta-hs)!important;height:var(--fl-cta-hs);
    font-size:var(--fl-cta-txts)!important;padding:0 var(--fl-cta-pad)!important;
    white-space:nowrap}
}
@media (max-width:1023.98px){
  .bl-cta{min-height:44px}
  /* the Live-chat / Telegram pills measured 43.x on it/help — padding and
     line-height, not intent; the same floor applies to them. */
  .bl-wapill,.bl-tgpill{min-height:44px!important}
  .bl-billing__link{padding-top:2px;padding-bottom:2px}
}/* the inline billing note is 23px tall on a desktop too — one pixel under the AA
   floor, so the floor is set for every width. Inline links in a sentence are
   exempt from 2.5.8, but a floor that costs one pixel is cheaper than an
   argument about the exemption. */
.bl-billing__link{min-height:24px!important}
/* THE COMPACT HEADER STILL HAS TO BE TOUCHABLE.
   `bundles/shared.css` shrinks the header pill's own CTA scale below 1024px
   (`--fl-cta-hs:clamp(30px,4.3vw,44px)`), which is how «Login» and «Start 7-day
   free trial →» measured 30px on a 390px screen — the compact scale was tuned
   for fit, before touch was measured. The floor goes back to 44 for the two
   controls only (the logo lockup keeps the compact scale, so the row grows by a
   few pixels and nothing is re-laid out), and the pill already wraps when
   nothing fits (components/bl-header.js). */
/* r109 — THE FOOTER GRID IS A NARROW-DESKTOP LAYOUT, NOT A PHONE ONE.
   The r38.2 block (src/ui/adaptiveCss.js → bundles/shared.css, home.css,
   pricing.css) turns `.bl-foot__cols` into `minmax(200px,340px) 1fr 1fr`
   under 1023px. Its own comment says «narrow DESKTOP», and the arithmetic
   agrees: the first track claims 200px and each `.bl-foot__col` carries
   `min-width:132px`, so the three tracks plus two ~28px gaps need ~520px of
   content box. At 390px there are ~330px, so the Support column is laid out
   past the right edge — where it still takes keyboard focus, while the
   document's own scrollWidth stays 390 and the visitor cannot bring it back.
   Below the width those tracks need, the base `.bl-foot__cols` flex row —
   which wraps — owns the footer again. Nothing about the desktop footer, the
   markup or the generated bundles changes; this is the site-wide adaptive
   layer doing what it exists for, and it loads after every one of them. */
@media (max-width:599.98px){
  .bl-foot .bl-foot__cols{display:flex;grid-template-columns:none}
  .bl-foot .bl-foot__brand{grid-row:auto}
}
@media (max-width:1023.98px){
  .bl-pill{--fl-cta-h:clamp(44px,4.3vw,48px)!important;--fl-cta-hs:clamp(44px,4.3vw,48px)!important}
  .bl-pill .bl-cta{min-height:44px!important}
}

/* ═══════════════════════════════════════════════════════════════════════════
   r109m — THE TYPE LADDER AND THE CONTROL TOKENS, SITE-WIDE.

   Asked for: pricing and registration-3, «по аналогии с главной». Both read the
   same ladder Home did — bundles/pricing.css and bundles/shared.css carry
   byte-identical copies of it — so the defect is identical too: every step was
   clamp(min, N vw, max) with a pure-vw middle term, which collapses onto floors
   chosen to keep 1440 proportions rather than to stay readable. On a 390px phone
   that is 11px body copy, 9.5px small print and an 11.5px button label.

   This file is linked by every shell and loads last, so the fix belongs here
   rather than in a third and fourth per-page layer. That means the other shells
   inherit it as well — deliberate, and worth stating plainly: the values below
   are the ones already measured on Home at 390 / 924 / 1440 and in en/es/it, and
   the two pages asked for share their whole CSS with those shells. Nothing here
   is new; it is the same block, applied where it was always missing.

   Why the shape and not just the numbers: the rem term is what makes the ladder
   respond to the reader's own browser font-size setting. A pure-vw font size
   ignores a 200% text-size preference outright (WCAG 1.4.4). Floors: body 16px
   on a phone (Material body-1, iOS HIG, and the size below which Safari zooms a
   focused field), supporting copy ≥13.5px, small print ≥12px.

   Controls move with the text through the same two tokens — a bigger label in an
   unchanged pill is the defect this pass exists to avoid — and on these two
   pages that also carries the plan cards' prices and the payment field, which
   read --fl-cta-* exactly as Home's hero field does.
   ═══════════════════════════════════════════════════════════════════════════ */
: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   */
  --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);
  --fl-cta-hs:   clamp(44px, 3.4vw, 54px);
  --fl-cta-pad:  clamp(16px, 1.95vw, 32px);
  --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 */
  --fl-more-txt: clamp(0.75rem,  0.715rem + 0.14vw, 0.875rem);
  --fl-cap:      clamp(0.781rem, 0.746rem + 0.14vw, 0.875rem);
  --fl-score:    clamp(0.875rem, 0.798rem + 0.31vw, 1.094rem);
  --fl-logo:        clamp(28px, 1.4rem + 0.90vw, 38px);
  --fl-logo-sticky: clamp(28px, 1.4rem + 0.90vw, 38px);
}
/* the same two strings Home needed: an error message is the highest-priority
   text on a form, and these pages are almost entirely forms. */
.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}
/* review cards are shared with Home; the testimonial is the page's evidence */
.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}
/* the footer is the same component on all eight shells */
.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}
.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}
.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}
/* r109n — the pill's SCOPED block, all five declarations. shared.css:434
   re-declares the whole token set on .bl-pill @≤1023, and custom properties
   inherit, so everything inside the hero pill reads THAT block and not :root —
   the ladder above cannot reach it. Carrying only --fl-logo over from Home left
   the pricing hero exactly where Home's was before it was fixed: Login 10.35px,
   the trial CTA 9.89px, badge labels 8.60px, the sub-label 7.21px.
   !important because components/bl-header.js re-injects this same block at
   runtime as the last <style> in <head>, where no linked sheet can out-order it
   (site.responsive.css already relies on this for --fl-cta-h). */
@media (max-width:1023.98px){
  .bl-pill{
    --fl-logo:     clamp(26px, 1.3rem + 0.70vw, 32px)!important;
    --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 */
  }
}
@media (max-width:599.98px){
  .bl-foot .bl-foot__col:has(>.bl-foot__go){grid-column:1/-1}
}

/* ── r109x — THE PILL GOES BACK TO PROGRESSIVE DEGRADATION ─────────────────
   Owner: «что ты намутил? регрессия». Correct, and the diagnosis is mine to own.
   The pill was never meant to stack. Its design is ONE row that sheds cargo as
   the viewport narrows: three trust badges, then two, then one, then none; then
   Login goes; the primary action is the last thing standing. r109p–w replaced
   that with a forced three-row centred block — which fixed the four-line CTA and
   broke the behaviour the layout was built around.
   So the forcing is gone: no flex-wrap:wrap on .bl-pill, no flex-basis:100% on
   .bl-pill__logo / .bl-pill__end, no centring, no reserved band under the badge
   row. What stays is the one thing that was a real defect — the CTA label wraps
   to four lines because shared.css sets white-space:normal on it, and a
   fixed-height pill cannot hold four lines at any size.
   The shedding is expressed as widths, not as guesses: each threshold is the
   point at which the row can no longer hold that item plus the primary action at
   its verified size, and es/it labels are the longer ones, so each drop is set
   by the longest locale rather than by English. */
.bl-pill .bl-cta--dark{white-space:nowrap!important;max-width:none!important;
  min-width:0!important;overflow:hidden;text-overflow:ellipsis}

/* 1023 → 900: the third badge is the first thing the row cannot afford. */
@media (max-width:1023.98px){
  .bl-pill-badges{min-width:0!important}
  .bl-pill-badges>*{flex:0 1 auto!important;min-width:0!important}
  .bl-pill-badges>*:nth-child(n+3){display:none!important}
}
/* 900 → 720: down to a single badge. */
@media (max-width:899.98px){
  .bl-pill-badges>*:nth-child(n+2){display:none!important}
}
/* 720 → 560: the badges have said all they can; the row is brand + two actions,
   which is what the header is actually for. */
@media (max-width:719.98px){
  .bl-pill-badges{display:none!important}
}
/* below 560 Login stands down — it is reachable from the footer of every page
   and from the sticky bar, while the trial CTA is the page's one job. This is
   the same call components/site.responsive.css already makes for the sticky bar
   («.bl-sticky .bl-cta--ghost{display:none}» in its ≤599 branch). */
@media (max-width:559.98px){
  .bl-pill .bl-cta--ghost{display:none!important}
  /* r110a — the .bl-pill__end declaration that used to live here moved into the
     ≤719 block below: it sat EARLIER in the file, so the later ≤719 copy won at
     this width too and replaced the shrink with flex:0 0 auto. One owner. */
}

/* ── r109y — THE PLAN CARDS: ONE GRID, THREE INTENTS ───────────────────────
   Forcing a single 815px column at every width below 1024 was the same mistake
   in the other direction: it threw away the tablet layout to fix the tablet
   crush. Three intents, three widths, and the card's own auto-fit does the work:
     ≥1024  three across — the comparison the page exists for
     600-1023  two across — a 380px card holds its lines, which is what broke
     ≤599  one across — the original phone design, unchanged
   No fixed column count below 600, so nothing can orphan a card again. */
/* r109z — 2-up is never right for THREE tiers: it puts Max alone on row two
   with 463px empty beside it, which both breaks the side-by-side comparison the
   page exists for and re-creates the dead space r109v claimed to have removed.
   The count was the wrong lever. One column was structurally right all along —
   what actually read as broken was the MEASURE: .bl-card-tier carries
   max-width:none, so a single column stretched one card to 815px.
   So the item is constrained instead of the track: one centred column with a
   comfortable card measure. Tablet gets its own look (a centred 520px card,
   wider than the phone's full-bleed one), the phone keeps its original
   full-width card, and no width can orphan a tier. */
/* r110 — OWNER'S CALL, and it is the right one: three tiers stay THREE ACROSS
   on a tablet and become one column only on a phone. A pricing table is a
   comparison; stacking it on a 900px screen destroys the thing the page is for,
   and a centred single card left half the row empty.
   Three across at 600-1023 means ~290px per card, so the CARD has to give — not
   the grid. Padding, the CTA's own padding and the gap come down at that band so
   the copy keeps a usable measure inside a narrower card; the type itself is left
   on the ladder, because shrinking it back is what this whole session undid. */
@media (min-width:600px) and (max-width:1023.98px){
  div:has(>.bl-card-tier){grid-template-columns:repeat(3,minmax(0,1fr))!important;
    gap:clamp(10px,1.4vw,16px)!important}
  .bl-card-tier{padding:clamp(14px,1.8vw,20px)!important;max-width:none!important}
  [data-bl-plan]{padding-left:8px!important;padding-right:8px!important;
    white-space:normal!important;text-wrap:balance;line-height:1.2}
}
@media (max-width:599.98px){
  div:has(>.bl-card-tier){grid-template-columns:1fr!important}
  .bl-card-tier{max-width:none!important}
}

/* ── r110 — THE PILL MUST NOT KEEP THE ROOM IT NO LONGER USES ──────────────
   .bl-pill is justify-content:space-between, and .bl-pill__end keeps a flexible
   basis — so once the badges and Login have shed, the end container still holds
   its share of the row and leaves an empty box to the right of the CTA (owner's
   red rectangle). The point of shedding is that the row gets TIGHTER, so the
   container hugs its remaining contents and the pill closes up around them. */
@media (max-width:719.98px){
  /* r110a — grow AND shrink, not flex:0 0 auto. flex-grow:1 with
     justify-content:flex-end already closes the owner's empty box — the CTA sits
     flush against the pill's right padding with no dead gap — while
     flex-shrink:1 + min-width:0 is what lets the container narrow so the CTA's
     own overflow:hidden/text-overflow:ellipsis can engage. Without the shrink the
     container refuses to give, so there is nothing to clip against and the pill
     overflows instead: 21px in EN at a 390px phone, 125px with «Empezar mi
     prueba gratis de 7 días →». The ellipsis is the designed degradation; a pill
     hanging off the side of the screen is not. */
  .bl-pill__end{flex:1 1 auto!important;min-width:0!important;
    justify-content:flex-end!important}
  .bl-pill{gap:clamp(8px,2vw,16px)!important}
}

/* ── r113 — THE PHONE HEADER IS TWO ROWS AGAIN (owner, with a screenshot) ───
   «ты сломал все шапки на моб версии, ранее был иной дизайн адаптивной шапки…
   логотип и черная кнопка стали кривыми». Correct, and the regression is r112's:
   T4 deleted Home's forced stack as a duplicate of the site-wide progressive
   degradation — but degradation below 560px has nowhere left to shed. The row is
   already brand + primary action, and the action alone does not fit: the full
   label is 34 characters (ES «Empezar mi prueba gratis de 7 días →» is longer),
   so the ≤719 shrink + ellipsis clips the button INTO the lockup — which is the
   crooked header in the screenshot. Ellipsising the one control that earns is not
   a degradation step, it is a defect; and pricing/reg pages never even get the
   compact label (components/bl-responsive-copy.js loads on Home only).

   So below 560px the pill wraps into the two rows it had before r112 — brand,
   then the action — and this time it is written ONCE, on .bl-pill, in the file
   that owns the pill's degradation, so every page behaves identically (r109p's
   real mistake was scoping the stack to [data-bl-island="hero-pill"] on Home).
   Two differences from r109p, both from the r109x post-mortem:
     • the CTA is NOT stretched to the full row — it keeps width:fit-content and
       is centred, so nothing can draw over the lockup;
     • on its own row the label WRAPS (max 2 lines) instead of being clipped: a
       header can afford a second line, it cannot afford a half-read promise.
   Placed after the ≤719 block on purpose: both are (0,1,0)+!important, so source
   order decides. Do not move it above them. */
@media (max-width:559.98px){
  .bl-pill{flex-wrap:wrap!important;justify-content:center!important;
    row-gap:10px!important;
    padding:12px var(--fl-pill-pad) 14px!important}
  .bl-pill__logo{flex:0 0 100%!important;justify-content:center!important}
  .bl-pill__end{flex:0 0 100%!important;min-width:0!important;
    justify-content:center!important}
  .bl-pill .bl-cta--dark{flex:0 1 auto!important;width:fit-content!important;
    max-width:100%!important;white-space:normal!important;text-wrap:balance;
    overflow:visible!important;text-overflow:clip!important;line-height:1.2}
}

/* ── r110b — THE REVIEWS WALL NEEDS THE PAGE'S OWN INSET ───────────────────
   Owner screenshot: the review cards sit flush against both edges of the page.
   Home's wall is fine because bundles/home.css gives .bl-reviews
   `padding: var(--fl-sec) var(--fl-inset) 0`; the walls that were added to the
   other surfaces later never got it, so their cards run to the document edge
   with no gutter — and a card with a border and a shadow needs one, or the
   shadow reads as a cut.
   --fl-inset is the page's single horizontal rhythm value, so the wall lines up
   with every other block above and below it rather than with a new number.
   r110d — grounded on .bl-revtrack, the wall's real grid container. The first
   attempt used .bl-reviews (a Home-only class that these pages never carry) and
   an invented [data-bl-reviews-wall], so it matched nothing while the wall stayed
   full-bleed beside H2s sitting in a 48px gutter. .bl-revslide is no use either:
   it computes to display:contents, so it has no box to pad. */
.bl-revtrack{padding-left:var(--fl-inset);padding-right:var(--fl-inset);
  box-sizing:border-box}
/* r110e — ONE gutter per wall. Home already owns one: bundles/home.css ships
   `.bl-reviews{padding:var(--fl-sec) var(--fl-inset) 0}`, and .bl-revtrack is a
   descendant of it, so the rule above stacked a second inset on top and pushed
   the cards 48px past their own heading. Where the container carries the gutter,
   the track carries none. */
.bl-reviews .bl-revtrack{padding-left:0!important;padding-right:0!important}

/* ═══════════════════════════════════════════════════════════════════════════
   r110g — THE REGISTRATION / LOGIN TOKENS, RE-APPENDED.

   This block was authored in r109s and then destroyed by r109x: that rebuild
   sliced the file at the r109p marker and re-wrote everything after it, and this
   block had been appended later, so it went out with the pill work it was never
   part of. Recorded here because it is the failure mode of a slice-and-rebuild,
   not of a rule: anything appended after the cut point is silently in scope.

   reg-1, reg-2, reg-4, login and the recovery screens do not read the --fl-t
   ladder for their body text. They have their own set (bundles/shared.css:50-62)
   and it is sized by VIEWPORT HEIGHT:

     --fl-reg-h1:    clamp(19px, 3vh,   28px)
     --fl-reg-body:  clamp(13px, 1.8vh, 16px)
     --fl-reg-small: clamp(11px, 1.5vh, 13px)
     --fl-reg-quote: clamp(15px, 2.6vh, 24px)
     --fl-reg-field: clamp(44px, 6.4vh, 60px)

   On a 640px-tall phone every one sits on its floor: a 19px H1 over 13px body
   over 11px small print — the whole funnel's copy smaller than the marketing
   page that feeds it.

   But the floors are the lesser problem. SIZING TYPE BY vh IS WRONG ON A FORM.
   When the on-screen keyboard opens, the viewport height drops 40-50%, so every
   one of these RESHRINKS while the visitor is typing — heading, body copy and
   the field itself all step down mid-interaction, on the screens where the field
   IS the page. That is not a scale, it is a layout that moves under the user.
   And like the ladder before it, a pure viewport unit ignores the reader's own
   font-size preference (WCAG 1.4.4).

   So these five move to rem + vw: stable while typing, responsive to the
   reader's setting, floored where the funnel can be read —
     h1 24→32 · body 16→18 · small 13→15 · quote 17→26
   The field takes --fl-cta-h's own expression so the input and the button beside
   it are one height by construction rather than two numbers that agree today.
   The vh GAPS are left alone: spacing by available height is legitimate, and it
   is what keeps these pages on one screen.

   NOTE this also carries src/pages/login.content.js's BRAND_TXT, which was
   pointed at --fl-reg-small in place of its own clamp(13px,2vh,19px): without
   this block that token resolves to 11px, so the 13 trust-marquee labels per
   page were left SMALLER than before that edit. With it they are ≥13px. */
:root{
  --fl-reg-h1:    clamp(1.5rem,   1.281rem + 0.90vw, 2rem);      /* 19 -> 24-32 */
  --fl-reg-body:  clamp(1rem,     0.945rem + 0.23vw, 1.125rem);  /* 13 -> 16-18 */
  --fl-reg-small: clamp(0.813rem, 0.758rem + 0.23vw, 0.938rem);  /* 11 -> 13-15 */
  --fl-reg-quote: clamp(1.063rem, 0.816rem + 1.01vw, 1.625rem);  /* 15 -> 17-26 */
  --fl-reg-field: clamp(48px, 4.2vw, 64px);                      /* 44 -> 48-64 */
}


/* ── r115 — THE TELEGRAM IN-APP BROWSER SHOWS THE PAGE ABOVE THE HEADER ────
   ФР (owner screenshots 5 and 6, iOS Telegram webview, mid-scroll): a live
   strip of the page is visible ABOVE the sticky header, with a magenta rule
   under it. Both are one root cause and it is not a layout bug.

   In an iOS in-app browser the VISUAL viewport and the LAYOUT viewport come
   apart during scroll — the host app's own chrome overlays the top and the
   page keeps scrolling behind it. `position:fixed` is anchored to the LAYOUT
   viewport, so both fixed elements on this page (`.bl-sticky` at z-index 9000
   and `.bl-bar` at 9999) are painted some 90px below the real top edge, and
   what fills that strip is the scrolled document. Screenshot 6 is the header
   with the hero's input field showing above it; screenshot 5 is the same thing
   with the header still hidden, so only the magenta line is left.

   ОР: nothing of the page above the header, ever. Two declarations:

   1. The bar owns the space above itself. `::before` is a child, so it rides
      the same `translateY(-130%)` when the bar is away and cannot leak at the
      top of the page; when the bar is in view it paints its own white up to
      320px above its edge, which is more than any mobile browser chrome. This
      is the standard treatment for the case and it costs no layout: the
      pseudo-element is absolutely positioned outside the flow.
   2. The finished load bar retires. `.bl-bar.is-done` was a permanent 3px
      gradient line pinned to `top:0` for the life of the page — invisible at
      the top edge of a desktop window, a stray rule floating over content in a
      shifted mobile viewport. It now plays its completion pulse (blBarDone,
      unchanged) and then collapses. A progress bar that has finished has said
      everything it has to say.
   All widths and all pages: the cause is the browser, not the breakpoint. */
.bl-sticky::before{content:"";position:absolute;left:0;right:0;bottom:100%;
  height:320px;background:#FFFFFF;pointer-events:none}
@keyframes blBarRetire{to{height:0;opacity:0}}
.bl-bar.is-done{animation:blBarRetire .34s ease-out .9s forwards;overflow:hidden}
@media (prefers-reduced-motion:reduce){
  .bl-bar.is-done{animation:none;height:0;overflow:hidden}
}
