/* KoreDetail — luxury pricing cards.
 * Restyles the price + feature blocks that reveal.js/index.html emit as
 * .kore-price / .kore-feats inside each [data-framer-name="Package Card"].
 * Matches the site tokens: Inter (sans), Bodoni Moda (serif), gold #9B7A3F.
 */
html {
  overscroll-behavior: none;  /* desktop: no rubber-band past the page ends */
  /* iOS shows the html background behind toolbars and bounce zones: cream up top, footer-dark below */
  background: linear-gradient(to bottom, #FFFFFF 0%, #FFFFFF 50%, #131210 50%, #131210 100%);
  scrollbar-width: none;      /* Firefox */
}
/* The page scrollbar is chrome the design doesn't want: a grey gutter down the right edge cuts
   the full-bleed hero. Scrolling itself is untouched -- wheel, trackpad, touch, keyboard,
   Space/PageDn/Home/End all still scroll; only the painted bar goes. Same pattern .krv-track
   already uses. Side effect worth knowing: 100vw now equals the content width, so the hero
   breakout further down lands exactly instead of overhanging into `overflow-x: clip`. */
html::-webkit-scrollbar { display: none; }   /* Chromium, Safari */

:root {
  /* Section breathing. Sections sit flush, so the gap between any two is
     bottom(prev) + top(next) = 2x this value. Was 96/18/0/88/76/88/52/52 -> gaps of
     96, 18, 164 and 140px, which reads as four unrelated decisions. */
  --kore-band: 64px;
  --kore-gold: #9B7A3F;
  --kore-gold-text: #82662F; /* darkened gold for <18px text on cream: 4.78:1 on #f4f1ea, 4.96:1 on #f8f5ee (WCAG 4.5 floor) */
  --kore-gold-line: rgba(155, 122, 63, .22);
  --kore-ink: #171715;
  --kore-veh: #6D665A;
  --kore-feat: #514D45;
  --kore-mute: #8A837722;
  --kore-hair: rgba(30, 30, 28, .1);
  /* Required marker. Brick rather than a pure red so it sits with the gold:
     6.5:1 on white, 6.0:1 on the cream panel -- both clear of the 4.5 floor. */
  --kore-req: #B3261E;
  /* Selected fill. The old rgb(252,250,245) was ~2% off white and read as
     nothing next to a dimmed step. */
  --kore-pick: #F3EBDA;
  /* One family for the whole site. Both tokens survive because 69 rules name them and the
     distinction is still real -- it is just no longer a change of typeface. --kore-display
     means "set this heavier and tighter", which .kore-display below does. */
  --kore-sans: "Archivo", "Archivo Fallback", system-ui, sans-serif;
  --kore-serif: var(--kore-sans);
}

/* ---------- card layout: top-align so titles/lists line up across all cards ---------- */
/* Framer sets justify-content:space-between, so shorter cards spread their content
   vertically (Tier 3's title/list drop). Pack from the top; slack falls to the bottom. */
[data-framer-name="Package Card"] {
  justify-content: flex-start !important;
  gap: 18px !important;   /* desktop had no gap (relied on space-between); restores even rail/section spacing */
}
/* Smaller service title (was 30px). */
[data-framer-name="Package Name"] h3 {
  font-size: 22px !important;
}
/* Reserve a two-line title zone so every price grid + list starts at the same level,
   even when a title wraps (e.g. Tier 06 "Paint Enhancement + Ceramic Coating"). */
[data-framer-name="Package Name"] {
  min-height: 46px !important;
}
/* Pin the CTA to the bottom so every SELECT PACKAGE button sits at the same level. */
[data-framer-name="Select Package"] {
  margin-top: auto !important;
}

/* ---------- faint rough-paper texture (same cream color, self-contained SVG grain) ---------- */
[data-framer-name="Package Card"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='kpaper'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23kpaper)' opacity='0.05'/%3E%3C/svg%3E");
  background-size: 160px 160px;
  background-repeat: repeat;
  background-blend-mode: multiply;   /* grain darkens into the cream like paper fibre, never lightens it */
}

/* ---------- price grid (aligned, even) ---------- */
[data-framer-name="Package Card"] .kore-price {
  display: flex;
  flex-direction: column;
  width: 100%;
  margin: 4px 0 2px;
}
[data-framer-name="Package Card"] .kp-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: .9rem;
  padding: .74rem .1rem;
}
[data-framer-name="Package Card"] .kp-row + .kp-row {
  border-top: 1px solid var(--kore-gold-line);
}
[data-framer-name="Package Card"] .kp-size {
  display: none;
}
[data-framer-name="Package Card"] .kp-veh {
  font: 600 .75rem/1.2 var(--kore-sans);
  text-transform: uppercase;
  letter-spacing: .14em;
  color: var(--kore-veh);
}
[data-framer-name="Package Card"] .kp-price {
  text-align: right;
  line-height: 1.1;
}
[data-framer-name="Package Card"] .kp-amt {
  display: block;
  font: 500 1.18rem/1 var(--kore-serif);
  color: var(--kore-ink);
  font-variant-numeric: tabular-nums;
}
[data-framer-name="Package Card"] .kp-dur {
  display: block;
  margin-top: 4px;
  /* was .62rem (9.9px) at #8A8377 = 3.45:1 — under the 4.5 floor and below any
     legibility minimum, on the line that justifies the price. */
  font: 500 .72rem/1 var(--kore-sans);
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--kore-veh);
}

/* ---------- feature list (clean, hairline gold markers) ---------- */
[data-framer-name="Package Card"] .kore-feats {
  list-style: none;
  margin: .5rem 0 0;
  padding: 1.1rem 0 0;
  width: 100%;
  border-top: 1px solid var(--kore-hair);
  display: flex;
  flex-direction: column;
  gap: .62rem;
}
[data-framer-name="Package Card"] .kore-feats li {
  position: relative;
  padding-left: 1.2rem;
  font: 400 .86rem/1.5 var(--kore-sans);
  color: var(--kore-feat);
}
[data-framer-name="Package Card"] .kore-feats li.kf-gold { color: var(--kore-gold-text); font-weight: 700; }
[data-framer-name="Package Card"] .kore-feats li.kf-gold::before { background: var(--kore-gold); }
[data-framer-name="Package Card"] .kore-feats li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .66em;
  transform: translateY(-50%);
  width: .3rem;
  height: .3rem;
  background: var(--kore-ink);
}

/* ---------- signature gloss sweep: light raking across coated paint (buttons, one pass per hover) ---------- */
[data-framer-name="See What Your Car Needs"],
[data-framer-name="Select Package"],
[data-framer-name="Ask a Question"] {
  position: relative;
  overflow: hidden;
}
[data-framer-name="See What Your Car Needs"]::before,
[data-framer-name="Select Package"]::before,
[data-framer-name="Ask a Question"]::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 42%, rgba(255, 255, 255, 0.34) 50%, transparent 58%);
  transform: translateX(-70%);
}
[data-framer-name="See What Your Car Needs"]:hover::before,
[data-framer-name="Select Package"]:hover::before,
[data-framer-name="Ask a Question"]:hover::before { animation: koreGloss .5s ease; }
@keyframes koreGloss { to { transform: translateX(70%); } }
@media (prefers-reduced-motion: reduce) {
  [data-framer-name="See What Your Car Needs"]:hover::before,
  [data-framer-name="Select Package"]:hover::before,
  [data-framer-name="Ask a Question"]:hover::before { animation: none; }
}

/* ---------- button micro-interaction (markup unchanged) ---------- */
[data-framer-name="Select Package"] {
  transition: transform .25s ease, box-shadow .25s ease, background-color .25s ease;
}
[data-framer-name="Select Package"]:hover {
  transform: translateY(-1px);
  box-shadow: 0 10px 24px rgba(30, 30, 28, .18);
}
[data-framer-name="Select Package"] svg {
  transition: transform .25s ease;
}
[data-framer-name="Select Package"]:hover svg {
  transform: translateX(3px);
}

@media (prefers-reduced-motion: reduce) {
  [data-framer-name="Select Package"],
  [data-framer-name="Select Package"] svg { transition: none; }
}

/* ---------- card presentation tilt: cursor-tracked 3D bend on the six package cards and the
   add-ons ledger. reveal.js drives rotateX/rotateY from the mouse position (the card yields
   under the cursor); this block supplies the smoothing transition and the gold-warmed hover
   shadow. Desktop pointers only. No transform here — a :hover transform (or any !important
   transform) would override the JS inline style and freeze the tracking. The reduced-motion
   transform guard below DOES use !important deliberately: stylesheet !important beats inline
   style, so it kills the tilt even if the JS gate were ever bypassed. ---------- */
@media (hover: hover) and (pointer: fine) {
  [data-framer-name="Package Card"],
  [data-framer-name="Add-ons"] {
    transition: transform .15s ease-out, box-shadow .25s ease;
  }
  [data-framer-name="Package Card"]:hover,
  [data-framer-name="Add-ons"]:hover {
    box-shadow: 0 24px 52px rgba(30, 30, 28, .15), 0 2px 12px rgba(155, 122, 63, .18) !important;
  }
}
@media (prefers-reduced-motion: reduce) {
  [data-framer-name="Package Card"],
  [data-framer-name="Add-ons"] { transition: none; }
  [data-framer-name="Package Card"]:hover,
  [data-framer-name="Add-ons"]:hover { transform: none !important; }
}

/* ---------- add-on list: hover feedback (gold wash + growing accent bar + pill deepen) ---------- */
[data-framer-name="Add-on Row"] {
  position: relative;
  border-radius: 2px;
  transition: background-color .25s ease, padding-left .25s ease;
}
[data-framer-name="Add-on Row"]::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 2px;
  height: 0;
  background: #A78A55;
  transform: translateY(-50%);
  transition: height .25s ease;
}
[data-framer-name="Add-on Row"]:hover {
  background-color: rgba(185, 151, 88, .08);
  padding-left: 12px;
}
[data-framer-name="Add-on Row"]:hover::before {
  height: 56%;
}
[data-framer-name="Add-on Price"] mark {
  transition: background-color .25s ease;
}
[data-framer-name="Add-on Row"]:hover [data-framer-name="Add-on Price"] mark {
  background-color: rgba(185, 151, 88, .2) !important;
}

@media (prefers-reduced-motion: reduce) {
  [data-framer-name="Add-on Row"],
  [data-framer-name="Add-on Row"]::before,
  [data-framer-name="Add-on Price"] mark { transition: none; }
}

/* ---------- subtract the gold rules: airier, less "template" (whitespace + type separate) ---------- */
/* All the card/block top rails. */
[data-framer-name="Gold Detail Rail"] {
  display: none !important;
}
/* Full-width gold section dividers -> gone; sections breathe on whitespace.
   (Zeroes the gold top border; card/button box-outlines are untouched.) */
[data-framer-name="Detailing Packages"],
[data-framer-name="Studio Close"],
[data-framer-name="Add-ons and Service Area"] {
  --border-top-width: 0px !important;
}

/* ---------- the one typeface ----------
   Archivo, variable, self-hosted: weight 100-900 and width 62-125 in a single 88KB file,
   latin subset. That replaces 22 files and 613KB of Inter subsets plus Bodoni cuts.
   Self-hosted rather than linked from Google so the page still makes no third-party request
   and the file can be preloaded from the same origin. */
