/* ============================================================
   Fabian Biedermann · shared stylesheet
   House rules: rem for container measures (never ch on a wrapper),
   one italic serif accent per headline, one accent color.
   ============================================================ */

:root{
  --bg:#FAFAF8; --bg-2:#F2F1ED; --ink:#0A0A0A; --ink-60:#5A5A56; --ink-30:#A8A8A2;
  --line:#E2E1DB; --accent:#E8461E; --dark:#0A0A0A; --dark-line:#232320; --dark-txt:#9C9C96;
  --pad:clamp(20px,5vw,72px); --maxw:1320px;
  --ease-out:cubic-bezier(.23,1,.32,1);
}

/* ---------- press feedback ----------
   Touch devices have no hover, so :active is the only signal that a tap
   registered. Compact controls scale; wide rows dim instead, because a 3%
   scale on a 1320px row is a visible 40px of shrink and reads as a glitch.
   .case presses its image, not the card: the card also carries .rv, whose
   transform would fight a transform here. */
.btn:active{transform:scale(.97)}
.burger{transition:transform .16s var(--ease-out)}
.burger:active{transform:scale(.92)}
.case:active .case-img img{transform:scale(.99)}
.art:active,.lnk:active,.crow a.v:active{opacity:.55}
.mmenu-in a:active{color:var(--accent)}
.lnk,.crow a.v{transition:opacity .16s var(--ease-out)}
/* Fonts come from Google Fonts, linked in the <head> of each page.
   The privacy policy discloses this. If it is ever self-hosted instead,
   drop the woff2 files in assets/fonts/, add @font-face here, and rewrite
   the "Fonts" section of privacy.html. */

*{margin:0;padding:0;box-sizing:border-box}
/* Deliberately auto. The anchor scroll on the work page is animated in JS so its
   duration can be controlled; the browser's own smooth scroll offers no timing
   control and would fight the animation frame by frame. */
html{scroll-behavior:auto}
body{background:var(--bg);color:var(--ink);font-family:Inter,system-ui,sans-serif;
  font-size:16px;line-height:1.55;-webkit-font-smoothing:antialiased;overflow-x:hidden}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--pad)}
em,.ac{font-family:'Instrument Serif',Georgia,serif;font-style:italic;font-weight:400;letter-spacing:-.01em}
a{color:inherit;text-decoration:none}
img,video,svg{max-width:100%}

/* ---------- type ---------- */
h1{font-size:clamp(2.9rem,7.4vw,6.6rem);line-height:.94;letter-spacing:-.045em;font-weight:500}
h2{font-size:clamp(2rem,4.4vw,3.9rem);line-height:1.02;letter-spacing:-.037em;font-weight:500}
h3{font-size:clamp(1.05rem,1.5vw,1.28rem);letter-spacing:-.02em;font-weight:600}
/* The serif accent in headlines carries the accent color. Scoped to h1 and h2
   on purpose: <em> also appears in body copy, which must stay ink.
   The .dark variants are listed because `.dark h2` outranks a bare `h2 em`. */
h1 em,h2 em,.dark h1 em,.dark h2 em{color:var(--accent)}
/* Emphasis inside body copy: full ink weight, no serif italic, no accent.
   Body copy sits at --ink-60, so the jump to --ink plus 500 does the work. */
.hi{color:var(--ink);font-weight:500}
.dark .hi{color:var(--bg)}
.eyebrow{font-size:.685rem;letter-spacing:.19em;text-transform:uppercase;color:var(--ink-60);font-weight:500}
.lead{font-size:clamp(1.02rem,1.42vw,1.24rem);line-height:1.55;color:var(--ink-60);max-width:56ch}
.body-txt{color:var(--ink-60);max-width:68ch}
.body-txt p+p{margin-top:1.15em}
.small{font-size:.82rem;color:var(--ink-60)}

/* ---------- nav ---------- */
nav{position:fixed;top:0;left:0;right:0;z-index:60;padding:20px 0;
  transition:background .35s,border-color .35s,padding .35s;border-bottom:1px solid transparent}
nav.solid{background:rgba(250,250,248,.88);backdrop-filter:blur(14px);border-color:var(--line);padding:13px 0}
/* The menu overlay is a sibling of .nav-in inside <nav>, so they compete for
   stacking order INSIDE nav. .nav-in must win, or the overlay covers the burger
   and swallows the click that would close it. */
