/* ============================================================================
   shared-components.css

   Components shared by EVERY page, including index.html.

   Why this file exists: index.html carries its own CSS inline in a <style>
   block, while the other 22 pages use css/service-pages.css. Anything new that
   both need would otherwise have to be written twice and kept in sync by hand.
   That is already the situation for :root and the .ba-* rules, and it is the
   main source of drift in this repo. New shared components go here instead.

   Load order matters: this file must be linked AFTER service-pages.css (and
   after index.html's inline <style>) so its overrides win on source order.

   It intentionally declares no :root. Brand tokens are inherited from whichever
   stylesheet loaded first on the page.
   ============================================================================ */

/* ===== REVIEW SLIDER NAV =====
   Moved out of css/service-pages.css. Drives the prev/next buttons on the
   exterior, interior and cabinet review carousels.

   Cory missed these entirely: "I would have probably missed the buttons
   though. Matter of fact, I did originally, so maybe making those stand out a
   little bit more, maybe have them on the right and the left, in a different
   colour." So: coral instead of white-on-white, and flanking the track rather
   than parked underneath it.

   Safe to restyle in place. js/reviews-slider.js finds the buttons with
   slider.querySelector('.rev-prev'), not by sibling position, so they need no
   markup change. .rev-slider is already position:relative, and the buttons are
   siblings of .rev-track, so its overflow-x:auto does not clip them. */
.rev-nav { display: flex; gap: 10px; justify-content: center; margin-top: 30px; }
.rev-btn {
  width: 50px; height: 50px; border-radius: 50%;
  border: 0; background: var(--coral); color: #fff;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  font-size: 21px;
  box-shadow: 0 14px 30px -10px rgba(240,111,77,0.60);
  transition: background .15s, transform .15s, box-shadow .15s;
}
.rev-btn:hover {
  background: var(--coral-deep); color: #fff;
  transform: scale(1.07);
  box-shadow: 0 18px 36px -10px rgba(216,87,53,0.65);
}
.rev-btn:active { transform: scale(0.97); }
.rev-btn:focus-visible { outline: 3px solid var(--teal); outline-offset: 3px; }

/* Desktop: flank the track. Built as min-width so it layers on top of the
   existing max-width:900px rules in service-pages.css instead of fighting them
   on source order. .wrap has 36px of side padding, so a 50px button pulled
   25px out still sits inside the gutter and never crosses the viewport edge. */
@media (min-width: 901px) {
  .rev-nav { display: block; margin-top: 0; }
  .rev-btn { position: absolute; top: 50%; z-index: 5; transform: translateY(-50%); }
  .rev-btn:hover  { transform: translateY(-50%) scale(1.07); }
  .rev-btn:active { transform: translateY(-50%) scale(0.97); }
  .rev-prev { left: -25px; }
  .rev-next { right: -25px; }
}

/* ===== TRUST BAR =====
   Cory: "I think we could use a trust bar right below this... that could be
   effective right here, breaking this up", and on the badges elsewhere,
   "they're kind of hidden... maybe something to grab the eye a little bit
   more." Same eight logos as .awards-strip, but compact and above the fold.
   White band with hairline rules so it reads as a deliberate break against
   snow above and snow/mist below without needing a new token. */
.trustbar { background: #fff; border-block: 1px solid var(--stone); padding: 22px 0; }
.trustbar-inner {
  display: flex; align-items: center; justify-content: center;
  gap: 36px; flex-wrap: wrap;
}
.trustbar-lede {
  font-size: 11.5px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--teal-dark); flex-shrink: 0;
}
.trustbar-logos {
  display: flex; align-items: center; justify-content: center;
  gap: 20px 40px; flex-wrap: wrap;
}
.trustbar-logos img {
  height: 46px; width: auto;
  mix-blend-mode: multiply; opacity: 0.88;
  transition: opacity .15s;
}
.trustbar-logos img.wide { height: 27px; }
.trustbar-logos img:hover { opacity: 1; }

@media (max-width: 980px) {
  .trustbar { padding: 18px 0; }
  .trustbar-inner { gap: 16px; }
  .trustbar-lede { width: 100%; text-align: center; }
  .trustbar-logos { gap: 16px 28px; }
  .trustbar-logos img { height: 36px; }
  .trustbar-logos img.wide { height: 22px; }
}
/* Below 620px the row becomes a swipeable strip, same scroll-snap device the
   review carousel already uses, so the logos never shrink to illegibility. */
