/* Layout and components. Colors, type and spacing come from tokens.css.
   G-Race $1500, brief v2 ("established land company"): photography carries the page; type is a sturdy serif
   with a plain sans; one dark button style, text links for everything else; space instead of boxes. */

/* ---------- Base ---------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Jumps to a section (the header links, "Request an estimate") land with the section's top edge exactly under the
   header, where the header turns solid, so no sliver of the section above shows through it; each section's own
   padding gives the breathing room. On phones the header scrolls away with the page, so there's nothing to clear
   at the top, but the action bar covers the bottom: a focused form field stays above it. */
html {
  -webkit-text-size-adjust: 100%;
  scroll-padding: 0 0 calc(80px + env(safe-area-inset-bottom));
}

@media (min-width: 768px) {
  html {
    scroll-padding: var(--header-height) 0 0;
  }
}

/* A form field brought into view (an error, a label tapped) keeps a little air above it. */
input,
select,
textarea {
  scroll-margin-top: 2.5rem;
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  background: var(--color-paper) var(--grain);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: var(--body-size);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
video {
  display: block;
  max-width: 100%;
}

/* Big type sits tight, reading type stays open. */
h1,
h2,
h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 0.98;
  letter-spacing: 0;
  text-wrap: balance;
}

p {
  max-width: 66ch;
  margin: 0 0 1em;
}

p:last-child {
  margin-bottom: 0;
}

a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

/* Buttons: the text color would vanish as a ring (white on paper, ink on the dark hero), so a clay ring instead,
   6.9:1 on paper; white over the hero photo. */
.btn:focus-visible {
  outline: 3px solid var(--color-clay);
  outline-offset: 3px;
}

.hero .btn--light:focus-visible {
  outline-color: var(--color-white);
}

ul,
ol {
  margin: 0;
  padding: 0;
}

/* Taps answer on touch-down, with no double-tap-zoom wait. */
a,
button,
label,
input,
summary {
  touch-action: manipulation;
}

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 100;
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  background: var(--color-white);
  color: var(--color-ink);
  font-weight: 600;
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: none;
}

/* ---------- Buttons and links ---------- */
/* One button style (solid ink, or solid white on photos). Everything secondary is a text link with an arrow. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 0 1.5rem;
  border: 0;
  border-radius: var(--radius);
  font: inherit;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.1;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 200ms var(--ease), opacity 150ms var(--ease), transform 120ms var(--ease);
}

/* Pressed: the button gives the moment it's touched, not when it's let go. */
.btn:active {
  opacity: 0.92;
  transform: scale(0.97);
  transition-duration: 100ms;
}

.btn--primary {
  background: var(--color-ink);
  color: var(--color-white);
}

.btn--primary:hover {
  background: var(--color-pine);
}

.btn--light {
  background: var(--color-white);
  color: var(--color-ink);
}

.btn--light:hover {
  background: var(--color-paper);
}

.btn--small {
  min-height: 44px;
  padding: 0 1.1rem;
  font-size: 0.9375rem;
}

.btn--large {
  min-height: 56px;
  padding: 0 1.75rem;
  font-size: 1.0625rem;
}

.btn[disabled] {
  opacity: 0.6;
  cursor: progress;
}

.link-arrow {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  -webkit-tap-highlight-color: transparent;
  transition: text-decoration-color 200ms var(--ease), opacity 150ms var(--ease);
}

.link-arrow::after {
  content: "\2192";
  margin-left: 0.45rem;
  transition: transform 250ms var(--ease);
}

.link-arrow:hover {
  text-decoration-color: currentColor;
}

.link-arrow:hover::after {
  transform: translateX(3px);
}

.link-arrow:active {
  opacity: 0.7;
}

.link-arrow--clay {
  color: var(--color-clay);
}

/* ---------- Estimate link: mowed in ---------- */
/* Over the hero photo, the estimate link gets a clay underline that's always there, so it reads as a link before
   anyone hovers. Once the logo has drawn in, a tiny push mower rolls along under the words and mows that underline
   in, throwing a few clippings out the back, then fades; the arrow gives one nudge. It plays once, about 2.4 to 4.7
   seconds after the first paint, in CSS like the logo. With reduced motion the underline is simply there. */

.link-arrow--mow {
  --mow-clay: #d0663f; /* the logo plate's clay on dark */
  text-decoration: none;
}

.mow {
  position: relative;
}

/* The mowed stripe: the link's underline. Turns the text color on hover. */
.mow::after {
  content: "";
  position: absolute;
  inset: auto 0 -0.38em;
  height: 2px;
  background: var(--mow-clay);
  transform-origin: left;
  transition: background-color 200ms var(--ease);
}

.link-arrow--mow:hover .mow::after {
  background: currentColor;
}

/* The mower rides on the stripe. The track slides by the width of the words, so the mower's front edge stays exactly
   where the stripe ends. */
.mow__track {
  position: absolute;
  inset: auto 0 -0.38em;
  height: 2px;
  pointer-events: none;
}

.mow__mower {
  position: absolute;
  right: 100%;
  bottom: 0;
  width: auto;
  height: 0.85em; /* small enough to ride under the words, not through them */
  overflow: visible;
  opacity: 0;
}

.mow__deck {
  fill: var(--mow-clay);
}

.mow__engine {
  fill: #ece6da;
}

.mow__wheel {
  fill: #0f1211;
  stroke: #ece6da;
  stroke-width: 0.9;
}

.mow__handle {
  fill: none;
  stroke: #ece6da;
  stroke-width: 1.7;
  stroke-linejoin: round;
}

.mow__clippings rect {
  fill: #a9c97a;
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  /* 2.4s: rolls in and drives the length of the words, easing in and out like it's being pushed, with a little
     engine shake and clippings flying; 3.9s: fades off; 3.95s: the arrow nudges toward the click. */
  .mow::after {
    animation: mow-stripe 1.5s 2.4s cubic-bezier(0.4, 0, 0.3, 1) both;
  }

  .mow__track {
    animation: mow-drive 1.5s 2.4s cubic-bezier(0.4, 0, 0.3, 1) both;
  }

  .mow__mower {
    animation:
      mow-presence 1.8s 2.4s linear both,
      mow-shake 0.09s 2.4s 16 alternate ease-in-out;
  }

  .mow__clippings rect {
    animation: mow-spit 0.36s 2.55s 4 ease-out;
  }

  .mow__clippings rect:nth-child(2) {
    animation-delay: 2.67s;
  }

  .mow__clippings rect:nth-child(3) {
    animation-delay: 2.79s;
  }

  /* backwards, not both, so the hover nudge still works once it's done. */
  .link-arrow--mow::after {
    animation: arrow-nudge 0.8s 3.95s cubic-bezier(0.3, 0, 0.2, 1) backwards;
  }
}

@keyframes mow-stripe {
  from { transform: scaleX(0); }
}

