/* ---------- fonty ----------
   Hostované lokálně místo fonts.gstatic.com, takže se při načtení stránky
   neodesílá IP adresa návštěvníka třetí straně a odpadají dvě cizí domény
   z kritické cesty vykreslování.

   Jde o variabilní fonty — jeden soubor pokrývá celý rozsah řezů, proto je
   font-weight zapsaný jako rozsah a ne jako jedna hodnota.

   Díky unicode-range se latin-ext (česká diakritika) stáhne jen tehdy, když
   ho stránka opravdu potřebuje.

   Space Grotesk a JetBrains Mono, oba pod SIL Open Font License 1.1. */
@font-face{
  font-family:'JetBrains Mono';
  font-style:normal;
  font-weight:400 500;
  font-display:swap;
  src:url('../fonts/jetbrainsmono-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'JetBrains Mono';
  font-style:normal;
  font-weight:400 500;
  font-display:swap;
  src:url('../fonts/jetbrainsmono-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Space Grotesk';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('../fonts/spacegrotesk-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Space Grotesk';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('../fonts/spacegrotesk-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root{
  --ink:#05050a;
  --ink2:#0a0912;
  --violet:#a78bfa;
  --magenta:#e879f9;
  --text:#ece9f6;
  --muted:#8a83a6;
  --line:rgba(167,139,250,.13);
  --mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --disp:"Space Grotesk",system-ui,-apple-system,sans-serif;
  --pad:clamp(20px,5vw,88px);
  /* Height of the fixed header: 22px padding, the 28px language switcher,
     22px padding. The section nav is shorter than the switcher, so adding it
     did not change this. Sections offset their anchor targets by it. */
  --header-h:72px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0;background:var(--ink);color:var(--text);
  font-family:var(--disp);font-weight:400;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
}
body.locked{overflow:hidden}
a{color:inherit}

/* faint grid, same texture as the LinkedIn banner */
body::before{
  content:"";position:fixed;inset:0;z-index:0;pointer-events:none;
  background-image:linear-gradient(var(--line) 1px,transparent 1px),
                   linear-gradient(90deg,var(--line) 1px,transparent 1px);
  background-size:64px 64px;opacity:.5;
}
.glow{position:fixed;border-radius:50%;filter:blur(120px);z-index:0;pointer-events:none}
.glow.a{width:720px;height:520px;top:-180px;right:-120px;background:rgba(124,58,237,.22)}
.glow.b{width:560px;height:440px;bottom:-160px;left:-140px;background:rgba(236,72,153,.11)}

/* ---------- loader ---------- */
#loader{
  position:fixed;inset:0;z-index:100;background:var(--ink);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:22px;
  transition:opacity .6s ease,visibility .6s;
}
#loader.done{opacity:0;visibility:hidden}
#loader .lbl{font-family:var(--mono);font-size:11px;letter-spacing:.34em;color:var(--muted);text-transform:uppercase}
#loader .num{font-family:var(--mono);font-size:clamp(48px,11vw,96px);color:var(--violet);line-height:1;font-weight:500}
#loader .bar{width:min(320px,60vw);height:1px;background:rgba(167,139,250,.18);position:relative;overflow:hidden}
#loader .bar i{position:absolute;inset:0 100% 0 0;background:var(--magenta);transition:right .12s linear}

/* ---------- shell ---------- */
.wrap{position:relative;z-index:1}
header{
  position:fixed;top:0;left:0;right:0;z-index:50;
  display:flex;align-items:center;justify-content:space-between;
  padding:22px var(--pad);
  font-family:var(--mono);font-size:11px;letter-spacing:.26em;text-transform:uppercase;
}
header .mark{color:var(--violet);text-decoration:none}
header .mark b{color:var(--magenta);font-weight:500}

/* ---------- section nav ---------- */
/* Plain anchors — html{scroll-behavior:smooth} above animates the jump, so no
   script sits behind the links. Only the active highlight needs JavaScript,
   and without it the links still navigate.

   Letter-spacing is tighter than the .26em the header sets: at .26em the six
   labels do not fit beside the monogram and the switcher until well past
   1400px. */
.secnav{display:flex;gap:clamp(12px,1.6vw,26px);letter-spacing:.12em}
.secnav a{
  position:relative;display:inline-flex;gap:6px;
  color:var(--muted);text-decoration:none;
  border-bottom:1px solid transparent;padding-bottom:3px;transition:.2s;
}
.secnav a:hover{color:var(--text)}
.secnav a[aria-current="location"]{color:var(--violet);border-color:var(--violet)}

/* Middle tier: numbers only. Plain display:none is safe here because each link
   names itself with aria-label in the markup — nothing about the accessible
   name depends on this span being rendered. */
@media (max-width:1200px){
  .secnav .lbl{display:none}
}
/* Narrow tier: gone. The page is short enough to scroll, and a hamburger
   would be more chrome than the content behind it warrants. */
@media (max-width:768px){
  .secnav{display:none}
}
.lang{display:flex;gap:2px;border:1px solid rgba(167,139,250,.24);border-radius:2px;overflow:hidden}
.lang button{
  background:none;border:0;cursor:pointer;padding:6px 11px;
  font:inherit;letter-spacing:.2em;color:var(--muted);transition:.2s;
}
.lang button:hover{color:var(--text)}
.lang button[aria-pressed="true"]{background:rgba(167,139,250,.14);color:var(--violet)}
.lang button:focus-visible{outline:2px solid var(--magenta);outline-offset:-2px}

/* scroll-margin-top, not padding: it moves only where an anchor jump lands,
   leaving the layout alone, so the header never covers a section's top edge. */
section{padding:clamp(90px,13vh,150px) var(--pad);max-width:1400px;margin:0 auto;
  scroll-margin-top:var(--header-h)}
.eyebrow{
  font-family:var(--mono);font-size:11px;letter-spacing:.32em;text-transform:uppercase;
  color:var(--muted);margin:0 0 34px;display:flex;align-items:center;gap:14px;
  font-weight:400;
}
.eyebrow::after{content:"";flex:1;height:1px;background:var(--line)}
.eyebrow span{color:var(--magenta)}

/* The about eyebrow was picking up `.about p` (higher specificity than
   `.eyebrow`) back when it was a <p>. It is an <h2> now for heading order,
   so those values are restated here to keep the rendering identical. */
.about .eyebrow{
  font-size:clamp(1.15rem,2.2vw,1.9rem);line-height:1.48;letter-spacing:-.015em;
  max-width:30ch;margin:0 0 1.1em;
}

/* ---------- hero ---------- */
#hero{
  min-height:100svh;display:flex;flex-direction:column;justify-content:center;
  padding-top:120px;padding-bottom:48px;max-width:1400px;
}
.status{
  display:inline-flex;align-items:center;gap:9px;align-self:flex-start;
  font-family:var(--mono);font-size:11px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--muted);margin-bottom:32px;
}
.status i{width:6px;height:6px;border-radius:50%;background:var(--magenta);box-shadow:0 0 0 0 rgba(232,121,249,.6);animation:pulse 2.4s infinite}
@keyframes pulse{70%{box-shadow:0 0 0 9px rgba(232,121,249,0)}100%{box-shadow:0 0 0 0 rgba(232,121,249,0)}}
h1{
  font-size:clamp(2.4rem,6.4vw,5.6rem);font-weight:700;line-height:1.02;
  letter-spacing:-.035em;margin:0 0 30px;max-width:17ch;
}
h1 em{font-style:normal;color:var(--violet)}
.lede{font-size:clamp(1rem,1.5vw,1.24rem);line-height:1.62;color:var(--muted);max-width:56ch;margin:0}

/* ---------- traceroute signature ---------- */
.hops{margin-top:clamp(44px,7vh,84px)}
.hops svg{width:100%;height:auto;display:block;overflow:visible}
.path{
  fill:none;stroke:var(--magenta);stroke-width:1.4;stroke-linecap:round;
  filter:drop-shadow(0 0 7px rgba(232,121,249,.5));
  stroke-dasharray:1200;stroke-dashoffset:1200;
}
.ready .path{animation:draw 2.2s cubic-bezier(.45,0,.15,1) forwards}
@keyframes draw{to{stroke-dashoffset:0}}
.rail{stroke:rgba(167,139,250,.16);stroke-width:1}
.node{fill:var(--ink);stroke:var(--violet);stroke-width:1.4;opacity:0}
.node.end{stroke:var(--magenta)}
.ready .node{animation:pop .45s cubic-bezier(.2,1.4,.4,1) forwards}
@keyframes pop{from{opacity:0;transform:scale(.4)}to{opacity:1;transform:scale(1)}}
.hoplbl{font-family:var(--mono);font-size:10px;letter-spacing:.2em;fill:var(--muted);opacity:0}
.hopms{font-family:var(--mono);font-size:11px;letter-spacing:.06em;fill:var(--violet);opacity:0}
.ready .hoplbl,.ready .hopms{animation:fadein .45s ease forwards}
@keyframes fadein{to{opacity:.9}}
.hops figcaption{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);margin-top:18px;
}

