/* ==========================================================================
   UG Herrera Construction Corporation
   Single-page site. No frameworks, no build step, no external requests.
   Mobile-first: most visitors arrive on a phone.
   ========================================================================== */

:root {
  --navy:      #0f2a43;
  --navy-deep: #0a1d2f;
  --navy-soft: #17395a;
  --amber:     #f5a524;
  --amber-dk:  #d98a0b;
  /* Amber works as a background and as an accent on dark surfaces. As text on
     white it only reaches 2.77:1, so amber text on a light surface uses this
     darker variant, which clears AA at 4.62:1. */
  --amber-text: #a36808;
  /* Amber text on an AMBER-TINTED dark surface is its own case, because the
     pill tint lifts the background towards the text colour. --amber on the hero
     eyebrow measured 4.46:1 against its own tint over the glow, which the audit
     only caught once it started testing the glow peak instead of flat navy.
     This brighter variant clears AA at 6.35:1. */
  --amber-bright: #ffd08a;
  --ink:       #1c2430;
  --body:      #4a5768;
  /* Secondary text. Both values came out of tools/contrast_audit.py rather than
     being picked by eye: each clears WCAG AA (4.5:1) against the WORST surface
     it appears on, which for --muted is the gallery grey, not white. Do not
     lighten these without re-running the audit. */
  --muted:        #626d79;
  --muted-invert: #93a3b6;
  --line:      #e2e8f0;
  --bg:        #ffffff;
  --bg-alt:    #f6f8fa;
  --radius:    12px;
  --shadow:    0 1px 2px rgba(15,42,67,.06), 0 8px 24px rgba(15,42,67,.07);
  --wrap:      1140px;
}

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

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

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  font-size: 17px;
  line-height: 1.65;
  color: var(--body);
  background: var(--bg);
}

h1, h2, h3 { color: var(--ink); line-height: 1.2; margin: 0 0 .5em; }
h1 { font-size: clamp(1.85rem, 5.2vw, 3.15rem); letter-spacing: -.02em; }
h2 { font-size: clamp(1.45rem, 3.4vw, 2.1rem); letter-spacing: -.015em; }
h3 { font-size: 1.12rem; }
p  { margin: 0 0 1rem; }
a  { color: var(--navy-soft); }

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

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

/* Marks content that still needs a confirmed fact. Nothing carries it as of
   launch. The convention stays so that anything unverified added later is both
   visible on the page and caught by tools/check_ready.py, which refuses to
   deploy while any element still has it. */
.ph {
  text-decoration: underline dashed var(--amber-dk);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--amber); color: var(--navy-deep);
  padding: 10px 16px; font-weight: 700;
}
.skip-link:focus { left: 0; }

/* Keyboard focus. The whole site funnels to one button, so a keyboard user has
   to be able to see where they are. The UA default ring is unreliable against
   the hero's amber button and its gradient, so this draws an explicit one:
   dark amber on light surfaces, pale amber on the dark sections. Using
   :focus-visible rather than :focus means a mouse click does not leave a ring
   behind. */
:focus-visible {
  outline: 3px solid var(--amber-text);
  outline-offset: 2px;
  border-radius: 4px;
}
.hero :focus-visible,
.section-dark :focus-visible,
.site-footer :focus-visible {
  outline-color: var(--amber-bright);
}

/* ============================ HEADER ============================ */

