/* =====================================================================
   hvac.expert — style.css
   ---------------------------------------------------------------------
   Every visual decision for the site lives in this file.
   index.html / about.html carry structure only; app.js carries
   behaviour only. Nothing in those files sets a colour, a font or a size.

   RESTYLING GUIDE (for a person or an AI doing a design pass)
   1. Start at the DESIGN TOKENS block directly below. Colours, fonts,
      spacing, corner radius and shadows are all variables. Most restyles
      never need to go past this block.
   2. The DARK THEME block only overrides tokens. Any colour you add to
      :root needs a dark value there too, or it will not adapt.
   3. After that, sections run in page order:
      base → header → hero + search → buttons → results →
      prose page (about) → forms → motion.
   4. Class names are safe to rename in BOTH the CSS and the HTML.
      Never rename an id — app.js finds elements by id.
   5. Things in this file that are not "style" and must survive a restyle:
      - .visually-hidden and .skip-link  (screen-reader / keyboard users)
      - .hp                              (the anti-spam honeypot field)
      - [hidden] { display: none }       (app.js shows/hides with `hidden`)
      - :focus-visible outlines and the reduced-motion block at the end

   DESIGN INTENT, in one line: the opposite of a lead-gen site.
   One question, one box, one list. Quiet, readable in the sun, fast.
   ===================================================================== */


/* ---------------------------------------------------------------------
   DESIGN TOKENS
   Change the whole look here. Light theme values; dark theme is below.
   --------------------------------------------------------------------- */
:root {
  /* Surfaces */
  --paper:        #f7f4ee;   /* page background — warm off-white, easy on a hot day */
  --paper-2:      #ffffff;   /* cards, inputs, raised surfaces */
  --line:         #e4dfd5;   /* hairlines, card borders */
  --line-strong:  #cbc4b7;   /* input borders */

  /* Ink */
  --ink:          #1b1a17;   /* primary text */
  --ink-2:        #5b574f;   /* secondary text */
  --ink-3:        #8a857b;   /* hints, meta, placeholders */

  /* Brand accents. "cool" is for actions (buttons, links).
     "heat" is used sparingly for emphasis: the thermal rule under the
     header, star ratings, the Sponsored tag, errors.                  */
  --cool:         #0e6b8a;
  --cool-strong:  #0a5570;   /* hover state of --cool */
  --on-cool:      #ffffff;   /* text on top of --cool */
  --heat:         #d6532a;
  --ok:           #2f7d4a;   /* "Open now" dot */

  /* Type. System fonts on purpose: zero downloads, fastest possible
     first paint, and the "no tracking" promise stays literally true.
     Swap in a self-hosted .woff2 here if you want a custom face.      */
  --font-display: Charter, "Bitstream Charter", "Iowan Old Style", Cambria, Georgia, serif;
  --font-body:    system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono:    ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;

  /* Shape & layout */
  --radius:       10px;
  --radius-lg:    16px;
  --shadow:       0 1px 2px rgba(20, 18, 12, .05), 0 10px 28px -14px rgba(20, 18, 12, .22);
  --measure:      40rem;     /* max width of a block of running text */
  --wrap:         68rem;     /* max width of the page */
  --logo-height:  40px;      /* header logo height; width follows the image */

  /* If your logo already contains the words "hvac.expert", leave this
     as `none`. If it is only a mark, set it to `inline` to keep the
     text wordmark next to it.                                         */
  --wordmark-with-logo: none;

  color-scheme: light;
}


/* ---------------------------------------------------------------------
   DARK THEME
   Follows the device setting. To force a theme, put data-theme="dark"
   or data-theme="light" on <html>.
   --------------------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:        #151413;
    --paper-2:      #1f1d1b;
    --line:         #2d2a27;
    --line-strong:  #3d3935;
    --ink:          #ece7de;
    --ink-2:        #b3ada2;
    --ink-3:        #807a70;
    --cool:         #5cb8d8;
    --cool-strong:  #86cde6;
    --on-cool:      #0d1a20;
    --heat:         #f07a52;
    --ok:           #6cc48a;
    --shadow:       0 1px 2px rgba(0, 0, 0, .3), 0 10px 28px -14px rgba(0, 0, 0, .6);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --paper:        #151413;
  --paper-2:      #1f1d1b;
  --line:         #2d2a27;
  --line-strong:  #3d3935;
  --ink:          #ece7de;
  --ink-2:        #b3ada2;
  --ink-3:        #807a70;
  --cool:         #5cb8d8;
  --cool-strong:  #86cde6;
  --on-cool:      #0d1a20;
  --heat:         #f07a52;
  --ok:           #6cc48a;
  --shadow:       0 1px 2px rgba(0, 0, 0, .3), 0 10px 28px -14px rgba(0, 0, 0, .6);
  color-scheme: dark;
}


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

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

body {
  margin: 0;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;          /* lets the footer sit at the bottom on short pages */
  background: var(--paper);
  color: var(--ink);
  font: 400 1rem/1.55 var(--font-body);
  -webkit-font-smoothing: antialiased;
}

