

.qd-tail > * { position: static; margin: 0; }

.qd-proposal { width: 100%; max-width: 36.5rem; }

/* ==========================================================================
   CONTENT REFLOW — customise add-on rows
   --------------------------------------------------------------------------
   Same problem, same shape: the row's title, blurb, spec list and price sit at
   fixed coordinates inside a fixed-height row, authored around the design's own
   four identical add-ons. A tenant's real add-ons have longer names and real
   descriptions, so the blocks collided.
   The panel becomes a two-column grid — text flows, price keeps its column at
   the design's x and width — and the row grows with it.
   ========================================================================== */
.qc-row { height: auto; min-height: 13.5rem; }

.qc-panel > .qc-h     { margin: 0 0 0.5rem; overflow-wrap: anywhere; }
.qc-panel > .qc-blurb { margin: 0 0 0.75rem; overflow-wrap: anywhere; }
.qc-panel > .qc-specs { margin: 0; }

.qc-specs li { height: auto; align-items: flex-start; }
.qc-specs li img { flex: none; margin-top: 0.15rem; }
.qc-specs li .qc-spec-t { white-space: normal; overflow-wrap: anywhere; }

.qd-body-0 > .qd-panel > .qd-h2 { margin: 2.5rem 0 0; }
.qd-body-0 > .qd-panel > .qd-h2:first-child { margin-top: 0; }
.qd-body-0 > .qd-panel > .qd-p { margin: 0.75rem 0 0; overflow-wrap: anywhere; }

/* ==========================================================================
   DESKTOP GEOMETRY ONLY
   --------------------------------------------------------------------------
   Everything below re-places or re-sizes something on the design's 1920 canvas.
   The design ships no separate mobile stylesheet: its own `@media (max-width:
   767.98px)` blocks live inside quote-*.css and restate these same boxes for the
   428 canvas. Unscoped, these rules outranked those blocks at every width and
   the phone layout inherited desktop coordinates.

   Scoped to >=768 they apply exactly as before on desktop — which is unchanged —
   and below it the design's own mobile rules govern, as they were written to.

   Rules that are not geometry (colour, type, wrapping, hover and disabled
   states, the brand wordmark) stay global above: they are correct at any width.
   ========================================================================== */

