/* ============================================================
   Prime Shine — page layer. Loads last. Layout and the hero
   logo animation only; components live in kit.css and brand.css.
   ============================================================ */

/* ---- Hero -------------------------------------------------------------
   Split: brand + message on the left, real proof on the right.

   THE CONSTRAINT THAT SHAPES EVERYTHING HERE: the two buttons must be above
   the fold on a real laptop. Measured 13 Aug, the first build pushed them
   244px below the fold at 1366x768 and 113px below on a MacBook Air, because
   a browser eats 150-200px in tabs, address bar and bookmarks that a naive
   1920x1080 test never sees. A hero CTA you have to scroll to find is not a
   hero CTA. Every size below is capped against viewport HEIGHT as well as
   width so it self-corrects on a short screen instead of needing a
   breakpoint per laptop. */
.ps-hero { position: relative; overflow: hidden; background: var(--surface-page); }
.ps-hero__grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.02fr);
  gap: clamp(1.6rem, 4vw, 4rem); align-items: center;
  padding-block: clamp(1.2rem, 2.6vh, 2.75rem);
}
.ps-hero__copy { position: relative; z-index: 2; }
.ps-hero h1 {
  font-size: clamp(1.95rem, min(1.3rem + 2.3vw, 5.2vh), 3.25rem);
  line-height: 1.05; letter-spacing: -0.035em; margin: 0 0 .75rem; text-wrap: balance;
}
.ps-hero h1 em { font-style: normal; color: var(--ps-blue); }
.ps-hero .lead {
  max-width: 52ch; margin: 0 0 1.25rem; color: var(--text-muted);
  font-size: clamp(.98rem, 2.2vh, 1.12rem);
}
.ps-hero__micro {
  margin: .9rem 0 0; font-size: var(--cb-type-scale-small); color: var(--text-muted); max-width: 46ch;
}
.ps-hero__media { position: relative; z-index: 2; }
@media (max-width: 900px) {
  .ps-hero__grid { grid-template-columns: 1fr; gap: 2rem; padding-block: 1.5rem 2.5rem; }
}

/* ---- The animated logo -------------------------------------------------
   The <img> is the logo artwork, untouched. The <svg> sits on top in
   the SAME coordinate space: both children fill the wrapper, the wrapper is
   locked to the artwork's own aspect ratio, and the SVG viewBox equals the
   trimmed pixel size (929x744). Identical box, identical fitting rule, so
   the overlay cannot drift at any width, with no JS and no resize handler.

   Nothing here draws a NEW jet. The logo already has one; a second would read
   as a bug. Every moving part is traced onto the artwork that is already
   there: two highlight passes and droplets along the drawn jet's own curve,
   bubbles rising out of the drawn foam, one shine across the wordmark.     */
.hero-logo {
  position: relative; display: block;
  /* min() against vh is what keeps the CTAs above the fold on a laptop.
     Sized to spend the measured slack: after the first pass the CTAs cleared
     the fold by 118-317px depending on screen, so the cap went back up until
     the tightest common case (1366x768) still had ~90px in hand. Resolves to
     ~187px on that laptop and 300px on a tall desktop. */
  width: clamp(150px, min(21vw, 30vh), 300px);
  aspect-ratio: 929 / 744;          /* zero CLS: the box is known before load */
  margin: 0 0 1rem;
}
.hero-logo__img,
.hero-logo__fx { position: absolute; inset: 0; width: 100%; height: 100%; }
.hero-logo__img { object-fit: contain; }
.hero-logo__fx { overflow: visible; pointer-events: none; }

/* The hero logo is a STATIC image. An animated overlay was built twice and
   removed twice by decision. Do not add a third without asking.
   The generator is kept at /root/clients/prime-shine/logo-overlay-generator.py.

   What stays here is load-bearing, not decorative: the width is capped against
   viewport HEIGHT as well as width, which is what keeps the hero CTAs above
   the fold on a laptop, and the aspect-ratio holds CLS at zero because the box
   is known before the image loads. */

/* ---- Section rhythm ---- */
.ps-sec { padding-block: clamp(3rem, 7vw, 6rem); }
.ps-sec--alt { background: var(--surface-alt); }
.ps-sec--ink { background: var(--ps-navy); color: #fff; }
.ps-sec--ink h2, .ps-sec--ink .eyebrow { color: #fff; }
.ps-sec--ink p { color: rgba(255,255,255,.82); }
.ps-sec--ink .eyebrow { color: var(--ps-water-pale); }
.ps-head { max-width: 60ch; margin-bottom: clamp(1.8rem, 4vw, 3rem); }
.ps-head h2 { margin: .35rem 0 .7rem; letter-spacing: -0.03em; text-wrap: balance; }
.ps-head p { color: var(--text-muted); margin: 0; }
.ps-sec--ink .ps-head p { color: rgba(255,255,255,.82); }
.eyebrow {
  font-family: var(--cb-font-heading_family); font-size: .72rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ps-blue); display: block;
}

/* ---- Two-column proof block ---- */
.ps-split { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1.1fr); gap: clamp(1.8rem, 4vw, 3.5rem); align-items: center; }
@media (max-width: 880px) { .ps-split { grid-template-columns: 1fr; } }

