/* ZS R3 FOUNDATION, LC-R3 MERGED (r3-tokens.css). ZS's own code; the single source for the merged type system, tone planes,
   the one photo grade, motion tokens and the shared components. The spec is evidence/r3/final/BIBLE_R3.md; read it first.
   Base = direction C "Proof Stage" (panel 1 winner). Round-2 foundation changes (architect), all listed in BIBLE_R3 section "foundation changes":
     F1 Growth plane: indigo night -> neutral graphite (--r3-c-graphite; night stays as a deprecated alias)
     F2 tier colour (--tier) re-declared inside every dark/paper plane (a custom property is computed where it is declared)
     F3 every plane has a flat fallback colour; the oklab blend is an enhancement behind @supports; svh/dvh have vh fallbacks
     F4 ONE price style: Cormorant 600 lining (was Space Grotesk); Space Grotesk digits come from Inter (R3 Figures) so "1" is clean
     F5 metric-matched fallback faces (size-adjust) so the font swap does not move the page (CLS)
     F6 [data-plane] auto neighbours (A's seam discipline) and the warm bridge for ink <-> cream
     F7 light-theme contrast: tier numerals, price units, wash tokens instead of color-mix on text backgrounds
   Previous header (direction C):

   RULES THIS FILE FOLLOWS
   - Everything is namespaced: classes r3-*, custom properties --r3-*. The example sites load this file too (their own stylesheets
     define --bg, --ink, ...), so nothing here restyles a bare element or a non-r3 class, except the clearly marked NEUTRALISERS block
     at the end, which only removes things David's tone rule bans (hairline ornaments) and only on the ZS pages that load zs-editorial.css.
   - Hidden start states hang on html.lib-on (set in <head> only while motion is allowed). html.no-motion (reduced motion or the page's
     motion toggle) always leaves the composed page fully visible. Without r3-core.js every component is in its composed rest state.
   - Only transform / opacity / clip-path are animated on scroll. Never a layout property.
   - Light and dark theme: tokens come from zs-editorial.css (:root, [data-theme="light"]) and are never redefined here, only extended.
   Order of sections: 1 tokens, 2 type, 3 buttons and links, 4 price and tier mark, 5 tone planes, 6 photo grade, 7 devices (the stage),
   8 stage layouts, 9 switcher and chips, 10 word index, 11 arc, 12 belt, 13 ledger and spec, 14 aside and dock, 15 compare,
   16 scroll-ink, 17 reveal, 18 ending plates, 19 neutralisers, 20 reduced motion (last on purpose). */

/* ================================ 0. FONT FACES (F4, F5) ================================ */
/* F4: Space Grotesk's "1" has a long flag ("1 499", "1 sida", "01" read as a stray accent). Digits of the display family come from Inter
   instead: a digits-only face (unicode-range U+0030-0039) that reuses the Inter file already in the tree. No new asset, no extra request
   (inter-500 is loaded by every page). Letters keep Space Grotesk. */
@font-face { font-family: "R3 Figures"; src: url("fonts/inter-500.woff2") format("woff2"); font-weight: 400 600; font-display: swap; unicode-range: U+0030-0039; }
/* F5: metric-matched fallbacks. The first paint uses these (size-adjust + ascent/descent overrides measured in Chrome with
   evidence/r3/final/tools/measure_fonts.cjs), so when the webfont arrives the text does not reflow (this was the layout shift at load on desktop). */
@font-face { font-family: "ZS Grotesk Fallback"; src: local("Arial Bold"), local("Helvetica Bold"), local("Liberation Sans Bold"); font-weight: 400 600; size-adjust: 100.04%; ascent-override: 97.92%; descent-override: 28.95%; line-gap-override: 0%; }
@font-face { font-family: "ZS Grotesk Fallback"; src: local("Arial Bold"), local("Helvetica Bold"), local("Liberation Sans Bold"); font-weight: 700; size-adjust: 101.3%; ascent-override: 96.6%; descent-override: 28.5%; line-gap-override: 0%; }   /* FXF 7: was 103 / 95 / 28: re-measured over 245 real strings of the site (Space Grotesk 700 is 1.7 % narrower than the old fallback; the bold words of the /om statement re-wrapped it at 1440 = CLS 0.136), tools FXF/fallback_corpus.cjs */
@font-face { font-family: "ZS Inter Fallback"; src: local("Arial"), local("Helvetica"), local("Liberation Sans"); font-weight: 400; size-adjust: 107.56%; ascent-override: 90.13%; descent-override: 22.28%; line-gap-override: 0%; }
@font-face { font-family: "ZS Inter Fallback"; src: local("Arial"), local("Helvetica"), local("Liberation Sans"); font-weight: 500; size-adjust: 106.35%; ascent-override: 91.16%; descent-override: 22.59%; line-gap-override: 0%; }
@font-face { font-family: "ZS Inter Fallback"; src: local("Arial Bold"), local("Helvetica Bold"), local("Liberation Sans Bold"); font-weight: 600 700; size-adjust: 100.25%; ascent-override: 96.71%; descent-override: 23.9%; line-gap-override: 0%; }
@font-face { font-family: "ZS Serif Fallback"; src: local("Times New Roman"), local("Times"), local("Liberation Serif"); font-weight: 400 500; size-adjust: 97.16%; ascent-override: 94.66%; descent-override: 29.8%; line-gap-override: 0%; }
@font-face { font-family: "ZS Serif Fallback"; src: local("Times New Roman Bold"), local("Times Bold"), local("Liberation Serif Bold"); font-weight: 600 700; size-adjust: 93.75%; ascent-override: 98.2%; descent-override: 30.96%; line-gap-override: 0%; }

/* FXF round 2 (F-07): six fallback faces were re-fitted on the LAYOUT, not on single strings. For 11 routes x 19 window sizes (360x740 to 1920x1080) the first-screen boxes with the
   real fonts were compared with the fallback-only layout and scored like a layout shift (impact x distance; captures/fix2_FXF/tools/fit_fallback.cjs); the sum over all routes and
   sizes fell from 0.60 to 0.20. Grotesk 400-600: size-adjust 109.7 -> 100.0 and base font Arial -> Arial Bold (same availability list; the per-word error against Space Grotesk 500
   drops from 6.1 % to 4.3 %), Inter 400 107 -> 107.6, Inter 500 108.2 -> 106.4, Inter 600-700 101.1 -> 100.3, Serif 400-500 96.2 -> 97.2, Serif 600-700 90.7 -> 93.8. Ascent and
   descent overrides are percentages of the size-adjusted size, so they were rescaled (old / new size-adjust) to keep every face's effective ascent and descent: a first run that left
   them alone put the lines 1 to 3 px off. A scale cannot remove a flip that sits inside the per-word error of the fallback (3 to 6 % per word, whichever system font is used), so the
   one block that is a long run of display type, the scroll-ink statement, is set in a copy of the face with font-display: block (it sits below the hero on every page that has one).
   While the file is on its way the statement is invisible (the fallback is laid out but not painted; r3-core.js also holds it until BOTH weights are in) and it appears once, already
   in Space Grotesk, so it can never re-wrap in front of the reader (/om shifted 0.09 to 0.15). font-display: optional was tried first and rejected: Chrome only uses an optional
   face that is already decoded at the first layout, which left the statement in Arial on every first visit, also on loopback. */
@font-face { font-family: "R3 Statement"; src: url("fonts/space-grotesk-500.woff2") format("woff2"); font-weight: 500; font-display: block; }
@font-face { font-family: "R3 Statement"; src: url("fonts/space-grotesk-700.woff2") format("woff2"); font-weight: 700; font-display: block; }

