/* ===================================================================
   OpenPane shared stylesheet
   Palette, type scale, and voice rules all come from brand_assets/BRAND.md.
   Loaded by every page. Page-specific one-offs stay inline.
   =================================================================== */

:root {
  --ink:   #1C1A17;
  --bone:  #F6F3EE;
  --linen: #EDE7DB;
  --clay:  #946640;

  /* Clay darkened for small text only. The brand clay measures 4.48:1 on bone
     and 4.03:1 on linen, so it fails WCAG AA (4.5:1) wherever it sets type.
     This variant keeps the brand hue and chroma and drops only lightness,
     reaching 5.52:1 on bone and 4.96:1 on linen. Brand clay stays in use for
     icons, borders, overlays and focus rings, which are governed by 3:1. */
  --clay-text: #855831;

  /* Spacing scale. Every gap and pad picks from this list. */
  --s-1: 0.5rem;   --s-2: 0.75rem;  --s-3: 1rem;
  --s-4: 1.5rem;   --s-5: 2rem;     --s-6: 3rem;
  --s-7: 4rem;     --s-8: 6rem;     --s-9: 8rem;

  --fs-display: clamp(30px, 4.4vw, 52px);
  --fs-h2:      clamp(26px, 3.1vw, 38px);

  /* Depth: base (bone) -> elevated (linen) -> floating (card).
     Shadows are tinted with ink and clay, never neutral grey. */
  --shadow-elev:
    0 1px 2px rgba(28, 26, 23, 0.04),
    0 4px 10px -2px rgba(28, 26, 23, 0.05),
    0 10px 26px -8px rgba(148, 102, 64, 0.09);
  --shadow-float:
    0 1px 2px rgba(28, 26, 23, 0.05),
    0 8px 18px -4px rgba(28, 26, 23, 0.07),
    0 22px 48px -14px rgba(148, 102, 64, 0.16);

  --ease-spring: cubic-bezier(0.2, 0.9, 0.25, 1);
}
@supports (color: oklch(0.55 0.08 60)) {
  :root {
    --clay: oklch(0.55 0.08 60);
    --clay-text: oklch(0.50 0.08 60);
  }
}

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

body {
  background: var(--bone);
  color: var(--ink);
  font-family: 'Inter Tight', system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

/* Grain. Kept very low so the page still reads as calm, not textured. */
.grain::before {
  content: '';
  position: fixed; inset: 0; z-index: 60; pointer-events: none;
  opacity: 0.032;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Warm ambient wash. Two soft radial pools of clay, well under 10%. */
.wash {
  background-image:
    radial-gradient(60rem 32rem at 78% -6%, rgba(148, 102, 64, 0.09), transparent 62%),
    radial-gradient(46rem 30rem at 4% 12%, rgba(148, 102, 64, 0.055), transparent 58%);
}

/* ------------------------------ Type ------------------------------ */
h1, h2 { font-family: 'Fraunces', Georgia, serif; font-weight: 500; }
.t-display, .t-h2 { font-family: 'Fraunces', Georgia, serif; font-weight: 500; }
.t-display { font-size: var(--fs-display); line-height: 1.08; letter-spacing: -0.015em; }
.t-h2      { font-size: var(--fs-h2);      line-height: 1.14; letter-spacing: -0.01em; }
.t-h3      { font-family: 'Inter Tight', system-ui, sans-serif; font-size: 18px; font-weight: 600; line-height: 1.4; }
.t-label {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--clay-text);
}
/* Clay is a seasoning: one clay element per view. Supporting labels drop
   to muted ink, or to bone on dark surfaces (clay on ink is 3.3:1, which
   fails AA at this size). */
.t-label-quiet { color: rgba(28, 26, 23, 0.65); }
.t-label-onink { color: rgba(246, 243, 238, 0.62); }
.muted { color: rgba(28, 26, 23, 0.75); }

/* ---------------------------- Structure --------------------------- */
.wrap { width: 100%; max-width: 1180px; margin-inline: auto; padding-inline: var(--s-4); }
@media (min-width: 768px) { .wrap { padding-inline: var(--s-6); } }
.wrap-narrow { max-width: 820px; }

.section { padding-block: var(--s-8); }
@media (min-width: 768px) { .section { padding-block: var(--s-9); } }
.section-tight { padding-block: var(--s-7); }

/* Page masthead used by every page except Home. */
.page-head { padding-block: var(--s-7) var(--s-6); }
@media (min-width: 768px) { .page-head { padding-block: var(--s-8) var(--s-7); } }

.crumb { font-size: 14px; color: rgba(28, 26, 23, 0.6); margin-bottom: var(--s-3); }
.crumb a { color: inherit; text-decoration: none; border-bottom: 1px solid rgba(28, 26, 23, 0.25); }
.crumb a:hover { color: var(--clay-text); border-color: var(--clay); }
.crumb span { margin-inline: 0.4rem; }

/* ---------------------------- Controls ---------------------------- */
.focus-ring:focus-visible { outline: 2px solid var(--clay); outline-offset: 3px; border-radius: 4px; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-1);
  padding: 0.85rem 1.5rem;
  border-radius: 6px;
  font-weight: 500; font-size: 16px; text-align: center;
  will-change: transform;
  transition: transform 0.22s var(--ease-spring),
              box-shadow 0.22s var(--ease-spring),
              background-color 0.18s ease,
              color 0.18s ease;
}
.btn:focus-visible { outline: 2px solid var(--clay); outline-offset: 3px; }

