/* MandićLab — shared styles for every page.
   Values come from concept/standalone.html. Where a value matches a design
   token exactly, the token is used; where it does not, the concept value is
   copied as-is, because rounding it to the nearest token would change the look. */

/* ── Fonts ─────────────────────────────────────────────────────────────── */
/* One variable file per script covers weights 200–500. The browser downloads
   a file only when the page contains characters from its unicode-range. */

@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 200 500;
  font-display: swap;
  src: url("/assets/fonts/montserrat-cyrillic-ext.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 200 500;
  font-display: swap;
  src: url("/assets/fonts/montserrat-cyrillic.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 200 500;
  font-display: swap;
  src: url("/assets/fonts/montserrat-vietnamese.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 200 500;
  font-display: swap;
  src: url("/assets/fonts/montserrat-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: 'Montserrat';
  font-style: normal;
  font-weight: 200 500;
  font-display: swap;
  src: url("/assets/fonts/montserrat-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;
}

/* ── Tokens ────────────────────────────────────────────────────────────── */

:root {
  --bg:#0B0B0C;
  --surface-1:rgba(242,242,240,0.04);
  --surface-2:rgba(242,242,240,0.08);
  --overlay-header:rgba(11,11,12,0.55);

  --text-1:#F2F2F0;
  --text-2:rgba(242,242,240,0.78);
  --text-3:rgba(242,242,240,0.58);
  --text-disabled:rgba(242,242,240,0.38);

  --line-1:rgba(242,242,240,0.08);
  --line-2:rgba(242,242,240,0.16);
  --line-3:rgba(242,242,240,0.28);

  --accent-rose:#E89189;
  --accent-green:#9FE3C1;
  --accent-blue:#9CC2EE;
  --accent-gold:#E8C98C;

  --fs-display:clamp(34px,4vw,56px);
  --fs-h1:clamp(26px,2.8vw,38px);
  --fs-h2:clamp(20px,1.9vw,24px);
  --fs-h3:17px;
  --fs-body:15px;
  --fs-small:13px;
  --fs-label:12px;

  --section-y:clamp(64px,9vh,128px);
  --gutter:clamp(20px,4vw,48px);
  --container:1280px;
  --measure:66ch;
  --measure-narrow:46ch;

  --dur-fast:160ms;
  --dur-base:300ms;
  --dur-slow:500ms;
  /* Slideshow slides travel further, so they need longer than --dur-slow. */
  --dur-slide:1500ms;
  --ease:cubic-bezier(.16,1,.3,1);

  /* Height of the fixed header. Pages with a photo at the very top reserve it,
     so the header never covers the picture (docs/odluke.md). */
  --header-h:56px;
}

/* ── Base ──────────────────────────────────────────────────────────────── */

html, body { margin: 0; padding: 0; background: var(--bg); }
body { font-family: Montserrat, system-ui, sans-serif; -webkit-font-smoothing: antialiased; }
a { color: var(--text-1); text-decoration: none; }
/* In the concept every link sets its own colour inline, which beats this rule.
   :where() keeps this rule weaker than any component rule to match that. */
a:where(:hover) { color: var(--text-1); }
button { display: inline-block; background: none; border: 0; margin: 0; padding: 0; font: inherit; color: inherit; text-align: inherit; letter-spacing: inherit; -webkit-appearance: none; appearance: none; cursor: pointer; }
::selection { background: var(--line-2); }
:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: 2px; }
input:focus-visible, textarea:focus-visible { outline: none; border-color: var(--text-2); transition: border-color var(--dur-fast) var(--ease); }
[hidden] { display: none !important; }
/* Unreleased content (data-draft) is hidden unless the site is opened
   locally, where site.js shows it (docs/odluke.md). */
:root:not([data-show-drafts]) [data-draft] { display: none !important; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

.page {
  background: var(--bg);
  color: var(--text-1);
  font-family: Montserrat, system-ui, sans-serif;
  min-height: 100vh;
  overflow-x: hidden;
}

/* ── Header ────────────────────────────────────────────────────────────── */

.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 60;
  display: grid;
  grid-template-columns: minmax(0,1fr) auto minmax(0,1fr);
  align-items: center;
  height: var(--header-h);
  padding: 0 clamp(24px,4vw,64px);
  background: var(--overlay-header);
  backdrop-filter: blur(18px) saturate(120%);
  -webkit-backdrop-filter: blur(18px) saturate(120%);
  border-bottom: 1px solid var(--surface-1);
  view-transition-name: site-header;
}

.header-logo {
  display: flex;
  align-items: center;
  justify-self: end;
  padding: 8px 4px;
  margin-right: clamp(34px,4vw,68px);
}

.nav {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(32px,3.2vw,48px);
}

.nav a {
  display: block;
  padding: 16px 4px;
  font-size: var(--fs-label);
  font-weight: 400;
  letter-spacing: 0.18em;
  color: var(--text-3);
  text-shadow: 0 0 0 rgba(242,242,240,0);
  transition: color var(--dur-base) var(--ease), text-shadow var(--dur-base) var(--ease);
}
.nav a:hover { text-shadow: 0 0 16px var(--text-disabled); }
.nav a[aria-current] { color: var(--text-1); }

/* ── Footer ────────────────────────────────────────────────────────────── */

.footer {
  display: grid;
  grid-template-columns: auto minmax(0,1fr) auto;
  align-items: center;
  gap: clamp(24px,3vw,48px);
  padding: clamp(32px,3vw,48px) clamp(24px,4vw,64px);
  border-top: 1px solid var(--line-1);
}

.footer-brand { display: flex; align-items: center; gap: 16px; }
.footer-brand span {
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--text-3);
}

.footer-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(16px,2vw,32px);
  font-size: var(--fs-label);
  font-weight: 300;
  letter-spacing: 0;
  color: var(--text-3);
}
.footer-meta a { color: var(--text-3); }

/* 24×24 touch target around a 16×16 icon; the negative margins keep the
   on-screen spacing unchanged. See docs/odluke.md. */
.footer-social {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: clamp(12px,1.6vw,24px);
  margin: -4px;
  padding: 4px;
}
.footer-social a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  margin: -4px;
}
.footer-social span {
  display: block;
  width: 16px;
  height: 16px;
  background: var(--text-3);
  -webkit-mask: var(--icon) center / contain no-repeat;
  mask: var(--icon) center / contain no-repeat;
  transition: background var(--dur-base) var(--ease);
}

/* ── Shared layout ─────────────────────────────────────────────────────── */

.container { max-width: var(--container); margin: 0 auto; }

/* Centered display-size statement used as the About and Contact headline. */
.statement {
  margin: 0;
  text-align: center;
  font-size: var(--fs-display);
  font-weight: 200;
  line-height: 1.55;
  letter-spacing: -0.01em;
  color: var(--text-1);
}

.rule { margin-top: clamp(32px,3.6vh,48px); height: 1px; background: var(--line-1); }

/* Glass button, e.g. "Show more". */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 12px 24px;
  border: 1px solid var(--line-2);
  background: var(--surface-2);
  backdrop-filter: blur(26px);
  -webkit-backdrop-filter: blur(26px);
  font-size: var(--fs-label);
  font-weight: 400;
  letter-spacing: 0.18em;
  color: var(--text-1);
  text-decoration: none;
  transition: background var(--dur-slow) var(--ease), border-color var(--dur-slow) var(--ease);
}
.btn:hover { background: var(--line-2); border-color: var(--line-3); }

/* Accent pill tags are a deliberate, contained exception to the type scale:
   11px text with 5px/10px padding. Contrast is 8.3:1 or better, the text is
   uppercase and two or three words long, so the 12px small-text minimum does
   not apply here. Do not "fix" these back to 12px. The exception covers only
   these pills (project cards, product pages) — 11px elsewhere stays banned. */
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  line-height: 1;
  padding: 5px 10px;
  padding-right: calc(10px - 0.18em);
  border-radius: 999px;
  border: 1px solid;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.pill-green { border-color: rgba(159,227,193,0.28); background: rgba(159,227,193,0.08); color: var(--accent-green); }
.pill-rose { border-color: rgba(232,145,137,0.28); background: rgba(232,145,137,0.08); color: var(--accent-rose); }
.pill-gold { border-color: rgba(232,201,140,0.28); background: rgba(232,201,140,0.08); color: var(--accent-gold); }

/* ── Slideshow ─────────────────────────────────────────────────────────── */
/* Shared by the Home hero and the product page heroes; behaviour lives in
   assets/js/slideshow.js. Each .slide holds one image; arrows, dots and
   thumbnails are added by the script when there are at least two slides. */

