/* THE STANDARD THEME.
 *
 * ONE CONSTRAINT SHAPES ALL OF THIS: a theme file is text, so there are no images. Every bit of visual interest
 * has to come from the grid, the type and the space — which is a good constraint for a starting point, because
 * those three are also the parts an author cannot break by uploading the wrong thing.
 *
 * THE GRID. A twelve-column container, centred, and everything aligns to it: the header, every section, the
 * footer. The first version had no container at all — text flush against a `padding` and half the screen empty —
 * which reads as an unfinished page rather than a spacious one.
 *
 * THE RHYTHM IS SPACE, NOT RULES. Version one drew a hairline between every two sections, and a page separated
 * by lines reads as a table. Sections are separated by air; a rule appears only where it means something (over a
 * feature, under the footer's top edge).
 *
 * FOUR TOKENS COME FROM THE EDITOR — ink, paper, accent, measure (see layout/theme.liquid) — so changing the
 * accent changes the buttons, the links, the feature rules and the dark band without anybody touching CSS.
 */

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

:root {
  /* The four an author controls. Repeated here so the stylesheet stands alone if the layout ever forgets one. */
  --ink: #14161a;
  --paper: #ffffff;
  --accent: #3b5bdb;
  --measure: 68ch;

  /* Derived. A grey carrying the accent's hue reads as chosen; a pure grey reads as forgotten. */
  --muted: color-mix(in oklab, var(--ink) 55%, var(--paper));
  --line: color-mix(in oklab, var(--ink) 14%, var(--paper));
  --wash: color-mix(in oklab, var(--accent) 6%, var(--paper));

  /* THE GRID. One container width and one gutter, used by every band on the page. */
  --page: 76rem;
  --gutter: clamp(1.25rem, 4vw, 3.5rem);

  /* A spacing scale, not a pile of magic numbers. Each step is roughly 1.5× the last. */
  --s1: 0.5rem;
  --s2: 0.875rem;
  --s3: 1.5rem;
  --s4: 2.5rem;
  --s5: clamp(3rem, 6vw, 5rem);
  --s6: clamp(4.5rem, 9vw, 8rem);

  --sans: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
  --serif: ui-serif, 'Iowan Old Style', Georgia, 'Palatino Linotype', serif;
}

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 1.0625rem/1.65 var(--sans);
  text-rendering: optimizeLegibility;
}

a { color: inherit; }
a:focus-visible,
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }

.vh,
.skip:not(:focus) {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap;
}
.skip:focus {
  position: fixed; z-index: 10; inset: var(--s1) auto auto var(--s1);
  padding: 0.6rem 1rem; background: var(--ink); color: var(--paper);
  border-radius: 8px; text-decoration: none;
}

/* ── THE CONTAINER ─────────────────────────────────────────────────────────────────────────────────
 *
 * Every band is a full-width element whose CONTENT is constrained, rather than a narrow element floating in the
 * middle. That is what lets the CTA band paint edge to edge while its text still lines up with the hero's.
 *
 * BY CLASS, NEVER BY PARENT — and this cost an evening, so it is written down.
 *
 * These rules said `main > section` and `main > section > *`. Correct on the live site, and silently wrong in the
 * editor: its preview wraps every section in `<div data-cms-section style="display:contents">` so a click can
 * name what it hit. `display: contents` keeps that div out of the LAYOUT, which is what the package's comment
 * promises and what it delivers — but a selector reads the DOM, not the layout. The section became
 * `main > div > section`, every one of these rules stopped matching, and the preview lost its gutters, its
 * measure and all of its vertical rhythm. The page was fine. The thing you build the page IN was not.
 *
 * So: a theme for this CMS never selects through the chain above a section. Every band carries its own class,
 * and so does its inner container.
 */
.hdr,
.hero,
.prose,
.feat,
.cta,
.ftr { padding-inline: var(--gutter); }

.hdr-in,
.hero-in,
.prose-in,
.feat-in,
.cta-in,
.ftr-in { max-width: var(--page); margin-inline: auto; }

/* ── HEADER ────────────────────────────────────────────────────────────────────────────────────── */

.hdr { padding-block: var(--s3); }
.hdr-in {
  display: flex; align-items: baseline; gap: var(--s4);
}
.hdr-mark {
  font: 600 1.125rem/1 var(--sans);
  letter-spacing: -0.02em;
  text-decoration: none;
}
.hdr-nav { display: flex; flex-wrap: wrap; gap: var(--s3); margin-right: auto; }
.hdr-nav a {
  color: var(--muted); text-decoration: none; font-size: 0.9375rem;
  padding-bottom: 2px; border-bottom: 1px solid transparent;
}
.hdr-nav a:hover { color: var(--ink); border-bottom-color: var(--accent); }

/* ── A MENU ITEM WITH LINKS UNDER IT ────────────────────────────────────────────────────
   `<details>` positioned under its own summary, so the fold-out opens where the reader pressed. The summary
   reads as a menu link with a small chevron; the open panel is the language panel's shape. */
.hdr-menu { position: relative; }
.hdr-menu > summary {
  list-style: none; cursor: pointer;
  color: var(--muted); font-size: 0.9375rem;
  padding-bottom: 2px; border-bottom: 1px solid transparent;
}
.hdr-menu > summary::-webkit-details-marker { display: none; }
.hdr-menu > summary::after { content: "▾"; margin-left: 0.25em; font-size: 0.75em; }
.hdr-menu[open] > summary, .hdr-menu > summary:hover { color: var(--ink); border-bottom-color: var(--accent); }
.hdr-menu-pop {
  position: absolute; left: 0; top: calc(100% + var(--s2)); z-index: 30;
  display: grid; gap: var(--s2); min-width: 12rem; padding: var(--s3);
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--paper); box-shadow: 0 10px 30px rgb(0 0 0 / 12%);
}
.hdr-menu-pop a { border-bottom: 0; }

/* ── A LOGO, WHEN THERE IS ONE ─────────────────────────────────────────────────────
   THE ROW ALIGNS ON THE BASELINE, which is right for a word and wrong for a picture: a logo would hang its
   bottom edge off the same line as the menu's x-height. So the header carries a class when a picture is in
   it and the row centres instead — a theme with a text mark is not moved by a rule it never matches.

   AND THE WIDTH IS THE OPERATOR'S, as a length. `height: auto` is what keeps a wide logo from being
   squashed; without it a tall one sets the height of the whole header. */
.hdr-has-logo .hdr-in { align-items: center; }
.hdr-logo { display: block; width: var(--logo-w, 120px); height: auto; }

/* ── STUCK TO THE TOP, WHEN THE SHOP ASKS ───────────────────────────────────────────────
   IT NEEDS ITS OWN BACKGROUND. A sticky element is transparent by default, so the page scrolls THROUGH it
   and the menu reads on top of whatever is passing underneath. */
.hdr-stick {
  position: sticky; top: 0; z-index: 20;
  background: var(--paper);
}

/* ── THE MARK ON ITS OWN LINE, CENTRED ────────────────────────────────────────────────
   THREE RULES AND NO SECOND MARKUP. `flex-basis: 100%` on the mark takes the first line, and everything
   else wraps under it in the order it is written — which is the same mechanism the narrow layout at the
   bottom of this file already uses for the menu. */
.hdr-mid .hdr-in { flex-wrap: wrap; justify-content: center; }
.hdr-mid .hdr-mark { flex-basis: 100%; text-align: center; }
/* AND A PICTURE IS NOT CENTRED BY `text-align`. The logo is display:block, so the line above moves a
   brand NAME and left a logo hard against the gutter — seen on the shot, not in the markup. */
.hdr-mid .hdr-logo { margin-inline: auto; }
.hdr-mid .hdr-nav { margin-right: 0; justify-content: center; }

/* THE READER'S OWN PAGES. Quiet, like a menu link, because it is one — not a button. */
.hdr-acct { color: var(--muted); text-decoration: none; font-size: 0.9375rem; }
.hdr-acct:hover { color: var(--ink); }

/* ── LANGUAGE AND MARKET, AS ONE CONTROL ──────────────────────────────────────────
   IT WAS TWO WORDS SIDE BY SIDE, which is right for two languages and wrong the moment there is a currency
   as well: four items in a header row, none of them saying which is chosen. So it is a BUTTON showing what
   is in force, and the choices are in a popover under it.

   THE POPOVER IS THE BROWSER'S OWN. `[popover]` is display:none until it is shown, positioned in the top
   layer — so `position: absolute` here is relative to the VIEWPORT and not to the button. `anchor-name`
   would tie the two together and is not in every browser this shop will meet yet, so the panel is pinned to
   the top right, which is where the control is. */
.hdr-loc { display: flex; }
.hdr-locbtn {
  display: inline-flex; align-items: baseline; gap: 0.35rem;
  padding: 0.35rem 0.5rem; margin: -0.35rem -0.5rem;
  border: 0; border-radius: 999px;
  background: transparent; color: var(--muted); cursor: pointer;
  font: 500 0.875rem/1 var(--sans);
  transition: color var(--press) var(--ease-out);
}
.hdr-locbtn:hover { color: var(--ink); }
.hdr-locbtn i { font-style: normal; opacity: 0.5; }

.hdr-locpop {
  position: absolute; inset: auto var(--gutter) auto auto; top: 3.25rem;
  min-width: 11rem; padding: var(--s3);
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--paper); color: var(--ink);
  box-shadow: 0 10px 30px rgb(0 0 0 / 12%);
}
.hdr-locttl {
  margin: 0 0 var(--s2); font: 600 0.75rem/1 var(--sans);
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted);
}
.hdr-locttl + .hdr-locrows { margin-bottom: var(--s3); }
.hdr-locrows:last-child { margin-bottom: 0; }
.hdr-locrows { display: flex; flex-direction: column; align-items: stretch; gap: 2px; }
/* ONE RULE FOR THE LINK AND THE BUTTON, because a language and a market are the same row to a reader and
   only the machinery under them differs — see the section's own comment. */
