/* packages.html page geometry (flow layer lives in css/patterns.css):
   the rate-card hero, the add-ons carousel, the rotating quotes, and the
   pricing FAQ accordion. All selectors are page-scoped (svc-*, qrot, qa-acc)
   so this file is inert elsewhere. */

/* ---- hero: the rate card ---- */
.svc-hero { background: var(--black); color: var(--cream-text); overflow: hidden; }
.svc-hero-wrap { max-width: 1200px; margin: 0 auto; padding: 148px 60px 0;
  display: grid; grid-template-columns: 7fr 5fr; gap: 64px; align-items: center; }
.svc-kicker { margin: 0 0 24px; font-family: var(--font-pop); font-weight: 300;
  font-size: 13px; letter-spacing: .24em; text-transform: uppercase; opacity: .8; }
.svc-h1 { margin: 0; font-family: var(--font-serif); font-weight: 400;
  font-size: 68px; line-height: 1.08; }
.svc-h1 em { font-family: var(--font-italic); font-style: normal; }
.svc-lede { margin: 26px 0 0; max-width: 480px; font-family: var(--font-pop);
  font-weight: 300; font-size: 16px; line-height: 1.6; letter-spacing: .02em; }
.svc-ctas { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 38px; }
.svc-hero .btn { min-height: 48px; padding: 14px 26px; }
.svc-btn-solid { background: var(--cream); border-color: var(--cream); color: var(--ink); }
.svc-btn-solid:hover { background: var(--accent); border-color: var(--accent); color: var(--cream-text); }

.svc-hero-media { position: relative; }
.svc-hero-media > img,
.svc-hero-media > video { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }

/* giant serif ticker at the hero's foot (marquee machinery from style.css) */
.svc-ticker { margin-top: 64px; padding: 26px 0 34px;
  border-top: 1px solid rgba(241,243,246,.18); }
.svc-ticker span { font-family: var(--font-serif); font-size: 92px; line-height: 1.1;
  text-transform: uppercase; color: var(--cream-text); opacity: .22; white-space: nowrap; }

/* hero load choreography */
@keyframes svc-rise { from { opacity: 0; transform: translateY(26px); }
  to { opacity: 1; transform: none; } }
@keyframes svc-settle { from { transform: scale(1.06); } to { transform: none; } }
.svc-hero-copy > *, .svc-hero-media { animation: svc-rise .9s ease both; }
.svc-kicker { animation-delay: .05s; }
.svc-h1 { animation-delay: .15s; }
.svc-lede { animation-delay: .3s; }
.svc-ctas { animation-delay: .45s; }
.svc-hero-media { animation-delay: .3s; }
.svc-hero-media > img,
.svc-hero-media > video { animation: svc-settle 2.2s ease-out both; }

/* ---- the foundation: editorial split with menu rows ---- */
.svc-found { display: grid; grid-template-columns: 5fr 6fr; gap: 72px; align-items: start; }
.svc-found-list { list-style: none; margin: 0; padding: 0; }
.svc-found-list li { display: grid; grid-template-columns: 86px 1fr; gap: 0 24px;
  padding: 30px 0 32px; border-top: 1px solid var(--line); }
.svc-found-list li:last-child { border-bottom: 1px solid var(--line); }
.svc-found-list h3 { margin: 0; font-family: var(--font-serif); font-weight: 400;
  font-size: 26px; line-height: 1.2; }
.svc-found-list p { margin: 10px 0 0; font-family: var(--font-pop); font-weight: 300;
  font-size: 15px; line-height: 1.6; }

/* ---- packages: cards lift on hover ----
   The featured card used to ride 24px high (`transform: translateY(-24px)`).
   That came out 2026-08-06 with the equal-length cards below: once the four
   are the same length, one of them sitting proud reads as a different SIZE
   rather than as emphasis, and the dark fill already carries that job. The
   lift also outranked `.fade-in.is-in`'s `transform: none` (1-2-0 vs 0-2-0),
   so the featured card was the one card on the page that never played the
   reveal rise. Removing the rule fixes both; do not re-add it as an override,
   re-add it here or not at all. */
#packages .pcard { transition: transform .5s ease; }
#packages .pcard-price { font-size: 44px; }
@media (min-width: 901px) {
  #packages .card-grid { margin-top: 78px; }
  #packages .pcard:hover { transform: translateY(-8px); }
}

