/* ============================================================
   CONSID · Shared chrome — tokens, reset, nav/footer, rail+card
   system, CTA card, reveal-on-scroll. Loaded by every page under
   /viden/. index.html keeps its own copy inline (it predates this
   split and stays self-contained) — keep the two in sync by hand
   when editing either one.
   ============================================================ */
:root{
  /* Consid's official brand palette — ui.consid.dev/?path=/docs/design-colors--docs.
     Every colour below is one of these swatches, or a color-mix() tint of
     one; nothing off-palette. */
  --c-burgundy:#701131;      /* Primary Dark / Burgundy */
  --c-raspberry:#B5223F;     /* Primary / Raspberry */
  --c-light-orange:#F49E88;  /* Secondary / Light Orange */
  --c-dark-purple:#492A34;   /* Complementary / Dark purple */
  --c-beige:#EFE6DD;         /* Beige */
  --c-greige-15:#F2F0EF;     /* Greige 15 */
  --c-light-orange-15:#FDF0ED; /* Light Orange 15 */
  --c-light-orange-70:#F7BBAC; /* Light Orange 70 */
  --c-light-orange-40:#FBD8CF; /* Light Orange 40 */
  --c-white:#FFFFFF;
  --c-dark:#1C1C1C;
  --c-muted:#4C4C4C;

  --ink-900:var(--c-dark);
  --ink-800:var(--c-dark);
  --ink-700:color-mix(in srgb, var(--c-dark), white 15%);
  --ink-600:color-mix(in srgb, var(--c-dark), white 30%);
  --graphite:var(--c-muted);
  --stone:var(--c-muted);

  --air:var(--c-greige-15);
  --surface:var(--c-white);
  --sand:var(--c-beige);
  --blush:var(--c-light-orange-15);

  --crimson:var(--c-raspberry);
  --crimson-700:var(--c-burgundy);
  --plum:var(--c-dark-purple);
  --plum-tint:color-mix(in srgb, var(--plum), white 22%);
  --wine:var(--c-burgundy);
  --coral:var(--c-light-orange);
  --hairline:rgba(28,28,28,.08);

  /* ConsidSans is the site's one and only typeface — headings, body copy,
     nav, footer, and every meta/label style all share it, matching Consid's
     own typography system (see ui.consid.dev's "Jakarta" type docs, which
     this brand face stands in for). It only ships Regular/Medium/SemiBold
     (400/500/600) — nothing heavier — so anything that used to ask for a
     700/900 weight is capped at 600 (semibold) instead. */
  --font-considsans:"ConsidSans",-apple-system,"Segoe UI","Helvetica Neue",Helvetica,Arial,sans-serif;
  --font-display:var(--font-considsans);
  --font-body:var(--font-considsans);
  --font-mono:var(--font-considsans);
  --font-wordmark:var(--font-considsans);

  /* consid.com's nav/footer chrome — Dark background, Raspberry link colour.
     Now the same official swatches as --ink-900/--crimson above; kept as
     their own tokens since the nav/footer rules already reference them by
     these names. */
  --consid-dark:var(--c-dark);
  --consid-dark-700:color-mix(in srgb, var(--c-dark), black 15%);
  --consid-red:var(--c-raspberry);

  --t-display:clamp(2.57rem,6.66vw,5.85rem);
  --t-h2:clamp(2rem,4.2vw,3.6rem);
  --t-h3:clamp(1.2rem,1.7vw,1.5rem);
  --t-lead:clamp(1.0625rem,1.4vw,1.3rem);
  --t-body:1.0625rem;
  --t-small:.9375rem;
  --t-micro:.75rem;

  --s-1:.25rem;--s-2:.5rem;--s-3:.75rem;--s-4:1rem;--s-5:1.5rem;
  --s-6:2rem;--s-7:3rem;--s-8:4rem;--s-9:6rem;--s-10:8rem;

  --r-xs:10px; --r-sm:16px; --r-md:24px; --r-lg:36px; --r-xl:48px; --r-pill:999px;

  --lift-1:0 1px 2px rgba(20,20,22,.03), 0 6px 18px -10px rgba(20,20,22,.10);
  --lift-2:0 2px 5px rgba(20,20,22,.04), 0 22px 48px -22px rgba(20,20,22,.20);

  --ease-out:cubic-bezier(.19,.72,.28,1);
  --ease-spring:cubic-bezier(.34,1.32,.48,1);
  --d-fast:150ms;--d-base:260ms;--d-slow:520ms;

  --measure:64ch;
  --gutter:clamp(1.1rem,4.5vw,4rem);
  --maxw:1300px;
  --nav-height:85px;
}

