/* ---------- refinements ----------
   Loaded last on every page. Everything here came out of the UI/UX audit and
   is deliberately kept out of the extracted legacy stylesheets so the split
   assets stay byte-identical to the original build and this file reads as the
   complete list of intentional changes.

   Scope: touch devices only, apart from the breadcrumb rule. Nothing here
   changes the desktop rendering. */

@media (pointer: coarse) {
  /* The audit measured these at 38-43px against the 44px comfort minimum
     (Apple HIG / Material). Growing them by a few pixels of padding costs no
     layout anywhere, because every one of them sits in a flex or grid row
     that is taller than the control itself. */
  .btn--sm {
    min-height: 44px;
    padding-block: 11px;
  }
  .sd-next a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
  .fav {
    height: 44px;
  }
  .lw-mail {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
}

/* Breadcrumbs on the article page were 12px tall — too small to hit reliably
   on any device, so this one is not gated behind a coarse pointer. The row
   keeps its height; only the links grow into it. */
.post-crumbs a {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding-inline: 2px;
}
@media (pointer: coarse) {
  .post-crumbs a { min-height: 44px; }
  .post-crumbs   { margin-bottom: 12px; }
}

/* ---------- website-redesign band: vertical balance ----------
   An earlier revision biased the copy 80px down here, to even out a capped
   panel that left bare white under the button. The full-bleed rule further down
   replaced that panel with a full-viewport one, which fixes the imbalance at the
   source — and the bias actively hurts now, because the JS centres the circle on
   the panel (`cy = h / 2`). Any offset applied to the copy alone pushes it off
   that centre, so the button drifts outside the circle mid-morph.

   The copy is therefore left centred, matching the circle. Kept as an explicit
   zero rather than deleted so the reasoning survives with the rule. */
@media (min-width: 691px) {
  .ri-on .ri-layer {
    padding-top: 0;
    padding-bottom: 0;
  }
}

/* ---------- pinned service stack: softer black, lighter lift ----------
   Panel 06 was `var(--ink)`, which is pure #000 in light mode. Against the
   white page that is harsher than anything else on the site — every other dark
   surface (the drawer, the dark theme's own background) is #111111 — so it now
   matches them.

   Scoped to light mode on purpose: in dark mode `--ink` flips to #FFFFFF and
   the panel deliberately inverts to a white card, which is correct and must
   not be overridden. */
html:not(.dark) .panel-6 { background: #111111; }

/* The six panels overlap, so each one's shadow falls on the card beneath and
   the lift reads far heavier than the token suggests — most visibly as a dark
   band under panel 06. Roughly half the opacity and a shorter throw keeps the
   stack's depth without the smudge. `--shadow-2` itself is left alone because
   the floating nav and the card hover states share it. */
.stack-panel {
  box-shadow: 0 1px 4px rgba(18, 16, 12, .03),
              0 8px 20px rgba(18, 16, 12, .05);
}

/* ---------- website-redesign band: full-bleed on desktop + tablet ----------
   The pinned panel was capped (min(84vh,620px), offset from the top), so on a
   777px-tall window it left a ~103px white strip under it. The morph is clipped
   to the panel, so the black circle stopped short of the viewport bottom and
   that strip stayed white through the whole animation.

   Extending the panel to the bottom of the viewport removes the strip: the
   circle now rises from below the fold and reaches the bottom edge. The morph
   maths needs no change — main.home.js derives both the rise distance and the
   final radius from the panel's own box (`cover = sqrt(w*w + h*h) * 1.03`), so
   a taller panel simply grows a bigger circle.

   The top offset is deliberately kept. core.css sets it so a sliver of page
   background stays above the band and the floating nav sits on that rather than
   on the black — with top:0 the glass nav renders over black and washes out to
   grey. So only the bottom is extended: same offset, height fills the rest.

   Phones (<=690px) keep the capped panel: there the section is short and a
   full-height pin costs more scroll than the effect is worth. */
@media (min-width: 691px) {
  .ri-on .ri-sticky {
    top: min(64px, 7vh);
    height: calc(100vh - min(64px, 7vh));
  }
}
@supports (height: 100dvh) {
  @media (min-width: 691px) {
    .ri-on .ri-sticky {
      top: min(64px, 7dvh);
      height: calc(100dvh - min(64px, 7dvh));
    }
  }
}

/* ---------- founder avatars: the "Meet" cue, in the pill ----------
   The custom cursor used to answer this hover with a 76px opaque disc reading
   "MEET", centred on the pointer — which put it directly over the name the
   hover had just revealed. The cue belongs to the pill, not the cursor: here it
   expands alongside the name, so it can never cover anything.

   aria-hidden because each avatar already carries an explicit aria-label
   ("<name> on LinkedIn"), which is the accessible name either way. */
.fav__cta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: 10px;
  padding-left: 10px;
  border-left: 1px solid rgba(255, 255, 255, .22);
  font: 600 10px/1 var(--font-ui);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
}
.fav__cta svg { flex: none; }

/* the pill has to fit the name plus the cue */
.fav.is-open .fav__name,
.fav:hover .fav__name,
.fav:focus-visible .fav__name { max-width: 320px; }

/* ---------- magnetic headings must not double when copied ----------
   effects.js clones the heading text into .mag__circle to drive the hover
   reveal. The clone is aria-hidden, so screen readers are fine, but a normal
   text selection still picks it up and every heading pastes twice. Excluding
   it from selection leaves the effect untouched and makes copy match what is
   on the screen. */
.mag__circle {
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

/* ---------- founder avatars carry the real photographs ----------
   .fav__mark was a lettered disc; the letter stays underneath as the fallback
   for a missing file, exactly as it works on the About page. The two of them
   now link into their own section there rather than out to LinkedIn. */
.fav__mark { position: relative; overflow: hidden; }
.fav__mark .portrait-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  border-radius: inherit;
}
.fav__mark:has(.portrait-img) > span { visibility: hidden; }

/* the anchors the homepage avatars land on should not sit under the fixed nav */
#johannes, #ashik { scroll-margin-top: clamp(90px, 12vh, 130px); }

/* ---------- offer pricing ----------
   Rendered by server/pricing.js so the reduction lives in one module. <del> and
   <ins> carry the meaning; the visual job here is to make the offer the figure
   the eye lands on, with the regular price legible but clearly secondary. */
.pricetag { display: inline-flex; align-items: baseline; flex-wrap: wrap; gap: 10px; }
.pricetag__was {
  order: 1;
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
  text-decoration-color: rgba(0, 0, 0, .35);
  color: var(--text-muted);
  font-weight: 400;
}
.pricetag__now { order: 2; text-decoration: none; color: inherit; }
.pricetag__off {
  order: 3;
  padding: 4px 9px;
  border-radius: var(--r-pill);
  background: var(--accent); color: var(--accent-ink);
  font: 600 11px/1 var(--font-ui); letter-spacing: .04em;
  white-space: nowrap;
}

/* the big price on a pricing tier: regular above, offer at full size below */
.amt .pricetag--amt { display: grid; grid-template-columns: auto auto; gap: 2px 10px; align-items: baseline; }
.amt .pricetag__was { grid-column: 1 / -1; font-size: .42em; line-height: 1.2; }
.amt .pricetag__now { grid-column: 1; }
.amt .pricetag__off { grid-column: 2; align-self: center; justify-self: start; }

/* inline "from €x" on the index cards and the service hero card */
.pricetag--from { gap: 7px; }
.svc-from .pricetag__was,
.sd-card__price .pricetag__was { font-size: .8em; }

/* No price currently renders on an ink ground — the "most popular" tier is
   white with a black border, not a dark card — so the light-on-dark variant is
   opt-in by class rather than assumed. Measured across every page that shows a
   price before writing this. */
.pricetag--on-dark .pricetag__was {
  color: rgba(255, 255, 255, .6);
  text-decoration-color: rgba(255, 255, 255, .45);
}

/* one line of context, so a struck price is never unexplained */
.price-offer-note {
  margin: 18px 0 0;
  font-size: 13px; line-height: 1.6;
  color: var(--text-muted);
}
.price-offer-note b { color: var(--ink); font-weight: 600; }
/* on the index the note leads the list rather than trailing a heading */
.price-offer-note--lead { margin: 0 0 22px; }

/* ---------- contact form: consent and honeypot ----------
   Mirrors the order form, which already had all three bot filters. */
.ct-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.ct-check {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 4px 0 6px;
  font-size: 13px; line-height: 1.55; color: var(--text-muted);
  cursor: pointer;
}
.ct-check input { flex: none; margin-top: 2px; width: 16px; height: 16px; accent-color: var(--ink); }
.ct-check a { text-decoration: underline; text-underline-offset: 2px; }
.ct-err { margin: 0 0 10px; font-size: 12.5px; color: #B42318; min-height: 0; }
.ct-note.is-error { color: #B42318; }


/* ---------- stock imagery, sized to the box ----------
   The panels render 600px wide on a desktop and 388px on a phone, so the 1200w
   file is right for one and three times too big for the other. Below 700px the
   800w set is used instead, which is still 2x for that box. */
@media (max-width: 700px) {
  .panel-media.m1{background-image:linear-gradient(0deg,rgba(22,21,20,.12),rgba(22,21,20,.12)),image-set(url('/images/stock/workspace-sm.webp') type('image/webp'),url('/images/stock/workspace-sm.jpg') type('image/jpeg'));}
  .panel-media.m2{background-image:linear-gradient(0deg,rgba(22,21,20,.12),rgba(22,21,20,.12)),image-set(url('/images/stock/meeting-sm.webp') type('image/webp'),url('/images/stock/meeting-sm.jpg') type('image/jpeg'));}
  .panel-media.m3{background-image:linear-gradient(0deg,rgba(22,21,20,.12),rgba(22,21,20,.12)),image-set(url('/images/stock/screens-sm.webp') type('image/webp'),url('/images/stock/screens-sm.jpg') type('image/jpeg'));}
  .panel-media.m4{background-image:linear-gradient(0deg,rgba(22,21,20,.12),rgba(22,21,20,.12)),image-set(url('/images/stock/desk-sm.webp') type('image/webp'),url('/images/stock/desk-sm.jpg') type('image/jpeg'));}
  .panel-media.m5{background-image:linear-gradient(0deg,rgba(22,21,20,.12),rgba(22,21,20,.12)),image-set(url('/images/stock/studio-sm.webp') type('image/webp'),url('/images/stock/studio-sm.jpg') type('image/jpeg'));}
  .panel-media.m6{background-image:linear-gradient(0deg,rgba(22,21,20,.12),rgba(22,21,20,.12)),image-set(url('/images/stock/analytics-sm.webp') type('image/webp'),url('/images/stock/analytics-sm.jpg') type('image/jpeg'));}
}

/* "Selected package" sat at 10.5px, below the 11px floor the rest of the site
   keeps for anything a person has to read. */
.order-choice__label { font-size: 11.5px; }

/* ---------- mobile nav: the switch belongs with the menu button ----------
   The bar is space-between with three visible children below 1000px — brand,
   language switch, hamburger — so the switch landed dead centre with 71px of
   nothing on either side. Mathematically even, but it read as a control that
   had come loose. Pushing it right groups the two things you can act on and
   leaves the brand alone on its side. */
@media (max-width: 999px) {
  .floatnav .langsw-root,
  .floatnav [role="group"][aria-label] { margin-left: auto; }
  .floatnav .hamburger { margin-left: 4px; }
}


/* ---------- the brand mark ----------
   Both marks were a gold gradient disc standing in for a logo. The anchor is
   the logo now; the box, size and radius are unchanged so nothing reflows. */
.brand-dot {
  background: url('/images/brand/mark.png') center / contain no-repeat !important;
}