.slideshow-wrap { width: 100%; height: 100%; }

.slideshow {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 0;
  overflow: hidden;
  outline: none;
  border-bottom: 1px solid var(--line-1);
}
.slideshow:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: 2px; }

.slide, .slide-empty { position: absolute; inset: 0; overflow: hidden; }
/* The images travel as one strip; the script sets each one's position and
   timing (assets/js/slideshow.js). A waiting image rests off to the side. */
.slide { transform: translateX(100%); z-index: 1; pointer-events: none; }
.slide.is-active { z-index: 2; pointer-events: auto; }
/* A copy that finishes leaving the frame while the image itself comes back in
   on the other side. */
.slide.is-ghost { z-index: 1; pointer-events: none; }
/* Before the script runs (or without it) the first slide shows. */
.slideshow:not([data-ready]) .slide:first-child { transform: none; z-index: 2; }
.slide img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Empty frame while there are no images yet. */
.slide-empty { background: var(--surface-1); }
.slide ~ .slide-empty { display: none; }

.slide-arrow {
  position: absolute;
  z-index: 6;
  top: 50%;
  margin-top: -22px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  box-sizing: border-box;
  color: var(--text-2);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease);
}
.slide-arrow.is-prev { left: clamp(16px,1.6vw,24px); }
.slide-arrow.is-next { right: clamp(16px,1.6vw,24px); }
.slide-arrow:hover { color: var(--text-1); }
.slide-arrow span { display: block; width: 11px; height: 11px; transform: rotate(45deg); }
.slide-arrow.is-prev span { border-left: 1px solid currentColor; border-bottom: 1px solid currentColor; margin-left: 4px; }
.slide-arrow.is-next span { border-right: 1px solid currentColor; border-top: 1px solid currentColor; margin-right: 4px; }
@media (hover: hover) { .slideshow:hover .slide-arrow { opacity: 1; } }
/* On touch there is no hover, so the arrows stay visible — the bare arrow,
   with no plate behind it (the concept had one). */
@media (hover: none) { .slide-arrow { opacity: 1; } }
.slide-arrow:focus-visible { opacity: 1; outline: 2px solid var(--accent-blue); outline-offset: 2px; }
.slideshow:focus-visible .slide-arrow { opacity: 1; }

.slide-dots {
  position: absolute;
  z-index: 6;
  left: 0;
  right: 0;
  bottom: clamp(24px,3vh,32px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 16px;
  box-sizing: border-box;
}
/* The dots are centred on the frame, not on the row: the play button stands to
   their left, and an empty counterweight of the same width on the right keeps
   it from pushing them off centre. See docs/odluke.md. */
.slide-dots:has(.slide-play)::after { content: ""; width: 8px; height: 0; }
/* 24×24 touch target around an 8×8 dot; the negative margin keeps the
   on-screen gap at 8px. See docs/odluke.md. */
.slide-dot, .slide-play {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  margin: -8px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  cursor: pointer;
}
.slide-dot span {
  display: block;
  width: 8px;
  height: 8px;
  box-sizing: border-box;
  border: 1px solid var(--line-2);
  background: transparent;
  transition: background var(--dur-fast) var(--ease);
}
.slide-dot[aria-current="true"] span { background: var(--text-1); }
/* The play/pause mark stands on its own, a little taller than a dot and with
   thicker strokes, so it reads at a glance without a box around it. */
.slide-play > span {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 14px;
  height: 14px;
  box-sizing: border-box;
}
.slide-play .bar { display: block; width: 3px; height: 12px; background: var(--text-1); }
.slide-play .tri { display: block; width: 0; height: 0; border-left: 10px solid var(--text-1); border-top: 6px solid transparent; border-bottom: 6px solid transparent; }
/* It grows a little on hover, dips on click, and the new mark (play or pause)
   grows into place when the two swap. */
.slide-play { transition: transform var(--dur-base) var(--ease); }
.slide-play:hover { transform: scale(1.12); }
.slide-play:active { transform: scale(0.9); transition-duration: var(--dur-fast); }
@keyframes mlPlayPop { from { transform: scale(0.72); opacity: 0.35; } to { transform: scale(1); opacity: 1; } }
.slide-play.is-toggled > span { animation: mlPlayPop var(--dur-base) var(--ease); }

.slide-thumbs-outer { padding: 0 clamp(24px,4vw,64px); }
.slide-thumbs-inner { max-width: var(--container); margin: 0 auto; }
/* 2px of room around the row, pulled back by the margin, so the hover scale of
   a thumbnail is not clipped at the top. */
.slide-thumbs { display: flex; gap: 12px; margin: 10px -2px 0; padding: 2px 2px 4px; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
.slide-thumb {
  position: relative;
  flex: 0 0 auto;
  padding: 0;
  cursor: pointer;
  width: clamp(96px,10vw,148px);
  height: clamp(62px,6.4vw,94px);
  overflow: hidden;
  border: 1px solid var(--line-1);
  box-shadow: 0 0 0 rgba(0,0,0,0);
  /* The concept also declares a 300ms transform transition for thumbnails,
     but its inline transition overrides it, so the hover scale is instant. */
  transition: border-color var(--dur-slow) var(--ease), box-shadow var(--dur-slow) var(--ease);
}
.slide-thumb[aria-current="true"] { border-color: var(--text-disabled); box-shadow: 0 0 18px var(--surface-2); }
.slide-thumb:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: 2px; }
@media (hover: hover) { .slide-thumb:hover { transform: scale(1.02); } }
.slide-thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* ── Home ──────────────────────────────────────────────────────────────── */

/* 100svh is the height visible with the browser bars shown, so on phones the
   bottom of the hero (text and button) is not hidden under the address bar.
   100vh stays as the fallback for older browsers. */
/* 66.667vw is width ÷ 1.5, so the frame never gets narrower than 3:2: below
   that the crop starts eating into the subject. On a window taller than it is
   wide the hero therefore stops short of the fold, and on a phone it changes
   shape altogether — see the block near the end of this file (docs/odluke.md). */
/* The hero starts under the header, never behind it, and still fills what is
   left of the screen: header + hero is exactly one screenful. */
.hero { position: relative; margin-top: var(--header-h); height: min(100vh - var(--header-h),66.667vw); height: min(100svh - var(--header-h),66.667vw); min-height: min(620px,66.667vw); width: 100%; overflow: hidden; }
.hero-slideshow { position: absolute; inset: 0; }
.hero-fade {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 180px;
  z-index: 7;
  pointer-events: none;
  background: linear-gradient(180deg,rgba(11,11,12,0.5) 0%,rgba(11,11,12,0) 100%);
}

/* Text over a hero image: it sits inside its slide, so it fades in and out
   with that image and a slide without text shows only the photo. */
.hero-gradient {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(to right, rgba(11,11,12,0.52) 0%, rgba(11,11,12,0.28) 40%, transparent 70%);
}
.hero-text {
  position: absolute;
  z-index: 4;
  top: 50%;
  transform: translateY(-50%);
  left: clamp(24px,4vw,64px);
  right: clamp(24px,4vw,64px);
  max-width: max(280px,50%);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
}
.hero-title {
  margin: 0;
  font-size: var(--fs-display);
  font-weight: 200;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--text-1);
  text-wrap: pretty;
}
/* Second line of the headline, under the project name and smaller. */
.hero-tagline { display: block; margin-top: 8px; font-size: var(--fs-h1); }
.hero-sub {
  margin: 16px 0 0;
  max-width: var(--measure-narrow);
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  color: var(--text-2);
  text-wrap: pretty;
}
.hero-text .btn { margin-top: 32px; white-space: nowrap; }
/* Someone else's handles under a hero description: icon plus handle, no
   underline, and the whole pair lights up on hover. */
.hero-social { display: flex; flex-wrap: wrap; gap: 8px 24px; margin-top: 16px; }
.hero-social a {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 24px;
  font-size: var(--fs-body);
  font-weight: 300;
  color: var(--text-2);
  transition: color var(--dur-base) var(--ease);
}
.hero-social a:hover { color: var(--text-1); }
.hero-social .repo-icon { width: 18px; height: 18px; background: currentColor; }

