/* ==========================================================================
   MyCabin Living 80 Page Pack — frontend.css
   Built from the final, accepted Milla 47 Clean Page Pack
   (page-packs/milla-47-clean, v1.0.23) as the implementation base — same
   product-page design system, same rail engine, same button/tab/badge/link
   primitives, same WordPress Flow-margin-defense technique — with content,
   assets and prices replaced from source-design/living-80-original.zip
   (the Living 80 authoritative source) and structural deltas applied where
   Living 80 genuinely differs: no floor-plan tabs (Living 80 is a single
   floor, Milla 47 has ground floor + loft), no "Ready now" stock-note (no
   equivalent section in the Living 80 source), and one new component,
   .pp-l80-energy-note, that Milla 47 has no equivalent of at all. Every
   selector is scoped under .pp-living-80-clean (Page Pack Spec §5). Design
   tokens below are the same MyCabin site-wide palette/scale used by every
   other Page Pack in this project — copied here (not shared) because each
   pack owns its own CSS per spec, not because these values are page-specific.
   ========================================================================== */

.pp-living-80-clean {
  --pp-ink:          #27272C;
  --pp-bone:         #FFFFFF;
  --pp-beige:        #FBF6F3;
  --pp-surface:      var(--pp-beige);
  --pp-accent:       #917EBC;
  --pp-accent-soft:  #CDCBFF;
  --pp-tint:         #E6E6FF;
  --pp-stone:        color-mix(in oklab, var(--pp-ink) 11%, var(--pp-bone));
  --pp-ink-hair:      color-mix(in oklab, var(--pp-ink) 7%,  var(--pp-bone));
  --pp-ink-line:     color-mix(in oklab, var(--pp-ink) 13%, var(--pp-bone));
  --pp-tint-line:        color-mix(in oklab, var(--pp-accent) 18%, var(--pp-tint));
  --pp-tint-line-strong: color-mix(in oklab, var(--pp-accent) 34%, var(--pp-tint));
  --pp-ink-72: color-mix(in oklab, var(--pp-ink) 72%, transparent);
  --pp-ink-56: color-mix(in oklab, var(--pp-ink) 65%, transparent);

  --pp-maxw:    1280px;
  --pp-gutter:  clamp(18px, 4vw, 40px);
  --pp-hdr-h:   clamp(58px, 7vw, 74px);
  --pp-sec-y-p: clamp(48px, 7vw, 104px);
  --pp-rail-pad: max(var(--pp-gutter), calc((100% - var(--pp-maxw)) / 2 + var(--pp-gutter)));

  --pp-r-pill: 999px;
  --pp-r-lg:  10px;
  --pp-r-md:  9px;
  --pp-r-sm:  8px;
  --pp-r-card: 11px;

  /* New tokens this page introduces (Living 80 source styles.css) — Milla
     47 has no equivalent component, so these were never needed there. */
  --pp-good:      #4F7A44;
  --pp-good-soft: #E3ECD9;

  --pp-ease:   cubic-bezier(.22, 1, .36, 1);
  --pp-t-med:  .25s;
  --pp-t-slow: .35s;

  font-family: "Poppins", "Helvetica Neue", Helvetica, sans-serif;
  color: var(--pp-ink);
  overflow-x: clip;
}

/* Fine paper-grain dot texture over the whole page (the shared site
   styles.css §02: "Fine paper grain over the whole page. Very low opacity —
   it stops large flat areas of bone from looking like a screen."), included
   from this pack's first version — Milla 47's own pack omitted this rule
   through v1.0.22 and only added it at v1.0.23, a lesson already learned
   and applied here directly rather than repeated. Source declares
   it as body::after; ported here as ::after on this pack's own root
   (Page Pack CSS may never target bare body, Page Pack Spec §5), which
   produces an identical visual result because position:fixed positions
   against the viewport regardless of which element the pseudo-element is
   attached to — a single global overlay layer over the whole viewport, not
   a per-section background, so it is inherently seamless and continuous
   across every section without any section-by-section scoping decision. */
.pp-living-80-clean::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 200;
  pointer-events: none;
  opacity: .05;
  background-image: radial-gradient(color-mix(in oklab, var(--pp-ink) 55%, transparent) .5px, transparent .5px);
  background-size: 3px 3px;
}

/* Real WordPress typography-cascade fix (Master Workflow §44) — the active
   theme's own generated global-styles block declares a direct font-family
   rule on h1-h6 and .wp-block-button__link/.wp-element-button (confirmed
   live: both rendered Inter despite this root correctly declaring Poppins,
   while plain paragraphs — no competing theme rule — inherited correctly).
   An inherited value never competes in the same cascade contest as an
   explicit rule on the element itself, regardless of that rule's own
   specificity. font-family:inherit (not a restated literal stack) keeps
   this root as the single source of truth. */
.pp-living-80-clean h1,
.pp-living-80-clean h2,
.pp-living-80-clean h3,
.pp-living-80-clean h4,
.pp-living-80-clean .wp-block-button__link,
.pp-living-80-clean .wp-element-button {
  font-family: inherit;
}

/* Page-wide anchor reset — source carries this as a single global rule
   (styles.css line 148-150: a{color:var(--ink);text-decoration:none}
   a:hover{color:var(--accent)}) that every link component on the page
   (buttons included) relies on and never restates itself; this file had no
   equivalent at all. Two concrete, reported symptoms trace back to this
   gap: (1) "pricing & inclusions." (.pp-l80-inline-link) sets no color of
   its own in source OR here, so its hover colour shift was simply missing
   entirely; (2) every .pp-l80-link/.pp-l80-tour-row__link instance sets
   text-decoration:none on its own DEFAULT state but never restates it on
   :hover — leaving hover exposed to the active theme's own default link
   styling (a common WordPress/theme convention is a:hover{text-decoration:
   underline}), which would draw a real browser-native underline at its own
   font-metric position, independent of and misaligned with this file's
   custom border-bottom + background-size wipe underline — i.e. exactly a
   second, differently-positioned line on hover. text-decoration carries
   !important on both states so it can never depend on stylesheet load
   order against theme CSS of equal or higher specificity; color does not,
   so a future on-dark/on-photo variant can still override it normally,
   the same way source's own .link--on-dark:hover{color:var(--paper)}
   overrides this same global rule for that one case. */
.pp-living-80-clean a { color: var(--pp-ink); text-decoration: none !important; }
.pp-living-80-clean a:hover { color: var(--pp-accent); text-decoration: none !important; }

/* Source's own keyboard-focus treatment (styles.css line 156-160) — never
   removed, only restyled, per source's own comment there. This file never
   carried an equivalent, so focus indication was falling back entirely to
   the active theme's own default outline. Added, not replacing anything of
   this file's own, so no existing focus behaviour is being removed. */