/* ---- Areas ---- */
.areas { display: flex; flex-wrap: wrap; gap: .5rem; }
.areas li {
  list-style: none; font-size: var(--cb-type-scale-small); font-weight: 500;
  padding: .45rem .95rem; border: 1px solid var(--surface-rule); border-radius: 999px; color: var(--text-muted);
}
.areas li:first-child { border-color: var(--ps-blue); color: var(--ps-blue); }

/* ---- Contact rows ---- */
.crow { display: flex; align-items: center; gap: .85rem; padding: .95rem 0; border-bottom: 1px solid var(--surface-rule); text-decoration: none; color: inherit; }
.crow:last-child { border-bottom: 0; }
.crow svg { width: 1.35rem; height: 1.35rem; color: var(--ps-blue); flex: none; }
.crow span { display: block; font-size: .7rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-muted); }
.crow b { font-weight: 600; font-size: 1.02rem; word-break: break-word; }

/* ---- FAQ ---- */
.faq details { border-bottom: 1px solid var(--surface-rule); padding: 1rem 0; }
.faq summary { cursor: pointer; font-weight: 600; font-size: 1.05rem; list-style: none; display: flex; justify-content: space-between; gap: 1rem; min-height: 44px; align-items: center; }   /* 44, not 32: this is a tap target. brand.css used to also declare 44 and lost the cascade to this line, so the accessible value sat here dead. One owner now. */
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--ps-blue); font-size: 1.5rem; line-height: 1; flex: none; }
.faq details[open] summary::after { content: "\2013"; }
.faq p { color: var(--text-muted); margin: .7rem 0 0; max-width: 66ch; }

