/* Milutin — milutin.ai.rs
   Same palette as the app it describes, so the site and the product look like one
   thing. No web fonts, no CDN, no analytics: a page about not sending your data
   anywhere should not open six connections to load itself. */

:root {
  --bg: #ffffff;
  --bg-2: #f4f4f5;
  --bg-3: #e9e9ec;
  --fg: #16161a;
  --fg-2: #55555f;
  --fg-3: #8b8b96;
  --line: #e2e2e7;
  --accent: #ff7a3d;
  --accent-fg: #ffffff;
  --ok: #1baf7a;
  --code-bg: #f6f6f8;
  --radius: 18px;
  --wrap: 68rem;
  --mesh: .22;
  --glow: .09;
  --wire: .3;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Velvet, not true black: a deep plum base with the surfaces lifted off it on the
       same hue, so cards read as raised cloth rather than as holes cut in the page.
       The app uses #000 because OLED power matters on a phone; a marketing page can
       afford the depth. */
    --bg: #12101c;
    --bg-2: #1a1728;
    --bg-3: #242036;
    --fg: #f4f3f8;
    --fg-2: #b3b0c2;
    --fg-3: #837f96;
    --line: #2c2840;
    --accent: #ff8a52;
    --accent-fg: #14140f;
    --code-bg: #100e17;
    --mesh: .26;         /* pattern strength — texture, not wallpaper */
    --glow: .2;          /* the soft light behind the hero */
    --wire: .5;          /* conductor layer */
  }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  position: relative;
  background: var(--bg);
  color: var(--fg);
  font: 17px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* Two fixed layers behind everything: a lattice that reads as a graph without
   announcing itself, and one soft light above the hero so the page has a direction.
   Both are pointer-events:none and sit at z-index 0; every section is relative, so
   nothing here can swallow a click. A real file rather than a data: URI, so the CSP
   stays at img-src 'self' with no exception carved for inline images. */
body::before, body::after {
  content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none;
}
body::before {
  background: url("/pattern.svg") repeat;
  background-size: 64px 64px;
  opacity: var(--mesh);
  /* Fade it out down the page: texture at the top, calm where the reading happens. */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.35) 55%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.35) 55%, transparent 100%);
}
body::after {
  background:
    radial-gradient(70rem 38rem at 50% -8rem,
      color-mix(in srgb, var(--accent) 100%, transparent) 0%, transparent 70%);
  opacity: var(--glow);
}
header.top, .hero, section, footer { position: relative; z-index: 1; }

/* ---------- conductors ----------
   Traces with a charge running along them: the same path drawn twice, once dim and
   static as the copper, once bright and offset over time as the signal. The cheapest
   honest way to say "this thing computes" without a stock hero image.

   Inline SVG rather than a background image, because style-src is 'self' and an
   external sheet animating inline SVG needs no exception carved for it. */
