/* =====================================================================
   LIGNUM — Composite fences, gates & acoustic panels
   Shared design system
   Style: Scandinavian minimalism (inspired by kompositlageret.dk)
   - White canvas, charcoal text, generous whitespace
   - Red accent reserved for sale/savings only
   - Product photography as the hero (swap placeholders for real photos)
   ===================================================================== */

/* ---------- Design tokens ---------- */
:root {
  /* Colour */
  --bg:        #ffffff;
  --bg-soft:   #f6f7f8;   /* section backgrounds */
  --bg-dark:   #16191b;   /* footer / dark blocks */
  --ink:       #1a1d1f;   /* primary text */
  --muted:     #6b7280;   /* secondary text */
  --line:      #e6e8ea;   /* hairline borders */
  --primary:   #1a1d1f;   /* primary buttons */
  --primary-h: #000000;   /* primary button hover */
  --accent:    #c8102e;   /* SALE red — savings only */
  --accent-soft:#fce9ec;
  --star:      #f5a623;   /* rating stars */

  /* Type */
  --font: "Josefin Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          Helvetica, Arial, sans-serif;
  /* Every font-weight in the stylesheets resolves through these two (see the
     block at the end of the file). Josefin Sans Light throughout — the split
     is kept so display and body type can diverge again from one line each. */
  --w-display: 300;
  /* Light for running text lost too much stroke at 12–13px. Display type
     keeps it; body copy and UI labels are Regular. */
  --w-text:    400;
  /* The wordmark carries more weight than the rest — it sits beside a solid
     logo mark and Light left it looking faint next to one. */
  --w-brand:   600;

  /* Shape & depth */
  --radius:    12px;
  --radius-sm: 8px;
  --shadow:    0 1px 2px rgba(16,19,21,.04), 0 8px 24px rgba(16,19,21,.06);
  --shadow-sm: 0 1px 2px rgba(16,19,21,.06);

  /* Layout */
  --maxw:      1240px;
  --gutter:    24px;
}

/* ---------- Typographic scale ----------
   Display sizes were a flat clamp on viewport width with default tracking,
   which reads as a template. Large type now sits tighter and heavier, body
   copy gets a longer measure, and small caps labels get real letterspacing. */
h1, h2 { letter-spacing: -.025em; font-weight: 800; }
h3 { letter-spacing: -.01em; }
h1 { line-height: 1.06; }
h2 { line-height: 1.12; }

.eyebrow { font-size: .7rem; letter-spacing: .18em; font-weight: 700; }

.section__head { align-items: flex-end; margin-bottom: 40px; }
.section__head h2 { margin-bottom: 0; }
.section__head .eyebrow { margin-bottom: 12px; }

/* A hairline under section heads gives the page a spine to hang off. */
.section__head { border-bottom: 1px solid var(--line); padding-bottom: 20px; }

/* Buttons: slightly tighter, with a weight shift that reads as deliberate. */
.btn { letter-spacing: .01em; }
.btn--primary { box-shadow: 0 1px 2px rgba(40,28,16,.16); }
.btn--primary:hover { transform: translateY(-1px); box-shadow: 0 4px 14px rgba(40,28,16,.2); }

/* ---------- Icons ----------
   Emoji rendered differently on every platform and read as placeholder.
   These are inline SVG at a consistent stroke weight. */
.usp__icon svg, .assurances svg, .install-link svg { width: 21px; height: 21px; flex: none; }
.usp__icon { border-radius: 10px; }
.assurances li { gap: 12px; align-items: center; }
.install-link svg { width: 18px; height: 18px; }

/* ---------- Hero sustainability note ----------
   Set apart from the lead paragraph by a rule and a tighter measure, so
   it reads as a separate claim rather than more body copy. */
.hero__note {
  margin: 4px 0 18px;
  padding-left: 16px;
  border-left: 3px solid var(--primary);
}
.hero__note b {
  display: block; margin-bottom: 4px;
  font-size: .95rem; font-weight: var(--w-text); letter-spacing: -.01em;
}
.hero__note p {
  margin: 0;
  font-size: .875rem; line-height: 1.55; max-width: 46ch;
}

/* ---------- Depth ----------
   One shadow ramp instead of the same flat card everywhere. */
.card, .cat-card, .hero__panel, .hero__mini {
  box-shadow: 0 1px 2px rgba(40,28,16,.06), 0 12px 28px -12px rgba(40,28,16,.22);
}
.card { transition: transform .28s cubic-bezier(.2,.6,.2,1), box-shadow .28s ease; }
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 2px 4px rgba(40,28,16,.08), 0 24px 44px -18px rgba(40,28,16,.32);
}
.cat-card { overflow: hidden; }
.cat-card:hover .ph, .card:hover .ph { transform: scale(1.05); }


/* ---------- Scrolling backdrop ----------
   A fixed stack of full-bleed material shots behind the page. Sections
   tagged [data-bg] cross-fade between them as they scroll past (see the
   observer in footer.ejs). The scrim above the stack is what keeps text
   readable, and each theme sets its own value. */
.bgstage { position: fixed; inset: 0; z-index: -2; overflow: hidden; pointer-events: none; }
.bgstage__layer {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  opacity: 0; transition: opacity 1s ease;
  will-change: opacity;
}
.bgstage__layer.is-active { opacity: 1; }
.bgstage__scrim { position: absolute; inset: 0; background: var(--scrim); }

