/* ==========================================================================
   Local web design pages — /sacramento-web-design/, /roseville-web-design/
   and /rocklin-web-design/.

   One sheet for the three city editions, because they share a layout and
   never load with each other. The shared house devices live in
   public/assets/css/service-devices.css, loaded first via
   ServicePageData.extraStyles. This file is only what is genuinely these
   pages' own and must not redefine anything that sheet owns.

   NAMESPACE. `lwd-`. Page-owned sections take .svcd-section in markup, so
   there is no palette block here: the custom properties come from that
   class. Rules that reach into the closing CTA card (.lwd-areas, .lwd-nearby)
   render outside any .svcd-section and carry fallbacks for that reason.
   ========================================================================== */

/* --- Hero backdrop ----------------------------------------------------------
   The same device as .rk-hero-bg in rocklin-seo.css: a local landmark, full
   bleed behind the hero and the fixed nav, dimmed and washed so it reads as a
   backdrop rather than a picture. Duplicated rather than moved into the
   shared sheet because the two sheets never load together and the shared
   sheet is already modified on this branch.

   The whole device is keyed on the hero *having* a backdrop. A city page that
   ships without a photo yet keeps the plain stacked hero every other
   commercial page uses, and nothing below applies to it. */

.svc-hero:has(.lwd-hero-bg) {
  isolation: isolate;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* The stat rail is part of the hero, so on a short viewport the whole thing
   scrolls rather than the rail being clipped. */
@media (max-height: 760px) {
  .svc-hero:has(.lwd-hero-bg) {
    min-height: 0;
  }
}

.lwd-hero-bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

.lwd-hero-bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Each page sets --lwd-pos inline on the wrapper to put its landmark clear
     of the headline, which sits left. */
  object-position: var(--lwd-pos, 30% 34%);
  /* Dark and desaturated enough that white 900-weight type clears WCAG AA
     over any part of it. */
  opacity: 0.42;
  filter: saturate(0.72) contrast(1.04);
  -webkit-mask-image: linear-gradient(180deg, #000 88%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 88%, transparent 100%);
}

/* Protects the copy column: near-opaque behind the headline, thinning toward
   the landmark on the right. */
.lwd-hero-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(10, 10, 15, 0.94) 18%,
    rgba(10, 10, 15, 0.76) 46%,
    rgba(10, 10, 15, 0.42)
  );
}

/* ServicePage renders heroMedia inside .svc-hero__inner, the centred
   max-width column, which is position:relative. An absolutely positioned
   backdrop in there resolves against that column and comes out inset. Making
   the inner static hands the containing block back to .svc-hero, which spans
   the full viewport. The inner's z-index goes inert once it is static, so the
   copy and the stat rail take their own layer explicitly. */
.svc-hero:has(.lwd-hero-bg) .svc-hero__inner {
  position: static;
}

.svc-hero:has(.lwd-hero-bg) .svc-hero__lead,
.svc-hero:has(.lwd-hero-bg) .svc-stats {
  position: relative;
  z-index: 2;
}

/* --- The local story ---------------------------------------------------------
   The one section that makes each page a city page rather than the template
   with a city name dropped in: a named local client and what their site did,
   beside a framed screenshot of it. */

.lwd-story__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.95fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

.lwd-p {
  margin-top: 1.1rem;
  font-size: var(--step-0);
  line-height: 1.7;
  color: var(--text-secondary);
  max-width: 62ch;
}

.lwd-p a {
  color: var(--text-primary);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  text-decoration-color: var(--purple-border);
  transition: text-decoration-color var(--dur, 340ms) var(--ease-out);
}

.lwd-p a:hover,
.lwd-p a:focus-visible {
  text-decoration-color: var(--purple-light);
}

/* The figures the story rests on. Same tile as .rk-credentials. */
.lwd-facts {
  margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
  list-style: none;
}

.lwd-fact {
  padding: clamp(1.1rem, 2.4vw, 1.5rem);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-lg, 10px);
  background: var(--surface-2);
}

.lwd-fact__num {
  font-family: var(--font-display);
  font-stretch: var(--wdth-display, 108%);
  font-weight: 900;
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  line-height: 1;
  color: var(--text-primary);
}

.lwd-fact__label {
  margin-top: 0.55rem;
  font-size: var(--step--1);
  line-height: 1.45;
  color: var(--text-muted);
}