@keyframes mow-drive {
  from { transform: translateX(0); }
  to { transform: translateX(100%); }
}

@keyframes mow-presence {
  0% { opacity: 0; }
  8%, 84% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes mow-shake {
  to { transform: translateY(-0.6px); }
}

@keyframes mow-spit {
  0% { opacity: 1; transform: translate(0, 0); }
  100% { opacity: 0; transform: translate(-6px, -4px); }
}

@keyframes arrow-nudge {
  0%, 100% { transform: none; }
  35% { transform: translateX(6px); }
  60% { transform: translateX(-1px); }
  80% { transform: translateX(2px); }
}

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 2rem;
}

/* ---------- Header ---------- */

.site-header {
  position: relative;
  z-index: 10;
  border-bottom: 1px solid var(--color-line);
  background: var(--color-paper);
}

/* top: auto keeps the header where it would sit in the flow, so a draft notice above it pushes it down. */
.site-header--over {
  position: absolute;
  inset: auto 0;
  border-bottom: 0;
  background: transparent;
}

.site-header--on-photo {
  color: var(--color-white);
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: 2rem;
  min-height: var(--header-height);
}

.brand {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-right: auto;
  text-decoration: none;
}

.brand__logo {
  display: block;
  width: auto;
  height: 56px;
}

.brand__logos {
  display: grid;
}

.brand__logos .brand__logo {
  grid-area: 1 / 1;
  transition: opacity 300ms var(--ease);
}

/* Over the photo the light-on-dark logo shows; once the header turns solid paper, the regular one. */
.brand__logos .brand__logo--light-bg,
.js .site-header--over.is-solid .brand__logo--dark-bg {
  opacity: 0;
}

.js .site-header--over.is-solid .brand__logo--light-bg {
  opacity: 1;
}

.brand__name {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 800;
  line-height: 1.1;
}

.brand__name--stacked {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.6rem;
}

.brand__short {
  font-size: 1.625rem;
  letter-spacing: -0.02em;
}

.brand__rest {
  font-family: var(--font-body);
  font-size: 0.875rem;
  font-weight: 500;
}

.site-nav__list {
  display: flex;
  gap: 1.75rem;
  list-style: none;
}

.site-nav__link,
.header__phone,
.lang-switch__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.35em;
  transition: text-decoration-color 200ms var(--ease);
}

.site-nav__link:hover,
.header__phone:hover,
.lang-switch__link:hover {
  text-decoration-color: currentColor;
}

.header__phone {
  font-weight: 600;
  white-space: nowrap;
}

.lang-switch {
  list-style: none;
}

/* "Español" is always underlined, so it reads as the language switch it is. */
.lang-switch__link {
  text-decoration-color: currentColor;
}

@media (max-width: 899px) {
  .site-nav {
    display: none;
  }
}

@media (max-width: 767px) {
  .header__phone,
  .header__action {
    display: none;
  }

  .brand__rest {
    display: none;
  }

  .brand__logo {
    height: 48px;
  }
}

/* Wide screens, with the script running: the header stays put, turns solid once the hero has scrolled away,
   tucks up while you read down, and drops back the moment you scroll up or tab into it. */
@media (min-width: 768px) {
  .js .site-header--over {
    position: fixed;
    inset: 0 0 auto;
    transition: background-color 300ms var(--ease), color 300ms var(--ease), box-shadow 300ms var(--ease),
      transform 450ms var(--ease);
  }

  /* Solid means frosted paper: the page shows faintly through it as it scrolls underneath. */
  .js .site-header--over.is-solid {
    background: rgb(245 242 236 / 0.78);
    -webkit-backdrop-filter: blur(20px) saturate(170%);
    backdrop-filter: blur(20px) saturate(170%);
    color: var(--color-ink);
    box-shadow: 0 1px 0 rgb(29 33 30 / 0.08);
  }

  .js .site-header--over.is-tucked {
    transform: translateY(-100%);
  }
}