@media (min-width: 768px) {
  /* Additive fixes for the package-details sheet, loaded AFTER quote-details.css.
   *
   * The design lays the Details panel out on a fixed canvas — the panel is
   * absolutely placed at a fixed height and every child sits at its own absolute
   * y. An earlier attempt made those children flow so the proposal block could be
   * inserted mid-panel; that cost the video its box and broke the layout, so the
   * panel and everything the design positions inside it are left exactly as
   * authored.
   *
   * Instead the tail of the Details tab — the platform's proposal detail, then the
   * design's video and its fine print — is rendered AFTER the panel, in the
   * sheet's own flow. Nothing can overlap, because nothing here is inside the
   * panel any more.
   */

  /* The scroll body grows with the tail, and clears the sticky price bar so the
     last line of the proposal can actually be scrolled to. */
  .qd-body-0 {
    height: auto;
    /* NOT the design's 97.5rem. That is the height of ITS body, measured with the
       panel at the design's own 864 and the video still inside it. Both are gone —
       the panel sizes to its copy and the video moved to the tail — so the figure
       now only forces the grid taller than its content, and auto rows share the
       surplus out BETWEEN them. That gap is what appeared above the proposal. */
    min-height: 0;
    padding-bottom: 14rem;             /* the price bar is ~120 tall + breathing room */
  }

  /* The tail column sits on the panel's own left edge and width. */
  .qd-tail {
    position: static;
    margin: 1.5rem 0 0 21rem;
    width: 36.5rem;                    /* 584 — the panel's own width */
    max-width: 36.5rem;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
  }

  /* The video keeps the design's own box and its inner crop; only the absolute
     placement is dropped, since it is no longer inside the panel. */
  .qd-tail .qd-video {
    position: relative;
    left: auto;
    top: auto;
    width: 100%;
    height: 20rem;                     /* 320 — the design's own */
  }

  /* The fine print keeps the design's measure. */
  .qd-tail .qd-fine {
    left: auto;
    top: auto;
    width: 100%;
    max-width: 32.5rem;                /* 520 — the authored measure */
  }

  /* ==========================================================================
     CUSTOMISE RAIL — the chosen package card
     --------------------------------------------------------------------------
     The design names the tier in one short word, so it leaves 4.25rem between the
     title's top (272) and the What's-included chip (340) — room for two lines of
     the 28px leading. A real catalogue title ("Trina Vertex S+ 450W Dual Glass
     Full Black N-Type Mono 450W Panels + Alpha ESS SMILE G3 4.8kWh Battery")
     wraps to three, and the third line ran under the chip.

     The title and the chip therefore stack in normal flow and the card grows.
     The artwork stays absolute: like the price box's quote mark, its four images
     are positioned relative to each other by coordinate alone and have no layout
     size of their own, so the padding-top reserves the band they occupy instead.

     With a two-line title this reproduces the design exactly:
     17 + 3.5 + 0.75 + 1.75 + 1.5 = 24.5rem, the authored card height.
     ========================================================================== */
  /* Lifted out of this desktop block — see THE RAIL'S PACKAGE CARD, AT EVERY
     WIDTH at the end of this file. Kept here as a pointer so the derivation
     above stays next to the rule it explains. */

  .qc-panel {
    height: auto;
    min-height: 11rem;
    display: grid;
    grid-template-columns: minmax(0, 57.5rem) 9.25rem;
    align-items: start;
    padding: 1.25rem 1.25rem 1.25rem 1.5rem;
    box-sizing: border-box;
  }

  .qc-panel > .qc-h,
  .qc-panel > .qc-blurb,
  .qc-panel > .qc-specs {
    position: static;
    left: auto;
    top: auto;
    grid-column: 1;
    width: 100%;
    max-width: 100%;
  }

  .qc-panel > .qc-price {
    position: relative;
    left: auto;
    top: auto;
    grid-column: 2;
    grid-row: 1 / span 3;
    height: auto;
    min-height: 9rem;
  }

  

  /* ==========================================================================
     CONTENT REFLOW — details panel copy
     --------------------------------------------------------------------------
     Safe to flow now: the video and its fine print were moved out of this panel
     into `.qd-tail`, so what remains is text only. That was the element whose
     fixed box an earlier reflow attempt destroyed — it is no longer in here.
     ========================================================================== */
  .qd-panel-0 {
    height: auto;
    /* NOT the design's 54rem. That height was measured to hold this panel's copy
       AND the video box at y392. The video now lives in `.qd-tail`, so the same
       min-height reserved ~500px of empty grey below the last paragraph. The
       panel sizes to the copy it actually holds. */
    min-height: 0;
    padding: 2rem;
    box-sizing: border-box;
  }

  .qd-body-0 > .qd-panel > * {
    position: static;
    left: auto;
    top: auto;
    width: 100%;
    max-width: 32.5rem;
  }

  /* ==========================================================================
     THE SHEET'S TITLE
     --------------------------------------------------------------------------
     The design wraps the name in a 469-wide box at y40, and the artwork card
     below starts at y128 — 88px, which is two lines of the authored 32/40. Its
     own name wraps to two. A real catalogue name wraps to three and ran over the
     card.

     The band above the card is empty across the sheet's width, so the title is
     given the room that is actually there rather than being shrunk: at 736 the
     same name wraps to two lines. The two-line clamp stays as the guard for a
     longer one, with the full name on the element's tooltip.
     ========================================================================== */
  .qd-title {
    /* 712, not 736. The band above the card is free of the CARD, but not of the
       two head pills: "Request eSurvey" starts at x767, and a 736 box from x40
       ends at 776 — measured, the title's second line ran 7px into the pill. 712
       ends at 752 and keeps the design's own 15 clear of it. */
    width: 44.5rem;
    max-width: calc(100% - 12.5rem);   /* the pills' own 153 band, plus that gap */
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  /* Same containment fix for the customise row: the panel joins the row's flow so
     the row grows with a long add-on name or description. */
  .qc-row > .qc-panel {
    position: static;
    margin: 1.25rem 1.25rem 1.25rem 13.25rem;
  }

  /* ==========================================================================
     THE DETAILS TAB'S FLOW — no gap between the panel and the tail
     --------------------------------------------------------------------------
     `.qd-rail` is the design's only in-flow child and it carries a 554px top
     margin, which is its resting position on the fixed canvas. Everything after
     it in the flow — the tail — therefore started at 554 + 172 + its own gap,
     regardless of where the panel actually ended. With the panel now sized to its
     copy rather than the design's 864, that left a large blank between them.

     For the Details tab only, the body becomes a two-column grid: the rail keeps
     column one and its sticky behaviour, and the panel and the tail stack in
     column two, so the tail starts where the panel ends whatever its height. The
     design's offsets are preserved as margins, so at the design's own content
     length nothing moves. Tabs 1 and 2 are untouched.
     ========================================================================== */
  @media (min-width: 768px) {
    /* EVERY tab, not just Details. The spec column above the panel is rendered
       on all three — it is a direct child of `.qd-body`, outside the per-tab
       conditionals — so all three had the same collision, and scoping the grid
       to `.qd-body-0` left "What's included?" and "Reviews" exactly as they
       were: the column's own rows painted straight over the panel's first
       inclusion row. Tabs 1 and 2 have no tail, so their row 3 is simply never
       created. */
    .qd-body {
      display: grid;
      /* The rail's own 40..336 band, then the panel's 336..920 — as TRACKS, not
         a container padding plus a gap. `padding-left` on `.qd-body` shifts only
         its in-flow content: the panel moved 40 right while the absolutely
         positioned title, artwork and spec column above it stayed on the
         design's x, so the Details tab's grey panel sat 40 right of the same
         panel on the other two tabs. Measured at 1440: panel x282 here against
         x252 on tabs 1 and 2. */
      grid-template-columns: 21rem 36.5rem;
      align-items: start;
      /* Rows take their content height and nothing more, so any space left over
         lands after the last row rather than being shared between them. */
      align-content: start;
    }

    /* Column one. The rail belongs BESIDE the panel — the design puts its first
       tab at y554 against the panel's y534, i.e. 20 below its top edge, and the
       tabs' left radii are drawn to butt into that panel.

       It used to carry that 554 as a flat margin from the top of the grid, which
       was right only while the panel was also pinned to a canvas y. Now that the
       panel is pushed down by the column above it, a fixed 554 left the rail
       floating above it — measured 112px above the panel's top edge at 1440,
       which is the misalignment in the report.

       Sharing the panel's row instead makes the offset relative: the panel's own
       90 within that row, plus the design's 20. So the tabs sit 20 below the
       panel's top edge wherever the panel ends up, and at the design's own
       content length that is still exactly 554. Spanning rows 2-3 is what gives
       `sticky` its travel, and it no longer travels above the panel it labels. */
    .qd-body > .qd-rail {
      grid-column: 1;
      grid-row: 2 / span 2;
      margin: 6.875rem 0 0 2.5rem;    /* the panel's own 90 + the design's 20 */
    }

    /* Column two, top to bottom: the spec column, the panel, the tail. The spec
       column is row 1 (see THE SPEC COLUMN block below), so the panel's own
       offset is now what remains of the design's 534 after it: 534 - (184 + the
       column's own 260) = 90. At the design's content length that lands the
       panel on 534 exactly; past it the panel moves down instead of being
       painted over. */
    .qd-body > .qd-panel {
      position: relative;
      left: auto;
      top: auto;
      grid-column: 2;
      grid-row: 2;
      width: 100%;
      margin: 5.625rem 0 0;           /* 90 */
    }

    .qd-body > .qd-tail {
      grid-column: 2;
      grid-row: 3;
      margin: 1.5rem 0 0;             /* just the gap — no left offset now */
      width: 100%;
      max-width: none;
    }
  }
}

/* ==========================================================================
   MOBILE — lifted back to the top level
   --------------------------------------------------------------------------
   These blocks were written for phones, and an automated pass that scoped the
   desktop geometry swept them inside `@media (min-width: 768px)`. A max-width
   query nested in a min-width query can never match, so they were silently
   inert at every width. Restored to the top level, where they apply.
   ========================================================================== */
@media (max-width: 767.98px) {
  .qc-panel {
    grid-template-columns: minmax(0, 1fr);
    padding: 1.25rem;
  }
  .qc-panel > .qc-price {
    grid-column: 1;
    grid-row: auto;
    width: 100%;
    margin-top: 1rem;
  }
}

/* ==========================================================================
   MOBILE — the tail column, and a long name in the phone's title slot
   --------------------------------------------------------------------------
   `.qd-tail` is ours: the design has no rules for it at any width, because in
   the design the video and its fine print live INSIDE the panel at fixed
   coordinates. We moved them out so the proposal detail could sit between them,
   and gave the tail desktop widths — which left the phone with the design's own
   `.qd-video { width: 32.5rem }`. That is 520 design pixels: at a 360 viewport
   the root scales to 13.46px, so the video rendered 437px wide inside a 360px
   sheet and hung off the right edge.

   The design's mobile block already makes `.qd-body` a flex column with
   `height: auto` and the panel `relative`, so the tail only needs the sheet's
   own gutters — 16 either side, matching `.qd-title`'s `left: 1rem`.

   Nothing the design positions is moved. Desktop is untouched: these rules are
   inside `max-width` only.
   ========================================================================== */
@media (max-width: 767.98px) {
  .qd-tail {
    position: static;
    margin: 1.5rem 1rem 0;
    width: auto;
    max-width: none;
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
  }

  /* The video keeps its 16:10 shape rather than the design's fixed 520x320. */
  .qd-tail .qd-video {
    position: relative;
    left: auto;
    top: auto;
    width: 100%;
    height: auto;
    aspect-ratio: 13 / 8;
  }
  .qd-tail .qd-video img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .qd-tail .qd-fine,
  .qd-tail .qd-proposal {
    position: static;
    left: auto;
    top: auto;
    width: 100%;
    max-width: none;
  }

  /* The phone's title slot is 356 wide at y354, with the copy block beneath it.
     A real catalogue name wraps past the slot, so it is bounded here as it is on
     desktop — the full name stays on the element's tooltip. */
  .qd-title {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
  }

  /* ---- the Details panel sizes to its copy on a phone too -----------------
     `height: auto` alone COLLAPSED it. The design gives this panel `height: 61rem`
     on mobile with every child absolutely placed inside it, and relaxing the
     height without releasing the children left a zero-tall box: measured at 420
     the panel was 0 tall with 220px of copy hanging out of it, and at 320 it was
     0 against 526px. The tail then rendered ~900px ABOVE the copy it follows.

     The design already solves this for the other two panels — `.qd-panel-1` and
     `.qd-panel-2` are `height: auto` with `> * { position: relative }` — so this
     is that same treatment applied to the third, with the 20 inset this frame is
     authored at as padding. The children's own vertical rhythm is the margin pair
     at the top of this file, which is already scoped to exactly these elements. */
  .qd-panel-0 {
    height: auto;
    min-height: 0;
    padding: 1.25rem;                /* Figma's own 20 on the 428 frame */
    box-sizing: border-box;
  }
  .qd-panel-0 > * {
    position: relative;
    left: auto;
    top: auto;
    width: 100%;
  }
}

/* ==========================================================================
   THE SPEC LIST — long equipment names wrap instead of running off the sheet
   --------------------------------------------------------------------------
   `.qd-bullets li` is a 20px-tall flex row and `.qd-copy` is 331 wide. Both were
   measured against the design's own spec lines ("Up-to 2 years 0% APR"). A real
   one is far longer — "5kWh EcoFlow Power Ocean LFP 5kWh Battery battery storage
   system" — so the row ran past the sheet's right edge and was clipped.

   The row now grows to the lines it needs and the text wraps inside the column
   the design drew. The tick stays top-aligned with the first line, which is
   where it reads correctly once a row is more than one line.
   ========================================================================== */
.qd-bullets li {
  height: auto;
  min-height: 1.25rem;
  align-items: flex-start;
}
.qd-bullets img {
  margin-top: 0.1rem;
}
.qd-bul-t {
  /* THE line that was missing. quote-details.css sets `white-space: nowrap` on
     this run, so no width constraint could ever make it wrap — a long equipment
     name simply ran on until the sheet clipped it. The design's own spec lines
     are short enough that nowrap never showed, which is why it was authored. */
  white-space: normal;
  min-width: 0;
  overflow-wrap: anywhere;
}
/* The list is absolutely positioned at the column's left edge, so it needs the
   column's width to wrap against. */
.qd-copy > .qd-bullets {
  right: 0;
  width: auto;
}

/* ==========================================================================
   REVIEWS — every published review, not the design's two
   --------------------------------------------------------------------------
   The design draws exactly two cards at fixed coordinates (`.qd-rev-card-0` at
   y281, `-1` at y525) and repeats one quote between them. A tenant may have any
   number of published reviews, so the cards now stack inside `.qd-rev-list`.

   `.qd-rev-list` is ours — the design has no rule for it — so it takes the first
   card's own coordinates and the 12px gap the design's two cards sit apart
   (525 - 281 - 232). Card width, height, background, radius, stars and type are
   all still the design's, and each card's children stay absolute inside it, so a
   single card is pixel-identical to before.
   ========================================================================== */
.qd-rev-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;                        /* 12 — the design's own card spacing */
}

