/* ============================================================
   LAYRA — landing · "Glas"

   The tells in design/notes/ai-tells.md were taken out on
   2026-09-17: one flat accent instead of a gradient used eleven
   times, no scroll-reveal, fewer and flatter panels, and the
   page's single remaining gradient spent on the final call to
   action. design/notes/brez-ai.md lists every one of them, with
   what was deliberately left alone.

   The brand is a voice, so the voice is the brand element: a row
   of speaking bars. It lives in the wordmark, in the hero call
   card, and as the marker on every reason. Nothing else on the
   page carries motion or saturation — one motif, repeated small.

   Same ground rules as before: nothing animates a blur, a shadow
   or a blend mode. Canvas for the wave, transform/opacity for
   everything else.
   ============================================================ */

/* ---- the typeface ------------------------------------------
 *
 * **Self-hosted since 2026-09-19.** The page ran on the system stack until
 * now, which meant it had no face of its own: Segoe UI on Windows, SF on a
 * Mac, something else again on Android, and on none of them anything a
 * visitor would remember. A default typeface at hero size reads as an
 * absence — `design/notes/ai-tells.md` §5 says exactly that, and its own
 * escape hatch ("pick something with an opinion") was closed only because
 * a webfont was assumed to be off the table.
 *
 * It is not: the GDPR objection is to *hotlinking* Google's servers, which
 * sends every visitor's IP to a third country. These two files are served
 * off our own domain by the same Caddy block as the rest of `web/`, so
 * nothing leaves the page.
 *
 * **Why this one.** The same notes rule out Inter (§5, the default) and
 * Space Grotesk (§8b, the second-order cliché — the one people reach for
 * once they know Inter is wrong). Six candidates were rendered on the real
 * page and compared as images: Archivo, Onest, Instrument Sans, Familjen
 * Grotesk, Bricolage Grotesque and this. Instrument Sans and Familjen
 * Grotesk stop at weight 700, and the page sets 800 on every display
 * line, so both would have been synthesised — visibly lighter in the
 * comparison. Of the four that reach 900, Schibsted Grotesk is the one
 * drawn for a news publisher rather than for software, which is the
 * register this page is arguing in, and its Latin Extended is first-class
 * because it was built for European newsrooms — č, š and ž are drawn, not
 * composed out of spare parts.
 *
 * **Two files, not one**, because Slovene straddles the split: č U+010D,
 * š U+0161 and ž U+017E are Latin Extended-A, everything else is Latin-1.
 * The `unicode-range` on each is Google's own, so a browser fetches only
 * what a page actually uses — and both, here. 66 KB together, once, then
 * cached. `font-display: swap` means the text is readable in the system
 * font while that happens rather than invisible.
 *
 * To update: refetch from fonts.googleapis.com with a desktop UA, keep the
 * `latin` and `latin-ext` blocks, and drop the files in beside this. OFL,
 * licence in `web/assets/fonts/OFL.txt` — it has to ship with them.
 */