.circuit {
  position: fixed; top: 0; left: 0; width: 100%; height: 72vh;
  z-index: 0; pointer-events: none; opacity: var(--wire);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.45) 45%, transparent 92%);
          mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.45) 45%, transparent 92%);
}
.circuit g { fill: none; }
.circuit .trace path {
  stroke: color-mix(in srgb, #a89bff 45%, transparent);
  stroke-width: 1; stroke-linecap: round; stroke-linejoin: round;
}
.circuit .via circle { fill: color-mix(in srgb, #a89bff 55%, transparent); }

/* The charge. A short lit segment chasing a long gap, so most of each trace is dark
   at any moment and the eye follows one moving thing per wire, not a parade. */
.circuit .pulse path {
  stroke: var(--accent); stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 26 1400;
  filter: drop-shadow(0 0 5px color-mix(in srgb, var(--accent) 70%, transparent));
  animation: charge 9s linear infinite;
}
.circuit .pulse path:nth-child(2) { animation-duration: 12s; animation-delay: -3s; }
.circuit .pulse path:nth-child(3) { animation-duration: 10s; animation-delay: -6s; }
.circuit .pulse path:nth-child(4) { animation-duration: 14s; animation-delay: -1s; }
.circuit .pulse path:nth-child(5) { animation-duration: 11s; animation-delay: -8s; }
.circuit .pulse path:nth-child(6) { animation-duration: 13s; animation-delay: -4s; }

@keyframes charge {
  from { stroke-dashoffset: 1426; }
  to   { stroke-dashoffset: 0; }
}

/* Motion is decoration, and decoration is the first thing to drop. */
@media (prefers-reduced-motion: reduce) {
  .circuit .pulse { display: none; }
  html { scroll-behavior: auto; }
}

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 22px; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

code, .mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .92em;
}
code { background: var(--code-bg); padding: 1px 6px; border-radius: 6px; }

/* ---------- header ---------- */

header.top {
  position: sticky; top: 0; z-index: 10;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--line);
}
header.top .wrap { display: flex; align-items: center; gap: 12px; height: 60px; }
header.top img { width: 28px; height: 28px; border-radius: 7px; }
header.top b { font-size: 17px; letter-spacing: -.01em; }
header.top nav { margin-left: auto; display: flex; gap: 18px; font-size: 14.5px; }
header.top nav a { color: var(--fg-2); }
@media (max-width: 620px) { header.top nav a.hide-sm { display: none; } }

/* ---------- hero ---------- */

.hero { padding: 74px 0 56px; }
.hero h1 {
  margin: 0 0 18px;
  /* Capped so "On a machine in your own company." holds one line on a desktop;
     at 4.2rem it broke after "own" and left one word stranded. */
  font-size: clamp(2.2rem, 6vw, 3.55rem);
  line-height: 1.04; letter-spacing: -.035em; font-weight: 800;
}
.hero h1 .sub { display: block; color: var(--fg-2); font-weight: 700; }
.hero p.lede {
  margin: 0 0 28px; max-width: 44rem;
  font-size: clamp(1.05rem, 2.4vw, 1.32rem); color: var(--fg-2);
}
.hero .cta { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 46px; padding: 0 20px; border-radius: 999px;
  font-size: 15.5px; font-weight: 650;
  background: var(--accent); color: var(--accent-fg);
}
.btn:hover { text-decoration: none; filter: brightness(1.06); }
.btn.ghost { background: var(--bg-2); color: var(--fg); border: 1px solid var(--line); }

/* ---------- numbers strip ---------- */

.stats {
  display: grid; gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 760px) { .stats { grid-template-columns: repeat(4, 1fr); } }
.stats { background: color-mix(in srgb, var(--line) 100%, transparent); }
.stats div {
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  padding: 20px 18px;
}
.stats b { display: block; font-size: clamp(1.5rem, 4vw, 2rem); letter-spacing: -.03em; }
.stats span { font-size: 13.5px; color: var(--fg-3); }

/* ---------- sections ---------- */

section { padding: 58px 0; border-top: 1px solid var(--line); }
section > .wrap > h2 {
  margin: 0 0 10px; font-size: clamp(1.5rem, 3.6vw, 2.1rem);
  letter-spacing: -.025em; line-height: 1.15;
}
section > .wrap > p.intro { margin: 0 0 28px; max-width: 46rem; color: var(--fg-2); }

.grid { display: grid; gap: 18px; grid-template-columns: 1fr; }
@media (min-width: 720px) { .grid.two { grid-template-columns: 1fr 1fr; } }
@media (min-width: 960px) { .grid.three { grid-template-columns: repeat(3, 1fr); } }

.card {
  /* Slightly translucent so the lattice continues underneath instead of stopping
     dead at every card edge — which is what makes it read as one surface. */
  background: color-mix(in srgb, var(--bg-2) 88%, transparent);
  border: 1px solid var(--line);
  border-radius: var(--radius); padding: 22px;
  backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
}
.card h3 { margin: 0 0 8px; font-size: 17.5px; letter-spacing: -.01em; }
.card p { margin: 0; color: var(--fg-2); font-size: 15.5px; }
.card p + p { margin-top: 10px; }
.card .tag {
  display: inline-block; margin-bottom: 10px; padding: 3px 9px; border-radius: 999px;
  background: var(--bg-3); color: var(--fg-3);
  font-size: 11.5px; font-weight: 650; text-transform: uppercase; letter-spacing: .05em;
}

/* ---------- tooltips ----------
   Jargon on a page an executive reads has to explain itself in place. CSS only, so it
   works with no script: hover with a pointer, focus with a tap or the keyboard, and the
   same words sit in the DOM for a screen reader instead of being locked in an attribute.

   The bubble is anchored to the CARD, not to the word. Anchoring it to the word means
   centring it on a span that can sit anywhere, and near an edge half the bubble ends up
   off the page — a problem with no CSS solution, only ever more special cases. Pinned to
   the container it is always in bounds, at any width, with no arithmetic. */
.tip {
  position: static;
  border-bottom: 1px dotted color-mix(in srgb, var(--accent) 70%, var(--fg-3));
  cursor: help;
}
.tip:focus { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }

.card, .stats div, .cta-band, p.intro, .hero p.lede { position: relative; }

.tip::after {
  content: attr(data-tip);
  position: absolute; left: 0; right: 0; top: calc(100% + 8px);
  padding: 12px 15px; border-radius: 12px;
  background: var(--bg-3); color: var(--fg);
  border: 1px solid color-mix(in srgb, var(--accent) 32%, var(--line));
  box-shadow: 0 18px 44px -12px rgba(0,0,0,.85);
  font-size: 13.5px; font-weight: 400; line-height: 1.5; text-align: left;
  opacity: 0; visibility: hidden; pointer-events: none; z-index: 40;
  transform: translateY(-5px);
  transition: opacity .16s ease, transform .16s ease, visibility .16s;
}
.tip:hover::after, .tip:focus::after {
  opacity: 1; visibility: visible; transform: translateY(0);
}
/* The last row of cards has nothing beneath it to overlay, so send those upward. */
.grid.three .card:nth-last-child(-n+3) .tip::after {
  top: auto; bottom: calc(100% + 8px); transform: translateY(5px);
}
.grid.three .card:nth-last-child(-n+3) .tip:hover::after,
.grid.three .card:nth-last-child(-n+3) .tip:focus::after { transform: translateY(0); }

/* The same words, for a screen reader, without repeating them on screen. */
.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* A question posed as a heading, in the voice a reader would ask it in. */
h3.q {
  margin: 36px 0 0; font-size: clamp(1.15rem, 2.6vw, 1.45rem);
  letter-spacing: -.02em;
}

/* Not shipped yet, and the card should not pretend otherwise. */
.card.soon { border-style: dashed; background: none; }
.card.soon .tag { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }

/* Permission gate mock — the security story is easier shown than described. */
.gate {
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: 14px; padding: 14px 16px; max-width: 30rem;
}
.gate .q { font-size: 15.5px; margin-bottom: 12px; }
.gate .row { display: flex; gap: 8px; }
.gate .row span {
  padding: 7px 16px; border-radius: 9px; font-size: 14px; font-weight: 650;
}
.gate .yes { background: var(--accent); color: var(--accent-fg); }
.gate .no { background: var(--bg-3); color: var(--fg-2); }

/* Closing call to action. Sits where the argument has just been made, and reads as
   an offer rather than a banner: same card language as everything above it. */
.cta-band {
  margin-top: 30px; padding: 26px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 20px;
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--accent) 9%, transparent),
      color-mix(in srgb, var(--bg-2) 92%, transparent) 60%);
  border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--line));
  border-radius: var(--radius);
}
.cta-band > div { flex: 1 1 22rem; min-width: 0; }
.cta-band h3 { margin: 0 0 8px; font-size: 20px; letter-spacing: -.015em; }
.cta-band p { margin: 0; color: var(--fg-2); font-size: 15.5px; }
.cta-band .btn { flex: none; }

