/* ==========================================================================
   Clark's Custom Lawn: the one shared stylesheet.

   Phase 1 scope: design tokens, reset, base elements, layout primitives.
   Components are added in Phase 2 beneath the marker at the end of this file.

   Every value below is a token or derives from one. No raw colour, no raw
   type size, and no magic number outside the token block.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens

   Colours carry their measured WCAG contrast ratio in the comment beside
   them, computed with the relative-luminance formula rather than estimated.
   The three call-to-action fills are darkened from the live site's values,
   which failed in eight distinct pairs (worst case 1.78:1). Hue is held; only
   lightness moves. See DECISIONS.md D8.
   -------------------------------------------------------------------------- */

:root {
  /* Surfaces */
  --color-surface: #ffffff;
  --color-surface-alt: #f3f5f8;
  --color-surface-dark: #00102e;

  /* Text on light surfaces */
  --color-text: #000000; /* 21.00:1 on surface, 19.23:1 on alt */
  --color-heading: #1c244b; /* 14.96:1 on surface, 13.70:1 on alt */
  --color-muted: #324a6d; /* 8.99:1 on surface */

  /* Interactive, light surfaces. Both clear 4.5:1 on surface AND on alt. */
  --color-accent: #2165f5; /* 4.95:1 on surface, 4.53:1 on alt */
  --color-accent-hover: #16408f; /* 9.70:1 on surface */
  --cta-call: #1e7994; /* white label 4.98:1; fill vs surface 4.98:1 */
  --cta-text: #387f38; /* white label 4.93:1; fill vs surface 4.51:1 on alt */

  /* ON-DARK ONLY. Both FAIL on any light surface and must never be used
     there: --color-text-on-dark is 1.00:1 on white, --color-accent-on-dark
     is 3.72:1 on white. They are valid against --color-surface-dark alone. */
  --color-text-on-dark: #ffffff; /* 18.86:1 on surface-dark */
  --color-muted-on-dark: #c8d2e4; /* 12.39:1 on surface-dark */
  --color-accent-on-dark: #467ff7; /* 5.06:1 on surface-dark */

  /* Decorative separators only, at 1.36:1 against surface. Anything that is
     the SOLE visual indication of a control's boundary (a text input, a
     checkbox) needs 3:1 under WCAG 1.4.11 and must use --color-border-strong
     instead. That applies to the contact form in Phase 4. */
  --color-border: #d7dde7;
  --color-border-strong: #1c244b; /* 14.96:1 on surface */
  --color-focus: #b8480f; /* 5.29:1 surface, 4.84:1 alt, 3.57:1 dark */

  /* Type. Step 1 of the parent's font procedure: the system stack, which the
     live site already used for body copy. No webfont ships. See D7. */
  --font-body:
    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu,
    Cantarell, "Helvetica Neue", Arial, sans-serif;
  --font-heading: var(--font-body);

  /* Fluid scale. Upper bounds match the reference: h1 42px, h2 28px. */
  --text-xs: 0.8125rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);
  --text-2xl: clamp(1.5rem, 1.3rem + 1vw, 1.75rem); /* h2 -> 28px */
  --text-3xl: clamp(1.875rem, 1.5rem + 1.9vw, 2.625rem); /* h1 -> 42px */

  --leading-body: 1.68; /* the reference's 26.88px on 16px */
  --leading-heading: 1.2;

  --weight-body: 400;
  --weight-medium: 500;
  --weight-bold: 600; /* the reference's heading weight */

  /* Spacing, a 4px base */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;
  --space-9: 6rem;

  /* Radii, from the reference's 10px controls and 100px pills */
  --radius-sm: 0.375rem;
  --radius-md: 0.625rem;
  --radius-pill: 6.25rem;

  --border-thin: 1px solid var(--color-border);
  --shadow-card: 0 1px 3px rgb(0 16 46 / 0.08);
  --shadow-raised: 0 6px 20px rgb(0 16 46 / 0.12);

  /* Content widths. --width-wide matches the reference's centred card. */
  --width-prose: 68ch;
  --width-wide: 75rem;
  --gutter: var(--space-4); /* the 1rem that makes the hero slot 100vw - 2rem */

  --z-base: 0;
  --z-raised: 10;
  --z-header: 100;
  --z-skiplink: 200;

  --duration-fast: 150ms;
  --duration-base: 250ms;
  --ease: cubic-bezier(0.2, 0, 0.2, 1);
}