.site-header {
  position: sticky; top: 0; z-index: 50;
  background: rgba(255,255,255,.94);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.header-inner {
  display: flex; align-items: center; gap: 16px;
  min-height: 68px;
}

.brand { display: flex; align-items: center; gap: 11px; text-decoration: none; margin-right: auto; }

/* The company's own logo mark, taken from their existing site. It is a JPEG on
   white, so it sits directly on the white header rather than in a coloured box. */
.brand-mark { display: grid; place-items: center; width: 40px; height: 40px; flex: none; }
.brand-mark img { display: block; width: auto; height: 40px; }

.brand-text { display: flex; flex-direction: column; line-height: 1.15; }
.brand-text strong { color: var(--ink); font-size: 1.03rem; letter-spacing: -.01em; }
.brand-text small  { color: var(--muted); font-size: .74rem; text-transform: uppercase; letter-spacing: .07em; }

.site-nav { display: none; gap: 26px; }
.site-nav a {
  color: var(--body); text-decoration: none; font-size: .93rem; font-weight: 500;
  padding-block: 4px; border-bottom: 2px solid transparent;
}
.site-nav a:hover { color: var(--navy); border-bottom-color: var(--amber); }

/* ============================ BUTTONS ============================ */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 12px 20px;
  border: 2px solid transparent; border-radius: 999px;
  font: inherit; font-size: .95rem; font-weight: 650;
  text-decoration: none; cursor: pointer;
  /* Deliberately NOT nowrap. With nowrap, "Call for a free quotation" measured
     428px inside a 390px phone at 200% text, and the hero's overflow:hidden
     clipped the end of the label - the one button the whole site exists to get
     pressed. Letting it wrap costs nothing at normal sizes and keeps the text
     intact when it is enlarged. */
  max-width: 100%; text-align: center;
  transition: transform .12s ease, background-color .15s ease, border-color .15s ease;
}
.btn:active { transform: translateY(1px); }