/* ---------- the stage ----------
   The screenshots ARE the hero: a phone rail across the top, headline underneath.
   Capped so the first lines of the headline are visible without scrolling — the
   gallery has to invite, not swallow the page.

   The 3D is scroll-driven and pure CSS: each slide carries its own view timeline
   along the rail's inline axis, so its rotation follows its position in the
   scroller. Browsers without scroll-driven animations get flat slides that still
   scroll and snap — the layout never depends on the effect landing. */
.stage {
  padding: 22px 0 8px;
  border-top: 0;
}
.stage .wrap { padding: 0; }

.shots {
  display: grid; gap: 22px;
  grid-auto-flow: column; grid-auto-columns: max-content;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  padding: 26px max(22px, calc(50% - 9rem)) 14px;
  scrollbar-width: none;
  perspective: 1400px; perspective-origin: 50% 45%;
}
.shots::-webkit-scrollbar { display: none; }

.shots figure {
  margin: 0; scroll-snap-align: center; scroll-margin-inline: 22px;
  transform-style: preserve-3d;
  will-change: transform;
  animation: coverflow linear both;
  animation-timeline: view(inline);
  animation-range: cover 0% cover 100%;
}
@keyframes coverflow {
  0%   { transform: rotateY(34deg)  scale(.82) translateZ(-90px); opacity: .45; }
  50%  { transform: rotateY(0)      scale(1)   translateZ(0);     opacity: 1; }
  100% { transform: rotateY(-34deg) scale(.82) translateZ(-90px); opacity: .45; }
}

.shots a { display: block; }
.shots img {
  /* Sized by HEIGHT, not width: the cap has to leave the headline's first lines
     on screen without scrolling, and that is a vertical budget. */
  display: block; width: auto; height: min(46vh, 520px);
  border: 1px solid var(--line); border-radius: 20px;
  background: var(--bg-2);
  box-shadow: 0 22px 50px -18px rgba(0,0,0,.75), 0 2px 10px rgba(0,0,0,.4);
  transition: border-color .25s ease, box-shadow .25s ease;
}
.shots a:hover img {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  box-shadow: 0 26px 60px -16px color-mix(in srgb, var(--accent) 30%, rgba(0,0,0,.8));
}
.shots figcaption {
  margin: 12px auto 0; max-width: 17rem;
  font-size: 12.5px; line-height: 1.45; color: var(--fg-3); text-align: center;
}