.qd-rev-list > .qd-rev-card {
  position: relative;
  left: auto;
  top: auto;
  width: auto;
  height: auto;
  min-height: 14.5rem;                 /* 232 — the design's card height */
  flex: none;
}

/* The quote sits between y72 and the attribution at y176 — 104px, three lines of
   the design's 32px leading. A longer review is bounded to that rather than
   running under the name. */
.qd-rev-q {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

/* Placeholder and empty states reuse the card shell, so nothing new is drawn and
   the panel does not jump when the real cards arrive. */
.qd-rev-card-loading {
  background: rgba(17, 17, 17, 0.04);
}
.qd-rev-card-empty {
  min-height: 7rem;
  display: flex;
  align-items: center;
}
.qd-rev-card-empty > .qd-rev-by {
  position: static;
  left: auto;
  top: auto;
  width: auto;
  padding: 0 1.5rem;
}

@media (min-width: 768px) {
  /* The list takes the place the design gives its first card. */
  .qd-rev-list {
    position: absolute;
    left: 2rem;
    right: 2rem;
    top: 17.5625rem;                   /* 281 — `.qd-rev-card-0`'s own top */
  }

  /* The Reviews tab's body was a fixed 1485 tall, measured for two cards. It
     grows with however many the tenant has published. */
  .qd-body-2 {
    height: auto;
    min-height: 92.8125rem;
  }

  /* "What's included?" needs the same release from its declared 1540: a `height`
     on a grid is a hard height, so a taller spec column or a longer inclusion
     list overflowed it instead of extending it. The floor is set to 0 further
     down, where the flow already measures the panel. */
  .qd-body-1 {
    height: auto;
  }
}

/* ==========================================================================
   THE SHEET CLEARS ITS OWN PRICE BAR — on every tab
   --------------------------------------------------------------------------
   `.qd-body-0` was given bottom padding so the Details tab's last line could be
   scrolled past the sticky price bar. The other two tabs never got it, so on
   Reviews the final card sat underneath the bar and read as cut off — the more
   reviews a company publishes, the more obvious it became.

   Applied to all three so the rule holds whichever tab is open, and to the tab
   bodies rather than the scroller, so the bar keeps overlaying the content the
   way the design intends.
   ========================================================================== */
.qd-body-1,
.qd-body-2 {
  padding-bottom: 14rem;               /* the price bar is ~120 tall + breathing room */
}

/* The Reviews tab grows with however many reviews there are, at every width —
   the desktop rule above only relaxed its fixed height above 768. */
.qd-body-2 {
  height: auto;
}

/* ==========================================================================
   THE SPEC COLUMN PUSHES THE PANEL DOWN INSTEAD OF BEING CAPPED
   --------------------------------------------------------------------------
   The previous attempt here capped the column at the 350px between its own y184
   and the panel's y534, hid the list's overflow and clamped every spec row to
   two lines. That stopped the list painting over the panel, but it did it by
   throwing product information away — and it did not even stop the overlap it
   was aimed at, because `-webkit-line-clamp` only truncates when the SAME
   element also has `overflow: hidden`. It did not, so the clamp set the box to
   two lines while the third line went on painting. Measured on the running build
   at 1920, 1440 and 1280, with the catalogue's own names:

     row  "Ultra powerful 665w Aiko Stellar 3N+ ... (Traceable)"  2 shown, 3 needed
     row  "6kWh SolaX X1 Hybrid G4 3.0D + TP30 Batt Bundle ..."   2 shown, 3 needed

   — and `overflow: visible` on both. That third line is what lands on the row
   beneath it. The list was also being clipped (2px at 1440, more on a longer
   name) and finished 4px off the panel, so any longer product name collided.

   The real constraint is that the column and the panel are both placed by
   coordinate, so neither can know about the other. The fix is to stop placing
   the column by coordinate: on the Details tab it joins the same grid the panel
   and the tail already use, as the row ABOVE the panel. The panel is pushed down
   by whatever the column actually needs, so the rows can wrap as far as they
   like and nothing is capped, clipped or clamped.

   Every offset is the design's own, re-expressed so the 1920 render does not
   move:

     .qd-copy    y184, x589 (=920-331)   -> margin: 11.5rem 0 0 auto, width 331
                 the design's own 260    -> min-height, so a SHORT column still
                                            leaves the panel at its own y534
     .qd-panel   y534                    -> margin-top 90 (534 - (184 + 260))
     .qd-bullets y144 inside the column   -> margin-top 24 (144 - the blurb's 120)

   The column's two children come into flow with it. That is what gives the box a
   height at all — they were absolute, which is why the design had to declare
   `height: 16.25rem` — and it makes the gap between blurb and list hold at 24
   however many lines the blurb takes, instead of only at the design's five.
   ========================================================================== */
@media (min-width: 768px) {
  .qd-bul-t {
    /* No clamp. A spec row is product information, not decoration: it wraps to
       as many lines as it needs and the row grows with it (`.qd-bullets li` is
       already `height: auto` above). */
    display: block;
    -webkit-line-clamp: none;
    line-clamp: none;
  }

  .qd-body > .qd-copy {
    position: static;                 /* out of the canvas, into the grid */
    grid-column: 2;
    grid-row: 1;
    margin: 11.5rem 0 0 auto;         /* the design's y184; auto puts it on x589 */
    width: 20.6875rem;                /* 331 */
    height: auto;
    max-height: none;
    min-height: 16.25rem;             /* the design's own 260 — holds the panel at y534 */
    display: flex;
    flex-direction: column;
  }
  .qd-body > .qd-copy > .qd-copy-p {
    position: static;
    left: auto;
    top: auto;
    width: auto;
  }
  .qd-body > .qd-copy > .qd-bullets {
    position: static;
    left: auto;
    right: auto;
    top: auto;
    width: auto;
    margin-top: 1.5rem;               /* 144 - the blurb's own 120 */
    max-height: none;
    overflow: visible;
  }
}

/* ==========================================================================
   "WHAT'S INCLUDED?" — TENANT LISTS CAN OUTGROW THE DESIGN'S CARDS
   --------------------------------------------------------------------------
   Every string in this sheet is now company-configurable, but the sheet was
   still laid out by coordinate for the exact copy it was drawn with: the two
   cards are a fixed 390x713 with `overflow: hidden`, and the header, pill and
   cards are absolute siblings inside a fixed 960x1057 body.

   So a company that adds a fourth inclusion, or writes a longer line than the
   design's, simply loses it behind the card's edge — content they deliberately
   entered, gone with no indication. Clamping is the wrong answer here for that
   reason; this is the one region where the content must be allowed to win.

   The body therefore flows instead. It already lives inside `.qd-scroll`, so
   growth just means a slightly longer scroll. The grid below is the design's own
   geometry restated as flow — with the design's default copy it lands within a
   pixel of Figma at every step:

     40 pad + 40 h + 8 + 39 sub  = 127   Figma: sub ends 127
     + 40 gap                    = 167   Figma: pill at 168
     + 96 pill + 40 gap          = 303   Figma: cards at 304
     + 713 card                  = 1016  Figma: content ends 1017

   Columns: 80 + 390 + 20 + 390 + 80 = 960, so the 880 span is centred exactly
   as authored, and the pill keeps its full 880 width.
   ========================================================================== */
@media (min-width: 768px) {
  .qi-body {
    height: auto;
    min-height: 66.0625rem;                /* the design's 1057, as a floor */
    display: grid;
    grid-template-columns: 24.375rem 24.375rem;   /* 390 + 390 */
    column-gap: 1.25rem;                          /* 490 - 80 - 390 */
    row-gap: 0;                                   /* gaps are per-row margins */
    justify-content: center;                      /* the authored 80 side inset */
    padding: 2.5rem 0 2.5rem;                     /* h at y40; 1057 - 1016 tail */
  }

  /* Out of the absolute layer, into the grid. The header rows span both cards. */
  .qi-body > .qi-h,
  .qi-body > .qi-sub,
  .qi-body > .qi-pill {
    position: static;
    grid-column: 1 / -1;
  }
  .qi-body > .qi-h { margin: 0; }
  .qi-body > .qi-sub {
    /* `left:0;right:0` centring becomes auto margins at the authored 455. */
    left: auto;
    right: auto;
    margin: 0.5rem auto 0;                 /* 88 - (40 + 40) */
  }

  /* The pill grows with its text rather than clipping it. Its three children
     were absolute at x44 / x84 / x249, which is exactly a 28-wide icon, a
     165-wide heading column and the rest — all vertically centred on 96. */
  .qi-body > .qi-pill {
    height: auto;
    min-height: 6rem;
    overflow: visible;
    margin: 2.5rem 0 0;                    /* 168 - 127 */
    display: grid;
    grid-template-columns: 1.75rem 10.3125rem 1fr;   /* 28 / 249-84 / rest */
    align-items: center;
    column-gap: 0.75rem;                   /* 44 + 28 + 12 = 84 */
    padding: 1.5rem 2.75rem;               /* the authored 44 inset */
  }
  .qi-pill > .qi-pill-icon,
  .qi-pill > .qi-pill-h,
  .qi-pill > .qi-pill-t {
    position: static;
    left: auto;
    top: auto;
  }

  /* The cards keep their 713 as a floor and stretch together, so the pair stays
     level however much either side is given. */
  .qi-body > .qi-card {
    position: static;
    height: auto;
    min-height: 44.5625rem;
    overflow: visible;
    margin: 2.5rem 0 0;                    /* 304 - 263 */
    padding: 2rem;                          /* what `.qi-groups` @32,32 was */
  }
  .qi-body > .qi-card-in  { grid-column: 1; }
  .qi-body > .qi-card-out { grid-column: 2; }
  .qi-card > .qi-groups {
    position: static;
    width: auto;                            /* the padding now sets the 326 */
  }
}

/* At every width: a tick stays with the top line of the text it marks, and no
   single long word can push a row out sideways. */
.qi-list li { align-items: flex-start; }
.qi-list li > .qs-tick,
.qi-list li > .qs-x { flex: none; }
.qi-t,
.qi-pill-t,
.qi-group-h { overflow-wrap: anywhere; }

/* ==========================================================================
   REQUEST CALLBACK SHEET
   --------------------------------------------------------------------------
   The backend has had a design-call endpoint since before the design landed,
   and the design has no screen for it — so this is the same situation as the
   tariffs step and the roof designer, and it takes the same approach the notes
   on those two describe: borrow the design's own vocabulary rather than invent
   a look, so it sits inside the journey without pretending to be a Figma frame.

   NOTHING BELOW IS NEW DESIGN. Every value is lifted from an existing rule:

     the shell    QuoteSheet / `.qd` — the scrim, the backdrop blur, the 160x6
                  handle, the 960x930 r[40,40,0,0] modal, the 720ms rise, the
                  Escape key and the 388-wide r20 phone geometry all arrive
                  unchanged from D11 / D14 / D15 / D16. Not one declaration of
                  it is repeated here.
     the head     `.qfa-h` / `.qfa-sub` — which quote-details.css repeats
                  verbatim as `.qi-h` / `.qs-h`, i.e. it is the sheet family's
                  one heading pair, not D14's in particular.
     the fields   `.qz-field` / `.qz-field-label` / `.qz-fields` from the
                  tariffs step, itself derived from the design's `.qz-search`
                  card — same 452 column, same 12 gap, same white card at
                  `var(--radius)` under the same 40-blur shadow.
     the button   the design's own `.qz-cta`, through QuoteCta, so the arrow
                  chip, the hover sheen and the disabled state come with it.
     the error    `.qz-addr-note` + `.qz-addr-note-error`, the line the EPC
                  lookup already fails into.

   Laid out in NORMAL FLOW rather than on Figma coordinates. The four sheets
   are absolute inside `.qd-scroll` because each is a fixed frame; a form is
   not — its error line appears and disappears, its labels wrap, and its rows
   collapse to one column on a phone. Same reasoning as `.qz-fields`.
   ========================================================================== */
.qcb-body {
  /* `.qd-scroll` is inset 0 in a modal with no padding, so this box carries
     the sheet's own 40 head inset. `min-height: 100%` holds the sheet's height
     so the wash below lands on its bottom edge, and lets the column grow past
     it when the form is taller. */
  min-height: 100%;
  box-sizing: border-box;
  padding: 2.5rem 1.5rem 3rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* FROM THE TOP, NOT CENTRED — and this is the whole of "the space above the
     heading is not the same".
     `center` vertically centred the column in a 930 sheet, which put the
     heading ~156 down instead of on the 40 the padding above states. Every
     other sheet in the family pins its heading to that 40 (`.qs-h` and
     `.qi-h` are literally `top: 2.5rem`), so this one drifted from the four
     it is supposed to be furniture-identical to. `flex-start` makes the
     padding mean what it says, and the pair below it — heading 32/40 then an 8
     gap to a 16/19.52 sub — is already `.qs-h`/`.qs-sub` to the declaration,
     so nothing about the type had to move. */
  justify-content: flex-start;
  /* over the wash, which is a later sibling: the savings sheet's cards end
     above its gradient so painting order never mattered there, but this form
     runs into it and would be painted over. */
  position: relative;
  z-index: 1;
}

/* THE LIME WASH — Rectangle 31, the same one D15 carries.
   `position` and the height are all that is here; the gradient
   (rgba(226,250,90,0) -> #e2fa5a) and the grain over it are the shared
   `.qfa-wash, .qs-wash, .qcb-wash` rule in quote-details.css, so this cannot
   drift from the sheet it was copied from. 323 is D15's own height. */
.qcb-wash {
  position: absolute;
  height: 20.1875rem;                               /* 323 */
  z-index: 0;
}

/* ---- the sheet family's heading pair ----------------------------------- */
.qcb-h {
  margin: 0;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 2rem;                                  /* 32 */
  line-height: 2.5rem;                              /* 40 */
  letter-spacing: -0.08rem;
  color: rgba(17, 17, 17, 0.92);
}
.qcb-sub {
  margin: 0.5rem 0 0;
  max-width: 28.4375rem;                            /* 455 — the authored wrap */
  text-align: center;
  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);
}