.hdr-locrows a,
.hdr-locrows button {
  display: block; width: 100%;
  padding: 0.4rem 0.5rem; margin: 0;
  border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--muted); text-align: left; cursor: pointer;
  font: 500 0.875rem/1.2 var(--sans); text-decoration: none;
}
.hdr-locrows a:hover,
.hdr-locrows button:hover { background: color-mix(in oklab, var(--ink) 6%, var(--paper)); color: var(--ink); }
.hdr-locrows [aria-current] { color: var(--ink); font-weight: 600; }

/* ── SECTIONS ──────────────────────────────────────────────────────────────────────────────────── */

/* Same reason as above: by class. `main > section` matches nothing in the editor's preview. */
.hero,
.prose,
.feat,
.cta { padding-block: var(--s6); }

/* ── HERO ──────────────────────────────────────────────────────────────────────────────────────────
 *
 * ASYMMETRIC ON PURPOSE. The heading takes seven of twelve columns and the lead sits in the last four,
 * bottom-aligned to it — an editorial arrangement rather than a centred stack, and it fills the width the first
 * version left empty. Below 60rem it becomes one column, in reading order.
 */
.hero-in {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s4);
}
/* ── THE BACKGROUND PICTURE ────────────────────────────────────────────────────────────────────────
 *
 * A REAL <img> RATHER THAN A background-image, and that is the whole reason this rule exists. A CSS
 * background cannot carry `srcset`, so every phone would download the desktop file; it cannot be given
 * `loading`/`decoding`; and it is invisible to the preload scanner, so it starts downloading after the
 * stylesheet instead of with it. The hero picture is the largest thing on the page and usually the one the
 * page is waiting for.
 *
 * SO IT IS AN IMAGE PINNED BEHIND THE TEXT. `object-fit: cover` keeps the crop centred at every width, and
 * `inset: 0` with the section relative is what puts it under the content without taking part in the grid.
 *
 * AND THE TEXT IS MADE READABLE BY A WASH RATHER THAN BY HOPE. A photograph is light in places and dark in
 * others; without the overlay a white heading is legible on the version the designer looked at and gone on
 * the one a shop uploads. The wash is on the section, above the picture and below the words.
 */
.hero--has-image { position: relative; isolation: isolate; color: #fff; }
.hero-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; }
.hero--has-image::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to right, rgba(0, 0, 0, .55), rgba(0, 0, 0, .15));
}
/* THE LINK INHERITS, because a brand-coloured button on a photograph is the one control that disappears. */
.hero--has-image .hero-eyebrow { opacity: .9; }

/* «Tall» is MORE AIR, not a minimum height. A min-height with the content bottom-aligned to it leaves a dead
   band above the heading — which is what the first attempt did: half a screen of nothing, then the page. */
.hero--tall { padding-block: calc(var(--s6) * 1.1) var(--s6); }
@media (min-width: 60rem) {
  .hero-in {
    grid-template-columns: 7fr 4fr;
    gap: var(--s5);
    align-items: end;
  }
}

.hero-eyebrow {
  display: flex; align-items: center; gap: var(--s2);
  margin: 0 0 var(--s3);
  font: 600 0.75rem/1 var(--sans);
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--accent);
}
/* The rule earns its place: it ties the label to the grid it starts on. */
.hero-eyebrow::after {
  content: ''; flex: 1 1 auto; height: 1px; background: var(--line);
}

.hero-h {
  margin: 0;
  font: 400 clamp(2.5rem, 1.2rem + 5.2vw, 5rem)/1.02 var(--serif);
  letter-spacing: -0.03em;
  text-wrap: balance;
}
.hero-lead {
  margin: 0;
  font-size: 1.1875rem;
  line-height: 1.6;
  color: var(--muted);
  max-width: 40ch;
}
.hero-lead b, .hero-lead strong { color: var(--ink); font-weight: 600; }
.hero-cta { margin: var(--s3) 0 0; }

.btn {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.8rem 1.4rem;
  background: var(--accent); color: var(--paper);
  border-radius: 999px; text-decoration: none;
  font: 600 0.9375rem/1 var(--sans);
  transition: transform 120ms ease, background-color 120ms ease;
}
.btn:hover { background: color-mix(in oklab, var(--accent) 82%, var(--ink)); }
/* `.btn` IS WRITTEN FOR A LINK, and on a `<button>` the browser's own border showed round the pill — on the
   sign-in, sign-up, search and contact forms alike. Seen on the contact page's shot, 24 September 2026. */
button.btn { border: 0; cursor: pointer; }
.btn:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) { .btn { transition: none; } }
.btn--big { padding: 0.95rem 1.75rem; font-size: 1rem; }
.btn--ghost {
  background: transparent; color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--line);
}
.btn--ghost:hover { background: transparent; box-shadow: inset 0 0 0 1px var(--ink); }

/* ── PROSE ─────────────────────────────────────────────────────────────────────────────────────────
 *
 * A measured column, offset into the grid rather than centred: a body of text that starts where the heading
 * above it starts is easier to come back to than one floating in the middle of the page.
 */
.prose-in {
  display: grid;
  gap: var(--s3);
}
@media (min-width: 60rem) {
  .prose-in { grid-template-columns: 3fr 8fr; gap: var(--s5); }
  /* The heading becomes a margin note — the shape a reference page wants, and it costs nothing on narrow. */
  .prose-in > h2 { grid-column: 1; margin-top: 0.35rem; }
  .prose-in > .prose-body { grid-column: 2; }
}
.prose-in > h2 {
  margin: 0;
  font: 600 0.8125rem/1.4 var(--sans);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted);
}
.prose-body {
  max-width: var(--measure);
  font-size: 1.125rem;
}
.prose-body > :first-child { margin-top: 0; }
.prose-body > :last-child { margin-bottom: 0; }

/* ── FEATURES ─────────────────────────────────────────────────────────────────────────────────── */

.feat-h {
  margin: 0 0 var(--s5);
  font: 400 clamp(1.75rem, 1.2rem + 1.6vw, 2.5rem)/1.15 var(--serif);
  letter-spacing: -0.02em;
  text-wrap: balance;
  max-width: 28ch;
}
.feat-list {
  display: grid;
  gap: var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  margin: 0; padding: 0; list-style: none;
}
/* The author's choice of two, three or four, honoured above the breakpoint and ignored below it — a four-column
   grid on a phone is four one-word columns. */
@media (min-width: 60rem) {
  .feat-list { grid-template-columns: repeat(var(--cols, 3), 1fr); }
}
.feat-item {
  padding-top: var(--s3);
  border-top: 2px solid var(--accent);
}
.feat-item h3 {
  margin: 0 0 var(--s1);
  font: 600 1.0625rem/1.35 var(--sans);
  letter-spacing: -0.01em;
}
.feat-item p { margin: 0; color: var(--muted); font-size: 0.9375rem; }
.feat-item b, .feat-item strong { color: var(--ink); font-weight: 600; }

/* ── CTA ───────────────────────────────────────────────────────────────────────────────────────────
 *
 * THE ONE DARK BAND. A page needs a place where the eye stops, and one inversion does more than three tinted
 * boxes. It paints edge to edge while its text stays on the grid — which is the whole reason for the container
 * pattern at the top of this file.
 */
.cta {
  background: var(--ink);
  color: var(--paper);
}
.cta-in {
  display: grid; gap: var(--s4);
}
@media (min-width: 60rem) {
  .cta-in { grid-template-columns: 7fr 4fr; align-items: center; }
}
.cta-h {
  margin: 0 0 var(--s2);
  font: 400 clamp(1.875rem, 1.2rem + 2.2vw, 3rem)/1.1 var(--serif);
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.cta p { margin: 0; color: color-mix(in oklab, var(--paper) 72%, var(--ink)); max-width: 44ch; }
.cta .btn {
  background: var(--paper); color: var(--ink);
}
.cta .btn:hover { background: color-mix(in oklab, var(--paper) 85%, var(--accent)); }
.cta-act { justify-self: start; }
@media (min-width: 60rem) { .cta-act { justify-self: end; } }

/* ── FOOTER ────────────────────────────────────────────────────────────────────────────────────── */

.ftr { padding-block: var(--s4); border-top: 1px solid var(--line); }
.ftr-in {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s3) var(--s4);
  font-size: 0.875rem; color: var(--muted);
}
.ftr-line { margin: 0; margin-right: auto; }
.ftr-line b, .ftr-line strong { color: var(--ink); font-weight: 600; }
.ftr-nav { display: flex; flex-wrap: wrap; gap: var(--s3); }
.ftr-nav a { color: inherit; text-decoration: none; }
.ftr-nav a:hover { color: var(--ink); text-decoration: underline; }

/* ── DARK, IF THAT IS WHAT THE READER SET ──────────────────────────────────────────────────────────
 *
 * Only the four author tokens are swapped; everything else is derived from them, so the whole page follows. The
 * CTA band inverts with them and keeps being the one place the eye stops.
 */
@media (prefers-color-scheme: dark) {
  :root {
    --ink: #edeff3;
    --paper: #0f1114;
    --accent: #93a8f7;
  }
  .cta { background: color-mix(in oklab, var(--paper) 82%, var(--ink)); }
  .cta p { color: var(--muted); }
}