/* ---- Footer ---- */
.ps-foot { background: var(--ps-navy); color: rgba(255,255,255,.78); padding-block: clamp(2.5rem, 5vw, 4rem) 1.5rem; }
.ps-foot a { color: rgba(255,255,255,.78); text-decoration: none; }
.ps-foot a:hover { color: #fff; text-decoration: underline; }
.ps-foot__grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr; gap: clamp(1.5rem, 4vw, 3rem); }
.ps-foot__brand b { display: block; color: #fff; font-family: var(--cb-font-heading_family); font-size: 1.15rem; letter-spacing: -0.02em; margin-bottom: .5rem; }
.ps-foot h3 { color: #fff; font-size: .78rem; letter-spacing: .14em; text-transform: uppercase; margin: 0 0 .9rem; }
.ps-foot ul { list-style: none; padding: 0; margin: 0; display: grid; gap: .55rem; font-size: .93rem; }
.ps-foot__base { margin-top: 2.2rem; padding-top: 1.3rem; border-top: 1px solid rgba(255,255,255,.16); display: flex; flex-wrap: wrap; gap: .6rem 1.4rem; justify-content: space-between; font-size: .84rem; }
@media (max-width: 720px) { .ps-foot__grid { grid-template-columns: 1fr; } }

/* ---- Utility ---- */
.vh { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.btn { min-height: 48px; display: inline-flex; align-items: center; justify-content: center; gap: .5rem; }
.btn svg { width: 1.15em; height: 1.15em; }
img { max-width: 100%; }

/* ---- Reviews wall ------------------------------------------------------
   Found 27 Aug 2026 by measuring the deployed page, not by reading markup.

   .quotes (kit.css) is `display:grid` with the default `align-items:stretch`,
   so every card in a row takes the height of the tallest one in that row.
   Nine real Google reviews range from 15 words to 120, and six of the nine
   cards rendered with between 223px and 630px of empty white below the
   customer's name. On a 1366px laptop the reviews section alone ran to about
   4,000px of mostly nothing.

   The fix is not "stop stretching" on its own: that just makes the bottoms
   ragged. The quote is clamped to seven lines so the cards start out close
   in height, the name is pushed to the bottom of whatever height the row
   gives, and a card can be opened in place. Opening one switches the whole
   grid to `align-items:start` so the expanded card grows on its own instead
   of dragging its two neighbours' dead space back. */
.quote { display: flex; flex-direction: column; }
.quote blockquote { margin: 0; }
.quote blockquote p {
  margin: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 7;
  overflow: hidden;
}
.quotes.has-open { align-items: start; }
.quote.is-open blockquote p { display: block; overflow: visible; }
.quote__by { margin-top: auto; padding-top: var(--cb-space-4, 16px); }
.quote__more {
  align-self: flex-start;
  margin-top: .75rem;
  padding: .25rem 0;
  min-height: 32px;
  background: none;
  border: 0;
  font: inherit;
  font-size: var(--cb-type-scale-small);
  font-weight: 600;
  font-style: normal;
  color: var(--ps-blue);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.quote__more:hover { color: var(--ps-navy); }

/* ---- Service block CTAs on /services/ ----------------------------------
   Three buttons of near-equal weight sat in a .btn-group inside the ~470px
   left column of a .ps-split. At 1366px they never fit: the phone number
   dropped to a second line on its own, eight times down the page, reading
   as a layout accident rather than a choice. Two buttons now carry the row
   and the phone is a plain call line under it, which also gives the block a
   real hierarchy instead of three things shouting equally. */
.svc-call {
  margin: .85rem 0 0;
  font-size: var(--cb-type-scale-small);
  color: var(--text-muted);
}
.svc-call a {
  color: var(--ps-blue);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-block: .35rem;
}
.svc-call a:hover { color: var(--ps-navy); }

/* ---- Service cards: one long title dropped a whole card out of step ------
   "Re-sanding and re-grouting" is the only one of the eight titles that
   wraps to two lines at three and two columns. Because .svc__body is a
   normal flow column, that second line pushed its description and its
   "What is included" link ~20px lower than the three cards beside it, and a
   grid of cards that is out of step by one line reads as a mistake even when
   nobody can name it. Reserving two lines of title on the cards that sit in
   a row lines the descriptions back up. Single column on a phone keeps its
   natural height, where there is no neighbour to line up with. */
@media (min-width: 621px) {
  .svc__body h3 { min-height: calc(2 * var(--cb-type-scale-h6) * 1.25); }
}

/* ---- Prose headings had no bottom margin at all -------------------------
   Measured across the live site 27 Aug 2026: every <h1>/<h2> that is a
   direct child of a .wrap, rather than sitting inside a .ps-head, computed
   to margin-bottom 0 and a 0px gap to the paragraph under it. .ps-head h2
   was the only heading with its margin restored after the reset, so the
   marketing sections looked right and everything else did not.

   That is 38 headings: 10 on the privacy notice, 4 on the cookie notice and
   3 on each of the 8 service pages. A 57.6px heading resting directly on
   its own body copy, with the descenders of one touching the cap height of
   the other, is the single loudest "unfinished" signal on those pages.

   Margins only. The type scale is deliberately large and is the same on
   every section heading on the site; shrinking it only on the legal pages
   would trade one inconsistency for another. */
.ps-sec > .wrap > :is(h1, h2, h3) { margin-bottom: .7rem; }
.ps-sec > .wrap > * + :is(h2, h3) { margin-top: 2.4rem; }

/* ============================================================================
   ABOUT: the two crew photos, corner to corner              added 2 Sep 2026
   Appended at the end of page.css, which loads after brand.css (index.html:37
   vs :35), so these win against the .ps-split rules at brand.css:967 and :1233.
   .crew is a new class, so nothing existing targets it and there is no
   specificity fight to lose.

   Side by side was tried first and rejected: two 2:3 portraits in a 540px
   column come out about 260px wide each and read as slivers. Offsetting them
   on the diagonal gives each photo 52% of the width instead, and the pair
   overlaps by only about 4% horizontally so they kiss at the middle rather
   than crowd each other.

   The container carries the height with aspect-ratio because both photos are
   absolutely positioned and would otherwise collapse it to zero.
   ========================================================================== */
.crew { position: relative; aspect-ratio: 1 / 1; }
.crew__ph {
  position: absolute;
  margin: 0;
  width: 52%;
  border: 4px solid var(--ps-blue);
  border-radius: var(--cb-radius-image, 8px);
  overflow: hidden;
  background: var(--surface-alt);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .20);
}
.crew__ph img { display: block; width: 100%; height: auto; }
.crew__ph--a { top: 0;    left: 0;  z-index: 2; }
.crew__ph--b { bottom: 0; right: 0; z-index: 1; }

/* Under 880px the .ps-split collapses to one column and .crew gets the full
   width, so the photos grow with it and the diagonal still holds. Nothing to
   override here; this note exists so the next person does not add a redundant
   breakpoint. */