.pp-living-80-clean :focus-visible {
  outline: 2px solid var(--pp-accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ==========================================================================
   WordPress Flow-margin defense — every custom component that owns its own
   direct-child spacing/layout must neutralize WordPress's default
   margin-block-start injection (Master Workflow §7.1/§17). Scoped to exactly
   the components below; ordinary heading/paragraph stacking elsewhere is
   left to WordPress's own default Flow spacing.
   INHERITED WHOLESALE FROM THE ACCEPTED MILLA 47 PACK (v1.0.23): this exact
   bug class — WordPress's own default Flow blockGap margin-block-start
   landing on a direct child (silently zeroing that child's own legitimate
   margin-top unless the component's own rule also carries !important, or,
   for a first-child-of-.pp-wrap top-level section, adding an UNWANTED extra
   gap on top of the section's own padding-block) — is a property of the
   shared WordPress/theme mechanism this Page Pack renders inside, not of
   Milla 47's markup specifically. It applies identically here, so every
   selector below is carried over unchanged (renamed pp-m47- -> pp-l80-)
   rather than re-discovered from scratch; the historical "v1.0.X found/
   fixed this" narrative in Milla 47's own frontend.css/manifest.json is
   that pack's development record, not repeated here. IMPORTANT: this reset
   carries !important, so it also silently zeroes any margin a listed
   container's own direct child legitimately owns on ITSELF (e.g.
   .pp-l80-specs's own margin-top) unless that rule ALSO carries !important
   — every such component-owned margin/padding-top pairing elsewhere in this
   file already does this (the *__rule separators, .pp-l80-faq__more,
   .pp-l80-cta-split__lead, .pp-l80-energy-note's own margin-top, etc.).
   Also included: EVERY top-level section under the page's one alignfull
   wp:group wrapper (.pp-l80-floorplan, .pp-l80-inside, .pp-l80-packages,
   .pp-l80-visit, .pp-l80-materials, .pp-l80-faq, .pp-l80-cta-split) gets its
   own margin-top:0 !important below — each is an exposed "later sibling" of
   that wrapper (.pp-l80-prod-head is the sole exception, as the wrapper's
   own first child — WordPress's "* + *" injection never targets a first
   child). The fixed WP blockGap value this margin would otherwise inject
   does not scale with viewport, while --pp-sec-y-p (each section's own top
   padding) does — left unguarded, the extra gap would read as a large
   fraction of the mobile gap and a comparatively small one on desktop.
   ========================================================================== */
.pp-living-80-clean .pp-l80-prod-head__grid > *,
.pp-living-80-clean .pp-l80-gallery-col > *,
.pp-living-80-clean .pp-l80-prod-head__copy > *,
.pp-living-80-clean .pp-l80-specs > *,
.pp-living-80-clean .pp-l80-specs__item > *,
.pp-living-80-clean .pp-l80-energy-note > *,
.pp-living-80-clean .pp-l80-price > *,
.pp-living-80-clean .pp-wrap > *,
.pp-living-80-clean .pp-l80-plan-grid > *,
.pp-living-80-clean .pp-l80-plan-img > *,
.pp-living-80-clean .pp-l80-plan-aside > *,
.pp-living-80-clean .pp-l80-plan-table > *,
.pp-living-80-clean .pp-l80-plan-table__row > *,
.pp-living-80-clean .pp-l80-plan-table__row-inner > *,
.pp-living-80-clean .pp-l80-marquee > *,
.pp-living-80-clean .pp-l80-marquee__track > *,
.pp-living-80-clean .pp-l80-marquee__group > *,
.pp-living-80-clean .pp-l80-interior > *,
.pp-living-80-clean .pp-l80-tour-row > *,
.pp-living-80-clean .pp-l80-tiers > *,
.pp-living-80-clean .pp-l80-tier > *,
.pp-living-80-clean .pp-l80-tier__top > *,
.pp-living-80-clean .pp-l80-tier__name-row > *,
.pp-living-80-clean .pp-l80-tier-cta > *,
.pp-living-80-clean .pp-l80-visit-grid > *,
.pp-living-80-clean .pp-l80-visit-copy > *,
.pp-living-80-clean .pp-l80-track > *,
.pp-living-80-clean .pp-l80-track__step > *,
.pp-living-80-clean .pp-l80-testimonial > *,
.pp-living-80-clean .pp-l80-testimonial__body > *,
.pp-living-80-clean .pp-l80-testimonial__who > *,
.pp-living-80-clean .pp-l80-cert-grid > *,
.pp-living-80-clean .pp-l80-cert-copy > *,
.pp-living-80-clean .pp-l80-faq-cols > *,
.pp-living-80-clean .pp-l80-faq-col > *,
.pp-living-80-clean .pp-l80-faq-row > *,
.pp-living-80-clean .pp-l80-cta-split > *,
.pp-living-80-clean .pp-l80-cta-split__body > *,
.pp-living-80-clean .pp-l80-btn-row > * {
  margin-block-start: 0 !important;
  margin-block-end: 0 !important;
}


/* ==========================================================================
   Layout helpers
   ========================================================================== */
.pp-living-80-clean .pp-wrap {
  max-width: var(--pp-maxw);
  margin: 0 auto;
  padding-inline: var(--pp-gutter);
}
.pp-living-80-clean .pp-l80-section--p { padding-block: var(--pp-sec-y-p); }
.pp-living-80-clean .pp-l80-bg-surface { background: var(--pp-surface); }


/* ==========================================================================
   Buttons, pills, links
   ========================================================================== */
.pp-living-80-clean .wp-block-button__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 40px;
  padding: 0 21px;
  border-radius: var(--pp-r-pill);
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
  transition: background var(--pp-t-med), color var(--pp-t-med), border-color var(--pp-t-med);
}
.pp-living-80-clean .pp-btn-ink .wp-block-button__link { background: var(--pp-ink); color: var(--pp-bone); border: 0; }
.pp-living-80-clean .pp-btn-ink .wp-block-button__link:hover { background: var(--pp-accent); color: var(--pp-bone); }
.pp-living-80-clean .pp-btn-accent .wp-block-button__link { background: var(--pp-accent-soft); color: var(--pp-ink); border: 0; }
.pp-living-80-clean .pp-btn-accent .wp-block-button__link:hover { background: var(--pp-accent); color: var(--pp-ink); }
.pp-living-80-clean .pp-btn-outline .wp-block-button__link { background: transparent; color: var(--pp-ink); border: 1px solid var(--pp-ink); }
.pp-living-80-clean .pp-btn-outline .wp-block-button__link:hover { background: var(--pp-surface); color: var(--pp-ink); }
.pp-living-80-clean .pp-btn-54 .wp-block-button__link { height: 43px; font-size: 15px; }
.pp-living-80-clean .pp-btn-56 .wp-block-button__link { height: 45px; font-size: 15px; }
.pp-living-80-clean .pp-btn-block { display: flex; width: 100%; }
.pp-living-80-clean .pp-btn-block .wp-block-button__link { width: 100%; }

/* Equal-width button rows by default — excludes .pp-l80-btn-row--stack (a
   column, not a row: a flex-basis there would set height, not width — see
   the manifest's own note and the source README). */
.pp-living-80-clean .pp-l80-btn-row.wp-block-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.pp-living-80-clean .pp-l80-btn-row:not(.pp-l80-btn-row--stack) > .wp-block-button { flex: 1 1 200px; }
.pp-living-80-clean .pp-l80-btn-row--stack.wp-block-buttons { flex-direction: column; width: 100%; max-width: 360px; }

/* Text link with the left-to-right underline wipe, plus a decorative arrow
   (source's own inline SVG, aria-hidden, next to the link text) reproduced
   as a background-image on a pseudo-element rather than embedded in the
   paragraph's own RichText content — RichText silently drops nested
   non-text elements from the editor's own live view even though the
   frontend renders them fine (Master Workflow §20); keeping it CSS-owned
   avoids that class of bug entirely, since the arrow carries no independent
   editorial meaning of its own (it's marked aria-hidden in source). */
/* .pp-l80-tour-row__link ("View virtual tour") shares this exact source
   class (link link--sm link--ink) with .pp-l80-link's "See the unit" /
   "Reserve now" instances, but had been given its own, separately-authored
   rule (border-bottom + text-decoration only, no background-image wipe, no
   :hover at all) instead of reusing this one — the tour-row link had no
   hover feedback whatsoever. Merged in here rather than left as a silently
   incomplete duplicate. */
/* Intentional deviation from source, inherited from Milla 47's own accepted
   pack (user-requested there, v1.0.16 — carried over here rather than
   reverting to source's original two-layer approach): source draws
   this underline as TWO independently-positioned layers — a border-bottom
   (always visible, grey) sitting in the border box, plus a background-image
   wipe (grows on hover) sitting in the padding box, immediately adjacent
   but never pixel-identical to the border. Source itself lets a sliver of
   the grey border remain visible under/beside the hover wipe; this pack now
   intentionally does not. Both lines are now the SAME background-image
   mechanism, stacked as two layers at the identical background-position/
   background-size Y-track (0 100%, height 1.5px) — layer 1 (painted on
   top) is the colour that animates 0%->100% width on hover; layer 2
   (underneath) is a static, always-100%-width grey base line. Because both
   layers use one coordinate system, hover's colour layer covers the grey
   layer with pixel-perfect, guaranteed alignment — no border-vs-background
   box-model discrepancy, no subpixel seam possible. border-bottom is
   removed entirely; padding-bottom absorbs its old 1.5px so total element
   height, text position and arrow position are all unchanged (old
   padding-bottom 3px + border-bottom 1.5px = new padding-bottom 4.5px). */
.pp-living-80-clean .pp-l80-link a,
.pp-living-80-clean .pp-l80-tour-row__link a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 15px;
  font-weight: 500;
  padding-bottom: 4.5px;
  text-decoration: none;
  background-image:
    linear-gradient(var(--pp-ink), var(--pp-ink)),
    linear-gradient(var(--pp-ink-line), var(--pp-ink-line));
  background-repeat: no-repeat, no-repeat;
  background-position: 0 100%, 0 100%;
  background-size: 0% 1.5px, 100% 1.5px;
  transition: background-size .45s var(--pp-ease);
}
.pp-living-80-clean .pp-l80-link a:hover,
.pp-living-80-clean .pp-l80-tour-row__link a:hover { background-size: 100% 1.5px, 100% 1.5px; }
/* Source only prefixes an aria-hidden arrow icon on some .link instances
   (Reserve now / Read full story / Quality and materials / More FAQ /
   View virtual tour) — See the unit stays plain text. ::before (not
   ::after) so the icon lands before the text, matching source DOM order.
   mask-image (not background-image): source's inline <svg stroke=
   "currentColor"> recolours the arrow with the link's own text colour, so
   it shifts ink->accent on hover the same as the text does. A background-
   image with a colour baked into the data URI can never do that — masking
   the same shape and painting it with background-color:currentColor
   reproduces source's actual behaviour instead of a static icon. */
.pp-living-80-clean .pp-l80-link--arrow a::before,
.pp-living-80-clean .pp-l80-tour-row__link a::before {
  content: "";
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 8h11M9 4l4 4-4 4' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 8h11M9 4l4 4-4 4' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
/* Source's "Read full story" instance carries its own inline override
   (style="border-bottom:0;padding-bottom:0") — genuinely no underline at
   all, not a bug. The underline mechanism above is now background-image,
   not border-bottom, so background-image:none is required here too or a
   1.5px line would paint flush against the (now zero-padding) text
   baseline instead of disappearing. */
.pp-living-80-clean .pp-l80-link--noborder a { padding-bottom: 0; background-image: none; }
.pp-living-80-clean .pp-l80-link--noborder.pp-l80-link--arrow a::before { width: 14px; height: 14px; }
.pp-living-80-clean .pp-l80-inline-link { border-bottom: 1.5px solid var(--pp-ink); padding-bottom: 1px; text-decoration: none; }
.pp-living-80-clean .pp-l80-inline-link--soft { border-bottom-color: var(--pp-ink-line); }
/* Quality and materials / More frequently asked questions use the bare
   source .link class (16px/9px gap/4px pad, accent hover-wipe), not
   .link--sm.link--ink like the rest of this page's text links. */
.pp-living-80-clean .pp-l80-cert-copy .pp-l80-link a,
.pp-living-80-clean .pp-l80-faq__more a {
  font-size: 16px;
  gap: 9px;
  padding-bottom: 5.5px;
  background-image:
    linear-gradient(var(--pp-accent), var(--pp-accent)),
    linear-gradient(var(--pp-ink-line), var(--pp-ink-line));
}
.pp-living-80-clean .pp-l80-faq__more a::before {
  content: "";
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 8h11M9 4l4 4-4 4' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 8h11M9 4l4 4-4 4' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
/* Quality and materials is the one .link instance in source whose arrow
   comes AFTER the text (source markup: text, then svg) — ::after, not
   ::before, unlike every other arrow-link on this page. */
.pp-living-80-clean .pp-l80-cert-copy .pp-l80-link a::after {
  content: "";
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 8h11M9 4l4 4-4 4' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 8h11M9 4l4 4-4 4' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* --- Round icon button (rail arrows) ------------------------------------ */
.pp-living-80-clean .pp-l80-iconbtn {
  position: relative;
  width: 35px;
  height: 35px;
  flex: 0 0 auto;
  border-radius: var(--pp-r-pill);
  border: 1px solid var(--pp-ink-line);
  background: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background var(--pp-t-med), color var(--pp-t-med), border-color var(--pp-t-med);
}
.pp-living-80-clean .pp-l80-iconbtn:hover { background: var(--pp-ink); color: var(--pp-bone); border-color: var(--pp-ink); }
.pp-living-80-clean .pp-l80-iconbtn:disabled { opacity: .35; cursor: default; }
.pp-living-80-clean .pp-l80-iconbtn:disabled:hover { background: transparent; color: inherit; border-color: var(--pp-ink-line); }

/* --- Tab pill (floor plan tabs, interior chips) ------------------------- */
.pp-living-80-clean .pp-l80-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 30px;
  padding: 0 14px;
  border-radius: var(--pp-r-pill);
  border: 1px solid var(--pp-ink-line);
  background: transparent;
  color: var(--pp-ink);
  font-size: 14px;
  font-weight: 500;
  font-family: inherit;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--pp-t-med), color var(--pp-t-med), border-color var(--pp-t-med);
}
.pp-living-80-clean .pp-l80-tab[aria-selected="true"],
.pp-living-80-clean .pp-l80-tab.is-active {
  background: var(--pp-ink);
  border-color: var(--pp-ink);
  color: var(--pp-bone);
}

/* --- Badge / chip -------------------------------------------------------- */
.pp-living-80-clean .pp-l80-badge {
  display: inline-flex;
  align-items: center;
  height: 26px;
  padding: 0 12px;
  border-radius: var(--pp-r-pill);
  background: var(--pp-ink);
  color: var(--pp-bone);
  font-size: 12px;
  white-space: nowrap;
}
.pp-living-80-clean .pp-l80-badge--outline {
  height: 28px;
  padding: 0 13px;
  border: 1px solid var(--pp-stone);
  background: var(--pp-bone);
  color: var(--pp-ink-72);
  letter-spacing: .04em;
}
/* Mobile-only, inherited from the accepted Milla 47 fix (v1.0.18 there):
   the "Move in ready" badge is a single fixed size at every viewport in
   source (height:28px, padding:0 13px, font-size:12px inherited from
   .badge) — reads as disproportionately large/wide against the narrow
   package card specifically below the 900px breakpoint, so this pack makes
   it more compact there only; desktop keeps the unmodified source size
   above. Scoped through .pp-l80-tier (Living 80 has no other .pp-l80-badge
   instance this could accidentally reach). */
@media (max-width: 899px) {
  .pp-living-80-clean .pp-l80-tier .pp-l80-badge--outline {
    height: 22px;
    padding: 0 9px;
    font-size: 10.5px;
  }
}

/* ==========================================================================
   Product head
   ========================================================================== */
.pp-living-80-clean .pp-l80-prod-head {
  background: var(--pp-surface);
  padding: calc(var(--pp-hdr-h) + clamp(20px, 3vw, 44px)) 0 clamp(48px, 7vw, 90px);
}
.pp-living-80-clean .pp-l80-prod-head__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  gap: clamp(28px, 4vw, 64px);
  align-items: start;
}

/* --- Gallery -------------------------------------------------------------- */
.pp-living-80-clean .pp-l80-gallery {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  border-radius: var(--pp-r-lg);
  scrollbar-width: none;
}
.pp-living-80-clean .pp-l80-gallery::-webkit-scrollbar { display: none; }
.pp-living-80-clean .pp-l80-gallery__item.wp-block-image {
  flex: 0 0 100%;
  scroll-snap-align: start;
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: var(--pp-r-lg);
  overflow: hidden;
  background: var(--pp-surface);
  margin: 0;
}
.pp-living-80-clean .pp-l80-gallery__item img { width: 100%; height: 100%; object-fit: cover; display: block; }

.pp-living-80-clean .pp-l80-gallery__controls {
  margin-top: 18px !important;
  display: flex;
  align-items: center;
  gap: 16px;
}
.pp-living-80-clean .pp-l80-dots { display: flex; gap: 6px; }
.pp-living-80-clean .pp-l80-dot {
  display: block;
  height: 3px;
  width: 14px;
  border-radius: var(--pp-r-pill);
  background: var(--pp-ink-line);
  border: 0;
  padding: 0;
  cursor: pointer;
  transition: width .3s ease, background .3s ease;
}
.pp-living-80-clean .pp-l80-dot.is-active { width: 26px; background: var(--pp-ink); }
.pp-living-80-clean .pp-l80-rail__arrows { margin-left: auto; display: flex; gap: 8px; }

/* --- Spec table ------------------------------------------------------------ */
.pp-living-80-clean .pp-l80-specs {
  margin-top: clamp(26px, 3.5vw, 34px) !important;
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--pp-ink-line);
  border-radius: var(--pp-r-sm);
  overflow: hidden;
}
.pp-living-80-clean .pp-l80-specs__item { padding: 16px 18px; }
.pp-living-80-clean .pp-l80-specs__item:nth-child(1),
.pp-living-80-clean .pp-l80-specs__item:nth-child(3) { border-right: 1px solid var(--pp-ink-line); }
.pp-living-80-clean .pp-l80-specs__item:nth-child(1),
.pp-living-80-clean .pp-l80-specs__item:nth-child(2) { border-bottom: 1px solid var(--pp-ink-line); }
.pp-living-80-clean .pp-l80-specs__label { font-size: 12.5px; color: var(--pp-ink-56); }
.pp-living-80-clean .pp-l80-specs__value { margin-top: 4px !important; font-size: 19px; font-weight: 500; }

/* --- Energy-efficiency note --------------------------------------------------
   NEW component — Milla 47 has no equivalent anywhere on its own page, so
   this is not adapted from any Milla rule. Ported from the Living 80
   source's own .energy-note (styles.css, values confirmed directly against
   that file, not estimated): a soft-green pill card with a cut-corner grade
   chip (an EU energy-label-style lozenge shape, via clip-path) and a short
   two-part sentence, bold lead-in + plain rest, matching the source's own
   <strong> markup exactly. Sits between the spec grid and the price rule,
   same position as source (.energy-note's own margin-top). */
.pp-living-80-clean .pp-l80-energy-note {
  margin-top: clamp(12px, 1.6vw, 16px) !important;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--pp-good-soft);
  border-radius: var(--pp-r-card);
}
.pp-living-80-clean .pp-l80-energy-note__grade {
  flex: 0 0 auto;
  width: 32px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  clip-path: polygon(0 0, 78% 0, 100% 50%, 78% 100%, 0 100%);
  background: var(--pp-good);
  color: var(--pp-bone);
  font-size: 15px;
  font-weight: 600;
}
.pp-living-80-clean .pp-l80-energy-note__body { margin: 0; font-size: 13px; line-height: 1.4; font-weight: 300; color: var(--pp-ink); }
.pp-living-80-clean .pp-l80-energy-note__body strong { font-weight: 500; }

