/* ==========================================================================
   home-mobile.css — the homepage below 768px, rebuilt from Figma's own
   mobile design: FRAME "Homepage - Mobile version" 7053:2, canvas 428 x 15377.
   ==========================================================================

   Read design-reference/mobile/MOBILE-NOTES.md before editing. Every number
   here is `figma_mobile_px / 16`, because base.css sets the sub-768 root to
   `calc(100vw / 26.75)` (428/16), so 1rem == 1 Figma mobile px at 428 wide.

   PURELY ADDITIVE. Every rule is inside `@media (max-width: 767.98px)`, so the
   locked >=768 render is untouched by construction — not by luck. This sheet
   loads LAST (after home-sections.css), so it wins on render order and needs
   no specificity tricks.

   Loading order, all <link>s in <body>, no `precedence` -> pure render order:
     1 base.css        (layout.tsx)
     2 motion.css      (layout.tsx)
     3 home.css        (page.tsx)
     4 home-sections.css (page.tsx)
     5 home-mobile.css (page.tsx)   <- here

   COMPLETE as of 2026-08-05 — §1, §1b, §2, §3, §4, §5, §6, §7, §8, §9, §10,
   §11a, §11b and the sticky quickbar are all built and measured against Figma.
   Every section boundary lands flush and exact on the 428 canvas:
     §1 0 · §1b 958 · §2 1054 · §3 2184 · §4 3827 · §5 5822 · §6 6842 ·
     §7 7494 · §8 8565 · §9 10446 · §10 11260 · §11a 12240 · §11b 13408
   and `document.scrollHeight` at 428 is 15376 against Figma's 15377-tall canvas.

   The one thing still open is NAVIGATION: the header burger (7053:15) and the
   quickbar burger (7053:266) both have empty `interactions` and the Figma file
   has no menu or drawer screen at all, so both are inert marks and mobile has
   no navigation. A drawer would be invented design — it needs the user's call.

   All 15 of the old narrow-DESKTOP fallback blocks in home-sections.css are now
   GONE — `grep -c "@media (max-width" public/assets/css/home-sections.css` is 0.
   They were never a phone layout and they fought the real mobile numbers at
   every turn (§3's `min-height: 28.75rem` beat the true 439 card height; §11's
   720 block put `padding: 1rem` on `.qna-faq`, which sits OUTSIDE the button
   that owns Figma's padding, so every FAQ row rendered 32px too tall). Several
   sections had two or three blocks rather than one, because the 720/620 ones
   were already below the old floor and never got moved to 767.98.
   home-sections.css is now purely the >=768 render; everything below lives here.
   ========================================================================== */

/* Mobile-only elements are hidden by default, BEFORE the media query — a bare
   `display: none` after it would win on order and hide them everywhere. */
.hero-burger { display: none; }

/* Copy swaps. Seven places in the mobile frame use different words to the
   desktop frame (see design-reference/mobile/BUILD-PLAN.md); each is a
   `.d-only` / `.m-only` <span> pair so the locked desktop copy is untouched.
   Both are `inline` — every swap so far is a text run inside a heading.
   Where the swap is a whole BLOCK whose own rule owns `display` (§6's check
   row is a `.icar-bullets` flex row), the pair gets its own classes instead so
   `display` is never clobbered — see `.icar-bullets-d` / `-m` below. */
.m-only { display: none; }
.icar-bullets-m { display: none; }

/* §8's band needs its OWN pair of gates, and this is the trap worth knowing: the
   two utilities above are (0,1,0), while `.sob-band img` in home-sections.css
   declares `display: block` at (0,1,1) — so a bare `.m-only` LOSES and the still
   would keep painting under the desktop clip. §4's cards get away with the plain
   utility only because `.psh-shot` declares no `display` at all. (0,2,0) is what it
   takes; both rules are pure gates, no geometry. Hidden here BEFORE the query for
   the reason above — after it, this would hide the still at every width. */
.sob-band .m-only { display: none; }

@media (max-width: 767.98px) {

.d-only { display: none; }
.m-only { display: inline; }

/* ...and the mirror image below 768: the still comes back (as `block`, which is what
   `.sob-band img` gives it today — NOT the utility's `inline`, so nothing about the
   mobile render changes), and the clip goes. The <source>s are `media`-gated too, so
   mobile does not merely hide the video, it never fetches it. */
.sob-band .m-only { display: block; }
.sob-band .d-only { display: none; }

/* ==========================================================================
   §1  HERO — FRAME "Homepage" 7053:5, 428x926, clipsContent
   ========================================================================== */

.hero {
  height: 57.875rem;              /* 926 */
}

/* --- background -----------------------------------------------------------
   Figma nests the sky in a 1920x1051 frame at (-890, 0) whose IMAGE fill is
   scaleMode STRETCH with imageTransform [[0.8577134,0,0.14228661],[0,1,0]] —
   i.e. it shows the RIGHT 85.77% of the source, stretched on both axes
   independently. Composing the frame offset with that crop collapses to one
   element: full image width = 1920 / 0.8577134 = 2238.51, left = -890 -
   (0.14228661 / 0.8577134) * 1920 = -1208.51. `object-fit: fill` because the
   two axes are scaled independently (sy = 1, sx = 0.8577134), so `cover` would
   letterbox the crop back in.
   Mobile has ONE sky, 1051 tall against a 926 hero — no mirrored second copy. */
.hero-sky {
  left: -75.5318751914rem;        /* -1208.5100030625 */
  top: 0;
  width: 139.9068731066rem;       /*  2238.5099697061 */
  height: 65.6875rem;             /*  1051 */
  max-width: none;                /* home.css's `img { max-width: 100% }` clamps 2238 -> 428 */
  object-fit: fill;
}
.hero-sky-flip { display: none; }

/* 7053:10 — 428x526 @ (0,0). Stop is #ffffff a0.8 but the PAINT also carries
   opacity 0.5, so the effective top stop is 0.4, not desktop's 0.8. Height is
   the same 526 either way. */
.hero-grad-top {
  height: 32.875rem;              /* 526 */
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0));
}

/* 7053:40 — 428x275 @ (0,651); 651 + 275 = 926 = the hero bottom exactly. */
.hero-grad-bottom {
  bottom: 0;
  height: 17.1875rem;             /* 275 */
}

/* 7053:9 — the house photo IS the box on mobile: 823x469 @ (-195, 529), FILL.
   Box aspect 1.75480 vs the photo's 1661/947 = 1.75396, so `cover` crops ~0.05%
   off the sides — the same thing Figma's FILL does. There is no mirrored
   second house here: 7053:7 / 7053:8 are the pair and both are visible:false. */
.hero-houses {
  top: 33.0625rem;                /*  529 */
  left: -12.1875rem;              /* -195 */
  width: 51.4375rem;              /*  823 */
  height: 29.3125rem;             /*  469 */
  transform: none;                /* drops the desktop translateX(-50%) */
}
.hero-house-main { left: 0; width: 100%; height: 100%; }
.hero-house-mirror { display: none; }

/* GROUP 7053:31 — 368 x 108.69 @ (57, 590). That is the desktop panel outline
   at 50.2% (733 x 216.5), and home-hero-paneloutline.svg is viewBox
   735.618x221.753 with preserveAspectRatio="none", so the same asset stretches
   to fit. Expressed as % of the 823x469 house box above, so it rides the box:
     left  (57 - -195) / 823   top  (590 - 529) / 469
     width  368 / 823          height 108.69 / 469                            */
.hero-panel-outline {
  left: 30.6196841%;
  top: 13.0063966%;
  width: 44.7144593%;
  height: 23.1748401%;
}

/* --- header — FRAME "Header Container" 7053:12, 428x88 @ y32 ---------------
   auto-layout HORIZONTAL, SPACE_BETWEEN, padding 20/24/20/20, radius 14.
   The counter axis is 48 (the burger), NOT 60 (the logo): Figma's logo lives
   in a 336x24 FILL frame and overflows it by 18 top and bottom, so it must not
   grow the header. Hence `.header-left { height: 1.5rem }` — 20 + 48 + 20 = 88.

   THE TOP MARGIN IS 16, NOT FIGMA'S 32 — the user's explicit call on 2026-08-05.
   So the header box runs y16 -> y104 and `.hero-inner` starts at 104, which pulls
   the whole hero copy block (h1 136, sub 254, CTA 338, checks 414) and the
   absolutely-positioned `.hero-reviews` up by 16 with it — the reviews land on
   540.38 rather than Figma's 556.38, keeping their offset from the check row.
   `.hero-callout` and `.hero-houses` are positioned against `.hero`, not
   `.hero-inner`, so they stay put, and the hero is still exactly 926 tall.
   Do not "fix" the 16 back to 32. */
.site-header {
  max-width: none;
  margin: 1rem 0 0;                              /* 16 — user's call 2026-08-05, was Figma's 32 */
  padding: 1.25rem 1.5rem 1.25rem 1.25rem;       /* 20 24 20 20 */
  gap: 0;
}
.header-left {
  flex: 1 1 auto;                 /* Figma: layoutGrow 1 / sizingH FILL */
  height: 1.5rem;                 /* 24 — the logo overflows this on purpose */
}
.header-right { flex: 0 0 auto; }
.header-nav { display: none; }    /* mobile has no nav links at all */
.header-right .btn { display: none; }            /* replaced by the burger */
.logo { filter: drop-shadow(0 0 3.125rem white); }  /* r50, was r40 on desktop */

/* FRAME "Link - Solid Black" 7053:15 — 48x48, r12, #ffffff, stroke #111111 w2.
   Inner icon frame is 32x32 at rel(8,8); three bars 24 x 2.6667 at icon-rel
   y 6.6667 / 14.6667 / 22.6667 -> pitch 8, so the gap is 8 - 2.6667 = 5.3333.
   The bars are pure #000000; only the button's border is #111111.
   Visual only — Figma wires no interaction on this node and the file contains
   no menu/drawer screen. See the note in app/page.tsx. */
.hero-burger {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3333333333rem;           /* 5.3333 */
  width: 3rem; height: 3rem;      /* 48 */
  box-sizing: border-box;
  border: 0.125rem solid var(--ink);
  border-radius: 0.75rem;         /* 12 */
  background: var(--white);
}
.hero-burger > span {
  display: block;
  width: 1.5rem;                  /* 24 */
  height: 0.1666666667rem;        /* 2.6667 */
  background: #000000;
}

/* --- hero copy ------------------------------------------------------------
   Figma order top-to-bottom is h1, sub, CTA, checks — the CTA and the checks
   are SWAPPED relative to the desktop DOM, hence the explicit `order`s.
   The trustpilot cluster leaves the flow entirely (see below).             */
.hero-inner { align-items: center; }
.hero h1        { order: 1; }
.hero-sub       { order: 2; }
.hero-inner > .btn { order: 3; }
.hero-checks    { order: 4; }

/* 7053:22 — 388x112 @ (20,152), CENTER, autoResize HEIGHT, copy carries an
   explicit \n. Base style 500 never renders: run 1 "Solar panel\n" is 400 at
   fill #111111 * paint opacity 0.7 (= --ink-70, same as desktop) and run 2
   "installation" is 600 italic at solid #111111. The \n is reproduced by
   making .thin a block — the markup has a plain space between the spans. */
.hero h1 {
  margin: 2rem 0 0;               /* 32 -> h1 top = 120 + 32 = 152 */
  width: 24.25rem;                /* 388, centred by .hero-inner -> x20 */
  font-size: 3rem;                /* 48 */
  line-height: 3.5rem;            /* 56, lineHeightUnit PIXELS */
  letter-spacing: -0.08rem;       /* -1.28 */
  white-space: normal;
}
.hero h1 .thin { display: block; }

/* VECTOR 7053:21 — 215x0 @ (106,248), stroke #e2fa5a w12 strokeAlign CENTER,
   so it paints y242..254 and x106..321. The h1 box is 388 wide and the bar is
   centred in it ((388-215)/2 = 86.5), i.e. it spans exactly the word — which
   is what `/ 100% 0.75rem` on the <em> already gives.
   The 0.875rem bottom offset is measured, not derived: an inline element's
   background box is the font's content area, whose height is a Host Grotesk
   metric rather than the 56px line box, so the offset cannot be computed from
   Figma's numbers. 0.625rem put the bar at y246; 0.875rem lands it on 242. */
.hero h1 .hl {
  background: linear-gradient(var(--accent), var(--accent)) no-repeat left bottom 0.875rem / 100% 0.75rem;
}

/* 7053:11 — 308x60 @ (20+40, 270), Instrument Sans 500 16, CENTER, 3 lines.
   lineHeightUnit is INTRINSIC_% (Figma "Auto"), so line-height stays `normal`
   and the browser's own font metric supplies it — setting 1.22rem here would
   fight the metric. This is the documented line-height-normal drift. */
.hero-sub {
  margin: 0.375rem 0 0;           /* 6 -> 264 + 6 = 270 */
  width: 19.25rem;                /* 308 */
  max-width: none;
  font-weight: 500;
  font-size: 1rem;                /* 16 */
}

/* 7053:23 — 193x52 @ (118,354), r12 #111111, padding 10/10/10/16, gap 10.
   Label Geist 600 16 / 25.6 PIXELS — the only 16px button label in the design;
   .btn-lg would otherwise make it 20. Chip 32x32 r8 with a 28px arrow, so
   10 + 32 + 10 = 52 is the height: the chip drives it, not the label. */
.hero-inner > .btn.btn-lg {
  margin-top: 1.5rem;             /* 24 -> 330 + 24 = 354 */
  font-size: 1rem;                /* 16 */
  line-height: 1.6rem;            /* 25.6 */
}
.hero-inner > .btn.btn-lg .chip { width: 2rem; height: 2rem; }        /* 32 */
.hero-inner > .btn.btn-lg .chip img { width: 1.75rem; height: 1.75rem; }  /* 28 */

