/* ==========================================================================
   tokens.css — SOURCE. Decorator build, Direction B "Masking Tape".
   Brand block below is project-specific. The two alias blocks under it
   are kit-required. Names stay, only values change.
   ========================================================================== */

:root {
  /* ============ BRAND TOKENS: Masking Tape ============
     The working-trade palette: dust sheets, primer, charcoal, red
     oxide primer. Tape yellow is for the signature strip ONLY, never
     a button fill or text colour. */
  --ink:          #1e2329;   /* Charcoal */
  --paper:        #e9e4d8;   /* Dust Sheet */
  --paper-alt:    #dcd5c5;   /* Primer */
  --accent-raw:   #a3432c;   /* Red Oxide */
  --accent-raw-hover: #873522;
  --muted:        #5d5a52;
  --border-raw:   #c9c1ae;
  --tape:         #e2c46a;   /* Masking Tape */

  /* Archivo is variable on weight AND width. Display text uses the
     expanded cut (font-stretch: 125%), UI text stays normal width.
     Public Sans for body. Both variable, so no faux-bold risk. */
  --font-display: 'Archivo', system-ui, sans-serif;
  --font-body:    'Public Sans', system-ui, sans-serif;

  /* Trade-sharp: square corners throughout. */
  --radius:       0;
  --radius-lg:    0;

  /* ============ STRUCTURAL TOKENS: reusable as-is ============ */
  --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;

  --container-max:   72rem;
  --container-pad:   clamp(1.5rem, 6vw, 5rem);
  --nav-height:       4.5rem;

  /* ============ REQUIRED ALIAS: base.css focus-ring depends on this ============ */
  --accent:        var(--accent-raw);
  --accent-hover:  var(--accent-raw-hover);

  /* ============ GENERIC ALIAS LAYER: powers admin.html / calendar-help.html ============ */
  --color-accent:        var(--accent);
  --color-accent-hover:  var(--accent-hover);
  --color-bg:            var(--paper);
  --color-bg-alt:        var(--paper-alt);
  --color-text:          var(--ink);
  --color-text-muted:    var(--muted);
  --color-border:        var(--border-raw);
  --color-white:         #ffffff;
  --color-error:         #b3261e;
  --color-success:       #15803d;

  --space-1-alt: var(--space-1);
  --text-sm:     0.875rem;
}
/* ==========================================================================
   base.css — SOURCE. Reset + element defaults. Reusable as-is across
   every project — don't edit per client.
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Fix: sticky/fixed nav needs scroll-padding-top equal to its height,
     set once globally, or every anchor jump (native fragment nav,
     scrollIntoView, tab links) lands its target underneath the nav. */
  scroll-padding-top: var(--nav-height);
}

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

h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: 1.15;
  font-weight: 600;
}

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

/* Opt-in, not opt-out: lists default to no markers because most lists
   in a landing page are nav/primitive lists, not real numbered/bulleted
   content. Pages with genuine step lists must opt back in explicitly
   per list (e.g. `ol.help-steps { list-style: decimal; }`) — otherwise
   the numbers silently vanish while the text still reads fine, which
   is easy to miss in review. */
ul, ol { list-style: none; padding: 0; }

a { color: inherit; text-decoration: none; }

button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }

/* Fix: some shared layout classes (e.g. .stack, .cluster) set
   display:flex on their own children — that silently beats the
   browser's own [hidden] { display:none } default on any element that
   also carries one of those classes. This override makes [hidden]
   actually win regardless of what else is applied alongside it. */
[hidden] { display: none !important; }

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

/* No skip-to-content link by default — these are simple one-pagers.
   Add one explicitly only if a specific project asks for it. */
/* ==========================================================================
   layout.css — SOURCE. Generic layout primitives. Reusable as-is,
   rarely needs edits. Before writing fresh flex/grid for a new section,
   check this file first.

   Canonical breakpoints, used everywhere in this file and components.css:
     max-width: 640px   mobile
     max-width: 960px   tablet & down
     min-width: 961px   desktop & up
   ========================================================================== */

.container {
  max-width: var(--container-max);
  margin-inline: auto;
  /* Fix: --container-pad has a clamp() floor in tokens.css so this
     never collapses to near-zero on narrow viewports. */
  padding-inline: var(--container-pad);
}

.section          { padding-block: var(--space-8); }
.section--alt     { background: var(--paper-alt); }
.section--dark    { background: var(--ink); color: var(--paper); }

.stack            { display: flex; flex-direction: column; }
.stack > * + *     { margin-top: var(--space-4); }
.stack--tight > * + * { margin-top: var(--space-2); }
.stack--loose > * + * { margin-top: var(--space-7); }
/* Fix: margin-top does nothing to inline elements. A footer link list
   built from bare <a> tags inside .stack collapses onto one line
   without this — markup is correct, display:inline just ignores
   margin-top. */