/* The focus ring is a warm colour deliberately: it must be visible against
   the navy header, the white surface and the pale alt surface, and a blue
   ring on a blue-and-navy palette disappears on at least one of them.
   Measured on all three: 5.29:1 on surface, 4.84:1 on alt, 3.57:1 on
   surface-dark, so it clears the 3:1 non-text minimum everywhere it appears.
   Paired with an offset so it never sits on the control's own fill, and it
   changes the element's box rather than only its colour, so focus is never
   signalled by colour alone. */

/* --------------------------------------------------------------------------
   2. Reset and base
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

html {
  /* .photo-band's calc(50% - 50vw) full-bleed breakout is 1px-accurate
     against the visual viewport but not the scrollbar-inclusive layout
     viewport, so it overflows by the scrollbar's width on any platform
     that reserves one. Guarded on the root, not just body: body-only
     clipping left documentElement.scrollWidth still reporting the
     pre-clip width. Kept in one place regardless of which future
     component breaks out to full-bleed. */
  overflow-x: hidden;
}

body {
  margin: 0;
  background-color: var(--color-surface);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: var(--weight-body);
  line-height: var(--leading-body);
  /* Guards against a long unbroken URL in body copy forcing a horizontal
     scrollbar, which section 3 forbids at every width. */
  overflow-wrap: break-word;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  margin: 0 0 var(--space-4);
  color: var(--color-heading);
  font-family: var(--font-heading);
  font-weight: var(--weight-bold);
  line-height: var(--leading-heading);
  /* The system stack sets wider than the reference's Poppins at the same
     size. A small negative tracking on display sizes closes most of that gap
     without touching the size itself. Tuned by measured comparison against
     build-log/legacy-shots/, not by eye. */
  letter-spacing: -0.015em;
}

h1 {
  font-size: var(--text-3xl);
}
h2 {
  font-size: var(--text-2xl);
}
h3 {
  font-size: var(--text-xl);
}
h4 {
  font-size: var(--text-lg);
}

p,
ul,
ol,
dl,
figure,
blockquote {
  margin: 0 0 var(--space-4);
}

a {
  color: var(--color-accent);
  text-decoration-thickness: max(0.08em, 1px);
  text-underline-offset: 0.15em;
}

a:hover {
  color: var(--color-accent-hover);
}

/* One focus treatment, reused site-wide and verified against every surface a
   focusable element sits on. */
:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

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

img {
  height: auto;
}

ul,
ol {
  padding-inline-start: var(--space-5);
}

/* Vertical rhythm for plain prose lists only (a bare <ul>/<ol> in body
   copy). Scoped to unclassed lists so it never reaches a component list
   (.site-nav__list, .grid, .mosaic, .breadcrumb__list, .site-footer__grid),
   which already manage their own spacing via flex/grid gap. An unscoped
   `li + li` rule here previously leaked into .site-nav__list and pushed
   every nav item but the first down 8px, since Home is the only <li> with
   no preceding sibling. */
ul:not([class]) li + li,
ol:not([class]) li + li {
  margin-top: var(--space-2);
}

blockquote {
  margin-inline: 0;
}

hr {
  border: 0;
  border-top: var(--border-thin);
  margin: var(--space-7) 0;
}

table {
  border-collapse: collapse;
  width: 100%;
}

th,
td {
  border-bottom: var(--border-thin);
  padding: var(--space-2) var(--space-3);
  text-align: left;
}

/* Form controls inherit type rather than falling back to the UA default. */
input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--width-wide);
  margin-inline: auto;
  /* This 1rem per side is load-bearing: it makes a full-width slot
     calc(100vw - 2rem), which is what every `sizes` attribute declares. A
     change here without the matching `sizes` change re-fetches the wrong
     rung. */
  padding-inline: var(--gutter);
}

