/* =====================================================================
   Gavin Voss Electrical — one-page site.

   The design language is SIGNWRITING, taken from the client's own van:
   flat colour, hard edges, no shadows, short stacked lines, a squared
   grotesque. Rules that follow from that, and that everything here obeys:

   - Seven values, every one MEASURED off the vehicle (see the block below).
     The van is warm and almost unsaturated — hue 30-33 degrees throughout —
     so the warmth is carried by the GROUND. The one accent, a bronze taken
     from the body colour, appears only as a 56px tick, twice: opening the
     promise and opening the tailgate band.
   - Zero box-shadows anywhere. Every edge square EXCEPT the brand's one
     curve — the plate cap off the mark — which the buttons reproduce.
   - Archivo 700 for display, Source Sans 3 for reading. Hard size jumps.
   - Left-aligned, sentence/Title case. No tracked-caps eyebrows.
   - Services are a SET, not a sequence — stacked hairline rows, not
     three cards in a row and not numbered.
   - Breathing room comes from vertical rhythm, not from big gutters.

   See DESIGN-LANGUAGE.md for the reasoning and the source photograph.
   ===================================================================== */

/* THE PALETTE IS THE VEHICLE — every value below is measured off the signage
   photograph, not chosen. Corrected 2026-08-03 after a high-resolution shot of
   the tailgate replaced the low-res crop the first pass worked from.

   What the measurement said, and what it killed:

     body cream, lit        #C8BCAD   hue  33deg, sat 20%
     body cream, shadowed   #B0A498   hue  30deg, sat 13%
     logo plate             #76777A   hue 225deg, sat  2%   (i.e. neutral)
     tailgate lettering     #7B7671   hue  30deg, sat  4%

   The whole vehicle sits at hue 30-33 degrees and almost no saturation. The
   first pass had --ink at #14212C (hue 207, sat 38%) and --steel at #6E8299
   (hue 212, sat 17%) — a navy and a steel blue that ARE NOT ON THE VAN. Both
   were invented from a dark patch in a low-resolution crop and then described
   in this file as "the tagline box navy", which made an invention look like a
   measurement. There is no blue anywhere on this vehicle.

   So: everything warm now holds hue 30-33 and moves only lightness and chroma.
   The dark comes from the plate on the client's own logo mockup (#202226),
   warmed to sit with the cream rather than fight it. (Ethan, 2026-08-03.) */
:root {
  --paper:  #f7f3ed;   /* the body cream, opened up to a page ground */
  --panel:  #f1e9df;   /* the same cream a step down — alternating sections */
  --sand:   #c8bcad;   /* the measured body colour itself — marks on the dark */
  --ink:    #24211f;   /* the mockup's plate, warmed into the van's hue family */
  --grey:   #7b7671;   /* the measured tailgate lettering — DISPLAY sizes only */
  --quiet:  #6f6962;   /* same hue, darkened until 17px clears 4.5:1 (see below) */
  --body:   #5b544d;   /* reading text */
  --bronze: #a48865;   /* the cream deepened until it reads on BOTH grounds */

  --hair:  rgba(36, 33, 31, 0.16);
  --hair-invert: rgba(247, 243, 237, 0.18);
  --error: #9c3520;

  --display: 'Archivo', ui-sans-serif, system-ui, sans-serif;
  --text: 'Source Sans 3', ui-sans-serif, system-ui, sans-serif;

  /* --quiet exists because the measured value does not survive being read.
     #7b7671 is vinyl on a car door, judged from three metres; at 17px on the
     cream it lands at 4.07:1 and the hours line, the promise and the "optional"
     tag all sat under the 4.5 floor. --grey is kept, unaltered, for the display
     sizes where it is both faithful and legible (the 44px service-area line
     measures 3.74 against a floor of 3). Fidelity where it can be read;
     a darker sibling where it cannot. */

  --container: 1280px;
  --gutter: 64px;
  --section-y: 128px;
  --nav-h: 76px;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: var(--nav-h); }

body {
  font-family: var(--text);
  font-size: 17px;
  line-height: 1.55;
  color: var(--body);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; cursor: pointer; border: 0; background: none; }