/* ConsidSans — Consid's brand typeface, used across the whole site. */
@font-face{font-family:"ConsidSans";src:url("/assets/fonts/ConsidSans-Regular.woff2") format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"ConsidSans";src:url("/assets/fonts/ConsidSans-Italic.woff2") format("woff2");font-weight:400;font-style:italic;font-display:swap}
@font-face{font-family:"ConsidSans";src:url("/assets/fonts/ConsidSans-Medium.woff2") format("woff2");font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:"ConsidSans";src:url("/assets/fonts/ConsidSans-MediumItalic.woff2") format("woff2");font-weight:500;font-style:italic;font-display:swap}
@font-face{font-family:"ConsidSans";src:url("/assets/fonts/ConsidSans-SemiBold.woff2") format("woff2");font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:"ConsidSans";src:url("/assets/fonts/ConsidSans-SemiBoldItalic.woff2") format("woff2");font-weight:600;font-style:italic;font-display:swap}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;background:var(--air);color:var(--ink-800);
  font-family:var(--font-body);font-size:var(--t-body);line-height:1.6;
  -webkit-font-smoothing:antialiased;font-synthesis-weight:none;overflow-x:hidden;
}
h1,h2,h3,h4{font-family:var(--font-display);margin:0;font-weight:600;letter-spacing:-.026em}
h1{font-size:var(--t-display);line-height:.99;letter-spacing:-.042em}
h2{font-size:var(--t-h2);line-height:1.04;letter-spacing:-.034em}
h3{font-size:var(--t-h3);line-height:1.25}
p{margin:0}
strong,b{font-weight:600}
a{color:inherit}
img,svg{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
:focus-visible{outline:2px solid var(--crimson);outline-offset:3px;border-radius:6px}

/* Off-screen until focused, rather than display:none — a display:none
   skip link can't ever receive keyboard focus in the first place. */
.skip-link{
  position:absolute;top:var(--s-4);left:var(--s-4);z-index:1000;
  transform:translateY(-150%);
  background:var(--ink-800);color:#fff;padding:.85rem 1.4rem;
  border-radius:var(--r-md);text-decoration:none;white-space:nowrap;
  font-size:var(--t-small);font-weight:600;
  transition:transform var(--d-fast) var(--ease-out);
}
.skip-link:focus{transform:translateY(0)}

.wrap{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gutter)}
.stack{padding-top:clamp(3.5rem,8vw,7rem);padding-bottom:clamp(1rem,2vw,1.5rem)}
main > .stack:last-child,main > section:last-child.stack{padding-bottom:max(7rem,clamp(7rem,10vw,9.75rem))}
/* The closing CTA card uses the same generous rhythm everywhere as on the
   front page, so it never sits tight against the footer. */
.stack:has(> .wrap > .ctacard){padding-block:clamp(5.25rem,10.5vw,9.75rem)}
.lead{font-size:var(--t-lead);line-height:1.5;color:var(--graphite);max-width:var(--measure)}
.mono{font-family:var(--font-mono);font-size:var(--t-micro);letter-spacing:.13em;text-transform:uppercase}

.eyebrow{
  display:inline-flex;align-items:center;gap:var(--s-2);
  font-family:var(--font-mono);font-size:var(--t-micro);letter-spacing:.13em;
  text-transform:uppercase;color:var(--wine);
  background:var(--surface);padding:.45rem .85rem;border-radius:var(--r-pill);
  box-shadow:var(--lift-1);
}
.eyebrow i{width:6px;height:6px;border-radius:50%;background:var(--crimson);flex:none}