.news {
  position: relative;
  overflow: hidden;
  padding: clamp(64px,9vh,128px) clamp(24px,4vw,64px) clamp(96px,12vh,128px);
}
.news-grid-mask {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 11%, rgba(0,0,0,1) 89%, rgba(0,0,0,0) 100%), linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 12%, rgba(0,0,0,1) 88%, rgba(0,0,0,0) 100%);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to right, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 11%, rgba(0,0,0,1) 89%, rgba(0,0,0,0) 100%), linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 12%, rgba(0,0,0,1) 88%, rgba(0,0,0,0) 100%);
  mask-composite: intersect;
}
.news-grid {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(to right, var(--surface-1) 1px, transparent 1px), linear-gradient(to bottom, var(--surface-1) 1px, transparent 1px);
  background-size: 20vw 20vw;
  background-position: center top;
}
.news-inner { position: relative; z-index: 1; max-width: var(--container); margin: 0 auto; }
.news-heading { margin: 0; font-size: var(--fs-h2); font-weight: 300; line-height: 1.4; color: var(--text-1); }
.news-list { margin-top: clamp(32px,3.6vh,48px); }

/* Rows alternate image/text sides with direction: rtl; both children reset to
   ltr so no text runs right-to-left. See docs/odluke.md. */
.news-row {
  display: grid;
  grid-template-columns: repeat(auto-fit,minmax(300px,1fr));
  gap: clamp(24px,3vw,54px);
  align-items: center;
  direction: ltr;
  padding: 0;
  margin-top: 0;
}
.news-row:nth-child(even) { direction: rtl; }
.news-row + .news-row { margin-top: clamp(64px,8vh,110px); }
.news-img { position: relative; direction: ltr; width: 100%; aspect-ratio: 16 / 9; height: auto; overflow: hidden; background: var(--surface-1); }
.news-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* A news image can hold several photos that change on their own. */
.news-img .slideshow { position: absolute; inset: 0; height: auto; border-bottom: 0; }
.news-body {
  direction: ltr;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(12px,1.4vw,16px);
  padding: clamp(4px,1vw,16px) 0;
}
.news-kicker { font-size: var(--fs-small); font-weight: 400; line-height: 1.55; color: var(--text-3); }
.news-title { margin: 0; font-size: 24px; font-weight: 300; letter-spacing: -0.01em; line-height: 1.15; }
.news-text {
  margin: 0;
  max-width: var(--measure-narrow);
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  color: var(--text-2);
  text-wrap: pretty;
}
.news-cta {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: 4px;
  padding: 12px 16px;
  border: 1px solid var(--line-2);
  background: var(--surface-1);
  font-size: var(--fs-label);
  font-weight: 400;
  letter-spacing: 0.18em;
  color: var(--text-1);
  transition: background var(--dur-slow) var(--ease), border-color var(--dur-slow) var(--ease);
}
.news-cta:hover { background: var(--line-2); border-color: var(--line-3); }

/* ── Projects ──────────────────────────────────────────────────────────── */
/* Everything on this page sits on a 46px grid (--g). The card column (--cw)
   and the toolbar height (--tbh) are kept on whole grid units by
   assets/js/projects.js, so the background lines stay aligned with the cards. */

.projects {
  --g: 46px;
  --cw: calc(var(--g) * 24);
  position: relative;
  overflow: hidden;
  padding: calc(var(--g) * 3) calc(var(--g) / 2);
  min-height: 100vh;
  box-sizing: border-box;
}

.projects-grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: linear-gradient(to right, var(--surface-1) 1px, transparent 1px), linear-gradient(to bottom, var(--surface-1) 1px, transparent 1px);
  background-size: var(--g) var(--g);
  background-position: calc((100% - var(--cw)) / 2) calc(-1 * var(--g) / 2);
  -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 10%, rgba(0,0,0,1) 90%, rgba(0,0,0,0) 100%), linear-gradient(to bottom, rgba(0,0,0,0) 56px, rgba(0,0,0,1) 240px, rgba(0,0,0,1) calc(100% - 240px), rgba(0,0,0,0) calc(100% - 56px));
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to right, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 10%, rgba(0,0,0,1) 90%, rgba(0,0,0,0) 100%), linear-gradient(to bottom, rgba(0,0,0,0) 56px, rgba(0,0,0,1) 240px, rgba(0,0,0,1) calc(100% - 240px), rgba(0,0,0,0) calc(100% - 56px));
  mask-composite: intersect;
}

.projects-inner { position: relative; z-index: 1; max-width: var(--container); margin: 0 auto; }

.projects-toolbar {
  position: relative;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  align-content: flex-start;
  justify-content: center;
  column-gap: clamp(16px,2vw,32px);
  row-gap: 0;
  width: 100%;
  min-height: var(--tbh, calc(var(--g) * 2));
  margin: 0 0 calc(var(--g) * 2);
}

.search-slot { flex: 0 0 600px; max-width: 100%; min-width: 0; height: calc(var(--g) * 2); display: flex; align-items: center; }

.search {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 0 0 600px;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  overflow: hidden;
  padding: 12px 16px;
  border: 1px solid var(--text-disabled);
  background: var(--surface-1);
  transition: border-color var(--dur-fast) var(--ease);
}
.search:focus-within { border-color: var(--text-2); }
.search svg { flex: 0 0 auto; display: block; }

/* The real font-size is 16px so iOS Safari does not zoom the page when the
   field is tapped; scale(0.75) brings it back to 12px on screen, and the width
   compensates for the scaling. See docs/odluke.md — do not simplify. */
.search input {
  flex: 0 0 auto;
  width: calc(133.3333% - 33.34px);
  min-width: 0;
  height: 18.6px;
  padding: 4px 0;
  box-sizing: content-box;
  border: 0;
  background: transparent;
  color: var(--text-1);
  font-family: Montserrat, system-ui, sans-serif;
  font-size: 16px;
  font-weight: 300;
  letter-spacing: 0;
  line-height: 1.55;
  transform: scale(0.75);
  transform-origin: left center;
  -webkit-appearance: none;
  appearance: none;
}

.controls-slot { flex: 0 0 auto; height: var(--g); display: flex; align-items: center; }
.projects-controls { display: flex; align-items: center; justify-content: flex-start; gap: clamp(16px,1.4vw,24px); }

.menu { position: relative; }
.menu-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-3);
  cursor: pointer;
  transition: color var(--dur-base) var(--ease);
}
.menu-toggle[aria-expanded="true"], .menu-toggle.is-active { color: var(--text-1); }
.menu-toggle:hover { color: var(--text-1); }

.caret {
  display: block;
  width: 5px;
  height: 5px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--dur-fast) cubic-bezier(0.22,1,0.36,1);
}
[aria-expanded="true"] > .caret { transform: rotate(-135deg); }

.filter-dot { display: block; width: 5px; height: 5px; }
.filter-dot[data-kind="g"] { background: var(--accent-green); }
.filter-dot[data-kind="r"] { background: var(--accent-rose); }
.filter-dot[data-kind="y"] { background: var(--accent-gold); }

@keyframes mlMenuIn {
  from { opacity: 0; transform: translateX(var(--ml-shift,0px)) translateY(-6px) scale(0.985); filter: blur(2px); }
  to { opacity: 1; transform: translateX(var(--ml-shift,0px)) translateY(0) scale(1); filter: blur(0); }
}
@keyframes mlMenuOut {
  from { opacity: 1; transform: translateX(var(--ml-shift,0px)) translateY(0) scale(1); filter: blur(0); }
  to { opacity: 0; transform: translateX(var(--ml-shift,0px)) translateY(-4px) scale(0.99); filter: blur(1px); }
}

.menu-panel {
  position: absolute;
  top: calc(100% + 14px);
  left: 0;
  min-width: 170px;
  max-width: calc(100vw - 32px);
  box-sizing: border-box;
  padding: 8px;
  border: 1px solid var(--line-1);
  background: rgba(13,13,14,0.96);
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  transform-origin: left top;
  animation: mlMenuIn var(--dur-base) cubic-bezier(0.22,1,0.36,1) both;
}
.menu-panel.is-closing { animation: mlMenuOut var(--dur-fast) cubic-bezier(0.4,0,1,1) both; }

.sort-opt {
  padding: 8px 12px;
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  color: var(--text-3);
  background: transparent;
  transition: background var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}
.sort-opt.is-selected { color: var(--text-1); background: var(--surface-1); }