/* ---- add-ons carousel (replaces the estimator; lives on the fl-dark band) ---- */
.svc-addons .svc-addons-head { max-width: 660px; margin-bottom: clamp(44px, 5vw, 66px); }
.svc-addons .svc-addons-head .fl-lede { max-width: 640px; }

/* click-through carousel: one slide per add-on, count-agnostic */
.svc-carousel-viewport { overflow: hidden; }
.svc-carousel-track { display: flex; transition: transform .6s cubic-bezier(.2,.7,.2,1);
  will-change: transform; }
.svc-slide { flex: 0 0 100%; display: grid;
  grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
  border: 1px solid var(--line); background: rgba(241,243,246,.04);
  overflow: hidden; transition: opacity .6s ease; }
.svc-slide[aria-hidden="true"] { opacity: .18; }

.svc-slide-media { position: relative; overflow: hidden; height: clamp(360px, 38vw, 480px); }
.svc-slide-media img,
.svc-slide-media video { display: block; width: 100%; height: 100%; object-fit: cover; }
/* The photo fills its card. The slides share one height (the track is a flex
   row), set by the LONGEST description, while the photo had a fixed height, so
   one long add-on left a blank strip under every photo: 94px at 1440 and 163px
   at 901 on Posie, whose Day-of Coordinating copy runs five lines. On the
   two-column layout the photo now stretches with its grid row, and the old
   fixed height stays as its floor, so a short card looks exactly as before.
   The stacked phone layout keeps its fixed 260px photo (rule below). */
@media (min-width: 901px) {
  .svc-slide-media { height: auto; min-height: clamp(360px, 38vw, 480px); }
}
.svc-slide-tag { position: absolute; top: 20px; left: 20px;
  background: var(--accent); color: var(--cream-text); padding: 8px 16px;
  font-family: var(--font-mont); font-weight: 500; font-size: 10px;
  letter-spacing: .22em; text-transform: uppercase; }

.svc-slide-body { display: flex; flex-direction: column; justify-content: center;
  padding: clamp(32px, 4vw, 60px); }
.svc-slide-index { margin: 0 0 22px; font-family: var(--font-pop); font-weight: 300;
  font-size: 12px; letter-spacing: .24em; text-transform: uppercase;
  color: rgba(241,243,246,.55); }
.svc-slide-index b { color: var(--accent-lift); font-weight: 400; }
.svc-slide-top { display: flex; align-items: baseline; justify-content: space-between; gap: 20px; }
.svc-slide-name { margin: 0; font-family: var(--font-serif); font-weight: 400;
  font-size: clamp(28px, 3.2vw, 42px); line-height: 1.1; }
.svc-slide-price { font-family: var(--font-italic); font-size: clamp(24px, 2.6vw, 34px);
  line-height: 1; color: var(--accent-lift); white-space: nowrap; }
/* The price sits beside the add-on name and drops under it only when the two
   cannot share the row (a long name on the narrowest phones overflowed the
   slide). The name sizes from zero, so only an item that truly does not fit
   wraps: wherever a price fitted beside the name before, the row lays out
   exactly as it did. A hidden price leaves this area BLANK: the whole
   .svc-slide-price carries data-bc-if-price (owner, 2026-10-08: never a giant
   "Inquire for pricing" beside the name). */
.svc-slide-top { flex-wrap: wrap; row-gap: 8px; }
.svc-slide-name { flex: 1 1 0; }
.svc-slide-blurb { margin: 24px 0 0; max-width: 46ch; font-family: var(--font-pop);
  font-weight: 300; font-size: 15px; line-height: 1.75; color: rgba(241,243,246,.75); }

.svc-addon-add { align-self: flex-start; margin-top: 32px; display: inline-flex;
  align-items: center; gap: 12px; padding: 0; background: none; border: 0; cursor: pointer;
  font-family: var(--font-mont); font-weight: 400; font-size: 11px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--cream-text); transition: color .4s; }
.svc-addon-add:hover { color: var(--accent-lift); }
.svc-addon-add:focus-visible { outline: 1px solid var(--accent-lift); outline-offset: 5px; }
.svc-addon-add-i { width: 32px; height: 32px; flex: none; display: inline-flex;
  align-items: center; justify-content: center; border: 1px solid rgba(241,243,246,.4);
  border-radius: 50%; font-size: 18px; line-height: 1;
  transition: transform .5s cubic-bezier(.2,.7,.2,1), background-color .4s, color .4s, border-color .4s; }