.nav-in{display:flex;align-items:center;justify-content:space-between;gap:24px;
  position:relative;z-index:2}
.mark{font-weight:600;letter-spacing:-.03em;font-size:.95rem;line-height:1.05}
.mark span{display:block;color:var(--accent)}
.nav-links{display:flex;gap:34px;font-size:.76rem;letter-spacing:.13em;text-transform:uppercase;font-weight:500}
.nav-links a{position:relative;padding:3px 0;color:var(--ink-60);transition:color .2s}
.nav-links a::after{content:'';position:absolute;left:0;bottom:0;width:0;height:1px;background:var(--accent);transition:width .3s}
@media(hover:hover) and (pointer:fine){
  .nav-links a:hover{color:var(--ink)}.nav-links a:hover::after{width:100%}
}
.nav-links a.on::after{width:100%}
.btn{display:inline-flex;align-items:center;gap:9px;border:1px solid var(--ink);padding:11px 21px;
  border-radius:100px;font-size:.72rem;letter-spacing:.13em;text-transform:uppercase;font-weight:500;
  transition:background .25s,color .25s,border-color .25s,transform .16s var(--ease-out);
  white-space:nowrap;cursor:pointer}
.btn-a{border-color:var(--accent);color:var(--accent)}
@media(hover:hover) and (pointer:fine){
  .btn:hover{background:var(--ink);color:var(--bg)}
  .btn-a:hover{background:var(--accent);border-color:var(--accent);color:#fff}
}
/* Below 940px the links and CTA hide, so the burger takes over at exactly the
   same breakpoint. One number governs both, which is what stops the nav from
   ever being empty. */
nav .nav-links,nav .btn{display:none}
@media(min-width:940px){nav .nav-links{display:flex}nav .btn{display:inline-flex}}

/* ---------- mobile menu ---------- */
.burger{display:flex;flex-direction:column;justify-content:center;gap:6px;
  width:44px;height:44px;padding:0 9px;background:none;border:0;cursor:pointer;
  margin-right:-9px}
@media(min-width:940px){.burger{display:none}}
.burger span{display:block;height:1.5px;width:100%;background:var(--ink);border-radius:2px;
  transition:transform .32s cubic-bezier(.2,.7,.3,1),opacity .2s}
.on-dark .burger span{background:#fff}
.on-dark nav.solid .burger span{background:var(--ink)}
body.dark .burger span{background:#fff}
/* open state: top and bottom bars cross, middle one fades */
.burger[aria-expanded="true"] span:nth-child(1){transform:translateY(7.5px) rotate(45deg)}
.burger[aria-expanded="true"] span:nth-child(2){opacity:0;transform:scaleX(.2)}
.burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-7.5px) rotate(-45deg)}
.burger[aria-expanded="true"] span{background:#fff !important}

.mmenu{position:fixed;inset:0;z-index:1;background:var(--dark);
  display:flex;align-items:center;
  opacity:0;visibility:hidden;transition:opacity .35s,visibility .35s}
.mmenu.open{opacity:1;visibility:visible}
@media(min-width:940px){.mmenu{display:none}}
.mmenu-in{display:flex;flex-direction:column;gap:clamp(14px,2.6vh,26px);width:100%}
.mmenu-in a{font-size:clamp(2.1rem,9vw,3.2rem);line-height:1.05;letter-spacing:-.04em;
  font-weight:500;color:#fff;opacity:0;transform:translateY(14px);
  transition:opacity .4s,transform .4s,color .2s}
.mmenu.open .mmenu-in a{opacity:1;transform:none}
.mmenu.open .mmenu-in a:nth-child(1){transition-delay:.06s}
.mmenu.open .mmenu-in a:nth-child(2){transition-delay:.11s}
.mmenu.open .mmenu-in a:nth-child(3){transition-delay:.16s}
.mmenu.open .mmenu-in a:nth-child(4){transition-delay:.21s}
.mmenu.open .mmenu-in a:nth-child(5){transition-delay:.28s}
.mmenu-in a.on{color:var(--accent)}
@media(hover:hover) and (pointer:fine){.mmenu-in a:hover{color:var(--accent)}}
.mmenu-in .mmenu-cta{margin-top:clamp(18px,3vh,32px);padding-top:clamp(20px,3vh,30px);
  border-top:1px solid var(--dark-line);color:var(--accent);
  font-size:clamp(1.5rem,6vw,2.1rem)}
body.menu-open{overflow:hidden}

/* While the menu is open the nav bar sits ON TOP of it (z-index 60 vs 55), so the
   burger stays clickable as the close control. Its own background has to go, or a
   pale strip would cut across the dark menu, and both marks turn white. */
body.menu-open nav,body.menu-open nav.solid{background:transparent;
  backdrop-filter:none;border-color:transparent}
body.menu-open .mark{color:#fff}
body.menu-open .mark span{color:var(--accent)}
/* enlarge the X slightly so it reads as a close control, not a shrunken burger */
body.menu-open .burger{width:46px;height:46px}

/* nav over a dark hero (home only) */
.on-dark nav .mark,.on-dark nav .nav-links a{color:#fff}
.on-dark nav .mark span{color:var(--accent)}
.on-dark nav .nav-links a{color:rgba(255,255,255,.72)}
.on-dark nav .btn-a{border-color:rgba(255,255,255,.5);color:#fff}
@media(hover:hover) and (pointer:fine){
  .on-dark nav .btn-a:hover{background:#fff;color:#0A0A0A;border-color:#fff}}
.on-dark nav.solid .mark{color:var(--ink)}
.on-dark nav.solid .nav-links a{color:var(--ink-60)}
@media(hover:hover) and (pointer:fine){.on-dark nav.solid .nav-links a:hover{color:var(--ink)}}
.on-dark nav.solid .btn-a{border-color:var(--accent);color:var(--accent)}
@media(hover:hover) and (pointer:fine){.on-dark nav.solid .btn-a:hover{background:var(--accent);color:#fff}}

/* ---------- home hero, full bleed ---------- */
.hero{position:relative;min-height:100svh;display:flex;flex-direction:column;
  justify-content:flex-end;overflow:hidden;background:#0B0B0C;color:#fff;isolation:isolate}
.hero-bg{position:absolute;inset:0;z-index:-2}
.hero-bg video,.hero-bg img{width:100%;height:100%;object-fit:cover;display:block}
.hero::before{content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:
    linear-gradient(to top,rgba(6,6,7,.92) 0%,rgba(6,6,7,.62) 26%,rgba(6,6,7,.12) 58%,rgba(6,6,7,.34) 100%),
    linear-gradient(to right,rgba(6,6,7,.78) 0%,rgba(6,6,7,.30) 42%,rgba(6,6,7,0) 72%)}
/* Longhand only. This div also carries .wrap, and a `padding` shorthand here
   would wipe out .wrap's horizontal padding, leaving the hero text flush to the
   edge below 1320px. Bottom value scales with viewport height so the CTAs keep
   room before the brand ticker. */
.hero-in{padding-top:150px;padding-bottom:clamp(56px,11vh,120px);width:100%}
.hero h1{margin:20px 0 26px;max-width:15ch;text-wrap:balance}
.hero .lead{color:rgba(255,255,255,.80);max-width:52ch}
/* Sits over moving video, so the effective contrast changes frame to frame.
   Kept high rather than tuned to the darkest frame. */
.hero .eyebrow{color:rgba(255,255,255,.86)}
.hero-cta{display:flex;flex-wrap:wrap;gap:13px;margin:34px 0 0}
.hero .btn{border-color:rgba(255,255,255,.42);color:#fff}
.hero .btn-a{border-color:var(--accent);color:#fff;background:var(--accent)}
@media(hover:hover) and (pointer:fine){
  .hero .btn:hover{background:#fff;color:#0A0A0A;border-color:#fff}
  .hero .btn-a:hover{background:#fff;border-color:#fff;color:#0A0A0A}
}

/* ---------- subpage hero ---------- */
.phero{padding:clamp(140px,17vh,210px) 0 clamp(52px,7vw,86px);border-bottom:1px solid var(--line)}
.phero h1{margin:22px 0 0;max-width:17ch;text-wrap:balance}
.phero .lead{margin-top:28px}
.phero.dark-hero{background:var(--dark);color:var(--bg);border-color:var(--dark-line)}
.phero.dark-hero .eyebrow{color:rgba(255,255,255,.82)}
.phero.dark-hero .lead{color:#B4B4AE}

/* ---------- marquee ---------- */
.marq{border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:34px 0;overflow:hidden}
.marq-lab{text-align:center;margin-bottom:19px}
.track{display:flex;gap:52px;width:max-content;align-items:center}
/* Opt in rather than opt out. An endless auto-scroll is exactly what WCAG 2.2.2
   is about, so the animation is only ever declared for users who have not asked
   for less motion. They see a static row instead, clipped by .marq. */
@media(prefers-reduced-motion:no-preference){
  .track{animation:sc 46s linear infinite}
}
@keyframes sc{to{transform:translateX(-50%)}}
.track span{font-size:clamp(1.05rem,1.85vw,1.6rem);font-weight:600;letter-spacing:-.03em;
  color:var(--ink);white-space:nowrap;opacity:.72}
.track i{color:var(--accent);font-style:normal;font-size:.72rem;opacity:.85}
/* Logo marks: greyscale and dimmed so 14 different brand palettes read as one row.
   Each mark carries its own --s scale (set in main.js) so that letterforms end up
   optically equal instead of mathematically equal. A shared max-width stops any
   single wordmark from dominating the row. */
.track .logo{--logo-h:clamp(30px,3.4vw,44px);display:flex;align-items:center;justify-content:center;
  height:calc(var(--logo-h) * var(--s,1));max-width:clamp(110px,13vw,168px)}
/* No hover state: the row neither pauses nor changes, so the marks sit at full
   strength permanently instead of only rewarding a mouse. */
.track .logo img{height:100%;width:auto;max-width:100%;object-fit:contain;
  filter:grayscale(1) contrast(.95);opacity:1}
.dark .track .logo img{filter:grayscale(1) brightness(0) invert(1);opacity:.5}
.dark .marq{border-color:var(--dark-line)}
.dark .track span{color:var(--bg);opacity:.55}
.track-sm span{font-size:clamp(.85rem,1.2vw,1.05rem);font-weight:500;letter-spacing:.02em}

/* ---------- sections ---------- */
section{padding:clamp(76px,10vw,148px) 0}
section.tight{padding:clamp(56px,7vw,96px) 0}
/* rem, not ch: ch on a 16px wrapper resolves ~4x too narrow */
.head{max-width:min(100%,62rem);margin-bottom:clamp(44px,5.5vw,74px)}
.head h2{text-wrap:balance}
.head .eyebrow{display:block;margin-bottom:20px}
.split{display:grid;gap:44px}
@media(min-width:900px){.split{grid-template-columns:.95fr 1.05fr;gap:56px}}
.alt{background:var(--bg-2)}
.rule{height:1px;background:var(--line);border:0}

/* ---------- metrics ---------- */
.mets{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:var(--line);border:1px solid var(--line)}
@media(min-width:860px){.mets{grid-template-columns:repeat(4,1fr)}}
/* five-up: 2 on mobile, 3 on tablet, 5 across on desktop so none is orphaned */
@media(min-width:700px){.mets-5{grid-template-columns:repeat(3,1fr)}}
@media(min-width:1060px){.mets-5{grid-template-columns:repeat(5,1fr)}}
@media(min-width:1060px){.mets-5 .met b{font-size:clamp(2.2rem,3.4vw,3.1rem)}
  .mets-5 .met p{font-size:.79rem}}
.met{background:var(--bg);padding:clamp(26px,3.2vw,40px)}
.met b{display:block;font-size:clamp(2.5rem,5.2vw,4rem);line-height:.92;letter-spacing:-.05em;
  font-weight:500;color:var(--accent);margin-bottom:14px}
.met h3{margin-bottom:7px}
.met p{font-size:.83rem;color:var(--ink-60);line-height:1.5}

/* ---------- case cards (home) ---------- */
.cases{display:grid;gap:34px}
@media(min-width:820px){.cases{grid-template-columns:repeat(3,1fr)}}
.case-img{aspect-ratio:4/3;border-radius:4px;overflow:hidden;background:var(--bg-2);margin-bottom:19px}
.case-img img{width:100%;height:100%;object-fit:cover;transition:transform .8s cubic-bezier(.2,.7,.3,1)}
@media(hover:hover) and (pointer:fine){.case:hover .case-img img{transform:scale(1.045)}}
/* This one carries the client name, not a category, so it sits above body copy
   in the hierarchy. Weight 500 matters more than the last bit of contrast: at
   .68rem with .15em tracking, 400 renders as thin disconnected strokes. */
.case .lab{font-size:.68rem;letter-spacing:.15em;text-transform:uppercase;
  color:#3A3A37;font-weight:500;margin-bottom:9px}
.case h3{margin-bottom:9px}
.case p{font-size:.88rem;color:var(--ink-60);line-height:1.55;margin-bottom:15px}
.lnk{font-size:.71rem;letter-spacing:.14em;text-transform:uppercase;font-weight:500;
  display:inline-flex;gap:8px;align-items:center;color:var(--ink)}
.lnk .ar{color:var(--accent);transition:transform .3s}
@media(hover:hover) and (pointer:fine){.case:hover .lnk .ar,.lnk:hover .ar{transform:translateX(5px)}}
.dark .lnk{color:var(--bg)}
/* Two or more links in a row. Wraps to its own line on narrow screens instead
   of running the labels together. */
.lnks{display:flex;flex-wrap:wrap;gap:14px 34px}

/* ---------- full case entries (work page) ---------- */
/* scroll-margin keeps the fixed nav from covering the top of a case when it is
   reached through its anchor. */
.entry{padding:clamp(58px,7vw,104px) 0;border-bottom:1px solid var(--line);scroll-margin-top:92px}
.entry:last-of-type{border-bottom:0}
.entry-grid{display:grid;gap:38px}
@media(min-width:940px){.entry-grid{grid-template-columns:1.02fr .98fr;gap:64px;align-items:center}
  .entry:nth-child(even) .entry-media{order:-1}}
.entry-media{border-radius:4px;overflow:hidden;background:var(--bg-2);aspect-ratio:var(--ar,4/3)}
/* Case images all run portrait. Capped in height so a tall case cannot dwarf
   the page. An entry can still set --ar inline for a one-off ratio. */
.entry-media-tall{--ar:3/4;max-height:min(78vh,760px);margin-inline:auto}
.entry-media img,.entry-media video{width:100%;height:100%;object-fit:cover;display:block}
/* Set at --ink-60, not --ink-30. At .68rem uppercase with wide tracking the
   lighter grey only cleared 2.3:1 against the page, which is unreadable. */
.entry .lab{font-size:.68rem;letter-spacing:.15em;text-transform:uppercase;
  color:var(--ink-60);font-weight:500;margin-bottom:15px}
/* Client logo sitting on the label line. Height is fixed and width is free, so
   logos of very different proportions still share one optical baseline. The
   marks are solid black, and the opacity brings them down to roughly the weight
   of the label next to them, so the logo identifies without shouting. */
.lab-row{display:flex;align-items:center;gap:15px;margin-bottom:15px}
/* Divider hangs off the label, not the logo: an img is a replaced element and
   carries no pseudo-elements. Fixed height rather than a border, which would
   only be as tall as its own box and read as detached from the logo. */
.lab-row .lab{margin-bottom:0;padding-right:15px;position:relative}
.lab-row .lab::after{content:'';position:absolute;right:0;top:50%;
  transform:translateY(-50%);width:1px;height:20px;background:var(--line)}
/* One height for every mark. The files in logos/case/ are pre-normalised: each
   sits on a shared 78px canvas with its content scaled so a stacked lockup and
   a single-line wordmark carry the same optical weight here. Scaling by
   bounding box alone would make the wide wordmarks tower over the stacked ones. */
.clogo{height:32px;width:auto;flex:none;opacity:.62}
.dark .clogo{filter:invert(1);opacity:.72}
.entry h2{margin-bottom:24px;max-width:17ch;text-wrap:balance}
.ph{display:inline-block;margin-top:20px;font-size:.76rem;color:var(--accent);
  border:1px dashed rgba(232,70,30,.42);border-radius:4px;padding:9px 13px;background:rgba(232,70,30,.05)}
/* Case outcome numbers. Same idea as .mets on the home page but scaled down,
   because these sit inside a case column, not across the full grid. Two up is
   the cap: a third number dilutes the two that matter. */
.cstats{display:grid;gap:24px;margin-top:clamp(28px,3vw,38px);padding-top:26px;
  border-top:1px solid var(--line)}
@media(min-width:520px){.cstats{grid-template-columns:repeat(2,1fr);gap:34px}}
.cstat b{display:block;font-size:clamp(1.9rem,3.4vw,2.7rem);line-height:.95;letter-spacing:-.045em;
  font-weight:500;color:var(--accent);margin-bottom:9px}
.cstat p{font-size:.82rem;color:var(--ink-60);line-height:1.5}

/* ---------- pillars ---------- */
.pill{display:grid;gap:38px}
@media(min-width:760px){.pill{grid-template-columns:repeat(2,1fr);gap:44px 52px}}
@media(min-width:1120px){.pill{grid-template-columns:repeat(4,1fr)}}
.p-item{padding-top:22px;border-top:2px solid var(--ink)}
.p-item h3{margin-bottom:11px}
.p-item p{font-size:.88rem;color:var(--ink-60);line-height:1.6}
.p-num{font-size:.68rem;letter-spacing:.15em;color:var(--accent);margin-bottom:13px;font-weight:600}

/* ---------- numbered blocks (expertise / ai) ---------- */
.nums{display:grid;gap:0}
.num{display:grid;gap:18px;padding:clamp(34px,4vw,52px) 0;border-top:1px solid var(--line)}
@media(min-width:860px){.num{grid-template-columns:5rem 1fr;gap:44px;align-items:start}}
.num:last-child{border-bottom:1px solid var(--line)}
.num .n{font-size:.72rem;letter-spacing:.16em;color:var(--accent);font-weight:600;padding-top:6px}
/* h2 and h3 both styled: the expertise page needs h2 here because its blocks sit
   directly under the h1, while the AI page nests the same component under a
   section h2 and stays on h3. Same look, correct outline on both. */
.num h2,.num h3{font-size:clamp(1.3rem,2.3vw,1.85rem);letter-spacing:-.028em;font-weight:500;margin-bottom:13px}
.num p{color:var(--ink-60);max-width:62ch}
.dark .num{border-color:var(--dark-line)}
.dark .num p{color:var(--dark-txt)}
.dark .num h2,.dark .num h3{color:var(--bg)}

/* ---------- dark block ---------- */
.dark{background:var(--dark);color:var(--bg)}
.dark .eyebrow,.dark .lead,.dark p{color:var(--dark-txt)}
/* Light text on dark reads thinner than the same contrast ratio does on light,
   and these labels are small uppercase with wide tracking. Set above body copy
   so the label is never the weakest thing in the section. */
.dark .eyebrow{color:#C4C4BD}
.dark .head{max-width:min(100%,72rem)}
.dark h1,.dark h2,.dark h3{color:var(--bg)}
.dark .body-txt{color:var(--dark-txt)}
.ai-sub{display:grid;gap:32px;margin-top:clamp(44px,5vw,64px);padding-top:44px;border-top:1px solid var(--dark-line)}
@media(min-width:800px){.ai-sub{grid-template-columns:repeat(3,1fr);gap:44px}}
/* four-up variant: 2x2 on tablet, 4 across on desktop */
@media(min-width:700px){.ai-sub-4{grid-template-columns:repeat(2,1fr);gap:40px}}
@media(min-width:1060px){.ai-sub-4{grid-template-columns:repeat(4,1fr);gap:38px}}
.ai-sub h3{margin-bottom:10px}
.ai-sub p{font-size:.87rem;line-height:1.6}
.dark .btn{border-color:rgba(255,255,255,.4);color:#fff}
@media(hover:hover) and (pointer:fine){.dark .btn:hover{background:#fff;color:var(--ink)}}
.dark .btn-a{border-color:var(--accent);color:#fff;background:var(--accent)}
@media(hover:hover) and (pointer:fine){.dark .btn-a:hover{background:#fff;border-color:#fff;color:var(--ink)}}

/* ---------- articles ---------- */
.arts{border-top:1px solid var(--line)}
.art{display:grid;gap:8px;padding:27px 0;border-bottom:1px solid var(--line);
  transition:padding-left .35s,opacity .16s var(--ease-out)}
@media(min-width:800px){.art{grid-template-columns:1fr auto;align-items:center;gap:28px}}
@media(hover:hover) and (pointer:fine){.art:hover{padding-left:13px}}
.art h3{font-weight:500;letter-spacing:-.025em;font-size:clamp(1.15rem,2vw,1.6rem)}
.art .de{font-size:.8rem;color:var(--ink-60);margin-top:5px}
/* Accent text by deliberate choice. At .63rem the orange reaches 3.77:1 against
   the page and 1.4.3 asks for 4.5:1, so this is a known and accepted exception:
   the label only repeats what the article title already says in German. */
.tag{font-size:.63rem;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);
  border:1px solid var(--accent);padding:5px 11px;border-radius:100px;white-space:nowrap;justify-self:start}
.dark .arts,.dark .art{border-color:var(--dark-line)}
.dark .art .de{color:#93938C}

/* ---------- about ---------- */
/* Bio layout: a narrower image column than the standard .split, so the portrait
   supports the text instead of competing with it. Desktop only, stacks on mobile. */
@media(min-width:900px){.split-bio{grid-template-columns:.62fr 1.38fr;gap:clamp(44px,5vw,72px)}}
.ab-img{border-radius:4px;overflow:hidden;aspect-ratio:1/1;background:var(--bg-2);
  max-width:min(100%,24rem)}
.ab-img img{width:100%;height:100%;object-fit:cover;object-position:50% 18%}

/* ---------- contact ---------- */
.cinfo{display:grid;gap:0;margin-top:8px;border-top:1px solid var(--dark-line)}
.crow{display:grid;gap:5px;padding:22px 0;border-bottom:1px solid var(--dark-line)}
@media(min-width:700px){.crow{grid-template-columns:9rem 1fr;gap:28px;align-items:baseline}}
.crow .k{font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;color:#6E6E68;
  line-height:1.5}
/* Label break only applies once the row is two columns. Stacked on mobile the
   label already sits on its own line, so a second break there is just a gap. */
.brk{display:none}
@media(min-width:700px){.brk{display:inline}}
.crow .v{font-size:clamp(1.05rem,1.7vw,1.35rem);letter-spacing:-.02em;color:var(--bg)}
@media(hover:hover) and (pointer:fine){.crow a.v:hover{color:var(--accent)}}

/* ---------- legal pages ---------- */
.legal{max-width:min(100%,44rem);color:var(--ink-60)}
/* h2 in the markup: these are the top-level sections of the legal pages and sit
   directly under the h1. Size stays small on purpose, the global h2 scale would
   be far too loud for a privacy policy. */
.legal h2{color:var(--ink);font-size:1.02rem;letter-spacing:-.01em;font-weight:500;
  margin:clamp(34px,4vw,46px) 0 12px}
.legal h2:first-child{margin-top:0}
.legal p{margin-bottom:1em}
.legal a{border-bottom:1px solid var(--line);transition:border-color .2s}
@media(hover:hover) and (pointer:fine){.legal a:hover{border-color:var(--accent)}}
.legal .legal-date{margin-top:clamp(38px,4.5vw,54px);padding-top:22px;
  border-top:1px solid var(--line);font-size:.82rem;color:var(--ink-60)}

/* ---------- closing + footer ---------- */
.close h2{max-width:min(100%,34rem);margin-bottom:30px;text-wrap:balance}
.close-grid{display:grid;gap:34px;align-items:end}
@media(min-width:900px){.close-grid{grid-template-columns:1.25fr .75fr}}
footer{border-top:1px solid var(--dark-line);padding:44px 0;background:var(--dark);color:#9C9C96}
.f-in{display:flex;flex-wrap:wrap;gap:22px;justify-content:space-between;align-items:center;font-size:.73rem}
.f-nav{display:flex;flex-wrap:wrap;gap:24px;letter-spacing:.12em;text-transform:uppercase}
/* Smallest type on the site, uppercase and tracked out. Links sit above the
   copyright line so the clickable half is the more legible half. */
.f-nav a{color:#C4C4BD;transition:color .2s var(--ease-out)}
@media(hover:hover) and (pointer:fine){.f-nav a:hover{color:var(--bg)}}

/* ---------- reveal ---------- */
/* Scoped to .js so the whole site is not invisible when the script never
   arrives. The class is set by an inline snippet in <head> and dropped again by a
   watchdog timer if main.js fails to cancel it. */
.js .rv{opacity:0;transform:translateY(26px);transition:opacity .95s cubic-bezier(.2,.7,.3,1),transform .95s cubic-bezier(.2,.7,.3,1)}
.rv.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){
  .js .rv,.rv{opacity:1;transform:none;transition:none}
  html{scroll-behavior:auto}
}

/* ---------- focus + skip link ---------- */
/* Sits above the fixed nav. Hidden by transform rather than display or
   left:-9999px, so it stays in the accessibility tree and in the tab order. */
.skip{position:fixed;top:10px;left:10px;z-index:200;background:var(--ink);color:var(--bg);
  padding:12px 20px;border-radius:3px;font-size:.72rem;letter-spacing:.14em;
  text-transform:uppercase;font-weight:500;transform:translateY(-260%);
  transition:transform .18s var(--ease-out)}
.skip:focus{transform:none}

/* Visually hidden but announced. Used for the new-tab notice on external links. */
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
