/* ============================================================
   LAST HOPE TATTOO GALLERY — dark / blood red on black
   Type: Cinzel (display, engraved caps) · Space Grotesk (body)
   ============================================================ */
:root{
  --void:#0a0908; --panel:#100d0c; --ink2:#171312;
  --bone:#ddd6ca; --ash:#9a9188; --faint:rgba(221,214,202,.12);
  --blood:#b21622; --blood-2:#d21f2b; --oxblood:#6a0c13; --blood-glow:rgba(178,22,34,.45);
  --f-disp:"Cinzel",Georgia,serif; --f-body:"Space Grotesk",system-ui,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:auto}
body{background:var(--void);color:var(--bone);font-family:var(--f-body);-webkit-font-smoothing:antialiased;overflow-x:hidden}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
::selection{background:var(--blood);color:#fff}
h1,h2,h3,h4{font-family:var(--f-disp);font-weight:700;letter-spacing:.02em;text-transform:uppercase}

.grain{position:fixed;inset:0;pointer-events:none;z-index:60;opacity:.06;mix-blend-mode:screen;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>")}
.vig{position:fixed;inset:0;pointer-events:none;z-index:59;background:radial-gradient(130% 120% at 50% 40%, transparent 55%, rgba(0,0,0,.7))}

/* magnetic cursor */
.cursor{position:fixed;left:0;top:0;width:34px;height:34px;border:1px solid var(--blood-2);border-radius:50%;
  transform:translate(-50%,-50%);pointer-events:none;z-index:80;opacity:0;transition:width .25s,height .25s,background .25s,opacity .3s;mix-blend-mode:difference}
.cursor.hot{width:64px;height:64px;background:rgba(210,31,43,.15)}
.cursor-dot{position:fixed;left:0;top:0;width:5px;height:5px;background:var(--blood-2);border-radius:50%;transform:translate(-50%,-50%);pointer-events:none;z-index:80;opacity:0}
@media(hover:none){.cursor,.cursor-dot{display:none}}

.eyebrow{font-size:11px;letter-spacing:.44em;text-transform:uppercase;color:var(--ash)}

/* page-long blood thread — lives in the far-left gutter, never over text */
#vein{position:fixed;left:0;top:0;width:26px;height:100%;z-index:4;pointer-events:none;opacity:.6}

/* section chrome */
.sec-head{padding:0 clamp(18px,5vw,80px);margin-bottom:clamp(30px,5vh,60px)}
.sec-head .kicker{font-size:11px;letter-spacing:.36em;text-transform:uppercase;color:var(--blood-2);margin-bottom:14px}
.sec-head h2{font-size:clamp(40px,7vw,104px);line-height:.9}
.sec-head p{max-width:46ch;margin-top:18px;font-size:15px;line-height:1.6;color:var(--ash)}

/* ================= ARTISANS ================= */
.artisans{position:relative;background:var(--void);padding:clamp(70px,11vh,150px) 0 clamp(40px,7vh,90px);z-index:3}
.artist-grid{padding:0 clamp(18px,5vw,80px);display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(12px,1.6vw,24px)}
@media(max-width:900px){.artist-grid{grid-template-columns:repeat(2,1fr);gap:20px}}
@media(max-width:520px){.artist-grid{grid-template-columns:1fr}}
.artist{display:block;position:relative}
.artist .frame{display:block;position:relative;aspect-ratio:3/4;overflow:hidden;background:var(--ink2);border:1px solid var(--faint);clip-path:inset(0 0 100% 0);will-change:clip-path,transform}
/* Artist portraits render in colour (client decision, 2026-08-02) — no
   grayscale at rest or on hover. Same treatment as the portfolio .shot
   cards below, extended sitewide the same day. */
.artist .frame img{width:100%;height:100%;object-fit:cover;filter:contrast(1.05) brightness(.9);transition:filter .5s,transform .8s}
.artist:hover .frame img{filter:contrast(1.05);transform:scale(1.05)}
.artist .frame::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,transparent 55%, rgba(10,9,8,.85));pointer-events:none}
.artist .owner{position:absolute;left:12px;top:12px;z-index:2;font-size:10px;letter-spacing:.24em;text-transform:uppercase;color:var(--void);background:var(--blood-2);padding:4px 9px}
.artist .ig{position:absolute;right:12px;top:12px;z-index:2;width:30px;height:30px;border:1px solid rgba(221,214,202,.35);border-radius:50%;display:grid;place-items:center;opacity:0;transform:translateY(-4px);transition:.35s;background:rgba(10,9,8,.4)}
.artist:hover .ig{opacity:1;transform:translateY(0)}
.artist .ig svg{width:15px;height:15px}.artist .ig svg path{fill:var(--bone)}
.artist .meta{padding:16px 4px 0}
.artist .name{font-family:var(--f-disp);font-weight:700;font-size:clamp(24px,2.2vw,32px);line-height:1;text-transform:uppercase}
.artist:hover .name{color:var(--blood-2)}
.artist .style{font-family:var(--f-body);font-size:12px;letter-spacing:.05em;color:var(--ash);margin-top:6px}

/* ================= carousel mechanics — shared by the featured carousel
   below and by artist-page portfolio grids (assets/artist.js's shotFig
   builds .shot figures; assets/site.css is loaded on artist pages too).
   The per-artist "Mehr Stile" carousels that used to live here (.work,
   .car-head and friends) were removed 2026-08-02 along with #team-work —
   see PROJECT_STATUS.md §2b decision 8 and §5 Batch 5. Do not reintroduce
   a second homepage portfolio; the featured carousel is the only one. ================= */
.carousel{margin-bottom:clamp(40px,6vh,72px)}
.car-nav{display:flex;gap:8px}
.car-nav button{width:40px;height:40px;border:1px solid var(--faint);background:transparent;color:var(--bone);cursor:pointer;transition:.25s;font-size:16px;display:grid;place-items:center}
.car-nav button:hover{background:var(--blood);border-color:var(--blood);color:#fff}
.carousel .track{display:flex;gap:clamp(10px,1.2vw,16px);overflow-x:auto;padding:0 clamp(18px,5vw,80px);
  scroll-snap-type:x proximity;scroll-padding-left:clamp(18px,5vw,80px);scrollbar-width:none;cursor:grab}
.carousel .track::-webkit-scrollbar{display:none}
.carousel .track.drag{cursor:grabbing;scroll-snap-type:none}
/* Portfolio work renders in its true colours at rest (client decision,
   2026-08-02) — no grayscale here or on .artist/.ahero-portrait above/
   elsewhere. Premium comes from composition, spacing and motion, not from
   hiding colour. Hover/interaction behaviour (contrast bump, scale-up,
   gradient reveal) is unchanged. */
.shot{position:relative;flex:0 0 auto;width:clamp(230px,24vw,330px);aspect-ratio:3/4;overflow:hidden;background:var(--ink2);border:1px solid var(--faint);scroll-snap-align:start;will-change:transform}
.shot img{width:100%;height:100%;object-fit:cover;filter:contrast(1.05) brightness(.9);transition:filter .6s,transform .9s;pointer-events:none}
.shot:hover img{filter:contrast(1.06);transform:scale(1.05)}
.shot::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,transparent 65%,rgba(10,9,8,.6));opacity:0;transition:.4s;pointer-events:none}
.shot:hover::after{opacity:1}

/* ================= REVIEWS ================= */
.reviews{position:relative;background:var(--void);padding:clamp(60px,10vh,140px) 0 clamp(50px,8vh,110px);z-index:3;border-top:1px solid var(--faint)}
.rev-grid{padding:0 clamp(18px,5vw,80px);display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,1.6vw,22px)}
@media(max-width:1000px){.rev-grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:640px){.rev-grid{grid-template-columns:1fr}}
.rev{position:relative;background:var(--panel);border:1px solid var(--faint);padding:clamp(22px,2.6vw,32px);
  display:flex;flex-direction:column;gap:12px;transition:border-color .3s}
