/* ATTIC BREEZE - homeowner ventilation calculator, MOBILE UX PASS
 * /homeowners/ventilation-calculator/  (page 8863)             2026-08-27
 *
 * Loaded by wp-content/novamira-sandbox/ab-hoc-mobile.php at priority 103, so
 * this sheet prints AFTER abv-hlook (99), abv-hcalc (100), abv-hux (101) and
 * abv-hcx-calc (102). Every override below therefore wins on source order at
 * equal specificity - there is no !important anywhere in this file.
 *
 * Disable the loader to revert the whole pass. Nothing here changes markup,
 * state, engine values or any committed answer.
 *
 * ------------------------------------------------------------------------ */


/* ==========================================================================
   1. THE SLOPE RAIL WAS UNREACHABLE AT BOTH ENDS   *** THE ROOF PITCH BUG ***
   ==========================================================================
   MEASURED, at a 390px viewport, before this fix:

     rail port 335 . card min(78%,300px) = 261 . six cards
     scroll-snap-type: x mandatory  +  scroll-snap-align: center
     no side padding on the scroller

   A card can only be CENTRED when the scroller can reach
   `scrollLeft = cardCentre - port/2`. The deficit at each end is
   (port - card)/2 = (335 - 261)/2 = 37px, so:

     card 0 "Flat or very low"  needs scrollLeft   -37                -> impossible
     card 5 "Extra steep"       needs scrollLeft 1335, maxScroll 1298 -> impossible

   The four middle cards are reachable. The two OUTER ones have no valid snap
   position at all. Chromium clamps to 0 / maxScroll and tolerates it, which is
   why this never appeared in desktop emulation. Safari enforces `mandatory`
   strictly - it will not rest on a non-snap offset and springs back to the
   nearest VALID snap point - so on iOS the rail bounces off both ends and the
   first and last roof shapes cannot be settled on, or tapped. That is the
   reported "roof pitch glitches / gets stuck and never reaches the sun
   question": with no pitch committed, gate() keeps Continue disabled and
   syncSunVisible() keeps the sun row hidden, exactly as designed.

   IT IS GEOMETRY, NOT STATE. abv-pitch.js is not touched: apply(), the helper,
   identBest(), the two-step low-slope card and every committed pitch label are
   exactly as they were. Only the set of scroll offsets the rail may rest at
   changes.

     1. scroll-snap-align: start - card 0's snap position becomes exactly 0,
        which is always reachable. Start-alignment is also what leaves the next
        card peeking, which is the affordance that says "there are more".

     2. A trailing spacer so the LAST card's snap position lands exactly on
        maxScroll. For a start-aligned rail that spacer is

            spacer = port - card

        independent of the card count and of the gap, because the last card
        already carries margin-inline-end: 0. Proportionally that is
        `calc(100% - min(78%, 300px))`, which stays exact at every width.

        It is a ::after pseudo-element and NOT padding on the scroller:
        percentage padding would shrink the flex container's content box, and
        the cards' own 78% basis resolves against that same box, so padding
        would feed back into the card width. A pseudo-element flex item does not.

        paintBuckets() repaints the rail with innerHTML, which cannot remove a
        CSS-generated ::after. The spacer survives every repaint.
   ========================================================================== */
@media (max-width: 1024px) {
  body.ab-hcx .elementor-9063 .abv-root .abv-bks > .abv-bk {
    scroll-snap-align: start;
  }
  body.ab-hcx .elementor-9063 .abv-root .abv-bks::after {
    content: '';
    order: 99;                 /* never let a future reorder strand it mid-rail */
    flex: 0 0 calc(100% - min(78%, 300px));
    min-width: 0;
  }
}