.btn-primary { background: var(--amber); color: var(--navy-deep); }
.btn-primary:hover { background: #ffb63c; }

.btn-ghost { border-color: rgba(255,255,255,.4); color: #fff; }
.btn-ghost:hover { background: rgba(255,255,255,.12); border-color: #fff; }

/* Used on light surfaces, where a solid button would compete with the primary. */
.btn-outline { border-color: #c4d0dd; color: var(--navy); background: #fff; }
.btn-outline:hover { border-color: var(--navy); background: #f6f8fa; }

.btn-call {
  background: var(--navy); color: #fff;
  padding: 9px 17px; font-size: .9rem;
}
.btn-call:hover { background: var(--navy-soft); }
.btn-call .ph { text-decoration-color: var(--amber); }

.btn-lg { padding: 15px 27px; font-size: 1rem; }

.header-call { display: none; }

/* ============================ HERO ============================ */

.hero { position: relative; overflow: hidden; background: var(--navy-deep); }

/* Blueprint grid + warm glow. Pure CSS so the page has no image dependencies. */
.hero-bg {
  position: absolute; inset: 0;
  background-image:
    radial-gradient(900px 420px at 78% 8%, rgba(245,165,36,.20), transparent 62%),
    linear-gradient(rgba(255,255,255,.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.055) 1px, transparent 1px);
  background-size: 100% 100%, 46px 46px, 46px 46px;
  mask-image: linear-gradient(180deg, #000 55%, transparent);
  -webkit-mask-image: linear-gradient(180deg, #000 55%, transparent);
}

.hero-inner { position: relative; padding-block: clamp(58px, 11vw, 104px) clamp(52px, 9vw, 88px); }

.eyebrow {
  display: inline-block; margin: 0 0 16px;
  padding: 6px 14px; border-radius: 999px;
  background: rgba(245,165,36,.14); border: 1px solid rgba(245,165,36,.4);
  color: var(--amber-bright); font-size: .76rem; font-weight: 700;
  letter-spacing: .11em; text-transform: uppercase;
}

.hero h1 { color: #fff; max-width: 17ch; }
.lede { color: #b9c7d6; font-size: clamp(1rem, 2.1vw, 1.13rem); max-width: 56ch; margin-bottom: 30px; }

.hero-actions { display: flex; flex-wrap: wrap; gap: 13px; margin-bottom: 16px; }

/* The single secondary route, kept deliberately quiet so the call button is the
   only thing on the page that looks like the thing to do. */
.hero-secondary { margin: 0 0 30px; color: #9fb1c4; font-size: .93rem; }
.hero-secondary a { color: var(--amber); font-weight: 600; }

.hero-trust {
  display: flex; flex-wrap: wrap; gap: 10px 26px;
  margin: 0; padding: 22px 0 0; list-style: none;
  border-top: 1px solid rgba(255,255,255,.14);
}
.hero-trust li {
  color: #9fb1c4; font-size: .87rem; font-weight: 500;
  display: flex; align-items: center; gap: 8px;
}
.hero-trust li::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--amber); flex: none;
}
.hero-trust .ph { text-decoration-color: rgba(245,165,36,.75); }

/* ============================ SECTIONS ============================ */

.section { padding-block: clamp(56px, 9vw, 92px); }
.section-alt  { background: var(--bg-alt); border-block: 1px solid var(--line); }
.section-dark { background: var(--navy); }
.section-dark h2, .section-dark h3 { color: #fff; }
.section-dark p { color: #b9c7d6; }

.section-head { max-width: 62ch; margin-bottom: 42px; }
.section-note {
  display: inline-block;
  padding: 11px 15px; margin: 0;
  border-left: 3px solid var(--amber); border-radius: 0 7px 7px 0;
  background: #fff8e9; color: #7a5a12; font-size: .87rem; line-height: 1.5;
}
.section-dark .section-note { background: rgba(245,165,36,.1); color: #f0cd8e; }

/* ============================ CARDS ============================ */

.cards { display: grid; gap: 18px; grid-template-columns: 1fr; }

.card {
  padding: 26px 24px;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.card-icon {
  display: grid; place-items: center;
  width: 46px; height: 46px; margin-bottom: 15px; border-radius: 10px;
  background: #eef4fa; color: var(--navy);
}
.card h3 { margin-bottom: .4em; }
.card p  { margin: 0; font-size: .94rem; }

/* ============================ GALLERY ============================ */

.gallery { display: grid; gap: 14px; grid-template-columns: repeat(2, 1fr); }

/* A figure holds a real photograph once one exists. 3:2 is the compromise
   aspect ratio: the supplied photographs are a mix of 16:9 and 4:3, and 3:2
   crops the least from either while keeping the grid rows even. */
.shot {
  position: relative; margin: 0; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: #fff;
}
.shot img {
  display: block; width: 100%;
  /* height:auto is essential, not tidiness. The <img> tags carry width and
     height attributes so the browser can reserve space before the file loads,
     but those attributes also act as presentational hints. With width:100% and
     no height rule, the height attribute won and pinned each image to its
     natural pixel height, so a 1400x787 landscape rendered as a 355x787
     portrait slice and object-fit cropped the sides away. */
  height: auto;
  aspect-ratio: 3 / 2; object-fit: cover;
}
.shot figcaption {
  padding: 10px 13px 12px; color: var(--ink);
  font-size: .85rem; font-weight: 600; line-height: 1.4;
}

/* The empty state, for a slot still waiting on a photograph. */
.shot.is-empty {
  aspect-ratio: 4 / 3; border: 2px dashed #c4d0dd;
  background: repeating-linear-gradient(45deg, #f0f4f8 0 12px, #f7fafc 12px 24px);
  display: grid; place-items: center;
}
.shot.is-empty span {
  color: var(--muted); font-size: .82rem; font-weight: 600;
  letter-spacing: .05em; text-transform: uppercase;
}

/* ============================ SERVICE AREA ============================ */

.split { display: grid; gap: 34px; grid-template-columns: 1fr; align-items: start; }

.area-list {
  display: flex; flex-wrap: wrap; gap: 9px;
  list-style: none; margin: 22px 0 0; padding: 0;
}
.area-list li {
  padding: 8px 15px; border-radius: 999px;
  background: #eef4fa; color: var(--navy);
  font-size: .89rem; font-weight: 550;
}

.map-frame {
  border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--line); box-shadow: var(--shadow);
}
/* The frame only gets a fixed shape once a real map is inside it. Until then it
   sizes to the consent prompt, which is taller than a 4:3 box. */
.map-frame.is-loaded { aspect-ratio: 4 / 3; }
.map-frame iframe { display: block; width: 100%; height: 100%; border: 0; }

/* Click-to-load notice. No request reaches Google until the visitor asks, so
   there is no third-party cookie and nothing to consent to. */
.map-placeholder {
  display: grid; justify-items: start; gap: 12px;
  padding: 26px 24px; background: #eef4fa;
}
.map-title { margin: 0; color: var(--ink); font-weight: 700; }
.map-note { margin: 0; color: var(--muted); font-size: .89rem; max-width: 42ch; }
.map-alt { margin: 0; color: var(--body); font-size: .89rem; line-height: 1.6; }
.map-alt a { color: var(--navy-soft); }
.map-loading { display: grid; place-items: center; min-height: 240px; color: var(--muted); }

/* ============================ CONTACT ============================ */

.contact-grid { display: grid; gap: 16px; grid-template-columns: 1fr; }

/* Grid and flex items default to min-width:auto, which lets a long unbreakable
   string - here the email address - push its card wider than the screen. At
   200% text on a narrow phone this pushed the contact cards 4px off the side,
   which fails WCAG 1.4.4. min-width:0 lets the item shrink, and overflow-wrap
   lets the address break. Note that `break-word` would NOT fix this: unlike
   `anywhere`, it does not affect intrinsic min-content sizing. */
.contact-grid > * { min-width: 0; }
.contact-big { overflow-wrap: anywhere; }

.contact-card {
  padding: 24px 22px;
  background: rgba(255,255,255,.055);
  border: 1px solid rgba(255,255,255,.13); border-radius: var(--radius);
}
.contact-card h3 {
  margin-bottom: .55em; color: var(--amber);
  font-size: .76rem; font-weight: 700;
  letter-spacing: .11em; text-transform: uppercase;
}
.contact-big {
  display: inline-block; margin: 0;
  color: #fff; font-size: 1.22rem; font-weight: 650; text-decoration: none;
  line-height: 1.4;
}
a.contact-big:hover { color: var(--amber); }
.contact-big .ph { text-decoration-color: rgba(245,165,36,.8); }
.section-dark .muted { color: var(--muted-invert); }

/* Inquiry form — not rendered yet. It lives commented out in index.html and is
   styled here so that switching it on requires no CSS work. */
.inquiry {
  display: grid; gap: 16px;
  margin-top: 34px; padding: 26px 24px;
  background: rgba(255,255,255,.055);
  border: 1px solid rgba(255,255,255,.13); border-radius: var(--radius);
}
.inquiry .field { display: grid; gap: 7px; }
.inquiry label {
  color: #cfdae6; font-size: .78rem; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase;
}
.inquiry input, .inquiry select, .inquiry textarea {
  width: 100%; padding: 12px 14px;
  border: 1px solid rgba(255,255,255,.2); border-radius: 9px;
  background: rgba(0,0,0,.22); color: #fff;
  font: inherit; font-size: 1rem;
  letter-spacing: normal; text-transform: none;
}
.inquiry input::placeholder, .inquiry textarea::placeholder { color: var(--muted-invert); }
.inquiry input:focus, .inquiry select:focus, .inquiry textarea:focus {
  outline: 2px solid var(--amber); outline-offset: 1px; border-color: transparent;
}
.inquiry select option { color: var(--ink); }
.inquiry textarea { resize: vertical; min-height: 110px; }
.inquiry .btn { justify-self: start; }

/* An invalid field changes its border as well as showing a message, so the
   error is never signalled by colour alone. */
.inquiry [aria-invalid="true"] { border-color: #ff9f9f; }
.field-error { margin: 0; color: #ffc9c9; font-size: .82rem; line-height: 1.45; }
.form-error { margin-top: 4px; font-weight: 600; }

/* Honeypot. Moved off screen rather than display:none, because plenty of bots
   skip fields that are display:none. Never focusable, never announced. */
.hp-field {
  position: absolute; left: -9999px;
  width: 1px; height: 1px; overflow: hidden;
}

@media (min-width: 700px) {
  .inquiry { grid-template-columns: 1fr 1fr; }
  .inquiry .field:last-of-type, .inquiry .btn, .form-error { grid-column: 1 / -1; }
}

/* ============================ FOOTER ============================ */

.site-footer {
  background: var(--navy-deep); color: var(--muted-invert);
  padding-block: 34px; font-size: .89rem;
}
.footer-inner { display: grid; gap: 18px; }
.site-footer strong { color: #fff; font-size: .98rem; }
.site-footer p { margin: .3rem 0 0; }
.footer-meta { text-align: left; }
.site-footer .ph { text-decoration-color: rgba(245,165,36,.7); }

/* ============================ SUBPAGES ============================ */
/* Privacy, terms, and the 404 share one reading column. Direct children are
   capped rather than the wrapper itself, so the text starts on the same gutter
   as the brand in the header instead of floating in the middle of the page. */

.subpage { padding-block: clamp(48px, 8vw, 80px); }
.subpage .wrap > * { max-width: 720px; }

.prose h1 { margin-bottom: .3em; }
.prose h2 {
  margin-top: 1.9em; padding-top: 1.1em;
  border-top: 1px solid var(--line);
  font-size: 1.22rem;
}
.prose p, .prose li { font-size: .97rem; }
.prose a { color: var(--navy-soft); }
.legal-meta { color: var(--muted); font-size: .87rem; margin-bottom: 1.8em; }
.contact-line { line-height: 1.9; }
.prose-note {
  margin-top: 2.4em; padding: 14px 16px;
  border-left: 3px solid var(--amber); border-radius: 0 7px 7px 0;
  background: #fff8e9; color: #7a5a12; font-size: .87rem;
}

.error-code {
  margin: 0 0 .1em; color: var(--amber-text);
  font-size: .82rem; font-weight: 700; letter-spacing: .18em;
}
.lede-dark { color: var(--body); font-size: 1.05rem; max-width: 52ch; }

.cta-row { display: flex; flex-wrap: wrap; gap: 12px; margin: 30px 0 26px; }

.jump-links {
  display: flex; flex-wrap: wrap; gap: 9px;
  list-style: none; margin: 0; padding: 0;
}
.jump-links a {
  display: inline-block; padding: 8px 15px; border-radius: 999px;
  background: #eef4fa; color: var(--navy);
  font-size: .89rem; font-weight: 550; text-decoration: none;
}
.jump-links a:hover { background: #e0eaf4; }

/* Footer page links, present on every page including the homepage. */
.footer-nav { display: flex; flex-wrap: wrap; gap: 14px; margin: .5rem 0 0; }
.footer-nav a { color: var(--muted-invert); text-decoration: none; font-size: .89rem; }
.footer-nav a:hover { color: #fff; text-decoration: underline; }

/* ============================ RESPONSIVE ============================ */

@media (min-width: 600px) {
  .cards        { grid-template-columns: repeat(2, 1fr); }
  .gallery      { grid-template-columns: repeat(3, 1fr); }
  .contact-grid { grid-template-columns: repeat(2, 1fr); }
  .footer-inner { grid-template-columns: 1fr auto; align-items: end; }
  .footer-meta  { text-align: right; }
  .footer-meta .footer-nav { justify-content: flex-end; }
}

@media (min-width: 900px) {
  .site-nav     { display: flex; }
  .header-call  { display: inline-flex; }
  .cards        { grid-template-columns: repeat(4, 1fr); }
  .split        { grid-template-columns: 1fr 1.05fr; gap: 52px; }
  .contact-grid { grid-template-columns: repeat(4, 1fr); }
}

/* ============================ MOTION / PRINT ============================ */

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

@media print {
  .site-header, .hero-bg, .map-frame, .hero-actions { display: none; }
  body { font-size: 11pt; color: #000; }
  .hero, .section-dark { background: #fff !important; }
  .hero h1, .section-dark h2, .section-dark h3 { color: #000 !important; }
  .lede, .section-dark p { color: #333 !important; }
}