/* --- Price block ------------------------------------------------------------ */
.pp-living-80-clean .pp-l80-price__rule { border-top-width: 1px; border-color: var(--pp-ink-line); margin: clamp(24px, 3vw, 30px) 0 clamp(20px, 2.4vw, 26px) !important; }
.pp-living-80-clean .pp-l80-price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 18px;
}
.pp-living-80-clean .pp-l80-price__label { flex: 1 0 100%; font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--pp-ink-56); }
.pp-living-80-clean .pp-l80-price__value { font-size: clamp(30px, 3.6vw, 40px); font-weight: 500; letter-spacing: -.024em; line-height: 1; }
.pp-living-80-clean .pp-l80-price__vat { font-size: 14px; color: var(--pp-ink-56); font-weight: 300; }
.pp-living-80-clean .pp-l80-price__note { flex: 1 0 100%; margin-top: 4px !important; font-size: 13.5px; line-height: 1.5; color: var(--pp-ink-56); font-weight: 300; }
.pp-living-80-clean .pp-l80-prod-head__copy .pp-l80-btn-row { margin-top: clamp(20px, 2.6vw, 26px) !important; }

.pp-living-80-clean .pp-l80-prod-head__title { font-size: clamp(34px, 5vw, 54px); line-height: 1.04; letter-spacing: -.024em; font-weight: 500; }
.pp-living-80-clean .pp-l80-prod-head__lead { margin-top: 16px !important; max-width: 48ch; color: var(--pp-ink-72); font-weight: 300; font-size: clamp(16px, 1.9vw, 18px); }