/* The hop chain is a fixed 1200-unit viewBox scaled to the container width, so
   its labels shrink with it — untouched they render at ~2px on a 360px screen.
   These tiers hold the rendered size near the ~8-10px it has on desktop.

   .hopms stops growing at 28 units: its baseline sits 28 units below the node
   centres, so past that the digits collide with the node circles. That cap is
   the reason the figure needs the extra width below. */
@media (max-width:1200px){.hoplbl{font-size:12px}.hopms{font-size:13px}}
@media (max-width:1024px){.hoplbl{font-size:14px}.hopms{font-size:15px}}
@media (max-width:900px) {.hoplbl{font-size:16px}.hopms{font-size:17px}}

/* A <figure> carries a 40px side margin from the UA stylesheet, which nothing
   here ever cleared. On a phone that is 80px — a third of the usable width —
   spent on nothing, and it squeezes the hop labels below what the viewBox cap
   allows them to recover. Dropping it on narrow screens widens the graphic by
   about a third and lets the labels reach a readable size. */
@media (max-width:768px){
  .hops{margin-left:0;margin-right:0}
  /* Nudging the ms row 6 units further from the nodes buys back the headroom
     the 28-unit cap was costing, so the values can grow with everything else.
     The viewBox is 130 tall and the row ends near 92, so nothing spills out. */
  .hopms{transform:translateY(6px)}
  .hoplbl{font-size:18px}.hopms{font-size:19px}
}
@media (max-width:620px){.hoplbl{font-size:22px}.hopms{font-size:23px}}
@media (max-width:560px){.hoplbl{font-size:24px}.hopms{font-size:25px}}
@media (max-width:500px){.hoplbl{font-size:27px}.hopms{font-size:28px}}
@media (max-width:420px){.hoplbl{font-size:32px}.hopms{font-size:33px}}
@media (max-width:360px){.hoplbl{font-size:37px}.hopms{font-size:34px}}