@font-face {
  font-family: "Archivo";
  src: url("../assets/fonts/archivo-var.woff2") format("woff2");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
  /* latin only -- everything the site sets in Archivo lives here. The stars and arrows
     (U+2605, U+2192) fall through to a system face, exactly as they did under Inter. */
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
/* The face it swaps in from. Measured at 100px on the hero string, Archivo against Arial:
   99.98% at weight 400 and 100.13% at 700 -- Arial is a near-exact metric twin, so no
   size-adjust is needed at all. Only the vertical metrics differ: Archivo's ascent is
   0.880em against Arial's 0.910, descent 0.210 against 0.210. Overriding those two is what
   stops the line boxes changing height when the real file lands.
   This is also why the headline is set at the default width rather than the narrower wdth 92
   the comparison used: Arial has no width axis, so a hero set narrow would swap in from
   something 6.5% too wide, and under white-space:nowrap that overflows the column. */
@font-face {
  font-family: "Archivo Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans"), local("Roboto");
  ascent-override: 88%;
  descent-override: 21%;
  line-gap-override: 0%;
}

/* ---------- hero background video + matching still (dimmed, blends with cream) ----------
   .kore-hero-still is a browser-render-matched JPEG of frame 0 layered over the video; it
   fades only after playback provably advances, so the poster->video handoff can never flash. */
.kore-hero-video,
.kore-hero-still {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  opacity: var(--hero-video-opacity, 0.72);
  z-index: 0;
  pointer-events: none;
  /* One seamless smoothstep ramp, zero slope at both ends -- no kink for the eye
     to catch. Full strength down to 32%, then out to NOTHING at the bottom edge,
     which is what makes the hero meet the next section without a seam: the last
     row of the hero is whatever the page itself paints there. Shared by both
     themes; dark used to switch this off and rebuild it as a scrim. */
  -webkit-mask-image: linear-gradient(180deg,
    #000 0%, #000 32%,
    rgba(0,0,0,1) 32%, rgba(0,0,0,0.957) 40.5%, rgba(0,0,0,0.844) 49%,
    rgba(0,0,0,0.684) 57.5%, rgba(0,0,0,0.5) 66%, rgba(0,0,0,0.316) 74.5%,
    rgba(0,0,0,0.156) 83%, rgba(0,0,0,0.043) 91.5%, rgba(0,0,0,0) 100%);
          mask-image: linear-gradient(180deg,
    #000 0%, #000 32%,
    rgba(0,0,0,1) 32%, rgba(0,0,0,0.957) 40.5%, rgba(0,0,0,0.844) 49%,
    rgba(0,0,0,0.684) 57.5%, rgba(0,0,0,0.5) 66%, rgba(0,0,0,0.316) 74.5%,
    rgba(0,0,0,0.156) 83%, rgba(0,0,0,0.043) 91.5%, rgba(0,0,0,0) 100%);
}
/* The still is no longer downloaded on the normal path -- the <img> ships with no
   src and the video paints first. It is still the right answer for the three cases
   where there will be no video: reduced motion, Save-Data, and refused autoplay.
   Delivering it as a CSS background inside those conditions means the bytes are
   requested only when one of them is actually true. */
html.kore-no-video .kore-hero-still,
.kore-hero-still.kore-still-fallback {
  background-image: url("../assets/hero-v4-poster.jpg");
  background-size: cover;
  background-position: center;
}
@media (prefers-reduced-motion: reduce) {
  .kore-hero-still {
    background-image: url("../assets/hero-v4-poster.jpg");
    background-size: cover;
    background-position: center;
  }
}
.kore-hero-still { transition: opacity .25s ease; }
.kore-hero-still.kore-still-gone { opacity: 0; }
@media (prefers-reduced-motion: reduce) { .kore-hero-still { transition: none; } }
/* Desktop: no scrim layer — a second overlapping gradient is where visible seams come from.
   The veil is the video mask alone (hidden video reveals the cream body). Mobile re-adds
   its own vertical scrim in the media query below. */
.kore-hero-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: none;
}
[data-framer-name="Welcome Copy"] { position: relative; z-index: 2; max-width: 440px; }  /* narrower so the video reads earlier from the left */
/* The subline ships as rgba(30,30,28,.7), which over the video measured 1.86:1 on desktop
   and 1.48:1 on mobile. Framer feeds the colour through a variable, so the override goes
   on the variable. Full-strength ink also survives a darker video frame; 70% grey cannot. */