.svc-addon-add:hover .svc-addon-add-i { border-color: var(--accent-lift); }
.svc-slide.is-added .svc-addon-add-i { background: var(--accent); border-color: var(--accent);
  color: var(--cream-text); transform: rotate(45deg); }

/* nav: arrows flanking the dots (JS hides the row when there is one slide) */
.svc-carousel-nav { margin-top: clamp(28px, 3vw, 40px); display: flex; align-items: center;
  justify-content: center; gap: 22px; }
.svc-carousel-arrow { width: 50px; height: 50px; flex: none; border-radius: 50%; cursor: pointer;
  background: none; border: 1px solid rgba(241,243,246,.35); color: var(--cream-text);
  font-family: var(--font-serif); font-size: 24px; line-height: 1; display: inline-flex;
  align-items: center; justify-content: center;
  transition: background-color .4s, color .4s, border-color .4s; }
.svc-carousel-arrow:hover { background: var(--accent); color: var(--cream-text); border-color: var(--accent); }
.svc-carousel-arrow:focus-visible { outline: 1px solid var(--accent-lift); outline-offset: 3px; }
.svc-carousel-dots { display: flex; align-items: center; gap: 12px; }
.svc-carousel-dots button { width: 8px; height: 8px; border-radius: 50%; border: 0; padding: 0;
  cursor: pointer; background: rgba(241,243,246,.3); transition: background-color .3s, transform .3s; }
.svc-carousel-dots button.is-live { background: var(--accent-lift); transform: scale(1.4); }