input, select, textarea { font: inherit; color: inherit; }

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 700;
  color: var(--ink);
  letter-spacing: normal;
}

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--ink);
  color: var(--paper);
  padding: 12px 20px;
  font-weight: 600;
}
.skip-link:focus { left: 0; }

/* ---- layout ---------------------------------------------------------- */

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

.section { padding-block: var(--section-y); }
.section--panel { background: var(--panel); }

/* 40px, not 30: after a 64px hero everything below was landing at one flat
   size, so the page lost its hierarchy the moment you scrolled past the fold. */
.section__title {
  font-size: 40px;
  line-height: 1.12;
}

/* ---- header ---------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  height: var(--nav-h);
  background: var(--paper);
  border-bottom: 1px solid var(--hair);
}

.site-header__inner {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

/* The logo is a link back to the top, so it carries a 44px hit box like every
   other control — the box grows around the mark rather than scaling it. */
.brand {
  display: flex;
  align-items: center;
  min-height: 44px;
  gap: 14px;
  color: var(--ink);
}

/* The mark is a plate with the letters reversed out of it, so its height is NOT
   its cap height — the letters occupy about 70% of it. Set the plate taller than
   a wordmark would be, or the lettering comes out pinched. */
.brand__mark {
  width: auto;
  height: 36px;
}

.brand__name {
  font-family: var(--display);
  font-weight: 600;
  font-size: 17px;
  color: var(--ink);
  white-space: nowrap;
}

/* ---- buttons --------------------------------------------------------- */

/* THE PLATE — the brand's one curve, and the page's signature device.
   The mark is a flat-left rectangle closed by a semicircular cap, and that
   silhouette is the only rounded thing the business owns. The earlier rule
   here said "zero radius, cut vinyl has none", which the logo itself refuted:
   square is right for every edge on the page EXCEPT this one shape, which is
   reproduced exactly — cap radius equals half the height, as it does on the
   mark. Deployed on the buttons only; a device used everywhere stops being
   a signature. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 12px 34px 12px 26px;
  font-family: var(--display);
  font-weight: 600;
  font-size: 17px;
  border-radius: 0 999px 999px 0;
  transition: background-color 140ms ease;
}

.btn--primary {
  background: var(--ink);
  color: var(--paper);
}
.btn--primary:hover { background: #0c1720; }

.btn--block { width: 100%; }

/* ---- hero ------------------------------------------------------------ */

/* Bottom padding pulled in: the left column finishes well above the form, and
   deep padding under it only lengthened the gap it was already carrying. */
.hero { padding-block: 104px 88px; }

.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 468px;
  gap: 96px;
  align-items: start;
}

.hero__title {
  font-size: 64px;
  line-height: 1.02;
}

.hero__sub {
  margin-top: 24px;
  font-size: 20px;
  line-height: 1.45;
}

/* The phone number is the largest non-heading thing on the page, on
   purpose: a sole operator's whole funnel is one call he answers himself. */