/* ==========================================================================
   Floor plan
   ========================================================================== */
.pp-living-80-clean .pp-l80-floorplan { margin-top: 0 !important; padding-block: var(--pp-sec-y-p); }
.pp-living-80-clean .pp-l80-floorplan__h2 { font-size: clamp(28px, 4.4vw, 46px); line-height: 1.06; letter-spacing: -.022em; font-weight: 500; max-width: 18ch; }
.pp-living-80-clean .pp-l80-floorplan__lead { margin-top: 14px !important; max-width: 44ch; font-size: clamp(15.5px, 1.8vw, 18px); line-height: 1.6; color: var(--pp-ink-72); font-weight: 300; }

/* No .pp-l80-plan-tabs rule here — Living 80 is a single floor (source has
   no ground-floor/loft tab switcher at all, unlike Milla 47's two-floor
   plan), so this pack's floor-plan section shows one plan image with no
   tab control and no dead/empty tab markup, per this round's own
   instruction not to leave an unneeded tab UI in place. */

.pp-living-80-clean .pp-l80-plan-grid__rule { border-top-width: 1px; border-color: var(--pp-ink-line); margin: clamp(22px, 3vw, 30px) 0 clamp(24px, 3vw, 36px) !important; }
.pp-living-80-clean .pp-l80-plan-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(24px, 4vw, 48px);
  align-items: start;
}
/* The plan drawing renders at its own natural size — object-fit:contain,
   not the usual cover-crop every other photo on this page uses — a wide
   technical diagram was being cut off at the sides by a standard crop
   (inherited from the same fix on Milla 47's own floor plan, source
   styles.css §12.4 — the same shared site stylesheet documents this rule
   for both product pages). Unlike Milla 47, there is only one plan image
   here (no is-active toggle needed — nothing else to switch away from). */