/* ═════════════════════════════════════════════════════════════════════════════════════════════════════════
 * THE SHOP — product cards, a product page, and the cart.
 *
 * BUILT ON THE FOUR TOKENS ABOVE AND ADDING NO FIFTH COLOUR. Everything below is the same ink, paper, accent
 * and measure an author already controls, so a shop that changes its accent changes its buy button, its
 * price, its focus ring and its drawer handle in one move. A theme that introduced a «product blue» would be
 * a theme whose settings stop working halfway down the page.
 *
 * ─────────────────────────────────────────────────────────────────────────────────────────────────────────
 * TYPE: TRACKING AND LEADING ARE SIZE-SPECIFIC, NEVER ONE VALUE
 * ─────────────────────────────────────────────────────────────────────────────────────────────────────────
 *
 * Letters read too far apart as they grow, so display sizes take NEGATIVE tracking and tighten their leading;
 * body copy sits near zero and breathes. A single `letter-spacing` on `:root` is wrong somewhere on every
 * page. Hierarchy is built from weight AND size AND leading as a set — weight adds presence without taking
 * more space, which is what a dense product grid needs.
 *
 * ─────────────────────────────────────────────────────────────────────────────────────────────────────────
 * MOTION: ONLY `transform` AND `opacity`, ALWAYS UNDER 300ms, NEVER `ease-in`
 * ─────────────────────────────────────────────────────────────────────────────────────────────────────────
 *
 * `ease-in` starts slow, which delays the exact moment a reader is watching most closely and reads as a
 * slower interface at the identical duration. Every transition here names its properties: `transition: all`
 * animates things nobody chose, including layout, and drops frames on the one page that must not.
 * ═════════════════════════════════════════════════════════════════════════════════════════════════════════ */

:root {
  /* A strong ease-out. The built-in curves are too weak to read as deliberate. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --press: 120ms;
  --lift: 200ms;
  --sheet: 260ms;

  --radius: 14px;
  --radius-sm: 10px;

  /* Depth, and only two steps. A third is a decision nobody can defend. */
  --shade-1: 0 1px 2px color-mix(in oklab, var(--ink) 8%, transparent);
  --shade-2: 0 12px 32px -12px color-mix(in oklab, var(--ink) 32%, transparent);
}

/* ── THE BUY BUTTON, AND EVERY BUTTON ────────────────────────────────────────────────────────────────
   RESPONSE IS THE FOUNDATION. Feedback lives on the PRESS rather than on the release: a button that waits
   for the click to acknowledge the finger feels dead, and that gap is the whole difference between an
   interface that feels direct and one that feels remote. */
.btn-buy {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5em;
  width: 100%;
  padding: 0.95em 1.4em;
  border: 0; border-radius: var(--radius-sm);
  background: var(--accent); color: var(--paper);
  font: 600 1rem/1 var(--sans);
  letter-spacing: 0.01em;
  cursor: pointer;
  box-shadow: var(--shade-1);
  transition: transform var(--press) var(--ease-out), background-color var(--press) var(--ease-out);
}
.btn-buy:hover { background: color-mix(in oklab, var(--accent) 92%, var(--ink)); }
.btn-buy:active { transform: scale(0.97); }
.btn-buy[disabled] { opacity: 0.5; cursor: not-allowed; transform: none; }

/* ── THE BUY BUTTON WHILE THE ADD IS IN FLIGHT ───────────────────────────────────────────────────────
   THIS IS WHERE THE PRESS IS ANSWERED, AND IT IS THE WHOLE REASON THE DRAWER NO LONGER OPENS ON THE
   PRESS. The panel is a receipt and arrives after the fact; the button is the thing under the finger and
   answers immediately. It dims and stops taking presses — no spinner, because the round trip is normally
   quicker than a spinner's first frame and a spinner that flashes reads as a stutter.

   IT DOES NOT SHRINK. `:active` already scales on the press; carrying that into the wait would leave the
   button visibly squashed for as long as the network takes, which reads as stuck rather than as busy. */
.btn-buy[data-busy] { opacity: 0.62; pointer-events: none; transform: none; }

.btn-quiet {
  display: inline-flex; align-items: center; gap: 0.4em;
  padding: 0.6em 1em;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: transparent; color: inherit;
  font: 500 0.95rem/1 var(--sans);
  cursor: pointer;
  transition: transform var(--press) var(--ease-out), border-color var(--press) var(--ease-out);
}
.btn-quiet:hover { border-color: color-mix(in oklab, var(--ink) 32%, var(--paper)); }
.btn-quiet:active { transform: scale(0.97); }

/* ── A PICTURE THAT IS NOT THERE ─────────────────────────────────────────────────────────────────────
   THE TILE KEEPS ITS SHAPE WHETHER OR NOT THERE IS AN IMAGE. `aspect-ratio` on the frame rather than a
   height on the image is what stops a grid reflowing as pictures load — the layout is settled before the
   first byte of any of them arrives. */
.ph {
  display: block; width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius);
  overflow: hidden;
  background: color-mix(in oklab, var(--ink) 4%, var(--paper));
}
.ph > img, .ph > svg { width: 100%; height: 100%; object-fit: cover; display: block; }
.ph--tall { aspect-ratio: 4 / 5; }

/* ── THE PRODUCT GRID ────────────────────────────────────────────────────────────────────────────────
   `auto-fill` AND A MINIMUM, so a shop with three products does not stretch them across a desktop and a
   shop with forty wraps without a breakpoint being named anywhere. */
/* ══ A FIXED NUMBER OF COLUMNS, NOT `auto-fill` ═══════════════════════════════════════════════
   MEASURED AT 1440px: `repeat(auto-fill, minmax(15rem, 1fr))` makes FIVE tracks in a 76rem container, so a
   band of three products filled three of them and left the right-hand two-fifths of the page empty. It
   reads as a page that failed to load rather than as a shop with three things in it.

   `auto-fit` is the other half-answer: it collapses the empty tracks, and then a band of ONE collection is
   a single card 1216 pixels wide.

   So the count is the SECTION'S, defaulting to four, with a floor of two on a phone — which is Shopify's
   own answer and is the only one that reads correctly at every count. `--cols` is set inline by whichever
   section drew the grid. */
.pgrid { display: grid; gap: var(--s3); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 44rem) { .pgrid { grid-template-columns: repeat(min(var(--cols, 4), 3), minmax(0, 1fr)); } }
@media (min-width: 66rem) { .pgrid { grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr)); } }

.pcard { display: flex; flex-direction: column; gap: 0.65rem; text-decoration: none; color: inherit; }
.pcard .ph { transition: transform var(--lift) var(--ease-out), box-shadow var(--lift) var(--ease-out); }
/* HOVER IS GATED ON A REAL POINTER. A touch device fires hover on tap, so an ungated lift sticks to
   whatever was last tapped and reads as a selection nobody made. */
@media (hover: hover) and (pointer: fine) {
  .pcard:hover .ph { transform: translateY(-3px); box-shadow: var(--shade-2); }
}
.pcard-title { font: 500 1.0625rem/1.35 var(--sans); letter-spacing: -0.005em; }
.pcard-price { font: 600 1rem/1.2 var(--sans); font-variant-numeric: tabular-nums; }
/* A PRODUCT WITH NO PRICE SAYS SO. Blank would read as free, and «0,00» would read as a promise. */
.pcard-noprice { font: 400 0.9375rem/1.2 var(--sans); color: var(--muted); }

/* ── THE PRODUCT PAGE ────────────────────────────────────────────────────────────────────────────────
   A BUILDER NOW: the section is a form around blocks, and a Group lays them out (see GROUPS below). What
   stays page-specific is the sticky buying column — on a tall screen the second column of the page's row
   keeps the price and the button reachable while the pictures scroll. */
.pbuild { display: grid; gap: var(--s4); }
@media (min-width: 48rem) {
  .pbuild > .grp--row > .grp--column { position: sticky; top: var(--s4); }
}

/* ── GROUPS ──────────────────────────────────────────────────────────────────────────────────────────
   THE LAYOUT BLOCK. A row splits by `layout`; a column stacks. Every row is one column under 48rem — the
   breakpoint is the theme's, not the author's, because four columns on a phone are four words wide. */