@media (min-width: 768px) and (prefers-reduced-transparency: reduce) {
  .js .site-header--over.is-solid {
    background: rgb(245 242 236 / 0.98);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/* ---------- Header logo: drawn in on load ---------- */
/* Light-on-dark over the hero photo, the regular colors once the header is solid (and on pages without a photo).
   The parts' colors ease across when the header changes. */

.site-header {
  --logo-ink: #0f1211;
  --logo-sub: #4a4f4a;
  --logo-plate: #b4522f;
  --logo-letter: #ece6da;
  --logo-etch: #b4522f;
}

.site-header--on-photo {
  --logo-ink: #ece6da;
  --logo-sub: #ddd7cb;
  --logo-plate: #d0663f;
  --logo-letter: #0f1211;
  --logo-etch: #f6a982;
}

@media (min-width: 768px) {
  .js .site-header--over.is-solid {
    --logo-ink: #0f1211;
    --logo-sub: #4a4f4a;
    --logo-plate: #b4522f;
    --logo-letter: #ece6da;
  }
}

/* Sized so the trade line under the name stays about 9.5px tall on wide screens and 8px on phones. */
.logo {
  display: block;
  width: auto;
  height: 56px;
  overflow: visible;
}

@media (max-width: 767px) {
  .logo {
    height: 48px;
  }

  /* On phones the top of the hero photo is left bright, and light patches (a swing set's bars) can pass behind the
     small trade line. A soft shade behind the logo keeps it at 4.5:1 or better; it fades out well inside its box, so
     there's no edge to see. */
  .site-header--on-photo .brand {
    position: relative;
    isolation: isolate;
  }

  .site-header--on-photo .brand::before {
    content: "";
    position: absolute;
    inset: -20px -32px;
    z-index: -1;
    background: radial-gradient(farthest-side, rgb(12 14 13 / 0.5) 55%, rgb(12 14 13 / 0));
    pointer-events: none;
  }
}

.logo__fill {
  fill-rule: evenodd;
}

.logo__fill path {
  transition: fill 300ms var(--ease);
}

.logo__plate {
  fill: var(--logo-plate);
}

.logo__g {
  fill: var(--logo-letter);
}

.logo__name path {
  fill: var(--logo-ink);
}

.logo__tag path {
  fill: var(--logo-sub);
}

/* Hidden outright when not playing: a glow filter over invisible lines still paints a dark speck in Chrome. */
.logo__etch {
  visibility: hidden;
}

.logo__etch path {
  fill: none;
  stroke: var(--logo-etch);
  stroke-width: 2.5;
  stroke-linejoin: round;
  opacity: 0;
}

.logo__glint {
  opacity: 0;
}

/* The reveal, once, about 3 seconds from the first paint, left to right like the logo reads:
   0.20s  every outline is traced, one part after another, in a glowing clay line (a torch cut)
   0.75s  the letters of G-RACE rise into place
   1.10s  GRADING & CONSTRUCTION LLC types in under the name, letter by letter
   1.30s  the plate at the right fills
   1.55s  the G stamps onto it, last, like a seal
   1.85s  the traced lines cool off
   2.10s  a glint crosses the whole logo
   With reduced motion none of this runs: the logo is simply there. */
@media (prefers-reduced-motion: no-preference) {
  .logo__etch {
    visibility: visible;
    animation: logo-hide 0.01s 2.4s forwards;
  }

  .logo__etch path {
    opacity: 1;
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
    animation:
      logo-etch 0.8s cubic-bezier(0.65, 0, 0.35, 1) calc(0.2s + var(--i, 0) * 60ms) forwards,
      logo-cool 0.6s 1.85s ease forwards;
  }

  .logo__plate {
    animation: logo-in 0.5s 1.3s ease both;
  }

  .logo__g {
    transform-box: fill-box;
    transform-origin: center;
    animation: logo-stamp 0.5s 1.55s cubic-bezier(0.2, 0.8, 0.2, 1) both;
  }

  .logo__name path {
    transform-box: fill-box;
    transform-origin: 50% 100%;
    animation: logo-rise 0.5s calc(0.75s + var(--i, 0) * 60ms) cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }

  .logo__tag > * {
    animation: logo-type 0.45s calc(1.1s + var(--i, 0) * 20ms) cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }

  .logo__glint {
    animation: logo-glint 0.9s 2.1s cubic-bezier(0.45, 0, 0.2, 1) both;
  }
}

.logo__etch path:nth-child(2),
.logo__name path:nth-child(2),
.logo__tag > :nth-child(2) { --i: 1; }
.logo__etch path:nth-child(3),
.logo__name path:nth-child(3),
.logo__tag > :nth-child(3) { --i: 2; }
.logo__etch path:nth-child(4),
.logo__name path:nth-child(4),
.logo__tag > :nth-child(4) { --i: 3; }
.logo__etch path:nth-child(5),
.logo__name path:nth-child(5),
.logo__tag > :nth-child(5) { --i: 4; }
.logo__etch path:nth-child(6),
.logo__name path:nth-child(6),
.logo__tag > :nth-child(6) { --i: 5; }
.logo__etch path:nth-child(7),
.logo__tag > :nth-child(7) { --i: 6; }
.logo__etch path:nth-child(8),
.logo__tag > :nth-child(8) { --i: 7; }
.logo__tag > :nth-child(9) { --i: 8; }
.logo__tag > :nth-child(10) { --i: 9; }
.logo__tag > :nth-child(11) { --i: 10; }
.logo__tag > :nth-child(12) { --i: 11; }
.logo__tag > :nth-child(13) { --i: 12; }
.logo__tag > :nth-child(14) { --i: 13; }
.logo__tag > :nth-child(15) { --i: 14; }
.logo__tag > :nth-child(16) { --i: 15; }
.logo__tag > :nth-child(17) { --i: 16; }
.logo__tag > :nth-child(18) { --i: 17; }
.logo__tag > :nth-child(19) { --i: 18; }
.logo__tag > :nth-child(20) { --i: 19; }
.logo__tag > :nth-child(21) { --i: 20; }
.logo__tag > :nth-child(22) { --i: 21; }
.logo__tag > :nth-child(23) { --i: 22; }

@keyframes logo-etch {
  to { stroke-dashoffset: 0; }
}

@keyframes logo-cool {
  to { opacity: 0; }
}

@keyframes logo-hide {
  to { visibility: hidden; }
}

@keyframes logo-in {
  from { opacity: 0; }
}

@keyframes logo-stamp {
  from { opacity: 0; transform: scale(1.35); }
  60% { opacity: 1; }
  to { opacity: 1; transform: none; }
}

@keyframes logo-rise {
  from { opacity: 0; transform: translateY(18px); }
}

@keyframes logo-type {
  from { opacity: 0; transform: translateY(9px); }
}

@keyframes logo-glint {
  from { opacity: 1; transform: translateX(0) skewX(-18deg); }
  to { opacity: 1; transform: translateX(760px) skewX(-18deg); }
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: var(--color-ink);
  color: var(--color-white);
}

.hero__title {
  font-size: clamp(3.25rem, 1.6rem + 5.4vw, 7rem);
  line-height: 0.94;
}

/* Long headlines (the Spanish one) step down a size so they keep to about three or four lines. */
.hero__title--long {
  font-size: clamp(2.875rem, 1.4rem + 4.6vw, 5.875rem);
}

.hero__tagline {
  max-width: 36ch;
  margin: 1.5rem 0 2.25rem;
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.3125rem);
  line-height: 1.5;
}

.hero__lang {
  margin-top: 1.5rem;
  font-size: 0.9375rem;
  font-weight: 500;
}

/* "Se habla español" and the profile marks on one line. The marks are white at about 70%, so they read as part of
   the photo's overlay rather than buttons; hovering brings one up to full. Each keeps a 44px tap area. */
.hero__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 1rem;
  margin-top: 1rem;
}

.hero__meta .hero__lang {
  margin: 0;
}

.hero__social {
  display: flex;
  margin: 0;
  padding: 0 0 0 0.5rem;
  border-left: 1px solid rgb(255 255 255 / 0.22);
  list-style: none;
}

.hero__meta .hero__social:first-child {
  padding-left: 0;
  border-left: 0;
}

.hero__social a {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  color: var(--color-white);
  opacity: 0.72;
  transition: opacity 200ms var(--ease), background-color 200ms var(--ease);
}

.hero__social a:hover {
  background: rgb(255 255 255 / 0.1);
  opacity: 1;
}

.hero__social a:focus-visible {
  outline-color: var(--color-white);
  opacity: 1;
}

.hero__social .social-icon {
  width: 21px;
  height: 21px;
}

/* Full-screen photo. The shade comes from the bottom-left only, so the machine stays in plain view. */
.hero--plate {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 100vh;
  min-height: 100svh;
}

.plate {
  position: absolute;
  inset: 0;
  z-index: -1;
}

/* A little taller than the hero, so the scroll drift never shows an edge. */
.plate__media {
  position: absolute;
  inset: -5% 0;
}

.plate__media picture,
.plate__img {
  display: block;
  width: 100%;
  height: 100%;
}

.plate__img {
  object-fit: cover;
  object-position: 62% 50%;
}

/* Shade only where the words sit (left and lower left, plus a band under the header), so the right of the photo
   keeps its color and light. */
.plate__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgb(29 33 30 / 0.86) 0%, rgb(29 33 30 / 0.8) 7%, rgb(29 33 30 / 0.3) 14%, rgb(29 33 30 / 0) 22%),
    linear-gradient(to right, rgb(29 33 30 / 0.88) 0%, rgb(29 33 30 / 0.84) 40%, rgb(29 33 30 / 0.7) 54%, rgb(29 33 30 / 0.3) 66%, rgb(29 33 30 / 0) 78%),
    linear-gradient(to top, rgb(29 33 30 / 0.5) 0%, rgb(29 33 30 / 0) 40%);
}