.btn-primary { background: var(--ink); color: var(--bone); box-shadow: var(--shadow-elev); }
.btn-primary:hover  { transform: translateY(-2px); box-shadow: var(--shadow-float); }
.btn-primary:active { transform: translateY(0);    box-shadow: var(--shadow-elev); }

.btn-secondary { background: transparent; color: var(--ink); box-shadow: inset 0 0 0 1.5px rgba(28, 26, 23, 0.3); }
.btn-secondary:hover  { transform: translateY(-2px); box-shadow: inset 0 0 0 1.5px rgba(28, 26, 23, 0.45), var(--shadow-elev); }
.btn-secondary:active { transform: translateY(0);    box-shadow: inset 0 0 0 1.5px rgba(28, 26, 23, 0.45); }

.link-quiet { color: var(--ink); text-decoration: none; transition: color 0.18s ease, opacity 0.18s ease; }
.link-quiet:hover { color: var(--clay-text); }
.link-quiet:active { opacity: 0.7; }

.link-inline { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--clay); transition: color 0.18s ease; }
.link-inline:hover { color: var(--clay-text); }

/* ----------------------------- Surfaces --------------------------- */
.card {
  background: var(--bone);
  border-radius: 10px;
  box-shadow: var(--shadow-elev);
  transition: transform 0.28s var(--ease-spring), box-shadow 0.28s var(--ease-spring);
}
.card-lift:hover { transform: translateY(-4px); box-shadow: var(--shadow-float); }
.card-linen { background: var(--linen); }

/* Photo treatment. Warm ink gradient plus a clay multiply pass, so images
   sit inside the palette instead of going cold and grey. */
.shot { position: relative; overflow: hidden; border-radius: 10px; background: var(--linen); }
.shot img { display: block; width: 100%; height: 100%; object-fit: cover; }
.shot::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, rgba(28, 26, 23, 0.20), transparent 46%);
}
.shot:has(.shot-cap)::after {
  background: linear-gradient(to top, rgba(28, 26, 23, 0.62), rgba(28, 26, 23, 0.05) 52%, transparent);
}
.shot::before {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: var(--clay); mix-blend-mode: multiply; opacity: 0.13;
}
.shot > .shot-cap { position: absolute; z-index: 2; left: var(--s-4); bottom: var(--s-3); color: var(--bone); }

.rule { height: 1px; background: rgba(28, 26, 23, 0.12); border: 0; }

/* Hairlines give the spec lists structure without adding bullet noise. */
.spec-list li { padding-block: 0.55rem; border-top: 1px solid rgba(28, 26, 23, 0.1); }
.spec-list li:first-child { border-top: 0; }

/* Numbered process strip, shared by Windows, Doors and Home. */
.steps { counter-reset: step; }
.steps > li::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  display: block;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 12px; font-weight: 500; letter-spacing: 0.14em;
  color: rgba(28, 26, 23, 0.65);
  margin-bottom: var(--s-2);
}

/* Placeholder blocks. Deliberately visible: these mark content that does
   not exist yet and must not ship as-is. */
.todo {
  border: 1.5px dashed rgba(148, 102, 64, 0.55);
  border-radius: 10px;
  background: rgba(148, 102, 64, 0.05);
  padding: var(--s-4);
  color: rgba(28, 26, 23, 0.7);
  font-size: 15px;
}
.todo strong { color: var(--clay-text); font-weight: 600; }

