/* Rate cards + comparison table + a la carte for packages.html (the only
   page that links this file). Same design tokens as styles.css; nothing
   here reuses the home page's section layouts — only the shared type
   system (serif display + script accents + Work Sans labels), palette,
   buttons, and image treatments. */

/* ---------- Rate cards ---------- */

.rates { background: var(--cream); padding: clamp(3.5rem, 8vw, 6.5rem) clamp(1.25rem, 4vw, 3rem); }
.rates-head { text-align: center; margin-bottom: clamp(2.5rem, 6vw, 4rem); }
.rates-head h2 { font-family: var(--serif); font-weight: 300; font-size: clamp(2.2rem, 4.5vw, 3.2rem); line-height: 1; }
.rates-head .script { display: block; font-size: clamp(2.2rem, 4.5vw, 3.4rem); line-height: 0.9; }
.rates-head .eyebrow { color: var(--rose); margin-bottom: 1.6rem; }

.rate-cards {
  --rc-gap: clamp(1.25rem, 3vw, 2.25rem);
  max-width: 1100px;
  margin: 0 auto;
  /* FLEX, not grid, on purpose. This list is RECONCILED, so the card count is
     whatever the client's price list holds (the kit demos 3; a 5-package
     client gets 5). Grid leaves a trailing row of 1 or 2 stranded against a
     hole; flex-wrap + justify-content centres it. The inert <template> is
     display:none so it never takes a slot. */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: stretch;
  gap: var(--rc-gap);
}
.rate-cards > .rate-card {
  flex: 0 1 calc((100% - 2 * var(--rc-gap)) / 3 - 0.5px);
  min-width: 260px;
}

.rate-card {
  position: relative;
  border: 1px solid var(--ink);
  padding: 1.2rem 1.4rem 1.3rem;
  display: flex;
  flex-direction: column;
  background: #fff;
}
.rate-card--dark { background: var(--brown); color: var(--cream); border-color: var(--brown); }
.rate-number {
  position: absolute;
  top: 0.4rem;
  right: 0.9rem;
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(2.6rem, 4vw, 3.6rem);
  line-height: 1;
  color: rgba(20, 20, 20, 0.12);
}
.rate-card--dark .rate-number { color: rgba(255, 255, 255, 0.3); }
/* 3/2, tighter margins, and a vh cap: with 5-package reconciled content
   (9-row inclusion lists, 5-line descriptions) the 4/3 crop pushed the card
   to ~990px and a card never fit a laptop window. Text blocks are reconciler
   data and cannot shrink, so the figure and the spacing rhythm carry it. */
.rate-fig { overflow: hidden; margin: 1.1rem 0 0.9rem; }
.rate-fig img {
  width: 100%;
  aspect-ratio: 3 / 2;
  max-height: clamp(150px, 20vh, 200px);
  object-fit: cover;
}
/* The kit tuned crop focal points for its own demo photos via slug selectors
   (glow / moonlight). Those slugs do not exist in this build and the photos
   are the client's own, so the rules are removed rather than left dead. Add
   per-slug object-position here only if a specific card crops badly. */
@media (prefers-reduced-motion: no-preference) {
  .rate-card { transition: translate 0.35s ease, box-shadow 0.35s ease; }
  .rate-card:hover { translate: 0 -6px; box-shadow: 0 18px 40px rgba(0, 0, 0, 0.1); }
  .rate-fig img { transition: scale 0.6s ease; }
  .rate-card:hover .rate-fig img { scale: 1.05; }
}
/* padding-right reserves the corner the .rate-number watermark sits in (it
   reaches ~40px into this box at 1440 and ~27px below that). The kit's demo
   tags are all short enough to miss it by luck; real package tags are not, and
   between 901 and 1024, where the slider squeezes three cards into the row,
   even a 23-character tag ran under the numeral. Reserving the space makes a
   long tag WRAP instead, which the card already handles. */