/* Buttons ------------------------------------------------ */
.btn{
  display:inline-flex;align-items:center;gap:var(--s-3);
  padding:.95rem 1.6rem;border-radius:var(--r-pill);
  font-size:var(--t-small);font-weight:600;text-decoration:none;white-space:nowrap;
  transition:background-color var(--d-fast) var(--ease-out),
             color var(--d-fast) var(--ease-out),
             box-shadow var(--d-base) var(--ease-out),
             transform var(--d-base) var(--ease-spring);
}
/* Dot coverage bumped from the original 42%/44%/2.5px (~28% of each
   cell filled — read as pale/washed-out at the arrow's real ~22px
   size) to 65%/70%/2px (~65% coverage): reads as a solid, confident
   glyph at actual size while still breaking up into visible dots on
   close inspection, keeping the dithered texture used elsewhere. */
/* The dots take their colour from currentColor so an arrow always matches
   the label it sits next to. -webkit-text-fill-color (not color:transparent)
   hides the glyph itself — setting color here would make currentColor
   transparent and the arrow would disappear. */
.arw{
  font-size:1.5em;
  background-image:radial-gradient(currentColor 65%, transparent 70%);
  background-size:2px 2px;background-position:center;
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;
}
.btn .arw{transition:transform var(--d-base) var(--ease-spring)}
.btn:hover{transform:translateY(-2px)}
.btn:hover .arw{transform:translateX(5px)}
.btn:active{transform:translateY(0)}
.btn--primary{background:var(--crimson);color:#fff;box-shadow:var(--lift-1)}
.btn--primary:hover{background:var(--crimson-700);box-shadow:var(--lift-2)}
.btn--soft{background:var(--surface);color:var(--ink-800);box-shadow:var(--lift-1)}
.btn--soft:hover{box-shadow:var(--lift-2)}
.btn--onDark{background:rgba(255,255,255,.1);color:#fff}
.btn--onDark:hover{background:rgba(255,255,255,.18)}
.btn:disabled,.btn[aria-disabled="true"]{opacity:.5;cursor:default;pointer-events:none}

/* NAV -----------------------------------------------------
   Matches consid.com's own real header exactly — measured directly off
   the live site's computed styles and DOM (not guessed from a screenshot):
   - Nav links are plain text, Dark (#1C1C1C) by default, no border/pill on
     the CTA at all — "Contact us" is just red text, same weight/size as
     every other link.
   - Two independent things toggle the colour scheme:
     .nav--onDark (set per-page, unchanged): the page's own top section is
     dark (Ydelser's plum band), so at rest the nav shows white text/logo,
     matching consid.com over its own dark photo hero.
     [data-stuck="true"] (site.js, on scroll): a `.nav-backdrop`-style
     white/blurred bar slides down from behind the nav — real values are
     rgba(255,255,255,.8) + backdrop-filter:saturate(1.8) blur(5px),
     revealed via `transform` (not opacity), exactly as consid.com does it.
   --nav-fg drives regular link + logo colour; --nav-cta drives just the
   CTA, since on consid.com the CTA is red whenever content is light but
   turns white (matching the other links) over a dark hero. */
.nav{position:sticky;top:0;z-index:50;font-family:var(--font-considsans);
  --nav-fg:var(--consid-dark);--nav-cta:var(--consid-red)}
.nav::before{
  content:"";position:absolute;inset:0;
  background:rgba(255,255,255,.8);
  backdrop-filter:saturate(1.8) blur(5px);-webkit-backdrop-filter:saturate(1.8) blur(5px);
  transform:translateY(-100%);
  transition:transform .3s cubic-bezier(.43,.195,.02,1);
  pointer-events:none;
}
.nav[data-stuck="true"]::before{transform:translateY(0)}
.nav--onDark:not([data-stuck="true"]){--nav-fg:#fff;--nav-cta:#fff}
.nav__in{
  position:relative;z-index:1;
  display:flex;align-items:center;gap:var(--s-5);
  height:var(--nav-height);padding-inline:40px;
}
.brand{display:flex;align-items:center;text-decoration:none;flex:none;position:relative}
.brand__mark{height:32px;width:auto;display:block;transition:opacity var(--d-fast) var(--ease-out)}
.brand__mark--light{position:absolute;left:0;top:0;opacity:0}
.nav--onDark:not([data-stuck="true"]) .brand__mark--dark{opacity:0}
.nav--onDark:not([data-stuck="true"]) .brand__mark--light{opacity:1}
/* Links sit right after the logo (not pushed to the far right); the CTA
   is the one pushed to the end, via its own margin-left:auto inside this
   same flex row — .nav__links needs flex:1 so that auto-margin has real
   space to push into. */
.nav__links{display:flex;gap:var(--s-1);align-items:center;flex:1}
.nav__link,.nav__cta{text-decoration:none;font-size:16px;font-weight:600;
  padding:.5rem .75rem;border-radius:var(--r-pill);
  transition:color var(--d-fast) var(--ease-out),background-color var(--d-fast) var(--ease-out)}
.nav__link{color:var(--nav-fg)}
.nav__link:hover{background:rgba(255,255,255,.2)}
.nav__cta{color:var(--nav-cta);margin-left:auto;padding:.5rem 1.25rem;border:2px solid var(--nav-cta);position:relative}
/* CTA outline draw — consid.com's own .btn-outline-anim interaction (see
   ui.consid.dev "Blocks / CTA"). The visible outline is not a CSS border
   at all: it's an SVG <rect> stroked with currentColor, whose dash pattern
   animates on hover so the outline redraws itself around the pill. The
   dash lengths depend on the button's measured size, so site.js injects
   the SVG and sets these custom properties; the CSS border above stays as
   the no-JS fallback and, once the SVG is in, goes transparent while still
   holding its 2px of layout. */
.nav__cta.has-outline-anim{border-color:transparent}
.nav__cta .cta-outline{
  position:absolute;inset:0;overflow:visible;pointer-events:none;
  stroke:currentColor;stroke-width:2;fill:none;
  stroke-dasharray:var(--button-animation-perimeter),0;
  stroke-dashoffset:calc(var(--button-animation-offset) + 20);
  transform:rotateX(180deg);
  /* consid.com transitions every property here at .9s; the dash sweep is
     scoped to that, with stroke colour left on the nav's own 150ms so the
     outline doesn't lag the label when the onDark scheme flips. */
  transition:stroke-dasharray .9s cubic-bezier(.43,.195,.02,1),
             stroke-dashoffset .9s cubic-bezier(.43,.195,.02,1),
             stroke var(--d-fast) var(--ease-out);
}
.nav__cta:hover .cta-outline{
  stroke-dasharray:var(--button-animation-perimeter),var(--button-animation-perimeter);
  stroke-dashoffset:var(--button-animation-offset);
}
@media (prefers-reduced-motion:reduce){.nav__cta .cta-outline{transition:none}}
@media (max-width:900px){.nav__links .nav__link{display:none}}

/* RAIL + CARD system (Ydelser + Viden share this) --------- */
.railhead{display:flex;flex-wrap:wrap;gap:var(--s-5);align-items:end;justify-content:space-between}
.filters{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-top:var(--s-6)}
.chip{padding:.6rem 1.1rem;border-radius:var(--r-pill);font-size:var(--t-small);color:var(--graphite);
  background:var(--surface);box-shadow:var(--lift-1);
  transition:color var(--d-fast) var(--ease-out),background-color var(--d-fast) var(--ease-out),transform var(--d-fast) var(--ease-spring)}
.chip:hover{color:var(--ink-800);transform:translateY(-2px)}
.chip:active{transform:scale(.97)}
.chip[aria-pressed="true"]{background:var(--ink-800);color:#fff}

.rail{display:flex;gap:var(--s-4);overflow-x:auto;scroll-snap-type:x mandatory;
  scroll-padding-inline:var(--gutter);
  margin-top:var(--s-6);padding:var(--s-3) var(--gutter) var(--s-8);
  margin-inline:calc(var(--gutter)*-1);scrollbar-width:none;
  mask-image:linear-gradient(to right, transparent 0, #000 var(--gutter), #000 calc(100% - var(--gutter)), transparent 100%);
  -webkit-mask-image:linear-gradient(to right, transparent 0, #000 var(--gutter), #000 calc(100% - var(--gutter)), transparent 100%);
}
.rail::-webkit-scrollbar{display:none}
.ocard{
  flex:0 0 clamp(260px,26vw,340px);scroll-snap-align:start;
  background:var(--surface);border-radius:var(--r-lg);padding:clamp(1.4rem,2.6vw,1.9rem);
  display:flex;flex-direction:column;gap:var(--s-3);text-decoration:none;min-height:290px;
  box-shadow:var(--lift-1);
  transition:transform var(--d-base) var(--ease-out),box-shadow var(--d-base) var(--ease-out),opacity var(--d-base) var(--ease-out);
}
.ocard:hover{transform:translateY(-6px);box-shadow:var(--lift-2)}
.ocard:active{transform:scale(.97)}
/* Filter-driven show/hide (initRail's applyFilter) — fade+scale instead
   of the bare [hidden] teleport. .is-entering has no transition of its
   own so the first paint lands at this reduced state instantly, then
   removing the class on the next frame animates it in via the rule
   above. */
.ocard.is-leaving{opacity:0;transform:scale(.96)}
.ocard.is-entering{opacity:0;transform:scale(.96);transition:none}
.ocard:nth-child(3n+2){background:var(--sand)}
.ocard:nth-child(5n+4){background:var(--blush)}
.ocard__tag{display:flex;align-items:center;gap:.4em;font-family:var(--font-mono);font-size:var(--t-micro);letter-spacing:.09em;text-transform:uppercase;color:var(--stone)}
.oicon{width:15px;height:15px;flex:none;stroke:currentColor}
.ocard h3{font-size:1.25rem;letter-spacing:-.028em;font-weight:600;transition:color var(--d-fast) var(--ease-out)}
.rail__spacer{flex:0 0 var(--gutter)}
.ocard:hover h3{color:var(--wine)}
.ocard p{font-size:var(--t-small);color:var(--graphite);line-height:1.6}
.ocard__foot{margin-top:auto;display:flex;align-items:center;gap:var(--s-3);font-size:var(--t-small);font-weight:600;padding-top:var(--s-4)}
.ocard__foot .arw{transition:transform var(--d-base) var(--ease-spring)}
.ocard:hover .ocard__foot .arw{transform:translateX(5px)}
.ocard[hidden]{display:none}
.dots{display:flex;gap:4px}
.dot{width:6px;height:6px;border-radius:50%;background:var(--hairline)}
.dot--on{background:var(--crimson)}
.railnav{display:flex;gap:var(--s-2)}
.rbtn{width:2.75rem;height:2.75rem;border-radius:50%;background:var(--surface);box-shadow:var(--lift-1);
  display:grid;place-items:center;transition:transform var(--d-fast) var(--ease-spring),box-shadow var(--d-fast) var(--ease-out)}
.rbtn:hover{transform:translateY(-2px);box-shadow:var(--lift-2)}
.rbtn:active{transform:scale(.94)}

/* Viden — plain white cards. Niveau doesn't apply to this content
   (articles/whitepapers aren't leveled the way services are), so
   .ocard.vcard stays at the same specificity as the nth-child
   alternation above and wins on source order, keeping Viden cards
   white instead of picking up Ydelser's sand/blush alternation. */
.ocard.vcard{background:var(--surface)}
.vcard.is-soon{cursor:default}
.vcard.is-soon:hover{transform:none;box-shadow:var(--lift-1)}
.vcard.is-soon h3{color:inherit}
.vcard .ocard__tag{display:flex;align-items:center;gap:.5em}

/* Grid overview page — same cards, no rail/scroll/mask, just a grid. */
.vgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-4);margin-top:var(--s-6)}
.vgrid .ocard{flex:none;min-height:260px}
@media (max-width:880px){.vgrid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:640px){.vgrid{grid-template-columns:1fr}}

/* CTA + FOOTER --------------------------------------------- */
.ctacard{
  background:var(--plum);color:#fff;border-radius:var(--r-xl);padding:clamp(1.9rem,5vw,4.5rem);
  box-shadow:var(--lift-1);text-align:center;position:relative;overflow:hidden;
}
.ctacard__noise{position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none}
@media (prefers-reduced-motion:reduce){.ctacard__noise{display:none}}
.ctacard__content{position:relative;z-index:1}
.ctacard h2{max-width:18ch;margin-inline:auto;margin-top:var(--s-5)}
.ctacard .lead{margin-inline:auto;margin-top:var(--s-5);text-align:center;color:rgba(255,255,255,.72)}
.ctacard__actions{display:flex;gap:var(--s-3);flex-wrap:wrap;justify-content:center;margin-top:var(--s-7)}
/* FOOTER ----------------------------------------------------
   Matches consid.com's own real footer — measured directly off its live
   DOM/computed styles: solid #1C1C1C, three plain link columns (no
   separate header — the first link in each column is styled exactly like
   the rest, just first), a row of 30px white circular social icons
   pinned to the end of the same row, and a bottom row with the logo and
   two legal links — no copyright line, no divider border. */
.footer{background:var(--consid-dark);color:#fff;font-family:var(--font-considsans);
  padding-top:var(--s-8);padding-bottom:var(--s-6)}
.footer__grid{display:flex;flex-wrap:wrap;gap:var(--s-6) var(--s-5)}
.footer__col{display:flex;flex-direction:column;gap:var(--s-3);flex:1 1 200px}
.footer__col a{color:#fff;font-size:18px;font-weight:600;text-decoration:underline;text-underline-offset:.15em;text-decoration-color:rgba(255,255,255,.35);transition:text-decoration-color var(--d-fast) var(--ease-out)}
.footer__col a:hover{text-decoration-color:#fff}
.footer__social{display:flex;gap:var(--s-3);align-items:flex-start;margin-left:auto;flex:0 0 auto}
.footer__social a{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:999px;background:#fff;color:var(--consid-dark);transition:opacity var(--d-fast) var(--ease-out)}
.footer__social a:hover{opacity:.8}
.footer__social svg{width:16px;height:16px}
.footer__bottom{margin-top:var(--s-6);
  display:flex;flex-wrap:wrap;gap:var(--s-4);align-items:center;justify-content:space-between}
.footer__logo{display:block;height:32px}
.footer__logo img{height:100%;width:auto;display:block}
.footer__legal{display:flex;flex-wrap:wrap;gap:var(--s-5);align-items:center;font-size:18px;color:#fff}
.footer__legal a{color:#fff;text-decoration:none;transition:opacity var(--d-fast) var(--ease-out)}
.footer__legal a:hover{opacity:.7}

/* REVEAL --------------------------------------------------- */
.reveal{opacity:0;transform:translateY(16px)}
.reveal.is-in{opacity:1;transform:none;transition:opacity var(--d-slow) var(--ease-out),transform var(--d-slow) var(--ease-out)}
@media (prefers-reduced-motion:reduce){.reveal,.word{opacity:1;transform:none}}

/* ARTICLE page ---------------------------------------------
   No cover photography was supplied, so the header treatment is a
   plain CSS halftone accent — the same radial-gradient dot pattern
   already used for every arrow glyph on the site (see .arw above),
   scaled up into a small decorative rule under the title. Keeps the
   "dithered" identity without needing a WebGL context on every one
   of these pages. */
.article__head{padding-top:clamp(2.5rem,6vw,4.5rem)}
.article__dither{
  width:100%;height:clamp(2.5rem,6vw,4rem);margin-top:var(--s-6);
  background-image:radial-gradient(var(--crimson) 32%, transparent 34%);
  background-size:9px 9px;background-position:0 center;
  -webkit-mask-image:linear-gradient(to right, transparent 0%, #000 6%, #000 94%, transparent 100%);
  mask-image:linear-gradient(to right, transparent 0%, #000 6%, #000 94%, transparent 100%);
  opacity:.55;
}
.article__meta{display:flex;gap:var(--s-3);flex-wrap:wrap;align-items:center;margin-top:var(--s-5);
  font-family:var(--font-mono);font-size:var(--t-micro);letter-spacing:.08em;text-transform:uppercase;color:var(--stone)}
/* Reuses .chip verbatim (as plain links, not filter buttons) so a tag
   here is visually the same token a reader will click again on the
   overview page's filter bar — the link between the two is the point. */
.article__tags{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-top:var(--s-4)}
.article__tags .chip{text-decoration:none}
.article__body{max-width:var(--measure);margin-top:var(--s-8)}
.article__body h2{font-size:clamp(1.4rem,2.4vw,1.9rem);margin-top:var(--s-8)}
.article__body p{margin-top:var(--s-5);color:var(--ink-700);line-height:1.75;font-size:var(--t-body)}
.article__body p:first-of-type{margin-top:0}
.article__body hr{border:0;border-top:1px solid var(--hairline);margin:var(--s-8) 0}
.article__body strong{color:var(--ink-900)}
.article__body h3{font-size:clamp(1.15rem,1.9vw,1.4rem);margin-top:var(--s-7)}
.article__body ul{margin-top:var(--s-5);padding-left:1.2em;display:flex;flex-direction:column;gap:var(--s-3)}
.article__body li{color:var(--ink-700);line-height:1.75;font-size:var(--t-body)}
.article__body code{font-family:var(--font-mono);font-size:.9em;background:var(--sand);padding:.15em .4em;border-radius:6px}

/* YDELSE page — deliberately re-skinned to read as a service page, not
   an article: a dark plum header (the same "this matters more" surface
   already used for the CTA card and .whycard) instead of the article's
   plain background, plus a meta row (icon + kicker, niveau .dots) reused
   directly on the header. */
/* z-index:0 (not just position:relative) so this establishes its OWN
   stacking context — .ydelse__illus's z-index:-1 needs to be scoped
   locally, behind this header's text but above its own background,
   not resolved against some ancestor context further up the page. */
/* .nav is sticky, not fixed — at rest it reserves its own space in
   flow rather than overlapping whatever comes next, so without this
   the plum background would start BELOW the nav, leaving the page's
   own (light) background showing through the transparent nav above
   it instead of plum. Pulling the head up by exactly the nav's height
   and adding that same amount back as padding keeps the actual
   content (h1/lead/meta) sitting at the same visual position as
   before, while the plum itself now extends up behind the nav. */
.ydelse__head{position:relative;z-index:0;overflow:hidden;background:var(--plum);border-radius:0 0 var(--r-xl) var(--r-xl);
  margin-top:calc(-1 * var(--nav-height));
  padding-top:calc(var(--nav-height) + clamp(3.5rem,8vw,7rem));padding-bottom:clamp(2.5rem,6vw,4rem)}
.ydelse__head h1{color:#fff}
.ydelse__head .lead{color:rgba(255,255,255,.78)}
.ydelse__meta{display:flex;gap:var(--s-6);flex-wrap:wrap;align-items:center;justify-content:space-between;margin-top:var(--s-7)}
.ydelse__kicker{display:flex;align-items:center;gap:.5em;font-family:var(--font-mono);font-size:var(--t-micro);letter-spacing:.09em;text-transform:uppercase;color:rgba(255,255,255,.7)}

/* Level meter — the bare .dots component (still used on rail/related
   cards) reads as decoration, not information: 6px dots with no
   visible label, meaning only exposed via aria-label. On the Ydelse
   page's own header, this is the ONE place a visitor decides "is this
   for us?" — so it gets a labelled, numbered version instead. */
.ydelse__levels{display:flex;align-items:center;gap:.65em}
.ydelse__levels-label{font-family:var(--font-mono);font-size:var(--t-micro);letter-spacing:.09em;text-transform:uppercase;color:rgba(255,255,255,.55)}
.lvlmeter{display:flex;gap:5px}
/* .4/.24 measured 3.37:1 text / 2.11:1 border against --plum — both
   below the 4.5:1 (text) and 3:1 (UI-component boundary) AA minimums.
   .55/.4 clear both (4.98:1 / 3.37:1) while staying visibly dimmer
   than the solid .lvl--on pills. */
.lvl{display:grid;place-items:center;width:20px;height:20px;border-radius:50%;
  font-family:var(--font-mono);font-size:10px;font-weight:600;
  color:rgba(255,255,255,.55);border:1px solid rgba(255,255,255,.4);background:transparent}
.lvl--on{color:var(--plum);background:#fff;border-color:#fff}

/* One handrolled abstract shape per offering (assets/dither.js), run
   through the same matcap+dither pipeline as the article breaks below,
   but tinted a shade lighter than the plum it sits on (--plum-tint, set
   per-scene in dither.js) instead of the crimson used elsewhere — a
   background texture, not a foreground mark. Sized off the viewport,
   NOT the header's own box (a header-relative top/bottom:-20% just
   dilutes into a wide, mostly-empty frame once the width is huge) —
   width and height are equal and both huge, so it overflows the header
   on every side and reads as running behind the H1/lead text rather
   than sitting beside it. z-index:-1 keeps the header's own text
   stacked above it; .ydelse__head's overflow:hidden crops the bleed.
   Hidden below 900px rather than fighting the H1 for space. */
.ydelse__illus{
  position:absolute;z-index:-1;top:50%;left:50%;
  transform:translate(-42%,-50%);
  width:clamp(900px,95vw,1900px);
  height:clamp(900px,95vw,1900px);
  pointer-events:none;
}
.ydelse__illus canvas{display:block;width:100%;height:100%}
@media (max-width:900px){.ydelse__illus{display:none}}

/* Pull quote — a sentence lifted verbatim from the body, blown up in
   the site's serif wordmark face for contrast against the sans body
   text. The oversized glyph is a plain CSS quotation mark, not an
   image, so it inherits the ink colour and needs no asset. */
.pullquote{
  position:relative;margin:var(--s-9) 0;padding-left:clamp(1.5rem,4vw,2.5rem);
  border-left:3px solid var(--crimson);
  font-family:var(--font-wordmark);font-style:italic;font-weight:600;
  font-size:clamp(1.5rem,3vw,2.1rem);line-height:1.35;letter-spacing:-.01em;
  color:var(--ink-900);max-width:52ch;
}
.pullquote::before{
  content:"“";position:absolute;left:clamp(1.5rem,4vw,2.5rem);top:-.3em;
  font-family:var(--font-wordmark);font-style:normal;font-weight:600;
  font-size:2.4em;line-height:1;color:var(--crimson);opacity:.35;
  transform:translateX(-.15em);pointer-events:none;
}

/* Abstract dithered section-break shapes (assets/dither.js) — a real
   rhythm-break between article sections, not a small icon: wide
   enough that the shape's silhouette actually reads at a glance. */
.section-break{
  width:clamp(9rem,26vw,14rem);aspect-ratio:3/2;margin:var(--s-8) auto 0;
}
.section-break canvas{display:block;width:100%;height:100%}

.related{margin-top:var(--s-9)}
.related h3{font-size:var(--t-h3)}
.related .vgrid{margin-top:var(--s-5)}

/* Lead-gen — copy on the left half, form stacked and right-aligned
   on the right half. */
.leadcard{
  background:var(--sand);border-radius:var(--r-xl);padding:clamp(1.9rem,4.5vw,3.5rem);
  display:grid;grid-template-columns:1fr 1fr;gap:var(--s-8);align-items:start;
}
.leadcard h3{font-size:clamp(1.3rem,2.2vw,1.7rem)}
.leadform{display:flex;flex-direction:column;gap:var(--s-4);transition:opacity var(--d-base) var(--ease-out)}
.leadform.is-leaving{opacity:0}
/* Our own display:flex above has equal specificity to the browser's
   built-in [hidden]{display:none} and wins on source order, so setting
   the hidden attribute alone left the form's full-height box in place
   (invisible, opacity:0 from .is-leaving) — pushing #lf-status down
   into the empty space below it instead of taking its place. */
.leadform[hidden]{display:none}
.leadform .field{display:flex;flex-direction:column;gap:.4rem;width:75%}
.leadform label{font-family:var(--font-mono);font-size:var(--t-micro);letter-spacing:.08em;text-transform:uppercase;color:var(--graphite)}
.leadform input{
  padding:.85rem 1rem;border-radius:var(--r-sm);border:1px solid var(--hairline);
  background:var(--surface);font:inherit;font-size:var(--t-small);color:var(--ink-900)
}
.leadform input:focus-visible{outline:2px solid var(--crimson);outline-offset:1px}
.leadform button{align-self:flex-end}
@media (max-width:880px){.leadcard{grid-template-columns:1fr}}
#lf-status{
  margin-top:var(--s-4);font-size:var(--t-small);color:var(--wine);
  opacity:0;transform:translateY(6px);
  transition:opacity var(--d-slow) var(--ease-out),transform var(--d-slow) var(--ease-out);
}
#lf-status.is-in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){.leadform,#lf-status{transition:none}}

/* GDPR — point-of-collection notice. Art. 13 wants this information given
   where the data is actually handed over, not only behind a link, so it
   renders inline above each form's submit button. Colour is inherited so
   the same component reads correctly on the light lead-gen card and on the
   dark plum contact card. */
.formnotice{font-size:var(--t-small);line-height:1.55;opacity:.78;max-width:62ch;margin-top:var(--s-5)}
.formnotice strong{font-weight:600}
.formnotice a{text-decoration:underline;text-underline-offset:.15em}
.formnotice a:hover{opacity:.8}