.container--prose {
  max-width: var(--width-prose);
}

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

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

.section--alt {
  background-color: var(--color-surface-alt);
}

.section--dark {
  background-color: var(--color-surface-dark);
  color: var(--color-text-on-dark);
}

.section--dark :is(h1, h2, h3, h4, h5, h6) {
  color: var(--color-text-on-dark);
}

.section--dark a {
  color: var(--color-accent-on-dark);
}

.stack > * + * {
  margin-top: var(--space-4);
}

/* Testimonial avatar: the master is already native 1:1 (1536x1536), so a
   square display box matches the image's own ratio rather than cropping
   it, keeping this compliant with the no-crop policy without needing that
   policy's scoped exception. */
.testimonial__avatar {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
}

.grid {
  display: grid;
  gap: var(--space-5);
}

/* A <ul> or <ol> used purely as a layout container (a grid of cards, not a
   list a screen reader should announce item count for) resets the default
   list styling. Applied alongside .grid rather than folded into it, since
   .grid is also used on non-list elements. */
.grid--plain {
  list-style: none;
  padding: 0;
  margin: 0;
}

@media (min-width: 40rem) {
  .grid--2,
  .grid--4 {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 64rem) {
  .grid--3 {
    grid-template-columns: repeat(3, 1fr);
  }
  .grid--4 {
    grid-template-columns: repeat(4, 1fr);
  }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  z-index: var(--z-skiplink);
  padding: var(--space-2) var(--space-4);
  background-color: var(--color-surface);
  color: var(--color-accent);
  border: 2px solid var(--color-focus);
  border-radius: var(--radius-sm);
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: translateY(0);
}

/* The .page-backdrop rule that lived here (a decorative background photo,
   desktop only) was removed per DECISIONS.md D14: its source master,
   Pavers-Walkway, turned out to be a fabricated stock image, and no
   remaining verified-real master suits a repeating background role without
   stretching a photo composed for a content slot into a second, unrelated
   use. No replacement was introduced; the class name is not reused. */

/* --------------------------------------------------------------------------
   4. Motion

   Under a reduced-motion preference all non-essential movement stops. The
   near-zero durations rather than `none` keep transitionend handlers firing,
   so nothing that waits on one deadlocks.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   PHASE 2 COMPONENTS BELOW THIS LINE
   ========================================================================== */

/* --------------------------------------------------------------------------
   Button (.btn)

   One control, one accessible name: never a nested or duplicated link/button
   structure. Both CTA fills were darkened in Phase 1 specifically so the
   label clears 4.5:1 AND the fill clears 3:1 against the surface behind it
   (WCAG 1.4.11); the live reference failed both in eight pairs.
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 44px;
  padding-inline: var(--space-5);
  border-radius: var(--radius-pill);
  font-weight: var(--weight-bold);
  font-size: var(--text-sm);
  text-decoration: none;
  border: 2px solid transparent;
  cursor: pointer;
  transition:
    background-color var(--duration-fast) var(--ease),
    border-color var(--duration-fast) var(--ease),
    opacity var(--duration-fast) var(--ease);
}

.btn--cta {
  background-color: var(--cta-call);
  color: var(--color-text-on-dark);
}
.btn--cta:hover {
  background-color: #16576a; /* darkened further; label stays white throughout */
  color: var(--color-text-on-dark);
}

.btn--text {
  background-color: var(--cta-text);
  color: var(--color-text-on-dark);
}
.btn--text:hover {
  background-color: #2c632c;
  color: var(--color-text-on-dark);
}

.btn--ghost {
  background-color: transparent;
  border-color: currentColor;
  color: var(--color-accent);
}
.btn--ghost:hover {
  background-color: var(--color-surface-alt);
}

.section--dark .btn--ghost {
  color: var(--color-text-on-dark);
}

.btn[disabled] {
  opacity: 0.6;
  pointer-events: none;
}