@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url(../fonts/schibsted-grotesk-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: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url(../fonts/schibsted-grotesk-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 {
  /* ground: cool porcelain, pulled back from icy blue toward stone */
  --paper:     #F1F5FB;
  --card:      #FFFFFF;

  /* near-black with a navy bias, not #000 */
  --ink:       #101725;
  --ink-soft:  #5C6779;
  --ink-faint: #8D97A8;

  /* one flat accent. --indigo survives for exactly one thing: the
     gradient on the final call to action, which is the only gradient
     left on the page. */
  --azure:     #1F6FE5;
  --indigo:    #4338CA;

  /* the one strong dark section, in Layra blue rather than a wash */
  --navy:      #101F3A;

  /* muted teal-green for reassurance */
  --pine:      #10786A;

  /* errors stay warm — a blue error just reads as more accent */
  --alert:     #C8372D;

  /* the shadow cards cast: deep navy, never neutral grey */
  --cast:      19, 30, 66;

  --line:      rgba(16, 23, 37, .10);
  --line-soft: rgba(16, 23, 37, .06);

  /* the system stack stays behind it, for the swap and for a failed fetch */
  --font-sans: "Schibsted Grotesk", "Segoe UI Variable Display", "Segoe UI",
               -apple-system, BlinkMacSystemFont, "SF Pro Display",
               "Helvetica Neue", Arial, sans-serif;

  --shell: 1180px;
  --gutter: clamp(1.25rem, 4vw, 2.75rem);
  --mast: clamp(4.25rem, 7vh, 5.25rem);

  --ease: cubic-bezier(.22, 1, .36, 1);
}

/* ---- reset ------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  font-family: var(--font-sans);
  color: var(--ink);
  background-color: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

h1, h2, h3, p, figure, blockquote { margin: 0; }
svg { display: block; }
a { color: inherit; text-decoration: none; }
button, input { font: inherit; color: inherit; }

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

.sr-only {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

.skip {
  position: absolute; left: 50%; top: 0; z-index: 200;
  transform: translate(-50%, -120%);
  padding: .7rem 1.1rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 0 0 10px 10px;
  font-size: .9rem;
}
.skip:focus-visible { transform: translate(-50%, 0); }

.icon { width: 17px; height: 17px; fill: currentColor; flex: none; }
.icon--line {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* barely-there texture, so the big flat ground doesn't band */
.grain {
  position: fixed; inset: 0; z-index: 90;
  pointer-events: none;
  opacity: .022;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---- the voice glyph --------------------------------------- */

/* four bars, everywhere the brand shows its face. animation runs
   only where a parent says so (.is-live), so a page full of glyphs
   stays still and the one under your cursor speaks. */
.glyph { width: 20px; height: 20px; flex: none; }
.glyph rect {
  fill: var(--azure);
  transform-origin: center;
  transform-box: fill-box;
}
.is-live .glyph rect,
.glyph.glyph--live rect,
.reason:hover .glyph rect,
.wordmark:hover .glyph rect,
.foot__brand:hover .glyph rect { animation: speak 1.05s var(--ease) infinite; }
.glyph rect:nth-child(1) { animation-delay: 0s;    }
.glyph rect:nth-child(2) { animation-delay: .14s;  }
.glyph rect:nth-child(3) { animation-delay: .28s;  }
.glyph rect:nth-child(4) { animation-delay: .42s;  }

@keyframes speak {
  0%, 100% { transform: scaleY(1); }
  35%      { transform: scaleY(1.65); }
  70%      { transform: scaleY(.62); }
}

/* ---- masthead ---------------------------------------------- */

.masthead {
  position: sticky; top: 0; z-index: 50;
  background: var(--card);
  border-bottom: 1px solid var(--line-soft);
}

.masthead__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  height: var(--mast);
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-size: 1.05rem;
  font-weight: 800;
  letter-spacing: .17em;
}

.nav {
  display: flex;
  gap: clamp(1rem, 2.2vw, 2rem);
  font-size: .93rem;
  font-weight: 500;
  color: var(--ink-soft);
}
.nav a {
  position: relative;
  padding-block: .3rem;
  transition: color .25s var(--ease);
}
.nav a::after {
  content: "";
  position: absolute; left: 0; right: 100%; bottom: 0;
  height: 2px;
  background: var(--azure);
  border-radius: 2px;
  transition: right .3s var(--ease);
}
.nav a:hover { color: var(--ink); }
.nav a:hover::after { right: 0; }

.masthead__actions {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

.link-quiet {
  font-size: .93rem;
  font-weight: 500;
  color: var(--ink-soft);
  transition: color .25s var(--ease);
}
.link-quiet:hover { color: var(--ink); }

.btn-call {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding: .6rem 1.15rem;
  border-radius: 999px;
  border: 1px solid rgba(31, 111, 229, .3);
  background: var(--card);
  font-size: .93rem;
  font-weight: 600;
  transition: border-color .25s var(--ease), background .25s var(--ease);
}
.btn-call:hover {
  border-color: rgba(31, 111, 229, .55);
  background: rgba(31, 111, 229, .05);
}
.btn-call .icon { color: var(--azure); }

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

.hero {
  display: grid;
  /* **1.12 / .88, widened from 1.04 / .96 on 2026-09-19.** The headline's
     longest line, "morete oglasiti,", measures 529px at the capped 4.6rem;
     the copy column measured 530. One pixel is not a margin, it is a coin
     toss between browsers, and it landed the wrong way on the owner's screen.
     At 1.12 the column is 571px — 42px of slack — and the call card, at 449px
     rather than 470, loses nothing but one extra line-wrap in its first
     bubble. */
  grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 4.5rem);
  max-width: var(--shell);
  margin-inline: auto;
  min-height: calc(100svh - var(--mast) - 6rem);
  padding: clamp(2.5rem, 6vh, 4rem) var(--gutter) clamp(2.5rem, 6vh, 4rem);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .38rem .85rem;
  border-radius: 999px;
  border: 1px solid rgba(16, 120, 106, .22);
  background: rgba(16, 120, 106, .06);
  font-size: .8rem;
  font-weight: 600;
  color: var(--pine);
}
.chip__dot {
  width: 7px; height: 7px; flex: none;
  border-radius: 50%;
  background: var(--pine);
  animation: breathe 2.6s var(--ease) infinite;
}
@keyframes breathe {
  0%, 100% { transform: scale(1);   opacity: 1; }
  50%      { transform: scale(.55); opacity: .55; }
}

/* **The page's type went up a step on 2026-09-19**, at the owner's word: the
   headline 4.3 → 4.6rem and every section title 2.4 → 3rem at desktop, with
   the two ledes lifted just enough to keep the ratio. Four sizes were rendered
   and compared (+0/+12/+25/+38%); the hero took the smaller step and the
   section titles the larger one, because past a point the headline wraps to
   four lines and "Ko se vi" is left alone on the first, while the section
   titles had been reading light against the cards beside them.

   **4.8rem the same day, then 4.6** — the headline was set from the system
   stack, and Schibsted Grotesk (see the note at the top of this file) runs
   wider, so the same 4.8rem tipped to the four-line wrap this note was
   written to avoid. 4.6rem is the largest that still sets in three; it reads
   *larger* than the old 4.3rem by more than the numbers suggest, because the
   new face carries a taller x-height at the same em. */
.headline {
  margin-top: 1.1rem;
  max-width: 15ch;
  font-size: clamp(2.55rem, 5.65vw, 4.6rem);
  font-weight: 800;
  line-height: 1.04;
  letter-spacing: -.035em;
  text-wrap: balance;
}

/* Each line is its own block, so the browser never gets to re-break them;
   `text-wrap: balance` above is inert while that holds and matters again only
   if the lines are ever merged back into one run — which is exactly what the
   media query below does on the narrowest phones. Measured from 320px to
   2560px: three lines everywhere at 360px and up, and the tightest line has
   26px to spare at 360, 42px from 1440 on. At 320px "morete oglasiti," is
   wider than the column, so a forced break there splits it and the headline
   becomes five ragged lines; handing the wrap back to the browser gets four
   sensible ones. 360px and up are unaffected — checked, the browser chooses
   the same three lines there of its own accord. */
.headline__line { display: block; }
@media (max-width: 360px) {
  .headline__line { display: inline; }
}

/* **The name carries a marker stroke under it** (2026-09-19, the owner's ask,
   off a sheet of hand-drawn underlines he sent). Three of that sheet's were
   built and compared on the page — its top-left (this one), its fat brush and
   its double line; `design/assets/gen-underline.mjs` draws all three and
   prints this block, so switching is one command and a paste.

   **It is a mask, not a background image**, so the stroke takes the colour of
   the word rather than having azure frozen into the data URI — the same
   property the flat bar this replaced had, and the reason the bar was a
   pseudo-element in the first place: only a pseudo-element clears the "y"
   descender, which a `text-decoration` underline runs straight through.

   The two numbers are measured, not chosen. The "y" ink ends .204em below the
   baseline and the inline box already runs to .367em, so the box clears the
   descender on its own; -.09em is where the tail visibly clears the stroke
   and the stroke still leaves daylight above the lede. An earlier flat bar at
   -.12em sat 2px *inside* the lede's line box.

   The path data is generated rather than hand-drawn because the mask is
   stretched with `preserveAspectRatio="none"` — hand-authored beziers came
   out as hairlines, their thickness squashed by the vertical scale while
   their length was stretched by the horizontal one. The generator's header
   has the whole account. */
.headline__name {
  /* `relative` is what the stroke below is positioned against; without it the
     ::after escapes to the nearest positioned ancestor and lands nowhere near
     the word. */
  position: relative;
  color: var(--azure);
}

.headline__name::after {
  content: '';
  position: absolute;
  left: -.02em;
  right: -.02em;
  bottom: -.09em;
  height: .125em;
}
@supports ((-webkit-mask-image: url('')) or (mask-image: url(''))) {
  .headline__name::after {
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%205.96%20200%204.77%22%20preserveAspectRatio%3D%22none%22%3E%3Cpath%20d%3D%22M1%209.3%207.2%208.8%2013.4%208.6%2019.6%208.4%2025.8%208.1%2031.9%207.9%2038.1%207.7%2044.3%207.6%2050.5%207.4%2056.7%207.2%2062.9%207%2069.1%206.9%2075.3%206.8%2081.4%206.6%2087.6%206.5%2093.8%206.5%20100%206.4%20106.2%206.3%20112.4%206.3%20118.6%206.3%20124.8%206.2%20130.9%206.2%20137.1%206.2%20143.3%206.2%20149.5%206.2%20155.7%206.2%20161.9%206.3%20168.1%206.3%20174.3%206.4%20180.4%206.5%20186.6%206.7%20192.8%206.8%20199%207.2%20199%208.3%20192.8%208.5%20186.6%208.5%20180.4%208.6%20174.3%208.7%20168.1%208.7%20161.9%208.8%20155.7%208.8%20149.5%208.9%20143.3%209%20137.1%209%20130.9%209.1%20124.8%209.2%20118.6%209.2%20112.4%209.3%20106.2%209.3%20100%209.4%2093.8%209.5%2087.6%209.5%2081.4%209.6%2075.3%209.7%2069.1%209.8%2062.9%209.9%2056.7%2010%2050.5%2010.1%2044.3%2010.2%2038.1%2010.2%2031.9%2010.3%2025.8%2010.4%2019.6%2010.4%2013.4%2010.5%207.2%2010.5%201%2010.3Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E") no-repeat center / 100% 100%;
    mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%205.96%20200%204.77%22%20preserveAspectRatio%3D%22none%22%3E%3Cpath%20d%3D%22M1%209.3%207.2%208.8%2013.4%208.6%2019.6%208.4%2025.8%208.1%2031.9%207.9%2038.1%207.7%2044.3%207.6%2050.5%207.4%2056.7%207.2%2062.9%207%2069.1%206.9%2075.3%206.8%2081.4%206.6%2087.6%206.5%2093.8%206.5%20100%206.4%20106.2%206.3%20112.4%206.3%20118.6%206.3%20124.8%206.2%20130.9%206.2%20137.1%206.2%20143.3%206.2%20149.5%206.2%20155.7%206.2%20161.9%206.3%20168.1%206.3%20174.3%206.4%20180.4%206.5%20186.6%206.7%20192.8%206.8%20199%207.2%20199%208.3%20192.8%208.5%20186.6%208.5%20180.4%208.6%20174.3%208.7%20168.1%208.7%20161.9%208.8%20155.7%208.8%20149.5%208.9%20143.3%209%20137.1%209%20130.9%209.1%20124.8%209.2%20118.6%209.2%20112.4%209.3%20106.2%209.3%20100%209.4%2093.8%209.5%2087.6%209.5%2081.4%209.6%2075.3%209.7%2069.1%209.8%2062.9%209.9%2056.7%2010%2050.5%2010.1%2044.3%2010.2%2038.1%2010.2%2031.9%2010.3%2025.8%2010.4%2019.6%2010.4%2013.4%2010.5%207.2%2010.5%201%2010.3Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E") no-repeat center / 100% 100%;
  }
}


.lede {
  margin-top: 1.15rem;
  max-width: 46ch;
  font-size: clamp(1.05rem, 1.45vw, 1.2rem);
  line-height: 1.65;
  color: var(--ink-soft);
}

/* ---- the dial ----------------------------------------------
 *
 * **It is one button now** (2026-09-16). The field used to take a caller's
 * number and promise that Layra would ring it back; nothing serves
 * `/api/demo-call` and the Voximplant scenario is inbound-only, so on
 * 2026-08-30 it became a `tel:` link — but it kept the field's shape, a white
 * box with `+386` and the number sitting in it beside the button, and a
 * visitor reads that as somewhere to type. The box is gone: the gradient
 * button is the whole control, and the number is in print beneath it.
 */

.dial {
  /* the button is the whole control now: no box around it, nothing beside it.
     Block-level so the assurance line keeps its own row, `fit-content` so the
     clickable area is the button and not the whole column. */
  display: flex;
  width: fit-content;
  margin-top: clamp(1.6rem, 3.5vh, 2.3rem);
}

/* A link, so it carries none of an anchor's default decoration and all of the
   button's. */
.dial--call {
  text-decoration: none;
  color: inherit;
  border-radius: 999px;
}
/* **The lift moves the button inside the link, not the link** (2026-09-16).
   The anchor used to carry `data-reveal`, and `.js [data-reveal].in {
   transform: none }` was three selectors to a hover rule's two — so it won,
   and `.dial--call:hover { transform: … }` did nothing at all once the reveal
   settled. Measured, not reasoned: computed `transform` read `none` while
   hovered and while held. The reveals are gone since 2026-09-17, but the lift
   stays where it is: the span is the thing that should move, not the link. */
.dial--call:focus-visible {
  outline: 2px solid var(--azure);
  outline-offset: 4px;
}

/* the number in print: a `tel:` link does nothing on most desktop browsers,
   and this is the one place on the page the number can be read and copied */
.dial__print {
  margin: .9rem 0 0;
  font-size: .9rem;
  color: var(--ink-faint);
}

.dial__number {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: .01em;
  color: var(--ink-soft);
}

.dial__go {
  display: inline-flex;
  align-items: center;
  gap: .62rem;
  flex: none;
  /* The page's one call to action, so it is a step larger than the masthead's
     `.btn-call` rather than the same size — it was sized to sit *inside* the
     old field pill, and standing alone it read as a secondary control. */
  padding: 1.05rem 1.9rem;
  border: 0;
  border-radius: 999px;
  font-size: 1.06rem;
  font-weight: 650;
  color: #FFF;
  cursor: pointer;
  background: var(--azure);
  /* a hairline of light along the top edge, and one close shadow. The blue
     glow it used to sit in was the button announcing itself. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .24),
    0 2px 5px rgba(var(--cast), .16);
  transition: filter .25s var(--ease), transform .25s var(--ease);
}
/* The press is the whole point of this control, so it is worth the four lines:
   it rises under the cursor and sinks *past* its resting place when held,
   which is what makes a flat shape feel like a key. The push is quicker than
   the lift — a button that eases slowly into being pressed feels broken.
   Transform and brightness only; no shadow is animated anywhere on this page
   (README, "The call card"). */
.dial__go .icon { width: 19px; height: 19px; }

.dial--call:hover .dial__go { transform: translateY(-2px); }
.dial--call:active .dial__go {
  transform: translateY(1px) scale(.985);
  transition-duration: .07s;
}
.dial__go[disabled] { cursor: default; filter: saturate(.4) brightness(1.1); transform: none; }
/* Inside a link the button is a `<span>`, so it needs the layout it used to get
   from being a `<button>`. */
.dial--call .dial__go { pointer-events: none; }
.dial--call:hover .dial__go { filter: brightness(1.06); }

/* ---- the call card ----------------------------------------- */

/* the product, playing itself: a call comes in, Layra answers,
   the summary lands. this is the one place the page really moves. */
.call {
  width: min(100%, 470px);
  justify-self: end;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--card);
  box-shadow: 0 8px 22px rgba(var(--cast), .07);
  overflow: hidden;
}

.call__bar {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .8rem 1.15rem;
  border-bottom: 1px solid var(--line-soft);
  font-size: .82rem;
  font-weight: 600;
  color: var(--ink-faint);
}
.call__bar .icon { width: 15px; height: 15px; color: var(--azure); }
/* which of the four examples is playing — set from the slide's data-topic.
   On a narrow screen the framing goes and the topic stays: "povpraševanje"
   beside "povzetek poslan" wrapped the bar onto two lines under ~480px, and
   of the two the topic is the one carrying information. The caption under
   the card already says it is an example. */
.call__what { white-space: nowrap; }
.call__topic { font-weight: 500; color: var(--ink-faint); white-space: nowrap; }
.call__topic::before { content: "· "; }
.call__state { margin-left: auto; font-weight: 500; white-space: nowrap; }
@media (max-width: 520px) {
  .call__what { display: none; }
  .call__topic::before { content: none; }
}

.wave {
  display: block;
  width: 100%;
  height: 58px;
  background: rgba(16, 23, 37, .028);
}

/* Four examples on one track. `overflow-y` has to be stated: a box that
   scrolls on x cannot leave y visible, and the default `auto` would put a
   vertical scrollbar on the 8px the lines slide in from. */
.rail {
  display: flex;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  cursor: grab;
}
.rail::-webkit-scrollbar { display: none; }
.rail:focus-visible { outline-offset: -3px; }
/* a mouse drag (layra.js) has to turn snapping off while it is running,
   or every pointermove fights the snap it is being dragged out of */
.rail.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.rail.is-dragging .script__line { user-select: none; }

/* The hint that there is more than one example, and the whole of it: the
   track eases out and back once, the first time the card is on screen.
   A transform on the slides rather than a scroll, because `scroll-snap-type:
   x mandatory` pulls a programmatic `scrollLeft` straight back to the snap
   point and nothing would move. Transform only, so it keeps the rule at the
   top of this file — no blur, no shadow, no blend mode in motion. */
.rail.is-hint .script { animation: peek 1.05s var(--ease); }
@keyframes peek {
  0%, 100% { transform: translateX(0); }
  40%      { transform: translateX(-52px); }
}

.script {
  flex: 0 0 100%;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: .55rem;
  min-height: 232px;
  padding: 1rem 1.15rem 1.2rem;
}

.script__line {
  max-width: 88%;
  padding: .55rem .85rem;
  border-radius: 14px;
  font-size: .89rem;
  line-height: 1.5;
}

/* only a JS-driven page hides the dialogue before playing it */
.js .script__line {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.js .script__line.on { opacity: 1; transform: none; }

/* The caller's line arrives whole rather than typed (layra.js, "The call,
   playing itself"), so its entrance is the only motion it gets: a touch
   longer, and drifting in from the side it is aligned to. */
.js .script__line--caller {
  transform: translate(-6px, 8px);
  transition-duration: .55s;
}

.script__line--caller {
  align-self: flex-start;
  border-bottom-left-radius: 4px;
  background: rgba(19, 30, 66, .05);
  color: var(--ink);
}
.script__line--layra {
  align-self: flex-end;
  border-bottom-right-radius: 4px;
  background: rgba(31, 111, 229, .07);
  color: var(--ink);
}
.script__who {
  display: block;
  margin-bottom: .12rem;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.script__line--layra .script__who { color: var(--azure); }

/* the caret while a line is being spoken */
.script__line.saying::after {
  content: "";
  display: inline-block;
  width: 2px; height: .95em;
  margin-left: 2px;
  vertical-align: text-bottom;
  background: var(--azure);
  animation: caret .8s steps(2) infinite;
}
@keyframes caret { 50% { opacity: 0; } }

/* what the owner receives, sliding in under the conversation */
.slip {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin-top: .45rem;
  padding: .75rem .9rem;
  border-radius: 12px;
  border: 1px dashed rgba(16, 120, 106, .38);
  background: rgba(16, 120, 106, .05);
  font-size: .84rem;
  font-weight: 600;
  color: var(--pine);
}
.js .slip {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
}
.js .slip.on { opacity: 1; transform: none; }
.slip .icon { width: 16px; height: 16px; }
.slip small { display: block; font-weight: 500; color: var(--ink-soft); }

/* Four dots: where you are, and that there are three more. The filled one
   is the example on screen; the rest are hollow with a hairline, which is
   the whole of the chrome this carousel gets. */
.dots {
  display: flex;
  justify-content: center;
  gap: .45rem;
  padding: .1rem 0 .85rem;
}
.dots__dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(16, 23, 37, .22);
  background: transparent;
  cursor: pointer;
  transition: background .25s var(--ease), border-color .25s var(--ease);
}
.dots__dot:hover { border-color: var(--azure); }
.dots__dot.on {
  background: var(--azure);
  border-color: var(--azure);
}

.call__note {
  padding: 0 1.15rem 1rem;
  font-size: .78rem;
  color: var(--ink-faint);
}

/* ---- shared band scaffolding ------------------------------- */

.band {
  max-width: var(--shell);
  margin-inline: auto;
  padding: clamp(3.5rem, 9vh, 6rem) var(--gutter);
  border-top: 1px solid var(--line);
  scroll-margin-top: calc(var(--mast) + 1rem);
}

.band__eyebrow {
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--azure);
}

/* Sized with the headline — see the note above `.headline`. */
.band__title {
  margin-top: .6rem;
  font-size: clamp(2rem, 4vw, 3rem);
  font-weight: 800;
  letter-spacing: -.025em;
  line-height: 1.15;
  max-width: 24ch;
  text-wrap: balance;
}

.band__lede {
  margin-top: .9rem;
  max-width: 56ch;
  font-size: 1.06rem;
  line-height: 1.65;
  color: var(--ink-soft);
}

.band__head--split {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  align-items: end;
  gap: clamp(1.5rem, 4vw, 3rem);
}

/* ---- problem ----------------------------------------------- */

/* short lines, hard return after each — this is the one place on
   the page where the rhythm does the arguing. */
.beat {
  margin-top: 1.1rem;
  font-size: clamp(1.05rem, 1.6vw, 1.2rem);
  font-weight: 600;
  line-height: 1.55;
  max-width: 34ch;
}
.beat span { display: block; }
.beat span + span { margin-top: .15rem; }
.beat .beat--soft { font-weight: 500; color: var(--ink-soft); }

/* ---- calculator -------------------------------------------- */

/* the visitor's own arithmetic, not a borrowed statistic. every
   number on screen is one they set or one derived in front of
   them, and the assumption is printed under it. */
.calc {
  align-self: start;
  padding: 1.35rem 1.4rem 1.25rem;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--card);
  box-shadow: 0 8px 22px rgba(var(--cast), .06);
}

.calc__title {
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--azure);
}