/* 7053:47 — 228x60 @ (100,430). AL VERTICAL gap 12, counterAxisAlignItems
   CENTER (row 2 is 218 wide and sits 5 in, which is exactly centred).
   Rows are AL HORIZONTAL gap 8 with a 24 icon. Line-height stays `normal`
   (INTRINSIC_%), same as .hero-sub. */
.hero-checks {
  margin: 1.5rem 0 0;             /* 24 -> 406 + 24 = 430 */
  flex-direction: column;
  gap: 0.75rem;                   /* 12 */
  align-items: center;
}

/* FRAME "Frame 15" 7053:44 — AL HORIZONTAL gap 6, pre-rotation size 225x24,
   rotated 10.009851deg about its own top-left. Its relativeTransform puts that
   origin at (152.06396484375, 556.3818359375) in HERO coords; .hero-inner's box
   starts at y120 (header margin 32 + header height 88, and .hero has
   overflow:hidden so that margin can't collapse out), so the top here is
   556.3818359375 - 120. If the header height ever changes, this moves.
   Mobile has no "Check out our N reviews" line, and the two images are in the
   opposite order to desktop: wordmark first, stars second.
   The crop transforms on .tp-stars / .tp-logo are byte-identical to desktop's —
   verified: 1/sx and -tx/sx reproduce 172.68% / -36.63% / 291.68% / -62.21%
   and 100% / 0 / 241.9% / -140.95% exactly — so neither is touched here.
   They only need `flex: none`, which they lack (they collapse in a tight row). */
.hero-reviews {
  position: absolute;
  left: 9.5039978027rem;          /* 152.06396484375 */
  top: 27.2738647461rem;          /* 556.3818359375 - 120 */
  width: 14.0625rem;              /* 225 */
  height: 1.5rem;                 /*  24 */
  margin: 0;
  gap: 0.375rem;                  /*   6 */
  transform: rotate(10.009851deg);
  transform-origin: 0 0;
}
.hero-reviews p { display: none; }
.hero-reviews .tp-logo  { order: 1; flex: none; }
.hero-reviews .tp-stars { order: 2; flex: none; }

/* --- "Nothing to pay" callout ---------------------------------------------
   FRAME "Frame 17" 7053:41 — 333x111 @ (48,733). 333 wide, 111 tall, r8 and
   the 2px ink border are all identical to desktop; only the position changes,
   and (428 - 333) / 2 = 47.5 ~ 48, i.e. it is centred.
   Mobile has no horizontal dashed connector — home-hero-dashline.svg has no
   counterpart in the mobile frame; the lime dashes here are the panel outline
   on the roof, handled above.
   Both text nodes are INTRINSIC_% so line-height stays `normal`. The sub is
   solid #111111 on mobile, not --ink-70. */
.hero-callout {
  top: 45.8125rem;                /* 733 */
  left: 3rem;                     /*  48 */
  right: auto;
  width: 20.8125rem;              /* 333 */
}
.callout-dash { display: none; }
/* Figma's title sits 12 from the card's top and its sub 59. Both margins are 2
   short of that because the card's 2px INSIDE stroke is a real CSS border, so
   content starts at 2 — the same reason desktop writes 10 for a Figma 12.
   The sub's 5 (not 4) absorbs the 1px between Figma's 43-tall title box and
   the browser's 42 for Host Grotesk at `line-height: normal` — both nodes are
   lineHeightUnit INTRINSIC_%, so the metric wins and can't be dialled out. */
.callout-title { margin: 0.625rem 0 0; }  /* 10 -> renders at 12 */
.callout-sub {
  margin: 0.3125rem 0 0;          /*  5 -> renders at 59 */
  color: var(--ink);
}

/* ==========================================================================
   §1b CERTIFICATION MARQUEE — FRAME "Frame 68" 7053:169, 428x56 @ y958
   ==========================================================================
   Full-bleed, clipped, auto-layout HORIZONTAL gap 60, starting at x0 — eight
   logos (four unique, twice each, in the order the markup already has them)
   running to x1084 inside a 428 box. Two 138x56 white fades sit on top:
   Rectangle 33 at x0 and Rectangle 34 at x290 rotated 180deg, both
   `#ffffff -> transparent`. Note they are pure WHITE over the cream --bg
   page; that mismatch is what Figma specifies.

   Figma gives the row no animation, so this is static. The fades imply a
   marquee, but a scroll would be invented — say the word and it is one
   @keyframes.

   Gutters: .excl-wrap drops to the mobile 20px, which is also what §2 needs,
   and the marquee escapes it with a negative inline margin. */
.excl { padding: 2rem 0 0; }      /* 32 -> hero bottom 926 + 32 = 958 */
.excl-wrap { max-width: none; padding: 0 1.25rem; }   /* 20 */

.excl-certs {
  position: relative;
  margin: 0 -1.25rem 2.5rem;      /* full-bleed 428; 40 down to §2 at y1054 */
  justify-content: flex-start;
  flex-wrap: nowrap;
  gap: 3.75rem;                   /* 60 */
  height: 3.5rem;                 /* 56 */
  overflow: hidden;
}
/* height 56 with width:auto keeps each source's aspect: 93.02 / 93.02 / 52.20 /
   93.02 against Figma's 93 / 94 / 52 / 93. The one discrepancy is cert-2, where
   Figma's 94-wide rect crops ~0.5px off each side of a 392x236 source; letting
   the aspect win is the more faithful of the two and costs 1px in a clipped row. */