@media (max-width: 620px) {
  .trustbar-logos {
    flex-wrap: nowrap; justify-content: flex-start;
    overflow-x: auto; scroll-snap-type: x proximity;
    scrollbar-width: none; -ms-overflow-style: none;
    padding-bottom: 2px;
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
  }
  .trustbar-logos::-webkit-scrollbar { display: none; }
  .trustbar-logos img { flex-shrink: 0; scroll-snap-align: center; }
}

/* ===== BACK TO TOP =====
   Cory: "a back to the top button, potentially, could be nice."
   Injected by js/nav.js so there are no markup edits across 23 pages.
   z-index sits under .sticky-cta (90) so the estimate CTA always wins, and
   body.has-sticky-cta lifts it clear of that bar on the pages that carry it. */
.to-top {
  position: fixed; right: 22px; bottom: 22px; z-index: 80;
  width: 46px; height: 46px; border-radius: 50%;
  border: 1px solid var(--line); background: #fff; color: var(--navy);
  box-shadow: 0 16px 34px -14px rgba(11,33,122,0.45);
  font-size: 20px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; visibility: hidden; transform: translateY(10px);
  transition: opacity .2s, transform .2s, visibility .2s,
              background .15s, border-color .15s, color .15s;
}
.to-top.is-visible { opacity: 1; visibility: visible; transform: translateY(0); }
.to-top:hover { background: var(--teal); border-color: var(--teal); color: #fff; }
.to-top:focus-visible { outline: 3px solid var(--teal); outline-offset: 3px; }

@media (max-width: 980px) {
  .to-top { right: 16px; width: 42px; height: 42px; font-size: 18px; }
  /* .sticky-cta is ~66px tall, which is why service-pages.css pads the body by
     74px at this breakpoint. 88px clears it with room to spare. */
  body.has-sticky-cta .to-top { bottom: 88px; }
}

/* ===== DEPARTMENT SECTIONS (meet-the-team) =====
   Cory: "I'd probably group them by department. Estimators, project managers,
   in-house painters, client account managers." And: put Michael and Whitney at
   the bottom, because "the people that they're actually going to interact with
   should be at the top."

   Department assignments come from the Vault roster
   (company-reference/kindhome-people-and-routing.md). Public job titles do NOT
   come from there: that roster is an internal accountability chart carrying EOS
   seat language ("Director of Sales seat") and jargon ("L&E Coordinator", "SDR")
   that a homeowner cannot parse. Roster decides who exists and where they sit;
   the page decides what their title reads as. */

.dept-jump {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 10px;
  margin: 0 auto 8px; max-width: 900px;
}
.dept-jump a {
  font-size: 13.5px; font-weight: 600; color: var(--navy);
  background: #fff; border: 1px solid var(--stone); border-radius: 999px;
  padding: 9px 18px; text-decoration: none; white-space: nowrap;
  transition: background .15s, border-color .15s, color .15s;
}
.dept-jump a:hover { background: var(--teal); border-color: var(--teal); color: #fff; }
.dept-jump a:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; }

/* Keyed off the id, not .dept, so every jump target gets the offset including
   the leadership card, which is a .founder-card rather than a .dept. Without
   this the anchor parks the heading under the sticky header. */
[id^="dept-"], #warranty-claim, .faq-group-title[id] { scroll-margin-top: 96px; }
.dept + .dept { margin-top: 54px; }
.dept-head { margin-bottom: 22px; }
.dept-head h3 {
  font-family: var(--font-display); font-variation-settings: var(--fr-axes);
  font-size: 25px; font-weight: 600; color: var(--navy); margin-bottom: 6px;
}
.dept-head p { font-size: 15px; color: var(--ink-soft); max-width: 62ch; }
.dept-count { color: var(--teal-dark); font-weight: 700; }

/* ===== TEAM CARD HOVER-TO-EXPAND =====
   Cory: "it'd be cool if you hover over them, it gets a little bit bigger,
   maybe shows a little more detail. They used to have their own pages."

   Deliberately no JS. Where a real pointer exists, hover and keyboard focus
   reveal .team-more and grow the portrait. Where one does not (touch), the
   detail is simply always visible, so a tap target that expands-then-navigates
   never has to be explained. That is the tap-equivalent, not a fallback. */
/* Scoped to [tabindex] throughout, NOT bare .team-card. Ten pages use
   .team-card (contact, about, service-areas and others use it for non-person
   cards) and this file loads on all of them, so an unscoped hover rule would
   silently restyle nine pages nobody asked about. tabindex is the honest
   discriminator here: it marks exactly the cards that have something to
   reveal. */
.team-card[tabindex] { transition: transform .18s, box-shadow .18s, border-color .18s; }
.team-card[tabindex] .avatar-photo { transition: width .18s, height .18s; }
.team-card[tabindex]:focus-visible { outline: 3px solid var(--teal); outline-offset: 3px; }
.team-more {
  font-size: 14px; color: var(--ink-soft); margin-top: 10px;
  padding-top: 10px; border-top: 1px solid var(--line);
}

@media (hover: hover) {
  .team-more {
    /* grid-rows 0fr -> 1fr animates height without a magic max-height */
    display: grid; grid-template-rows: 0fr;
    margin-top: 0; padding-top: 0; border-top-color: transparent;
    opacity: 0; overflow: hidden;
    transition: grid-template-rows .22s, opacity .18s, margin-top .22s,
                padding-top .22s, border-top-color .22s;
  }
  .team-more > span { min-height: 0; }
  .team-card[tabindex]:hover, .team-card[tabindex]:focus-within {
    transform: translateY(-4px);
    border-color: var(--teal);
    box-shadow: 0 22px 44px -20px rgba(11,33,122,0.40);
  }
  .team-card[tabindex]:hover .avatar-photo,
  .team-card[tabindex]:focus-within .avatar-photo { width: 92px; height: 92px; }
  .team-card[tabindex]:hover .team-more,
  .team-card[tabindex]:focus-within .team-more {
    grid-template-rows: 1fr; opacity: 1;
    margin-top: 10px; padding-top: 10px; border-top-color: var(--line);
  }
}

/* ===== NAME CHIPS =====
   For departments where a headshot is not the point. Also the extension point:
   any department can take chips for the people who have no photo yet, without
   restructuring the section. */
.name-chips { display: flex; flex-wrap: wrap; gap: 10px; }
.name-chip {
  background: #fff; border: 1px solid var(--stone); border-radius: 12px;
  padding: 12px 16px; font-size: 14.5px; color: var(--navy);
}
.name-chip span { display: block; font-size: 12.5px; color: var(--ink-soft); margin-top: 2px; }

/* ===== JOB LIST (careers) =====
   Cory: "I would put what we're hiring for, and then a link to apply to that
   position where they can submit their resume."

   The four .role-card families above this stay: he said that part "is fine",
   and they answer a different question (who we hire) than this does (what is
   open). Departments here are the real ones from the Vault roster rather than
   invented categories. */
.job-list { display: grid; gap: 14px; max-width: 900px; margin: 0 auto; }
.job-card {
  background: #fff; border: 1px solid var(--stone); border-radius: 16px;
  padding: 24px 28px;
  display: grid; grid-template-columns: 1fr auto; gap: 18px 24px;
  align-items: center;
  transition: border-color .15s, box-shadow .15s;
}
.job-card:hover { border-color: var(--teal); box-shadow: 0 18px 38px -22px rgba(11,33,122,0.34); }
.job-card h3 { font-size: 19px; margin-bottom: 8px; }
.job-meta { display: flex; flex-wrap: wrap; gap: 8px 10px; margin-bottom: 10px; }
.job-meta span {
  font-size: 12px; font-weight: 600; letter-spacing: 0.04em;
  color: var(--teal-dark); background: var(--mist);
  border-radius: 999px; padding: 4px 11px;
}
.job-card p { font-size: 14.5px; color: var(--ink-soft); max-width: 58ch; }
.job-apply { white-space: nowrap; }

@media (max-width: 620px) {
  .job-card { grid-template-columns: 1fr; padding: 22px; }
  .job-apply { justify-self: stretch; text-align: center; }
}

/* ===== WARRANTY CLAIM (contact) =====
   Cory: "maybe a separate form for submitting for a warranty claim."
   Deliberately NOT .lead-form. js/lead-capture.js binds by that class and is
   locked to the Zapier/Salesforce field mapping, so reusing it here would fire
   a false generate_lead on every warranty claim. */
.wclaim { background: var(--mist); }
.wclaim-box {
  background: #fff; border: 1px solid var(--stone); border-radius: 20px;
  padding: 44px 46px; max-width: 760px; margin: 0 auto;
  box-shadow: 0 24px 54px -32px rgba(11,33,122,0.28);
}
.wclaim-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; margin-bottom: 20px; }
.wclaim-grid .field.full { grid-column: 1 / -1; }
/* service-pages.css styles .field input but never a textarea or select, because
   the lead form has neither. Scoped to .wclaim so the locked form is untouched. */