/* ==========================================================================
   2. "HOW IT LOOKS" - THE LAST CARD COULD NOT BE REACHED EITHER
   ==========================================================================
   Same defect, milder shape. abv-hlook.css part 12 gives the appearance band
   `flex: 0 0 86%` cards with `scroll-snap-align: start` and gap 14px, and no
   trailing spacer, so at 390px the third card's snap position (630) sits 49px
   past maxScroll (581) and cannot be rested on.

   Here the spacer must also absorb the gap that precedes it, because `gap`
   applies between EVERY pair of flex items including the pseudo-element:

       spacer = port - card - gap

   TWO THINGS THIS GOT WRONG FIRST TIME, both found by measuring:

   1. THE CARD IS NOT 86%. abv-hlook.css part 12 says `flex: 0 0 86%`, but
      abv-hux.css wins with `flex: 0 0 min(82%, 560px)` on the shared
      `.abhc-rail.e-con > .abhx-card`, which is the rule that actually sizes
      these cards (287px at a 390px viewport, not 301px). The spacer has to be
      written against the rule that WINS, not the one that reads first.

   2. A ::after FLEX ITEM DEFAULTS TO `order: 0`. abv-hlook.js lifts the
      recommended product to the front of the rail with `order` - the three
      cards carry order 0, 1 and 3 - so a spacer left at the default order sat
      BETWEEN the first and second card instead of after the last one, and the
      last card stayed unreachable. `order: 99` puts it at the end whatever the
      recommendation reorders.

   The gap goes 14px -> 16px: still inside the 14-18px the brief asks for, and
   the extra 2px is what stops two white cards on a white band reading as one
   block with a seam.
   ========================================================================== */
@media (max-width: 767px) {
  body.ab-hcx .elementor-9063 .abhx-looks__grid.e-con-full,
  body.ab-hcx .elementor-9063 .abhx-looks__grid.e-con-boxed > .e-con-inner {
    gap: 16px;
    scroll-padding-inline-start: 0;
  }
  body.ab-hcx .elementor-9063 .abhx-looks__grid.e-con-full::after,
  body.ab-hcx .elementor-9063 .abhx-looks__grid.e-con-boxed > .e-con-inner::after {
    content: '';
    order: 99;
    flex: 0 0 calc(100% - min(82%, 560px) - 16px);
    min-width: 0;
  }
}


/* ==========================================================================
   3. RESULT TYPOGRAPHY - ONE POPPINS STACK, NOT TWO
   ==========================================================================
   The result screen mixes two font stacks:

     --abv-font   'Poppins', system-ui, ...                             (abv-tokens.css)
     --abhx-font  'Poppins', 'Poppins metric fallback', system-ui, ...  (abv-hlook.css)

   Seven elements resolve to --abv-font - the "Recommendation ready" chip and
   its tick, "Download my recommendation", "Share plan" - and everything else
   resolves to --abhx-font. Once Poppins is cached both render Poppins, so this
   is invisible on a second visit and never showed up in a computed-style audit:
   every element reports font-family starting "Poppins".

   IT IS NOT INVISIBLE ON FIRST PAINT. The result screen is the first place the
   page asks for WEIGHT 800, so that face is fetched at the moment the
   recommendation appears. During the swap --abhx-font falls back to
   'Poppins metric fallback' (a size-adjusted stand-in carrying Poppins'
   metrics) while --abv-font falls straight through to system-ui - San
   Francisco on iOS. Two visibly different typefaces render side by side for the
   length of the font fetch. That is the reported "typography switches to a
   different font once it finishes calculating".

   Fixed at the token and scoped to this page, so the professional calculator's
   --abv-font is left exactly as it was. No !important, and no blanket
   font-family override: those seven elements go on inheriting normally, they
   just now inherit a stack with the same fallback as their neighbours.
   ========================================================================== */
body.ab-hcx .elementor-9063 .abv-root {
  --abv-font: var(--abhx-font);
}


/* ==========================================================================
   4. THE HERO'S PAIRED CTAs SIT SIDE BY SIDE
   ==========================================================================
   abv-hcalc.css stacks .abhc-ctarow below 600px, which gave two 350px pills -
   90% of a 390px viewport - one under the other. The Elementor container is
   already set to Direction: Row; only that one media query overrode it, so this
   restores the container's own setting rather than fighting it.

   Both buttons share the row equally (flex: 1 1 0 with min-width: 0, so a long
   label shrinks its box instead of pushing the row wider than the viewport).
   Text wraps rather than shrinking: white-space has to be reset on the inner
   .elementor-button-text too, because `nowrap` inherits down from the button.
   min-height keeps the 48px touch target while the label wraps to two lines.
   ========================================================================== */