[hidden] { display: none !important; }   /* app.js toggles the `hidden` attribute; keep this */

a { color: var(--cool); text-underline-offset: .15em; }
a:hover { color: var(--cool-strong); }

:focus-visible {
  outline: 3px solid var(--cool);
  outline-offset: 3px;
  border-radius: 4px;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0 0 .5em;
  text-wrap: balance;
}

p { margin: 0 0 1em; }

img { max-width: 100%; }

.wrap {
  width: min(100% - 2rem, var(--wrap));   /* 1rem gutter each side on phones */
  margin-inline: auto;
}

.measure { max-width: var(--measure); }

/* Screen-reader-only text. Not decoration — keep. */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Keyboard users: first Tab press reveals a "skip to search" link. Keep. */
.skip-link {
  position: absolute;
  left: -999px;
  top: 1rem;
  z-index: 10;
  padding: .5rem 1rem;
  background: var(--paper-2);
  color: var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.skip-link:focus { left: 1rem; }


/* ---------------------------------------------------------------------
   HEADER
   Brand on the left (logo image and/or text wordmark), one nav link on
   the right, then a thin warm-to-cool "thermal rule" — the only piece
   of decoration on the site. Heating and cooling, in one line.
   --------------------------------------------------------------------- */
.site-header { padding-block: 1rem; }

.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  color: var(--ink);
  text-decoration: none;
  font-family: var(--font-display);
  font-size: 1.35rem;
  letter-spacing: -0.01em;
}
.brand:hover { color: var(--ink); }

/* The logo <img>. app.js adds .has-logo to .brand once the image has
   actually loaded, and removes the <img> if the file is missing — so
   with no logo file the text wordmark simply shows on its own.       */
.brand-logo {
  display: block;
  height: var(--logo-height);
  width: auto;
}
.brand.has-logo .brand-name { display: var(--wordmark-with-logo); }

.site-nav a {
  color: var(--ink-2);
  text-decoration: none;
  font-size: .95rem;
  padding: .4rem 0;
}
.site-nav a:hover { color: var(--ink); text-decoration: underline; }

.thermal-rule {
  height: 2px;
  background: linear-gradient(90deg, var(--heat), var(--cool));
  opacity: .85;
}


/* ---------------------------------------------------------------------
   HERO + SEARCH
   One line, then the one input that matters.
   --------------------------------------------------------------------- */
.hero { padding-block: clamp(2.5rem, 8vw, 5.5rem) clamp(1.5rem, 4vw, 3rem); }

.hero h1 { font-size: clamp(2.2rem, 1.2rem + 4.5vw, 3.6rem); max-width: 16ch; }

.hero .lede {
  font-size: clamp(1.05rem, .95rem + .5vw, 1.25rem);
  color: var(--ink-2);
  max-width: var(--measure);
}

.search { margin-top: 1.75rem; max-width: 34rem; }

.search-row {
  display: flex;
  flex-direction: column;   /* stacked on phones … */
  gap: .6rem;
}
@media (min-width: 560px) {
  .search-row { flex-direction: row; }    /* … side by side from tablet up */
  .search-row .field { flex: 1; }
}

.field input {
  width: 100%;
  font: 500 1.35rem/1 var(--font-body);
  letter-spacing: .06em;
  padding: .95rem 1rem;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--paper-2);
  color: var(--ink);
}
.field input::placeholder { color: var(--ink-3); font-weight: 400; letter-spacing: normal; }
.field input:focus {
  outline: none;
  border-color: var(--cool);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--cool) 18%, transparent);
}

.field-error {
  margin: .5rem 0 0;
  font-size: .9rem;
  color: var(--heat);
}

/* One-line status under the form: "Asking Google…", errors, demo notes */
.status {
  margin: 1rem 0 0;
  min-height: 1.5em;
  font-size: .95rem;
  color: var(--ink-2);
}
.status.is-error { color: var(--heat); }
.status a { color: inherit; font-weight: 600; }


/* ---------------------------------------------------------------------
   BUTTONS
   --------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  font: 600 1.05rem/1 var(--font-body);
  padding: .95rem 1.4rem;
  border: 1.5px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color .15s, color .15s, border-color .15s, transform .05s;
}
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .6; cursor: progress; }

.btn-primary { background: var(--cool); color: var(--on-cool); }
.btn-primary:hover { background: var(--cool-strong); color: var(--on-cool); }

.btn-secondary {
  background: transparent;
  color: var(--cool);
  border-color: color-mix(in srgb, var(--cool) 45%, transparent);
}
.btn-secondary:hover {
  background: color-mix(in srgb, var(--cool) 9%, transparent);
  color: var(--cool-strong);
}

.btn-sm { padding: .6rem .95rem; font-size: .95rem; }


/* ---------------------------------------------------------------------
   RESULTS
   The list, one card per company.
   --------------------------------------------------------------------- */
.results { padding-block: .5rem 3rem; }

.results-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .25rem 1rem;
  margin-bottom: 1rem;
}
.results-head h2 { margin: 0; font-size: clamp(1.45rem, 1.1rem + 1.5vw, 1.9rem); }
.results-head h2:focus { outline: none; }   /* app.js moves focus here; no ring needed */