/* Per-type feature disclosure inside the product cards. Keeps the grid
   scannable by default and opens the detail in place. */
.type-detail { border-top: 1px solid rgba(28, 26, 23, 0.1); margin-top: var(--s-3); }
.type-detail summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);
  padding-top: var(--s-3);
  font-family: 'Inter Tight', system-ui, sans-serif;
  font-size: 15px; font-weight: 500;
  color: var(--clay-text);
  transition: color 0.18s ease;
}
.type-detail summary::-webkit-details-marker { display: none; }
.type-detail summary::after {
  content: '+';
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 16px; line-height: 1;
  transition: transform 0.24s var(--ease-spring);
}
.type-detail[open] summary::after { transform: rotate(45deg); }
.type-detail summary:hover { color: var(--ink); }
.type-detail summary:focus-visible { outline: 2px solid var(--clay); outline-offset: 3px; border-radius: 4px; }
.type-detail .panel { padding-top: var(--s-3); animation: panelIn 0.28s var(--ease-spring) both; }
.type-detail .panel h4 {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px; font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase;
  color: rgba(28, 26, 23, 0.65);
  margin-bottom: var(--s-1);
}
.type-detail .panel ul { margin-bottom: var(--s-4); }
.type-detail .panel ul:last-child { margin-bottom: 0; }

/* Feature icon grid. Replaces long bulleted lists so a card stays scannable. */
.feat-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3) var(--s-2); }
.feat { display: flex; gap: 0.55rem; align-items: flex-start; font-size: 13.5px; line-height: 1.35; color: rgba(28, 26, 23, 0.78); }
.feat svg { flex: none; width: 20px; height: 20px; color: var(--clay); margin-top: 1px; }

/* Hardware options, shown as the actual product rather than described. */
.hw-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-2); }
.hw { text-align: center; }
.hw img {
  width: 100%; height: 60px; object-fit: contain;
  background: var(--linen); border-radius: 8px; padding: 6px;
}
.hw span { display: block; margin-top: 0.4rem; font-size: 12px; line-height: 1.3; color: rgba(28, 26, 23, 0.72); }

/* Compact option chips, instead of a bulleted paragraph of options. */
.opt-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.opt-chips li {
  font-size: 12.5px; line-height: 1.3;
  padding: 0.28rem 0.6rem;
  border-radius: var(--s-4);
  background: var(--linen);
  color: rgba(28, 26, 23, 0.75);
}

/* ------------------------- Colour picker -------------------------- */
/* Real Vinylguard casement cutout, recoloured live. The tint layer is masked
   to the frame using the photo's own alpha channel, so the glass and the
   hardware are never touched. isolate keeps the multiply inside this box. */
.recolour {
  --pick: #F2F0EA;
  position: relative;
  isolation: isolate;
  width: 100%; max-width: 250px;
  margin-inline: auto;
}
.recolour img { display: block; width: 100%; height: auto; }
.recolour .tint {
  position: absolute; inset: 0;
  background: var(--pick);
  mix-blend-mode: multiply;
  pointer-events: none;
  -webkit-mask-image: url('/images/casement-frame-mask.png');
          mask-image: url('/images/casement-frame-mask.png');
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

.sw-grid { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 0.5rem; }
@media (max-width: 640px) { .sw-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); } }
.sw-btn {
  aspect-ratio: 1 / 1; width: 100%;
  border: 0; padding: 0; cursor: pointer;
  border-radius: 6px;
  box-shadow: inset 0 0 0 1px rgba(28, 26, 23, 0.18);
  transition: transform 0.18s var(--ease-spring), box-shadow 0.18s ease;
}
.sw-btn:hover { transform: scale(1.09); }
.sw-btn[aria-pressed='true'] {
  box-shadow: inset 0 0 0 1px rgba(28, 26, 23, 0.2), 0 0 0 2px var(--bone), 0 0 0 4px var(--ink);
}
.sw-btn:focus-visible { outline: 2px solid var(--clay); outline-offset: 3px; }