/* ---------- reveal ---------- */
.rv{opacity:0;transform:translateY(22px);transition:opacity .8s ease,transform .8s cubic-bezier(.2,.7,.2,1)}
.rv.in{opacity:1;transform:none}

/* ---------- about ---------- */
.about p{
  font-size:clamp(1.15rem,2.2vw,1.9rem);line-height:1.48;letter-spacing:-.015em;
  max-width:30ch;margin:0 0 1.1em;
}
.about p:last-child{color:var(--muted);font-size:clamp(.98rem,1.4vw,1.14rem);line-height:1.66;max-width:52ch}

/* ---------- capabilities ---------- */
.rows{border-top:1px solid var(--line)}
.row{
  display:grid;grid-template-columns:minmax(0,3fr) minmax(0,7fr);gap:clamp(16px,4vw,64px);
  padding:clamp(24px,3.4vw,40px) 0;border-bottom:1px solid var(--line);
  transition:background .3s;
}
.row:hover{background:rgba(167,139,250,.035)}
.row h3{
  font-family:var(--mono);font-weight:500;font-size:clamp(.95rem,1.5vw,1.18rem);
  letter-spacing:.16em;text-transform:uppercase;color:var(--violet);margin:0;
}
.row p{margin:0;color:var(--muted);line-height:1.66;font-size:clamp(.95rem,1.2vw,1.06rem);max-width:58ch}