.stack > a        { display: block; }

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-7);
  align-items: center;
}
@media (max-width: 960px) {
  .split { grid-template-columns: 1fr; }
}

.grid-auto {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--space-6);
}

.grid-fixed-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
}
@media (max-width: 960px) {
  .grid-fixed-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid-fixed-3 { grid-template-columns: 1fr; }
}
/* ==========================================================================
   components.css — SOURCE. Nav/button/card/form/tab mechanics are
   reusable as-is. Colours, radius values, and the signature element
   are project-specific — replace those, keep the mechanics.
   ========================================================================== */

/* ---------- Nav ----------
   Fix: .nav__bar and .nav__panel are BOTH children of .nav__inner, a
   single shared flex row — not siblings of it. Splitting them as
   siblings under <header> misaligns the nav links from the logo/toggle
   the moment the panel opens. */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--paper);
  border-bottom: 1px solid var(--border-raw);
}
.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--nav-height);
  position: relative; /* .nav__panel anchors to this */
}
.nav__logo {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.1rem;
}
.nav__bar {
  display: none;
  gap: var(--space-6);
}
.nav__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: none;
  border: none;
  font-weight: 600;
}
.nav__panel {
  display: none;
  flex-direction: column;
  gap: var(--space-1);
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--paper);
  border-bottom: 1px solid var(--border-raw);
  padding: var(--space-4) 0;
}
.nav__panel.is-open { display: flex; }
/* Fix: a nav CTA button reusing full .btn styling can collide with
   .nav__panel's own link styling depending on load order/specificity.
   Scoping plain nav links to :not(.btn) keeps the CTA button looking
   like a button regardless. */
.nav__panel a:not(.btn) {
  padding: var(--space-2) var(--container-pad);
  font-weight: 500;
}
.nav__panel .btn { margin-inline: var(--container-pad); }

@media (min-width: 961px) {
  .nav__bar { display: flex; align-items: center; }
  .nav__toggle { display: none; }
  .nav__panel { display: none !important; }
}

/* ---------- Buttons ----------
   Fix: inline-flex without justify-content:center pins a full-width
   button's label to the left in a flex column. Centering is part of
   the default, not something each variant re-adds. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius);
  font-weight: 600;
  border: 1.5px solid transparent;
  text-align: center;
}
.btn--primary {
  background: var(--accent);
  color: var(--color-white);
}
.btn--primary:hover { background: var(--accent-hover); }
.btn--outline {
  background: transparent;
  border-color: var(--border-raw);
  color: var(--ink);
}
.btn--block { width: 100%; }

/* ---------- Cards ----------
   Fix: an offset "behind" shape using a second independently-curved
   element (its own per-corner border-radius) doesn't stay a constant
   distance from the card if box size or curvature differs even
   slightly — the two curves cross at the corners and leak a hairline
   of the background colour through anti-aliasing. A single box-shadow
   on the card itself gives the same offset/shadow effect with nothing
   to keep in geometric sync. Swap the colour/offset per project;
   don't reintroduce a second shape. */
.card {
  background: var(--color-white);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: 0.4rem 0.4rem 0 var(--accent);
}

/* ---------- Forms ----------
   Fix: inputs/textareas inside a flex or grid layout size to their own
   intrinsic width by default, not their column — width:100% plus
   min-width:0 (to guard against overflow in a tight grid track) is
   required on every field, not assumed. */
.field { margin-bottom: var(--space-4); }
.field label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: var(--space-2);
}
.field input,
.field textarea,
.field select {
  width: 100%;
  min-width: 0;
  padding: var(--space-3);
  border: 1.5px solid var(--border-raw);
  border-radius: var(--radius);
  background: var(--color-white);
}
.field input:focus,
.field textarea:focus { outline: none; border-color: var(--accent); }
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}
@media (max-width: 640px) {
  .field-row { grid-template-columns: 1fr; }
}

/* ---------- Tabs ----------
   Fix (progressive enhancement): content hidden via [hidden] is
   unreachable with no JS and no fallback. Panels are visible (stacked)
   by default; only .js — added by an inline script at the very top of
   <head>, before anything else runs — gates the collapse to a tab
   view. This uses its own class rather than the [hidden] attribute so
   it doesn't collide with base.css's global [hidden] override. */
.tabs__list { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-5); }
.tabs__tab {
  padding: var(--space-2) var(--space-4);
  border-radius: 999px;
  border: 1.5px solid var(--border-raw);
  background: var(--color-white);
  font-weight: 600;
  font-size: 0.9rem;
}
.tabs__tab[aria-selected="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--color-white);
}
.tab-panel + .tab-panel { margin-top: var(--space-6); }
/* Nav/anchor jumps to a panel land it flush under the sticky nav
   (scroll-padding-top only clears the nav itself). This adds
   breathing room above the panel's heading on arrival. */
