/* D15's three "before" values are the one place in the whole design that uses
   a fourth family.  Imported here rather than added to base.css's font import:
   base.css is shared with the frozen homepage, where the standing rule is "add
   new selectors, never alter an existing rule or token value". */
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@500&display=swap");

/* ==========================================================================
   /quote/results?panel=details — the "View details" overlay.
   Built same-to-same from the LIVE Figma file R4YlVFqXtGfx3rlvWSMro8,
   FRAME "View details" 7064:1823 (D11), 1920x1010.
   Spec: design-reference/wizard/spec/desktop/D11-view-details-1.md
   Render: design-reference/wizard/render/D11_view-details-1_7064-1823.png

   Linked FROM app/quote/results/page.tsx alongside quote-results.css, never
   from the layout.  Namespace is `.qd-`, verified zero hits across base /
   home / home-sections / home-mobile / motion / quote-wizard / quote-results /
   quote / flow / results.  Adding a SECOND page sheet here is safe precisely
   because every selector in it is `.qd-`-prefixed: the "exactly one page
   sheet" invariant exists because quote/flow/results clobber each other on
   shared selectors, and this file shares none.

   Every length is rem = figma_px / 16, against base.css's fluid root
   (calc(100vw/120) above 768).  Never write px here.

   D11 IS ONE OF THREE TABS, NOT ONE OF THREE PACKAGES.  WIZARD-NOTES reads
   D11/D12/D13 as "overlay, package 1/2/3"; the wiring says otherwise —
   D11's "What's included?" row -> 7064:2115 (D12) and its "Reviews" row ->
   7064:2257 (D13), and all three carry the SAME package title.  So they are
   the Details / What's included? / Reviews tabs of the same overlay, and all
   three D10 package cards open THIS one.  D12 and D13 are not built yet.
   ========================================================================== */

/* The overlay is a modal: while it is open the 2758-tall page behind it must
   not scroll.  New selectors, so base.css is untouched — and `:has` at (0,1,1)
   outranks the bare `html` there without depending on load order.

   `scrollbar-gutter` is the other half and it is load-bearing — note it is on
   `:has(.qd)`, i.e. ALWAYS, not on the open state.  `overflow: hidden` alone
   takes the scrollbar away and the page behind widens by its 15px, which reads
   as a jump through the scrim; reserving the gutter permanently means the two
   states measure the same.  Measured both ways: gated on `.is-open` the page's
   own `.qr-card` moves 535.78 -> 540 on open, ungated it holds 535.78 through
   open, close and reopen.  Reserving it costs nothing when closed, because a
   2758-tall page has a real scrollbar in that gutter anyway. */
html:has(.qd) { scrollbar-gutter: stable; }
html:has(.qd.is-open) { overflow: hidden; }

/* ==========================================================================
   THE FRAME — 1920x1010, pinned to the viewport
   ==========================================================================
   Figma draws D11 as a full 1920x1010 screen with the D10 page baked in as
   `image 148`.  Here the real /quote/results page is that layer, so the image
   is not reproduced; everything from `Rectangle 24` down is.

   IT IS A POPUP, NOT A SCREEN (user, 2026-08-07: "aese lgna chahiye k popup
   nikal rha na k new screen load ho rhi" / "jb popup close ho to results page
   should not reload ... just popup fade out ho jay or bottom ki traf jay").
   So this subtree is ALWAYS mounted and only toggles `.is-open`; nothing here
   ever navigates, and the page behind is never re-rendered.  Two consequences
   worth knowing:

   1. `visibility` + `transition-behavior: allow-discrete` is what keeps the
      overlay painted for the whole leave transition — the same mechanism
      FaqAccordion and .qz-step already use.  Without it the closed state would
      hard-cut instead of fading.
   2. NONE of these elements may be a `motion-spec.json` reveal target.
      MotionLayer runs one `querySelectorAll` in a mount effect and never
      observes the DOM again, so anything revealed here would work on a direct
      `?panel=details` load and then be permanently stuck at
      `opacity: 0` — `motion.css` hides reveal targets with
      `:is(...):not(.rv-in)` and nothing would ever add `rv-in`.  Eighteen
      `.qd-*` groups were written and then removed for exactly this reason; the
      entrance below is the popup's own animation instead. */
.qd {
  /* Authored, like the wizard's step transition, and deliberately NOT
     --ease-premium: that is an expo-out that spends ~80% of the travel in the
     first fifth, so a sheet on it reads as snapping rather than arriving.
     This is a swift-out curve — smooth and even the whole way, with no flick
     at either end.  Opening is slower than closing (720 / 560), which is what
     makes the sheet feel like it has weight coming up and gets out of the way
     going down; both values are read off the state being transitioned TO, so
     the override on .is-open below is all it takes. */
  --qd-dur: 560ms;
  --qd-ease: cubic-bezier(0.25, 0.8, 0.25, 1);
  /* one token for the sheet's height AND its travel, so the closed state is
     always exactly "one sheet below the fold" */
  --qd-sheet-h: min(58.125rem, calc(100vh - 5rem));

  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  visibility: hidden;
  transition: visibility var(--qd-dur) var(--qd-ease);
  transition-behavior: allow-discrete;
}
.qd.is-open {
  --qd-dur: 720ms;
  pointer-events: auto;
  visibility: visible;
}

/* The sheet and the price bar travel as ONE object — they overlap, so a
   per-element `translate: 0 100%` would move them at different rates and the
   bar would visibly detach on the way up.  This wrapper is inset 0, i.e. the
   same box the two already position against, so no offset inside it changes. */
.qd-sheet {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  translate: 0 var(--qd-sheet-h);
  /* its own compositor layer, so 930px of travel never lands on the main
     thread — this is the difference between smooth and stepped here */
  will-change: translate, opacity;
  transition:
    translate var(--qd-dur) var(--qd-ease),
    opacity var(--qd-dur) var(--qd-ease);
}
.qd-sheet > * { pointer-events: auto; }
.qd.is-open .qd-sheet { opacity: 1; translate: 0 0; }

/* The two arrows only fade — sliding them would read as a second object
   arriving.  The SCRIM does not fade by opacity, and that is the fix for a
   real bug (user, 2026-08-07: "blur effect shroo se hi lga hona chahiye
   background kyun k abi 1st wese black background aajata hai with opacity then
   after some time blur effect lgta hai").

   `backdrop-filter` is scaled by the element's own opacity, so animating
   opacity ramps the blur in alongside the darkness — and because the blur is
   the slower of the two to become legible, it reads as "black first, blur
   later".  Animating the background COLOUR instead leaves the element at
   opacity 1 for the whole transition, so the backdrop is at full blur from the
   first painted frame and only the darkness arrives. */
.qd-nav {
  opacity: 0;
  transition: opacity var(--qd-dur) var(--qd-ease);
}
.qd.is-open .qd-nav { opacity: 1; }

/* The fade is LINEAR, not --qd-ease, and that is what makes the darkness
   leave with the sheet rather than after it (user, 2026-08-07: "jb popup niche
   chla jata hai to background pe us k sath hi fadout ho k khatam hojana
   chahiye").  On the sheet an ease-out is right — it decelerates into place —
   but the same curve on an alpha spends its whole tail between 0.2 and 0, and
   a nearly-transparent black over a bright page is still visible, so the
   screen stayed dim after the sheet had gone.  A linear alpha is perceptually
   even and reaches 0 on time.  Same duration, so the two still end together.

   THE BLUR IS ASYMMETRIC, AND BOTH HALVES WERE ASKED FOR:

     opening   instant — full blur on the first painted frame
               ("blur effect shroo se hi lga hona chahiye")
     closing   fades out over --qd-dur with everything else
               ("ye blur popup niche jane k sath hi khatam hona chahiye or
                 smoothly vanish hona chahiye")

   Left un-transitioned the blur held at full strength for the whole 560ms of
   the close and then vanished the instant `visibility` flipped — the page
   behind sat fully blurred under a sheet that had already gone, then snapped
   sharp.  CSS gets both directions from one pair of rules because a transition
   is read off the state being transitioned TO: the base rule below owns the
   LEAVING transition, `.qd.is-open` owns the ENTERING one, and it sets the
   blur's duration to 0s. */
.qd-scrim {
  background-color: rgba(17, 17, 17, 0);
  -webkit-backdrop-filter: blur(0);
          backdrop-filter: blur(0);
  transition:
    background-color var(--qd-dur) linear,
    -webkit-backdrop-filter var(--qd-dur) linear,
    backdrop-filter var(--qd-dur) linear;
}
.qd.is-open .qd-scrim {
  background-color: rgba(17, 17, 17, 0.9);
  -webkit-backdrop-filter: blur(1rem);
          backdrop-filter: blur(1rem);
  transition:
    background-color var(--qd-dur) linear,
    -webkit-backdrop-filter 0s,
    backdrop-filter 0s;
}

/* ---- the scrim — ONE element, not Figma's four ------------------------
   Figma draws four rects here (24 / 28 / 26 / 27), all `#111111 op0.9` +
   BACKGROUND_BLUR radius 16, all wired ON_CLICK -> D10.  They are a
   PROTOTYPING device, not a design: four boxes tiled around the sheet so that
   in Figma's own preview a stray click near the sheet cannot land on it
   (user, 2026-08-07: "figma main to is liye rkha tha ta k prototype main
   galati se click na ho jay").  In HTML one anchor does that job, so this is
   one element.

   Collapsing them also removes two real artefacts they caused here:
     - 24 and 28 overlap across the top and 28 laps 10px past 26/27, so the
       tint composited 0.9 / 0.99 / 0.999 in bands;
     - worse, each rect carried its own `backdrop-filter`, and stacked backdrop
       filters blur the backdrop twice (three times in those 10px strips) and
       leave a hard edge at every boundary — which is what showed as two bright
       vertical seams just outside the sheet's top corners.
   Figma's own render is flat, which is the target: sampled across y=40 from
   x460 to x1460 it holds 17..19.

   The blur is Figma's radius 16 used DIRECTLY as the CSS blur length, not the
   16 / 2.82 = 5.674px support conversion CLAUDE.md derives elsewhere (user,
   2026-08-07: "background ko black blur pe le k jao").  The conversion is the
   right one when a blur's visible spread has to match Figma's — here nothing
   is being matched edge for edge, the backdrop is 90% covered by ink, and at
   5.7px there was no legible blur left at all. */
.qd-scrim {
  position: absolute;
  inset: 0;
  display: block;
}

/* ---- Rectangle 25, the sheet handle @880,66 160x6 ---------------------- */
.qd-handle {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 4.125rem;
  width: 10rem;
  height: 0.375rem;
  border-radius: 1.25rem;
  background: rgba(254, 255, 249, 0.16);            /* #fefff9 @ .16 */
}

/* ---- the two 60x60 nav arrows @380,515 and @1480,515 --------------------
   Figma wires NOTHING on either (interactions.json has no entry for 7064:1830
   or 7064:1835) and the file contains no second package's detail screen for
   them to reach, so they ship as inert marks — the same call already made for
   the mobile header burger.  Constraints are LEFT/CENTER: box top 515 against
   the frame's own centre 505, i.e. centre + 10. */
.qd-nav {
  position: absolute;
  top: calc(50% + 0.625rem);
  width: 3.75rem;
  height: 3.75rem;
}
.qd-nav img { width: 100%; height: 100%; }
.qd-nav-prev { left: calc(50% - 36.25rem); transform: rotate(180deg); }        /* 960-580 = 380, rotationRad pi */
.qd-nav-next { left: calc(50% + 32.5rem); }                                    /* 960+520 = 1480 */