.contact {
  margin-top: 44px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

/* Both contact links carry a 44px hit box of their own rather than borrowing
   one from the line spacing — they are the page's real calls to action on a
   phone, not links inside a sentence. The box grows around the text, so the
   type sizes and the rhythm are unchanged. */
.contact__phone,
.contact__email {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.contact__phone {
  font-family: var(--display);
  font-weight: 700;
  font-size: 40px;
  line-height: 1.1;
  color: var(--ink);
}
.contact__phone:hover { color: var(--bronze); }

.contact__email { color: var(--body); text-decoration: underline; text-underline-offset: 3px; }
.contact__email:hover { color: var(--ink); }

.contact__hours { margin-top: 4px; color: var(--quiet); }

/* The promise, at the foot of the hero lede. It was the strongest sentence in
   the copy and it was sitting in the middle of the second About paragraph,
   four screens down — this is what a visitor actually needs to read before
   they decide to call, and it gives the left column the mass it was missing.
   The gold tick introduces it, the same device that opens the tailgate band. */
.promise {
  margin-top: 48px;
  padding-top: 28px;
  max-width: 34ch;
  font-family: var(--display);
  font-weight: 600;
  font-size: 21px;
  line-height: 1.4;
  color: var(--quiet);
  border-top: 0;
}

.promise::before {
  content: '';
  display: block;
  width: 56px;
  height: 3px;
  margin-bottom: 24px;
  background: var(--bronze);
}

/* ---- the tailgate ----------------------------------------------------
   THE SIGNATURE. Four lines painted across the back of his van, here running
   the full width of the page on the navy his signage uses. It was a 22px block
   tucked under the hero's contact details, which put the one device the page is
   remembered by in its weakest position and left a hole beneath it.

   The gold tick leads the band — the single warm mark on the page, and the only
   place an accent earns its keep now that the ground carries the warmth. */

.tailgate {
  background: var(--ink);
  padding-block: 72px;
}

.tailgate .container::before {
  content: '';
  display: block;
  width: 56px;
  height: 3px;
  margin-bottom: 40px;
  background: var(--bronze);
}

.tailgate__lines {
  list-style: none;
  padding-left: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 32px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 30px;
  line-height: 1.15;
  color: var(--paper);
}

/* ---- quote form ------------------------------------------------------ */

.hero__form { border: 1px solid var(--hair); background: var(--paper); }

.quote { padding: 32px; display: flex; flex-direction: column; gap: 15px; }

.quote__title { font-size: 26px; line-height: 1.15; }
.quote__sub { margin-top: -12px; color: var(--body); }

.field { display: flex; flex-direction: column; gap: 6px; }

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; }

.field label {
  font-family: var(--display);
  font-weight: 600;
  font-size: 13px;
  color: var(--ink);
}

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

.field input,
.field select,
.field textarea {
  width: 100%;
  min-height: 48px;
  padding: 11px 14px;
  border: 1px solid var(--hair);
  border-radius: 0;
  background: var(--paper);
  color: var(--ink);
  transition: border-color 140ms ease;
}
.field textarea { min-height: 84px; resize: vertical; }

.field input:hover,
.field select:hover,
.field textarea:hover { border-color: var(--grey); }

.field select:invalid { color: var(--grey); }

.field.is-invalid input,
.field.is-invalid select { border-color: var(--error); }

/* Reserve the error line's height so validation never moves the layout. */
.field__error {
  min-height: 20px;
  font-size: 14px;
  line-height: 20px;
  color: var(--error);
}
.field:has(textarea) .field__error { display: none; }

.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.quote__status { min-height: 24px; font-size: 15px; color: var(--body); }
.quote__status.is-error { color: var(--error); }

.quote.is-sent .quote__status { color: var(--ink); font-weight: 600; }

/* ---- services -------------------------------------------------------- */

/* Stacked hairline rows rather than three cards in a row: these are a SET, not
   a sequence, so nothing here is numbered and nothing is boxed. Scaled up from
   the first pass, where a 260px label and a 62ch body left the right third of
   every row empty — the label now carries real size and the body runs to the
   gutter. */
.rows { margin-top: 64px; border-top: 1px solid var(--hair); }

.row {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 56px;
  padding-block: 44px;
  border-bottom: 1px solid var(--hair);
}

.row__label { font-size: 28px; line-height: 1.15; }
.row__body { font-size: 18px; line-height: 1.6; }

/* ---- service area ---------------------------------------------------- */

/* The closing band. Statement left, the act right — so the page ends on the
   two things a visitor can actually do, at the size they deserve, instead of
   trailing off into a small button and a lot of nothing. */
.area {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 400px;
  gap: 96px;
  align-items: start;
}

/* Six words, so they get set at display size and allowed to fill their column
   rather than being tucked into a narrow measure inside wide empty gutters. */
.area__line {
  margin-top: 24px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 44px;
  line-height: 1.12;
  color: var(--grey);
  max-width: 30ch;   /* two lines, composed — never an incidental third */
}

.area__act {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding-top: 6px;
}

.area__note { margin-top: 2px; color: var(--body); }
.area__act .btn { margin-top: 28px; }

/* ---- prose -----------------------------------------------------------
   Two columns, so the owner's own words use the width of the band. A single
   66ch measure sitting in half a container reads as an unfinished column. */

.prose {
  margin-top: 40px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 56px;
  font-size: 18px;
  line-height: 1.6;
}

/* ---- footer ---------------------------------------------------------- */

.site-footer {
  background: var(--ink);
  color: rgba(255, 255, 255, 0.78);
  padding-block: 72px 40px;
}

/* Three columns, not two. Brand on one side and contact on the other left a
   void down the middle of the darkest band on the page, which read as an
   unfinished footer rather than a spacious one. */
.site-footer__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) auto;
  gap: 48px 72px;
  align-items: start;
}