.grp { display: grid; gap: var(--gap, var(--s3)); min-width: 0; }
.grp > * { min-width: 0; }
.grp--gap-small { --gap: var(--s2); }
.grp--gap-medium { --gap: var(--s3); }
.grp--gap-large { --gap: var(--s5); }
.grp--column { align-content: start; }
@media (min-width: 48rem) {
  .grp--row { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
  .grp--row.grp--wide-first { grid-template-columns: minmax(0, 1.4fr); grid-auto-columns: minmax(0, 1fr); }
  .grp--row.grp--wide-last { grid-template-columns: minmax(0, 1fr); grid-auto-columns: minmax(0, 1.4fr); }
  .grp--row.grp--third-first { grid-template-columns: minmax(0, 1fr); grid-auto-columns: minmax(0, 2fr); }
  .grp--row.grp--align-center { align-items: center; }
  .grp--row.grp--align-end { align-items: end; }
}
.grp--pad { padding: var(--s4); border-radius: 6px; }
.grp--tone-soft { background: var(--wash); }
.grp--tone-dark { background: var(--ink); color: var(--paper); }
.grp--tone-dark .btn { background: var(--paper); color: var(--ink); }

/* ── THE SHARED BLOCKS ───────────────────────────────────────────────────────────────────────────────── */
.blk--center { text-align: center; justify-self: center; }
.blk-h { margin: 0; text-wrap: balance; letter-spacing: -0.02em; }
.blk-h--large { font: 400 clamp(2rem, 1.4rem + 2.4vw, 3.25rem)/1.08 var(--serif); }
.blk-h--medium { font: 400 clamp(1.5rem, 1.2rem + 1.2vw, 2.25rem)/1.15 var(--serif); }
.blk-h--small { font: 600 1.125rem/1.3 var(--sans); letter-spacing: -0.01em; }
.blk-text { margin: 0; max-width: var(--measure); color: color-mix(in oklab, currentColor 82%, transparent); }
.blk-text.blk--center { margin-inline: auto; }
.blk-text--large { font-size: 1.25rem; line-height: 1.5; }
.blk-text--small { font-size: 0.9375rem; }

/* ── A LINK INSIDE A PARAGRAPH, AND A LIST ─────────────────────────────────────────────
   Prose that came from somewhere else — a shop's pages, moved here — keeps its links and its lists. The link
   is the accent, underlined, because inside a sentence a colour alone is not a link to everybody. */
.blk-link { color: inherit; text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 0.15em; }
.blk-link:hover { color: var(--ink); }
.blk-list { margin: 0; padding-left: 1.25em; max-width: var(--measure); display: grid; gap: var(--s2); color: color-mix(in oklab, currentColor 82%, transparent); }
.blk-menu { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: baseline; }
.blk-btn { margin: 0; }
.blk-img { margin: 0; display: grid; gap: var(--s1); }
.blk-img img { width: 100%; height: auto; display: block; border-radius: 4px; background: var(--wash); }
.blk-img--square img { aspect-ratio: 1; object-fit: cover; }
.blk-img--portrait img { aspect-ratio: 4 / 5; object-fit: cover; }
.blk-img--landscape img { aspect-ratio: 3 / 2; object-fit: cover; }
.blk-img figcaption { font-size: 0.875rem; color: var(--muted); }
.blk-icon { margin: 0; display: flex; align-items: center; gap: 0.6em; }
.ico { width: 1.5rem; height: 1.5rem; flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.blk-space--small { height: var(--s2); }
.blk-space--medium { height: var(--s4); }
.blk-space--large { height: var(--s6); }
.blk-hr { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* A VIDEO IN ITS BOX — the shape is the author's, the fit is always «cover». */
.vid { position: relative; aspect-ratio: 16 / 9; background: var(--ink); border-radius: 4px; overflow: hidden; }
.vid--square { aspect-ratio: 1; }
.vid--tall { aspect-ratio: 9 / 16; max-height: 80vh; margin-inline: auto; }
.vid iframe, .vid video, .vid img { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; object-fit: cover; }

/* ── A STRIP THAT SNAPS — the product's pictures, and every carousel below ─────────────────────────────
   scroll-snap does the sliding, so a swipe works with no script; the arrows are theme.js's. */
.pgal2 { position: relative; display: grid; gap: var(--s2); }
.pgal2-track, .slides-track {
  display: grid; grid-auto-flow: column; grid-auto-columns: 100%;
  overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; overscroll-behavior-x: contain;
}
.pgal2-track::-webkit-scrollbar, .slides-track::-webkit-scrollbar { display: none; }
.pgal2-slide { margin: 0; scroll-snap-align: start; }
.pgal2-slide img { width: 100%; display: block; aspect-ratio: 4 / 5; object-fit: cover; border-radius: 4px; background: var(--wash); }
.pgal2--square .pgal2-slide img { aspect-ratio: 1; }
.pgal2-thumbs { display: grid; gap: var(--s1); grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr)); }
.pgal2-thumbs a { display: block; border-radius: 3px; overflow: hidden; outline-offset: 2px; }
.pgal2-thumbs img { width: 100%; aspect-ratio: 1; object-fit: cover; display: block; }
.slide-arrow {
  position: absolute; top: 40%; z-index: 1; width: 2.5rem; height: 2.5rem; border-radius: 50%;
  border: 1px solid var(--line); background: color-mix(in oklab, var(--paper) 88%, transparent);
  color: var(--ink); font: 400 1.5rem/1 var(--sans); cursor: pointer; display: grid; place-items: center;
}
.slide-arrow--prev { left: var(--s1); }
.slide-arrow--next { right: var(--s1); }
.slide-arrow:hover { background: var(--paper); }

.pmain-title {
  margin: 0 0 0.35em;
  font: 600 clamp(1.9rem, 4.2vw, 3rem)/1.06 var(--sans);
  /* NEGATIVE TRACKING AS IT GROWS — the one rule that separates a display size from a big body size. */
  letter-spacing: -0.022em;
  font-optical-sizing: auto;
  text-wrap: balance;
}
.pmain-price {
  margin: 0 0 var(--s3);
  font: 600 1.5rem/1.2 var(--sans);
  letter-spacing: -0.012em;
  font-variant-numeric: tabular-nums;
}
.pmain-body { max-width: var(--measure); color: color-mix(in oklab, var(--ink) 82%, var(--paper)); }
.pmain-body > :first-child { margin-top: 0; }

/* ── THE VARIANT PICKER ──────────────────────────────────────────────────────────────────────────────
   RADIOS, NOT A SELECT. Every choice is visible without opening anything, which is what a shop with three
   colours needs; the input stays a real radio so the keyboard and a screen reader get the grouping free. */
.vpick { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 var(--s3); padding: 0; border: 0; }
.vpick legend { padding: 0 0 0.5rem; font: 500 0.875rem/1 var(--sans); color: var(--muted); letter-spacing: 0.01em; }
.vpick label {
  position: relative;
  display: inline-flex; align-items: center;
  padding: 0.55em 0.95em;
  border: 1px solid var(--line); border-radius: 999px;
  font: 500 0.9375rem/1 var(--sans);
  cursor: pointer;
  transition: border-color var(--press) var(--ease-out), background-color var(--press) var(--ease-out),
    transform var(--press) var(--ease-out);
}
.vpick label:active { transform: scale(0.97); }
.vpick input { position: absolute; opacity: 0; pointer-events: none; }
.vpick label:has(input:checked) { border-color: var(--accent); background: var(--wash); font-weight: 600; }
/* THE FOCUS RING IS ON THE LABEL, because the input it belongs to is visually hidden. Without this the
   whole picker is invisible to a keyboard — the control works and nothing shows where you are. */
.vpick label:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── THE CART DRAWER ─────────────────────────────────────────────────────────────────────────────────
   A TRANSLUCENT LAYER OVER A DIMMED PAGE. The scrim is what says «this is a task, the page is waiting»;
   the material is what keeps the shop visible behind it so nobody loses their place.
   ENTER AND EXIT ALONG THE SAME PATH — in from the right, out to the right. A panel that arrived from one
   edge and left by another reads as two different objects. */
.drawer { position: fixed; inset: 0; z-index: 60; visibility: hidden; }
.drawer[data-open] { visibility: visible; }
.drawer-scrim {
  position: absolute; inset: 0;
  background: color-mix(in oklab, var(--ink) 42%, transparent);
  opacity: 0;
  transition: opacity var(--sheet) var(--ease-out);
}
.drawer[data-open] .drawer-scrim { opacity: 1; }
.drawer-panel {
  position: absolute; inset-block: 0; inset-inline-end: 0;
  width: min(26rem, 100%);
  display: flex; flex-direction: column;
  background: color-mix(in oklab, var(--paper) 86%, transparent);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  box-shadow: var(--shade-2);
  transform: translateX(100%);
  transition: transform var(--sheet) var(--ease-out);
}
.drawer[data-open] .drawer-panel { transform: translateX(0); }
.drawer-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
  padding: var(--s3) var(--s3) var(--s2);
}
.drawer-head h2 { margin: 0; font: 600 1.125rem/1.2 var(--sans); letter-spacing: -0.01em; }
.drawer-body { flex: 1; overflow-y: auto; padding: 0 var(--s3); }
.drawer-foot { padding: var(--s3); border-top: 1px solid var(--line); display: grid; gap: var(--s2); }
.drawer-total { display: flex; justify-content: space-between; font: 600 1.0625rem/1.2 var(--sans); font-variant-numeric: tabular-nums; }
/* THE DRAWER'S BLOCKS beyond the lines and the foot — the free-shipping bar, a note, a product to add. The
   bar is the native <progress>, labelled by its sentence, so it needs no role and no script to be read out. */
.drawer-ship { padding: var(--s2) var(--s3); border-top: 1px solid var(--line); display: grid; gap: 0.4em; }
.drawer-ship p { margin: 0; font: 500 0.9375rem/1.35 var(--sans); }
.drawer-ship progress { width: 100%; height: 0.4rem; accent-color: var(--accent); }
.drawer-note { margin: 0; padding: var(--s2) var(--s3); font: 0.9375rem/1.45 var(--sans); color: var(--ink); }
.drawer-pick { padding: var(--s2) var(--s3); border-top: 1px solid var(--line); display: grid; gap: var(--s1); }

.cline { display: grid; grid-template-columns: 3.5rem 1fr auto; gap: var(--s2); align-items: center; padding: var(--s2) 0; border-bottom: 1px solid var(--line); }
.cline:last-child { border-bottom: 0; }
.cline-name { font: 500 0.9375rem/1.35 var(--sans); }
.cline-meta { font: 400 0.875rem/1.35 var(--sans); color: var(--muted); font-variant-numeric: tabular-nums; }

/* ── AN EMPTY STATE, WHICH EVERY ONE OF THESE SECTIONS HAS ───────────────────────────────────────────
   A SHOP WITH NOTHING IN IT YET IS THE ORDINARY FIRST DAY, not an error. The section says what is not
   here and, where there is one, the control that changes it. Nothing is painted red. */
.shop-empty { padding: var(--s4) 0; text-align: center; color: var(--muted); }
.shop-empty p { margin: 0 auto; max-width: 42ch; }

/* ── AND THE THREE PREFERENCES, HONOURED RATHER THAN LISTED ──────────────────────────────────────────
   Reduced motion is not «no feedback»: the opacity that tells a reader something changed stays, and the
   movement that causes motion sickness goes. Reduced transparency makes the material solid rather than
   frosted — a translucent surface a reader cannot see through is worse than an opaque one. */
@media (prefers-reduced-motion: reduce) {
  .btn-buy, .btn-quiet, .vpick label, .pcard .ph { transition: opacity var(--press) ease; transform: none !important; }
  .drawer-panel { transition: opacity var(--sheet) ease; transform: none; opacity: 0; }
  .drawer[data-open] .drawer-panel { opacity: 1; }
}
@media (prefers-reduced-transparency: reduce) {
  .drawer-panel { background: var(--paper); backdrop-filter: none; -webkit-backdrop-filter: none; }
}
@media (prefers-contrast: more) {
  .pcard-title, .cline-name { font-weight: 600; }
  .drawer-panel { background: var(--paper); border-inline-start: 2px solid var(--ink); }
}