/* ---------- projects ---------- */
/* Built on .rows / .row above — grid, dividers and hover tint all carry over,
   and the heading is a plain descriptive label exactly like in capabilities.

   The description, stack line and repo link share a wrapper rather than being
   further children of .row: .row is a two-column grid, so a third child would
   land in the left column on a new row instead of under the text.

   .repo prints its own destination, so it stays lower-case even though almost
   every other mono label here is upper-cased — a URL path is case-sensitive
   and transforming it would misrepresent the target. */
/* both beat `.row p` (0-1-1) on font-size and margin, hence the two classes */
.row .stack{
  margin:14px 0 0;font-family:var(--mono);
  font-size:clamp(.78rem,1vw,.86rem);letter-spacing:.08em;
}
.row .repo{
  display:inline-block;margin-top:12px;
  font-family:var(--mono);font-size:clamp(.78rem,1vw,.86rem);
  letter-spacing:.02em;text-transform:none;color:var(--muted);
  text-decoration:none;border-bottom:1px solid rgba(167,139,250,.3);
  padding-bottom:2px;transition:.25s;
}
.row .repo:hover{color:var(--violet);border-color:var(--violet)}

/* ---------- lab spec ---------- */
.spec{list-style:none;padding:0;margin:0;display:grid;gap:0 clamp(24px,5vw,72px);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr))}
.spec li{
  font-family:var(--mono);font-size:clamp(.82rem,1.1vw,.94rem);letter-spacing:.04em;
  padding:14px 0;border-bottom:1px solid var(--line);color:var(--text);
  display:flex;align-items:baseline;gap:14px;
}
.spec li::before{content:"—";color:var(--magenta);flex:none}
.note{margin:26px 0 0;color:var(--muted);font-size:.95rem;line-height:1.66;max-width:54ch}

/* ---------- timeline ---------- */
.tl{display:grid;gap:0}
.tl .item{
  display:grid;grid-template-columns:minmax(0,2fr) minmax(0,8fr);gap:clamp(16px,4vw,56px);
  padding:clamp(20px,2.6vw,30px) 0;border-bottom:1px solid var(--line);
}
.tl .item:first-child{border-top:1px solid var(--line)}
.tl .yr{font-family:var(--mono);font-size:.86rem;letter-spacing:.14em;color:var(--magenta)}
.tl .body strong{display:block;font-weight:500;font-size:clamp(1rem,1.4vw,1.16rem);margin-bottom:5px}
.tl .body span{color:var(--muted);font-size:.95rem;line-height:1.6}

/* ---------- contact ---------- */
#contact{padding-bottom:clamp(70px,10vh,120px)}
.mailto{
  display:inline-block;font-size:clamp(1.5rem,5vw,3.4rem);font-weight:700;letter-spacing:-.03em;
  text-decoration:none;color:var(--text);word-break:break-all;
  border-bottom:1px solid rgba(167,139,250,.3);padding-bottom:6px;transition:.25s;
}
.mailto:hover{color:var(--magenta);border-color:var(--magenta)}
.links{display:flex;flex-wrap:wrap;gap:28px;margin-top:38px;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.24em;text-transform:uppercase}
.links a{color:var(--muted);text-decoration:none;transition:.2s;border-bottom:1px solid transparent;padding-bottom:3px}
.links a:hover{color:var(--violet);border-color:var(--violet)}
a:focus-visible,button:focus-visible{outline:2px solid var(--magenta);outline-offset:3px;border-radius:1px}

footer{
  padding:26px var(--pad);border-top:1px solid var(--line);
  display:flex;justify-content:space-between;flex-wrap:wrap;gap:12px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.22em;text-transform:uppercase;color:var(--muted);
}

@media (max-width:760px){
  .row,.tl .item{grid-template-columns:1fr;gap:10px}
  h1{max-width:none}
}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}
  .path{stroke-dashoffset:0}
  .node,.hoplbl,.hopms{opacity:.9}
  .rv{opacity:1;transform:none}
}
