/*
 * milanvarady.dev
 *
 * Black and white, serif, light first. There is deliberately no accent colour:
 * the drone photographs at the foot of the page are the only colour on it, which
 * is what earns the monochrome everywhere else.
 *
 * Tokens follow the same shape as applite-site/src/styles/tokens.css so the two
 * sites stay recognisably related without sharing a framework.
 */

/* ---------- fonts ---------------------------------------------------------
 * Self-hosted, no external requests. Split by unicode-range so an English page
 * fetches only the ~23 KB latin files; the latin-ext files carry o-double-acute
 * and u-double-acute for Hungarian and are fetched only if a word needs them.
 * Licence: fonts/OFL.txt
 */
@font-face {
  font-family: "EB Garamond"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("fonts/ebgaramond-400-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: "EB Garamond"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("fonts/ebgaramond-400-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: "EB Garamond"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("fonts/ebgaramond-600-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: "EB Garamond"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("fonts/ebgaramond-600-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: "EB Garamond"; font-style: italic; font-weight: 400; font-display: swap;
  src: url("fonts/ebgaramond-400-italic-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: "EB Garamond"; font-style: italic; font-weight: 400; font-display: swap;
  src: url("fonts/ebgaramond-400-italic-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;
}

/* Metric-matched fallback. EB Garamond xWidthAvg 0.385em vs Georgia 0.446em, so
   Georgia is scaled to 86.4% and its vertical metrics overridden to match. This
   makes the font swap nearly imperceptible instead of a visible reflow. */
@font-face {
  font-family: "EB Garamond Fallback";
  src: local("Georgia"), local("Times New Roman"), local("Times");
  size-adjust: 86.4%;
  ascent-override: 116.6%;
  descent-override: 34.5%;
  line-gap-override: 0%;
}

/* ---------- tokens -------------------------------------------------------- */
:root {
  --bg:         #fdfdfc;
  --bg-subtle:  #f5f4f1;
  --text:       #1a1917;   /* 17.3:1 on --bg  (AAA) */
  --text-muted: #6d6a63;   /*  5.3:1 on --bg  (AA)  */
  --border:     #e2e0da;
  --rule:       #cfccc4;

  --font: "EB Garamond", "EB Garamond Fallback", Georgia, serif;

  --page: 720px;
  --pad: clamp(1.25rem, 5vw, 2rem);
  /* Body measure. The photo strip matches it so the images share both edges with
     the text; they must stay equal, hence one token rather than two literals. */
  --measure: 66ch;
  --gap: clamp(2.75rem, 2rem + 3vw, 4.5rem);

  /* EB Garamond has a small x-height, so the whole scale runs a step large. */
  --step--1: clamp(0.95rem, 0.93rem + 0.1vw, 1rem);
  --step-0:  clamp(1.15rem, 1.11rem + 0.18vw, 1.26rem);
  --step-1:  clamp(1.35rem, 1.28rem + 0.32vw, 1.55rem);
  --step-2:  clamp(1.7rem, 1.55rem + 0.7vw, 2.15rem);
  --step-3:  clamp(2.4rem, 1.95rem + 2.1vw, 3.6rem);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:         #121211;   /* near black, not blue black */
    --bg-subtle:  #1a1918;
    --text:       #eceae4;   /* 15.6:1 on --bg  (AAA) */
    --text-muted: #9a968c;   /*  6.4:1 on --bg  (AA)  */
    --border:     #2c2a27;
    --rule:       #3a3733;
  }
}

/* ---------- reset --------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body, h1, h2, h3, p, ul, dl, dd { margin: 0; }
ul { padding: 0; list-style: none; }
img { display: block; max-width: 100%; height: auto; }

html:focus-within { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html:focus-within { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important; scroll-behavior: auto !important;
  }
}

/* ---------- base ---------------------------------------------------------- */
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--step-0);
  line-height: 1.62;
  font-kerning: normal;
  font-variant-ligatures: common-ligatures;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

p { max-width: var(--measure); }
p + p { margin-top: 0.9em; }

a {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: var(--rule);
  transition: text-decoration-color 120ms ease;
}
a:hover { text-decoration-color: currentColor; }

:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute; left: -9999px;
  background: var(--bg); color: var(--text);
  padding: 0.6em 1em; border: 1px solid var(--text); z-index: 10;
}
.skip-link:focus { left: 1rem; top: 1rem; }

.page {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--pad);
}