.calc__row { display: block; margin-top: 1.05rem; }
.calc__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  font-size: .9rem;
  font-weight: 600;
}
.calc__val {
  font-variant-numeric: tabular-nums;
  color: var(--azure);
}
.calc__row input[type="range"] {
  width: 100%;
  margin-top: .5rem;
  accent-color: var(--azure);
  cursor: pointer;
}

.calc__out {
  margin-top: 1.3rem;
  padding-top: 1.05rem;
  border-top: 1px dashed var(--line);
}
.calc__num {
  display: block;
  font-size: clamp(1.9rem, 3.6vw, 2.5rem);
  font-weight: 800;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  color: var(--azure);
}
.calc__cap { margin-top: .2rem; font-size: .95rem; font-weight: 600; }
.calc__sum {
  display: block;
  margin-top: .3rem;
  font-size: .82rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

/* The "this is still our example" line. Same faint register as .calc__note
   below it — deliberately not a pill or a badge, which is the first tell in
   design/notes/ai-tells.md and the reason no other element on this page wears
   one. It is removed from the DOM on the first slider move. */
.calc__hint {
  margin-top: .55rem;
  font-size: .78rem;
  line-height: 1.5;
  color: var(--ink-faint);
  font-style: italic;
}

.calc__note {
  margin-top: .75rem;
  font-size: .78rem;
  line-height: 1.5;
  color: var(--ink-faint);
}

/* ---- reasons ----------------------------------------------- */

.reasons {
  display: flex;
  flex-direction: column;
  margin-top: clamp(1.75rem, 4vh, 2.75rem);
  max-width: 780px;
}

.reason {
  display: grid;
  grid-template-columns: minmax(0, 15rem) 1fr;
  align-items: baseline;
  gap: .4rem 1.25rem;
  padding: 1.15rem 0;
  border-top: 1px solid var(--line-soft);
}
.reason:first-child { border-top: 0; }

.reason__claim {
  font-size: 1.08rem;
  font-weight: 700;
  letter-spacing: -.012em;
}

.reason__body {
  font-size: .95rem;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* ---- the voices -------------------------------------------- */

/* Proof for the claim two bands up ("govori slovensko"), and for the one
   nobody writes down: that she does not sound like a robot. A panel, by the
   same rule the calculator gets one — it is a thing you operate. */
.glasovi {
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1fr);
  align-items: start;
  gap: clamp(1.5rem, 4vw, 3.5rem);
}

.voices {
  padding: .35rem 1.25rem 1rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  box-shadow: 0 8px 22px rgba(var(--cast), .06);
}

.voice {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: .95rem;
  padding: .95rem 0;
  border-top: 1px solid var(--line-soft);
}
.voice:first-of-type { border-top: 0; }

.voice__play {
  display: grid; place-items: center;
  width: 38px; height: 38px; flex: none;
  border: 1px solid rgba(31, 111, 229, .35);
  border-radius: 50%;
  background: var(--card);
  color: var(--azure);
  cursor: pointer;
  transition: background .2s var(--ease), border-color .2s var(--ease);
}
.voice__play svg { width: 13px; height: 13px; fill: currentColor; margin-left: 2px; }
/* the row that is playing, marked by the state layra.js already sets for
   assistive technology rather than by a second icon */
.voice__play[aria-pressed="true"] { background: var(--azure); border-color: var(--azure); color: #FFF; }
.voice:hover .voice__play { background: rgba(31, 111, 229, .07); border-color: rgba(31, 111, 229, .6); }
.voice__play[disabled] { opacity: .45; cursor: default; }

.voice__name { font-size: 1rem; font-weight: 700; letter-spacing: -.01em; }
.voice__note {
  display: block; margin-top: .1rem;
  font-size: .88rem; font-weight: 500; line-height: 1.45;
  color: var(--ink-soft);
}
/* **No `tabular-nums` here, unlike every other figure on the page** (2026-09-19).
   Schibsted Grotesk sets the colon on the full digit advance under `tnum`, so
   "0:28" opens up into "0 : 28". It bought nothing anyway: measured, all four
   rows come out the same width either way and the flex row right-aligns them
   regardless, because these are four hand-written values that never change.
   The rule still holds where it was written for — `.calc__num`, which does. */
.voice__len { font-size: .82rem; color: var(--ink-faint); }

.voices__foot { margin-top: .9rem; font-size: .84rem; line-height: 1.55; color: var(--ink-faint); }

/* ---- steps ------------------------------------------------- */

.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  margin-top: clamp(1.75rem, 4vh, 2.75rem);
}

.step {
  position: relative;
  padding-top: 1.1rem;
}
.step::before {
  content: "";
  position: absolute; top: 0; left: 0;
  width: 2.4rem; height: 3px;
  background: var(--azure);
}

.step__no {
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .09em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.step__claim {
  margin-top: .35rem;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -.012em;
}

.step__body {
  margin-top: .4rem;
  font-size: .95rem;
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 30ch;
}

/* ---- proof ------------------------------------------------- */

.proof {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(2rem, 5vw, 4.5rem);
}

.proof__card {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

.msg {
  width: min(100%, 430px);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 1.2rem 1.35rem;
}
.msg__head {
  display: flex;
  align-items: center;
  gap: .55rem;
  font-size: .8rem;
  font-weight: 600;
  color: var(--ink-faint);
}
.msg__head .icon { width: 15px; height: 15px; color: var(--azure); }
.msg__from { margin-top: .65rem; font-size: 1rem; font-weight: 700; }
.msg__body { margin-top: .3rem; font-size: .95rem; line-height: 1.55; color: var(--ink-soft); }
.msg__foot {
  margin-top: .85rem;
  padding-top: .75rem;
  border-top: 1px dashed var(--line);
  font-size: .82rem;
  color: var(--pine);
  font-weight: 600;
}

.proof__note {
  width: min(100%, 430px);
  margin-top: .6rem;
  font-size: .78rem;
  color: var(--ink-faint);
}

/* ---- trust strip ------------------------------------------- */

.trust {
  display: flex;
  flex-wrap: wrap;
  gap: .8rem 2.5rem;
  margin-top: clamp(1.5rem, 3.5vh, 2.25rem);
}
.trust__item {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-size: .95rem;
  font-weight: 600;
}

/* ---- zna / še ne zna --------------------------------------- */

/* Two columns, no ticks: the headings carry the yes and the no, so a mark on
   every row would be decoration (notes/ai-tells.md §3). The asymmetry is the
   argument, which is why the short column is allowed to look short. */
.meje {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 clamp(1.75rem, 5vw, 4rem);
  margin-top: clamp(1.5rem, 3.5vh, 2.25rem);
  max-width: 860px;
}
.meje__head {
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding-bottom: .7rem;
  border-bottom: 2px solid currentColor;
}
.meje__head--zna { color: var(--pine); }
.meje__head--ne { color: var(--ink-faint); }

.meje__list { margin: 0; padding: 0; list-style: none; }
.meje__list li {
  padding: .85rem 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: .97rem;
  line-height: 1.5;
}
.meje__list--ne li { color: var(--ink-soft); }

.meje__note { margin-top: 2rem; max-width: 60ch; font-size: .9rem; line-height: 1.6; color: var(--ink-soft); }

/* ---- faq --------------------------------------------------- */

.faq {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 clamp(1.75rem, 4vw, 3.25rem);
  margin-top: clamp(1.5rem, 3.5vh, 2.25rem);
  align-items: start;
}

.faq__group {
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding-bottom: .6rem;
}

.faq details {
  border-top: 1px solid var(--line-soft);
}
.faq details:last-child { border-bottom: 1px solid var(--line-soft); }

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.05rem 0;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  transition: color .25s var(--ease);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--azure); }

.faq summary .icon {
  width: 16px; height: 16px;
  color: var(--ink-faint);
  transition: transform .3s var(--ease);
}
.faq details[open] summary .icon { transform: rotate(45deg); }

.faq__body {
  padding: 0 0 1.15rem;
  max-width: 62ch;
  font-size: .95rem;
  line-height: 1.65;
  color: var(--ink-soft);
}

/* ---- cena ---------------------------------------------------
   Four rows, each a fact: the label, the figure, and one sentence saying what
   the figure means. A definition list rather than a table because that is what
   it is, and because a table would invite a second column of a competing plan —
   which `design/notes/DIRECTIONS.md` ruled out in as many words.

   The figure is set in the same weight as the loss figure in the calculator
   above it, deliberately: the two numbers are meant to be read against each
   other, and typography is what pairs them. */

.price {
  margin-top: clamp(1.75rem, 4vh, 2.5rem);
  border-top: 1px solid var(--line);
}

.price__row {
  display: grid;
  grid-template-columns: 12rem 1fr;
  gap: .35rem 2rem;
  padding: 1.15rem 0;
  border-bottom: 1px solid var(--line-soft);
}

.price__row dt {
  grid-row: span 2;
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding-top: .15rem;
}

.price__figure {
  margin: 0;
  font-size: clamp(1.15rem, 2.1vw, 1.45rem);
  font-weight: 800;
  line-height: 1.25;
  color: var(--ink);
}

.price__note {
  margin: 0;
  max-width: 54ch;
  font-size: .92rem;
  line-height: 1.6;
  color: var(--ink-soft);
}

.price__foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .9rem 1.4rem;
  margin-top: clamp(1.5rem, 3.5vh, 2.25rem);
}