/* The tag shipped at #cbb6ae, which is 6.58:1 on the DARK card variant it was
   evidently picked against but only 1.72:1 on the cream ground every light card
   actually sits on: 11px uppercase label text, effectively unreadable, and the
   kit renders it that way too, so this is an inherited miss rather than one this
   build introduced. Darkened along the same warm rose hue to the first value
   clearing 4.5:1 on cream (4.59), keeping it lighter than the --rose price line
   below it, which is the tonal step the design wanted. The dark-variant override
   mirrors the .rate-card--dark .rate-price rule two declarations down, so a dark
   card cannot inherit a value measured for cream (it would read 2.46:1). */
.rate-tag {
  font-family: var(--label);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #886558;
  margin-bottom: 0.2rem;
  padding-right: 2.5rem;
}
.rate-card--dark .rate-tag { color: #cbb6ae; }
.rate-card h3 {
  font-size: clamp(2rem, 3vw, 2.6rem);
  line-height: 1;
  margin-bottom: 0.5rem;
}
.rate-price {
  font-family: var(--label);
  font-size: 0.8125rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--rose);
  margin-bottom: 0.8rem;
}
.rate-card--dark .rate-price { color: #cbb6ae; }
.rate-blurb {
  font-family: 'Raleway', var(--body);
  font-size: 0.95rem;
  line-height: 1.5;
  margin-bottom: 0.8rem;
}
/* margin-bottom is AUTO, not a fixed 1.8rem, because this list is reconciled:
   its length is whatever that package's client_packages.inclusions holds (9
   rows on ELITE GLAM, 4 on SIGNATURE SOCIAL). Cards in the row are equal
   height, so the slack has to go somewhere. Sending it here pins the CTA to the
   foot of every card; when it sat on the button instead, the short cards opened
   a ~240px hole above it. The minimum gap now lives on .btn below. */
.rate-list {
  list-style: none;
  border-top: 1px solid rgba(20, 20, 20, 0.25);
  padding-top: 0.9rem;
  margin-bottom: auto;
  display: grid;
  gap: 0.35rem;
}
.rate-card--dark .rate-list { border-top-color: rgba(255, 255, 255, 0.35); }
.rate-list li {
  font-family: 'Raleway', var(--body);
  font-size: 0.875rem;
  line-height: 1.4;
  position: relative;
  padding-left: 1.1em;
}
.rate-list li::before {
  content: '+';
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--serif);
  font-weight: 300;
  color: var(--rose);
}
.rate-card--dark .rate-list li::before { color: #cbb6ae; }
/* The cross-link that used to sit between the list and the CTA was removed
   (owner, 2026-08-02), so the CTA is now the only thing below the bullets and
   this gap is the whole foot of the card. */
.rate-card .btn { margin-top: 1.4rem; align-self: start; }

/* ---------- Small screens ---------- */

@media (max-width: 800px) {
  /* Mobile type scale matching the home page's vw-based canvas */
  .rates-head h2 { font-size: 8.4vw; }
  .rates-head .script { font-size: 10.9vw; }
  .rate-cards { gap: 2rem; }
  .rate-cards > .rate-card { flex: 1 1 100%; }
  /* Leave the focal point CENTRED. The phone crop is far wider (1.79) than the
     sources (~1.26), so ~128px is lost off the top AND the bottom, and biasing
     the window upward to save the back row's hair was tried and reverted: on
     p15 and p09 it cut the FRONT subject's face at the mouth, which is the
     worse defect of the two. Centre keeps every face whole. */
  .rate-fig img { aspect-ratio: 240 / 134; }
}

/* ---------- package cards: count-aware layout (see the JS in services.js) ----
   Four or more package cards turn the row into a one-row slider with arrows.
   At three or fewer nothing here applies and the list renders as designed.
   Recovered from live San Diego 2026-07-28; canonical copy in design-01. */
@media (min-width: 901px) {
  .rate-cards.is-slider {
    display: flex; justify-content: flex-start; flex-wrap: nowrap;
    /* BOTH axes hidden, NOT auto: the arrows are the only way the rail moves.
       As an auto scroller with x-mandatory snap it captured trackpad gestures.
       And overflow-x alone is not enough: a lone overflow-x forces overflow-y
       to compute to auto, and the hover-lift headroom (padding-top 22px /
       margin-top -22px) leaves ~26px of vertical overflow, so the rail became
       a 26px-deep vertical scroller that latched the wheel and froze PAGE
       scrolling over the whole section. hidden blocks user scrolling on both
       axes while scrollTo() in services.js keeps working. */
    overflow: hidden;
    padding-top: 22px; margin-top: -22px;
  }
  .rate-cards.is-slider > article {
    flex: 0 0 calc((100% - 2 * var(--rc-gap, 2.25rem)) / 3);
  }
}
.svc-pkg-shell { position: relative; }
.svc-pkg-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 5;
  width: 48px; height: 48px; border-radius: 50%; cursor: pointer;
  background: #fff; border: 1px solid rgba(0, 0, 0, .25); color: inherit;
  font-size: 24px; line-height: 1; display: none;
  align-items: center; justify-content: center;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .14);
  transition: background .35s, color .35s, border-color .35s;
}
@media (min-width: 901px) { .svc-pkg-shell .svc-pkg-arrow { display: inline-flex; } }
.svc-pkg-arrow:hover { background: #111; color: #fff; border-color: #111; }
.svc-pkg-arrow:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.svc-pkg-prev { left: -22px; }
.svc-pkg-next { right: -22px; }

/* ---------- rate cards: the SOLO layout (services.js adds .is-solo) ----------
   One package is its own layout, not a third of a row. The flex row above puts
   a lone card in a ~340px column stranded in the middle of an 1100px section,
   which reads as a broken grid rather than a design.

   .is-solo unfolds the SAME card into an editorial split: photo left, the
   package read top to bottom on the right. No markup changes, so the reconciler
   (src/site_prices.js) still clones and removes cards exactly as before, and the
   class comes from the DOM card count at load, so a portal save that adds a
   second package drops straight back to the grid with nothing rebuilt.

   Desktop only. Under 800px the row is already a full width stack, which is the
   right answer for one card too. */
@media (min-width: 801px) {
  .rate-cards.is-solo { display: block; }
  .rate-cards.is-solo > .rate-card {
    max-width: 1100px; margin-inline: auto;
    display: grid;
    grid-template-columns: 0.78fr 1.22fr;
    /* six rows for the six children that sit in column 2; the inclusions take
       the 1fr so the CTA lands on the bottom edge whatever the copy length */
    grid-template-rows: auto auto auto auto 1fr auto;
    column-gap: clamp(1.8rem, 3.4vw, 3.2rem);
    padding: clamp(1.6rem, 2.4vw, 2.4rem);
  }
  /* the photo IS the left column: full height, rectangular, no vh cap (that cap
     exists to keep three cards in a row on a laptop, which does not apply here) */
  .rate-cards.is-solo .rate-fig {
    grid-column: 1; grid-row: 1 / -1;
    align-self: stretch; margin: 0; height: 100%;
  }
  .rate-cards.is-solo .rate-fig img {
    height: 100%; width: 100%; aspect-ratio: auto; max-height: none; object-fit: cover;
    /* the booth sits right of centre in this frame; a centred crop leads with
       the gilt picture behind it instead of the thing being sold */
    object-position: 72% center;
  }
  .rate-cards.is-solo .rate-tag,
  .rate-cards.is-solo .rate-card h3,
  .rate-cards.is-solo .rate-price,
  .rate-cards.is-solo .rate-blurb,
  .rate-cards.is-solo .rate-list,
  .rate-cards.is-solo .rate-card > .btn { grid-column: 2; }

  .rate-cards.is-solo .rate-list { align-self: start; margin-bottom: 0; }
  .rate-cards.is-solo .rate-card > .btn { align-self: end; justify-self: start; margin-top: 1.4rem; }
  /* the corner ordinal is a position in a set; there is no set */
  .rate-cards.is-solo .rate-number { display: none; }
  .rate-cards.is-solo .rate-tag { padding-right: 0; }
}
@media (min-width: 801px) and (prefers-reduced-motion: no-preference) {
  /* a full width band that jumps 6px on hover reads as a bug, not a nicety */
  .rate-cards.is-solo > .rate-card:hover { translate: none; box-shadow: none; }
}