@media (prefers-reduced-motion: reduce) {
  .bgstage__layer { transition: none; }
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
/* Josefin Sans has a small x-height: at a given pixel size its lowercase is
   noticeably shorter than the Inter this was drawn for, so the same numbers
   read smaller. 17px puts the x-height back where 16px Inter had it. Set on
   html so the rem sizes throughout the stylesheet scale with it, and as a
   percentage so it still follows the reader's own browser setting. */
html { scroll-behavior: smooth; font-size: 106.25%; }
body {
  margin: 0;
  font-family: var(--font);
  color: var(--ink);
  background: var(--bg);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
/* Form controls do not inherit the page font by default — the wishlist
   button was rendering in the browser's Arial while everything around it
   was not. Only .btn set `font: inherit`; this covers the rest. */
button, input, select, textarea { font-family: inherit; }
h1, h2, h3, h4 { margin: 0 0 .4em; line-height: 1.2; letter-spacing: -.01em; }
h1 { font-size: clamp(2rem, 4vw, 3.25rem); font-weight: 700; }
h2 { font-size: clamp(1.5rem, 2.6vw, 2.15rem); font-weight: 700; }
h3 { font-size: 1.15rem; font-weight: 600; }
p  { margin: 0 0 1em; }
ul { margin: 0; padding: 0; list-style: none; }

/* ---------- Layout helpers ---------- */
.container { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }
.section   { padding: 72px 0; }
.section--soft { background: var(--bg-soft); }
.section__head { display: flex; align-items: end; justify-content: space-between;
  gap: 16px; margin-bottom: 32px; flex-wrap: wrap; }
.section__head p { color: var(--muted); margin: 0; max-width: 52ch; }
.eyebrow { text-transform: uppercase; letter-spacing: .14em; font-size: .75rem;
  font-weight: 600; color: var(--muted); margin: 0 0 10px; }
.link-more { font-weight: 600; display: inline-flex; align-items: center; gap: 6px; }
.link-more:hover { color: var(--accent); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font: inherit; font-weight: 600; cursor: pointer;
  padding: 13px 22px; border-radius: var(--radius-sm);
  border: 1px solid transparent; transition: .18s ease;
  white-space: nowrap;
}
.btn--primary { background: var(--primary); color: #fff; }
.btn--primary:hover { background: var(--primary-h); }
.btn--ghost { background: #fff; color: var(--ink); border-color: var(--line); }
.btn--ghost:hover { border-color: var(--ink); }
.btn--light { background: #fff; color: var(--ink); }
.btn--light:hover { background: #f0f1f2; }
.btn--block { width: 100%; }
.btn--sm { padding: 9px 14px; font-size: .875rem; }

/* ---------- Top USP bar ---------- */
.topbar { background: var(--ink); color: #fff; font-size: .8rem; }
.topbar .container { display: flex; justify-content: center; gap: 28px;
  padding: 9px var(--gutter); flex-wrap: wrap; }
.topbar span { display: inline-flex; align-items: center; gap: 7px; opacity: .92; }
.topbar svg { width: 15px; height: 15px; }

/* ---------- Header ---------- */
.header { position: sticky; top: 0; z-index: 50; background: rgba(255,255,255,.9);
  backdrop-filter: blur(10px); border-bottom: 1px solid var(--line); }
.header__row { display: flex; align-items: center; gap: 24px;
  height: 72px; }
.brand { font-weight: 800; font-size: 1.4rem; letter-spacing: -.02em;
  display: inline-flex; align-items: center; gap: 8px; }
.brand__mark { width: 26px; height: 26px; border-radius: 6px;
  background: var(--ink); color: #fff; display: grid; place-items: center;
  font-size: .95rem; font-weight: 800; }
.nav { display: flex; gap: 4px; margin-left: 8px; }
.nav a { padding: 10px 12px; border-radius: 8px; font-weight: 500; font-size: .95rem;
  color: #33383b; }
.nav a:hover, .nav a[aria-current="page"] { background: var(--bg-soft); color: var(--ink); }
.header__actions { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.icon-btn { width: 42px; height: 42px; border-radius: 10px; display: grid;
  place-items: center; color: var(--ink); position: relative; }
.icon-btn:hover { background: var(--bg-soft); }
.icon-btn svg { width: 21px; height: 21px; }
.cart-count { position: absolute; top: 4px; right: 4px; background: var(--accent);
  color: #fff; font-size: .62rem; font-weight: 700; min-width: 16px; height: 16px;
  border-radius: 999px; display: grid; place-items: center; padding: 0 4px; }
.burger { display: none; }

/* ---------- Image placeholder (swap for real photos) ---------- */
/* Tiles carry a material shot set inline (see res.locals.material). The
   dev label that used to sit here read as an unfinished page, so it is
   gone; an empty tile now shows material rather than a grey box. */
.ph { position: relative; overflow: hidden;
  background-color: #e6ded4;
  background-size: cover;
  /* The scenes are shot with sky at the top; bias downward so a cropped
     tile shows decking and fence rather than roofline. */
  background-position: center 62%;
  transition: transform .5s cubic-bezier(.2,.6,.2,1); }
.cat-card .ph { background-position: center 58%; }
.ph--wide  { aspect-ratio: 16 / 9; }
.ph--sq    { aspect-ratio: 1 / 1; }
.ph--tall  { aspect-ratio: 3 / 4; }
.ph--hero  { aspect-ratio: 16 / 7; }

/* ---------- Hero ---------- */
.hero { padding-top: 28px; }
.hero__grid { display: grid; grid-template-columns: 1.15fr .85fr; gap: 20px; }
.hero__panel { position: relative; border-radius: var(--radius); overflow: hidden;
  min-height: 340px; box-shadow: var(--shadow-sm); }
.hero__panel .ph { position: absolute; inset: 0; }
.hero__panel--split { display: grid; grid-template-rows: 1fr 1fr; gap: 20px;
  min-height: 0; background: none; box-shadow: none; }
.hero__mini { position: relative; border-radius: var(--radius); overflow: hidden;
  box-shadow: var(--shadow-sm); }
.hero__mini .ph { position: absolute; inset: 0; }
.hero__content { position: absolute; inset: 0; display: flex; flex-direction: column;
  justify-content: flex-end; padding: 36px; gap: 6px;
  background: linear-gradient(to top, rgba(10,12,14,.66) 0%, rgba(10,12,14,.05) 55%, transparent 100%);
  color: #fff; }
.hero__content h1, .hero__content h2 { color: #fff; }
.hero__content p { color: rgba(255,255,255,.9); margin: 0 0 12px; max-width: 34ch; }
.hero__mini .hero__content { padding: 24px; }
.hero__mini .hero__content h2 { font-size: 1.35rem; }

/* ---------- Category cards ---------- */
/* auto-fit means the row always fills: four categories no longer leave a
   single orphan tile on a second row when the grid drops to three. */
.cat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 20px; }
.cat-card { position: relative; border-radius: var(--radius); overflow: hidden;
  box-shadow: var(--shadow-sm); background: #fff; }
.cat-card .ph { aspect-ratio: 3 / 4; }
.cat-card__body { position: absolute; inset: 0; display: flex; flex-direction: column;
  justify-content: flex-end; padding: 22px;
  background: linear-gradient(to top, rgba(10,12,14,.72), rgba(10,12,14,0) 60%);
  color: #fff; }
.cat-card__body h3 { color: #fff; font-size: 1.2rem; margin-bottom: 2px; }
.cat-card__body span { font-size: .85rem; opacity: .85; }
.cat-card:hover .ph { transform: scale(1.04); }
.cat-card .ph { transition: transform .4s ease; }

/* ---------- Product cards ---------- */
.prod-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 20px; }
.card { background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; display: flex; flex-direction: column; transition: .18s ease; }
.card:hover { box-shadow: var(--shadow); transform: translateY(-2px); }
.card__media { position: relative; }
.card__media .ph { aspect-ratio: 1 / 1; }
.badge { position: absolute; top: 12px; left: 12px; background: var(--accent);
  color: #fff; font-size: .78rem; font-weight: 700; padding: 5px 9px;
  border-radius: 6px; letter-spacing: .02em; }
.badge--new { background: var(--ink); left: auto; right: 12px; }
.wish { position: absolute; top: 10px; right: 10px; width: 34px; height: 34px;
  background: rgba(255,255,255,.9); border-radius: 999px; display: grid;
  place-items: center; color: var(--ink); box-shadow: var(--shadow-sm); }
.wish:hover { color: var(--accent); }
.card__body { padding: 16px; display: flex; flex-direction: column; gap: 8px;
  flex: 1; }
.card__cat { font-size: .72rem; text-transform: uppercase; letter-spacing: .1em;
  color: var(--muted); font-weight: 600; }
.card__title { font-size: 1rem; font-weight: var(--w-text); line-height: 1.35; }
.card__title a:hover { color: var(--accent); }
.rating { display: flex; align-items: center; gap: 4px; font-size: .8rem; color: var(--muted); }
.rating .stars { color: var(--star); letter-spacing: 1px; }
.price { display: flex; align-items: baseline; gap: 8px; margin-top: auto; }
.price__now { font-size: 1.2rem; font-weight: var(--w-text); }
.price__was { font-size: .9rem; color: var(--muted); text-decoration: line-through; }
.price__save { font-size: .78rem; font-weight: 700; color: var(--accent);
  background: var(--accent-soft); padding: 2px 7px; border-radius: 5px; }
.card__foot { padding: 0 16px 16px; }

/* ---------- Feature (USP) strip ---------- */
.usp { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; }
.usp__item { display: flex; gap: 14px; align-items: flex-start; }
.usp__icon { flex: none; width: 46px; height: 46px; border-radius: 12px;
  background: var(--bg-soft); display: grid; place-items: center; color: var(--ink); }
.usp__icon svg { width: 23px; height: 23px; }
.usp__item h4 { margin: 0 0 2px; font-size: 1rem; }
.usp__item p { margin: 0; font-size: .88rem; color: var(--muted); }

/* ---------- Advice / CTA band ---------- */
.band { background: var(--bg-dark); color: #fff; border-radius: 16px;
  padding: 48px; display: grid; grid-template-columns: 1.4fr 1fr;
  gap: 32px; align-items: center; }
.band h2 { color: #fff; }
.band p { color: rgba(255,255,255,.78); margin: 0; }
.band__actions { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }

/* ---------- Testimonials ---------- */
.quotes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.quote { background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 26px; }
.quote .stars { color: var(--star); letter-spacing: 2px; margin-bottom: 10px; }
.quote p { font-size: .98rem; }
.quote__who { display: flex; align-items: center; gap: 12px; margin-top: 16px; }
.quote__avatar { width: 40px; height: 40px; border-radius: 999px; background: #e2e6e9;
  display: grid; place-items: center; font-weight: 700; color: #7b8388; font-size: .9rem; }
.quote__who b { display: block; font-size: .9rem; }
.quote__who span { font-size: .8rem; color: var(--muted); }

/* ---------- Newsletter ---------- */
.news { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; align-items: center; }
.news form { display: flex; gap: 10px; }
.input { flex: 1; font: inherit; padding: 13px 15px; border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: #fff; }
.input:focus { outline: none; border-color: var(--ink); }

/* ---------- Footer ---------- */
.footer { background: var(--bg-dark); color: #c7ccd0; padding: 64px 0 28px; }
.footer a { color: #c7ccd0; }
.footer a:hover { color: #fff; }
.footer__grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr;
  gap: 32px; padding-bottom: 40px; border-bottom: 1px solid rgba(255,255,255,.12); }
.footer .brand { color: #fff; margin-bottom: 12px; }
.footer .brand__mark { background: #fff; color: var(--ink); }
.footer__grid h4 { color: #fff; font-size: .95rem; text-transform: uppercase;
  letter-spacing: .08em; margin-bottom: 14px; }
.footer__grid li { font-size: .92rem; }
/* These were 15px-tall text links — fine to click with a mouse, hard to
   hit with a thumb. The row keeps its old rhythm; the padding that makes
   up the height is inside the link, so it is the link that grows. */
.footer__grid li a { display: block; padding: 5px 0; }
.footer__about p { font-size: .92rem; max-width: 34ch; }
/* Four badges in a row do not fit a phone once they are big enough to
   read — at 375px they ran 15px past the column. Let them wrap. */
.footer__pay { display: flex; gap: 8px; margin-top: 16px; flex-wrap: wrap; }
.footer__pay span { font-size: .72rem; font-weight: 700; letter-spacing: .05em;
  border: 1px solid rgba(255,255,255,.25); border-radius: 5px; padding: 4px 8px;
  color: #fff; }
.footer__bottom { display: flex; justify-content: space-between; gap: 16px;
  padding-top: 22px; font-size: .82rem; color: #8b9298; flex-wrap: wrap; }

/* ---------- Breadcrumbs ---------- */
.crumbs { font-size: .85rem; color: var(--muted); padding: 18px 0; display: flex;
  gap: 8px; flex-wrap: wrap; }
/* 23px tall as bare text — a pixel under the 24px minimum target. */
.crumbs a { display: inline-block; padding: 2px 0; }
.crumbs a:hover { color: var(--ink); }

/* ---------- Category / listing layout ---------- */
.page-head { padding: 40px 0 8px; }
.page-head h1 { margin-bottom: 6px; }
.page-head p { color: var(--muted); max-width: 60ch; margin: 0; }
.listing { display: grid; grid-template-columns: 260px 1fr; gap: 36px;
  padding-bottom: 20px; }
.filters { position: sticky; top: 92px; align-self: start; }
.filters__group { border-bottom: 1px solid var(--line); padding: 18px 0; }
.filters__group:first-child { padding-top: 0; }
.filters h4 { font-size: .95rem; margin-bottom: 12px; }
.check { display: flex; align-items: center; gap: 9px; padding: 5px 0;
  font-size: .92rem; color: #3a3f42; cursor: pointer; }
.check input { width: 16px; height: 16px; accent-color: var(--ink); }
.check span.count { margin-left: auto; color: var(--muted); font-size: .82rem; }
.toolbar { display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 22px; gap: 12px; flex-wrap: wrap; }
.toolbar .result-count { color: var(--muted); font-size: .9rem; }
.select { font: inherit; padding: 10px 14px; border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: #fff; }
.prod-grid--3 { grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }

/* ---------- Product detail ---------- */
.pdp { display: grid; grid-template-columns: 1.05fr .95fr; gap: 48px;
  padding: 12px 0 20px; }
.gallery__main { border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-sm); }
.gallery__main .ph { aspect-ratio: 1 / 1; }
.gallery__thumbs { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
  margin-top: 12px; }
.gallery__thumbs .ph { aspect-ratio: 1 / 1; border-radius: var(--radius-sm); cursor: pointer;
  border: 2px solid transparent; }
.gallery__thumbs .ph.is-active { border-color: var(--ink); }
.pdp__info .card__cat { margin-bottom: 8px; }
.pdp__info h1 { font-size: clamp(1.6rem, 3vw, 2.2rem); }
.pdp__rating { display: flex; align-items: center; gap: 8px; margin: 6px 0 18px;
  font-size: .9rem; color: var(--muted); }
.pdp__price { display: flex; align-items: baseline; gap: 12px; margin-bottom: 4px; }
.pdp__price .price__now { font-size: 2rem; }
.pdp__price .price__was { font-size: 1.1rem; }
.pdp__vat { color: var(--muted); font-size: .85rem; margin-bottom: 22px; }
.pdp__desc { color: #3a3f42; margin-bottom: 22px; }
.opt { margin-bottom: 18px; }
.opt__label { font-weight: 600; font-size: .9rem; margin-bottom: 8px; }
.chips { display: flex; gap: 10px; flex-wrap: wrap; }
.chip { padding: 9px 16px; border: 1px solid var(--line); border-radius: 999px;
  font-size: .9rem; cursor: pointer; background: #fff; }
.chip.is-active, .chip:hover { border-color: var(--ink); }
.qty { display: inline-flex; align-items: center; border: 1px solid var(--line);
  border-radius: var(--radius-sm); overflow: hidden; }
.qty button { width: 42px; height: 46px; background: #fff; border: none; font-size: 1.2rem;
  cursor: pointer; color: var(--ink); }
.qty button:hover { background: var(--bg-soft); }
.qty input { width: 46px; height: 46px; border: none; text-align: center; font: inherit;
  font-weight: 600; }
.buy-row { display: flex; gap: 12px; margin: 22px 0; flex-wrap: wrap; }
.buy-row .btn--primary { flex: 1; min-width: 180px; }
.assurances { display: grid; gap: 10px; border-top: 1px solid var(--line); padding-top: 20px; }
.assurances li { display: flex; gap: 10px; align-items: center; font-size: .9rem;
  color: #3a3f42; }
.assurances svg { width: 18px; height: 18px; color: var(--ink); flex: none; }

/* ---------- Spec table ---------- */
.specs { max-width: 720px; }
.specs table { width: 100%; border-collapse: collapse; }
.specs td { padding: 12px 0; border-bottom: 1px solid var(--line); font-size: .95rem; }
.specs td:first-child { color: var(--muted); width: 42%; }
.specs td:last-child { font-weight: 500; }

/* ---------- Contact ---------- */
.contact { display: grid; grid-template-columns: 1fr 1fr; gap: 48px; }
.contact__info .item { display: flex; gap: 14px; padding: 16px 0;
  border-bottom: 1px solid var(--line); }
.contact__info .item:last-child { border-bottom: none; }
.contact__info .usp__icon { background: var(--bg-soft); }
.contact__info h4 { margin: 0 0 2px; font-size: 1rem; }
.contact__info p { margin: 0; color: var(--muted); font-size: .92rem; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field.full { grid-column: 1 / -1; }
.field label { font-size: .85rem; font-weight: 600; }
.field textarea { min-height: 130px; resize: vertical; }
.map .ph { aspect-ratio: 16 / 7; border-radius: var(--radius); }

/* ---------- Utilities ---------- */
.text-center { text-align: center; }
.mt-0 { margin-top: 0; }
.stack-sm > * + * { margin-top: 10px; }

/* ---------- Responsive ---------- */
@media (max-width: 1024px) {
  .usp { grid-template-columns: repeat(2, 1fr); }
  .footer__grid { grid-template-columns: 1fr 1fr; }
  .listing { grid-template-columns: 1fr; }
  .filters { position: static; display: grid; grid-template-columns: repeat(2, 1fr);
    gap: 8px 28px; margin-bottom: 8px; }
}
@media (max-width: 820px) {
  /* The catalogue button IS the small-screen nav, so it stays put. */
  .burger { display: grid; }
  .hero__grid { grid-template-columns: 1fr; }
  .hero__panel--split { grid-template-rows: none; grid-template-columns: 1fr 1fr; }
  .pdp, .contact, .news, .band { grid-template-columns: 1fr; }
  .band { padding: 32px; }
  .band__actions { justify-content: flex-start; }
  .quotes { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .section { padding: 48px 0; }
  .cat-grid, .prod-grid, .prod-grid--3 { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
  .topbar .container { gap: 16px; }
  .form-grid { grid-template-columns: 1fr; }
  .hero__panel--split { grid-template-columns: 1fr; }
}

/* =====================================================================
   App additions (auth, cart, account, flash, data tables, pills)
   ===================================================================== */

/* Header search */
.header__search input { font: inherit; padding: 9px 14px; border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: var(--bg-soft); width: 180px; }
.header__search input:focus { outline: none; border-color: var(--ink); background:#fff; }
.header__actions .btn--sm { margin-left: 4px; }
.card__img { aspect-ratio: 1/1; object-fit: cover; width: 100%; }
.gallery__main img { aspect-ratio: 1/1; object-fit: cover; width: 100%; }

/* Flash + alerts */
.flash { position: sticky; top: 72px; z-index: 40; font-size: .92rem; }
.flash .container { padding: 12px var(--gutter); }
.flash--ok  { background: #e9f7ef; color: #1e6b43; border-bottom: 1px solid #bfe6cf; }
.flash--err { background: var(--accent-soft); color: #93122a; border-bottom: 1px solid #f3c2ca; }
.alert { background: var(--accent-soft); color: #93122a; padding: 12px 14px;
  border-radius: var(--radius-sm); font-size: .9rem; margin-bottom: 16px; }
.linkbtn { background: none; border: none; padding: 0; font: inherit; color: inherit;
  cursor: pointer; text-decoration: none; }
.linkbtn:hover { color: var(--accent); }
.wish-form { position: absolute; top: 10px; right: 10px; }
.wish-form .wish { position: static; }
.btn--danger { background: #fff; color: var(--accent); border: 1px solid #f0c4cb; }
.btn--danger:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
.muted { color: var(--muted); }
.hint { color: var(--muted); font-size: .78rem; }
.empty { text-align: center; padding: 60px 20px; border: 1px dashed var(--line);
  border-radius: var(--radius); }
.empty p { color: var(--muted); margin-bottom: 16px; }

/* Auth */
.auth { display: grid; place-items: center; min-height: 60vh; }
.auth__box { max-width: 420px; width: 100%; }
.auth .stack .field { margin-bottom: 14px; }
.stack .field { display: flex; flex-direction: column; gap: 6px; }
.auth__alt { margin-top: 16px; color: var(--muted); }
.auth__alt a { color: var(--ink); font-weight: 600; text-decoration: underline; }

/* Cart */
.cart-layout { display: grid; grid-template-columns: 1fr 340px; gap: 32px; align-items: start; }
.cart-line { display: grid; grid-template-columns: 90px 1fr auto auto; gap: 18px;
  align-items: center; padding: 18px 0; border-bottom: 1px solid var(--line); }
.cart-line__media img, .cart-line__media .ph { width: 90px; aspect-ratio: 1/1;
  object-fit: cover; border-radius: var(--radius-sm); }
.cart-line__name { font-weight: 600; }
.cart-line__price { color: var(--muted); font-size: .9rem; margin: 4px 0; }
.cart-line__qty { display: flex; gap: 8px; align-items: center; }
.cart-line__sub { font-weight: 700; min-width: 80px; text-align: right; }
.cart-summary { background: var(--bg-soft); border-radius: var(--radius); padding: 24px; }
.cart-summary h3 { margin-bottom: 16px; }
.cart-summary .row { display: flex; justify-content: space-between; padding: 8px 0;
  font-size: .95rem; }
.cart-summary .row--total { border-top: 1px solid var(--line); margin-top: 8px;
  padding-top: 14px; font-size: 1.15rem; font-weight: 700; }
.cart-summary .btn { margin-top: 14px; }
.checkout-form h3 { margin-bottom: 16px; }

/* Account layout */
.acct-layout { display: grid; grid-template-columns: 240px 1fr; gap: 36px; align-items: start; }
.acct-nav { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.acct-nav__user { display: flex; gap: 12px; align-items: center; padding: 18px;
  background: var(--bg-soft); border-bottom: 1px solid var(--line); }
.acct-nav__user b { display: block; font-size: .92rem; }
.acct-nav__user span { font-size: .78rem; color: var(--muted); }
.acct-nav nav { display: flex; flex-direction: column; padding: 8px; }
.acct-nav nav a, .acct-nav nav .linkbtn { text-align: left; padding: 10px 12px;
  border-radius: 8px; font-size: .92rem; color: #33383b; }
.acct-nav nav a:hover, .acct-nav nav .linkbtn:hover { background: var(--bg-soft); }
.acct-nav nav a.is-active { background: var(--ink); color: #fff; }
.stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.stat { border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; }
.stat__num { display: block; font-size: 1.8rem; font-weight: 700; text-transform: capitalize; }
.stat__lbl { color: var(--muted); font-size: .85rem; }

/* Data tables */
.data { width: 100%; border-collapse: collapse; }
.data th { text-align: left; font-size: .75rem; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); padding: 10px 12px; border-bottom: 1px solid var(--line); }
.data td { padding: 12px; border-bottom: 1px solid var(--line); font-size: .92rem; vertical-align: middle; }
.data tbody tr:hover, .data tbody tr:hover { background: var(--bg-soft); }
.data tfoot td { border-bottom: none; }

/* Status pills */
.pill { display: inline-block; font-size: .72rem; font-weight: 700; padding: 3px 10px;
  border-radius: 999px; text-transform: capitalize; background: #eef0f2; color: #4a5157; }
.pill--new        { background: #e7efff; color: #234e9e; }
.pill--processing { background: #fff3d9; color: #9a6a00; }
.pill--shipped    { background: #e3f1fb; color: #1f6ea3; }
.pill--completed  { background: #e9f7ef; color: #1e6b43; }
.pill--cancelled  { background: var(--accent-soft); color: #93122a; }

@media (max-width: 860px) {
  .cart-layout, .acct-layout { grid-template-columns: 1fr; }
}


/* Brand lockup: logo on the left, wordmark on the right */
.brand__logo { height: 30px; width: auto; flex: none; }

/* Centring the flex row centres the text's *line box*, and Josefin Sans has
   a deep descender — 22 units above the baseline against 7 below at this
   size. That pushes the capitals about 3.5px above the middle of the logo,
   which is what reads as the wordmark sitting high. Nothing in the box model
   knows about cap height, so the difference is added back by hand; in em so
   it holds as the lockup scales with the viewport.
   (text-box: trim-both cap alphabetic would do this properly — too new to
   rely on here.) */
.brand__name { line-height: 1; position: relative; top: .117em; }

/* Header lockup at 2x on wide screens, scaling down so it never
   collides with the nav on narrower viewports. */
body.site .header__row { height: 104px; gap: 18px; }
body.site .header .brand {
  font-size: clamp(1.4rem, 3.1vw, 2.8rem);
  gap: .32em;
  flex: none;
  white-space: nowrap;
}
body.site .header .brand__logo { height: 1.34em; }
/* The nav is a single catalogue button now, so it never needs to shrink
   or wrap; the actions keep their width on the right. */
body.site .header .nav { flex: none; margin-left: 0; }
body.site .header__actions { flex: none; margin-left: auto; }
body.site .flash { top: 104px; }

/* ---------- Hero: fits any language ----------
   Three problems this solves, all of which showed up once Danish (which
   runs noticeably longer than English) was switched on:
   1. The placeholder label sat dead-centre in the panel and printed on
      top of the overlaid copy. It moves to the top-left corner, clear of
      the text, and disappears entirely once a real photo is set.
   2. The panel was locked to 340px, so longer copy had nowhere to go.
      The content is now in normal flow, so the panel grows to fit.
   3. Headings scale with the *panel* width (cqw) rather than the
      viewport, so they stay proportionate however wide the tile is. */
.hero__panel, .hero__mini { container-type: inline-size; }

.hero__panel .hero__content,
.hero__mini .hero__content {
  position: relative; inset: auto; width: 100%;
}
.hero__panel .hero__content { min-height: 340px; }
.hero__mini  .hero__content { min-height: 160px; }
.hero__panel, .hero__mini { min-height: 0; }

.hero__content h1 { font-size: clamp(1.5rem, 7.2cqw, 3rem); }
.hero__mini .hero__content h2 { font-size: clamp(1.05rem, 6cqw, 1.5rem); }
.hero__content p:not(.eyebrow) { font-size: clamp(.86rem, 2.9cqw, 1rem); max-width: 32ch; }

/* Category tiles scale with their own width too, and long compound words
   (Danish is full of them — "Affaldsskjulere", "Kompositthegn") are
   allowed to break rather than run past the tile edge. */
.cat-card { container-type: inline-size; }
.cat-card__body h3 { font-size: clamp(.95rem, 9cqw, 1.2rem); }
.cat-card__body span { font-size: clamp(.72rem, 5.2cqw, .85rem); }
.cat-card__body h3,
.cat-card__body span,
.catalog__menu a { overflow-wrap: anywhere; }
@container (max-width: 200px) {
  .cat-card__body { padding: 14px; }
}

/* Placeholder label out of the way of any overlaid copy. */
.hero__panel .ph::after,
.hero__mini .ph::after,
.cat-card .ph::after {
  position: absolute; top: 10px; left: 14px;
  font-size: .62rem; opacity: .5;
}

/* ---------- Catalogue dropdown ----------
   Replaces the row of nav tabs with one button, so the header stays the
   same width whatever the labels say — which is what kept breaking when
   Danish ran longer than English. */
.catalog { position: relative; }
/* Icon only — the three bars carry the meaning; the label stays in the
   markup for screen readers and the tooltip. */
.catalog__btn {
  display: grid; place-items: center;
  width: 42px; height: 42px; padding: 0;
  font: inherit; cursor: pointer;
  color: var(--primary);
  background: transparent;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  transition: background .18s ease, border-color .18s ease, color .18s ease;
}
.catalog__btn:hover,
.catalog__btn.is-open { background: var(--primary); border-color: var(--primary); color: #fff; }

/* Three bars that read as a menu without needing an icon font. */
.catalog__bars { display: grid; gap: 4px; width: 20px; }
.catalog__bars i { display: block; height: 2px; border-radius: 2px; background: currentColor; }
.catalog__bars i:nth-child(2) { width: 70%; }

.catalog__chev { display: none; }
.catalog__label { position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }

.catalog__menu {
  position: absolute; top: calc(100% + 8px); left: 0; z-index: 60;
  min-width: 240px; padding: 8px;
  background: var(--menu-bg);
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--menu-shadow);
  display: flex; flex-direction: column;
}
.catalog__menu[hidden] { display: none; }
.catalog__menu a {
  padding: 10px 12px; border-radius: var(--radius-sm);
  font-size: .95rem; font-weight: 500; color: var(--ink);
  white-space: nowrap;
}
.catalog__menu a:hover,
.catalog__menu a:focus-visible { background: var(--menu-hover); color: var(--primary); outline: none; }
.catalog__menu a.is-current { color: var(--primary); font-weight: 700; }
.catalog__sep { border: none; border-top: 1px solid var(--line); margin: 6px 8px; }

/* Footer grid: `fr` columns refuse to shrink below their content's
   min-width, and "KompositFabrikken" is one unbreakable word — which
   pushed the first column past the grid and scrolled the page sideways
   on phones. Let the tracks shrink and the wordmark wrap. */
.footer__grid > * { min-width: 0; }
.footer .brand { flex-wrap: wrap; }
.footer .brand__name { overflow-wrap: anywhere; }
@media (max-width: 520px) {
  .footer__grid { grid-template-columns: 1fr; gap: 24px; }
  .footer__about p { max-width: none; }
}

/* Small screens: drop the wordmark, then the button label, so the header
   row keeps fitting instead of forcing the page to scroll sideways. */
@media (max-width: 760px) {
  body.site .header .brand__name { display: none; }
}

/* Product titles: same unbreakable-compound-word problem as the tiles. */
.card__title, .card__title a { overflow-wrap: anywhere; }

/* USP strip: grid items default to min-width:auto, so the icon plus a long
   heading kept the two columns wider than the phone. */
.usp__item { min-width: 0; }
.usp__item h4, .usp__item p { overflow-wrap: anywhere; }
@media (max-width: 520px) {
  .usp { grid-template-columns: 1fr; gap: 18px; }
}

/* ---------- Installation guide ---------- */
.pdp__links { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 22px; }
.pdp__links form { margin: 0; }
.install-link { display: inline-flex; align-items: center; gap: 9px; }
.install-link__icon { font-size: 1.05rem; line-height: 1; }

.guide { display: grid; grid-template-columns: 1fr 320px; gap: 40px; align-items: start; }
.guide__text {
  white-space: pre-line;           /* the CMS field is plain text, one step per line */
  font-size: 1.02rem; line-height: 1.75; max-width: 68ch;
}
.panel-soft {
  background: var(--bg-soft); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 24px;
}
.panel-soft h3 { margin-bottom: 8px; }
.panel-soft p { font-size: .92rem; margin-bottom: 16px; }
@media (max-width: 900px) {
  .guide { grid-template-columns: 1fr; gap: 28px; }
}

/* ---------- Header control row ----------
   One shared shape for every control: 42px tall, hairline border, the
   same 8px rounding as the buttons. */
body.site .header .catalog__btn,
body.site .header__actions .icon-btn,
body.site .header__search,
body.site .header__search-btn,
body.site .header__actions .btn--sm,
body.site .langswitch { height: 42px; border-radius: var(--radius-sm); }
/* Log in is sized by padding, not a box, so pin it to the row height. */
body.site .header__actions .btn--sm { display: inline-flex; align-items: center; }

body.site .header .catalog__btn,
body.site .header__actions .icon-btn,
body.site .header__search-btn {
  width: 42px;
  border: 1px solid var(--line);
  background: transparent;
}
body.site .header__actions .icon-btn,
body.site .header__search-btn,
body.site .header__actions .btn--ghost { color: var(--primary); }
body.site .header__actions .icon-btn:hover,
body.site .header__search-btn:hover,
body.site .header__actions .btn--ghost:hover {
  background: var(--primary); border-color: var(--primary); color: #fff;
}
/* The field pops out of the button, so only the button carries the frame. */
body.site .header__search { border: none; }

/* ---------- Language switcher ---------- */
.langswitch { display: flex; align-items: center; gap: 2px; margin-left: 4px;
  border: 1px solid var(--line); padding: 3px; flex: none; }
.langswitch__opt { font-size: .78rem; font-weight: 700; letter-spacing: .04em;
  padding: 7px 10px; border-radius: 5px; color: var(--muted); line-height: 1.25;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; min-height: 30px; }
.langswitch__opt:hover { color: var(--ink); }
.langswitch__opt.is-active { background: var(--primary); color: #fff; }

/* ---------- Collapsing search ----------
   Sits as a 42px icon button by default and expands on hover, focus,
   or once the field holds a query, so it never crowds the nav. */
/* The button holds the only space in the flex row. The field is absolutely
   positioned and opens leftward *over* the nav, so expanding it never
   reflows the header. */
.header__search { position: relative; width: 42px; height: 42px; flex: none; }
.header__search-btn {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center;
  font: inherit; font-size: 1.5rem; line-height: 1;
  background: none; border: none; border-radius: 10px;
  color: var(--ink); cursor: pointer; padding: 0;
  transition: background .18s ease;
}
.header__search-btn:hover { background: var(--bg-soft); }
.header__search input {
  position: absolute; top: 50%; right: 38px; transform: translateY(-50%);
  z-index: 3; width: 0; padding: 9px 0; border-width: 0; opacity: 0;
  pointer-events: none; box-shadow: 0 2px 10px rgba(0,0,0,.25);
  transition: width .22s ease, padding .22s ease, opacity .18s ease;
}
body.site .header__search input,
body.site .header__search input:focus { background: var(--field-bg); }
.header__search:hover input,
.header__search:focus-within input,
.header__search input:not(:placeholder-shown) {
  width: 210px; padding: 9px 16px 9px 14px; border-width: 1px; opacity: 1;
  pointer-events: auto;
}
@media (max-width: 860px) {
  .header__search:hover input,
  .header__search:focus-within input,
  .header__search input:not(:placeholder-shown) { width: 150px; }
}


/* Tighten the action cluster so the row still fits a 375px phone — a
   logged-in admin shows five icon buttons plus login and the switcher.
   These sit after the shared sizing rules on purpose: same specificity,
   so source order is what makes them win. */
@media (max-width: 600px) {
  /* Narrower gutters buy back the width the icon row needs. */
  body.site { --gutter: 14px; }
  .catalog__menu { left: 0; right: auto; }
  body.site .header__row { gap: 8px; }
  body.site .header__actions { gap: 2px; }

  body.site .header .catalog__btn,
  body.site .header__actions .icon-btn,
  body.site .header__search,
  body.site .header__search-btn,
  body.site .langswitch { height: 36px; }

  body.site .header .catalog__btn,
  body.site .header__actions .icon-btn,
  body.site .header__search-btn { width: 36px; }

  body.site .header__actions .icon-btn svg { width: 18px; height: 18px; }
  body.site .langswitch { padding: 2px; margin-left: 0; gap: 0; }
  body.site .langswitch__opt { padding: 4px 6px; font-size: .72rem; letter-spacing: 0;
    min-width: 30px; min-height: 28px; }
  body.site .header__actions .btn--sm { padding: 0 9px; font-size: .8rem; height: 36px; }
}

/* Between tablet and desktop auto-fit lands on three columns, which leaves
   a lone fourth category stranded on its own row. Pair them up instead. */
@media (min-width: 821px) and (max-width: 1120px) {
  .cat-grid { grid-template-columns: repeat(2, 1fr); }
}

/* =====================================================================
   Weight
   ---------------------------------------------------------------------
   Rather than editing the ~40 individual font-weight declarations above,
   this block routes all of them through two tokens, so the site's weight
   is changed here and nowhere else. Both are Light today; they are kept
   separate so display type can be made lighter or heavier than body copy
   without touching anything else.

   It has to come last: it wins on source order, not specificity, against
   the equally-specific rules it overrides.
   ===================================================================== */
body,
h3, h4, h5, h6,
b, strong, th, label, button, input, select, textarea, optgroup,
.btn, .pill, .badge, .chip, .price, .eyebrow,
.nav a, .link-more, .logo, .side-count, .admin-side nav a,
.admin-side__label, .data th, .kpi__value, .quote__avatar,
.footer__pay span, .langswitch__opt, .crumbs, .qty button {
  font-weight: var(--w-text);
}

h1, h2 { font-weight: var(--w-display); }
.brand, .brand__name { font-weight: var(--w-brand); }
