/* ============================================================================
   ADHELM — landing page v2

   v1 (site/landing) is the cinematic one. It is accurate and it is handsome,
   and it frightened the audience it was written for: a Handwerksbetrieb or a
   Mittelständler who does not know what a CPA is reads a black WebGL night
   scene as "this is not for me". Owner, 2026-09-17: *"sence müşteriyi korkutmaz
   mı? … hedef kitlen teknolojiden anlamayan, yani bir nevi salağa anlatır
   gibi."*

   So v2 is built on the opposite instinct, in the register of the sites the
   owner named as the mark — hops.ai, leadinfo.com, lemlist.com: a light page,
   one plain sentence at a time, the product shown rather than described, and
   every promise immediately followed by the limit that makes it safe.

   The palette is not a marketing palette. It is `panel/frontend/src/styles/ds/
   tokens.css`, unchanged — the same paper, the same one black button, the same
   one blue accent, the same traffic light. A visitor who books a demo and then
   opens the Werkbank should not feel they have changed products.
   ============================================================================ */

/* ============================================================= tokens */
:root{
  /* --- Ground (DESIGN.md §5) --------------------------------------------- */
  --canvas:#f6f6f3;
  --surface:#ffffff;
  --surface-2:#f1f1ee;
  --surface-hover:#f3f3f0;
  --hairline:#e7e6e2;
  --hairline-strong:#d8d7d2;

  /* --- Ink --------------------------------------------------------------- */
  --text:#16161a;
  --muted:#6b6b70;
  --subtle:#8a8a90;

  /* --- Interactive -------------------------------------------------------- */
  --primary:#111111;
  --primary-fg:#ffffff;
  --primary-hover:#262629;
  --accent:#2f6bff;

  /* --- Tint pairs --------------------------------------------------------- */
  --rose-bg:#fce8e8;    --rose-fg:#b42318;
  --amber-bg:#fff1d6;   --amber-fg:#b54708;
  --emerald-bg:#e3f5e9; --emerald-fg:#067647;
  --blue-bg:#e6eeff;    --blue-fg:#175cd3;
  --slate-bg:#eeeef0;   --slate-fg:#475467;

  /* --- Shape -------------------------------------------------------------- */
  --r-card:12px;
  --r-control:8px;
  --r-pill:999px;
  --r-shot:16px;

  --shadow-hover:0 1px 2px rgba(0,0,0,.04), 0 8px 24px rgba(0,0,0,.06);
  --shadow-float:0 2px 6px rgba(0,0,0,.06), 0 16px 40px rgba(0,0,0,.12);
  --shadow-shot:0 2px 8px rgba(22,22,26,.05), 0 24px 60px -18px rgba(22,22,26,.20);

  --pad:clamp(20px, 4vw, 40px);
  --wrap:1180px;
  --nav-h:68px;
  --sec-y:clamp(68px, 9vw, 124px);
  /* The panel's own pair (tokens.css): --ease is the UI curve used for every
     state change in the Werkbank, --ease-out is the longer decelerating one a
     page-scale reveal needs. Nothing on this page invents a third. */
  --ease:cubic-bezier(.16,1,.3,1);
  --ease-ui:cubic-bezier(.2,0,0,1);
  --ease-out:cubic-bezier(.22,1,.36,1);

  /* --- The dark set -------------------------------------------------------
     `#nacht` used to be painted #05070b with a cold blue — a colour that
     exists nowhere in the product. Owner, 2026-09-17: *"bu çok kötü, renk
     zaten saçma olmuş, açık renkten koyuya, hiç UX friendly değil."* He was
     right twice over: the hue was invented, and the cut from paper to black
     had no ramp at all.

     The panel HAS a dark theme — tokens.css `[data-theme="dark"]`, DESIGN §8.2
     — and it is a warm-neutral graphite, not a navy. These are those values
     verbatim. So the dark section is no longer "a dark section": it is the
     Werkbank at night, in the clothes it actually wears at night. */
  /* Take three of this section was the panel's dark theme, and it was right
     about the hue and wrong about the value. Owner: *"bu night card uymuyor
     design rengi olarak — light'ta dark olmasa, gözüme kötü geliyor."* Three
     rejections of a dark band is the answer: on a page made of paper, a slab
     of graphite is a hole, however correct its colour.

     So the section keeps its own room and loses the dark. 06:12 in September
     is not night — it is first light, which is what the headline has been
     saying all along ("während Sie noch geschlafen haben"). The card is now
     the sky at that hour: paper with a blue cast, the ring and the column
     field in the product's own #2f6bff, and the three proposals as white
     cards on it. The closing line at 08:20 then lands in daylight.

     Everything below still reads --n-*, so the whole room changes value here
     and nowhere else. */
  --n-canvas:var(--surface-2);   /* the card's ground — the page's quieter paper */
  --n-surface:var(--surface);    /* the proposal cards on it */
  --n-surface-2:#e9e9e5;
  --n-hairline:#e2e1dc;
  --n-hairline-strong:#d0cfc9;
  --n-text:#16161a;
  --n-muted:var(--muted);
  --n-subtle:var(--subtle);
  --n-accent:#2f6bff;
  --n-rose:var(--rose-fg);
  --n-amber:var(--amber-fg);
  --n-emerald:var(--emerald-fg);
  --n-blue:var(--blue-fg);
  --n-shadow:0 1px 2px rgba(22,22,26,.05), 0 16px 40px -14px rgba(22,22,26,.18);
}

*,*::before,*::after{ box-sizing:border-box }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; scroll-padding-top:calc(var(--nav-h) + 20px);
  overflow-x:clip; }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto } }
body{
  margin:0; background:var(--canvas); color:var(--text);
  font-family:'Onest',system-ui,-apple-system,'Segoe UI','Helvetica Neue',sans-serif;
  font-weight:400; font-size:16px; line-height:1.6;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}
img{ max-width:100%; display:block }
a{ color:inherit; text-decoration:none }
button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer }
:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:4px }
::selection{ background:var(--blue-bg); color:var(--blue-fg) }
.sr{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap }

/* the page never sits on flat white: one very soft wash at the top so the
   hero has somewhere to stand, and nothing else anywhere */
body::before{
  content:''; position:fixed; inset:0 0 auto 0; height:min(920px,86vh); z-index:0; pointer-events:none;
  background:
    radial-gradient(60% 52% at 50% -6%, rgba(47,107,255,.10), rgba(47,107,255,0) 72%),
    radial-gradient(42% 40% at 88% 4%, rgba(6,118,71,.05), rgba(6,118,71,0) 70%);
}
.page{ position:relative; z-index:1 }

/* ============================================================= type */
h1,h2,h3,h4{ margin:0; font-weight:500; letter-spacing:-.022em; line-height:1.1 }
.h1{ font-size:clamp(33px,5.1vw,60px); line-height:1.055; letter-spacing:-.028em }
.h2{ font-size:clamp(27px,3.5vw,44px); line-height:1.08 }
.h3{ font-size:clamp(18px,1.5vw,21px); letter-spacing:-.014em }
p{ margin:0 }
.lead{ font-size:clamp(17px,1.35vw,20px); line-height:1.6; color:var(--muted) }
.body{ font-size:15px; line-height:1.66; color:var(--muted) }
.small{ font-size:13px; line-height:1.55; color:var(--subtle) }
strong{ font-weight:500; color:var(--text) }
.tnum{ font-variant-numeric:tabular-nums; font-feature-settings:'tnum' 1 }

/* the one highlight in the page: a soft accent swash under the phrase the
   whole promise turns on. It is drawn behind the baseline, not through it. */
/* An absolutely positioned bar is placed against the element's BOX, whose
   bottom edge is the descender line — on a 60px display size that is fifteen
   pixels under the baseline, and the swash reads as a separate rule floating
   below the words. text-decoration is placed against the BASELINE, so a small
   negative offset lifts it into the glyphs where a highlighter would be, at
   every size, in both languages. */
.mark{
  white-space:nowrap;
  text-decoration-line:underline;
  text-decoration-color:rgba(47,107,255,.22);
  text-decoration-thickness:.22em;
  text-underline-offset:-.055em;
  text-decoration-skip-ink:none;
}

/* ============================================================= layout */
.wrap{ width:100%; max-width:var(--wrap); margin:0 auto; padding-inline:var(--pad) }
.sec{ padding-block:var(--sec-y) }
.sec--tight{ padding-block:clamp(44px,6vw,80px) }
.sec--paper{ background:var(--surface); border-block:1px solid var(--hairline) }
.sec-head{ max-width:660px; margin-bottom:clamp(30px,4vw,54px) }
.sec-head.is-centred{ margin-inline:auto; text-align:center }
.sec-head .eyebrow{ margin-bottom:14px }
.sec-head .lead{ margin-top:16px }
.eyebrow{
  display:inline-flex; align-items:center; gap:8px;
  font-size:12px; font-weight:500; letter-spacing:.02em; color:var(--muted);
}
.eyebrow::before{
  content:''; width:7px; height:7px; border-radius:50%;
  background:var(--dot,var(--emerald-fg)); flex:0 0 auto;
}

/* ============================================================= buttons */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  height:48px; padding:0 24px; border-radius:var(--r-pill);
  font-size:15px; font-weight:500; letter-spacing:-.005em; white-space:nowrap;
  transition:background .18s ease, color .18s ease, border-color .18s ease,
             transform .18s var(--ease), box-shadow .18s ease;
}
.btn svg{ width:15px; height:15px; flex:0 0 auto }
.btn--primary{ background:var(--primary); color:var(--primary-fg) }
.btn--primary:hover{ background:var(--primary-hover); transform:translateY(-1px); box-shadow:var(--shadow-hover) }
.btn--ghost{ background:var(--surface); color:var(--text); border:1px solid var(--hairline-strong) }
.btn--ghost:hover{ background:var(--surface-hover); transform:translateY(-1px) }
.btn--sm{ height:38px; padding:0 17px; font-size:14px }
.btn--lg{ height:54px; padding:0 30px; font-size:16px }
.btn-row{ display:flex; flex-wrap:wrap; gap:12px }
.btn-row.is-centred{ justify-content:center }

/* ============================================================= nav */
.nav{
  position:sticky; top:0; z-index:50; height:var(--nav-h);
  background:rgba(246,246,243,.86);
  backdrop-filter:blur(12px) saturate(1.2); -webkit-backdrop-filter:blur(12px) saturate(1.2);
  border-bottom:1px solid transparent; transition:border-color .25s ease, background .25s ease;
}
.nav.stuck{ border-bottom-color:var(--hairline); background:rgba(246,246,243,.94) }
.nav-in{ height:100%; display:flex; align-items:center; gap:clamp(14px,2vw,30px) }
.brand{ display:flex; align-items:center; gap:10px; flex:0 0 auto }
.brand svg{ width:30px; height:30px; display:block }
.brand b{ font-size:16px; font-weight:600; letter-spacing:-.01em }
.nav-links{ display:flex; align-items:center; gap:clamp(10px,1.35vw,22px); margin-left:auto }
.nav-link{ font-size:14px; color:var(--muted); padding:7px 2px; white-space:nowrap; transition:color .18s ease }
.nav-link:hover{ color:var(--text) }
.nav-tools{ display:flex; align-items:center; gap:10px; flex:0 0 auto }
.lang{ display:flex; align-items:center; gap:2px; padding:2px; border:1px solid var(--hairline); border-radius:var(--r-pill); background:var(--surface) }
.lang button{ font-size:12px; font-weight:500; padding:5px 10px; border-radius:var(--r-pill); color:var(--subtle); transition:.18s ease }
.lang button[aria-pressed="true"]{ background:var(--surface-2); color:var(--text) }
.lang button:hover{ color:var(--text) }
.nav-burger{ display:none; width:38px; height:38px; border:1px solid var(--hairline); border-radius:var(--r-control); background:var(--surface); position:relative }
.nav-burger i{ position:absolute; left:11px; width:16px; height:1.6px; background:var(--text); border-radius:2px; transition:.25s var(--ease) }
.nav-burger i:nth-child(1){ top:14px } .nav-burger i:nth-child(2){ top:21px }
.nav-burger.active i:nth-child(1){ top:18px; transform:rotate(45deg) }
.nav-burger.active i:nth-child(2){ top:18px; transform:rotate(-45deg) }