@media (max-width: 767px) {
  .plate__img {
    object-position: 50% 40%;
  }

  /* Phones: the photo shows bright in the top third, under a band for the header; the words sit on the dark below. */
  .plate__scrim {
    background:
      linear-gradient(to bottom, rgb(29 33 30 / 0.86) 0%, rgb(29 33 30 / 0.7) 6%, rgb(29 33 30 / 0.1) 11%, rgb(29 33 30 / 0.1) 18%, rgb(29 33 30 / 0.74) 26%, rgb(29 33 30 / 0.76) 40%, rgb(29 33 30 / 0.78) 70%, rgb(29 33 30 / 0.86) 100%);
  }
}

.hero--plate .hero__inner {
  position: relative;
  z-index: 1;
  padding-top: calc(var(--header-height) + 3rem);
  padding-bottom: clamp(3rem, 10vh, 6.5rem);
}

.hero--plate .hero__content {
  max-width: 60rem;
}

/* On wide screens the headline keeps to the shaded left side of the photo (about four lines). */
.hero--plate .hero__title {
  max-width: 20ch;
}

@media (min-width: 768px) {
  .hero--plate .hero__title {
    max-width: min(20ch, 46vw);
  }
}

.hero--plate .hero__tagline {
  color: var(--color-paper);
}

.plate .sample-tag {
  top: auto;
  right: var(--gutter);
  bottom: 1.25rem;
  left: auto;
}

/* Without a photo: the headline on paper beside a marked slot. */
.hero--static {
  background: var(--color-paper);
  color: var(--color-ink);
}

.hero__grid {
  display: grid;
  gap: 2.5rem;
  align-items: center;
  padding-top: calc(var(--header-height) + 2.5rem);
  padding-bottom: var(--section-space);
}

@media (min-width: 900px) {
  .hero__grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: 4.5rem;
  }
}

.hero--static .hero__tagline {
  color: var(--color-muted);
}

.hero__photo {
  position: relative;
  margin: 0;
}

.hero__photo img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* The template's video hero (not used for G-Race). */
.hero:not(.hero--plate):not(.hero--static) {
  display: grid;
  align-items: end;
  min-height: 100vh;
  min-height: 100svh;
}

.hero__media,
.hero__scrim {
  position: absolute;
  inset: 0;
}

.hero__media {
  z-index: -2;
}

.hero__scrim {
  z-index: -1;
  background: var(--hero-scrim);
}

.hero__poster,
.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__video {
  opacity: 0;
  transition: opacity 600ms var(--ease);
}

.hero__video.is-playing {
  opacity: 1;
}

.hero:not(.hero--plate):not(.hero--static) .hero__content {
  padding-top: 8rem;
  padding-bottom: clamp(3rem, 8vh, 6rem);
}

.hero__toggle {
  position: absolute;
  right: var(--gutter);
  bottom: 1.25rem;
  min-height: 44px;
  padding: 0 1rem;
  border: 0;
  border-radius: var(--radius);
  background: rgb(29 33 30 / 0.6);
  color: var(--color-white);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
}

@media (max-width: 767px) {
  .hero .actions {
    align-items: stretch;
    flex-direction: column;
  }

  .hero .actions .btn {
    width: 100%;
  }

  .hero .actions .link-arrow {
    justify-content: center;
  }

  .hero__toggle {
    top: calc(var(--header-height) + 0.5rem);
    bottom: auto;
  }
}

/* ---------- Quick facts (template) ---------- */

.facts {
  border-bottom: 1px solid var(--color-line);
}

.facts__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem 2rem;
  margin: 0;
  padding-block: 1.5rem;
}

.facts__item dt {
  color: var(--color-muted);
  font-size: 0.875rem;
}

.facts__item dd {
  margin: 0;
  font-weight: 600;
}

/* ---------- Sections ---------- */

.section {
  padding-block: var(--section-space);
}

.section__head {
  max-width: 44rem;
  margin-bottom: clamp(2.5rem, 6vw, 4.5rem);
}

.section__title {
  font-size: clamp(2.875rem, 1.7rem + 3.6vw, 4.75rem);
}

.section__intro,
.lead {
  margin-top: 1.25rem;
  color: var(--color-muted);
  font-size: 1.1875rem;
  line-height: 1.55;
}

.section__more {
  margin-top: 2.5rem;
  font-weight: 600;
}

/* ---------- Texture ---------- */
/* Fine paper grain on every flat surface, sand behind Our work, and faint survey contours (the land he
   shapes) behind three sections. Contours fade out at their edges so they never read as wallpaper.
   Both are image files: tools/contours.mjs draws the contours; grain.svg is a few lines of SVG noise. */

.section--work {
  background: var(--color-sand) var(--grain);
}

.section--work .slot {
  background: var(--color-paper);
}

.section--services,
.section--contact,
.site-footer {
  position: relative;
  isolation: isolate;
}

.section--services::before,
.section--contact::before,
.site-footer::before {
  content: "";
  position: absolute;
  z-index: -1;
  pointer-events: none;
  background-repeat: no-repeat;
}