.tab-panel { scroll-margin-top: var(--space-6); }
.js .tab-panel:not(.is-active) { display: none; }

/* ---------- Scroll reveal ----------
   Fix: a hidden starting state set unconditionally in CSS
   ([data-reveal]{opacity:0}) means that if the driving script ever
   fails to run, the content is gone permanently — including, on a
   past build, an entire hero headline. The script adds its own
   .reveal-pending class before animating; the [data-reveal] attribute
   alone does nothing visually. */
.reveal-pending { opacity: 0; transform: translateY(1rem); }
.reveal-pending.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 0.5s ease, transform 0.5s ease;
}

/* ==========================================================================
   PROJECT LAYER: Decorator, Direction B "Masking Tape".
   Everything below is this build's visual layer only. No kit mechanic
   above has been edited.
   ========================================================================== */

/* ---------- Type ----------
   Archivo's width axis does the heavy lifting: expanded (125%) for
   display, normal for UI. Weights are real, not synthesised. */
h1, h2, h3, h4 { font-weight: 700; letter-spacing: -0.01em; }
h1, h2 { font-stretch: 125%; }
h1 { font-size: clamp(2.1rem, 5vw, 3.8rem); line-height: 1.02; }
h2 { font-size: clamp(1.6rem, 3.4vw, 2.4rem); line-height: 1.05; }
h3 { font-size: 1.15rem; }

.eyebrow {
  font-family: var(--font-display);
  font-stretch: 125%;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}
.lede { color: var(--muted); max-width: 54ch; font-size: 1.05rem; }

/* ---------- Nav ---------- */
.nav__logo {
  font-weight: 800;
  font-stretch: 125%;
  font-size: 1rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.nav__bar a:not(.btn) { font-weight: 500; }

/* ---------- Buttons ----------
   Stencil-ish trade labels: expanded caps, tight size. */
.btn {
  font-family: var(--font-display);
  font-stretch: 112%;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ---------- Full-width hero ----------
   Same mechanics as the holiday-home .hero-banner (full-bleed <img>,
   overlay, content anchored to the bottom), with a hard charcoal
   gradient so white text holds up on any photo. */
.hero-tape {
  position: relative;
  min-height: clamp(32rem, 80vh, 46rem);
  display: flex;
  align-items: flex-end;
  color: var(--paper);
  overflow: hidden;
}
.hero-tape img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.hero-tape::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(30, 35, 41, 0.94) 0%, rgba(30, 35, 41, 0.7) 38%, rgba(30, 35, 41, 0.1) 72%, rgba(30, 35, 41, 0) 100%);
}
.hero-tape__content {
  position: relative;
  z-index: 1;
  width: 100%;
  padding-block: var(--space-7);
}
.hero-tape__content > * + * { margin-top: var(--space-4); }
.hero-tape h1 { color: var(--paper); max-width: 20ch; }
.hero-tape .lede { color: rgba(233, 228, 216, 0.82); }
.hero-tape .cluster { margin-top: var(--space-6); }
.hero-tape .btn--outline { color: var(--paper); border-color: rgba(233, 228, 216, 0.55); }
.hero-tape .btn--outline:hover { border-color: var(--paper); }
/* Mobile: no photo. The hero becomes a solid charcoal band that runs
   straight into the tab band below. */
@media (max-width: 640px) {
  .hero-tape { min-height: 0; background: var(--ink); }
  .hero-tape img,
  .hero-tape::after { display: none; }
  .tab-band { border-top: 1px solid rgba(233, 228, 216, 0.14); }
  .tape { font-size: 0.68rem; padding: 0.5rem 1.1rem; }
}

/* ---------- Masking tape strip (signature element, used once) ----------
   A strip of tape stuck across the photo carrying the hero label.
   Ragged torn ends come from clip-path on the strip itself (one
   element, no second shape to keep in sync). Slight sheen via a
   gradient so it reads as paper tape, not a flat badge. */
.tape {
  display: inline-block;
  padding: 0.6rem 1.6rem;
  background-color: var(--tape);
  background-image: linear-gradient(90deg, rgba(255, 255, 255, 0.22), rgba(0, 0, 0, 0.05) 45%, rgba(255, 255, 255, 0.15));
  color: var(--ink);
  font-family: var(--font-display);
  font-stretch: 125%;
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transform: rotate(-2deg);
  transform-origin: left center;
  clip-path: polygon(
    1.5% 0, 98.5% 0,
    100% 16%, 98% 32%, 99.6% 50%, 97.9% 66%, 100% 83%, 98.4% 100%,
    1.2% 100%,
    0 84%, 2% 68%, 0.4% 50%, 2.2% 33%, 0 17%
  );
}