.btn .icon {
  width: 1.1em;
  height: 1.1em;
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   Global navigation (header)
   -------------------------------------------------------------------------- */

.site-header {
  background-color: var(--color-surface-dark);
  position: relative;
  z-index: var(--z-header);
}

.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
  padding-block: var(--space-4);
}

.site-header__logo-link {
  color: var(--color-text-on-dark);
  font-weight: var(--weight-bold);
  font-size: var(--text-xl);
  text-decoration: none;
  white-space: nowrap;
  line-height: var(--leading-heading);
}

.site-header__logo-link:hover {
  color: var(--color-muted-on-dark);
}

.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding: 0;
  gap: var(--space-1) var(--space-5);
}

.site-nav__list a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-1);
  color: var(--color-text-on-dark);
  text-decoration: none;
  font-weight: var(--weight-medium);
}

.site-nav__list a:hover {
  color: var(--color-muted-on-dark);
}

/* The current-page link uses the link token plus bold plus underline, NEVER
   the surface-fill token. The :not(.btn) guard is required: without it this
   selector outranks .btn at equal specificity by source order and repaints
   a filled nav CTA's label in its own fill colour, 1:1 contrast, invisible,
   while Lighthouse still scores the page 100. There is no .btn in the
   primary nav today, but the guard costs nothing and the parent requires it
   written exactly this way regardless. */
.site-nav a[aria-current]:not(.btn) {
  font-weight: var(--weight-bold);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 2px;
}

/* --------------------------------------------------------------------------
   Breadcrumbs
   -------------------------------------------------------------------------- */

.breadcrumb {
  padding-block: var(--space-4);
  font-size: var(--text-sm);
}

.breadcrumb__list {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding: 0;
  gap: 0;
  color: var(--color-muted);
}

.breadcrumb__list li:not(:last-child)::after {
  content: "/";
  margin-inline: var(--space-2);
  color: var(--color-border-strong);
}

.breadcrumb__list li[aria-current] {
  color: var(--color-muted);
}

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

.site-footer {
  background-color: var(--color-surface-dark);
  color: var(--color-text-on-dark);
}

.site-footer__grid {
  display: grid;
  gap: var(--space-6);
  padding-block: var(--space-7);
}

@media (min-width: 48rem) {
  .site-footer__grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.site-footer__heading {
  color: var(--color-text-on-dark);
  font-size: var(--text-lg);
  margin-bottom: var(--space-3);
}

.site-footer a {
  color: var(--color-accent-on-dark);
}

.site-footer__hours th,
.site-footer__hours td {
  border-bottom: 1px solid #1c2a4a;
  padding: var(--space-1) var(--space-2) var(--space-1) 0;
  color: var(--color-muted-on-dark);
}

.site-footer__bottom {
  border-top: 1px solid #1c2a4a;
  padding-block: var(--space-4);
  font-size: var(--text-xs);
  color: var(--color-muted-on-dark);
}

.site-footer__bottom-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.site-footer__legal a {
  color: var(--color-muted-on-dark);
}

/* --------------------------------------------------------------------------
   Card (.card)

   One clear primary link, one accessible name. Media ratio follows the
   Cropping policy: no forced aspect-ratio, no object-fit: cover, so cards in
   one row that mix a 1:1 and a 4:3 master do not force a crop to match.
   -------------------------------------------------------------------------- */

.card {
  display: flex;
  flex-direction: column;
  background-color: var(--color-surface);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  transition: box-shadow var(--duration-base) var(--ease);
}

.card:hover,
.card:focus-within {
  box-shadow: var(--shadow-raised);
}

.card__link {
  color: inherit;
  text-decoration: none;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.card__link:hover .card__title,
.card__link:focus-visible .card__title {
  color: var(--color-accent);
}

.card__media {
  width: 100%;
  height: auto;
}

.card__body {
  padding: var(--space-5);
}

/* display: block rather than requiring callers to use a block element:
   build_pages.py generates these as <span> to avoid nesting a block element
   inside a card's anchor for the linked variant. Without this, margin-bottom
   on an inline element does nothing and the title runs into the excerpt on
   the same line. */
.card__title {
  display: block;
  font-size: var(--text-lg);
  margin-bottom: var(--space-2);
}

.card__excerpt {
  display: block;
  color: var(--color-muted);
  margin-bottom: 0;
}

/* A card with no image gets a designed fallback panel, never a broken image
   or an empty box. Applied only where a slot's master is absent. */
.card__media--fallback {
  aspect-ratio: 4 / 3;
  background-color: var(--color-surface-alt);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-muted);
}

/* --------------------------------------------------------------------------
   Figure, caption, and full-size image links
   -------------------------------------------------------------------------- */

.figure {
  margin: 0 0 var(--space-6);
}

.figcaption {
  margin-top: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-muted);
}