.section--services::before {
  inset: 0 0 auto auto;
  width: min(72rem, 100%);
  height: min(56rem, 100%);
  background-image: url("/img/contours-ink.svg");
  background-position: right -14rem top -6rem;
  background-size: 100rem auto;
  opacity: 0.6;
  -webkit-mask-image: radial-gradient(ellipse 100% 100% at 100% 0%, #000 35%, transparent 100%);
  mask-image: radial-gradient(ellipse 100% 100% at 100% 0%, #000 35%, transparent 100%);
}

/* Behind the form card, so the rings show around its edges and never cross the reading column. */
.section--contact::before {
  inset: 0 0 0 auto;
  width: min(64rem, 100%);
  background-image: url("/img/contours-ink.svg");
  background-position: right -10rem top -2rem;
  background-size: 100rem auto;
  opacity: 0.6;
  -webkit-mask-image: radial-gradient(ellipse 90% 80% at 70% 40%, #000 40%, transparent 100%);
  mask-image: radial-gradient(ellipse 90% 80% at 70% 40%, #000 40%, transparent 100%);
}

.site-footer::before {
  inset: 0;
  background-image: url("/img/contours-paper.svg");
  background-position: right -10rem center;
  background-size: 100rem auto;
  opacity: 0.4;
  -webkit-mask-image: linear-gradient(to left, #000 20%, transparent 85%);
  mask-image: linear-gradient(to left, #000 20%, transparent 85%);
}

@media (max-width: 767px) {
  .section--services::before,
  .section--contact::before,
  .site-footer::before {
    background-size: 70rem auto;
  }

  /* Phones have no empty column beside the text, so the lines sit fainter behind it. */
  .section--services::before,
  .section--contact::before {
    opacity: 0.4;
  }
}

/* ---------- Services ---------- */
/* The three core jobs: large alternating rows, photo across seven columns and words across five. */

.features {
  display: grid;
  gap: clamp(3.5rem, 9vw, 7rem);
  list-style: none;
}

.feature {
  display: grid;
  gap: 1.75rem;
  align-items: center;
}

.feature__media {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--color-sand);
}

.feature__media picture,
.feature__media img,
.minor__media picture,
.minor__media img,
.gallery__media picture,
.gallery__media img,
.band__media picture,
.band__media img {
  display: block;
  width: 100%;
  height: 100%;
}

.feature__media img {
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

.feature__name {
  font-size: clamp(2.375rem, 1.6rem + 2.2vw, 3.5rem);
}

.feature__summary {
  max-width: 36ch;
  margin: 1rem 0 1.25rem;
  color: var(--color-muted);
  font-size: 1.1875rem;
}

@media (max-width: 767px) {
  /* On phones the photos run edge to edge. */
  .feature__media {
    margin-inline: calc(var(--gutter) * -1);
  }
}

@media (min-width: 900px) {
  .feature {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 0;
  }

  .feature__media {
    grid-column: 1 / span 7;
    grid-row: 1;
  }

  .feature__body {
    grid-column: 9 / span 4;
    grid-row: 1;
  }

  .feature:nth-child(even) .feature__media {
    grid-column: 6 / span 7;
  }

  .feature:nth-child(even) .feature__body {
    grid-column: 1 / span 4;
  }
}

/* The other two: a quieter pair with smaller photos, under a hairline. */
.minor-services {
  display: grid;
  gap: 3rem 2.5rem;
  margin-top: clamp(4rem, 9vw, 7rem);
  padding-top: clamp(3rem, 6vw, 4.5rem);
  border-top: 1px solid var(--color-line);
  list-style: none;
}

@media (min-width: 768px) {
  .minor-services {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.minor {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  grid-template-areas: "media name" "media summary" "media start";
  align-content: start;
  gap: 0 1.5rem;
}

.minor__media {
  position: relative;
  grid-area: media;
  align-self: start;
  margin: 0;
  overflow: hidden;
  background: var(--color-sand);
}

.minor__media img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.minor__name {
  grid-area: name;
  font-size: clamp(1.75rem, 1.4rem + 1vw, 2.25rem);
}

.minor__summary {
  grid-area: summary;
  margin: 0.6rem 0 0.4rem;
  color: var(--color-muted);
}

.minor .service__start {
  grid-area: start;
  justify-self: start;
}

/* Without photos: a plain ruled list. */
.service-list {
  display: grid;
  border-bottom: 1px solid var(--color-line);
  list-style: none;
}

.service {
  padding: 1.5rem 0;
  border-top: 1px solid var(--color-line);
}

.service__name {
  font-size: 1.625rem;
}

.service__summary {
  margin: 0.5rem 0 0.25rem;
  color: var(--color-muted);
}

.service__price {
  margin-top: 0.5rem;
  font-weight: 600;
}

/* ---------- Commercial band ---------- */

.band {
  position: relative;
  isolation: isolate;
  color: var(--color-white);
}

.band--pine {
  padding-block: var(--section-space);
  background: var(--color-pine) var(--grain);
}

.band--photo {
  display: flex;
  align-items: flex-end;
  min-height: min(82vh, 46rem);
  padding-block: var(--section-space) clamp(3rem, 8vw, 5.5rem);
  background: var(--color-ink);
}

.band__media {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.band__media img {
  object-fit: cover;
}

.band__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgb(29 33 30 / 0.86) 0%, rgb(29 33 30 / 0.5) 45%, rgb(29 33 30 / 0.12) 100%),
    linear-gradient(to right, rgb(29 33 30 / 0.5) 0%, rgb(29 33 30 / 0) 60%);
}

.band__media .sample-tag {
  z-index: 1;
  top: auto;
  right: var(--gutter);
  bottom: 1.25rem;
  left: auto;
}

.band__inner {
  max-width: var(--wrap);
}

.band__title {
  max-width: 16ch;
  font-size: clamp(2.875rem, 1.7rem + 3.6vw, 4.75rem);
}

.band__text {
  max-width: 44ch;
  margin: 1.25rem 0 1rem;
  font-size: 1.1875rem;
}

.band__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0 2rem;
  max-width: none;
}

/* ---------- Our work ---------- */

.gallery {
  display: grid;
  gap: 3rem 1.25rem;
  list-style: none;
}

@media (min-width: 640px) {
  .gallery {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 3.5rem 2rem;
  }
}

.gallery figure {
  margin: 0;
}

.gallery__media {
  position: relative;
  overflow: hidden;
  background: var(--color-sand);
}

.gallery__media img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.gallery__caption {
  margin-top: 0.85rem;
  color: var(--color-muted);
  font-size: 0.9375rem;
}

.gallery__label {
  margin-right: 0.35rem;
  color: var(--color-ink);
  font-weight: 600;
}

/* ---------- Our work: the photo ring ---------- */
/* No script or reduced motion: a two-column grid of photo links. main.js turns it into a 3D ring (.is-3d) on every
   screen size. Photos stay square-cornered, like everywhere else. */

.ring {
  width: min(var(--wrap), 100% - 2 * var(--gutter));
  margin-inline: auto;
  --ring-wash: var(--color-sand); /* what photos fade into as they turn away */
}

.ring__track {
  display: grid;
  gap: 2.5rem 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 640px) {
  .ring__track {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.ring__item {
  position: relative;
}

.ring__open {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--color-paper);
  transition: transform 160ms var(--ease);
}

.ring__open img {
  display: block;
  aspect-ratio: 4 / 3;
  width: 100%;
  height: auto;
  object-fit: cover;
}

.ring__open:focus-visible {
  outline: 3px solid var(--color-clay);
  outline-offset: 4px;
}

.ring__caption {
  margin-top: 0.85rem;
  color: var(--color-muted);
  font-size: 0.9375rem;
  font-weight: 600;
}

.ring__hint {
  display: none;
  margin-top: 0.75rem;
}

.section--work:has(.ring.is-3d) .ring__hint {
  display: block;
}

.ring__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem 1rem;
  margin-top: 1.75rem;
}

.ring__controls[hidden] {
  display: none;
}

.ring__btn {
  display: inline-grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--color-field-line);
  border-radius: 50%;
  background: var(--color-paper);
  color: var(--color-ink);
  font-size: 1.25rem;
  cursor: pointer;
  transition: transform 100ms ease-out, background-color 200ms var(--ease), border-color 200ms var(--ease);
}

.ring__btn:hover {
  border-color: var(--color-ink);
}

.ring__btn:active {
  transform: scale(0.92);
  background: var(--color-white);
}

.ring__btn:focus-visible,
.ring__pause:focus-visible {
  outline: 3px solid var(--color-clay);
  outline-offset: 3px;
}

.ring__now {
  min-width: min(16rem, 50vw);
  margin: 0;
  color: var(--color-ink);
  font-size: 0.9375rem;
  font-weight: 600;
  text-align: center;
}

.ring__pause {
  min-height: 44px;
  padding: 0 0.5rem;
  border: 0;
  background: none;
  color: var(--color-muted);
  font: inherit;
  font-size: 0.875rem;
  text-decoration: underline;
  text-underline-offset: 0.3em;
  cursor: pointer;
}

/* The ring. Photos keep their own size at the front and wash into the sand as they turn away
   (--d runs from 1 at the front to 0 at the sides, set every frame by main.js). */
.ring.is-3d {
  --ring-item: clamp(20rem, 30vw, 30rem);
  width: 100%;
  overflow: hidden;
  perspective: 2000px;
}

.ring.is-3d .ring__track {
  position: relative;
  display: block;
  width: var(--ring-item);
  height: calc(var(--ring-item) * 0.75);
  margin: 3.5rem auto 0;
  transform-style: preserve-3d;
  cursor: grab;
  touch-action: pan-y;
  user-select: none;
}

.ring.is-3d .ring__track.is-dragging {
  cursor: grabbing;
}

.ring.is-3d .ring__item {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  will-change: transform; /* drawn once at full size, so photos don't re-sharpen with a flicker when it stops */
}

.ring.is-3d .ring__open::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ring-wash);
  opacity: calc(0.7 * (1 - var(--d, 1)));
  pointer-events: none;
}

.ring.is-3d .ring__open,
.ring.is-3d .ring__open img {
  -webkit-user-drag: none;
}

.ring.is-3d .ring__item.is-pressed .ring__open {
  transform: scale(0.97);
  transition-duration: 100ms;
}

.ring.is-3d .ring__caption {
  display: none;
}

/* Phones: the same ring, smaller and tighter, so the front photo sits in the middle with its neighbors angled away
   at both edges, the way it reads on desktop. A closer perspective keeps the turn reading as 3D on a narrow screen.
   The pause button takes its own row. */
@media (max-width: 767px) {
  .ring.is-3d {
    --ring-item: min(60vw, 18rem);
    --ring-spread: 1;
    perspective: 900px;
  }

  .ring.is-3d .ring__track {
    margin-top: 2.5rem;
  }

  .ring__controls {
    flex-wrap: wrap;
    padding-inline: var(--gutter);
  }

  .ring__now {
    min-width: 0;
    flex: 1;
  }

  .ring__pause {
    flex-basis: 100%;
  }
}

/* ---------- Full-size photo view ---------- */
/* The photo flies out of its thumbnail and back (main.js moves it with springs); the scrim and buttons fade with
   how far open it is (--open). Buttons are frosted glass over the dark scrim. */

html:has(.lightbox[open]) {
  overflow: hidden;
}

.lightbox {
  position: fixed;
  inset: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--color-on-dark);
  overflow: hidden;
}

.lightbox[open] {
  display: grid;
  place-items: center;
}

.lightbox::backdrop {
  background: transparent;
}

.lightbox__scrim {
  position: absolute;
  inset: 0;
  background: rgb(15 18 17 / 0.94);
  opacity: 0;
}

.lightbox__figure {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 0.9rem;
  margin: 0;
  padding-inline: max(16px, env(safe-area-inset-left, 0px)) max(16px, env(safe-area-inset-right, 0px));
  pointer-events: none;
}

.lightbox__img {
  display: block;
  width: auto;
  max-width: min(92vw, 1400px);
  height: auto;
  max-height: calc(100vh - 10rem);
  max-height: calc(100dvh - 10rem);
  transform-origin: 0 0;
  will-change: transform;
  touch-action: none;
  cursor: grab;
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: auto;
}

.lightbox__img.is-dragging {
  cursor: grabbing;
}

.lightbox__caption {
  color: var(--color-on-dark-muted);
  font-size: 0.9375rem;
  text-align: center;
  opacity: var(--open, 0);
}

.lightbox__close,
.lightbox__nav {
  position: absolute;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border: 1px solid rgb(245 242 236 / 0.22);
  border-radius: 50%;
  background: rgb(245 242 236 / 0.12);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  backdrop-filter: blur(16px) saturate(160%);
  color: var(--color-on-dark);
  font-size: 1.375rem;
  line-height: 1;
  cursor: pointer;
  opacity: var(--open, 0);
  transition: transform 100ms ease-out, background-color 200ms var(--ease);
}

.lightbox__close:hover,
.lightbox__nav:hover {
  background: rgb(245 242 236 / 0.2);
}

.lightbox__close:active,
.lightbox__nav:active {
  transform: scale(0.92);
}

.lightbox__close:focus-visible,
.lightbox__nav:focus-visible {
  outline: 3px solid var(--color-on-dark);
  outline-offset: 3px;
}

.lightbox__close {
  top: calc(1rem + env(safe-area-inset-top, 0px));
  right: calc(1rem + env(safe-area-inset-right, 0px));
}

.lightbox__nav {
  top: 50%;
  margin-top: -24px;
}

.lightbox__nav--prev {
  left: calc(1rem + env(safe-area-inset-left, 0px));
}

.lightbox__nav--next {
  right: calc(1rem + env(safe-area-inset-right, 0px));
}

@media (max-width: 767px) {
  .lightbox__nav {
    top: auto;
    bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));
    margin-top: 0;
  }
}