.excl-certs img { flex: none; height: 3.5rem; width: auto; }
.excl-certs::before,
.excl-certs::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  z-index: 1;
  width: 8.625rem;                /* 138 */
  pointer-events: none;
}
.excl-certs::before {
  left: 0;
  background: linear-gradient(90deg, #ffffff 0%, rgba(255, 255, 255, 0) 100%);
}
.excl-certs::after {
  right: 0;                       /* Figma x290; 290 + 138 = 428 */
  background: linear-gradient(270deg, #ffffff 0%, rgba(255, 255, 255, 0) 100%);
}

/* ==========================================================================
   §2  EXCLUSIVE SOLAR SYSTEM — video card, heading, CTA, 3 stat cards
   ==========================================================================
   Figma order is video -> heading -> CTA -> stats, i.e. the video moves ABOVE
   the copy (desktop has them side by side). .excl-stats already lives inside
   .excl-left, so one `order` swap on the two grid children is enough.
   Mobile drops the "An exclusive" eyebrow entirely — it is not in the mobile
   frame's text at all.
   Flow: marquee bottom 1014 + 40 = 1054 (video), stats end 2144, + 40 = 2184
   (§3's top), which is what the 2.5rem padding-bottom below buys. */
.excl { padding: 2rem 0 2.5rem; }         /* 32 top (§1b), 40 bottom (to §3) */
.excl-grid {
  display: flex;
  flex-direction: column;
  gap: 0;
  align-items: stretch;
}
.excl-video { order: 1; }
.excl-left  { order: 2; }
.excl-eyebrow { display: none; }

/* FRAME "Frame 116" 7053:180 — 388x444 @ (20,1054), r12, clipsContent, #ffffff,
   INNER_SHADOW #111111 r40 AND DROP_SHADOW #e2fa5a r60 offset(0,4). Figma paints
   an inner shadow ABOVE children, so it has to be an overlay ::after — a plain
   inset box-shadow would sit behind the <img>. */
.excl-video {
  width: 100%;
  height: 27.75rem;               /* 444 */
  box-shadow: 0 0.25rem 3.75rem 0 #e2fa5a;   /* 0 4px 60px, full alpha here */
}
.excl-video::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  border-radius: inherit;
  box-shadow: inset 0 0 2.5rem #111111;      /* INNER_SHADOW r40 */
}

/* RECTANGLE "image 153" 7053:181 — 855x570 at rel(-211,-33), scaleMode FILL.
   The desktop rule is inset:0 + cover; mobile needs the real Figma crop box. */
.excl-photo {
  inset: auto;
  left: -13.1875rem;              /* -211 */
  top: -2.0625rem;                /*  -33 */
  width: 53.4375rem;              /*  855 */
  height: 35.625rem;              /*  570 */
  max-width: none;                /* home.css's img { max-width: 100% } clamps 855 -> 388 */
}

/* RECTANGLE "Rectangle 13" 7053:182 — 388x339 at rel(0,105); 105 + 339 = 444,
   so it is bottom-anchored. Ink, not desktop's rgba(0,0,0,.85). */
.excl-vgrad {
  height: 21.1875rem;             /* 339 */
  background: linear-gradient(to top, #111111, rgba(17, 17, 17, 0));
}

/* progress + play share a row: the bars sit at rel y34 and the 36-tall button at
   rel y20, and 20 + (36-8)/2 = 34 — they are centred on each other. */
.excl-top {
  top: 1.25rem;                   /* 20 */
  left: 1.25rem;
  right: 1.25rem;
  gap: 1rem;                      /* 296 ends at 316, button starts at 332 */
}
.excl-progress { gap: 0.25rem; }  /* 4 */
/* FRAME "Arrow Icon Wrapper" 7053:188 — 36x36 r8, fill rgba(255,255,255,.32)
   (NOT solid white) + BACKGROUND_BLUR radius 4 -> blur(4 / 2.82). Glyph 15x18. */
.excl-play {
  width: 2.25rem; height: 2.25rem;         /* 36 */
  background: rgba(255, 255, 255, 0.32);
  backdrop-filter: blur(0.0886rem);        /* Figma layer/background blur r4 */
  -webkit-backdrop-filter: blur(0.0886rem);
}
.excl-play svg { width: 0.9375rem; height: 1.125rem; }   /* 15 x 18 */

/* caption block: text box rel(24,270) 280 wide, lime chip rel(324,340) 40x80.
   Both bottom out at 420 against a 444 card -> 24 inset all round. */
.excl-caption { left: 1.5rem; right: 1.5rem; bottom: 1.5rem; gap: 0.5rem; }
.excl-caption p {
  font-size: 1.375rem;            /* 22 — the only 22px in the design */
  line-height: 1.5625rem;         /* 25, lineHeightUnit PIXELS */
  max-width: 17.5rem;             /* 280 */
}
.excl-chip img { width: 1.75rem; height: 1.75rem; }   /* 28, was 22 on desktop */

/* heading — TWO separate text nodes in Figma, 264x64 @ (20,1538) and
   294x37 @ (20,1604), LEFT aligned. They overlap 2px because the gradient
   node's 63.84 line box is taller than its ink. Mobile carries the CORRECT
   dark->lime stop (~70.6%), not the 21.751% the desktop selector still holds. */
/* "designed for UK weather." is a BARE TEXT NODE after a <br />, not a span, so
   it is styled through .excl-h itself and only .excl-italic overrides. Its ink is
   solid #111111 on mobile, where the desktop h2 is --ink-70.
   The two Figma nodes sit 2px apart (1538+63.84 = 1601.84 vs Figma's 1604); a
   <br /> cannot carry that margin, so the second line lands 2px high. Left as is. */
.excl-h {
  margin: 2.5rem 0 0;             /* 40 -> video bottom 1498 + 40 = 1538 */
  /* CENTRED, not Figma's left (user, 2026-08-13: "in text or button ko screen k
     center align krdo mobile version main"). Both lines centre independently —
     they are two text nodes either side of a <br />. .excl-italic keeps its
     shrink-to-fit inline-block box, so its background-clip gradient is laid out
     over exactly the same width as before and only the box's x moves. */
  text-align: center;
  font-weight: 400;
  font-size: 1.75rem;             /* 28 — the only 28px in the design */
  line-height: 2.3275rem;         /* 37.2400016784668 */
  color: var(--ink);
}
.excl-italic {
  font-size: 3rem;                /* 48 */
  line-height: 3.99rem;           /* 63.840003967285156 */
  background-image: linear-gradient(85.9deg, #111111 70.59%, #e2fa5a 136.42%);
}
/* CTA 7053:161 — 193x52 @ (20,1665); heading bottom 1641 -> 24 gap.
   Label is Geist 600 20 here (unlike the hero's 16), i.e. .btn-lg's own size. */
/* 193 wide with a 16px label, exactly like the hero's — .btn-lg's own 20px
   would render it 224 wide. Both 52-tall CTAs in the design use the 16px label. */
.excl-left .btn {
  /* 26, not Figma's 24: the <br /> between the heading's two lines cannot carry
     the 2px Figma puts between its two text nodes, so the 2px is absorbed here
     and nothing below the heading drifts. */
  margin-top: 1.625rem;
  font-size: 1rem;                /* 16 */
  line-height: 1.6rem;            /* 25.6 */
  /* CENTRED with the heading above it (same instruction). base.css's .btn is
     `inline-flex`, on which `margin-inline: auto` does nothing, so the outer
     display has to go block-level first — and then `width: max-content` is what
     keeps the pill hugging its label at Figma's 193 instead of stretching to the
     388 column. Done on the button rather than with `text-align: center` on
     .excl-left deliberately: that would inherit straight into .excl-stats and
     need undoing on all three cards. Inner layout is untouched — `flex` and
     `inline-flex` differ only on the outside. */
  display: flex;
  width: max-content;
  margin-inline: auto;
}
.excl-left .btn .chip { width: 2rem; height: 2rem; }             /* 32 */
.excl-left .btn .chip img { width: 1.75rem; height: 1.75rem; }   /* 28 */

/* FRAME "Frame 121" 7053:201 — 388x395 @ (20,1749), AL VERTICAL gap 8.
   Cards are 113 / 133 / 133 tall: card 1's body copy is one line, cards 2-3 wrap
   to two, so the heights are content-driven — nothing is hardcoded. Each card
   is r12 #ffffff with a 4px #f6f6f6 border, icon 48 at rel(24, 33/43/43),
   number at rel(96,24) and body at rel(96,69) on a 268 column. */
.excl-stats {
  flex-direction: column;
  gap: 0.5rem;                    /* 8 */
  margin-top: 2rem;               /* 32 -> CTA bottom 1717 + 32 = 1749 */
}
.excl-card {
  display: grid;
  /* 4.6rem, not Figma's 3rem, because the icon asset became 73.6x48 on
     2026-08-18 (see .excl-card img in home-sections.css — the badge had to
     double, then took a 2px gap off the panel). The track HAS to follow the
     asset or the img overflows it onto the copy.
     COSTS NO HEIGHT: the icon is `grid-row: 1 / span 2` in a 65-tall content box
     and stayed 48 tall, so the cards are still 113 and nothing below §2 moves.
     The copy column pays the 25.6: 268 -> 242.4. Safe, and measured rather than
     assumed — the three strings' own ink is 163.16 / 124.92 / 127.33, so the
     longest still has 79 of slack and all three stay on one line. */
  grid-template-columns: 4.6rem 1fr;            /* 73.6 icon + copy */
  column-gap: 1.5rem;                           /* 96 - 24 - 48 = 24 */
  align-items: start;
  min-height: 0;
  /* 20, not 24: box-sizing is border-box and the border is 4, so content starts
     at 24 — which is where Figma puts the icon and the 268 copy column. */
  padding: 1.25rem;
  border-width: 0.25rem;                        /* 4 */
}
/* the icon is vertically CENTRED in the card, not top-aligned: rel y33 in a 113
   card and y43 in a 133 card both put its centre on the card's centre. */
.excl-card img { grid-row: 1 / span 2; align-self: center; margin: 0; }
.excl-card h3 { font-size: 2rem; line-height: 2.66rem; }         /* 32 / 42.56 */
.excl-card p { max-width: 16.75rem; margin: 0.1525rem 0 0; }     /* 268 wide, rel y69 */

/* ==========================================================================
   §3  SOLAR-PV AS EASY AS 1-2-3
   ==========================================================================
   RECTANGLE "Rectangle 13" 7053:3 is the section's own box: 428x1643 @ y2184,
   `linear-gradient(0deg, #e2fa5a 0%, rgba(226,250,90,0) 100%)`. It spans exactly
   heading-top -> §4-top, so putting the paint on .pvsec reproduces it.
   Mobile omits desktop's intro paragraph under the heading entirely. */
.pvsec {
  background: linear-gradient(to top, #e2fa5a 0%, rgba(226, 250, 90, 0) 100%);
  padding: 0 0 1.25rem;           /* content ends 3807, §4 at 3827 -> 20 */
}
/* Mobile paints the gradient on the section itself (its own 100% end stop, and
   the box is the real 428x1643 Figma rect here), so desktop's pinned 100vh
   layer must not double up. */
.pvsec-bg { display: none; }
.pv-wrap { max-width: none; padding: 0 1.25rem; }
.pv-head { margin-top: 0; }
.pv-h .pv {
  font-size: 3rem;                /* 48 */
  line-height: 3.99rem;           /* 63.840003967285156 */
  background-image: linear-gradient(84.06deg, #111111 70.6%, #e2fa5a 135.57%);
}
.pv-h .rest {
  font-size: 2.25rem;             /* 36 */
  line-height: 2.75rem;           /* 44 */
  margin-top: 0.375rem;           /* 2248 + 6 = 2254 */
}
/* 7053:219 — 298x80 @ (65,2330), AL HORIZONTAL gap 24. The 80 thumb, its 2px
   lime border and the 24 play chip are all already the desktop values. */
.pv-how { margin-top: 2rem; gap: 1.5rem; }     /* 2298 + 32 = 2330 */
.pv-how a { font-weight: 600; font-size: 1.25rem; line-height: 1.6rem; }

/* identical 388x439 cards on a uniform 20 gap — y2450 / 2909 / 3368 for the
   three Figma steps, simply continuing for the two authored ones (user's call,
   2026-08-06: "mobile pe simple 5 cards ayen ge ek dosre ki niche jese abi bi
   hai"). Mobile has NO stagger, NO filler panels, NO opacity .7 and NO
   conveyor, so the entire desktop mechanism is undone: the track stops being a
   scroll runway, the stage stops being sticky, and the slots go back in flow.
   Because the fillers are gone the card could finally take overflow:hidden,
   but the sketch wrapper is kept anyway so the hover zoom still has its clip. */
.pv-track {
  margin-top: 2.5rem;             /* 2410 + 40 = 2450 */
  height: auto;
}
.pv-cards {
  position: static;
  height: auto;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;                   /* 20 */
}
/* [data-step] as well as the bare class: the desktop reduced-motion fallback
   staggers the slots at that same specificity, and this file only wins on
   source order when the selectors match it. */
.pvc-slot,
.pvc-slot[data-step] {
  --pv-o: 1;
  position: static;
  width: 100%;
  margin-top: 0;
  translate: none;
  z-index: auto;
}
.pvc-fill { display: none; }
.pvc-card {
  width: 100%;
  height: 27.4375rem;             /* 439 */
  min-height: 0;                  /* the removed fallback's 28.75rem won on min-height */
  padding: 2rem 2.5rem 0 2.5rem;  /* numeral right edge 388 - 40 = 348 */
  opacity: 1;
}
/* .pvc-title's three per-box gradients are GONE as of 2026-08-06 — the user
   asked for the step title to be flat #111111 (see the note on .pvc-title in
   home-sections.css), and mobile only ever restated the same paint at the
   angle its own 136 / 95 / 126 box demanded. They could not simply be left
   here: with the clip removed from the desktop rule, a surviving
   `background-image` would paint the gradient as a solid bar across the whole
   title box instead of through the letters — exactly the failure CLAUDE.md
   documents under "the background shorthand silently kills
   background-clip: text". If the gradient is ever restored, restore all four
   rules together. */
/* 27x60 box for all three, so one gradient; the 0.4 comes from the PAINT's own
   opacity in Figma and is already on .pvc-num as a node opacity. */
.pvc-num { background-image: linear-gradient(56.7deg, #111111 70.75%, #e2fa5a 109.53%); }
.pvc-desc { max-width: 19.25rem; }              /* 308 */
/* RECTANGLE "image 112" 7053:231 — 354.04x195 at rel(17.96,212). Native 512x282
   is the same 1.8156 aspect, so unlike desktop this crops nothing and needs no
   object-position offset. */
.pvc-sketchwrap {
  left: 1.1225rem;                /* 17.96 */
  top: 13.25rem;                  /* 212 */
  width: 22.1275rem;              /* 354.04 */
  height: 12.1875rem;             /* 195 */
}
.pvc-sketch { object-position: 50% 50%; }

/* ==========================================================================
   §4  PRODUCT SHOWCASE — FRAME "Homepage" 7053:60, 428x1955 @ y3827, clip
   ==========================================================================
   Mobile is heading + three cards and NOTHING else: the whole left column
   below the heading (checks, the "Nothing to pay" callout, the trustpilot row
   and the "Read reviews" CTA) and every card's dashed rule + bulb note are
   absent from the mobile frame. There is no sticky-scroll either — the section
   is one 1955-tall column.

   Vertical flow, all section-relative:
     heading  40 .. 152        (2 lines x 56)
     card 1  192 .. 765        h573
     card 2  785 .. 1340       h555
     card 3 1360 .. 1915       h555
     bottom pad 40            -> 1955, and §5 starts 40 later at y5822.
   So .psh-wrap is `padding: 40 20` with a 40 gap, and 40 + 112 + 40 + 1723 +
   40 = 1955 exactly. */
.pshow { overflow: clip; }        /* Figma clipsContent; already desktop's value */

/* --- background -----------------------------------------------------------
   7053:61 repeats the hero's sky: the SAME 1920x926 frame at rel(-890,0) with
   the SAME imageRef / imageTransform, so the crop math from §1 is reused
   verbatim (full width 1920 / 0.8577134, left -890 - (0.14228661/0.8577134) *
   1920). Figma's own node is 926 tall and pinned (scrollBehavior
   STICKY_SCROLLS), which is exactly what desktop's `.psh-bg` already does —
   `position: sticky; top: 0; height: 100vh; margin-bottom: -100vh` — so mobile
   deliberately does NOT override it: the backdrop fills the viewport at any
   screen size, stays pinned for the whole section, and scrolls away with it
   because `.pshow` is `overflow: clip`.
   The `-100vh` is load-bearing: it keeps the 100vh box out of the flow so the
   section stays exactly 1955 tall. (This is the trick the known
   `psh-left-100vh` deviation is missing — and it cannot bite here, because the
   mobile rules below make `.psh-left` static/auto.)
   Only the image's crop is mobile-specific. `height: 100%` means the sky
   stretches to the viewport rather than to Figma's 926, which is the intent:
   sx != sy in the imageTransform already, so `fill` (not `cover`) is what
   reproduces Figma's independent per-axis scaling. */
.psh-bg img {
  position: absolute;
  left: -75.5318751914rem;        /* -1208.5100030625 */
  top: 0;
  width: 139.9068731066rem;       /*  2238.5099697061 */
  height: 100%;
  max-width: none;                /* home.css's `img { max-width: 100% }` clamps 2238 -> 428 */
  object-fit: fill;               /* sx != sy in the imageTransform, so `cover` would re-letterbox */
}
/* Mobile adds a SECOND fill on 7053:61 that the desktop frame does not have:
   a linear gradient at paint opacity 0.12, dark at the bottom -> lime at the
   top (Figma handles (0.5,1)->(0.5,0), i.e. CSS 360deg == `to top`). It is a
   fill on the frame, so it covers the whole sticky box, not Figma's 926.
   It has to sit above the photo but BELOW the white scrim, and `::after`
   paints after every child — hence the explicit z-index ladder. */
.psh-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(to top, rgba(17, 17, 17, 0.12), rgba(226, 250, 90, 0.12));
}
/* 7053:62 — 1920x526 @ rel(0,0), clipped to 428. Unlike desktop (fill opacity
   .32) and the hero (paint opacity .5), this paint carries NO opacity, so the
   top stop is the full #ffffff a0.8 the stop itself declares.
   Height stays Figma's absolute 526 rather than a share of the sticky box —
   same as desktop, where a fixed 32.875rem scrim also sits in a 100vh bg. */
.psh-bg-fade {
  z-index: 2;
  height: 32.875rem;              /* 526 */
  opacity: 1;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0));
}

/* --- section shell -------------------------------------------------------- */
.psh-wrap {
  width: auto;
  max-width: none;
  padding: 2.5rem 1.25rem;        /* 40 / 20 gutters -> a 388 content column */
  flex-direction: column;
  gap: 2.5rem;                    /* heading bottom 152 -> cards 192 */
}
/* the column collapses to just the heading */
.psh-left {
  position: static;
  width: 100%;
  height: auto;
  padding: 0;
  display: block;
}
.psh-checks,
.psh-callout,
.psh-reviews,
.psh-btn-reviews { display: none; }

/* 7053:64 — 388x112 @ (20,40), CENTER, autoResize HEIGHT, copy carries an
   explicit \n. Same two-run structure as desktop (base 500 never renders):
   run 1 "Shop our\n" is 400 at #111111 * paint opacity 0.7 (= --ink-70) and
   run 2 "solar now" is 600 italic at solid #111111 — so only the words, the
   size and the alignment change. The \n is the existing <br />. */
.psh-h {
  width: 100%;                    /* 388 */
  font-size: 3rem;                /* 48 */
  line-height: 3.5rem;            /* 56, lineHeightUnit PIXELS */
  letter-spacing: -0.08rem;       /* -1.28 */
  text-align: center;
}
/* VECTOR 7053:63 — 204x0 @ (112,136), stroke #e2fa5a w12 strokeAlign CENTER,
   so it paints x112..316 / y130..142. Heading-box-relative that is left 92,
   top 90, and 92 = (388 - 204) / 2 — the bar is centred on the section, i.e.
   it spans exactly the centred "solar now". Figma's own 204 is used rather
   than `100%` of the <em> so the bar cannot drift with a font metric. */
/* The heading is centred here, so the bar's left AND width both track the word
   it underlines. Was 92 / 204 for "solar now" (202.09 wide), then 106 / 176 for
   "included" (174.09) on 2026-08-13, and now 104 / 180 for "Package" (177.58 at
   the mobile 48px em) as of 2026-08-17. 104 + 180 + 104 = 388, so the bar is
   still exactly centred on the column, and the 2.42 overhang matches what the
   desktop bar carries. Re-measure BOTH numbers if the word changes again. */
.psh-h-bar {
  left: 6.5rem;                   /* 104 */
  top: 5.625rem;                  /*  90 */
  width: 11.25rem;                /* 180 */
  height: 0.75rem;                /*  12 */
}

/* --- cards ----------------------------------------------------------------
   7053:65 / :95 / :125 — 388 wide, r8 #ffffff, clip, at rel y 192 / 785 / 1360
   and heights 573 / 555 / 555. Each is a FIXED-size frame with absolutely
   positioned children, and every child except the brand mark and the title
   sits at the SAME card-relative y in all three cards:
     photo   (195,24) 193x193      blurb (24,241) 340
     CTA     (24,313) 340x52       bullets (24,397) 340
   The brand mark + title are the only pair that moves (y70/70/52 and
   y99/99/81) — because the pair is vertically CENTRED against the photo: both
   groups have their midpoint on y120.5, which is the photo's own centre.
   So the card is a centred flex column whose content box is forced to exactly
   the photo's 193 by the padding, and everything below is absolute at Figma's
   y. That needs no :nth-child and keeps every offset exact; the card's own
   height is the one declared number, which is what Figma declares too. */
/* `grid-auto-rows: 1fr` makes every row as tall as the tallest card, so the five
   match again after the column went into flow (user, 2026-08-13: "card ki height
   ko responsive bnao ... ye b ab different show ho rhi"). Content stays
   top-aligned, so the slack lands BELOW the note — which is the only place it
   can go without making one of the gaps uneven again, and those gaps are what
   the previous instruction asked to equalise. No hardcoded height anywhere: the
   tallest card sets it, so copy changes still cannot overflow. */
.psh-cards {
  width: 100%;
  display: grid;
  grid-auto-rows: 1fr;
  gap: 1.25rem;                          /* 20 */
}
/* Heights are +23 on Figma's 555 / 573 as of 2026-08-13. Every element below
   the image band is absolutely positioned at a Figma y, and the client's copy
   broke that: `.psh-sub` sits at 241 with the CTA at 313, i.e. exactly 72 of
   room, which is two lines. Card 2's blurb is THREE (73.2) and was landing on
   the button. So the CTA and the points moved down 23 — enough to give the
   3-line card Figma's own ~23 breathing gap — and the card grew by the same 23
   so the points do not clip against the declared height. The 2-line cards get a
   larger sub->CTA gap as a result; a single absolute y cannot serve both.
   RE-MEASURE the tallest blurb before touching any of these four numbers. */
/* ---------------------------------------------------------------------------
   THE MOBILE CARD IS IN FLOW as of 2026-08-13, and that is a deliberate break
   from how it was built.

   Figma's mobile card is a DECLARED height (555 / 573) with every element below
   the image band absolutely positioned at its own y — sub 241, CTA 313, points
   397. That is exact while the copy is Figma's, and it broke repeatedly once it
   was not: a 3-line blurb landed on the button, the bulb note ran past the card,
   and once the points packed into uneven rows the gap above the dashed rule
   ranged from 24 to 104 across the five cards. Each fix moved one hardcoded y
   and exposed the next one.

   So the whole column below the image now flows and every gap is a margin —
   Figma's own gaps, kept: image band -> sub 24, sub -> CTA 24, CTA -> points 32,
   points -> rule 24, rule -> note 15, note -> card bottom 16. Whatever the copy
   does, the spacing is identical on all five cards, which is what the user asked
   for ("hr card main equal space ho kahi zyada kahin km na ho").

   THE COST, accepted: card heights are content-driven now, so the five are no
   longer the same height — a 3-line blurb makes a taller card than a 2-line one.
   `.psh-card-tall` is therefore inert here and is explicitly neutralised.
   --------------------------------------------------------------------------- */
.psh-card {
  width: 100%;
  height: auto;
  padding: 1.5rem;                       /* 24 all round */
  /* a flex column so the rule + note can be pushed to the card's bottom edge —
     see `.psh-rule`'s `margin-top: auto` */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
/* the image is absolute at (195,24) 193x193, so the title reserves that band and
   centres itself in it, exactly as `justify-content: center` used to */
.psh-card-tall {
  height: auto;
  padding-bottom: 1.5rem;
}
/* brand mark 54x20 and title on a 176 column — 176 is load-bearing, it is what
   wraps the three titles to 2 / 2 / 3 lines (72 / 72 / 108, and 3x36 = 108 is
   why card 3 sits 18 higher). The 9px gap is already desktop's margin.
   NOTE: Figma's mobile frame puts the LONGi mark on all three cards (imageRef
   a0907dbb on 7053:67 / :97 / :127), which is a duplicate-and-edit slip in the
   mobile frame — the desktop frame has Enphase and AlphaESS. The correct three
   marks are kept. To take Figma literally instead, point all three <img> src at
   /assets/img/home-ps-logo-longi.png and set every width to 3.375rem. */
.psh-title {
  /* Figma's 176 wrapped the old three titles to 2/2/3 lines. With the client's
     five, it left "Solar Panels" alone on ONE line while the other four took
     two — so the column dropped to 160 on 2026-08-13 ("mobile main solar panels
     ko b 2 lines main likh do"). Measured across 176/160/150/140/130/120: 160
     is the widest that puts all five on two lines, and nothing reaches three. */
  /* 168, not the 160 it was: `box-sizing` is border-box, so the 4 border + 20
     padding come out of this and "Monitoring" — one unbreakable 144-wide word —
     was spilling out of a 132 column. The hard ceiling is 171, the gap between
     the card's 24 padding edge and the shot at 195, so 168 + a 20 padding is the
     widest pair that clears the image. */
  width: 10.5rem;                 /* 168 */
  font-size: 2rem;                /*  32 */
  line-height: 2.25rem;           /*  36 */
  /* reserves the 193 image band and centres in it — what the card's old
     `justify-content: center` did before the column went into flow */
  min-height: 12.0625rem;         /* 193 */
  display: flex;
  align-items: center;
  /* Bold, and a lime rule down the left with a fading lime wash behind it —
     the user's own values, taken from DevTools 2026-08-13. MOBILE ONLY;
     desktop keeps Figma's 400 with no border, padding or wash.
     NOTE: `box-sizing: border-box` is global, so the 4 border + 24 padding come
     OUT of the 160 width, leaving 132 for the text. */
  font-weight: 600;
  margin: 0;
  border-left: 0.25rem solid var(--accent);   /* 4px #e2fa5a */
  padding-left: 1.25rem;                      /* 20 (the user asked for 24; 20 is
                                                 what keeps "Monitoring" inside) */
  background: linear-gradient(
    90deg,
    rgba(226, 250, 90, 0.16) 0%,
    rgba(226, 250, 90, 0) 100%
  );
}
/* RECTANGLE "image 123" 193x193 @ rel(195,24); 195 + 193 = 388, i.e. flush to
   the card's right edge. All three sources are square, so FILL crops nothing. */
.psh-shot {
  left: auto;
  right: 0;
  top: 1.5rem;                    /*  24 */
  width: 12.0625rem;              /* 193 */
  height: 12.0625rem;
}
/* The LONGi mark is centred along the shot's bottom edge with a 20px inset, so
   both offsets are read off the MOBILE shot rather than the desktop one: it sits
   at right 0 and runs 24..217, and is 193 wide.
     right = half the leftover width -> centre on x291.5
     top   = 24 + 193 - 20 margin - 20 mark height = 177
   Without this it would inherit home-sections.css's 117 / 248, which belong to
   the 240-wide desktop cut-out. */
.psh-logo-onshot {
  left: 12.1875rem;               /* 195 = 388 - 193, the mobile shot's left */
  right: 0;                       /* the mobile shot sits flush right */
  top: 11.0625rem;                /* 177 */
}
/* ...and as of 2026-08-17 the mark is GONE FROM ALL FIVE CARDS on mobile ("mobile
   pe sare cards ka logo remove krdo"), so the three offsets above now match
   nothing. They stay rather than being deleted: they are the only record of
   Figma's own mobile placement, and they are exactly what a restored mark would
   need — the `.excl-eyebrow` reasoning. Card 1's <img> is gone from the markup
   entirely (its desktop clip carries its own logos), so this rule is what hides
   the four on cards 02-05, which still show theirs above 768.
   `.psh-logo`'s `display: block` lives in home-sections.css at the same (0,1,0)
   specificity, so this wins on load order alone — no !important needed. */
.psh-logo-onshot {
  display: none;
}
.psh-sub {
  position: static;
  width: 21.25rem;                /* 340 */
  margin: 1.5rem 0 0;             /* 24 below the image band (Figma: 217 -> 241) */
}
/* FRAME "Link - Solid Black" 340x52 @ rel(24,313), r12, gap 10 but
   primaryAxisAlignItems SPACE_BETWEEN with a FILL label, so the label really
   occupies 16..298 (282 wide) and CENTERS its text there while the 32 chip
   pins to the right. The label is a bare text node in the markup — an
   anonymous flex item that cannot take `flex: 1` — so the chip leaves the flow
   and the right padding (10 + 32) reserves its space: 340 - 16 - 42 = 282, and
   `justify-content: center` then lands the text's centre on 157, not 170. */
.psh-card .psh-btn {
  position: relative;             /* was absolute; its chip is absolute against it */
  width: 21.25rem;                /* 340 */
  height: 3.25rem;                /*  52 */
  margin: 1.5rem 0 0;             /* 24 under the blurb, whatever its line count */
  display: flex;
  justify-content: center;
  gap: 0;
  padding: 0.625rem 2.625rem 0.625rem 1rem;   /* 10 / 42 / 10 / 16 */
  font-size: 1rem;                /* 16 — Geist 600, the 52-tall button size */
  line-height: 1.6rem;            /* 25.6 */
}
.psh-card .psh-btn-ico {
  position: absolute;
  right: 0.625rem;                /* 10 -> chip x298..330 */
  top: 0.625rem;                  /* 10 -> 10 + 32 + 10 = 52 */
  flex: none;
  width: 2rem;                    /* 32 */
  height: 2rem;
}
/* FRAME "Frame 16" 340 @ rel(24,397), AL VERTICAL gap 16. Rows are AL
   HORIZONTAL gap 8 / counterAxis CENTER with a 24 icon and a 308 text column —
   all four already desktop's values, so only the widths and the position move.
   Row heights are the text's own: 2 lines render 39.04 against Figma's rounded
   40 and 1 line is the 24 icon, so the list comes out 2.88 (card 1) / 1.92
   (cards 2-3) shorter than Figma's 152 / 136. That drift lands in the card's
   bottom whitespace and nowhere else — the card height is declared — and it is
   the documented fractional-line-height class, not something to force. */
.psh-card .psh-bullets {
  position: static;
  width: 21.25rem;                /* 340 */
  /* 32 above (Figma's own CTA -> points gap) and 24 below, which is the minimum
     clearance before the rule — flex margins do not collapse, so this survives
     the rule's `margin-top: auto`. */
  margin: 2rem 0 1.5rem;
  /* One per row left a short point like "Fast charging" with the rest of the 340
     empty beside it, so the list PACKS here (user, 2026-08-13: "samne white
     space bari na lge ... jo ek line main aa sakte wo ek row main rkhdo"). As
     wrapping flex items each point takes only its own width, so two short ones
     share a row and a long one keeps the row to itself. Overrides desktop's
     `1fr 1fr` grid, which is why `display` is restated and not just the axis. */
  /* ONE PER ROW. A packed, wrapping version was tried on 2026-08-13 and taken
     straight back out ("points ko ek dosre k niche") — at 340 only some pairs
     fitted, so the rows came out ragged (2 / 3 / 3 / 2 / 3 across the five
     cards) and it needed the gaps tightened to 12 / 4 to manage even that.
     Card 2's first two can never pair at all: "Up to 98% efficiency" +
     "Smart energy conversion" is 394 against a 340 row. */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  /* the lime panel + dashed edge on desktop's `.psh-bullets` is desktop's alone */
  padding: 0;
  border: 0;
  background: none;
}
/* auto, not Figma's 308 (340 - 24 icon - 8 gap): the text has to shrink to its
   own width so the dashed leader after it has room to fill. */
.psh-bullets span { width: auto; }

/* ---- dashed leader after each point ----
   Added 2026-08-13 ("points k samne is trah ki dashes de do jo card k end tk ja
   rhi hon point se thore margin se shro hon"). The pattern is `.psh-rule`'s own
   — 1px, #111 @ .12, 8 on / 8 off — so the two read as one device. Mobile only:
   desktop lays the points out two-up in a grid, where a leader has nothing to
   lead to. The rows stretch to the full 340 content column, and `flex: 1` on the
   pseudo eats whatever the text leaves, so every leader ends on the same x. */
.psh-card .psh-bullets li {
  align-self: stretch;
}
.psh-card .psh-bullets li::after {
  content: "";
  flex: 1 1 auto;
  min-width: 1.5rem;              /* never collapse to nothing on a long point */
  margin-left: 0.75rem;           /* 12 clear of the text */
  height: 0.0625rem;
  background-image: repeating-linear-gradient(
    to right,
    rgba(17, 17, 17, 0.12) 0 0.5rem,
    transparent 0.5rem 1rem
  );
}
/* Figma's mobile frame has neither the dashed rule nor the bulb note, so both
   used to be `display: none`. Shown from 2026-08-13 ("mobile main b show
   krwao ye point"), which means positioning them: everything in this card
   except the title is absolute — that is what lets the title stay centred in
   the 193 image band — so these two cannot simply join the flex flow.
   Stacked under the points, which end at 564:
     rule  564 + 24 = 588   (full-bleed, hence left/right 0)
     note  588 +  1 + 15 = 604
   and the card's declared height is note-bottom + 16. */
/* `margin-top: auto` pins the rule + note to the CARD'S BOTTOM. All five cards
   are the same height (`.psh-cards` grid) but hold different amounts of copy, so
   the leftover has to sit somewhere — this puts it above the dashed rule, where
   it reads as breathing space, instead of below the note, where it left a 24 /
   48 / 88 / 128 / 88 ragged edge (user, 2026-08-13: "sabi cards main ye tip k
   niche se margin same hona chahiye"). The points keep a 24 bottom margin, so
   even the tallest card — the one with no slack at all — still clears the rule.
   Equal height + equal internal gaps + equal bottom margin cannot all hold at
   once with unequal copy; this trades the points->rule gap for the other two. */
.psh-card .psh-rule {
  display: block;
  position: static;
  align-self: stretch;            /* the card is `align-items: flex-start` now */
  margin: auto -1.5rem 0;         /* auto top; -24 sides keep it full-bleed */
}
.psh-card .psh-note {
  display: flex;
  position: static;
  /* `align-self` is load-bearing: the card is `align-items: flex-start`, so
     without this the note takes its MAX-CONTENT width, runs past the 340 column
     and the card's `overflow: hidden` clips the text ("tips kt na rhi ho").
     Stretching it to the content box is what lets the sentence wrap. */
  align-self: stretch;
  margin: 0.9375rem 0 0;          /* 15, Figma's own rule -> note gap */
}

/* ==========================================================================
   §5  TRUST BAND — FRAME "Frame 124" 7053:242, 388x980 @ y5822, r12 #000, clip
   ==========================================================================
   Same four blocks as desktop, stacked instead of in a row, and the two dashed
   dividers turn from vertical column separators into full-bleed horizontal
   rules. EVERY group internal is already desktop's value — the 80 logo slot and
   its centring, the 16 logo->t1 gap, the 4 t1->t2 gap, all three fonts, the
   285 column width, and `#fff @.7` on t2 — so only the axis, the gutters and
   the divider geometry are restated here. No markup change, no copy delta.

   Vertical flow, section-relative:
     title      40 .. 152     285x112, CENTER (desktop's is LEFT)
     group 1   192 .. 388     logo +0 / t1 +96 / t2 +164, group 196 tall
     divider 1 427 .. 429
     group 2   468 .. 664
     divider 2 703 .. 705
     group 3   744 .. 940
     bottom pad 40           -> 980
   i.e. 40 above/below every divider, a uniform 276 group pitch, and 40 of
   padding at each end of the band. */
.tband-sec { padding-top: 2.5rem; }        /* §4 ends 5782, band starts 5822 */
/* 388 of 428 -> 20px gutters, and the content column is centred rather than
   desktop's asymmetric 330/306. Figma writes x52 for a 285 column in a 388
   band, i.e. 52 left / 51 right; centring splits it 51.5/51.5 — 0.5px. */
.tband {
  max-width: calc(100% - 2.5rem);          /* 40 -> band 388 at the 428 canvas */
  padding: 2.5rem 0;                       /* 40 top and bottom */
}
.tband-inner {
  width: 17.8125rem;                       /* 285 */
  flex-direction: column;
  align-items: stretch;
  gap: 2.5rem;                             /* title -> group 1 */
}
.tband-title {
  align-self: stretch;
  text-align: center;                      /* textAlignHorizontal CENTER on mobile */
}
/* the 40 gap plus this 40 makes the 80 that carries a divider between groups */
.tband-col + .tband-col { margin-top: 2.5rem; }

/* VECTOR "Vector 7" / "Vector 8" 7053:248 / :249 — declared 388x0 at rel y428
   / y704 but `rotationDeg: -90` with a pre-rotation size of 0x388, i.e. a
   VERTICAL line laid down horizontally. So on mobile it is a full-bleed 388
   horizontal rule, not desktop's 195 vertical one, and it reaches past the 285
   column to both band edges — safe, because `.tband` is `overflow: hidden`.
   Anchored off the column's centre (which is the band's centre) so it does not
   depend on the 51.5 gutter.

   Figma scales `strokeDashes: [8,8]` to fit a whole number of periods:
   n = round(388 / 16) = 24, so the period is 388/24 = 16.16667 and dash = gap =
   8.08333 — NOT the nominal 8/8, and not desktop's 8.125 either. Phase is a
   half dash at each end. Verified against render/mobile-full@1x.png: the line
   occupies exactly 2 rows at abs y6249..6250, dash starts land within 1px of
   `11.83 + 16.16667k` across all 24 periods (a flat 16.0 period drifts 4px by
   the far end), the peak sits at x207 = 53.4% of 388, and its value is 99/255 =
   0.388 — which is the stroke paint's own `opacity: 0.4`, over 3x desktop's
   0.12. Same three-stop white fade, middle stop 52.4%. */
.tband-col + .tband-col::before {
  left: 50%;
  top: -2.5625rem;                         /* -41 -> the 2px rule spans rel 427..429 */
  margin-left: -12.125rem;                 /* -194, half of 388 */
  width: 24.25rem;                         /* 388 */
  height: 0.125rem;                        /* strokeWeight 2, strokeAlign CENTER */
  background-image: repeating-linear-gradient(
    to right,
    #ffffff 0 0.2526041667rem,
    rgba(255, 255, 255, 0) 0.2526041667rem 0.7578125rem,
    #ffffff 0.7578125rem 1.0104166667rem
  );
  -webkit-mask-image: linear-gradient(
    to right,
    rgba(0, 0, 0, 0) 0%,
    #000000 52.403843%,
    rgba(0, 0, 0, 0) 100%
  );
  mask-image: linear-gradient(
    to right,
    rgba(0, 0, 0, 0) 0%,
    #000000 52.403843%,
    rgba(0, 0, 0, 0) 100%
  );
  opacity: 0.4;
}

/* ==========================================================================
   §6  INSTALLS CAROUSEL — loose children of 7053:2, y6842 .. 7454
   ==========================================================================
   Mobile keeps TWO slides and they are desktop's slide 1 (photo `a42a933a` =
   home-icar-slide1.webp, FRAME 7053:272) and desktop's slide **3** (the lime
   dot-grid card, FRAME 7053:278) — NOT slides 1+2. Verified by paint: 7053:272
   is `#fff` + `rgba(0,0,0,.12)` w2, which is `.icar-card-1`, and 7053:278 is
   `#fff` + `#111111` w2 + `INNER_SHADOW #e2fa5a r40`, which is `.icar-card-3`.
   So `.icar-slide:nth-child(2)` is the one that goes.

   Flow, all canvas-absolute:
     heading  6842 .. 6954   240x112, 2 lines, gradient italic 48/56 CENTER
     sub      6954 .. 6998   310x44, HG 400 36/44 CENTER, solid #111 (not ink-70)
     slides   7038 .. 7318   340x280 at x20 and x384 -> pitch 364, gap 24
     caption  7334 .. 7414   255x80 HG 500 32/40 LEFT  (+ the 40x64 lime arrow
                             at x320, vertically centred on the caption box)
     checks   7430 .. 7454   340x24, TWO items
   §5 ends 6802 and §7 starts 7494, so the section is `padding: 40 0`.

   THE ONE INVENTED THING: Figma wires no interaction on mobile §6 — there are
   no prev/next buttons in the mobile frame at all, and slide 2 sits at x384 on
   a 428 canvas, i.e. deliberately off-screen. What Figma *does* draw is a
   68x416 `#fefff9 -> transparent` fade pinned to the right edge
   (RECTANGLE 7053:515), which is a scroll affordance and nothing else. So the
   viewport becomes a native horizontally-scrolling snap container and the nav
   is hidden. The alternative — keeping desktop's buttons — would be inventing
   design rather than behaviour. BUILD-PLAN reaches the same conclusion for §7's
   chip row, which has the identical shape.

   DEFECT FOUND, NOT FIXED (design is locked): the dot-grid card carries five
   badge images in BOTH frames — `FRAME 1707481499..502` + `RECTANGLE "image
   139"` (imageRefs 8afac944 / 86a05f84 / 1b6b5872 / 227191b2 / 57e2209b), at
   identical card-relative positions in desktop 5142:2521 and mobile 7053:278 —
   and the live build renders NONE of them. On desktop all five are inside the
   733x460 card and visible; on mobile the 340x280 clip leaves only `86a05f84`
   fully visible. Reported rather than fixed, so the call can be made for both
   breakpoints at once. */
.icar {
  padding: 2.5rem 0;              /* §5 ends 6802 -> heading 6842; checks end 7454 -> §7 7494 */
}
/* RECTANGLE "Rectangle 35" 7053:515 — 68x416 @ (360,7038), i.e. it starts 236
   below the section top and covers the slide row, the caption row AND the check
   row. `linear-gradient(270deg, …)` is CSS `to left`, so the cream stop is at
   the right edge. It lives on `.icar` (not the scroller) so it stays put.

   REMOVED 2026-08-13 on the user's instruction ("ye white overlay hta do").
   Figma draws it as a scroll affordance for a row that runs off-canvas; the
   row is still a native scroller, so only the hint is gone, not the behaviour.
   Kept commented as the record of what the mobile frame specifies.
.icar::after {
  content: "";
  position: absolute;
  right: 0;
  top: 14.75rem;                  / 7038 - 6802 /
  width: 4.25rem;                 / 68 /
  height: 26rem;                  / 416 /
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(to left, #fefff9 0%, rgba(254, 255, 249, 0) 100%);
}
*/

/* --- heading -------------------------------------------------------------
   Both text nodes are `WIDTH_AND_HEIGHT` (hug) and CENTER, and both hug boxes
   are centred on the canvas: heading 240 at x94 and sub 310 at x59 both put
   their midpoint on 214 = 428/2. So the boxes go full-width and `text-align`
   does the centring. The 15rem on the gradient span is load-bearing: it is
   Figma's own 240 hug width, it is what breaks "Solar installations" after
   "Solar" (the copy has no <br />), and it is the box the gradient below was
   computed over. */
.icar-head {
  width: auto;
  max-width: none;
  margin: 0;
  text-align: center;
}
.icar-h {
  font-size: 3rem;                /* 48 */
  line-height: 3.5rem;            /* 56 */
}
.icar-h-em {
  /* Figma authored 240 for "Solar installations", which fell on 2 lines. The
     client copy is longer and went to THREE in that box (the 388 column was
     never the constraint — this width is). Measured: 2 lines start at 280, so
     288 takes the threshold plus slack and still sits inside the column.
     The paint is re-derived for the new box rather than left alone: the Figma
     handles (0,.5)->(1.3722,.0943) give angle = atan(1.3722w / 0.4057h), which
     reproduces every documented angle in this build exactly, and the end stop
     is that ratio carried across from the 240 and 321 boxes' own corrections.
     The 70.6% first stop is box-independent, so it never moves. */
  width: 18rem;                   /* 288 */
  /* handles (0,.5)->(1.3722,.0943), stops #111 @.5144 / #e2fa5a @1 over 288x112 */
  background-image: linear-gradient(83.44deg, #111111 70.6%, #e2fa5a 135.36%);
}
/* 310x44 hug @ (59,6954) — heading box ends 6954, so no gap. Solid #111111
   here, where the desktop node is #111 @ fill-opacity .7. */
.icar-sub {
  width: auto;
  margin: 0;
  line-height: 2.75rem;           /* 44, not desktop's 56 */
  color: var(--ink);
}
.icar-nav { display: none; }       /* the mobile frame has no prev/next at all */

/* --- track ---------------------------------------------------------------- */
/* The active slide's white sheet sits at `inset: -12` and casts
   `0 4px 40px rgba(0,0,0,.16)`, so its ink reaches 48 above the slide box
   (12 + 40 - 4) and 56 below (12 + 40 + 4). This element is a scroll container,
   and a scroll container clips BOTH axes — `overflow-x: auto` alone computes y
   to auto, which is why the y is declared — so the shadow was being cut off top
   and bottom (user, 2026-08-13: "uper niche se shadow kt rha"). The fix is to
   give the clip that much room and take it straight back with negative margins,
   so the shadow paints in full and not one measured offset moves: slide top
   stays 7038 and every section below §6 keeps its y.

   The side padding is 32, not the page's 20: the active slide's sheet sits at
   `inset: -12`, so a 32 inset lands the SHEET's edge on the 20 gutter and the
   box lines up with every other section (user, 2026-08-13: "box ko content k
   sath align kro"). The card then sits 12 inside its own sheet, which is what
   the desktop render does too. */
.icar-viewport {
  margin-top: -0.5rem;            /* 40 - 48, i.e. the old 2.5rem less the new pad */
  margin-bottom: -3.5rem;         /* -56, cancels the bottom pad */
  padding: 3rem 2rem 3.5rem;      /* 48 / 32 so the sheet lands on 20 / 56 */
  overflow-x: auto;
  overflow-y: hidden;             /* explicit: `overflow-x` alone computes y to auto */
  scroll-snap-type: x mandatory;
  /* without this the snapport starts at the padding edge, so slide 1's own
     20px inset would fight the snap and jump on first drag */
  scroll-padding-left: 2rem;
  scrollbar-width: none;
}
.icar-viewport::-webkit-scrollbar { display: none; }
.icar-track {
  transform: none;                /* no button-driven translate on mobile */
  gap: 1.5rem;                    /* 384 - 20 - 340 = 24 */
}
.icar-slide {
  width: 21.25rem;                /* 340 */
  scroll-snap-align: start;
}
/* Figma's mobile frame carries only TWO slides — desktop's 1 and 3 — so this
   rule used to hide slide 2. The user asked for all three on mobile as well
   (2026-08-13: "is ko slide 3 kro jo web main hain"), and with the client copy
   every slide now says something distinct, so the deviation is deliberate.
   The rule is kept, disabled, because it is the only record of what the mobile
   frame actually specifies. */
/* .icar-slide:nth-child(2) { display: none; } */
/* Figma's mobile frame has no `RECTANGLE "Rectangle 15"` sheet — the slides
   carry their own r12 + stroke and nothing sits behind them — so this used to
   be `content: none`. Restored 2026-08-13 on the user's instruction ("active
   card k pich white background do jese web pe hai"): the override is simply
   dropped, so the active slide inherits desktop's own sheet (inset -12,
   r12, #fff, `0 4px 40px rgba(0,0,0,.16)`) rather than a second recipe.
   Only slide 1 is ever active below 768 — the nav buttons are hidden there, so
   the component's index never moves off 0. */

/* --- cards ---------------------------------------------------------------
   340x280. Both paints are already desktop's — `.icar-card-1`'s #fff +
   rgba(0,0,0,.12) w2 and `.icar-card-3`'s #fff + #111111 w2 + inset lime r40
   are byte-for-byte what 7053:272 / 7053:278 specify — so only the height moves. */
.icar-card { height: 17.5rem; }   /* 280 */

/* RECTANGLE "image 154" 7053:273 — 611x407 at card-rel (-151.5,-59).
   `!important` is deliberate and is the only one in this sheet: the crop is an
   INLINE style on the <img> (InstallsCarousel.tsx's `imgStyle`), and an inline
   declaration outranks every stylesheet rule. The alternative was to move the
   desktop crop out of the locked component, which is a bigger change for the
   same result. See CLAUDE.md's "two px values live outside the CSS". */
.icar-card-1 .icar-photo {
  left: -9.46875rem !important;   /* -151.5 */
  top: -3.6875rem !important;     /*  -59   */
  width: 38.1875rem !important;   /*  611   */
  height: 25.4375rem !important;  /*  407   */
}
/* VECTOR "Vector 12" 7053:274 is 158x66 at card-rel (60.5,45) and still bounds
   the other three sketch vectors, so the SVG box is that box grown by the 3px
   half of its 6px CENTER stroke — the same construction as desktop's. */
.icar-overlay {
  left: 3.59375rem;               /*  57.5 = 60.5 - 3 */
  top: 2.625rem;                  /*  42   = 45 - 3   */
  width: 10.25rem;                /* 164   = 158 + 6  */
  height: 4.5rem;                 /*  72   =  66 + 6  */
}
/* FRAME "Frame 130" 7053:279 keeps its full 669x396 at rel(32,32) even though
   the card is only 340x280 — it overflows on purpose and the card clips it, so
   `inset: 2rem` (which would resolve to 276x216) has to be undone. Dot pitch
   38.88 = (669-8)/17 and row pitch 43.11 = (396-8)/9 both still fall out of
   SPACE_BETWEEN, so nothing is hardcoded. */
.icar-dots {
  inset: auto;
  left: 2rem;                     /*  32 */
  top: 2rem;                      /*  32 */
  width: 41.8125rem;              /* 669 */
  height: 24.75rem;               /* 396 */
}

/* --- caption + arrow + checks --------------------------------------------
   TEXT 7053:505 — 255x80 (2 lines) at slide-rel (0,296), HG **500** where the
   desktop node is 400. The 255 is what wraps it to 2 lines. */
.icar-label {
  margin-top: 1rem;               /* card ends 280 -> caption 296 */
  /* Figma's own value is 255, which exists to clear the 40-wide arrow parked at
     slide-rel x300. Raised to 280 on 2026-08-13 ("is ko 1 line main kro"):
     "Premium installation" needs 267 and goes to one line at 275, so 280 puts
     all three captions on one line — which also lines the three arrows up with
     each other — and still leaves a 20px gap before the arrow. */
  width: 17.5rem;                 /* 280 (Figma: 255) */
  font-weight: 500;
}
.icar-foot { margin-top: 1rem; }  /* caption ends 376 -> check row 392 */
/* FRAME "Arrow Icon Wrapper" 7053:507 — 40x64 at slide-rel (300,304), i.e. it
   leaves the check row and sits beside the caption, vertically centred on it
   ((80-64)/2 = 8 -> 296+8 = 304). Its containing block is `.icar-foot`, not
   `.icar-slide`, because `.icar-slide > *` already sets `position: relative` —
   hence the negative top rather than an absolute one. */
/* FRAME "Arrow Icon Wrapper" 7053:507 — 40x64 at slide-rel (300,304), i.e. it
   leaves the check row and sits beside the caption, vertically centred on it
   ((80-64)/2 = 8 -> 296+8 = 304). Its containing block is `.icar-foot`, not
   `.icar-slide`, because `.icar-slide > *` already sets `position: relative` —
   hence the negative top rather than an absolute one.
   Hidden briefly on 2026-08-13 and put straight back the same day
   ("lime button show krdo pehle jese"), then MOVED off Figma's y304 down to the
   check rows ("button ko bottom text k samne le ao"), and then bottom-aligned
   within them ("button ko bottom align kro"). Pinned to the foot's bottom edge
   rather than to a number, so a different count of points keeps it flush with
   the last one. No translate — that property belongs to the motion layer. */
.icar-cta {
  position: absolute;
  right: 0;
  top: auto;
  bottom: 0;
}
/* Figma's mobile frame carries a 2-item check row (FRAME "Frame 16" 7053:479,
   340x24, two items 137 + 160) instead of desktop's four. The user asked for
   every slide to show the full desktop list on mobile too (2026-08-13: "points
   sar likho sab slides k jo web pe hain"), so the swap is inverted: the desktop
   list shows and the 2-item row is hidden. `.icar-bullets` is 468 wide on
   desktop, which would overflow the 340 slide, hence the width reset — the list
   already wraps, so the four points simply stack. */
.icar-bullets-d {
  display: flex;
  width: 100%;                    /* 340 */
}
.icar-bullets-m { display: none; }

/* ==========================================================================
   §7  LIME PANEL — FRAME "Frame 78" 7053:516, 428x1071 @ y7494, #e2fa5a, clip
   ==========================================================================
   Desktop's two-column 1260x671 panel with r12 and 24px gutters becomes a
   FULL-BLEED, SQUARE-CORNERED single column: 7053:516 is 428 wide at x0 and
   carries no `cornerRadius` at all. Mobile also drops the "An exclusive"
   eyebrow — that string is nowhere in the mobile frame.

   Flow, section-relative, and it adds up to 1071 with nothing hardcoded except
   the shot's own authored 389:
     heading   40 ..  96   241x56 hug, gradient italic 48/56 CENTER
     sub      104 ..  168  357x64, IS 400 24/32 CENTER ink-70
     chips    208 ..  268  388x60 declared, 1219.93 of content -> scrolls
     card     288 ..  622  388x334 = 23 + 288 (9 lines) + 23
     shot     642 .. 1031  388x389
     bottom pad 40         -> 1071, and §8's aerial starts flush at y8565.

   Same invented-behaviour call as §6, and BUILD-PLAN calls it out explicitly:
   `7053:519` is declared 388 wide with `layoutWrap: NO_WRAP` while its seven
   children sum to 1219.93, i.e. Figma drew ONE row that overflows by design
   rather than desktop's wrapped 3-row grid. So the tablist scrolls. */
.iexc { padding: 0; }             /* §6 ends 7494; §8's band starts flush at 8565 */
.iexc-panel {
  width: auto;
  max-width: none;
  margin: 0;
  border-radius: 0;               /* no cornerRadius on 7053:516 */
  display: block;
}
.iexc-left { padding: 2.5rem 0 0; }        /* heading top = 40 */
.iexc-eyebrow { display: none; }           /* "An exclusive" is not in the mobile frame */
/* TEXT 7053:517 — 241x56 hug @ (94,40), centred on the canvas (94 + 120.5 = 214.5).
   The copy differs from desktop by ONE character: "Installations", capital I.
   Done with `text-transform` rather than a .d-only/.m-only pair because the string
   is a single word — but with `::first-letter`, NOT `capitalize`.

   `capitalize` broke on 2026-08-13 when the heading colour sweep began splitting
   this heading into per-character spans: `capitalize` uppercases the first letter of
   every WORD, and word boundaries are per text run, so thirteen one-character inline
   boxes became thirteen words and it rendered "INSTALLATIONS". `::first-letter`
   cannot have that problem — it matches one letter of the block container and does
   not care how many inline elements are wrapped round it. Verified both ways:
   "Installations" at 239.53 split and 239.45 unsplit, so a JS-off render is right
   too, which is more than `capitalize` ever guaranteed.

   `.iexc-h-em` is `inline-block`, i.e. a block container, which is what makes it a
   legal `::first-letter` host. The pseudo goes on the em span rather than `.iexc-h`
   because the em is what starts the line. */
.iexc-h {
  margin: 0;                      /* desktop's -0.14rem existed only to hug the eyebrow */
  font-size: 3rem;                /* 48 */
  line-height: 3.5rem;            /* 56 */
  text-align: center;
}
.iexc-h-em::first-letter {
  text-transform: uppercase;
}
/* handles (0,.5)->(1.3722,.0943), stops #111 @.5144 / #e2fa5a @1 over 241x56 */
.iexc-h-em {
  background-image: linear-gradient(86.07deg, #111111 70.59%, #e2fa5a 136.48%);
}
/* 357x64 @ (35,104) — the 357 width and the 8px gap are already desktop's, only
   the centring is new. (428 - 357) / 2 = 35.5 against Figma's 35. */
.iexc-sub {
  margin: 0.5rem auto 0;
  text-align: center;
}
/* FRAME "Frame 88" 7053:519 — declared 388x60 @ (20,208) but NO_WRAP with 7
   children running to x1239.93, so it is a scroller, not a grid. Chip widths
   stay content-driven (the browser gives 194.67..165.38 against Figma's
   194.99..165.99) and the chip's own r12 / 60 height / 9.99 gap /
   padding[10,10,10,16] / 40 ink icon / Geist 600 20 are all desktop's already. */
.iexc-chips {
  margin-top: 2.5rem;             /* sub ends 168 -> chips 208 */
  width: auto;
  max-width: none;
  flex-wrap: nowrap;
  padding: 0 1.25rem;             /* 20 gutter, and the trailing one too */
  overflow-x: auto;
  overflow-y: hidden;             /* explicit: `overflow-x` alone computes y to auto */
  scrollbar-width: none;
}
.iexc-chips::-webkit-scrollbar { display: none; }
/* The block above now matches nothing — the tabs are off since 2026-08-18
   (SHOW_TABS in ExclusiveTabs.tsx). It stays deliberately, the `.excl-eyebrow`
   reasoning: it is the only record of what Figma's mobile frame specifies here,
   and it is exactly what the scroller needs when the tabs come back. */

/* BOTH ARE DESKTOP-ONLY. §7's replacement for the chips lives above 768 only, so
   the 428 render just loses the tabs. The Trustpilot row follows §4, whose own
   `.psh-reviews` / `.psh-btn-reviews` are already hidden here
   (home-mobile.css:716) — showing it would put the only Trustpilot row on the
   whole mobile page inside §7.

   HISTORY, because this rule was written three times in one session and the end
   state is the deliberate one: "Sirf desktop" (both hidden) → then the CTA was
   shown here, because hiding both costs §7 exactly the chips' 100 (their 40
   margin + 60 height) and "section ki height choti ni krni" had just been said,
   and the CTA's own 40 + 60 closes that gap to the pixel → then, on seeing it,
   "mobile se button hta do". So the CTA is hidden again and the height cost is
   ACCEPTED on this breakpoint: §7 measures 971 against the old 1071, docH 17336
   against 17436, and every section below §7 sits 100 higher. That is normal for
   the 428 column, which is content-driven and re-baselined whenever copy or
   content changes (CLAUDE.md says so explicitly) — the 671 desktop lock is the
   one that must not move, and it does not.

   If the 100 is ever wanted back as empty space, it goes on `.iexc-right`'s top
   margin here (1.25rem -> 7.5rem), NOT as a height on `.iexc-left`. */
.iexc-cta,
.iexc-reviews { display: none; }

/* FRAME "Frame 89" 7053:576 @ (20,288) and FRAME "Frame 128" 7053:578 @ (20,642)
   — one column, 20 gutters, 20 between them, 40 to the section bottom. */
.iexc-right {
  display: block;
  width: auto;
  max-width: none;
  margin: 1.25rem 1.25rem 2.5rem;
}
/* the card's r8, #fff, padding 23/24 and its IS 400 24/32 ink-70 + Medium-500
   lead run are all already desktop's values; at 340 the copy runs to 9 lines,
   so 23 + 288 + 23 = 334 falls out and nothing is declared. */

/* 388x389. The Figma crop needs NO mobile rule at all: it is height-driven
   (`height: 279.1774%` = 1086/389) plus a translate in % of the image's own box,
   and the box height is the SAME 389 here as on desktop — only the width drops
   598 -> 388. So the identical 1448x1086 at (-65,-563) reproduces exactly. */
.iexc-shot {
  flex: none;
  aspect-ratio: auto;             /* the removed fallback pinned this to 598/389 */
  height: 24.3125rem;             /* 389 */
  margin-top: 1.25rem;            /* card ends 622 -> shot 642 */
}

/* ==========================================================================
   §8  SAVE ON ELECTRICITY BILLS — loose children of 7053:2, y8565 .. 10406
   ==========================================================================
   No markup change and no new assets: the card row just turns from a 3-across
   row into a stack, and every card internal is already a desktop value (the
   32 padding, the 60x60 r8 lime square, the 60 icon->title gap, the 6
   title->body gap, and all three fonts). Two real deltas: the aerial band is
   FULL-BLEED with NO radius where desktop has r12 + 12px gutters, and the
   heading carries `letterSpacing: -1.28` where the desktop node is the one
   display heading with **0**.

   Flow, all canvas-absolute:
     aerial   8565 ..  8968   428x403, full-bleed, #000 + inset 40 rgba(0,0,0,.25)
     heading  9008 ..  9120   321x112 (2 lines), gradient italic 48/56 CENTER
     para     9140 ..  9492   388x352 (11 lines), IS 400 24/32 CENTER ink-70
     cards    9524 .. 10406   388x882 shell, r12 #f5f6f0, pad 12 gap 12
     bottom pad 40           -> 10446, which is exactly §9's top.
   Card heights 294 / 270 / 270 all fall out of 32 + 60 + 60 + 32 + 6 + body +
   32 at a 3-line / 2-line / 2-line body, so nothing is declared. */
.sob { padding: 0 0 2.5rem; }     /* §7 ends flush at 8565; cards end 10406 -> §9 10446 */

/* FRAME "Frame 1707481504" 7053:582 — 428x403 at x0, i.e. the 12px gutters and
   the r12 both go. RECTANGLE "image 156" 7053:583 is 916x515 at rel(-244,-25),
   expressed as % of the 428x403 frame so it rides the box like desktop's does. */
.sob-band {
  width: auto;
  max-width: none;
  margin: 0;
  aspect-ratio: 428 / 403;
  border-radius: 0;
}
.sob-band img {
  left: -57.0093457944%;           /* -244 / 428 */
  top: -6.2034739454%;             /*  -25 / 403 */
  width: 214.0186915888%;          /*  916 / 428 */
  height: 127.7915632754%;         /*  515 / 403 */
}
.sob-band::after { border-radius: 0; }

/* TEXT 7053:584 — 321x112 @ (54,9008), and (428 - 321) / 2 = 53.5, i.e. centred.
   `textAutoResize: HEIGHT` means the 321 is authored and load-bearing: it is
   what wraps "Save on Electricity Bills" to two lines, and it is the box the
   gradient below was computed over. Unlike desktop, ls is -1.28 here. */
.sob-h {
  /* Figma's own 40, restated because DESKTOP moved to 7.5rem on 2026-08-18 (the
     user's value, "web pe" only) and this file does not otherwise touch this
     margin — without this line the 428 column would inherit the +80 and every
     section from the heading down would shift. Verified at 428: gap 40, docH 17336. */
  margin-top: 2.5rem;             /* 40 — desktop is 120 since 2026-08-18 */
  font-size: 3rem;                /* 48, desktop 52 */
  line-height: 3.5rem;            /* 56, desktop 60 */
  letter-spacing: -0.08rem;       /* -1.28 — the desktop node is the one with 0 */
}
.sob-h-em {
  width: 20.0625rem;              /* 321 */
  /* handles (0,.5)->(1.3722,.0943), stops #111 @.5144 / #e2fa5a @1 over 321x112 */
  background-image: linear-gradient(84.11deg, #111111 70.6%, #e2fa5a 135.6%);
}
/* TEXT 7053:586 — 388x352 @ (20,9140); heading ends 9120, so 20. */
.sob-p {
  margin: 1.25rem auto 0;
  width: 24.25rem;                /* 388 */
  max-width: none;
}
/* FRAME "Frame 101" 7053:587 — 388x882 @ (20,9524); para ends 9492, so 32.
   r12, #f5f6f0, `padding: 12` and `gap: 12` are already desktop's; only the
   axis and the width change. */
.sob-cards {
  margin: 2rem auto 0;
  width: 24.25rem;                /* 388 */
  max-width: none;
  flex-direction: column;
}
/* `flex: 1 1 0` now sizes the MAIN (vertical) axis, which would force all three
   cards to one height and lose Figma's 294 / 270 / 270. */
.sob-card { flex: none; }
/* the 364-wide card's 32 padding leaves exactly the 300 Figma authors for the
   body copy, so `.sob-card p` needs no width at all */

/* ==========================================================================
   §9  INSIGHTS & UPDATES — loose children of 7053:2, y10446 .. 11220
   ==========================================================================
   Mobile shows ONE card, not three, and the "See All Blogs" CTA leaves the
   heading row to sit full-width UNDER the card. Everything else is already a
   desktop value: `RECTANGLE 36` 7053:4's paint is byte-for-byte `.blog`'s
   existing `linear-gradient(to top, #e2fa5a, rgba(226,250,90,0))`, the card's
   internal rhythm (12 photo->tag, 12 tag->date, 16 tag->title, 6 title->excerpt,
   20 side padding, 20 bottom) is identical, the tag pill's 6/10 padding and its
   `#fefff9` label are identical, and the title's gradient really is the same
   `88.7deg / 70.59% / 137.14%` because the box is the same 366 either side.

   Flow, section-relative (the section top IS the heading top — no padding):
     heading    0 ..  112   321x112 (2 lines), gradient italic 48/56 CENTER
     sub      120 ..  152   357x32, IS 400 24/32 CENTER ink-70
     card     184 ..  656   388x472, r12 clip #fff
     CTA      682 ..  734   388x52, full-width
     bottom pad 40         -> 774, exactly `RECTANGLE 36`'s height.

   The CTA move is done with `display: contents` on `.blog-head`, which promotes
   the h2/sub/CTA to direct flex children of `.blog` so a plain `order` can put
   the CTA last. Absolute positioning would have needed a hardcoded 682 AND a
   magic padding-bottom to give the section its height back. */
.blog {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0 0 2.5rem;            /* CTA ends 11180 -> the rect's bottom 11220 */
}
.blog-head { display: contents; }
.blog-h    { order: 1; }
.blog-sub  { order: 2; }
.blog-cards { order: 3; }
.blog-cta  { order: 4; }

/* TEXT 7053:585 — 321x112 @ (54,10446); (428 - 321) / 2 = 53.5, i.e. centred.
   `textAutoResize: HEIGHT` makes the 321 authored and load-bearing: it wraps
   the heading to two lines and it is the box the gradient was computed over.
   Identical numbers to §8's heading, because that box is 321x112 too. */
.blog-h {
  font-size: 3rem;                /* 48, desktop 60 */
  line-height: 3.5rem;            /* 56, desktop 64 */
}
.blog-h-em {
  width: 20.0625rem;              /* 321 */
  text-align: center;
  background-image: linear-gradient(84.11deg, #111111 70.6%, #e2fa5a 135.6%);
}
/* 357x32 @ (36,10566) — the 357 width and the 8px gap are already desktop's. */
.blog-sub { text-align: center; }

/* FRAME "Frame 126" 7053:601 — 388x472 @ (20,10630); sub ends 152, so 32.
   Cards 2 and 3 are absent from the mobile frame. */
.blog-cards {
  width: 24.25rem;                /* 388 */
  max-width: none;
  margin: 2rem 0 0;
}
.blog-card {
  flex: none;
  width: 100%;
}
.blog-card:nth-child(n + 2) { display: none; }
/* RECTANGLE "image 140" 7053:602 — 406x306 at rel(0,0), i.e. 406 inside a 388
   card, overflowing 18 to the right and clipped by `.blog-shotwrap`. Desktop's
   `width: 100%` would instead squeeze it to 388 and lose the crop. */
.blog-shot {
  width: 25.375rem;               /* 406 */
  max-width: none;                /* home.css's `img { max-width: 100% }` clamps 406 -> 388 */
}
/* TEXT 7053:606 keeps the desktop card's authored 366 box even though the mobile
   card's content column is only 348 — 20 + 366 = 386 still fits inside 388, so
   nothing clips, and the gradient stays laid over the 366 it was computed for.
   (Immaterial visually either way: 70.6% of 348 is 246 and the glyphs stop at
   ~205, so this title renders solid #111 at both breakpoints.) */
.blog-card h3 { width: 22.875rem; }   /* 366 */

/* FRAME "Link - Solid Black" 7053:155 — 388x52 @ (20,11128), so it is in flow
   under the card rather than desktop's absolute top-right pill. Same
   SPACE_BETWEEN-with-a-FILL-label shape as §4's card CTA: the label really
   occupies 16..346 (330 wide) and centres its text there, so the chip leaves
   the flow and its space is reserved as padding-right (10 + 32): 388 - 16 - 42
   = 330 exactly. */
.blog-cta {
  /* `relative` (not `static`) because the chip below is absolute against it —
     which means desktop's `top: 1.375rem` survives as a RELATIVE offset and has
     to be cleared, or the CTA lands 22px low. */
  position: relative;
  top: auto;
  right: auto;
  box-sizing: border-box;
  width: 24.25rem;                /* 388 */
  height: 3.25rem;                /*  52 */
  margin: 1.625rem 0 0;           /* card ends 656 -> CTA 682 */
  display: flex;
  justify-content: center;
  gap: 0;
  padding: 0.625rem 2.625rem 0.625rem 1rem;   /* 10 / 42 / 10 / 16 */
  font-size: 1rem;                /* 16 — the 52-tall button label, not .btn-lg's 20 */
  line-height: 1.6rem;            /* 25.6 */
}
.blog-cta .chip {
  position: absolute;
  right: 0.625rem;                /* 10 -> chip x346..378 */
  top: 0.625rem;                  /* 10 -> 10 + 32 + 10 = 52 */
  flex: none;
  width: 2rem;                    /* 32 */
  height: 2rem;
}
.blog-cta .chip img { width: 1.75rem; height: 1.75rem; }   /* 28 */

/* ==========================================================================
   §10  FAMILY BUSINESS — FRAME "Frame 84" 7053:608, 388x940 @ y11260, r12 #000
   ==========================================================================
   Desktop's full-bleed 1920x572 band with the photo on the RIGHT becomes a
   gutter-inset r12 card with the photo across the BOTTOM. Mobile also drops two
   of desktop's decorations outright — `Rectangle 6` (the 4px-on-24px dot
   pattern) and `Rectangle 5` (the 26x922 bar rotated 45deg) are not in the
   mobile frame at all — and keeps only ONE of desktop's four photo fade rects.

   `ELLIPSE "Ellipse 2"` survives unchanged: 628x8 with `LAYER_BLUR 64` in BOTH
   frames, so its size, its white->lime paint and its blur are already the
   desktop values and only its position moves. Note desktop's `max-width: 100%`
   has to be undone or the 628 glow gets clamped to the 388 band.

   Flow, band-relative:
     heading   24 .. 152   340x128 (2 lines), white->lime italic 48/**64** LEFT
     body     168 .. 400   340x232, IS 400 24/29.28 solid #fff
     CTA      432 .. 484   193x52, lime body + #111 chip, "Get online quote"
     photo    516 .. 940   522.85x424 at rel(-55.85,516), bottom-anchored
   940 is authored, and it is also 516 + 424 exactly. */
.fbiz {
  margin: 2.5rem 1.25rem 0;       /* §9's rect ends 11220 -> band 11260; 20 gutters */
  height: 58.75rem;               /* 940 */
  border-radius: 0.75rem;         /* 12 — desktop's band is square and full-bleed */
}
.fbiz-dots { display: none; }     /* no `Rectangle 6` in the mobile frame */
.fbiz-glow { display: none; }     /* no `Rectangle 5` either */

/* ELLIPSE 7053:609 — 628x8 @ band-rel(-106,84). Same paint and same blur as
   desktop; `.fbiz-inner` fills the band, so these offsets are band-relative and
   `.fbiz`'s own `overflow: hidden` clips the part that runs off to the left. */
.fbiz-hglow {
  left: -6.625rem;                /* -106 */
  top: 5.25rem;                   /*   84 */
  max-width: none;                /* desktop's 100% would clamp 628 -> 388 */
}

.fbiz-inner {
  width: auto;
  max-width: none;
  margin: 0;
  padding: 1.5rem;                /* 24 — heading lands at rel(24,24) */
}
/* TEXT 7053:610 — 340x128 @ rel(24,24). Only the size changes: 48/**64** here
   against desktop's 60/64, and the 340 is what wraps it to two lines. */
.fbiz-h {
  font-size: 3rem;                /* 48 */
  line-height: 4rem;              /* 64 — unchanged from desktop */
}
.fbiz-h-em {
  width: 21.25rem;                /* 340 */
  /* handles (0,.5)->(1.2139,.1719), stops #ffffff @0 / #e2fa5a @1 over 340x128 */
  background-image: linear-gradient(84.19deg, #ffffff 1.84%, #e2fa5a 119.96%);
}
/* TEXT 7053:611 — 340x232 @ rel(24,168); heading ends 152, so 16. Font and
   colour are already desktop's; the 340 wraps it to 8 lines. */
.fbiz-p {
  margin: 1rem 0 0;
  width: 21.25rem;                /* 340 */
}
/* FRAME 7053:612 — 193x52 @ rel(24,432); body ends 400, so 32. Width is
   content-driven (16 + 125 label + 10 + 32 chip + 10 = 193). The lime body,
   the #111 chip and the white arrow are all already desktop's. */
.fbiz-btn {
  margin-top: 2rem;
  height: 3.25rem;                /* 52 */
  padding: 0.625rem 0.625rem 0.625rem 1rem;   /* 10 / 10 / 10 / 16 */
  gap: 0.625rem;                  /* 10 */
  font-size: 1rem;                /* 16 — not .btn-lg's 20 */
  line-height: 1.6rem;            /* 25.6 */
}
.fbiz-btn .chip { width: 2rem; height: 2rem; }             /* 32 */
.fbiz-btn .chip img { width: 1.75rem; height: 1.75rem; }   /* 28 */

/* RECTANGLE "image 127" 7053:620 — 522.85x424 at rel(-55.85,516). There is no
   wrapper frame on mobile: the image rect IS the box, bottom-anchored (516 + 424
   = 940) and overflowing the band 79 to the right, which `.fbiz` clips. */
.fbiz-photo {
  top: 32.25rem;                  /* 516 */
  left: -3.490625rem;             /* -55.85 */
  right: auto;
  width: 32.678125rem;            /* 522.85 */
  height: 26.5rem;                /* 424 */
}
.fbiz-photo img {
  left: 0;
  right: auto;
  top: 0;
  width: 100%;
  height: 100%;
}
/* RECTANGLE "Rectangle 11" 7053:621 — the ONLY fade rect on mobile (desktop has
   four). Declared 388x103 at band-rel(0,516) with `rotationDeg: 90` and a
   pre-rotation size of 103x388, gradient #000 -> transparent across its own
   x-axis. Desktop's verified -90deg version puts black at the BOTTOM, so +90
   puts it at the TOP: the photo emerges downward out of the black band.
   It is aligned to the BAND, not to the photo box, hence the 55.85 left offset
   that cancels the photo's own -55.85. */
.fbiz-photo::after {
  inset: auto;
  left: 3.490625rem;              /* +55.85 -> band x0 */
  top: 0;
  width: 24.25rem;                /* 388 */
  height: 6.4375rem;              /* 103 */
  background: linear-gradient(to bottom, #000000 0%, rgba(0, 0, 0, 0) 100%);
}

/* ==========================================================================
   §11a FAQ — loose children of 7053:2, y12240 .. 13388
   ==========================================================================
   Two columns become one, and mobile drops the whole contact card (`Frame 100`,
   the "Have questions about solar installation…" box with its own CTA) — it is
   not in the mobile frame. Everything inside a row is already a desktop value:
   the r12 white box, the `[16,16,16,24]` padding, the 9.99 gap, Geist 400 20/25.6
   for the question, and the 40x40 r8 `#f6f6f6` chevron with its +90deg rotation.

   The sub's copy is IDENTICAL to desktop's ("Have questions about Salesflow?…"),
   so BUILD-PLAN's copy delta 7 turned out to be a no-op — verified, no swap.

   Flow:
     heading  12240 .. 12352   340x112 (2 lines), CENTER
     sub      12360 .. 12488   388x128 (4 lines), HG 400 24/32 CENTER ink-70
     shell    12528 .. 13388   388x860, r12, #f5f6f0 -> #e2fa5a, pad 12 gap 10
   860 = 12 + 9x84 + 8x10 + 12 exactly. §11b then starts 20 later at 13408.

   Note the heading's gradient carries the CANONICAL 0.5144 stop (-> 70.6%) here,
   NOT the 0.1554 (-> 22.02%) that the desktop node genuinely has. Mobile is the
   frame that gets this paint right everywhere. */
.qna { padding: 2.5rem 0 0; }     /* §10's band ends 12200 -> heading 12240 */
.qna-row {
  width: auto;
  max-width: none;
  margin: 0 1.25rem;              /* 20 gutters -> a 388 column */
  flex-direction: column;
  gap: 2.5rem;                    /* sub ends 12488 -> shell 12528 */
}
.qna-left { width: auto; }
.qna-card { display: none; }      /* `Frame 100` is not in the mobile frame */

/* TEXT 7053:622 — 340x112 @ (44,12240); (428 - 340) / 2 = 44, i.e. centred, and
   the 340 is what wraps it to two lines. 48/56 with ls -1.28 where the desktop
   node is 52/60 with ls 0. */
.qna-h {
  font-size: 3rem;                /* 48 */
  line-height: 3.5rem;            /* 56 */
  letter-spacing: -0.08rem;       /* -1.28 — the desktop node has 0 */
}
.qna-h-em {
  width: 21.25rem;                /* 340 */
  margin: 0 auto;
  text-align: center;
  /* stops #111 @.5144 / #e2fa5a @1 over 340x112 — the canonical paint */
  background-image: linear-gradient(84.44deg, #111111 70.6%, #e2fa5a 135.77%);
}
/* 388x128 @ (20,12360); heading ends 12352, so 8. Desktop's `max-width: 100%`
   already clamps its 491 to the 388 column, so only the gap and the centring
   are restated. */
.qna-sub {
  margin: 0.5rem 0 0;
  text-align: center;
}
/* `flex: 1` would resolve against a `flex-basis: 0%` on the now-VERTICAL main
   axis and collapse the list to nothing. */
.qna-faqs { flex: none; }
/* Rows are 84 on mobile, not 72: the question box is only 274.01 wide
   (364 - 24 - 9.99 - 40 - 16), so Figma's string wraps to two lines and
   16 + 52 + 16 = 84. `min-height` rather than `height` because the nine
   questions this build ships are authored, not Figma's one repeated string —
   a 1-line question still measures 84 with its text centred, and a hypothetical
   3-line one grows instead of being clipped by `.qna-faq`'s overflow. */
.qna-faq-btn {
  height: auto;
  min-height: 5.25rem;            /* 84 */
}

/* ==========================================================================
   §11b FOOTER — FRAME 7053:679, 388x1949 @ y13408
   ==========================================================================
   Same three-part shell as desktop (gradient outer, white card, white legal bar)
   and its `padding: 12` / `gap: 10` / r12 / `#f5f6f0 -> #e2fa5a` are already the
   desktop values, so 12 + 1855 + 10 + 60 + 12 = 1949 falls out. What changes is
   inside the card: the photo goes from 534 tall to 216, the brand column and the
   nav grid stop being side by side, and the 18 nav items become PILLS.

   Flow, card-relative (card = 364 wide at rel(12,12)):
     heading    40 ..  184   303x144 (3 lines), HG 400 40/48 CENTER
     sub       196 ..  276   304x80  (4 lines), IS 400 16/19.52 CENTER
     CTA       308 ..  368   231.99x60 — exactly `.btn .btn-lg`'s own size
     photo     403 ..  619   500x216 at rel(-68,403), + a 111 white bottom scrim
     logo      659 ..  719   117x60, social chips 40x40 on the SAME row at x208/256/304
     blurb     735 ..  807   324x72 (3 lines)
     nav      847 / 1183 / 1519, each 324x296 — a 336 pitch
     bottom pad 40          -> 1855
   Every one of those gaps is a margin, so nothing but the photo is declared.

   THREE deltas that are not CSS:
     - the heading drops "living" (`.d-only` span in app/page.tsx)
     - the General column gains a SECOND "T&C's" -> 18 items, not 17 (`.m-only` <li>)
     - the nav items get an arrow, which is a `::after` background rather than 18
       new <img> tags. `arrow.svg` at 26 reproduces `Arrow Icon` exactly: its
       viewBox-28 path is 14x9.33 at (7,9.33), and x 26/28 gives 13x8.66 at
       (6.5,8.66) — Figma's numbers to 0.01. */
/* Top 20 is Figma's (§11a ends 13388 -> footer 13408). The bottom 144 is the
   user's call (2026-08-05), not the canvas: Figma's mobile frame ends flush at
   15377 with no tail, so the page bottomed out right under the legal bar with
   the sticky quickbar (68 tall, pinned 40 off the bottom) sitting on top of it. */
.ftr { padding: 1.25rem 0 9rem 0; }
.ftr-shell {
  width: auto;
  max-width: none;
  margin: 0 1.25rem;              /* 20 gutters -> a 388 shell, 364 card */
}
.ftr-card { padding: 2.5rem 0; }  /* 40 top and bottom */

/* TEXT 7053:692 — 303x144 @ (30,40). 40/48 and ls -1.28 are already desktop's;
   the 303 is what wraps "Innovative solar energy solutions" to two lines above
   the explicit <br />, giving three lines total. */
.ftr-h {
  width: 18.9375rem;              /* 303 */
  margin: 0 auto;
}
/* TEXT 7053:683 — 304x80 @ (29,196); heading ends 184, so 12. 16/19.52 here
   against desktop's 20/24.4. */
.ftr-sub {
  width: 19rem;                   /* 304 */
  margin: 0.75rem auto 0;
  font-size: 1rem;                /* 16 */
  line-height: 1.22rem;           /* 19.52 */
}
/* FRAME 7053:684 — 231.99x60 @ (65,308); sub ends 276, so 32. The 60 height, the
   Geist 600 20/25.6 label and the 40x40 lime chip are `.btn-lg`'s own values, so
   16 + 156 + 9.99 + 40 + 10 = 231.99 needs no override at all. */
.ftr-cta { margin: 2rem auto 0; }

/* RECTANGLE " 1235104227" 7053:681 — 500x216 at rel(-68,403), i.e. it overflows
   the 364 card by 68 on BOTH sides and `.ftr-card`'s r12 clip trims it.
   RECTANGLE "Rectangle 12" 7053:682 — the 364x111 white scrim, bottom-anchored
   to the photo (403 + 216 = 619 = 508 + 111), which desktop's `bottom: 0` gives. */
.ftr-photo {
  margin-top: 2.1875rem;          /* 35 — CTA ends 368 -> photo 403 */
  height: 13.5rem;                /* 216 */
}
.ftr-photo img {
  width: 31.25rem;                /* 500 */
  max-width: none;                /* home.css's `img { max-width: 100% }` clamps 500 -> 364 */
  margin-left: -4.25rem;          /* -68 */
}
.ftr-photo::after { height: 6.9375rem; }   /* 111, was 258 */

/* The brand row: logo LEFT and the three social chips RIGHT on one line, blurb
   underneath. DOM order is logo -> blurb -> social, so explicit grid placement
   does the reorder without touching the markup. 20 padding puts the logo at x20
   and the last chip's right edge on 344, which is 364 - 20. */
.ftr-bottom {
  display: block;
  margin-top: 2.5rem;             /* photo ends 619 -> logo 659 */
  padding: 0 1.25rem;             /* 20 -> a 324 content column */
}
.ftr-brand {
  width: auto;
  margin: 0;
  display: grid;
  /* The logo's track is DECLARED at its Figma 117, not left as `auto`, and the
     social row is placed with `justify-self` rather than `justify-content:
     space-between`. Both matter: `.ftr-blurb` spans the two columns, and a
     spanning item's max-content contribution is distributed into `auto` tracks —
     which inflated them until there was no free space left to distribute, so
     space-between did nothing AND the logo's track shrank to 94, which
     home.css's `img { max-width: 100% }` then clamped the 117 logo down to. */
  grid-template-columns: 7.3125rem 1fr;   /* 117 logo | the rest */
  align-items: center;            /* centres the 40 chips on the 60 logo -> y669 */
  row-gap: 1rem;                  /* logo ends 719 -> blurb 735 */
}
.ftr-logo   { grid-area: 1 / 1; }
.ftr-social { grid-area: 1 / 2; justify-self: end; margin-top: 0; }
.ftr-blurb  { grid-area: 2 / 1 / 3 / -1; margin: 0; }

/* Three stacked 324x296 blocks on a 336 pitch. Each is a 32-tall gradient
   heading + 20 + a 244 list, so 296 falls out. */
.ftr-nav {
  display: flex;
  flex-direction: column;
  gap: 2.5rem;                    /* 336 pitch - 296 block */
  margin-top: 2.5rem;             /* blurb ends 807 -> nav 847 */
}
/* HG 600 italic 24/31.92 ls 0 here, against desktop's 20/26.6. Same `0.1554`
   paint, but each hug box has its own width (93 / 107 / 85 vs desktop's
   77 / 89 / 71), so all three angles and end stops move.
   `background-image`, never the `background` shorthand — see the desktop note. */
.ftr-navh {
  font-size: 1.5rem;              /* 24 */
  line-height: 1.995rem;          /* 31.920001983642578 */
}
.ftr-navh-services span { background-image: linear-gradient(84.19deg, #111111 22.51%, #e2fa5a 135.64%); }  /* 93x32 */
.ftr-navh-company  span { background-image: linear-gradient(84.95deg, #111111 22.23%, #e2fa5a 136.01%); }  /* 107x32 */
.ftr-navh-general  span { background-image: linear-gradient(83.65deg, #111111 22.73%, #e2fa5a 135.34%); }  /* 85x32 */

/* FRAME "Frame 102" — AL VERTICAL gap 8; 6 x 34 + 5 x 8 = 244. */
.ftr-nav ul { gap: 0.5rem; }      /* 8, was 12; the 20 margin-top is desktop's */
/* Each item is now `Frame 17074815xx`: 324x34 r8 #f5f6f0, SPACE_BETWEEN,
   padding [4,12,4,12], a Geist 500 16/25.6 label (already desktop's font) and a
   26x26 arrow whose right edge lands on 312 = 324 - 12. */
.ftr-nav li {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;                    /* 8 */
  height: 2.125rem;               /* 34 = 4 + 26 + 4 */
  padding: 0.25rem 0.75rem;       /* 4 / 12 */
  border-radius: 0.5rem;          /* 8 */
  background: var(--panel);       /* #f5f6f0 */
}
.ftr-nav li::after {
  content: "";
  flex: none;
  width: 1.625rem;                /* 26 */
  height: 1.625rem;
  background: url("/assets/img/arrow.svg") 50% / contain no-repeat;
}
/* the legal bar needs nothing: 364x60, r12, #fff and its centred
   Instrument Sans 500 16/19.52 are already the desktop values. */

/* ==========================================================================
   STICKY QUICKBAR — FRAME "Frame 113" 7053:259
   ==========================================================================
   `FRAME "Frame 115" 7053:258` is an empty 428x926 frame at y926, i.e. Figma
   drew a SECOND copy of the viewport purely to hold this, so its child's
   position is a VIEWPORT position, not a document one: 259x68 at rel(85,818)
   means centred ((428 - 259) / 2 = 84.5) and 40 off the bottom
   (926 - 818 - 68 = 40). Which is exactly what `.quickbar`'s fixed + centred
   transform already does — only the width, the bottom offset and the shadow move.

   Mobile drops "Ask a question" and the "from our experts" line, leaving burger
   + CTA: 4 + 60 + 4 + 186 = 254 inside the 259 shell, so the right inset is 5
   and the left is 4. `margin-left: auto` on the CTA (already desktop's) lands it
   on 68 exactly once the padding is asymmetric.

   `.pill-menu` needs nothing at all — its 60x60, r12, 2px ink border, and its
   three 27x3 bars on a 6 gap centred in 60 (which reproduces Figma's 36x36 icon
   frame at rel(12,12) with bars at y 7.5 / 16.5 / 25.5) are ALL already the
   desktop values. Only the white fill is restated. */
.quickbar {
  width: 16.1875rem;              /* 259 */
  bottom: 2.5rem;                 /* 40 */
}
.pv-pill {
  height: 4.25rem;                /* 68 — unchanged from desktop */
  gap: 0;                         /* the CTA's auto margin does the spacing */
  padding: 0.25rem 0.3125rem 0.25rem 0.25rem;   /* 4 / 5 / 4 / 4 */
  box-shadow: 0 0 2.5rem rgba(0, 0, 0, 0.2);    /* DROP_SHADOW r40 @ .20 */
}
.pill-ask,
.pill-experts { display: none; }  /* neither string is in the mobile frame */
.pill-menu { background: var(--white); }

/* FRAME 7053:260 — 186x60 @ rel(68,4). `.pill-cta` is `.btn .btn-dark` WITHOUT
   `.btn-lg`, so it inherits the 16px label / 32 chip / 22 arrow and needs the
   larger set. The width is DECLARED rather than left to content because the
   markup carries a trailing space after "Get a quote": that space is part of the
   anonymous flex item, which would make the button ~191 and overlap the burger.
   `space-between` then pins the chip at 186 - 10 - 40 = 136, which is Figma's
   own rel x, and lets the trailing space hang harmlessly. */
.pill-cta {
  flex: none;
  width: 11.625rem;               /* 186 */
  justify-content: space-between;
  gap: 0;
  font-size: 1.25rem;             /* 20 */
  line-height: 1.6rem;            /* 25.6 */
}
.pill-cta .chip { width: 2.5rem; height: 2.5rem; }             /* 40 */
.pill-cta .chip img { width: 1.75rem; height: 1.75rem; }       /* 28 */

} /* end @media (max-width: 767.98px) */