/* --- Areas served and the nearby line, in the closing card -------------------
   Chips are pills on this site; buttons never are. */

.lwd-areas {
  margin-top: 0.5rem;
  margin-bottom: 1.25rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  list-style: none;
}

.lwd-area {
  padding: 0.45em 0.9em;
  border: 1px solid var(--card-border, #1a1a24);
  border-radius: 999px;
  font-size: var(--step--2);
  color: var(--text-muted, #6a6a77);
}

.lwd-nearby {
  margin-top: 0.75rem;
  font-size: var(--step--1);
  line-height: 1.7;
  color: var(--text-secondary, #a1a1b5);
}

.lwd-nearby a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
}

.lwd-nearby a:hover,
.lwd-nearby a:focus-visible {
  text-decoration-color: transparent;
}

/* --- Responsive -------------------------------------------------------------- */

@media (max-width: 980px) {
  .lwd-story__inner {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .lwd-facts {
    grid-template-columns: 1fr;
  }
  /* On a phone the frame is mostly headline, so the backdrop is cropped hard.
     Quieter, and centred on the landmark so what survives the crop is the
     place rather than a wall of texture. */
  .lwd-hero-bg img {
    opacity: 0.3;
    object-position: var(--lwd-pos-sm, 34% 42%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .lwd-p a {
    transition: none;
  }
}

/* --- The trades ---------------------------------------------------------------
   The local story above is a med spa. These pages are for every local
   service business, so each follows it with the two contractor accounts from
   the same region (TradesProof.tsx): a device mockup of the JC site, which
   sits loose on the surface because the PNG is already a mounted exhibit,
   and the Outdoor Landscape Innovations screenshot in the usual frame. */

.lwd-trades__row {
  margin-top: clamp(2rem, 4vw, 3rem);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.25rem, 3vw, 2rem);
  list-style: none;
}

.lwd-trade {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding: clamp(1.1rem, 2.4vw, 1.5rem);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-lg, 10px);
  background: var(--surface-2);
}

.lwd-trade__media img {
  display: block;
  width: 100%;
  height: auto;
}

/* The framed screenshot keeps .svcd-frame's mat; the loose mockup gets the
   same height band so the two cards line up at the top of the copy. */
.lwd-trade__media--loose {
  display: grid;
  place-items: center;
  /* The framed screenshot is a 1440x950 capture inside the mat; the loose
     mockup takes the same box, mat included, so both numbers start on the
     same line. */
  aspect-ratio: 1440 / 950;
  box-sizing: content-box;
  padding: clamp(0.6rem, 1.4vw, 1rem) clamp(0.5rem, 2vw, 1.5rem);
  border: 1px solid transparent;
}

.lwd-trade__media--loose img {
  max-height: 100%;
  width: auto;
  max-width: 100%;
  filter: drop-shadow(0 18px 32px rgba(0, 0, 0, 0.45));
}

.lwd-trade__num {
  font-family: var(--font-display);
  font-stretch: var(--wdth-display, 108%);
  font-weight: 900;
  font-size: clamp(2rem, 4vw, 2.8rem);
  line-height: 1;
  color: var(--purple-light);
}

.lwd-trade__label {
  margin-top: 0.5rem;
  font-size: var(--step--1);
  line-height: 1.45;
  color: var(--text-muted);
  max-width: 36ch;
}

.lwd-trade__name {
  margin-top: 1.25rem;
}

.lwd-trade__where {
  margin-top: 0.3rem;
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.lwd-trade__p {
  margin-top: 0.9rem;
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--text-secondary);
}

.lwd-trade__link {
  display: inline-block;
  margin-top: 1rem;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-primary);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  text-decoration-color: var(--purple-border);
  transition: text-decoration-color var(--dur, 340ms) var(--ease-out);
}

.lwd-trade__link:hover,
.lwd-trade__link:focus-visible {
  text-decoration-color: var(--purple-light);
}

/* Same arrival as .svcd-row: the two cards rise in turn once the list is
   staged. From-state only behind .has-motion, so no script means no hidden
   content. */
.has-motion .lwd-trade {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.8s var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) var(--fd, 0s),
    transform 0.8s var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) var(--fd, 0s);
}

.has-motion .lwd-trades__row.is-in .lwd-trade {
  opacity: 1;
  transform: none;
}

@media (max-width: 860px) {
  .lwd-trades__row {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  .lwd-trade__link {
    transition: none;
  }
  .has-motion .lwd-trade {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
