/* ══════════════════════════════════════════════════════════════════════════════════════════
   app-site.css — THE PUBLIC SITE'S CHROME: bar, buttons, section base, footer, skip link.
   ══════════════════════════════════════════════════════════════════════════════════════════

   WHY IT EXISTS (08-09-2026)
   `/bramming/` and `/tarp/` were built with the house's TOKENS (colours, fonts) and then invented
   all the rest themselves. Measured: the front page carries 2.813 lines of `<style>` and 239 classes; the two
   subpages had 82 lines and reused **1 of the 239**. They thus hit the theme in COLOUR and not in FORM —
   no bar, no logo, sentence headings in normal weight. The owner saw it at once:
   «følger bare ikke vores theme / udseende og heller ej med logo».

   ⭐ The lesson behind the file: **a set of tokens is not a look.** Tokens are the raw material; the look is
   the component rules that use them. A page can be 100 % tokenised and still look like a
   foreign product — and exactly that no automatic test sees, because every single value is «right».

   WHAT IS HERE, AND WHERE IT COMES FROM
   The blocks are UNCHANGED extracts of `index.html`'s own `<style>` (lines 375-435, 436-524, 562-805,
   1116-1155, 2209-2238, 2286-2413, 2522-2534 on `27f82e92`), so the subpages get the front page's
   look by CONSTRUCTION and not by reinterpretation. Only chrome — no hero, no sections
   that belong to one page.

   ⛔ THE DEBT, WRITTEN ALOUD SO IT IS NOT HIDDEN: `index.html` STILL has its own copy of these
   ~600 lines inline. There are thus two sources for one look, until the front page also fetches this
   sheet. That was deliberately not done in the same operation: the front page is the house's most valuable surface,
   and the owner asked for the subpages. **The move is a task of its own with its own measurement.**
   ⇒ If you change the chrome, fix BOTH places, until that task has been run.

   ⚠ The token names below are the BRIDGE from the engine's `--app-*` to the surface's short names. Do not touch it
   without reading the comments: `--paa-brand` is DELIBERATELY not declared (it is consumed directly
   from the theme, where it is an alias for the COMPUTED `--on-brand`), and an earlier attempt to

/* ─── TOKENS (extract of index.html 375-435 on 27f82e92) ─────────────────── */
/* ─── TOKENS (draws from the shared design system, with fallback) ─── */
:root {
  --bg:        var(--app-bg, #080808);
  --bg-2:      var(--app-bg-2, #111111);
  --bg-3:      var(--app-bg-3, #1a1a1a);
  --border:    var(--app-bg-4,#242424);
  --red:       var(--app-red, #ff1c35);
  --red-dark:  var(--app-red-dark, #d90020);
  --blue:      #0e274f;
  --white:     var(--app-ink, #ffffff);
  /* `--paa-brand` (the ink ON the brand surface) is DELIBERATELY NOT declared here — audit D1.
     It is consumed directly from `assets/pulsn-theme.css`, where it is an alias for the engine's
     COMPUTED `--on-brand`. If it is declared here, this block wins (it stands after the sheet,
     same specificity) and locks the foreground — exactly the error the portal made in F3.
     `--white` is the ink on the PAGE and is the wrong choice on top of red: measured, it gave
     2,75:1 on frost against the style direction's own 6,02:1. No fallback, because the theme sheet is
     a hard dependency — a fallback would only hold on to a value the engine has left. */
  /* ─ D1 · THE THREE GREYS ARE NOW DERIVED FROM THE STYLE DIRECTION'S OWN INK, not from fixed hex. As hex
     they measured 1,01–1,14 · 2,08–2,61 · 2,60–3,28:1 on the four LIGHT style directions: the surfaces
     turned with the theme, the ink did not. Now ≥4,5:1 on all 11 style directions' four
     surfaces (worst 11,16 · 5,78 · 4,81). `--gray-3` carries the opening hours, the "Lukket"
     marks and the reception's phone time — what a person with poor sight comes to read.
     .94 reproduces #f0f0f0 exactly on the standard style direction; .72 is the canon's
     `--app-ink-soft`; .66 is the sign-up's measured `--muted-2` and clears 4,5:1 on all four
     light ones — the canon's .62 measures 4,26:1 on «ler». Measured in public_theme_reach_test.php, section 4c. */
  --gray-1:    rgba(var(--app-ink-rgb), .94);
  --gray-2:    rgba(var(--app-ink-rgb), .72);
  --gray-3:    rgba(var(--app-ink-rgb), .66);
  --font-display: var(--app-font-display, 'Exo', sans-serif);
  /* ⛔ THE HEADING'S EXPRESSION IS PART OF THE STYLE DIRECTION — not a fixed number in the surface.
     The theme has had `--app-display-style/-weight` all along, and **7 of 11 directions
     ask for UPRIGHT display type** (vaerksted · skovnat · violet · kontrast · avispapir ·
     ler · frost), while five want weight 600 or 700. The front page hardcoded
     `font-style:italic; font-weight:800` in six places and ignored them all.
     MEASURED on avispapir: Playfair Display is a SERIF with swashy letters, and in
     italic 800 at line height 0,95 the N and D collide with the line below.
     The direction said `normal`; the surface said italic, and the surface won.
     ⚠ `letter-spacing` is DELIBERATELY not moved over: it is per element (a 140px
     heading and an 18px label should not be spaced alike), while the token is a
     direction default. That would be trading a real value for a general one.
     ⚠ AND NO LOCAL NAME WAS INVENTED. The first version put
     `--display-style/-weight` in here as an alias — and `token_vocabulary_test` failed
     it: the surface's vocabulary may only shrink. The house's rule is to consume
     the engine's canonical `--app-*` rather than christen a new name for the surface. */
  --font-body:    var(--app-font-body, 'Inter', sans-serif);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in:  cubic-bezier(0.7, 0, 0.84, 0);
  --max-w: 1280px;
  --gutter: clamp(20px, 5vw, 80px);
  /* ⛔ THE MENU BAR'S HEIGHT AS ONE NAME — owner report 03-09: «"Her Starter Forandringen",
     den tekst på forsiden, det er den som nogen gange er under menuen».
     Measured: `#navbar` is `position: fixed` and 72 px tall, while `#hero` was `min-height:100dvh`
     with `align-items: flex-end` and `padding-top: 0`. If the content is taller than the screen, it
     therefore grows UPWARD — in under the bar — and `overflow: hidden` clips it away. Reproduced
     at 375×600 (only «FORANDRINGEN» left) and 740×380, phone sideways («Her» gone).
     Two places decided the bar's height: the bar itself and the space the hero had to keep free.
     One name, like `--p-tabbar-h` on the member surface — it was added for exactly the same
     reason, when FOUR places disagreed about the bottom bar's height. */
  --nav-h: 72px;
}


/* ─── RESET + KEYBOARD FOCUS (extract of index.html 436-524 at 27f82e92) ─────────────────── */
/* ─── RESET ──────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* ⛔⛔ HERE STOOD `font-size: 16px` ON <html> — REMOVED 28-08-2026 (WCAG 1.4.4).
   It looked harmless, because 16px IS the browser's default: nothing moved, and therefore it
   survived. But it moves something for the one it concerns. If a human has turned up the
   font size in their browser — because their sight is poor, or because the phone is held
   at arm's length — the line sets the root BACK to 16px. And because the whole ladder is in `rem`
   (deliberate, see `assets/app-type.css`), it simultaneously pulled every single one of the 121
   font sizes below back to the DESIGNER's number. The setting seemed to work
   everywhere except on pulsn.dk.
   The guidance in `assets/pulsn-theme.css` says it without reservation: **NEVER set
   `html { font-size: … }`.** No test caught it; only a read-through did.
   ⚠ At the default setting the removal changes NOTHING — that is measured. The difference arises only
   for whoever has asked for it themselves. That is exactly why it was hard to spot.

   ─── THE FONT NOW COMES FROM THE LADDER (assets/app-type.css) ─────────────────────────────
   140 raw `font-size` numbers → 18. The 121 that have been moved are chosen by ROLE, and
   the UI ramp (9 · 10 · 11 · 12 · 13 · 14 · 15 · 16px) hits the front page's own numbers ONE TO ONE:
   113 of them do not change a single pixel. The rest move at most 1px:
       12,5px ×2 → --fs-sm (12)      half a pixel, indistinguishable at 1× DPR
       17px   ×1 → --fs-2xl (16)     `.cta-sub` lines up with the page's other leads
       22px   ×4 → --fs-4xl (21,6)   26px ×1 → --fs-5xl (25,9)
       clamp(13px,1.4vw,15px) → clamp(var(--fs-md), 1.4vw, var(--fs-xl))  — verbatim the same

   ⛔ THE 18 THAT DELIBERATELY STAY — AND WHY IT IS NOT LAZINESS.
   The front page's display font is LARGER THAN THE LADDER REACHES. Measured against each other:
       the ladder's display ramp tops out at  --fs-8xl   = 44,8px
       the ladder's fluid step tops out at    --fs-fluid-hero = clamp(37,3px, 14vw, 77,4px)
       the front page's hero is               clamp(72px, 10vw, 140px)
   `--fs-fluid-hero` would thus cut the ceiling from 140px to 77,4px — almost a halving of
   the first thing a visitor sees. That is a REDESIGN decision, not a tidy-up, and it is
   not mine to take. The same story for `.pricing-amount` (72px), `.cta-headline`
   (→110px), `.section-title` (→80px), `.about-title` (→68px), `.hero-stat-number` (52px),
   `.location-name`/`.mobile-nav a`/`.form-success-icon` (40px), `.mobile-nav-close` (28px)
   and the three 20px (`.pricing-currency`, `.form-success h3`, `.ci-modal-name`), which lie
   2px from the nearest step in both directions.
   ⚠ AND THEY MUST NOT BE «SOLVED» WITH A MULTIPLICATION SIGN: `calc(var(--fs-8xl) * 3.125)` would count as
   tokenised to the ratchet and be a magic number with a nicer name — exactly what the ladder
   was built to get rid of. A half tokenisation that looks finished is worse than
   an honest px.
   ⇒ THE WAY FORWARD, if they are to be closed: the ladder lacks steps ABOVE --fs-8xl, and a new step
   belongs in `assets/app-type.css`, derived from `--fs-base`/`--fs-ratio` — never here. That is
   an owner and type-file decision. Until then a raw px number is the honest answer. */
html { scroll-behavior: smooth; overflow-x: hidden; }
body {
  background: var(--bg);
  color: var(--white);
  font-family: var(--font-body);
  font-weight: 400;
  line-height: 1.6;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
img { display: block; max-width: 100%; }
/* <picture> is only a wrapper around <img> — it must not be able to change the layout.
   Every image rule on the page is written as `.holder img { … }` (descendant, not `>`), so
   they still hit. But a `<picture>` is `inline` by default, and an inline box gets a
   line height: that is exactly where the classic 4-5 px under an image comes from, and in a
   frame with `overflow:hidden` and fixed height the image would then be pushed. `display:contents`
   removes the wrapper's own box, so `<img>` lies in the parent's layout exactly as before the
   WebP alternative was added. Without the line the change is no longer only an optimisation. */
picture { display: contents; }
a { color: inherit; text-decoration: none; }
button { cursor: pointer; border: none; background: none; font: inherit; }
/* The icons from assets/app-icons.js. ONE rule, and it chooses nothing: `1em` means
   "same size as the text around", so the glyphs' old measures (22px in the benefits, 40px
   in the receipt, 15px in the arrows) follow along by themselves from the font-size rules
   that already stood there. A `--ico-sm/md/lg` would have been a sixth vocabulary for a
   concept that already has one. The colour is `currentColor` from the SVG itself — the brand colour has
   not been chosen yet, and an icon layer is exactly where you end up choosing it. */
.ico { width: 1em; height: 1em; flex: none; vertical-align: -.125em; }

/* ─── KEYBOARD FOCUS ─────────────────────────────────────── */
/* WHO IT LOCKS OUT: whoever cannot use a mouse. The front page had 48 `:hover` rules and
   ZERO `:focus-visible` (audit D5) — the mouse got 48 feedbacks, the keyboard none.
   Measured: 86 focusable elements (25 buttons, 54 links, 7 fields) without a single visible
   focus mark. Worst was the contact form, which with `outline:none` switched off the browser's
   OWN ring without setting anything in its place: you could not see which field you were typing in, nor
   that you had reached "Send". It is the same error class as F2 in `fx-header.js`.
   DERIVED, NOT CHOSEN: `--focus-ring` points to the style direction's accent tone in
   `assets/pulsn-theme.css` — the same token the sign-up uses, and the ONE that exists.
   A ring with its own colour here would have to be chosen again when the brand colour is chosen.
   `--red` is only an emergency flare if the theme sheet was not fetched at all. */
:focus-visible {
  outline: 2px solid var(--focus-ring, var(--red));
  outline-offset: 2px;
}


/* ─── NAVBAR, BUTTONS, MOBILE TRIGGERS (extract of index.html 562-805 at 27f82e92) ─────────────────── */
/* ─── NAVBAR ─────────────────────────────────────────────── */
/* THE BAR DOES NOT FOLLOW THE STYLE DIRECTION — and must therefore not borrow its ink either (D1+D5).
   Measured 2026-08-03: the bar is hardcoded dark, while `--gray-2`/`--white` are the PAGE's ink,
   which on the four light style directions is DARK. The main navigation's links measured 1,03–1,11:1
   on the black bar, and the focus ring (the page's accent) 2,51–2,68:1 — under WCAG 1.4.11.
   The bar now has its own pair in `assets/pulsn-theme.css` (`--app-nav-bg` +
   `--app-nav-ink-rgb` + `--app-nav-panel`), exactly like the sidebar's `--sb-ink-rgb`.
   The front page does NOT DECLARE them — it consumes them, so the sheet cannot be overridden (F3).
   The fallbacks are exactly the sheet's own values, so the look is unchanged on all twelve.
   Measured after: ring worst 19,17:1, nav text worst 10,09:1; against the dark
   style directions nothing got worse (ring 5,22–12,83 → 19,91–20,03). */
#navbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  padding: 0 var(--gutter);
  height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* No fallback (EB-08 c): it read `rgba(8,8,8,0.97)` and agreed with the OLD default.
     After the bar follows the theme, the same fallback would claim the opposite of the engine —
     exactly the error class `tests/token_vocabulary_test.php` exists for. The token cannot
     be missing: `pulsn-theme.css` is fetched by this page (measured), and without that sheet there is no theme
     to fall back to anyway. */
  background: var(--app-nav-bg);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--border);
}
.nav-logo {
  display: flex;
  align-items: center;
  height: 42px;
  /* ⛔ A LOGO MUST NEVER SHRINK — it is the identity, not layout. Measured on the real page
     03-09 at 375 px: the wordmark stood 68x36, that is at the ratio 1,887 against the image's own
     2,177 — **13 % squeezed** — and touched the red PORTAL button with 0 px in between. That is why
     «pulsn» looked as if it was cut in half (owner report).
     The chain was: `#navbar` is a flex row, this element had `flex-shrink: 1`, and the row
     is wider than a phone. The image has a LOCKED height (36 px inline) and inherits `max-width`
     from the shrunken ancestor — and a ceiling on the width with a locked height gives a
     DISTORTION, not a reduction.
     ⚠ No media rule here, on purpose: the rule applies at every width, and the house has only three
     breakpoints (480/768/1024). A fourth number would be a kink no other surface knows
     — `arkitektur_gaeld_skralde` caught exactly that in my first version and was right. */
  flex: 0 0 auto;
}
.nav-logo img {
  height: 42px;
  width: auto;
}
.nav-links {
  display: flex;
  gap: 36px;
  list-style: none;
  align-items: center;
}
.nav-links a {
  font-size: var(--fs-md);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(var(--app-nav-ink-rgb,255,255,255), .72);
  transition: color 0.2s;
}
.nav-links a:hover { color: rgba(var(--app-nav-ink-rgb,255,255,255), 1); }
.nav-cta {
  display: flex;
  align-items: center;
  gap: 12px;
}
.nav-portal-btn {
  display: flex;
  align-items: center;
  gap: 7px;
  background: var(--red);
  color: var(--paa-brand);
  font: 600 var(--fs-sm)/1 var(--font-body);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 11px 18px;
  border-radius: 2px;
  min-height: 44px;
  transition: background 0.2s;
  white-space: nowrap;
}
.nav-portal-btn:hover { background: var(--red-dark); color: var(--paa-brand); }
.nav-social {
  position: relative;
}
.nav-social-btn {
  width: 44px;
  height: 44px;
  border: 1px solid rgba(var(--app-nav-ink-rgb,255,255,255),0.15);
  border-radius: 50%;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
  color: rgba(var(--app-nav-ink-rgb,255,255,255),0.75);
  padding: 0;
}
.nav-social-btn:hover {
  border-color: var(--accent-ink, var(--red));
  background: rgba(var(--app-red-rgb,255,28,53),0.08);
  color: rgba(var(--app-nav-ink-rgb,255,255,255),1);
}
.nav-social-btn svg {
  width: 16px;
  height: 16px;
  fill: currentColor;
}
.nav-social-drop {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  background: var(--app-nav-panel);   /* fallback removed — see the note at --app-nav-bg */
  border: 1px solid rgba(var(--app-nav-ink-rgb,255,255,255),0.1);
  border-radius: 10px;
  overflow: hidden;
  min-width: 148px;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-6px);
  transition: opacity 0.18s, transform 0.18s;
  z-index: 200;
}
.nav-social:hover .nav-social-drop,
.nav-social:focus-within .nav-social-drop {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
.nav-social-drop a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 16px;
  font-size: var(--fs-md);
  font-weight: 500;
  color: rgba(var(--app-nav-ink-rgb,255,255,255),0.8);
  text-decoration: none;
  letter-spacing: 0.02em;
  transition: background 0.15s, color 0.15s;
}
.nav-social-drop a:hover {
  background: rgba(var(--app-red-rgb,255,28,53),0.1);
  color: rgba(var(--app-nav-ink-rgb,255,255,255),1);
}
.nav-social-drop a + a {
  border-top: 1px solid rgba(var(--app-nav-ink-rgb,255,255,255),0.07);
}
.nav-social-label {
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* The alpha is UNCHANGED (.3) — it measures 2,56:1 and is an open owner decision, not
     a theme problem: it is equally low on all twelve style directions. See the D5 row. */
  color: rgba(var(--app-nav-ink-rgb,255,255,255),0.3);
  padding: 9px 16px 4px;
}
/* ─── FIVE DEAD BUTTON RULES ARE REMOVED (audit D5, 2026-08-03) ─────────────────────
   Here stood `.btn-outline` and `.btn-primary`; further down stood `.btn-cta-primary` and
   `.btn-cta-secondary`; and in the 480px media query stood `.btn`. All five had real
   CSS with hover and active — and ZERO carriers. Measured with `git grep` in the whole tree: no
   markup, no JS template, only the CSS's own self-references (a media query
   switched off `.nav-cta .btn-outline`, that is a button that did not exist). They are DELETED,
   not merged: a class without a carrier cannot change a pixel, so exactly that
   cleanup is free and provable. 20 → 16 base classes measured mechanically.

   THE SIXTEEN THAT STAYED ARE MEASURED AND ARE DIFFERENT. «16 → 1» can therefore not be taken
   as a cleanup here: the geometries range from 11px 18px/r2 (nav) via 14px/r6 (book) and
   10px 18px/r20 (the center picker) to 16px 32px/r2 (the hero). Exactly ONE pair shares every
   single geometry property — `.btn-hero-primary` and `.form-submit` — and they are still
   not alike: one animates its `gap`, the other lifts 1px on hover. A
   merge would thus change the MOTION on the public surface. That is the owner's
   choice, not the cleanup's. The measurement is kept alive by `tests/button_basis_test.php`.

   AND THE BASE CANNOT MOVE TO `assets/` UNDER THE NAME `.btn`: three surfaces already own
   that name with three different geometries (the portal 11px 18px/r11 · the sign-up
   15px 24px/r12 · the receipt 15px 34px/r13) and 442 carriers in total. A shared `.btn` in
   the theme sheet would give the portal's 433 buttons `width:100%` and `justify-content:center`,
   which the portal's own rule does not set and therefore cannot override. Measured, not guessed
   — see the note in `assets/pulsn-theme.css`. */
.nav-hamburger {
  display: none;
  flex-direction: column;
  gap: 5px;
  padding: 10px;
  min-width: 44px;
  min-height: 44px;
  align-items: center;
  justify-content: center;
}
.nav-hamburger span {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--white);
  transition: all 0.3s;
}
/* Hamburger → X when the menu is open (clearly "press to close") */
.nav-hamburger.active span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-hamburger.active span:nth-child(2) { opacity: 0; }
.nav-hamburger.active span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ⛔ THE LOGO WAS SQUEEZED TOGETHER ON A PHONE  (owner report 03-09-2026)
   Measured on the real page at viewport 375: the wordmark stood 68 x 36 px, that is at the ratio
   1,887 against the image's own 2,177 — **13 % squeezed** — and it touched the red PORTAL button
   with 0 px in between. That is why «pulsn» looked as if it was cut in half.

   THE CAUSE is a chain where every link is reasonable: `#navbar` is a flex row, `.nav-logo`
   is a flex item with `flex-shrink: 1`, and the row is wider than 375 px. So the
   logo shrinks. The image has `height: 36px; width: auto` (inline), but inherits `max-width: 100%` from
   the shrunken ancestor — and with a LOCKED height and a ceiling on the width the result is a
   distortion, not a reduction.
   ⭐ A logo must never shrink: it is the identity, not layout. Hence `flex: 0 0 auto`.

   When the logo no longer gives way, the space must come from somewhere else. On a PHONE
   the WORD «Portal» yields, so the icon stands alone — and it costs no access: **PORTAL is already in
   the hamburger menu** (measured), and the button's `aria-label` is unchanged. */
/* ⚠ 480 is the house's own phone breakpoint, not a new number. My first version had 430 and
   374 — two kinks no other surface knows — and `arkitektur_gaeld_skralde` objected and was
   right. The second version became both simpler AND more principled: on a phone the portal is an icon,
   from tablet and up it carries its word.
   Measured on the real page AFTER the fix — viewport / logo / ratio / air to the buttons /
   hamburger within the edge. The ratio is the image's own 2,177 all the way, that is zero
   distortion; the word «Portal» is hidden on all four, because they are all <= 480:
       480   78x36   2,177   77 px   ja
       430   78x36   2,177   54 px   ja
       375   78x36   2,177   32 px   ja
       320   78x36   2,177    5 px   ja  (the portal button measures 44 x 44) */
@media (max-width: 480px) {
  .nav-portal-txt { display: none; }
  /* On the narrowest screen (320 px) there was only 1 px between the logo and the buttons. Eight
     pixels instead of twelve between the four buttons gives eight back to the air. */
  .nav-cta { gap: var(--space-2); }
  /* Without the word the button became 30 px wide — under the house's 44 px floor for a touch surface.
     `min-width` is the floor; `justify-content` keeps the icon in the middle. */
  .nav-portal-btn { padding: 11px var(--space-2); min-width: 44px; justify-content: center; }
}


/* ─── SECTION BASE (extract of index.html 1116-1155 at 27f82e92) ─────────────────── */
/* ─── SECTION BASE ───────────────────────────────────────── */
section {
  padding: clamp(80px, 10vw, 140px) var(--gutter);
  scroll-margin-top: 80px;
}
.section-inner {
  max-width: var(--max-w);
  margin: 0 auto;
}
.section-tag {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 20px;
}
.section-tag-line { width: 32px; height: 2px; background: var(--red); }
.section-tag span {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent-ink, var(--red));
}
.section-title {
  font-family: var(--font-display);
  font-size: clamp(44px, 6vw, 80px);
  font-weight: var(--app-display-weight, 800);
  font-style: var(--app-display-style, italic);
  line-height: 0.95;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  margin-bottom: 24px;
}
.section-sub {
  font-size: var(--fs-2xl);
  color: var(--gray-2);
  line-height: 1.7;
  max-width: 540px;
}



/* ─── THE BADGE FAMILY (extract of index.html 1548-1591) ──────────────────────────────
   ⚠ MOVED ALONG FOR A MEASURED REASON, not for tidiness. The front page's markup is
   `<span class="location-reception-dynamic hours-badge">` — the element carries BOTH
   classes, and they set the same `padding`. Before, `.hours-badge` won, because it stood
   LATER in the file. When the time card moved here (a sheet loaded BEFORE the front page's
   own `<style>`), `.location-reception-dynamic` won instead, and the badge changed
   from 3px 9px to 3px 8px. Measured on 50 selectors, not seen with the eye.
   ⭐ The lesson: **moving CSS out into a sheet changes the CASCADE, not just the file.** Two
   rules that resolved each other by order must move TOGETHER and in the same order. */
.location-reception-dynamic {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 3px 8px;
  border-radius: 20px;
  background: rgba(var(--app-red-rgb,255,28,53),0.15);
  color: var(--accent-ink, var(--red));
  white-space: nowrap;
}
.location-reception-dynamic.recep-closed { background: rgba(var(--app-ink-rgb), 0.06); color: var(--gray-3); }
.location-phone-dynamic {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 3px 8px;
  border-radius: 20px;
  background: rgba(var(--app-red-rgb,255,28,53),0.15);
  color: var(--accent-ink, var(--red));
  white-space: nowrap;
}
.location-phone-dynamic.phone-closed { background: rgba(var(--app-ink-rgb), 0.06); color: var(--gray-3); }
.fitness-status-badge {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 3px 9px;
  border-radius: 20px;
  white-space: nowrap;
  background: color-mix(in srgb, var(--ok) 12%, transparent);
  color: var(--ok);
}
.fitness-status-badge.closed { background: rgba(var(--app-ink-rgb), 0.06); color: var(--gray-3); }
.location-badge-always-open {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 3px 8px;
  border-radius: 20px;
  background: color-mix(in srgb, var(--ok) 12%, transparent);
  color: var(--ok);
  white-space: nowrap;
}

/* ─── OPENING-HOURS CARD (extract of index.html 2098-2158 at 27f82e92) ─────────────────── */
.hours-card {
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 28px 28px 20px;
  background: var(--bg-2);
}
.hours-card-title {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gray-3);
  margin-bottom: 20px;
}
.hours-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.hours-row:last-child { border-bottom: none; padding-bottom: 0; }
.hours-icon {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(var(--app-ink-rgb), 0.04);
  border: 1px solid var(--border);
  border-radius: 2px;
  color: var(--accent-ink, var(--red));
  flex-shrink: 0;
}
.hours-row-info { flex: 1; min-width: 0; }
.hours-row-label { font-size: var(--fs-md); font-weight: 600; color: var(--white); line-height: 1.3; }
.hours-row-time { font-size: var(--fs-sm); color: var(--gray-3); margin-top: 2px; }
.hours-badge {
  font-size: var(--fs-xs);
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 20px;
  white-space: nowrap;
}
/* ⛔ THE TWO SEMANTIC COLOURS CAME FROM THE THEME 27-08 — and they were invisible to the ratchet.
   «Åbent nu» and «næsten fuldt» stood as `var(--stat-ok,#22c55e)` and `#e07020`, that is RAW hex in the middle of a rule.
   `pr_immune()` in `public_theme_reach_test` counts `:root` tokens and raw white/black — **it does not
   see a bare hex in a rule body**, so the eight occurrences lay in a file whose colour architecture
   is otherwise measured to the smallest detail.

   ⚠ `var(--stat-ok,#22c55e)` was incidentally EXACTLY the value `--stat-ok` has today — so the page hardcoded
   the token's current number. Another style direction sets `--stat-ok: #35d39a`, and there
   the front page would have kept the old green while everything else changed.

   ⭐ The orange changes shade (`#e07020` → `--stat-warn` `var(--stat-warn,#f5a623)`), and that is an improvement, not
   a side effect: measured against the page's three base colours the contrast goes from 5,39–6,21:1 up to
   8,59–9,88:1. `--ok` is unchanged at 8,79–9,88:1. */
.hours-badge-green { background: color-mix(in srgb, var(--ok) 12%, transparent); color: var(--ok); }
.hours-badge-dynamic { background: rgba(var(--app-red-rgb,255,28,53),0.12); color: var(--accent-ink, var(--red)); }
.hours-badge-closed { background: rgba(var(--app-ink-rgb), 0.06); color: var(--gray-3); }


/* ─── FOOTER: SOCIAL FOLD-OUTS (extract of index.html 2209-2238 at 27f82e92) ─────────────────── */
/* ─── FOOTER SOCIAL DROPDOWNS ───────────────────────────── */
.footer-social-row { display: flex; gap: 10px; margin-top: 20px; flex-wrap: wrap; }
.footer-social-item { position: relative; }
.footer-social-btn {
  display: flex; align-items: center; gap: 7px;
  background: var(--bg-3); border: 1px solid var(--border);
  color: var(--gray-2); font-size: var(--fs-md); font-weight: 500;
  padding: 12px 14px; min-height: 44px; border-radius: 6px; cursor: pointer;
  transition: border-color 0.2s, color 0.2s;
}
.footer-social-btn:hover, .footer-social-item:focus-within .footer-social-btn { color: var(--white); border-color: var(--gray-3); }
.footer-social-chevron { transition: transform 0.2s; }
.footer-social-item:hover .footer-social-chevron,
.footer-social-item:focus-within .footer-social-chevron { transform: rotate(180deg); }
.footer-social-drop {
  position: absolute; bottom: calc(100% + 6px); left: 0;
  background: var(--bg-3); border: 1px solid var(--border);
  border-radius: 8px; padding: 6px; min-width: 130px;
  opacity: 0; pointer-events: none; transform: translateY(6px);
  transition: opacity 0.18s, transform 0.18s; z-index: 100;
}
.footer-social-item:hover .footer-social-drop,
.footer-social-item:focus-within .footer-social-drop { opacity: 1; pointer-events: auto; transform: translateY(0); }
.footer-social-drop a {
  display: block; padding: 7px 10px; font-size: var(--fs-md);
  color: var(--gray-2); text-decoration: none; border-radius: 5px;
  transition: background 0.15s, color 0.15s;
}
.footer-social-drop a:hover { background: rgba(var(--app-ink-rgb), 0.06); color: var(--white); }


/* ─── FOOTER + MOBILE MENU (extract of index.html 2286-2413 at 27f82e92) ─────────────────── */
/* ─── FOOTER ─────────────────────────────────────────────── */
footer {
  background: var(--bg-2);
  border-top: 1px solid var(--border);
  padding: 60px var(--gutter) 32px;
}
.footer-inner {
  max-width: var(--max-w);
  margin: 0 auto;
}
.footer-top {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: 60px;
  margin-bottom: 60px;
}
.footer-brand {}
.footer-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  text-decoration: none;
}
.footer-tagline {
  font-size: var(--fs-lg);
  color: var(--gray-2);
  line-height: 1.7;
  max-width: 280px;
  margin-bottom: 28px;
}
.footer-social {
  display: flex;
  gap: 12px;
}
.footer-social a {
  width: 36px;
  height: 36px;
  border: 1px solid var(--border);
  border-radius: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gray-2);
  transition: color 0.2s, border-color 0.2s;
}
.footer-social a:hover { color: var(--white); border-color: var(--gray-3); }
.footer-col-title {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--white);
  margin-bottom: 20px;
}
.footer-links {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.footer-links a {
  font-size: var(--fs-lg);
  color: var(--gray-2);
  transition: color 0.2s;
  display: inline-block;
  padding: 6px 0;
}
.footer-links a:hover { color: var(--white); }
.footer-bottom {
  border-top: 1px solid var(--border);
  padding-top: 28px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}
.footer-copy {
  font-size: var(--fs-md);
  color: var(--gray-3);
}
.footer-legal {
  display: flex;
  gap: 24px;
}
.footer-legal a {
  font-size: var(--fs-md);
  color: var(--gray-3);
  transition: color 0.2s;
}
.footer-legal a:hover { color: var(--gray-2); }

/* ─── MOBILE NAV ─────────────────────────────────────────── */
.mobile-nav {
  display: none;
  position: fixed;
  inset: 0;
  background: var(--bg);
  z-index: 99;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 32px;
  opacity: 0;
  transition: opacity 0.3s;
}
.mobile-nav.open { display: flex; opacity: 1; }
/* HEADING: the menu items stand in heading size — «Om os», «Hold», «Priser» (markup l.2988-2993). */
.mobile-nav a {
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: var(--app-display-weight, 800);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--gray-2);
  transition: color 0.2s;
}
.mobile-nav a:hover { color: var(--white); }
.mobile-nav-close {
  position: absolute;
  top: 24px;
  right: var(--gutter);
  font-size: 28px;
  color: var(--white);
  cursor: pointer;
}