/* ---------- Tab band (structural risk) ----------
   The tab row is a full-width charcoal band directly under the hero,
   edge to edge, reading as the page's real navigation. Overrides the
   kit's pill tabs for this group only. */
.tab-band { background: var(--ink); }
.tab-band .tabs__list {
  margin-bottom: 0;
  gap: 2.5rem;
  flex-wrap: nowrap;
}
.tab-band .tabs__tab {
  flex: 0 0 auto;
  padding: 1.3rem 0;
  border: 0;
  border-bottom: 4px solid transparent;
  border-radius: 0;
  background: transparent;
  color: rgba(233, 228, 216, 0.65);
  font-family: var(--font-display);
  font-stretch: 125%;
  font-weight: 700;
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.tab-band .tabs__tab:hover { color: var(--paper); }
/* Beats the kit's filled-pill selected state on specificity. */
.tab-band .tabs__tab[aria-selected="true"] {
  background: transparent;
  color: var(--paper);
  border-bottom-color: var(--accent);
}
@media (max-width: 640px) {
  .tab-band .tabs__list { gap: var(--space-3); }
  .tab-band .tabs__tab {
    flex: 1 1 0;
    min-width: 0;
    padding: 1.1rem 0;
    font-size: 0.66rem;
    font-stretch: 100%;
    letter-spacing: 0.05em;
    white-space: nowrap;
    text-align: center;
  }
}

.panel-head { margin-bottom: var(--space-7); }
.panel-head > * + * { margin-top: var(--space-3); }

/* ---------- Services: ruled list ---------- */
.service-list { border-top: 2px solid var(--ink); }
.service-row {
  display: grid;
  grid-template-columns: 5rem 1fr 1.4fr;
  gap: var(--space-6);
  align-items: baseline;
  padding-block: var(--space-6);
  border-bottom: 1px solid var(--border-raw);
}
.service-row__num {
  font-family: var(--font-display);
  font-stretch: 125%;
  font-weight: 800;
  font-size: 2.25rem;
  line-height: 1;
  color: var(--accent);
}
.service-row p { color: var(--muted); }
@media (max-width: 960px) {
  .service-row { grid-template-columns: 3.5rem 1fr; gap: var(--space-2) var(--space-4); }
  .service-row p { grid-column: 2; }
  .service-row__num { font-size: 1.6rem; }
}

/* ---------- Recent work ---------- */
.work-item img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}
.work-item figcaption {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 2px solid var(--ink);
  font-size: 0.9rem;
  color: var(--muted);
}
.work-item figcaption strong {
  display: block;
  color: var(--ink);
  font-weight: 600;
}

/* ---------- FAQ: two-column grid ---------- */
.faq-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-6) var(--space-7);
}
.faq-grid > div {
  padding-top: var(--space-4);
  border-top: 2px solid var(--ink);
}
.faq-grid h3 { margin-bottom: var(--space-2); }
.faq-grid p { color: var(--muted); }
@media (max-width: 960px) {
  .faq-grid { grid-template-columns: 1fr; }
}

/* ---------- Contact (dark band) ---------- */
.section--dark .eyebrow { color: rgba(233, 228, 216, 0.7); }
.section--dark .lede { color: rgba(233, 228, 216, 0.78); }
.contact-details > div > span {
  display: block;
  font-family: var(--font-display);
  font-stretch: 125%;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.65;
}
.contact-details a { text-decoration: underline; text-underline-offset: 0.2em; }
/* Form card: Dust Sheet on charcoal, red oxide top edge instead of
   the kit's offset shadow. */
.card {
  background: var(--paper);
  color: var(--ink);
  box-shadow: none;
  border-top: 6px solid var(--accent);
}

/* ---------- Footer ---------- */
.site-footer {
  padding-block: var(--space-6);
  border-top: 1px solid rgba(233, 228, 216, 0.14);
}
.site-footer a { opacity: 0.8; }
.site-footer a:hover { opacity: 1; }
/* ---------- Legal pages ---------- */
.legal { max-width: 46rem; }
.legal > * + * { margin-top: var(--space-3); }
.legal > h1 { margin-top: var(--space-2); }
.legal > h2 { font-size: 1.35rem; margin-top: var(--space-7); }
.legal__updated { color: var(--muted); font-size: 0.9rem; }
.legal ul { list-style: disc; padding-left: 1.25rem; }
.legal li + li { margin-top: var(--space-2); }
.legal a { text-decoration: underline; text-underline-offset: 0.2em; }