/* ═════════════════════════════════════════════════════════════════════════════════════════════════════════
 * THE SHOP'S OWN BANDS, ITS CART CHROME, AND THE COLLECTION HEAD
 * ═════════════════════════════════════════════════════════════════════════════════════════════════════════
 *
 * `.band` AND `.wrap` ARE THE SHOP'S EQUIVALENT OF `.hero` AND `.hero-in` and they exist because the
 * marketing bands above bake their own vertical rhythm into the section's own class name. A shop stacks
 * many bands of the same kind — three product grids on one front page — so the padding belongs to a band
 * rather than to whichever section happens to be in it.
 *
 * THEY WERE NAMED BY THREE SECTIONS BEFORE THEY WERE DESCRIBED, which is the estate's own rule pointed at
 * this file: a class a template names and the sheet does not have renders NOTHING, silently. Found by
 * grepping the sheet for what the sections wrote.
 * ═════════════════════════════════════════════════════════════════════════════════════════════════════════ */

.band { padding-inline: var(--gutter); padding-block: var(--s5); }
.band + .band { padding-block-start: 0; }
.wrap { max-width: var(--page); margin-inline: auto; }

/* THE HEADING ROW OF A BAND: the name at the left, one quiet link at the right. Shopify's own card header,
   one surface over — a title, and at most one place to go and see all of them. */
.band-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3);
  margin: 0 0 var(--s3);
}
.band-h {
  margin: 0;
  font: 600 clamp(1.375rem, 2.6vw, 1.875rem)/1.15 var(--sans);
  letter-spacing: -0.018em;
  text-wrap: balance;
}
.band-link { color: var(--muted); text-decoration: none; font-size: 0.9375rem; white-space: nowrap; }
.band-link:hover { color: var(--ink); text-decoration: underline; }

/* ── THE COLLECTION'S OWN HEAD ───────────────────────────────────────────────────────────────────────
   A title, a sentence, and the count. The count is a FACT and reads as one: tabular figures, muted, beside
   the words rather than under them. */
.chead { padding-inline: var(--gutter); padding-block: var(--s5) var(--s3); }
.chead-in { max-width: var(--page); margin-inline: auto; display: grid; gap: var(--s2); }
.chead-h {
  margin: 0;
  font: 600 clamp(1.75rem, 4.5vw, 2.75rem)/1.08 var(--sans);
  letter-spacing: -0.024em;
  text-wrap: balance;
}
.chead-count { margin: 0; color: var(--muted); font-size: 0.9375rem; font-variant-numeric: tabular-nums; }
.chead-body { margin: 0; max-width: var(--measure); color: color-mix(in oklab, var(--ink) 78%, var(--paper)); }
/* A description is paragraphs now (| richtext), so the last one keeps no margin below it. */
.chead-body > :last-child, .pmain-body > :last-child { margin-bottom: 0; }

/* ── THE CART BUTTON IN THE HEADER ───────────────────────────────────────────────────────────────────
   A COUNT THAT IS ZERO IS NOT DRAWN. An empty badge on every page is noise a reader learns to stop seeing,
   and then does not see it on the day it matters. The button stays; the badge arrives with the first item.

   THE BADGE IS `aria-hidden` IN THE MARKUP and the figure is in the button's own label instead, so a screen
   reader hears «Handlekurv, 2 varer» rather than «Handlekurv 2». */
.hdr-cart {
  position: relative;
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.4rem 0.75rem;
  border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: inherit; cursor: pointer;
  /* IT IS A BUTTON OR A LINK, decided by `settings.cart_type` — a drawer is pressed and a cart page is
     followed. One rule for both, so the two cannot drift apart; `text-decoration` is the only thing an
     anchor brings that a button does not. */
  text-decoration: none;
  font: 500 0.875rem/1 var(--sans);
  transition: border-color var(--press) var(--ease-out), transform var(--press) var(--ease-out);
}
.hdr-cart:hover { border-color: color-mix(in oklab, var(--ink) 30%, var(--paper)); }
.hdr-cart:active { transform: scale(0.97); }
.hdr-cart-n {
  min-width: 1.35rem; padding: 0 0.3rem;
  border-radius: 999px; background: var(--accent); color: var(--paper);
  font: 600 0.75rem/1.35rem var(--sans); text-align: center; font-variant-numeric: tabular-nums;
}

/* ── THE LINE'S QUANTITY STEPPER ─────────────────────────────────────────────────────────────────────
   THREE CONTROLS AND NOT AN `<input type=number>`. A spinner's arrows are four pixels tall on a phone, and
   a cart is the one place where changing a figure by one is the whole interaction. */
.qty { display: inline-flex; align-items: center; border: 1px solid var(--line); border-radius: 999px; }
.qty button {
  width: 1.9rem; height: 1.9rem;
  border: 0; background: transparent; color: inherit; cursor: pointer;
  font: 500 1rem/1 var(--sans);
  border-radius: 999px;
  transition: background var(--press) var(--ease-out), transform var(--press) var(--ease-out);
}
.qty button:hover { background: var(--wash); }
.qty button:active { transform: scale(0.9); }
.qty button[disabled] { opacity: 0.35; cursor: not-allowed; transform: none; }
.qty output { min-width: 1.6rem; text-align: center; font-variant-numeric: tabular-nums; font-size: 0.9375rem; }

/* THE LINE'S OWN PICTURE, and the remove control that is a word rather than an icon — «Fjern» is what an
   admin says, and a bin glyph beside a price is a guess about what it does. */
.cline .ph { border-radius: var(--radius-sm); }
.cline-rm {
  border: 0; background: transparent; padding: 0; cursor: pointer;
  color: var(--muted); font: 400 0.8125rem/1.4 var(--sans); text-decoration: underline;
}
.cline-rm:hover { color: var(--ink); }
.cline-side { display: grid; gap: 0.35rem; justify-items: end; }

/* ── AND WHAT THE DRAWER SAYS WHILE IT IS THINKING ───────────────────────────────────────────────────
   A cart redraw is one round trip and it is fast. The panel dims rather than emptying: a list that blanks
   and refills reads as a page reloading, and a reader who has just pressed «+» wants to see the figure they
   pressed it on. */
.drawer[data-busy] .drawer-body { opacity: 0.55; transition: opacity var(--press) ease; }
.drawer[data-busy] .qty button { pointer-events: none; }

/* THE «GÅ TIL KASSEN» SEAM, SAID ON THE SCREEN RATHER THAN IN A CONSOLE. Checkout is not built; the button
   below the total says so where somebody would press it, and the line is quiet rather than red because an
   unbuilt half is not an error. */
.drawer-seam { margin: 0; color: var(--muted); font-size: 0.8125rem; text-align: center; }

/* ═════════════════════════════════════════════════════════════════════════════════════════════════════════
 * THE PRODUCT PAGE AS A BUILDER, AND THE TWO CONTENT BANDS
 * ═════════════════════════════════════════════════════════════════════════════════════════════════════════
 *
 * ─────────────────────────────────────────────────────────────────────────────────────────────────────────
 * A BLOCK IS A ROW, AND THE RHYTHM BELONGS TO THE COLUMN RATHER THAN TO THE BLOCKS
 * ─────────────────────────────────────────────────────────────────────────────────────────────────────────
 *
 * Every block in the buy column is a `.pb`, and the spacing between them is the COLUMN's — a flex gap —
 * rather than a margin each block carries. That is the whole reason an author can drag them into any order
 * and the page still looks composed: with margins, «price above title» would collapse two margins into one
 * and «text, text, text» would stack three, and the rhythm would depend on the order.
 *
 * A FEW PAIRS GET THEIR OWN ANSWER, because they read as one thing rather than two: a price directly under
 * a title, and the small print directly under a price. `+` selectors, four of them, and no more.
 * ═════════════════════════════════════════════════════════════════════════════════════════════════════════ */

.pmain--flip { direction: rtl; }
.pmain--flip > * { direction: ltr; }

.pmain-buy > form { display: flex; flex-direction: column; gap: var(--s3); }
.pb { margin: 0; }
.pb > :first-child { margin-top: 0; }
.pb > :last-child { margin-bottom: 0; }

/* THE FOUR PAIRS THAT READ AS ONE THING. A title and the price under it are a heading and its figure; a
   price and its small print are one statement. Everything else keeps the column's own rhythm. */
.pb--pb_title + .pb--pb_price { margin-top: calc(var(--s3) * -0.55); }
.pb--pb_price + .pb--pb_text { margin-top: calc(var(--s3) * -0.5); }
.pb--pb_variants + .pb--pb_quantity { margin-top: calc(var(--s3) * -0.4); }
.pb--pb_fold + .pb--pb_fold { margin-top: calc(var(--s3) * -1); }

.pmain-title--md { font-size: clamp(1.375rem, 2.6vw, 1.875rem); letter-spacing: -0.018em; }

/* THE SMALL PRINT UNDER A PRICE OR A REFUSED BUTTON. Muted, one size down, and never red: «this has no
   price in this shop» is a fact about the shop's setup, not an error the reader caused. */
.pmain-note { margin: 0; color: var(--muted); font-size: 0.875rem; }
.pmain-line { margin: 0; color: color-mix(in oklab, var(--ink) 78%, var(--paper)); }
.pmain-sku { margin: 0; color: var(--muted); font-size: 0.8125rem; font-variant-numeric: tabular-nums; }

/* A VARIANT THIS CHANNEL DOES NOT PRICE — visibly off rather than absent. `not-allowed` is the cursor that
   says «this is a control and it is refusing», where `default` would say «this is not a control». */
