/* ============================================================================
   AnalystX — landing (editorial, neutral)
   Inspiration: Basecamp's editorial walkthrough. Palette: neutral warm-off-white,
   near-black ink + buttons, a single yellow highlight. Display headlines in
   Instrument Serif (the product's own heading font); body in Inter.
   Built on tokens.css.
============================================================================ */

:root {
  /* The product's own surface — warm cream + white. Neutral ink + black accent. */
  --bg:          #fdfaf7;
  --bg-raised:   #ffffff;
  --bg-sunken:   #f6f1e8;
  --line:        #ece4d3;
  --line-2:      #f3ecdd;
  --line-strong: #ddd2bd;
  --ink:    #221f1c;
  --ink-2:  #423d37;
  --ink-3:  #6a645b;   /* WCAG AA: ≥4.5:1 as text on cream/white/sunken */
  --ink-4:  #6d6760;   /* AA-safe muted text (≥4.5:1 even on the sunken bg) */
  --accent:     #221f1c;   /* near-black — buttons, marks */
  --accent-ink: #ffffff;
  --hl:     #221f1c;        /* highlight = the neutral near-black accent (matches buttons) */

  --maxw: 1140px;
  --measure: 60ch;
  --gutter: clamp(24px, 5vw, 56px);   /* phone floor 24px — a touch more breathing room so body copy isn't cramped to the edge */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --spring: cubic-bezier(0.34, 1.5, 0.5, 1);   /* gentle overshoot — macOS-like */
  --hero-top: 76px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--sans);
  background: var(--bg);
  color: var(--ink);
  font-size: 18px;
  line-height: 1.65;
  letter-spacing: -0.003em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }

.wrap { max-width: var(--maxw); margin: 0 auto; padding-inline: var(--gutter); }

/* ── Type ─────────────────────────────────────────────────────────────── */
/* Sans display — like the product UI and the new Basecamp. Serif only as a tiny accent. */
h1, h2, h3 { font-family: var(--sans); font-weight: 600; letter-spacing: -0.032em; line-height: 1.04; margin: 0; color: var(--ink); }
h1 { font-size: clamp(40px, 5.4vw, 66px); }
h2 { font-size: clamp(30px, 4vw, 48px); }
h3 { font-size: clamp(24px, 3vw, 34px); line-height: 1.1; }
.eyebrow { font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-3); }
em { font-style: italic; }
.it { font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: 0.01em; }
p { margin: 0 0 1.05em; }
.lead { font-size: clamp(19px, 2vw, 23px); line-height: 1.5; color: var(--ink-2); }

/* the one accent: yellow highlight marker */
.hl { background: var(--hl); color: #fff; padding: 0.02em 0.2em; border-radius: 3px; -webkit-box-decoration-break: clone; box-decoration-break: clone; font-weight: inherit; }

/* ── Focus visibility (WCAG 2.4.7) ────────────────────────────────────────
   Keyboard focus ring for every interactive element. The 2px offset places it
   just outside the element on the page background, so it stays visible even on
   the dark buttons. Light variant inside dark sections. Mouse clicks don't show
   it (:focus-visible), so the look is unchanged for pointer users. */
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; border-radius: 3px; }
/* white ring only where the focused element sits on a dark background */
.section-ink :focus-visible, .calm :focus-visible { outline-color: #fff; }
main:focus { outline: none; }   /* skip-link target; don't ring the whole region */

/* ── Skip link (WCAG 2.4.1) — hidden until keyboard-focused ─────────────── */
.skip-link { position: fixed; top: 10px; left: 10px; z-index: 200; background: var(--ink); color: #fff; padding: 11px 18px; border-radius: var(--radius); font-family: var(--sans); font-weight: 600; font-size: 14px; text-decoration: none; transform: translateY(-160%); transition: transform .18s var(--ease); }
.skip-link:focus { transform: none; }

/* ── Buttons ──────────────────────────────────────────────────────────── */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--sans); font-size: 15px; font-weight: 500; line-height: 1;
  padding: 14px 26px; border-radius: var(--radius); border: 1px solid transparent; cursor: pointer;
  transition: transform .12s var(--ease), background .18s, border-color .18s, color .18s; }
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--ink); color: #fff; }
.btn-primary:hover { background: #000; }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line-strong); }
.btn-ghost:hover { background: var(--bg-sunken); border-color: var(--ink-4); }
.btn-white { background: var(--bg-raised); color: var(--ink); border-color: var(--line-strong); }
.btn-white:hover { background: #fff; border-color: var(--ink-4); }
.btn-sm { font-size: 14px; padding: 10px 18px; }

/* ── Nav ──────────────────────────────────────────────────────────────── */
/* Not a bar — just the actions at the top, scrolls away with the page. No divider. */
.lnav { position: absolute; inset: 0 0 auto 0; z-index: 50; height: 64px; display: flex; align-items: center; background: transparent; border: 0; }
.lnav.scrolled { background: transparent; }
.lnav .wrap { display: flex; align-items: center; justify-content: flex-end; width: 100%; }
.brand { display: inline-flex; align-items: center; gap: 10px; font-family: var(--sans); font-weight: 600; font-size: 16px; color: var(--ink); text-decoration: none; letter-spacing: -0.01em; }
.brand img { width: 26px; height: 26px; border-radius: 7px; }
.lnav-links { display: flex; align-items: center; gap: 30px; }
.lnav-links a { font-family: var(--sans); font-size: 14px; color: var(--ink-3); text-decoration: none; transition: color .15s; }
.lnav-links a:hover { color: var(--ink); }

/* ── Layout rhythm ────────────────────────────────────────────────────── */
section { padding-block: clamp(44px, 6vw, 84px); }
.tight { padding-block: clamp(40px, 5vw, 64px); }
.rule { height: 1px; background: var(--line); border: 0; margin: 0; }
article p, .prose p { color: var(--ink-2); max-width: var(--measure); }
article a, .prose a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--line-strong); }
article a:hover, .prose a:hover { text-decoration-color: var(--ink); }

/* ── Hero (two-column, full) ──────────────────────────────────────────── */
.hero { display: flex; align-items: flex-start; padding: var(--hero-top) 0 48px; overflow: hidden; }
.hero > .wrap { width: 100%; }
.hero-grid { width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.12fr); gap: clamp(36px, 5vw, 72px); align-items: start; }
/* left column is sized to the viewport: menu pinned up top, headline anchored to the bottom (and still on-screen) */
.hero-copy { display: flex; flex-direction: column; justify-content: space-between; min-height: calc(90vh - 56px); min-height: calc(90svh / var(--zoom, 1) - 56px); }
.hero-visual { align-self: start; }
/* Title block — big problem-first hook + a small supporting line, tight together.
   The headline carries the weight, so it is set a step larger than the line under
   it and the gap between the two sizes is wide enough to read as a hierarchy
   rather than as two paragraphs.

   The supporting line is deliberately the same type as the page-menu descriptions
   above it ("ingen ventetid", "KI som tar seg av rutinearbeidet") — same family,
   same fixed 16px, same 400 weight, same tracking as body, same --ink-3. They sit
   inches apart in the same column, so any difference read as a mistake. If
   `.hero-menu a` changes size, change it here too. Only line-height differs, and
   on purpose: this one wraps to four or five lines, where the menu's inherited
   1.65 is leading that never renders because every item is a single line. `text-wrap: balance` is what stops a headline
   ending on a one-word line: it is free to pick the break point, so
   "CRM-et som gjør jobben selv." splits evenly instead of orphaning "selv."
   The supporting line gets `pretty` rather than `balance` — it can run to four
   or five lines, where balancing every one of them reads worse than simply
   avoiding a stranded last word.

   `balance` is the safety net, not the plan: both home-page headlines carry an
   explicit break in the CMS, so the split is the one we chose at every width and
   in every browser. No max-width here on purpose — the break decides the line
   length, and a character cap would only fight it. */
.hero-headline { font-family: var(--sans); font-weight: 400; font-size: 16px; line-height: 1.5; letter-spacing: -0.003em; color: var(--ink-3); max-width: 38ch; margin: 0; text-wrap: pretty; }
.hero-headline .big { display: block; font-weight: 600; color: var(--ink); font-size: clamp(32px, 3.4vw, 46px); line-height: 1.05; letter-spacing: -0.035em; margin-bottom: 18px; text-wrap: balance; }
.hero-headline .it { font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: 0.01em; color: var(--ink); }
.hero-ctas { display: flex; gap: 14px; margin-top: 32px; flex-wrap: wrap; }
.hero-visual { position: relative; }
/* Full app, content-filled (no empty band). Width tuned so the whole shot fits the hero
   at full height and bleeds off the right. */
.hero-visual .shot { width: 1380px; max-width: none; }

/* Logo lives in the hero (Basecamp-style), not the top bar */
.hero-brand { display: inline-flex; align-items: center; gap: 12px; margin-top: 8px; margin-bottom: 34px; font-family: var(--sans); font-weight: 600; font-size: 22px; color: var(--ink); letter-spacing: -0.02em; }
.hero-brand img { width: 34px; height: 34px; border-radius: 9px; }

/* Real nav, with descriptions. Grouped tight (proximity) + underlined labels (link affordance). */
.hero-menu { display: grid; gap: 2px; margin-bottom: 36px; max-width: 540px; }
.hero-menu a { font-family: var(--sans); font-size: 16px; color: var(--ink-3); width: fit-content; padding: 3px 0; transition: transform .15s var(--ease); }
.hero-menu a strong { color: var(--ink); font-weight: 600; text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px; text-decoration-color: var(--line-strong); transition: text-decoration-color .15s; }
.hero-menu a:hover { color: var(--ink-2); }
.hero-menu a:hover strong { text-decoration-color: var(--ink); }
.hero-menu a .dash { color: var(--ink-4); margin: 0 3px; }

/* Globe + EN language toggle in the nav, left of Sign in — no box */
.lang--icon .lang-btn { gap: 6px; padding: 7px 9px; border: 0; background: transparent; color: var(--ink-3); border-radius: var(--radius); font-family: var(--sans); font-size: 14px; font-weight: 500; }
.lang--icon .lang-btn:hover, .lang--icon .lang-btn[aria-expanded="true"] { color: var(--ink); background: var(--bg-sunken); }
.lang--icon .lang-btn .globe { width: 16px; height: 16px; }
.lang--icon .lang-menu { right: 0; left: auto; }

/* ── Mobile nav: brand in the bar + hamburger panel (Basecamp-style) ───── */
/* Brand only appears in the bar on mobile; on desktop the logo lives in the hero */
.lnav .lnav-brand { display: none; align-items: center; gap: 10px; font-family: var(--sans); font-weight: 600; font-size: 18px; letter-spacing: -0.02em; color: var(--ink); text-decoration: none; }
.lnav .lnav-brand img { width: 30px; height: 30px; border-radius: 8px; }

.nav-burger { display: none; position: relative; width: 42px; height: 42px; flex: 0 0 auto; padding: 0; border: 0; background: transparent; border-radius: var(--radius); color: var(--ink); cursor: pointer; -webkit-tap-highlight-color: transparent; transition: background .15s; }
.nav-burger:hover { background: var(--bg-sunken); }
.nav-burger .bx { position: absolute; inset: 0; display: grid; place-items: center; transition: opacity .2s var(--ease), transform .2s var(--ease); }
.nav-burger .bx svg { width: 20px; height: 20px; display: block; }
.nav-burger .b-close { opacity: 0; transform: rotate(-90deg); }
.nav-open .nav-burger .b-open { opacity: 0; transform: rotate(90deg); }
.nav-open .nav-burger .b-close { opacity: 1; transform: none; }

/* Slide-down panel + scrim — kept out of the DOM flow on desktop */
.nav-scrim, .nav-panel { display: none; }
.nav-scrim { position: fixed; inset: 0; z-index: 90; background: rgba(34,31,28,.22); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); opacity: 0; pointer-events: none; transition: opacity .25s var(--ease); }
.nav-panel { position: fixed; top: 60px; right: var(--gutter); left: var(--gutter); margin-left: auto; max-width: 340px; z-index: 95; background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: 10px; transform-origin: top right; opacity: 0; transform: translateY(-10px) scale(.97); pointer-events: none; transition: opacity .2s var(--ease), transform .28s var(--spring); }
.nav-panel-links { display: grid; gap: 1px; }
.nav-panel-links a { display: flex; align-items: baseline; gap: 8px; padding: 11px 12px; border-radius: var(--radius); font-family: var(--sans); font-size: 16px; line-height: 1.2; color: var(--ink-3); text-decoration: none; transition: background .12s; }
.nav-panel-links a strong { color: var(--ink); font-weight: 600; }
.nav-panel-links a span { font-size: 13.5px; }
.nav-panel-links a:hover, .nav-panel-links a:active { background: var(--bg-sunken); }
.nav-panel-foot { display: grid; gap: 8px; margin-top: 8px; padding-top: 10px; border-top: 1px solid var(--line); }
.btn-block { width: 100%; justify-content: center; }
/* Language: same globe-dropdown as the desktop bar (scales past 2 languages) */
.nav-panel-lang { position: relative; margin-top: 10px; }
.nav-panel-lang .lang-btn { width: 100%; justify-content: flex-start; gap: 9px; padding: 11px 13px; border: 1px solid var(--line); border-radius: var(--radius); background: transparent; color: var(--ink-2); font-family: var(--sans); font-size: 14.5px; font-weight: 500; cursor: pointer; }
.nav-panel-lang .lang-btn:hover, .nav-panel-lang .lang-btn[aria-expanded="true"] { background: var(--bg-sunken); color: var(--ink); }
.nav-panel-lang .lang-btn .globe { width: 16px; height: 16px; }
.nav-panel-lang .lang-btn .chev { width: 12px; height: 12px; margin-left: auto; color: var(--ink-4); transition: transform .2s var(--ease); }
.nav-panel-lang .lang-btn[aria-expanded="true"] .chev { transform: rotate(180deg); }
/* opens upward from the bottom row, full panel width, scrolls if many languages */
.nav-panel-lang .lang-menu { top: auto; bottom: calc(100% + 8px); left: 0; right: 0; min-width: 0; max-height: 248px; overflow-y: auto; transform: translateY(6px); }
.nav-panel-lang .lang-menu.open { transform: none; }
.nav-panel-lang .lang-menu button { padding: 11px 12px; font-size: 15px; }

@media (max-width: 980px) {
  .hero { min-height: 0; padding-top: clamp(84px, 12vw, 108px); }
  .hero-grid { grid-template-columns: 1fr; gap: clamp(28px, 5vw, 40px); }
  .hero-copy { display: block; min-height: 0; }   /* drop the desktop viewport-height spacer */
  .hero-headline { margin-top: 0; }
  .hero-visual { align-self: auto; margin-right: calc(-1 * var(--gutter)); }
  /* margin:0 kills the UA <figure> margin so the shot's LEFT edge lines up with
     the headline + "1-minute tour" button (the gutter), then bleeds off right */
  .hero-visual .shot { width: 130%; margin: 0; }
}

