:root{
--accent:#FF4D00;--accent-lo:#FF7A3D;--accent-hi:#C93A00;
--ink:#0A0A0A;--ink-70:rgba(10,10,10,.68);--muted:rgba(10,10,10,.55);--dim:rgba(10,10,10,.42);--ink-35:rgba(10,10,10,.32);--ink-20:rgba(10,10,10,.2);
--rule:rgba(10,10,10,.11);--rule-soft:rgba(10,10,10,.06);--wash:rgba(10,10,10,.025);
--paper:#FCFCFB;
--r-pill:999px;--r-card:24px;--r-box:32px;--r-in:18px;
--pad:clamp(20px,5vw,72px);--maxw:1340px;
--ease:cubic-bezier(.22,1,.36,1);
--mono:"JetBrains Mono",ui-monospace,monospace;
}
*{box-sizing:border-box}
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{margin:0;background:var(--paper);color:var(--ink);font-family:"Schibsted Grotesk",system-ui,sans-serif;font-size:16px;line-height:1.5;letter-spacing:-.011em;-webkit-font-smoothing:antialiased;overflow-x:hidden}
a{color:var(--ink);text-decoration:none;transition:color .3s var(--ease)}
a:hover{color:var(--accent)}
h1,h2,h3{margin:0;font-weight:600;letter-spacing:-.035em;line-height:1.02;text-wrap:balance}
p{margin:0;text-wrap:pretty}
ul{margin:0;padding:0;list-style:none}
svg{display:block}
.accent{color:var(--accent)}
.eyebrow{font:500 11px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.grillage{position:fixed;inset:0;width:100%;height:100%;z-index:0;pointer-events:none}
main{position:relative;z-index:1}

/* ── contained glow (never a page background) ─────── */
.glow-box{position:relative;overflow:hidden;isolation:isolate}
.glow-box>*:not(.glow):not(.svc-marker):not(.panel-lattice){position:relative;z-index:1}
.glow{position:absolute;z-index:0;border-radius:50%;pointer-events:none}
.g-accent{width:62%;aspect-ratio:1;left:-8%;top:-16%;background:radial-gradient(circle at 50% 50%,rgba(255,77,0,.34),rgba(255,77,0,0) 70%);filter:blur(44px);animation:drift 26s var(--ease) infinite alternate}
.g-accent.sm{width:120%;left:-24%;top:-46%;filter:blur(34px)}
.g-ink{width:52%;aspect-ratio:1;right:-14%;bottom:-18%;left:auto;top:auto;background:radial-gradient(circle at 50% 50%,rgba(10,10,10,.16),rgba(10,10,10,0) 70%);filter:blur(48px);animation:drift 34s var(--ease) infinite alternate-reverse}
@keyframes drift{0%{transform:translate3d(0,0,0) scale(1)}50%{transform:translate3d(6%,5%,0) scale(1.1)}100%{transform:translate3d(-4%,-3%,0) scale(.95)}}

/* ── nav: floating glass pill ─────────────────────── */
.nav{position:fixed;top:0;left:0;right:0;z-index:30;display:flex;justify-content:center;padding:22px var(--pad) 0;pointer-events:none}
.pill{pointer-events:auto;display:flex;align-items:center;gap:clamp(16px,2.4vw,38px);padding:9px 9px 9px 22px;border:1px solid rgba(10,10,10,.09);border-radius:var(--r-pill);background:rgba(252,252,251,.72);backdrop-filter:blur(16px) saturate(1.4);-webkit-backdrop-filter:blur(16px) saturate(1.4);box-shadow:0 1px 0 rgba(255,255,255,.7) inset,0 12px 34px -14px rgba(10,10,10,.18)}
.wordmark{display:inline-flex;align-items:baseline;gap:.34em;font-size:15px;font-weight:600;letter-spacing:-.02em;white-space:nowrap}
.wordmark:hover{color:var(--ink)}
.wm-thin{font-weight:400;color:var(--muted);letter-spacing:-.01em}
.pill-links{display:flex;align-items:center;gap:clamp(14px,2vw,26px);font-size:14.5px}
.pill-cta{display:inline-flex;align-items:center;gap:9px;padding:10px 17px;border-radius:var(--r-pill);background:var(--ink);color:#fff;font-size:14px;transition:background .3s var(--ease)}
.pill-cta:hover{background:#1d1d1d;color:#fff}
.pill-cta .dot{width:6px;height:6px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 0 rgba(255,77,0,.6);animation:ping 2.8s ease-out infinite}
@keyframes ping{0%{box-shadow:0 0 0 0 rgba(255,77,0,.55)}70%{box-shadow:0 0 0 8px rgba(255,77,0,0)}100%{box-shadow:0 0 0 0 rgba(255,77,0,0)}}

/* ── mobile nav ───────────────────────────────────── */
/* Both controls are display:none here and switched on only inside the
   <=767px block below. That is the whole desktop cost of this feature: two
   declarations on two elements that did not exist before, which cannot move a
   pixel of the existing design. Everything else lives in the media query. */
.pill-burger,.pill-menu{display:none}
/* Drawn in CSS rather than added to the icon set: no twelfth Lucide file, no
   extra request, and the bars can morph to an X without a second asset. */
.burger-bars{position:relative}
.burger-bars,.burger-bars::before,.burger-bars::after{display:block;width:17px;height:1.5px;border-radius:2px;background:currentColor;transition:transform .32s var(--ease),opacity .2s var(--ease)}
.burger-bars::before,.burger-bars::after{content:"";position:absolute}
.burger-bars::before{transform:translateY(-6px)}
.burger-bars::after{transform:translateY(6px)}
.pill-burger.open .burger-bars{background:transparent}
.pill-burger.open .burger-bars::before{transform:rotate(45deg)}
.pill-burger.open .burger-bars::after{transform:rotate(-45deg)}

/* ── skip link ────────────────────────────────────── */
/* Off-screen until focused, never display:none - a hidden skip link that
   cannot receive focus is not a skip link. */
.skip{position:fixed;left:12px;top:-100px;z-index:60;padding:12px 20px;border-radius:var(--r-pill);background:var(--ink);color:#fff;font-size:14px;transition:top .2s var(--ease)}
.skip:focus{top:12px;color:#fff}
main:focus{outline:none}

/* ── focus, everywhere ────────────────────────────── */
/* Only .wk-view carried a focus style before this, and the browser default
   ring is close to invisible against the dark footer block. Two rules: an ink
   ring on paper, a white one on the footer's ink surface. */
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:4px}
.footer :focus-visible,.stats-ink :focus-visible,.vstate :focus-visible,.stack-band :focus-visible{outline-color:#fff}

/* ── pressed states ───────────────────────────────── */
/* There was no :active anywhere, so every tap on a phone gave no feedback at
   all between touch and navigation. Invisible on desktop and in every
   screenshot; only a finger can see it. */
.btn:active,.pill-cta:active,.wk-more:active,.btn-inv:active{transform:translateY(1px);opacity:.9}
.wk-nav:active:not(:disabled),.socials a:active,.pill-burger:active{transform:scale(.94)}
.wordmark:active,.btn-ghost:active,.pback:active,.foot-col a:active,.foot-legal a:active,.cookie-btn:active{opacity:.62}

/* ── tap targets ──────────────────────────────────── */
/* A transparent ::after grows the HIT area; the visible box is untouched, so
   the rendered design is identical and only a finger notices. Each of these
   needs position:relative or the pseudo-element resolves against .nav
   (position:fixed) instead of the control, and spans the whole header.
   Reached 44px wherever the geometry allows. Where it does not - dense link
   lists and the carousel dots - the box grows to the full pitch instead, so
   the row is contiguous with no dead space between targets, and the measured
   number is recorded in docs/visual-deltas.md rather than rounded up. */
.wordmark,.pill-cta,.btn-ghost,.pback,.pill-burger{position:relative}
.wordmark::after,.pill-cta::after,.btn-ghost::after,.pback::after{content:"";position:absolute;left:0;right:0;top:50%;height:44px;transform:translateY(-50%)}
/* The burger is drawn at 40px to sit inside the pill without stretching it;
   the hit box is the full 44. */
.pill-burger::after{content:"";position:absolute;left:50%;top:50%;width:44px;height:44px;transform:translate(-50%,-50%)}

/* ── hero: copy left, services box right ──────────── */
.hero{display:grid;grid-template-columns:minmax(0,1fr) minmax(250px,auto);align-items:center;gap:clamp(26px,3vw,48px);min-height:92svh;max-width:var(--maxw);margin:0 auto;padding:clamp(132px,15vh,168px) var(--pad) clamp(64px,8vw,104px)}
.hero-copy{display:flex;flex-direction:column;align-items:flex-start;gap:26px}
.hero-copy h1{font-size:clamp(32px,4.6vw,65px);letter-spacing:-.04em}
.hero-copy h1 .l1,.hero-copy h1 .l2{display:block}
.subline{max-width:44ch;font-size:clamp(15.5px,1.2vw,18.5px);color:var(--ink-70)}
.hero-act{display:flex;align-items:center;gap:clamp(14px,2vw,26px);flex-wrap:wrap;margin-top:4px}
.btn{display:inline-flex;align-items:center;gap:10px;padding:13px 24px 13px 19px;border-radius:var(--r-pill);background:var(--ink);color:#fff;font-size:15px;letter-spacing:-.008em;transition:transform .32s var(--ease),background .32s var(--ease)}
.btn:hover{color:#fff;background:#1d1d1d;transform:translateY(-2px)}
.ic.btn-arrow{width:18px;height:18px;flex:none;transition:transform .32s var(--ease)}
.btn:hover .btn-arrow{transform:translateX(3px)}
.btn-ghost{font-size:15px;color:var(--ink-70);border-bottom:1px solid var(--ink-20);padding-bottom:2px}
.btn-ghost:hover{border-color:var(--accent)}

/* inline iso cube stack */
.iso-inline{display:inline-block;width:1.6em;height:.95em;margin-left:.24em;vertical-align:baseline;position:relative}
.iso-scene{position:absolute;inset:0;transform-origin:50% 78%;animation:isoFloat 7s ease-in-out infinite alternate}
@keyframes isoFloat{0%{transform:rotate(-3.5deg) translateY(.025em)}100%{transform:rotate(3.5deg) translateY(-.03em)}}
.cube{position:absolute;width:var(--s);height:var(--s);transform-style:preserve-3d;transform:rotateX(-24deg) rotateY(-45deg)}
.cube:nth-child(1){--s:.22em;left:0;bottom:0}
.cube:nth-child(2){--s:.28em;left:.40em;bottom:.14em}
.cube:nth-child(3){--s:.34em;left:.84em;bottom:.30em}
.cube .f{position:absolute;left:50%;top:50%;width:var(--s);height:var(--s);margin:calc(var(--s) / -2)}
.cube .top{transform:rotateX(90deg) translateZ(calc(var(--s) / 2));background:var(--accent-lo)}
.cube .front{transform:translateZ(calc(var(--s) / 2));background:var(--accent)}
.cube .right{transform:rotateY(90deg) translateZ(calc(var(--s) / 2));background:var(--accent-hi)}

/* ── hero rotator: bare word, depth rack-focus ────── */
.rotator{align-self:center;display:flex;flex-direction:column;gap:12px;padding-left:clamp(16px,1.8vw,24px);border-left:1px solid var(--rule)}
.svc-viewport{position:relative;height:clamp(36px,3.2vw,46px)}
.svc-item{position:absolute;left:0;top:0;width:100%;height:100%;display:flex;align-items:center;font-size:clamp(20px,2.1vw,31px);font-weight:600;letter-spacing:-.035em;line-height:1.1;white-space:nowrap;color:var(--ink);opacity:0;will-change:transform,filter,opacity}
.svc-item.on{opacity:1}
.svc-item.out{opacity:1;animation:rackOut .6s var(--ease) forwards}
.svc-item.in{animation:rackIn .6s var(--ease) .07s forwards}
@keyframes rackOut{0%{transform:scale(1) translateY(0);filter:blur(0);opacity:1}100%{transform:scale(.86) translateY(-7px);filter:blur(12px);opacity:0}}
@keyframes rackIn{0%{transform:scale(1.14) translateY(9px);filter:blur(14px);opacity:0}60%{opacity:1}100%{transform:scale(1) translateY(0);filter:blur(0);opacity:1}}

/* ── section heading ──────────────────────────────── */
.why{position:relative;padding:0 var(--pad) clamp(70px,9vw,132px)}
.chip-rule{position:relative;display:grid;place-items:center;height:clamp(96px,12vw,152px)}
.chip-rule::before{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:var(--rule)}
.chip{position:relative;padding:12px 28px;border:1px solid var(--rule);border-radius:var(--r-pill);background:var(--paper);font-size:clamp(15px,1.4vw,19px);font-weight:500;letter-spacing:-.02em}

/* ── section index label ───────────────────────── */
.card-idx{font:500 11px/1 var(--mono);letter-spacing:.16em;color:var(--muted)}

/* ── iso icons ────────────────────────────────────── */
.ico{position:relative;height:132px;margin-top:auto}
.iso-plane{position:absolute;left:6px;bottom:14px;display:grid;grid-template-columns:repeat(3,26px);gap:5px;transform:rotateX(56deg) rotateZ(-45deg);transform-style:preserve-3d}
.tile{width:26px;height:26px;border-radius:3px;background:#ECECEA;box-shadow:2px 2px 0 #DCDCD8}
.tile.hot{background:var(--accent);box-shadow:2px 2px 0 var(--accent-hi)}
.glass{position:absolute;left:88px;bottom:54px;width:40px;height:40px;border:2.5px solid var(--ink);border-radius:50%;animation:bob 5.5s ease-in-out infinite alternate}
.glass i{position:absolute;right:-16px;bottom:-13px;width:20px;height:2.5px;border-radius:2px;background:var(--ink);transform:rotate(42deg);transform-origin:left center}
@keyframes bob{0%{transform:translate(0,0)}100%{transform:translate(-4px,-7px)}}
.ico-pipe{display:flex;align-items:center;justify-content:center;gap:4px;min-width:0}
.gear{flex:0 1 auto;width:clamp(38px,26%,56px);min-width:0;transform:rotateX(30deg)}
.gear svg{width:100%;filter:drop-shadow(3px 5px 0 rgba(10,10,10,.06));animation:spin 26s linear infinite}
.gear .teeth{fill:#DEDEDA}
.gear .hub{fill:var(--paper)}
@keyframes spin{to{transform:rotate(360deg)}}
.pipe{flex:1 1 0;min-width:0;max-width:132px;height:56px;overflow:visible}
.pipe-line{fill:none;stroke:var(--ink-35);stroke-width:1.4;stroke-linecap:round;stroke-dasharray:5 6}
/* `.card.landed .pipe-line` stood here and matched nothing: there is no
   element with class `card` in any of the five pages (only card-idx, wk-card,
   svc-card, mhero-card). The live rule is `.pstep.lit .pipe-line` in
   sections.css, which covers the homepage process spine.
   The three .pipe-line instances on the project pages sit in
   .jrn-media.jrn-art, so the selector that WOULD animate them is
   `.jrn-row.lit .pipe-line`. Deliberately not added: it would start a dashed
   flow animation where the handoff renders a static line, which is a visible
   change to a design declared final. Removed rather than fixed, and recorded
   in docs/visual-deltas.md so it is not "tidied up" into existence later. */
@keyframes flow{to{stroke-dashoffset:-22}}
.pipe-node{fill:var(--accent)}
.doc{flex:0 1 auto;width:clamp(32px,22%,44px);min-width:0;height:58px;display:flex;flex-direction:column;justify-content:center;gap:6px;padding:8px;background:#fff;border:1.5px solid var(--ink);border-radius:5px;transform:rotate(-4deg);box-shadow:4px 5px 0 rgba(10,10,10,.07)}
.doc i{height:2px;background:var(--ink-35);border-radius:2px}
.doc i:last-child{width:60%}

/* ── reveal ───────────────────────────────────────── */
/* Scoped to .js, and that scope is load-bearing rather than tidy. Only
   site.js ever adds .landed, so an UNSCOPED `opacity:0` means that if the
   script does not run - JS off, a blocked script, a 404 - 13 elements on the
   homepage and up to 11 per project page are invisible forever. The class is
   set by an inline script in <head> (which cannot 404) and taken off again by
   the onerror on each <script> tag (which covers the file that can). CSS ships
   the finished state; motion only adds the journey. */
/* :not(.landed) is not tidiness, it is the fix for a regression this scoping
   caused. `.reveal` alone is (0,1,0) and loses to `.reveal.landed` (0,2,0);
   `.js .reveal` is also (0,2,0), so the two tie and SOURCE ORDER decides. Here
   that happened to be harmless, but the copy inside the reduced-motion block
   at the end of this file then beat .landed and held every revealed element at
   opacity 0 - a blank page for anyone who asks their OS for less motion.
   Excluding .landed makes the intent explicit and takes the cascade out of it. */
.js .reveal:not(.landed){opacity:0;transform:translateY(16px)}
.reveal.landed{opacity:1;transform:none;transition:opacity .5s var(--ease) var(--d),transform .5s var(--ease) var(--d)}

/* ── footer ───────────────────────────────────────── */
.footer{position:relative;z-index:1;max-width:var(--maxw);margin:0 auto;padding:clamp(56px,7vw,96px) var(--pad) 32px;border-top:1px solid var(--rule)}
.foot-cta{display:flex;align-items:center;justify-content:space-between;gap:clamp(24px,4vw,60px);flex-wrap:wrap}
.foot-cta-copy{display:flex;flex-direction:column;gap:14px}
.foot-cta h2{font-size:clamp(28px,3.4vw,48px);max-width:22ch}
.foot-rule{height:1px;background:var(--rule);margin:clamp(44px,5vw,72px) 0 clamp(32px,4vw,52px)}
.foot-grid{display:flex;flex-wrap:wrap;gap:clamp(32px,6vw,90px);justify-content:space-between}
.foot-brand{max-width:32ch;display:flex;flex-direction:column;gap:14px}
.foot-brand p{font-size:14px;color:var(--muted)}
.foot-cols{display:flex;flex-wrap:wrap;gap:clamp(30px,5vw,76px)}
.foot-col{display:flex;flex-direction:column;gap:11px;font-size:14px}
.foot-col a{color:var(--ink-70)}
.foot-col a:hover{color:var(--accent)}
.foot-h{font:500 11px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--muted);margin-bottom:6px}
.foot-bottom{display:flex;justify-content:space-between;gap:16px;margin-top:clamp(40px,5vw,68px);padding-top:22px;border-top:1px solid var(--rule-soft);font:400 12px/1 var(--mono);letter-spacing:.06em;color:var(--muted)}

/* ── responsive ───────────────────────────────────── */
@media (max-width:1080px){
.hero{grid-template-columns:1fr;min-height:0;gap:36px}
.rotator{max-width:460px;align-self:start;border-left:0;padding-left:0}
}
@media (max-width:767px){
/* position:relative is the ONLY change to an existing rule in this whole
   phase, and it is confined to this media query so the desktop cascade is
   untouched. It gives .pill-menu something to hang off; with no offsets it
   moves nothing and, at z-index:auto, creates no stacking context. */
.pill{position:relative;padding:8px 8px 8px 18px;gap:12px}
.pill-links{display:none}
.pill-burger{display:grid;place-items:center;width:40px;height:40px;padding:0;border:1px solid rgba(10,10,10,.09);border-radius:50%;background:rgba(252,252,251,.9);color:var(--ink);cursor:pointer;transition:transform .3s var(--ease),border-color .3s var(--ease)}
/* The four links vanished here with nothing in their place: a phone visitor
   got a wordmark and a CTA, and four sections had no entry point above the
   fold. The panel reuses those same four destinations, so it cannot drift. */
/* OPAQUE, deliberately, and not the .72 glass the pill uses. The panel covers
   186x101px of a 62px headline, and at .94 with a backdrop blur the words read
   straight through it - measured, not guessed. The blur is no help here: .pill
   already has backdrop-filter, which makes it a stacking context, so a nested
   backdrop-filter samples the parent's ALREADY-FILTERED backdrop rather than
   the page, and does nothing. An interaction surface and an ambient layer must
   not compete for the same pixels; the border and shadow are what make the
   panel read as an object sitting above the page rather than as a rendering
   fault. */
.pill-menu{display:flex;flex-direction:column;gap:2px;position:absolute;top:calc(100% + 12px);right:0;min-width:186px;padding:9px;border:1px solid rgba(10,10,10,.09);border-radius:22px;background:var(--paper);box-shadow:0 1px 0 rgba(255,255,255,.7) inset,0 18px 44px -18px rgba(10,10,10,.34)}
.pill-menu a{padding:12px 15px;border-radius:15px;font-size:15px;transition:background .25s var(--ease)}
.pill-menu a:active{background:var(--wash)}
.hero{padding-top:116px}
.hero-copy{gap:20px}
.foot-cta{align-items:flex-start}
.foot-bottom{flex-direction:column;gap:10px}
}
@media (prefers-reduced-motion:reduce){
html{scroll-behavior:auto}
/* Scoped for the same reason as the rule above, and easy to miss: an
   unscoped copy in here would re-hide everything for the one reader who has
   both reduced motion on AND no JS. */
.js .reveal:not(.landed){opacity:0;transform:none}
.reveal.landed{transition:opacity .4s linear var(--d)}
.iso-scene,.glass,.gear svg,.pstep.lit .pipe-line,.glow,.pill-cta .dot{animation:none!important}
.svc-item.out,.svc-item.in{animation-duration:.01s}
.btn:hover{transform:none}
}

/* ── consent banner ───────────────────────────────── */
/* P5. Lives in site.css and not in legal.css because the banner is on every
   page, and it is the only new component in this phase that is.

   OPAQUE background, and that is a decision rather than a default. The nav
   pill next to it is `rgba(252,252,251,.72)` with a backdrop blur, and copying
   that here was the first draft. Two reasons it did not ship, both already
   established in this codebase:
     1. .pill-menu (site.css, <=767px block) is opaque for exactly this reason,
        and the note there is the general rule: "an interaction surface and an
        ambient layer must not compete for the same pixels". A banner asking
        for a legal decision is the strongest case of an interaction surface on
        this site.
     2. Contrast on a translucent surface is computed against whatever happens
        to be behind it, and behind this is the grillage canvas, which is
        DRAWN AT RUNTIME and moves. test-a11y.mjs holds six accepted pairings
        as exact {fg,bg,ratio} triples and a seventh fails the build. A surface
        whose composite depends on a canvas frame cannot be given an exact
        triple, so it could not be graded at all.
   Also cheaper: no backdrop-filter means no edge-clamp behaviour, which is the
   class of bug the carousel fade pass spent a round on. */
.consent{position:fixed;z-index:50;left:0;right:0;bottom:0;display:flex;justify-content:center;padding:0 var(--pad) clamp(14px,2vw,22px);pointer-events:none}
.consent-inner{pointer-events:auto;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:clamp(14px,2.4vw,40px);width:100%;max-width:var(--maxw);padding:clamp(15px,1.7vw,21px) clamp(17px,1.9vw,25px);border:1px solid rgba(10,10,10,.09);border-radius:var(--r-card);background:var(--paper);box-shadow:0 1px 0 rgba(255,255,255,.7) inset,0 18px 44px -18px rgba(10,10,10,.34)}
.consent-copy{display:flex;flex-direction:column;gap:7px;flex:1 1 300px;min-width:0}
/* Not .eyebrow, which is --muted on paper at 4.36:1 and one of the six
   contrast pairings Max accepted. Those six are a decision taken about a
   design that already existed; adding a SEVENTH node set to an accepted
   failure on the one component whose whole job is compliance would be a poor
   place to spend that allowance. --ink-70 on paper measures ~7:1. */
.consent-h{font:500 11px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ink-70)}
.consent-copy p{font-size:14.5px;line-height:1.5;color:var(--ink-70);max-width:64ch}
/* Underlined rather than accent-coloured. Accent on paper is 3.24:1, another
   of the six accepted pairings, and a link is the one place where colour must
   not be the only signal anyway. */
/* The hit area is grown, and NOT the banner. This link is the only route to
   /privacy while the banner is up, and it measured 18px tall at 375 - inside a
   component that already covers 223px of a 760px viewport, so making the banner
   itself any taller to fit a bigger target would trade one problem for a worse
   one. Equal and opposite margin keeps the text exactly where it was: the
   padding grows the box to ~45px, the negative margin gives the space back to
   the layout, so not one pixel moves and the line box does not reflow. */
.consent-link{color:var(--ink);text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--ink-35);
  display:inline-block;padding:12px 2px;margin:-12px -2px}
.consent-link:hover{color:var(--accent);text-decoration-color:var(--accent)}
/* Reject FIRST in source order and in the row, and both buttons identical in
   size, weight, border and background. A prominent Accept beside a quiet
   Decline is the single most enforced consent defect in Germany, and it is
   also just dishonest. If one of these ever grows a fill, the choice stops
   being a choice. 12px of vertical padding on a 21px line box clears the 44px
   tap target unaided, so no ::after hit box is needed here. */
.consent-acts{display:flex;gap:10px;flex:0 0 auto}
.consent-btn{padding:12px 22px;border:1px solid var(--ink-20);border-radius:var(--r-pill);background:transparent;color:var(--ink);font:inherit;font-size:14.5px;letter-spacing:-.008em;cursor:pointer;transition:border-color .3s var(--ease),background .3s var(--ease)}
.consent-btn:hover{border-color:var(--ink);background:var(--wash)}
.consent-btn:active{transform:translateY(1px);opacity:.9}
@media (max-width:480px){
/* At 375 the two buttons and the copy do not share a line. They get their own
   row and split it evenly, so neither reads as the default. */
.consent-acts{width:100%}
.consent-btn{flex:1 1 0;padding:12px 10px}
}
@media (prefers-reduced-motion:reduce){
.consent-btn:active{transform:none}
}