.pp-living-80-clean .pp-l80-plan-img { position: relative; }
.pp-living-80-clean .pp-l80-plan-img__photo.wp-block-image { margin: 0; }
.pp-living-80-clean .pp-l80-plan-img__photo img { width: 100%; height: auto; object-fit: contain; display: block; }

.pp-living-80-clean .pp-l80-plan-table {
  border: 1px solid var(--pp-ink-line);
  border-radius: var(--pp-r-sm);
  overflow: hidden;
  background: var(--pp-bone);
}
.pp-living-80-clean .pp-l80-plan-table__row-rule { border-top-width: 1px; border-color: var(--pp-ink-line); margin: 0 !important; }
.pp-living-80-clean .pp-l80-plan-table__row-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 18px;
}
.pp-living-80-clean .pp-l80-plan-table__label { font-size: 14.5px; color: var(--pp-ink-56); }
.pp-living-80-clean .pp-l80-plan-table__value { font-size: 14.5px; font-weight: 500; text-align: right; }
.pp-living-80-clean .pp-l80-plan-dl.wp-block-buttons { margin-top: clamp(20px, 2.5vw, 26px) !important; max-width: 460px; }
/* Source's download icon (script-free inline svg, before the button text) —
   reproduced the same way as the arrow-link icons elsewhere in this file
   (Master Workflow §20: RichText silently drops nested non-text elements
   from the editor's own live view, even though the frontend renders them
   fine, so a real <svg> inside this wp:button's RichText content is not a
   safe option). The button link is already display:inline-flex with its
   own gap:10px (matching source .btn's gap exactly), so the icon needs no
   extra spacing/alignment rules of its own — it lands before the text,
   vertically centered, 10px from it, for free. White stroke because this
   specific button is always the pp-btn-ink (dark-background) variant. */
.pp-living-80-clean .pp-l80-plan-dl .wp-block-button__link::before {
  content: "";
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M10 3v10m0 0 4-4m-4 4-4-4M4 16h12' fill='none' stroke='%23FFFFFF' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}


/* ==========================================================================
   Inside Living 80 (interior chips + rail)
   ========================================================================== */
.pp-living-80-clean .pp-l80-inside { margin-top: 0 !important; padding-block: var(--pp-sec-y-p); }
.pp-living-80-clean .pp-l80-inside__h2 { font-size: clamp(28px, 4.4vw, 46px); line-height: 1.06; letter-spacing: -.022em; font-weight: 500; }

.pp-living-80-clean .pp-l80-chips {
  margin-top: clamp(20px, 2.6vw, 28px) !important;
  display: flex;
  gap: 8px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  touch-action: pan-x;
}
.pp-living-80-clean .pp-l80-chips::-webkit-scrollbar { display: none; }

.pp-living-80-clean .pp-l80-interior {
  margin-top: clamp(20px, 2.6vw, 28px);
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding: 0 var(--pp-rail-pad) 6px;
  scroll-padding-left: var(--pp-rail-pad);
  scrollbar-width: none;
}
.pp-living-80-clean .pp-l80-interior::-webkit-scrollbar { display: none; }
.pp-living-80-clean .pp-l80-interior__item.wp-block-image {
  flex: 0 0 min(84%, 720px);
  scroll-snap-align: start;
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--pp-r-md);
  overflow: hidden;
  background: var(--pp-surface);
  margin: 0;
}
.pp-living-80-clean .pp-l80-interior__item img { width: 100%; height: 100%; object-fit: cover; display: block; }

.pp-living-80-clean .pp-l80-tour-row {
  margin-top: clamp(20px, 2.6vw, 28px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}
.pp-living-80-clean .pp-l80-tour-row__label { font-size: 16px; font-weight: 500; }
/* .pp-l80-tour-row__link a's styling now lives with .pp-l80-link above —
   same source class (link link--sm link--ink), merged so it gets the
   background-image hover-wipe and :hover rule it was missing here. */

/* ==========================================================================
   Packages (tiers)
   ========================================================================== */
.pp-living-80-clean .pp-l80-packages { margin-top: 0 !important; background: var(--pp-surface); padding-block: var(--pp-sec-y-p); }
.pp-living-80-clean .pp-l80-packages__h2 { font-size: clamp(28px, 4.4vw, 46px); line-height: 1.06; letter-spacing: -.022em; font-weight: 500; }
.pp-living-80-clean .pp-l80-packages__lead { margin-top: 14px !important; max-width: 46ch; font-size: clamp(15.5px, 1.8vw, 18px); line-height: 1.6; color: var(--pp-ink-72); font-weight: 300; }

.pp-living-80-clean .pp-l80-tiers {
  margin-top: clamp(26px, 3.5vw, 40px) !important;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: clamp(14px, 1.8vw, 20px);
  align-items: stretch;
}
.pp-living-80-clean .pp-l80-tier {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: clamp(22px, 2.4vw, 28px);
  border-radius: var(--pp-r-md);
  background: var(--pp-bone);
  border: 1px solid var(--pp-ink-line);
}
.pp-living-80-clean .pp-l80-tier--1 { background: color-mix(in oklab, var(--pp-bone) 35%, transparent); }
.pp-living-80-clean .pp-l80-tier--2 { background: color-mix(in oklab, var(--pp-bone) 50%, transparent); }
.pp-living-80-clean .pp-l80-tier--3 { background: var(--pp-bone); }
.pp-living-80-clean .pp-l80-tier--rec { border-color: var(--pp-ink); }
.pp-living-80-clean .pp-l80-tier__top { display: flex; flex-direction: column; gap: 6px; }
.pp-living-80-clean .pp-l80-tier__name-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* line-height:normal — same theme-interference fix as .pp-l80-faq__q
   (v1.0.13) and .pp-l80-track__step-title: a real <h3> with no explicit
   line-height inherits the active theme's own heading default instead of
   source's plain browser "normal" (source's .tier h3 also sets none). */