/* ================================ 1. TOKENS ================================ */
:root {
  /* families: the same three self-hosted faces; the roles are fixed in BIBLE_R3 section b. The ZS base tokens --f-display / --f-text / --f-serif are
     extended here (digits face first, fallbacks last) so every older stylesheet that reads them heals too. */
  --f-display: "R3 Figures", "Space Grotesk", "ZS Grotesk Fallback", "Inter", system-ui, sans-serif;
  --f-text: "Inter", "ZS Inter Fallback", system-ui, sans-serif;
  --f-serif: "Cormorant Garamond", "ZS Serif Fallback", Georgia, serif;
  --r3-f-display: var(--f-display);
  --r3-f-text: var(--f-text);
  --r3-f-serif: var(--f-serif);

  /* shared type steps (not tier scoped) */
  --r3-t-micro: .8125rem;                                  /* 13  label, meta (b6: the floor for functional text) */
  --r3-t-small: .875rem;                                  /* 14  caption, note, unit, spec */
  --r3-t-body: 1.0625rem;                                 /* 17  body */
  --r3-t-lead: clamp(1.1875rem, 1.08rem + .45vw, 1.4rem); /* 19 -> 22 */
  --r3-t-h4: clamp(1.2rem, 1.1rem + .5vw, 1.5rem);        /* item titles */
  --r3-t-h3: clamp(1.5rem, 1.25rem + 1.1vw, 2.2rem);      /* block titles */
  /* tier scoped steps: default = Growth ("M"); .tier-starter and .tier-premium re-scope them below.
     vh values are the fallback; the svh versions are re-declared in the @supports block after the tier scopes (F3). */
  --r3-t-h1: min(clamp(2.7rem, min(1.7rem + 4.4vw, 11.5vh), 5.25rem), 13.5vw);      /* 43 -> 84; never taller than 11.5 % of the window (short windows); b6 fix60: never wider than the 320 px / 100 % size per vw, so larger text cannot cut a long word */
  --r3-t-h2: min(clamp(2rem, 1.45rem + 2.4vw, 3.4rem), 10vw);        /* 32 -> 54 */
  --r3-lh-h1: 1; --r3-lh-h2: 1.06; --r3-ls-h1: -.035em; --r3-ls-h2: -.028em;
  --r3-fam-h: var(--r3-f-display); --r3-w-h: 500;
  /* THE PRICE (F4): ONE style everywhere, Cormorant 600 lining, a plain Inter unit on the same baseline. Sizes: l hero, m card/aside, s dock/tag/table */
  --r3-f-price: var(--r3-f-serif); --r3-w-price: 600; --r3-ls-price: -.02em;
  --r3-price-l: clamp(3.6rem, 2.4rem + 3.9vw, 6.2rem);    /* 58 -> 99 */
  --r3-price-m: clamp(2.9rem, 2.3rem + 1.9vw, 4rem);      /* 46 -> 64 */
  --r3-price-s: 2.5rem;                                   /* 40 */
  /* merged type system (R's editorial scale), consumed by the r3a-* components (r3-graft-press.css) and by Premium page rules */
  --r3-t-poster: clamp(4.25rem, .9rem + 14.4vw, 14.5rem);  /* 68 -> 232: poster word, ghost chapters (never the hero H1 on a photo) */
  --r3-t-statement: clamp(1.75rem, 1rem + 2.9vw, 3.75rem); /* 28 -> 60 scroll-ink statements */
  --r3-t-num: clamp(4rem, 2.4rem + 6.4vw, 9rem);           /* 64 -> 144 chapter numeral (N2) */
  --r3-t-ghost: clamp(9rem, 38vw, 28rem);                  /* ghost numeral / word behind a heading */
  --r3-t-fig: clamp(5.5rem, 3rem + 10vw, 12rem);           /* 88 -> 192 batch figures 1 / 4 / 30 */
  --r3-t-mail: clamp(1.5rem, 1rem + 2.2vw, 2.5rem);     /* RC2 (David N003): 24 -> 40 sign-off e-mail (was 28 -> 92) */
  --r3-t-kicker: clamp(.875rem, .66rem + .62vw, 1.3125rem);/* 14 -> 21 tracked-serif kicker */

  /* spacing */
  --r3-sec: 56px;           /* gap between blocks inside one plane (phone) */
  --r3-fade: 96px;          /* tone blend length (phone) */
  --r3-radius: 14px; --r3-radius-l: 22px;
  --r3-edge: var(--gutter, 16px);

  /* tone planes (F1, F3): raw colours; theme aware ones follow the page theme. EVERY plane is also a flat colour (no gradient needed to read).
     Dark planes (void, graphite, walnut) are dark in BOTH themes and re-scope the text tokens; paper is light in both. Contrast numbers: BIBLE_R3 c. */
  --r3-c-page: var(--page-bg, #0C0C0F);
  --r3-c-lift: #151518;      /* page + one step: quiet second plane (Starter, Growth ledgers, home ladder) */
  --r3-c-void: #0C0C0F;      /* always dark: full-stop band, stage plane, photo floor */
  --r3-c-graphite: #222125;  /* Growth's stage plane (replaces the indigo night): neutral graphite, no hue, dark in both themes */
  --r3-c-night: var(--r3-c-graphite);   /* DEPRECATED alias: the old violet-ink plane no longer exists; old markup lands on graphite */
  --r3-c-walnut: #221913;    /* Premium's plane: ink with a walnut cast (sampled from the candle table), dark in both themes */
  --r3-c-paper: #EDE7DA;     /* light plane, light in both themes: Starter's full stop, cream cards */
  --r3-floor: #0C0C0F;       /* photographs always bottom out here (the one grade's black point); examples override it */
  /* washes: a quiet fill that works on every plane without color-mix (F7) */
  --r3-wash: rgba(243, 240, 234, .09); --r3-wash-2: rgba(243, 240, 234, .15);

  /* tier signatures (the colour that means the tier; --tier itself comes from zs-editorial.css) */
  --r3-glow: 216, 210, 198;  /* rgb triple of the tier glow behind a device */
  --r3-bloom-rgb: 158, 118, 86;   /* FXL fix round 2 (F-11): was 200,146,88 (khaki on grey); walnut-amber oklch(.60 .06 62), the tinted midpoint of a dark <-> light hand-off, see section 5 */

  /* motion tokens. Durations/easings come from the library study; sources in BIBLE_R3 section e */
  --r3-ease: var(--lib-ease, cubic-bezier(.2, .7, .1, 1));       /* ZS lib easing (reveals, settles) */
  --r3-ease-out: cubic-bezier(.25, .46, .45, .94);               /* ease-out-quad: henecon rows .4s, inflouno stage .5s power1.out */
  --r3-ease-in: cubic-bezier(.22, .61, .36, 1);                  /* relab incoming crossfade (power2.out) */
  --r3-ease-io: cubic-bezier(.45, 0, .55, 1);                    /* relab outgoing crossfade (power2.inOut) */
  --r3-ease-quart: cubic-bezier(.165, .84, .44, 1);              /* outQuart: label roll, headline rise (W-76, W-39) */
  --r3-d-micro: .2s;        /* hover, press, focus (Pierce 0.2 s) */
  --r3-d-swap: .35s;        /* crossfade between panels (relab 350 ms) */
  --r3-d-ui: .4s;           /* row flood, chip ring (henecon .4s) */
  --r3-d-glide: .9s;        /* device glide to a beat, arc step (own value on --r3-ease) */
  --r3-d-reveal: .9s;       /* rise / settle (tier scoped) */
  --r3-d-sig: 0s;           /* the tier's one slow signature move (G-49: Starter none, Growth 1.6 s, Premium 2.1 s) */
  --r3-stagger: 45ms;       /* group cascade step (Mythos00 0.07-0.08 s on belts, 75 ms on triads) */
  --r3-rise: 16px;
  --r3-z-dock: 40; --r3-z-aside: 30; --r3-z-stage: 2;
}
@media (min-width: 768px) { :root { --r3-sec: 72px; --r3-fade: 120px; } }
@media (min-width: 1100px) { :root { --r3-sec: 88px; --r3-fade: 140px; } }

[data-theme="light"] {
  --accent: #4B2EC6;         /* F7: the light-theme violet, 7.4 : 1 on cream and 5.7 : 1 on a card wash (the brand #5236D6 measured 4.0 on the home belt card); dark theme keeps #A48FFF */
  --r3-c-lift: #EAE5DC;
  --r3-c-paper: #FBF8F1;
  --r3-wash: rgba(20, 19, 23, .07); --r3-wash-2: rgba(20, 19, 23, .12);
}

/* tier scopes: type scale, motion weight, glow. The page's <main> (or <body>) carries .tier-starter / .tier-growth / .tier-premium */
.tier-starter {
  --r3-t-h1: min(clamp(2.15rem, min(1.75rem + 1.9vw, 9.2vh), 3.4rem), 10.75vw);     /* 34 -> 54: calm, small, precise */
  --r3-t-h2: min(clamp(1.75rem, 1.4rem + 1.4vw, 2.5rem), 8.75vw);      /* 28 -> 40 */
  --r3-lh-h1: 1.05; --r3-lh-h2: 1.1; --r3-ls-h1: -.03em; --r3-ls-h2: -.024em;
  --r3-price-l: clamp(3.3rem, 2.3rem + 3.2vw, 5.1rem);    /* 53 -> 82: Starter is the calm one */
  --r3-d-reveal: .7s; --r3-d-sig: 0s; --r3-stagger: 0ms; --r3-rise: 10px;
  --r3-glow: 216, 210, 198;
}
.tier-growth {
  --r3-t-h1: min(clamp(2.5rem, min(1.65rem + 3.7vw, 11vh), 4.5rem), 12.5vw);       /* 40 -> 72: structured, confident (the default step is 84 px, used by the home display line) */
  --r3-t-h2: min(clamp(1.9rem, 1.4rem + 2.1vw, 3.1rem), 9.5vw);       /* 30 -> 50 */
  --r3-d-reveal: .95s; --r3-d-sig: 1.6s; --r3-stagger: 40ms; --r3-rise: 16px;
  --r3-glow: 206, 198, 186;                                /* warm neutral (was violet 164,143,255: the indigo glow is gone with the indigo plane) */
}
.tier-premium {
  --r3-t-h1: min(clamp(3.1rem, min(1.4rem + 7.4vw, 15.5vh), 7.8rem), 15.5vw);       /* 50 -> 125: serif poster; 15.5 % of the window height at most */
  --r3-t-h2: min(clamp(2.3rem, 1.4rem + 4vw, 5.25rem), 11.5vw);        /* 37 -> 84: R's poster H2 (two-tone with .r3a-tail) */
  --r3-lh-h1: .9; --r3-lh-h2: .96; --r3-ls-h1: -.02em; --r3-ls-h2: -.015em;
  --r3-fam-h: var(--r3-f-serif); --r3-w-h: 600;
  --r3-price-l: clamp(3.6rem, 2.4rem + 3.9vw, 6.2rem);
  --r3-d-reveal: 1.3s; --r3-d-sig: 2.1s; --r3-stagger: 60ms; --r3-rise: 22px;
  --r3-glow: 220, 188, 126;
}
/* F3: svh (small viewport height: no jump when the phone's address bar moves) where it exists; the vh values above are the fallback */
@supports (height: 1svh) {
  :root { --r3-t-h1: min(clamp(2.7rem, min(1.7rem + 4.4vw, 11.5svh), 5.25rem), 13.5vw); }
  .tier-starter { --r3-t-h1: min(clamp(2.15rem, min(1.75rem + 1.9vw, 9.2svh), 3.4rem), 10.75vw); }
  .tier-growth { --r3-t-h1: min(clamp(2.5rem, min(1.65rem + 3.7vw, 11svh), 4.5rem), 12.5vw); }
  .tier-premium { --r3-t-h1: min(clamp(3.1rem, min(1.4rem + 7.4vw, 15.5svh), 7.8rem), 15.5vw); }
}

/* ================================ 2. TYPE ================================ */
/* Roles (BIBLE_R3 b), merged system. The rule that stops the roles bleeding: WORDS are sans, NUMBERS THAT MATTER are serif.
     DISPLAY = Space Grotesk 500: Starter + Growth headings, studio headings (home, /paket), item titles. Its digits are Inter (R3 Figures, F4).
     SERIF   = Cormorant 600 lining: (1) the Premium page's own voice: H1 / H2 / H3, item titles, spec values; (2) every PRICE and every stat FIGURE
               (1 / 4 / 30) on every tier; (3) one signature moment per page: the ZS phrase (.r3-sig), the sign-off e-mail (.r3a-signoff).
     TEXT    = Inter 400/500/600: body, UI, captions, units, labels.
   Two-tone poster headlines, tracked-serif kickers and ghost numerals are the r3a-* components (r3-graft-press.css). */
.r3-h1, .r3-h2 { font-family: var(--r3-fam-h); font-weight: var(--r3-w-h); margin: 0; text-wrap: balance; }
.r3-h1 { font-size: var(--r3-t-h1); line-height: var(--r3-lh-h1); letter-spacing: var(--r3-ls-h1); }
.r3-h2 { font-size: var(--r3-t-h2); line-height: var(--r3-lh-h2); letter-spacing: var(--r3-ls-h2); }
.r3-h3 { font: 500 var(--r3-t-h3)/1.12 var(--r3-f-display); letter-spacing: -.02em; margin: 0; text-wrap: balance; }
.r3-h4 { font: 500 var(--r3-t-h4)/1.2 var(--r3-f-display); letter-spacing: -.012em; margin: 0; }
.tier-premium .r3-h3 { font-family: var(--r3-f-serif); font-weight: 600; letter-spacing: -.012em; }
/* a poster line that is not a tier headline (home hero): Growth scale, display face, signature phrase allowed */
.r3-display { font: 500 clamp(2.7rem, min(1.5rem + 5.1vw, 12vh), 6rem)/.99 var(--r3-f-display); letter-spacing: -.038em; margin: 0; text-wrap: balance; }
@supports (height: 1svh) { .r3-display { font: 500 clamp(2.7rem, min(1.5rem + 5.1vw, 12svh), 6rem)/.99 var(--r3-f-display); } }
.r3-lead { font: 400 var(--r3-t-lead)/1.5 var(--r3-f-text); color: var(--ink-2); max-width: 34em; margin: 0; text-wrap: pretty; }
.r3-body { font: 400 var(--r3-t-body)/1.6 var(--r3-f-text); color: var(--ink-2); margin: 0; }
.r3-small { font: 400 var(--r3-t-small)/1.5 var(--r3-f-text); color: var(--ink-2); margin: 0; }
/* ONE tracked-caps style, for section labels only. It has no trailing rule. */
.r3-label { display: inline-block; font: 600 var(--r3-t-micro)/1.2 var(--r3-f-text); letter-spacing: .13em; text-transform: uppercase; color: var(--ink-2); margin: 0; }
/* the one numbering notation: two digits, Space Grotesk letterforms with Inter digits (F4), no brackets, no dots. Optional "/ 05" total in .r3-n__t */
.r3-n { font: 500 var(--r3-t-small)/1 var(--r3-f-display); letter-spacing: .03em; font-variant-numeric: lining-nums proportional-nums; color: var(--ink-3); }
.r3-n__t { opacity: .6; }
.r3-n--tier { color: var(--tier, var(--ink-3)); }
/* captions under screenshots and photographs: sentence case, never tracked caps */
.r3-cap { font: 400 var(--r3-t-small)/1.45 var(--r3-f-text); color: var(--ink-2); margin: 12px 0 0; }
.r3-cap b { color: var(--ink); font-weight: 600; }
/* numerals inside Cormorant text must be lining (Cormorant's default figures are old-style) */
.r3-num, .tier-premium .r3-h1, .tier-premium .r3-h2, .tier-premium .r3-h3 { font-variant-numeric: lining-nums; }
/* emphasis inside a headline: the tier colour on the emphasised words, same face, never italic (no italic files are shipped) */
.r3-em { color: var(--tier, var(--gold)); font-style: normal; }
/* the ZS signature phrase: Cormorant 600 in brand gold, enlarged 1.22 em so its x-height matches Space Grotesk (0.39 vs 0.49 em), line-height pulled in */
.r3-sig { font-family: var(--r3-f-serif); font-weight: 600; font-style: normal; color: var(--gold); font-size: 1.22em; line-height: .8; letter-spacing: -.012em; }
.r3-measure { max-width: 38em; }
.r3-sr { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }

/* ================================ 3. BUTTONS AND LINKS ================================ */
/* size ladder: xl 64 (hero, final ask), l 54, m 44 (default, nav), s 36 (chips, docks). One primary colour per page: cream/ink everywhere,
   gold only on the Premium page and the Premium card. Quiet = filled tone, no border (the secondary action); text link = tertiary. */
.r3-btn { --h: 44px; --fs: .9375rem; --px: 20px; position: relative; display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  min-height: var(--h); padding: 0 var(--px); border-radius: 999px; border: 1px solid transparent; font: 600 var(--fs)/1 var(--r3-f-text); text-decoration: none;
  white-space: nowrap; cursor: pointer; overflow: hidden; max-width: 100%;
  transition: background var(--r3-d-micro) var(--r3-ease-out), color var(--r3-d-micro) var(--r3-ease-out), border-color var(--r3-d-micro) var(--r3-ease-out); }
.r3-btn--xl { --h: 64px; --fs: 1.1875rem; --px: 34px; }
.r3-btn--l { --h: 54px; --fs: 1.0625rem; --px: 28px; }
.r3-btn--s { --h: 36px; --fs: .8125rem; --px: 15px; }
.r3-btn--primary { background: var(--btn-bg, #F3F0EA); color: var(--btn-ink, #0C0C0F); }
.r3-btn--primary:hover { background: var(--btn-bg-hover, #fff); }
.r3-btn--gold { background: #DCBC7E; color: #141317; }
.r3-btn--gold:hover { background: #E7CB93; }
.r3-btn--quiet { background: var(--r3-wash); color: var(--ink); }
.r3-btn--quiet:hover { background: var(--r3-wash-2); }
.r3-btn--ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.r3-btn--ghost:hover { border-color: var(--ink-2); }
.r3-btn__arr { display: inline-block; transition: transform var(--r3-d-micro) var(--r3-ease-out); }
.r3-btn:hover .r3-btn__arr { transform: translateX(3px); }
.r3-btn--wide { width: 100%; }
@media (max-width: 559px) { .r3-btn--xl { --h: 58px; --fs: 1.0625rem; --px: 24px; } .r3-btn--phone-wide { width: 100%; } }
/* the full label "Be om en kostnadsfri skiss" is never clipped (panel: truncated at 320): smaller type + padding first, then the label wraps */
@media (max-width: 380px) { .r3-btn--xl, .r3-btn--l { --fs: 1rem; --px: 18px; } .r3-btn { gap: .45em; } }
@media (max-width: 340px) {
  .r3-btn { white-space: normal; text-align: center; line-height: 1.15; padding-block: 10px; height: auto; }
  .r3-roll .r3-btn__t { height: auto; flex-direction: row; } .r3-roll .r3-btn__t > span { height: auto; } .r3-roll .r3-btn__t > span + span { display: none; }
}
/* label roll (W-76): r3-core.js wraps the label in two stacked spans; hover only where hover exists, :focus-visible always.
   Ladder: Starter = arrow nudge only. Growth = label roll. Premium = label roll + the arrow turns diagonal. */
/* RC2 (David N004, 2026-10-14): the label NO LONGER ROLLS (the second copy of the text slid into view and read as "scrolls to the same text"). The whole control zooms 1.04 instead,
   on hover where hover exists and on keyboard :focus-visible. r3-core.js still wraps the label in two spans; the second one is never shown.
   Starter: arrow nudge only (no zoom). Premium: the arrow also turns diagonal. Full-width buttons zoom 1.02 so a hovered button can never widen the page. Reduced motion: no zoom (see section 10). */
.r3-roll .r3-btn__t { display: inline-flex; flex-direction: row; height: auto; overflow: visible; line-height: inherit; }
.r3-roll .r3-btn__t > span { display: block; height: auto; }
.r3-roll .r3-btn__t > span + span { display: none; }
.r3-roll { transition: background var(--r3-d-micro) var(--r3-ease-out), color var(--r3-d-micro) var(--r3-ease-out), border-color var(--r3-d-micro) var(--r3-ease-out), transform .28s var(--r3-ease-out); }
.r3-roll:focus-visible { transform: scale(1.04); }
@media (hover: hover) { .r3-roll:hover { transform: scale(1.04); } }
.r3-roll.r3-btn--wide:hover, .r3-roll.r3-btn--wide:focus-visible { transform: scale(1.02); }
@media (max-width: 559px) { .r3-roll.r3-btn--phone-wide:hover, .r3-roll.r3-btn--phone-wide:focus-visible { transform: scale(1.02); } }
.tier-premium .r3-btn:hover .r3-btn__arr { transform: translate(3px, -3px); }
.tier-starter .r3-roll, .tier-starter .r3-roll:hover, .tier-starter .r3-roll:focus-visible { transition: background var(--r3-d-micro) var(--r3-ease-out), color var(--r3-d-micro) var(--r3-ease-out), border-color var(--r3-d-micro) var(--r3-ease-out); transform: none; }  /* Starter: no zoom */
/* release QA 2026-10-13: the <=340 px wrap override above comes BEFORE these base roll rules (same specificity), so at 320 px the label box stayed one line high with overflow hidden and the second line was cut
   ("Be om en kostnadsfri" without "skiss"). Repeated here, after them. */
@media (max-width: 340px) {
  .r3-roll .r3-btn__t { height: auto; flex-direction: row; overflow: visible; } .r3-roll .r3-btn__t > span { height: auto; } .r3-roll .r3-btn__t > span + span { display: none; }
}
/* tertiary link: underline, 44 px hit area without moving the line box */
.r3-link { color: var(--ink); font-weight: 500; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 4px; text-decoration-color: var(--line); padding-block: 12px; margin-block: -12px; transition: text-decoration-color var(--r3-d-micro); }
.r3-link:hover { text-decoration-color: currentColor; }
.r3-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 16px; }

/* ================================ 4. PRICE AND TIER MARK ================================ */
/* The price renders ONE way everywhere (F4): Cormorant 600, LINING + proportional figures (Cormorant's default figures are old-style), unit in Inter on the
   same baseline. Use a plain no-break space between thousands ("1&nbsp;499"; r3-core.js normalises it). Sizes l (hero) / m (card, aside) / s (dock, tag, table). */
.r3-price { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px; margin: 0; }
.r3-price__n { font: var(--r3-w-price) var(--r3-price-fs, var(--r3-price-m))/.92 var(--r3-f-price); letter-spacing: var(--r3-ls-price); font-variant-numeric: lining-nums proportional-nums; white-space: nowrap; color: var(--ink); }
.r3-price__u { font: 400 var(--r3-t-small)/1.3 var(--r3-f-text); color: var(--ink-2); }
.r3-price--l { --r3-price-fs: var(--r3-price-l); }
.r3-price--m { --r3-price-fs: var(--r3-price-m); }
.r3-price--s { --r3-price-fs: var(--r3-price-s); }
.r3-price__note { font: 400 var(--r3-t-small)/1.4 var(--r3-f-text); color: var(--ink-2); margin: 10px 0 0; }
/* tier mark: a three-segment ladder bar (1, 2 or 3 segments lit in the tier colour) + the tier name in sentence case. NOT tracked caps. */
.r3-tier { display: inline-flex; align-items: center; gap: 10px; font: 600 .9375rem/1 var(--r3-f-display); letter-spacing: -.005em; color: var(--ink); margin: 0; }
.r3-tier__bar { display: inline-grid; grid-auto-flow: column; gap: 3px; }
.r3-tier__bar i { width: 15px; height: 4px; border-radius: 2px; background: var(--line); }
.r3-tier--1 .r3-tier__bar i:nth-child(-n+1), .r3-tier--2 .r3-tier__bar i:nth-child(-n+2), .r3-tier--3 .r3-tier__bar i { background: var(--tier, var(--ink)); }
.r3-tier .r3-n { margin-right: 2px; flex: none; white-space: nowrap; }

/* ================================ 5. TONE PLANES (F1, F3, F6) ================================ */
/* A plane is a tonal region of the page (3 to 6 per page). Its tone changes ONLY by blending: the blend lives in the plane's own top padding (never over
   the previous plane's text), is --r3-fade long (140 px desktop / 120 tablet / 96 phone), is eased (smoothstep-like stops) and mixed in oklab so it never
   smears through mid-grey. NO divider lines, ever.
     <section class="r3-plane r3-tone-walnut r3-from-page"> ... </section>            explicit: tone of this plane + the plane above
     <section class="r3-plane" data-plane="walnut"> ... </section>                   automatic (F6): the plane above is read from the previous sibling plane
   F3: a plane is first a FLAT colour (readable on any engine); the oklab blend is an enhancement behind @supports. Tones: page (theme), lift, void, graphite,
   walnut, paper. Dark planes (void, graphite, walnut) are dark in BOTH themes and re-scope the text tokens, like .band-dark. Paper is light in both themes.
   Cadence is the tier signal: Starter 2 tones (page + paper), Growth 3 (graphite, page, lift), Premium 4+ (void, walnut, photographic, void). */
.r3-plane { --r3-c: var(--r3-c-page); position: relative; isolation: isolate; overflow-x: clip; color: var(--ink);
  padding-top: var(--r3-fade); padding-bottom: var(--r3-sec);
  background: var(--r3-c); }                                   /* flat fallback */
@supports (background: color-mix(in oklab, red 50%, blue)) {
  .r3-plane { background:
    linear-gradient(180deg, var(--r3-from, var(--r3-c-page)) 0,
      color-mix(in oklab, var(--r3-c) 3%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * 0.1),
      color-mix(in oklab, var(--r3-c) 10%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * 0.2),
      color-mix(in oklab, var(--r3-c) 22%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * 0.3),
      color-mix(in oklab, var(--r3-c) 35%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * 0.4),
      color-mix(in oklab, var(--r3-c) 50%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * 0.5),
      color-mix(in oklab, var(--r3-c) 65%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * 0.6),
      color-mix(in oklab, var(--r3-c) 78%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * 0.7),
      color-mix(in oklab, var(--r3-c) 90%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * 0.8),
      color-mix(in oklab, var(--r3-c) 97%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * 0.9),
      var(--r3-c) var(--r3-fade)) top / 100% var(--r3-fade) no-repeat,
    var(--r3-c); }
  /* ink <-> cream without a grey smear: the blend passes through a warm bridge instead of neutral grey (A's discipline). F-11 (FXL, fix round 2): the bridge colour was #5A4636, a dark
     coffee brown that panel 3 read as a muddy band; it is now the walnut-amber of the room itself, oklch(.60 .06 62) = rgb(158,118,86), an opaque midpoint at the lightness the
     blend really crosses (L about .6), so the middle of the blend is a deliberate warm taupe. Another hue: set --r3-bridge on the plane (plum 132,81,105 / forest 66,111,76). */
  .r3-bridge { --r3-bridge: #9E7656; background:
    linear-gradient(180deg, var(--r3-from, var(--r3-c-page)) 0,
      color-mix(in oklab, var(--r3-bridge) 22%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * .14),
      color-mix(in oklab, var(--r3-bridge) 80%, var(--r3-from, var(--r3-c-page))) calc(var(--r3-fade) * .40),
      color-mix(in oklab, var(--r3-c) 52%, var(--r3-bridge)) calc(var(--r3-fade) * .64),
      color-mix(in oklab, var(--r3-c) 86%, var(--r3-bridge)) calc(var(--r3-fade) * .84),
      var(--r3-c) var(--r3-fade)) top / 100% var(--r3-fade) no-repeat,
    var(--r3-c); }
}
.r3-plane--first { padding-top: 0; background: var(--r3-c); }          /* the first plane under the header has nothing to blend from */
.r3-plane--tight { padding-bottom: 24px; }
.r3-plane--foot { --r3-fade: 72px; padding-bottom: 0; }   /* the footer is a plane too: <footer class="foot r3-plane r3-plane--foot r3-tone-page r3-from-graphite"> blends from the plane above */
/* dark <-> light hand-offs (ink/walnut to paper or cream): oklab keeps the midpoint clean, a bloom adds a faint warm glow in the middle of the blend so the
   crossing reads as light, not as grey fog. Use it ONLY where the neighbours differ in lightness by more than half the scale, and pick the variant by theme:
     .r3-bloom    always (dark band <-> paper/cream, e.g. walnut/void/graphite next to paper, in both themes)
     .r3-bloom-d  only in the dark theme (page ink <-> paper plane, e.g. Starter's full stop)
     .r3-bloom-l  only in the light theme (dark band <-> the cream page)
   Never between two light or two dark tones: there it paints a visible stripe. */
/* F-11 (FXL, fix round 2): the bloom is the TINTED MIDPOINT of a dark <-> light hand-off. It was rgb(200,146,88) at .30 laid on the grey oklab midpoint = (145,126,106), the khaki
   panel 3 sampled on the Starter ask; it is now a bell (0 .22 .62 1 .62 .22 0 of --r3-bloom-a, default .70) of the room's own hue, default walnut-amber oklch(.60 .06 62) = 158,118,86,
   which makes the middle of the blend a clean warm taupe. Other hues are one variable on the plane: --r3-bloom-rgb: 132,81,105 (plum), 66,111,76 (forest). Bench: captures/fix2_FXL/scratch/lab_mid*.png */
.r3-plane::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: var(--r3-fade); z-index: -1; pointer-events: none; opacity: var(--r3-bloom-on, 0);
  background: linear-gradient(180deg, rgba(var(--r3-bloom-rgb, 158, 118, 86), 0) 0, rgba(var(--r3-bloom-rgb, 158, 118, 86), calc(var(--r3-bloom-a, .7) * .22)) 16%, rgba(var(--r3-bloom-rgb, 158, 118, 86), calc(var(--r3-bloom-a, .7) * .62)) 32%,
    rgba(var(--r3-bloom-rgb, 158, 118, 86), var(--r3-bloom-a, .7)) 50%, rgba(var(--r3-bloom-rgb, 158, 118, 86), calc(var(--r3-bloom-a, .7) * .62)) 68%, rgba(var(--r3-bloom-rgb, 158, 118, 86), calc(var(--r3-bloom-a, .7) * .22)) 84%, rgba(var(--r3-bloom-rgb, 158, 118, 86), 0) 100%); }
.r3-bloom, :root:not([data-theme="light"]) .r3-bloom-d, [data-theme="light"] .r3-bloom-l { --r3-bloom-on: 1; }
/* the stage may straddle the blend: its top edge sits inside the previous tone's fade, so no gap reads as empty */
.r3-straddle { margin-top: calc(var(--r3-fade) * -.62); position: relative; z-index: var(--r3-z-stage); }

.r3-tone-page, [data-plane="page"] { --r3-c: var(--r3-c-page); }
.r3-tone-lift, [data-plane="lift"] { --r3-c: var(--r3-c-lift); }
.r3-tone-void, [data-plane="void"] { --r3-c: var(--r3-c-void); }
.r3-tone-graphite, [data-plane="graphite"], .r3-tone-night, [data-plane="night"] { --r3-c: var(--r3-c-graphite); }
.r3-tone-walnut, [data-plane="walnut"] { --r3-c: var(--r3-c-walnut); }
.r3-tone-paper, [data-plane="paper"] { --r3-c: var(--r3-c-paper); }
.r3-from-page { --r3-from: var(--r3-c-page); }
.r3-from-lift { --r3-from: var(--r3-c-lift); }
.r3-from-void { --r3-from: var(--r3-c-void); }
.r3-from-graphite, .r3-from-night { --r3-from: var(--r3-c-graphite); }
.r3-from-walnut { --r3-from: var(--r3-c-walnut); }
.r3-from-paper { --r3-from: var(--r3-c-paper); }
/* F6 AUTO NEIGHBOURS: [data-plane] siblings. A plane blends from the plane above it by itself (zero specificity, so .r3-from-* and inline --r3-from still win).
   Same tone twice = no blend. No :has() anywhere (F3): only the previous-sibling combinator. */
:where([data-plane="page"] + [data-plane="page"]) { --r3-from: var(--r3-c-page); }
:where([data-plane="page"] + [data-plane="lift"]) { --r3-from: var(--r3-c-page); }
:where([data-plane="page"] + [data-plane="void"]) { --r3-from: var(--r3-c-page); }
:where([data-plane="page"] + [data-plane="graphite"]) { --r3-from: var(--r3-c-page); }
:where([data-plane="page"] + [data-plane="walnut"]) { --r3-from: var(--r3-c-page); }
:where([data-plane="page"] + [data-plane="paper"]) { --r3-from: var(--r3-c-page); }
:where([data-plane="lift"] + [data-plane="page"]) { --r3-from: var(--r3-c-lift); }
:where([data-plane="lift"] + [data-plane="lift"]) { --r3-from: var(--r3-c-lift); }
:where([data-plane="lift"] + [data-plane="void"]) { --r3-from: var(--r3-c-lift); }
:where([data-plane="lift"] + [data-plane="graphite"]) { --r3-from: var(--r3-c-lift); }
:where([data-plane="lift"] + [data-plane="walnut"]) { --r3-from: var(--r3-c-lift); }
:where([data-plane="lift"] + [data-plane="paper"]) { --r3-from: var(--r3-c-lift); }
:where([data-plane="void"] + [data-plane="page"]) { --r3-from: var(--r3-c-void); }
:where([data-plane="void"] + [data-plane="lift"]) { --r3-from: var(--r3-c-void); }
:where([data-plane="void"] + [data-plane="void"]) { --r3-from: var(--r3-c-void); }
:where([data-plane="void"] + [data-plane="graphite"]) { --r3-from: var(--r3-c-void); }
:where([data-plane="void"] + [data-plane="walnut"]) { --r3-from: var(--r3-c-void); }
:where([data-plane="void"] + [data-plane="paper"]) { --r3-from: var(--r3-c-void); }
:where([data-plane="graphite"] + [data-plane="page"]) { --r3-from: var(--r3-c-graphite); }
:where([data-plane="graphite"] + [data-plane="lift"]) { --r3-from: var(--r3-c-graphite); }
:where([data-plane="graphite"] + [data-plane="void"]) { --r3-from: var(--r3-c-graphite); }
:where([data-plane="graphite"] + [data-plane="graphite"]) { --r3-from: var(--r3-c-graphite); }
:where([data-plane="graphite"] + [data-plane="walnut"]) { --r3-from: var(--r3-c-graphite); }
:where([data-plane="graphite"] + [data-plane="paper"]) { --r3-from: var(--r3-c-graphite); }
:where([data-plane="walnut"] + [data-plane="page"]) { --r3-from: var(--r3-c-walnut); }
:where([data-plane="walnut"] + [data-plane="lift"]) { --r3-from: var(--r3-c-walnut); }
:where([data-plane="walnut"] + [data-plane="void"]) { --r3-from: var(--r3-c-walnut); }
:where([data-plane="walnut"] + [data-plane="graphite"]) { --r3-from: var(--r3-c-walnut); }
:where([data-plane="walnut"] + [data-plane="walnut"]) { --r3-from: var(--r3-c-walnut); }
:where([data-plane="walnut"] + [data-plane="paper"]) { --r3-from: var(--r3-c-walnut); }
:where([data-plane="paper"] + [data-plane="page"]) { --r3-from: var(--r3-c-paper); }
:where([data-plane="paper"] + [data-plane="lift"]) { --r3-from: var(--r3-c-paper); }
:where([data-plane="paper"] + [data-plane="void"]) { --r3-from: var(--r3-c-paper); }
:where([data-plane="paper"] + [data-plane="graphite"]) { --r3-from: var(--r3-c-paper); }
:where([data-plane="paper"] + [data-plane="walnut"]) { --r3-from: var(--r3-c-paper); }
:where([data-plane="paper"] + [data-plane="paper"]) { --r3-from: var(--r3-c-paper); }

/* dark planes re-scope the text tokens; static hex for the derived surfaces (no color-mix, F3: 10 / 14 / 20 % white over the plane) */
.r3-tone-void, .r3-tone-graphite, .r3-tone-night, .r3-tone-walnut, [data-plane="void"], [data-plane="graphite"], [data-plane="walnut"] {
  --bg: var(--r3-c); --bg-2: #242427; --surface: #2E2E31; --surface-2: #3D3D3F;
  --ink: #F3F0EA; --ink-2: #CFCAC1; --ink-3: #A7A298; --line: rgba(243, 240, 234, .18); --line-2: rgba(243, 240, 234, .09);
  --accent: #A48FFF; --gold: #DCBC7E; --stone: #D8D2C6; --btn-bg: #F3F0EA; --btn-ink: #0C0C0F; --btn-bg-hover: #FFFFFF; --elev: 0 0 0 1px var(--line-2);
  --r3-wash: rgba(243, 240, 234, .09); --r3-wash-2: rgba(243, 240, 234, .15);
  --logo-dark: none; --logo-light: block; color-scheme: dark; color: var(--ink); }
.r3-tone-graphite, .r3-tone-night, [data-plane="graphite"] { --bg-2: #383739; --surface: #414043; --surface-2: #4E4D51; }
.r3-tone-walnut, [data-plane="walnut"] { --bg-2: #38302B; --surface: #413934; --surface-2: #4E4742; }
.r3-tone-paper, [data-plane="paper"] {
  --bg: var(--r3-c); --bg-2: #E4DDCE; --surface: #FFFFFF; --surface-2: #FBF9F5;
  --ink: #141317; --ink-2: #46424C; --ink-3: #55505B; --line: rgba(20, 19, 23, .16); --line-2: rgba(20, 19, 23, .07);
  --accent: #4B2EC6; --gold: #654810; --stone: #55505B; --btn-bg: #141317; --btn-ink: #F4F1EB; --btn-bg-hover: #000;
  --r3-wash: rgba(20, 19, 23, .07); --r3-wash-2: rgba(20, 19, 23, .12);
  --elev: 0 1px 2px rgba(20, 19, 23, .05), 0 18px 40px rgba(20, 19, 23, .07); --logo-dark: block; --logo-light: none; color-scheme: light; color: var(--ink); }
.r3-tone-paper .r3-btn--gold, [data-plane="paper"] .r3-btn--gold { background: #141317; color: #F4F1EB; }   /* gold is a dark-ground colour */
/* F2: --tier is a custom property: it is computed where it is declared. A page that carries .tier-growth on <main> declared --tier: var(--accent) there, with the
   PAGE's accent (deep violet in the light theme), and every plane below inherited that value: violet-on-graphite numerals at 1.8:1. Re-declare it inside each
   plane, from the plane's own re-scoped tokens. Order matters (starter, growth, premium): a premium card inside a growth page wins. */
.tier-starter :is(.r3-tone-void, .r3-tone-graphite, .r3-tone-night, .r3-tone-walnut, .r3-tone-paper, [data-plane]) { --tier: var(--stone); }
.tier-growth :is(.r3-tone-void, .r3-tone-graphite, .r3-tone-night, .r3-tone-walnut, .r3-tone-paper, [data-plane]) { --tier: var(--accent); }
.tier-premium :is(.r3-tone-void, .r3-tone-graphite, .r3-tone-night, .r3-tone-walnut, .r3-tone-paper, [data-plane]) { --tier: var(--gold); }
/* same element (the plane itself carries the tier class): after the descendant rules so a growth plane inside a premium page keeps its own tier */
.tier-starter:is(.r3-tone-void, .r3-tone-graphite, .r3-tone-night, .r3-tone-walnut, .r3-tone-paper, [data-plane]) { --tier: var(--stone); }
.tier-growth:is(.r3-tone-void, .r3-tone-graphite, .r3-tone-night, .r3-tone-walnut, .r3-tone-paper, [data-plane]) { --tier: var(--accent); }
.tier-premium:is(.r3-tone-void, .r3-tone-graphite, .r3-tone-night, .r3-tone-walnut, .r3-tone-paper, [data-plane]) { --tier: var(--gold); }

/* AUTO BLOOM: the lower plane of a dark <-> light hand-off lights its blend. --r3-bloom-on is read by .r3-plane::before. Explicit helpers: .r3-bloom / -d / -l. */
:where([data-plane="void"] + [data-plane="paper"]), :where([data-plane="paper"] + [data-plane="void"]) { --r3-bloom-on: 1; }
:where([data-plane="graphite"] + [data-plane="paper"]), :where([data-plane="paper"] + [data-plane="graphite"]) { --r3-bloom-on: 1; }
:where([data-plane="walnut"] + [data-plane="paper"]), :where([data-plane="paper"] + [data-plane="walnut"]) { --r3-bloom-on: 1; }
:root:not([data-theme="light"]) :where([data-plane="page"] + [data-plane="paper"]), :root:not([data-theme="light"]) :where([data-plane="paper"] + [data-plane="page"]) { --r3-bloom-on: 1; }
[data-theme="light"] :where([data-plane="page"] + [data-plane="void"]), [data-theme="light"] :where([data-plane="void"] + [data-plane="page"]) { --r3-bloom-on: 1; }
[data-theme="light"] :where([data-plane="page"] + [data-plane="graphite"]), [data-theme="light"] :where([data-plane="graphite"] + [data-plane="page"]) { --r3-bloom-on: 1; }
[data-theme="light"] :where([data-plane="page"] + [data-plane="walnut"]), [data-theme="light"] :where([data-plane="walnut"] + [data-plane="page"]) { --r3-bloom-on: 1; }

/* ================================ 5b. TINTED BRIDGE: the blend recipe for dark <-> light hand-offs (FXL round 3b-1: P4-012, 034, 047, 059, 073) ================================
   PROBLEM. The foundation ramp above is clean between tones of one family. Between near-neutral ink and near-neutral cream, though, the middle of an oklab ramp has chroma about .01:
   grey, mauve-grey or khaki "smoke" (panel 3 F-11, panel 4 P4-012 / 047 / 059 / 073; round 2 tried a bloom, a plum bridge colour and a 44 % tint: all still read as dust, because they pulled
   the LIGHTNESS toward a mid colour and left the chroma thin, and a colour that holds one lightness over 40 % of the blend is a stripe: the lab is evidence/r3/final8/FXL/lab/lab1..3.html).
   RECIPE. Leave the eased lightness curve exactly as it is and LIFT THE CHROMA OF THE MIDDLE with a bell, in the hue of the room (relative colour syntax, one rule, 9 stops):
       stop(t) = oklab( mix_oklab(from, c, ease(t)) )  +  K(t) * (0, C cos h, C sin h)          K(t) = sin(pi t)^2,  t = 0 .. 1 over --r3-fade (140 / 120 / 96 px)
   so the middle of ink -> cream is a clean rose / plum / amber / leaf of chroma C instead of grey, the ends are untouched, and nothing leaves the range of the two tones (boundary_check overshoot 0).
   TOKENS (set them on the plane or any ancestor; they are read where the plane is painted):
       --r3-bridge-h   hue in degrees (oklch).  plum 352, rose 12, amber 62 (the default room), leaf 140
       --r3-bridge-c   chroma at the middle of the blend.  .075 plum, .075 rose, .065 amber, .045 leaf (green <-> wheat already has chroma .07 of its own, so less is added)
       --r3-bridge-k   strength multiplier, default 1; 0 = plain ramp.  Use 0 between two light or two dark tones: a bell there paints a stripe.
   USE.  1. Any .r3-plane: add class r3-bridge (and r3-bridge--plum | --rose | --amber | --leaf to pick the room). It blends from --r3-from (or the auto neighbour) to --r3-c.
         2. Dark theme, an ink / void / graphite / walnut plane next to a paper plane (either order): automatic, nothing to add (the Starter ask: tier-starter sets the plum room).
         3. A sheet with its own plane classes (the example sites): give the plane class r3-bridge-vars, set --r3-from / --r3-c / --r3-fade from your own variables and paint the blend zone with
            background: var(--r3-bridge-bg)   (a pure gradient for 0..100 % of the zone), or bake the stops with evidence/r3/final8/FXL/scripts/blend_recipe.py (same math, plain sRGB).
   Engines without relative colour syntax (before Chrome 119 / Safari 16.4 / Firefox 128) keep the ramp above plus the sRGB bloom of the room (--r3-bloom-rgb), as in round 2. */
:root { --r3-bridge-h: 62; --r3-bridge-c: .065; --r3-bridge-k: 1; }
.tier-starter { --r3-bridge-h: 352; --r3-bridge-c: .075; }        /* Starter's room is plum and rose: Studio Alina, its own example */
.r3-bridge--plum { --r3-bridge-h: 352; --r3-bridge-c: .075; --r3-bloom-rgb: 149, 91, 112; }
.r3-bridge--rose { --r3-bridge-h: 12; --r3-bridge-c: .075; --r3-bloom-rgb: 168, 108, 100; }
.r3-bridge--amber { --r3-bridge-h: 62; --r3-bridge-c: .065; --r3-bloom-rgb: 158, 118, 86; }
.r3-bridge--leaf { --r3-bridge-h: 140; --r3-bridge-c: .045; --r3-bloom-rgb: 112, 134, 66; }
.r3-bridge { --r3-bloom-on: 1; }                                                              /* the fallback for engines without relative colours */
@supports (color: oklab(from red l a b)) and (background: color-mix(in oklab, red 50%, blue)) {
  .r3-bridge, .r3-bridge-vars,
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="page"] + [data-plane="paper"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="paper"] + [data-plane="page"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="void"] + [data-plane="paper"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="paper"] + [data-plane="void"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="graphite"] + [data-plane="paper"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="paper"] + [data-plane="graphite"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="walnut"] + [data-plane="paper"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="paper"] + [data-plane="walnut"]) {
    --r3-bloom-on: 0;
    --r3-bridge-a: calc(var(--r3-bridge-c) * var(--r3-bridge-k) * cos(var(--r3-bridge-h) * 1deg));
    --r3-bridge-b: calc(var(--r3-bridge-c) * var(--r3-bridge-k) * sin(var(--r3-bridge-h) * 1deg));
    --r3-bridge-bg: linear-gradient(180deg, var(--r3-from, var(--r3-c-page)) 0,
        oklab(from color-mix(in oklab, var(--r3-c) 3%, var(--r3-from, var(--r3-c-page))) l calc(a + var(--r3-bridge-a) * 0.0955) calc(b + var(--r3-bridge-b) * 0.0955)) calc(var(--r3-fade) * 0.1),
        oklab(from color-mix(in oklab, var(--r3-c) 10%, var(--r3-from, var(--r3-c-page))) l calc(a + var(--r3-bridge-a) * 0.3455) calc(b + var(--r3-bridge-b) * 0.3455)) calc(var(--r3-fade) * 0.2),
        oklab(from color-mix(in oklab, var(--r3-c) 22%, var(--r3-from, var(--r3-c-page))) l calc(a + var(--r3-bridge-a) * 0.6545) calc(b + var(--r3-bridge-b) * 0.6545)) calc(var(--r3-fade) * 0.3),
        oklab(from color-mix(in oklab, var(--r3-c) 35%, var(--r3-from, var(--r3-c-page))) l calc(a + var(--r3-bridge-a) * 0.9045) calc(b + var(--r3-bridge-b) * 0.9045)) calc(var(--r3-fade) * 0.4),
        oklab(from color-mix(in oklab, var(--r3-c) 50%, var(--r3-from, var(--r3-c-page))) l calc(a + var(--r3-bridge-a) * 1) calc(b + var(--r3-bridge-b) * 1)) calc(var(--r3-fade) * 0.5),
        oklab(from color-mix(in oklab, var(--r3-c) 65%, var(--r3-from, var(--r3-c-page))) l calc(a + var(--r3-bridge-a) * 0.9045) calc(b + var(--r3-bridge-b) * 0.9045)) calc(var(--r3-fade) * 0.6),
        oklab(from color-mix(in oklab, var(--r3-c) 78%, var(--r3-from, var(--r3-c-page))) l calc(a + var(--r3-bridge-a) * 0.6545) calc(b + var(--r3-bridge-b) * 0.6545)) calc(var(--r3-fade) * 0.7),
        oklab(from color-mix(in oklab, var(--r3-c) 90%, var(--r3-from, var(--r3-c-page))) l calc(a + var(--r3-bridge-a) * 0.3455) calc(b + var(--r3-bridge-b) * 0.3455)) calc(var(--r3-fade) * 0.8),
        oklab(from color-mix(in oklab, var(--r3-c) 97%, var(--r3-from, var(--r3-c-page))) l calc(a + var(--r3-bridge-a) * 0.0955) calc(b + var(--r3-bridge-b) * 0.0955)) calc(var(--r3-fade) * 0.9),
        var(--r3-c) var(--r3-fade));
  }
  .r3-bridge,
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="page"] + [data-plane="paper"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="paper"] + [data-plane="page"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="void"] + [data-plane="paper"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="paper"] + [data-plane="void"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="graphite"] + [data-plane="paper"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="paper"] + [data-plane="graphite"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="walnut"] + [data-plane="paper"]),
  :root:not([data-theme="light"]) .r3-plane:is([data-plane="paper"] + [data-plane="walnut"]) {
    background: var(--r3-bridge-bg) top / 100% var(--r3-fade) no-repeat, var(--r3-c);
  }
  .r3-plane--first.r3-bridge { background: var(--r3-c); }
}

/* ================================ 5c. MELT: a photograph or film band that meets a plane (FXL round 3b-1: P4-060) ================================
   A band of photograph whose top (or foot) edge is a straight line across the page reads as a seam (boundary_check calls it PHOTO_EDGE and does not judge it). Put the class on the picture layer
   (the wrapper of the img / video, NOT on a box that also holds the text: the mask would thin the type), over a plane of the neighbouring tone: the first 100 px (96 on phones, --r3-melt) fade out
   in smootherstep stops and the plane's own colour shows through. Glöd /meny "Nästa Vid spisen" and /galleri "Nästa Atmosfären": r3-melt-top on the band's picture wrapper. */
.r3-melt-top { --r3-melt: min(100px, var(--r3-fade)); -webkit-mask-image: linear-gradient(180deg, transparent 0, rgba(0, 0, 0, 0.0086) calc(var(--r3-melt) * 0.1), rgba(0, 0, 0, 0.0579) calc(var(--r3-melt) * 0.2), rgba(0, 0, 0, 0.1631) calc(var(--r3-melt) * 0.3), rgba(0, 0, 0, 0.3174) calc(var(--r3-melt) * 0.4), rgba(0, 0, 0, 0.5) calc(var(--r3-melt) * 0.5), rgba(0, 0, 0, 0.6826) calc(var(--r3-melt) * 0.6), rgba(0, 0, 0, 0.8369) calc(var(--r3-melt) * 0.7), rgba(0, 0, 0, 0.9421) calc(var(--r3-melt) * 0.8), rgba(0, 0, 0, 0.9914) calc(var(--r3-melt) * 0.9), #000 var(--r3-melt)); mask-image: linear-gradient(180deg, transparent 0, rgba(0, 0, 0, 0.0086) calc(var(--r3-melt) * 0.1), rgba(0, 0, 0, 0.0579) calc(var(--r3-melt) * 0.2), rgba(0, 0, 0, 0.1631) calc(var(--r3-melt) * 0.3), rgba(0, 0, 0, 0.3174) calc(var(--r3-melt) * 0.4), rgba(0, 0, 0, 0.5) calc(var(--r3-melt) * 0.5), rgba(0, 0, 0, 0.6826) calc(var(--r3-melt) * 0.6), rgba(0, 0, 0, 0.8369) calc(var(--r3-melt) * 0.7), rgba(0, 0, 0, 0.9421) calc(var(--r3-melt) * 0.8), rgba(0, 0, 0, 0.9914) calc(var(--r3-melt) * 0.9), #000 var(--r3-melt)); }
.r3-melt-bottom { --r3-melt: min(100px, var(--r3-fade)); -webkit-mask-image: linear-gradient(0deg, transparent 0, rgba(0, 0, 0, 0.0086) calc(var(--r3-melt) * 0.1), rgba(0, 0, 0, 0.0579) calc(var(--r3-melt) * 0.2), rgba(0, 0, 0, 0.1631) calc(var(--r3-melt) * 0.3), rgba(0, 0, 0, 0.3174) calc(var(--r3-melt) * 0.4), rgba(0, 0, 0, 0.5) calc(var(--r3-melt) * 0.5), rgba(0, 0, 0, 0.6826) calc(var(--r3-melt) * 0.6), rgba(0, 0, 0, 0.8369) calc(var(--r3-melt) * 0.7), rgba(0, 0, 0, 0.9421) calc(var(--r3-melt) * 0.8), rgba(0, 0, 0, 0.9914) calc(var(--r3-melt) * 0.9), #000 var(--r3-melt)); mask-image: linear-gradient(0deg, transparent 0, rgba(0, 0, 0, 0.0086) calc(var(--r3-melt) * 0.1), rgba(0, 0, 0, 0.0579) calc(var(--r3-melt) * 0.2), rgba(0, 0, 0, 0.1631) calc(var(--r3-melt) * 0.3), rgba(0, 0, 0, 0.3174) calc(var(--r3-melt) * 0.4), rgba(0, 0, 0, 0.5) calc(var(--r3-melt) * 0.5), rgba(0, 0, 0, 0.6826) calc(var(--r3-melt) * 0.6), rgba(0, 0, 0, 0.8369) calc(var(--r3-melt) * 0.7), rgba(0, 0, 0, 0.9421) calc(var(--r3-melt) * 0.8), rgba(0, 0, 0, 0.9914) calc(var(--r3-melt) * 0.9), #000 var(--r3-melt)); }

/* ================================ 6. PHOTO GRADE ================================ */
/* THE ONE GRADE ("walnut floor", BIBLE_R3 d). Every photograph and film is BAKED once (tools: evidence/r3/final/tools/r3_grade.py, assets/zs/img/r3-g-*.webp,
   assets/zs/film/r3-g-*.mp4): black point = the page ink #0C0C0F (so a photograph's blacks dissolve into the page instead of sitting on it as a rectangle),
   white point = warm cream (about #F0E1C6, never paper white), amber mids, saturation .72-.92 by source family, a gentle S-curve. Baked files need NO filter:
   wrap them in .r3-photo only. Example sites get the same recipe re-floored to their own ground (--r3-floor on the wrapper).
   .r3-photo--raw approximates the bake with CSS for a prototype or a crop nobody has baked yet. Never a filter on a scrolling image. */
.r3-photo { position: relative; isolation: isolate; overflow: hidden; background: var(--r3-floor); margin: 0; }
.r3-photo > img, .r3-photo > video, .r3-photo > picture > img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: var(--r3-fx, 50%) var(--r3-fy, 50%); }
.r3-photo > picture { display: block; width: 100%; height: 100%; }
.r3-photo--floor > img, .r3-photo--floor > video, .r3-photo--floor > picture > img { mix-blend-mode: lighten; }   /* any pixel darker than the floor becomes the floor */
.r3-photo--vig::after { content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: radial-gradient(125% 105% at 50% 45%, rgba(12, 12, 15, 0) 52%, rgba(12, 12, 15, var(--r3-vig, .3)) 100%); }
.r3-photo--raw > img, .r3-photo--raw > video { filter: sepia(.14) saturate(.9) contrast(1.06) brightness(.96); }
.r3-photo--raw::before { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; mix-blend-mode: multiply; background: #E8DCC5; }
.r3-photo--raw.r3-cool > img, .r3-photo--raw.r3-cool > video { filter: sepia(.3) saturate(.74) contrast(1.12) brightness(.8); }
/* legacy names of the first round (C): kept so old markup still works; they now mean the unified approximation */
.r3-grade > img, .r3-grade > video { filter: sepia(.14) saturate(.9) contrast(1.06) brightness(.96); }
.r3-grade::after { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; mix-blend-mode: multiply; background: #E8DCC5; }
.r3-grade--lift > img, .r3-grade--lift > video { filter: sepia(.3) saturate(.74) contrast(1.12) brightness(.8); }   /* high-key sources (white seamless, pale hair) */
.r3-grade--film::after { mix-blend-mode: soft-light; background: linear-gradient(180deg, rgba(168, 112, 56, .38), rgba(60, 38, 22, .30)); }  /* unbaked video: warm soft-light, never a filter on the video itself */
/* crops: the wrapper takes the ratio, --r3-fx / --r3-fy the focal point (never enlarge past the source: see the size table in BIBLE_R3 d) */
.r3-ar-21x9 { aspect-ratio: 21 / 9; } .r3-ar-16x9 { aspect-ratio: 16 / 9; } .r3-ar-16x10 { aspect-ratio: 16 / 10; } .r3-ar-3x2 { aspect-ratio: 3 / 2; } .r3-ar-4x3 { aspect-ratio: 4 / 3; }
.r3-ar-1x1 { aspect-ratio: 1; } .r3-ar-4x5 { aspect-ratio: 4 / 5; } .r3-ar-3x4 { aspect-ratio: 3 / 4; } .r3-ar-9x16 { aspect-ratio: 9 / 16; }
/* a photograph that dissolves into the plane below it (its black point equals the page ground); the melt is INSIDE the photograph, never a hard edge (panel 12) */
.r3-photo--melt::before { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: var(--r3-fade); z-index: 2; pointer-events: none;
  background: linear-gradient(180deg, rgba(12, 12, 15, 0), var(--r3-melt, var(--r3-c-void))); }
.r3-soft-top { -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 var(--r3-fade)); mask-image: linear-gradient(180deg, transparent 0, #000 var(--r3-fade)); }
.r3-soft-bottom { -webkit-mask-image: linear-gradient(0deg, transparent 0, #000 var(--r3-fade)); mask-image: linear-gradient(0deg, transparent 0, #000 var(--r3-fade)); }
.r3-soft { -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 var(--r3-fade), #000 calc(100% - var(--r3-fade)), transparent 100%); mask-image: linear-gradient(180deg, transparent 0, #000 var(--r3-fade), #000 calc(100% - var(--r3-fade)), transparent 100%); }
/* caption plate on a photograph (W-35): fixed fill so contrast never depends on the picture. The disclosure keeps its "påhittat" wording (TRUTH rule). */
.r3-plate-cap { position: absolute; left: 14px; bottom: 14px; z-index: 3; max-width: min(320px, calc(100% - 28px)); padding: 10px 14px; border-radius: 12px; background: #EDE7DA; color: #141317; font: 500 .8125rem/1.35 var(--r3-f-text); }
.r3-plate-cap--dark { background: rgba(12, 12, 15, .88); color: #F3F0EA; }

/* ================================ 7. DEVICES (THE STAGE) ================================ */
/* A device shows a real full-page capture of a finished example site (assets/zs/img/r3-shot-<id>-d|m.webp, regions in r3-shots.json).
     <figure class="r3-dev tier-growth" data-r3-dev data-r3-pan="scrub|auto|user|beat|rest" data-r3-rest=".12">
       <div class="r3-dev__bar"><i></i><i></i><i></i><b>Kvarteret</b></div>
       <div class="r3-dev__view"><div class="r3-dev__page"><img class="r3-dev__shot" src="..." alt="..."> [pins] </div></div>
     </figure>
   The page is translated by --r3-f (0..1) x --r3-travel (px, measured by r3-core.js). Without JS it rests at --r3-rest (default top). */
.r3-dev { --r3-bar: 34px; position: relative; margin: 0; border-radius: var(--r3-radius); overflow: hidden; background: #0C0C0F; color: #F3F0EA;
  box-shadow: 0 0 0 1px rgba(243, 240, 234, .14), inset 0 1px 0 rgba(255, 255, 255, .08), 0 50px 90px -40px rgba(0, 0, 0, .75), 0 30px 100px -34px rgba(var(--r3-glow), .30); }
.r3-dev__bar { display: flex; align-items: center; gap: 7px; height: var(--r3-bar); padding: 0 14px; background: #1A1A21; }
.r3-dev__bar i { width: 9px; height: 9px; border-radius: 50%; background: #3A3A44; flex: none; }
.r3-dev__bar b { margin-left: 10px; font: 600 13px/1 var(--r3-f-text); letter-spacing: .01em; color: #D9D4CA; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.r3-dev__view { position: relative; overflow: hidden; aspect-ratio: var(--r3-ar, 16 / 10); background: #EFEAE2; }
.r3-dev__page { position: absolute; left: 0; top: 0; width: 100%;
  transform: translate3d(0, calc(var(--r3-f, var(--r3-rest, 0)) * var(--r3-travel, 0px) * -1), 0); will-change: transform; }
.r3-dev__shot { display: block; width: 100%; height: auto; max-width: none; }
.r3-dev--glide .r3-dev__page { transition: transform var(--r3-d-glide) var(--r3-ease); }   /* beat driven: the page glides to its mark */
/* user mode: the visitor scrolls the site inside the window (wheel, touch, keys). Scroll chaining returns to the page at the ends. */
.r3-dev__view[data-user] { overflow-y: auto; overflow-x: hidden; scrollbar-width: thin; scrollbar-color: rgba(20, 19, 23, .35) transparent; overscroll-behavior: auto; }
.r3-dev__view[data-user] .r3-dev__page { position: relative; transform: none; }
.r3-dev__view[data-user]:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; box-shadow: none; }
/* control inside the frame (pause / play) */
.r3-dev__ctl { position: absolute; right: 12px; bottom: 12px; z-index: 4; min-height: 36px; padding: 0 14px; border-radius: 999px; border: 1px solid rgba(243, 240, 234, .35);
  background: rgba(12, 12, 15, .76); color: #F3F0EA; font: 600 13px/1 var(--r3-f-text); cursor: pointer; }
.r3-dev__ctl[hidden] { display: none; }
.r3-dev__ctl:focus-visible { outline: 2px solid #DCBC7E; outline-offset: 2px; box-shadow: none; }
/* a film that plays INSIDE the frame, over the screenshot's own film band (W-70 in C): position it with --fx/--fy/--fw/--fh in % of the page */
.r3-dev__film { position: absolute; left: calc(var(--fx, 0) * 1%); top: calc(var(--fy, 0) * 1%); width: calc(var(--fw, 100) * 1%); height: calc(var(--fh, 20) * 1%); object-fit: cover; opacity: 0; transition: opacity .6s var(--r3-ease); }
.r3-dev__film.is-playing { opacity: 1; }
/* pins: numbered hot spots on the page, moving with it (the booking button, the contact form) */
.r3-pin { position: absolute; left: calc(var(--px) * 1%); top: calc(var(--py) * 1%); width: 30px; height: 30px; margin: -15px 0 0 -15px; border-radius: 50%;
  display: grid; place-items: center; background: #0C0C0F; color: #F3F0EA; font: 600 12px/1 var(--r3-f-display); font-variant-numeric: lining-nums proportional-nums;
  box-shadow: 0 0 0 2px var(--r3-pin, #DCBC7E), 0 0 0 9px rgba(220, 188, 126, .28), 0 8px 18px rgba(0, 0, 0, .4); opacity: 1; z-index: 3;
  transition: opacity var(--r3-d-ui) var(--r3-ease-out), transform var(--r3-d-ui) var(--r3-ease-out); }
/* pins are always visible (the static state shows them all); the pin of the beat being read is full size and pulses, the others are quieter */
.r3-dev [data-r3-pin]:not(.is-on) { opacity: .62; transform: scale(.86); }
.r3-dev [data-r3-pin].is-on { opacity: 1; transform: none; }
/* breakpoint variants of one device: <picture> swaps the desktop capture for the phone capture below 1100 px; pins and targets exist twice (.r3-pin--d / .r3-pin--m,
   data-r3-at-map / data-r3-at-map-m) because the two layouts differ. On phones the browser bar is dropped and the window is a full-width slice (--r3-ar-m). */
.r3-pin--m { display: none; }
@media (max-width: 1099px) {
  .r3-pin--d { display: none; } .r3-pin--m { display: grid; }
  .r3-dev--bp { --r3-bar: 0px; --r3-ar: var(--r3-ar-m, 358 / 240); border-radius: 12px; }
  .r3-dev--bp .r3-dev__bar { display: none; }
}
/* phone: the stage window sticks under the header while the beats scroll below it (not on very short screens) */
@media (max-width: 1099px) and (min-height: 700px) {
  .r3-sticky--m { position: sticky; top: calc(var(--nav-h, 68px) + 6px); z-index: 6; padding: 8px 0 14px; margin-inline: calc(-1 * var(--gutter, 16px)); padding-inline: var(--gutter, 16px); background: var(--bg); }
  .r3-sticky--m::after { content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 14px; background: var(--bg); -webkit-mask-image: linear-gradient(180deg, #000, transparent); mask-image: linear-gradient(180deg, #000, transparent); pointer-events: none; }
}
/* phone frame */
.r3-dev--phone { --r3-bar: 0px; width: var(--r3-pw, 260px); aspect-ratio: 9 / 19.5; border-radius: 11% / 5.1%; padding: 2.4%; background: #0C0C0F; }
.r3-dev--phone::before { content: ""; position: absolute; top: 3.4%; left: 50%; width: 26%; height: 2.1%; translate: -50% 0; border-radius: 99px; background: #000; z-index: 5; }
.r3-dev--phone .r3-dev__bar { display: none; }
.r3-dev--phone .r3-dev__view { aspect-ratio: auto; height: 100%; border-radius: 9% / 4.2%; }
/* browser + phone pair: the phone overlaps the browser's lower right corner and arrives with the section (W-102) */
.r3-pair { position: relative; padding-bottom: 7%; }
.r3-pair > .r3-dev--phone { position: absolute; right: -3%; bottom: 0; --r3-pw: 22%; width: 22%; translate: 0 calc((1 - var(--r3-pp, 1)) * 70px); z-index: 3; }
@media (max-width: 767px) {
  .r3-pair { padding-bottom: 0; }
  .r3-pair > .r3-dev:not(.r3-dev--phone) { display: none; }                    /* phones: the phone frame alone is what a visitor on a phone sees */
  .r3-pair > .r3-dev--phone { position: relative; right: auto; width: min(66vw, 280px); margin-inline: auto; translate: none; }
}
/* print: a still with a mat (W-64). One constant tilt for a set; dark theme gets a ring + a tier-tinted fall-off because black shadows vanish on black */
.r3-print { padding: 5px; border-radius: 16px; background: #26262E; transform: rotate(1.2deg);
  box-shadow: 0 0 0 1px var(--line), inset 0 1px 0 rgba(255, 255, 255, .14), 0 2.5px 4.4px rgba(0, 0, 0, .06), 0 6.4px 11.5px rgba(0, 0, 0, .16), 0 10.8px 50px rgba(0, 0, 0, .13), 0 30.8px 18px rgba(0, 0, 0, .13), 0 46px 80px -30px rgba(var(--r3-glow), .30); }
.r3-print img { display: block; width: 100%; border-radius: 11px; }
[data-theme="light"] .r3-dev { box-shadow: 0 0 0 1px rgba(20, 19, 23, .12), 0 2.5px 4.4px rgba(20, 19, 23, .06), 0 6.4px 11.5px rgba(20, 19, 23, .16), 0 30.8px 38px rgba(20, 19, 23, .12), 0 55px 70px -20px rgba(20, 19, 23, .12); }
[data-theme="light"] .r3-print { background: #fff; box-shadow: 0 0 0 1px rgba(20, 19, 23, .08), 0 6.4px 11.5px rgba(20, 19, 23, .16), 0 55px 33px rgba(20, 19, 23, .10); }
/* a device inside a dark/walnut/night plane in the light theme keeps the dark-ground shadow */
.r3-tone-void .r3-dev, .r3-tone-night .r3-dev, .r3-tone-walnut .r3-dev { box-shadow: 0 0 0 1px rgba(243, 240, 234, .14), inset 0 1px 0 rgba(255, 255, 255, .08), 0 50px 90px -40px rgba(0, 0, 0, .75), 0 30px 100px -34px rgba(var(--r3-glow), .30); }

/* ================================ 7b. WORLDS (the stage takes the tone of the selected example) ================================ */
/* G-105 + G-106 + G-108: the plane behind a device and the light under it follow the example that is shown. Dark theme: a tint 1.05-1.09:1 from the page
   ground (so no band appears, the glow and the frame carry the world). Light theme: the example's own paper. Registered so the change animates (.9 s). */
@property --r3-w { syntax: "<color>"; inherits: true; initial-value: #0C0C0F; }
@property --r3-glow { syntax: "<number>#"; inherits: true; initial-value: 216, 210, 198; }
.r3-worldhost { transition: --r3-w .9s var(--r3-ease), --r3-glow .9s var(--r3-ease); }
.r3-world-glod { --r3-w: #211914; --r3-glow: 217, 150, 70; }
.r3-world-norr { --r3-w: #21171E; --r3-glow: 200, 120, 150; }
.r3-world-lumen { --r3-w: #29231F; --r3-glow: 222, 204, 184; }
.r3-world-kvarteret { --r3-w: #1C100F; --r3-glow: 168, 66, 56; }
.r3-world-smula { --r3-w: #121912; --r3-glow: 236, 214, 130; }
.r3-world-alina { --r3-w: #1C130F; --r3-glow: 160, 96, 118; }
[data-theme="light"] .r3-world-smula { --r3-w: #F9E9B4; } [data-theme="light"] .r3-world-kvarteret { --r3-w: #F3ECDD; }
[data-theme="light"] .r3-world-norr { --r3-w: #F2EDE8; } [data-theme="light"] .r3-world-lumen { --r3-w: #F4F0E9; }
[data-theme="light"] .r3-world-alina { --r3-w: #F7F1E8; } [data-theme="light"] .r3-world-glod { --r3-w: #2A1F18; }
.r3-tone-world { --r3-c: var(--r3-w); }
.r3-stage__glow { position: absolute; inset: -12% -8% -20%; z-index: -1; pointer-events: none; background: radial-gradient(closest-side, rgba(var(--r3-glow), .26), rgba(var(--r3-glow), 0)); }

/* ================================ 7c. STACK, MOVING BELT, DIAL ================================ */
/* STACK (W-64): the page set of a site as a fan of prints, front sheet bottom-left, each further sheet one step up and to the right (--k = 0 front). */
.r3-stack { position: relative; aspect-ratio: var(--r3-ar, 16 / 10.5); }
.r3-stack > * { position: absolute; left: 0; bottom: 0; width: 70%; margin: 0; --k: 0;
  transform: translate(calc(var(--k) * 10.4%), calc(var(--k) * -8.4%)) rotate(calc(var(--k) * .55deg)); z-index: calc(10 - var(--k));
  transition: transform var(--r3-d-glide) var(--r3-ease) calc(var(--k) * 45ms); }
.lib-on .r3-stack:not(.is-in) > * { transform: translate(0, 0); }
.r3-stack > * .r3-dev__view { aspect-ratio: 16 / 10; }
.r3-stack figcaption { position: absolute; left: 0; right: 0; bottom: -26px; font: 500 .8125rem/1.2 var(--r3-f-text); color: var(--ink-2); opacity: 0; }
.r3-stack > :first-child figcaption { opacity: 1; }
/* MOVING BELT (the "rörligt galleri" form of Growth's one moving element): a doubled track that drifts; runs only while its layer is shown, has a real pause control */
@keyframes r3-marq { to { transform: translate3d(calc(-50% - 7px), 0, 0); } }
.r3-marq { overflow: hidden; border-radius: var(--r3-radius); position: relative; }
.r3-marq__t { display: flex; gap: 14px; width: max-content; animation: r3-marq var(--r3-marq-d, 46s) linear infinite; animation-play-state: paused; }
.r3-layer.is-on .r3-marq__t, .r3-marq.is-run .r3-marq__t { animation-play-state: running; }
.r3-marq.is-paused .r3-marq__t { animation-play-state: paused !important; }
.r3-marq figure { margin: 0; flex: none; width: clamp(150px, 15vw, 210px); aspect-ratio: 4 / 5; border-radius: 12px; overflow: hidden; }
.r3-marq figure img { width: 100%; height: 100%; object-fit: cover; display: block; }
.r3-marq__ctl { position: absolute; right: 12px; top: 12px; z-index: 3; min-height: 36px; padding: 0 14px; border-radius: 999px; border: 1px solid rgba(243, 240, 234, .35); background: rgba(12, 12, 15, .76); color: #F3F0EA; font: 600 13px/1 var(--r3-f-text); cursor: pointer; }
.no-motion .r3-marq__t, .r3-marq.is-reduced .r3-marq__t { animation: none !important; }
@media (prefers-reduced-motion: reduce) { .r3-marq__t { animation: none !important; } .r3-marq__ctl { display: none; } }
/* DIAL: a ring that fills to --v (0..1) with a numeral in the middle ("30" minutes) */
.r3-dial { --v: 1; position: relative; width: var(--r3-dial, 150px); aspect-ratio: 1; border-radius: 50%; display: grid; place-items: center; text-align: center;
  background: conic-gradient(var(--tier, var(--ink)) calc(var(--v) * 360deg), var(--line) 0);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px)); mask: radial-gradient(farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px)); }
.r3-dialwrap { position: relative; width: var(--r3-dial, 150px); aspect-ratio: 1; display: grid; place-items: center; }
.r3-dialwrap > .r3-dial { position: absolute; inset: 0; width: 100%; }
.r3-dialwrap > span { position: relative; font: 500 calc(var(--r3-dial, 150px) * .36)/1 var(--r3-f-display); letter-spacing: -.04em; font-variant-numeric: lining-nums proportional-nums; }
.lib-on .r3-dial { --v: 0; transition: --v 1.6s var(--r3-ease); }
.lib-on .is-in .r3-dial, .lib-on .r3-dial.is-in { --v: 1; }
@property --v { syntax: "<number>"; inherits: true; initial-value: 1; }

/* ================================ 8. STAGE LAYOUTS ================================ */
/* two columns: copy + stage (hero), or beats + sticky stage (W-15 / W-95). Below 1100 px everything stacks with the stage first. */
.r3-stage { display: grid; gap: var(--r3-sec) var(--r3-gap-x, 40px); }
.r3-stage__head { min-width: 0; }
.r3-stage__view { min-width: 0; position: relative; }
@media (min-width: 1100px) {
  .r3-stage { grid-template-columns: var(--r3-cols, minmax(0, 5fr) minmax(0, 7fr)); align-items: center; --r3-gap-x: clamp(48px, 5vw, 96px); }
  .r3-stage--top { align-items: start; }
  .r3-stage--top > .r3-stage__view { align-self: stretch; }   /* full row height, so a .r3-sticky inside can travel the whole scene */
  .r3-stage--flip { direction: rtl; } .r3-stage--flip > * { direction: ltr; }
  .r3-sticky { position: sticky; top: calc(var(--nav-h, 68px) + 28px); }
  .r3-bleed-r { margin-right: calc(-1 * max(var(--gutter, 32px), (100vw - var(--wrap, 1320px)) / 2)); }   /* the stage runs off the right edge */
}
@media (max-width: 1099px) { .r3-stage--stage-first > .r3-stage__view { order: -1; } }
.r3-beats { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; counter-reset: beat; }
.r3-beat { position: relative; display: grid; grid-template-columns: min(3rem, 48px) 1fr; column-gap: 16px; padding: 28px 0; }
.r3-beat > div { container-type: inline-size; }   /* b6 fix74: the heading cap follows the text column */
.r3-beat > .r3-n { padding-top: .55em; }
.r3-beat h3 { margin: 0 0 8px; font: 500 var(--r3-t-h3)/1.1 var(--r3-f-display); letter-spacing: -.02em; color: var(--ink); }
.tier-premium .r3-beat h3 { font-family: var(--r3-f-serif); font-weight: 600; font-size: clamp(1.7rem, 1.25rem + 1.5vw, 2.5rem); line-height: 1.04; }
.r3-beat p { margin: 0; color: var(--ink-2); max-width: 32em; }
@media (min-width: 1100px) {
  .r3-beats--tall { padding-bottom: 34vh; }                       /* keeps the sticky stage pinned until the last beat has been read */
  .r3-beats--tall .r3-beat { min-height: 38vh; align-content: center; }
  @supports (height: 1svh) { .r3-beats--tall { padding-bottom: 34svh; } .r3-beats--tall .r3-beat { min-height: 38svh; } }   /* FXF 7: svh twin of the two vh boxes above */
  .r3-beat::before { content: ""; position: absolute; left: -22px; top: calc(50% - 26px); width: 2px; height: 52px; background: var(--tier, var(--accent)); transform: scaleY(0); transform-origin: 50% 0; transition: transform .6s var(--r3-ease); }
  .r3-beat.is-on::before { transform: none; }
}
/* the inline picture of a beat: shown on phones and when no sticky stage exists; hidden when the sticky stage takes over (>= 1100) */
.r3-beat__inline { grid-column: 1 / -1; margin: 18px 0 0; }
@media (min-width: 1100px) { [data-r3-sync] .r3-beat__inline { display: none; } }
.r3-count { display: inline-flex; align-items: center; gap: 12px; font: 500 1rem/1.1 var(--r3-f-display); letter-spacing: .08em; font-variant-numeric: lining-nums proportional-nums; }
.r3-count__odo { height: 1.1em; overflow: hidden; }
.r3-count__odo > span { display: block; height: 1.1em; transform: translateY(calc(var(--i, 0) * -1.1em)); transition: transform .5s var(--r3-ease); }
.r3-count__rail { width: 56px; height: 2px; background: var(--line); position: relative; }
.r3-count__rail::after { content: ""; position: absolute; inset: 0; background: var(--tier, var(--ink)); transform-origin: 0 50%; transform: scaleX(calc((var(--i, 0) + 1) / var(--n, 3))); transition: transform .5s var(--r3-ease); }
/* layers inside a sticky stage: crossfade (opacity only), one is-on at a time */
.r3-layers { position: relative; display: grid; }
.r3-layer { grid-area: 1 / 1; opacity: 0; visibility: hidden; transition: opacity var(--r3-d-swap) var(--r3-ease-io), visibility 0s var(--r3-d-swap); }
.r3-layer.is-on, .r3-layer:first-child:not(.r3-layer--lazy) { opacity: 1; visibility: visible; transition-delay: 0s; transition-timing-function: var(--r3-ease-in); }
.r3-ready .r3-layer:first-child:not(.is-on) { opacity: 0; visibility: hidden; }
html:not(.js) .r3-layer { opacity: 1; visibility: visible; grid-area: auto; }

/* ================================ 9. SWITCHER AND CHIPS ================================ */
/* tablist + crossfading panels (W-94). The first panel is is-on in the markup, so the static page is a finished composition. */
.r3-tabs { display: flex; flex-wrap: nowrap; gap: 6px; padding: 5px; border-radius: 999px; background: var(--r3-wash); width: max-content; max-width: 100%; overflow-x: auto; scrollbar-width: none; scroll-snap-type: x proximity; }
.r3-tabs::-webkit-scrollbar { display: none; }
.r3-tab { flex: none; scroll-snap-align: center; min-height: 44px; padding: 0 18px; border: 0; border-radius: 999px; background: transparent; color: var(--ink-2); font: 600 .875rem/1 var(--r3-f-text); cursor: pointer;
  transition: background var(--r3-d-ui) var(--r3-ease-out), color var(--r3-d-ui) var(--r3-ease-out); }
.r3-tab:hover { color: var(--ink); }
.r3-tab[aria-selected="true"] { background: var(--btn-bg, #F3F0EA); color: var(--btn-ink, #0C0C0F); }
.r3-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; box-shadow: none; }
.r3-panels { display: grid; position: relative; }
.r3-panel { grid-area: 1 / 1; min-width: 0; opacity: 0; visibility: hidden; scale: .97; pointer-events: none;
  transition: opacity var(--r3-d-swap) var(--r3-ease-io), scale var(--r3-d-swap) var(--r3-ease-io), visibility 0s var(--r3-d-swap); }
.r3-panel.is-on { opacity: 1; visibility: visible; scale: 1; pointer-events: auto; z-index: 2; transition-delay: 0s; transition-timing-function: var(--r3-ease-in); }
.r3-panel.was-on { scale: 1.02; }
html:not(.js) .r3-panel { opacity: 1; visibility: visible; scale: 1; pointer-events: auto; grid-area: auto; margin-bottom: 24px; }
/* round thumbnail chips: the page / site selector (G-92). 56 px (48 on phones), ring + 1.14 scale on the active one. */
.r3-chips { display: flex; flex-wrap: nowrap; align-items: flex-start; gap: 14px; overflow-x: auto; scroll-snap-type: x proximity; scrollbar-width: none; padding: 8px 4px; }
.r3-chips::-webkit-scrollbar { display: none; }
.r3-chip { flex: none; display: grid; justify-items: center; gap: 8px; width: 72px; border: 0; background: transparent; color: var(--ink-2); font: 500 .8125rem/1.25 var(--r3-f-text); text-align: center; cursor: pointer; scroll-snap-align: center; }
.r3-chip__img { width: 52px; height: 52px; border-radius: 50%; overflow: hidden; background: #1A1A21 center / cover no-repeat; box-shadow: 0 0 0 1px var(--line);
  transition: transform var(--r3-d-ui) var(--r3-ease-out), box-shadow var(--r3-d-ui) var(--r3-ease-out); }
.r3-chip__img img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.r3-chip[aria-selected="true"] { color: var(--ink); }
.r3-chip[aria-selected="true"] .r3-chip__img { transform: scale(1.14); box-shadow: 0 0 0 2px var(--tier, var(--ink)), 0 8px 22px rgba(0, 0, 0, .35); }
.r3-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; box-shadow: none; border-radius: 12px; }
.r3-chip--page { width: 112px; }                                                   /* labelled page thumbnail (Growth's five pages) */
.r3-chip--page .r3-chip__img { width: 112px; height: 70px; border-radius: 8px; }
.r3-chip--page[aria-selected="true"] .r3-chip__img { transform: none; }
@media (max-width: 559px) { .r3-chip__img { width: 48px; height: 48px; } .r3-chip { width: 66px; } .r3-chip--page { width: 104px; } .r3-chip--page .r3-chip__img { width: 104px; height: 64px; } }

/* ================================ 10. WORD INDEX WITH PREVIEW ================================ */
/* big type rows, one lit, a picture answers (W-72, G-94). Rows are real links; hover, focus and tap all set --on (r3-core.js). Row 1 is lit at rest.
     <div class="r3-index" data-r3-index style="--on:0"> <ol class="r3-index__rows"><li><a href="..." data-i="0">..</a></li></ol>
       <div class="r3-index__pv"><figure class="r3-index__img" style="--i:0"><img ..></figure>...</div></div> */
.r3-index { --on: 0; display: grid; gap: var(--r3-sec) 48px; }
.r3-index__rows { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.r3-index__rows li { border-bottom: 1px solid var(--line); }
.r3-index__rows a { display: grid; grid-template-columns: 3.4rem minmax(0, 1fr) auto; align-items: baseline; gap: 0 16px; padding: 22px 14px; text-decoration: none; color: var(--ink-3);
  font: 500 var(--r3-idx-fs, clamp(1.7rem, 1.2rem + 2vw, 3rem))/1.08 var(--r3-f-display); letter-spacing: -.025em;
  background: linear-gradient(var(--ink), var(--ink)) 0 100% / 100% 0 no-repeat;
  transition: background-size var(--r3-d-ui) var(--r3-ease-out), color var(--r3-d-ui) var(--r3-ease-out); }
.r3-index__t { display: block; transition: transform var(--r3-d-ui) var(--r3-ease-out); }
.tier-premium .r3-index__rows a { font-family: var(--r3-f-serif); font-weight: 600; }
.r3-index__rows a .r3-n { color: inherit; }
.r3-index__rows a small { font: 400 var(--r3-t-small)/1.4 var(--r3-f-text); letter-spacing: 0; color: inherit; opacity: .8; text-align: right; }
.r3-index__rows a:is(:hover, :focus-visible), .r3-index__rows a[aria-current="true"] { color: var(--bg); background-size: 100% 100%; }
.r3-index__rows a:is(:hover, :focus-visible) .r3-index__t, .r3-index__rows a[aria-current="true"] .r3-index__t { transform: translateX(.3em); }
.r3-index__rows a:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; box-shadow: none; }
.r3-index__pv { position: relative; aspect-ratio: var(--r3-pv-ar, 16 / 9); border-radius: var(--r3-radius); overflow: hidden; background: #1A1A21; box-shadow: 0 0 0 1px var(--line-2); }
.r3-index__img { position: absolute; inset: 0; margin: 0; opacity: calc(1 - min(1, max(var(--on) - var(--i), var(--i) - var(--on)))); transition: opacity .5s var(--r3-ease-out); }
.r3-index__img img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }
@media (min-width: 900px) { .r3-index { grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); align-items: start; } .r3-index__pv { position: sticky; top: calc(var(--nav-h, 68px) + 28px); } }
@media (max-width: 899px) {
  /* phones: no sticky pane, each row carries its own thumbnail (CSS custom property --th set on the li) */
  .r3-index__pv { display: none; }
  .r3-index__rows a { grid-template-columns: 76px minmax(0, 1fr); gap: 4px 14px; align-items: center; color: var(--ink); }
  .r3-index__rows a::before { content: ""; grid-row: 1 / span 2; width: 76px; aspect-ratio: 16 / 10; border-radius: 6px; background: var(--th) top / cover no-repeat, #1A1A21; }
  .r3-index__rows a .r3-n { display: none; }
  .r3-index__rows a small { grid-column: 2; text-align: left; }
  .r3-index__rows a:is(:hover, :focus-visible), .r3-index__rows a[aria-current="true"] { color: var(--ink); background-size: 0 0; }
  .r3-index__rows a .r3-index__t { transform: none !important; }
  .r3-index__rows a { padding-inline: 0; }
}

/* ================================ 11. ARC (the example line-up) ================================ */
/* a bowl of tilted cards on a stage glow, outer cards soft (G-56 + G-28; Carousel template 56). One --k per card (-3 .. 3).
   Phones: a scroll-snap rail, no 3D. Reduced motion: at rest on the first card; the arrow buttons still step it. */
.r3-arc { --cw: clamp(176px, 16vw, 244px); position: relative; height: calc(var(--cw) * 1.25 + 56px); perspective: 1500px; perspective-origin: 50% 38%; }
.r3-arc::before { content: ""; position: absolute; left: 50%; bottom: -14%; width: 80%; height: 60%; translate: -50% 0; z-index: 0; pointer-events: none;
  background: radial-gradient(closest-side, rgba(var(--r3-glow), .22), rgba(var(--r3-glow), 0)); }
.r3-arc__c { position: absolute; left: 50%; top: 0; width: var(--cw); margin-left: calc(var(--cw) / -2); aspect-ratio: 4 / 5; overflow: hidden; border-radius: 14px; background: #1A1A21; display: block; text-decoration: none; color: inherit;
  transform: translate3d(calc(var(--k, 0) * var(--cw) * 1.04), calc(var(--k, 0) * var(--k, 0) * 18px), calc(var(--k, 0) * var(--k, 0) * -70px)) rotateY(calc(var(--k, 0) * -12deg));
  filter: blur(calc(max(0, var(--k, 0) * var(--k, 0) - 1) * 1.7px)) brightness(calc(1 - var(--k, 0) * var(--k, 0) * .045));
  opacity: calc(1 - max(0, var(--k, 0) * var(--k, 0) - 9) * 1);
  box-shadow: 0 0 0 1px rgba(243, 240, 234, .14), 0 40px 70px -30px rgba(0, 0, 0, .8); z-index: calc(10 - var(--k, 0) * var(--k, 0)); }
.r3-arc.is-live .r3-arc__c { transition: transform var(--r3-d-glide) var(--r3-ease), filter var(--r3-d-glide) var(--r3-ease), opacity var(--r3-d-glide) var(--r3-ease); }
.r3-arc__c img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }
.r3-arc__c:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; box-shadow: none; }
.r3-arc__c figcaption, .r3-arc__lab { position: absolute; left: 0; right: 0; bottom: 0; padding: 28px 12px 10px; background: linear-gradient(180deg, transparent, rgba(12, 12, 15, .82)); font: 600 .8125rem/1.25 var(--r3-f-text); color: #F3F0EA; opacity: calc(1 - min(1, max(var(--k, 0), -1 * var(--k, 0)))); }
.r3-arc__ctl { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 18px; }
.r3-arc__ctl button { min-height: 40px; min-width: 40px; border-radius: 999px; border: 1px solid var(--line); background: transparent; color: var(--ink); font: 600 .8125rem/1 var(--r3-f-text); padding: 0 14px; cursor: pointer; }
.r3-arc__ctl button:hover { border-color: var(--ink-2); }
@media (max-width: 1099px) {
  .r3-arc { height: auto; perspective: none; display: flex; gap: 12px; overflow-x: auto; scroll-snap-type: x mandatory; padding: 4px var(--gutter, 16px) 14px; margin-inline: calc(-1 * var(--gutter, 16px)); scrollbar-width: none; }
  .r3-arc::-webkit-scrollbar, .r3-arc::before { display: none; }
  .r3-arc__c { position: relative; left: auto; top: auto; margin: 0; flex: 0 0 min(72vw, 280px); transform: none !important; filter: none !important; opacity: 1 !important; scroll-snap-align: center; z-index: auto; }
  .r3-arc__c figcaption, .r3-arc__lab { opacity: 1; }
  .r3-arc__ctl [data-r3-arc-prev], .r3-arc__ctl [data-r3-arc-next] { display: none; }
}

/* ================================ 12. BELT OF SOFT CARDS ================================ */
/* Mythos00 screen 02: a horizontal belt of soft rounded paper cards over a held photograph (G-78 edge bleed + W-26). Native scroll-snap, no JS.
   Cards carry a FIXED paper fill, so contrast never depends on the photograph. The last card is cut by the viewport edge to say "more". */
.r3-belt { display: flex; gap: 14px; overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--r3-belt-pad, var(--gutter, 16px)); padding: 6px var(--r3-belt-pad, var(--gutter, 16px)) 18px; scrollbar-width: none; overscroll-behavior-x: contain; }
.r3-belt::-webkit-scrollbar { display: none; }
.r3-card { flex: 0 0 min(78%, 296px); scroll-snap-align: start; display: flex; flex-direction: column; gap: 14px; min-height: 280px; padding: 24px; border-radius: 28px; background: #EDE7DA; color: #141317;
  box-shadow: 0 30px 60px -34px rgba(0, 0, 0, .6); }
.r3-card .r3-n { color: #55505B; }
.r3-card__t { margin: 0; font: 500 clamp(1.6rem, 1.3rem + 1.1vw, 2.1rem)/1.02 var(--r3-f-display); letter-spacing: -.03em; color: #141317; }
.tier-premium .r3-card__t { font-family: var(--r3-f-serif); font-weight: 600; letter-spacing: -.015em; }
.r3-card p { margin: auto 0 0; font: 400 .9375rem/1.5 var(--r3-f-text); color: #46424C; }
@media (min-width: 1100px) { .r3-belt { --r3-belt-pad: max(var(--gutter, 32px), calc((100vw - var(--wrap, 1320px)) / 2)); } .r3-card { flex-basis: 296px; } }
.r3-belt-host { position: relative; isolation: isolate; overflow: hidden; }

/* ================================ 13. LEDGER AND SPEC ================================ */
/* ruled rows INSIDE content (the tone rule allows lines inside lists, tables and FAQ rows; it bans them between sections) */
.r3-ledger { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.r3-ledger--open { border-top: 0; }                      /* a ledger that opens a plane starts without a top rule (no line at the seam) */
.r3-ledger > li { display: grid; gap: 6px 32px; padding: 22px 0; border-bottom: 1px solid var(--line-2); }
@media (min-width: 768px) { .r3-ledger > li { grid-template-columns: var(--r3-lc, minmax(0, .8fr) minmax(0, 1.4fr)); align-items: baseline; } }
.r3-ledger h3, .r3-ledger strong { margin: 0; font: 500 var(--r3-t-h4)/1.25 var(--r3-f-display); color: var(--ink); letter-spacing: -.012em; }
.tier-premium .r3-ledger h3 { font-family: var(--r3-f-serif); font-weight: 600; font-size: clamp(1.4rem, 1.2rem + .8vw, 1.9rem); }
.r3-ledger p { margin: 0; color: var(--ink-2); max-width: 36em; }
/* label / value pairs (facts about an example: Bransch, Sidor, Rörligt, Bokning) */
.r3-spec { margin: 0; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px 22px; align-content: start; }
.r3-spec dt { font: 500 var(--r3-t-small)/1.5 var(--r3-f-text); color: var(--ink-3); }
.r3-spec dd { margin: 0; font: 500 var(--r3-t-small)/1.5 var(--r3-f-text); color: var(--ink); }
.tier-premium .r3-spec dd { font-family: var(--r3-f-serif); font-weight: 600; font-size: 1.15rem; line-height: 1.3; }
/* comparison table (restyled /paket table): no header slab, tinted column for the current tier (W-88), Premium values in serif, lining numerals */
.r3-table { width: 100%; border-collapse: collapse; table-layout: fixed; font: 400 var(--r3-t-small)/1.5 var(--r3-f-text); }
.r3-table th, .r3-table td { text-align: left; padding: 18px 16px 18px 0; border-bottom: 1px solid var(--line-2); vertical-align: top; }
.r3-table thead th { font: 600 .9375rem/1.3 var(--r3-f-display); color: var(--ink); border-bottom: 1px solid var(--line); padding-bottom: 14px; }
.r3-table tbody th, .r3-table thead th:first-child { font-weight: 500; color: var(--ink-3); width: 22%; }
.r3-table td { color: var(--ink); }
.r3-table [data-current] { background: var(--r3-wash); }
@supports (color: color-mix(in srgb, red 10%, blue)) { .r3-table [data-current] { background: color-mix(in srgb, var(--tier, var(--ink)) 9%, transparent); } }
.r3-table td.r3-prem { font: 600 clamp(1.15rem, 1rem + .6vw, 1.45rem)/1.25 var(--r3-f-serif); font-variant-numeric: lining-nums; }
@media (max-width: 767px) {
  .r3-table thead { display: none; }
  .r3-table tr { display: grid; padding: 14px 0; border-bottom: 1px solid var(--line-2); }
  .r3-table th, .r3-table td { border: 0; padding: 3px 0; width: auto !important; }
  .r3-table td[data-l]::before { content: attr(data-l); display: block; font: 500 .8125rem/1.6 var(--r3-f-text); color: var(--ink-3); }
}

/* FOLD: a block that is always open from 768 px and collapsed behind its heading on phones (the comparison table, a long ledger). The summary carries the
   block's existing heading, so nothing is added or removed; r3-core.js opens/closes it with the viewport. */
.r3-fold > summary { list-style: none; cursor: pointer; display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
.r3-fold > summary::-webkit-details-marker { display: none; }
.r3-fold > summary::after { content: "+"; font: 500 1.6rem/1 var(--r3-f-display); color: var(--ink-2); }
.r3-fold[open] > summary::after { content: "–"; }
@media (min-width: 768px) { .r3-fold > summary { pointer-events: none; cursor: default; } .r3-fold > summary::after, .r3-fold[open] > summary::after { content: none; } }
.r3-fold__body { padding-top: 18px; }

/* ================================ 14. ASIDE AND DOCK ================================ */
/* sticky price + ask beside long content (W-95), bottom dock on phones. Both use ONLY existing sentences (price line, the CTA). */
.r3-aside { position: sticky; top: calc(var(--nav-h, 68px) + 24px); align-self: start; display: grid; gap: 16px; padding: 24px; border-radius: var(--r3-radius-l); background: var(--surface); box-shadow: var(--elev); z-index: var(--r3-z-aside); }
[data-theme="dark"] .r3-aside { background: var(--surface-2); }
.r3-aside .r3-btn { width: 100%; }
/* DOCK (F3, panel 9): the phone's price + the one ask, fixed to the bottom once the hero CTA has scrolled away. While it is off screen it is NOT focusable:
   visibility hidden (CSS) + inert and aria-hidden (r3-core.js). The label "Be om en kostnadsfri skiss" is never clipped: below 381 px the dock stacks in two
   rows (price over a full-width button) instead of shrinking the label. */
.r3-dock { position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--r3-z-dock); display: none; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px var(--gutter, 16px) calc(8px + env(safe-area-inset-bottom)); isolation: isolate;   /* round 3a: ONE row of 64 px at every phone width (48 px ask + 2 x 8 px; it was 70 px from 381 px up) */
  transform: translateY(calc(100% + 48px)); visibility: hidden; transition: transform .4s var(--r3-ease), visibility 0s .4s; pointer-events: none; }
/* round 3a (P4-094): r3-core.js decides the dock before the first paint and adds .is-instant for two frames, so it is simply THERE at the first paint (no slide-in at load);
   every later change slides as before */
[data-r3-dock].is-instant { transition: none !important; }   /* any page's own dock class (Kvarteret .r3xk-dock too) */
/* F-26: the dock's box is SOLID page tone (no copy shows through the price or the button); the fade to the page lives ABOVE the box, 40 px tall (it was 18 px inside the padding, so
   a heading line showed through between the price and the button at 320 px). */
.r3-dock::before { content: ""; position: absolute; left: 0; right: 0; bottom: 0; top: -40px; z-index: -1; background: var(--bg); -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 40px); mask-image: linear-gradient(180deg, transparent 0, #000 40px); }
.r3-dock > * { pointer-events: auto; }
.r3-dock.is-on { transform: none; visibility: visible; transition-delay: 0s; }
.r3-dock .r3-price { flex-direction: column; align-items: flex-start; gap: 0; flex: none; }
.r3-dock .r3-price__n { font-size: 2.1rem; }
.r3-dock .r3-price__u { font-size: .875rem; line-height: 1.2; }                /* FXF 7: the unit is never below 14 px on a phone (it was 11 px) */
.r3-dock .r3-btn { flex: 1 1 auto; min-width: 0; --h: 48px; --fs: .9375rem; --px: 16px; }
/* FXF 7: with the unit at 14 px (125 px wide) the ask was only 212-221 px wide between 381 and 413 px, and its label clipped; a 14 px label with 12 px side padding fits that band (a 15 px label returns from 414 px) */
@media (min-width: 381px) and (max-width: 413px) { .r3-dock .r3-btn { --fs: .875rem; --px: 12px; } }
@media (max-width: 1023px) { html.js .r3-dock { display: flex; } html.js body.r3-has-dock { padding-bottom: calc(80px + (1rem - 16px) * 2); } }   /* b6 fix60: the reserve grows with the text size (the dock is 92-97 px at 200 %) */
/* F-26: <= 380 px the dock is ONE row, about 64 px (it was two rows, 100 px = 17.6 % of a 568 px screen): the price (figure over its 14 px unit) left, the ask right. The ask's label
   is never clipped: at 14 px with 12 px side padding it fits on one line from about 345 px and wraps to two centred lines below that. */
@media (max-width: 380px) {
  .r3-dock { flex-wrap: nowrap; justify-content: space-between; align-items: center; gap: 10px; padding-top: 8px; padding-bottom: calc(8px + env(safe-area-inset-bottom)); }
  .r3-dock .r3-price { flex-direction: column; align-items: flex-start; gap: 0; flex: 0 0 auto; }
  .r3-dock .r3-price__n { font-size: 1.75rem; line-height: 1; } .r3-dock .r3-price__u { font-size: .875rem; line-height: 1.15; }
  .r3-dock .r3-btn { flex: 1 1 0; min-width: 0; --h: 48px; --fs: .875rem; --px: 12px; white-space: normal; text-align: center; line-height: 1.15; padding-block: 5px; }
  html.js body.r3-has-dock { padding-bottom: calc(80px + (1rem - 16px) * 2); }
}
@media (max-height: 520px) { .r3-dock { display: none !important; } html.js body.r3-has-dock { padding-bottom: 0 !important; } }   /* landscape phones: no dock (the hero keeps price + ask in the fold) */

/* ================================ 15. COMPARE (W-96 mechanic) ================================ */
/* two same-size layers, the top one clipped by clip-path from a visually hidden but focusable range input (keyboard, touch, screen reader).
   Used for "Starter <-> Growth" on /paket (two real example sites at one scale). It never shows invented before/after results. */
.r3-cmp { --x: 50%; position: relative; border-radius: var(--r3-radius); overflow: hidden; touch-action: pan-y; background: #0C0C0F; box-shadow: 0 0 0 1px var(--line); }
.r3-cmp img { display: block; width: 100%; aspect-ratio: var(--r3-ar, 16 / 10); object-fit: cover; object-position: top; }
.r3-cmp__a { position: absolute; inset: 0; clip-path: inset(0 0 0 var(--x)); }
.r3-cmp__h { position: absolute; top: 0; bottom: 0; left: var(--x); width: 2px; margin-left: -1px; background: #fff; pointer-events: none; }
.r3-cmp__h::after { content: ""; position: absolute; top: 50%; left: 50%; width: 40px; height: 40px; margin: -20px 0 0 -20px; border-radius: 50%; background: #fff; box-shadow: 0 6px 20px rgba(0, 0, 0, .4); }
.r3-cmp input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; margin: 0; cursor: ew-resize; }
.r3-cmp input:focus-visible ~ .r3-cmp__h::after { outline: 3px solid var(--accent); outline-offset: 3px; }
.r3-cmp__l { position: absolute; top: 12px; z-index: 2; padding: 7px 12px; border-radius: 999px; background: rgba(12, 12, 15, .8); color: #F3F0EA; font: 600 .8125rem/1 var(--r3-f-text); pointer-events: none; }
.r3-cmp__l--a { right: 12px; } .r3-cmp__l--b { left: 12px; }

/* ================================ 16. SCROLL-INK STATEMENT ================================ */
/* a statement whose words ink in as it crosses the screen (r3-core.js writes --w per word). At rest and in every static state: full ink. */
.r3-ink { font: 500 clamp(1.7rem, 1.2rem + 2.3vw, 3.2rem)/1.16 var(--r3-f-display); letter-spacing: -.03em; color: var(--ink); max-width: 24em; margin: 0; text-wrap: balance; }
/* the unlit word keeps AA contrast: dim .48 on dark (4.53:1), .60 on light (4.65:1; .56 fails), measured in the W-38 study */
html .r3-ink { font-family: "R3 Statement", "ZS Grotesk Fallback", "Inter", system-ui, sans-serif; }   /* FXF round 2 F-07: the optional alias face, no late swap (section 0) */
.r3-ink.is-fontwait { visibility: hidden; }   /* r3-core.js: held (still laid out) until both weights of the statement face are in, at most 2.5 s */
.r3-ink { --r3-ink-dim: .48; }
[data-theme="light"] .r3-ink { --r3-ink-dim: .6; }
.r3-ink .w { opacity: calc(var(--r3-ink-dim) + (1 - var(--r3-ink-dim)) * var(--w, 1)); transition: opacity .15s linear; }
/* words that summon a picture (W-101): the words are real buttons; the three prints stand under the statement at every size (so the static state and phones
   show them), and the word under hover or focus lifts its print and quiets the others (r3-core.js sets data-hot on the host). */
.r3-sw { all: unset; cursor: pointer; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .14em; text-decoration-color: var(--line); border-radius: 6px; transition: background var(--r3-d-micro), color var(--r3-d-micro), padding var(--r3-d-micro); }
.r3-sw:is(:hover, :focus-visible, [aria-expanded="true"]) { background: var(--ink); color: var(--bg); padding: 0 .28em; text-decoration-color: transparent; }
.r3-sw:focus-visible { box-shadow: var(--focus); }
.r3-sc-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(12px, 2vw, 28px); margin-top: clamp(28px, 4vw, 56px); }
.r3-sc-row .r3-print { transition: transform .5s var(--r3-ease-out), opacity .5s var(--r3-ease-out), box-shadow .5s var(--r3-ease-out); }
.r3-sc-row .r3-print:nth-child(2) { transform: rotate(-1.2deg); }
[data-hot] .r3-sc-row .r3-print { opacity: .5; }
[data-hot="0"] .r3-sc-row > :nth-child(1), [data-hot="1"] .r3-sc-row > :nth-child(2), [data-hot="2"] .r3-sc-row > :nth-child(3) { opacity: 1; transform: translateY(-10px) rotate(0deg) scale(1.03); }
@media (max-width: 559px) { .r3-sc-row { grid-template-columns: 1fr 1fr; } .r3-sc-row > :nth-child(3) { display: none; } }

/* ================================ 17. REVEAL ================================ */
/* hidden start states only under .lib-on; r3-core.js adds .is-in once, from an IntersectionObserver. Failsafe after 2.5 s. */
.lib-on .r3-rise { opacity: 0; transform: translateY(var(--r3-rise)); transition: opacity var(--r3-d-reveal) var(--r3-ease) calc(var(--i, 0) * var(--r3-stagger)), transform var(--r3-d-reveal) var(--r3-ease) calc(var(--i, 0) * var(--r3-stagger)); }
.lib-on .r3-rise.is-in { opacity: 1; transform: none; }
.lib-on .r3-settle img, .lib-on .r3-settle video { transform: scale(1.05); transition: transform calc(var(--r3-d-reveal) * 1.25) var(--r3-ease); }
.lib-on .r3-settle.is-in img, .lib-on .r3-settle.is-in video { transform: none; }
/* the stage rises into place (inflouno: rise, .5 s power1.out). F-06 (LCP): the first-screen stage holds the LCP image, and an image under a hidden or fading ancestor is not
   painted as a candidate before the ancestor is done (LCP 1.3 s loopback / 1.9 s at 4x CPU vs 0.3-0.6 s in LC-R2). So the image is NEVER hidden: the stage only RISES (2 rem, .4 s,
   no hold) and the screen of the device is a dark veil that clears in .38 s ("the screen turns on"). The settle zoom is switched off on the first-screen stage (it ran 1.1 s on the
   LCP image). Everything hangs on html.lib-on; no-motion and reduced motion have the composed page at once. */
.lib-on .r3-stage-in { transform: translateY(2rem); transition: transform .4s var(--r3-ease-out); }
.lib-on .r3-stage-in.is-in { transform: none; }
.lib-on .r3-stage-in.r3-settle img, .lib-on .r3-stage-in.r3-settle video { transform: none; transition: none; }
.lib-on .r3-stage-in .r3-dev__view::before { content: ""; position: absolute; inset: 0; z-index: 6; pointer-events: none; background: #0C0C0F; opacity: 1; transition: opacity .38s var(--r3-ease-out); }
.lib-on .r3-stage-in.is-in .r3-dev__view::before { opacity: 0; }
@keyframes r3-fs-show { to { opacity: 1; transform: none; } }
@keyframes r3-fs-veil { to { opacity: 0; } }
.lib-on:not(.r3-ready) :is(.r3-rise, .r3-stage-in) { animation: r3-fs-show 0s 2.5s forwards; }
.lib-on:not(.r3-ready) .r3-stage-in .r3-dev__view::before { animation: r3-fs-veil 0s 2.5s forwards; }
.lib-on:not(.r3-ready) .r3-settle img { animation: r3-fs-show 0s 2.5s forwards; }

/* ================================ 18. ENDING PLATES ================================ */
/* The last 30 percent (BIBLE g): [proof / compare] -> [ASK, designed per tier] -> [limits and terms as a quiet colophon]. Trust copy is never
   the last thing before the ask. .r3-ask is the ask block; .r3-colophon the limits + terms ledger that follows it. */
.r3-ask { display: grid; gap: 28px; }
.r3-ask__q { font: 500 clamp(2.2rem, 1.3rem + 2.2vw, 3.1rem)/1.05 var(--r3-fam-h); font-weight: var(--r3-w-h); letter-spacing: var(--r3-ls-h2); margin: 0; text-wrap: balance; }
.r3-pricerow { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; align-items: end; list-style: none; margin: 0; padding: 0; }
.r3-pricerow li { display: grid; gap: 6px; }
.r3-colophon { display: grid; gap: var(--r3-sec) 48px; }
@media (min-width: 900px) { .r3-colophon { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
.r3-colophon .r3-chips-excl { list-style: none; margin: 18px 0 0; padding: 0; border-top: 1px solid var(--line); }
/* LIMITS LINE (panel 3): a compact "Ingår inte" line BEFORE the ask, so the limits are never after the CTA. Same words as the page's existing exclusion list
   (label + the five items), set as one wrapping line of quiet text; the full "Avtal och villkor" stays in the colophon AFTER the ask. Both are in the static page.
     <p class="r3-limits"><strong>Ingår inte i något paket</strong> <span>Item</span> <span>Item</span> ...</p>                                                       */
.r3-limits { margin: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 18px; font: 400 var(--r3-t-small)/1.5 var(--r3-f-text); color: var(--ink-2); }
.r3-limits strong { font-weight: 600; color: var(--ink); }
.r3-limits > span { position: relative; }
.r3-limits > span + span::before { content: ""; position: absolute; left: -11px; top: .62em; width: 3px; height: 3px; border-radius: 50%; background: var(--ink-3); }
.tier-premium .r3-limits { font-family: var(--r3-f-serif); font-weight: 600; font-size: 1.1875rem; }
.r3-colophon .r3-chips-excl li { padding: 14px 0; border-bottom: 1px solid var(--line-2); font: 400 var(--r3-t-body)/1.4 var(--r3-f-text); color: var(--ink); }
.tier-premium .r3-colophon .r3-chips-excl li { font: 600 1.3rem/1.3 var(--r3-f-serif); }

/* ================================ 18b. EXAMPLE-SITE ADAPTER ================================ */
/* The example sites (Kvarteret, Lumen, ...) define their own palette as --paper, --ink, --muted, --accent, --soft, --line on the body class. Put .r3-ex-map on the
   <body> of an example page and every r3 component used INSIDE the site (word index, location plate, ledger, chips) paints in the site's own palette. ZS-owned
   pieces on the same page (the sticky bottom bar, the closing package plane) take .r3-tone-void or .r3-tone-night, which reset the tokens to ZS ink. */
.r3-ex-map { --bg: var(--paper); --page-bg: var(--paper); --surface: var(--soft); --surface-2: var(--soft); --ink-2: var(--muted); --ink-3: var(--muted);
  --line-2: rgba(20, 19, 23, .14); --btn-bg: var(--ink); --btn-ink: var(--paper); --btn-bg-hover: var(--accent, var(--ink));
  --tier: var(--ink); --gold: var(--ink); --focus: 0 0 0 3px var(--paper), 0 0 0 5px var(--ink); --elev: 0 0 0 1px var(--line-2); --r3-c-page: var(--paper); --r3-c-lift: var(--soft); }

/* ================================ 19. NEUTRALISERS ================================ */
/* David's tone rule, applied once for every ZS page that loads zs-editorial.css: no hairline ornaments on section labels, no rail frames,
   no "+" crosshair marks, no hairline above the closing band. (Lines inside lists, tables and FAQ rows stay.) */
.kicker::after { content: none; }
.pm-frame { display: none; }
.pm-hero__marks { display: none; }
.pm-cta::before { content: none; }
.eyebrow-row { border-bottom: 0; }
.cta-band, .cta-home { border-top: 0; }
.nav.band-dark { border-bottom-color: transparent; }          /* the header over a dark plane has no hairline under it (the hero and the header are one tone) */

/* ================================ 19b. FOCUS, SCROLL PADDING, FIRST SCREEN, FALLBACKS (FXF, panel 2) ================================ */
/* FXF 2: the sticky header (and on phones the bottom dock) used to hide the control the keyboard had just focused. The browser scrolls a focused element into view
   INSIDE scroll-padding, so the padding is the header's height + 12 px at the top, and 96 px at the bottom where a dock exists (html.r3-has-dock is set by r3-core.js;
   the dock is off from 1024 px up and in landscape phones, so the padding is too). */
html { scroll-padding-top: calc(var(--nav-h, 68px) + 12px); }
@media (max-width: 1023px) and (min-height: 521px) { html.r3-has-dock { scroll-padding-bottom: 96px; } }
@media (max-width: 380px) and (min-height: 521px) { html.r3-has-dock { scroll-padding-bottom: 96px; } }   /* round 2: the dock is one row (about 64 px) from 380 px down, no longer two */
/* scroll-padding and a target's own scroll-margin ADD. Targets that used to clear the header by themselves (scroll-margin-top: header + 24 / + 28) would now land 80 px too low
   (measured: #exempel on Growth / Starter 92 -> 172 px from the top), so those few get a 12 px margin: with the 80 px padding they land exactly where they did (92 px). Targets
   with no margin (Premium #exempel, home #fragor) used to land UNDER the header (0 px) and now land at 80 px. */
html #exempel, html #innehall-lista, html #t1, html #t2, html #t3 { scroll-margin-top: 12px; }
html .r3x-s-doc__body h2 { scroll-margin-top: 16px; }
/* FXF 4: the current page's nav link carries an underline (inset shadow) that out-specified the focus ring (box-shadow), so the keyboard ring vanished on the link you are on */
.nav__links a[aria-current="page"]:focus-visible { box-shadow: inset 0 -1px 0 var(--ink), var(--focus); }
/* FXF 8: spec labels (Bransch / Sidor / Rörligt / Bokning) sat at ink-3 on the warm world glow behind the Premium aside: 3.7:1 and 4.8:1 measured. Ink-2 reads 6+:1 on the same glow. */
[class*="r3-world-"] .r3-spec dt { color: var(--ink-2); }   /* only where a world glow sits behind the labels (the Premium aside, in a .r3-world-glod / -norr panel) */
/* FXF digest H.4: a card of the example arc that takes keyboard focus is the front card (r3-core.js moves it): no blur, no fade, so the ring and the caption are drawn clean */
.r3-arc__c:focus-visible { filter: none; opacity: 1; }
/* FXF 6: the first screen never waits for a script. .r3-rise hides until r3-core.js adds .is-in (2.5 s CSS failsafe when the script never runs), which left the h1 and the lead of
   /exempel and /om invisible for 2.5 s with the script blocked or slow. The hero copy (label, h1, lead, ask) is drawn by a CSS animation instead: the SAME rise (distance, duration,
   easing, stagger), no dependency. With the script it looks identical; without it the hero is on screen at once. */
@keyframes r3-hero-rise { from { opacity: 0; transform: translateY(var(--r3-rise)); } to { opacity: 1; transform: none; } }
.lib-on h1.r3-rise,
.lib-on .r3-plane--first :is(.r3-label, .r3-lead, .r3-actions, .r3-price, .r3-ask__q).r3-rise {
  opacity: 1; transform: none; transition: none;
  animation: r3-hero-rise var(--r3-d-reveal) var(--r3-ease) calc(var(--i, 0) * var(--r3-stagger)) backwards; }
/* FXF 7: the unit under a price ("kr/mån exkl. moms") is 14 px or more on every phone, in every component (dock, ledger, ticket, aside; the older sheets set it to 11 / 12 px with
   selectors of the same weight). One floor, one extra element in the selector so it wins over them: a 12 px unit was the least legible words of the offer's terms. */
@media (max-width: 767px), (max-height: 520px) and (orientation: landscape) { html .r3-price .r3-price__u { font-size: .875rem; } }
/* FXF 7: engines without color-mix() / oklab (Chrome < 111, Safari < 16.2, Firefox < 127) painted the tone planes as flat rectangles (hard edges, 59 of 264 seams failed the tone rule
   in an emulated old engine). They get a plain sRGB blend of the same length (--r3-fade) between the same two colours; the eased oklab blend of section 5 stays the enhancement. */
@supports not (background: color-mix(in oklab, red 50%, blue)) {
  .r3-plane:not(.r3-plane--first) { background: linear-gradient(180deg, var(--r3-from, var(--r3-c-page)) 0, var(--r3-c) var(--r3-fade)) top / 100% var(--r3-fade) no-repeat, var(--r3-c); }
  .r3-bridge:not(.r3-plane--first) { --r3-bridge: #5A4636; background: linear-gradient(180deg, var(--r3-from, var(--r3-c-page)) 0, var(--r3-bridge) 42%, var(--r3-c) var(--r3-fade)) top / 100% var(--r3-fade) no-repeat, var(--r3-c); }
}

/* ================================ 19c. MOTION TOGGLE, CHIP LABEL TOKEN (FXF, fix round 2) ================================ */
/* F-34 / FILM POLICY: R3.toggle and R3.film.bind (example kind) give a motion button ONE constant accessible name, aria-pressed for the state and a 44 x 44 px minimum hit area
   (set inline by r3-core.js, so a page sheet cannot shrink it). The label never changes, so the pressed state is drawn: a 2 px ring in the text colour. */
.r3-tg { touch-action: manipulation; }
.r3-tg[aria-pressed="true"] { box-shadow: inset 0 0 0 2px currentColor; }
.r3-tg:focus-visible { outline: 2px solid var(--accent, #DCBC7E); outline-offset: 3px; }
/* F-32: in the light theme the 12 px chip label (ink-2 #46424C) measured 4.36 to 4.58 : 1 where the stage glow darkens the paper (Growth page chips). A 30 % pull toward --ink
   (one step darker, about 5.4 : 1 on the worst pixel) clears it; on a dark plane --ink is the light ink, so the label gets one step lighter there. Dark theme untouched. */
@supports (color: color-mix(in srgb, red, blue)) {
  [data-theme="light"] .r3-chip:not([aria-selected="true"]) { color: color-mix(in srgb, var(--ink-2) 70%, var(--ink)); }
}

/* ================================ 20. REDUCED MOTION (last on purpose) ================================ */
/* every animated thing rests in its composed state. html.no-motion is the page's own toggle and the system setting; r3-core.js never starts a timer then. */
.no-motion .r3-rise, .no-motion .r3-stage-in { opacity: 1 !important; transform: none !important; transition: none !important; animation: none !important; }
.no-motion .r3-settle img, .no-motion .r3-settle video { transform: none !important; transition: none !important; }
.no-motion .r3-stage-in .r3-dev__view::before { display: none !important; }
.no-motion .r3-panel, .no-motion .r3-layer, .no-motion .r3-index__img, .no-motion .r3-index__rows a, .no-motion .r3-index__t, .no-motion .r3-chip__img, .no-motion .r3-tab, .no-motion .r3-pin,
.no-motion .r3-arc__c, .no-motion .r3-beat::before, .no-motion .r3-count__odo > span, .no-motion .r3-count__rail::after, .no-motion .r3-dock, .no-motion .r3-dev__film { transition: none !important; }
.no-motion .r3-dev--glide .r3-dev__page { transition: none !important; }
.no-motion .r3-roll .r3-btn__t > span, .no-motion .r3-btn__arr { transition: none !important; transform: none !important; }
.no-motion .r3-roll, .no-motion .r3-roll:hover, .no-motion .r3-roll:focus-visible { transition: none !important; transform: none !important; }
.no-motion .r3-ink .w { opacity: 1 !important; transition: none !important; }
.no-motion .r3-sc { transition: none !important; }
@media (prefers-reduced-motion: reduce) {
  .r3-rise, .r3-stage-in { opacity: 1 !important; transform: none !important; transition: none !important; animation: none !important; }
  .r3-stage-in .r3-dev__view::before { display: none !important; }
  .r3-panel, .r3-layer, .r3-index__img, .r3-index__rows a, .r3-chip__img, .r3-tab, .r3-pin, .r3-arc__c, .r3-dock, .r3-dev__film, .r3-dev__page { transition: none !important; }
  .r3-roll .r3-btn__t > span, .r3-btn__arr { transition: none !important; transform: none !important; }
  .r3-roll, .r3-roll:hover, .r3-roll:focus-visible { transition: none !important; transform: none !important; }
  .r3-ink .w { opacity: 1 !important; }
}

/* LIGHT THEME PARKED (David 2026-10-06): the toggle is hidden on every page and the page is always dark; the light-theme code below and in r3-light.css stays untouched for a later round.
   To un-park: delete this rule, the PARK block in r3-core.js, restore line 1 of this file (@import url("r3-light.css"); removed 2026-10-13 for the release, plus the <link rel="preload" href="/assets/zs/r3-light.css" as="style"> of the pages) and the ignore of a stored "light" in the head snippet of each page (if(t==="dark")d.setAttribute("data-theme",t);). */
[data-theme-toggle] { display: none !important; }

/* RC3 WP-ROBUST */
.r3-card, .r3-beat, .r3-colophon, .r3-h2, .r3-h3, .r3-card__t, .r3-beat h3 { overflow-wrap: anywhere; }

/* b6 G4 TYP-10: no one-word last lines in short texts */
.r3-lead, .r3-body, .r3a-ledger__d, main p, main li, main figcaption, main dd, main dt, main summary { text-wrap: pretty; }

/* b6 long30: long words break at the edge */
.r3-beat h3, .r3-beat p { overflow-wrap: anywhere; }

/* b6 text 200 %: wrap, never cut off */
:where(h1, h2, h3, h4, p, li, dd, dt, figcaption, summary, label, td, th, .r3-display, .r3-lead, .r3-body, .r3-small) { overflow-wrap: anywhere; }
.r3-btn { white-space: normal; text-align: center; line-height: 1.12; padding-block: 8px; }

/* b6 text 200 %: columns that size to their text */
.r3a-pricelg__t small, .r3-spec dd, .r3-spec dt { overflow-wrap: break-word; min-width: 0; }

/* b6 text 200 %: ledger rows size to their text (inheritance) */
.r3a-pricelg, .r3a-pricelg * { overflow-wrap: break-word; }

/* b6 text 200 %: labels may wrap */
.r3-label, .eyebrow { white-space: normal; }

/* b6 DOCK-200 */
@media (max-width: 1023px) { .r3-dock { flex-wrap: wrap; row-gap: 8px; } .r3-dock .r3-btn { flex: 1 1 9.5rem; } }

/* b6 fix5: numerals never break */
.r3-n { white-space: nowrap; }

/* b6 fix26: tier label keeps its words whole */
@media (min-width: 700px) { .r3-tier { overflow-wrap: break-word; } }

/* b6 fix51 tab labels, enlarged text */
.r3-tab { overflow-wrap: anywhere; min-width: 0; }
/* b6 fix60: the arrow of a text link never stands alone on a line */
.r3-link > span[aria-hidden="true"] { white-space: nowrap; }

/* b6 fix70 table scroll */
/* b6 fix70 table scroll: a comparison table grows with the text size (rem) and scrolls inside its own region instead of cutting its words */
@media (min-width: 768px) { .r3-tblscroll { overflow-x: auto; max-width: 100%; } .r3-tblscroll > .r3-table { min-width: 26rem; } }

/* b6 fix71 beat headings */
/* b6 fix71 beat headings: capped by the beat's own width (a 16-letter word in a 300 px list at 200 % text) */
.r3-beat h3 { font-size: min(var(--r3-t-h3), 12cqi); }
.tier-premium .r3-beat h3 { font-size: min(clamp(1.7rem, 1.25rem + 1.5vw, 2.5rem), 12cqi); }

/* b6 fix83 no-wrap range */
/* b6 fix83: a range such as "3-5 sidor" never breaks at its en dash */
.r3x-nb { white-space: nowrap; }

/* b6 fix94 table region container */
/* b6 fix94: the comparison table's region is a size container (the stacked comparison cards follow its width in rem) */
.r3-tblscroll { container: r3tbl / inline-size; }

/* b6 f2 moms unit balance */
/* b6 f2 moms: the price unit ("kr/mån exkl. moms") is balanced when it has to wrap: "kr/mån" over "exkl. moms" instead of "kr/mån exkl." over a lone "moms".
   Same box, same number of lines (balance never adds a line), so nothing around it moves. Browsers without text-wrap support keep the greedy wrap. */
.r3-price__u { text-wrap: balance; }

/* RELEASE (2026-10-13): the production consent loader (assets/analytics/consent.js, byte-identical to production 0aea81fd) appends its "Cookieinställningar" button and its status
   line to <footer>. R3's footer has no .foot-inner, so they sit under the .wrap row: align them with it. The panel #zs-consent itself is styled by consent.css (production). */
footer.foot > .zs-cookie-settings { width: 100%; max-width: calc(var(--wrap) + 2 * var(--gutter)); margin: var(--s-3, 12px) auto 0; padding: 10px var(--gutter); box-sizing: border-box; text-align: left; }
/* consent.css hard-codes the lavender link colour #b8a8ff (made for a dark page): R3 footers sit on different tone planes (the Starter page ends on paper, 237,231,218: 1.69:1).
   The button takes the footer's own text colour (the tone system keeps that AA on every plane) and its focus ring follows it. */
footer.foot > .zs-cookie-settings, footer.foot > .zs-cookie-settings:hover { color: inherit; }
footer.foot > .zs-cookie-settings:focus-visible { outline-color: currentColor; }