.svc-addons-foot { margin-top: clamp(34px, 4vw, 50px); display: flex; align-items: center;
  justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.svc-addons-note { max-width: 46ch; margin: 0; font-family: var(--font-pop); font-weight: 300;
  font-size: 13px; line-height: 1.6; color: rgba(241,243,246,.6); }
.svc-addons-foot .btn { min-height: 48px; }

/* ---- rotating quotes ---- */
.qrot { position: relative; text-align: center; }
.qrot::before { content: "\201C"; position: absolute; left: 50%; top: 66px;
  transform: translateX(-50%); font-family: var(--font-serif); font-size: 240px;
  line-height: 1; opacity: .08; pointer-events: none; }
.qrot-stage { position: relative; min-height: 250px; }
.qrot-stage figure { position: absolute; inset: 0; margin: 0; opacity: 0;
  transition: opacity .8s ease; display: flex; flex-direction: column;
  justify-content: center; }
.qrot-stage figure.is-on { opacity: 1; }
.qrot-stage blockquote { margin: 0 auto; max-width: 880px;
  font-family: var(--font-italic); font-size: 36px; line-height: 1.3; }
.qrot-stage figcaption { margin-top: 26px; font-family: var(--font-pop);
  font-weight: 300; font-size: 15px; }
.qrot-stage figcaption span { display: block; opacity: .65; font-size: 13px; margin-top: 4px; }
.qrot-dots { display: flex; justify-content: center; gap: 12px; margin-top: 36px; }
/* color: inherit is load-bearing: iOS WebKit's UA button color is the system
   BLUE and `color` does not inherit into form controls, so without it every
   currentColor below paints the dots blue on an iPhone (fine in Chrome). */
.qrot-dots button { width: 9px; height: 9px; border-radius: 50%;
  border: 1px solid currentColor; background: transparent; padding: 0;
  cursor: pointer; opacity: .5; color: inherit; -webkit-appearance: none; appearance: none; }
.qrot-dots button.is-on { background: currentColor; opacity: 1; }

/* ---- pricing FAQ accordion (progressive: without js every answer stays open) ---- */
.qa-acc .qa-q button { display: flex; width: 100%; align-items: baseline;
  justify-content: space-between; gap: 20px; background: none; border: 0;
  padding: 0; margin: 0; color: inherit; font: inherit; text-align: left;
  cursor: pointer; }
.qa-tog { flex: none; font-family: var(--font-italic); font-size: 17px;
  opacity: .65; white-space: nowrap; transition: opacity .3s ease; }
.qa-tog::before { content: "( Open )"; }
.qa-item.is-open .qa-tog::before { content: "( Close )"; }
.qa-acc .qa-q button:hover .qa-tog { opacity: 1; }
.qa-acc .qa-body { grid-column: 2; }
.qa-acc.js .qa-body { display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .55s ease; }
.qa-acc.js .qa-item.is-open .qa-body { grid-template-rows: 1fr; }
.qa-acc.js .qa-clip { min-height: 0; overflow: hidden; }

/* ---- motion off ---- */
@media (prefers-reduced-motion: reduce) {
  .svc-hero-copy > *,
  .svc-hero-media,
  .svc-hero-media > img,
  .svc-hero-media > video { animation: none; }
  .svc-ticker .marq-track { animation: none; }
  #packages .pcard { transition: none; }
  .qa-acc.js .qa-body { transition: none; }
  .svc-carousel-track { transition: none; }
}

/* ---- mobile (kit breakpoint) ---- */
/* Guest Book slide (the 4-up print): two framings, because the slide media is a tall box on desktop and a
   wide one under 900px. Keyed on the add-on slug, not nth-of-type, since the price-list sync reorders slides.
   Launch photo audit 2026-10-17: at 344x260 the 0% 20% framing cut the lower row through the eyes. */
.svc-slide[data-bc-pkg="guest-book"] img { object-position: 0% 20%; }
@media (max-width: 900px) {
  /* What's included: the three sublines show on desktop only (owner, 2026-10-17: on a phone the
     three headings stand alone). */
  #whats-included li > div > p { display: none; }
  .svc-slide[data-bc-pkg="guest-book"] img { object-position: 0% 100%; }
  .svc-hero-wrap { grid-template-columns: 1fr; gap: 46px; padding: 108px 22px 0; }
  .svc-h1 { font-size: clamp(38px, 11vw, 50px); }
  .svc-ctas { flex-direction: column; margin-top: 30px; }
  .svc-hero .btn { width: 100%; max-width: 340px; }
  .svc-ticker { margin-top: 46px; padding: 18px 0 24px; }
  .svc-ticker span { font-size: 44px; }

  .svc-found { grid-template-columns: 1fr; gap: 34px; }
  .svc-found-list li { grid-template-columns: 62px 1fr; gap: 0 16px; padding: 24px 0 26px; }

  .svc-slide { grid-template-columns: 1fr; }
  .svc-slide-media { height: 260px; }
  .svc-addons-foot { flex-direction: column; align-items: flex-start; }
  .svc-addons-foot .btn { width: 100%; }

  .qrot::before { font-size: 150px; top: 120px; }
  .qrot-stage { min-height: 330px; }
  .qrot-stage blockquote { font-size: 24px; }

  .qa-acc .qa-body { grid-column: 1; }
}

/* ---- packages hero: fixed photo backdrop under a dark overlay -------------
   Built as a position:fixed LAYER clipped by the section's clip-path, not
   background-attachment:fixed. A fixed background cannot be promoted to a
   compositor layer, so it repaints the full-bleed photo on every scroll frame,
   which is the stutter; clip-path clips descendants without becoming their
   containing block, so the layer stays viewport-anchored and the parallax
   reads the same. It also works on iOS, where attachment:fixed is effectively
   broken. Same technique as the home hero (css/home.css .sec-hero::before).
   The overlay rides in the same layer stack as the photo, so there is one
   painted element and the hero's own content only needs lifting above it.
   BUILD: swap the photo per client and re-measure the overlay alpha. .82 is
   what carries cream copy past AA on this photo's lightest patches; a brighter
   photo needs more, and the probe is the layout-audit contrast check. */
.svc-hero { position: relative; clip-path: inset(0); }
.svc-hero::before { content: ""; position: fixed; inset: 0; z-index: 0;
  background:
    linear-gradient(rgba(19,19,19,.82), rgba(19,19,19,.82)),
    url("../images/packages-hero.jpg") center / cover no-repeat; }
.svc-hero-wrap, .svc-ticker { position: relative; z-index: 1; }

/* ---- packages hero: exactly one window tall --------------------------------
   The section is a flex column: the wrap takes the slack so the ticker always
   sits on the bottom edge, and every part that would otherwise pin a minimum
   height is viewport-derived instead. The 4/5 photo is the real driver (529px
   at a 940 window), so it is given an explicit vh height with object-fit
   already doing the cropping; the display type and the ticker scale with it.
   Scoped to the slider's 901px breakpoint: below that the hero stacks and a
   phone should scroll it, not squeeze it. */
@media (min-width: 901px) {
  .svc-hero { min-height: 100vh; display: flex; flex-direction: column; }
  .svc-hero-wrap { flex: 1 1 auto; align-content: center;
    padding-top: clamp(76px, 11vh, 148px);
    padding-bottom: clamp(12px, 2.4vh, 36px); }
  .svc-hero-media > img,
  .svc-hero-media > video { aspect-ratio: auto; height: clamp(240px, 42vh, 560px); }
  .svc-h1 { font-size: clamp(34px, 5.4vh, 68px); }
  .svc-lede { margin-top: clamp(14px, 2.4vh, 26px); }
  .svc-ctas { margin-top: clamp(18px, 3.4vh, 38px); }
  .svc-kicker { margin-bottom: clamp(12px, 2.2vh, 24px); }
  .svc-ticker { margin-top: 0; flex: 0 0 auto;
    padding: clamp(12px, 2.2vh, 26px) 0 clamp(16px, 3vh, 34px); }
  .svc-ticker span { font-size: clamp(40px, 8.5vh, 92px); }
}

/* ---- package cards: all the same length -----------------------------------
   The shared .card-grid's `align-items: start` is what staggers them, so the
   grid stretches here and the CTA is pinned to the foot: the bottoms line up
   whatever the inclusion count, which is the whole point when the counts are
   the client's and unknown at kit time. Pairs with the featured-card change
   above; reverting is a one-block delete. */
@media (min-width: 901px) {
  #packages .card-grid { align-items: stretch; }
  #packages .pcard { position: relative; padding-bottom: 50px; }
  #packages .pcard ul { margin-bottom: 20px; }
  #packages .pcard .btn { margin-top: auto; }
  #packages .pcard-link { position: absolute; left: 28px; right: 28px; bottom: 24px; margin: 0; }
}

/* The 50px reserve above fits a ONE LINE .pcard-link (21px tall, sitting 24px
   off the card foot, clearing the CTA by 5px). The link is out of flow, so the
   reserve cannot grow with it: once the column narrows enough for the label to
   wrap to two lines the link is 42px tall, needs 66px, and climbs 16px INTO the
   button, striking through its bottom border and printing the first line of
   link text across the control. Measured on the Desert Glow build at every
   10px from 1140 down to 901: the wrap starts at 1090 (link box 247.5px, one
   line still fits at 250.8px) and the 16px collision then holds all the way to
   the 901 breakpoint. 71px = 24 bottom + 42 two lines + the same 5px clearance.
   Only the CARD padding moves, so every CTA stays on one baseline and the link
   itself does not shift; the band is capped at 1199 rather than the measured
   1090 so a longer label wraps into headroom instead of into the button.
   Above 1199 nothing changes. (The occasion page carries this same #packages
   section since 2026-10-07, so one rule covers both pages.) */
@media (min-width: 901px) and (max-width: 1199px) {
  #packages .pcard { padding-bottom: 71px; }
}

/* her accents on the packages page's own bands (see style.css for the rule) */
.svc-kicker { color: var(--accent-lift); }
.qrot .fl-kicker { color: var(--accent); opacity: 1; }


/* THE ADD-ON SLOT ALWAYS SHIPS, and hides itself until the client actually has
   an add-on, so a price list with none never renders an empty band. The inert
   <template data-bc-pkg-item> lives in a separate DocumentFragment, so :has()
   cannot see it, and the section reappears on its own the moment
   src/site_prices.js clones a real card. Never delete #addons from a build to
   "tidy up" a client who has no add-ons today: that is the one-way door this
   rule exists to replace. */
#addons:not(:has([data-bc-pkg])) { display: none; }

/* #addons sits on the DARK band (.fl-dark) since 2026-09-30, the ground the
   .svc-* carousel styles above were written for, so it needs no restatement.
   It spent a month on .fl-cream beside a second, fixed showcase carousel
   (#custom-design) with a block of light-ground twins here; the showcase was
   deleted (owner: one carousel per page, the add-on one) and the twins went
   with it. If the band ever moves back to a light ground, every foreground
   above is cream and every accent is --accent-lift, so each needs a light twin
   (--accent on light, ink for text) or it renders cream-on-cream. */


/* The accent note was removed from the add-ons footer (owner, 2026-08-27).
   The footer is a flex row at justify-content: space-between, so with the note
   gone its one remaining child (the button) would jump from the right edge to
   the left. Guarded on the note being ABSENT, so a footer that still carries
   one keeps the original two-up layout untouched. */
.svc-addons-foot:not(:has(.svc-addons-note)) { justify-content: flex-end; }