.filter-opt {
  appearance: none;
  -webkit-appearance: none;
  margin: 0;
  font: inherit;
  text-align: inherit;
  display: block;
  width: 100%;
  padding: 8px 12px;
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  border: 0;
  transition: background var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
  background: transparent;
}
.filter-opt[data-kind="all"] { color: var(--text-3); }
.filter-opt[data-kind="all"].is-selected { color: var(--text-1); background: var(--surface-1); }
.filter-opt[data-kind="g"] { color: var(--accent-green); text-shadow: 0 0 12px rgba(159,227,193,0.25); }
.filter-opt[data-kind="g"].is-selected { background: rgba(159,227,193,0.08); text-shadow: 0 0 12px rgba(159,227,193,0.4); }
.filter-opt[data-kind="r"] { color: var(--accent-rose); text-shadow: 0 0 12px rgba(232,145,137,0.25); }
.filter-opt[data-kind="r"].is-selected { background: rgba(232,145,137,0.08); text-shadow: 0 0 12px rgba(232,145,137,0.4); }
.filter-opt[data-kind="y"] { color: var(--accent-gold); text-shadow: 0 0 12px rgba(232,201,140,0.25); }
.filter-opt[data-kind="y"].is-selected { background: rgba(232,201,140,0.08); text-shadow: 0 0 12px rgba(232,201,140,0.4); }
.menu-panel button:hover { background: var(--surface-2); }
.menu-panel .filter-opt[data-kind]:hover { background: var(--surface-2); }

.pcard-wrap { width: var(--cw); margin: 0 0 var(--g); margin-left: calc(50% - var(--cw) / 2); }

.pcard {
  position: relative;
  overflow: hidden;
  box-sizing: border-box;
  height: calc(var(--g) * 7);
  border: 1px solid var(--line-1);
  box-shadow: 0 4px 14px rgba(0,0,0,0.22);
  transform: scale(1);
  transition: transform var(--dur-base) var(--ease);
}
.pcard:hover { transform: scale(1.02); }

/* Card images are always 16:9 (docs/odluke.md). On wide screens the card is
   24 grid units wide and 7 tall; the image column takes the width that makes
   the image 16:9 and the text gets the rest (533px vs 569px for the image). */
.pcard-grid {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0,1fr);
  grid-template-rows: 100%;
  height: 100%;
}
.pcard-img { position: relative; overflow: hidden; height: 100%; aspect-ratio: 16 / 9; background: var(--surface-1); }
.pcard-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

.pcard-body {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 24px;
  padding: 32px;
  background: rgba(10,10,10,0.74);
}
.pcard-title { margin: 0; font-size: 24px; font-weight: 500; letter-spacing: -0.01em; line-height: 1.15; }
.pcard-desc {
  margin: 24px 0 0;
  max-width: var(--measure-narrow);
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  color: var(--text-2);
  text-wrap: pretty;
}
.pcard-foot { display: flex; align-items: center; justify-content: space-between; gap: 24px; }
.pcard-tags { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; flex: 1 1 auto; min-width: 0; }
.pcard-foot .btn { flex: 0 0 auto; white-space: nowrap; }

.projects-empty {
  max-width: var(--container);
  padding: clamp(32px,3vw,48px) 0;
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  color: var(--text-3);
}

/* ── Product pages (DJC-DIY, easyrace) ─────────────────────────────────── */

/* Room for the fixed header, so it never covers the photo at the top. */
.product { padding-top: var(--header-h); padding-bottom: clamp(96px,10vh,128px); }
/* 66.667vw is width ÷ 1.5, so the frame never gets narrower than 3:2 — on a
   phone it shrinks instead of cropping into the photo (docs/odluke.md). */
.product .slideshow { height: min(74vh,760px,66.667vw); min-height: min(440px,66.667vw); }
.product-body { padding: 0 clamp(24px,4vw,64px); }
.product-inner { max-width: var(--container); margin: 0 auto; }
.product-title {
  margin: clamp(64px,7vw,96px) 0 0;
  max-width: var(--measure-narrow);
  font-size: var(--fs-display);
  font-weight: 200;
  line-height: 1.15;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.product-tags { display: flex; margin-top: clamp(16px,1.4vw,24px); }
.product-intro {
  margin: clamp(24px,2.6vw,48px) 0 0;
  max-width: var(--measure);
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  color: var(--text-2);
  text-wrap: pretty;
}

/* Gentle support note under the DJC-DIY intro: gold, softly glowing frame and
   title (the "In development" pill colours with the bundle-card glow), body
   in regular text so it stays easy to read. */
.support-note {
  margin-top: clamp(24px,2.6vw,48px);
  padding: 24px;
  border: 1px solid rgba(232,201,140,0.35);
  background: rgba(232,201,140,0.08);
  box-shadow: 0 0 26px rgba(232,201,140,0.08);
}
.support-note-title {
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--accent-gold);
  text-shadow: 0 0 12px rgba(232,201,140,0.25);
}
.support-note p {
  margin: 12px 0 0;
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  color: var(--text-2);
  text-wrap: pretty;
}
.support-note a {
  color: var(--accent-gold);
  border-bottom: 1px solid rgba(232,201,140,0.28);
  transition: border-color var(--dur-base) var(--ease);
}
.support-note a:hover { border-color: var(--accent-gold); }

/* Small uppercase heading used across the product panels. */
.label {
  margin: 0;
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--text-3);
}

/* Body paragraph; .pretty only where the concept balances the last line. */
.text {
  margin: 24px 0 0;
  max-width: var(--measure);
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  color: var(--text-2);
}
.pretty { text-wrap: pretty; }

.text-link { color: var(--text-1); border-bottom: 1px solid var(--line-3); transition: border-color var(--dur-base) var(--ease); }
.text-link:hover { border-color: var(--text-2); }

/* Tabs. The bar scrolls sideways on narrow screens; a fade on the right edge
   shows while more tabs are hidden (assets/js/product.js sets data-fade). */
.tabbar-wrap {
  position: relative;
  margin-top: clamp(48px,5vw,64px);
  border-top: 1px solid var(--line-1);
  border-bottom: 1px solid var(--line-1);
  background: var(--surface-1);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
.tabbar-wrap::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 32px;
  pointer-events: none;
  background: linear-gradient(to right, rgba(11,11,12,0), #0B0B0C);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease);
}
.tabbar-wrap[data-fade="1"]::after { opacity: 1; }
.tabbar {
  display: flex;
  align-items: stretch;
  gap: clamp(8px,1.8vw,24px);
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}
.tabbar::-webkit-scrollbar { display: none; }
.tab {
  position: relative;
  flex: 0 0 auto;
  padding: 24px clamp(12px,1.2vw,16px);
  cursor: pointer;
  font-size: var(--fs-label);
  font-weight: 400;
  letter-spacing: 0.18em;
  white-space: nowrap;
  color: var(--text-3);
  transition: color var(--dur-slow) var(--ease);
  scroll-snap-align: start;
}
.tab[aria-selected="true"] { color: var(--text-1); }

.panel { max-width: var(--container); padding: clamp(64px,7vh,96px) 0 clamp(96px,12vh,128px); }

/* Overview */
.overview { width: 100%; padding: clamp(64px,7vh,96px) 0 0; }
.overview-grid { display: grid; grid-template-columns: minmax(0,0.86fr) minmax(0,1fr); align-items: start; gap: clamp(48px,5vw,96px); }
.overview-media { min-width: 0; display: flex; flex-direction: column; gap: clamp(64px,7vh,96px); }
.overview-info { min-width: 0; }
.video-tabs { display: flex; align-items: center; flex-wrap: wrap; gap: clamp(16px,2.2vw,32px); }
.video-tab {
  cursor: pointer;
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-3);
  text-shadow: 0 0 0 rgba(242,242,240,0);
  transition: color var(--dur-slow) var(--ease), text-shadow var(--dur-base) var(--ease);
}
.video-tab.is-active { color: var(--text-1); }
.video-tab:hover { text-shadow: 0 0 14px var(--text-disabled); }
.video-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  margin-top: 24px;
  background: var(--surface-1);
  border: 1px solid var(--line-1);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
/* Switching videos: the frame stays, the old video fades out, and the new one
   fades in only once YouTube has loaded it (docs/odluke.md). */
.video-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  opacity: 1;
  transition: opacity var(--dur-slow) var(--ease);
}
.video-frame.is-switching iframe { opacity: 0; transition-duration: var(--dur-base); }

.info-intro { margin: 24px 0 0; font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-2); text-wrap: pretty; }
.info-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit,minmax(150px,1fr));
  gap: clamp(24px,2.2vw,32px);
  max-width: var(--measure-narrow);
  margin-top: clamp(32px,3.4vh,48px);
}
.info-list { margin-top: 12px; border-top: 1px solid var(--line-1); }
.info-list > div { padding: 8px 0; font-size: var(--fs-body); font-weight: 300; color: var(--text-2); }
/* drivepad: one list right after the intro sentence, without the top line;
   details in small text below an item. */