@media (prefers-reduced-transparency: reduce) {
  .lightbox__close,
  .lightbox__nav {
    background: var(--color-ink);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/* One grade on every photo (slightly warm, a little less saturated, a touch more contrast), so photos from
   different cameras read as one shoot. His own photos get it too. */
.plate__img,
.feature__media img,
.minor__media img,
.gallery__media img,
.ring__open img,
.band__media img,
.hero__photo img {
  filter: saturate(0.86) contrast(1.05) sepia(0.07);
}

/* ---------- Placeholders and sample labels ---------- */
/* Quiet but readable: a small dark label in the corner of every stock photo or empty slot. Preview only;
   the launch build fails while one is left. */

.sample-tag,
.slot__tag {
  position: absolute;
  bottom: 0.75rem;
  left: 0.75rem;
  padding: 0.3rem 0.55rem;
  border-radius: var(--radius);
  background: rgb(0 0 0 / 0.6);
  color: var(--color-white);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.2;
}

.slot {
  position: relative;
  display: flex;
  align-items: flex-start;
  aspect-ratio: 4 / 3;
  padding: 1.25rem;
  border: 1px dashed var(--color-field-line);
  background: var(--color-sand);
}

.slot__label {
  max-width: 28ch;
  color: var(--color-muted);
  font-weight: 500;
  line-height: 1.4;
}

/* ---------- Tool picker (template) ---------- */

.tool {
  display: grid;
  gap: 2rem;
}

.picker {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
}

.picker__option {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--color-clay);
  font-weight: 600;
}

.picker__option[aria-current="true"] {
  color: var(--color-ink);
}

/* ---------- Reasons, reviews, story (template) ---------- */

.reason-list,
.review-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: 2.5rem 3rem;
  list-style: none;
}