/* ============================================================= hero */
.hero{ padding-top:clamp(46px,6vw,84px); padding-bottom:clamp(30px,4vw,50px); text-align:center }
.hero .h1{ max-width:20ch; margin:20px auto 0 }
.hero .lead{ max-width:60ch; margin:22px auto 0 }
.hero .btn-row{ margin-top:30px }
.hero-trust{
  display:flex; flex-wrap:wrap; justify-content:center; gap:8px 22px; margin-top:22px;
  font-size:13.5px; color:var(--subtle);
}
.hero-trust span{ display:inline-flex; align-items:center; gap:7px }
.hero-trust svg{ width:14px; height:14px; color:var(--emerald-fg); flex:0 0 auto }

/* ---------------------------------------------------- the product shot
   Not a photograph and not a screenshot: the Werkbank's real surfaces,
   rebuilt in markup at the size they are used. It stays honest (the copy is
   the product's own), it stays sharp on every display, and it is the one
   thing on this page that answers "what will I actually be looking at?". */
.shot{
  position:relative; margin-top:clamp(34px,4.5vw,58px);
  border:1px solid var(--hairline); border-radius:var(--r-shot); background:var(--surface);
  box-shadow:var(--shadow-shot); overflow:hidden; text-align:left;
}
.shot-bar{
  display:flex; align-items:center; gap:10px; height:44px; padding:0 14px;
  border-bottom:1px solid var(--hairline); background:var(--surface-2);
}
.shot-dots{ display:flex; gap:6px }
.shot-dots i{ width:9px; height:9px; border-radius:50%; background:var(--hairline-strong) }
.shot-url{
  flex:1 1 auto; max-width:320px; margin-inline:auto; height:26px; border-radius:var(--r-pill);
  background:var(--surface); border:1px solid var(--hairline);
  display:flex; align-items:center; justify-content:center; gap:6px;
  font-size:11.5px; color:var(--subtle);
}
.shot-url svg{ width:11px; height:11px }
.shot-body{ display:grid; grid-template-columns:190px minmax(0,1fr); min-height:420px }

/* the rail */
.ui-rail{ border-right:1px solid var(--hairline); padding:14px 10px; background:var(--surface) }
.ui-rail-h{ display:flex; align-items:center; gap:8px; padding:4px 10px 12px }
.ui-rail-h .mk{ width:18px; height:18px; flex:0 0 auto }
.ui-rail-h b{ font-size:13px; font-weight:600; letter-spacing:-.01em; color:var(--text) }
.ui-rail a{ display:flex; align-items:center; gap:10px; padding:8px 10px; border-radius:var(--r-control); font-size:14px; color:var(--muted) }
.ui-rail a i{ width:15px; height:15px; border-radius:4px; background:var(--slate-bg); flex:0 0 auto }
.ui-rail a.on{ background:var(--surface-2); color:var(--text); font-weight:500 }
.ui-rail a.on i{ background:var(--text) }
.ui-rail .badge{ margin-left:auto; font-size:11px; font-weight:600; padding:1px 7px; border-radius:var(--r-pill); background:var(--primary); color:var(--primary-fg) }

/* the main pane */
.ui-main{ padding:clamp(16px,1.6vw,22px); min-width:0; background:var(--canvas);
  display:flex; flex-direction:column; gap:14px }
/* PageHeader (shell/PageHeader.tsx): breadcrumb, name, one sentence, refresh */
.ui-bc{ display:flex; align-items:center; gap:4px; font-size:11px; color:var(--muted) }
.ui-bc svg{ width:10px; height:10px; opacity:.6; stroke:currentColor; stroke-width:2; fill:none; stroke-linecap:round; stroke-linejoin:round }
.ui-bc b{ font-weight:500; color:var(--text) }
.ui-ph-row{ display:flex; align-items:flex-start; justify-content:space-between; gap:16px; margin-top:4px }
.ui-ph-row b{ display:block; font-size:18px; font-weight:600; letter-spacing:-.015em }
.ui-ph-row i{ display:block; margin-top:2px; font-style:normal; font-size:12.5px; color:var(--muted) }
.ui-rf{ width:28px; height:28px; border-radius:var(--r-control); display:grid; place-items:center; color:var(--muted); flex:0 0 auto }
.ui-rf svg{ width:14px; height:14px; stroke:currentColor; stroke-width:2; fill:none; stroke-linecap:round; stroke-linejoin:round }

/* The status line is a card in the panel (a-surface, px-5 py-4), with the
   "Stand:" line beside the sentence rather than under it, and a 12px dot. */
.ui-status{
  display:flex; flex-wrap:wrap; align-items:flex-start; gap:12px; padding:14px 16px;
  background:var(--surface); border:1px solid var(--hairline); border-radius:var(--r-card);
}
.ui-status .dt{ width:12px; height:12px; border-radius:50%; margin-top:4px; background:var(--dot,var(--emerald-fg)); flex:0 0 auto }
.ui-status p{ min-width:0; flex:1 1 320px; font-size:clamp(13.5px,1.15vw,16px); line-height:1.4; color:var(--text) }
.ui-status .as{ flex:0 0 auto; font-size:11.5px; color:var(--muted); font-variant-numeric:tabular-nums }

.ui-tiles{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:12px }
/* KpiTile (ui/kpi-tile.tsx): label, then the big tabular number with a visual
   beside it, then the goal line, then the breakdown. The visual is a slot —
   the four tiles show four different things and the panel does not pretend
   otherwise: a ring for progress toward a goal, a dot for a threshold, a dot
   with a percentage for a share. */
.ui-tile{ background:var(--surface); border:1px solid var(--hairline); border-radius:var(--r-card); padding:14px }
.ui-tile .lb{ font-size:12px; font-weight:500; color:var(--muted) }
.ui-tile-row{ display:flex; align-items:flex-start; justify-content:space-between; gap:10px; margin-top:8px }
.ui-tile b{ display:block; font-size:clamp(19px,1.85vw,26px); font-weight:500; line-height:1; letter-spacing:-.02em }
.ui-tile .gl{ display:block; margin-top:8px; font-size:11.5px; line-height:1.45; color:var(--subtle) }
.ui-tile .gl + .gl{ margin-top:3px }
.ui-tile .ring{ width:38px; height:38px; flex:0 0 auto; margin-top:-3px }
/* the ring fills as the tile arrives, the way it does when the month's data
   lands — held at zero until the reveal so it has somewhere to travel from */
.ui-tile .ring circle:last-child{
  stroke-dasharray:0 100; transition:stroke-dasharray 1.15s var(--ease-out) .25s;
}
[data-rv].rv-in .ui-tile .ring circle:last-child{ stroke-dasharray:73 27 }
.ui-tile .dt{ width:10px; height:10px; border-radius:50%; background:var(--dot); flex:0 0 auto; margin-top:3px }
.ui-tile .dt--sm{ width:7px; height:7px; margin-top:0 }
.ui-tile .pctd{ display:inline-flex; align-items:center; gap:6px; font-size:12px; color:var(--muted); white-space:nowrap }

/* ---- Verlauf (marketing/TrendChart.tsx) ----------------------------------
   A LineChart with two Y axes: spend on the left in euro, enquiries on the
   right as whole numbers. The grid is horizontal only and dashed 3 3; spend
   carries no dots and enquiries carry r=2, because one is a flow and the
   other is a count of events. */
.tc-h{ align-items:flex-start }
.tc-h > span:first-child b{ display:block }
.tc-h > span:first-child i{ display:block; margin-top:2px; font-style:normal; font-size:12px; color:var(--muted) }
.seg{ display:inline-flex; align-items:center; gap:2px; padding:2px; border-radius:var(--r-pill);
  background:var(--surface-2); flex:0 1 auto; max-width:100%; overflow-x:auto; scrollbar-width:none }
.seg::-webkit-scrollbar{ display:none }
.seg i, .seg button{
  font-style:normal; font-size:11.5px; font-weight:500; line-height:1; font-family:inherit;
  padding:6px 9px; border:0; background:none; border-radius:var(--r-pill);
  color:var(--muted); white-space:nowrap;
}
.seg button{ cursor:pointer; transition:color .15s var(--ease-ui), background .15s var(--ease-ui) }
.seg button:hover{ color:var(--text) }
.seg i.on, .seg button.on{ background:var(--surface); color:var(--text); box-shadow:0 1px 2px rgba(0,0,0,.06) }

/* ---- Verlauf ------------------------------------------------------------ */
.tc-plot{ padding:6px 12px 0; position:relative }
/* recharts draws a vertical cursor at the hovered category; this is the same
   line in the page's own hairline rather than recharts' neutral #ccc, which is
   the only grey on this page that would not be a warm one. */
.tc-cur{ stroke:var(--hairline-strong); stroke-width:1 }
.tc-hit{ fill:transparent }
.tc-tip{
  position:absolute; z-index:4; top:0; left:0; pointer-events:none; opacity:0;
  min-width:132px; padding:9px 11px; font-size:12px; line-height:1.5; color:var(--text);
  border:1px solid var(--hairline); border-radius:12px; background:var(--surface);
  box-shadow:var(--shadow-float); transition:opacity .12s var(--ease-ui);
}
.tc-tip.on{ opacity:1 }
.tc-tip p{ margin:0; font-variant-numeric:tabular-nums }
.tc-tip-d{ margin-bottom:3px !important; font-weight:500 }
.tc-tip-r--s{ color:var(--rose-fg) }
.tc-tip-r--l{ color:var(--blue-fg) }
.tc-svg{ width:100%; height:auto; display:block; overflow:visible }
.tc-grid line{ stroke:var(--hairline); stroke-width:1 }
.tc-tick text{ font-size:11px; fill:var(--muted); font-variant-numeric:tabular-nums }
.tc-tick--l text{ text-anchor:end }
.tc-tick--r text{ text-anchor:start }
.tc-tick--x text{ text-anchor:middle }
.tc-tick--x text:first-child{ text-anchor:start }
.tc-tick--x text:last-child{ text-anchor:end }
.tc-line{ fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round }
.tc-line--spend{ stroke:var(--rose-fg) }
.tc-line--leads{ stroke:var(--blue-fg) }
.tc-dot circle{ fill:var(--blue-fg) }
/* the chart draws itself once, when it first comes into view. pathLength="1"
   makes the dash geometry independent of the real path length, so the two
   lines finish together however long each one actually is. */
.tc[data-draw] .tc-line{ stroke-dasharray:1; stroke-dashoffset:1 }
.tc[data-draw] .tc-dot{ opacity:0 }
.tc[data-draw].is-drawn .tc-line{ stroke-dashoffset:0; transition:stroke-dashoffset 1.5s var(--ease-ui) }
.tc[data-draw].is-drawn .tc-line--leads{ transition-delay:.18s }
.tc[data-draw].is-drawn .tc-dot{ opacity:1; transition:opacity .5s ease 1.25s }
.tc-leg{
  display:flex; flex-wrap:wrap; align-items:center; gap:4px 16px;
  padding:8px 15px 13px; font-size:12px; color:var(--muted);
}
.tc-leg > span{ display:inline-flex; align-items:center; gap:7px }
.tc-leg .ln{ width:16px; height:2px; border-radius:2px; background:var(--c) }
.see{ margin-left:auto; font-style:normal; font-size:12px; font-weight:500; color:var(--muted) }
.ui-block-h .bh{ display:flex; align-items:center; gap:8px }
.ui-block-h .ct{
  font-size:10.5px; font-weight:500; padding:1px 7px; border-radius:var(--r-pill);
  background:var(--surface-2); color:var(--muted);
}