.info-intro + .info-list { border-top: 0; }
.info-note { margin: 24px 0 0; font-size: var(--fs-small); font-weight: 300; line-height: 1.65; color: var(--text-3); text-wrap: pretty; }
.info-links { margin: clamp(32px,4vh,48px) 0 0; font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-2); text-wrap: pretty; }
.info-links + .info-links { margin-top: 24px; }
/* Info heading between the specs and the links text: it takes the gap the
   text had, and the text sits under it like the specs under theirs. */
.info-title { margin-top: clamp(32px,4vh,48px); }
.info-title + .info-links { margin-top: 24px; }

.repo-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: clamp(32px,4.5vh,48px); }
.repo-actions a {
  display: inline-flex;
  flex: 0 0 auto;
  white-space: nowrap;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border: 1px solid var(--line-2);
  background: var(--surface-2);
  backdrop-filter: blur(26px);
  -webkit-backdrop-filter: blur(26px);
  font-size: var(--fs-label);
  font-weight: 400;
  letter-spacing: 0.18em;
  color: var(--text-1);
  transition: background var(--dur-slow) var(--ease), border-color var(--dur-slow) var(--ease);
}
.repo-actions a:hover { background: var(--line-2); border-color: var(--line-3); }
.repo-icon {
  display: block;
  width: 14px;
  height: 14px;
  background: var(--text-1);
  -webkit-mask: var(--icon) center / contain no-repeat;
  mask: var(--icon) center / contain no-repeat;
}

/* Gallery (under Overview). Each .shot holds one image at its own proportions;
   empty tiles use the concept's placeholder proportions. */
.gallery { width: 100%; }
.gallery-inner { margin-top: clamp(96px,10vh,128px); padding: clamp(48px,5.5vh,64px) 0 clamp(96px,12vh,128px); }
.gallery-head { display: flex; align-items: center; gap: clamp(16px,2vw,32px); }
.gallery-line { flex: 1 1 auto; height: 1px; background: var(--line-1); }
.gallery-head .label { flex: 0 0 auto; }
.gallery-grid { column-width: clamp(150px,12vw,210px); column-gap: clamp(12px,1.1vw,16px); margin-top: clamp(32px,3.6vh,48px); }
.shot {
  display: block;
  position: relative;
  width: 100%;
  margin: 0 0 clamp(12px,1.1vw,16px);
  break-inside: avoid;
  overflow: hidden;
  background: var(--surface-1);
  border: 1px solid var(--line-1);
  cursor: pointer;
  transition: transform var(--dur-base) var(--ease);
}
.shot:hover { transform: scale(1.02); }
.shot img { display: block; width: 100%; height: auto; }
.shot:not(:has(img)):nth-child(6n+1) { aspect-ratio: 4 / 3; }
.shot:not(:has(img)):nth-child(6n+2) { aspect-ratio: 3 / 4; }
.shot:not(:has(img)):nth-child(6n+3) { aspect-ratio: 1 / 1; }
.shot:not(:has(img)):nth-child(6n+4) { aspect-ratio: 3 / 2; }
.shot:not(:has(img)):nth-child(6n+5) { aspect-ratio: 4 / 5; }
.shot:not(:has(img)):nth-child(6n+6) { aspect-ratio: 16 / 9; }

/* Under the gallery: how someone's own photo gets in there. */
.gallery-note { max-width: var(--measure); margin: clamp(48px,5vh,64px) auto 0; text-align: center; }
.gallery-note p { margin: 0; font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-2); text-wrap: pretty; }
.gallery-note p + p { margin-top: 16px; }
.gallery-channel { color: var(--text-1); }
.gallery-terms { font-size: var(--fs-small); color: var(--text-3); }

/* Lightbox (assets/js/lightbox.js). Sizes that depend on the image and the
   window are set by the script; everything else lives here. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(16px,2vh,32px) clamp(16px,1.6vw,24px);
  box-sizing: border-box;
  background: rgba(11,11,12,0.55);
  backdrop-filter: blur(14px) saturate(118%);
  -webkit-backdrop-filter: blur(14px) saturate(118%);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease);
}
.lightbox.is-visible { opacity: 1; }
.lb-comp {
  position: relative;
  z-index: 4;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: clamp(24px,3vw,48px);
  max-width: 100%;
  max-height: 100%;
  opacity: 0;
  transform: translateY(6px) scale(0.976);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.lightbox.is-visible .lb-comp { opacity: 1; transform: translate(0,0) scale(1); transition-duration: var(--dur-slow); }
/* Moving between photos: the content fades out and back in while the photo and
   its text are swapped; the arrows and the close mark stay where they are. */
.lightbox.is-visible.is-fading .lb-comp { opacity: 0; transform: translate(0,0) scale(1); transition-duration: var(--dur-base); }
.lb-stage { position: relative; flex: 0 0 auto; line-height: 0; }
.lb-photo { display: block; object-fit: contain; pointer-events: auto; }
/* Fixed in the top corner, in line with the arrow below it. */
.lb-close {
  position: absolute;
  top: clamp(16px,2vh,32px);
  right: calc(clamp(58px,8vw,120px) / 2 - 17px);
  z-index: 7;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  pointer-events: auto;
  cursor: pointer;
}
.lb-x { position: relative; display: block; width: 15px; height: 15px; opacity: 0.22; transition: opacity var(--dur-slow) var(--ease); }
.lb-close:hover .lb-x { opacity: 0.9; }
.lb-x span { position: absolute; top: 50%; left: 0; width: 100%; height: 1px; background: var(--text-1); transform: rotate(45deg); }
.lb-x span + span { transform: rotate(-45deg); }
/* The text column starts level with the top edge of the photo. */
.lb-info {
  flex: 0 1 auto;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: clamp(24px,2.4vh,32px);
  max-width: 100%;
  max-height: 100%;
  box-sizing: border-box;
  overflow-y: auto;
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease);
}
.lightbox.is-visible .lb-info { opacity: 1; }
.lb-links { display: flex; flex-direction: column; gap: 4px; }
.lb-links > * {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line-1);
  font-size: var(--fs-small);
  font-weight: 500;
  letter-spacing: 0;
  color: var(--text-2);
  transition: color var(--dur-base) var(--ease);
}
/* The first tag sits a touch below the top edge of the photo, so the icon
   does not read as sticking out above it. */
.lb-links > *:first-child { padding-top: 8px; }
/* Without any text under them the last handle needs no line either. */
.lb-links:last-child > *:last-child { border-bottom: 0; }
.lb-links a:hover { color: var(--text-1); }
.lb-link-icon {
  display: block;
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  background: currentColor;
  -webkit-mask: var(--icon) center / contain no-repeat;
  mask: var(--icon) center / contain no-repeat;
}
.lb-desc { margin: 0; max-width: var(--measure-narrow); font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-2); text-wrap: pretty; }
.lb-desc + .lb-desc { margin-top: 16px; }
.lb-edge {
  position: absolute;
  z-index: 6;
  top: 0;
  bottom: 0;
  width: clamp(58px,8vw,120px);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.lb-prev { left: 0; }
.lb-next { right: 0; }
.lb-edge span { display: block; width: 13px; height: 13px; opacity: 0.22; transition: opacity var(--dur-slow) var(--ease); }
.lb-prev span { border-left: 1px solid var(--text-1); border-top: 1px solid var(--text-1); transform: rotate(-45deg); }
.lb-next span { border-right: 1px solid var(--text-1); border-top: 1px solid var(--text-1); transform: rotate(45deg); }
.lb-edge:hover span { opacity: 0.92; }

/* Parts */
.parts-group { margin-top: clamp(48px,5vh,64px); }
.parts-group.is-last { margin-top: clamp(64px,7vh,96px); }
.parts-scroll { margin-top: 24px; overflow-x: auto; }
.parts-table { min-width: 520px; }
.parts-table.parts-wide { min-width: 640px; }
.parts-head, .parts-row { display: grid; grid-template-columns: 90px minmax(0,1fr) minmax(0,1fr); gap: 24px; }
.parts-wide .parts-head, .parts-wide .parts-row { grid-template-columns: 90px minmax(0,0.8fr) minmax(0,1.6fr); }
.parts-head {
  padding: 0 4px 12px;
  border-bottom: 1px solid var(--line-2);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-3);
}
.parts-row {
  padding: 16px 4px;
  border-bottom: 1px solid var(--surface-1);
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.55;
  color: var(--text-2);
}
.parts-row > div:nth-child(odd) { color: var(--text-3); }