.vpick label.vpick-off { opacity: 0.45; cursor: not-allowed; }
.vpick label.vpick-off:active { transform: none; }

/* ── HOW MANY ────────────────────────────────────────────────────────────────────────────────────────
   A number box, because this one IS typed into — unlike the cart's stepper. Narrow, because a quantity is
   at most three digits and a full-width box invites a postcode. */
.qtybox { display: grid; gap: 0.4rem; }
.qtybox > span { font: 500 0.875rem/1 var(--sans); color: var(--muted); letter-spacing: 0.01em; }
.qtybox input {
  width: 5.5rem; padding: 0.55rem 0.7rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--paper); color: inherit;
  font: 500 1rem/1.2 var(--sans); font-variant-numeric: tabular-nums;
}
.qtybox input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── A ROW THAT OPENS ────────────────────────────────────────────────────────────────────────────────
   A native `<details>`: the keyboard works, the state is announced, and there is no script to fail. The
   marker is rotated rather than replaced, so it keeps whatever the platform draws. */
.fold { border-top: 1px solid var(--line); }
.fold:last-of-type { border-bottom: 1px solid var(--line); }
.fold summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
  padding: 0.9rem 0; cursor: pointer; list-style: none;
  font: 500 1rem/1.3 var(--sans);
}
.fold summary::-webkit-details-marker { display: none; }
.fold summary::after {
  content: '+';
  font: 400 1.25rem/1 var(--sans); color: var(--muted);
  transition: transform var(--lift) var(--ease-out);
}
.fold[open] summary::after { transform: rotate(45deg); }
.fold-body { padding: 0 0 0.9rem; color: color-mix(in oklab, var(--ink) 78%, var(--paper)); }
.fold-body > :first-child { margin-top: 0; }
.fold-body > :last-child { margin-bottom: 0; }

/* ── WORDS ON THEIR OWN ──────────────────────────────────────────────────────────────────────────────
   Centred and NARROW. A full-width paragraph across a shop front is a paragraph nobody finishes; 60ch is
   about the line length reading research keeps landing on, and `text-wrap: balance` stops a heading
   breaking after one word. */
.rtext { max-width: 44rem; margin-inline: auto; text-align: center; display: grid; gap: var(--s2); }
.rtext--wide { max-width: 60rem; }
.rtext .band-h { text-wrap: balance; }
.rtext-body { color: color-mix(in oklab, var(--ink) 78%, var(--paper)); }
.rtext-body > :first-child { margin-top: 0; }
.rtext-body > :last-child { margin-bottom: 0; }
.rtext > p:last-child { margin: var(--s1) 0 0; }

/* ── A PICTURE BESIDE A SENTENCE ─────────────────────────────────────────────────────────────────────
   One column on a phone, two from 60rem. `direction: rtl` flips the pair without reordering the DOM, so
   the reading order and the tab order stay what the markup says whichever side the picture is on. */
.iwt { display: grid; gap: var(--s4); align-items: center; }
@media (min-width: 60rem) {
  .iwt { grid-template-columns: 1fr 1fr; gap: var(--s5); }
  .iwt--flip { direction: rtl; }
  .iwt--flip > * { direction: ltr; }
}
.iwt .ph { border-radius: var(--radius); }
.iwt-words { display: grid; gap: var(--s2); }
.iwt-words > p:last-child { margin: var(--s1) 0 0; }

/* ═════════════════════════════════════════════════════════════════════════════════════════════════════════
 * THE SHOP'S HERO — two shapes, because a shop with a photograph and one without are different pages
 * ═════════════════════════════════════════════════════════════════════════════════════════════════════════ */

.shero { padding-inline: var(--gutter); padding-block: var(--s5); position: relative; }
.shero-in { max-width: var(--page); margin-inline: auto; position: relative; }
.shero-words { display: grid; gap: var(--s2); max-width: 42rem; }

/* TIGHT WITHOUT A PICTURE. The first version was one shape and no picture, and it screenshotted as a
   heading with three hundred pixels of white under it. A hero is a promise about what is below it, and a
   long one delays the thing somebody came for. */
.shero-h {
  margin: 0;
  font: 400 clamp(2.25rem, 6vw, 4.25rem)/1.03 var(--serif);
  letter-spacing: -0.028em;
  text-wrap: balance;
}
.shero-lead {
  margin: 0;
  max-width: 40ch;
  font-size: clamp(1.0625rem, 1.4vw, 1.25rem);
  line-height: 1.55;
  color: color-mix(in oklab, var(--ink) 70%, var(--paper));
}
.shero-lead b, .shero-lead strong { color: var(--ink); font-weight: 600; }
.shero-acts { margin: var(--s2) 0 0; display: flex; flex-wrap: wrap; gap: 0.75rem; }
.shero--tall { padding-block: var(--s6) var(--s5); }

/* ── WITH A PICTURE: THE WORDS SIT ON IT ─────────────────────────────────────────────────────────────
   Full-bleed and tall, with the copy at the bottom left. The scrim is not decoration: white text on an
   unknown photograph is unreadable about a third of the time, and a gradient strongest exactly where the
   text is costs nothing and makes it readable every time. */
.shero--shot {
  display: grid; align-items: end;
  min-height: 32rem; padding-block: var(--s5);
  color: #fff; isolation: isolate;
}
.shero--shot.shero--tall { min-height: min(78svh, 46rem); }
.shero-media { position: absolute; inset: 0; z-index: -2; overflow: hidden; }
.shero-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shero--shot::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top, rgb(0 0 0 / 0.62) 0%, rgb(0 0 0 / 0.34) 38%, rgb(0 0 0 / 0) 72%);
}
.shero--shot .shero-h { font-weight: 400; }
.shero--shot .shero-lead { color: rgb(255 255 255 / 0.86); }
/* AND THE EMPHASIS INSIDE IT. `.shero-lead b` is `var(--ink)` on the plain hero, which is right — and on a
   photograph it is near-black on near-black, so the one word an author chose to stress is the one word
   nobody can read. Measured on the default art. */
.shero--shot .shero-lead b, .shero--shot .shero-lead strong { color: #fff; }
.shero--shot .hero-eyebrow { color: rgb(255 255 255 / 0.78); }
.shero--shot .hero-eyebrow::after { background: rgb(255 255 255 / 0.5); }
/* THE BUTTON ON A PHOTOGRAPH IS WHITE-ON-INK, because the accent may be any colour an operator chose and
   half of those disappear against a dark picture. */
.shero--shot .btn { background: var(--paper); color: var(--ink); }
.shero--shot .btn:hover { background: color-mix(in oklab, var(--paper) 88%, var(--ink)); }
.shero--shot .btn--ghost {
  background: transparent; color: #fff; box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.65);
}
.shero--shot .btn--ghost:hover { background: rgb(255 255 255 / 0.12); box-shadow: inset 0 0 0 1px #fff; }

@media (prefers-contrast: more) {
  /* A GRADIENT IS NOT ENOUGH FOR SOMEBODY WHO ASKED FOR CONTRAST. The picture stays; the scrim stops
     being a gradient and becomes a floor. */
  .shero--shot::after { background: rgb(0 0 0 / 0.62); }
}

/* ═════════════════════════════════════════════════════════════════════════════════════════════════════════
 * THE HEADER ON A PHONE — and it was pushing the whole document wider than the screen
 * ═════════════════════════════════════════════════════════════════════════════════════════════════════════
 *
 * MEASURED AT 430px: brand, menu, language switcher and the cart button sat in one non-wrapping flex row,
 * so the row's min-content width was wider than the viewport — and a document whose SCROLL width exceeds
 * the screen clips every band on the page at its right edge, not just the header. The product grid looked
 * like a card cut in half; the hero heading ran off; and none of it was the grid's or the hero's doing.
 *
 * THE HOUSE RULE IS EXPLICIT ABOUT IT — «the page body must never scroll horizontally» — and this is the
 * shape that breaks it: not a wide element, but a wide ROW nobody told to wrap.
 *
 * SO IT WRAPS, IN A DELIBERATE ORDER. The brand and the cart stay on the first line, because those are the
 * two a visitor reaches for; the menu takes the second line and may use all of it. `order` does that
 * without moving anything in the markup, so the tab order stays what the header says it is.
 * ═════════════════════════════════════════════════════════════════════════════════════════════════════════ */

.hdr-in { flex-wrap: wrap; row-gap: var(--s2); }
/* `min-width: 0` ON THE MENU is the other half. A flex item's default `min-width: auto` refuses to shrink
   below its content, which is exactly how a row of four links makes a document 500px wide. */
.hdr-nav { min-width: 0; }

@media (max-width: 47.99rem) {
  .hdr-in { column-gap: var(--s3); }
  .hdr-mark { order: 1; margin-right: auto; }
  .hdr-loc { order: 2; }
  /* SEARCH BESIDE LANGUAGE — same order, so the markup's own order decides between the two. An element
     missing from this list is order 0 and jumps in front of the brand, which is how this line was found. */
  .hdr-srch { order: 2; }
  .hdr-acct { order: 3; }
  .hdr-cart { order: 4; }
  /* THE MENU TAKES THE WHOLE SECOND LINE. `flex-basis: 100%` is what makes it a line rather than a
     leftover, so the links start at the gutter instead of wherever the row happened to break. */
  .hdr-nav { order: 5; flex-basis: 100%; margin-right: 0; gap: var(--s3); }
}

/* AND THE HERO'S DISPLAY TYPE IS CAPPED BY THE MEASURE IT IS IN. `text-wrap: balance` shapes a heading that
   fits; it does nothing for one that cannot. */
.shero-words { min-width: 0; }
.shero-h { overflow-wrap: break-word; }

/* ── THE CART'S OWN PAGE ─────────────────────────────────────────────────────────────────────────────
   NOT A SECOND CART — the same object, the same lines, the same three writes. What differs is the FORM: a
   drawer appears beside what you were doing, and this is a page you went to, so the lines are roomier and
   the total is a panel rather than a strip. */
.cartpage { display: grid; gap: var(--s4); align-items: start; margin-top: var(--s3); }
@media (min-width: 60rem) { .cartpage { grid-template-columns: 1fr 20rem; gap: var(--s5); } }
.cartpage-lines { display: grid; }
.cline--page { grid-template-columns: 5rem 1fr auto; gap: var(--s3); padding: var(--s3) 0; }
.cline--page .qty { margin-top: 0.4rem; }
.cartpage-sum {
  display: grid; gap: var(--s2);
  padding: var(--s3); border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--wash);
}
.cartpage-sum p { margin: 0; }
/* THE STEPPER ON THIS PAGE IS A FORM, so the buttons are submits. They must not look like the page's
   primary action — the `.qty` object already says what they are, and this keeps a browser's own button
   styling out of it. */
.qty button[type='submit'] { appearance: none; }

/* ── A CART LINE'S MIDDLE COLUMN IS A STACK, NOT A SENTENCE ──────────────────────────────────────────
   MEASURED: the name, the variant, the price and the stepper were four inline elements in one `<span>`, so
   a line read «Kanne SKU-1 329,00 kr [− 1 +]» as though it were prose. They are four different facts and
   the reader's eye needs them on four lines — which is also what makes the stepper hittable rather than
   wedged between two pieces of text. */
.cline-main { display: grid; gap: 0.3rem; justify-items: start; min-width: 0; }
.cline-main .cline-name { text-decoration: none; }
.cline-main .cline-name:hover { text-decoration: underline; }
.cline-side { align-self: start; }

/* ── THE ACCOUNT FORM ───────────────────────────────────────────────────────────────────────────────
   Narrow, centred and stacked: a sign-in box is two fields and a button, and a full-width row of them
   reads as a page that has lost its layout. The label sits above the input rather than beside it,
   because the labels here are one word and the inputs are the width of the column. */
.acct { max-width: 26rem; margin: 0 auto; }
.acct-lead { color: var(--muted); margin: 0 0 1.25rem; }
.acct-form { display: grid; gap: 1rem; }
.acct-row { display: grid; gap: .35rem; margin: 0; }
.acct-row label { font-size: .9rem; color: var(--muted); }
.acct-row input {
  width: 100%;
  padding: .6rem .7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--paper);
  color: inherit;
  font: inherit;
}
.acct-act { margin: .25rem 0 0; }
.acct-act .btn { width: 100%; justify-content: center; }
/* The way out of this page for somebody it is not for — to an account on the sign-in page, or back to the
   sign-in page from a new account. One line, centred under the box, and quieter than the button. */