.price__foot-note {
  max-width: 46ch;
  font-size: .88rem;
  line-height: 1.55;
  color: var(--ink-soft);
}

/* One column under the narrower breakpoint, where a 12rem label column leaves
   the figure nowhere to go. The label keeps its own row rather than shrinking. */
@media (max-width: 720px) {
  .price__row { grid-template-columns: 1fr; gap: .3rem; }
  .price__row dt { grid-row: auto; }
}

/* ---- finale ------------------------------------------------ */

.finale { margin-top: clamp(3.5rem, 9vh, 6rem); }

/* The one dark section on the page: flat, full width, no radius and no
   shadow. A rounded slab floating in a gradient was three tells at once. */
.finale__panel {
  padding: clamp(3rem, 7vh, 4.5rem) var(--gutter);
  background: var(--navy);
  color: #FFF;
  text-align: center;
}
.finale__title, .finale__lede, .finale__actions { max-width: var(--shell); margin-inline: auto; }

.finale__title {
  position: relative;
  font-size: clamp(1.9rem, 3.8vw, 2.85rem);
  font-weight: 800;
  letter-spacing: -.025em;
  line-height: 1.15;
  text-wrap: balance;
}

.finale__lede {
  position: relative;
  margin: .8rem auto 0;
  max-width: 46ch;
  font-size: 1rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, .82);
}