.promo {
  margin-top: clamp(48px,5vh,64px);
  padding: clamp(24px,3vw,32px);
  border: 1px solid var(--line-1);
  background: var(--surface-1);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
.promo-title { font-size: var(--fs-body); font-weight: 400; letter-spacing: 0; }
.promo .text { margin-top: 16px; }
.promo-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px; }
.btn-solid, .btn-ghost {
  display: inline-flex;
  align-items: center;
  padding: 12px 24px;
  font-size: var(--fs-label);
  font-weight: 400;
  letter-spacing: 0.18em;
}
.btn-solid { border: 1px solid var(--line-2); background: var(--surface-2); color: var(--text-1); transition: background var(--dur-slow) var(--ease), border-color var(--dur-slow) var(--ease); }
.btn-solid:hover { background: var(--line-2); border-color: var(--line-3); }
.btn-ghost { border: 1px solid var(--line-1); color: var(--text-2); transition: border-color var(--dur-slow) var(--ease), color var(--dur-slow) var(--ease); }
.btn-ghost:hover { border-color: var(--line-2); color: var(--text-1); }
.promo-note { margin: 24px 0 0; max-width: var(--measure); font-size: var(--fs-label); font-weight: 300; line-height: 1.65; color: var(--text-3); }

/* Software */
.software-intro { color: var(--text-3); }
.software-list { margin-top: clamp(32px,4.5vh,64px); border-top: 1px solid var(--line-1); }
.software-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 32px 4px;
  border-bottom: 1px solid var(--line-1);
}
.software-info { min-width: 240px; flex: 1 1 320px; }
.software-name { font-size: var(--fs-body); font-weight: 400; line-height: 1.55; }
.software-desc { margin-top: 12px; max-width: var(--measure); font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-3); }
.software-row .btn { flex: 0 0 auto; gap: normal; }

/* Assembly */
.steps { display: flex; flex-direction: column; gap: clamp(48px,6vh,64px); margin-top: clamp(48px,5.5vh,64px); }
.step-head { display: flex; gap: 16px; align-items: baseline; padding-bottom: 16px; border-bottom: 1px solid var(--line-1); }
.step-num { font-size: var(--fs-small); font-weight: 300; color: var(--text-3); }
.step-title { font-size: var(--fs-h3); font-weight: 400; letter-spacing: -0.01em; }
.text.after-figure { margin-top: 32px; }
/* Assembly drawings are A4 landscape SVGs, so the frame takes A4 proportions
   instead of the concept's 16:9 placeholder (docs/odluke.md). */
.figure {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 3508 / 2481;
  margin-top: 24px;
  border: 1px solid var(--line-1);
  background: var(--surface-1);
}
.figure img { display: block; width: 100%; height: 100%; }
.warning { margin-top: 24px; padding: 24px 24px; border: 1px solid rgba(232,145,137,0.28); background: rgba(232,145,137,0.08); }
.warning-title { font-size: var(--fs-small); font-weight: 400; line-height: 1.55; color: var(--accent-rose); }
.warning .text { margin-top: 16px; }

/* Licenses */
.licenses-title { margin-bottom: clamp(32px,4.5vh,64px); }
.licenses { display: flex; flex-direction: column; gap: 24px; margin-top: 24px; }
.license { font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-3); }
.license a { color: var(--text-1); border-bottom: 1px solid var(--line-2); }

/* FAQ accordion. The answer is visibility: hidden while closed, otherwise
   screen readers read it despite max-height: 0 (docs/odluke.md).
   --faq-h is each answer's own height, measured by product.js at the click. */
.faq { margin-top: clamp(32px,4.5vh,64px); border-top: 1px solid var(--line-1); }
.faq-item { border-bottom: 1px solid var(--line-1); }
.faq-q {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 32px;
  padding: 24px 4px;
  cursor: pointer;
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.55;
  color: var(--text-2);
  transition: color var(--dur-base) var(--ease);
}
.faq-q[aria-expanded="true"] { color: var(--text-1); }
.faq-q > span:first-child { max-width: var(--measure); }
.faq-icon { flex: 0 0 auto; width: 12px; height: 12px; margin-top: 8px; position: relative; opacity: 0.6; }
.faq-icon span { position: absolute; top: 50%; left: 0; width: 12px; height: 1px; background: currentColor; }
.faq-icon span + span { transform: rotate(90deg) scaleX(1); transition: transform var(--dur-slow) var(--ease); }
.faq-q[aria-expanded="true"] .faq-icon span + span { transform: rotate(90deg) scaleX(0); }
.faq-a {
  overflow: hidden;
  visibility: hidden;
  max-height: 0;
  opacity: 0;
  transition: max-height var(--dur-slow) var(--ease), opacity var(--dur-base) ease-out, visibility 0s linear var(--dur-slow);
}
.faq-q[aria-expanded="true"] + .faq-a {
  visibility: visible;
  max-height: var(--faq-h, 200px);
  opacity: 1;
  transition: max-height var(--dur-slow) var(--ease), opacity var(--dur-base) ease-out, visibility 0s linear 0s;
}
.faq-a p {
  margin: 0;
  padding: 0 4px 32px;
  max-width: var(--measure);
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  color: var(--text-3);
  text-wrap: pretty;
}

/* ── easyrace ──────────────────────────────────────────────────────────── */

/* The hero is the shared slideshow (see the Slideshow section above). */

.er-lead { display: flex; flex-wrap: wrap; align-items: flex-start; gap: clamp(32px,4vw,64px); }
.er-intro {
  flex: 1 1 440px;
  min-width: 0;
  position: relative;
  margin-top: clamp(48px,4.4vw,64px);
  display: flex;
  flex-direction: column;
  gap: 32px;
  max-width: var(--measure);
  padding: 12px 0 0 16px;
}
/* Faint 28px grid behind the intro text, faded out at the edges. */
.er-intro::before {
  content: '';
  position: absolute;
  left: -48px;
  right: -32px;
  top: -48px;
  bottom: -48px;
  background-image: repeating-linear-gradient(to right, var(--surface-1) 0 1px, transparent 1px 28px), repeating-linear-gradient(to bottom, var(--surface-1) 0 1px, transparent 1px 28px);
  mask-image: linear-gradient(to right, transparent 0, #000 9%, #000 91%, transparent 100%), linear-gradient(to bottom, transparent 0, #000 9%, #000 93%, transparent 100%);
  mask-composite: intersect;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 9%, #000 91%, transparent 100%), linear-gradient(to bottom, transparent 0, #000 9%, #000 93%, transparent 100%);
  -webkit-mask-composite: source-in;
  pointer-events: none;
}
.er-intro p { margin: 0; max-width: var(--measure); font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-2); }
.er-intro p span { font-weight: 500; color: var(--text-1); }
.er-video-col { flex: 1 1 380px; min-width: 0; margin-top: clamp(48px,4.4vw,64px); }
/* Empty 16:9 frame reserved for a video. */
.er-video {
  aspect-ratio: 16 / 9;
  width: 100%;
  border: 1px solid var(--line-1);
  background: var(--surface-1);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}

/* Bundles: a comparison table that scrolls sideways on narrow screens, with a
   fade on the right edge while there is more to see. */