@media (max-width: 600px) {
  body.ab-hcx .elementor-9063 .abhx-ctarow.abhc-ctarow {
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 10px;
  }
  body.ab-hcx .elementor-9063 .abhx-ctarow.abhc-ctarow > .elementor-widget {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
  }
  body.ab-hcx .elementor-9063 .abhx-ctarow.abhc-ctarow .elementor-button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    min-height: 48px;
    padding: 12px 14px;
    line-height: 1.25;
    white-space: normal;
    text-align: center;
  }
  body.ab-hcx .elementor-9063 .abhx-ctarow.abhc-ctarow .elementor-button-text {
    white-space: normal;
  }
}


/* ==========================================================================
   5. THE SHARED `.abhc-rail` HAD THE ROOF-SLOPE BUG TOO, ON BOTH ITS RAILS
   ==========================================================================
   Found by sweeping the page at 320/375/390/430/768/820/1024 rather than by
   looking at it. Two rails on this page share the `.abhc-rail` class and both
   are `scroll-snap-align: center` on a `mandatory` scroller with no side
   padding - the exact defect that made the roof-slope cards unreachable:

     .abhx-sym__grid   (the three scenario cards)
     .abhx-looks__grid (the appearance band)

   At a 390px viewport, port 350 and card min(82%,560px) = 287:

     deficit = (port - card)/2 = (350 - 287)/2 = 31.5px
     card 0 needs scrollLeft  -31.5              -> impossible
     card 2 needs scrollLeft  570.5, maxScroll 539 -> impossible

   So on iOS the first and last scenario card, and the first and last product
   card, spring away from the finger. Only the middle one can be settled on.

   START-ALIGNMENT + A TRAILING SPACER, for the same reasons set out in part 1:
   card 0's snap becomes exactly 0, and the spacer puts the last card's snap
   exactly on maxScroll.

   THE SPACER IS SIZED PER RAIL because the two rails space their cards
   differently: the scenario rail uses a 14px margin on the card and no `gap`,
   the appearance rail uses a 16px `gap` (which also applies before the
   pseudo-element, so it has to come out of the spacer). Over-sizing a spacer is
   harmless - it only adds trailing room - but under-sizing leaves the last card
   unreachable, which is the bug.

   `order: 99` on both, because abv-hlook.js lifts the recommended product with
   `order` and a default-order spacer would sit mid-rail.
   ========================================================================== */
@media (max-width: 1024px) {
  body.ab-hcx .elementor-9063 .abhc-rail.e-con > .abhx-card {
    scroll-snap-align: start;
  }
  body.ab-hcx .elementor-9063 .abhx-sym__grid.abhc-rail::after {
    content: '';
    order: 99;
    flex: 0 0 calc(100% - min(82%, 560px));
    min-width: 0;
  }
}
/* 1024, not 767: the appearance rail is sized by `.abhc-rail.e-con > .abhx-card`
   which runs to 1024, so it is STILL a scroller at 768-1024 (measured) and the
   767-scoped spacer above left its last card unreachable there. The gap is
   restated at the same breakpoint so the spacer arithmetic matches. */
@media (max-width: 1024px) {
  body.ab-hcx .elementor-9063 .abhx-looks__grid.abhc-rail {
    gap: 16px;
  }
  body.ab-hcx .elementor-9063 .abhx-looks__grid.abhc-rail::after {
    content: '';
    order: 99;
    flex: 0 0 calc(100% - min(82%, 560px) - 16px);
    min-width: 0;
  }
}


/* ==========================================================================
   6. THE LAST FULL-WIDTH BAR ON THIS PAGE
   ==========================================================================
   The pre-footer "FIND AN INSTALLER" ran to 350px of a 390px viewport - 90% -
   which is the giant-bar shape the brief rules out for a lone CTA. Capped and
   centred at 320px, the same cap Beat the Heat and Find an Installer use for a
   single CTA, so all three homeowner pages agree.
   ========================================================================== */
@media (max-width: 767px) {
  body.ab-hcx .elementor-9063 .elementor-element-hohelpcopy .elementor-button {
    width: auto;
    max-width: 320px;
    margin-inline: auto;
    min-height: 48px;
  }
}