/* ── Screenshot frame ─────────────────────────────────────────────────── */
.shot { border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--bg-raised); box-shadow: var(--shadow-lg); overflow: hidden; }
.shot img, .shot video { width: 100%; height: auto; display: block; }
.vidwrap { margin: 0 0 30px; }
.vctl { display: flex; gap: 2px; margin-top: 8px; }
.vctl-btn { width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--ink-4); cursor: pointer; transition: color .15s, background .15s; }
.vctl-btn:hover { color: var(--ink); background: var(--bg-sunken); }
.vctl-btn svg { width: 13px; height: 13px; display: block; }
/* fullscreen affordance — phones/tablets only (on desktop the clips are already
   large, and tapping for OS fullscreen is a touch convenience) */
.vctl-fs { display: none; }
@media (max-width: 900px) { .vctl-fs { display: inline-flex; margin-left: auto; } }   /* sits at the right end of the control row */
.vctl-btn .i-pause { display: none; }
.vctl-btn.is-playing .i-play { display: none; }
.vctl-btn.is-playing .i-pause { display: block; }
.shot.bleed { max-width: 1120px; margin-inline: auto; }
figcaption { margin-top: 14px; font-size: 14px; color: var(--ink-3); font-family: var(--sans); }

/* ── Two-column letter (Basecamp "columns") ───────────────────────────── */
.columns { display: grid; grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr); gap: clamp(32px, 6vw, 80px); align-items: start; }
.columns header h2 { position: sticky; top: 92px; }
.columns .prose { font-size: 19px; }
/* second sentence of the "Come see it live" intro — its own line. Tight on
   desktop, a little more air on phones (where the cramped <br> read badly). */
.cls-sub { display: block; margin-top: .18em; }
.sig { margin-top: 28px; font-family: var(--sans); font-size: 15px; color: var(--ink-3); line-height: 1.4; }
.sig--person { display: flex; align-items: center; gap: 14px; }
.sig-photo { width: 54px; height: 54px; border-radius: 50%; object-fit: cover; flex-shrink: 0; border: 1px solid var(--line-strong); }
.sig .name { font-family: var(--sans); font-style: normal; font-weight: 600; font-size: 17px; letter-spacing: -0.01em; color: var(--ink); display: block; margin-bottom: 2px; }
.sig a { color: var(--ink); }

/* ── Pillar eyebrow ───────────────────────────────────────────────────── */
.pillar { font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-3); }
.pillar b { color: var(--ink); font-weight: 600; }

/* ── Audience split (two doors in) ────────────────────────────────────── */
.who { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 40px; }
.who .card { background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 30px 32px; box-shadow: var(--shadow-xs); transition: transform .2s var(--ease), box-shadow .25s var(--ease); }
.who .card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.who .card .eyebrow { display: block; margin-bottom: 13px; }
.who .card h3 { font-size: 22px; margin-bottom: 10px; letter-spacing: -0.02em; }
.who .card p { color: var(--ink-3); font-size: 16px; max-width: 40ch; margin: 0; }
.who .card p .hl { color: var(--ink); }
@media (max-width: 760px) { .who { grid-template-columns: 1fr; } }

/* ── Alternating feature rows ─────────────────────────────────────────── */
.frow { display: grid; grid-template-columns: 1fr 1.06fr; gap: clamp(32px, 5vw, 72px); align-items: center; }
.frow + .frow { margin-top: clamp(56px, 8vw, 110px); }
.frow .ftext .eyebrow, .frow .ftext .pillar { display: block; margin-bottom: 14px; }
.frow .ftext h3 { font-size: clamp(24px, 2.7vw, 33px); letter-spacing: -0.03em; line-height: 1.08; margin-bottom: 16px; }
.frow .ftext p { color: var(--ink-2); font-size: 18px; line-height: 1.55; max-width: 46ch; }
.frow .ftext p .hl { color: var(--ink); }
.frow.rev .ftext { order: 2; }
.frow .fvisual .shot { width: 100%; }
@media (max-width: 900px) { .frow { grid-template-columns: 1fr; gap: 28px; } .frow.rev .ftext { order: 0; } }

/* feature chips under copy */
.feat-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; }
.feat-chips span { font-family: var(--sans); font-size: 13.5px; color: var(--ink-2); background: var(--bg-raised); border: 1px solid var(--line); border-radius: 999px; padding: 6px 13px; }
.feat-chips span b { color: var(--ink); font-weight: 600; }

/* three-view strip */
.viewstrip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 16px; }
.viewstrip figure { margin: 0; }
.viewstrip .shot { width: 100%; }
.viewstrip figcaption { margin-top: 9px; font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-4); text-align: center; }
@media (max-width: 700px) { .viewstrip { grid-template-columns: 1fr; max-width: 420px; margin-inline: auto; } }

/* ============================================================================
   Long-form pages (Features / Simplicity / Speed / Intelligence)
   Basecamp Features layout: one calm, centered column. Centered hero,
   then a stack of big screenshots, each followed by a left-aligned heading
   + paragraph. Lots of breathing room.
============================================================================ */
/* Brand header — the AnalystX logo is its own top-of-page header on every
   subpage, decoupled from the hero, so it sits at the exact same spot no matter
   what the first section does (centred fold, tight video, etc.). The .wrap
   inside keeps it aligned to the same gutter as the headings below. */
/* Floor scales down on phones so the logo sits up near the top like a normal
   mobile header (matching index's top bar) instead of ~100px down; desktop is
   unchanged (10vw ≥ 88 once past ~880px). */
.page-brand { padding-top: clamp(32px, 10vw, 140px); }
.page-brand .hero-brand { margin: 0; }

/* Heading section top spacing — the gap from the brand header down to the H1.
   (The brand itself no longer lives here, so this is a smaller gap, not the
   page's whole top padding.) */
.page-head { padding-top: clamp(16px, 2.5vw, 28px); }
.page-head--flush { padding-bottom: 0; }                      /* live app sits flush below (intelligence) */
.page-head--tight { padding-bottom: clamp(20px, 3vw, 40px); } /* journeys */

.lp { max-width: 860px; margin: 0; }
.lp-head { text-align: left; max-width: 720px; margin: clamp(26px, 4vw, 44px) 0 clamp(46px, 7vw, 80px); }
.lp-head:has(+ .journeys) { margin-bottom: clamp(16px, 2.5vw, 28px); }
.lp-head .eyebrow, .lp-head .pillar { display: block; margin-bottom: 18px; }
.lp-head h1 { font-size: clamp(34px, 5vw, 54px); letter-spacing: -0.035em; line-height: 1.04; }
.lp-head .lead { margin: 22px 0 0; max-width: 52ch; color: var(--ink-3); font-size: clamp(18px, 2vw, 21px); line-height: 1.5; }
.lp-head .doccta { margin-top: 30px; display: flex; gap: 12px; justify-content: flex-start; flex-wrap: wrap; }

.lp-block + .lp-block { margin-top: clamp(56px, 8vw, 100px); }
.lp-block figure.shot { margin: 0; width: 100%; }
.lp-block .eyebrow { display: block; margin-bottom: 14px; }
.lp-block h2 { font-size: clamp(24px, 2.7vw, 32px); letter-spacing: -0.03em; line-height: 1.12; margin: 0 0 14px; }
.lp-block h2 .tag-exc, .lp-block h2 .tag-soon { vertical-align: middle; margin-left: 6px; }
.lp-block p { color: var(--ink-2); font-size: 18px; line-height: 1.6; }
.lp-block p + p { margin-top: 1em; }
.lp-block .lead-p { font-size: 20px; color: var(--ink); }