/* ---------- header -------------------------------------------------------- */
.masthead { padding-block: clamp(3rem, 8vw, 5.5rem) 0; }

.identity {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 4vw, 2rem);
  flex-wrap: wrap;
}

.portrait {
  width: clamp(84px, 20vw, 116px);
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bg-subtle);
  flex: none;
}

h1 {
  font-size: var(--step-3);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.012em;
}

.lede {
  margin-top: 1.4em;
  font-size: var(--step-1);
  line-height: 1.5;
  max-width: 58ch;
}

/* Two rows of two, grouped by meaning: where I am, then how to reach me. Letting
   flex wrap four loose items produced a ragged 3 + 1 break that read as an
   accident. The icons mark each item, so no separator character is needed. */
.meta {
  margin-top: 1.5em;
  color: var(--text-muted);
  font-size: var(--step--1);
  display: flex;
  flex-wrap: wrap;
  gap: 0.35em 1.4em;
}
.meta + .meta { margin-top: 0.4em; }

.meta > span {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45em;
}
/* Hairline glyphs at the same weight as the rule lines, so they label the items
   without competing with them. Decorative only: every one is aria-hidden, because
   the text beside it already says the same thing. */
.meta svg {
  width: 0.95em;
  height: 0.95em;
  flex: none;
  transform: translateY(0.11em);   /* optical baseline, not geometric */
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.7;
}

/* The GitHub mark is a filled brand logo, not part of the monoline set. Filled is the
   only thing that survives at this size, so its opacity is dropped instead to match
   the optical weight of the hairline icons beside it. */
.meta svg.brand {
  fill: currentColor;
  stroke: none;
  opacity: 0.55;
  transform: translateY(0.14em);
}

/* An abbreviation only a Hungarian would recognise: the link is the real answer,
   the title is a bonus for anyone on a pointer device. */
abbr[title] {
  text-decoration: none;
  cursor: help;
}

/* Narrow screens: one item per line. */
@media (max-width: 34rem) {
  .meta { display: block; }
  .meta > span { display: flex; }        /* flex, not block: keeps icon beside label */
  .meta > span + span { margin-top: 0.35em; }
}

/* ---------- sections ------------------------------------------------------ */
section { padding-block: var(--gap); }
section + section { border-top: 1px solid var(--border); }

h2 {
  font-size: var(--step--1);
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 1.6em;
}

/* ---------- projects ------------------------------------------------------ */
.project + .project { margin-top: 2.6em; }

.project h3 {
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.2;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 0.7em;
}

.stars {
  font-size: var(--step--1);
  font-weight: 400;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.project p { margin-top: 0.5em; }

.links {
  margin-top: 0.7em;
  font-size: var(--step--1);
  color: var(--text-muted);
  display: flex;
  flex-wrap: wrap;
  gap: 0.4em 1.1em;
}

/* ---------- tools --------------------------------------------------------- */
.tools { display: grid; gap: 0.85em; max-width: 40rem; }
.tools div {
  display: grid;
  grid-template-columns: minmax(9.5rem, auto) 1fr;
  gap: 0.3em 1.5em;
  align-items: baseline;
}
.tools dt { font-weight: 600; }
.tools dd { color: var(--text-muted); font-size: var(--step--1); }
@media (max-width: 34rem) {
  .tools div { grid-template-columns: 1fr; }
}

/* ---------- drone strip --------------------------------------------------
 * The one playful element, and the only colour on the page. It sits inside
 * .page and shares --measure with the body copy: a full-bleed version that
 * started at the text column but ran off the right edge read as a mistake.
 */
.strip {
  display: flex;
  gap: 2px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  padding-bottom: 0.5rem;
  /* Shares --measure with the body copy so the photographs line up with the text
     on both edges. It scrolls within that column. */
  max-width: var(--measure);
  margin-top: 2rem;
  scrollbar-width: thin;
}
.strip picture { flex: none; display: block; }
.strip img {
  /* Fixed height, width follows the photo's own ratio, so nothing is cropped. The
     intrinsic width/height attributes on each <img> keep this shift-free while
     loading. */
  height: clamp(158px, 27vw, 208px);
  width: auto;
  max-width: none;          /* overrides the global img rule: the strip scrolls */
  scroll-snap-align: center;
  background: var(--bg-subtle);
}


/* ---------- footer -------------------------------------------------------- */
footer {
  border-top: 1px solid var(--border);
  padding-block: 2.5rem 3.5rem;
  color: var(--text-muted);
  font-size: var(--step--1);
}