/* ==========================================================================
   THE SHEET — Frame 1707481545 @480,80 960x930, radii [40,40,0,0]
   ==========================================================================
   constraints CENTER/BOTTOM and 80 + 930 = 1010, i.e. flush with the frame
   bottom, so it is bottom-anchored rather than top-positioned.  The height is
   capped the same way .qr-side is on the page behind: at Figma's own 1010-tall
   viewport `100vh - 5rem` IS 930, taller windows keep 930, and a short window
   shrinks the sheet instead of pushing its head off screen. */
.qd-modal {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0;
  width: 60rem;
  height: var(--qd-sheet-h);                        /* min(930, 100vh - 80) */
  background: var(--bg);                            /* #fefff9 */
  border-radius: 2.5rem 2.5rem 0 0;
  overflow: hidden;                                 /* clipsContent */
}

/* ---- Frame 1707481572, the marble ground -------------------------------
   RECTANGLE 7064:1842 — bbox rel(-1791,-1241) 3953.91x3137.77, rotationRad
   -0.45275724 (= -25.9411deg).  Same centre-preserving conversion as the
   page's own marble: the bbox is the ROTATED box, fillGeometry gives the real
   3536.36 x 1769.04, and rotation preserves the centre —
       centre = (-1791 + 3953.91/2, -1241 + 3137.77/2) = (185.955, 327.885)
       left   = 185.955 - 3536.36/2 = -1582.225
       top    = 327.885 - 1769.04/2 =  -556.635
   3536.36/1769.04 = 1.9990 = 4096/2049, so `cover` crops nothing.  It sits in
   its own clip layer, NOT in the scroller: Figma sizes this frame 960x930, the
   sheet's viewport, so the texture must not travel with the content. */
.qd-marble {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  /* Held back from Figma's full strength (user, 2026-08-07: "give some opacity
     to the background image").  The texture's own mean colour is #fefff9, so
     what actually reads on screen is its pale-lime veining, and at full
     strength those streaks compete with the copy sitting on top of them. */
  opacity: 0.5;
}
.qd-marble img {
  position: absolute;
  left: -98.8890625rem;
  top: -34.7896875rem;
  width: 221.0225rem;
  height: 110.565rem;
  max-width: none;
  object-fit: cover;
  transform: rotate(-25.9411deg);
}

/* ---- the scroller ------------------------------------------------------
   The sheet clips at 930 but its content runs to 1560: the grey panel ends at
   1398, then Figma parks a pixel-aligned DUPLICATE of the green bar at
   @40,1438 880x122.  That duplicate is how the file says "the bar is pinned" —
   scrolled to the end, 1438 - 630 = 808, exactly where the real bar sits — so
   it is not reproduced, and its box survives as the 40 + 122 of clearance
   under the last paragraph.  `Frame 1707481571` carries scroll: STICKY_SCROLLS,
   which is the other half of the same statement.

   Positioned by `left` throughout, never `right`, so a scrollbar taking width
   off the scrollport cannot move anything.  At 960 wide the bar lands in
   x945..960, clear of the grey panel's own 920 right edge. */
.qd-scroll {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overflow-x: hidden;
  /* Light, so the platform's default heavy bar does not sit as a grey slab
     against the sheet's #fefff9 (user, 2026-08-07: "scroll bar ko light color
     kro").  `scrollbar-width: thin` is what stops Windows drawing the wide
     one; the WebKit block below is the same two colours for browsers that do
     not honour the standard properties.  Ink at low alpha rather than a new
     grey, so it stays in the page's own palette. */
  scrollbar-width: thin;
  scrollbar-color: rgba(17, 17, 17, 0.16) transparent;
}
.qd-scroll::-webkit-scrollbar { width: 0.5rem; }
.qd-scroll::-webkit-scrollbar-track { background: transparent; }
.qd-scroll::-webkit-scrollbar-thumb {
  background: rgba(17, 17, 17, 0.16);
  border-radius: 0.25rem;
}
.qd-scroll:hover { scrollbar-color: rgba(17, 17, 17, 0.28) transparent; }
.qd-scroll::-webkit-scrollbar-thumb:hover { background: rgba(17, 17, 17, 0.28); }
/* `flow-root`, not the default: .qd-rail is the only in-flow child and its
   30.875rem top margin would otherwise collapse straight out of this box. */
.qd-body {
  position: relative;
  display: flow-root;
}
/* panel bottom (534 + its own height) + Figma's 40 gap + the 122 bar */
.qd-body-0 { height: 97.5rem; }                     /* 534 + 864 + 162 = 1560 */
.qd-body-1 { height: 96.25rem; }                    /* 534 + 844 + 162 = 1540 */
.qd-body-2 { height: 92.8125rem; }                  /* 534 + 789 + 162 = 1485 */
.qd-body > .qd-title,
.qd-body > .qd-esurvey,
.qd-body > .qd-savebtn,
.qd-body > .qd-card,
.qd-body > .qd-dots,
.qd-body > .qd-copy,
.qd-body > .qd-panel { position: absolute; }

/* ---- TEXT 7064:1860, the title @40,40 469x80 --------------------------- */
.qd-title {
  left: 2.5rem;
  top: 2.5rem;
  width: 29.3125rem;                                /* 469 — the authored wrap width */
  margin: 0;
  font-family: var(--font-display);                 /* HostGrotesk-Medium */
  font-weight: 500;
  font-size: 2rem;                                  /* 32 */
  line-height: 2.5rem;                              /* 40 */
  letter-spacing: -0.08rem;                         /* -1.28 */
  color: rgba(17, 17, 17, 0.92);
}

/* ---- Frame 1707481568 "Request eSurvey" @767,43 153x33 -----------------
   padding [6,12,6,12] + a 129-wide Geist-SemiBold 16 label = 153x33 exactly.
   The stroke is `#111111 op0.08 weight 2 align=INSIDE`, so it is an inset
   shadow, not a border — a real border would move nothing here (no absolute
   children) but the inset form keeps the box at Figma's 153 without
   box-sizing games.

   `inline-block`, deliberately not `inline-flex`: the word splitter turns a
   direct text child into one span per word, and inside a flex box every one of
   those becomes a flex item while the whitespace between them does not — the
   label would render with its spaces gone.  6 + 20.8 + 6 = 32.8 -> Figma's 33,
   so padding alone centres it and no flex is needed. */
.qd-esurvey,
.qd-savebtn {
  display: inline-block;
  padding: 0.375rem 0.75rem;                        /* 6 / 12 */
  border-radius: 0.75rem;
  font-family: var(--font-ui);                      /* Geist-SemiBold */
  font-weight: 600;
  font-size: 1rem;                                  /* 16 */
  line-height: 1.3rem;                              /* 20.8 */
  letter-spacing: -0.01rem;                         /* -0.16 */
  color: var(--ink);
  white-space: nowrap;
}
.qd-esurvey {
  left: 47.9375rem;                                 /* 767 */
  top: 2.6875rem;                                   /* 43 */
  background: var(--white);
  box-shadow: inset 0 0 0 0.125rem rgba(17, 17, 17, 0.08);
}
/* Frame 1707481569 — no fill and no stroke in Figma, only the radius and the
   padding, i.e. a text button. */
.qd-savebtn {
  left: 50.6875rem;                                 /* 811 */
  top: 5.25rem;                                     /* 84 */
  background: none;
}

/* ==========================================================================
   Frame 116 — the product card @40,152 469x324
   ========================================================================== */
.qd-card {
  left: 2.5rem;
  top: 9.5rem;
  width: 29.3125rem;
  height: 20.25rem;
  background: var(--white);
  border-radius: 0.75rem;
  overflow: hidden;                                 /* clipsContent */
  /* DROP_SHADOW #e2fa5a a0.4 radius 40 offset 0,8 */
  box-shadow: 0 0.5rem 2.5rem rgba(226, 250, 90, 0.4);
}
/* The 2px INSIDE gradient stroke.  handles [[0.5,1],[0.5,0],[1,1]] = bottom ->
   top, stops #111111 @0 / #e2fa5a @0.699061 — the same paint as Rectangle 23
   on the page behind, at full alpha here.  Painted by a masked ::after rather
   than a border: a real border resolves absolutely-positioned children against
   the PADDING box and would shift the whole product group 2px in, which
   Figma's INSIDE stroke does not do. */
.qd-card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 0.125rem;                                /* weight 2 */
  pointer-events: none;
  background: linear-gradient(to top, #111111 0%, #e2fa5a 69.9061%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
}

/* ---- the slides --------------------------------------------------------
   Figma draws three progress segments under this card but only one Group 26,
   and its first segment is 43 of 70.67 — a fill caught mid-slide.  So the card
   is an auto-advancing slider (the homepage's ExclusiveVideo loop, same 4500 /
   40 ms), and slides 2 and 3 are the same four Figma images regrouped along
   the package's own bullets: panels, then battery.  Every image keeps its
   exact Figma size; only the group's origin moves, so the deviation is these
   two translates and nothing else.

     slide 2  panels + LONGi, union 217.66x263 -> centred in 469x324
              left (469-217.66)/2 = 125.67, top (324-263)/2 = 30.5
              group sits at 12,37  ->  +113.67, -6.5
     slide 3  Sigenergy logo + battery, union 158.71x208.59 at group +191.58,
              +54.41 -> centred: left 155.145, top 57.705
              currently at 203.58, 91.41  ->  -48.435, -33.705            */
.qd-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.qd-slide.is-on { opacity: 1; }
.qd-slide-1 .qd-art { translate: 7.104375rem -0.40625rem; }
.qd-slide-2 .qd-art { translate: -3.0271875rem -2.1065625rem; }

/* ---- Group 26, the product art @12,37 ----------------------------------
   The group's own box is only the union of its children, so it is a zero-size
   anchor at Figma's 12,37 and each image keeps its group-relative offset.
   All four rasters already ship — verified against
   design-reference/wizard/images/ by imageRef, not by filename:
     88c2977303cd -> results-panel.png            a0907dbb0218 -> results-longi.png
     eae21463dbfb -> results-sigenergy-logo.webp  c0e0102d4d58 -> results-sigenergy-battery.png */
.qd-art { position: absolute; left: 0.75rem; top: 2.3125rem; }
.qd-art img { position: absolute; max-width: none; object-fit: contain; }
.qd-im-panels  { left: 0;             top: 2.83375rem;   width: 13.6034375rem; height: 13.6034375rem; } /* @0,45.34    217.66^2 */
.qd-im-longi   { left: 4.888750rem;   top: 0;            width: 3.8023500rem;  height: 1.42588125rem; } /* @78.22,0    60.84x22.81 */
.qd-im-siglogo { left: 13.745rem;     top: 3.400625rem;  width: 6.4324375rem;  height: 2.55663125rem; } /* @219.92,54.41 102.92x40.91 */
.qd-im-batt    { left: 11.97375rem;   top: 6.518125rem;  width: 9.9191875rem;  height: 9.9191875rem; }  /* @191.58,104.29 158.71^2 */

/* ---- Frame 1707481547, the 3 segments @165,488 220x6 -------------------
   Three FILL children on a 4 gap: 3x70.67 + 2x4 = 220.  Figma's Rectangle 14
   is a 43x6 r9 fill at #111111 @.24 inside the FIRST one — i.e. this is the
   slider's progress bar caught 61% through slide 1, not three static dots.
   The fill's width is the one thing JS writes here. */