.ui-block{ background:var(--surface); border:1px solid var(--hairline); border-radius:var(--r-card); overflow:hidden }
.ui-block-h{ display:flex; align-items:center; justify-content:space-between; gap:10px; padding:12px 15px; border-bottom:1px solid var(--hairline) }
.ui-block-h b{ font-size:14px; font-weight:500 }
.ui-block-h span{ font-size:12px; color:var(--subtle) }
.ui-prop{ display:flex; align-items:center; gap:14px; padding:13px 15px }
.ui-prop + .ui-prop{ border-top:1px solid var(--hairline) }
.ui-prop .tx{ min-width:0; flex:1 1 auto }
.ui-prop .tx .hd{ display:flex; align-items:center; gap:7px; min-width:0 }
.ui-prop .tx .hd i{ font-style:normal; font-size:11.5px; color:var(--muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.ui-prop .tx b{ display:block; margin-top:7px; font-size:14px; font-weight:500; letter-spacing:-.01em }
.ui-prop .tx > span.tnum{ display:block; margin-top:3px; font-size:12px; color:var(--muted) }
.ui-prop .acts{ display:flex; gap:7px; flex:0 0 auto }
.ui-prop .acts i{
  font-style:normal; font-size:12.5px; font-weight:500; padding:7px 13px; border-radius:var(--r-pill);
}
.ui-prop .acts i:first-child{ background:var(--primary); color:var(--primary-fg) }
.ui-prop .acts i:last-child{ border:1px solid var(--hairline-strong); color:var(--muted) }
.chip{
  display:inline-flex; align-items:center; gap:6px; flex:0 0 auto;
  font-size:11.5px; font-weight:500; padding:4px 9px; border-radius:var(--r-pill);
  background:var(--slate-bg); color:var(--slate-fg);
}
.chip--blue{ background:var(--blue-bg); color:var(--blue-fg) }
.chip--amber{ background:var(--amber-bg); color:var(--amber-fg) }
.chip--emerald{ background:var(--emerald-bg); color:var(--emerald-fg) }
.chip--rose{ background:var(--rose-bg); color:var(--rose-fg) }
.chip--slate{ background:var(--slate-bg); color:var(--slate-fg) }

/* ============================================================= logo row */
.logos{ text-align:center }
.logos p{ font-size:13px; color:var(--subtle) }
.logos ul{
  list-style:none; margin:18px 0 0; padding:0;
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:clamp(20px,3.4vw,52px);
}
/* Every mark here is the company's own, in its own colours: Google Ads,
   Analytics and the Tag Manager from Google's own asset host, the Search
   Console from the current icon the owner supplied, Slack and LinkedIn from
   Brandfetch. Nothing on this row is drawn by us and nothing is tinted — a
   "works with" row whose logos are approximations is the first thing a reader
   who knows those products will notice. */
.logos li{ display:flex; align-items:center; gap:9px; color:var(--muted);
  transition:color .2s ease, opacity .2s ease; opacity:.86 }
.logos li:hover{ color:var(--text); opacity:1 }
.logos svg, .logos img{ width:22px; height:22px; flex:0 0 auto; display:block; object-fit:contain }
.logos img{ border-radius:4px }
.logos span{ font-size:14px; font-weight:500; letter-spacing:-.01em; white-space:nowrap }

/* ============================================================= pains */
.pains{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:clamp(12px,1.6vw,20px) }
.pain{ background:var(--surface); border:1px solid var(--hairline); border-radius:var(--r-card); padding:clamp(18px,2vw,26px) }
.pain b{ display:block; font-size:17px; font-weight:500; letter-spacing:-.015em; margin-bottom:9px }
.pain p{ font-size:14.5px; line-height:1.6; color:var(--muted) }

/* ============================================================= steps */
.steps{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:clamp(14px,2vw,26px); counter-reset:step }
.step{ position:relative }
.step-n{
  display:inline-flex; align-items:center; justify-content:center;
  width:34px; height:34px; border-radius:var(--r-pill);
  background:var(--text); color:var(--surface); font-size:14px; font-weight:500;
}
.step h3{ margin-top:16px }
.step p{ margin-top:10px; font-size:15px; line-height:1.62; color:var(--muted) }
.step-shot{
  margin-top:18px; background:var(--surface); border:1px solid var(--hairline);
  border-radius:var(--r-card); padding:14px; min-height:132px;
  box-shadow:var(--shadow-hover);
}
.step-shot .row{ display:flex; align-items:center; gap:9px; padding:7px 0; font-size:12.5px; color:var(--muted) }
.step-shot .row + .row{ border-top:1px solid var(--hairline) }
.step-shot .row .dt{ width:8px; height:8px; border-radius:50%; background:var(--dot,var(--slate-fg)); flex:0 0 auto }

/* The connection rows, in the shape the Integrationen cards use: the mark on a
   WHITE tile — "that is how the brands ask to be shown, and a dark tile would
   swallow the Analytics orange" (BrandMark.tsx) — the name, and a StatusPill,
   which is a dot in the tint's own colour plus the word. The word is the one
   statusMeta() returns: "Verbunden", with a capital V. */
.step-shot .cn{ display:flex; align-items:center; gap:10px; padding:8px 0; font-size:13px }
.step-shot .cn + .cn{ border-top:1px solid var(--hairline) }
.step-shot .cn-mk{
  width:26px; height:26px; border-radius:7px; flex:0 0 auto; display:grid; place-items:center;
  background:#fff; box-shadow:inset 0 0 0 1px var(--hairline);
}
.step-shot .cn-mk svg{ width:15px; height:15px; display:block }
.step-shot .cn-n{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.step-shot .cn .chip{ margin-left:auto; font-size:11px; padding:3px 8px }
.step-shot .lbl{ font-size:11px; font-weight:500; letter-spacing:.06em; text-transform:uppercase; color:var(--subtle); margin-bottom:8px }

/* ---- the Tagesbudget slider -------------------------------------------
   The number you set is a pill ABOVE the handle and travels with it, because a
   value parked in the middle of the row stops being the handle's value the
   moment you drag. `clamp()` keeps the pill inside the card at both ends
   without a line of JavaScript.

   Every euro on this page goes through the panel's own formatter — two
   decimals and a non-breaking space before the sign — so `30,00 €`, not
   `30 €`. `lib/format.ts` pins it to de-DE with no locale branch, which is
   why the English page shows German money too. */
.step-shot .sl{ position:relative; margin:30px 0 0 }
.step-shot .sl-val{
  position:absolute; bottom:calc(100% + 10px); left:clamp(30px, var(--p,47%), calc(100% - 30px));
  transform:translateX(-50%); white-space:nowrap;
  font-size:12.5px; font-weight:600; color:var(--text);
}
.step-shot .slider{ height:6px; border-radius:var(--r-pill); background:var(--surface-2); position:relative }
.step-shot .slider i{ position:absolute; inset:0 auto 0 0; width:var(--p,47%); border-radius:var(--r-pill); background:var(--accent); z-index:1 }
.step-shot .slider b{
  position:absolute; top:50%; left:var(--p,47%); width:18px; height:18px; margin:-9px 0 0 -9px;
  border-radius:50%; background:var(--surface); border:2px solid var(--accent);
  box-shadow:0 1px 3px rgba(22,22,26,.18); z-index:2; transition:transform .14s var(--ease);
}
/* There is no band drawn around the handle any more. It was a pale blue capsule
   spanning the ±10 % range, and it was the third thing on this card saying the
   same sentence — after the words and after the figures — in the least legible
   of the three forms. Owner, twice: *"bu background şeffaf mavi şeyi anlamadım,
   kötü duruyor"*. He is right: it overlapped the blue fill, so it read as a
   rendering fault rather than as a range, and `39,60 € – 48,40 €` under it is
   already the clearest statement the card can make. The range is still
   computed — it is what those figures are. */

/* the grab zone is 24px tall and invisible; the groove stays 6px */
.step-shot[data-demo="budget"] .slider{ cursor:ew-resize; touch-action:none }
.step-shot[data-demo="budget"] .slider::after{ content:''; position:absolute; inset:-9px 0; border-radius:inherit }
.step-shot[data-demo="budget"] .slider:active b{ transform:scale(1.15) }
.step-shot .scale{ display:flex; justify-content:space-between; margin-top:10px; font-size:11.5px; color:var(--subtle) }
.step-shot .sl-bd{ margin-left:auto; font-weight:500; color:var(--text) }

/* the approval card answers. It is still aria-hidden — a screen reader hears
   the sentence above it, not a button that changes nothing on the server. */
.step-shot[data-demo="approve"]{ position:relative; overflow:hidden }
.step-shot[data-demo="approve"] i{ cursor:pointer; transition:filter .15s var(--ease) }
.step-shot[data-demo="approve"] i:hover{ filter:brightness(.94) }
.step-done{
  position:absolute; inset:auto 0 0 0; display:flex; align-items:center; gap:8px;
  padding:14px; font-size:12.5px; font-weight:500; color:var(--emerald-fg);
  background:linear-gradient(0deg, var(--surface) 62%, rgba(255,255,255,0));
  opacity:0; transform:translateY(8px); pointer-events:none;
  transition:opacity .26s var(--ease), transform .26s var(--ease-out);
}
.step-done svg{ width:16px; height:16px; flex:0 0 auto; stroke:currentColor; stroke-width:2.4; fill:none; stroke-linecap:round; stroke-linejoin:round }
.step-shot.is-done .step-done{ opacity:1; transform:none }
.step-shot.is-off .step-done{
  opacity:1; transform:none; color:var(--muted);
}
.step-shot.is-off .step-done svg{ display:none }
.step-done .nope{ display:none }
.step-shot.is-off .step-done .yes{ display:none }
.step-shot.is-off .step-done .nope{ display:inline }
.step-shot.is-done .acts, .step-shot.is-off .acts{ opacity:0; transition:opacity .2s ease }

/* ============================================================= features */
.feats{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:clamp(12px,1.6vw,20px) }
.feat{
  background:var(--surface); border:1px solid var(--hairline); border-radius:var(--r-card);
  padding:clamp(20px,2.2vw,28px); transition:box-shadow .2s ease, transform .2s var(--ease);
}
.feat:hover{ box-shadow:var(--shadow-hover); transform:translateY(-2px) }
.feat-ic{
  width:38px; height:38px; border-radius:10px; display:grid; place-items:center;
  background:var(--ic-bg,var(--blue-bg)); color:var(--ic-fg,var(--blue-fg)); margin-bottom:16px;
}
.feat-ic svg{ width:19px; height:19px }
.feat h3{ font-size:17.5px }
.feat p{ margin-top:9px; font-size:14.5px; line-height:1.62; color:var(--muted) }

/* ============================================================= control */
.control{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:clamp(12px,1.6vw,20px) }
.ctl{ background:var(--surface); border:1px solid var(--hairline); border-radius:var(--r-card); overflow:hidden }
.ctl-h{ display:flex; align-items:center; gap:9px; padding:15px 18px; border-bottom:1px solid var(--hairline);
  font-size:14px; font-weight:500 }
.ctl-h::before{ content:''; width:9px; height:9px; border-radius:50%; background:var(--dot); flex:0 0 auto }
.ctl ul{ list-style:none; margin:0; padding:14px 18px 18px }
.ctl li{ position:relative; padding-left:20px; font-size:14.5px; line-height:1.55; color:var(--muted) }
.ctl li + li{ margin-top:10px }
/* A hollow square in front of "Kalte B2B-E-Mails" reads as an unticked
   checkbox — as if the thing were merely not done yet. A dot in the column's
   own colour just marks the item, which is what it is. */
.ctl li::before{
  content:''; position:absolute; left:2px; top:.62em; width:6px; height:6px; border-radius:50%;
  background:var(--dot); opacity:.55;
}
.ctl li em{ font-style:normal; color:var(--text) }
.ctl-note{ padding:0 18px 18px; font-size:12.5px; color:var(--subtle) }

/* ============================================================= case */
.case{ display:grid; grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr); gap:clamp(24px,3.6vw,56px); align-items:center }
.case figure{ margin:0 }
.case img{ width:100%; height:auto; border-radius:var(--r-card); border:1px solid var(--hairline) }
.case figcaption{ margin-top:10px; font-size:12.5px; color:var(--subtle) }
.finds{ list-style:none; margin:26px 0 0; padding:0 }
.finds li{ display:flex; gap:14px; padding:15px 0; border-top:1px solid var(--hairline) }
.finds li:last-child{ border-bottom:1px solid var(--hairline) }
.finds .n{ flex:0 0 auto; min-width:78px; font-size:19px; font-weight:500; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums; color:var(--sig,var(--text)) }
.finds .t{ font-size:14.5px; line-height:1.58; color:var(--muted) }
.case-note{ margin-top:20px; padding:14px 16px; border-radius:var(--r-card);
  background:var(--surface-2); font-size:13.5px; line-height:1.6; color:var(--muted) }

/* ============================================================= faq */
.faq{ max-width:820px; margin-inline:auto }
.faq details{ border-bottom:1px solid var(--hairline) }
.faq details:first-of-type{ border-top:1px solid var(--hairline) }
.faq summary{
  list-style:none; cursor:pointer; display:flex; align-items:center; gap:16px;
  padding:19px 2px; font-size:clamp(16px,1.35vw,18px); font-weight:500; letter-spacing:-.014em;
}
.faq summary::-webkit-details-marker{ display:none }
.faq summary::after{
  content:''; flex:0 0 auto; margin-left:auto; width:11px; height:11px;
  border-right:1.6px solid var(--subtle); border-bottom:1.6px solid var(--subtle);
  transform:rotate(45deg) translate(-3px,-3px); transition:transform .22s var(--ease);
}
.faq details[open] summary::after{ transform:rotate(225deg) translate(-3px,-3px) }
.faq summary:hover{ color:var(--accent) }
.faq .ans{ padding:0 44px 22px 2px; font-size:15px; line-height:1.66; color:var(--muted) }

/* ============================================================= final cta */
.cta{
  background:var(--text); color:#fff; border-radius:20px;
  padding:clamp(34px,5vw,68px) clamp(24px,4vw,56px); text-align:center;
}
.cta .h2{ max-width:20ch; margin-inline:auto }
.cta p{ max-width:52ch; margin:16px auto 0; font-size:16px; line-height:1.6; color:rgba(255,255,255,.72) }
.cta .btn--primary{ background:#fff; color:var(--text) }
.cta .btn--primary:hover{ background:#eceae5 }
.cta .btn--ghost{ background:transparent; color:#fff; border-color:rgba(255,255,255,.28) }
.cta .btn--ghost:hover{ background:rgba(255,255,255,.08) }
.cta .btn-row{ margin-top:28px }
.cta-note{ margin-top:18px; font-size:13px; color:rgba(255,255,255,.55) }

/* ============================================================= footer */
.foot{ border-top:1px solid var(--hairline); background:var(--surface) }
.foot-grid{ display:grid; grid-template-columns:minmax(0,1.5fr) repeat(3,minmax(0,1fr));
  gap:clamp(22px,3vw,44px); padding-block:clamp(38px,5vw,64px) }
.foot-brand .brand{ margin-bottom:14px }
.foot-brand p{ font-size:14px; line-height:1.6; color:var(--muted); max-width:34ch }
.foot h4{ font-size:12px; font-weight:500; letter-spacing:.06em; text-transform:uppercase; color:var(--subtle); margin-bottom:14px }
.foot ul{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:10px }
.foot li a{ font-size:14.5px; color:var(--muted); transition:color .18s ease }
.foot li a:hover{ color:var(--text) }
.foot .legal-pending{ font-size:14.5px; color:var(--subtle) }
.foot-base{ display:flex; flex-wrap:wrap; gap:10px 24px; align-items:center;
  padding-block:20px; border-top:1px solid var(--hairline); font-size:13px; color:var(--subtle) }
.foot-base .sp{ margin-left:auto }

/* ============================================================= reveal */
[data-rv]{ opacity:0; transform:translate3d(0,18px,0) }
[data-rv].rv-in{ opacity:1; transform:none;
  transition:opacity .6s ease, transform .7s var(--ease);
  transition-delay:var(--rv-d,0ms) }
@media (prefers-reduced-motion:reduce){
  [data-rv]{ opacity:1 !important; transform:none !important }
  .feat:hover,.btn:hover{ transform:none !important }
}

/* ============================================================= responsive */
@media (max-width:1040px){
  .pains,.steps,.feats,.control{ grid-template-columns:repeat(2,minmax(0,1fr)) }
  .feats > :last-child{ grid-column:span 2 }
  .steps > :last-child{ grid-column:span 2 }
  .case{ grid-template-columns:1fr }
  .shot-body{ grid-template-columns:150px minmax(0,1fr) }
  .ui-tiles{ grid-template-columns:repeat(2,minmax(0,1fr)) }
  .foot-grid{ grid-template-columns:repeat(2,minmax(0,1fr)) }
}
@media (max-width:760px){
  .nav-links{
    position:fixed; inset:var(--nav-h) 0 auto 0; flex-direction:column; align-items:stretch; gap:0;
    padding:8px var(--pad) 18px; background:var(--canvas); border-bottom:1px solid var(--hairline);
    box-shadow:var(--shadow-hover);
    transform:translate3d(0,-8px,0); opacity:0; visibility:hidden; pointer-events:none;
    transition:transform .24s var(--ease), opacity .2s ease, visibility 0s linear .24s;
  }
  .nav.menu-open .nav-links{ transform:none; opacity:1; visibility:visible; pointer-events:auto; transition-delay:0s }
  .nav-links .nav-link{ padding:13px 2px; font-size:16px; border-bottom:1px solid var(--hairline) }
  .nav-burger{ display:block }
  .nav-tools .btn{ display:none }
  .pains,.steps,.feats,.control{ grid-template-columns:1fr }
  .feats > :last-child,.steps > :last-child{ grid-column:auto }
  /* The shot is the product, so it does not get cropped away on a phone — the
     rail goes and the pane takes the width, which is exactly what the Werkbank
     itself does below 768. */
  .shot-body{ grid-template-columns:1fr; min-height:0 }
  .ui-rail{ display:none }
  /* two tiles per row, and one of the labels wraps to two lines — without a
     floor under the label the two big numbers beside each other sit at
     different heights, which is the first thing the eye picks up in a grid */
  .ui-tile .lb{ display:block; min-height:2.6em }
  .ui-prop{ flex-wrap:wrap }
  .ui-prop .acts{ width:100% }
  .ui-prop .acts i{ flex:1 1 auto; text-align:center }
  .finds li{ flex-direction:column; gap:4px }
  .finds .n{ min-width:0 }
  .foot-grid{ grid-template-columns:1fr }
  .foot-base .sp{ margin-left:0 }
  .btn{ width:100% }
  .btn-row{ flex-direction:column }
  .hero-trust{ flex-direction:column; align-items:center; gap:10px }
}

/* ============================================================= the token
   hops.ai sets a small rounded chip inside its display line — a face, a
   document, a bot — and that single move is most of why the page has a
   character rather than a layout. Ours carries the thing the sentence is
   actually about: the Google Ads mark, in its own colour, at reading size.
   It is the only place on the page where a brand colour appears at full
   strength, so it reads as an object in the sentence rather than as
   decoration. */
.h1 .nb{ white-space:nowrap }
.tok{
  display:inline-flex; align-items:center; justify-content:center;
  width:.92em; height:.92em; margin-inline:0; vertical-align:-.06em;
  border-radius:.24em; background:var(--surface); border:1px solid var(--hairline);
  box-shadow:0 1px 2px rgba(0,0,0,.05), 0 6px 14px -6px rgba(0,0,0,.18);
  transform:rotate(-4deg);
}
.tok img{ width:.68em; height:.68em; display:block; object-fit:contain }

/* ---------------------------------------------------- the shot, lit
   A page whose every surface is white paper has no depth, and the product
   shot is the one thing on it that has to look like an object. One soft
   accent wash underneath it does what a drop shadow cannot: it makes the
   card look lit rather than cut out. */
.shot-wrap{ position:relative; margin-top:clamp(34px,4.5vw,58px) }
.shot-wrap::before{
  content:''; position:absolute; left:6%; right:6%; top:8%; bottom:-6%;
  background:radial-gradient(60% 60% at 50% 50%, rgba(47,107,255,.16), rgba(47,107,255,0) 70%);
  filter:blur(28px); pointer-events:none;
}
.shot-wrap .shot{ margin-top:0 }

/* the rail carries the product's own icons — lucide, the same set and the
   same order as panel/frontend/src/app/components/shell/nav-items.ts */
.ui-rail a svg{
  width:16px; height:16px; flex:0 0 auto; color:var(--subtle);
  stroke:currentColor; stroke-width:2; fill:none;
  stroke-linecap:round; stroke-linejoin:round;
}
.ui-rail a.on svg{ color:var(--text) }

/* the status dot breathes, because the screen behind it is live */
.ui-status .dt{ animation:pulse 2.8s ease-in-out infinite }
@keyframes pulse{
  0%,100%{ box-shadow:0 0 0 0 color-mix(in srgb, var(--dot) 42%, transparent) }
  55%{ box-shadow:0 0 0 5px color-mix(in srgb, var(--dot) 0%, transparent) }
}
/* ============================================================= the night
   The one dark section, and the reason the page has a middle. Everything
   above it is the offer; this is the product actually working, on a real
   morning, in the order it happened — which is the single most convincing
   thing we can show somebody who has been sent monthly PDFs for years.

   It is also where v1 survives: same ground, same ring, same blue. A light
   page with one dark room in it reads as designed; a light page all the way
   through reads as a template. */
/* The dark room, rebuilt twice.
   Owner, 2026-09-17, on the first dark version: *"bu çok kötü, renk zaten saçma
   olmuş, açık renkten koyuya, hiç UX friendly değil."* Both halves of that were
   right and they are different faults.

   The HUE was invented. #05070b with a #2f6bff glow is a colour that appears
   nowhere in the product; next to --text (#16161a) it reads as a different
   brand. The panel already has a dark theme — tokens.css [data-theme="dark"],
   a warm-neutral graphite — so this section now wears it. The dark is the
   page's own ink, and the blue is the one the product itself lightens to in
   the dark (#6b95ff). Nothing here is picked by eye any more.

   The CUT was the other fault: a full-bleed jump from paper to near-black with
   no transition. Rather than smudging a gradient between them — which reads as
   a print error — the dark is now a CARD on the paper: inset, rounded, with the
   page's own radius language. The reader sees a thing on a page instead of a
   second page, which is what "UX friendly" meant here. */
.night{ position:relative; padding-block:var(--sec-y) }
.night-card{
  position:relative; isolation:isolate; overflow:hidden;
  border-radius:clamp(18px,2.2vw,30px);
  background:linear-gradient(176deg, #efefeb 0%, #f4f4f1 52%, #fafaf8 100%);
  color:var(--n-text);
  padding:clamp(46px,6vw,88px) clamp(24px,4.4vw,72px) clamp(92px,11vw,150px);
  box-shadow:inset 0 0 0 1px var(--n-hairline), 0 2px 10px rgba(22,22,26,.04), 0 34px 76px -40px rgba(22,22,26,.26);
  --muted:var(--n-muted); --subtle:var(--n-subtle); --hairline:var(--n-hairline);
  --hairline-strong:var(--n-hairline-strong);
}
.night::before{                              /* the mark, held in the dark */
  content:''; position:absolute; z-index:-1; pointer-events:none;
  right:-14%; top:-24%; width:min(62vw,720px); aspect-ratio:1; border-radius:50%;
  border:1px solid rgba(122,162,255,.22);
  box-shadow:0 0 120px 10px rgba(47,107,255,.14) inset, 0 0 90px rgba(47,107,255,.10);
}
.night::after{
  content:''; position:absolute; inset:auto 0 -40% 0; height:80%; z-index:-1; pointer-events:none;
  background:radial-gradient(52% 60% at 22% 0%, rgba(47,107,255,.16), rgba(47,107,255,0) 70%);
}
.night .eyebrow{ color:var(--n-muted) }
.night .h2{ color:var(--n-text) }
.night .lead{ color:var(--n-muted) }

/* the timeline */
.tl{ list-style:none; margin:clamp(24px,3vw,38px) 0 0; padding:0; position:relative }
.tl::before{                                  /* the thread the night runs on */
  content:''; position:absolute; left:73px; top:14px; bottom:26px; width:1px;
  background:linear-gradient(rgba(47,107,255,.06), rgba(47,107,255,.32), rgba(47,107,255,.06));
}
.tl li{
  position:relative; display:grid; grid-template-columns:56px 34px minmax(0,1fr);
  align-items:baseline; gap:0 4px; padding:13px 0;
}
.tl .t{
  font-size:13px; font-variant-numeric:tabular-nums; letter-spacing:.01em; color:var(--n-accent);
}
.tl .d{ position:relative; height:1em }
.tl .d::before{
  /* The thread is drawn at left:73px on .tl; this dot is positioned inside
     the second grid column, which starts at 60px — 56px of column one plus the
     4px column gap. The gap is what was missed: at left:14px the dot's centre
     landed at 77.5 and the thread's at 73.5, and every dot sat four pixels to
     the right of the line it was supposed to be on. */
  content:''; position:absolute; left:10px; top:.34em; width:7px; height:7px; border-radius:50%;
  background:#fff; border:1.5px solid rgba(47,107,255,.45);
}
.tl li:last-child .d::before{ background:var(--n-accent); box-shadow:0 0 0 3px rgba(47,107,255,.16) }
.tl .x{ font-size:15px; line-height:1.6; color:var(--n-muted) }
.tl li:last-child .x{ color:var(--n-text) }
.tl .x b{ color:var(--n-text); font-weight:500 }
.night-close{
  margin-top:clamp(22px,2.6vw,32px); padding-top:20px;
  border-top:1px solid var(--n-hairline);
  font-size:clamp(15px,1.2vw,17px); line-height:1.6; color:var(--n-muted); max-width:56ch;
}
.night-close b{ color:var(--n-text); font-weight:500 }

@media (max-width:900px){
  .tl li{ grid-template-columns:52px 26px minmax(0,1fr) }
  .tl::before{ left:64px }
  /* column two now starts at 56 (52 + the 4px gap), so 5 puts the dot's
     centre at 64.5 — the thread's centre. Same arithmetic as above. */
  .tl .d::before{ left:5px }
}
@media (prefers-reduced-motion:reduce){
  .ui-status .dt{ animation:none }
}






/* ======================================================= the Besucher panel
   The first attempt drew an abstract "flow" — three floating cards joined by a
   dashed thread. The owner's verdict was exact: *"bu tam bir çöp … niye
   panelden almıyorsun, nasıl görünüyorsa panelde."* The second attempt was the
   right shape with the wrong contents, and he was right again: *"bizim panelin
   kodlarina bak ona gore detay koy — siteye nereden geldi, kac saniye gezdi
   veya organic, google, keywordlar."*

   So this is `panel/frontend/src/app/pages/BesucherPage.tsx`, rebuilt in markup
   with the fields it actually carries (lib/api/visitors.ts): sources, keyword,
   pages, duration_s, sessions_count, score/hot, city, country, device — every
   one under the panel's own word for it (lib/visitors.ts, lib/sessions.ts):
   Heiß / Interessiert / Kurz vorbei, Google Ads / Google (organisch) / Direkt /
   Verweis, "Keyword folgt in ~3 Std." for a click whose attribution has not
   landed yet. The Keywords panel beside the list is the panel's own, and it is
   the thing the owner asked for by name.

   Drawn rather than screenshotted, so it stays sharp at any density and
   switches language with the rest of the page.

   The companies are real and public. They are also, deliberately, companies
   from the customer's own region — Benteler and Phoenix Contact are down the
   road from Event Liner — because a Mittelständler in OWL believes a list with
   his neighbours on it, and reads a list of Californian platforms as somebody
   else's product. Nothing is claimed about any of them, and the note under the
   screen says which parts are invented. */
.pv{ display:grid; grid-template-columns:172px minmax(0,1fr) 296px; min-height:520px; text-align:left }

.pv-rail{ border-right:1px solid var(--hairline); padding:12px 8px; background:var(--surface) }
.pv-rail .ui-rail-h{ padding:5px 9px 9px }
.pv-rail a{ display:flex; align-items:center; gap:9px; padding:7px 9px; border-radius:var(--r-control); font-size:13px; color:var(--muted) }
.pv-rail a.on{ background:var(--surface-2); color:var(--text); font-weight:500 }
.pv-rail svg{ width:15px; height:15px; flex:0 0 auto; color:var(--subtle); stroke:currentColor; stroke-width:2; fill:none; stroke-linecap:round; stroke-linejoin:round }
.pv-rail a.on svg{ color:var(--text) }
.pv-rail .badge{ margin-left:auto; font-size:10.5px; font-weight:600; padding:1px 6px; border-radius:var(--r-pill); background:var(--primary); color:var(--primary-fg) }

.pv-main{ background:var(--canvas); min-width:0; display:flex; flex-direction:column }

/* PageHeader: the page's name, the sentence under it, the search and the period */
.pv-head{ padding:13px 16px; background:var(--surface); border-bottom:1px solid var(--hairline) }
.pv-ti b{ display:block; font-size:15px; font-weight:500; letter-spacing:-.015em }
.pv-ti i{ display:block; margin-top:3px; font-style:normal; font-size:12px; line-height:1.5; color:var(--muted) }
.pv-tools{ display:flex; align-items:center; gap:8px; margin-top:11px; flex-wrap:wrap }
.pv-find{
  display:inline-flex; align-items:center; gap:7px; flex:1 1 170px; min-width:0;
  height:30px; padding:0 11px; border:1px solid var(--hairline); border-radius:var(--r-pill);
  background:var(--surface); font-size:11.5px; color:var(--subtle); white-space:nowrap;
}
.pv-find svg{ width:12px; height:12px; stroke:currentColor; stroke-width:2; fill:none; flex:0 0 auto; stroke-linecap:round }
.pv-find span{ overflow:hidden; text-overflow:ellipsis }

.pv-stats{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:9px; padding:13px 16px 0 }
.pv-stats .ui-tile{ padding:11px 12px }
.pv-stats .ui-tile b{ font-size:22px }

.pv-cols{ display:grid; grid-template-columns:minmax(0,1fr) 224px; gap:13px; padding:13px 16px 16px; align-items:start }
.pv-panel{ background:var(--surface); border:1px solid var(--hairline); border-radius:var(--r-card); overflow:hidden }
.pv-panel-h{ display:flex; align-items:center; gap:8px; padding:11px 14px 0 }
.pv-panel-h b{ font-size:13.5px; font-weight:500; letter-spacing:-.012em }
.pv-panel-h .ct{
  font-size:10.5px; font-weight:500; padding:1px 7px; border-radius:var(--r-pill);
  background:var(--surface-2); color:var(--muted);
}
.pv-panel-h .pv-filt{
  margin-left:auto; display:inline-flex; align-items:center; gap:5px; font-size:11px; font-weight:500; padding:2px 9px; border-radius:var(--r-pill);
  border:1px solid var(--blue-fg); background:var(--blue-bg); color:var(--text); white-space:nowrap;
}
.pv-panel-d{ padding:3px 14px 10px; font-size:11.5px; line-height:1.45; color:var(--muted) }

/* the day heading sits on --surface-2, the way it does in the panel */
.pv-day{
  padding:6px 14px; background:var(--surface-2); border-block:1px solid var(--hairline);
  font-size:11.5px; font-weight:500; color:var(--muted);
}
.pv-day + .pv-row{ border-top:0 }

/* VisitorRow: grid-cols-[auto_minmax(0,1fr)_auto], gap-x-3, px-4 py-3 */
.pv-row{ display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:center; gap:0 12px; padding:11px 14px }
.pv-row + .pv-row{ border-top:1px solid var(--hairline) }
.pv-row.is-on{ background:var(--surface-hover) }

/* VisitorAvatar: when the enrichment found a logo the tile IS the logo, on
   white, filling the 40px square at a 9px radius. The two-letter Monogram
   (ds/monogram.tsx) is only the fallback, and its tint is what .pv-logo falls
   back to without --brand. The monogram is never rose, because the traffic
   light's red means "handeln" and a company is not a verdict. */
.pv-logo{
  width:40px; height:40px; border-radius:9px; flex:0 0 auto; display:grid; place-items:center;
  font-size:14px; font-weight:600; letter-spacing:-.01em;
  background:var(--slate-bg); color:var(--slate-fg); overflow:hidden;
}
.pv-logo:has(img){ background:var(--surface); box-shadow:inset 0 0 0 1px var(--hairline) }
.pv-logo img{ width:100%; height:100%; display:block; object-fit:cover }
.pv-logo--lg{ width:44px; height:44px; font-size:15px }

.pv-r{ min-width:0 }
.pv-r .l1{ display:flex; align-items:center; gap:7px; min-width:0 }
.pv-r .l1 b{ font-size:13.5px; font-weight:500; letter-spacing:-.012em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.pv-r .l2{ display:flex; align-items:center; gap:6px; margin-top:2px; font-size:11.5px; color:var(--muted); min-width:0 }
.pv-r .l2 svg{ width:13px; height:13px; flex:0 0 auto; stroke:currentColor; stroke-width:2; fill:none; stroke-linecap:round; stroke-linejoin:round }
.pv-r .l2 > span:first-child{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.pv-r .l3{ display:flex; align-items:center; flex-wrap:wrap; gap:5px 8px; margin-top:6px; font-size:11.5px; color:var(--muted) }
.pv-r .sl{ font-size:11px; flex:0 0 auto }
.pv-r .kw{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.pv-r .kw.is-pending{ font-style:italic; color:var(--subtle) }

/* the score bar is h-1 w-24 in the panel — 4px by 96px, on --surface-2 */
.pv-bar{
  width:96px; height:4px; border-radius:var(--r-pill); background:var(--surface-2);
  flex:0 0 auto; overflow:hidden; position:relative;
}
.pv-bar::after{
  content:''; position:absolute; inset:0 auto 0 0; width:var(--w); border-radius:var(--r-pill); background:var(--c);
  transform-origin:left; transform:scaleX(0); transition:transform .9s var(--ease-out) var(--bd,0ms);
}
[data-rv].rv-in .pv-bar::after{ transform:scaleX(1) }
.pv-row:nth-child(2) .pv-bar::after{ --bd:120ms }
.pv-row:nth-child(3) .pv-bar::after{ --bd:200ms }
.pv-row:nth-child(4) .pv-bar::after{ --bd:280ms }

.pv-m{ text-align:right; font-size:11px; color:var(--muted); white-space:nowrap; display:flex; flex-direction:column; gap:1px; align-items:flex-end }
.pv-m b{ font-size:12.5px; font-weight:500; color:var(--text) }

/* the Keywords panel — "Google Ads · Heute · was Besucher brachte" */
.pv-kwr{ display:flex; align-items:center; gap:9px; padding:8px 14px }
.pv-kwr + .pv-kwr{ border-top:1px solid var(--hairline) }
.pv-kwr-t{ min-width:0; flex:1 1 auto }
.pv-kwr-t b{ display:block; font-size:12.5px; font-weight:500; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.pv-kwr-t i{ display:block; margin-top:1px; font-style:normal; font-size:10.5px; color:var(--muted) }

/* the Assistent rail */
.pv-ass{ border-left:1px solid var(--hairline); background:var(--surface); padding:14px; min-width:0 }
.pv-ass-h{ display:flex; align-items:flex-start; gap:11px }
.pv-ass-t{ min-width:0 }
.pv-ass-t b{ display:block; font-size:14px; font-weight:600; letter-spacing:-.015em; line-height:1.3 }
.pv-ass-t i{ display:block; margin-top:1px; font-style:normal; font-size:11.5px; color:var(--muted) }
.pv-ass-t .l1{ display:flex; flex-wrap:wrap; gap:5px; margin-top:7px }
.pv-btn{
  display:flex; align-items:center; justify-content:center; gap:7px; margin-top:12px; height:32px;
  border-radius:var(--r-pill); background:var(--primary); color:var(--primary-fg); font-size:12px; font-weight:500;
}
.pv-btn svg{ width:13px; height:13px; flex:0 0 auto; stroke:currentColor; stroke-width:2; fill:none }
.pv-quad{
  display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:6px; margin:12px 0 0;
  padding:9px 11px; border-radius:var(--r-control); background:var(--surface-2);
}
.pv-quad dt{ font-size:10.5px; color:var(--muted) }
.pv-quad dd{ margin:1px 0 0; font-size:12.5px; font-weight:500 }
.pv-sec{ margin-top:11px; padding:9px 11px; border:1px solid var(--hairline); border-radius:var(--r-control) }
.pv-sec h4{ display:flex; align-items:center; gap:6px; font-size:11.5px; font-weight:600 }
.pv-sec h4 svg{ width:13px; height:13px; flex:0 0 auto; stroke:currentColor; stroke-width:2; fill:none; stroke-linecap:round; color:var(--subtle) }
.pv-srcs{ display:flex; flex-wrap:wrap; gap:5px; margin-top:7px }
.pv-desc{ margin-top:6px; font-size:11.5px; line-height:1.55; color:var(--muted) }
.pv-fine{ margin-top:7px; font-size:10.5px; line-height:1.5; color:var(--subtle) }
.pv-sec + .pv-fine{ margin-top:9px }
.pv-facts .lk{ font-style:normal; color:var(--accent); text-decoration:underline; text-underline-offset:2px }
.pv-facts .pv-li{ padding:1px 6px; font-size:10px }
.pv-facts{ display:grid; grid-template-columns:82px minmax(0,1fr); gap:3px 8px; margin:7px 0 0; font-size:11px }
.pv-facts dt{ color:var(--muted) }
.pv-facts dd{ margin:0; min-width:0; overflow-wrap:anywhere }
.pv-ppl{ display:flex; align-items:center; gap:9px; padding:7px 0 }
.pv-ppl + .pv-ppl{ border-top:1px solid var(--hairline) }
.pv-ppl .av{
  width:30px; height:30px; border-radius:50%; flex:0 0 auto; display:grid; place-items:center;
  background:var(--surface-2); color:var(--muted); font-size:10.5px; font-weight:500;
}
.pv-ppl .nm{ min-width:0; flex:1 1 auto }
.pv-ppl .nm b{ display:block; font-size:12px; font-weight:500 }
.pv-ppl .nm i{ display:block; font-style:normal; font-size:10.5px; color:var(--muted) }
.pv-li{
  flex:0 0 auto; display:inline-flex; align-items:center; gap:4px; padding:3px 7px; border-radius:6px;
  border:1px solid var(--hairline); color:#0A66C2; background:var(--surface); font-size:10.5px; font-weight:500;
}
.pv-li svg{ width:12px; height:12px; flex:0 0 auto }
.pv-li.is-ghost{ color:var(--muted) }
.pv-li.is-ghost svg{ stroke:currentColor; stroke-width:2; fill:none; stroke-linejoin:round }
.pv-act{
  display:flex; align-items:center; justify-content:center; gap:7px; margin-top:12px;
  height:34px; border-radius:var(--r-pill); border:1px solid var(--hairline-strong);
  color:var(--text); font-size:12px; font-weight:500;
}
/* An inline lucide path with no width is an SVG at its default size, which in
   a flex row means "as large as the container will allow" — the call icon came
   out 200px tall and sat over the two contacts above it. Every icon in this
   mock is sized where it is used; this was the one that was missed. */
.pv-act svg{ width:14px; height:14px; flex:0 0 auto; stroke:currentColor; stroke-width:2; fill:none; stroke-linecap:round; stroke-linejoin:round }
.pv-legal{
  margin-top:9px; padding-top:8px; border-top:1px solid var(--hairline);
  font-size:10px; line-height:1.5; color:var(--muted);
}
.chip--dot::before{ content:''; width:5px; height:5px; border-radius:50%; background:currentColor; flex:0 0 auto }
.chip--outline{ background:transparent; border:1px solid var(--hairline-strong); color:var(--muted) }

.shot-note{
  max-width:74ch; margin:14px auto 0; text-align:center;
  font-size:12px; line-height:1.55; color:var(--subtle);
}

/* The three columns and the two sub-columns cannot both survive a narrow
   window: at 1180 the list and the Keywords panel end up at 400 and 224, and
   a keyword is longer than 224px. The rail goes first (it is the one part a
   reader can infer), then the Keywords panel drops under the list where it
   has the full width, then the Assistent, then the row itself unstacks. */
@media (max-width:1240px){
  .pv{ grid-template-columns:minmax(0,1fr) 282px }
  .pv-rail{ display:none }
  .pv-cols{ grid-template-columns:minmax(0,1fr) }
}
@media (max-width:980px){
  .pv-stats{ grid-template-columns:repeat(2,minmax(0,1fr)) }
}
@media (max-width:820px){
  .pv{ grid-template-columns:minmax(0,1fr); min-height:0 }
  .pv-ass{ border-left:0; border-top:1px solid var(--hairline) }
}
@media (max-width:560px){
  .pv-row{ grid-template-columns:auto minmax(0,1fr); gap:0 10px }
  .pv-m{ grid-column:2; flex-direction:row; gap:10px; margin-top:6px; text-align:left; align-items:baseline; justify-content:flex-start }
  .pv-bar{ width:64px }
}

/* ==================================================== the night, rebuilt
   First attempt: a dark band with the timeline on the left and a generated
   photograph of a control room on the right. Owner: *"burası çok kötü, v1 ile
   alakası yok ve genel temayla hiç uyumlu olmamış."* Correct on both counts —
   a stock-looking night photo is not v1, it is the opposite of v1, whose whole
   point is that nothing in it is photographed. And a dark band that carries no
   mark of its own just interrupts a light page.

   So the photograph is gone and v1's actual furniture is here instead: the
   Adhelm ring holding the sky, and the field of budget columns along the
   bottom edge — both drawn, both in the same blue, at the scale they have on
   the other page. */
/* the closing line has to clear the column field, or the last sentence of the
   section is read against the brightest thing in it */
.night::before, .night::after{ content:none }          /* the old faint arc and wash */
.night-art{ position:absolute; inset:0; z-index:-1; pointer-events:none; overflow:hidden }
.night-art .field{
  position:absolute; left:-2%; right:-2%; bottom:-1px; width:104%; height:auto;
  color:var(--n-accent); opacity:.22;
}
.night-art .wash{
  position:absolute; inset:auto 0 0 0; height:72%;
  background:radial-gradient(58% 100% at 26% 100%, rgba(47,107,255,.07), rgba(47,107,255,0) 72%);
}
/* the fine grain v1 lays over the whole frame */
.night-art .grain{
  position:absolute; inset:0; opacity:.03; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* one column, held to a reading measure, with the art around it rather than
   beside it — the two-column version put the timeline in a 50 % gutter and it
   read as a sidebar */
@media (max-width:900px){
  .night-art .field{ opacity:.6 }
}

/* ============================================================== motion
   Owner, 2026-09-17: *"biraz effect ekle ama aşırıya kaçmadan, v1'de nasıl
   efektler vardı… biraz yaratıcı ol"* — with two ThreeUI briefs attached as
   things to think with, not to copy. Both were fetched and read in full and
   their hashes verified before a line of this was written: KoiStudies
   (synthralos-halftone.html, 32cf6493414a…) and SylvaHero (inner-green-3d.html,
   69c3694bd63f…).

   What is taken is technique, not ornament. Four things, and nothing else:
   a field of turning rings behind the hero, a screen that leans toward the
   cursor and catches light on the edge nearest it, a chart that draws itself
   once, and bars that fill when they arrive. Every one of them is off under
   prefers-reduced-motion, and none of them moves anything a reader is reading. */

/* ---- 1 · the orbital field (KoiStudies) ---------------------------------
   A conic gradient is masked down to the ring's own outline with a radial
   mask, so what turns is a line rather than a disc. Three of them at three
   speeds, one of them reversed, is enough to read as depth. */
.orbits{
  position:absolute; left:50%; top:clamp(-140px,-8vw,-40px); z-index:0;
  width:min(1180px,128vw); aspect-ratio:1; translate:-50% 0;
  pointer-events:none; opacity:.85;
}
.orbits i{
  position:absolute; left:50%; top:50%; width:var(--sz); aspect-ratio:1;
  border-radius:50%; translate:-50% -50%; rotate:0deg;
  background:conic-gradient(from var(--a),
    transparent 0 12%,
    rgba(47,107,255,.05) 19%,
    rgba(47,107,255,.26) 28%,
    rgba(6,118,71,.16) 35%,
    transparent 46% 68%,
    rgba(47,107,255,.14) 77%,
    transparent 89%);
  -webkit-mask:radial-gradient(farthest-side, transparent calc(100% - var(--ln)), #000 calc(100% - var(--ln) + .75px));
          mask:radial-gradient(farthest-side, transparent calc(100% - var(--ln)), #000 calc(100% - var(--ln) + .75px));
  animation:orbit var(--sp) linear infinite;
  will-change:rotate;
}
.orbits .o1{ --sz:52%; --ln:1.5px; --a:18deg;  --sp:34s }
.orbits .o2{ --sz:76%; --ln:1px;   --a:154deg; --sp:52s; animation-direction:reverse }
.orbits .o3{ --sz:100%;--ln:1px;   --a:252deg; --sp:74s }
@keyframes orbit{ to{ rotate:360deg } }
.hero .wrap{ position:relative; z-index:1 }

/* ---- 2 · the screen leans, and the edge nearest the cursor lights up -----
   --px/--py are written on the shot once per frame, in -1…1. The rotation is
   small on purpose: this is a product screenshot, not a playing card, and
   anything past about three degrees starts to make the type wobble.
   The rim is SylvaHero's: a conic gradient whose start angle points at the
   pointer, masked to the one-pixel border with mask-composite. It is the
   reason the frame reads as lit rather than as outlined. */
[data-tilt]{
  --px:0; --py:0;
  transform:perspective(1600px) rotateY(calc(var(--px) * 1.5deg)) rotateX(calc(var(--py) * -1.1deg));
  transition:transform .55s var(--ease-out);
  will-change:transform;
}
[data-tilt].is-tracking{ transition-duration:90ms; transition-timing-function:linear }
[data-spec]{ --sa:2.4rad; --sb:0 }
[data-spec]::after{
  content:''; position:absolute; inset:0; z-index:6; padding:1px; border-radius:inherit;
  pointer-events:none; opacity:var(--sb); transition:opacity .4s var(--ease);
  background:conic-gradient(from var(--sa) at 50% 50%,
    rgba(47,107,255,0) 0deg, rgba(47,107,255,.10) 14deg, rgba(47,107,255,.85) 28deg,
    rgba(47,107,255,.18) 46deg, rgba(47,107,255,0) 68deg, rgba(47,107,255,0) 180deg,
    rgba(47,107,255,.10) 194deg, rgba(47,107,255,.85) 208deg, rgba(47,107,255,.18) 226deg,
    rgba(47,107,255,0) 248deg, rgba(47,107,255,0) 360deg);
  -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite:xor; mask-composite:exclude;
}

/* ---- 4 · the screen resolves in a stepped wipe --------------------------
   SylvaHero's portal-cut: steps(14) rather than a smooth wipe, because the
   thing being revealed is a screen filling with data, and a screen fills in
   rows. It runs once; afterwards the clip is dropped entirely, because a live
   clip-path holds a stacking context open for the whole life of the page. */
.pv{ clip-path:inset(0 100% 0 0) }
.rv-in .pv{ animation:pv-cut 1.05s steps(14,end) .15s both }
.rv-done .pv{ clip-path:none; animation:none }
@keyframes pv-cut{ from{ clip-path:inset(0 100% 0 0) } to{ clip-path:inset(0 0 0 0) } }

@media (prefers-reduced-motion:reduce){
  .orbits i{ animation:none }
  .ui-status .dt{ animation:none }
  [data-tilt]{ transform:none !important }
  [data-spec]::after{ display:none }
  .pv{ clip-path:none !important; animation:none !important }
  .tc[data-draw] .tc-line{ stroke-dasharray:none; stroke-dashoffset:0 }
  .tc[data-draw] .tc-dot{ opacity:1 }
  .ui-tile .ring circle:last-child{ stroke-dasharray:73 27; transition:none }
  .pv-bar::after{ transform:scaleX(1) !important; transition:none }
}

.pv-panel-h .pv-filt b{ font-weight:500; color:var(--muted) }

/* ---- the night, take four: the stack --------------------------------------
   Takes one to three were a photograph, then a wall of timeline, then the same
   wall in better colours. Owner on the third: *"bunu hâlâ hiç beğenmedim"*,
   with KoiStudies attached — "a tactile stack … with CSS 3D depth, pointer
   tilt, drag and keyboard navigation".

   He was right that the section had no object in it. The headline says three
   proposals were waiting at 06:12 and then the page made you read about them.
   Now they ARE there: three cards you can pick up, flick through and approve.
   The timeline moves beside them, where it belongs — evidence, not the story. */
.night-head{ max-width:66ch }
.night-body{
  display:grid; grid-template-columns:minmax(0,1.04fr) minmax(0,.96fr);
  gap:clamp(30px,4.4vw,72px); align-items:start;
  margin-top:clamp(32px,4vw,54px);
}
.night-tl-h{
  font-size:11px; font-weight:500; letter-spacing:.09em; text-transform:uppercase;
  color:var(--n-subtle);
}
.night-tl .tl{ margin-top:6px }
.night-tl .small{ margin-top:14px; color:var(--n-subtle) }

/* ---- the deck -------------------------------------------------------------
   `--stack-*` per depth, exactly KoiStudies' model: only the front card takes
   the pointer, the ones behind are offset, turned and scaled down a step each.
   The 3-D is on .deck-scene (perspective) so the cards keep their own
   transforms for the drag. */
.deck{ position:relative; user-select:none }
.deck-scene{
  position:relative; perspective:1100px; height:clamp(318px,34vw,368px);
  transform-style:preserve-3d;
}
.dcard{
  --sx:0px; --sy:0px; --sz:0px; --srot:0deg; --sscale:1;
  --dx:0px; --dy:0px; --turn:0deg; --tx:0deg; --ty:0deg; --blur:0px;
  position:absolute; inset:0 20px 26px 16px; outline:none;
  transform:translate3d(var(--sx),var(--sy),var(--sz));
  transition:transform .42s var(--ease-out);
  transform-style:preserve-3d; will-change:transform;
}
.dcard-in{
  position:absolute; inset:0; overflow:hidden; display:flex; flex-direction:column;
  padding:clamp(18px,2vw,26px);
  border-radius:clamp(14px,1.5vw,20px);
  background:var(--n-surface); color:var(--n-text);
  box-shadow:var(--n-shadow), inset 0 0 0 1px var(--n-hairline);
  transform:translate3d(var(--dx),var(--dy),0) rotateX(var(--tx)) rotateY(var(--ty)) rotateZ(calc(var(--srot) + var(--turn)))
            scale(var(--sscale));
  transform-origin:88% 92%;
  filter:blur(var(--blur));
  transition:transform .42s var(--ease-out), filter .2s ease, opacity .2s ease;
  will-change:transform;
}
.deck.is-tracking .dcard.is-top .dcard-in{ transition-duration:80ms; transition-timing-function:linear }
.deck.is-dragging .dcard.is-top .dcard-in{ transition:none }
.dcard.is-top{ cursor:grab }
.deck.is-dragging .dcard.is-top{ cursor:grabbing }
/* the lit edge, brightest where the card is nearest the light */
.dcard-in::after{
  content:''; position:absolute; inset:0; z-index:3; padding:1px; border-radius:inherit;
  pointer-events:none; opacity:0; transition:opacity .35s var(--ease);
  background:linear-gradient(150deg, rgba(47,107,255,.50), rgba(47,107,255,.10) 44%, rgba(47,107,255,.04) 74%, rgba(47,107,255,.26));
  -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite:xor; mask-composite:exclude;
}
.dcard.is-top .dcard-in::after{ opacity:1 }
/* On paper you see the EDGES of the cards under the top one, not their
   contents — and the black Genehmigen button of the card behind was poking out
   below the front card like a shadow that had come loose. */
.dcard:not(.is-top) .dcard-in > *{ opacity:0; transition:opacity .2s var(--ease) }
.dcard:not(.is-top) .dcard-in{ background:var(--n-surface) }
.dcard:focus-visible .dcard-in{ box-shadow:0 0 0 2px var(--n-accent), var(--n-shadow) }

.dcard-h{ display:flex; align-items:center; gap:9px; flex-wrap:wrap }
.dcard-h i{ font-style:normal; font-size:11.5px; color:var(--n-muted) }
.dcard-h b{ margin-left:auto; font-size:12px; font-weight:500; color:var(--n-muted) }
.dcard h3{ margin-top:13px; font-size:clamp(17px,1.7vw,21px); font-weight:500; line-height:1.24; letter-spacing:-.016em }
.dcard .mn{ margin-top:7px; font-size:13px; color:var(--n-accent) }
.dcard .rs{ margin-top:11px; font-size:13.5px; line-height:1.55; color:var(--n-muted) }
.dcard .rs b{ font-weight:500; color:var(--n-text); margin-right:.3em }
.dcard-a{ display:flex; gap:9px; margin-top:auto; padding-top:16px }
.dcard-a button{
  font-size:13px; font-weight:500; padding:9px 17px; border-radius:var(--r-pill);
  transition:background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.dcard-a .ok{ background:var(--primary); color:var(--primary-fg) }
.dcard-a .ok:hover{ background:var(--primary-hover) }
.dcard-a .no{ border:1px solid var(--n-hairline-strong); color:var(--n-muted) }
.dcard-a .no:hover{ color:var(--n-text); border-color:var(--n-muted) }

/* approved: the card says so, then goes to the back of the stack */
.dcard-done{
  position:absolute; inset:auto 0 0 0; display:flex; align-items:center; gap:9px;
  padding:clamp(18px,2vw,26px); opacity:0; transform:translateY(8px);
  font-size:13.5px; font-weight:500; color:var(--n-emerald);
  background:linear-gradient(0deg, var(--n-surface) 64%, transparent);
  transition:opacity .28s var(--ease), transform .28s var(--ease-out);
  pointer-events:none;
}
.dcard-done svg{ width:17px; height:17px; flex:0 0 auto; stroke:currentColor; stroke-width:2.4; fill:none; stroke-linecap:round; stroke-linejoin:round }
.dcard.is-done .dcard-done{ opacity:1; transform:none }
.dcard.is-done .dcard-a{ opacity:0; transition:opacity .2s ease }
.dcard.is-done .dcard-in{ box-shadow:var(--n-shadow), inset 0 0 0 1px rgba(6,118,71,.34) }

.deck-ui{ position:relative; z-index:1; display:flex; align-items:center; gap:10px; margin-top:14px }
.deck-nav{
  width:30px; height:30px; border-radius:50%; display:grid; place-items:center;
  border:1px solid var(--n-hairline-strong); color:var(--n-muted);
  transition:color .18s var(--ease), border-color .18s var(--ease);
}
.deck-nav:hover{ color:var(--n-text); border-color:var(--n-muted) }
.deck-nav svg{ width:14px; height:14px; stroke:currentColor; stroke-width:2; fill:none; stroke-linecap:round; stroke-linejoin:round }
.deck-dots{ display:flex; gap:5px }
.deck-dots i{ width:5px; height:5px; border-radius:50%; background:var(--n-hairline-strong); transition:background .2s var(--ease), width .2s var(--ease) }
.deck-dots i.on{ width:16px; border-radius:var(--r-pill); background:var(--n-accent) }
.deck-hint{ margin-left:auto; font-size:11px; color:var(--n-subtle) }

@media (max-width:980px){
  .night-body{ grid-template-columns:minmax(0,1fr); gap:clamp(34px,6vw,50px) }
  .deck-scene{ height:390px }
}
/* One column of card at phone width wraps the headline to two lines and the
   Grund to five, and a fixed scene height then cuts the buttons in half. The
   card is absolutely positioned inside the scene, so the scene has to be told
   how tall the tallest card gets — it cannot find out by itself. */
@media (max-width:620px){
  .deck-scene{ height:366px }
  .dcard-in{ padding:17px }
  .dcard h3{ margin-top:11px; font-size:17px }
  .dcard .rs{ margin-top:9px; font-size:13px; line-height:1.5 }
  .dcard-a{ padding-top:13px }
  .dcard-a button{ padding:8px 14px; font-size:12.5px }
  .dcard-h b{ font-size:11.5px }
  .deck-hint{ display:none }
}
@media (prefers-reduced-motion:reduce){
  .dcard,.dcard-in{ transition:none }
}

/* "Kommt als Nächstes" — the one place on the page where something is shown
   that the customer cannot switch on yet. The behaviours behind the board are
   shipped; the board is not, and a landing page that blurs that is a landing
   page that will be caught. */
.soon{
  font-size:10.5px; font-weight:500; letter-spacing:.02em; padding:2px 9px;
  border-radius:var(--r-pill); background:var(--blue-bg); color:var(--blue-fg);
}



/* ======================================================= Helbot, the canvas
   Owner: *"modern 2027 workflow nasıl oluşturuyorsun, drag'n'drop ile
   kurabiliyorsun gibi"*, with a sequence-builder screenshot — a dotted board,
   node cards with an icon and a ⋯ menu, a + on every connector, a Ja/Nein
   branch, one node selected, and the step's own panel.

   So the board BUILDS itself, once every ten seconds, and the sequence is the
   argument: a trigger, a question, two answers, and a draft that waits for you.
   Ten beats, and what happens in them is written in the markup, not here:

     data-at="N"     the piece is placed at beat N
     data-off="N"    and taken away again at beat N
     data-hot="N"    it goes ACTIVE at N — a pressed +, a live wire, the step
     data-hot="N M"  whose panel is open — until M, if a second number is given

   The markup is the FINISHED board, the one you get with JavaScript off and
   under prefers-reduced-motion, `is-hot` and all. `is-playing` is what hides
   the pieces that have not been placed yet; ui.js strips the state, walks the
   beats, and fast-forwards to the end when you scroll away.

   A FIXED 760×330 stage, centred on the board, with the wires in the same pixel
   space. The percentage version could not make a wire touch a node — a node's
   height is its content's, so its bottom edge in percent depends on the board's
   height, and the two were always a few pixels apart (*"Auslöser'e kadar
   bağlanmıyor"*). In pixels the wire starts exactly where the node ends.

   Which means the node widths are set for ENGLISH, the longer of the two: a
   label that wraps makes its node taller than the 54 px the wires are drawn
   against, and the connector ends up buried inside the card it should touch. */
.hb{
  max-width:900px; margin:clamp(28px,3.4vw,44px) auto 0; overflow:hidden;
  background:var(--surface); border:1px solid var(--hairline); border-radius:var(--r-card);
}
.hb-head{ display:flex; align-items:center; gap:10px; padding:14px 18px; border-bottom:1px solid var(--hairline) }
.hb-head b{ font-size:14.5px; font-weight:600; letter-spacing:-.01em }
.hb-head .rh-sub{ margin-left:auto; font-size:12.5px; color:var(--subtle) }

.hb-board{
  position:relative; height:360px; display:grid; place-items:center; overflow:hidden;
  background:var(--surface-2); border-bottom:1px solid var(--hairline);
}
.hb-grid{
  position:absolute; inset:0;
  background-image:radial-gradient(currentColor .9px, transparent .9px);
  background-size:19px 19px; color:var(--hairline-strong); opacity:.75;
}
.hb-stage{ position:relative; width:760px; height:330px; flex:0 0 auto }

/* ---- wires -------------------------------------------------------------- */
.hb-wire{ position:absolute; inset:0; width:760px; height:330px; overflow:visible }
.hb-wire .w{
  fill:none; stroke:var(--hairline-strong); stroke-width:2; stroke-linecap:round;
  stroke-dasharray:2 5;
}
/* Only the branch the run actually took. A run takes ONE answer, and a board
   that lights both is lying about what happened — owner: *"Nein tarafına da
   neden mavi çizgi devam ediyor?"*. The other answer keeps its plain grey
   connector: the step exists, it just did not run this time. */
.hb-wire .w.is-hot{ stroke:var(--accent); animation:hb-run 4s linear infinite }
@keyframes hb-run{ to{ stroke-dashoffset:-28 } }

/* ---- nodes -------------------------------------------------------------- */
.hb-node{
  position:absolute; left:var(--x); top:var(--y); width:var(--w); min-height:54px;
  display:flex; align-items:center; gap:10px; padding:9px 12px;
  border-radius:11px; background:var(--surface);
  box-shadow:0 1px 2px rgba(22,22,26,.05), 0 6px 18px -8px rgba(22,22,26,.20), inset 0 0 0 1px var(--hairline);
}
.hb-node.is-hot{ box-shadow:0 0 0 2px var(--accent), 0 10px 28px -8px rgba(47,107,255,.40) }
.hb-ic{
  width:30px; height:30px; border-radius:9px; flex:0 0 auto; display:grid; place-items:center;
  background:var(--t,var(--slate-bg)); color:var(--tf,var(--slate-fg));
}
.hb-ic svg{ width:16px; height:16px; stroke:currentColor; stroke-width:2; fill:none; stroke-linecap:round; stroke-linejoin:round }
.hb-tx{ min-width:0; flex:1 1 auto }
.hb-tx i{ display:block; font-style:normal; font-size:9.5px; font-weight:500; letter-spacing:.09em; text-transform:uppercase; color:var(--subtle) }
.hb-tx b{ display:block; margin-top:1px; font-size:13px; font-weight:400; line-height:1.35; color:var(--text) }
.nx{ display:flex; gap:2.5px; flex:0 0 auto; padding-left:4px }
.nx i{ width:3px; height:3px; border-radius:50%; background:var(--hairline-strong) }

.hb-plus{
  position:absolute; left:var(--x); top:var(--y); translate:-50% -50%; z-index:2;
  width:20px; height:20px; border-radius:50%; display:grid; place-items:center;
  background:var(--surface); box-shadow:inset 0 0 0 1px var(--hairline-strong); color:var(--muted);
  transition:background .25s var(--ease-ui), color .25s var(--ease-ui), box-shadow .25s var(--ease-ui);
}
.hb-plus svg{ width:11px; height:11px; stroke:currentColor; stroke-width:2.4; fill:none; stroke-linecap:round }
.hb-plus.is-hot{
  background:var(--accent); color:var(--primary-fg);
  box-shadow:inset 0 0 0 1px var(--accent), 0 0 0 5px rgba(47,107,255,.15);
}

.hb-yn{
  position:absolute; left:var(--x); top:var(--y); translate:-50% -50%; z-index:2;
  font-size:10.5px; font-weight:500; padding:2px 9px; border-radius:var(--r-pill);
  /* a ring in the board's own colour, so the wire breaks around the label
     instead of running through it */
  box-shadow:0 0 0 3px var(--surface-2);
}
.hb-yn--y{ background:var(--emerald-bg); color:var(--emerald-fg) }
.hb-yn--n{ background:var(--rose-bg); color:var(--rose-fg) }
.hb-yn.is-hot{ font-weight:600 }

/* ---- the step picker ----------------------------------------------------
   Owner: *"niye + basma, sonra available açılan aksiyonlardan otomatik
   seçmiyor, Verzweigung mesela?"* — so the + is pressed, this opens beside it,
   a step is chosen, and the node lands where the menu was. It is on screen for
   three beats and belongs to no finished board, so unlike everything else here
   it is hidden unless ui.js has placed it: the resting state of a menu is shut. */
.hb-pick{
  position:absolute; left:var(--x); top:var(--y); width:252px; z-index:3;
  padding:6px; border-radius:12px; background:var(--surface); pointer-events:none;
  box-shadow:0 2px 8px rgba(22,22,26,.06), 0 22px 48px -18px rgba(22,22,26,.34), inset 0 0 0 1px var(--hairline);
  opacity:0; transform:scale(.94); transform-origin:-18px 18px;
}
.hb-pick.is-on{ opacity:1; transform:none }
.hb-pick-q{
  display:flex; align-items:center; gap:7px; padding:5px 8px 9px;
  border-bottom:1px solid var(--hairline); color:var(--subtle); font-size:12px;
}
.hb-pick-q svg{ width:13px; height:13px; flex:0 0 auto; stroke:currentColor; stroke-width:2; fill:none; stroke-linecap:round }
.hb-pick-q i{ width:1px; height:12px; margin-right:-4px; background:var(--text); animation:hb-caret 1.1s steps(1) infinite }
@keyframes hb-caret{ 50%{ opacity:0 } }
.hb-pick ul{ list-style:none; margin:5px 0 0; padding:0 }
.hb-pick li{
  display:flex; align-items:center; gap:9px; padding:6px 8px; border-radius:8px;
  box-shadow:inset 0 0 0 1px transparent; transition:background .2s var(--ease-ui), box-shadow .2s var(--ease-ui);
}
.hb-pick li.is-hot{ background:var(--surface-hover); box-shadow:inset 0 0 0 1px var(--accent) }
.hb-pick .hb-ic{ width:24px; height:24px; border-radius:7px }
.hb-pick .hb-ic svg{ width:13px; height:13px }
.hb-pick .hb-tx b{ margin-top:0; font-size:12.5px; font-weight:500 }
.hb-pick .hb-tx em{ display:block; margin-top:1px; font-style:normal; font-size:10.5px; color:var(--subtle) }

/* ---- the docked step panel ----------------------------------------------
   It used to float over the board on a negative margin, which left a slab of
   empty white under the canvas for as long as it had not been placed yet
   (owner: *"altı neden beyaz kaldı?"*). Docked, the panel IS the bottom of the
   module: `.hb-live` sits in flow and gives the dock its height, so nothing
   reflows when it opens, and the "nothing selected" line every builder shows
   sits behind it and comes through as it fades. */
.hb-dock{ position:relative; border-bottom:1px solid var(--hairline) }
.hb-live{ position:relative; z-index:1; padding:15px 18px 16px; background:var(--surface) }
.hb-live-h{ display:flex; align-items:center; gap:10px }
.hb-src{ margin-left:auto; flex:0 0 auto; font-size:11.5px; color:var(--subtle) }
.hb-msg{
  margin-top:11px; padding:10px 12px; border-radius:10px;
  background:var(--blue-bg); color:var(--text); font-size:13px; line-height:1.55;
}
.hb-legal{ margin-top:9px; font-size:10.5px; line-height:1.5; color:var(--muted) }
.hb-rest{
  position:absolute; inset:0; z-index:0;
  display:grid; place-content:center; justify-items:center; gap:3px; text-align:center;
}
.hb-rest .hb-ic{ margin-bottom:6px }
.hb-rest b{ font-size:12.5px; font-weight:500; color:var(--muted) }
.hb-rest em{ font-style:normal; font-size:11.5px; color:var(--subtle) }
.hb-live.is-on + .hb-rest{ opacity:0; transition:opacity .2s var(--ease-ui) }
.hb-note{ padding:13px 18px; background:var(--surface-2); font-size:12.5px; line-height:1.6; color:var(--muted) }

/* ---- the build ----------------------------------------------------------
   Everything is VISIBLE by default, so the board is complete with JavaScript
   off and under prefers-reduced-motion. `is-playing` is what hides the pieces
   that have not been placed yet — the animation is opt-in, never the baseline. */
[data-at]{ transition:opacity .5s var(--ease), transform .55s var(--ease-out) }
.hb-pick[data-at]{ transition:opacity .24s var(--ease-ui), transform .3s var(--ease-out) }
.hb.is-playing [data-at]{ opacity:0 }
.hb.is-playing .hb-node[data-at]{ transform:translateY(10px) scale(.985) }
.hb.is-playing .hb-live[data-at]{ transform:translateY(8px) }
/* `translate` and `transform` are two separate properties and they COMPOSE, so
   writing the -50%/-50% centring in both moved every pill and the + by a full
   100 % of its own box — which is why the Ja/Nein labels sat above the wire
   they belong to. The centring lives in `translate`; `transform` only scales. */
.hb.is-playing .hb-plus[data-at], .hb.is-playing .hb-yn[data-at]{ transform:scale(.6) }
.hb.is-playing [data-at].is-on{ opacity:1 }
.hb.is-playing .hb-node[data-at].is-on, .hb.is-playing .hb-live[data-at].is-on{ transform:none }
.hb.is-playing .hb-plus[data-at].is-on, .hb.is-playing .hb-yn[data-at].is-on{ transform:none }
.hb.is-playing .hb-plus[data-at].is-on.is-hot{ transform:scale(1.12) }

/* A wire draws itself in and only then settles into the dashed connector it is:
   a dash travelling along a line that is still being drawn reads as a glitch. */
.hb.is-playing .w[data-at]{
  opacity:1; stroke:var(--hairline-strong); animation:none;
  stroke-dasharray:var(--len); stroke-dashoffset:var(--len);
}
.hb.is-playing .w[data-at].is-on{
  stroke-dashoffset:0;
  transition:stroke-dashoffset .55s var(--ease-out) var(--d,0s), stroke .45s var(--ease);
}
.hb.is-playing .w[data-at].is-dash{ stroke-dasharray:2 5; stroke-dashoffset:0 }
.hb.is-playing .w[data-at].is-hot{ stroke:var(--accent); animation:hb-run 4s linear infinite }

/* A canvas is a shape, and a shape does not survive a 375px screen: scaled down
   the type is unreadable, scrolled sideways half the sequence hides behind a
   gesture nobody knows is there. So on a phone the board stops being a canvas
   and becomes the list it is describing — same nodes, same order, the wire a
   dashed drop. This is why the markup is written in READING order and
   positioned rather than laid out: absolute positioning ignores document order,
   so one order serves both. */
@media (max-width:820px){
  .hb-board{ height:auto; padding:16px 14px; place-items:stretch }
  .hb-stage{ width:auto; height:auto; display:flex; flex-direction:column }
  .hb-wire{ display:none }
  /* a menu overlay means nothing in a stacked list and opening one would shove
     the list around; ui.js shortens the beats that belong to it */
  .hb-pick{ display:none }
  /* `left`/`top` still apply to a POSITION:RELATIVE box — they offset it —
     so they have to be cleared or the nodes keep their canvas coordinates. */
  .hb-node{ position:relative; left:auto; top:auto; width:auto; height:auto; padding:11px 12px; margin-bottom:14px }
  .hb-node:not(:last-child)::after{
    content:''; position:absolute; left:26px; top:100%; width:0; height:14px;
    border-left:2px dashed var(--hairline-strong);
  }
  .hb-plus, .hb-yn{ position:static; translate:none; align-self:flex-start; margin:0 0 14px 17px }
  .hb-yn{ box-shadow:none }
  .hb.is-playing .hb-plus[data-at], .hb.is-playing .hb-yn[data-at]{ transform:scale(.6) }
  .hb.is-playing .hb-plus[data-at].is-on, .hb.is-playing .hb-yn[data-at].is-on{ transform:none }
  .hb-live{ padding:14px }
  .hb-src{ display:none }
}
@media (prefers-reduced-motion:reduce){
  .hb-wire .w{ animation:none }
  .hb-pick-q i{ animation:none }
}