/* ------------------------------ Tabs ------------------------------ */
.tablist { display: flex; flex-wrap: wrap; gap: var(--s-5); border-bottom: 1px solid rgba(28, 26, 23, 0.14); }
.tab {
  font-family: 'Inter Tight', system-ui, sans-serif;
  font-size: 16px; font-weight: 500;
  /* 0.55 alpha measured 3.67:1 on linen and failed AA. 0.75 matches the
     .muted body token and reaches 6.83:1, while the ink underbar plus the
     remaining colour step still separates selected from unselected. */
  color: rgba(28, 26, 23, 0.75);
  background: none; border: 0;
  padding: 0 0 0.75rem; margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  transition: color 0.18s ease, border-color 0.18s ease;
}
.tab:hover { color: var(--ink); }
.tab[aria-selected='true'] { color: var(--ink); border-bottom-color: var(--ink); }
.tab:focus-visible { outline: 2px solid var(--clay); outline-offset: 4px; border-radius: 3px; }
.tabpanel[hidden] { display: none; }
.tabpanel { animation: panelIn 0.32s var(--ease-spring) both; }
@keyframes panelIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Small inline pill, used for privacy levels and spec tags. */
.pill {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  background: var(--linen);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px; font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase;
  color: rgba(28, 26, 23, 0.7);
  white-space: nowrap;
}

/* Compact spec table for grill and sizing matrices. */
.spec-table { width: 100%; border-collapse: collapse; font-size: 15px; }
.spec-table th, .spec-table td { text-align: left; padding: 0.6rem 0.75rem; border-top: 1px solid rgba(28, 26, 23, 0.1); }
.spec-table thead th { border-top: 0; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 11px; font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase; color: rgba(28, 26, 23, 0.65); }
.spec-table tbody th { font-weight: 600; }
.spec-table td { color: rgba(28, 26, 23, 0.75); }
.table-scroll { overflow-x: auto; }

/* ---------------------------- Swatches ---------------------------- */
/* Hex values are approximations of the Vinylguard paint range and must be
   replaced with the supplier's real values. */
.swatch { display: block; width: 100%; aspect-ratio: 1 / 1; border-radius: 6px; box-shadow: inset 0 0 0 1px rgba(28, 26, 23, 0.14); }
.swatch-name { display: block; margin-top: 0.5rem; font-size: 13px; line-height: 1.3; color: rgba(28, 26, 23, 0.7); }

/* ------------------------------ Forms ----------------------------- */
.field {
  width: 100%;
  background: var(--bone);
  border: 1.5px solid rgba(28, 26, 23, 0.18);
  border-radius: 6px;
  padding: 0.7rem 0.85rem;
  font: inherit; font-size: 16px;
  color: var(--ink);
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
.field::placeholder { color: rgba(28, 26, 23, 0.55); }
.field:hover { border-color: rgba(28, 26, 23, 0.34); }
.field:focus { outline: none; border-color: var(--clay); box-shadow: 0 0 0 3px rgba(148, 102, 64, 0.16); }

/* ------------------------------- FAQ ------------------------------ */
.faq summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3);
  padding-block: var(--s-3);
  transition: color 0.18s ease;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--clay-text); }
.faq summary:focus-visible { outline: 2px solid var(--clay); outline-offset: 3px; border-radius: 4px; }
.faq details { border-bottom: 1px solid rgba(28, 26, 23, 0.12); }
.faq .chev { transition: transform 0.24s var(--ease-spring); flex: none; color: var(--clay); }
.faq details[open] .chev { transform: rotate(45deg); }
.faq .answer { padding-bottom: var(--s-4); font-size: 15px; max-width: 68ch; color: rgba(28, 26, 23, 0.75); }
/* The question is a real <h3> so target keywords land in a heading. It sits in
   the summary's flex row, so it must not carry heading margins. */
.faq-q { margin: 0; }

/* ---------------------------- Map embed --------------------------- */
/* Google renders the administrative boundary as a tinted outline when the
   query resolves to a locality. Lazy loaded: the iframe pulls a few hundred KB
   and sets Google cookies, so it must not load until scrolled to. */
/* The keyless embed paints a place card in its top left corner reading
   "<Area> — No reviews". On a site that deliberately carries no reviews yet,
   that is the worst possible thing to render, so the top strip is cropped off.
   The iframe is grown by exactly the crop and pulled up, which keeps its bottom
   right corner in place so Google's logo and attribution stay visible, as their
   terms require. If Google resizes that card this value needs revisiting. */