.qd-dots {
  left: 10.3125rem;
  top: 30.5rem;
  width: 13.75rem;
  height: 0.375rem;
  display: flex;
  gap: 0.25rem;
}
.qd-dot {
  flex: 1 1 0;
  height: 0.375rem;
  border-radius: 0.625rem;                          /* 10 */
  background: rgba(17, 17, 17, 0.08);
  overflow: hidden;                                 /* clipsContent */
}
.qd-dot i {
  display: block;
  height: 0.375rem;
  border-radius: 0.5625rem;                         /* 9 */
  background: rgba(17, 17, 17, 0.24);
}

/* ==========================================================================
   Group 28 — the right column @589,184 331x260
   ========================================================================== */
.qd-copy { left: 36.8125rem; top: 11.5rem; width: 20.6875rem; height: 16.25rem; }

/* TEXT 7064:1894 @ group +2,0 329x120.  Instrument Sans MEDIUM here, unlike
   every other body run on this screen, which is Regular. */
.qd-copy-p {
  position: absolute;
  left: 0.125rem;
  top: 0;
  width: 20.5625rem;                                /* 329 */
  margin: 0;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 1rem;
  line-height: 1.5rem;                              /* 24 */
  letter-spacing: -0.01rem;
  color: var(--ink-70);
}

/* Frame 1707481540 @ group +0,144 — VERTICAL autolayout, gap 12, rows 20 tall,
   so the pitch is Figma's own 32 (rows at 0 / 32 / 64 / 96).  The 20x20 check
   is `results-check.svg`, already shipped and already #00AB55. */
.qd-bullets {
  position: absolute;
  left: 0;
  top: 9rem;                                        /* 144 */
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;                                     /* 12 */
}
.qd-bullets li {
  display: flex;
  align-items: center;
  gap: 0.25rem;                                     /* 4 — 20 + 4 = the text's own x24 */
  height: 1.25rem;
}
.qd-bullets img { flex: none; width: 1.25rem; height: 1.25rem; }
.qd-bul-t {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.22rem;                             /* 19.52 */
  letter-spacing: -0.01rem;
  color: var(--ink);                                /* full #111111, not .7 */
  white-space: nowrap;
}

/* ==========================================================================
   Frame 1707481571 — the tab rail @40,494 296x236, scroll: STICKY_SCROLLS
   ==========================================================================
   ONE DELIBERATE DEVIATION (user, 2026-08-07: "dont make it fixed. ye sticky
   kro scroll hone pe scroll hoga but top pe ja k rk jayega. top se 40px ka
   margin rkhna").  Read literally, Figma's sticky holds the rail where it
   already is — it starts at 494 and would therefore pin at 494 from the first
   pixel of scroll, i.e. it would never appear to move at all.  So `top` is 40,
   not 494: the rail travels with the content and parks 40 below the sheet's
   own top edge.

   The sticky element is the TAB LIST, not Figma's 296x236 wrapper.  That
   wrapper carries 60 of empty space above the list, and pinning it would park
   the tabs at 40 + 60 = 100 instead of the 40 that was asked for.  The list
   keeps its exact Figma resting position all the same: 494 + 60 = 554.

   This is the one in-flow child of .qd-body — hence the margin, and hence the
   flow-root above. */
.qd-rail {
  position: sticky;
  top: 2.5rem;                                      /* 40 — see above */
  margin: 34.625rem 0 0 2.5rem;                     /* resting position = 40,554 */
  width: 18.5rem;                                   /* 296 */
  height: 10.75rem;                                 /* 172 */
  z-index: 2;
}
.qd-tabs {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;                                      /* 8 — 52 + 8 = Figma's 60 pitch */
}
/* radii [12,0,0,12]: the tabs butt into the grey panel, whose left edge is at
   336 = 40 + 296.  The label is wrapped in .qd-tab-t rather than sitting bare:
   this box is a flex container, and the word splitter would make one flex item
   per word while the whitespace between them would not become an item at all —
   the label would lose its spaces.  Same reason as .qr-inc-t on the page. */
.qd-tab {
  display: flex;
  align-items: center;
  box-sizing: border-box;
  width: 18.5rem;
  height: 3.25rem;                                  /* 52 */
  padding: 0 1.25rem;                               /* the 20 inset; 16/16 vertical is a centre */
  border-radius: 0.75rem 0 0 0.75rem;
  font-family: var(--font-sans);                    /* InstrumentSans-SemiBold */
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.22rem;                             /* 19.52 */
  letter-spacing: -0.01rem;
  text-align: left;
  appearance: none;                                 /* they are <button role="tab"> */
}
.qd-tab-on  { background: #f1f1f1; color: var(--ink); }
.qd-tab-off { background: rgba(236, 236, 236, 0.2); color: var(--ink-70); }

/* ==========================================================================
   Frame 1707481567 — the details panel @336,534 584x864
   ========================================================================== */
.qd-panel {
  left: 21rem;
  top: 33.375rem;
  width: 36.5rem;                                   /* 584 — the same on all three */
  background: #f1f1f1;
  border-radius: 0.75rem;
  overflow: hidden;                                 /* clipsContent */
}
.qd-panel-0 { height: 54rem; }                      /* D11 864 */
.qd-panel-1 { height: 52.75rem; }                   /* D12 844 */
.qd-panel-2 { height: 49.3125rem; }                 /* D13 789 */
.qd-panel > * { position: absolute; margin: 0; }

.qd-h2 {
  font-family: var(--font-display);                 /* HostGrotesk-Medium */
  font-weight: 500;
  font-size: 1.5rem;                                /* 24 */
  line-height: 1.995rem;                            /* 31.92 */
  letter-spacing: -0.08rem;                         /* -1.28 */
  color: rgba(17, 17, 17, 0.92);
}
.qd-p {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.5rem;                              /* 24 */
  letter-spacing: -0.01rem;
  color: var(--ink-70);
  white-space: pre-line;                            /* the TEXT node's own \n\n */
}
.qd-dim-h { left: 2rem; top: 2rem;     width: 7.1875rem; }        /* @32,32  115x32 */
.qd-dim   { left: 2rem; top: 4.75rem;  width: 32.5rem; }          /* @32,76  520x24 */
/* Group 32 @32,132 520x700 — a bare anchor, so its four children keep their
   own panel-relative y: 132 / 176 / 392 / 736. */
.qd-eco-h { left: 2rem; top: 8.25rem;  width: 15rem; }            /* +0,0   240x32 */
.qd-eco-p { left: 2rem; top: 11rem;    width: 32.5rem; }          /* +0,44  520x192 */
.qd-fine  { left: 2rem; top: 46rem;    width: 32.5rem; }          /* +0,604 520x96  */

/* Frame 1707481551 @ +0,260 520x320 — a white r12 card holding `image 150` at
   -166,-80 852x480.  (520-852)/2 = -166 and (320-480)/2 = -80, i.e. the image
   is centred and cropped; 852/480 = 1.775 = 529/298, the source's own aspect,
   so `cover` crops nothing beyond that.  Figma puts no play control over it —
   the YouTube chrome is baked into the bitmap — and wires no interaction, so
   it is an image, not a link. */
.qd-video {
  left: 2rem;
  top: 24.5rem;                                     /* 392 */
  width: 32.5rem;                                   /* 520 */
  height: 20rem;                                    /* 320 */
  background: var(--white);
  border-radius: 0.75rem;
  overflow: hidden;                                 /* clipsContent */
}
.qd-video img {
  position: absolute;
  left: -10.375rem;                                 /* -166 */
  top: -5rem;                                       /* -80 */
  width: 53.25rem;                                  /* 852 */
  height: 30rem;                                    /* 480 */
  max-width: none;
  object-fit: cover;
}

/* ==========================================================================
   TAB 2 — "What's included?", Frame 1707481567 7064:2135 (D12), 584x844
   ==========================================================================
   Eight 520x80 rows at @32, y 32 + 100k.  Each is a HORIZONTAL autolayout,
   gap 12, counter=CENTER: an 80x80 image, then a two-line block on its own
   6 gap (19.52 + 6 + 19.52 = 45.04 in an 80 box -> Figma's y17). */
.qd-inc {
  left: 2rem;
  top: 2rem;
  width: 32.5rem;                                   /* 520 */
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;                                     /* the 100 pitch less the 80 row */
}
.qd-inc li {
  display: flex;
  align-items: center;
  gap: 0.75rem;                                     /* 12 -> the text's own x92 */
  height: 5rem;
}
.qd-inc-img {
  flex: none;
  position: relative;
  width: 5rem;
  height: 5rem;
  overflow: hidden;
}
.qd-inc-img img { width: 100%; height: 100%; object-fit: cover; }
/* Only two of the four carry `radius=12` in Figma. */
.qd-inc-mcs,
.qd-inc-dno { border-radius: 0.75rem; }
/* RECC is 640x226 in an 80 box and its imageTransform letterboxes it to
   80x28.25 centred — which is exactly what `contain` does. */
.qd-inc-recc img { object-fit: contain; }
/* DNO's transform scales by 1.4225646, i.e. the 24x24 source is drawn at
   1/1.4225646 = 70.29% of the box and centred, not filling it. */
.qd-inc-dno img {
  position: absolute;
  left: 14.855%;
  top: 14.855%;
  width: 70.29%;
  height: 70.29%;
  object-fit: contain;
}
.qd-inc-txt {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;                                    /* 6 */
  min-width: 0;
}
.qd-inc-h,
.qd-inc-s {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.22rem;                             /* 19.52 */
  letter-spacing: -0.01rem;
}
.qd-inc-h { color: var(--ink); }
.qd-inc-s { color: var(--ink-70); }

/* ==========================================================================
   TAB 3 — "Reviews", Frame 1707481567 7064:2277 (D13), 584x789
   ========================================================================== */

/* Frame 72 @32,32 520x237 — the one #00b779 green box in the whole overlay */
.qd-rev-head {
  left: 2rem;
  top: 2rem;
  width: 32.5rem;
  height: 14.8125rem;                               /* 237 */
  background: #00b779;
  border-radius: 0.5rem;                            /* 8 */
  overflow: hidden;                                 /* clipsContent */
}
.qd-rev-head > * { position: absolute; margin: 0; }
.qd-rev-h { left: 1.5rem; top: 1.25rem; }           /* @24,20 184x32 */

/* `image 111` 146x28, imageTransform [[1,0,0],[0,0.41338712,0.58267742]] — the
   box shows the source's vertical band from 58.268% to 99.607%, i.e. the same
   crop-by-transform the homepage's .tp-stars uses.  1 / 0.41338712 = 241.94%
   of the box height, offset -0.58267742 x that = -140.94%. */
.qd-rev-stars,
.qd-rev-cstars {
  display: block;
  width: 9.125rem;                                  /* 146 */
  height: 1.75rem;                                  /* 28 */
  overflow: hidden;
}
.qd-rev-stars img,
.qd-rev-cstars img {
  position: absolute;
  left: 0;
  top: -140.94%;
  width: 100%;
  height: 241.94%;
  max-width: none;
  object-fit: cover;
}
.qd-rev-stars { left: 1.5rem; top: 3.75rem; }       /* @24,60 */

/* Group 33 @24,101 453x116 — five 20-tall rows on a 24 pitch */
.qd-rev-bars {
  left: 1.5rem;
  top: 6.3125rem;                                   /* 101 */
  width: 28.3125rem;                                /* 453 */
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;                                     /* 24 pitch less the 20 row */
}
.qd-rev-bars li { display: flex; align-items: center; height: 1.25rem; }
.qd-rev-n,
.qd-rev-pc {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.22rem;
  letter-spacing: -0.01rem;
  color: var(--ink);
}
.qd-rev-n { width: 1.125rem; }                      /* the track's own x18 */
.qd-rev-pc { flex: 1; text-align: right; }          /* 18 + 387 = 405, so 48 left */
.qd-rev-track {
  width: 24.1875rem;                                /* 387 */
  height: 0.375rem;
  border-radius: 0.625rem;
  background: rgba(255, 255, 255, 0.4);
  overflow: hidden;                                 /* clipsContent */
}
.qd-rev-track i {
  display: block;
  height: 0.375rem;
  border-radius: 0.5625rem;
  background: var(--white);
}

/* "Link - Solid Black" @303,28 174x52 — the layer name lies here exactly as it
   does on the homepage's §10 CTA: the body is LIME and the chip is ink, with a
   lime arrow.  16 + 106 + 9.99 + 32 + 10 = 174. */
.qd-rev-cta {
  left: 18.9375rem;                                 /* 303 */
  top: 1.75rem;                                     /* 28 */
  height: 3.25rem;                                  /* 52 */
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;                                    /* 9.99 */
  padding: 0.625rem 0.625rem 0.625rem 1rem;
  border-radius: 0.75rem;
  background: var(--accent);
}
.qd-rev-cta-t {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.6rem;                              /* 25.6 */
  letter-spacing: -0.01rem;
  color: var(--ink);
}
.qd-rev-cta-chip {
  flex: none;
  width: 2rem;
  height: 2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--ink);
  border-radius: 0.5rem;
}
.qd-rev-cta-chip img { width: 1.75rem; height: 1.75rem; }