.acct-alt { margin: 1rem 0 0; text-align: center; font-size: .9rem; }
/* What the door said about the last attempt. Above the fields, because it is about the whole form rather
   than about one of them, and in the page's own text colour on a tinted band: red type on white reads as a
   validation error the reader caused, and «that e-mail and password do not match» often is not one. */
/* THE ACCOUNT PAGE. Not inside `.acct`, which is 26rem wide because a sign-in form is two fields — a list
   of orders wants the page's own width, so this stack sits straight in the wrap. */
.acct-who { margin: 0 0 1rem; line-height: 1.5; }
.acct-tags { margin: 0 0 1.5rem; display: flex; flex-wrap: wrap; gap: .4rem; }
.acct-tag {
  font-size: .8125rem;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .15rem .6rem;
}
.acct-h2 { font-size: 1.125rem; margin: 2rem 0 .75rem; }
.acct-orders { list-style: none; margin: 0; padding: 0; }
.acct-order {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: .75rem 0;
  border-top: 1px solid var(--line);
}
.acct-order:last-child { border-bottom: 1px solid var(--line); }
.acct-order-sum { font-variant-numeric: tabular-nums; }
.acct-empty { color: var(--muted); margin: 0; }

.acct-row textarea {
  width: 100%;
  padding: .6rem .7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--paper);
  color: inherit;
  font: inherit;
  resize: vertical;
}
/* WHAT A SENT FORM SAYS IN ITS OWN PLACE — the contact form's thanks. The error's box, without the alarm. */
.acct-ok { margin: 0; padding: .6rem .7rem; border-radius: var(--radius); background: var(--wash); }

.acct-err {
  margin: 0;
  padding: .6rem .7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--wash);
  font-size: .95rem;
}

/* ── SLIDESHOW ───────────────────────────────────────────────────────────────────────────────────────
   Full width, the picture filling the slide and the words laid on it. The shade under the words is on the
   words' side only, so a light picture stays light where there is nothing to read. */
.band--flush { padding: 0; }
.band--flush > .wrap { padding: var(--s5) var(--gutter); }
.band--flush + .band { padding-block-start: var(--s5); }
/* A PLACEHOLDER PICTURE AT A READABLE SIZE — the icon in a soft box, never stretched to fill a slide or a stage. */
.ph-img { object-fit: contain !important; padding: 14%; box-sizing: border-box; background: var(--wash); opacity: 0.9; }
.look-img.ph-img { aspect-ratio: 16 / 9; }
.slides { position: relative; }
.slide { position: relative; scroll-snap-align: start; display: grid; min-height: 32rem; overflow: hidden; background: var(--wash); }
.slideshow--medium .slide { min-height: 24rem; }
.slideshow--full .slide { min-height: min(100svh, 56rem); }
.slide-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* THE PICTURE, THEN THE SHADE, THEN THE WORDS. The picture is later in the markup than `::before`, so without a
   stacking order it painted over the shade and white words sat on a bare photograph — seen on the placeholder,
   where they all but vanished (25 September 2026). */
.slide-words {
  position: relative; z-index: 2; align-self: end; display: grid; gap: var(--s2); max-width: 36rem;
  padding: var(--s5) var(--gutter); box-sizing: border-box;
}
.slide--center .slide-words { justify-self: center; text-align: center; justify-items: center; }
.slide--right .slide-words { justify-self: end; text-align: right; justify-items: end; }
.slide--light { color: #fff; }
.slide--light::before { content: ''; position: absolute; inset: 0; z-index: 1; background: linear-gradient(to top, rgb(0 0 0 / 0.5), transparent 65%); }
.slide--dark { color: #111; }
.slide-h { margin: 0; font: 400 clamp(2rem, 1.3rem + 2.8vw, 3.75rem)/1.05 var(--serif); letter-spacing: -0.02em; text-wrap: balance; }
.slide-text { margin: 0; font-size: 1.125rem; }
.slide-words p { margin: 0; }
.slide-dots { position: absolute; left: 0; right: 0; bottom: var(--s2); display: flex; justify-content: center; align-items: center; gap: 0.5rem; }
.slide-dots [data-slider-go] { width: 0.6rem; height: 0.6rem; padding: 0; border-radius: 50%; border: 1px solid rgb(255 255 255 / 0.9); background: rgb(255 255 255 / 0.35); cursor: pointer; }
.slide-dots [data-slider-go][aria-current] { background: #fff; }
.slide-pause { margin-left: var(--s1); border: 1px solid rgb(255 255 255 / 0.8); background: rgb(0 0 0 / 0.35); color: #fff; border-radius: 999px; padding: 0.2rem 0.7rem; font: 500 0.8125rem/1.4 var(--sans); cursor: pointer; }
.slides .slide-arrow { top: 50%; translate: 0 -50%; }

/* ── GALLERY, AND ITS VIEWER ─────────────────────────────────────────────────────────────────────── */
.gal-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); grid-template-columns: repeat(2, 1fr); }
@media (min-width: 48rem) { .gal-grid { grid-template-columns: repeat(var(--cols, 3), 1fr); } }
.gal-grid a { display: block; border-radius: 4px; overflow: hidden; }
.gal-grid img { width: 100%; aspect-ratio: 1; object-fit: cover; display: block; background: var(--wash); transition: scale var(--lift, 200ms) ease; }
.gal-grid a:hover img { scale: 1.03; }
.gal-cap { margin: 0.4em 0 0; font-size: 0.875rem; color: var(--muted); }
.lbox { border: 0; padding: 0; background: transparent; max-width: min(92vw, 70rem); max-height: 92vh; overflow: visible; }
.lbox::backdrop { background: rgb(0 0 0 / 0.82); }
.lbox figure { margin: 0; display: grid; gap: var(--s1); }
.lbox img { max-width: 100%; max-height: 84vh; object-fit: contain; display: block; margin-inline: auto; }
.lbox figcaption { color: #fff; text-align: center; font-size: 0.9375rem; }
.lbox-close, .lbox-step { position: fixed; border: 0; background: rgb(255 255 255 / 0.14); color: #fff; width: 2.75rem; height: 2.75rem; border-radius: 50%; font: 400 1.6rem/1 var(--sans); cursor: pointer; }
.lbox-close { top: var(--s3); right: var(--s3); }
.lbox-step { top: 50%; translate: 0 -50%; }
.lbox-step--prev { left: var(--s3); }
.lbox-step--next { right: var(--s3); }

/* ── TESTIMONIALS AND REVIEWS ────────────────────────────────────────────────────────────────────── */
.quotes--grid { display: grid; gap: var(--s4); grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr)); }
.quotes--carousel { position: relative; }
.quotes-track { grid-auto-columns: 100%; }
@media (min-width: 60rem) {
  .quotes-track { grid-auto-columns: calc((100% - 2 * var(--s4)) / 3); gap: var(--s4); }
  /* Three or fewer all fit in one row here, so arrows would move nothing. */
  .quotes--few .slide-arrow { display: none; }
}
.quote { margin: 0; display: grid; gap: var(--s3); align-content: space-between; padding: var(--s4); background: var(--wash); border-radius: 6px; scroll-snap-align: start; }
.quote blockquote { margin: 0; font: 400 1.25rem/1.45 var(--serif); letter-spacing: -0.01em; }
.quote figcaption { display: flex; align-items: center; gap: var(--s2); font-size: 0.9375rem; color: var(--muted); }
.quote figcaption b { color: var(--ink); font-weight: 600; }
.quote figcaption img { width: 2.75rem; height: 2.75rem; border-radius: 50%; object-fit: cover; }
.quotes--carousel .slide-arrow { top: auto; bottom: calc(-1 * var(--s4) - 0.5rem); }
.quotes--carousel .slide-arrow--prev { left: auto; right: 3.25rem; }
.quotes--carousel .slide-arrow--next { right: 0; }
.stars { margin: 0; display: inline-block; font-size: 1.05rem; letter-spacing: 0.1em; line-height: 1;
  background: linear-gradient(90deg, var(--accent) calc(var(--r, 0) / 5 * 100%), var(--line) 0);
  -webkit-background-clip: text; background-clip: text; color: transparent; }
.rev-sum { display: flex; align-items: center; gap: var(--s1); margin: 0 0 var(--s4); font-weight: 500; }
.revs { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s3); grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); }
.rev { display: grid; gap: var(--s1); padding: var(--s3); border: 1px solid var(--line); border-radius: 6px; align-content: start; }
.rev-text, .rev-who { margin: 0; }
.rev-who { font-size: 0.875rem; color: var(--muted); }
.rev-who b { color: var(--ink); font-weight: 600; }