.bundles { max-width: var(--container); margin: 0 auto; padding: clamp(64px,7vh,96px) 0 clamp(96px,12vh,128px); }
.bundles-wrap { position: relative; }
.bundles-wrap::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 32px;
  pointer-events: none;
  background: linear-gradient(to right, rgba(11,11,12,0), #0B0B0C);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease);
}
.bundles-wrap[data-fade="1"]::after { opacity: 1; }
.bundles-scroll { display: flex; justify-content: safe center; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.bundles-scroll > * { flex: 0 0 auto; min-width: 820px; }
.bundles-scroll::-webkit-scrollbar { display: none; }

.bundles-grid {
  display: grid;
  grid-template-columns: minmax(240px,1fr) repeat(3,minmax(150px,190px));
  justify-content: center;
  column-gap: clamp(12px,1.6vw,24px);
  max-width: var(--container);
  margin: 0 auto;
}
.bundles-grid.is-head { margin: clamp(32px,3.8vh,48px) auto 0; }
.bundles-grid.is-matrix { margin-top: clamp(24px,2.8vh,32px); }
.bundles-grid.is-tools { margin-top: clamp(32px,3.8vh,48px); }
.bundles-grid .label { padding-right: 16px; }

.bundle {
  padding: clamp(24px,2vw,32px) 16px clamp(24px,2.2vw,32px);
  text-align: center;
  border: 1px solid;
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
.bundle-name { font-size: var(--fs-label); font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; }
.bundle-was { margin-top: 16px; font-size: var(--fs-body); font-weight: 300; color: var(--text-3); text-decoration: line-through; }
.bundle-price { margin-top: 8px; font-size: var(--fs-h1); font-weight: 200; letter-spacing: -0.01em; color: var(--text-1); }
.bundle-save { display: flex; justify-content: center; margin-top: 12px; }
.bundle-save span { font-size: var(--fs-label); font-weight: 500; letter-spacing: 0.18em; }
.bundle-buy {
  display: block;
  box-sizing: border-box;
  width: 100%;
  text-align: center;
  margin-top: clamp(16px,1.8vw,24px);
  padding: 12px 16px;
  border: 1px solid;
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  transition: background var(--dur-base) var(--ease);
}
.bundle.is-green { border-color: rgba(159,227,193,0.35); background: rgba(159,227,193,0.08); box-shadow: 0 0 26px rgba(159,227,193,0.08); }
.bundle.is-green .bundle-name, .bundle.is-green .bundle-save span, .bundle.is-green .bundle-buy { color: var(--accent-green); }
.bundle.is-green .bundle-buy, .bundle.is-green .bundle-buy:hover { border-color: rgba(159,227,193,0.35); background: rgba(159,227,193,0.08); }
.bundle.is-blue { border-color: rgba(156,194,238,0.35); background: rgba(156,194,238,0.08); box-shadow: 0 0 26px rgba(156,194,238,0.08); }
.bundle.is-blue .bundle-name, .bundle.is-blue .bundle-save span, .bundle.is-blue .bundle-buy { color: var(--accent-blue); }
.bundle.is-blue .bundle-buy, .bundle.is-blue .bundle-buy:hover { border-color: rgba(156,194,238,0.35); background: rgba(156,194,238,0.08); }
.bundle.is-rose { border-color: rgba(232,145,137,0.35); background: rgba(232,145,137,0.08); box-shadow: 0 0 26px rgba(232,145,137,0.08); }
.bundle.is-rose .bundle-name, .bundle.is-rose .bundle-save span, .bundle.is-rose .bundle-buy { color: var(--accent-rose); }
.bundle.is-rose .bundle-buy, .bundle.is-rose .bundle-buy:hover { border-color: rgba(232,145,137,0.35); background: rgba(232,145,137,0.08); }

.bundle-row { display: contents; }
.bundle-feature { display: flex; align-items: center; height: 52px; padding-right: 16px; font-size: var(--fs-body); font-weight: 300; color: var(--text-2); }
.bundle-feature span { font-weight: 500; color: var(--text-1); }
.bundle-check { display: flex; align-items: center; justify-content: center; height: 52px; }
.bundle-check > div {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: 1px solid var(--line-1);
  background: var(--surface-1);
  box-shadow: none;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.bundle-check > div > div { width: 13px; height: 13px; background: transparent; }
.bundle-check.is-on > div { border-color: var(--text-disabled); box-shadow: 0 0 14px var(--surface-1); }
.bundle-check.is-on > div > div { background: rgba(236,236,233,0.88); }

.matrix-title { font-size: var(--fs-small); font-weight: 400; line-height: 1.55; color: var(--text-3); padding: 0 16px 12px 0; }
.matrix-name { font-size: var(--fs-small); font-weight: 300; line-height: 1.55; color: var(--text-2); padding: 12px 16px 12px 0; }
.spec { margin-top: 4px; font-size: var(--fs-label); line-height: 1.55; color: var(--text-3); }
.matrix-qty {
  font-size: var(--fs-small);
  font-weight: 300;
  line-height: 1.55;
  color: var(--text-3);
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px clamp(8px,0.8vw,12px);
}
.matrix-sep, .matrix-qty + .matrix-qty { border-left: 1px solid var(--line-1); }
.tools-title { font-size: var(--fs-small); font-weight: 400; line-height: 1.55; color: var(--text-3); padding-right: 16px; }
.tools-list { grid-column: 2 / span 3; display: flex; flex-wrap: wrap; gap: clamp(24px,2.6vw,48px); padding: 0 clamp(12px,1.2vw,16px); }
.tools-list > div { font-size: var(--fs-small); font-weight: 300; line-height: 1.55; color: var(--text-2); }
.soft-link { color: var(--text-2); text-decoration: none; border-bottom: 1px solid var(--line-3); transition: border-color var(--dur-base) var(--ease); }
.soft-link:hover { border-bottom-color: var(--text-3); }
.bundles-note { grid-column: 1 / -1; margin-top: clamp(24px,2.4vh,32px); font-size: var(--fs-small); font-weight: 300; line-height: 1.55; color: var(--text-2); }

/* Product sections (easysteer, easydrive, easyshift, easydrift). */
.er-panel { width: 100%; padding: clamp(64px,7vh,96px) 0 clamp(96px,12vh,128px); }
.er-sections { display: flex; flex-direction: column; gap: clamp(96px,10vh,128px); }
.er-divider { width: 100%; height: 0; border-top: 1px solid var(--line-1); margin-bottom: clamp(96px,10vh,128px); }
.er-title { margin: 0; font-size: var(--fs-display); font-weight: 200; line-height: 1.15; letter-spacing: -0.01em; text-transform: lowercase; }
.er-block { display: flex; flex-wrap: wrap; align-items: flex-start; gap: clamp(32px,4vw,64px); margin-top: clamp(48px,4.4vw,64px); }
.er-block-video { flex: 1 1 380px; min-width: 0; }
.er-block-text { flex: 1 1 440px; min-width: 0; display: flex; flex-direction: column; gap: clamp(32px,3vw,48px); max-width: var(--measure); }
.er-block-text p { margin: 12px 0 0; max-width: var(--measure); font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-2); text-wrap: pretty; }
.er-lines { display: flex; flex-direction: column; gap: 4px; margin-top: 12px; max-width: var(--measure); font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-2); }
.er-block-text .label.pad { padding-right: 16px; }
.er-need { display: flex; flex-wrap: wrap; gap: clamp(24px,2.4vw,32px) 0; margin-top: 16px; }
.er-need-parts { flex: 0 1 calc(265px + clamp(24px,3vw,46px)); min-width: 200px; box-sizing: border-box; }
.er-need-tools { flex: 1 1 150px; min-width: 150px; box-sizing: border-box; padding-left: clamp(24px,3vw,48px); border-left: 1px solid var(--line-1); }
.er-need-title { font-size: var(--fs-small); font-weight: 400; line-height: 1.55; color: var(--text-3); }
.er-need-tools .er-need-title { padding-right: 16px; }
.er-need-list { display: flex; flex-direction: column; gap: 16px; margin-top: 12px; }
.er-part { display: flex; align-items: center; justify-content: space-between; gap: 16px; max-width: min(265px, calc(100% - clamp(24px,3vw,46px))); }
.er-part-name { min-width: 0; font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-2); }
.er-part-qty { flex: 0 0 auto; font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-3); }
.er-tool { font-size: var(--fs-body); font-weight: 300; line-height: 1.65; color: var(--text-2); }
.er-tool .text-link { transition: border-color var(--dur-base) var(--ease); }
.er-tool .text-link:hover { border-bottom-color: var(--text-3); }
.er-price { font-size: var(--fs-h2); font-weight: 200; letter-spacing: -0.01em; color: var(--text-1); }
.er-buy-row { display: flex; margin-top: 16px; }
.er-buy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 180px;
  padding: 12px 16px;
  border: 1px solid rgba(232,145,137,0.35);
  background: rgba(232,145,137,0.08);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-rose);
  text-decoration: none;
  transition: background var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
}
.er-buy:hover { background: rgba(232,145,137,0.08); border-color: rgba(232,145,137,0.28); box-shadow: 0 0 22px rgba(232,145,137,0.08); }

/* ── About ─────────────────────────────────────────────────────────────── */

.about {
  padding: clamp(128px,18vh,192px) clamp(24px,4vw,64px);
  min-height: 100vh;
  box-sizing: border-box;
}

.about-text { max-width: var(--measure); margin: clamp(32px,3.6vh,48px) auto 0; text-align: center; }
.about-text p {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  color: var(--text-2);
  text-wrap: pretty;
}
.about-text p + p { margin-top: clamp(24px,3vh,32px); }

.about-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit,minmax(260px,1fr));
  gap: clamp(32px,5vw,96px);
  margin-top: clamp(32px,3.6vh,48px);
  padding-top: clamp(32px,4vw,48px);
  border-top: 1px solid var(--line-1);
}

.about-heading {
  text-align: center;
  font-size: var(--fs-h2);
  font-weight: 300;
  line-height: 1.4;
  color: var(--text-1);
}