.stage-note {
  margin: 4px 0 10px; text-align: center;
  font-size: 13px; color: var(--fg-3);
}
.dots { display: flex; gap: 8px; justify-content: center; margin: 0 0 4px; }
.dots a {
  width: 28px; height: 28px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 650;
  color: var(--fg-3); background: var(--bg-2); border: 1px solid var(--line);
}
.dots a:hover {
  text-decoration: none; color: var(--fg);
  border-color: color-mix(in srgb, var(--accent) 50%, var(--line));
}

/* Desktop: a vertical mouse wheel does not scroll a horizontal container, and no CSS
   maps one to the other. So on a wide screen with a real pointer, stop asking — shrink
   the slides until all five fit and remove the centering pad. Nothing scrolls, so
   nothing needs to be scrolled.

   The rail keeps overflow-x, deliberately: view(inline) needs a scrollport to measure
   against. With the content fitting, each slide's position is fixed, so the coverflow
   becomes a static arc — flat in the middle, turned at both ends. Touch devices keep
   the swipe, which is the better gesture there anyway.

   Keyed on width alone, not (pointer: fine): touch laptops and hybrids report coarse,
   and a 1180px-wide screen wants the full set either way. */
@media (min-width: 1180px) {
  .shots {
    grid-auto-columns: auto;
    justify-content: center;
    padding-inline: 22px;
    gap: 26px;
  }
  .shots img { height: min(42vh, 460px); }
  .dots { display: none; }
  .stage-note { margin-bottom: 4px; }
}

/* ---------- zoom overlay ----------
   :target and nothing else. Tapping a shot used to open the raw .webp in a new tab,
   which throws the visitor out of the page to look at a picture of the page. */
.zoom {
  position: fixed; inset: 0; z-index: 60;
  display: none; align-items: center; justify-content: center;
  padding: max(18px, env(safe-area-inset-top)) 18px max(18px, env(safe-area-inset-bottom));
}
.zoom:target { display: flex; }
.zoom-veil {
  position: absolute; inset: 0;
  background: rgba(4, 3, 8, .88);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.zoom img {
  position: relative;
  max-height: 92vh; max-width: min(94vw, 440px); width: auto; height: auto;
  border: 1px solid var(--line); border-radius: 20px;
  box-shadow: 0 30px 80px -20px rgba(0,0,0,.9);
}
.zoom-x {
  position: absolute; top: max(14px, env(safe-area-inset-top)); right: 16px;
  width: 44px; height: 44px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 24px; line-height: 1; color: var(--fg);
  background: color-mix(in srgb, var(--bg-2) 86%, transparent);
  border: 1px solid var(--line);
}
.zoom-x:hover { text-decoration: none; border-color: var(--accent); }

/* The headline follows the stage, so it needs less air above it than a hero
   starting a page would. */
.hero { padding: 26px 0 52px; }

@media (prefers-reduced-motion: reduce) {
  .shots { scroll-behavior: auto; }
  .shots figure { animation: none; }
  .shots img { transition: none; }
}

/* Tables */
table { width: 100%; border-collapse: collapse; font-size: 15px; }
th, td { text-align: left; padding: 11px 12px; border-bottom: 1px solid var(--line); }
th { color: var(--fg-3); font-size: 12.5px; text-transform: uppercase; letter-spacing: .05em; }
td.n { text-align: right; font-variant-numeric: tabular-nums; }
.scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

ul.plain { margin: 0; padding-left: 1.1rem; color: var(--fg-2); }
ul.plain li { margin: 7px 0; }

pre {
  margin: 0; padding: 16px; overflow-x: auto;
  background: var(--code-bg); border: 1px solid var(--line); border-radius: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13.5px; line-height: 1.55; color: var(--fg-2);
}

.note {
  border-left: 3px solid var(--accent); padding: 4px 0 4px 16px;
  color: var(--fg-2); font-size: 15.5px;
}

footer {
  border-top: 1px solid var(--line); padding: 40px 0 56px;
  color: var(--fg-3); font-size: 14px;
}
footer p { margin: 0 0 8px; }

/* Replaces the inline margin-top attributes, which style-src 'self' blocks. */
.gap { margin-top: 22px; }
.grid.gap { margin-top: 26px; }