.pp-living-80-clean .pp-l80-tier__name { font-size: 19px; font-weight: 500; line-height: normal; letter-spacing: normal; }
/* Higher specificity than the generic body-paragraph rule below on purpose
   — a bare .pp-l80-tier__price class alone loses that fight and silently
   renders at the muted paragraph weight/colour (source styles.css §12.6). */
.pp-living-80-clean .pp-l80-tier__top .pp-l80-tier__price { color: var(--pp-ink); font-size: 17px; font-weight: 700; letter-spacing: -.01em; }
.pp-living-80-clean .pp-l80-tier__adds { margin-top: 14px !important; font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--pp-ink-56); }
/* Mobile-only, intentional deviation from source, inherited from Milla 47's
   own accepted pack (user-requested there, v1.0.18): source's .tier__adds
   ("Adds") is 12px at every viewport; this pack bumps it slightly below the
   900px breakpoint only, where it reads too small next to the rest of the
   card. Letter-spacing/uppercase/colour unchanged. Desktop keeps the
   unmodified source size. Living 80's own source shows the identical
   pattern (bare 12px .tier__adds, no breakpoint override of its own), so
   this same correction applies here for the same reason. */
@media (max-width: 899px) {
  .pp-living-80-clean .pp-l80-tier__adds { font-size: 13px; }
}
.pp-living-80-clean .pp-l80-tier__adds + .pp-l80-tier__body { margin-top: 6px !important; }
.pp-living-80-clean .pp-l80-tier p:not(.pp-l80-tier__price):not(.pp-l80-tier__adds) { font-size: 14.5px; line-height: 1.55; color: var(--pp-ink-72); font-weight: 300; }
.pp-living-80-clean .pp-l80-tier__body { margin-top: 14px !important; }

.pp-living-80-clean .pp-l80-tier-cta__rule { border-top-width: 1px; border-color: var(--pp-ink-line); margin: clamp(24px, 3vw, 32px) 0 clamp(22px, 2.6vw, 28px) !important; }
.pp-living-80-clean .pp-l80-tier-cta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  gap: 14px;
}
.pp-living-80-clean .pp-l80-tier-cta__h3 { font-size: clamp(28px, 4.4vw, 46px); line-height: 1.06; letter-spacing: -.022em; font-weight: 500; }
.pp-living-80-clean .pp-l80-tier-cta__body { margin: 0; max-width: 34ch; font-size: 14.5px; line-height: 1.55; color: var(--pp-ink-72); font-weight: 300; }
.pp-living-80-clean .pp-l80-tier-cta__btn.wp-block-buttons { align-self: stretch; }

/* No "Ready now" stock-note component here — the Living 80 source has no
   equivalent section after the package tiers (Milla 47's stock-house note
   is a Milla-only element; removed rather than carried over unused). */

/* ==========================================================================
   Visit
   ========================================================================== */
.pp-living-80-clean .pp-l80-visit { margin-top: 0 !important; padding-block: var(--pp-sec-y-p); }
.pp-living-80-clean .pp-l80-visit-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(28px, 4vw, 56px);
  align-items: stretch;
}
.pp-living-80-clean .pp-l80-visit-img.wp-block-image {
  position: relative;
  min-height: 260px;
  border-radius: var(--pp-r-lg);
  overflow: hidden;
  background: var(--pp-surface);
  margin: 0;
}
.pp-living-80-clean .pp-l80-visit-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }

.pp-living-80-clean .pp-l80-visit__h2 { font-size: clamp(28px, 4vw, 44px); line-height: 1.06; letter-spacing: -.022em; font-weight: 500; max-width: 16ch; }
.pp-living-80-clean .pp-l80-visit__lead { margin-top: 12px !important; max-width: 42ch; font-size: clamp(15.5px, 1.8vw, 17px); line-height: 1.55; color: var(--pp-ink-72); font-weight: 300; }

/* --- Four-step vertical tracker ------------------------------------------- */
.pp-living-80-clean .pp-l80-track { margin-top: clamp(22px, 2.8vw, 30px) !important; display: flex; flex-direction: column; }
.pp-living-80-clean .pp-l80-track__step {
  position: relative;
  padding: 0 0 16px 24px;
}
.pp-living-80-clean .pp-l80-track__step--last { padding-bottom: 0; }
/* Dot + connecting line, drawn per-step so no extra non-editable markup is
   needed for the rail itself (source has separate .track__rail elements;
   here each step draws its own dot via ::before and its own line via
   ::after, which is purely decorative rail chrome). Dot top:5px / line
   top:15px match source's rail exactly: a flex column (dot margin-top:5px,
   10px dot height, then the line) — not the 6px/16px this pack had before.
   The dot needs its own explicit box-sizing:border-box — this file has no
   global *, *::before, *::after border-box reset the way source's own
   styles.css does, so without it the browser default (content-box) adds
   the 1px border OUTSIDE the declared 10px width/height, rendering a true
   12px-diameter circle whose real center sits 1px right of x=5 — 1px off
   from .track__line's left:4.5px (itself already centered under a TRUE
   10px-wide box). border-box makes width/height include the border, so
   the rendered circle is genuinely 10px across and both centerlines land
   on the same x=5. */
.pp-living-80-clean .pp-l80-track__step::before {
  content: "";
  position: absolute;
  box-sizing: border-box;
  left: 0; top: 5px;
  width: 10px; height: 10px;
  border-radius: var(--pp-r-pill);
  border: 1px solid var(--pp-ink-line);
  background: var(--pp-bone);
}
.pp-living-80-clean .pp-l80-track__step--on::before { background: var(--pp-ink); border-color: var(--pp-ink); }
.pp-living-80-clean .pp-l80-track__step::after {
  content: "";
  position: absolute;
  left: 4.5px; top: 15px; bottom: 0;
  width: 1px;
  background: var(--pp-ink-line);
}
.pp-living-80-clean .pp-l80-track__step--last::after { display: none; }
/* line-height:normal is required, not decorative — without it this element
   inherits the active WordPress theme's own default paragraph line-height
   (measured live: 25.57px rendered height) instead of the plain browser
   default source's own unstyled <p> renders with (measured on source:
   23.5px). The dot itself is anchored to a fixed 5px-below-row-top offset
   (unaffected either way), but the ~2px-per-row line-height difference
   inflates every .track__step's own height, so it accumulates down all 4
   rows — each dot drifting further from its source position by the time
   the tracker reaches "Manufacture and install" (~6px of accumulated drift
   measured live before this fix). Master Workflow §44-pattern: a real
   WordPress theme default, not a Page Pack CSS value. */
.pp-living-80-clean .pp-l80-track__step-title { font-size: 15.5px; font-weight: 500; line-height: normal; color: var(--pp-ink-72); }
.pp-living-80-clean .pp-l80-track__step--on .pp-l80-track__step-title { color: var(--pp-ink); }
.pp-living-80-clean .pp-l80-track__step-note { display: block; margin-top: 3px !important; font-size: 13.5px; line-height: 1.5; color: var(--pp-ink-56); font-weight: 300; }

.pp-living-80-clean .pp-l80-visit-copy .pp-l80-btn-row { margin-top: clamp(24px, 3vw, 32px) !important; }
.pp-living-80-clean .pp-l80-visit-note { margin-top: 12px !important; font-size: 13.5px; color: var(--pp-ink-56); font-weight: 300; }