/* .media-link inserts an <a> between .figure and the <img>, so the radius
   rule has to reach through it or corners render sharp-edged. */
.figure > .media-link > img,
.figure > img {
  border-radius: var(--radius-md);
  display: block;
}

/* A lazy linked image with both dimensions auto has no intrinsic size, so
   the anchor box collapses to ~2px and WCAG target-size fails before the
   image loads. Standalone figures get width:100% so the box reserves full
   width immediately; gallery figures (inside .mosaic) get a definite height
   instead, scoped below. Never applied globally: a card's media sits in a
   different parent and a stray height:auto here would undo an intentional
   crop, which this project has none of, but the scoping still matters. */
.figure > .media-link > img {
  width: 100%;
  height: auto;
}

/* --------------------------------------------------------------------------
   Gallery mosaic (.mosaic), /portfolio/ only

   column-count, not grid, so every photo keeps its native aspect ratio
   across the mix of 4:3, 3:4, and 2.16:1 masters in the portfolio set. No
   object-fit: cover and no forced aspect-ratio here (Cropping policy).
   -------------------------------------------------------------------------- */

.mosaic {
  list-style: none;
  padding: 0;
  margin: 0;
  column-count: 1;
  column-gap: var(--space-5);
}

@media (min-width: 40rem) {
  .mosaic {
    column-count: 2;
  }
}

@media (min-width: 64rem) {
  .mosaic {
    column-count: 3;
  }
}

.mosaic__item {
  break-inside: avoid;
  margin-bottom: var(--space-5);
}

/* Gallery figures reserve a height before the lazy image loads, since a
   column layout cannot rely on width:100% the way a standalone figure can
   (the column width itself is intrinsic to the content). */
.mosaic__item > .media-link > img {
  width: 100%;
  height: auto;
  min-height: 12rem;
  background-color: var(--color-surface-alt);
}

/* --------------------------------------------------------------------------
   Icons

   Inline SVG only, never a Unicode dingbat or emoji (font coverage for
   those codepoints is not guaranteed). Meaning-bearing icons are paired
   with a visually-hidden text equivalent at the call site, not here.
   -------------------------------------------------------------------------- */

.icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   Hero (home page only)

   Wraps the sole <picture> in the build so the Call/Text pair can overlay
   the photo itself, matching the reference's placement, rather than sitting
   in plain text above it.
   -------------------------------------------------------------------------- */

/* Full-bleed photo backdrop, breaking out of .container's max-width to the
   viewport edge, with a padded surface card floating on top. Reuses an
   already-verified real project photo rather than a new asset: decorative
   background use of a real photo already shown in full elsewhere on the
   page is not a new claim, unlike the fabricated images this build
   otherwise excludes entirely (DECISIONS.md D14). */
.photo-band {
  position: relative;
  margin-inline: calc(50% - 50vw);
  padding-block: var(--space-7);
  background-size: cover;
  background-position: center;
}