.rev:hover{border-color:rgba(221,214,202,.28)}
.rev .rv-s{color:var(--blood-2);font-size:12px;letter-spacing:.16em}
.rev .rv-q{font-size:15px;line-height:1.7;color:#c9c2b7}
.rev .rv-tr{font-size:12.5px;line-height:1.6;color:var(--ash);font-style:italic}
.rev .rv-by{margin-top:auto;padding-top:6px;font-family:var(--f-disp);font-size:13px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--bone)}
.rev .rv-when{font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--ash);margin-top:5px}

/* ================= FAQ — studio-level content only (client decision, 2026-08-02).
   Native <details>, no JS — static markup in each locale's HTML so the content
   is present in the page source, not built by assets/site.js (see
   PROJECT_STATUS.md §11.3 on JS-rendered content being a technical-SEO risk).
   This ruleset used to live in assets/artist.css as .afaq, back when FAQ was
   an artist-page module; moved here unchanged, renamed, when that module was
   retired. ================= */
.faq{position:relative;background:var(--panel);padding:clamp(60px,10vh,130px) 0;z-index:3;border-top:1px solid var(--faint)}
.faq-list{padding:0 clamp(18px,5vw,80px);max-width:70ch;display:flex;flex-direction:column;gap:2px}
.faq-list details{border-top:1px solid var(--faint);padding:18px 0}
.faq-list details:last-child{border-bottom:1px solid var(--faint)}
.faq-list summary{cursor:pointer;font-family:var(--f-disp);font-size:16px;text-transform:uppercase;letter-spacing:.02em;
  list-style:none;display:flex;justify-content:space-between;align-items:center;gap:16px;color:var(--bone)}