/* ---- the tariffs step's field column ----------------------------------- */
.qcb-form {
  width: 28.25rem;                                  /* 452 — `.qz-fields` */
  max-width: 100%;
  margin: 2rem 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;                                     /* `.qz-fields` own gap */
  text-align: left;
}
/* First and last name share a row at the design's own field gap, and drop to
   one column below 768 where the modal is 388 wide. */
.qcb-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
}
.qcb-field { display: block; }
.qcb-label {
  display: block;
  margin-bottom: 0.25rem;
  font-family: var(--font-sans);
  font-size: 0.85rem;
  color: var(--ink-70);
}
/* The required mark is the one the form already drew, kept in the palette's
   own red rather than Tailwind's. */
.qcb-req { color: #8c1d16; }

.qcb-field input,
.qcb-field textarea {
  box-sizing: border-box;
  width: 100%;
  height: 3.25rem;                                  /* 52 — `.qz-field input` */
  padding: 0 1.25rem;
  border: 0;
  border-radius: var(--radius);
  background: var(--white);
  box-shadow: 0 0 2.5rem rgba(0, 0, 0, 0.08);
  outline: none;
  appearance: none;
  font-family: var(--font-sans);
  font-size: 1rem;
  color: var(--ink);
}
/* A textarea cannot keep the field's fixed 52: it needs its own block padding
   and room to grow, so only the height rule is replaced. */
.qcb-field textarea {
  height: auto;
  min-height: 6rem;
  padding: 0.875rem 1.25rem;
  line-height: 1.4;
  resize: vertical;
}
.qcb-field input::placeholder,
.qcb-field textarea::placeholder { color: var(--ink-70); }
/* The design's own focus treatment on a field — `.qz-search:focus-within`'s
   accent ring, at the weight the sheet's other controls use. */
.qcb-field input:focus-visible,
.qcb-field textarea:focus-visible {
  box-shadow:
    0 0 2.5rem rgba(0, 0, 0, 0.08),
    0 0 0 0.125rem rgba(226, 250, 90, 0.9);
}

/* ---- the EPC lookup's own note line ------------------------------------ */
.qcb-note {
  margin: 0;
  padding: 12px 20px;
  background: #fff;
  border: 1px solid rgba(17, 17, 17, 0.12);
  border-radius: 12px;
  font-size: 0.85rem;
  line-height: 1.4;
  color: rgba(17, 17, 17, 0.7);
}
.qcb-note-error {
  border-color: rgba(180, 35, 24, 0.35);
  background: #fff6f5;
  color: #8c1d16;
}

/* ---- the design's CTA -------------------------------------------------- */
/* `.qz-cta` carries `top: 33.9375rem`, which only ever applied because
   `.qz-step > *` positions it absolutely. Outside a step it is static and the
   `top` is inert — declared anyway, so a future change to that rule cannot
   drop this button 543px down the sheet. */
.qcb-actions {
  margin-top: 0.5rem;
  display: flex;
  justify-content: center;
}
.qcb-actions .qz-cta {
  position: static;
  top: auto;
}

.qcb-fine {
  margin: 0.25rem 0 0;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  line-height: 1.4;
  color: rgba(17, 17, 17, 0.55);
}

/* ---- the success state ------------------------------------------------- */
/* The same heading pair as the form it replaces, so the sheet does not change
   shape or type when the request lands. */
.qcb-done {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
}
.qcb-done-lines {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

@media (max-width: 767.98px) {
  /* The modal is 388 wide here, so the head inset comes in and the name row
     stacks — at two columns each field would be under 11rem. */
  .qcb-body { padding: 2rem 1.25rem 2.5rem; }
  .qcb-h { font-size: 1.75rem; line-height: 2.125rem; }
  .qcb-row { grid-template-columns: 1fr; }
}

/* ==========================================================================
   TABS 1 AND 2 GROW WITH THEIR CONTENT
   --------------------------------------------------------------------------
   Both panels were authored as fixed frames — `.qd-panel-1` 844 tall for the
   design's eight inclusion rows, `.qd-panel-2` 789 for its two review cards —
   and `.qd-panel` carries `overflow: hidden` (Figma's clipsContent). Neither
   list is a fixed length in the product: the inclusions come from the tenant's
   dashboard and the reviews from whatever it has published. Measured at 1440
   before this block:

     What's included, 1 row      panel 633 tall, 84 of content -> 549 blank
     Reviews, 1 review           panel 592 tall, 409 of content -> 183 blank
     Reviews, 8 reviews          panel 592 tall, 1858 of content -> 1266 CLIPPED

   The last one is the serious case: past the fourth review the cards were cut
   off by the panel and there was no scroll position that revealed them.

   `.qd-body-1` / `-2` were fixed too (1540 / 1485), and could not have helped
   even relaxed, because `.qd-panel` is absolutely positioned on these two tabs —
   `.qd-rail` is the body's only in-flow child, so the body never measured the
   panel at all. So the panel joins the flow, in the same two-column grid the
   Details tab already uses, and the body then grows with it.

   NOTHING VISUAL CHANGES AT THE DESIGN'S OWN CONTENT LENGTH. The tracks are the
   design's own bands (rail 40..336, panel 336..920), the panel keeps its 534 y
   as a margin, its 584 width, its #f1f1f1, its radius and its 32 inset; the rows
   and cards keep every dimension, colour and type they had. Only the panel's
   HEIGHT is now its content's, which is what the design's own mobile rules
   already do for these same two panels.
   ========================================================================== */
@media (min-width: 768px) {
  .qd-body-1,
  .qd-body-2 {
    height: auto;
    /* Supersedes the `min-height: 92.8125rem` the Reviews tab was given earlier
       in this file: that was the design's own body height, which reserved the
       full two-card frame however few reviews there were. The flow now measures
       the panel, so nothing has to be reserved. Safe to drop to 0: the deepest
       absolutely positioned child of `.qd-body` is `.qd-dots` at 30.875rem, and
       the rail alone already stands 45.375rem tall. */
    min-height: 0;
  }

  /* The grid, the tracks, the rail's row and the panel's row are NOT restated
     here any more. This block was written before the Details tab's spec column
     joined the same grid, and it declared its own row scheme: rail row 1 and
     panel row 1, against the shared scheme's column row 1 / panel row 2. Being
     later in the file it won, which is exactly what left these two tabs on the
     old behaviour — measured at 1440, the spec column shared row 1 with the
     panel and painted over its first inclusion row, and the rail sat 318px above
     the panel it labels.

     One scheme for all three tabs now: `.qd-body > .qd-copy` row 1,
     `.qd-body > .qd-panel` row 2, `.qd-body > .qd-rail` row 2, `.qd-body >
     .qd-tail` row 3 — see THE DETAILS TAB'S FLOW above. Everything below is
     genuinely per-tab and stays. */

  /* ---- What's included: the rows set the height --------------------------- */
  .qd-panel-1 {
    height: auto;
    min-height: 0;
    padding: 2rem;                          /* what `.qd-inc`'s @32,32 was */
    box-sizing: border-box;
  }
  .qd-panel-1 > .qd-inc {
    position: relative;
    left: auto;
    top: auto;
    width: 100%;
  }

  /* ---- Reviews: the head, then however many cards ------------------------ */
  /* A flex column on the design's own 12 gap — the same structure its mobile
     rule gives this panel, so the two widths now agree. */
  .qd-panel-2 {
    height: auto;
    min-height: 0;
    padding: 2rem;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;                           /* 525 - 281 - 232, the design's own */
  }
  /* The green summary box keeps its authored 237 — it is a fixed frame with
     absolutely placed children, and it is genuinely required. */
  .qd-panel-2 > .qd-rev-head {
    position: relative;
    left: auto;
    top: auto;
    width: 100%;
    flex: none;
  }
  /* Supersedes the absolute placement this list was given earlier in the file,
     which pinned it to the first card's y inside the fixed panel. */
  .qd-panel-2 > .qd-rev-list {
    position: relative;
    left: auto;
    right: auto;
    top: auto;
  }
}

/* ==========================================================================
   THE DETAILS TAB IS ONE CARD — the proposal sits ON the panel's own ground
   --------------------------------------------------------------------------
   `.qd-tail` (the platform's proposal detail, then the design's video and its
   fine print) renders after the panel rather than inside it — that is what
   keeps it clear of the coordinates the design positions inside that frame, and
   it stays that way. But it was also rendering on the sheet's bare ground, so
   the tab read as a short grey card followed by loose copy on the marble, with
   a band of nothing between them.

   The two now share one surface: the panel keeps the card's top and loses its
   bottom radius and bottom padding, the tail takes the same #f1f1f1, the
   matching bottom radius and the frame's own 32 inset, and the row gap goes to
   zero. Same DOM, same order, same everything the design positions — the tail
   simply stops floating and becomes the bottom of the card it belongs to.

   Nothing here introduces a height. Both boxes stay content-sized, so the card
   is as long as the proposal is and no longer.
   ========================================================================== */
@media (min-width: 768px) {
  .qd-body-0 > .qd-panel {
    border-radius: 0.75rem 0.75rem 0 0;
    padding-bottom: 0;
  }
  .qd-body-0 > .qd-tail {
    margin: 0;                                /* was the 1.5rem row gap */
    background: #f1f1f1;                      /* the panel's own ground */
    border-radius: 0 0 0.75rem 0.75rem;
    padding: 1.5rem 2rem 2rem;                /* the frame's own 32 inset */
    box-sizing: border-box;
  }
  /* Inside the padded card the content column is the design's own 520, which is
     what `.qd-video` and `.qd-fine` are already authored at. */
  .qd-body-0 > .qd-tail > .qd-proposal { max-width: 100%; }
}

@media (max-width: 767.98px) {
  /* ---- THE TAIL WAS RENDERING ABOVE EVERYTHING ---------------------------
     The design's mobile block orders the rail 1 and the panel 2. `.qd-tail` is
     ours and had no `order`, so it took the initial 0 and sorted FIRST: on every
     phone the proposal, the video and the fine print appeared ABOVE the tabs and
     above the Dimensions copy they are meant to follow. Measured at 420 the tail
     sat 1569px above the panel's bottom edge.

     3, so it lands after the panel's 2 — the DOM order it already has. */
  .qd-tail { order: 3; }

  /* The same one-card join, at this frame's own 20 inset and 356 box. */
  .qd-panel-0 {
    border-radius: 0.75rem 0.75rem 0 0;
    padding-bottom: 0;
  }
  .qd-tail {
    margin: 0 1rem;                           /* was 1.5rem 1rem 0 */
    width: auto;
    background: #f1f1f1;
    border-radius: 0 0 0.75rem 0.75rem;
    padding: 1.25rem;
    box-sizing: border-box;
  }

  /* ---- AND THE LAST LINE CAN NOW BE REACHED -------------------------------
     The price bar overlays the sheet at every width, but the clearance that
     lets the final line scroll out from under it was only ever given to this
     tab ABOVE 768 — `.qd-body-1` and `-2` carry it globally, `.qd-body-0` had
     it inside a `min-width` block. So on a phone the end of the Details tab was
     unreachable, which is the content that read as cut off. Ordering the tail
     last is what made it the visible symptom: measured at 420, the fine print
     ended 99px underneath the bar at maximum scroll. */
  .qd-body-0 { padding-bottom: 14rem; }
}

/* ==========================================================================
   THE RAIL'S PACKAGE CARD, AT EVERY WIDTH
   --------------------------------------------------------------------------
   The block above derived all of this and then scoped it to >=768, which left
   the phone on the design's canvas coordinates: `.qc-pkg-h` pinned at y272 and
   `.qc-pkg-inc` at y340, 68 apart — room for the two lines of 28px leading the
   design's one-word tier name needs. Measured at 390 with a real catalogue name
   ("Aiko Neostar 3P+ 545W ... + SolaX X1 Hybrid G4 3.0D + TP30 Batt Bundle"):

       short name   title 412..463   chip 474..507   overlap 0
       real name    title 412..539   chip 474..507   overlap 66, card overrun 18

   One rule set serves both breakpoints because the numbers are the same on
   both: the artwork band ends at 252 on EITHER canvas (desktop 20+92+140, the
   428 frame's Group 26 at 20 + 232), and the card is 24.5rem on both. So
   `padding-top: 17rem` reproduces the title's own y — measured at 390, 248px
   against the design's 248 — and the card grows downward from there instead of
   the title growing over the chip.

   The artwork stays absolute: its four images are placed relative to each other
   by coordinate alone and have no layout size, so the padding reserves their
   band. Absolute children resolve against the padding box, so the inset does
   not move them.
   ========================================================================== */
.qc-pkg {
  height: auto;
  min-height: 24.5rem;
  padding: 17rem 1.25rem 1.5rem;      /* top band = the artwork's own space */
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.75rem;                       /* the design's own 272+56 -> 340 gap */
}
.qc-pkg-h,
.qc-pkg-inc {
  position: static;
  left: auto;
  top: auto;
  width: auto;
  max-width: 100%;
  overflow-wrap: anywhere;
}
/* The chip's label is `white-space: nowrap` in the design, correct for its own
   fixed string but it makes the chip unshrinkable — on the narrowest phones it
   pushed past the card. It wraps instead; the chip keeps its own box. */
.qc-pkg-inc { flex-wrap: wrap; }
.qc-pkg-inc-t { white-space: normal; }

/* ==========================================================================
   THE MOBILE "NEXT, SUBMIT" BAR FILLS ITS BAR AGAIN
   --------------------------------------------------------------------------
   The design's mobile rule for this control is `width: auto`, and on the
   reference build that means FILL, because there the element is an anchor:

       <a className="qc-continue" href="/quote/submit">

   A block-level box with `width: auto` fills its containing block. The
   integration made it a <button>, which it has to be — the journey must not
   navigate, `onNext()` advances it — and a form control sizes to `fit-content`
   under `width: auto` even when it is `display: flex`. So the same declaration
   that filled the bar for an <a> shrink-wraps for a <button>.

   Measured against the reference at four widths, `.qc-continue`'s box:

       390    reference 354    ours 200
       360    reference 326    ours 184
       320    reference 290    ours 164
       428    reference 388    ours 219

   — a pill floating at the left of a full-width green bar instead of filling it.

   `width: 100%` restores the anchor's own behaviour: the topbar carries the
   design's `padding: 1rem 1.25rem 1.5rem`, and 100% of its content box is
   exactly the 354 the reference measures at 390. `box-sizing: border-box` is
   already global in base.css, so the button's own 12 padding stays inside.

   Mobile only. On desktop the design gives this control a fixed width and the
   button and the anchor size identically there.
   ========================================================================== */
@media (max-width: 767.98px) {
  .qc-continue { width: 100%; }
}