/* checkmark list (Reliability) */
.checks { list-style: none; margin: 18px 0 0; padding: 0; display: grid; gap: 12px; max-width: 60ch; }
.checks li { position: relative; padding-left: 30px; font-family: var(--sans); font-size: 17px; color: var(--ink-2); line-height: 1.5; }
.checks li::before { content: "✓"; position: absolute; left: 0; top: 1px; color: #2c9e63; font-weight: 700; }
.checks li strong, .checks li b { color: var(--ink); font-weight: 600; }

/* speed page — instant timing chips */
.ticks { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 22px 0 0; max-width: 60ch; }
.ticks div { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius); padding: 13px 16px; }
.ticks .lbl { font-family: var(--sans); font-size: 15px; color: var(--ink-2); }
.ticks .t { font-family: var(--mono); font-size: 14px; font-weight: 600; color: #2c9e63; letter-spacing: -0.01em; }
@media (max-width: 560px) { .ticks { grid-template-columns: 1fr; } }

/* big statement line for the speed page */
.bigstate { font-family: var(--sans); font-weight: 600; letter-spacing: -0.035em; line-height: 1.04; font-size: clamp(30px, 4.4vw, 52px); color: var(--ink); max-width: 18ch; }
.bigstate .dim { color: var(--ink-4); }

/* example automations list (intelligence) */
.recipes { list-style: none; margin: 20px 0 0; padding: 0; display: grid; gap: 10px; max-width: 62ch; }
.recipes li { background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 16px; font-family: var(--sans); font-size: 16px; color: var(--ink-2); line-height: 1.45; }
.recipes li b { color: var(--ink); font-weight: 600; }
.recipes li .ic { color: var(--ink-4); margin-right: 8px; }

/* ============================================================================
   Homepage v2 — varied rhythm (letter → one-liners → big feature → bento →
   bold stat → proof → it's time → CTA)
============================================================================ */
.section-ink { background: var(--ink); color: #fff; }
.section-ink .eyebrow, .section-ink .pillar { color: rgba(255,255,255,.5); }
.section-ink .pillar b { color: #fff; }
.section-ink h2, .section-ink h3 { color: #fff; }
.section-ink p { color: rgba(255,255,255,.72); }
.section-ink .composer-hint { color: rgba(255,255,255,.4); }

/* ── "The noise is gone" — full-height dark moment that clears on scroll ── */
.calm { position: relative; min-height: 100vh; min-height: calc(100svh / var(--zoom, 1)); display: flex; align-items: center; justify-content: center; text-align: center; background: #15120f; color: #fff; overflow: hidden; padding-block: clamp(56px, 10vh, 80px); }
.calm .wrap { position: relative; z-index: 3; max-width: 820px; }
.calm h2 { color: #fff; font-size: clamp(30px, 5vw, 56px); letter-spacing: -0.035em; line-height: 1.05; filter: blur(9px); opacity: 0; transform: translateY(10px) scale(.99); transition: filter 1s var(--ease), opacity 1s var(--ease), transform 1s var(--ease); }
.calm p { color: rgba(255,255,255,.62); max-width: 48ch; margin: 22px auto 0; font-size: clamp(17px, 1.9vw, 20px); line-height: 1.5; opacity: 0; transform: translateY(8px); transition: opacity .9s ease .35s, transform .9s var(--ease) .35s; }
.calm.in h2 { filter: blur(0); opacity: 1; transform: none; }
.calm.in p { opacity: 1; transform: none; }
/* the noise: scattered chips that wink out */
.calm-noise { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.calm-noise span { position: absolute; font-family: var(--sans); font-size: 13px; color: rgba(255,255,255,.5); background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.10); border-radius: 9px; padding: 6px 12px; white-space: nowrap; opacity: 1; transform: none; transition: opacity .6s ease, transform 1s var(--ease); }
.calm.in .calm-noise span { opacity: 0; transform: translateY(-14px) scale(.9); }
@media (prefers-reduced-motion: reduce) {
  .calm h2, .calm p { filter: none; opacity: 1; transform: none; transition: none; }
  .calm-noise { display: none; }
}

/* trust strip under hero */
.proof-row { display: flex; align-items: center; justify-content: center; gap: 12px 22px; flex-wrap: wrap; font-family: var(--sans); font-size: 14px; color: var(--ink-3); }
.proof-row b { color: var(--ink); font-weight: 600; }
.proof-row .dot { width: 4px; height: 4px; border-radius: 50%; background: var(--ink-4); }

/* problem one-liners */
.pains { list-style: none; margin: 6px 0 0; padding: 0; }
.pains li { font-family: var(--sans); font-weight: 600; letter-spacing: -0.03em; font-size: clamp(21px, 2.8vw, 32px); line-height: 1.18; color: var(--ink); padding: 24px 0; border-bottom: 1px solid var(--line); }
.pains li:first-child { border-top: 1px solid var(--line); }

/* big feature (Autopilot centerpiece) */
.bigfeat { display: grid; grid-template-columns: 1fr 1.05fr; gap: clamp(32px, 5vw, 64px); align-items: center; }
@media (max-width: 900px) { .bigfeat { grid-template-columns: 1fr; gap: 32px; } }

/* ── Hero-style product showcase (big screenshot bleeding off one edge) ──── */
.show { overflow: hidden; }
.show-grid { display: grid; grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr); gap: clamp(32px, 5vw, 64px); align-items: center; }
.show-text h2 { font-size: clamp(30px, 4vw, 46px); letter-spacing: -0.035em; line-height: 1.04; }
.show-text p { color: var(--ink-2); font-size: 19px; line-height: 1.55; margin-top: 18px; max-width: 42ch; }
.show-text .composer { margin-top: 26px; }
.show-visual .shot { width: 1240px; max-width: none; }
/* view switcher (Table / Pipeline / Calendar) that swaps the screenshot.
   Active state is a single sliding pill (JS-positioned), mirroring the app. */
.viewswitch { position: relative; display: inline-flex; gap: 2px; margin-top: 26px; padding: 4px; background: var(--bg-sunken); border: 1px solid var(--line); border-radius: 999px; }
.vw-btn { position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 7px; font-family: var(--sans); font-size: 14px; font-weight: 500; color: var(--ink-3); background: transparent; border: 0; padding: 9px 16px; border-radius: 999px; cursor: pointer; transition: color .2s ease; }
.vw-btn svg { width: 15px; height: 15px; }
.vw-btn:hover { color: var(--ink); }
.vw-btn.is-on { color: var(--ink); }
.viewswitch .seg-pill { position: absolute; top: 4px; left: 0; height: calc(100% - 8px); width: 0; background: var(--bg-raised); border-radius: 999px; box-shadow: var(--shadow-xs); transform: translateX(0); transition: transform 340ms cubic-bezier(.22,.8,.22,1), width 340ms cubic-bezier(.22,.8,.22,1); z-index: 0; pointer-events: none; }
/* stacked screenshots that crossfade */
.shot--stack { position: relative; aspect-ratio: 16 / 9; }
.shot--stack img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: top left; opacity: 0; transition: opacity .5s var(--ease); }
.shot--stack img.is-on { opacity: 1; }

/* reversed — visual on the left, bleeding off the left edge */
.show-grid.rev { grid-template-columns: minmax(0, 1.18fr) minmax(0, 0.82fr); }
.show-grid.rev .show-text { order: 2; }
.show-grid.rev .show-visual { order: 1; display: flex; justify-content: flex-end; }
.show-grid.rev .show-visual .shot { flex-shrink: 0; }
@media (max-width: 900px) {
  .show-grid, .show-grid.rev { grid-template-columns: 1fr; gap: 30px; }
  .show-grid.rev .show-text { order: 0; }
  /* keep the desktop left/right rhythm on phones: default sections bleed off the
     RIGHT edge (flush left with the text/buttons above), reversed sections bleed
     off the LEFT edge (flush right). margin:0 on the shot removes the UA <figure>
     margin so the anchored edge lines up exactly with the content gutter. */
  .show-visual { margin-left: 0; margin-right: calc(-1 * var(--gutter)); }
  .show-grid.rev .show-visual { margin-left: calc(-1 * var(--gutter)); margin-right: 0; justify-content: flex-end; }
  .show-visual .shot { width: 170%; flex-shrink: 0; margin: 0; }   /* bigger so the app is legible on phones */
}

/* bento grid */
.bento { display: grid; grid-template-columns: repeat(6, 1fr); gap: 16px; }
.bento .cell { background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: clamp(24px, 2.4vw, 32px); box-shadow: var(--shadow-xs); display: flex; flex-direction: column; transition: transform .2s var(--ease), box-shadow .25s var(--ease); }
.bento .cell:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.bento .cell .eyebrow { display: block; margin-bottom: 11px; }
.bento .cell h3 { font-size: clamp(20px, 2vw, 23px); letter-spacing: -0.02em; line-height: 1.15; margin: 0 0 9px; }
.bento .cell p { color: var(--ink-3); font-size: 15.5px; line-height: 1.5; margin: 0; }
.bento .cell .ss { margin-top: 20px; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--bg-sunken); }
.bento .cell .ss img { width: 100%; display: block; }
.bento .c2 { grid-column: span 2; }
.bento .c3 { grid-column: span 3; }
.bento .c4 { grid-column: span 4; }
@media (max-width: 900px) { .bento { grid-template-columns: 1fr; } .bento .c2, .bento .c3, .bento .c4 { grid-column: auto; } }

/* urgency — "it's time" */
.timelist { list-style: none; margin: 8px 0 0; padding: 0; max-width: 860px; }
.timelist li { font-family: var(--sans); font-weight: 500; font-size: clamp(18px, 2.1vw, 25px); line-height: 1.35; padding: 16px 0; border-bottom: 1px solid rgba(255,255,255,.12); color: rgba(255,255,255,.6); }
.timelist li strong { color: #fff; font-weight: 600; }

/* light "it's time" list (calm, on cream) */
.timelite { list-style: none; margin: 0; padding: 0; }
.timelite li { font-family: var(--sans); font-size: clamp(17px, 1.9vw, 21px); line-height: 1.4; color: var(--ink-3); padding: 15px 0; border-bottom: 1px solid var(--line); }
.timelite li:first-child { border-top: 1px solid var(--line); }
.timelite li strong { color: var(--ink); font-weight: 600; }
.timelite li strong.hl { color: #fff; }

/* live class cards (Basecamp-style dated cards) */
.classes-grid { display: flex; flex-direction: column; gap: 14px; margin-top: 34px; }

/* calendar badge (shared) */
.cal-badge { flex-shrink: 0; width: 52px; text-align: center; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; background: var(--bg-raised); }
.cal-badge .m { display: block; font-family: var(--mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; background: var(--ink); color: #fff; padding: 4px 0; }
.cal-badge .d { display: block; font-family: var(--sans); font-weight: 600; font-size: 21px; color: var(--ink); padding: 5px 0 6px; }
.cal-badge--lg { width: 62px; }
.cal-badge--lg .m { font-size: 10px; padding: 4px 0; }
.cal-badge--lg .d { font-size: 22px; padding: 3px 0 5px; }

/* featured "next session" card */
.class-next { display: flex; align-items: center; gap: 20px; background: var(--bg-raised); border: 1px solid var(--line-strong); border-radius: var(--radius-lg); padding: 22px 24px; box-shadow: var(--shadow-xs); transition: transform .2s var(--ease), box-shadow .2s var(--ease), border-color .2s; }
.class-next:hover { transform: translateY(-2px); box-shadow: var(--shadow); border-color: var(--ink); }
.cn-body { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }
.cn-eyebrow { display: inline-flex; align-items: center; font-size: 12px; font-weight: 600; letter-spacing: .02em; color: var(--ink-2); text-transform: uppercase; }
.cn-title { font-family: var(--sans); font-weight: 600; font-size: 19px; color: var(--ink); margin-top: 2px; }
.cn-meta { font-size: 14px; color: var(--ink-3); }
.cn-btn { flex-shrink: 0; display: inline-flex; align-items: center; gap: 8px; background: var(--ink); color: #fff; font-family: var(--sans); font-weight: 500; font-size: 15px; padding: 12px 20px; border-radius: var(--radius); white-space: nowrap; transition: gap .2s var(--ease), background .2s; }
.class-next:hover .cn-btn { background: var(--accent); }
.cn-arrow { transition: transform .2s var(--ease); }
.class-next:hover .cn-arrow, .class-row:hover .cn-arrow { transform: translateX(3px); }

/* upcoming rows */
.class-list { display: flex; flex-direction: column; }
.class-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 20px 14px; border-radius: var(--radius); border-bottom: 1px solid var(--line); transition: background .15s var(--ease), padding-left .2s var(--ease); }
.class-row:hover { background: var(--bg-raised); padding-left: 18px; }
.cr-main { display: flex; flex-direction: column; gap: 7px; flex: 1; min-width: 0; }
.cr-title { font-family: var(--sans); font-weight: 600; font-size: 19px; line-height: 1.25; color: var(--ink); }
.cr-date { display: flex; flex-direction: column; gap: 1px; }
.cr-date b { font-family: var(--sans); font-weight: 600; font-size: 15px; color: var(--ink); }
.cr-date span { font-size: 13px; color: var(--ink-3); }
.cr-go { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; font-weight: 500; color: var(--ink-2); }
.class-row:hover .cr-go { color: var(--ink); }

/* "Want your own meeting with us? Book demo" — opens the Cal demo overlay */
.class-note { margin-top: 26px; font-size: 14px; color: var(--ink-3); }
.class-note-link { font: inherit; font-weight: 700; color: var(--ink); background: none; border: 0; padding: 0; margin-left: 4px; cursor: pointer; text-decoration: none; -webkit-appearance: none; appearance: none; transition: color .15s var(--ease); }
.class-note-link:hover { color: var(--accent); }

@media (max-width: 560px) {
  .class-next { flex-wrap: wrap; gap: 14px; }
  .cn-btn { width: 100%; justify-content: center; }
  .class-row { gap: 12px; padding: 18px 12px; }
  .cr-title { font-size: 17px; }
}

/* ── "The answer is yes" — bigger, bolder, with green check badges ──────── */
.yes-kicker { font-family: var(--sans); font-size: clamp(18px, 2vw, 22px); color: var(--ink-3); margin: 0 0 16px; }
.yes--big { columns: 2; column-gap: 64px; max-width: 1020px; margin-top: clamp(30px, 4vw, 44px); }
.yes--big li { break-inside: avoid; position: relative; list-style: none; font-family: var(--sans); font-size: clamp(17px, 1.7vw, 19px); line-height: 1.4; color: var(--ink-2); padding: 18px 0 18px 32px; border-bottom: 1px solid var(--line); }
.yes--big li::before { content: "✓"; position: absolute; left: 0; top: 18px; color: #2c9e63; font-weight: 700; font-size: 16px; }
@media (max-width: 760px) { .yes--big { columns: 1; } }

/* floating peekaboo CTA — springs up from the bottom-right after ~30% scroll */
.peek { position: fixed; right: 24px; bottom: 24px; z-index: 80; transform: translateY(170%);
  display: inline-flex; align-items: center; gap: 10px; background: var(--ink); color: #fff;
  font-family: var(--sans); font-weight: 600; font-size: 15px; letter-spacing: -0.01em;
  padding: 13px 24px 13px 20px; border-radius: var(--radius); box-shadow: 0 16px 36px -12px rgba(20,18,15,.55);
  opacity: 0; pointer-events: none;
  transition: transform .55s var(--spring), opacity .3s ease, box-shadow .2s var(--ease); }
.peek.show { transform: translateY(0); opacity: 1; pointer-events: auto; }
.peek:hover { box-shadow: 0 22px 44px -12px rgba(20,18,15,.65); }
.peek img { width: 20px; height: 20px; filter: brightness(0) invert(1); }
@media (prefers-reduced-motion: reduce) { .peek { transition: opacity .25s ease; } .peek.show { transform: translateY(0); } }

/* ── Statement divider ────────────────────────────────────────────────── */
.statement h2 { max-width: 18ch; }
.statement .lead { margin-top: 18px; color: var(--ink-3); }

/* ── Walkthrough block (headline + intro + visual) ────────────────────── */
.walk { max-width: 760px; }
.walk .eyebrow { display: block; margin-bottom: 16px; }
.walk h3 { margin-bottom: 16px; }
.walk p { color: var(--ink-2); font-size: 19px; max-width: var(--measure); }
.visual { margin-top: clamp(28px, 4vw, 48px); }
.visual + .walk, section + section { }
.walk-list { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 10px; max-width: 620px; }
.walk-list li { background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 16px; font-family: var(--sans); font-size: 16px; color: var(--ink-2); }

/* ── Stats inline ─────────────────────────────────────────────────────── */
.stats { display: grid; grid-template-columns: repeat(3,1fr); gap: 28px; margin-top: 8px; }
.stat .n { font-family: var(--sans); font-weight: 600; letter-spacing: -0.04em; font-size: clamp(40px, 5vw, 56px); line-height: 1; color: var(--ink); }
.stat .l { margin-top: 8px; font-family: var(--sans); font-size: 14px; color: var(--ink-3); }

/* Three things — plain text columns, no boxes */
.three { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(28px, 4vw, 56px); }
.three .item .eyebrow { display: block; margin-bottom: 14px; }
.three .item h3 { font-size: 21px; margin-bottom: 10px; }
.three .item p { color: var(--ink-3); font-size: 16px; max-width: 34ch; }
.three .item .mini { margin-top: 14px; font-family: var(--sans); font-size: 14px; color: var(--ink-2); }
.three .item .mini b { font-weight: 600; }
@media (max-width: 880px) { .three { grid-template-columns: 1fr; gap: 36px; } }

/* ── YES list ─────────────────────────────────────────────────────────── */
.yes-head { display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap; }
.yes-tag { font-family: var(--sans); font-weight: 600; font-style: normal; color: #fff; background: var(--hl); padding: 0 .16em; border-radius: 5px; }
.yes { list-style: none; margin: 36px 0 0; padding: 0; columns: 2; column-gap: 56px; max-width: 920px; }
.yes li { break-inside: avoid; font-family: var(--sans); font-size: 16px; color: var(--ink-2); padding: 13px 0 13px 28px; border-bottom: 1px solid var(--line); position: relative; line-height: 1.45; }
.yes li::before { content: "✓"; position: absolute; left: 0; top: 13px; color: #2c9e63; font-weight: 700; font-size: 14px; }

/* ── "It's time" closer ───────────────────────────────────────────────── */
.timer { max-width: 880px; }
.timer h2 { max-width: 18ch; margin-bottom: 28px; }
.timer ul { list-style: none; margin: 0; padding: 0; }
.timer li { font-family: var(--serif); font-size: clamp(20px, 2.4vw, 27px); line-height: 1.35; color: var(--ink-3); padding: 16px 0; border-bottom: 1px solid var(--line); }
.timer li strong { color: var(--ink); font-weight: 400; }

/* ── FAQ ──────────────────────────────────────────────────────────────── */
.faq { max-width: 760px; }
.faq-q { font-family: var(--sans); font-weight: 600; letter-spacing: -0.02em; font-size: clamp(19px, 2vw, 23px); color: var(--ink); margin: 44px 0 10px; }
.faq-q:first-of-type { margin-top: 28px; }
.faq-a { font-family: var(--sans); font-size: 17px; color: var(--ink-2); max-width: var(--measure); }
.faq-a a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

/* ── Final CTA ────────────────────────────────────────────────────────── */
.cta { text-align: center; }
.cta h2 { max-width: 16ch; margin: 0 auto; }
.cta .lead { margin: 20px auto 32px; max-width: 30ch; color: var(--ink-3); }

/* ── Footer ───────────────────────────────────────────────────────────── */
.lfoot { border-top: 1px solid var(--line); margin-top: 28px; padding-top: 76px; }
.lfoot-top { display: flex; align-items: center; justify-content: space-between; gap: 20px 44px; flex-wrap: wrap; }
.lfoot-links { display: flex; flex-wrap: wrap; gap: 10px 28px; }
.lfoot-links a { font-family: var(--sans); font-size: 14.5px; color: var(--ink-3); text-decoration: none; }
.lfoot-links a:hover { color: var(--ink); }
.lfoot-base { display: flex; align-items: center; justify-content: space-between; gap: 10px 24px; flex-wrap: wrap; margin-top: 48px; font-family: var(--sans); font-size: 13.5px; color: var(--ink-4); }
/* Plain text flow (NOT flex) so the inline flag stays in the sentence instead of
   splitting it into text│flag│text columns that wrap badly on phones. */
.lfoot-made { color: var(--ink-3); margin-right: auto; }
.lfoot-legal { display: inline-flex; align-items: center; gap: 18px; }
.lfoot-legal a { color: var(--ink-4); text-decoration: none; transition: color .15s; }
.lfoot-legal a:hover { color: var(--ink); }
/* Norwegian statutory company disclosure (Foretaksregisterloven §10-2) — name, HQ, register, org no + MVA */
.lfoot-org { margin: 18px 0 0; font-family: var(--sans); font-size: 12.5px; line-height: 1.5; color: var(--ink-4); }
.lfoot-org strong { color: var(--ink-3); font-weight: 600; }
.lfoot-reg::before { content: " · "; }   /* separator after the company name on one line (desktop) */

/* ── Journeys page ─────────────────────────────────────────────────────── */
.journeys { display: block; margin-top: clamp(20px, 3vw, 36px); perspective: 1700px; }
.journey { background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: clamp(22px, 3vw, 34px); box-shadow: var(--shadow-xs); margin-bottom: 20px; transition: box-shadow .25s var(--ease), border-color .25s; }
.journey:hover { box-shadow: var(--shadow); border-color: var(--line-strong); }
.journey-head h2 { font-size: clamp(20px, 2.4vw, 26px); line-height: 1.15; margin: 0; }
.journey-head p { color: var(--ink-3); margin: 8px 0 0; max-width: 56ch; font-size: 15.5px; line-height: 1.5; }

.jpath { display: flex; align-items: flex-start; margin-top: clamp(26px, 3vw, 38px); }
.jnode { flex: 0 0 auto; width: 104px; text-align: center; }
.jlogo { width: 56px; height: 56px; border-radius: 16px; margin: 0 auto; background: var(--bg); border: 1px solid var(--line-strong); display: flex; align-items: center; justify-content: center; font-family: var(--sans); font-weight: 700; font-size: 18px; color: var(--ink-3); overflow: hidden; box-shadow: var(--shadow-xs); }
.jlogo img { max-width: 40px; max-height: 34px; width: auto; height: auto; object-fit: contain; }
.jlogo svg { width: 26px; height: 26px; color: var(--ink-3); }
.jnode-name { display: block; font-family: var(--sans); font-weight: 600; font-size: 13px; color: var(--ink-2); margin-top: 12px; line-height: 1.25; }
.jnode-cap { display: block; font-size: 11.5px; color: var(--ink-4); margin-top: 3px; line-height: 1.3; }
.jnode--end .jlogo { background: var(--ink); border-color: var(--ink); }
.jnode--end .jlogo img { filter: brightness(0) invert(1); }
.jnode--end .jnode-name { color: var(--ink); }

.jarc { flex: 1 1 auto; min-width: 22px; height: 56px; }
.jarc path { fill: none; stroke: var(--line-strong); stroke-width: 2; vector-effect: non-scaling-stroke; stroke-linecap: round; stroke-linejoin: round; }

/* Card deck: one stage pins to the viewport; cards are stacked papers, shuffled by scroll.
   JS (journeys.html) sets .journeys height + per-card transforms. Falls back to a plain
   list when JS is off, on mobile, or with reduced motion. */
.deck-on .journeys { position: relative; }
.deck-on .deck-stage { position: sticky; top: clamp(72px, 11vh, 116px); margin-bottom: 0; }
.deck-on .journey { position: absolute; left: 0; right: 0; top: 0; margin: 0; transform-origin: center top; backface-visibility: hidden; will-change: transform, opacity; transition: none; }

@media (max-width: 680px) {
  .jpath { flex-direction: column; align-items: center; gap: 4px; margin-top: 24px; }
  .jnode { width: auto; }
  .jarc { width: 2px; height: 22px; flex: 0 0 auto; }
}

/* plain social icons, sat on the baseline (no boxes) */
.lfoot-social { display: flex; align-items: center; gap: 18px; }
.lfoot-social a { display: inline-flex; color: var(--ink-4); transition: color .15s, transform .15s var(--ease); }
.lfoot-social a:hover { color: var(--ink); transform: translateY(-1px); }
.lfoot-social svg { width: 18px; height: 18px; display: block; }

/* small inline Norwegian flag — real proportions & colours */
.no-flag {
  display: inline-block; width: 22px; height: 16px; border-radius: 2px;
  margin: 0 8px; vertical-align: -3px;
  background:
    linear-gradient(180deg, transparent 7px, #00205b 7px 9px, transparent 9px),
    linear-gradient(90deg,  transparent 7px, #00205b 7px 9px, transparent 9px),
    linear-gradient(180deg, transparent 6px, #fff 6px 10px, transparent 10px),
    linear-gradient(90deg,  transparent 6px, #fff 6px 10px, transparent 10px),
    #ba0c2f;
  box-shadow: 0 0 0 1px rgba(34,31,28,.10);
}

/* Norwegian flag band — full-bleed at the very bottom, grows in height as you reach the end,
   and gently waves like cloth (animated wavy top edge) */
.flag-band { position: relative; height: 150px; margin-top: 42px; overflow: hidden; }
.flag-band__fill {
  position: absolute; left: 0; right: 0; bottom: 0; height: 0;
  will-change: height;
  background: linear-gradient(180deg,
    #ba0c2f 0 37.5%,
    #fff    37.5% 43.75%,
    #00205b 43.75% 56.25%,
    #fff    56.25% 62.5%,
    #ba0c2f 62.5% 100%);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='200' viewBox='0 0 240 200' preserveAspectRatio='none'%3E%3Cpath d='M0 16 C40 8 80 8 120 16 C160 24 200 24 240 16 L240 200 L0 200 Z' fill='white'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='200' viewBox='0 0 240 200' preserveAspectRatio='none'%3E%3Cpath d='M0 16 C40 8 80 8 120 16 C160 24 200 24 240 16 L240 200 L0 200 Z' fill='white'/%3E%3C/svg%3E");
  -webkit-mask-size: 240px 100%; mask-size: 240px 100%;
  -webkit-mask-repeat: repeat-x; mask-repeat: repeat-x;
  animation: flagwave 7s linear infinite;
}
@keyframes flagwave {
  from { -webkit-mask-position: 0 0;      mask-position: 0 0; }
  to   { -webkit-mask-position: -240px 0; mask-position: -240px 0; }
}
@media (prefers-reduced-motion: reduce) {
  .flag-band__fill { height: 150px !important; animation: none; -webkit-mask-image: none; mask-image: none; }
}

/* small inline American flag — 13 stripes and a navy canton, drawn rather than
   shipped as an image so it picks up the same rounding and hairline as .no-flag */
.us-flag {
  display: inline-block; width: 22px; height: 16px; border-radius: 2px;
  margin: 0 8px; vertical-align: -3px;
  background:
    linear-gradient(#0a3161, #0a3161) 0 0 / 40% 53.85% no-repeat,
    repeating-linear-gradient(180deg, #b31942 0 7.6923%, #fff 7.6923% 15.3846%);
  box-shadow: 0 0 0 1px rgba(34,31,28,.10);
}

/* American flag band, opted into per page with .flag-band--us on the band.
   The Norwegian fill above stays the default and only the stripes change: the
   wave mask, the height and the reduced-motion rule are all shared, which is
   why this is a variant here rather than a copy of the whole band.

   Two sites need it for different reasons, which is what makes it a shared
   rule rather than a brand appendix one. analystx.ai is incorporated in
   Delaware and uses it on every page. softsync.ai uses it on the English
   edition only, and keeps the Norwegian band under /no. */
.flag-band--us .flag-band__fill {
  background: repeating-linear-gradient(180deg,
    #b31942 0 15.38%,
    #fff    15.38% 30.77%);
}

/* ── Reveal (calm) ────────────────────────────────────────────────────── */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; transition: none; } html { scroll-behavior: auto; } }

/* ── Big & ultra-wide screens ─────────────────────────────────────────────
   New-Basecamp approach: above a reference width we ZOOM the whole page (see
   assets/zoom.js), so the layout — and the half-bleed product screenshots —
   scales up to fill the canvas instead of sitting small in a sea of margin.
   The zoom is uniform, so we don't bump --maxw here; we only have to keep the
   full-height (vh) sections one screen tall by dividing them back out by the
   live zoom factor (--zoom, set by the script; defaults to 1). */

/* ── Responsive ───────────────────────────────────────────────────────── */
@media (max-width: 880px) {
  body { font-size: 17px; }
  .lnav-links { display: none; }
  .columns { grid-template-columns: 1fr; gap: 24px; }
  .columns header h2 { position: static; }
  /* Calmer long-form reading on phones: the 19px desktop body copy felt dense
     edge-to-edge. Step it down a touch and open the line/paragraph rhythm. */
  .columns .prose, .prose { font-size: 16.5px; }
  .columns .prose p, .prose p { line-height: 1.65; }
  .columns .prose p + p { margin-top: 16px; }
  .show-text p { font-size: 16.5px; line-height: 1.62; }
  .cls-sub { margin-top: .55em; }   /* more air between the two lines on phones */
  .stats { grid-template-columns: 1fr; gap: 28px; text-align: left; }
  .yes { columns: 1; }
  .lfoot-top { flex-direction: column; align-items: flex-start; gap: 22px; }
  /* On phones the base row crammed Privacy/Terms hard-left and the social icons
     hard-right with a dead gap between. Stack it into a calm left-aligned column. */
  .lfoot-base { flex-direction: column; align-items: flex-start; gap: 18px; margin-top: 36px; }
  .lfoot-made { margin-right: 0; }
  .lfoot-made .made-rest { display: block; }   /* break after the flag on phones */
  /* company name on its own line, the register details break to the next line */
  .lfoot-org strong { display: block; }
  .lfoot-reg::before { content: none; }

  /* Sub-page header logo: match the index bar logo (30px / 18px) so the AnalystX
     mark is the same size everywhere on phones (index uses .lnav-brand there). */
  .page-brand .hero-brand { font-size: 18px; gap: 10px; }
  .page-brand .hero-brand img { width: 30px; height: 30px; border-radius: 8px; }
  /* Partner mark tracks the wordmark down. `min-width: 0` lets a wide partner
     lockup shrink on a narrow phone rather than pushing the row off-screen. */
  .brand-lockup { gap: 11px; max-width: 100%; }
  .brand-partner { height: calc(24px * var(--partner-logo-scale, 1)); min-width: 0; object-fit: contain; object-position: left center; }

  /* Nav: brand left, compact actions + hamburger right */
  .lnav .wrap { justify-content: space-between; gap: 12px; }
  .lnav .lnav-brand { display: inline-flex; }
  .nav-burger { display: inline-flex; }
  .nav-actions { gap: 8px; }
  .nav-actions .lang, .nav-actions .nav-login { display: none; }   /* moved into the panel */
  /* index only: logo + full menu now live in the bar/panel, so drop the hero
     duplicates. Scoped to .hero-top (which exists only on the homepage) so the
     sub-pages keep their hero-brand home link. */
  .hero-copy > .hero-top { display: none; }

  /* The bar was jammed against the very top edge on phones (logo ~17px down),
     while the sub-pages sit much lower. Drop it down so the logo/CTA/burger sit
     at a comfortable height, and push the hero copy down to keep clear of it. */
  .lnav { top: 26px; }
  .hero { padding-top: clamp(124px, 19vw, 152px); padding-bottom: clamp(40px, 9vw, 72px); }

  /* Panel + scrim become live (animated via .nav-open on <body>) */
  .nav-scrim, .nav-panel { display: block; }
  .nav-panel { top: 88px; }   /* sits just below the lowered bar */
  .nav-open .lnav { z-index: 100; }   /* keep brand + close button above the scrim */
  .nav-open .nav-scrim { opacity: 1; pointer-events: auto; }
  .nav-open .nav-panel { opacity: 1; transform: none; pointer-events: auto; }

  /* "Take a 1-minute tour" on phones: no scroll-spring to hunt for (easy to tap),
     but it fades up with the rest of the hero copy instead of popping in instantly
     before the page settles. (JS skips adding .tour--show on mobile so this wins.) */
  .hero .tour { max-height: none; margin-top: 18px; pointer-events: auto;
    opacity: 0; transform: translateY(12px); animation: tourReveal .7s var(--ease) .32s both; }

  /* "It's time for AnalystX." reads awkwardly mid-sentence when the highlight
     box wraps on a narrow screen — drop it onto its own line under the question. */
  .timelite li strong.hl { display: block; width: fit-content; margin-top: 9px; }
}

/* Keep the primary CTA in the bar on phones — it's the main conversion action,
   so we never want to lose it to the burger. Compact it down and, on the very
   smallest screens, drop the brand wordmark (logo still links home) to make room. */
@media (max-width: 440px) {
  .nav-actions .nav-signup { padding: 8px 13px; font-size: 13.5px; }
}
@media (max-width: 360px) {
  .lnav .lnav-brand span { display: none; }
}

/* ============================================================================
   Subtle interactivity — micro-interactions, kept calm and simple
============================================================================ */

/* Buttons: gentle lift */
.btn { transition: transform .14s var(--ease), background .18s, border-color .18s, color .18s, box-shadow .2s var(--ease); }
.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 8px 20px -8px rgba(20,18,15,.4); }
.btn-ghost:hover { transform: translateY(-1px); }

/* Screenshots: lift on hover */
.shot { transition: transform .55s var(--ease), box-shadow .55s var(--ease); will-change: transform; }
.shot:hover { transform: translateY(-6px); box-shadow: 0 44px 88px -26px rgba(31,30,28,.28), 0 8px 16px rgba(31,30,28,.06); }

/* Animated underline for text links */
.lnav-links a, .lfoot-links a, .sig a, .faq-a a, .prose a, .link-anim {
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px; background-position: 0 100%; background-repeat: no-repeat;
  transition: background-size .28s var(--ease), color .15s;
}
.lnav-links a:hover, .lfoot-links a:hover, .sig a:hover, .faq-a a:hover, .prose a:hover, .link-anim:hover { background-size: 100% 1px; }
.prose a, .faq-a a { text-decoration: none; } /* replace static underline with animated one */

.nav-actions { display: flex; align-items: center; gap: 10px; }
.nav-signin { font-family: var(--sans); font-size: 14px; color: var(--ink-3); }
.nav-signin:hover { color: var(--ink); }

/* ── Language selector ────────────────────────────────────────────────── */
/* Matches the button shape/height so EN · Sign in · Sign up free read as one row */
.lang { position: relative; }
.lang-btn { display: inline-flex; align-items: center; gap: 6px; font-family: var(--sans); font-size: 14px; font-weight: 500; line-height: 1; color: var(--ink-3); background: transparent; border: 1px solid var(--line-strong); border-radius: var(--radius); padding: 10px 13px; cursor: pointer; transition: color .15s, border-color .15s, background .15s; }
.lang-btn:hover { color: var(--ink); border-color: var(--ink-4); background: var(--bg-raised); }
.lang-btn .globe { width: 15px; height: 15px; }
.lang-btn .chev { width: 9px; height: 9px; transition: transform .2s var(--ease); }
.lang-btn[aria-expanded="true"] .chev { transform: rotate(180deg); }
.lang-menu { position: absolute; top: calc(100% + 8px); right: 0; min-width: 156px; background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: 5px; z-index: 60; opacity: 0; transform: translateY(-6px); pointer-events: none; transition: opacity .18s var(--ease), transform .18s var(--ease); }
.lang-menu.open { opacity: 1; transform: none; pointer-events: auto; }
.lang-menu button { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; font-family: var(--sans); font-size: 14px; color: var(--ink-2); background: transparent; border: 0; border-radius: 8px; padding: 9px 11px; cursor: pointer; transition: background .12s, color .12s; }
.lang-menu button:hover { background: var(--bg-sunken); color: var(--ink); }
.lang-menu button .flag { font-size: 15px; line-height: 1; }
.lang-menu button .tick { margin-left: auto; opacity: 0; color: var(--ink); font-weight: 600; }
.lang-menu button[aria-checked="true"] { color: var(--ink); font-weight: 500; }
.lang-menu button[aria-checked="true"] .tick { opacity: 1; }

/* Reveal: refined + stagger helpers */
.reveal { transition-duration: .62s; transform: translateY(12px); }
.d1 { transition-delay: .06s; } .d2 { transition-delay: .12s; } .d3 { transition-delay: .18s; } .d4 { transition-delay: .26s; }
/* Hero screenshot: slightly bigger, slower entrance */
.hero-shot.reveal { transform: translateY(30px) scale(.992); transition-duration: .9s; }
.hero-shot.reveal.in { transform: none; }

/* Walk-list rows: subtle hover */
.walk-list li { transition: border-color .18s, transform .18s var(--ease); }
.walk-list li:hover { border-color: var(--line-strong); transform: translateX(2px); }

/* ── Live Autopilot composer (the one interactive moment) ─────────────── */
.composer { max-width: 600px; margin-top: 28px; }
.composer-box { display: flex; align-items: center; gap: 12px; background: var(--bg-raised);
  border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 15px 15px 15px 20px; box-shadow: var(--shadow-sm); }
.composer-field { flex: 1; min-width: 0; display: flex; align-items: center; font-family: var(--sans); font-size: 16px; color: var(--ink-2); line-height: 1.4; min-height: 1.5em; }
.composer-caret { width: 2px; height: 19px; background: var(--ink); display: inline-block; margin-left: 1px; animation: bk 1.05s steps(1) infinite; }
@keyframes bk { 50% { opacity: 0; } }
.composer-go { flex-shrink: 0; background: var(--ink); color: #fff; font-family: var(--sans); font-size: 13px; font-weight: 500; padding: 9px 15px; border-radius: var(--radius); }
.composer-hint { margin-top: 13px; font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-4); }
@media (prefers-reduced-motion: reduce) { .composer-caret { animation: none; } .shot, .btn, .walk-list li { transition: none; } }

/* ── Descriptive link list (Basecamp-style "menu") ────────────────────── */
.navlist { display: grid; gap: 0; max-width: 600px; margin-top: 38px; }
.navlist a { display: flex; align-items: baseline; gap: 8px; padding: 15px 2px; border-top: 1px solid var(--line); font-family: var(--sans); font-size: 16px; color: var(--ink-3); transition: padding-left .2s var(--ease), color .15s; }
.navlist a:last-child { border-bottom: 1px solid var(--line); }
.navlist a strong { color: var(--ink); font-weight: 600; flex-shrink: 0; }
.navlist a .dash { color: var(--ink-4); }
.navlist a:hover { color: var(--ink); padding-left: 8px; }
.navlist a .arrow { margin-left: auto; opacity: 0; transform: translateX(-4px); transition: opacity .2s, transform .2s var(--ease); color: var(--ink-3); }
.navlist a:hover .arrow { opacity: 1; transform: none; }

/* ── Testimonials — gentle auto-scroll, pause on hover ────────────────── */
.marquee { overflow: hidden; margin-top: 8px; -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); }
.marquee-track { display: flex; gap: 20px; width: max-content; animation: marq 60s linear infinite; }
.marquee:hover .marquee-track { animation-play-state: paused; }
@keyframes marq { to { transform: translateX(-50%); } }
.quote { flex: 0 0 400px; background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 28px 30px; box-shadow: var(--shadow-xs); }
.quote p { font-family: var(--sans); font-size: 17px; line-height: 1.5; color: var(--ink); margin: 0 0 16px; }
.quote cite { font-style: normal; font-family: var(--sans); font-size: 13px; color: var(--ink-3); }
@media (prefers-reduced-motion: reduce) { .marquee-track { animation: none; flex-wrap: wrap; } }
@media (max-width: 880px) { .quote { flex-basis: 300px; } }

/* ── Customer logos — "in good company" quiet strip ───────────────────── */
.logos { padding-block: clamp(34px, 4.5vw, 60px); }
.logos-line { text-align: center; font-family: var(--sans); font-size: 16px; color: var(--ink-3); margin: 0 0 30px; }
.logos-line strong { color: var(--ink); font-weight: 600; }
.logos-track { gap: clamp(38px, 5vw, 64px); align-items: center; animation-duration: 52s; animation-play-state: paused; }
/* Hold the row at its starting arrangement until the strip scrolls into view,
   so the first impression is the order we designed (banks in the clear centre,
   not the clipped left edge). Hover still pauses it. */
.logos-marquee.in .logos-track { animation-play-state: running; }
.logos-marquee.in:hover .logos-track { animation-play-state: paused; }
/* Logos sit quiet and monochrome, then bloom to full colour on hover.
   Works for <img> (real logos) and the .logo--ph text wordmarks below. */
.logo { flex: 0 0 auto; height: 30px; width: auto; max-width: 132px; object-fit: contain; filter: grayscale(1); opacity: .5; transition: opacity .3s var(--ease), filter .3s var(--ease); }
/* Per-logo optical balance — trimmed sources vary in glyph weight/ratio, so a
   couple are nudged off the 30px baseline so none visually dominates the row. */
.logo[data-logo="dnb"] { height: 44px; }            /* flagship bank — sized up for emphasis */
.logo[data-logo="enetgi"], .logo[data-logo="placemoint"] { height: 22px; }  /* very wide wordmarks */
.logo--ph { display: inline-flex; align-items: center; height: 30px; font-family: var(--serif); font-size: 22px; font-weight: 500; color: var(--ink); white-space: nowrap; filter: none; }
.logos-marquee:hover .logo { opacity: .28; }
.logos-marquee .logo:hover { opacity: 1; filter: grayscale(0); }
@media (prefers-reduced-motion: reduce) {
  .logos-track { justify-content: center; gap: 30px 48px; }
  .logos-marquee:hover .logo { opacity: .5; }
}
/* Phones: smaller line + logos so the strip shows a few names at once and the
   intro reads comfortably. (Big screens scale up via the page zoom.) */
@media (max-width: 600px) {
  .logos { padding-block: clamp(30px, 9vw, 48px); }
  .logos-line { font-size: 15px; margin-bottom: 22px; max-width: 30ch; margin-inline: auto; }
  .logos-track { gap: 40px; }
  .logo { height: 25px; }
  .logo[data-logo="dnb"] { height: 37px; }
  .logo[data-logo="enetgi"], .logo[data-logo="placemoint"] { height: 18px; }
}

/* ── "Take a tour" banner — animated product preview (no real video) ──── */
.tour { display: inline-flex; align-items: center; gap: 14px; margin-top: 28px;
  background: var(--ink); color: #fff; padding: 10px 22px 10px 10px; border-radius: 14px;
  box-shadow: var(--shadow-sm); transition: transform .16s var(--ease), box-shadow .2s var(--ease); }
.tour:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.tour-thumb { position: relative; width: 92px; height: 60px; border-radius: 8px; overflow: hidden; flex-shrink: 0; background: var(--bg-sunken); }
.tour-thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: left top; opacity: 0; animation: tourCycle 12s infinite; }
.tour-thumb img:nth-child(2) { animation-delay: 4s; }
.tour-thumb img:nth-child(3) { animation-delay: 8s; }
@keyframes tourCycle { 0%, 25% { opacity: 1; } 33%, 100% { opacity: 0; } }
.tour-play { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
.tour-play i { position: relative; width: 30px; height: 30px; border-radius: 50%; background: rgba(255,255,255,.95); display: flex; align-items: center; justify-content: center; }
.tour-play i::after { content: ""; border-left: 9px solid var(--ink); border-top: 6px solid transparent; border-bottom: 6px solid transparent; margin-left: 3px; }
.tour-play i::before { content: ""; position: absolute; inset: -7px; border-radius: 50%; border: 2px solid rgba(255,255,255,.55); animation: tourPulse 2.1s ease-out infinite; }
@keyframes tourPulse { 0% { transform: scale(.75); opacity: .7; } 100% { transform: scale(1.45); opacity: 0; } }
/* mobile hero tour: fades up with the rest of the hero copy (see @media 880) */
@keyframes tourReveal { to { opacity: 1; transform: none; } }
.tour-label { font-family: var(--sans); font-weight: 500; font-size: 15px; letter-spacing: -0.01em; }
@media (prefers-reduced-motion: reduce) {
  .tour-thumb img { animation: none; }
  .tour-thumb img:nth-child(2), .tour-thumb img:nth-child(3) { opacity: 0; }
  .tour-thumb img:first-child { opacity: 1; }
  .tour-play i::before { animation: none; display: none; }
  .hero .tour { animation: none; opacity: 1; transform: none; }
}

/* Tour banner sits just below the headline (off-screen on load). A short scroll lifts the
   title naturally and slides the banner into view — so the hero isn't busy on landing. */
/* In-flow: the pill grows from nothing and fluidly pushes the title up (macOS-like spring). */
.tour { max-height: 0; margin-top: 0; opacity: 0; transform: translateY(6px) scale(.96); transform-origin: left center;
  overflow: hidden; pointer-events: none;
  transition: max-height .6s var(--spring), margin-top .6s var(--spring), opacity .38s ease, transform .6s var(--spring), box-shadow .2s var(--ease); }
.tour.tour--show { max-height: 96px; margin-top: 30px; opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.tour.tour--show:hover { box-shadow: var(--shadow); }
@media (prefers-reduced-motion: reduce) { .tour { transition: opacity .3s; max-height: 96px; margin-top: 30px; opacity: 1; transform: none; } }

/* ============================================================================
   Pricing page
============================================================================ */

/* Subpage top bar: brand left, actions right, sticky + faintly frosted */
.lnav--bar { position: sticky; top: 0; height: 60px; background: rgba(253,250,247,0.82); -webkit-backdrop-filter: saturate(140%) blur(12px); backdrop-filter: saturate(140%) blur(12px); border-bottom: 1px solid transparent; transition: border-color .2s, background .2s; }
.lnav--bar.scrolled { border-bottom-color: var(--line); }
.lnav--bar .wrap { justify-content: space-between; }
.lnav-brand { display: inline-flex; align-items: center; gap: 10px; font-family: var(--sans); font-weight: 600; font-size: 17px; color: var(--ink); letter-spacing: -0.02em; }
.lnav-brand img { width: 27px; height: 27px; border-radius: 7px; }

/* Centered hero */
.price-hero { text-align: center; padding: clamp(64px, 9vw, 104px) 0 clamp(36px, 5vw, 56px); }
.price-hero .eyebrow { display: block; margin-bottom: 18px; }
.price-hero h1 { max-width: 16ch; margin: 0 auto; font-size: clamp(38px, 5vw, 60px); }
.price-hero .lead { max-width: 46ch; margin: 20px auto 0; color: var(--ink-3); }
.price-proof { margin-top: 22px; font-family: var(--sans); font-size: 14px; color: var(--ink-3); }
.price-proof b { color: var(--ink); font-weight: 600; }

/* Billing toggle — the product's segmented control (.seg-toggle), landing-sized */
.billing { position: relative; display: inline-flex; align-items: center; gap: 1px; margin: 30px auto 0; padding: 3px; background: var(--bg-sunken); border: 1px solid var(--line); border-radius: 999px; }
.billing button { position: relative; z-index: 1; display: inline-flex; align-items: center; font-family: var(--sans); font-size: 14px; font-weight: 500; letter-spacing: -0.005em; color: var(--ink-3); background: transparent; border: 0; padding: 9px 20px; border-radius: 999px; cursor: pointer; line-height: 1; transition: color .2s ease; }
.billing button:hover { color: var(--ink); }
.billing button.on { color: var(--ink); }
.billing .seg-pill { position: absolute; top: 3px; left: 0; height: calc(100% - 6px); width: 0; background: var(--bg-raised); border-radius: 999px; box-shadow: var(--shadow-xs); transform: translateX(0); transition: transform 340ms cubic-bezier(.22,.8,.22,1), width 340ms cubic-bezier(.22,.8,.22,1); z-index: 0; pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .seg-pill { transition: none !important; } }
.billing .save { font-family: var(--mono); font-size: 10.5px; font-weight: 600; letter-spacing: 0.04em; color: #1f6b43; margin-left: 7px; }

/* exclusive / soon tags (from the product's pricing matrix) */
.tag-exc, .tag-soon { display: inline-block; font-family: var(--mono); font-size: 9.5px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; padding: 2px 7px; border-radius: 5px; vertical-align: middle; }
.tag-exc { color: #1f6b43; background: #e6f4ec; border: 1px solid #cfe9da; }
.tag-soon { color: var(--ink-3); background: var(--bg-sunken); border: 1px solid var(--line); }

/* ── Simple pricing (Basecamp-style: free strip + two cards + checklists) ── */
.pquote { margin: 26px 0 0; padding-left: 18px; border-left: 2px solid var(--line-strong); font-family: var(--sans); font-size: 16px; line-height: 1.5; color: var(--ink-2); }
.pquote cite { display: block; margin-top: 10px; font-style: normal; font-size: 13px; color: var(--ink-3); }

/* "Start free" strip */
.freecard { display: flex; align-items: center; justify-content: space-between; gap: 30px; background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 24px 28px; box-shadow: var(--shadow-xs); }
.freecard .fc-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.freecard .fc-name { font-family: var(--sans); font-weight: 600; font-size: 19px; letter-spacing: -0.02em; color: var(--ink); }
.freecard .fc-price { font-family: var(--sans); font-size: 14px; color: var(--ink-3); }
.freecard p { margin: 8px 0 0; font-family: var(--sans); font-size: 15px; color: var(--ink-3); max-width: 64ch; }
.freecard .btn { flex-shrink: 0; }
@media (max-width: 720px) { .freecard { flex-direction: column; align-items: flex-start; } .freecard .btn { width: 100%; } }

.levelup { margin: 30px 0 18px; font-family: var(--sans); font-size: 15px; color: var(--ink-3); }
.levelup b { color: var(--ink); font-weight: 600; }

/* Two paid cards side by side */
.paid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
@media (max-width: 720px) { .paid2 { grid-template-columns: 1fr; } }

/* Simple checklist (core features / company) */
.corelist { list-style: none; margin: 0; padding: 0; display: grid; gap: 13px; }
.corelist li { position: relative; padding-left: 30px; font-family: var(--sans); font-size: 17px; line-height: 1.45; color: var(--ink-2); }
.corelist li::before { content: "✓"; position: absolute; left: 0; top: 1px; color: #2c9e63; font-weight: 700; font-size: 15px; }
.corelist li b { color: var(--ink); font-weight: 600; }
.corelist li .muted { color: var(--ink-4); }
.corelist .tag-exc, .corelist .tag-soon { margin-left: 4px; }

/* Plans */
.plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; align-items: stretch; margin-top: 48px; }
.plan { position: relative; display: flex; flex-direction: column; background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 30px 28px; box-shadow: var(--shadow-xs); transition: transform .2s var(--ease), box-shadow .25s var(--ease), border-color .2s; }
.plan:hover { transform: translateY(-4px); box-shadow: var(--shadow); border-color: var(--line-strong); }
.plan--featured { border-color: var(--ink); box-shadow: 0 24px 60px -28px rgba(31,30,28,.45); }
.plan--featured:hover { border-color: var(--ink); }
.plan-tag { position: absolute; top: -11px; left: 28px; font-family: var(--mono); font-size: 10px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: #fff; background: var(--hl); padding: 4px 10px; border-radius: 999px; }
.plan-name { font-family: var(--sans); font-weight: 600; font-size: 20px; letter-spacing: -0.02em; color: var(--ink); }
.plan-blurb { font-family: var(--sans); font-size: 14px; line-height: 1.45; color: var(--ink-3); margin: 8px 0 0; min-height: 40px; }
.plan-price { display: flex; align-items: baseline; gap: 4px; margin: 22px 0 2px; }
.plan-price .amount { font-family: var(--sans); font-weight: 600; font-size: 46px; letter-spacing: -0.04em; line-height: 1; color: var(--ink); }
.plan-price .per { font-family: var(--sans); font-size: 14px; color: var(--ink-3); line-height: 1.2; }
.plan-note { font-family: var(--sans); font-size: 13px; color: var(--ink-3); min-height: 34px; margin: 6px 0 0; line-height: 1.4; }
.plan .btn { width: 100%; margin: 18px 0 4px; }
.plan-feats { list-style: none; margin: 18px 0 0; padding: 18px 0 0; border-top: 1px solid var(--line); display: grid; gap: 11px; }
.plan-feats .lede { font-family: var(--sans); font-size: 13px; font-weight: 600; color: var(--ink); margin-bottom: -3px; }
.plan-feats li { position: relative; font-family: var(--sans); font-size: 14.5px; line-height: 1.4; color: var(--ink-2); padding-left: 26px; }
.plan-feats li:not(.lede)::before { content: "✓"; position: absolute; left: 0; top: 0; color: #2c7a4b; font-weight: 700; font-size: 13px; }
.plan-feats li b { font-weight: 600; color: var(--ink); }
@media (max-width: 900px) { .plans { grid-template-columns: 1fr; max-width: 460px; margin-inline: auto; } .plan-blurb, .plan-note { min-height: 0; } }

/* "Every plan includes" */
.includes { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2px 56px; margin-top: 36px; max-width: 920px; }
.includes li { list-style: none; padding: 16px 0; border-bottom: 1px solid var(--line); display: flex; gap: 14px; align-items: baseline; }
.includes li .t { font-family: var(--sans); font-size: 16px; font-weight: 600; color: var(--ink); flex-shrink: 0; }
.includes li .d { font-family: var(--sans); font-size: 15px; color: var(--ink-3); }
.includes li .repl { color: var(--ink-4); }
@media (max-width: 760px) { .includes { grid-template-columns: 1fr; } }

/* Trust row */
.trust { display: grid; grid-template-columns: repeat(4, 1fr); gap: 32px; margin-top: 8px; }
.trust .item .eyebrow { display: block; margin-bottom: 10px; }
.trust .item h4 { font-family: var(--sans); font-weight: 600; font-size: 17px; letter-spacing: -0.01em; margin: 0 0 6px; color: var(--ink); }
.trust .item p { font-family: var(--sans); font-size: 14.5px; color: var(--ink-3); margin: 0; max-width: 30ch; }
@media (max-width: 880px) { .trust { grid-template-columns: 1fr 1fr; gap: 28px; } }
@media (max-width: 520px) { .trust { grid-template-columns: 1fr; } }

/* The "no" line */
.nos { display: flex; flex-wrap: wrap; gap: 10px 14px; margin-top: 26px; }
.nos span { font-family: var(--sans); font-size: 15px; color: var(--ink-2); background: var(--bg-raised); border: 1px solid var(--line); border-radius: 999px; padding: 9px 18px; }
.nos span b { color: var(--ink); font-weight: 600; }

/* ── Tour video modal (placeholder) ───────────────────────────────────── */
.modal { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; padding: 28px; }
.modal[hidden] { display: none; }
.modal-backdrop { position: absolute; inset: 0; background: rgba(20, 18, 16, 0.55); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); animation: mFade .25s ease; }
.modal-dialog { position: relative; width: min(1180px, 94vw); animation: mPop .34s var(--spring); }
/* aspect-ratio defaults to 16:9 for the poster; JS snaps it to the real clip's
   ratio on metadata, so the video fills the frame edge-to-edge with no letterbox
   (was pillar-boxing — space left/right but none top/bottom). max-height keeps it
   on screen on short displays. */
.modal-video { position: relative; width: 100%; aspect-ratio: 16 / 10; max-height: 86vh; background: var(--ink); border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-lg); }
.modal-video video, .modal-video iframe, .modal-video img { width: 100%; height: 100%; object-fit: cover; display: block; border: 0; }
/* contain (not cover) so the native fullscreen player letterboxes the landscape
   clip on a portrait phone instead of zoom-cropping it. The 16:10 frame matches
   the clip, so inline there's no letterbox anyway. */
.modal-video video { object-fit: contain; }
.modal-video-ph { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px; }
.modal-play { width: 66px; height: 66px; border-radius: 50%; background: rgba(255,255,255,.96); display: flex; align-items: center; justify-content: center; }
.modal-play i::after { content: ""; display: block; border-left: 19px solid var(--ink); border-top: 12px solid transparent; border-bottom: 12px solid transparent; margin-left: 5px; }
.modal-ph-label { font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: rgba(255,255,255,.5); }
.modal-close { position: absolute; top: 14px; right: 14px; z-index: 3; width: 40px; height: 40px; border: 0; border-radius: 50%; background: rgba(20,18,16,.55); color: #fff; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); -webkit-tap-highlight-color: transparent; transition: background .15s; }
.modal-close:hover { background: rgba(20,18,16,.82); }
.modal-close svg { width: 16px; height: 16px; display: block; }
@keyframes mFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes mPop { from { opacity: 0; transform: translateY(10px) scale(.985); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .modal-backdrop, .modal-dialog { animation: none; } }

/* ============================================================
   Legal & trust — privacy.html / terms.html (in pages/)
   A quiet compliance strip, a few principle statements, and the
   long-form policy text. Reuses the neutral :root tokens; no caps,
   no burgundy — matches the homepage. See page-header-convention.
   ============================================================ */

/* principle statements — three plain claims under the hero */
.principles { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(24px, 4vw, 56px); margin: clamp(8px, 2vw, 24px) 0 0; }
.principle { border-top: 2px solid var(--ink); padding-top: 18px; }
.principle h2, .principle h3 { font-size: clamp(20px, 2.4vw, 26px); letter-spacing: -0.03em; line-height: 1.1; margin: 0 0 10px; font-weight: 600; }
.principle p { color: var(--ink-3); font-size: 16px; line-height: 1.55; margin: 0; }

/* compliance strip — GDPR / hosting / SOC 2 / ISO.
   NB: the bare ".trust" class is already taken (see ~line 892, a 4-col grid),
   so the section wrapper here is ".compliance" to avoid the collision. */
.compliance { padding: clamp(48px, 7vw, 96px) 0; }
.trust-head { max-width: 620px; margin: 0 0 clamp(28px, 4vw, 44px); }
.trust-head h2 { font-size: clamp(26px, 3.2vw, 38px); letter-spacing: -0.035em; line-height: 1.06; margin: 0 0 14px; }
.trust-head p { color: var(--ink-3); font-size: clamp(16px, 1.8vw, 19px); line-height: 1.55; margin: 0; max-width: 52ch; }
.trust-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(14px, 1.6vw, 20px); }
.trust-card { background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: clamp(20px, 2.2vw, 28px); box-shadow: var(--shadow-sm); }
.trust-card .ic { display: flex; width: 32px; height: 32px; color: var(--ink); margin-bottom: 16px; }  /* flex, not inline — an inline <span> ignores width/height and the SVG balloons */
.trust-card .ic svg { width: 100%; height: 100%; }
.trust-card h3 { font-size: 17px; letter-spacing: -0.02em; margin: 0 0 4px; display: flex; flex-direction: column; align-items: flex-start; gap: 9px; }
.trust-card .state { font-family: var(--sans); font-size: 11.5px; font-weight: 600; letter-spacing: 0.01em; color: var(--ink-3); background: var(--bg-sunken); border: 1px solid var(--line); border-radius: 999px; padding: 2px 9px; }
.trust-card .state.is-live { color: #1f7a4d; background: #eaf5ee; border-color: #cfe7d8; }
.trust-card p { color: var(--ink-3); font-size: 14.5px; line-height: 1.5; margin: 8px 0 0; }
.trust-note { margin: clamp(20px, 2.6vw, 30px) 0 0; font-size: 13.5px; color: var(--ink-4); line-height: 1.5; max-width: 64ch; }

/* long-form policy */
.legal { padding-bottom: clamp(64px, 9vw, 120px); }
.legal-wrap { max-width: 760px; margin: 0; }
.legal-body { overflow-wrap: break-word; }   /* long URLs/links wrap instead of overflowing on phones */
.legal-meta { display: flex; flex-wrap: wrap; align-items: center; margin: 0 0 clamp(28px, 4vw, 44px); padding-bottom: clamp(22px, 3vw, 32px); border-bottom: 1px solid var(--line); }
.legal-meta span { font-family: var(--mono); font-size: 12px; letter-spacing: 0.01em; color: var(--ink-3); }
.legal-meta span:not(:first-child) { margin-left: 14px; padding-left: 14px; border-left: 1px solid var(--line); }
.legal-body h2 { font-size: clamp(21px, 2.4vw, 27px); letter-spacing: -0.03em; line-height: 1.12; margin: clamp(40px, 5vw, 60px) 0 14px; padding-top: clamp(40px, 5vw, 60px); border-top: 1px solid var(--line); }
.legal-body h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.legal-body h3 { font-size: 17px; letter-spacing: -0.02em; line-height: 1.3; margin: 28px 0 10px; color: var(--ink); }
.legal-body p, .legal-body li { color: var(--ink-2); font-size: 16px; line-height: 1.65; }
.legal-body p { margin: 0 0 14px; }
.legal-body ul { margin: 0 0 16px; padding-left: 22px; }
.legal-body li { margin: 0 0 7px; }
.legal-body li::marker { color: var(--ink-4); }
.legal-body a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--line-strong); }
.legal-body a:hover { text-decoration-color: var(--ink); }
.legal-body strong { color: var(--ink); font-weight: 600; }
.legal-lead { font-size: clamp(17px, 1.9vw, 19px) !important; color: var(--ink-2) !important; line-height: 1.6 !important; margin-bottom: 18px !important; }
/* sub-processor tables — keep them readable; scroll horizontally on narrow screens */
.legal-table { margin: 4px 0 18px; overflow-x: auto; -webkit-overflow-scrolling: touch; border: 1px solid var(--line); border-radius: var(--radius); }
.legal-table table { width: 100%; border-collapse: collapse; font-size: 14px; min-width: 560px; }
.legal-table th, .legal-table td { text-align: left; padding: 10px 14px; border-bottom: 1px solid var(--line); vertical-align: top; line-height: 1.45; }
.legal-table thead th { background: var(--bg-sunken); color: var(--ink); font-weight: 600; font-size: 12.5px; letter-spacing: 0.01em; white-space: nowrap; }
.legal-table tbody td { color: var(--ink-2); }
.legal-table tbody td:first-child { color: var(--ink); font-weight: 600; }
.legal-table tbody tr:last-child td { border-bottom: 0; }

@media (max-width: 880px) {
  .principles { grid-template-columns: 1fr; gap: 22px; }
  .trust-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
  .trust-grid { grid-template-columns: 1fr; }
}


/* ── Cookie consent ───────────────────────────────────────────────────────
   Docked bottom-right so it never covers the headline, and never full-width:
   a bar across the bottom reads as a system error on mobile and hides the
   floating CTA. `hidden` does the hiding, so a visitor who already chose sees
   no flash of it — there is no CSS-only "open" class to get out of step. */
.consent {
  position: fixed;
  z-index: 60;
  right: max(16px, env(safe-area-inset-right));
  bottom: max(16px, env(safe-area-inset-bottom));
  left: auto;
  width: min(420px, calc(100vw - 32px));
  padding: 18px 20px 16px;
  background: var(--bg-raised, #fff);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.consent[hidden] { display: none; }
.consent-text {
  margin: 0 0 14px;
  font-size: 15px;
  line-height: 1.5;
  letter-spacing: -0.003em;
  color: var(--ink-2);
}
.consent-text a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--line-strong);
}
.consent-text a:hover { text-decoration-color: var(--ink); }
.consent-actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }
.consent-actions .btn { flex: 1 1 auto; justify-content: center; }

@media (max-width: 520px) {
  /* Full width on a phone, but still a card above the bottom edge. */
  .consent { left: max(16px, env(safe-area-inset-left)); width: auto; }
}

/* The footer link that reopens the banner. */
.lfoot-legal button.lfoot-cookies {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: none;
}
.lfoot-legal button.lfoot-cookies:hover { text-decoration: underline; text-underline-offset: 3px; }


/* ── Extra footer ─────────────────────────────────────────────────────────
   An optional band above the main footer for pages that live outside both the
   hero menu and the footer nav. The links flow as running text rather than
   sitting in a grid: the list is meant to grow to twenty entries of wildly
   different lengths, and a grid of those reads as ragged columns, while a
   paragraph of them just wraps. The middot separators are generated, so adding
   a link in the CMS never means thinking about punctuation. */
.xfoot { border-top: 1px solid var(--line); padding: 72px 0 8px; }
.xfoot-heading {
  font-family: var(--sans);
  font-weight: 600;
  font-size: clamp(26px, 2.6vw, 34px);
  line-height: 1.1;
  letter-spacing: -0.03em;
  color: var(--ink);
  margin: 0 0 28px;
}
/* Two layouts, chosen in the CMS.
   Columns (the default, 3) so that a handful of links fills a couple of rows
   instead of sitting in one thin line across a wide page. One column keeps the
   original running-text treatment, which suits a few long titles. */
/* Rows of links run together with dot dividers, the way Basecamp's footer does
   it. Deliberately NOT a grid: a grid of five short labels spreads them across
   a wide page into sparse columns with holes in it, which is exactly what this
   replaced. Packed running text stays dense at any link count, and each row
   wraps within itself on a narrow screen. Which links share a row is an
   editorial decision, made in the CMS, not inferred from a column count. */
.xfoot-rows {
  font-family: var(--sans);
  font-size: clamp(15px, 1.4vw, 17px);
  letter-spacing: -0.003em;
  max-width: 74rem;
}
.xfoot-row { line-height: 1.85; }
.xfoot-row a {
  color: var(--ink);
  font-weight: 500;
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 4px;
  text-decoration-color: var(--line-strong);
  transition: text-decoration-color .15s, color .15s;
}
.xfoot-row a:hover { text-decoration-color: var(--ink); }
/* Separator between links. A real element, not an ::before on the anchor: a
   pseudo-element inside the link inherits the underline and enlarges the click
   target, and a middot is neither part of the label nor worth clicking. */
.xfoot-dot { display: inline-block; margin: 0 7px; color: var(--ink-4); }

.lfoot--joined { border-top: 0; padding-top: 56px; margin-top: 0; }

@media (max-width: 880px) {
  .xfoot { padding-top: 52px; }
  .xfoot-row { line-height: 2; }
}


/* ── Final CTA ────────────────────────────────────────────────────────────
   The copy column used to be a hard 680px inline. Norwegian runs 15-20% longer
   than English for the same sentence, so the lead wrapped one word onto a line
   of its own ("...du slipper / inn."). Wider measure plus `pretty`, which asks
   the browser not to leave a widow on the last line. */
.final-cta-copy { max-width: 820px; }
.final-cta-lead { margin: 18px 0 30px; color: var(--ink-3); max-width: 46ch; text-wrap: pretty; }


/* ── Partner / integration pages ──────────────────────────────────────────
   "AnalystX × <someone else>": the hero lockup, the row of clutter, and the
   two-card bridge. Written for /no/fiken and kept partner-agnostic, so the next
   accounting system is a CMS document rather than another block of CSS. */

/* Co-branding in the sub-page header. The lockup used to sit in the hero as
   well, which put two of them within a few hundred pixels; the header is the
   one a reader is already looking at, so it won. */
.brand-lockup { display: inline-flex; align-items: center; gap: 16px; }
.brand-x { font-family: var(--mono); font-size: 12px; color: var(--ink-4); line-height: 1; }
/* Height-constrained, width auto: partner lockups arrive at wildly different
   aspect ratios, and only the cap height should agree with our wordmark.
   --partner-logo-scale is set inline by PageBrand from the partnerHero block's
   "Logo size" field, and multiplies the phone size below just as it does this
   one, so an editor's single choice holds at every width. Unset means 1. */
.brand-partner { height: calc(30px * var(--partner-logo-scale, 1)); width: auto; }

.phero { padding: clamp(40px, 8vw, 96px) 0 clamp(20px, 2.5vw, 32px); }

/* Campaign-hero accent: the headline's last phrase snaps to the serif face and
   back once on load (scripts/accentSnap.js). The same beat as .euword on the
   European page, minus that page's EU flag colours — here the phrase stays in
   the brand ink, because the meaning is the turn in the sentence, not a flag. */
.accentword { display: inline-block; line-height: 1; vertical-align: baseline; }
.accentword.it { font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: 0.01em; }
@keyframes accentSnap { 0% { transform: translateY(-2px) scale(.95); opacity: .35; } 60% { opacity: 1; } 100% { transform: none; } }
.accentword.snap { animation: accentSnap .16s var(--ease); }

/* Campaign-hero rolling word: the same closing slot as .accentword, cycling
   through a list instead of flicking once (blocks/PartnerHero.astro,
   scripts/cityRoll.js). It stays in the serif italic rather than snapping back
   to the sans, because here the face is doing a second job — it marks which
   word of the headline is the one that keeps changing.

   One element, one grid cell, every town stacked in it. So the box is laid out
   at the width of the longest town before any script runs, and it never
   changes size afterwards: the headline wraps once, on load, at its widest.
   Nothing follows the roll in the markup, so the slack after a short town sits
   at the end of the line with nothing to push around. That is the whole reason
   there is no full stop here — a period against a word that changes length
   slides back and forth and draws the eye to the ragged edge.

   Keep the list to towns no longer than the first one and the line a reader
   sees never moves at all.

   The clipping is clip-path, NOT overflow:hidden. An inline-level box whose
   overflow is anything but visible takes its baseline from its bottom margin
   edge (CSS 2.1 §10.8.1), which lifts the whole word clear off the headline's
   baseline by the depth of a descender. It looks like the obvious way to do
   this and it is wrong. The inset is negative so the clip sits slightly
   OUTSIDE the box: the ring on Å and the tail on ø overshoot a line-height of
   1, and the italic overhangs its advance width at the right edge. The words
   park at 140% rather than 100% so they clear that slack and are out of sight
   before the clip stops hiding them. */
.cityroll { display: inline-grid; white-space: nowrap; line-height: 1;
  vertical-align: baseline; clip-path: inset(-0.28em -0.06em);
  font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: 0.01em; }
.cityroll-word { grid-area: 1 / 1; opacity: 0; transform: translateY(140%); }
/* Only the two live states carry a transition. The default deliberately has
   none: a word leaving upwards has .is-out removed once it is out of sight, and
   with a transition on the default it would travel back down through the box in
   full view instead of cutting round. */
.cityroll-word.is-on,
.cityroll-word.is-out { transition: transform .5s var(--ease), opacity .34s var(--ease); }
.cityroll-word.is-on { opacity: 1; transform: none; }
.cityroll-word.is-out { opacity: 0; transform: translateY(-140%); }
/* cityRoll.js bails out under reduced motion, so the first town simply stands.
   This is the belt to that braces. */
@media (prefers-reduced-motion: reduce) {
  .cityroll-word { transition: none; }
}
/* A partner header is a much wider object than the bare AnalystX wordmark, so
   the same gap beneath it reads as a bigger one and the top of the page drifts
   apart. Pull the headline up under the lockup — only where the lockup is
   actually the wide kind. `+ main` holds because PageBrand renders immediately
   before <main> (see [...path].astro). */
.page-brand--partner + main .phero { padding-top: clamp(20px, 3.5vw, 44px); }
.phero-copy { max-width: 1040px; }
.phero h1 { max-width: 22ch; letter-spacing: -0.038em; text-wrap: balance; }
.phero-lead { margin: 22px 0 0; max-width: 52ch; color: var(--ink-3); text-wrap: pretty; }
.phero-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: clamp(28px, 3vw, 38px); }

/* ── Tag hero — the list price, hanging, struck through ──────────────────
   blocks/TagHero.astro.

   /no/prisen already carries two money graphics: priceLadder draws tiers as
   steps, priceReceipt draws two tills. So this is deliberately a PHYSICAL
   object rather than a third chart — a thing that hangs off a product, which is
   what a list price is.

   No script — CSS with delays. */
.taghero-kicker { margin: 0 0 16px; }
/* No padding-top and a smaller margin. Both existed to make room for a drawn
   string above the tag, and that string was wrong twice over: it was a sibling
   of the tag rather than a child, so it stayed put while the tag swung and came
   apart from it, and once the point was dropped it read as a stray rule rather
   than as anything holding the tag up. The hole and the swing carry it alone. */
.taghero { position: relative; margin: clamp(18px, 2.4vw, 26px) 0 0; width: max-content; }
/* No clip-path. The first version cut an angled point out of the left edge with
   one, which also cut the border and the box-shadow: clip-path clips the
   element's whole rendering, outline included, so the notch came out as a raw
   diagonal with no line on it and the tag read as damaged rather than shaped.
   A drawn point needs its own stroke, which means SVG; a rounded end needs
   nothing. The hole and the string already say "tag", so the shape is a plain
   rounded rectangle and the border runs unbroken the whole way round. */
.taghero-tag {
  position: relative; display: inline-flex; flex-direction: column; gap: 2px;
  padding: 18px 26px 18px 40px;
  background: var(--bg-raised); border: 1px solid var(--line-strong);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  transform-origin: 21px 20px;
  animation: tagSwing 1.5s var(--ease) .3s both;
}
/* Top-left, not centred: a tag hangs off its hole, and the swing below pivots
   on exactly this point, so a hole in the middle of the left edge would make it
   rock like a seesaw instead of hang. */
.taghero-hole { position: absolute; left: 17px; top: 16px; width: 8px; height: 8px;
  border-radius: 50%; border: 1px solid var(--line-strong); background: var(--bg); }
.taghero-price { position: relative; align-self: flex-start;
  font-family: var(--mono); font-size: clamp(26px, 4vw, 40px); line-height: 1; color: var(--ink); }
.taghero-unit { font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-4); }
/* Drawn left to right. A line that is simply there reads as a typo; a line that
   arrives reads as a correction being made. */
.taghero-strike { position: absolute; left: -3px; right: -3px; top: 52%; height: 2px;
  background: var(--ink); transform: scaleX(0); transform-origin: left center;
  animation: tagStrike .34s var(--ease) 1.55s forwards; }
.taghero-note { margin: 14px 0 0; font-size: 14px; color: var(--ink-3);
  opacity: 0; animation: tagNote .4s var(--ease) 1.95s forwards; }
/* Damped: each swing smaller than the last, ending at rest. An undamped swing
   loops forever and reads as a loading spinner. */
@keyframes tagSwing {
  0% { transform: rotate(-9deg); }
  30% { transform: rotate(5deg); }
  55% { transform: rotate(-2.5deg); }
  78% { transform: rotate(1deg); }
  100% { transform: none; }
}
@keyframes tagStrike { to { transform: scaleX(1); } }
@keyframes tagNote { to { opacity: 1; } }
/* Reduced motion: the tag hanging still, already struck. The correction is the
   point; watching the hand make it is not. */
@media (prefers-reduced-motion: reduce) {
  .taghero-tag { animation: none; }
  .taghero-strike { transform: scaleX(1); animation: none; }
  .taghero-note { opacity: 1; animation: none; }
}

/* ── Upload hero — the file, as it actually is ───────────────────────────
   blocks/UploadHero.astro. A file chip carrying the name everyone recognises,
   then the checks ticking on.

   NOT a grid. sheetDecay further down /no/bytte/regneark draws the spreadsheet
   itself and /no/regnearket's hero sets a headline in cells, so a third drawing
   of a spreadsheet would be one too many. A file chip is a different object.

   No script — CSS with delays. */
.uhero-kicker { margin: 0 0 16px; }
.uhero { margin: clamp(26px, 3.5vw, 36px) 0 0; max-width: 520px; }
.uhero-file {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 14px 16px; border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--bg-raised); box-shadow: var(--shadow-sm);
}
/* A small ruled square standing in for a spreadsheet file, drawn rather than
   iconographed: two lines is enough to read as a sheet at 18px, and it keeps
   the block free of an icon dependency. */
.uhero-icon {
  flex: none; width: 18px; height: 18px; border-radius: 3px;
  border: 1.5px solid var(--ink-4);
  background:
    linear-gradient(var(--ink-4), var(--ink-4)) 0 33% / 100% 1.5px no-repeat,
    linear-gradient(var(--ink-4), var(--ink-4)) 0 67% / 100% 1.5px no-repeat;
}
/* break-all, not nowrap: the filename is long by design and it is the point, so
   on a phone it has to wrap inside the chip rather than push the chip wider
   than the screen. */
.uhero-name { font-family: var(--mono); font-size: 13px; color: var(--ink); word-break: break-all; }
.uhero-meta { font-family: var(--mono); font-size: 11px; color: var(--ink-4); margin-left: auto; white-space: nowrap; }

.uhero-checks { list-style: none; display: flex; flex-wrap: wrap; gap: 8px 22px; margin: 14px 0 0; padding: 0 2px; }
.uhero-checks li {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13.5px; color: var(--ink-2);
  opacity: 0; animation: uheroCheck .34s var(--ease) var(--d, 0ms) forwards;
}
@keyframes uheroCheck { to { opacity: 1; } }
.uhero-tick { width: 14px; height: 14px; flex: none; color: var(--ink); }
/* Drawn, not faded: a tick that appears has been printed, a tick that draws has
   just been decided. dashoffset runs 1 → 0 against pathLength="1". */
.uhero-tick path {
  fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: uheroTick .3s var(--ease) var(--d, 0ms) forwards;
}
@keyframes uheroTick { to { stroke-dashoffset: 0; } }
/* Reduced motion: the file read and both checks done, drawn at once. */
@media (prefers-reduced-motion: reduce) {
  .uhero-checks li { opacity: 1; animation: none; }
  .uhero-tick path { stroke-dashoffset: 0; animation: none; }
}

/* ── Duration hero — the migration you remember, next to this one ────────
   blocks/DurationHero.astro. The fear the lead names, drawn: a long bar for the
   switch people remember, a short one for the weekend on offer.

   NOT a second timeline. stepClock further down /no/bytte is the timeline, and
   a step rail and a pair of bars are different objects: the rail says what
   happens, the bars say how long it takes.

   No script — CSS with delays, like the sheet and tab heroes. */
.dhero { margin: clamp(26px, 3.5vw, 38px) 0 0; max-width: 620px; }
.dhero-row + .dhero-row { margin-top: 18px; }
.dhero-label { margin: 0 0 8px; font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-4); }
.dhero-track { display: flex; align-items: center; gap: 12px; }
/* The bar grows from nothing. width, not transform: a scaled bar carries its
   rounded end with it and the cap visibly stretches, which reads as rubber
   rather than as a measurement being taken. */
.dhero-bar { flex: none; height: 10px; border-radius: 999px; width: 0; }
.dhero-bar--slow { background: var(--line-strong); animation: dheroGrow .75s var(--ease) .35s forwards; }
.dhero-bar--fast { background: var(--ink); animation: dheroGrowFast .5s var(--ease) 1.05s forwards; }
@keyframes dheroGrow { to { width: 100%; } }
/* The short bar's width comes from --dhero-w, set inline by the component: only
   it knows the ratio, and a keyframe cannot read a field. */
@keyframes dheroGrowFast { to { width: var(--dhero-w, 8%); } }
.dhero-value { flex: none; font-size: 14px; color: var(--ink-3); white-space: nowrap;
  opacity: 0; animation: dheroFade .4s var(--ease) .8s forwards; }
.dhero-value--ours { color: var(--ink); font-weight: 500; animation-delay: 1.4s; }
@keyframes dheroFade { to { opacity: 1; } }
/* Reduced motion: both bars at their final widths, nothing drawn. The
   comparison is the point; watching it arrive is not. */
@media (prefers-reduced-motion: reduce) {
  .dhero-bar, .dhero-value { animation: none; opacity: 1; }
  .dhero-bar--slow { width: 100%; }
  .dhero-bar--fast { width: var(--dhero-w, 8%); }
}

/* ── Tab hero — two browser tabs, and one of them closes ─────────────────
   blocks/TabHero.astro. Only the tab strip: browserFrame further down /no/chrome
   draws the other half of a browser (URL bar, page, side panel, on a card), and
   a browser drawn twice on one page is spent the second time.

   No script. Like the sheet hero, nothing here waits on a beat a reader would
   notice missing, so it is CSS with a delay.

   The close animates max-width, padding and border to nothing rather than
   display:none, so the remaining tab slides left into the gap instead of the
   strip snapping. overflow:hidden on the tab is what makes that legible: the
   label is clipped as the tab narrows, the way a real one behaves. */
/* The strip clips, not the tabs. On a narrow phone two tabs are wider than the
   column, and without this the page grows a horizontal scrollbar. What gets cut
   there is the right-hand tab, which is the one that closes anyway. */
.thero-kicker { margin: 0 0 16px; }
.thero-tabs { display: flex; align-items: flex-end; overflow: hidden;
  margin-bottom: clamp(22px, 3vw, 32px); border-bottom: 1px solid var(--line); }
/* No overflow or max-width on the base tab. Both belong to the closing one
   alone: they are what lets its label clip as it narrows. Left here they also
   clipped the "Lagret" badge off the end of the tab that STAYS, which is the
   one thing on the strip that has to survive. */
.thero-tab { display: inline-flex; align-items: center; gap: 7px; flex: none;
  white-space: nowrap;
  margin-right: 5px; padding: 7px 12px;
  border: 1px solid var(--line); border-bottom: 0; border-radius: 9px 9px 0 0;
  background: var(--bg-raised);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.02em; color: var(--ink-3); }
.thero-fav { flex: none; width: 8px; height: 8px; border-radius: 2px; background: var(--ink-4); }
.thero-x { font-weight: 400; font-size: 13px; line-height: 1; color: var(--ink-4); margin-left: 2px; }
/* max-width is set here, not on .thero-tab, and it has to be an explicit length
   rather than none: the close animates it to 0, and none does not interpolate. */
.thero-tab--go { max-width: 34ch; overflow: hidden;
  animation: tabClose .5s var(--ease) 1.15s forwards; }
@keyframes tabClose {
  to { max-width: 0; margin-right: 0; padding-left: 0; padding-right: 0;
       border-left-width: 0; border-right-width: 0; opacity: 0; }
}
/* The confirmation on the surviving tab, in after the other has gone. It exists
   to answer the question the close otherwise raises: if that tab held the new
   customer, did closing it throw the customer away? It did not — you never had
   to open it. So the tab that goes is named after the errand, and this says the
   record landed anyway. */
.thero-done { display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 7px; border-radius: 999px; font-weight: 400; font-size: 10px;
  letter-spacing: 0.06em; color: var(--bg-raised); background: var(--ink);
  opacity: 0; transform: translateY(2px);
  animation: tabDone .34s var(--spring) 1.75s forwards; }
@keyframes tabDone { to { opacity: 1; transform: none; } }
/* Reduced motion gets the END state, one tab with the record saved, because
   that is what the page promises — "uten å forlate fanen", singular. Holding
   both tabs still would leave the reader looking at the problem with no
   resolution. */
@media (prefers-reduced-motion: reduce) {
  .thero-tab--go { display: none; }
  .thero-done { opacity: 1; transform: none; animation: none; }
}

/* ── Count hero — a number in the headline that climbs ───────────────────
   blocks/CountHero.astro, driven by scripts/countUp.js.

   tabular-nums is the whole trick. Proportional digits are different widths, so
   a counter set in them jitters on every frame as 1s and 7s trade places, which
   reads as a broken font rather than as a number moving. Tabular figures are
   all one width, so only the value changes.

   The box is then held at the final number's width, with the digits ranged
   right inside it, so the words AFTER the counter never move while it climbs.
   The reserved space opens up in front of the number instead, which reads as a
   counter filling up. min-width is set inline by the component from the length
   of the final number, because only it knows how many digits are coming. */
.count {
  display: inline-block;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* ── Sheet hero — the headline sitting in the spreadsheet ────────────────
   blocks/SheetHero.astro. Only the furniture of a spreadsheet, never the
   window: /no/regnearket also carries sheetDecay, which IS a window (a card, a
   chrome bar, a dense scrolling table), and drawing that twice on one page
   would spend the device the second time it appears.

   So: column letters, row numbers, and a selected range around display type,
   sitting straight on the page ground with no card behind it.

   No script. Unlike the flag and the recording light, nothing here has to wait
   for a beat that a reader would notice missing, so the whole thing is CSS with
   delays, and prefers-reduced-motion turns it off at the bottom of the block. */
.shero-sheet {
  --shero-gut: clamp(22px, 3vw, 34px);
  --shero-pad: 6px;
  margin-bottom: clamp(24px, 3vw, 34px);
  /* Pull the sheet left by exactly its own furniture, so the CELL TEXT sits on
     the same edge as the lead paragraph beneath it and the row numbers hang in
     the page margin. Without this the headline is indented by the gutter and
     the lead is not, which reads as a broken column rather than a spreadsheet.
     max() caps the pull at the page gutter, so on a phone, where the furniture
     is wider than the padding, it stops at the edge instead of overflowing.
     Same trick as .hero-visual and .show-visual further up this file. */
  margin-left: max(
    calc(-1 * (var(--shero-gut) + var(--shero-pad))),
    calc(-1 * var(--gutter))
  );
}

/* The letter strip. One dead cell over the row-number gutter, then equal
   columns, exactly as a sheet lays them out. */
.shero-head {
  display: grid;
  grid-template-columns: var(--shero-gut) repeat(5, 1fr);
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.14em;
  color: var(--ink-4); text-align: center;
  border-bottom: 1px solid var(--line);
  opacity: 0; animation: sheetChrome .5s var(--ease) .35s forwards;
}
.shero-head span { padding: 5px 0; border-left: 1px solid var(--line); }
.shero-head span:first-child { border-left: 0; }

/* The selected range. Ranged off the gutter so the row numbers stay OUTSIDE the
   selection, which is where a spreadsheet puts them. */
.shero-rows {
  position: relative;
  margin-left: var(--shero-gut);
  max-width: none;
  letter-spacing: -0.038em;
  outline: 0 solid var(--ink);
  animation: sheetSelect .01s linear .95s forwards;
}
/* A step down from the default h1 clamp. Every row has to hold a whole line of
   the headline on one line, and at the h1 size the second row wrapped, which
   turned two rows into three and cost the block its shape. */
.shero-line {
  display: block; position: relative;
  font-size: clamp(30px, 4.6vw, 56px);
  padding: .1em 10px .16em var(--shero-pad);
}
.shero-line + .shero-line { border-top: 1px solid var(--line); }
/* The row number rides in the gutter to the left of its own line, so it can
   never drift out of step with the text the way a parallel column would. */
.shero-line i {
  position: absolute; left: calc(-1 * var(--shero-gut)); top: 0; bottom: 0;
  width: var(--shero-gut);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-style: normal; font-size: 10.5px;
  font-weight: 400; letter-spacing: 0.06em; color: var(--ink-4);
  border-right: 1px solid var(--line);
  opacity: 0; animation: sheetChrome .5s var(--ease) .5s forwards;
}
/* The fill handle. The single most recognisable seven pixels in the genre, and
   the reason the block reads as a live selection rather than a box. */
.shero-rows::after {
  content: ""; position: absolute; right: -4px; bottom: -4px;
  width: 7px; height: 7px; background: var(--ink);
  border: 1px solid var(--bg);
  opacity: 0; transform: scale(0);
  animation: sheetHandle .3s var(--spring) 1.15s forwards;
}
@keyframes sheetChrome { to { opacity: 1; } }
@keyframes sheetSelect { to { outline-width: 2px; } }
@keyframes sheetHandle { to { opacity: 1; transform: none; } }

/* Reduced motion: the finished sheet, drawn at once. */
@media (prefers-reduced-motion: reduce) {
  .shero-head, .shero-line i { opacity: 1; animation: none; }
  .shero-rows { outline-width: 2px; animation: none; }
  .shero-rows::after { opacity: 1; transform: none; animation: none; }
}

/* ── Flag hero — the Norwegian flag on one word of the headline ──────────
   blocks/FlagHero.astro, switched on by scripts/flagMark.js a beat after the
   copy settles. The word takes the flag's red; the flag itself follows it.

   Borrowing a national palette for a headline word is the device /european
   already uses for "Europa" (.euword). The rule both pages follow: the colours
   are only borrowed where the meaning of the word IS the flag. An accent phrase
   that merely turns the sentence stays in the brand ink.

   The flag is drawn rather than an emoji. 🇳🇴 renders as two letters on most of
   Windows, which on a page arguing that nobody builds for Norway would be an
   unusually pointed bug. */
:root { --flag-red: #ba0c2f; }
/* The drawn flag keeps its own colours in the dark theme — a flag is a flag,
   and the white cross keeps the blue legible against a dark ground. Only the
   WORD needs lifting, because #ba0c2f on #201d19 is unreadable. */
[data-theme="dark"] { --flag-red: #e8556f; }

/* The word and its flag are one object and must never break apart; the line is
   still free to break before them. */
.flagword { display: inline-block; white-space: nowrap; color: var(--flag-red);
  font-family: var(--serif); font-style: italic; font-weight: 400; letter-spacing: 0.01em; }
/* Sized in em off the headline, so it holds its proportion to the word at every
   breakpoint. The radius is 1px flat, not em: a flag with a scaled corner
   radius reads as a sticker. */
.flagmark { display: inline-block; width: .58em; height: auto; margin-left: .2em;
  vertical-align: .04em; border-radius: 1px; opacity: 0; transform: scale(.4); }
.flagword.on .flagmark { animation: flagIn .44s var(--spring) forwards; }
@keyframes flagIn { to { opacity: 1; transform: none; } }
/* fill-box, so each cross scales about its own centre rather than the SVG
   viewport's origin — without it both bars grow out of the top-left corner and
   the flag assembles itself sideways. */
.fm-cross { transform-box: fill-box; transform-origin: center; transform: scale(0); }
.flagword.on .fm-white { animation: flagCross .3s var(--ease) .2s forwards; }
.flagword.on .fm-blue { animation: flagCross .3s var(--ease) .29s forwards; }
@keyframes flagCross { to { transform: none; } }
/* Reduced motion: the finished flag, no raising. Set by flagMark.js, which adds
   .on and .still together, so these have to beat the animations above. */
.flagword.still .flagmark,
.flagword.still .fm-cross { animation: none; opacity: 1; transform: none; }

/* ── Live hero — the recording light on the headline's live word ─────────
   blocks/LiveHero.astro. Hidden until scripts/liveMark.js switches it on a beat
   after the copy has settled, so it reads as a light coming on rather than as
   punctuation that was always there. A warm red, not a signal red: the page is
   warm paper, and a pure #f00 next to burgundy ink reads as an error state. */
.lhero { --rec: oklch(57% 0.21 27); }
/* The dot and its word are one object and must never break apart; the line is
   still free to break before the mark. Sized and offset in em, so the dot holds
   its place against the centre of the headline's x-height at every breakpoint. */
.livemark { display: inline-block; white-space: nowrap; }
.livedot { position: relative; display: inline-block; width: .27em; height: .27em;
  margin-right: .22em; vertical-align: .12em; border-radius: 50%; background: var(--rec);
  opacity: 0; transform: scale(0); }
/* A filled disc fading outwards, not a ring: a hard hoop expanding across the
   words either side of the dot reads as a UI element that escaped. This is a
   bloom, and it is a child of the dot so it rides the dot's own pop. */
.livedot::after { content: ""; position: absolute; inset: -.18em; border-radius: 50%;
  background: var(--rec); opacity: 0; }
.livemark.on .livedot { animation: recOn .42s var(--spring) forwards, recBreathe 3.4s ease-in-out .42s infinite; }
/* Three beats, then quiet. Something pulsing forever beside a headline is a
   thing to look away from; the dot's own breathing carries "still live". */
.livemark.on .livedot::after { animation: recBloom 2.2s ease-out .5s 3; }
.livemark.still .livedot { animation: none; opacity: 1; transform: none; }
.livemark.still .livedot::after { animation: none; }
@keyframes recOn { from { opacity: 0; transform: scale(0); } to { opacity: 1; transform: scale(1); } }
@keyframes recBreathe { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@keyframes recBloom { 0% { opacity: .28; transform: scale(.6); } 100% { opacity: 0; transform: scale(1.6); } }
@media (prefers-reduced-motion: reduce) {
  .livedot { opacity: 1; transform: none; animation: none; }
  .livedot::after { animation: none; }
}

/* The heart in the thank-you hero's headline (blocks/ThanksHero.astro), the
   third of these marks after the recording dot above and the flag further up.
   Its own red, scoped to the hero the same way --rec is, because a heart in the
   burgundy body ink reads as a typo rather than a heart. */
.thero { --heart: oklch(57% 0.21 27); }
[data-theme="dark"] .thero { --heart: oklch(70% 0.16 22); }
/* Sized and offset in em so it holds against the centre of the headline's
   x-height at every breakpoint, and asymmetric margins because the glyph's own
   bounding box is wider on the left than the shape inside it looks. */
.heartmark { display: inline-block; width: .5em; height: .5em; margin: 0 .1em 0 .13em;
  vertical-align: .07em; color: var(--heart);
  opacity: 0; transform: scale(0); transform-origin: 50% 60%;
  animation: heartOn .5s var(--spring) .35s forwards, heartBeat 1.5s var(--ease) .85s 3; }
.heartmark svg { display: block; width: 100%; height: 100%; }
/* No script switches this on, unlike .livemark and .flagmark: the thank-you hero
   is always above the fold, so a delay does the same job and the heart still
   arrives with JavaScript off. See the note in ThanksHero.astro. */
@keyframes heartOn { to { opacity: 1; transform: scale(1); } }
/* Three beats, then rest. Same rule as the recording dot: something pulsing
   forever beside a headline is a thing to look away from. */
@keyframes heartBeat {
  0%, 44%, 100% { transform: scale(1); }
  12% { transform: scale(1.18); }
  22% { transform: scale(1.02); }
  32% { transform: scale(1.11); }
}
@media (prefers-reduced-motion: reduce) {
  .heartmark { opacity: 1; transform: none; animation: none; }
}

.clutter { padding: clamp(44px, 6vw, 84px) 0 clamp(16px, 2vw, 28px); }
.clutter-kicker { margin: 0 0 24px; color: var(--ink-4); }
/* The track is wider than the viewport by design, so the fade has to be a mask
   on an overflow-hidden parent rather than a gradient overlay — an overlay in
   front of the pills would also sit in front of the page background. */
.clutter-mask {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 12%, #000 88%, transparent);
}
.clutter-track { display: flex; width: max-content; gap: 10px; animation: ss-marquee 46s linear infinite; }
/* -50% and not -100%: the list is rendered twice, so half the track is one full
   copy and the loop restarts exactly where it began. */
@keyframes ss-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.clutter-pill {
  flex: 0 0 auto; font-size: 15px; white-space: nowrap; color: var(--ink-4);
  background: var(--bg-sunken); border: 1px solid var(--line); border-radius: 999px; padding: 9px 17px;
}

/* Reduced motion: a frozen marquee would clip every pill past the first
   viewport, which loses the point of the section. Wrap the row into a block
   instead and drop the duplicate copy — the same phrases, all readable, no
   movement. */
@media (prefers-reduced-motion: reduce) {
  .clutter-track { animation: none; width: auto; flex-wrap: wrap; row-gap: 10px; }
  .clutter-pill[aria-hidden="true"] { display: none; }
  .clutter-mask { -webkit-mask-image: none; mask-image: none; }
}

.bridge { padding-block: clamp(96px, 13vw, 170px); }
.bridge-intro { max-width: 760px; margin-inline: auto; text-align: center; }
.bridge-intro h2 { max-width: 22ch; margin-inline: auto; font-size: clamp(28px, 3.8vw, 46px); letter-spacing: -0.035em; line-height: 1.05; text-wrap: balance; }
.bridge-lead { margin: 14px auto 0; max-width: 52ch; font-size: 19px; line-height: 1.6; color: var(--ink-2); }
.bridge-grid {
  max-width: 800px; margin: clamp(34px, 4vw, 52px) auto 0;
  display: grid; grid-template-columns: minmax(210px, 1fr) minmax(120px, 0.55fr) minmax(210px, 1fr);
  gap: 12px; align-items: stretch;
}
.bridge-card { background: var(--bg-raised); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow-xs); padding: clamp(20px, 2vw, 26px); }
/* Our side of the bridge carries the stronger border — the one visual nudge on
   a section that is otherwise deliberately even-handed. */
.bridge-card--ours { border-color: var(--line-strong); }
.bridge-logo { width: 26px; height: auto; }
.bridge-name { margin: 16px 0 0; font-weight: 600; font-size: 18px; letter-spacing: -0.02em; color: var(--ink); }
.bridge-text { margin: 6px 0 0; font-size: 16px; line-height: 1.5; color: var(--ink-3); }
.bridge-link { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 8px 4px; }
.bridge-rule { display: flex; align-items: center; gap: 8px; width: 100%; }
.bridge-hair { flex: 1 1 auto; height: 1px; background: var(--line-strong); }
.bridge-arrow { font-size: 17px; line-height: 1; color: var(--ink-3); }
.bridge-cap { font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-4); text-align: center; line-height: 1.7; }

/* Stack the bridge on a phone: the arrow turns a quarter-turn so it still reads
   as "these two exchange things" rather than pointing off the side of a card. */
@media (max-width: 720px) {
  .bridge-grid { grid-template-columns: 1fr; }
  .bridge-link { flex-direction: row; gap: 14px; padding: 4px 0; }
  .bridge-rule { flex-direction: column; width: auto; align-self: stretch; }
  .bridge-hair { width: 1px; height: auto; min-height: 14px; }
  .bridge-arrow { transform: rotate(90deg); }
}

/* Optional decoration over a showcase screenshot (the Fiken mascot). Absolute
   inside .show-visual, which the padding-top makes room for so the graphic
   never crops against the section edge. */
.show-visual.has-decor { position: relative; padding-top: clamp(48px, 6vw, 84px); }
.show-decor { position: absolute; top: 0; right: clamp(12px, 4vw, 48px); width: clamp(110px, 14vw, 170px); height: auto; z-index: 1; pointer-events: none; }

/* One-column variant of the answer list, for a campaign page with a handful of
   longer questions. `columns: 1` alone would keep the 1020px measure, which
   reads as a very long line, so the width comes in with it. */
.yes--big.yes--one { columns: 1; max-width: 760px; }

/* ── English hero measure ──────────────────────────────────────────────────
   The 38ch cap on .hero-headline is measured at THIS element's 16px, so it
   resolves to ~340px — and the 46px headline nested inside inherits that box,
   leaving it about fourteen characters a line. Norwegian headlines are short
   enough to have hidden it ("CRM-et som gjør jobben selv."); English says the
   same thing in more words and broke over four lines.

   So size the English box for the headline rather than for the supporting line
   under it. The supporting line goes to ~53ch, still inside a normal reading
   measure. Scoped to lang="en" because Norwegian fits at 38ch today, and
   widening a line that already breaks well would only make it worse. */
html[lang="en"] .hero-headline { max-width: 30rem; }