.wclaim .field textarea,
.wclaim .field select {
  width: 100%; font-family: var(--font-body); font-size: 15px; color: var(--navy);
  background: var(--snow); border: 1.5px solid var(--line); border-radius: 8px;
  padding: 13px 15px; outline: none; transition: border-color .15s, box-shadow .15s;
}
.wclaim .field textarea { min-height: 132px; resize: vertical; line-height: 1.55; }
.wclaim .field textarea:focus,
.wclaim .field select:focus { border-color: var(--teal); box-shadow: 0 0 0 3px rgba(28,184,167,0.15); }
.wclaim-form .btn { width: 100%; justify-content: center; margin-top: 6px; }

.wclaim-note {
  font-size: 13.5px; color: var(--ink-soft); margin-top: 16px;
  display: flex; gap: 8px; align-items: flex-start;
}
.wclaim-note i { color: var(--teal-dark); flex-shrink: 0; }
.wclaim-status { font-size: 14px; margin-top: 14px; text-align: center; }
.wclaim-status.is-err { color: var(--coral-deep); }

@media (max-width: 620px) {
  .wclaim-box { padding: 32px 24px; }
  .wclaim-grid { grid-template-columns: 1fr; }
}

/* ===== CHANGE LOG (site-updates.html) =====
   TEMPORARY. Ships so Corey can see what moved after his walkthrough without
   diffing the site from memory. Remove with the page and its footer links once
   the build is approved; tracked in GO-LIVE.md. */