/* Shown only while app.js is in DEMO_MODE */
.demo-banner {
  margin: 0 0 1rem;
  padding: .6rem .9rem;
  font-size: .9rem;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--heat) 12%, var(--paper-2));
  border: 1px solid color-mix(in srgb, var(--heat) 35%, transparent);
}

.place-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .9rem;
}

/* One company */
.place {
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 1.1rem 1.2rem;
  box-shadow: var(--shadow);
}

.place-top {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: .25rem 1rem;
}

.place-name { margin: 0; font-size: 1.25rem; }
/* The name is a link to the company's Google listing, and should look like one */
.place-name a {
  color: var(--cool);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
  text-decoration-color: color-mix(in srgb, var(--cool) 45%, transparent);
}
.place-name a:hover { color: var(--cool-strong); text-decoration-color: currentColor; }

.rating {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-weight: 600;
  white-space: nowrap;
}
.rating .star { color: var(--heat); }
.rating .count { color: var(--ink-3); font-weight: 400; }

.place-addr { margin: .3rem 0 0; font-size: .95rem; color: var(--ink-2); }

/* "Open now" / "Closed right now" with a coloured dot */
.open {
  margin: .4rem 0 0;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .85rem;
  color: var(--ink-2);
}
.open::before {
  content: "";
  width: .55em; height: .55em;
  border-radius: 50%;
  background: var(--ok);
}
.open.is-closed::before { background: var(--ink-3); }

.place-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: .9rem;
}

/* The Featured slot. Empty and hidden today. When a company pays to be
   here, app.js fills it and the Sponsored tag is shown — that label is
   the label that makes paid placement honest, so keep it visible.   */
.featured { margin-bottom: 1rem; }
.featured .place { border-color: color-mix(in srgb, var(--heat) 45%, var(--line)); }

.tag-sponsored {
  display: inline-block;
  margin-bottom: .5rem;
  padding: .15rem .55rem;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--heat);
  border: 1px solid currentColor;
  border-radius: 999px;
}

.empty { color: var(--ink-2); }

/* Google requires this attribution wherever Places data is shown
   without a Google map. Style it, don't remove it.                    */
.attribution {
  margin: 1.25rem 0 0;
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .8rem;
  color: var(--ink-3);
}
.attribution img { height: 16px; width: auto; }
.attribution-extra { margin: .25rem 0 0; font-size: .8rem; color: var(--ink-3); }


/* ---------------------------------------------------------------------
   PROSE PAGE (about.html)
   --------------------------------------------------------------------- */
.prose {
  max-width: var(--measure);
  padding-block: clamp(2rem, 6vw, 4rem) 3rem;
}
.prose h1 { font-size: clamp(2rem, 1.3rem + 3vw, 3rem); }
.prose h2 { font-size: 1.5rem; margin-top: 2.25rem; }
.prose .lede { font-size: 1.15rem; color: var(--ink-2); }
.prose .updated { font-size: .85rem; color: var(--ink-3); }

.prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: .95rem;
  margin: 1rem 0 1.25rem;
}
.prose th, .prose td {
  text-align: left;
  vertical-align: top;
  padding: .6rem .75rem .6rem 0;
  border-bottom: 1px solid var(--line);
}
.prose th {
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.prose code {
  font-family: var(--font-mono);
  font-size: .9em;
  padding: .1em .35em;
  border-radius: 4px;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
}


/* ---------------------------------------------------------------------
   FORMS (the remove / correct a listing form)
   --------------------------------------------------------------------- */
.form-grid { display: grid; gap: 1rem; margin-top: 1rem; }

.form-grid label { display: block; font-weight: 600; margin-bottom: .35rem; }
.form-grid label small { display: block; font-weight: 400; color: var(--ink-3); }

.form-grid input[type="text"],
.form-grid textarea {
  width: 100%;
  font: inherit;
  padding: .75rem .9rem;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--paper-2);
  color: var(--ink);
}
.form-grid input[type="text"]:focus,
.form-grid textarea:focus {
  outline: none;
  border-color: var(--cool);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--cool) 18%, transparent);
}
.form-grid textarea { min-height: 8rem; resize: vertical; }
.form-grid .btn { justify-self: start; }

/* Honeypot: a field people never see but bots fill in. The server drops
   any submission where it has a value. Off-screen, not display:none, so
   bots that skip hidden fields still find it. KEEP.                   */
.hp {
  position: absolute;
  left: -10000px;
  top: auto;
  width: 1px; height: 1px;
  overflow: hidden;
}

.form-status { margin: 0; font-size: .95rem; color: var(--ink-2); }
.form-status.is-error { color: var(--heat); }


/* ---------------------------------------------------------------------
   MOTION
   Cards rise in gently. Everything is switched off for people who have
   asked their device for reduced motion.
   --------------------------------------------------------------------- */
.place { animation: rise .35s ease both; }
@keyframes rise {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  html { scroll-behavior: auto; }
}