/* ─── SKIP LINK (extract of index.html 2522-2534 at 27f82e92) ─────────────────── */
/* ─── SKIP LINK ──────────────────────────────────────────── */
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: var(--red);
  color: var(--paa-brand);
  padding: 8px 16px;
  font-size: var(--fs-lg);
  z-index: 999;
}
.skip-link:focus { top: 0; }


/* ─── THE CHROME'S RESPONSIVE RULES ──────────────────────────────────────────────────────────
   ⚠ WRITTEN BY HAND, not extracted — and that is a MEASURED decision, not laziness.
   The front page's `RESPONSIVE` block (index.html 2414-2521) is MIXED: it carries the bar's and the footer's
   phone rules side by side with `.hero-*`, `.team-grid`, `.pricing-*`, `.classes-*` and
   `.contact-grid`. The first attempt took the whole block along — and a fingerprint measurement of 34
   selectors on the front page BEFORE and AFTER found three real regressions: `.testimonial-card` lost
   background and padding, and `.contact-form` fell from `flex` to `block`.
   ⭐ Therefore only the chrome's own rules stand here, with the front page's values unchanged. The front page keeps
   its block; the seven lines thus exist in two places, and that is the cheapest of the chosen errors. */
@media (max-width: 1024px) { .footer-top { grid-template-columns: 1fr 1fr; gap: 40px; } }
@media (max-width: 768px)  { .nav-links { display: none; } .nav-hamburger { display: flex; }
                             .section-title { font-size: clamp(32px, 8vw, 52px); } }
@media (max-width: 540px)  { .footer-top { grid-template-columns: 1fr 1fr; }
                             .hours-card { padding: 20px 16px 14px; }
                             .footer-bottom { flex-direction: column; text-align: center; }
                             .section-inner { padding: 72px var(--gutter); } }
@media (max-width: 480px)  { .footer-top { grid-template-columns: 1fr; } }