.chg-group { margin-bottom: 54px; }
.chg-group > h2 {
  font-family: var(--font-display); font-variation-settings: var(--fr-axes);
  font-size: 27px; font-weight: 600; color: var(--navy);
  padding-bottom: 12px; margin-bottom: 22px;
  border-bottom: 2px solid var(--stone);
}
.chg-item {
  background: #fff; border: 1px solid var(--stone); border-radius: 16px;
  padding: 26px 28px; margin-bottom: 14px;
}
.chg-item h3 { font-size: 18px; margin-bottom: 12px; }
.chg-said {
  border-left: 3px solid var(--teal); background: var(--mist);
  border-radius: 0 10px 10px 0; padding: 12px 16px; margin-bottom: 14px;
  font-size: 15px; font-style: italic; color: var(--ink-soft); line-height: 1.6;
}
.chg-said b {
  display: block; font-style: normal; font-weight: 700; font-size: 11.5px;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--teal-dark); margin-bottom: 6px;
}
.chg-item > p { font-size: 15px; color: var(--ink-soft); }
.chg-where { margin-top: 14px; display: flex; flex-wrap: wrap; gap: 8px; }
.chg-where a {
  font-size: 12.5px; font-weight: 600; color: var(--navy);
  background: var(--snow); border: 1px solid var(--stone); border-radius: 999px;
  padding: 5px 13px; text-decoration: none; transition: background .15s, color .15s, border-color .15s;
}
.chg-where a:hover { background: var(--teal); border-color: var(--teal); color: #fff; }

/* the standing note at the top of the page */
.chg-banner {
  background: var(--mist); border: 1px solid var(--stone);
  border-left: 4px solid var(--coral); border-radius: 0 14px 14px 0;
  padding: 22px 26px; margin-bottom: 46px;
}
.chg-banner p { font-size: 15px; color: var(--ink-soft); margin-bottom: 10px; }
.chg-banner p:last-child { margin-bottom: 0; }
.chg-banner code {
  background: #fff; border: 1px solid var(--stone); border-radius: 5px;
  padding: 1px 6px; font-size: 13.5px; color: var(--navy);
}

/* owner headings in the launch list: plain on the section background, so the
   list cards below are not nested inside a second card */
.launch-owner {
  font-family: var(--font-display); font-variation-settings: var(--fr-axes);
  font-size: 20px; font-weight: 600; color: var(--navy);
  margin: 30px 0 12px;
}
.launch-owner:first-of-type { margin-top: 0; }
.launch-owner span {
  font-family: var(--font-body); font-variation-settings: normal;
  font-size: 12px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--teal-dark);
  margin-left: 10px; vertical-align: 2px;
}
.chg-open + .launch-owner { margin-top: 34px; }
.chg-open code {
  background: var(--snow); border: 1px solid var(--stone); border-radius: 5px;
  padding: 1px 6px; font-size: 13px; color: var(--navy);
}