.finale__actions {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .8rem;
  margin-top: 1.6rem;
}

/* The page's single gradient, spent here and nowhere else. */
.btn-solid {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding: .85rem 1.5rem;
  border-radius: 999px;
  background: linear-gradient(118deg, var(--azure) 0%, var(--indigo) 100%);
  color: #FFF;
  font-size: .97rem;
  font-weight: 600;
  transition: transform .25s var(--ease), box-shadow .25s var(--ease);
}
.btn-solid:hover { transform: translateY(-1px); }
.btn-solid .icon { color: #FFF; }

.btn-ghost {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding: .85rem 1.5rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .45);
  color: #FFF;
  font-size: .97rem;
  font-weight: 600;
  cursor: pointer;
  background: none;
  transition: background .25s var(--ease), border-color .25s var(--ease);
}
.btn-ghost:hover { background: rgba(255, 255, 255, .12); border-color: rgba(255, 255, 255, .7); }

/* ---- footer ------------------------------------------------ */

.foot {
  border-top: 1px solid var(--line);
  background: var(--card);
}

.foot__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  max-width: var(--shell);
  margin-inline: auto;
  padding: 1.9rem var(--gutter);
}

.foot__brand {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-weight: 800;
  letter-spacing: .17em;
  font-size: .95rem;
}