.pp-living-80-clean .pp-l80-testimonial__rule { border-top-width: 1px; border-color: var(--pp-ink-line); margin: clamp(24px, 3vw, 32px) 0 clamp(20px, 2.4vw, 26px) !important; }
.pp-living-80-clean .pp-l80-testimonial {
  display: flex;
  gap: 16px;
  align-items: flex-start;
}
.pp-living-80-clean .pp-l80-testimonial__portrait.wp-block-image {
  flex: 0 0 62px;
  width: 62px; height: 62px;
  border-radius: var(--pp-r-pill);
  overflow: hidden;
  background: var(--pp-surface);
  margin: 0;
}
.pp-living-80-clean .pp-l80-testimonial__portrait img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pp-living-80-clean .pp-l80-testimonial__quote { font-size: 15px; line-height: 1.5; max-width: 38ch; font-style: normal; }
.pp-living-80-clean .pp-l80-testimonial__who {
  margin-top: 10px !important;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  font-size: 13.5px;
  color: var(--pp-ink-56);
}
.pp-living-80-clean .pp-l80-testimonial__name { font-size: 13.5px; color: var(--pp-ink-56); }

/* ==========================================================================
   Materials — marquee + certifications
   ========================================================================== */
.pp-living-80-clean .pp-l80-materials { margin-top: 0 !important; padding-block: var(--pp-sec-y-p); overflow: hidden; }
.pp-living-80-clean .pp-l80-materials__h2 { font-size: clamp(28px, 4.4vw, 46px); line-height: 1.06; letter-spacing: -.022em; font-weight: 500; max-width: 16ch; }
.pp-living-80-clean .pp-l80-materials__lead { margin-top: 14px !important; max-width: 46ch; font-size: clamp(15.5px, 1.8vw, 18px); line-height: 1.6; color: var(--pp-ink-72); font-weight: 300; }

.pp-living-80-clean .pp-l80-marquee {
  position: relative;
  margin-top: clamp(28px, 4vw, 44px) !important;
}
.pp-living-80-clean .pp-l80-marquee__rule { border-top-width: 1px; border-color: var(--pp-ink-line); margin: 0 !important; }
.pp-living-80-clean .pp-l80-marquee__rule--top { margin-bottom: clamp(10px, 2vw, 16px) !important; }
.pp-living-80-clean .pp-l80-marquee__rule--bottom { margin-top: clamp(10px, 2vw, 16px) !important; }
.pp-living-80-clean .pp-l80-marquee__track {
  display: flex;
  width: max-content;
  animation: pp-l80-marquee 32s linear infinite;
}
.pp-living-80-clean .pp-l80-marquee:hover .pp-l80-marquee__track { animation-play-state: paused; }
.pp-living-80-clean .pp-l80-marquee__group {
  display: flex;
  align-items: center;
  gap: clamp(46px, 8vw, 100px);
  padding-right: clamp(46px, 8vw, 100px);
}
.pp-living-80-clean .pp-l80-marquee__group img,
.pp-living-80-clean .pp-l80-logo.wp-block-image { width: auto; display: block; flex: 0 0 auto; margin: 0; opacity: .72; }
.pp-living-80-clean .pp-l80-marquee__group img { opacity: .72; }
.pp-living-80-clean .pp-l80-logo--velux img, .pp-living-80-clean img.pp-l80-logo--velux { height: clamp(22px, 3vw, 30px); width: auto; }
.pp-living-80-clean .pp-l80-logo--ruukki img, .pp-living-80-clean img.pp-l80-logo--ruukki { height: clamp(20px, 2.7vw, 28px); width: auto; }
.pp-living-80-clean .pp-l80-logo--hansgrohe img, .pp-living-80-clean img.pp-l80-logo--hansgrohe { height: clamp(18px, 2.4vw, 25px); width: auto; }
.pp-living-80-clean .pp-l80-logo--tikkurila img, .pp-living-80-clean img.pp-l80-logo--tikkurila { height: clamp(20px, 2.7vw, 28px); width: auto; }

@keyframes pp-l80-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

.pp-living-80-clean .pp-l80-cert-grid {
  margin-top: clamp(34px, 4.5vw, 56px) !important;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(24px, 4vw, 56px);
  align-items: center;
}
/* No font-size/line-height/font-weight here on purpose: source's own
   typography rule for this copy is ".cert-copy p + p" (a SECOND paragraph
   adjacent to a first one) — Living 80's cert-copy has only ONE <p>, so that
   rule never actually matches it in source, and the paragraph renders at
   plain unstyled default text (no other rule in source's styles.css touches
   a bare <p>). This pack was previously restating the p+p sizing here
   unconditionally, which doesn't match what source actually renders —
   removed so this paragraph inherits the same way source's does. */
.pp-living-80-clean .pp-l80-cert-copy__body { max-width: 24ch; }
.pp-living-80-clean .pp-l80-cert-copy .pp-l80-link { margin-top: 20px !important; }
.pp-living-80-clean .pp-l80-cert-marks {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(22px, 3.2vw, 44px);
  align-items: center;
  justify-items: center;
}
.pp-living-80-clean .pp-l80-cert-mark.wp-block-image { margin: 0; }
.pp-living-80-clean .pp-l80-cert-mark img {
  max-width: 100%;
  max-height: clamp(72px, 9vw, 118px);
  width: auto; height: auto;
  display: block;
}

/* ==========================================================================
   FAQ — non-exclusive accordion (source script.js §09: exclusivity is
   opt-in via a [data-faq-exclusive] wrapper this page's FAQ does not carry
   — multiple answers may be open at once here, unlike an exclusive FAQ on
   a different page. Do not add that attribute to this section.)
   ========================================================================== */
.pp-living-80-clean .pp-l80-faq { margin-top: 0 !important; background: var(--pp-surface); padding-block: var(--pp-sec-y-p); }
.pp-living-80-clean .pp-l80-faq__h2 { font-size: clamp(28px, 4.4vw, 46px); line-height: 1.06; letter-spacing: -.022em; font-weight: 500; max-width: 16ch; }

/* margin-top matches source's own inline override on this specific
   .faq-cols instance (style="margin-top:clamp(26px,3.5vw,40px)"), not the
   larger clamp(28px,4vw,52px) the bare .faq-cols class defaults to
   elsewhere on the shared site. Needs !important: direct child of .pp-wrap,
   on this file's Flow-margin-defense reset list. */
.pp-living-80-clean .pp-l80-faq-cols {
  margin-top: clamp(26px, 3.5vw, 40px) !important;
  max-width: 1100px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr));
  gap: 0 clamp(28px, 5vw, 64px);
  align-items: start;
}
.pp-living-80-clean .pp-l80-faq-cols__rule { border-top-width: 1px; border-color: var(--pp-ink-line); margin: 0 !important; }
.pp-living-80-clean .pp-l80-faq-col { display: flex; flex-direction: column; }
.pp-living-80-clean .pp-l80-faq-row__rule { border-top-width: 1px; border-color: var(--pp-ink-line); margin: 0 !important; }