.community {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  column-gap: clamp(32px,4.4vw,64px);
  row-gap: clamp(24px,2.4vw,32px);
  margin-top: clamp(32px,3vw,48px);
}
.community a {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-body);
  font-weight: 300;
  color: var(--text-2);
  opacity: 0.88;
  transition: opacity var(--dur-base) cubic-bezier(0.22,1,0.36,1), color var(--dur-base) cubic-bezier(0.22,1,0.36,1), filter var(--dur-base) cubic-bezier(0.22,1,0.36,1);
}
.community a:hover { opacity: 1; color: var(--text-1); filter: drop-shadow(0 0 10px var(--line-2)); }
.community-name { display: inline-flex; align-items: center; gap: 12px; }
.community-icon {
  display: block;
  width: 26px;
  height: 26px;
  background: currentColor;
  -webkit-mask: var(--icon) center / contain no-repeat;
  mask: var(--icon) center / contain no-repeat;
}
.community-sub {
  font-size: var(--fs-label);
  font-weight: 300;
  letter-spacing: 0;
  line-height: 1.4;
  text-align: center;
  color: var(--text-3);
}

/* ── Contact ───────────────────────────────────────────────────────────── */

/* The 404 page uses the same layout as Contact. */
.contact, .notfound {
  padding: clamp(128px,18vh,192px) clamp(24px,4vw,64px) clamp(96px,12vh,128px);
  min-height: 100vh;
  box-sizing: border-box;
}

.notfound-actions { display: flex; justify-content: center; margin-top: clamp(32px,3.6vh,48px); }

.contact-rows {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: center;
  column-gap: clamp(64px,10vw,128px);
  row-gap: clamp(32px,4vh,48px);
  margin-top: clamp(32px,3.6vh,48px);
}
.contact-item { display: flex; flex-direction: column; align-items: center; gap: clamp(16px,1.6vw,24px); }
.contact-label { font-size: var(--fs-small); font-weight: 400; line-height: 1.55; color: var(--text-3); }
.contact-link {
  font-size: var(--fs-h2);
  font-weight: 200;
  letter-spacing: -0.01em;
  color: var(--text-1);
  transition: color var(--dur-base) cubic-bezier(0.22,1,0.36,1), filter var(--dur-base) cubic-bezier(0.22,1,0.36,1);
}
.contact-link:hover { color: var(--text-1); filter: drop-shadow(0 0 10px var(--line-2)); }

/* ── Page transition ───────────────────────────────────────────────────── */
/* The concept fades the page out, swaps it after 220ms and fades the new one
   in over 300ms ease-out, while the header stays put. */

@view-transition { navigation: auto; }
::view-transition-old(root) { animation: var(--dur-base) ease-out both ml-page-out; }
::view-transition-new(root) { animation: var(--dur-base) ease-out 220ms both ml-page-in; }
::view-transition-group(site-header) { animation-duration: var(--dur-base); animation-timing-function: var(--ease); }
@keyframes ml-page-out { to { opacity: 0; } }
@keyframes ml-page-in { from { opacity: 0; } }

/* ── Responsive ────────────────────────────────────────────────────────── */

/* Cards stack as soon as they leave their full 24-unit width, so the text
   column beside the 16:9 image never gets narrower (docs/odluke.md). */
@media (max-width: 1170px) {
  .pcard { display: flex; flex-direction: column; height: auto; }
  .pcard-grid { grid-template-columns: minmax(0,1fr); grid-template-rows: auto 1fr; height: auto; flex: 1 1 auto; }
  .pcard-img { aspect-ratio: 16 / 9; height: auto; }
  .pcard-body { justify-content: flex-start; padding: 24px; gap: 16px; }
  .pcard-foot { flex-direction: column; align-items: flex-start; gap: 16px; }
  .pcard-title { font-size: 20px; }
}

/* The concept switches the Overview to one column below 820px viewport width. */
@media (max-width: 819px) {
  .overview-grid { grid-template-columns: minmax(0,1fr); }
  .lb-comp { flex-direction: column; }
}

@media (max-width: 900px) {
  .news-row, .news-row:nth-child(even) { grid-template-columns: minmax(0,1fr); direction: ltr; }
  .news-row + .news-row { margin-top: 48px; }
  .news-title { font-size: 20px; }
  .hero-gradient { background: linear-gradient(to top, rgba(11,11,12,0.78) 0%, rgba(11,11,12,0.45) 45%, transparent 80%); }
  .hero-text { top: auto; bottom: 64px; transform: none; left: var(--gutter); right: var(--gutter); max-width: none; }
  .hero-title { font-size: clamp(26px,6vw,34px); }
  .hero-tagline { font-size: var(--fs-h2); }
  .header { display: flex; align-items: center; justify-content: center; gap: 0; }
  .header > :last-child { display: none; }
  .header-logo { justify-self: auto; margin-right: 24px; flex: 0 0 auto; }
  .nav { flex: 0 0 auto; }
}

@media (max-width: 640px) {
  .hero { min-height: 70vh; min-height: 70svh; max-height: calc(100vh - var(--header-h)); max-height: calc(100svh - var(--header-h)); }
  .header { padding-left: 16px; padding-right: 16px; }
  .header-logo { margin-right: 16px; }
  .nav { gap: 20px; }
  .footer { grid-template-columns: minmax(0,1fr); justify-items: center; text-align: center; row-gap: 24px; padding-left: 16px; padding-right: 16px; }
  .footer-brand { justify-content: center; }
  .footer-meta { flex-direction: column; flex-wrap: nowrap; align-items: center; justify-content: center; gap: 12px; }
  .footer-social { justify-content: center; }
  /* .product keeps its own padding on .product-body, so its hero photo can run
     from edge to edge like the one on the home page. */
  main section:not(.hero):not(.projects):not(.product) { padding-left: 16px; padding-right: 16px; }
  .community { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); column-gap: 16px; row-gap: 24px; justify-items: center; }
  .contact-rows { flex-direction: column; align-items: center; row-gap: 24px; }
  .contact .statement, .notfound .statement { font-size: clamp(20px,5vw,26px); }
  .tab { padding: 16px 12px; }
  .parts-head { display: none; }
  .parts-row, .parts-wide .parts-row { grid-template-columns: auto minmax(0,1fr); gap: 4px 16px; padding: 16px 4px; }
  .parts-row > div:nth-child(3) { grid-column: 1 / -1; font-size: 13px; color: var(--text-3); }
  .parts-table, .parts-table.parts-wide { min-width: 0; }
  .info-grid { grid-template-columns: minmax(0,1fr); gap: 32px; }
  .lb-close { width: 44px; height: 44px; }
}

/* ── Hero on a phone ───────────────────────────────────────────────────── */
/* Wider screens only need the 3:2 cap on the hero's height (see .hero above):
   the text still fits over the photo. On a phone a 3:2 frame is too short to
   hold the text as well, so the photo takes a band across the top and the text
   moves under it. --band is that band's height, the viewport width ÷ 1.5, and
   the hero grows past the fold rather than let the text be cut off.
   See docs/odluke.md. */

@media (max-width: 640px) and (max-aspect-ratio: 3/2) {
  /* The hero is only as tall as it needs to be — photo, a breath, the text,
     and room for the dots. --hero-text is the tallest text any slide carries,
     measured by site.js so the dots stay put as the slides change; the value
     here is the fallback used until it does (and without JavaScript). */
  .hero {
    --band: 66.667vw;
    --hero-gap: 24px;
    --hero-text: 420px;
    height: calc(var(--band) + var(--hero-gap) + var(--hero-text) + 56px);
    min-height: 0;
    max-height: none;
  }
  /* aspect-ratio, not --band, so the frame is 3:2 against the real width of the
     page — on a desktop window --band counts the scrollbar in and would fall a
     few pixels short. */
  .hero .slide img, .hero .slide-empty { bottom: auto; height: auto; aspect-ratio: 3 / 2; }
  /* The photo melts into the page below it instead of ending on a hard line. */
  .hero-gradient {
    bottom: auto;
    height: var(--band);
    background: linear-gradient(to top, rgba(11,11,12,0.95) 0%, rgba(11,11,12,0.4) 8%, transparent 18%);
  }
  /* Every slide's text starts right under the photo, so the shorter ones leave
     their spare room at the bottom instead of floating in the middle. */
  .hero-text {
    top: calc(var(--band) + var(--hero-gap));
    bottom: 56px;
    justify-content: flex-start;
  }
  .hero-text > * { flex: 0 0 auto; }
  /* The arrows belong to the photo, so they sit on its middle, not the hero's. */
  .hero .slide-arrow { top: calc(var(--band) / 2); }
}

/* ── Reduced motion ────────────────────────────────────────────────────── */

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