.faq-list summary::-webkit-details-marker{display:none}
.faq-list summary::after{content:"+";font-family:var(--f-body);font-size:20px;color:var(--blood-2);flex:0 0 auto;transition:transform .25s}
.faq-list details[open] summary::after{transform:rotate(45deg)}
.faq-list p{margin-top:14px;font-size:14.5px;line-height:1.7;color:#c3bcb1;max-width:60ch}
/* Two columns from tablet-landscape up — the 17-entry list otherwise reads
   as one long scroll on wide viewports where there's room to spare. Pure
   CSS columns (order/DOM untouched, so the FAQPage JSON-LD parity check
   above is unaffected); each entry keeps its own border-top/bottom rules. */
@media(min-width:900px){
  .faq-list{max-width:1180px;columns:2;column-gap:clamp(32px,4vw,64px)}
  .faq-list details{break-inside:avoid}
}

/* ================= BOOK ================= */
.book{position:relative;background:var(--panel);padding:clamp(70px,12vh,170px) clamp(18px,5vw,80px);z-index:3;overflow:hidden;border-top:1px solid var(--faint)}
.book .glow{position:absolute;width:80vw;height:80vw;left:-25vw;bottom:-40vw;border-radius:50%;background:radial-gradient(circle,var(--blood-glow),transparent 62%);pointer-events:none}
.book-inner{position:relative;max-width:1100px}
.book .kicker{font-size:11px;letter-spacing:.36em;text-transform:uppercase;color:var(--blood-2)}
.book h2{font-size:clamp(44px,8vw,132px);line-height:.9;margin:12px 0 20px}
.book .sub{max-width:56ch;font-size:clamp(15px,1.6vw,18px);line-height:1.65;color:#c3bcb1}
.ctas{display:flex;gap:14px;flex-wrap:wrap;margin-top:34px}
.btn{display:inline-flex;align-items:center;gap:10px;padding:16px 28px;font-size:12px;letter-spacing:.18em;text-transform:uppercase;font-weight:600;transition:transform .25s,background .25s,color .25s;border:1px solid transparent;font-family:var(--f-body)}
.btn-blood{background:var(--blood);color:#fff}.btn-blood:hover{transform:translateY(-3px);background:var(--blood-2)}
.btn-ghost{border-color:var(--faint);color:var(--bone)}.btn-ghost:hover{border-color:var(--bone)}
.walkin{margin-top:36px;display:inline-flex;align-items:center;gap:12px;font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:var(--ash);border-top:1px solid var(--faint);padding-top:22px}
.walkin b{color:var(--blood-2)}

/* ================= FOOTER ================= */
.foot{position:relative;background:var(--void);padding:clamp(60px,9vh,120px) clamp(18px,5vw,80px) 40px;z-index:3;border-top:1px solid var(--faint)}
.foot-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr;gap:40px}
@media(max-width:820px){.foot-grid{grid-template-columns:1fr 1fr}.foot-brand{grid-column:1/-1}}
@media(max-width:520px){.foot-grid{grid-template-columns:1fr}}
.foot-brand .fmark{display:flex;align-items:center;gap:16px}
.foot-brand .fmark img{width:52px;height:auto;filter:drop-shadow(0 0 16px rgba(178,22,34,.3))}
.foot-brand .fmark .txt{font-family:var(--f-disp);font-weight:700;font-size:clamp(26px,4vw,40px);line-height:.9;text-transform:uppercase}
.foot-brand p{margin-top:18px;max-width:38ch;font-size:14px;line-height:1.6;color:var(--ash)}
.foot h3{font-family:var(--f-body);font-size:10px;letter-spacing:.26em;text-transform:uppercase;color:var(--ash);margin-bottom:14px}
.foot ul{list-style:none;display:flex;flex-direction:column;gap:10px;font-size:15px;color:#c3bcb1}
.foot ul a:hover{color:var(--blood-2)}
.foot .socials{display:flex;gap:12px;margin-top:8px}
.foot .socials a{width:40px;height:40px;border:1px solid var(--faint);border-radius:50%;display:grid;place-items:center;transition:.25s}
.foot .socials a:hover{background:var(--blood);border-color:var(--blood)}
.foot .socials a:hover svg path{fill:#fff}
.foot .socials svg{width:17px;height:17px}.foot .socials svg path{fill:var(--bone)}
.legal{margin-top:clamp(40px,6vh,80px);padding-top:20px;border-top:1px solid var(--faint);display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--ash)}
.legal a{transition:color .2s}
.legal a:hover{color:var(--blood-2)}

/* ================= LEGAL PAGES — Impressum / Datenschutz (root-level
   utility pages, scoped to body[data-page="legal"]; reused .sec-head-style
   eyebrow/h1 pattern, plain prose otherwise). Do not let this bleed into
   any other page's typography. ================= */
.legal-doc{position:relative;padding:clamp(90px,14vh,160px) clamp(18px,5vw,80px) clamp(70px,10vh,120px);max-width:760px;margin:0 auto}
.legal-doc h1{font-size:clamp(34px,5vw,56px);line-height:1.05;margin-top:14px}
.legal-doc .legal-updated{font-size:12px;letter-spacing:.04em;color:var(--ash);margin-top:14px;margin-bottom:clamp(40px,6vh,64px);line-height:1.6}
.legal-doc section{margin-bottom:clamp(30px,5vh,48px)}
.legal-doc h2{font-family:var(--f-disp);font-size:18px;letter-spacing:.02em;text-transform:uppercase;margin-bottom:14px;color:var(--bone)}
.legal-doc p{font-size:14.5px;line-height:1.75;color:#c3bcb1;margin-bottom:12px}
.legal-doc p:last-child{margin-bottom:0}
.legal-doc address{font-style:normal;font-size:14.5px;line-height:1.75;color:#c3bcb1}
.legal-doc a{text-decoration:underline;color:var(--bone);transition:color .2s}
.legal-doc a:hover{color:var(--blood-2)}
.legal-back{display:inline-block;margin-top:clamp(20px,3vh,32px);font-family:var(--f-disp);font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--ash);border:1px solid var(--faint);padding:12px 20px;text-decoration:none !important;transition:.25s}
.legal-back:hover{border-color:var(--blood-2);color:var(--bone)}

@media(prefers-reduced-motion:reduce){
  .artist .frame{clip-path:none !important}
  #vein{display:none}
}

/* ================= language switch ================= */
.langsw{border:1px solid var(--faint);padding:4px 9px;letter-spacing:.14em;transition:border-color .25s,color .25s}
.langsw:hover{border-color:var(--bone);color:var(--bone)}

/* ================= book hint line ================= */
.book-hint{font-size:13px;color:var(--ash);letter-spacing:.06em;line-height:1.6;margin-bottom:24px;max-width:48ch}

/* ================= sticky mobile contact bar ================= */
.stickybar{position:fixed;left:0;right:0;bottom:0;z-index:70;display:none;gap:8px;
  padding:10px 12px calc(10px + env(safe-area-inset-bottom,0px));
  background:linear-gradient(0deg,rgba(10,9,8,.97),rgba(10,9,8,.86));
  border-top:1px solid var(--faint);backdrop-filter:blur(6px);
  transform:translateY(115%);transition:transform .38s cubic-bezier(.4,0,.2,1)}
.stickybar.show{transform:translateY(0)}
.stickybar a{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:14px 10px;font-family:var(--f-body);font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;font-weight:600;text-align:center}
.stickybar .sb-wa{background:var(--blood);color:#fff}
.stickybar .sb-wa svg{width:17px;height:17px;fill:#fff;flex:0 0 auto}
.stickybar .sb-quiz{border:1px solid var(--faint);color:var(--bone)}
@media(max-width:820px){
  .stickybar{display:flex}
  .foot{padding-bottom:104px}
}
@media(prefers-reduced-motion:reduce){
  .stickybar{transform:none;transition:none}
}

/* ============================================================
   HERO — full-bleed studio image/video, cinematic text overlay.
   One layout for mobile and desktop: the final studio-tour clip's
   aspect ratio isn't known yet, so the hero doesn't assume portrait
   (a split panel, as this used to be, only suits a 9:16 source).
   ============================================================ */
.shero{position:relative;height:100svh;display:flex;flex-direction:column;justify-content:flex-end;
  z-index:3;overflow:hidden;background:var(--void)}
.shero-media{position:absolute;inset:0;z-index:0;background:var(--void)}
.shero-media img,.shero-media video{width:100%;height:100%;object-fit:cover;object-position:50% 22%;display:block}
/* On narrow/tall viewports, `cover` on this near-square photo crops well
   over half its width to fill the height — exactly the amount that clips
   the "Your Last Hope" mural out of frame. `contain` instead shows the
   whole photo (top-anchored, since that's where the mural is); the empty
   strip below blends into the void background and the existing bottom
   gradient, so it reads as a deliberate frame, not a shrunken photo. */
@media(max-width:700px){
  .shero-media img,.shero-media video{object-fit:contain;object-position:50% 0%}
  /* `contain` leaves a letterbox strip below the photo — measured 49px at 360x780,
     77px at 390x844 and 137px at 430x932, i.e. it gets WORSE on larger phones (the
     photo's height follows the viewport's width, the gap follows its height). Two
     separate problems: the strip is dead space, AND the photo stops at a hard
     horizontal edge. Filling the strip alone doesn't help — the edge still reads.

     Fix, using no new media (same file, same single request):
     1. Size the <img> to its own aspect ratio at the top instead of `contain`-ing it
        inside a full-height box. Geometrically identical for this near-square photo
        (measured: 331.8px both ways at 360w) but it makes the element box equal the
        photo, so a mask can be positioned against the photo rather than the viewport.
     2. Feather the photo's bottom edge with a mask so it dissolves instead of cutting.
     3. Put a blurred, darkened copy of the same photo behind it, so what it dissolves
        INTO is a soft continuation rather than flat black.
     `z-index:-1` paints the backdrop above .shero-media's own background but below the
     <img> — works because .shero-media has z-index:0 and establishes a stacking
     context. scale() overfills so the blur doesn't bleed transparent edges.
     Desktop is untouched: this whole block is mobile-only. */
  .shero-media img{position:absolute;top:0;left:0;width:100%;height:auto;object-fit:fill;
    -webkit-mask-image:linear-gradient(180deg,#000 72%,rgba(0,0,0,.55) 88%,transparent 100%);
    mask-image:linear-gradient(180deg,#000 72%,rgba(0,0,0,.55) 88%,transparent 100%)}
  /* The blurred backdrop must match whatever photo the hero above it uses, or
     mobile shows one room dissolving into a different one. Pages that set a
     different hero image pass their own via --hero-bg on .shero-media; the
     fallback is the homepage's lounge photo. */
  .shero-media::before{content:"";position:absolute;inset:0;z-index:-1;
    background:var(--hero-bg,url("../images/studio-raum-last-hope-tattoo-frankfurt.webp")) center/cover no-repeat;
    filter:blur(30px) brightness(.72) saturate(.85);transform:scale(1.2)}
}
.shero-media video{position:absolute;inset:0;opacity:0;transition:opacity 1.1s ease}
.shero-media video.on{opacity:1}
.shero-media::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(10,9,8,.5) 0%,rgba(10,9,8,.14) 32%,rgba(10,9,8,.58) 64%,rgba(10,9,8,.96) 92%,var(--void) 100%)}

/* ---- Homepage hero: top scrim behind the navigation (2026-08-23) ---------
   The homepage hero photo has the studio's own "Your Last Hope" mural across
   its upper third — large pale-grey gothic lettering, sitting exactly where
   the nav sits. Bone text at 11px over those strokes was legible-ish but
   fighting them; the sitewide .shero-media::after gradient only reaches ~.44
   at that height, which is not enough against a mid-grey.

   This is a SCRIM, not a bar, and the difference is entirely in the falloff:
   the stops below trace an ease-out curve over a band far taller than the nav
   itself, so there is no edge anywhere for the eye to read as a navbar. Two
   rules keep it that way if it is ever retuned — the band must stay
   substantially taller than the nav, and no two adjacent stops should jump
   far enough to become a visible line.

   Scoped to the homepage on purpose. Walk-In has its own art-directed scrim
   tuned to the pale-skin back photo (see body[data-page="walkin"] below) and
   would double-darken; Consultation's hero has no comparable lettering.
   z-index 1 puts it above .shero-media (0) and below .topbar/.shero-mark-link
   (both 2). position:absolute keeps it out of .shero's flex flow. */
body[data-page="home"] .shero::before{
  content:"";position:absolute;left:0;right:0;top:0;
  height:clamp(150px,21vh,240px);z-index:1;pointer-events:none;
  background:linear-gradient(180deg,
    rgba(10,9,8,.60) 0%,
    rgba(10,9,8,.55) 14%,
    rgba(10,9,8,.46) 28%,
    rgba(10,9,8,.35) 43%,
    rgba(10,9,8,.23) 58%,
    rgba(10,9,8,.13) 73%,
    rgba(10,9,8,.05) 87%,
    rgba(10,9,8,0) 100%)}
.shero-inner{position:relative;z-index:2;display:flex;flex-direction:column;
  padding:0 clamp(18px,5vw,80px) clamp(30px,6vh,64px);gap:clamp(14px,2.4vh,26px)}
.shero .eyebrow{opacity:.95;text-shadow:0 1px 3px rgba(0,0,0,.9), 0 2px 18px rgba(0,0,0,.85)}
.shero h1{font-family:var(--f-disp);font-weight:700;text-transform:uppercase;letter-spacing:.01em;
  font-size:clamp(34px,6.4vw,84px);line-height:1.02;max-width:18ch;
  text-shadow:0 2px 34px rgba(0,0,0,.85)}
.shero h1 em{font-style:normal;color:var(--blood-2)}
.shero-sub{font-size:clamp(13px,1.5vw,17px);line-height:1.6;color:#c9c2b7;max-width:56ch;
  text-shadow:0 1px 18px rgba(0,0,0,.8)}
.shero .ctas{margin-top:2px}
/* ---- hero wordmark, and the Home link wrapping it ------------------------
   The mark is now an anchor back to the locale home. Positioning lives on the
   anchor; the <img> keeps only its own size/treatment, so the two never fight
   over `transform`.

   That split matters: the load animation sets `transform` on the ANCHOR with
   fill-mode `both`, and a finished animation's value beats a plain declaration
   in the cascade — so a hover `transform` on the same element would silently
   never apply. Hover therefore moves the IMG instead. Don't merge these back
   into one element.

   The mark used to be animated by a `gsap.from(".shero-mark", …)` line in
   assets/site.js. That was removed in favour of this CSS: it only ever ran on
   the homepage (walk-in and consultation don't load site.js), so the same logo
   animated on one page and appeared instantly on two others. CSS gives all
   three hero pages identical behaviour with no JS. */
.shero-mark-link{position:absolute;top:clamp(16px,3vw,34px);left:clamp(18px,5vw,80px);z-index:2;
  display:block;line-height:0;
  animation:lh-mark-in 620ms cubic-bezier(.22,.61,.36,1) both}
.shero-mark-link:focus-visible{outline:2px solid var(--blood-2);outline-offset:6px}
/* Sized up 2026-08-22 (client: the mark read as too small/incidental for a
   studio whose monogram is etched on its own shopfront window). Same clamp
   shape, ~28% larger at every stop; still well clear of .topbar on the right
   at 360px, which is the width that constrains it. */
/* Two shadows, not one: the wide soft one lifts the mark off the photograph
   generally, the tight 3px one gives it an actual edge. That edge matters
   because on the homepage the mark lands on the studio's own gothic mural —
   white strokes over grey strokes of a similar shape — where a soft glow
   alone leaves the two reading as one texture. Added 2026-08-23; no size,
   colour or position change. */
.shero-mark{display:block;width:clamp(74px,7.6vw,108px);height:auto;opacity:.95;
  filter:drop-shadow(0 2px 10px rgba(0,0,0,.9)) drop-shadow(0 0 3px rgba(0,0,0,.8));
  transition:transform .45s cubic-bezier(.22,.61,.36,1),opacity .45s,filter .45s}
.shero-mark-link:hover .shero-mark{transform:scale(1.045);opacity:1;
  filter:drop-shadow(0 3px 18px rgba(178,22,34,.5)) drop-shadow(0 0 3px rgba(0,0,0,.55))}
@keyframes lh-mark-in{from{opacity:0;transform:scale(.94)}to{opacity:1;transform:scale(1)}}
@media(prefers-reduced-motion:reduce){
  .shero-mark-link{animation:none}
  .shero-mark{transition:none}
  .shero-mark-link:hover .shero-mark{transform:none}
}

/* The Shop Life split-screen hero override that used to live here was REMOVED
   2026-08-22 (client direction: the photo-beside-text layout read as awkward).
   That page has no .shero at all any more — it opens with .topbar-solid plus
   a .slife-hero title block, like the style pages. See the Shop Life section
   further down for its current layout. */

/* ---- Walk-In hero — art-directed, page-scoped (2026-08-22) ---------------
   This page takes paid traffic, so the hero is treated as a landing-page
   asset rather than a decorative band. The photograph is a fully tattooed
   back with a Madonna at its centre; the tattoo work is the subject, not the
   person, so the crops deliberately place the head outside the frame.

   Two SOURCE crops, chosen by <picture> media in the markup, NOT one file
   squeezed by object-fit at every size:
     ≥901px  -wide-*  3:2 landscape, centred on the Madonna, shoulders kept
     ≤900px  (base)   3:4 portrait, top 420px of the original dropped
   object-position then does the small remaining adjustment per breakpoint.
   Without this the site default would apply — and that default is written for
   the near-square studio photo: below 700px it switches to object-fit:contain
   with a feathered mask and a blurred backdrop copy, which on this portrait
   photo would letterbox the tattoo instead of filling the screen. Every part
   of that treatment is therefore switched off here. */
body[data-page="walkin"] .shero-media picture{display:block;width:100%;height:100%}
body[data-page="walkin"] .shero-media img{
  width:100%;height:100%;object-fit:cover;
  /* Bias upward: cover crops height on a wide viewport, and the Madonna's
     halo is the first thing to go if this sits at 50%. */
  object-position:50% 42%}
/* Tablet — the portrait crop is already tighter; hold the composition centred. */
@media(max-width:900px){
  body[data-page="walkin"] .shero-media img{
    position:static;height:100%;object-fit:cover;object-position:50% 40%;
    -webkit-mask-image:none;mask-image:none}
  body[data-page="walkin"] .shero-media::before{display:none}
}
/* Phone — tallest viewport, least horizontal room. Pulled higher again so the
   Madonna clears the text block, which occupies the bottom half here. */
@media(max-width:640px){
  body[data-page="walkin"] .shero-media img{object-position:50% 28%}
}
/* Lighter than the sitewide hero scrim, which is authored for a room photo
   and would flatten the black-and-grey shading. Near-clear through the middle
   where the tattoo is; weight only at the top (nav/logo) and the bottom
   (headline, facts, CTAs). */
body[data-page="walkin"] .shero-media::after{
  background:linear-gradient(180deg,
    rgba(10,9,8,.42) 0%, rgba(10,9,8,.08) 24%, rgba(10,9,8,.12) 46%,
    rgba(10,9,8,.66) 74%, rgba(10,9,8,.95) 91%, var(--void) 100%)}
/* On a phone the text block starts around 42% of the viewport, not 74%, so the
   desktop ramp leaves the headline sitting on bare pale skin. Ramps earlier and
   harder here — this only covers the lower back (the belt-line lettering), the
   Madonna stays in the clear zone above it. */
@media(max-width:640px){
  body[data-page="walkin"] .shero-media::after{
    background:linear-gradient(180deg,
      rgba(10,9,8,.5) 0%, rgba(10,9,8,.12) 15%, rgba(10,9,8,.12) 33%,
      rgba(10,9,8,.68) 52%, rgba(10,9,8,.9) 70%, rgba(10,9,8,.97) 88%, var(--void) 100%)}
}

/* This photograph is mostly PALE skin, so light-on-dark text treatments that
   work over the studio-room heroes wash out here. Three targeted fixes rather
   than darkening the whole image (which would flatten the black-and-grey
   shading the page is selling): */
/* 1. The eyebrow is small, wide-tracked and lands squarely on bare skin — it
      gets the same dark chip as the facts pills below it. */
body[data-page="walkin"] .shero .eyebrow{display:inline-block;width:fit-content;
  padding:7px 13px;background:rgba(10,9,8,.5);backdrop-filter:blur(3px);
  border:1px solid rgba(221,214,202,.16);color:var(--bone);
  letter-spacing:.3em;text-shadow:0 1px 3px rgba(0,0,0,.9)}
/* 2. Tight dense shadows under the display type. The sitewide one is a single
      wide 34px blur, which disappears against busy midtones. */
body[data-page="walkin"] .shero h1{
  text-shadow:0 1px 2px rgba(0,0,0,.75), 0 3px 22px rgba(0,0,0,.92)}
body[data-page="walkin"] .shero-sub{color:#d5cec4;
  text-shadow:0 1px 2px rgba(0,0,0,.8), 0 2px 16px rgba(0,0,0,.9)}
/* 3. The nav sits over the brightest part of the frame at every breakpoint. */
body[data-page="walkin"] .topbar nav a{text-shadow:0 1px 3px rgba(0,0,0,.95), 0 2px 14px rgba(0,0,0,.85)}

/* Offer facts inside the hero. Ad traffic has to see "Saturday" and the
   starting price without scrolling; the .wi-strip below the fold is not
   enough on a phone. €80 is always labelled a STARTING price here — never
   presented as what a given tattoo costs. */
.wi-hero-facts{list-style:none;display:flex;flex-wrap:wrap;gap:9px 12px;margin:4px 0 0}
.wi-hero-facts li{display:inline-flex;align-items:baseline;gap:8px;
  padding:9px 15px;border:1px solid rgba(221,214,202,.26);
  background:rgba(10,9,8,.46);backdrop-filter:blur(3px);
  font-size:11.5px;letter-spacing:.13em;text-transform:uppercase;color:#c9c2b7}
.wi-hero-facts b{color:var(--blood-2);font-weight:600;letter-spacing:.1em}
@media(max-width:400px){ .wi-hero-facts li{padding:8px 12px;font-size:10.5px} }

/* ---- hero peek strip -----------------------------------------------------
   Three real tattoo thumbnails inside the hero, below the CTAs. Both heroes
   are a studio-room photograph, so before this the first screen showed
   atmosphere but no craft — measured on staging, the first tattoo sat 1.54
   screens down on Walk-In and 2.96 down on the homepage, i.e. past the point
   where the scroll decision is made.

   It is one anchor wrapping three decorative images plus a label, not three
   separate links: the images repeat what the label already says, so giving
   each its own tab stop would be three identical destinations for a keyboard
   or screen-reader user. Images are alt="" for the same reason — the link
   text carries the meaning.

   Deliberately small. The hero is 100svh and already carries eyebrow, h1,
   sub-line and two CTAs; this has to add proof without pushing the primary
   CTA off a short screen, so it hides entirely under 620px of viewport
   height rather than competing for space it hasn't got. */
a.shero-peek{display:flex;align-items:center;gap:8px;width:fit-content;margin-top:2px}
a.shero-peek img{width:clamp(46px,12vw,58px);height:auto;aspect-ratio:3/4;object-fit:cover;
  border:1px solid rgba(221,214,202,.3);background:var(--ink2);display:block;
  transition:border-color .3s,transform .35s}
a.shero-peek:hover img{border-color:var(--blood-2);transform:translateY(-2px)}
a.shero-peek .peek-label{margin-left:4px;font-size:10.5px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--bone);text-shadow:0 1px 10px rgba(0,0,0,.9);
  transition:color .3s}
a.shero-peek:hover .peek-label{color:var(--blood-2)}
a.shero-peek:focus-visible{outline:2px solid var(--blood-2);outline-offset:4px}
@media(max-height:620px){ a.shero-peek{display:none} }
@media(prefers-reduced-motion:reduce){ a.shero-peek img{transition:none} }

/* nav — overlaid top-right of the hero, opposite the mark */
.topbar{position:absolute;top:clamp(16px,3vw,34px);right:clamp(18px,5vw,80px);z-index:2;
  display:flex;justify-content:flex-end;align-items:center;gap:18px;
  font-size:11px;letter-spacing:.28em;text-transform:uppercase;color:var(--bone)}
.topbar nav{display:flex;align-items:center;gap:clamp(10px,2vw,26px)}
.topbar nav a{transition:color .3s;text-shadow:0 1px 10px rgba(0,0,0,.8)}
.topbar nav a:hover{color:var(--blood-2)}
/* on narrow screens the in-page anchors are redundant with the sticky mobile bar —
   keep only the Instagram link and the language switch */
@media(max-width:600px){ .topbar nav a.nav-anchor{display:none} .topbar{font-size:10px} }

@media(min-width:700px){
  .shero-inner{padding-bottom:clamp(50px,8vh,90px);max-width:70ch}
  .shero h1{font-size:clamp(48px,6vw,96px)}
}

/* ---- trust bar, directly under the hero ---- */
.trustbar{position:relative;z-index:3;background:var(--panel);border-block:1px solid var(--faint);
  padding:16px clamp(18px,5vw,80px);display:flex;align-items:center;gap:clamp(14px,3vw,34px);
  flex-wrap:wrap;font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--ash)}
.trustbar b{color:var(--bone);font-weight:600}
.trustbar .tb-stars{color:var(--blood-2);letter-spacing:.14em}
.trustbar a{text-decoration:underline;text-underline-offset:3px}
.trustbar a:hover{color:var(--blood-2)}
.trustbar .tb-sep{width:1px;height:14px;background:var(--faint);flex:0 0 auto}
@media(max-width:640px){.trustbar .tb-sep{display:none}.trustbar{gap:8px 16px;font-size:11px}}

/* ---- #studio — the merged "atmosphere + curated work" section (client
   decision, 2026-08-02; replaces the old standalone #work section and the
   removed #team-work). One section, two movements, NOT two sub-sections:
   one background, one top-level heading. See PROJECT_STATUS.md §5 Batch 5.

   NAMING CAUTION: an earlier, since-removed section was also headed "Das
   Studio" — Sabina's personal letter, dropped on explicit client direction
   (CLAUDE.md Gotchas). This is not that. This section carries no personal
   narrative and no first-person voice; it is deliberately studio-focused,
   not about any one artist. Don't let the shared heading text suggest the
   letter came back. ---- */
.studio{position:relative;background:var(--void);z-index:3;padding:clamp(56px,9vh,120px) 0 clamp(40px,6vh,80px)}

/* Movement A — the room. The media rail is modular, same contract as
   MEDIA.hero.video and the artist-page healed/faq sections: a slot only
   exists once assets/site.js's STUDIO.media array has entries, so the rail
   collapses to nothing (see :empty below) rather than leaving a gap while
   real studio photography is still pending. Placeholder media, if any is
   added before then, must still come only from the studio's own channels
   (CLAUDE.md constraint 2) — never stock, never AI-generated.

   Carousel, not a grid (2026-08-22): #studioRail is wrapped in the generic
   .carousel scaffold (see .carousel/.car-nav/.carousel .track above), so it
   inherits the same drag/wheel/button-scroll mechanics as every other
   carousel on the site with no JS duplication — only .studio-shot's own
   sizing differs. Desktop shows
   ~3 slides via a viewport-scaled width; mobile shows one slide at ~82% of
   the viewport so the next photo peeks in as a swipe cue (matches the
   .wi-gallery pattern used for the Walk-In gallery). Mandatory snap, since
   this is a small curated set rather than a long scroll like the featured
   carousel's proximity snap. */
.studio-rail:empty{display:none;margin:0}
.studio-carousel .track{scroll-snap-type:x mandatory}
.studio-shot{position:relative;flex:0 0 auto;width:clamp(230px,29vw,340px);aspect-ratio:4/5;
  overflow:hidden;background:var(--ink2);border:1px solid var(--faint);scroll-snap-align:start}
.studio-shot img{width:100%;height:100%;object-fit:cover;display:block}
.studio-shot figcaption{position:absolute;left:10px;bottom:10px;z-index:2;padding:5px 10px;
  background:rgba(10,9,8,.55);border:1px solid rgba(221,214,202,.18);
  font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--bone)}
@media(max-width:720px){
  .studio-shot{width:82vw}
}

/* .fw-nav-row: the nav-button row shared by every .carousel on the site
   (.studio-carousel here, each artist page's .aport-carousel). .fw-more: the
   plain "more" link treatment, still used by the Reviews section's "Read all
   reviews on Google" link. Both outlived the featured "Selected work"
   carousel they were named for — that section (and the .fw/.fw-carousel/
   .fw-tag CSS built only for it) was removed 2026-08-22; portfolios live on
   the artist pages, not duplicated on the homepage. */
.fw-nav-row{display:flex;justify-content:flex-end;padding:0 clamp(18px,5vw,80px);margin-bottom:16px}
.fw-more{padding:clamp(24px,4vh,44px) clamp(18px,5vw,80px) 0;font-size:12px;letter-spacing:.16em;text-transform:uppercase}
.fw-more a{color:var(--bone);border-bottom:1px solid var(--faint);padding-bottom:4px;transition:.25s}
.fw-more a:hover{color:var(--blood-2);border-color:var(--blood-2)}
/* .studio-carousel is the last thing in #studio now (Movement B's featured
   carousel is gone) — zero out the generic .carousel margin-bottom so the
   section's own padding-bottom is the only closing space, instead of both
   stacking into a too-large gap before #artisans. */
.studio-carousel{margin-bottom:0}

/* ---- Team Work carousel (#team-work, homepage, C4) — sits between the
   trust bar and the two-route fork. A curated VIEW over managed `works`
   rows (featured_home + home_order), reusing the exact .shot card + generic
   .carousel scaffold every artist page's Selected Work carousel already
   uses (same photo files, same sizing) — only the always-on artist-name
   caption (.tw-shot figcaption, unlike .studio-shot's optional one — see
   CLAUDE.md §CAROUSEL CONTENT) is new. The empty state is handled in JS:
   the whole section removes itself rather than leaving a heading over an
   empty carousel (assets/site.js), so no :empty rule is needed here. */
.team-carousel{margin-bottom:0}
.tw-shot a{display:block;width:100%;height:100%}
.tw-shot figcaption{position:absolute;left:10px;bottom:10px;z-index:2;padding:5px 10px;pointer-events:none;
  background:rgba(10,9,8,.55);border:1px solid rgba(221,214,202,.18);
  font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--bone)}

/* inline icons inside buttons must not stretch */
.btn svg{width:16px;height:16px;flex:0 0 auto;fill:currentColor}

/* ============================================================================
   WALK-IN PAGE (/de/walk-in.html, /en/walk-in.html)
   Its own beats, but built from the same tokens as everything else. The page's
   terminal action is NAVIGATION (Route ↗), not a form — so the route button is
   given the same visual weight as WhatsApp, not less.
   ========================================================================== */
.wi-lead{max-width:52ch;margin-top:20px;font-size:clamp(15px,1.3vw,17px);line-height:1.65;color:#c9c2b7}
/* live open/closed pill — set by a tiny inline script, hidden until resolved */
.wi-status{display:none;backdrop-filter:blur(2px);align-items:center;gap:10px;margin-top:26px;padding:11px 18px;
  border:1px solid var(--faint);background:var(--panel);font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;width:fit-content}
.wi-status.on{display:inline-flex}
.wi-status .dot{width:9px;height:9px;border-radius:50%;background:var(--ash);flex:none}
.wi-status.is-open .dot{background:#39b54a;box-shadow:0 0 0 4px rgba(57,181,74,.18)}
.wi-status.is-soon .dot{background:var(--blood-2);box-shadow:0 0 0 4px rgba(178,22,34,.18)}
.wi-status b{color:var(--bone);font-weight:600}

.wi-strip{background:var(--panel);border-bottom:1px solid var(--faint);
  padding:16px clamp(18px,5vw,80px);display:flex;flex-wrap:wrap;gap:10px 26px;
  font-size:12.5px;letter-spacing:.06em;color:var(--ash)}
.wi-strip b{color:var(--bone);font-weight:600}

.wi-sec{padding:clamp(60px,9vh,110px) 0}
.wi-steps,.wi-facts{padding:0 clamp(18px,5vw,80px);display:grid;gap:clamp(12px,1.6vw,22px)}
.wi-steps{grid-template-columns:repeat(3,1fr)}
.wi-facts{grid-template-columns:repeat(4,1fr)}
.wi-card{background:var(--panel);border:1px solid var(--faint);padding:clamp(22px,2.6vw,32px);
  display:flex;flex-direction:column;gap:12px;transition:border-color .3s}
.wi-card:hover{border-color:rgba(221,214,202,.28)}
.wi-card .n{font-family:var(--f-disp);font-size:12px;letter-spacing:.2em;color:var(--blood-2)}
.wi-card h3{font-size:clamp(19px,1.7vw,23px);line-height:1.15}
.wi-card p{font-size:14.5px;line-height:1.65;color:var(--ash)}
.wi-card .big{font-family:var(--f-disp);font-size:clamp(28px,3vw,40px);line-height:1;color:var(--bone)}
/* Emphasise the lead price tile in a .wi-facts grid (the starting price —
   the fact a walk-in visitor scans for first) without a new component. */
.wi-facts .wi-card.primary{border-color:var(--blood)}
.wi-facts .wi-card.primary .big{color:var(--blood-2)}

/* Per-piece price tag for a .shot figure — same overlay language as the
   featured carousel's .fw-tag, scoped to .shot instead since flash cards
   use that component. Unused today (walk-in.html's flash script only
   renders it when an item carries a real price field) — no flash
   inventory exists yet, and none is invented here. */
.shot .price-tag{position:absolute;left:10px;bottom:10px;z-index:2;
  padding:5px 10px;background:rgba(10,9,8,.72);border:1px solid rgba(221,214,202,.18);
  font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--bone)}

.wi-arrive{padding:0 clamp(18px,5vw,80px);display:grid;grid-template-columns:1.1fr 1fr;
  gap:clamp(20px,3vw,48px);align-items:center}
.wi-arrive img{width:100%;height:auto;border:1px solid var(--faint)}
.wi-addr{font-family:var(--f-disp);font-size:clamp(26px,3.4vw,44px);line-height:1.1;text-transform:uppercase}
.wi-arrive ul{margin-top:18px;display:flex;flex-direction:column;gap:8px;font-size:14.5px;color:var(--ash)}

@media(max-width:900px){
  .wi-steps{grid-template-columns:1fr}
  .wi-facts{grid-template-columns:repeat(2,1fr)}
  .wi-arrive{grid-template-columns:1fr}
  .wi-arrive img{order:-1}
}
@media(max-width:560px){
  .wi-facts{grid-template-columns:1fr}
}
/* 3-tile variant (Walk-In's practical-info grid, once the €50 deposit tile
   was dropped — that's Custom-only). Scoped modifier, not a change to the
   base 4-col .wi-facts, which the consultation page still uses as-is. */
.wi-facts.cols-3{grid-template-columns:repeat(3,1fr)}
@media(max-width:900px){ .wi-facts.cols-3{grid-template-columns:repeat(2,1fr)} }
@media(max-width:560px){ .wi-facts.cols-3{grid-template-columns:1fr} }

/* Tighter section rhythm for the Walk-In page specifically — the mobile
   restructure calls for less vertical padding than the desktop-authored
   default .wi-sec carries. Additive modifier so .wi-sec itself (shared
   with the consultation page) is untouched. */
.wi-sec.compact{padding:clamp(40px,7vh,90px) 0}

/* Standalone top bar for pages that have no .shero to sit on top of.
   .topbar itself is absolutely positioned over the hero image on the homepage;
   here it needs to be a real, in-flow bar. Same links, same hide-on-mobile
   behaviour (.nav-anchor), so the two never diverge visually. */
.topbar-solid{position:relative;top:auto;right:auto;background:var(--void);
  border-bottom:1px solid var(--faint);padding:14px clamp(18px,5vw,80px);
  justify-content:space-between}
.topbar-solid nav{flex-wrap:wrap;justify-content:flex-end;gap:clamp(12px,2vw,26px)}
@media(max-width:600px){ .topbar-solid nav{justify-content:flex-end} }

/* ---- .bar-mark — the home logo for the two page families that have no
   .shero to overlay a .shero-mark on: the style pages (.topbar-solid) and
   the artist pages (.abar). Before this the logo simply did not exist on
   those 14 pages and "back to the studio" was a text link, so the mark was
   not a consistent, always-present route home (client direction 2026-08-22).
   Same restrained hover as .shero-mark — a small scale plus a red drop
   shadow, nothing that spins or bounces. */
.bar-mark{display:inline-flex;align-items:center;gap:12px;flex:0 0 auto;line-height:0}
.bar-mark img{width:clamp(40px,4.4vw,56px);height:auto;display:block;
  filter:drop-shadow(0 0 12px rgba(178,22,34,.28));
  transition:transform .45s cubic-bezier(.22,.61,.36,1),filter .45s}
.bar-mark .bar-mark-txt{font-family:var(--f-disp);font-weight:700;
  font-size:clamp(13px,1.3vw,15px);letter-spacing:.12em;text-transform:uppercase;
  color:var(--bone);line-height:1.05;transition:color .3s}
.bar-mark:hover img{transform:scale(1.05);filter:drop-shadow(0 0 18px rgba(178,22,34,.5))}
.bar-mark:hover .bar-mark-txt{color:var(--blood-2)}
.bar-mark:focus-visible{outline:2px solid var(--blood-2);outline-offset:6px}
/* The wordmark beside the logo is redundant on a phone — the mark alone is
   the recognisable element and the nav needs the width. */
@media(max-width:600px){ .bar-mark .bar-mark-txt{display:none} }
@media(prefers-reduced-motion:reduce){
  .bar-mark img{transition:none}
  .bar-mark:hover img{transform:none}
}

/* ---- Style pages (/de/stil/*, /en/stil/*) ------------------------------- */
.sty-hero{padding:clamp(70px,11vh,120px) clamp(18px,5vw,80px) clamp(36px,5vh,60px);border-bottom:1px solid var(--faint)}
.sty-hero .kicker{font-size:11px;letter-spacing:.36em;text-transform:uppercase;color:var(--blood-2);margin-bottom:14px}
.sty-hero h1{font-size:clamp(42px,8.5vw,112px);line-height:.88}
.sty-hero h1 em{font-style:normal;color:var(--blood-2)}
.sty-grid{padding:0 clamp(18px,5vw,80px);display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(10px,1.4vw,20px)}
.sty-about{padding:0 clamp(18px,5vw,80px);max-width:62ch;display:flex;flex-direction:column;gap:16px}
.sty-about p{font-size:clamp(15px,1.25vw,17px);line-height:1.7;color:#c9c2b7}
.sty-artist{padding:0 clamp(18px,5vw,80px);display:flex;gap:clamp(20px,3vw,44px);align-items:center;flex-wrap:wrap}
.sty-artist img{width:min(260px,45vw);height:auto;border:1px solid var(--faint)}
.sty-artist .kicker{font-size:12px;letter-spacing:.22em;text-transform:uppercase;color:var(--ash)}
@media(max-width:820px){ .sty-grid{grid-template-columns:repeat(2,1fr)} }
@media(max-width:520px){ .sty-hero .ctas .btn{flex:1 1 100%;justify-content:center} }
/* .shot is sized for the horizontal carousel (flex:0 0 auto + a fixed clamp
   width). Inside the style-page grid the column defines the width instead —
   without this override the fixed min-width forces horizontal overflow on
   phones. */
.sty-grid .shot{flex:initial;width:auto}

/* Mobile swipe gallery — Walk-In examples + (future) flash inventory.
   Desktop keeps the plain .sty-grid editorial grid this sits alongside;
   below 768px it becomes a native horizontal scroll-snap strip: no JS, no
   carousel library, no cloned slides, works with JS disabled. Sized so
   ~1.15 cards show at once (a deliberate peek of the next photo), same
   scroll-padding-left pattern as .carousel .track elsewhere on the site.
   Placed after .sty-grid .shot above so its flex-basis/width win the
   cascade at equal specificity (both are two-class selectors). */
@media(max-width:767px){
  .wi-gallery{display:flex;overflow-x:auto;overflow-y:hidden;
    gap:14px;padding:0 clamp(18px,5vw,80px);scroll-snap-type:x mandatory;
    scroll-padding-left:clamp(18px,5vw,80px);-webkit-overflow-scrolling:touch;
    scrollbar-width:none}
  .wi-gallery::-webkit-scrollbar{display:none}
  .wi-gallery .shot{flex:0 0 78vw;width:78vw}
}
/* Subtle, mobile-only discoverability hint for the swipe galleries. */
.wi-swipe-hint{display:none}
@media(max-width:767px){
  .wi-swipe-hint{display:block;padding:0 clamp(18px,5vw,80px);margin:-8px 0 14px;
    font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--ash)}
}

/* ============================================================================
   STUDIO / SHOP LIFE page (/de/studio, /en/studio)
   Photography-led, deliberately NOT a uniform "Meet Our Team" grid: slots carry
   their own span so the rhythm stays irregular and reads as editorial rather
   than as employee cards. Built from the same tokens and the same .sec-head /
   .book / .btn furniture as every other page.
   ========================================================================== */
/* Title block — replaces the removed split-screen hero (client: awkward).
   Same shape as .sty-hero on the style pages, so Shop Life now opens the way
   every other non-hero page on the site does. */
.slife-hero{position:relative;z-index:3;background:var(--void);
  padding:clamp(54px,9vh,110px) clamp(18px,5vw,80px) clamp(32px,5vh,56px)}
.slife-hero h1{font-size:clamp(44px,8.5vw,112px);line-height:.88;margin-top:14px}
.slife-hero h1 em{font-style:normal;color:var(--blood-2)}
.slife-lead{margin-top:clamp(20px,3vh,30px);max-width:58ch;
  font-size:clamp(15px,1.35vw,17.5px);line-height:1.7;color:#c3bcb1}

.slife{position:relative;z-index:3;background:var(--void);padding:0 0 clamp(50px,8vh,110px)}
.slife-grid{padding:0 clamp(18px,5vw,80px);display:grid;grid-template-columns:repeat(6,1fr);
  gap:clamp(12px,1.8vw,26px);align-items:start}
.slife-shot{position:relative;margin:0;display:flex;flex-direction:column;gap:10px;
  grid-column:span 3}
/* object-position is set PER FIGURE as an inline style by
   tools/gen-studio-life.js, from each slot's own objectPosition in
   data/studio-life.json — deliberately not one shared value here, because
   these photos have nothing in common compositionally and a shared value
   cuts faces. Most slots are cropped to their slot's exact ratio at build
   time, so their value is an intentional no-op; the ones that differ
   (the team photo, and the two whose ratio changes at the mobile
   breakpoint) are the ones it actually moves. */
.slife-shot img{width:100%;height:100%;object-fit:cover;display:block;
  border:1px solid var(--faint);background:var(--ink2);
  aspect-ratio:var(--slife-ar,4/5);filter:contrast(1.04) brightness(.94);transition:filter .6s,transform .9s}
.slife-shot:hover img{filter:contrast(1.05);transform:scale(1.015)}
.slife-shot figcaption{font-size:13px;line-height:1.55;color:var(--ash);max-width:46ch}
/* Span variants control WIDTH only. Height comes from each figure's own
   --slife-ar (set inline per slot by tools/gen-studio-life.js) — the two are
   deliberately separate, because span alone produced ragged columns: a span-4
   at 4:5 next to a span-2 at 3:4 left ~400px of dead column beside the
   shorter one. Six columns so a row can be 6, 4+2, 2+4 or 3+3 rather than a
   flat 2-up grid. Rows must add up to 6; see data/studio-life.json. */
.slife-wide{grid-column:span 6}
.slife-tall{grid-column:span 3}
.slife-major{grid-column:span 4}
.slife-minor{grid-column:span 2}
/* Nudges a small figure out of alignment with its neighbour so the pair reads
   as a composition rather than two cells. Desktop only. */
@media(min-width:721px){ .slife-offset{margin-top:clamp(24px,5vw,72px)} }

/* Closing link out of the page. Shop Life is otherwise a dead end — this is
   the one CTA here and it has a real destination (the artists grid). */
.slife-outro{padding:clamp(34px,5vh,56px) clamp(18px,5vw,80px) 0;
  font-size:12px;letter-spacing:.18em;text-transform:uppercase}
.slife-outro a{color:var(--bone);border-bottom:1px solid var(--faint);padding-bottom:5px;transition:.25s}
.slife-outro a:hover{color:var(--blood-2);border-color:var(--blood-2)}

@media(max-width:720px){
  .slife-grid{grid-template-columns:1fr}
  .slife-shot,.slife-wide,.slife-tall,.slife-major,.slife-minor{grid-column:1/-1}
  /* Everything is full-width now, so tall portraits would run past a phone
     screen on their own. --slife-ar-mob is the per-slot override where one is
     needed (today: the cafe photo, whose 16:9 is only ~210px tall on a 375px
     phone — too small to read two faces; 3:2 gains height while cropping only
     ~5.5% off each side, which its subjects sit well inside of). Slots without
     one keep their delivered ratio. */
  .slife-shot img{aspect-ratio:var(--slife-ar-mob,var(--slife-ar,4/5))}
  /* Cap the extreme portraits so one photo cannot fill more than a screen. */
  .slife-minor img{max-height:82svh;width:100%;object-fit:cover}
  /* The desktop stagger would read as a random gap once everything is stacked. */
  .slife-offset{margin-top:0}
}
@media(prefers-reduced-motion:reduce){ .slife-shot img{transition:none} .slife-shot:hover img{transform:none} }

/* Styles strip on the homepage — the route into the style pages. */
.stylenav{background:var(--void);border-bottom:1px solid var(--faint);padding:18px clamp(18px,5vw,80px);
  display:flex;flex-wrap:wrap;align-items:center;gap:10px 22px}
.stylenav .lbl{font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--blood-2);margin-right:6px}
.stylenav a{font-family:var(--f-disp);font-size:clamp(15px,1.5vw,19px);text-transform:uppercase;letter-spacing:.04em;
  color:var(--bone);border-bottom:1px solid transparent;transition:border-color .3s,color .3s;padding-bottom:2px}
.stylenav a:hover{border-color:var(--blood-2);color:var(--blood-2)}
@media(max-width:560px){ .stylenav{gap:8px 16px} .stylenav .lbl{width:100%;margin-bottom:2px} }

/* ============================================================================
   TWO ROUTES — the homepage fork between the two funnels.
   Walk-in / small tattoo and custom booking are different customer intents and
   must stay visibly separate (strategy deck, slide 6). Built from the existing
   .wi-card component so it reads as the same system, just two-up.
   ========================================================================== */
.routes{padding:0 clamp(18px,5vw,80px);display:grid;grid-template-columns:repeat(2,1fr);
  gap:clamp(12px,1.6vw,22px)}
.routes .wi-card{gap:14px;border-left-width:2px}
.routes .rt-tag{font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--blood-2)}
.routes .wi-card h3{font-size:clamp(26px,3vw,38px);line-height:1.05;text-transform:uppercase;
  font-family:var(--f-disp)}
.routes .rt-when{font-size:13px;letter-spacing:.06em;color:var(--bone)}
.routes .wi-card p{flex:1}
.routes .btn{align-self:flex-start;margin-top:4px}
/* Custom reads as the primary path (blood-tinted edge, matches its own
   .btn-blood CTA); Walk-in stays neutral. Same .wi-card, no new component —
   makes the fork in "Zwei Wege"/"Two routes" read at a glance, not just on
   click. */
.routes .route-custom{border-left-color:var(--blood);
  background:linear-gradient(165deg,rgba(178,22,34,.07),transparent 55%)}
.routes .route-custom:hover{border-left-color:var(--blood-2)}
.routes .route-spontan{border-left-color:rgba(221,214,202,.3)}
@media(max-width:820px){ .routes{grid-template-columns:1fr} .routes .btn{align-self:stretch;justify-content:center} }
/* The "Browse styles" link row inside the custom route card (.rt-styles) was
   REMOVED 2026-08-22 on client direction, markup and CSS both.
   KNOWN CONSEQUENCE, accepted deliberately: it was the LAST internal link to
   the six style pages anywhere on the site — the artist-page Styles sections
   had already been removed on the same direction. The style pages are now
   reachable only from sitemap.xml and by direct URL; no page links to them.
   They are still generated, still valid and still in the sitemap. If style
   traffic ever matters, that link has to go back somewhere. */
/* Line that closes the Walk-In gallery and hands off to the CTA underneath it.
   The gallery's whole job is to make someone think "I could get something like
   that" — so the next action has to sit immediately under the last photo, not
   two paragraphs into the following section. */
.wi-after-gallery{padding:0 clamp(18px,5vw,80px);max-width:52ch;
  margin:clamp(26px,4vh,44px) 0 16px;font-size:15px;line-height:1.65;color:#c5bdb2}

/* Flash fallback copy — shown while there is no published inventory. The grid
   above it collapses when empty (:empty), so nothing renders an empty frame. */
.wi-flash-empty{padding:0 clamp(18px,5vw,80px);max-width:56ch;font-size:14.5px;line-height:1.65;color:var(--ash)}
.sty-grid:empty{display:none}

/* ============================================================================
   CONSULTATION FORM (/de/beratung, /en/consultation)
   Funnel 2's convert-point. No backend: the brief is composed into WhatsApp,
   so nothing is stored by us and no reference photo enters our custody.
   Built from the same tokens as everything else.
   ========================================================================== */
.enq{padding:0 clamp(18px,5vw,80px)}
.enq-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(14px,2vw,24px)}
.enq-wide{grid-column:1/-1}
.enq-field{display:flex;flex-direction:column;gap:8px}
.enq-field>span{font-size:11px;letter-spacing:.26em;text-transform:uppercase;color:var(--ash)}
.enq-field small{font-size:12px;line-height:1.5;color:var(--ash);opacity:.85}
.enq-field input,.enq-field textarea,.enq-field select{
  background:var(--void);border:1px solid var(--faint);color:var(--bone);
  font-family:var(--f-body);font-size:15px;line-height:1.5;padding:13px 15px;
  border-radius:0;transition:border-color .3s;width:100%}
.enq-field textarea{resize:vertical;min-height:110px}
.enq-field input:focus,.enq-field textarea:focus,.enq-field select:focus{
  outline:none;border-color:var(--blood-2)}
.enq-field input::placeholder,.enq-field textarea::placeholder{color:var(--ash);opacity:.55}
.enq-field select{appearance:none;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--ash) 50%),linear-gradient(135deg,var(--ash) 50%,transparent 50%);
  background-position:calc(100% - 19px) 50%,calc(100% - 14px) 50%;background-size:5px 5px,5px 5px;background-repeat:no-repeat;
  padding-right:40px}
.enq-field select option{background:var(--void);color:var(--bone)}
.enq-note{margin-top:22px;max-width:60ch;font-size:13.5px;line-height:1.65;color:var(--ash)}
.enq-preview-wrap{margin-top:26px;border:1px solid var(--faint);border-left:2px solid var(--blood);background:var(--void);padding:16px 18px}
.enq-preview-label{display:block;font-size:10.5px;letter-spacing:.26em;text-transform:uppercase;color:var(--blood-2);margin-bottom:10px}
.enq-preview{margin:0;font-family:var(--f-body);font-size:13.5px;line-height:1.7;color:#c9c2b7;
  white-space:pre-wrap;word-break:break-word}
@media(max-width:720px){
  .enq-grid{grid-template-columns:1fr}
  .enq .ctas .btn{flex:1 1 100%;justify-content:center}
}