/* line-height:normal is required, not decorative — this is a real <h3>
   heading (Master Workflow §44 territory: the active theme's own global
   styles bundle a line-height with every heading level's font-family
   preset), while source's equivalent element reaches the same "no line-
   height set anywhere" state differently (.faq h3{font:inherit} strips the
   browser's own h3 default back to inherit, then the source .faq__q button
   inside it never sets line-height either, landing on plain browser
   "normal"). Without this, every FAQ question - and therefore every row's
   own height, expanded or collapsed - inflates uniformly, which is why the
   whole grid, every divider after row 1, and the final "More FAQ" gap all
   drift progressively lower despite their own spacing values already
   matching source exactly. */
.pp-living-80-clean .pp-l80-faq__q {
  position: relative;
  margin: 0;
  padding: 20px 28px 20px 0;
  font: inherit;
  font-size: 16px;
  font-weight: 500;
  line-height: normal;
  letter-spacing: normal;
  cursor: pointer;
  transition: color .2s;
}
.pp-living-80-clean .pp-l80-faq__q:hover { color: var(--pp-accent); }
.pp-living-80-clean .pp-l80-faq__q::after {
  content: "+";
  position: absolute;
  right: 0;
  top: 20px;
  width: 20px;
  font-size: 20px;
  line-height: 1;
  font-weight: 300;
  color: var(--pp-ink-56);
  text-align: right;
}
.pp-living-80-clean .pp-l80-faq-row--open .pp-l80-faq__q::after { content: "\2212"; }

.pp-living-80-clean .pp-l80-faq__a {
  margin: 0 !important;
  padding: 0 0 22px;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--pp-ink-72);
  font-weight: 300;
  max-width: 52ch;
  display: none;
}
.pp-living-80-clean .pp-l80-faq-row--open .pp-l80-faq__a { display: block; }

.pp-living-80-clean .pp-l80-faq__more { margin-top: clamp(40px, 5vw, 52px) !important; }


/* ==========================================================================
   Closing split CTA
   ========================================================================== */
/* Source's .cta-split carries no top spacing of its own — the visible gap
   after FAQ is entirely FAQ's own bottom padding-block. This section is a
   direct child of the page's single alignfull wp:group wrapper alongside
   every other top-level section, none of which neutralize WordPress's
   default Flow margin-block-start injection on "* + *" — margin-top:0
   !important reproduces source's actual (implicit) zero rather than
   whatever blockGap the active theme injects between sections here. */
.pp-living-80-clean .pp-l80-cta-split {
  display: flex;
  flex-direction: column;
  margin-top: 0 !important;
  --pp-split-h: clamp(300px, 68vw, 400px);
}
.pp-living-80-clean .pp-l80-cta-split__media {
  position: relative;
  height: var(--pp-split-h);
  background: var(--pp-tint);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.pp-living-80-clean .pp-l80-cta-split__render.wp-block-image { margin: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
.pp-living-80-clean .pp-l80-cta-split__render img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: clamp(24px, 5vw, 56px);
  box-sizing: border-box;
}
/* box-sizing:border-box is load-bearing here, not decorative — source's
   universal *{box-sizing:border-box} reset (styles.css line 116) has no
   equivalent in this file (Master Workflow §7.1: added per-element only
   where proven necessary, not as a global reset). Without it, this panel's
   desktop flex:1 1 50% (below) targets the CONTENT box, so its own padding
   (clamp(36,6vw,72) block + clamp(56,6vw,112) left at desktop) is added on
   top of that 50% instead of living inside it — the resulting overflow
   forces flexbox to shrink BOTH this panel and its sibling .cta-split__media
   to fit, taking the padding-free media panel down with it even though
   nothing about the media panel itself is wrong. That is the actual
   mechanism behind "the house render is too small with excess lavender
   space above it": the render's own container was never the full 50% share
   source gives it. */
.pp-living-80-clean .pp-l80-cta-split__body {
  min-height: var(--pp-split-h);
  padding: clamp(36px, 6vw, 72px) var(--pp-gutter);
  background: var(--pp-bone);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  box-sizing: border-box;
}
.pp-living-80-clean .pp-l80-cta-split__h2 { font-size: clamp(28px, 5vw, 48px); line-height: 1.06; letter-spacing: -.022em; font-weight: 400; }
.pp-living-80-clean .pp-l80-cta-split__lead { margin-top: 14px !important; max-width: 46ch; color: var(--pp-ink-72); font-size: clamp(15.5px, 1.9vw, 18px); line-height: 1.55; font-weight: 300; }
/* Needs !important: .pp-l80-cta-split__body is on this file's Flow-margin-
   defense reset list (its own direct children's margin-block-start is
   zeroed !important), so this button row's own legitimate margin-top was
   being silently zeroed the same way .pp-l80-specs and five other rules
   were in v1.0.3 — the exact "subtitle sits too close to the first CTA"
   symptom reported for this section. */
.pp-living-80-clean .pp-l80-cta-split__body .pp-l80-btn-row { margin-top: clamp(24px, 3vw, 32px) !important; }

/* ==========================================================================
   Desktop layer — the design's single breakpoint (min-width: 900px)
   Preserved exactly at the source's own 900px cut, not Gutenberg's built-in
   782px default (Master Workflow §7.6/§46) — tested at 901/899.
   ========================================================================== */
@media (min-width: 900px) {
  .pp-living-80-clean .pp-l80-plan-grid { grid-template-columns: 2fr 1fr; align-items: center; }

  .pp-living-80-clean .pp-l80-visit-grid { grid-template-columns: 1fr 1fr; }
  .pp-living-80-clean .pp-l80-visit-img.wp-block-image { min-height: 100%; }

  .pp-living-80-clean .pp-l80-cert-grid { grid-template-columns: .85fr 1.3fr; align-items: end; }

  .pp-living-80-clean .pp-l80-faq-cols { grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr)); gap: 0 clamp(30px, 5vw, 72px); }

  .pp-living-80-clean .pp-l80-cta-split { flex-direction: row; }
  .pp-living-80-clean .pp-l80-cta-split__media,
  .pp-living-80-clean .pp-l80-cta-split__body { flex: 1 1 50%; min-width: 0; }
  .pp-living-80-clean .pp-l80-cta-split__media { height: auto; }
  .pp-living-80-clean .pp-l80-cta-split__body {
    min-height: 0;
    align-items: flex-start;
    text-align: left;
    padding-left: clamp(56px, 6vw, 112px);
  }

  /* Same grid as .pp-l80-tiers above it — not just three items in a row,
     but headline/subtext/button sharing the tier cards' own column lines
     (source styles.css §12.6 + README's "Make it yours" note). */
  .pp-living-80-clean .pp-l80-tier-cta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
    align-items: center;
    text-align: left;
    gap: clamp(14px, 1.8vw, 20px);
  }
  .pp-living-80-clean .pp-l80-tier-cta__body { max-width: none; }
  .pp-living-80-clean .pp-l80-tier-cta__btn.wp-block-buttons { align-self: center; width: 100%; justify-content: center; }
}


/* ==========================================================================
   Reduced motion
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .pp-living-80-clean .pp-l80-marquee__track { animation-duration: .001ms !important; animation-iteration-count: 1 !important; }
  .pp-living-80-clean .pp-l80-gallery,
  .pp-living-80-clean .pp-l80-interior,
  .pp-living-80-clean .pp-l80-chips { scroll-behavior: auto; }
}