/* Frames 82 / 83 @32,281 and @32,525, 520x232 — Figma repeats the same review
   twice, verbatim.  Host Grotesk REGULAR here, not the Medium the headings use. */
.qd-rev-card {
  left: 2rem;
  width: 32.5rem;
  height: 14.5rem;                                  /* 232 */
  background: rgba(17, 17, 17, 0.06);
  border-radius: 0.5rem;
  overflow: hidden;
}
.qd-rev-card-0 { top: 17.5625rem; }                 /* 281 */
.qd-rev-card-1 { top: 32.8125rem; }                 /* 525 */
.qd-rev-card > * { position: absolute; margin: 0; }
.qd-rev-cstars { left: 1.5rem; top: 1.5rem; }       /* @24,24 */
.qd-rev-q {
  left: 1.5rem;
  top: 4.5rem;                                      /* 72 */
  width: 29.5rem;                                   /* 472 */
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.5rem;                                /* 24 */
  line-height: 2rem;                                /* 32 */
  letter-spacing: -0.08rem;
  color: var(--ink);
}
.qd-rev-by {
  left: 1.5rem;
  top: 11rem;                                       /* 176 */
  width: 21.4375rem;                                /* 343 */
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1rem;
  line-height: 2rem;                                /* 32 */
  letter-spacing: -0.08rem;
  color: var(--ink-70);
}

/* ==========================================================================
   D14 "Form answers" — FRAME 7064:1933, the same sheet with a table in it
   ==========================================================================
   Namespace `.qfa-`, inside the shared `.qd` shell so the popup's transition,
   scrim and blur are identical by construction. */
/* structural only above 768: with no box of its own the four children below
   stay absolute against `.qd-scroll`, which is `inset: 0` in a modal that has
   no padding — i.e. exactly the box they resolved against before the wrapper
   existed.  It becomes the flow column at 428. */
.qfa-body { display: contents; }

.qfa-h,
.qfa-sub,
.qfa-rows,
.qfa-wash { position: absolute; margin: 0; }

/* both are align=CENTER and their boxes centre on the sheet's own 480, so they
   are centred blocks rather than boxes at an x */
.qfa-h,
.qfa-sub { left: 0; right: 0; text-align: center; }
.qfa-h {
  top: 2.5rem;                                      /* 40 */
  font-family: var(--font-display);                 /* HostGrotesk-Medium */
  font-weight: 500;
  font-size: 2rem;                                  /* 32 */
  line-height: 2.5rem;                              /* 40 */
  letter-spacing: -0.08rem;
  color: rgba(17, 17, 17, 0.92);
}
.qfa-sub {
  top: 5.5rem;                                      /* 88 */
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.22rem;                             /* 19.52 */
  letter-spacing: -0.01rem;
  color: var(--ink-70);
}

/* Group 30 @0,148 960x488.  Six 60-tall rows (16 + 28 + 16) plus the address
   row, whose value is four lines: 6x60 + (16 + 112) = 488 exactly, so the last
   row carries no bottom padding — hence its own class rather than :last-child,
   which is the nth-child fragility CLAUDE.md warns about. */
.qfa-rows {
  left: 0;
  top: 9.25rem;                                     /* 148 */
  width: 60rem;
}
.qfa-row {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1.5rem;
  padding: 1rem 11.25rem;                           /* 16 / 180 — the label's x and the value's right inset */
}
.qfa-row-last { padding-bottom: 0; }
/* Vectors 8..14 — a 960-long dashed lime rule above every row.  Each is a
   960x0 node rotated 90deg (the same "vertical line laid down horizontally"
   trick the homepage's §5 dividers use), so its GRADIENT_LINEAR runs across
   the rule: #e2fa5a at alpha 0 / 1 / 0 on stops 0 / 0.524038 / 1.
   strokeDashes [8,8] over 960 needs no adjustment — Figma scales dashes to a
   whole number of periods and 960 / 16 is exactly 60, so the period really is
   16 and dash = gap = 8.  The dashes are a mask so the fade can live in the
   paint underneath. */