/* ── LOGOS ───────────────────────────────────────────────────────────────────────────────────────── */
.logos { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--s4) var(--s5); }
.logos img { max-height: 3rem; max-width: 9rem; width: auto; display: block; }
.logos--grey img { filter: grayscale(1); opacity: 0.7; transition: filter 200ms, opacity 200ms; }
.logos--grey a:hover img { filter: none; opacity: 1; }

/* ── FAQ ─────────────────────────────────────────────────────────────────────────────────────────── */
.faq { max-width: 48rem; }

/* ── MULTICOLUMN ─────────────────────────────────────────────────────────────────────────────────── */
.mcol { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s4); grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); }
@media (min-width: 60rem) { .mcol { grid-template-columns: repeat(var(--cols, 3), 1fr); } }
.mcol-item { display: grid; gap: var(--s1); align-content: start; }
.mcol-item h3 { margin: var(--s1) 0 0; font: 600 1.0625rem/1.35 var(--sans); }
.mcol-item p { margin: 0; color: var(--muted); font-size: 0.9375rem; }
.mcol-img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 4px; }
.mcol-ico { display: inline-grid; place-items: center; width: 3rem; height: 3rem; border-radius: 50%; background: var(--wash); color: var(--accent); }

/* ── SCROLLING TEXT ──────────────────────────────────────────────────────────────────────────────── */
.marquee { overflow: hidden; border-block: 1px solid var(--line); padding-block: var(--s2); }
.marquee-track { display: flex; width: max-content; animation: marquee var(--speed, 30s) linear infinite; }
.marquee--right .marquee-track { animation-direction: reverse; }
.marquee--slow { --speed: 50s; }
.marquee--fast { --speed: 16s; }
.marquee ul { display: flex; list-style: none; margin: 0; padding: 0; }
.marquee li { padding-inline: var(--s4); white-space: nowrap; font: 500 1.125rem/1.3 var(--sans); }
.marquee li::after { content: '·'; margin-left: var(--s4); color: var(--muted); }
.marquee--large li { font: 400 clamp(1.75rem, 1rem + 3vw, 3rem)/1.1 var(--serif); letter-spacing: -0.02em; }
.marquee:hover .marquee-track, .marquee:focus-within .marquee-track { animation-play-state: paused; }
@keyframes marquee { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee-track { animation: none; } .marquee { overflow-x: auto; } }

/* ── VIDEO SECTION ───────────────────────────────────────────────────────────────────────────────── */
.vsec { display: grid; gap: var(--s3); }
.vsec-text { margin: var(--s1) 0 0; color: var(--muted); max-width: var(--measure); }

/* ── BEFORE / AFTER ──────────────────────────────────────────────────────────────────────────────────
   The second picture is clipped from the left at --pos; the range sits invisibly over the whole picture so
   a press anywhere moves the handle, and the line shows where it is. */
.ba { position: relative; overflow: hidden; border-radius: 6px; aspect-ratio: 3 / 2; background: var(--wash); }
.ba-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ba-img--after { clip-path: inset(0 0 0 var(--pos, 50%)); }
.ba-img--ph { filter: hue-rotate(40deg) saturate(1.4); }
.ba-line { position: absolute; top: 0; bottom: 0; left: var(--pos, 50%); width: 2px; translate: -1px 0; background: #fff; box-shadow: 0 0 0 1px rgb(0 0 0 / 0.15); pointer-events: none; }
.ba-line::after { content: '⟷'; position: absolute; top: 50%; left: 50%; translate: -50% -50%; width: 2.5rem; height: 2.5rem; display: grid; place-items: center; border-radius: 50%; background: #fff; color: #111; font-size: 1rem; box-shadow: 0 1px 4px rgb(0 0 0 / 0.25); }
.ba-range { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: ew-resize; }
.ba-range:focus-visible + .ba-line, .ba:has(.ba-range:focus-visible) .ba-line { outline: 2px solid var(--accent); }
.ba-label { position: absolute; top: var(--s2); padding: 0.2rem 0.6rem; border-radius: 999px; background: rgb(0 0 0 / 0.55); color: #fff; font: 500 0.8125rem/1.4 var(--sans); pointer-events: none; }
.ba-label--before { left: var(--s2); }
.ba-label--after { right: var(--s2); }

/* ── SHOP THE LOOK ───────────────────────────────────────────────────────────────────────────────── */
.look { position: relative; }
.look-img { width: 100%; display: block; border-radius: 6px; background: var(--wash); }
.look-dot { position: absolute; width: 1.75rem; height: 1.75rem; translate: -50% -50%; border-radius: 50%; border: 3px solid #fff; background: var(--accent); box-shadow: 0 0 0 6px rgb(255 255 255 / 0.35); cursor: pointer; }
.look-dot:hover { scale: 1.1; }
.look-pop { border: 1px solid var(--line); border-radius: 8px; padding: var(--s3); width: min(18rem, 86vw); background: var(--paper); color: var(--ink); box-shadow: 0 10px 40px rgb(0 0 0 / 0.18); }
.look-pop::backdrop { background: rgb(0 0 0 / 0.2); }

/* ── COLLECTION TABS ─────────────────────────────────────────────────────────────────────────────────
   No script: no strip, every panel with its own heading. With it: the strip, and one panel. */
.ctabs-list { display: none; gap: var(--s1); flex-wrap: wrap; margin-bottom: var(--s4); }
.ctabs.is-js .ctabs-list { display: flex; }
.ctabs.is-js .ctabs-h { display: none; }
.ctabs-list [role="tab"] { border: 1px solid var(--line); background: transparent; color: var(--ink); border-radius: 999px; padding: 0.45rem 1rem; font: 500 0.9375rem/1.3 var(--sans); cursor: pointer; }
.ctabs-list [role="tab"][aria-selected="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.ctabs-panel + .ctabs-panel { margin-top: var(--s5); }
.ctabs.is-js .ctabs-panel + .ctabs-panel { margin-top: 0; }
.ctabs-h { margin: 0 0 var(--s3); font: 600 1.125rem/1.3 var(--sans); }

/* ── COMPARISON TABLE ────────────────────────────────────────────────────────────────────────────── */
.cmp-scroll { overflow-x: auto; }
.cmp { width: 100%; border-collapse: collapse; min-width: 32rem; font-variant-numeric: tabular-nums; }
.cmp th, .cmp td { padding: 0.8rem var(--s2); border-bottom: 1px solid var(--line); text-align: center; }
.cmp th[scope="row"] { text-align: left; font-weight: 500; }
.cmp thead th { font: 600 1rem/1.3 var(--sans); border-bottom: 2px solid var(--ink); }
.cmp tbody tr:nth-child(even) { background: var(--wash); }

/* ── SECTION (EMPTY, TO BUILD IN) ────────────────────────────────────────────────────────────────── */
.sec--soft { background: var(--wash); }
.sec--dark { background: var(--ink); color: var(--paper); }
.sec--dark .btn { background: var(--paper); color: var(--ink); }
.sec-wrap { display: grid; gap: var(--s3); }
.sec-wrap--narrow { max-width: 44rem; }
.sec-wrap--full { max-width: none; }
.sec-body { display: grid; gap: var(--s3); }

/* ── SEARCH ─────────────────────────────────────────────────────────────────────────────────────────
   THE FIELD AND ITS BUTTON ON ONE ROW, the field taking what is left. The same input as the account forms
   (`.acct-row input`), so a shop has one look for «type here». The header's copy lives in the language
   popover's own panel, widened to hold a field rather than a list. */
.srch { display: grid; gap: var(--s3); max-width: 40rem; margin-bottom: var(--s5); }
.srch-form { display: flex; gap: var(--s2); }
.srch-input {
  flex: 1; min-width: 0;
  padding: .6rem .7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--paper);
  color: inherit;
  font: inherit;
}
.srch-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.srch-count { margin: 0; color: var(--muted); font-size: 0.9375rem; font-variant-numeric: tabular-nums; }
.srch-next { margin-top: var(--s5); }
.hdr-srch { display: flex; }

/* ── THE NEWSLETTER SIGNUP — the search field's row, a line of text above and the consent line below ──── */
.nl { display: grid; gap: var(--s3); max-width: 40rem; }
.nl-body > :last-child { margin-bottom: 0; }
.nl-form { display: grid; gap: var(--s2); }
.nl-consent { margin: 0; color: var(--muted); font-size: 0.875rem; }
.hdr-srchpop { width: min(26rem, calc(100vw - 2 * var(--gutter))); }