/* Each band names a specific derivative already generated for its content
   use elsewhere on the page (the hero photo, and the Hardscape Installation
   photo), never a new asset. Baked in here rather than an inline style
   attribute, which parent section 2 prohibits outright.

   Deliberately the smallest rung (480w), not the largest: a first attempt
   at 1536w pushed cold LCP to 4897ms (budget 2500ms) because the browser
   fetched this decorative background at full priority alongside the real
   LCP-critical hero <picture>, competing for the same connection. The
   480w file (21KB / 51KB) is visually indistinguishable here, since
   ::before's 35% dark scrim plus the white card covering most of the
   band already obscure any fine detail a larger rung would preserve. */
.photo-band--hero {
  background-image: url("/images/Clarks-Landscaping-Reno-Landscapers-Brick-Planters-480.avif");
}

.photo-band--services {
  background-image: url("/images/Clarks-Landscaping-Reno-Landscapers-Brick-Walkway-480.avif");
}

.photo-band::before {
  content: "";
  position: absolute;
  inset: 0;
  background-color: rgb(0 16 46 / 0.35);
}

.photo-band__card {
  position: relative;
  max-width: var(--width-wide);
  margin-inline: auto;
  padding: var(--space-6);
  background-color: var(--color-surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-raised);
}

@media (min-width: 40rem) {
  .photo-band__card {
    padding: var(--space-8);
  }
}

.hero {
  position: relative;
  margin-bottom: var(--space-7);
}

.hero picture,
.hero img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
}

.hero__actions {
  position: absolute;
  right: var(--space-4);
  bottom: var(--space-4);
  display: flex;
  gap: var(--space-3);
  margin: 0;
}

.hero__actions .btn {
  text-transform: uppercase;
  letter-spacing: 0.03em;
  box-shadow: 0 2px 8px rgb(0 16 46 / 0.35);
}

@media (max-width: 30rem) {
  .hero__actions {
    right: var(--space-2);
    bottom: var(--space-2);
    gap: var(--space-2);
  }
}

/* --------------------------------------------------------------------------
   Form (.form), the contact page

   Never styled beyond the base element reset, which shipped a functional
   but entirely unstyled form: browser-default input width (~20 characters),
   no border treatment, no field spacing. Fixed here rather than patched
   piecemeal, since none of it existed before.
   -------------------------------------------------------------------------- */

.form {
  max-width: 28rem;
}

.form__field {
  margin-bottom: var(--space-5);
}

.form__field label {
  display: block;
  margin-bottom: var(--space-2);
  font-weight: var(--weight-medium);
}

.form__field input,
.form__field textarea {
  display: block;
  width: 100%;
  padding: var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface);
}

.form__field textarea {
  resize: vertical;
}

.business-info {
  list-style: none;
  padding: 0;
  margin: 0;
}

.business-info li {
  padding-block: var(--space-2);
  border-bottom: 1px solid var(--color-border);
}

.business-info li:first-child {
  border-top: 1px solid var(--color-border);
}

/* --------------------------------------------------------------------------
   Card accent modifier (.card--accent), the "Why Choose Us" cards

   A shaded panel with a colored accent rule beneath the title, distinct
   from the plain white photo cards (.card alone), matching the reference's
   two visually distinct card treatments on the same page.
   -------------------------------------------------------------------------- */

.card--accent {
  background-color: var(--color-surface-alt);
  box-shadow: none;
  border: 1px solid var(--color-border);
}

.card--accent:hover,
.card--accent:focus-within {
  box-shadow: none;
}

.card--accent .card__title {
  padding-bottom: var(--space-2);
  border-bottom: 3px solid var(--color-accent);
}

/* --------------------------------------------------------------------------
   About section (home page only)

   Two columns above 40rem: a real project photo beside a bordered text
   panel, matching the reference. Below 40rem, the photo stacks above the
   text in source order.
   -------------------------------------------------------------------------- */

.about {
  display: grid;
  gap: var(--space-6);
  align-items: start;
  margin-top: var(--space-7);
  margin-bottom: var(--space-7);
}

@media (min-width: 40rem) {
  .about {
    grid-template-columns: 1fr 1fr;
  }
}

.about__photo {
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
}

.about__body {
  padding: var(--space-5);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
}

.about__body :first-child {
  margin-top: 0;
}

.about__body :last-child {
  margin-bottom: 0;
}