.reason__title {
  margin-bottom: 0.5rem;
  font-size: 1.5rem;
}

.proof-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
  margin-top: 2.5rem;
  list-style: none;
  font-weight: 600;
}

.review figure,
.review blockquote {
  margin: 0;
}

.review__quote p {
  font-size: 1.25rem;
  line-height: 1.5;
}

.review__author {
  margin-top: 1rem;
  color: var(--color-muted);
  font-weight: 600;
}

.story {
  display: grid;
  gap: 3rem 5rem;
}

@media (min-width: 900px) {
  .story:has(.story__text):has(.story__process) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- Request an estimate ---------- */

.section--contact {
  border-top: 1px solid var(--color-line);
}

/* The sand behind Our work already marks where it ends. */
.section--work + .section--contact {
  border-top: 0;
}

.contact {
  display: grid;
  grid-template-areas: "intro" "form" "info";
  gap: 3rem;
  align-items: start;
}

/* Phones see the form right after the heading; details follow. Wider screens put the form beside them. */
@media (min-width: 900px) {
  .contact {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    grid-template-areas: "intro form" "info form";
    grid-template-rows: auto 1fr;
    gap: 2.5rem 6rem;
  }
}

.contact__intro {
  grid-area: intro;
}

.contact__info {
  grid-area: info;
}

.contact__form,
.contact__cta {
  grid-area: form;
}

/* The steps: serif numerals, hairlines between, no boxes. */
.estimate-steps {
  margin-top: 2.75rem;
}

.estimate-steps__title {
  margin-bottom: 0.5rem;
  color: var(--color-muted);
  font-family: var(--font-body);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0;
}

.steps {
  list-style: none;
  counter-reset: step;
}

.steps__item {
  position: relative;
  padding: 1.1rem 0 1.1rem 3rem;
  border-top: 1px solid var(--color-line);
  counter-increment: step;
}

.steps__item:last-child {
  border-bottom: 1px solid var(--color-line);
}

.steps__item::before {
  content: counter(step);
  position: absolute;
  top: 0.95rem;
  left: 0;
  color: var(--color-clay);
  font-family: var(--font-display);
  font-size: 1.875rem;
  font-weight: 800;
  line-height: 1;
}

.steps__title {
  margin: 0;
  font-weight: 600;
  font-size: 1.125rem;
}

.steps__item p:not(.steps__title) {
  margin-top: 0.2rem;
  color: var(--color-muted);
}

.contact__details {
  display: grid;
  gap: 1.1rem;
  margin: 0 0 2rem;
}

.contact__details dt {
  color: var(--color-muted);
  font-size: 0.875rem;
}

.contact__details dd {
  margin: 0;
  font-weight: 600;
}

.contact__details a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.lang-note {
  display: block;
  color: var(--color-muted);
  font-weight: 400;
}

.hours {
  width: 100%;
  max-width: 24rem;
  border-collapse: collapse;
}

.hours th,
.hours td {
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--color-line);
  text-align: left;
  vertical-align: top;
}

.hours th {
  padding-right: 1.5rem;
  font-weight: 600;
}

.hours__note {
  margin-top: 0.75rem;
  color: var(--color-muted);
  font-size: 0.9375rem;
}

.social-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin-top: 1.5rem;
  list-style: none;
  font-weight: 600;
}

/* Footer and contact block: the mark beside the name. */
.social-list a {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
}

.social-list .social-icon {
  flex: none;
  width: 20px;
  height: 20px;
}

/* The form: one white card, thin borders, plain checkboxes. */
.contact__form {
  padding: clamp(1.5rem, 4vw, 2.75rem);
  border: 1px solid var(--color-line);
  border-radius: var(--radius);
  background: var(--color-white);
}

@media (max-width: 599px) {
  .contact__form {
    margin-inline: calc(var(--gutter) * -0.5);
  }
}

.lead-form {
  display: grid;
  gap: 1.5rem;
}

.field {
  display: grid;
  gap: 0.45rem;
}

.field__label {
  font-weight: 600;
}

.field__optional {
  color: var(--color-muted);
  font-weight: 400;
}

.field__hint {
  margin: 0;
  color: var(--color-muted);
  font-size: 0.9375rem;
}

.field__input {
  width: 100%;
  min-height: 52px;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--color-field-line);
  border-radius: var(--radius);
  background: var(--color-white);
  color: var(--color-ink);
  font: inherit;
  transition: border-color 150ms var(--ease);
}

.field__input:hover {
  border-color: var(--color-muted);
}

.field__input:focus {
  border-color: var(--color-ink);
  outline: none;
}

.field__input:focus-visible {
  outline: 2px solid var(--color-ink);
  outline-offset: 2px;
}

.field__input--area {
  min-height: 8rem;
  resize: vertical;
}

.field__input[type="file"] {
  padding: 0.55rem;
  color: var(--color-muted);
  cursor: pointer;
}

.field__input[type="file"]::file-selector-button {
  margin-right: 0.9rem;
  padding: 0.5rem 1rem;
  border: 1px solid var(--color-ink);
  border-radius: var(--radius);
  background: var(--color-paper);
  color: var(--color-ink);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 150ms var(--ease);
}

.field__input[type="file"]:hover::file-selector-button {
  background: var(--color-sand);
}

.field__input[type="file"] {
  padding: 0.65rem;
  font-size: 1rem;
}