.map-embed {
  position: relative; overflow: hidden;
  aspect-ratio: 16 / 9;
  border-radius: 10px;
  background: var(--linen);
  box-shadow: 0 0 0 1px rgba(28, 26, 23, 0.12);
}
.map-embed iframe {
  position: absolute; left: 0; top: -145px;
  width: 100%; height: calc(100% + 145px);
  border: 0;
  /* Google's tile palette is colder than the brand. A slight warm shift and a
     touch less saturation stop it fighting the linen it sits on. */
  filter: saturate(0.82) sepia(0.10);
}
@media (max-width: 640px) {
  .map-embed iframe { aspect-ratio: 4 / 3; }
}

/* ---------------------------- Chrome ------------------------------ */
.skip {
  position: absolute; left: var(--s-3); top: -3rem; z-index: 80;
  background: var(--ink); color: var(--bone);
  padding: 0.6rem 1rem; border-radius: 6px;
  transition: transform 0.2s var(--ease-spring);
}
.skip:focus { transform: translateY(3.6rem); }

.site-header { transition: box-shadow 0.25s ease, background-color 0.25s ease; }
.site-header[data-stuck='true'] { box-shadow: var(--shadow-elev); background: rgba(246, 243, 238, 0.92); backdrop-filter: blur(10px); }

/* Current page marker in the nav. */
.nav-link[aria-current='page'] { color: var(--clay-text); }

/* ------------------------- Nav dropdown --------------------------- */
/* One markup pattern serves both the desktop flyout and the mobile
   accordion. The panel carries [hidden], so with JS off both links are
   still in the document and reachable rather than lost. */
/* The parent stays a real link so clicking About goes to About. The caret is
   a separate button, which is what makes the submenu reachable by keyboard
   without stealing the link's job. */
.nav-menu { position: relative; display: flex; align-items: center; gap: 0.3rem; }

.nav-caret-btn {
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 0; padding: 0.25rem;
  color: inherit; cursor: pointer; line-height: 0;
}
.nav-caret-btn:hover { color: var(--clay-text); }

/* Marked when the current page is anywhere in the group, so /blog/ still
   shows where you are while the panel is shut. */
.nav-menu[data-current='true'] > a,
.nav-menu[data-current='true'] > .nav-caret-btn { color: var(--clay-text); }

.nav-caret { transition: transform 0.2s var(--ease-spring); }
.nav-caret-btn[aria-expanded='true'] .nav-caret { transform: rotate(180deg); }

.nav-menu-panel a {
  color: var(--ink); text-decoration: none; font-size: 15px;
  transition: color 0.18s ease, background-color 0.18s ease;
}
.nav-menu-panel a:hover { color: var(--clay-text); }
.nav-menu-panel a[aria-current='page'] { color: var(--clay-text); }
.nav-menu-panel[hidden] { display: none; }

/* Desktop: a floating panel beneath the button. */
@media (min-width: 1024px) {
  .nav-menu-panel {
    position: absolute; top: calc(100% + 0.65rem); left: 50%;
    transform: translateX(-50%);
    min-width: 9.5rem;
    display: flex; flex-direction: column;
    padding: 0.4rem;
    background: var(--bone);
    border-radius: 8px;
    box-shadow: var(--shadow-float);
    z-index: 60;
  }
  /* The gap between button and panel would otherwise drop the hover. */
  .nav-menu::after {
    content: ''; position: absolute; top: 100%; left: 0; right: 0; height: 0.65rem;
  }
  .nav-menu-panel a { padding: 0.5rem 0.75rem; border-radius: 5px; }
  .nav-menu-panel a:hover { background: var(--linen); }
}

/* Mobile: an inline accordion, indented under its parent. */
.nav-menu-mobile { display: flex; flex-direction: column; align-items: stretch; gap: 0; }
.nav-menu-mobile .nav-menu-row { display: flex; align-items: center; gap: 0.5rem; }
.nav-menu-mobile .nav-caret-btn { padding: 0.5rem; }
.nav-menu-mobile .nav-menu-panel {
  display: flex; flex-direction: column;
  padding-left: 1rem;
  border-left: 1.5px solid rgba(28, 26, 23, 0.12);
  margin: 0.15rem 0 0.35rem 0.25rem;
}
.nav-menu-mobile .nav-menu-panel a { padding: 0.4rem 0; }

/* Honeypot. Off screen rather than display:none, because bots check for the
   latter and skip it. Real visitors never see it and never tab to it. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* Anything deep-linked has to clear the sticky header when jumped to. */
main [id] { scroll-margin-top: 6rem; }