[data-framer-name="Welcome Body"] p { --framer-text-color: #171715 !important; }
/* top-left brand lockup — replaces the gold wordmark that was buried in the hero copy */
[data-framer-name="KoreDetail Wordmark"] { display: none !important; }
.kore-brand {
  position: absolute; top: 30px; left: 64px; z-index: 3;
  display: flex; align-items: center; gap: 14px;
  pointer-events: none;
}
.kore-brand-logo { width: 88px; height: auto; display: block; }
.kore-brand-name { font: 800 .82rem/1 var(--kore-sans); letter-spacing: .24em; color: var(--kore-ink); }
@media (max-width: 1199px) {
  .kore-brand { top: 22px; left: 20px; }
  .kore-brand-logo { width: 72px; }
}
/* reviews chapter — same anatomy as the menu and map chapters, quotes as an editorial ledger.
   Sits on the ink ground on purpose: everything from the map to the contact block was one
   unbroken white field (measured: 3,240px at chroma 0), and gold only reads as gold on dark. */
.kore-reviews { width: 100%; flex: 0 0 auto; background: var(--kore-ink); }
.krv-in { max-width: 1200px; margin: 0 auto; padding: var(--kore-band) 64px; }
.krv-eyebrow { font: 700 11px/1 var(--kore-sans); letter-spacing: .22em; color: #B99758; margin: 0 0 14px; }
.krv-title { font: 500 clamp(30px, 3.4vw, 42px)/1.15 var(--kore-serif); color: #F4F1EA; margin: 0 0 14px; }
.krv-wrap { position: relative; }
.krv-track {
  display: flex; gap: 0;
  overflow-x: auto; scroll-snap-type: x mandatory;
  padding: 10px calc(50% - min(200px, 42%)) 14px;   /* lets the first and last card reach dead center */
  scrollbar-width: none;
}
.krv-track::-webkit-scrollbar { display: none; }
.krv-item {
  flex: 0 0 min(400px, 84%);
  /* A flex item's default min-width:auto lets it outgrow its own basis to fit min-content.
     The head row's widest name ("Raymond Castorena") did exactly that below ~600px, which
     made the two rails different widths -- and two rails that are different widths cannot
     stay on the same review. Pin the basis; the name ellipsises instead. */
  min-width: 0;
  margin: 0 -30px;                  /* neighbors tuck behind the centered card */
  position: relative;
  scroll-snap-align: center;
  will-change: transform;
  transform-origin: center center;
  display: flex; flex-direction: column;
  --krv-far: 0;                     /* 0 = dead centre, 1 = fully receded; written by reveal.js */
}
/* Recede by dimming the CONTENTS, never the card. Dimming the card made it
   translucent, and because each item tucks 30px under its neighbour you could
   read the next review straight through this one. The bubble stays opaque so
   there is nothing to see through; only what is printed on it fades. */
.krv-bubble > * { opacity: calc(1 - var(--krv-far) * 0.62); }
.krv-bubble {
  position: relative; margin: 0 0 18px;
  flex: 1 1 auto; min-height: var(--krv-card-h, auto);
  background: #1F1F1D;
  border: 1px solid rgba(185, 151, 88, 0.30);
  border-radius: 6px;
  padding: 24px 26px 22px;
  box-shadow: rgba(0, 0, 0, 0.45) 0px 16px 40px 0px;
}
.krv-bubble::after {
  content: ""; position: absolute; left: 32px; bottom: -7px;
  width: 12px; height: 12px;
  background: #1F1F1D;
  border-right: 1px solid rgba(185, 151, 88, 0.30);
  border-bottom: 1px solid rgba(185, 151, 88, 0.30);
  transform: rotate(45deg);
}
/* stars left, attribution right, one baseline -- the caption for the quote below it */
.krv-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; margin: 0 0 14px;
}
.krv-stars { color: #B99758; font-size: 13px; letter-spacing: 4px; margin: 0; flex: 0 0 auto; }
.krv-bubble blockquote {
  margin: 0; font: 400 .92rem/1.62 var(--kore-sans); color: rgba(244, 241, 234, 0.82);
  /* No clamp: a card is as tall as its review. Truncating mid-sentence is worse than a tall
     card, and the Google set is picked so nothing on that rail runs long in the first place. */
}
.krv-who { display: flex; align-items: center; gap: 9px; min-width: 0; flex: 0 1 auto; }
.krv-ava {
  width: 30px; height: 30px; border-radius: 50%; object-fit: cover; display: block;
  border: 1px solid rgba(185, 151, 88, 0.38); flex: 0 0 auto;
}
.krv-ava--mono {
  display: grid; place-items: center;
  font: 700 12px/1 var(--kore-sans); color: #171715;
  /* ink on --kore-gold (#9B7A3F) is 4.49:1 -- short of the floor by a hair,
     the same miss as the CTA and the gold map label. #B99758 is 6.52:1. */
  background: #B99758;
}
.krv-name {
  font: 700 .7rem/1.2 var(--kore-sans); letter-spacing: .09em; text-transform: uppercase;
  color: #F4F1EA; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.krv-link { display: inline-block; margin: 0 0 38px; font: 600 .8rem/1 var(--kore-sans); letter-spacing: .08em; color: #B99758; text-decoration: none; border-bottom: 1px solid rgba(185, 151, 88, 0.38); padding-bottom: 4px; transition: color .2s ease; }
.krv-link:hover, .krv-link:focus-visible { color: #F4F1EA; }
/* ---------- ring mode ----------
   Eighteen cards on a circle 20 degrees apart, so the ring closes at exactly 360 and can turn
   forever with no end to hit and no seam to hide. Only the centre card is meant to be READ --
   it sits at 0 degrees, upright and fully opaque; its neighbours run away down the arc and are
   gone by the third step. That is the whole trick: the fan is texture, the middle is content.

   Everything here is gated behind .krv-is-ring, which reveal.js adds. Without JS the cards stay
   the plain horizontal scroll rail defined above, which a visitor can still drag and read.

   Geometry lives in reveal.js because it depends on the measured card box: x = R*sin(t),
   y = R*(1-cos(t)). Note y/x = tan(t/2) no matter what R is, so the arc's drop is fixed by the
   step angle alone -- a wider radius spreads the cards out but cannot flatten the curve. */
.krv-is-ring {
  --krv-card-w: min(340px, 72vw);
  /* The rim feather has to stop dead before the centre card, or it eats the edges of the one
     card that must stay at full strength. So it is exactly the gutter outside that card,
     capped at 90px -- roomy on a desktop, and about 40px on a phone, which is all there is. */
  --krv-feather: min(90px, max(0px, 50vw - var(--krv-card-w) / 2 - 6px));
}
.krv-is-ring .krv-track {
  display: block; position: relative;
  height: var(--krv-ring-h, 620px);
  padding: 0; overflow: hidden;
  scroll-snap-type: none;
  /* horizontal drag belongs to the ring; vertical still scrolls the page */
  touch-action: pan-y;
  cursor: grab;
  /* Full-bleed, using the same 100vw breakout as the hero layers. The fan is ~1310px wide at
     1440 and the content column is 1072, so a track sized to the column cut the outer cards
     off with a visible vertical edge INSIDE the page. Widened to the viewport, the outer
     cards simply end before they get anywhere near it; anything narrow enough for them to
     reach the rim meets the feather below instead of a straight edge. */
  width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--krv-feather),
    #000 calc(100% - var(--krv-feather)), transparent 100%);
          mask-image: linear-gradient(to right, transparent 0, #000 var(--krv-feather),
    #000 calc(100% - var(--krv-feather)), transparent 100%);
}
.krv-is-ring .krv-track:active { cursor: grabbing; }
.krv-is-ring .krv-track:focus { outline: none; }
.krv-is-ring .krv-track:focus-visible { outline: 2px solid #B99758; outline-offset: 6px; }

.krv-is-ring .krv-item {
  position: absolute; left: 50%; top: 0;
  width: var(--krv-card-w);
  height: var(--krv-card-h, auto);
  flex: none; margin: 0; min-width: 0;
  scroll-snap-align: none;
  transform-origin: center center;
  backface-visibility: hidden;
  will-change: transform;
}
/* The veil sits over the whole card box, so it covers the speech tail as well -- filter used
   to darken that and a bubble-level overlay would have left it lit. Over the transparent parts
   of the box it paints ground on ground, which is invisible. Ink in both themes: the reviews
   chapter is on the dark ground even in light mode. */
.krv-is-ring .krv-veil {
  position: absolute; inset: 0;
  background: var(--d-ground, #0D0B08);
  opacity: 0;
  pointer-events: none;
  z-index: 3;
  will-change: opacity;
}
/* the item carries the height now, and the card fades as a whole rather than dimming its
   own contents -- so the per-element recede from the rail layout has to be switched off or
   the two multiply and the neighbours vanish a step early */
.krv-is-ring .krv-bubble {
  min-height: 0;
  display: flex; flex-direction: column;
}
.krv-is-ring .krv-bubble > * { opacity: 1; }
/* Every card is pinned to the tallest review's height, so a short quote would otherwise hang
   from the top of a mostly empty card. Centred, the space reads as margin instead of a hole. */
.krv-is-ring .krv-bubble blockquote { margin: auto 0; }
/* a drag that starts on a card must not select its text */
.krv-is-ring .krv-track { -webkit-user-select: none; user-select: none; }

/* The position is announced rather than drawn: no visible control, but a screen reader still
   hears which review is centred when the ring turns. */
.krv-live {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
@media (max-width: 810px) {
  .krv-in { padding: var(--kore-band) 20px; }
  /* The head row is stars + name on one line inside a card that is only ~250px wide on a
     phone. Every part of it gives back a few pixels so the name survives: measured, an
     untrimmed row left "Allison T." with 68px and clipped it. */
  .krv-bubble { padding: 20px 18px 18px; }
  .krv-head { gap: 8px; margin-bottom: 12px; }
  .krv-stars { font-size: 11px; letter-spacing: 2px; }
  .krv-who { gap: 7px; }
  .krv-ava { width: 26px; height: 26px; }
  .krv-ava--mono { font-size: 11px; }
  .krv-name { font-size: .62rem; letter-spacing: .05em; }
}
/* Phone-sized cards. Every card is pinned to the tallest review, so the only lever that moves
   the whole set is how many lines that one review takes -- a smaller face and tighter leading
   pull lines out of it and the other seventeen follow it down. Widening the card would help
   too but costs the peek at the neighbours, which is the whole fan. */
@media (max-width: 640px) {
  .krv-is-ring { --krv-card-w: min(300px, 78vw); }
  .krv-is-ring .krv-bubble { padding: 13px 13px 12px; }
  .krv-is-ring .krv-head { margin-bottom: 9px; }
  .krv-is-ring .krv-bubble blockquote { font-size: .74rem; line-height: 1.48; }
  .krv-is-ring .krv-ava { width: 22px; height: 22px; }
  .krv-is-ring .krv-ava--mono { font-size: 10px; }
  .krv-is-ring .krv-name { font-size: .56rem; }
  .krv-is-ring .krv-stars { font-size: 10px; letter-spacing: 1.5px; }
}
@media (prefers-reduced-motion: reduce) { .krv-link { transition: none; } }

/* footer sections go full-bleed so the dark bottom is one edge-to-edge block;
   padding keeps their content on the 1200px column */
[data-framer-name="Studio Close"],
[data-framer-name="KoreDetail Footer"] {
  max-width: none !important;
  width: 100% !important;
  padding-left: max(64px, calc(50vw - 536px)) !important;
  padding-right: max(64px, calc(50vw - 536px)) !important;
}
@media (max-width: 810px) {
  [data-framer-name="Studio Close"],
  [data-framer-name="KoreDetail Footer"] {
    padding-left: 20px !important;
    padding-right: 20px !important;
  }
}

/* footer contact block — sits on the footer surface above the brand bar */
.kore-footer-info { width: 100%; flex: 0 0 auto; background: #1E1E1C; border-bottom: 1px solid rgba(244, 241, 234, 0.08); }
.kfi-in { max-width: 1200px; margin: 0 auto; padding: 44px 64px; display: grid; grid-template-columns: repeat(4, 1fr); gap: 36px; }
.kfi-item { display: flex; flex-direction: column; gap: 10px; }
.kfi-label { font: 700 10px/1 var(--kore-sans); letter-spacing: .22em; color: #B99758; }
.kfi-value { font: 400 15px/1.55 var(--kore-sans); color: rgba(244, 241, 234, 0.85); text-decoration: none; }
a.kfi-value { transition: color .2s ease; }
a.kfi-value:hover, a.kfi-value:focus-visible { color: #B99758; }
@media (max-width: 810px) { .kfi-in { grid-template-columns: 1fr 1fr; padding: 36px 20px; gap: 28px; } }
@media (max-width: 480px) { .kfi-in { grid-template-columns: 1fr; } }
@media (prefers-reduced-motion: reduce) { a.kfi-value { transition: none; } }

/* footer: leave-a-review link, right side, mirrors the brand line's type */
.kore-review {
  margin-left: auto;
  display: flex; align-items: center; gap: 8px;
  font: 600 11px/1 var(--kore-sans); letter-spacing: 1.8px;
  /* matches the "KORE DETAIL" brand line at the other end of the same bar,
     which computes to pure white -- at 72% cream this read as the dimmer of
     a pair that should be one value */
  color: #FFFFFF; text-decoration: none;
  transition: color .2s ease;
}
.kore-review svg { width: 13px; height: 13px; fill: currentColor; display: block; }
.kore-review:hover, .kore-review:focus-visible { color: #B99758; }
@media (prefers-reduced-motion: reduce) { .kore-review { transition: none; } }

/* social row: same level as the lockup, right side */
.kore-social {
  position: absolute; top: 30px; right: 64px; z-index: 3;
  height: 47px;                                /* logo height, so icons center on the brand row */
  display: flex; align-items: center; gap: 18px;
}
.kore-social a { display: block; color: var(--kore-ink); transition: color .2s ease; }
.kore-social a:hover, .kore-social a:focus-visible { color: var(--kore-gold-text); }
.kore-social svg { width: 20px; height: 20px; display: block; fill: currentColor; }
@media (max-width: 1199px) {
  .kore-social { top: 22px; right: 20px; height: 38px; gap: 14px; }
  .kore-social svg { width: 18px; height: 18px; }
}
@media (prefers-reduced-motion: reduce) { .kore-social a { transition: none; } }
/* short landscape viewports (phone rotated): everything steps down a size class —
   full desktop furniture in a ~430pt-tall box reads oversized and crowded */
@media (max-height: 560px) {
  [data-framer-name="KoreDetail Welcome"] { padding-top: 84px !important; padding-bottom: 44px !important; }
  [data-framer-name="Welcome Heading"] h1 { font-size: 38px !important; line-height: 1.1 !important; }
  [data-framer-name="Welcome Body"] p { font-size: 15px !important; line-height: 1.5 !important; }
  .kore-brand { top: 20px; }
  .kore-brand-logo { width: 64px; }
  .kore-brand-name { font-size: .72rem; }
  .kore-social { top: 20px; height: 36px; }
  .kore-social svg { width: 17px; height: 17px; }
}
/* hero CTA matches the gold of Select Package / Ask a Question. Same #B99758 read
   lighter against the dark video (surround contrast), so it's compensated a step darker. */
[data-framer-name="See What Your Car Needs"] {
  background-color: #A98A4E !important;
  color: #171715 !important;
}
[data-framer-name="See What Your Car Needs"] .framer-text { color: #171715 !important; }
[data-framer-name="See What Your Car Needs"] svg { --1m973uw: #171715 !important; } /* Framer feeds the arrow stroke from this var; hero's was cream */
[data-framer-name="Finish Detail"] { display: none !important; }        /* old hero image, replaced */

/* Full-viewport hero, copy vertically centered; type scale unchanged. */
[data-framer-name="KoreDetail Welcome"] {
  min-height: 100vh !important;
  min-height: 100svh !important;   /* stable on phones: ignores the collapsing URL bar */
  align-items: center !important;  /* desktop row: vertical centering only — copy stays left */
}
@media (max-width: 1199px) {
  [data-framer-name="KoreDetail Welcome"] {
    align-items: flex-start !important;   /* stacked layout: keep copy on the left */
    justify-content: center !important;   /* stacked layout: main axis is vertical */
  }
}
/* Stack Precision. / Protection. / Perfection. — keeps the staggered slide-in animation. */
[data-framer-name="Welcome Heading"] h1 span { display: block !important; }
/* Larger hero type above the phone layout (phones keep the stock scale) */
@media (min-width: 811px) {
  [data-framer-name="Welcome Copy"] { max-width: 500px; }
  [data-framer-name="Welcome Heading"] h1 { font-size: 66px !important; line-height: 1.05 !important; }
  [data-framer-name="Welcome Body"] p { font-size: 17px !important; line-height: 1.55 !important; }
  [data-framer-name="KoreDetail Wordmark"] p { font-size: 12.5px !important; }
}

/* Mobile: the video is the TOP BAND of the hero, not the whole of it.
   -------------------------------------------------------------------
   Filling a portrait hero with a 16:9 frame is not a framing problem, it is arithmetic.
   object-fit:cover renders the frame max(100vw, H x 16/9) wide, so the window you actually
   see is 100vw / (H x 1.778). The car spans 44.8% of the frame -- measured off the last
   frame, x 570..1430 of 1920 -- so the window has to be WIDER than 44.8% or the car is cut.
   At 100svh on a 390x844 phone the window is 26%: three quarters of the shot, including the
   nose, is off-screen.

   So the height is pinned to viewport WIDTH, not height, because width is what the crop
   depends on. H = 1.03 x 100vw puts the window at 54.5% -- the whole car with about 9% of
   padding a side. The svh cap is only a backstop for short screens (landscape phones), where
   103vw would otherwise be taller than the hero itself.

   Cropping cannot fix this and neither can a portrait re-encode: a portrait window cut from
   a 16:9 source is NARROWER than the source, so it holds less of the car, not more. A 3:4
   crop wide enough for the car needs 2600px of source height; the 4K master has 2160. */
/* Keyed on SHAPE, not just width. A portrait tablet at 811x1080 is above the phone breakpoint
   and has exactly the same problem -- its window is 42.2% against a 44.8% car, so the splitter
   and the rear tip are still shaved. 4/5 is about where a full-height hero stops being able to
   hold the car; anything squarer than that is fine on the normal path. */
@media (max-width: 810px), (max-aspect-ratio: 4/5) {
  [data-framer-name="KoreDetail Welcome"] {
    /* One source of truth for the band: the layers position off it and the copy reserves it,
       so the two cannot drift apart. */
    --hero-band-h: min(103vw, 56svh);
    --hero-band-top: 10svh;
  }
  .kore-hero-video,
  .kore-hero-still,
  .kore-hero-scrim {
    top: var(--hero-band-top);
    height: var(--hero-band-h);
    bottom: auto;                 /* inset:0 set it; height wins, but say so rather than rely on it */
  }
  .kore-hero-video, .kore-hero-still {
    /* Both edges dissolve. The bottom fade holds full strength past the car (frame y
       30.6%..63.9%) and then goes out over the empty pavement. The top fade is new, and is
       only needed because the band no longer starts at the viewport edge -- an image that
       begins 10svh down has to arrive out of the ink rather than butt against it with a hard
       horizontal line. Same smoothstep both ends, f*f*(3-2f), zero slope where it meets flat;
       a piecewise-linear ramp Mach-bands across this hero. */
    -webkit-mask-image: linear-gradient(180deg,
      rgba(0,0,0,0) 0%, rgba(0,0,0,0.156) 3%, rgba(0,0,0,0.5) 6%,
      rgba(0,0,0,0.844) 9%, #000 12%, #000 66%,
      rgba(0,0,0,1) 66%, rgba(0,0,0,0.957) 70.25%, rgba(0,0,0,0.844) 74.5%,
      rgba(0,0,0,0.684) 78.75%, rgba(0,0,0,0.5) 83%, rgba(0,0,0,0.316) 87.25%,
      rgba(0,0,0,0.156) 91.5%, rgba(0,0,0,0.043) 95.75%, rgba(0,0,0,0) 100%);
            mask-image: linear-gradient(180deg,
      rgba(0,0,0,0) 0%, rgba(0,0,0,0.156) 3%, rgba(0,0,0,0.5) 6%,
      rgba(0,0,0,0.844) 9%, #000 12%, #000 66%,
      rgba(0,0,0,1) 66%, rgba(0,0,0,0.957) 70.25%, rgba(0,0,0,0.844) 74.5%,
      rgba(0,0,0,0.684) 78.75%, rgba(0,0,0,0.5) 83%, rgba(0,0,0,0.316) 87.25%,
      rgba(0,0,0,0.156) 91.5%, rgba(0,0,0,0.043) 95.75%, rgba(0,0,0,0) 100%);
  }
}
@media (max-width: 810px) {
  .kore-hero-video, .kore-hero-still { opacity: var(--hero-video-opacity-mobile, 0.78); }
  [data-framer-name="Welcome Copy"] { max-width: none; }
}

/* Reduced motion / data-saver: drop the video, keep the still.
   A static poster is not motion, and it is already downloaded and decoded — painting
   white over it left these visitors a completely empty hero. */
@media (prefers-reduced-motion: reduce) {
  .kore-hero-video { display: none; }
}
@media (prefers-reduced-data: reduce) {
  .kore-hero-video { display: none; }
}

/* ---------- full-bleed hero: video + scrim span the viewport; copy stays in the 1200px column ---------- */
[data-framer-name="KoreDetail Welcome"] { overflow: visible !important; }   /* let the video, its still, and the scrim break out of the box */
.kore-hero-video,
.kore-hero-still,
.kore-hero-scrim {
  left: 50%;
  right: auto;
  width: 100vw;
  margin-left: -50vw;            /* center a 100vw layer over the centered hero -> full viewport width */
}
:root { overflow-x: clip; }      /* the 100vw breakout can't cause a horizontal scrollbar */

/* ---------- headline words: CSS keyframe stagger (compositor-driven; smooth while the video decodes) ---------- */
@keyframes koreWordIn {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: no-preference) {
  [data-framer-name="Welcome Heading"] h1 span {
    animation: koreWordIn 0.72s cubic-bezier(0.22, 0.68, 0.2, 1) both;
    will-change: transform, opacity;      /* own layer -> doesn't repaint the video behind it */
  }
  [data-framer-name="Welcome Heading"] h1 span:nth-of-type(1) { animation-delay: 0.05s; }
  [data-framer-name="Welcome Heading"] h1 span:nth-of-type(2) { animation-delay: 0.2s;  }
  [data-framer-name="Welcome Heading"] h1 span:nth-of-type(3) { animation-delay: 0.35s; }
}

/* ---------- hero copy: one bottom band ----------
   Was a 500px column parked mid-left, over the middle of the frame. Two things
   follow from moving it down: the copy lands on pavement, which is the darkest
   and least busy region of every frame, and the car gets the whole middle back.

   The headline sets on ONE line, sized to fill the column edge to edge. At that
   width the three words read as typeset -- a measure, not a block of text that
   happens to be big -- and the existing left-to-right stagger now lands word by
   word across the frame instead of dropping down a stack.

   The motto sits under the headline, on the same left margin -- the three P's
   are the thing being led with, and the motto is what they cash out to. */
[data-framer-name="KoreDetail Welcome"] {
  align-items: flex-end !important;      /* desktop row: cross axis is vertical */
  padding-bottom: 92px !important;       /* near the bottom, not flush to the edge */
}
@media (max-width: 1199px) {
  [data-framer-name="KoreDetail Welcome"] {
    justify-content: flex-end !important; /* stacked layout: main axis is vertical */
    align-items: flex-start !important;   /* ...so the CROSS axis is horizontal: keep copy left */
    padding-bottom: 64px !important;
  }
}
/* Below 810 the video no longer fills the hero, it is a band across the top (see the mobile
   hero block above), so pinning the copy to the bottom edge left 210px of dead ink between
   the two. Reserve the band's height as padding and centre the copy in what is left, which
   splits that gap evenly above and below it. Same expression as the band's own height --
   if one changes the other has to, so they are written the same way on purpose. */
@media (max-width: 810px), (max-aspect-ratio: 4/5) {
  [data-framer-name="KoreDetail Welcome"] {
    justify-content: center !important;
    /* Reserve the band AND its offset, then centre the copy in what is left -- that spreads
       the slack evenly above the band and below the copy instead of pooling it at the bottom
       of the hero, which is what made the car look pinned to the top. */
    padding-top: calc(var(--hero-band-top) + var(--hero-band-h)) !important;
    padding-bottom: 0 !important;
  }
}
/* Framer's sub-1200px variant drops the side padding to 20px. That was fine for
   a narrow copy column; a full-width 55px headline set 20px off the glass reads
   as a crop. Give the band a real margin here, and move the brand lockup and the
   social row onto the same line so all three still share one left/right edge. */
@media (min-width: 900px) and (max-width: 1199px) {
  [data-framer-name="KoreDetail Welcome"] { padding-left: 40px !important; padding-right: 40px !important; }
  .kore-brand { left: 40px; }
  .kore-social { right: 40px; }
}
[data-framer-name="Welcome Copy"] { max-width: none; }
/* Pulled for now. It was one of the three unwired Framer buttons, so no
   behaviour is lost -- only the affordance. */
[data-framer-name="See What Your Car Needs"] { display: none !important; }

@media (min-width: 900px) {
  /* Framer's own rule is two classes deep, so an attribute selector loses the tie.
     fit-content is what makes the motto's centring mean "centred under the
     headline" rather than "centred in the column" -- the headline is left-aligned
     and stops 62px short of the column's right edge, so those two centres are 31px
     apart. Shrinking the block to the headline collapses the difference to zero. */
  [data-framer-name="Welcome Copy"] {
    max-width: none; gap: 14px !important;
    /* !important on all three: Framer sets flex:1 0 0px and width:1px from a
       two-class selector, which wins a plain attribute selector on specificity */
    flex: 0 0 auto !important; width: fit-content !important;
  }
  /* Framer feeds alignment through a variable, so overriding text-align does
     nothing -- the variable is the handle. */
  [data-framer-name="Welcome Body"] p { --framer-text-alignment: center !important; }
  /* 17px under a 70px headline read as a stray; 19px holds its own beneath it */
  [data-framer-name="Welcome Body"] p { font-size: 19px !important; line-height: 1.5 !important; }
  [data-framer-name="Welcome Heading"] h1 span { display: inline-block !important; }
  [data-framer-name="Welcome Heading"] h1 {
    white-space: nowrap;
    /* vw below the 1200px cap so the fit ratio holds while the column grows;
       flat above it, where the column stops growing. Tuned by measuring the
       rendered line against the column, not by eye. */
    font-size: min(6.05vw, 70px) !important;
    line-height: 1.04 !important;
  }
}

/* ================= SERVICE MENU eyebrow: refined gold text, no heavy fill box ================= */
[data-framer-name="Package Menu Label"] mark {
  background-color: transparent !important;
  padding: 0 !important;
  border-radius: 0 !important;
  color: var(--kore-gold-text) !important;
}

/* small gold labels on cream fail WCAG at #9B7A3F/#a78a55 (3.0-3.5:1) — deepen to 4.5+ */
[data-framer-name="Coverage Label"] .framer-text,
[data-framer-name="Package Tier"] .framer-text {
  color: var(--kore-gold-text) !important;
}

/* ================= service-area map (your SVG, re-themed to site gold + Inter) ================= */
.kore-map {
  width:100%; max-width:1040px; margin:1.7rem auto 0;
  border:1px solid var(--kore-gold-line); border-radius:6px; overflow:hidden;
  box-shadow:0 22px 44px -26px rgba(30,30,28,0.28); line-height:0;
}
.kore-map-svg { display:block; width:100%; height:auto; font-family: var(--kore-sans); }
.kore-city   { cursor:default; outline:none; }
.kore-dot    { fill:var(--kore-gold); stroke:transparent; stroke-width:22; pointer-events:all; transition: r .2s ease, filter .2s ease; } /* fat transparent stroke = generous hover/hit target */
.kore-dot--inner { fill:var(--kore-gold-text); }
.kore-label  { fill:var(--kore-feat); font-weight:600; transition: fill .2s ease;
               paint-order: stroke fill; stroke: rgba(246,242,232,0.9);
               stroke-width: 0.2em; stroke-linejoin: round; }
.kore-label--gold  { fill:#77592A; }   /* --kore-gold-text is tuned for plain cream and lands
                                          at 4.4:1 on the glow-tinted land; this reads 5.3:1 */
.kore-label--inner { fill:#565045; font-weight:500; }   /* --kore-veh was 3.8:1 on the glow */
.kore-city:hover .kore-dot, .kore-city:focus-visible .kore-dot { filter: drop-shadow(0 0 6px rgba(155,122,63,0.5)); }
.kore-city--outer:hover .kore-dot, .kore-city--outer:focus-visible .kore-dot { r:5; }
.kore-city--inner:hover .kore-dot, .kore-city--inner:focus-visible .kore-dot { r:3.4; }
.kore-city:hover .kore-label, .kore-city:focus-visible .kore-label { fill:var(--kore-gold-text); }
/* The map scales to its container, so the authored 7.5/7 render at ~10px on a
   940px-wide desktop map but only 3.7px on a 348px phone one. 12/11.2 is the
   measured ceiling -- one step further and Costa Mesa collides with Newport
   Beach and Long Beach clips the edge. Placement was solved to stay clear at
   both sizes. */
@media (max-width: 810px) {
  .kore-map-svg .kore-label { font-size: 12px; }
  .kore-map-svg .kore-label--inner { font-size: 11.2px; }
}
.kore-ocean   { fill: rgba(15,42,64,0.9); font-size:8.5px; font-weight:300; letter-spacing:2.5px; }
@media (prefers-reduced-motion: reduce) { .kore-dot, .kore-label { transition:none; } }

/* ================= add-ons: horizontal price ledger on the cream card ================= */
/* The Framer "Add-ons" card already supplies the cream panel, gold border and padding —
   the ledger sits naked on it, same language as the package price grids. */
.kore-addons { width: 100%; }
.kore-addons-head { display: flex; align-items: baseline; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
.kore-addons-title { font: 700 0.72rem/1 var(--kore-sans); letter-spacing: 0.22em; text-transform: uppercase; color: var(--kore-gold-text); }
.kore-addons-sub   { font: 400 0.8rem/1.3 var(--kore-sans); color: var(--kore-veh); }
.kore-addons-grid  {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 2.4rem;
  border-top: 1px solid var(--kore-gold-line);
}
@media (max-width: 640px) { .kore-addons-grid { grid-template-columns: 1fr; } }
.kore-addon {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: 0.9rem 0.25rem;
  border-bottom: 1px solid var(--kore-hair);
  transition: background-color .25s ease;
}
.kore-addon:hover { background: rgba(155, 122, 63, .06); }
.kore-addon-name  { font: 600 0.74rem/1.3 var(--kore-sans); letter-spacing: 0.1em; text-transform: uppercase; color: var(--kore-feat); transition: color .25s ease; }
.kore-addon:hover .kore-addon-name { color: var(--kore-gold-text); }
.kore-addon-price { font: 500 1.05rem/1 var(--kore-serif); color: var(--kore-ink); font-variant-numeric: tabular-nums; }
.kore-addons-note { margin: 1.3rem auto 0; max-width: 720px; text-align: center; font: 400 0.72rem/1.55 var(--kore-sans); color: var(--kore-veh); }
@media (prefers-reduced-motion: reduce) { .kore-addon, .kore-addon-name { transition: none; } }

/* ================= stack: add-ons under the Service Menu, map alone on its row =================
   The section shipped as a side-by-side flex ROW (add-ons left / map right), which cramped the
   map into ~half width. Stack it: add-ons directly below the Service Menu, then the map full-width
   on its own line (nothing beside it) so it reads longer + taller. */
[data-framer-name="Add-ons and Service Area"] {
  flex-direction: column !important;
  align-items: center !important;
}
[data-framer-name="Add-ons"],
[data-framer-name="OC Service Area"] {   /* both cards: were flex:1 0 0px; width:1px, which collapses to min-content once the parent is a column */
  width: 100% !important;
  max-width: none !important;            /* full section width, so edges align with the package grid above */
  flex: 0 0 auto !important;
}

/* fold the add-ons into the Service Menu: erase the section seam (border + paddings) */
[data-framer-name="Detailing Packages"] { padding-bottom: 18px !important; }
[data-framer-name="Add-ons and Service Area"] {
  padding-top: 0 !important;
  border-top-width: 0 !important;
  --border-top-width: 0px !important;
}

/* de-card the service-area chapter: heading sits on the page background like
   "Choose Your Package", and the map panel (own gold hairline) is the content.
   The margin is the chapter pause after the pricing block. */
[data-framer-name="OC Service Area"] {
  background: none !important;
  border: none !important;
  --border-top-width: 0px !important;
  --border-right-width: 0px !important;
  --border-bottom-width: 0px !important;
  --border-left-width: 0px !important;
  box-shadow: none !important;
  border-radius: 0 !important;
  padding: 0 !important;
  margin-top: 56px !important;
}
[data-framer-name="OC Service Area"] [data-framer-name="Gold Detail Rail"] { display: none !important; }
/* Map fills its now-full-width card -> ~2x wider and taller than the old side-by-side. */
.kore-map { max-width: none !important; }

/* ---------- quote builder modal (.kqb-*) — own markup, outside the Framer tree ---------- */
.kqb {
  width: min(560px, calc(100vw - 28px));
  max-height: calc(100svh - 40px);
  padding: 0;
  border: 1px solid var(--kore-gold-line);
  border-radius: 8px;
  background: rgb(248, 245, 238);
  color: var(--kore-ink);
  box-shadow: rgba(30, 30, 28, 0.28) 0px 24px 70px 0px;
  overflow: hidden;
}
.kqb::backdrop { background: rgba(23, 23, 21, 0.55); }
.kqb-in { padding: 30px 32px 0; max-height: calc(100svh - 40px); overflow-y: auto; }
.kqb-x {
  position: absolute; top: 14px; right: 16px;
  width: 32px; height: 32px; padding: 0; line-height: 1;
  background: none; border: 0; cursor: pointer;
  font: 400 26px/1 var(--kore-sans); color: var(--kore-veh);
  background: rgb(248, 245, 238); border-radius: 50%;   /* stays put while the body scrolls under it */
  /* ...so it needs to read as sitting above the scroll, not tangled in it. */
  box-shadow: 0 0 0 7px rgb(248, 245, 238);
  transition: color .2s ease;
}
.kqb-x:hover, .kqb-x:focus-visible { color: var(--kore-ink); }
.kqb-eyebrow { font: 700 11px/1 var(--kore-sans); letter-spacing: .22em; color: var(--kore-gold-text); margin: 0 0 12px; }
.kqb-h { font: 500 30px/1.15 var(--kore-serif); margin: 0 0 24px; }
.kqb-h:focus { outline: none; }   /* programmatic landing spot on open, not keyboard reachable */
/* Several .kqb blocks set display, which beats the `hidden` attribute's UA rule. */
/* Attached to the elements themselves, not to an ancestor: these set display,
   which beats the UA [hidden] rule, and an ancestor-scoped guard silently stops
   working the moment the container around them is renamed. */
.kqb [hidden], .kqb-bundle[hidden], .kqb-note[hidden] { display: none !important; }
.kqb-f { border: 0; padding: 0; margin: 0 0 22px; min-width: 0; }
.kqb-f legend {
  padding: 0; margin: 0 0 10px;
  font: 700 10px/1 var(--kore-sans); letter-spacing: .18em;
  text-transform: uppercase; color: var(--kore-veh);
}
.kqb-opts { display: grid; gap: 6px; }
/* Same three chapters inside the modal: eight radio rows in a row is the same
   undifferentiated list the grid had. */
.kqb-group {
  margin: 14px 0 2px;
  font: 700 10px/1 var(--kore-sans); letter-spacing: .18em;
  text-transform: uppercase; color: var(--kore-gold-text);
}
.kqb-group:first-child { margin-top: 0; }
.kqb-opts--row { grid-auto-flow: column; grid-auto-columns: 1fr; margin-top: 10px; }
.kqb-opt {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 14px; border: 1px solid var(--kore-hair); border-radius: 4px;
  background: rgb(255, 255, 255); cursor: pointer;
  font: 500 .86rem/1.2 var(--kore-sans); color: var(--kore-feat);
  transition: border-color .15s ease, background-color .15s ease;
}
.kqb-opt:hover { border-color: var(--kore-gold-line); }
.kqb-opt:has(:checked) { border-color: var(--kore-gold); background: rgb(252, 250, 245); color: var(--kore-ink); }
.kqb-opt:has(:focus-visible) { outline: 2px solid var(--kore-gold); outline-offset: 2px; }
.kqb-opt input { accent-color: var(--kore-gold); margin: 0; flex: 0 0 auto; }
.kqb-opt-n { flex: 1 1 auto; }
.kqb-opt-p { font-variant-numeric: tabular-nums; color: var(--kore-gold-text); font-weight: 600; }
/* The close button floats over the top of the scroll area, which is exactly
   where the tier list starts -- and where each tier prints its price. Keep that
   corner clear so a price never sits under the X. */
#kqb-tiers .kqb-opt { padding-right: 48px; }
.kqb-adds { display: grid; gap: 6px; }
.kqb-add {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 14px; border: 1px solid var(--kore-hair); border-radius: 4px;
  background: rgb(255, 255, 255); cursor: pointer;
  font: 500 .82rem/1.2 var(--kore-sans); color: var(--kore-feat);
}
.kqb-add:has(:checked) { border-color: var(--kore-gold); color: var(--kore-ink); }
.kqb-add:has(:focus-visible) { outline: 2px solid var(--kore-gold); outline-offset: 2px; }
.kqb-add input { accent-color: var(--kore-gold); margin: 0; }
.kqb-add-n { flex: 1 1 auto; }
.kqb-add-p { font-variant-numeric: tabular-nums; color: var(--kore-gold-text); }
.kqb-add.is-inc { cursor: default; background: rgba(138, 131, 119, .06); color: var(--kore-veh); }
.kqb-add.is-inc .kqb-add-p { font: 700 10px/1 var(--kore-sans); letter-spacing: .14em; text-transform: uppercase; }
.kqb-bundle {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 14px 16px; margin: 0 0 22px;
  border: 1px solid var(--kore-gold); border-radius: 4px;
  background: rgba(155, 122, 63, .07);
}
.kqb-bundle-t { flex: 1 1 180px; font: 600 .84rem/1.35 var(--kore-sans); color: var(--kore-ink); }
.kqb-bundle-b {
  flex: 0 0 auto; padding: 9px 14px; border: 0; border-radius: 2px; cursor: pointer;
  background: var(--kore-gold); color: rgb(23, 23, 21);
  font: 600 .74rem/1 var(--kore-sans); letter-spacing: .08em; text-transform: uppercase;
}
.kqb-bundle-b--undo {
  background: none; color: var(--kore-gold-text);
  box-shadow: inset 0 0 0 1px var(--kore-gold);
}
.kqb-date {
  width: 100%; padding: 10px 13px;
  border: 1px solid var(--kore-hair); border-radius: 4px; background: rgb(255, 255, 255);
  font: 500 .86rem/1.2 var(--kore-sans); color: var(--kore-ink);
}
.kqb-date:focus-visible { outline: 2px solid var(--kore-gold); outline-offset: 2px; }
.kqb-note {
  margin: 0 0 20px; padding: 12px 14px;
  border-left: 2px solid var(--kore-gold);
  background: rgba(155, 122, 63, .07);
  font: 500 .8rem/1.55 var(--kore-sans); color: var(--kore-feat);
}
.kqb-foot {
  position: sticky; bottom: 0; z-index: 2;
  margin: 0 -32px; padding: 14px 32px 22px;
  background: rgb(248, 245, 238);
  border-top: 1px solid var(--kore-hair);
}
.kqb-pick {
  margin: 0 0 12px; padding: 0 0 12px;
  border-bottom: 1px solid var(--kore-hair);
  font: 500 .8rem/1.45 var(--kore-sans); color: var(--kore-ink);
}
.kqb-pick.is-todo { color: var(--kore-veh); }
.kqb-sum { margin: 0; }
.kqb-line { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; }
.kqb-line span:first-child { font: 700 10px/1 var(--kore-sans); letter-spacing: .18em; text-transform: uppercase; color: var(--kore-veh); }
.kqb-total { font: 500 30px/1.1 var(--kore-serif); color: var(--kore-ink); font-variant-numeric: tabular-nums; }
.kqb-line--sub { margin-top: 8px; }
.kqb-line--sub span:last-child { font: 500 .84rem/1 var(--kore-sans); color: var(--kore-feat); }
.kqb-fine { margin: 0 0 16px; font: 400 .72rem/1.5 var(--kore-sans); color: var(--kore-veh); }
@media (max-width: 560px) {
  .kqb-in { padding: 26px 20px 0; }
  .kqb-h { font-size: 25px; }
  .kqb-opts--row { grid-auto-flow: row; }
  /* Sedan / SUV / Van are three short words -- stacking them burns ~90px of a
     phone screen in a modal that is already long. They stay side by side; the
     day-window pair below keeps the stacked treatment it was written for. */
  #kqb-vehicles.kqb-opts--row { grid-auto-flow: column; grid-auto-columns: 1fr; gap: 5px; }
  #kqb-vehicles .kqb-opt { padding: 11px 6px; gap: 6px; font-size: .8rem; justify-content: center; }
  .kqb-foot { margin: 0 -20px; padding: 12px 20px 18px; }
  .kqb-total { font-size: 26px; }
}
@media (prefers-reduced-motion: reduce) {
  .kqb-opt, .kqb-x { transition: none; }
}

/* ---------- shared form controls + send button (quote modal and contact modal) ---------- */
.kqb-lab {
  display: block; margin: 0 0 10px;
  font: 700 10px/1 var(--kore-sans); letter-spacing: .18em;
  text-transform: uppercase; color: var(--kore-veh);
}
.kqb-input {
  width: 100%; box-sizing: border-box; padding: 11px 13px;
  border: 1px solid var(--kore-hair); border-radius: 4px; background: rgb(255, 255, 255);
  font: 500 .86rem/1.4 var(--kore-sans); color: var(--kore-ink);
}
.kqb-input:focus-visible { outline: 2px solid var(--kore-gold); outline-offset: 2px; }
.kqb-req { color: var(--kore-req); font-weight: 700; font-size: 1.15em; line-height: 0; }
/* Year / Make / Model. Year is narrow because four digits never need more; the
   two name fields split what is left. Collapses to one column on small phones
   where three inputs on a row leave nothing readable. */
.kqb-ymm { display: grid; grid-template-columns: 5.5rem 1fr 1fr; gap: 10px; }
.kqb-ymm-f { min-width: 0; }
.kqb-ymm .kqb-input { padding: 11px 10px; }
@media (max-width: 430px) {
  .kqb-ymm { grid-template-columns: 1fr; gap: 12px; }
}

/* Suggestion list. A native <datalist> popup is an OS menu: unreachable from
   CSS, and on a scaled Windows display each row stands taller than the input it
   belongs to. Same contract in our own markup -- suggestions only, free text
   always wins -- at a row height that matches the form. */
.kqb-ac { position: relative; }
.kqb-ac-list {
  position: absolute; z-index: 3; left: 0; right: 0; top: calc(100% + 5px);
  margin: 0; padding: 4px; list-style: none;
  max-height: 216px; overflow-y: auto; overscroll-behavior: contain;
  background: rgb(255, 255, 255);
  border: 1px solid var(--kore-gold-line); border-radius: 5px;
  box-shadow: rgba(30, 30, 28, .16) 0 12px 30px 0;
}
.kqb-ac-list li {
  padding: 7px 10px; border-radius: 3px; cursor: pointer;
  font: 500 .82rem/1.2 var(--kore-sans); color: var(--kore-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kqb-ac-list li:hover, .kqb-ac-list li.is-on { background: rgba(155, 122, 63, .13); }
/* 30px rows are right for a mouse and too mean for a thumb. Touch pointers get
   44px, the tap-target size Apple and Material both settle on. The list keeps
   roughly five rows visible either way, so nothing is hidden by the change. */
@media (pointer: coarse) {
  .kqb-ac-list li { padding: 13px 12px; font-size: .88rem; }
  .kqb-ac-list { max-height: 232px; }
}
/* The list is a child of the field, and the field sits in a scrolling modal, so
   a long list must never push the dialog wider. */
.kqb-ymm-f { min-width: 0; }
.kqb-area { resize: vertical; min-height: 96px; }
.kqb-send {
  width: 100%; padding: 15px 20px; border: 0; border-radius: 2px; cursor: pointer;
  background: var(--kore-gold); color: rgb(23, 23, 21);
  font: 600 12px/1 var(--kore-sans); letter-spacing: 1.2px; text-transform: uppercase;
  position: relative; overflow: hidden;
}
/* .5 rendered the label at 3.07:1; inactive controls are exempt, but unreadable is still unreadable */
.kqb-send[disabled] { background: rgba(155, 122, 63, .3); color: rgba(23, 23, 21, .72); cursor: not-allowed; }
.kqb-send::before {
  content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: linear-gradient(105deg, transparent 42%, rgba(255, 255, 255, 0.34) 50%, transparent 58%);
  transform: translateX(-70%);
}
.kqb-send:not([disabled]):hover::before { animation: koreGloss .5s ease; }
.kqb-sum + .kqb-send { margin-top: 16px; }
@media (prefers-reduced-motion: reduce) {
  .kqb-send:not([disabled]):hover::before { animation: none; }
}

/* ---------- hero: let it breathe on big screens ---------- */
/* Everything on the page is capped at 1200px. That is right for reading width,
   but in the hero it parks the 500px copy column at x=744 on a 2560 screen --
   directly over the car. Widening only the hero walks the copy back left and
   hands the middle of the frame to the video. The other sections keep 1200,
   and the quote flow keeps its own 940 cap, or it would strand itself left of
   a lake of empty space. */
/* The exception that used to live here widened the hero to 1440/1680 on big
   monitors, because a 500px copy column pinned to a 1200px cap ended up sitting
   on top of the car. The copy is a full-width bottom band now, so there is
   nothing to walk out of the way -- and keeping the cap means the headline fills
   its column at every width above 1200 instead of shrinking away from it. */

/* ---------- the section IS the builder ---------- */
/* Sticky so the size stays reachable while scrolling eight cards. z-index sits
   under .kore-bar (900), which is fixed and only appears on scroll-up. */
.kb-bar {
  width: 100%; flex: 0 0 auto;          /* Framer's sub-1200px variant centers instead of stretching */
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center;
  gap: 12px 24px;
  margin: 0 0 26px; padding: 12px 0;
  background: rgb(255, 255, 255);   /* the packages section is white; a cream bar reads as a stray band */
  box-shadow: 0 1px 0 var(--kore-gold-line);
}
.kb-size { display: flex; align-items: center; gap: 12px; }
.kb-size-lab {
  font: 700 10px/1 var(--kore-sans); letter-spacing: .18em;
  text-transform: uppercase; color: var(--kore-veh); white-space: nowrap;
}
.kb-size .kqb-opts--row { margin-top: 0; gap: 5px; min-width: 246px; }
.kb-size .kqb-opt { padding: 9px 12px; justify-content: center; }

/* A card that is the current pick. Framer draws its own border with ::after, so
   this rides on box-shadow rather than a border or a competing pseudo. */
[data-framer-name="Package Card"].kb-on {
  box-shadow: rgba(155, 122, 63, .55) 0 0 0 2px, rgba(30, 30, 28, .12) 0 18px 46px 0 !important;
}
.kb-on-tag {
  display: none;
  margin: 0 0 2px; font: 700 9px/1 var(--kore-sans); letter-spacing: .16em;
  text-transform: uppercase; color: var(--kore-gold-text);
}
.kb-on .kb-on-tag { display: block; }
/* Only hide the off-size rows once JS is running; with no JS all three stay. */
html.kb-live .kp-row.kb-off { display: none; }

.kb-panel {
  width: 100%; flex: 0 0 auto;
  margin: 34px 0 0; padding: 30px 32px;
  border: 1px solid var(--kore-gold-line); border-radius: 8px;
  background: rgb(248, 245, 238);
  scroll-margin-top: 96px;
}
.kb-panel-h { margin: 0 0 22px; }
.kb-h { margin: 0 0 6px; font: 500 27px/1.15 var(--kore-serif); color: var(--kore-ink); }
.kb-h:focus { outline: none; }
.kb-lead { margin: 0; font: 500 .86rem/1.45 var(--kore-sans); color: var(--kore-veh); }
.kb-cols { display: grid; grid-template-columns: 1fr 300px; gap: 34px; align-items: start; }
.kb-form { min-width: 0; }
.kb-form .kqb-f:last-child { margin-bottom: 0; }
.kb-sticky { position: sticky; top: 86px; }
.kb-side .kqb-sum { margin-top: 0; }
.kb-side .kqb-fine { margin: 12px 0 0; }
@media (max-width: 1000px) {
  .kb-cols { grid-template-columns: 1fr; gap: 24px; }
  .kb-sticky { position: static; }
}
@media (max-width: 810px) {
  .kb-panel { padding: 24px 20px; margin-top: 26px; }
  .kb-h { font-size: 23px; }
  /* Only the size strip pins on a phone. With the jump pills inside it the bar
     stood ~290px tall -- a third of the viewport -- and clipped the panel it
     was supposed to sit above. */
  .kb-bar { gap: 10px; padding: 9px 0; margin-bottom: 18px; }
  .kb-size { width: 100%; }
  .kb-size .kqb-opts--row { flex: 1 1 auto; min-width: 0; }
  .kb-size .kqb-opt { padding: 10px 4px; font-size: .8rem; gap: 6px; }
}

/* ---------- package chapters: 3 / 3 / 2 instead of one 8-up grid ---------- */
/* Framer sets grid-auto-rows: minmax(0,1fr) on the list, which forces every row
   to the same height. With only cards in the grid that is invisible; add a
   heading row and it stretches to a full card height, opening a ~900px void
   under each chapter title. auto still equalises cards within a row (they
   stretch), it just stops equalising the rows against each other. */
[data-framer-name="Package List"] { grid-auto-rows: auto !important; align-content: start !important; }
/* Full-bleed row inside the 3-col grid. Below 1200px the Framer parent switches
   to a flex column and grid-column is simply ignored, which is the wanted
   result -- the heading just stacks above its cards. */
.kp-chap {
  grid-column: 1 / -1;
  display: flex; align-items: baseline; gap: 13px;
  scroll-margin-top: 92px;      /* clears the sticky bar when jumped to */
}
.kp-chap + [data-framer-name="Package Card"] { margin-top: 0; }
.kp-chap:not(:first-child) { margin-top: 30px; }
.kp-chap-t { margin: 0; font: 500 1.34rem/1.1 var(--kore-serif); color: var(--kore-ink); }
.kp-chap-s { font: 500 .76rem/1.2 var(--kore-sans); color: var(--kore-veh); }
/* Safe here: this is our own element, not a Framer node with data-border, so
   there is no ::after border to collide with. */
.kp-chap::after {
  content: ''; flex: 1 1 auto; align-self: center;
  height: 1px; background: var(--kore-gold-line);
}
.kp-jump {
  width: 100%; flex: 0 0 auto;          /* or it collapses on the sub-1200px variant */
  display: flex; flex-wrap: wrap; gap: 8px;
  margin: 0 0 26px;
}
.kp-jump a {
  padding: 8px 15px; border: 1px solid var(--kore-gold-line); border-radius: 999px;
  font: 600 11px/1 var(--kore-sans); letter-spacing: .1em; text-transform: uppercase;
  color: var(--kore-gold-text); text-decoration: none;
  transition: background-color .15s ease, border-color .15s ease;
}
.kp-jump a:hover, .kp-jump a:focus-visible { background: rgba(155, 122, 63, .1); border-color: var(--kore-gold); }
@media (prefers-reduced-motion: reduce) { .kp-jump a { transition: none; } }
@media (max-width: 810px) {
  .kp-chap { flex-wrap: wrap; gap: 4px 12px; margin-bottom: 2px; }
  .kp-chap-t { font-size: 1.2rem; }
  .kp-chap::after { display: none; }    /* a hairline under a wrapped heading reads as a stray line */
  .kp-jump { gap: 6px; margin-bottom: 20px; }
  .kp-jump a { padding: 9px 13px; font-size: 10px; }
}


/* ================= quote flow: four steps, never more than three choices =================
   Replaces the eight tier cards. The numerals are real sequence markers -- step
   1 must happen before step 3 -- unlike TIER 01..08, which numbered a menu and
   implied a ranking that was never true.

   Signature: a selected package opens into a spec that reads like a work order.
   Everything else stays quiet so that one moment carries the section. */
.quote {
  width: 100%; flex: 0 0 auto;   /* Framer's sub-1200px variant centers rather than stretches */
  max-width: 940px;
}
.qs { border-top: 1px solid var(--kore-gold-line); padding: 30px 0 34px; }
.qs:first-child { border-top: 0; padding-top: 4px; }
.qs:last-child { padding-bottom: 0; }
.qs-h {
  display: flex; align-items: baseline; gap: 14px;
  margin: 0 0 20px;
}
/* Hanging numeral: the sequence reads down the left edge at a glance. */
.qs-n {
  flex: 0 0 auto; width: 30px;
  font: 400 1.6rem/1 var(--kore-serif);
  /* --kore-gold is 4.00:1 on white. That clears the large-text tier at 1.6rem,
     but the <=810px rule drops this to 1.3rem where the floor is 4.5. */
  color: var(--kore-gold-text); font-variant-numeric: lining-nums;
}
.qs-t { font: 500 1.28rem/1.2 var(--kore-serif); color: var(--kore-ink); }
/* Sans and raised, so it reads as a required marker rather than a Bodoni glyph
   sitting in the headline. */
.qs-t .kqb-req { font-family: var(--kore-sans); font-size: .58em; vertical-align: .5em; margin-left: 1px; }
.qs-body { padding-left: 44px; }

/* ---- step 1: size ---- */
.qsize { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; max-width: 460px; }
.qsize-o {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 13px 10px; cursor: pointer;
  border: 1px solid var(--kore-hair); border-radius: 4px; background: rgb(255, 255, 255);
  font: 500 .88rem/1 var(--kore-sans); color: var(--kore-feat);
  transition: border-color .15s ease, color .15s ease;
}
.qsize-o input { accent-color: var(--kore-gold); margin: 0; }
.qsize-o:hover { border-color: var(--kore-gold-line); }
.qsize-o:has(:checked) {
  border-color: var(--kore-gold); color: var(--kore-ink); background: var(--kore-pick);
  box-shadow: inset 0 0 0 1px var(--kore-gold);   /* reads as 2px without moving anything */
  font-weight: 600;
}
.qsize-o:has(:focus-visible) { outline: 2px solid var(--kore-gold); outline-offset: 2px; }

/* Year / make / model belongs with the size -- both answer "your vehicle".
   Capped so three fields do not stretch across the full 940px column. */
#q-size .kqb-f { margin: 22px 0 0; }
#q-size .kqb-ymm { max-width: 560px; }

/* ---- step 2: what it needs ---- */
.qgroups { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 0; padding: 0; list-style: none; }
.qg {
  position: relative; padding: 17px 18px 16px; cursor: pointer;
  border: 1px solid var(--kore-hair); border-radius: 5px; background: rgb(255, 255, 255);
  transition: border-color .15s ease, transform .15s ease;
}
.qg:hover { border-color: var(--kore-gold-line); transform: translateY(-1px); }
.qg.is-on {
  border-color: var(--kore-gold); background: var(--kore-pick);
  box-shadow: inset 0 0 0 1px var(--kore-gold);
}
.qg.is-on .qg-s { color: var(--kore-feat); }
.qg:focus-visible { outline: 2px solid var(--kore-gold); outline-offset: 2px; }
.qg-n { display: block; font: 500 1.06rem/1.15 var(--kore-serif); color: var(--kore-ink); }
.qg-s { display: block; margin-top: 5px; font: 400 .76rem/1.4 var(--kore-sans); color: var(--kore-veh); }
.qg-from {
  display: block; margin-top: 11px;
  font: 700 10px/1 var(--kore-sans); letter-spacing: .14em; text-transform: uppercase;
  color: var(--kore-gold-text);
}

/* ---- step 3: the packages ---- */
.qpkgs { margin: 0; padding: 0; list-style: none; border: 1px solid var(--kore-hair); border-radius: 5px; overflow: hidden; background: rgb(255, 255, 255); }
.qp + .qp { border-top: 1px solid var(--kore-hair); }
.qp.is-hidden { display: none; }
.qp-main {
  display: grid; grid-template-columns: 16px 1fr auto; align-items: start;
  gap: 4px 14px; padding: 16px 18px; cursor: pointer;
  transition: background-color .15s ease;
}
.qp:not(.is-on) .qp-main:hover { background: rgb(250, 247, 240); }
/* Same ring the size and group choices get, but around the whole row -- main
   and spec together -- so a selected package reads as one block rather than a
   tinted header sitting on a white panel. */
.qp.is-on {
  background: var(--kore-pick);
  box-shadow: inset 0 0 0 2px var(--kore-gold);
  border-radius: 4px;
}
.qp.is-on .qp-main { background: transparent; }
/* The separators either side of the ring would cut through it. */
.qp.is-on + .qp, .qp + .qp.is-on { border-top-color: transparent; }
.qp:has(:focus-visible) .qp-main { outline: 2px solid var(--kore-gold); outline-offset: -2px; }
/* The mark is the selection state; a real radio sits behind it for keyboard and AT. */
.qp-mark {
  grid-row: 1 / span 2; margin-top: 4px;
  width: 14px; height: 14px; border-radius: 50%;
  border: 1px solid var(--kore-gold-line); background: rgb(255, 255, 255);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.qp.is-on .qp-mark { border-color: var(--kore-gold); box-shadow: inset 0 0 0 3px var(--kore-gold); }
/* The real control. Off-screen but focusable, so the row works from a keyboard
   and announces as a radio; .qp-mark is only the visible dot. */
.kqb-vh { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.qp-name { font: 500 1.04rem/1.25 var(--kore-serif); color: var(--kore-ink); }
.qp-name { cursor: pointer; }
/* the one-line package description: 12.48px sat below every other piece of
   prose in the builder; .82rem lines it up with the add-on rows */
.qp-sum { grid-column: 2; font: 400 .82rem/1.45 var(--kore-sans); color: var(--kore-veh); }
.qp-prices { grid-column: 3; grid-row: 1 / span 2; margin: 0; padding: 0; list-style: none; text-align: right; }
.qp-price.is-off { display: none; }
.qp-veh { display: none; }
.qp-amt { display: block; font: 500 1.12rem/1 var(--kore-serif); color: var(--kore-ink); font-variant-numeric: tabular-nums; }
.qp-dur { display: block; margin-top: 5px; font: 500 .68rem/1 var(--kore-sans); letter-spacing: .1em; text-transform: uppercase; color: var(--kore-veh); }
/* Before a size is chosen every row shows all three prices, so label them. */
.quote:not(.has-size) .qp-veh { display: inline; margin-right: 9px; font: 500 .68rem/1 var(--kore-sans); letter-spacing: .1em; text-transform: uppercase; color: var(--kore-veh); }
.quote:not(.has-size) .qp-amt { display: inline; font-size: .96rem; }
.quote:not(.has-size) .qp-dur { display: none; }
.quote:not(.has-size) .qp-price + .qp-price { margin-top: 6px; }

/* The signature: the spec sheet. Hairline-ruled, two columns, opens on select. */
.qp-spec { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .32s cubic-bezier(.33, 1, .68, 1); }
.qp.is-on .qp-spec { grid-template-rows: 1fr; }
/* min-height:0 is load-bearing: a grid item defaults to min-height:auto and
   refuses to shrink below its content, so the 0fr row never actually closes. */
.qp-specin {
  overflow: hidden; min-height: 0;
  opacity: 0; transition: opacity .18s ease .04s;
}
.qp.is-on .qp-specin { opacity: 1; }
/* Grid, not multi-column. Multi-column re-balances against the box height, and
   the box height is exactly what is animating -- measured: all four items flew
   in from x=1564/2851/4138 and snapped to a 2x2. Grid places them once and the
   growing box merely uncovers them. The padding lives in here, inside the
   clipped wrapper, so it never snaps and the closed row still measures 0. */
.qp-feats {
  margin: 0; padding: 0 18px 18px 48px; list-style: none;
  display: grid; grid-template-columns: 1fr 1fr; column-gap: 30px;
}
.qp-feats li {
  position: relative; padding: 7px 0 7px 15px; min-width: 0;
  border-top: 1px solid var(--kore-hair);
  font: 400 .8rem/1.45 var(--kore-sans); color: var(--kore-feat);
}
.qp-feats li::before {
  content: ''; position: absolute; left: 0; top: 15px;
  width: 5px; height: 1px; background: var(--kore-veh);
}
.qp-feats li.qf-key { color: var(--kore-gold-text); font-weight: 600; }
.qp-feats li.qf-key::before { background: var(--kore-gold); height: 2px; top: 14px; }

/* The one thing on this page that changes what someone pays, so it is a block
   with a rule down its edge rather than grey small print under a button. */
/* Sits under Send, inside the summary card. White rather than the tinted fill
   the block above uses -- on a cream card a cream note is invisible. */
.qnote {
  margin: 14px 0 0; padding: 13px 14px 13px 15px;
  border: 1px solid var(--kore-gold-line); border-left: 3px solid var(--kore-gold);
  border-radius: 4px; background: rgb(255, 255, 255);
  font: 500 .77rem/1.55 var(--kore-sans); color: var(--kore-feat);
}
.qnote-link {
  padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; font-weight: 700; color: var(--kore-gold-text);
  text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px;
}
.qnote-link:hover { color: var(--kore-ink); }
.qnote-link:focus-visible { outline: 2px solid var(--kore-gold); outline-offset: 2px; border-radius: 2px; }
@media (max-width: 700px) { .qnote { padding: 12px 13px 12px 14px; } }

/* ---- step 4 ---- */
.qwhen { display: grid; grid-template-columns: minmax(0, 300px); gap: 10px; }
.qwhen-f { min-width: 0; }
.qwhen-note { margin: 9px 0 0; font: 400 .72rem/1.4 var(--kore-sans); color: var(--kore-veh); }
.qwhen-note:empty { display: none; }
@media (max-width: 480px) { .qwhen { grid-template-columns: 1fr; } }
.qs-body--split { display: grid; grid-template-columns: 1fr 274px; gap: 34px; align-items: start; }
.qcol { min-width: 0; }
.qcol .kqb-f:last-child { margin-bottom: 0; }
.qsum-in {
  position: sticky; top: 24px;
  padding: 20px 20px 22px; border: 1px solid var(--kore-gold-line); border-radius: 6px;
  background: rgb(252, 250, 245);
}
.qsum-lab { margin: 0; font: 700 10px/1 var(--kore-sans); letter-spacing: .18em; text-transform: uppercase; color: var(--kore-veh); }
.qsum-total { margin: 7px 0 0; font: 500 2.3rem/1 var(--kore-serif); color: var(--kore-ink); font-variant-numeric: tabular-nums; }
.qsum-time { display: flex; justify-content: space-between; gap: 12px; margin: 12px 0 0; padding-top: 12px; border-top: 1px solid var(--kore-gold-line); font: 500 .78rem/1.3 var(--kore-sans); color: var(--kore-feat); }
.qsum-fine { margin: 12px 0 0; font: 400 .68rem/1.5 var(--kore-sans); color: var(--kore-veh); }
.qsum-in .kqb-send { margin-top: 14px; }
/* .kqb-note rides inside the summary, which is on ink -- --kore-feat is 1.98:1 there */
.qsum-in .kqb-note {
  background: rgba(185, 151, 88, 0.14);
  color: rgba(244, 241, 234, 0.82);
}
.qsum-in .kqb-pick { margin: 12px 0 0; }
/* ---------- summary on ink ----------
   Was rgb(252,250,245): the most important surface on the page and the palest.
   Scoped to .qsum-in throughout -- the contact modal reuses these class names
   and must stay on its light ground. */
.qsum-in { background: var(--kore-ink); border-color: rgba(185, 151, 88, 0.30); }
.qsum-in .qsum-lab   { color: #B99758; }
.qsum-in .qsum-total { color: #F4F1EA; }
.qsum-in .qsum-time  { color: rgba(244, 241, 234, 0.78); border-top-color: rgba(185, 151, 88, 0.28); }
.qsum-in .qsum-fine  { color: rgba(244, 241, 234, 0.55); }
.qsum-in .kqb-pick   { color: rgba(244, 241, 234, 0.88); border-bottom-color: rgba(244, 241, 234, 0.14); }
.qsum-in .kqb-pick.is-todo { color: rgba(244, 241, 234, 0.62); }
/* #B99758 not --kore-gold: ink-on-#9B7A3F is 4.49:1, ink-on-#B99758 is 6.52:1 */
.qsum-in .kqb-send { background: #B99758; }
.qsum-in .kqb-send[disabled] { background: rgba(185, 151, 88, 0.25); color: rgba(244, 241, 234, 0.62); }
.qsum-in .kqb-bundle   { background: rgba(185, 151, 88, 0.13); border-color: rgba(185, 151, 88, 0.45); }
.qsum-in .kqb-bundle-t { color: #F4F1EA; }
.qsum-in .kqb-bundle-b { background: #B99758; }
.qsum-in .kqb-bundle-b--undo {
  background: none; color: #B99758; box-shadow: inset 0 0 0 1px rgba(185, 151, 88, 0.55);
}
.qsum-in .qnote {
  background: rgba(244, 241, 234, 0.05);
  border-color: rgba(185, 151, 88, 0.28);
  border-left-color: #B99758;
  color: rgba(244, 241, 234, 0.80);
}
.qsum-in .qnote-link { color: #B99758; }
.qsum-in .qnote-link:hover { color: #F4F1EA; }

/* A step you cannot act on yet reads as inactive rather than broken. */
/* A step that is not reachable yet keeps its numbered heading -- so the whole
   route stays visible -- but drops its body. Gated on .q-live so that with no
   JS every package, price and feature is still on the page. */
.qs.is-wait { pointer-events: none; }
.qs.is-wait .qs-h { opacity: .32; }
html.q-live .qs.is-wait .qs-body { display: none; }
html.q-live .qs.is-wait { padding-bottom: 22px; }
.qs.is-wait .qs-n { color: var(--kore-veh); }

@media (max-width: 900px) {
  .qs-body--split { grid-template-columns: 1fr; gap: 22px; }
  .qsum-in { position: static; }
  .qp-feats { grid-template-columns: 1fr; }
}
@media (max-width: 700px) {
  .qs { padding: 24px 0 26px; }
  .qs-h { gap: 10px; margin-bottom: 16px; }
  .qs-n { width: 20px; font-size: 1.3rem; }
  .qs-t { font-size: 1.14rem; }
  .qs-body { padding-left: 0; }
  .qgroups { grid-template-columns: 1fr; gap: 8px; }
  .qg { padding: 14px 15px; }
  .qg-from { margin-top: 8px; }
  .qsize { max-width: none; gap: 6px; }
  .qsize-o { padding: 13px 4px; font-size: .82rem; gap: 7px; }
  .qp-main { grid-template-columns: 16px 1fr; gap: 3px 12px; padding: 14px 15px; }
  .qp-prices { grid-column: 2; grid-row: auto; text-align: left; margin-top: 8px; }
  .qp-amt { display: inline; }
  .qp-dur { display: inline; margin: 0 0 0 10px; }
  .qp-feats { padding: 0 15px 16px 43px; grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .qg, .qp-main, .qp-mark, .qp-spec, .qp-specin { transition: none; }
}

/* ================= chapter system: one rhythm, one header shape ================= */
/* Every chapter opened differently: the menu put its title on the opposite side of the
   row, the map and reviews stacked it under the eyebrow, and the closing band had no
   eyebrow at all and a smaller title. Stacked-left wins on 2 of 4 already. */
[data-framer-name="Package Menu Heading"] {
  flex-direction: column !important;
  align-items: flex-start !important;
  gap: 14px !important;
}
/* Eyebrows rendered at three different weights and trackings (600/1.8px vs 700/2.42px). */
[data-framer-name="Package Menu Label"] mark,
[data-framer-name="Package Menu Label"] .framer-text,
[data-framer-name="Coverage Label"] .framer-text {
  font-weight: 700 !important;
  letter-spacing: .22em !important;
}
.kore-eyebrow {
  font: 700 11px/1 var(--kore-sans);
  letter-spacing: .22em;
  /* Its only use is the CONTACT label, which sits on the ink closing band.
     --kore-gold-text is tuned for cream and measures 3.33:1 there. */
  color: #B99758;
  margin: 0 0 14px;
}
/* The closing band was the only chapter title at 32px; the other three are 42px. */
[data-framer-name="Close Heading"] h2 { font-size: 42px !important; }

/* Section padding, from the single token. The menu carries a double top because the
   hero above it is full-bleed and contributes no bottom padding. */
[data-framer-name="Detailing Packages"] {
  padding-top: calc(var(--kore-band) * 2) !important;
  padding-bottom: var(--kore-band) !important;
}
[data-framer-name="Add-ons and Service Area"],
[data-framer-name="Studio Close"] {
  padding-top: var(--kore-band) !important;
  padding-bottom: var(--kore-band) !important;
}
@media (max-width: 810px) {
  :root { --kore-band: 44px; }
}

/* Reviews -> contact, brought in a little. The reviews chapter already ends with a lot of its
   own air: the ring reserves the depth the fanned cards swing down into, and under the centre
   card most of that is empty. Stacking two full band paddings on top of it opened a hole
   between the two chapters. Trimmed on both sides of the seam rather than one, so neither
   chapter ends up looking cropped. Studio Close gets its own rule because it shares the
   original one with the add-ons chapter, which has no such surplus above it. */
.krv-in { padding-bottom: calc(var(--kore-band) * 0.4); }
[data-framer-name="Studio Close"] { padding-top: calc(var(--kore-band) * 0.75) !important; }

/* ================= audit follow-ups ================= */
/* Social icons were 20x20 hit areas at the top of a mostly-mobile page. The glyph stays
   20px; an invisible ::after grows the target to 44x44 with no layout change. These are
   our own anchors, not Framer elements, so ::after is free here. */
.kore-social a { position: relative; }
.kore-social a::after { content: ""; position: absolute; inset: -12px; }

/* The closing paragraph ran 855px at 14px, about 122 characters per line. Comfortable
   measure is 45-75; the hero subline is already a well-judged 59. */
[data-framer-name="Studio Close Copy"] p { max-width: 62ch; }

/* Two blacks seven units apart (#171715 and #1E1E1C) read as a mismatch rather than a
   deliberate two-tone. One block, with the existing hairline doing the separation. */
[data-framer-name="KoreDetail Footer"] { background-color: var(--kore-ink) !important; }

/* ---------- sticky bar: brand + social, scroll progress on its lower edge ----------
   Hidden over the hero (which carries its own lockup), then reveals on scroll-UP and hides on
   scroll-DOWN, so it costs nothing while reading. A reserved band rather than a floating side
   rail on purpose: the reviews carousel bleeds its neighbour cards to within 8px of the viewport
   edge at 1440px, so anything pinned to the side would land on the testimonials.
   Lives as <body>'s first child, outside the Framer tree -- position:fixed resolves against the
   nearest transformed ancestor, and Framer transforms plenty of wrappers. */
.kore-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 900;
  background: rgb(255, 255, 255);
  border-bottom: 1px solid var(--kore-hair);
  transform: translateY(-100%);
  visibility: hidden;   /* not merely shifted off-screen: this keeps the CTA out of the tab order */
  transition: transform .34s cubic-bezier(.33, 1, .68, 1), visibility .34s;
}
@supports ((backdrop-filter: blur(12px)) or (-webkit-backdrop-filter: blur(12px))) {
  .kore-bar {
    background: rgba(255, 255, 255, .82);
    -webkit-backdrop-filter: saturate(1.5) blur(12px);
            backdrop-filter: saturate(1.5) blur(12px);
  }
}
.kore-bar[hidden] { display: none; }
.kore-bar.kore-bar-on { transform: none; visibility: visible; }
.kore-bar-in {
  max-width: 1200px; margin: 0 auto; padding: 9px 64px;
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
}
.kore-bar-brand { display: flex; align-items: center; gap: 12px; text-decoration: none; }
.kore-bar-logo { width: 58px; height: auto; display: block; }
.kore-bar-name { font: 800 .7rem/1 var(--kore-sans); letter-spacing: .22em; color: var(--kore-ink); white-space: nowrap; }
.kore-bar-social { display: flex; }
/* The row is cloned from the hero at runtime, so icon SVGs and hrefs stay defined once.
   Those base rules pin it absolutely into the hero -- undo that inside the bar. */
.kore-bar .kore-social { position: static; height: auto; gap: 16px; z-index: auto; }
.kore-bar .kore-social svg { width: 18px; height: 18px; }
/* Scroll progress. Chromium drives this off a scroll timeline -- pure CSS, compositor, no
   listener at all; everywhere else reveal.js writes the same transform in its rAF. */
.kore-bar-progress {
  position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  background: var(--kore-gold);
  transform: scaleX(0); transform-origin: 0 50%;
}
@supports (animation-timeline: scroll()) {
  .kore-bar-progress {
    animation-name: koreBarProgress;
    animation-duration: auto;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: scroll(root block);
  }
}
@keyframes koreBarProgress { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (max-width: 1199px) {
  .kore-bar-in { padding: 8px 20px; }
  .kore-bar .kore-social { gap: 14px; }
}
@media (max-width: 480px) {
  .kore-bar-name { display: none; }   /* logo + icons still fit; the wordmark is what runs out of room */
}
@media (prefers-reduced-motion: reduce) {
  .kore-bar { transition: none; }
}


/* ---------- one family, everywhere ----------
   The Framer export names its fonts through --framer-font-family, set inline on 13 elements
   and defaulted to Inter inside its own rules. An inline custom property loses to an
   important declaration in a stylesheet, so this is what actually unifies the page -- without
   it the tokens above would only reach the hand-authored layer and the generated headings
   would still be Bodoni. */
* { --framer-font-family: var(--kore-sans) !important; }
/* The Framer reset ends with `body,button{font-family:sans-serif}`, and it is inlined after
   this stylesheet, so anything the hand-authored layer does not name a family for never
   reached the token -- the star glyphs, the service-area labels, and every form control the
   browser was styling with its own UI font. Setting it at the root is what makes "one font
   everywhere" literally true rather than true of the parts we happened to list. */
body, button, input, select, textarea, optgroup { font-family: var(--kore-sans) !important; }

/* ---------- display treatment ----------
   With a single typeface, a heading earns its presence from weight and tracking instead of a
   change of face. Archivo tightens well: at 700 the counters stay open and the caps hold
   their colour, which is what keeps the triple P from looking like body copy scaled up. */
[data-framer-name="Welcome Heading"] h1,
[data-framer-name="Package Menu Title"] h2,
[data-framer-name="Close Heading"] h2,
.krv-title, .kqb-h, .kb-h, .kp-chap-t, .qsum-total {
  font-weight: 700 !important;
  letter-spacing: -0.02em;
}
/* The hero is the one place tracking is set in px rather than em: it is a single measured
   line under nowrap, so it is tuned against the column, not against its own size. */
[data-framer-name="Welcome Heading"] h1 { letter-spacing: -2px !important; }

/* Attached to the element itself, per the note above: .qsize sets display:grid,
   which beats the UA [hidden] rule, so the wrapper is what gets toggled. */
.qwin-f[hidden] { display: none !important; }
.qwin-span { display: block; font-size: .72rem; opacity: .68; margin-top: 2px; }

/* Turnstile mount. Rendered on demand at send (see reveal.js), so this is empty
   -- and therefore collapsed -- on every visit that never submits a form. */
.kqb-ts:empty { display: none; }
.kqb-ts { margin: 0 0 18px; }