.field--choices {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.field--choices .field__label {
  margin-bottom: 0.35rem;
  padding: 0;
}

.choices {
  display: grid;
  gap: 0 1.5rem;
}

@media (min-width: 520px) {
  .choices {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.choice {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  min-height: 44px;
  cursor: pointer;
}

.choice__input {
  flex: none;
  width: 1.125rem;
  height: 1.125rem;
  margin: 0;
  accent-color: var(--color-ink);
}

.field__input[aria-invalid="true"] {
  border-color: var(--color-error);
}

.field__error {
  margin: 0;
  color: var(--color-error);
  font-size: 0.9375rem;
  font-weight: 600;
}

.lead-form__privacy {
  margin: 0;
  color: var(--color-muted);
  font-size: 0.9375rem;
}

.lead-form__submit {
  justify-self: start;
}

.lead-form__status {
  margin: 0;
  font-weight: 600;
}

.lead-form__status[data-state="error"] {
  color: var(--color-error);
}

.lead-form__status a {
  color: var(--color-ink);
  white-space: nowrap;
}

.lead-form__status[data-state="success"] {
  color: var(--color-success);
}

.lead-form--sent > :not(.lead-form__status) {
  display: none;
}

.lead-form--sent .lead-form__status {
  font-family: var(--font-display);
  font-size: 2rem;
  font-weight: 800;
  line-height: 1.05;
}

/* ---------- Simple pages (thanks, 404) ---------- */

.simple-page {
  padding-block: clamp(5rem, 14vw, 9rem);
}

.simple-page__title {
  max-width: 22ch;
  margin-bottom: 1.5rem;
  font-size: clamp(2.5rem, 1.6rem + 3vw, 4rem);
}

/* The privacy page: one readable column. */
.prose {
  max-width: 44rem;
}

.prose h2 {
  margin: 2.5rem 0 0.75rem;
  font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem);
}

.prose p + p {
  margin-top: 1rem;
}

.prose__date {
  margin-bottom: 1.5rem;
  color: var(--color-muted);
}

/* Small links on their own (the privacy links, the privacy page's email and phone): a little height so they're at
   least 24px to tap. */
.prose p > a,
.lead-form__privacy a,
.site-footer__legal a {
  display: inline-block;
  padding-block: 0.35rem;
}

/* ---------- Footer ---------- */

.site-footer {
  padding-block: clamp(3.5rem, 8vw, 5rem) 2.5rem;
  background: var(--color-pine) var(--grain);
  color: var(--color-on-dark);
}

.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 2rem;
}

.site-footer__brand p {
  margin-bottom: 0.25rem;
}

.site-footer__brand a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.site-footer__brand .site-footer__name {
  margin-bottom: 1rem;
  font-family: var(--font-display);
  font-size: 1.75rem;
  font-weight: 800;
}

.site-footer__logo {
  display: block;
  width: 22rem; /* the trade line under the name stays about 12px tall */
  max-width: 100%;
  height: auto;
}

.social-list--footer {
  margin-top: 0;
}

/* The bottom row: © and Privacy at the left, the "Made by" credit at the right; stacked on narrow screens. */
.site-footer__legal {
  display: flex;
  flex-basis: 100%;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.25rem 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgb(245 242 236 / 0.16);
  color: var(--color-on-dark-muted);
  font-size: 0.875rem;
}

.site-footer__legal p {
  margin: 0;
}

.site-footer__credit {
  letter-spacing: 0.02em;
}

/* ---------- Phone action bar ---------- */

.action-bar {
  position: fixed;
  inset: auto 0 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem var(--gutter) calc(0.75rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--color-line);
  background: rgb(245 242 236 / 0.98);
  color: var(--color-ink);
  transition: transform 320ms var(--ease), visibility 0s;
}

/* Hidden: slides away, then drops out of the tab order and screen readers once it's gone. */
.action-bar.is-hidden {
  transform: translateY(110%);
  visibility: hidden;
  transition: transform 320ms var(--ease), visibility 0s 320ms;
}

.action-bar__primary {
  flex: 1;
  white-space: nowrap;
}

.action-bar__secondary,
.action-bar__call {
  flex: none;
  white-space: nowrap;
}

/* The first time the bar slides up (main.js adds is-greeted once), its arrow gives the same single nudge as the
   hero's estimate link, just after the bar lands. */
@media (prefers-reduced-motion: no-preference) {
  .action-bar.is-greeted .link-arrow::after {
    animation: arrow-nudge 0.8s 0.35s cubic-bezier(0.3, 0, 0.2, 1) backwards;
  }
}

@media (max-width: 767px) {
  .page--index {
    padding-bottom: calc(76px + env(safe-area-inset-bottom));
  }
}

@media (min-width: 768px) {
  .action-bar {
    display: none;
  }
}

/* ---------- Draft notice (preview only) ---------- */

.draft-notice {
  max-width: none;
  margin: 0;
  padding: 0.5rem var(--gutter);
  background: var(--color-ink);
  color: var(--color-white);
  font-size: 0.8125rem;
  font-weight: 500;
  text-align: center;
}

@media (min-width: 768px) {
  .draft-notice {
    position: fixed;
    bottom: 1rem;
    left: 1rem;
    z-index: 40;
    max-width: 22rem;
    padding: 0.55rem 0.8rem;
    border-radius: var(--radius);
    background: rgb(0 0 0 / 0.72);
    text-align: left;
  }
}

/* ---------- Motion: felt, not seen ---------- */

/* Hero: the photo settles in and the headline fades up once. The buttons never move or fade. */
.hero--plate .plate__img {
  animation: plate-in 1600ms var(--ease) both;
}

.hero--plate .hero__title {
  animation: rise 900ms var(--ease) 120ms both;
}

.hero--plate .hero__tagline {
  animation: rise 900ms var(--ease) 240ms both;
}

@keyframes plate-in {
  from { transform: scale(1.06); }
  to { transform: none; }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}

/* Sections: main.js marks only what starts below the fold, so nothing on screen at load ever hides.
   Content fades up 16px; photos inside come in from a slight zoom. Once each. */
.is-pending[data-reveal] {
  opacity: 0;
  transform: translateY(16px);
}

.is-pending[data-reveal] img {
  transform: scale(1.04);
}

.is-revealed[data-reveal] {
  transition: opacity var(--reveal) var(--ease), transform var(--reveal) var(--ease);
}

.is-revealed[data-reveal] img {
  transition: transform 1200ms var(--ease);
}

.minor:nth-child(2),
.gallery__item:nth-child(even) {
  transition-delay: 80ms;
}

/* After "Get an estimate", the service it ticked in the form gets a brief clay tint. */
.choice::before {
  content: "";
  position: absolute;
  inset: 0 -0.5rem;
  z-index: -1;
  border-radius: var(--radius);
  background: rgb(138 58 32 / 0.12);
  opacity: 0;
  pointer-events: none;
}

.lead-form {
  isolation: isolate;
}

.choice.is-picked::before {
  animation: picked 1400ms var(--ease) 300ms both;
}

@keyframes picked {
  0% { opacity: 0; }
  25% { opacity: 1; }
  100% { opacity: 0; }
}

/* The hero photo drifts a little slower than the page, where the browser can tie motion to scrolling. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero--plate .plate__media {
      animation: plate-drift linear both;
      animation-timeline: scroll(root);
      animation-range: 0 100vh;
    }

    @keyframes plate-drift {
      to { transform: translateY(5%); }
    }
  }
}

/* ---------- Reduced motion ---------- */
/* Nothing moves; everything is simply in place. The picked service still shows as checked. */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }

  .is-pending[data-reveal],
  .is-pending[data-reveal] img {
    opacity: 1;
    transform: none;
  }

  .hero--plate .plate__img,
  .hero--plate .hero__title,
  .hero--plate .hero__tagline,
  .choice.is-picked::before {
    animation: none !important;
  }
}