/* still-open items read as a list, not as completed work */
.chg-open { display: grid; gap: 10px; }
.chg-open li {
  list-style: none; background: #fff; border: 1px solid var(--stone);
  border-radius: 12px; padding: 15px 18px; font-size: 14.5px; color: var(--ink-soft);
}
.chg-open li b { color: var(--navy); }

/* Items Corey answered on the 2026-08-27 call. They are kept visible rather
   than deleted: he answered these verbally, and a list that silently shrinks
   gives him no way to confirm his answers were captured correctly. Muted and
   ticked so they read as closed at a glance and do not compete with the open
   items above. */
.chg-answered { display: grid; gap: 8px; margin-top: 14px; }
.chg-answered li {
  list-style: none; background: var(--snow); border: 1px solid var(--stone);
  border-left: 3px solid var(--teal); border-radius: 12px;
  padding: 13px 16px; font-size: 14px; color: var(--ink-soft);
}
.chg-answered li b { color: var(--navy); }
.chg-answered li::before {
  content: "\2713"; color: var(--teal); font-weight: 700; margin-right: 8px;
}
.chg-answered-head {
  font-size: 13px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--teal-dark); font-weight: 700; margin-top: 26px;
}

@media (max-width: 620px) {
  .chg-item { padding: 22px 20px; }
  .chg-group > h2 { font-size: 23px; }
}

@media (prefers-reduced-motion: reduce) {
  .rev-btn, .rev-btn:hover, .rev-btn:active { transition: background .15s; }
  .job-card { transition: none; }
  .to-top { transition: opacity .15s, visibility .15s; transform: none; }
  .to-top.is-visible { transform: none; }
  .team-card, .team-card .avatar-photo { transition: none; }
  .team-card:hover, .team-card:focus-within { transform: none; }
  .team-more { transition: opacity .15s; }
}

@media print { .to-top { display: none !important; } }

/* ===== BREADCRUMBS (service-area pages) =====
   A breadcrumb is semantically a <nav>, which means the global sticky-header
   `nav { }` rule in service-pages.css lands on it: position sticky, the header
   background, a border-bottom and z-index 50. It rendered as a stray white bar
   across the hero. Everything below is undoing that, not decorating. */
.crumbs {
  position: static; background: none; backdrop-filter: none;
  border: 0; z-index: auto; height: auto;
  display: block; margin-bottom: 20px;
  font-size: 13px; letter-spacing: .01em; color: var(--ink-soft);
}
.crumbs a { color: var(--ink-soft); text-decoration: none; border-bottom: 1px solid transparent; }
.crumbs a:hover { color: var(--teal-dark); border-bottom-color: currentColor; }
.crumbs span { color: #8f98b5; margin: 0 4px; }
.crumbs [aria-current="page"] { color: var(--navy); font-weight: 600; margin-left: 0; }
/* The service-area hero is centred, so centre the trail with it. */
.page-hero .crumbs { text-align: center; }

/* Inline route into the service-area hub. Corey asked for city coverage to be
   reachable without adding it to the main nav, which stays deliberately short,
   so it sits with the address-routing note under the estimate form, where a
   visitor is already thinking about whether they are in the footprint. */
.sa-inline-link {
  color: var(--teal-dark); font-weight: 600; white-space: nowrap;
  border-bottom: 1px solid rgba(20,154,140,.35);
}
.sa-inline-link:hover { border-bottom-color: currentColor; }