.site-footer__heading {
  font-family: var(--display);
  font-weight: 600;
  font-size: 13px;
  color: var(--sand);   /* on the ink band, the quiet value has to be the LIGHT one */
  margin-bottom: 10px;
}

.site-footer__nav { display: flex; flex-direction: column; align-items: flex-start; }
.site-footer__nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--paper);
}
.site-footer__nav a:hover { color: var(--sand); }

.site-footer__brand { color: var(--paper); }
.site-footer__brand .brand__mark { height: 44px; }

.site-footer__name {
  margin-top: 16px;
  font-family: var(--display);
  font-weight: 600;
  font-size: 18px;
  color: var(--paper);
}

.site-footer__contact { display: flex; flex-direction: column; gap: 2px; }
.site-footer__contact a {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  min-height: 44px;          /* a real hit box, same reasoning as .contact */
  color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* Anchored to the phone link itself, not to its position. This was
   `a:first-child`, which silently stopped matching the moment a column heading
   was added above it — the number quietly dropped from 24px display to body
   size, and nothing failed. */
.site-footer__contact a[href^="tel:"] {
  font-family: var(--display);
  font-weight: 700;
  font-size: 24px;
  text-decoration: none;
}

.site-footer__legal {
  grid-column: 1 / -1;
  padding-top: 32px;
  border-top: 1px solid var(--hair-invert);
  font-size: 14px;
}

/* ---- motion ---------------------------------------------------------
   One quiet moment: a fade-rise as sections arrive. Transform only, so
   nothing in the layout moves. Off entirely under reduced-motion, and off
   for everyone if JS never runs (the .is-armed class is set by app.js).  */

.is-armed [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
}

.is-armed [data-reveal].is-in {
  opacity: 1;
  transform: none;
  transition: opacity 620ms ease-out, transform 620ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .is-armed [data-reveal],
  .is-armed [data-reveal].is-in { opacity: 1; transform: none; transition: none; }
}

/* ---- responsive ------------------------------------------------------ */

@media (max-width: 1080px) {
  :root { --gutter: 40px; --section-y: 96px; }
  .hero__grid { grid-template-columns: minmax(0, 1fr) 420px; gap: 56px; }
  .hero__title { font-size: 52px; }
}

@media (max-width: 900px) {
  .hero { padding-block: 72px 88px; }
  .hero__grid { grid-template-columns: minmax(0, 1fr); gap: 56px; }
  .hero__sub { max-width: 46ch; }
  .prose { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .row { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .tailgate__lines { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 24px; }
  .area { grid-template-columns: minmax(0, 1fr); gap: 48px; }
  .site-footer__inner { grid-template-columns: minmax(0, 1fr); gap: 36px; }
}

@media (max-width: 620px) {
  :root { --gutter: 20px; --section-y: 72px; --nav-h: 66px; }
  body { font-size: 16px; }
  .brand__name { display: none; }
  .brand__mark { height: 30px; }
  .btn { padding: 12px 18px; font-size: 16px; }
  .hero__title { font-size: 40px; line-height: 1.06; }
  .hero__sub { font-size: 18px; }
  .contact__phone { font-size: 34px; }
  .stack { font-size: 20px; }
  .quote { padding: 24px 20px; }
  .field-row { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .section__title { font-size: 30px; }
  .promise { font-size: 19px; max-width: none; }
  .tailgate { padding-block: 52px; }
  .tailgate__lines { grid-template-columns: minmax(0, 1fr); gap: 14px; font-size: 24px; }
  .tailgate .container::before { margin-bottom: 28px; }
  .area__line { font-size: 30px; }
  .prose { font-size: 17px; }
}