.foot__tag {
  font-size: .88rem;
  color: var(--ink-soft);
}

.foot__links {
  display: flex;
  gap: 1.5rem;
  font-size: .88rem;
  color: var(--ink-soft);
}
.foot__links a { transition: color .25s var(--ease); }
.foot__links a:hover { color: var(--ink); }

/* ---- reveal ------------------------------------------------ */


/* ---- responsive -------------------------------------------- */

@media (max-width: 980px) {
  .nav { display: none; }

  .hero {
    grid-template-columns: 1fr;
    min-height: 0;
    gap: 2.5rem;
  }
  .call { justify-self: stretch; width: 100%; }

  .proof { grid-template-columns: 1fr; }
  .proof__card { align-items: flex-start; }

  .band__head--split { grid-template-columns: 1fr; align-items: start; }

  .faq { grid-template-columns: 1fr; }
  .faq__col + .faq__col .faq__group { padding-top: 1.5rem; }

  .glasovi { grid-template-columns: 1fr; }
  .meje { grid-template-columns: 1fr; }
  .meje__col + .meje__col { margin-top: 2rem; }
}

@media (max-width: 720px) {
  .btn-call { padding: .55rem .95rem; font-size: .875rem; }
  .link-quiet { display: none; }

  /* full width on a phone, where a thumb wants the whole row */
  .dial { width: auto; }
  .dial__go { flex: 1; justify-content: center; padding: .95rem 1.4rem; }

  /* one column since the glyph came off these rows (2026-09-17): the claim,
     then the line under it. The 44px track it used to reserve is gone. */
  .reason { grid-template-columns: 1fr; grid-template-rows: auto auto; }

  .steps { grid-template-columns: 1fr; gap: 1.75rem; }
  .step__body { max-width: none; }
}

/* ---- reduced motion ---------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .script__line, .slip { opacity: 1; transform: none; }
  .rail { scroll-snap-type: none; }
}