.qfa-row::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 0.125rem;                                 /* weight 2 */
  background: linear-gradient(
    to right,
    rgba(226, 250, 90, 0) 0%,
    rgba(226, 250, 90, 1) 52.4038%,
    rgba(226, 250, 90, 0) 100%
  );
  -webkit-mask: repeating-linear-gradient(to right, #000 0 0.5rem, transparent 0.5rem 1rem);
          mask: repeating-linear-gradient(to right, #000 0 0.5rem, transparent 0.5rem 1rem);
}
.qfa-k,
.qfa-v {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1.25rem;                               /* 20 */
  line-height: 1.75rem;                             /* 28 */
  letter-spacing: -0.01rem;
}
.qfa-k { color: var(--ink-70); }
.qfa-v {
  color: var(--ink);
  text-align: right;
  white-space: pre-line;                            /* the address node's own \n */
}

/* ---- the lime wash, shared by D14 (Rectangle 31 @0,696 960x234) and D15
   (Rectangle 31 @0,607 960x323).  Both are LEFT/BOTTOM constrained and both
   end flush with the sheet, so only the height differs.

   THE GRAIN IS ON A ::before WITH ITS OWN FADE, and that is the fix for a real
   edge (user, 2026-08-07: "gradient nichley wale ko is trah kro like top se
   background k sath merge ho rha hai").  Figma's NOISE effect covers the whole
   rect at constant strength, so painted as one background layer its top edge
   is a hard line across the sheet even though the lime under it starts at
   alpha 0.  Masking only the grain lets it arrive with the colour and leaves
   Figma's own linear ramp untouched.

   Figma does not export its noise parameters, so the feTurbulence is matched
   against the render rather than by number; the #111111 a0.16 colour is its. */
.qfa-wash,
.qs-wash,
/* the "Request callback" popup, which has no frame of its own in Figma and
   borrows this sheet family's furniture — see `.qcb-wash` in
   quote-details-integration.css, which sets only its height. Listed here so
   the gradient and the grain below have ONE definition. */
.qcb-wash {
  left: 0;
  right: 0;
  bottom: 0;
  background-image: linear-gradient(to bottom, rgba(226, 250, 90, 0) 0%, #e2fa5a 100%);
  pointer-events: none;
}
.qfa-wash::before,
.qs-wash::before,
.qcb-wash::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.0667 0 0 0 0 0.0667 0 0 0 0 0.0667 0 0 0 0.16 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 45%);
          mask-image: linear-gradient(to bottom, transparent 0%, #000 45%);
}
.qfa-wash { height: 14.625rem; }                    /* 234 */

/* ==========================================================================
   D15 "Your solar savings, how?" — FRAME 7064:1966
   ==========================================================================
   Namespace `.qs-`.  Two 390x377 cards at @80,170 and @490,170 whose every
   difference — fill, stroke weight, heading size, heading x, row gap, value
   font — is Figma's, not a tidy-up. */
/* no box of its own above 768, so the four children below stay absolute against
   `.qd-scroll` — see the twin rule on `.qfa-body`.  It becomes the flow column
   at 428, where the two cards stack. */
.qs-body { display: contents; }

.qs-h,
.qs-sub,
.qs-card,
.qs-wash { position: absolute; margin: 0; }

.qs-h,
.qs-sub { left: 0; right: 0; text-align: center; }
.qs-h {
  top: 2.5rem;                                      /* 40 */
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 2rem;                                  /* 32 */
  line-height: 2.5rem;
  letter-spacing: -0.08rem;
  color: rgba(17, 17, 17, 0.92);
}
/* the authored 455 is load-bearing: it is what wraps the sub to two lines */
.qs-sub {
  top: 5.5rem;                                      /* 88 */
  width: 28.4375rem;                                /* 455 */
  margin: 0 auto;
  right: auto;
  left: 15.8125rem;                                 /* 253 */
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.22rem;                             /* 19.52 */
  letter-spacing: -0.01rem;
  color: var(--ink-70);
}

.qs-card {
  top: 10.625rem;                                   /* 170 */
  width: 24.375rem;                                 /* 390 */
  height: 23.5625rem;                               /* 377 */
  border-radius: 0.75rem;
  overflow: hidden;                                 /* clipsContent */
}
.qs-card-before {
  left: 5rem;                                       /* 80 */
  background: rgba(255, 86, 48, 0.04);
  box-shadow: inset 0 0 0 0.0625rem rgba(255, 86, 48, 0.12);   /* weight 1 */
}
.qs-card-after {
  left: 30.625rem;                                  /* 490 */
  background: rgba(0, 171, 85, 0.06);
  box-shadow: inset 0 0 0 0.125rem rgba(0, 171, 85, 0.16);     /* weight 2 */
}

/* Both headings carry the canonical dark->lime paint, handles
   [[0,0.5],[1.37216,0.09434]] with stops #111111 @0.514423 / #e2fa5a @1.  The
   first stop is box-size-independent at ~70.6% but the ANGLE and the end stop
   are not, so each box gets its own — 239x32 and 117x37.
   `background-image` rather than the `background` shorthand, which would reset
   background-clip back to border-box and paint a solid bar over the letters. */
.qs-card-h {
  position: absolute;
  top: 2rem;                                        /* 32 */
  margin: 0;
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: -0.08rem;
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.qs-card-h-before {
  left: 2.75rem;                                    /* 44 — Figma's, and NOT the 32 its rows use */
  font-size: 1.5rem;                                /* 24 */
  line-height: 1.995rem;                            /* 31.92 */
  background-image: linear-gradient(87.73deg, #111111 70.32%, #e2fa5a 136.71%);
}
.qs-card-h-after {
  left: 2rem;                                       /* 32 */
  font-size: 1.75rem;                               /* 28 */
  line-height: 2.3275rem;                           /* 37.24 */
  background-image: linear-gradient(84.66deg, #111111 69.16%, #e2fa5a 134.45%);
}

/* Frame 74 / Frame 77 @32,101 326x244 — three blocks on a 32 gap, each an
   icon row plus a "Why:" line on a 12 gap. */
.qs-rows {
  position: absolute;
  left: 2rem;
  top: 6.3125rem;                                   /* 101 */
  width: 20.375rem;                                 /* 326 */
  display: flex;
  flex-direction: column;
  gap: 2rem;                                        /* 32 */
}
.qs-block { display: flex; flex-direction: column; gap: 0.75rem; }   /* 12 */
.qs-row { display: flex; align-items: center; height: 1.75rem; }
/* the one asymmetry that is easy to miss: 8 on the left card, 12 on the right */
.qs-card-before .qs-row { gap: 0.5rem; }
.qs-card-after .qs-row { gap: 0.75rem; }

.qs-x,
.qs-tick { flex: none; display: block; width: 1.75rem; height: 1.75rem; }
/* Frame 75 — a green r6 chip carrying the 24x24 checkmark at rel(2,2) */
.qs-tick {
  background: var(--qr-green, #00ab55);
  border-radius: 0.375rem;                          /* 6 */
  box-shadow: 0 0.5rem 1rem rgba(32, 32, 32, 0.07); /* #202020 a.07 r16 offset 0,8 */
  padding: 0.125rem;                                /* the instance's rel(2,2) */
  box-sizing: border-box;
}
.qs-x img,
.qs-tick img { width: 100%; height: 100%; }

/* Plus Jakarta Sans is the ONE place this design uses a fourth family, and it
   is only these three values.  Imported at the top of this sheet rather than
   added to base.css's font import — base.css is shared with the frozen
   homepage, where the rule is "add new selectors, never alter an existing
   rule". */
.qs-v-before {
  font-family: "Plus Jakarta Sans", var(--font-sans);
  font-weight: 500;
  font-size: 1.125rem;                              /* 18 */
  line-height: 1.4175rem;                           /* 22.68 */
  letter-spacing: 0;                                /* Figma's own 0, not -0.16 */
  color: var(--ink);
}
/* Frame 69/76/70 @40,0.5 286x27, SPACE_BETWEEN */
.qs-vrow {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.qs-v-after,
.qs-pc {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.25rem;                               /* 20 */
  line-height: 1.6625rem;                           /* 26.6 */
  letter-spacing: -0.08rem;
}
.qs-v-after { color: rgba(17, 17, 17, 0.92); }
.qs-pc { color: #00ab55; }

.qs-why {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.22rem;                             /* 19.52 */
  letter-spacing: -0.01rem;
  color: var(--ink-70);
}
.qs-why b { font-weight: 500; color: var(--ink); }  /* the styleOverrideTable run */

/* Rectangle 31 @0,607 960x323 — the shared wash rule is up with D14's */
.qs-wash { height: 20.1875rem; }                    /* 323 */

/* ==========================================================================
   D16 "What's included?" — FRAME 7064:2025
   ==========================================================================
   Namespace `.qi-`.  This one SCROLLS: the two 713-tall cards start at y304,
   so the content runs to 1017 in a sheet that clips at 930.  `Rectangle 32`
   @158,1017 623x40 is #fefff9 on a #fefff9 ground and paints nothing, but its
   box is the content's bottom extent — hence 1057. */
.qi-body {
  position: relative;
  /* declared, not `auto`: the scroller's scrollbar takes ~15px off its width,
     and the two centred texts here are `left:0; right:0`, so an auto width
     would slide them ~7.5px left of Figma's 480.  The bar then overlays the
     right 15, which is clear of everything — the pill ends at 920. */
  width: 60rem;
  height: 66.0625rem;                               /* 1057 */
}
.qi-body > * { position: absolute; margin: 0; }

.qi-h,
.qi-sub { left: 0; right: 0; text-align: center; }
.qi-h {
  top: 2.5rem;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 2rem;
  line-height: 2.5rem;
  letter-spacing: -0.08rem;
  color: rgba(17, 17, 17, 0.92);
}
.qi-sub {
  top: 5.5rem;                                      /* 88 */
  left: 15.8125rem;                                 /* 253 */
  right: auto;
  width: 28.4375rem;                                /* 455 — the authored wrap width */
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.22rem;
  letter-spacing: -0.01rem;
  color: var(--ink-70);
}

/* Frame 1707481573 @40,168 880x96 — a lime wash at radius 72, i.e. a stadium.
   Its inner frame sits at @44,32 with a 12 gap, and the trailing caption is a
   separate node at @249,38 rather than part of that auto-layout. */
.qi-pill {
  left: 2.5rem;
  top: 10.5rem;                                     /* 168 */
  width: 55rem;                                     /* 880 */
  height: 6rem;                                     /* 96 */
  border-radius: 4.5rem;                            /* 72 */
  background: rgba(226, 250, 90, 0.2);
  overflow: hidden;                                 /* clipsContent */
}
.qi-pill > * { position: absolute; }
.qi-pill-icon {
  left: 2.75rem;                                    /* 44 */
  top: 2.125rem;                                    /* 32 + the icon frame's own rel(0,2) */
  width: 1.75rem;
  height: 1.75rem;
}
.qi-pill-icon img { width: 100%; height: 100%; }
.qi-pill-h {
  left: 5.25rem;                                    /* 44 + 28 + 12 */
  top: 2rem;                                        /* 32 */
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.5rem;                                /* 24 */
  line-height: 1.995rem;                            /* 31.92 */
  letter-spacing: -0.08rem;
  color: var(--ink);
}
.qi-pill-t {
  left: 15.5625rem;                                 /* 249 */
  top: 2.375rem;                                    /* 38 */
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.22rem;
  letter-spacing: -0.01rem;
  color: var(--ink-70);
}

/* The two cards.  Same asymmetry as D15's — and note it is INVERTED here: the
   green card is on the LEFT this time, and it is still the one with the
   weight-2 stroke. */
.qi-card {
  top: 19rem;                                       /* 304 */
  width: 24.375rem;                                 /* 390 */
  height: 44.5625rem;                               /* 713 */
  border-radius: 0.75rem;
  overflow: hidden;
}
.qi-card-in {
  left: 5rem;                                       /* 80 */
  background: rgba(0, 171, 85, 0.06);
  box-shadow: inset 0 0 0 0.125rem rgba(0, 171, 85, 0.16);     /* weight 2 */
}
.qi-card-out {
  left: 30.625rem;                                  /* 490 */
  background: rgba(255, 86, 48, 0.04);
  box-shadow: inset 0 0 0 0.0625rem rgba(255, 86, 48, 0.12);   /* weight 1 */
}

/* Frame 1707481578 / 1707481576 @32,32 326 wide — groups on a 32 gap, each a
   heading plus a list on its own 32 gap. */
.qi-groups {
  position: absolute;
  left: 2rem;
  top: 2rem;
  width: 20.375rem;                                 /* 326 */
  display: flex;
  flex-direction: column;
  gap: 2rem;
}
.qi-group { display: flex; flex-direction: column; gap: 2rem; }
.qi-group-h {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.75rem;                               /* 28 */
  line-height: 2.3275rem;                           /* 37.24 */
  letter-spacing: -0.08rem;
  /* the canonical dark->lime paint over a 326-wide box:
     handle (1.37216w, -0.40566h) with h = 37.24 gives 88.03deg, and the
     0.514423 stop lands at 70.5% with the end at 137.03% */
  background-image: linear-gradient(88.03deg, #111111 70.5%, #e2fa5a 137.03%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
/* Frame 77 — rows on a 32 gap.  `counter=CENTER`, and the row's height is
   whatever the 282-wide text needs (28 / 40 / 60 / 80 in Figma), so nothing
   here is a hardcoded row height. */
.qi-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 2rem;
}
.qi-list li {
  display: flex;
  align-items: center;
  gap: 1rem;                                        /* 16 -> the text's own x44 */
  min-height: 1.75rem;
}
.qi-t {
  font-family: var(--font-sans);
  font-weight: 500;                                 /* InstrumentSans-Medium */
  font-size: 1rem;
  line-height: 1.22rem;                             /* 19.52 */
  letter-spacing: -0.01rem;
  color: var(--ink);                                /* full #111, not .7 */
}

/* ==========================================================================
   Frame 113 — the price bar @520,888 880x122
   ==========================================================================
   A SIBLING of the sheet, not a child, which is what lets its green
   DROP_SHADOW spill past the sheet's clip.  Bottom-anchored the same way:
   888 + 122 = 1010.

   The bar is in the DOM TWICE — once as QuoteSheet's `bar` prop (this one) and
   once inside `.qd-rail`, because M11 moves it into the tab rail's own sticky
   block and CSS cannot reparent.  Exactly one is ever displayed; the 428 half
   is switched on in the mobile block at the end of this file. */
.qd-bar-m { display: none; }
.qd-bar {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0;
  width: 55rem;                                     /* 880 */
  height: 7.625rem;                                 /* 122 */
  background: #057442;
  border-radius: 2.5rem 2.5rem 0 0;
  overflow: hidden;                                 /* clipsContent */
  /* DROP_SHADOW #00ab55 a0.32 radius 40 offset 0,0 */
  box-shadow: 0 0 2.5rem rgba(0, 171, 85, 0.32);
}

/* Frame 1707481566 @20,20 500x82 r100 */
.qd-pill {
  position: absolute;
  left: 1.25rem;
  top: 1.25rem;
  width: 31.25rem;
  height: 5.125rem;
  border-radius: 6.25rem;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;                                 /* clipsContent */
}
.qd-pill > * { position: absolute; margin: 0; }
.qd-cap {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.22rem;                             /* 19.52 */
  letter-spacing: -0.01rem;
  color: rgba(255, 255, 255, 0.7);
  white-space: nowrap;
}
.qd-val {
  font-family: var(--font-display);                 /* HostGrotesk-Medium */
  font-weight: 500;
  font-size: 1.5rem;                                /* 24 */
  line-height: 2rem;                                /* 32 */
  letter-spacing: -0.08rem;                         /* -1.28 */
  color: var(--white);
  white-space: nowrap;
}
.qd-cap-1 { left: 4.5625rem;  top: 0.75rem; }       /* @73,12  104x20 */
.qd-val-1 { left: 4.9375rem;  top: 2.375rem; }      /* @79,38   92x32 */
.qd-cap-2 { left: 19.75rem;   top: 0.75rem; }       /* @316,12 119x20 */
/* Frame 1707481537 @334,38 83x32 — "£673" 59 wide, gap 4, then a 20x20 chevron
   frame under a 90deg rotation (59 + 4 = 63, its own x).  The amount lives in
   its own .qd-money span in both values, so the word splitter never puts this
   4px gap between the digits — the flex-item trap again. */
.qd-val-2 {
  left: 20.875rem;
  top: 2.375rem;
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
.qd-val-2 img { width: 1.25rem; height: 1.25rem; transform: rotate(90deg); }
/* Vector 16 @250,0 0x82, stroke #ffffff @.08 weight 2 align=CENTER -> 249..251 */
.qd-pill-rule {
  left: 15.5625rem;
  top: 0;
  width: 0.125rem;
  height: 5.125rem;
  background: rgba(255, 255, 255, 0.08);
}

/* "Link - Solid Black" @560,31 280x60 — base.css's .btn recipe verbatim
   (padding 10/10/10/16, gap 9.99, r12, an r8 lime chip), so only the four
   things Figma changes are re-declared: the #f5f6f0 fill, the fixed 280x60,
   the 20px label, and the 40x40 / 28px chip.  560 + 280 = 840 = 880 - 40, and
   31 + 60 + 31 = 122, i.e. it is inset 40/31 on its own. */
.qd-next {
  position: absolute;
  left: 35rem;
  top: 1.9375rem;
  width: 17.5rem;
  height: 3.75rem;
  background: #f5f6f0;
  font-size: 1.25rem;                               /* 20 */
  line-height: 1.6rem;                              /* 25.6 */
}
/* the label is a FILL child in Figma, 204.01 = 280 - 16 - 9.99 - 40 - 10 */
.qd-next-t { flex: 1; text-align: center; }
.qd-next .chip { width: 2.5rem; height: 2.5rem; }
.qd-next .chip img { width: 1.75rem; height: 1.75rem; }

/* ==========================================================================
   INTERACTION LAYER
   ==========================================================================
   Figma authors NO hover anywhere on D11 — hover-states.json has no pair for
   this screen and interactions.json lists only the four scrim rects, the two
   inactive tabs and the "Next, customize" CTA.  So every rule below is
   authored, per the standing instruction "agle pages pe b aese hi hover
   animation loading animation rkhna", and it holds the four invariants: the
   resting render is untouched, no hover changes the box model, nothing that
   cannot be clicked gets a button hover (the two nav arrows and the video card
   get nothing at all), and there is a reduced-motion block at the end.
   ========================================================================== */

/* The CTA — base.css already gives it the lift, the shadow, the 1000ms sheen,
   the chip ring and the leading arrow.  Only the colours differ: #f5f6f0 is
   already light, so it brightens to white rather than darkening, and the
   shadow is green because an ink one is invisible on #057442. */
/* This one needed nothing for the sweep (user, 2026-08-10): it is
   `class="btn qd-next"`, so base.css's `.btn::before` band, its 80ms delay and
   the shared `@keyframes btn-sheen` already cross it — only the colours are
   re-declared here.  It is also why `.qd-next` is the reference the three
   hand-written copies (`.psh-btn`, `.qb-submit`, `.qc-add` / `.qc-continue`)
   are matched against. */
.qd-next:hover {
  background: var(--white);
  box-shadow:
    0 0.875rem 1.875rem -0.875rem rgba(0, 40, 20, 0.6),
    inset 0 0 0 0.0625rem rgba(17, 17, 17, 0.08);
}
.qd-next:active {
  box-shadow:
    0 0.1875rem 0.5rem -0.3125rem rgba(0, 40, 20, 0.6),
    inset 0 0 0 0.0625rem rgba(17, 17, 17, 0.08);
}
.qd-next:focus-visible { outline-color: var(--accent); }

/* The two head buttons.  Figma gives neither a destination, but both are
   controls in the design (one is stroked, one is a text button), so they get
   the restrained half of the vocabulary — ground and depth, no lift. */
.qd-esurvey,
.qd-savebtn {
  transition:
    background var(--dur-hover) var(--ease-premium),
    box-shadow var(--dur-hover) var(--ease-premium);
}
.qd-esurvey:hover {
  box-shadow:
    inset 0 0 0 0.125rem rgba(17, 17, 17, 0.16),
    0 0.375rem 1rem -0.5rem rgba(17, 17, 17, 0.28);
}
.qd-savebtn:hover { background: var(--ink-08); }
.qd-esurvey:focus-visible,
.qd-savebtn:focus-visible { outline: 0.125rem solid var(--ink); outline-offset: 0.1875rem; }

/* The two inactive tabs are real links (Figma wires them to D12 / D13), so
   they lean toward the selected look Figma already defines — #ececec @.2 is
   "off", #f1f1f1 is "on", and hover sits between the two. */
.qd-tab {
  transition:
    background var(--dur-hover) var(--ease-premium),
    color var(--dur-hover) var(--ease-premium);
}
.qd-tab-off:hover { background: rgba(236, 236, 236, 0.6); color: var(--ink); }
.qd-tab:focus-visible { outline: 0.125rem solid var(--ink); outline-offset: -0.125rem; }

/* The scrim is the close control.  Nothing visual on hover — dimming the page
   further would read as a state change rather than as "click to dismiss" — but
   it does take a cursor and a focus ring. */
.qd-scrim { cursor: pointer; }
.qd-scrim:focus-visible { outline: 0.125rem solid var(--accent); outline-offset: -0.375rem; }

@media (prefers-reduced-motion: reduce) {
  .qd-esurvey,
  .qd-savebtn,
  .qd-tab { transition-duration: 1ms; }
  /* the popup still fades — losing the state change entirely would be worse
     than the movement — but it does not travel */
  .qd { --qd-dur: 160ms; }
  .qd.is-open { --qd-dur: 160ms; }
  .qd-sheet { translate: none; will-change: auto; }
}

/* ==========================================================================
   428 — the mobile overlay.  FRAME "View details" 7064:3799, 428x926
   ==========================================================================
   Spec: design-reference/wizard/spec/mobile/M11-view-details.md.  Everything
   below sits in ONE max-width block at the end of the file, so the closed 1920
   render is untouched BY CONSTRUCTION; the only markup change is the second
   `.qd-bar-m` copy of the price bar, which is `display: none` above 768.

   NO ROOT SCALE HERE.  base.css already makes the sub-768 root
   `calc(100vw / 26.75)`, i.e. 1rem == 1 Figma mobile px at 428, so every
   number below is Figma's own.  Do NOT copy /quote's height-bound
   `html:has(.qz)` trick: that is right for a 1010-tall screen and this route's
   host page is a 5424-tall scroller.  The SHEET is height-bound instead, and it
   already was — only the cap changes (930 -> 846).

   ---- WHAT THE 428 FRAME CHANGES, beyond scale ---------------------------
   1. The scrim is ONE rect here in Figma too (`Rectangle 24` 428x926), so the
      "four rects are a prototyping device" note above is confirmed by the
      mobile frame rather than only inferred from the desktop one.
   2. `Frame 1707481571` is no longer just the tab rail — it is a 388x270
      #fefff9 block holding the green price card AND the tabs, in flow at
      modal-rel y538 and marked scroll: STICKY_SCROLLS.  It is also painted
      LAST, after the grey panel, which is what says the panel scrolls BEHIND
      it.  Hence `position: sticky; top: 0`: that is the one offset which
      reproduces Figma's resting y538 exactly (the block starts below the
      scrollport's top edge, so it rests in flow) and still pins.  `bottom: 0`
      was tried and is wrong — the block would pin immediately at 576 and the
      resting render would move 38px.
   3. The tabs go HORIZONTAL, radius 8 not [12,0,0,12], and their fills change:
      `#111 @.12` on / `#111 @.04` off, where the 1920 frame uses #f1f1f1 and
      #ececec @.2.
   4. `Frame 1707481569` "Save quote" gains a white fill AND the same
      `#111 @.08` weight-2 INSIDE stroke as "Request eSurvey" — on 1920 it is a
      bare text button.  Both become 174-wide halves of a 356 row (174+8+174),
      so they are centred rather than padding-sized.
   5. The green card holds the CTA (`Link - Solid Black` @12,82 324x60) and has
      NO `Frame 1707481566` pill behind the two readouts — the figures sit
      straight on the #057442.  Both readouts are still centred in their own
      half of the 348: (174-104)/2 = 35, (174-92)/2 = 41, and 174 + (174-119)/2
      = 201, 174 + (174-83)/2 = 219.
   6. Four things in the 1920 frame have NO node here and are switched off:
      `Frame 1707481572` the marble, the two 60x60 nav arrows, and
      `Frame 1707481540` the four spec bullets.  The title also drops 32/40 to
      24/32 and moves BELOW the card, and the blurb is the whole right column.
   ========================================================================== */
@media (max-width: 767.98px) {
  /* Figma's own 846 = 926 - 80, so `100vh - 5rem` IS 846 at the design
     viewport and the cap only binds on a shorter one. */
  .qd { --qd-sheet-h: min(52.875rem, calc(100vh - 5rem)); }

  /* Rectangle 25 @174,62 80x6.  Anchored to the SHEET, not the viewport top:
     the modal is bottom-anchored, so on a viewport shorter than 926 a `top`
     would drift away from it.  12 = Figma's 80 - 68, and at 428x926 this lands
     the handle back on y62 exactly. */
  .qd-handle {
    top: auto;
    bottom: calc(var(--qd-sheet-h) + 0.75rem);
    width: 5rem;                                    /* 80 — (428-80)/2 = 174 */
  }

  /* Frame 1707481545 @20,80 388x846, radii [20,20,0,0] */
  .qd-modal {
    width: 24.25rem;                                /* 388 */
    border-radius: 1.25rem 1.25rem 0 0;             /* 20 */
  }

  /* no node in 7064:3799 for either */
  .qd-marble,
  .qd-nav { display: none; }

  /* ---- the scroller's body -----------------------------------------------
     A flex column below 768, which is what lets the grey panel follow the
     sticky block in FLOW instead of being absolutely positioned at y808.  It
     has to: the panel is 976 tall on tab 1 and content-sized on tabs 2/3, so a
     declared `.qd-body-N` height would either clip it or leave dead scroll.
     `order` is required because the panel comes FIRST in the DOM (Figma's own
     paint order) and must come second in flow.  The rail's 538 top margin is
     Figma's y538 and does not collapse in a flex container, and 538 + 270 +
     976 = 1784 — the frame's own content extent — falls out by itself. */
  .qd-body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    width: 24.25rem;                                /* 388, declared so a
                                                       scrollbar cannot move it */
  }
  .qd-body-0,
  .qd-body-1,
  .qd-body-2 { height: auto; }
  .qd-body > .qd-panel { position: relative; }

  /* ---- Frame 1707481589 @16,16 356x33 — the two head pills ---------------
     174 + 8 + 174 = 356, both FILL, both white with the 2px INSIDE stroke, and
     both labels centred: 22.5 + 129 + 22.5 = 44.5 + 85 + 44.5 = 174. */
  .qd-esurvey,
  .qd-savebtn {
    top: 1rem;
    width: 10.875rem;                               /* 174 */
    text-align: center;
  }
  .qd-esurvey { left: 1rem; }                       /* @16,16 */
  .qd-savebtn {
    left: 12.375rem;                                /* 16 + 182 */
    background: var(--white);
    box-shadow: inset 0 0 0 0.125rem rgba(17, 17, 17, 0.08);
  }

  /* ---- Frame 116 @16,61 356x259 -----------------------------------------
     Same white fill, same 2px INSIDE dark->lime gradient stroke, same
     `#e2fa5a a0.4 r40 offset 0,8` glow — only the box moves. */
  .qd-card {
    left: 1rem;
    top: 3.8125rem;                                 /* 61 */
    width: 22.25rem;                                /* 356 */
    height: 16.1875rem;                             /* 259 */
  }

  /* Group 26 @32.3018,20 291.6854x219 — a differently COMPOSED group, not the
     1920 one scaled: 181.24 panels against the desktop 217.66 is 0.833 while
     the card is 0.759, so every child carries its own mobile size. */
  .qd-art { left: 2.0188625rem; top: 1.25rem; }
  .qd-im-panels {
    left: 0;
    top: 2.359925rem;                               /* 37.7588 */
    width: 11.3275875rem;                           /* 181.2414 */
    height: 11.3275875rem;
  }
  .qd-im-longi {
    left: 4.07083125rem;                            /* 65.1333 */
    top: 0;
    width: 3.16621875rem;                           /* 50.6595 */
    height: 1.18733125rem;                          /* 18.9973 */
  }
  .qd-im-siglogo {
    left: 11.4455875rem;                            /* 183.1294 */
    top: 2.83190625rem;                             /* 45.3105 */
    width: 5.3562625rem;                            /* 85.7002 */
    height: 2.12890625rem;                          /* 34.0625 */
  }
  .qd-im-batt {
    left: 9.97064375rem;                            /* 159.5303 */
    top: 5.42779375rem;                             /* 86.8447 */
    width: 8.2597rem;                               /* 132.1552 */
    height: 8.2597rem;
  }
  /* the two authored slides, re-centred on the 356x259 card:
       slide 2  panels+LONGi, union 181.2414x219.0002 -> left (356-181.2414)/2
                = 87.3793, top 19.9999; group at 32.3018,20 -> +55.0775, 0
                (the y really is 0 — the union already spans the full 219)
       slide 3  logo+battery, union 132.1552x173.6894 at group +159.5303,
                +45.3105 -> centred 111.9224, 42.6553; currently 191.8321,
                65.3105 -> -79.9097, -22.6552 */
  .qd-slide-1 .qd-art { translate: 3.44234375rem 0; }
  .qd-slide-2 .qd-art { translate: -4.99435625rem -1.41595rem; }

  /* Frame 1707481547 @84,328 220x6 — identical geometry to 1920, (388-220)/2 */
  .qd-dots { left: 5.25rem; top: 20.5rem; }

  /* TEXT 7064:3820 @16,354 356x64 — Host Grotesk Medium 24/32, not 32/40 */
  .qd-title {
    left: 1rem;
    top: 22.125rem;                                 /* 354 */
    width: 22.25rem;                                /* 356 */
    font-size: 1.5rem;                              /* 24 */
    line-height: 2rem;                              /* 32 */
  }

  /* TEXT 7064:3821 @16,426 356x96.  Group 28 collapses to just this run —
     Frame 1707481540, the four spec bullets, has no node on the 428 frame. */
  .qd-copy {
    left: 1rem;
    top: 26.625rem;                                 /* 426 */
    width: 22.25rem;
    height: auto;
  }
  .qd-copy-p { left: 0; width: 22.25rem; }
  .qd-bullets { display: none; }

  /* ---- Frame 1707481571 @0,538 388x270 ----------------------------------
     The price card + the tabs in one #fefff9 block.  `clipsContent` is false
     in Figma, so the card's glow is clipped by the MODAL and nothing else —
     which is what puts it over the tabs' top 4px, exactly as Figma's paint
     order does.  z-index 2 is inherited from the 1920 rule and is what keeps
     it over the grey panel scrolling underneath. */
  .qd-rail {
    top: 0;                                         /* see the note above */
    order: 1;
    margin: 33.625rem 0 0 0;                        /* 538 */
    width: 24.25rem;                                /* 388 */
    height: 16.875rem;                              /* 270 */
    background: var(--bg);                          /* #fefff9 */
  }

  /* Frame 1707481548 @16,206 356x52 — HORIZONTAL, gap 8, hug children on
     92 / 169 / 101.  Figma's own frame is FIXED at 356 while its children sum
     to 378 and it does NOT clip, so the file overflows the modal by 6px and
     the "Reviews" pill is cut.  Made a horizontal scroller instead: the
     resting render is identical (pills at 0 / 100 / 277) and the last 22px can
     be reached — the same invented-scroll call §6 and §7 already carry on
     mobile.  Bar hidden, because a 6px-tall track under a 52px pill reads as
     an artefact. */
  .qd-tabs {
    position: absolute;
    left: 1rem;
    top: 12.875rem;                                 /* 206 */
    width: 22.25rem;                                /* 356 */
    flex-direction: row;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
  }
  .qd-tabs::-webkit-scrollbar { display: none; }
  .qd-tab {
    flex: none;
    width: auto;                                    /* HUG: 52+40 / 129+40 / 61+40 */
    justify-content: center;
    border-radius: 0.5rem;                          /* 8, not [12,0,0,12] */
    white-space: nowrap;
  }
  .qd-tab-on  { background: rgba(17, 17, 17, 0.12); color: var(--ink); }
  .qd-tab-off { background: rgba(17, 17, 17, 0.04); color: var(--ink-70); }
  /* the 1920 hover interpolates #ececec @.2 -> #f1f1f1; here the pair is
     @.04 -> @.12, so the midpoint moves with it */
  .qd-tab-off:hover { background: rgba(17, 17, 17, 0.08); color: var(--ink); }

  /* "Save quote" is a stroked white pill here, not a text button, so it takes
     "Request eSurvey"'s hover rather than the ink-08 ground */
  .qd-savebtn:hover {
    background: var(--white);
    box-shadow:
      inset 0 0 0 0.125rem rgba(17, 17, 17, 0.16),
      0 0.375rem 1rem -0.5rem rgba(17, 17, 17, 0.28);
  }

  /* ---- Frame 113 @16,16 348x154, inside the sticky block ---------------- */
  .qd-sheet > .qd-bar { display: none; }            /* the 1920 copy */
  .qd-bar-m { display: block; }
  .qd-bar-m .qd-bar {
    left: 1rem;                                     /* 16 */
    top: 1rem;
    bottom: auto;
    transform: none;
    width: 21.75rem;                                /* 348 */
    height: 9.625rem;                               /* 154 */
    border-radius: 0.75rem;                         /* 12, not the 40/40/0/0 */
  }
  /* no Frame 1707481566 on this frame — the readouts sit on the green itself */
  .qd-bar-m .qd-pill {
    left: 0;
    top: 0;
    width: 21.75rem;
    height: 5.125rem;                               /* 82 — Vector 16's own run */
    border-radius: 0;
    background: none;
  }
  .qd-bar-m .qd-cap-1 { left: 2.1875rem;  top: 0.75rem; }    /* @35,12 */
  .qd-bar-m .qd-val-1 { left: 2.5625rem;  top: 2.375rem; }   /* @41,38 */
  .qd-bar-m .qd-pill-rule { left: 10.8125rem; height: 5.125rem; }  /* @174,0 0x82 */
  .qd-bar-m .qd-cap-2 { left: 12.5625rem; top: 0.75rem; }    /* @201,12 */
  .qd-bar-m .qd-val-2 { left: 13.6875rem; top: 2.375rem; }   /* @219,38 */
  /* Link - Solid Black @12,82 324x60 — base.css's .btn recipe again, and the
     label is still a FILL child: 16 + 248 + 10 + 40 + 10 = 324 */
  .qd-bar-m .qd-next {
    left: 0.75rem;                                  /* 12 */
    top: 5.125rem;                                  /* 82 */
    width: 20.25rem;                                /* 324 */
  }

  /* ---- Frame 1707481567 @16,808 356x976 — the grey panel ---------------- */
  .qd-panel {
    left: auto;
    top: auto;
    order: 2;
    margin-left: 1rem;                              /* 16 */
    width: 22.25rem;                                /* 356 */
  }
  .qd-panel-0 { height: 61rem; }                    /* 976 */

  /* every inset on this frame is Figma's own 20, not the 1920 frame's 32 */
  .qd-dim-h { left: 1.25rem; top: 1.25rem; }        /* @20,20  115x32 */
  .qd-dim   { left: 1.25rem; top: 4rem;    width: 19.75rem; }   /* @20,64  316x24 */
  /* Group 32 @20,120 316x836 — again a bare anchor, children at +0 / +44 /
     +352 / +692, i.e. panel-rel 120 / 164 / 472 / 812 */
  .qd-eco-h { left: 1.25rem; top: 7.5rem; }         /* 240x32 */
  .qd-eco-p { left: 1.25rem; top: 10.25rem; width: 19.75rem; }  /* 316x288 */
  .qd-video {
    left: 1.25rem;
    top: 29.5rem;                                   /* 472 */
    width: 19.75rem;                                /* 316 */
  }
  /* `image 150` @-268,-80 852x480 — (316-852)/2 and (320-480)/2, so it is the
     same centred crop at the same intrinsic size; only the offset moves. */
  .qd-video img { left: -16.75rem; }
  .qd-fine  { left: 1.25rem; top: 50.75rem; width: 19.75rem; }  /* 316x144 */

  /* ---- tabs 2 and 3 are AUTHORED at 428 --------------------------------
     7064:3799 is the only mobile View details node in the file — Figma draws
     no 428 frame for D12 or D13 — so the two panels below are the 1920 rows
     reflowed into the 356 box.  Every font, colour, radius, stroke and inset
     is Figma's; only the widths and the stacking are ours.  Same documented
     deviation as §7's six extra tabs and D11's own slides 2/3.
     Content-sized, so `.qd-body`'s flex column absorbs whatever they need. */
  .qd-panel-1 { height: auto; padding: 1.25rem; }
  .qd-panel-2 {
    height: auto;
    padding: 1.25rem 1.25rem 2rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;                                   /* Figma's own 12 between
                                                       the head box and the
                                                       two review cards */
  }
  .qd-panel-1 > *,
  .qd-panel-2 > * { position: relative; left: auto; top: auto; }

  /* 316 - 80 - 12 = 224 for the text, so a title wraps and the row grows
     instead of clipping — hence min-height, not height. */
  .qd-inc { width: auto; }
  .qd-inc li { height: auto; min-height: 5rem; }

  .qd-rev-head {
    width: auto;
    height: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 1.25rem 1.5rem 1.5rem;                 /* the 1920 box's own 20/24 */
  }
  .qd-rev-head > * { position: relative; left: auto; top: auto; }
  /* the 1920 deltas kept as margins: 60-20-32 = 8, 101-60-28 = 13, and the CTA
     leaves the heading's row for its own line, which 316 has no room for */
  .qd-rev-stars { margin-top: 0.5rem; }
  /* `align-self: stretch`, NOT `width: auto` — the parent is a flex column with
     `align-items: flex-start`, so an auto width is fit-content and the row
     collapsed to 18 + 0 + 48 with the flexible track measuring ZERO.  Same trap
     waits on any full-width child of these two boxes. */
  .qd-rev-bars { align-self: stretch; width: auto; margin-top: 0.8125rem; }
  .qd-rev-track { flex: 1 1 auto; width: auto; }    /* 18 + track + 48 */
  .qd-rev-pc { flex: none; width: 3rem; }
  .qd-rev-cta { margin-top: 1.5rem; }

  .qd-rev-card {
    width: auto;
    height: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 1.5rem;                                /* the 1920 box's own 24 */
  }
  .qd-rev-card > * { position: relative; left: auto; top: auto; }
  .qd-rev-q  { width: auto; margin-top: 1.25rem; }  /* 72 - 24 - 28 = 20 */
  .qd-rev-by { width: auto; margin-top: 0.5rem; }

  /* ======================================================================
     D16 "What's included?" at 428 — AUTHORED
     ======================================================================
     Figma draws NO 428 frame for this overlay, nor for D14 or D15: the only
     mobile nodes in the whole file are the nine wizard steps, M10, M11, M12,
     M13 and the homepage.  So this box is ours — but it is DERIVED, not
     invented.  The column is inset 16, which is M11's own inset (the one
     mobile overlay Figma does draw), and every gap below is D16's own 1920
     rhythm: 40 to the heading, 8 to the sub, 40 to the pill, 40 to the cards
     and a 40 tail (its invisible `Rectangle 32` is that tail).  Type, colour,
     stroke weights, radii and the two cards' inverted asymmetry are untouched.

     Without it the 960-wide body sat inside the 388 modal: measured 572px of
     horizontal overflow, with the whole "Not included" card off-screen at
     x490.  Every consumer is affected — the chip on /quote/customize's and
     /quote/submit's package cards, and the results page's top bar link.

     ONE KNOWN IMPRECISION, deliberately not chased: `.qi-group-h`'s gradient
     angle is computed for Figma's 326-wide box and the mobile column is 292,
     which moves it ~0.2deg.  The first stop (70.5%) and the end stop (137%)
     are both scale-invariant, so nothing else drifts. */
  .qi-body {
    width: auto;                                      /* undoes the declared 960 */
    height: auto;
    display: flex;
    flex-direction: column;
    padding: 2.5rem 1rem;                             /* 40 / 16 */
  }
  .qi-body > * {
    position: relative;
    left: auto;
    right: auto;
    top: auto;
  }
  /* ---- type: the whole ladder drops ONE step ---------------------------
     User's call (2026-08-10): "text size tum dekh lo jo humne baki screens
     bnai hai".  Every mobile screen in this build steps its display sizes down
     and leaves body copy at 16 — M11 takes its own overlay title from 32/40 to
     24/32, M10 its FAQ heading from 52 to 48/56 — so the three headings here
     move down one notch each and the hierarchy 32 > 28 > 24 is preserved as
     28 > 24 > 20.  NO NEW NUMBERS: 28/37.24 is `.qi-group-h`'s own 1920 pair,
     24/31.92 is `.qi-pill-h`'s, and 20/26.6 is D15's `.qs-v-after`.  All body
     copy (`.qi-sub`, `.qi-pill-t`, `.qi-t`) stays at Figma's 16, as it does on
     every other 428 screen. */
  .qi-h {
    width: auto;
    font-size: 1.75rem;                               /* 28, was 32 */
    line-height: 2.3275rem;                           /* 37.24 */
  }
  .qi-sub { width: auto; margin-top: 0.5rem; }        /* 88 - 40 - 40; still 16/19.52 */
  .qi-group-h {
    font-size: 1.5rem;                                /* 24, was 28 */
    line-height: 1.995rem;                            /* 31.92 */
  }
  .qi-pill-h {
    font-size: 1.25rem;                               /* 20, was 24 */
    line-height: 1.6625rem;                           /* 26.6 */
  }

  /* Frame 1707481573 — still a stadium: `radius 72` clamps to half the box's
     height whatever that height becomes, so the shape survives the extra row.
     The caption is a separate node at x249 on 1920 and cannot sit beside the
     heading in 356, so the pill wraps to two rows.  There is no row wrapper in
     the markup (Figma's `Frame 1707481575` groups the icon and heading, the
     caption is its sibling), so `flex-basis: 100%` on the caption is what
     breaks the line — and the two gaps stay Figma's own 12 across and a
     comfortable 8 down. */
  .qi-pill {
    /* 20, not Figma's own 40 (user, 2026-08-10: "ye margins km kro" — the two
       gaps either side of the pill).  20 is also the gap Figma already puts
       between the two cards, so all three gaps in this sheet are now uniform. */
    margin-top: 1.25rem;
    width: auto;
    height: auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;                              /* 8 down / 12 across */
    padding: 1.5rem 2rem;                             /* 24 / 32 */
  }
  .qi-pill > * { position: relative; left: auto; top: auto; }
  .qi-pill-icon { flex: none; }                       /* keeps its 28x28 */
  .qi-pill-t { flex-basis: 100%; }

  /* Frames 1707481574 / 1707481575 — stacked, and the 20 between them is
     Figma's own horizontal gap (490 - 80 - 390).  `.qi-groups` goes into flow
     so the card can be content-height, and the card's 32 padding is the 32
     inset that group already had. */
  .qi-card {
    width: auto;
    height: auto;
    padding: 2rem;                                    /* 32 */
  }
  .qi-card-in { margin-top: 1.25rem; }                /* 20, was Figma's 40 */
  .qi-card + .qi-card { margin-top: 1.25rem; }        /* 20 — Figma's own */
  .qi-groups { position: static; width: auto; }

  /* ======================================================================
     D14 "Form answers" at 428 — AUTHORED
     ======================================================================
     Figma draws no 428 frame for this one either (user, 2026-08-10: "figma
     main ni hai but tum k sakte h").  Three instructions came with it, and all
     three are below: take the type from the previous screen, hide the lime
     wash, and fit the table to the width.

     THE ROWS STAY A TWO-COLUMN TABLE (user, 2026-08-10: "sabi values ko ek
     dosre k samne le k ao uper niche ni sahi ... like table").  On 1920 each is
     a `space-between` pair with a symmetric 180 inset — only that inset goes,
     so the label still sits left and the value still right-aligns.  Everything
     else is Figma's: the dashed lime rule above each row, the 16 vertical
     padding, the last row's missing bottom padding, and the address's own
     `pre-line` breaks. */
  .qfa-body {
    display: flex;
    flex-direction: column;
    padding: 2.5rem 1rem;                             /* 40 / 16 */
  }
  .qfa-h,
  .qfa-sub,
  .qfa-rows {
    position: relative;
    left: auto;
    right: auto;
    top: auto;
  }
  /* the same 28/37.24 the what's-included heading takes at 428, so the two
     overlays read as one screen size */
  .qfa-h {
    font-size: 1.75rem;                               /* 28, was 32 */
    line-height: 2.3275rem;                           /* 37.24 */
  }
  .qfa-sub { margin-top: 0.5rem; }                    /* Figma's 88 - 40 - 40; still 16/19.52 */
  .qfa-rows { width: auto; margin-top: 1.25rem; }     /* the reduced 20 gap */
  /* Figma's 16 vertical, and the 180 horizontal inset dropped.  Every row fits
     one line at 356 on Figma's own 24 gap; the LABEL is the one allowed to
     shrink and wrap if a longer answer ever arrives, and the value never does —
     that is what keeps the address's four lines intact. */
  .qfa-row { padding: 1rem 0; }
  .qfa-k { min-width: 0; }
  .qfa-v { flex: none; }
  /* restated: the shorthand above would otherwise give the last row back the
     bottom padding Figma deliberately omits */
  .qfa-row-last { padding-bottom: 0; }
  /* one step down from the 1920 table's 20/28, i.e. the 16 every other 428
     screen uses for body copy.  The label is still told apart by colour. */
  .qfa-k,
  .qfa-v {
    font-size: 1rem;                                  /* 16, was 20 */
    line-height: 1.5rem;                              /* 24, was 28 */
  }
  /* Rectangle 31 is KEPT here (user, 2026-08-10: "form answers screen pe yellow
     gradient rkh do" — it was hidden for one pass while the rows were stacked).
     It fits now precisely because the rows went back to a table: the content
     ends at 573 and the wash's own `bottom: 0` + 234 height starts it at 612,
     so it closes the sheet under the table exactly as it does on 1920 rather
     than lying over the last rows.  Its containing block is `.qd-scroll`, not
     `.qfa-body` — that box is a flex container but is not positioned — so
     `left/right/bottom: 0` still means the sheet's own edges.

     AND IT SITS BEHIND THE TABLE (user: "layer content k niche rkhna yani agr
     screen height km ho to content k uper na dikhe piche aye").  It is the last
     child, so paint order alone would put it OVER the rows the moment a shorter
     viewport pushes the content down into its band.  Both sides are already
     positioned here, so a plain z-index pair settles it — note it is 0 vs 1 and
     not a negative value, which keeps it clear of the `z-index: -1`
     paints-behind-the-ancestor's-background trap. */
  .qfa-wash { z-index: 0; }
  .qfa-h,
  .qfa-sub,
  .qfa-rows { z-index: 1; }

  /* ======================================================================
     D15 "Your solar savings, how?" at 428 — AUTHORED
     ======================================================================
     No 428 frame in Figma for this one either.  Two instructions came with it
     (user, 2026-08-10): "green box ko red k uper rkhna" and "yellow gradient
     hta do".  Both are below, and nothing else about the two cards is touched —
     every one of Figma's asymmetries survives: the red card keeps its @.04 fill
     with a WEIGHT-1 @.12 stroke, an 8 row gap and its Plus Jakarta Sans 18
     values; the green keeps @.06 / weight-2 @.16, a 12 gap, Host Grotesk values
     and the green percentage right-aligned in the row. */
  .qs-body {
    display: flex;
    flex-direction: column;
    padding: 2.5rem 1rem;                             /* 40 / 16 */
  }
  .qs-h,
  .qs-sub,
  .qs-card {
    position: relative;
    left: auto;
    right: auto;
    top: auto;
  }
  .qs-h {
    font-size: 1.75rem;                               /* 28 — the same screen
                                                         heading the other two
                                                         overlays take at 428 */
    line-height: 2.3275rem;                           /* 37.24 */
  }
  /* the authored 455 wrap width and the 253 centring both go; it is a plain
     centred block at 356 now */
  .qs-sub {
    width: auto;
    margin: 0.5rem 0 0;                               /* Figma's 88 - 40 - 40 */
  }

  /* GREEN ABOVE RED.  The DOM order is Figma's (before, then after), so the
     green card is re-ordered rather than moved in the markup — and because
     `order` changes only the visual order, BOTH cards carry the same 20 top
     margin and the two gaps come out equal either way round.  `+` would not
     work here: it matches on DOM order, so it would put the gap above the
     green card instead of between them. */
  /* 1 and 2, NOT `order: -1` on the green card — the heading and the sub are
     flex items too and default to order 0, so a negative order hoisted the card
     above BOTH of them (measured: green at y60, heading at y430).  Ordering the
     two cards explicitly leaves the text at 0 and only swaps the pair. */
  .qs-card-after { order: 1; }
  .qs-card-before { order: 2; }
  .qs-card {
    width: auto;
    height: auto;                                     /* was Figma's 377 */
    margin-top: 1.25rem;                              /* 20 */
    padding: 2rem;                                    /* Figma's own 32 inset */
  }
  /* both headings drop one step and KEEP Figma's asymmetry: 24 -> 20 on the red
     card, 28 -> 24 on the green.  Their gradient angles are computed for the
     1920 boxes and move under a degree at these sizes — the first and end stops
     are scale-invariant, so nothing else drifts. */
  .qs-card-h { position: static; }
  .qs-card-h-before {
    font-size: 1.25rem;                               /* 20, was 24 */
    line-height: 1.6625rem;                           /* 26.6 */
  }
  .qs-card-h-after {
    font-size: 1.5rem;                                /* 24, was 28 */
    line-height: 1.995rem;                            /* 31.92 */
  }
  .qs-rows {
    position: static;
    width: auto;
    margin-top: 2rem;                                 /* Figma's 101 - 32 - the
                                                         heading, i.e. ~32 */
  }

  /* Rectangle 31 — hidden (user: "yellow gradient hta do").  Unlike D14's, this
     wash is 323 tall and the two stacked cards run well past the sheet's own
     height, so it would lie over the red card rather than close the sheet. */
  .qs-wash { display: none; }
}
