/* ============================================================================
   Nova Cafe — landing + privacy, "Sharp Neutral"
   ----------------------------------------------------------------------------
   Standalone copy of the app's design tokens (src/styles/design-tokens.css).
   This directory has no build step and does not import from src/, so the values
   are duplicated here on purpose. If the app's tokens change, change these too.

   The direction, in short: near black-and-white, hierarchy carried by type size
   and weight rather than colour, hairline borders instead of shadows, 4px
   corners, generous whitespace. The electric-blue accent is rationed — links
   and focus rings only. Solid actions are black.
   ========================================================================== */

:root {
  /* Neutral ramp */
  --color-neutral-0:   #ffffff;
  --color-neutral-50:  #fafafa;
  --color-neutral-100: #f4f4f5;
  --color-neutral-200: #eaeaea; /* the hairline border */
  --color-neutral-300: #d4d4d8;
  --color-neutral-400: #8f8f8f;
  --color-neutral-500: #666666;
  --color-neutral-900: #0a0a0a;

  /* Ink — solid actions read as black */
  --color-ink-300: #c4c4c7; /* secondary text ON the dark hero */
  --color-ink-600: #1a1a1c;
  --color-ink-900: #000000;

  /* Accent — rationed */
  --color-accent-600: #0038ff;
  --color-accent-700: #002ccc;

  --surface-page:   var(--color-neutral-0);
  --surface-sunken: var(--color-neutral-50);
  --border-default: var(--color-neutral-200);
  --text-primary:   var(--color-neutral-900);
  --text-secondary: var(--color-neutral-500);
  --text-tertiary:  var(--color-neutral-400);
  --text-link:      var(--color-accent-600);

  --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* Type scale — 1rem = 14px (html is pinned below, as in the app) */
  --text-xs:   0.786rem; /* 11px   */
  --text-sm:   0.893rem; /* 12.5px */
  --text-base: 1rem;     /* 14px   */
  --text-lg:   1.143rem; /* 16px   */
  --text-xl:   1.429rem; /* 20px   */
  --text-2xl:  1.714rem; /* 24px   */
  --text-3xl:  2.143rem; /* 30px   */
  --text-4xl:  2.714rem; /* 38px   */
  --text-5xl:  3.286rem; /* 46px   */

  --tracking-display: -0.035em;
  --tracking-tight:   -0.02em;
  --tracking-label:    0.08em;

  --radius-md: 4px;

  --duration-base: 150ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ── Reset ────────────────────────────────────────────────────────────────── */

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

html {
  font-size: 14px; /* 1rem = 14px — the scale above is relative to this */
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.6;
  color: var(--text-primary);
  background: var(--surface-page);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }

/*
 * Russian compounds are long and unbreakable: "конфиденциальности" alone is
 * 304px at the 30px heading size, which overflowed a 320px screen and pushed
 * the whole document sideways. Break inside a word only when there is no
 * other option — normal wrapping still wins wherever it can.
 */
h1, h2, h3, p, li, dt, dd, figcaption, .lead { overflow-wrap: break-word; }

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

:focus-visible {
  outline: 2px solid var(--color-accent-600);
  outline-offset: 2px;
  border-radius: var(--radius-md);
}

/* ── Layout ───────────────────────────────────────────────────────────────── */

.wrap {
  max-width: 640px;
  margin: 0 auto;
  padding: 0 24px;
}

.section {
  padding: 56px 0;
  border-top: 1px solid var(--border-default);
}
.section:first-of-type { border-top: 0; }

/* The section directly under the hero has to clear the phone hanging into it.
   Tied to .hero-visual's negative margin — change the two together. */
.hero + .section { padding-top: 136px; }

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

.site-header {
  border-bottom: 1px solid var(--border-default);
}
.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 64px;
}

.logo {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px; /* hit area — the mark itself is 32px */
  color: var(--text-primary);
}
.logo:hover { text-decoration: none; }
.logo svg { flex-shrink: 0; color: var(--text-primary); }
.logo-text { display: flex; flex-direction: column; line-height: 1; }
.logo-name {
  font-size: var(--text-lg);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  line-height: 1.2;
}
.logo-sub {
  margin-top: 2px;
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
}

/* ══════════════════════════════════════════════════════════════════════════
   THE DARK BLOCK — masthead + hero, inverted
   ══════════════════════════════════════════════════════════════════════════
   The weight here comes from contrast, not decoration: no gradient, no
   photograph, no blurred colour, nothing animated. Same near-black the real
   kitchen display uses (--color-neutral-900, see .screen--kds), so the page
   and the product agree rather than the page inventing a look of its own.

   The masthead is inside the block on purpose. A white header strip above a
   black hero reads as two unrelated bars; one dark region that happens to
   contain the logo reads as a single opening.

   Contrast on this ground (all measured, see the check in the summary):
     #ffffff        on #0a0a0a  = 19.6:1   heading, buttons, logo
     #c4c4c7 (ink-300) on #0a0a0a = 11.5:1  lead paragraph, well past AA
   Do not reach for --text-secondary (#666) here — it lands at ~3.9:1 and
   fails AA for body text. That is the trap this block sets.
   ────────────────────────────────────────────────────────────────────────── */

/*
 * `.on-dark` is worn by the masthead and the hero as two stacked siblings
 * rather than one wrapper, so the hero stays inside <main> where an h1 and
 * the page's primary call to action belong. Same background on both, no gap
 * between them, so they read as one region.
 */
.on-dark {
  background: var(--color-neutral-900);
  color: #ffffff;
}

.on-dark .site-header,
.site-header.on-dark { border-bottom-color: rgb(255 255 255 / 0.12); }

.on-dark .logo,
.on-dark .logo svg { color: #ffffff; }
.on-dark .logo-sub { color: rgb(255 255 255 / 0.55); }

/* The primary action is black on white ground and white on black ground — in
   both cases maximum contrast against the page, which is the actual rule.
   The accent is still spent only on links and focus rings. */
.on-dark .btn-primary {
  background: #ffffff;
  color: var(--color-neutral-900);
}
.on-dark .btn-primary:hover {
  background: var(--color-neutral-100);
  color: var(--color-neutral-900);
}

.on-dark .btn-secondary {
  border-color: rgb(255 255 255 / 0.32);
  color: #ffffff;
}
.on-dark .btn-secondary:hover {
  background: rgb(255 255 255 / 0.08);
  border-color: rgb(255 255 255 / 0.5);
  color: #ffffff;
}

.on-dark :focus-visible { outline-color: #ffffff; }

/* ── Hero ─────────────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  z-index: 1; /* lets the phone hang over the white section below */
  padding: 72px 0 80px;
}
.hero .wrap {
  position: relative; /* above the substrate */
  max-width: 880px;
}

/*
 * Hairline substrate, hero only. Hard colour stops — this draws 1px rules on
 * a 64px module, it is not a colour wash.
 *
 * Started at 0.04 and that read as a pattern: you could count the squares,
 * which makes it decoration. 0.022 is the level where it registers as grain
 * in the surface and disappears once you look at the words. If it ever needs
 * changing, change the alpha, not the module — a wider grid just makes the
 * lines lonely and more obvious, not less.
 *
 * Kept off the masthead so there is no seam where the two meet.
 */
.hero.on-dark::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(to right, rgb(255 255 255 / 0.022) 0 1px, transparent 1px 64px),
    repeating-linear-gradient(to bottom, rgb(255 255 255 / 0.022) 0 1px, transparent 1px 64px);
}

/* Text left, product right. */
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 260px;
  gap: 56px;
  align-items: center;
}

/*
 * The phone hangs past the bottom of the dark block into the white section.
 * That overlap is the transition: the two regions are stitched by the product
 * itself crossing the seam, instead of meeting at a hard butt joint that
 * reads as two pages stapled together.
 */
/* Overlap = |margin-bottom| − .hero padding-bottom. At -104px it came to 24px,
   which looks like the phone almost fits rather than like a decision; -144px
   gives a clear 64px. */
.hero-visual { margin-bottom: -144px; }
.hero-visual .frame { margin-top: 0; }

.hero h1 {
  font-size: var(--text-4xl);
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: var(--tracking-display);
  max-width: 20ch;
  color: #ffffff;
}

.hero .lead {
  margin-top: 20px;
  font-size: var(--text-lg);
  color: var(--color-ink-300);
  max-width: 44ch;
}

@media (min-width: 768px) {
  .hero h1 { font-size: var(--text-5xl); }
}

/* ── Buttons ──────────────────────────────────────────────────────────────── */

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 32px;
}

/* 44px, not 40: this is used one-handed, standing at a table. Applies to the
   masthead button too, which sits inside a 64px bar and so does not move. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 18px;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  font-size: var(--text-base);
  font-weight: 500;
  line-height: 1;
  transition: background-color var(--duration-base) var(--ease-out),
              border-color var(--duration-base) var(--ease-out),
              color var(--duration-base) var(--ease-out);
}
.btn:hover { text-decoration: none; }

/* The primary action is black — not the accent. */
.btn-primary {
  background: var(--color-ink-600);
  color: #ffffff;
}
.btn-primary:hover { background: var(--color-ink-900); color: #ffffff; }

.btn-secondary {
  background: transparent;
  border-color: var(--border-default);
  color: var(--text-primary);
}
.btn-secondary:hover {
  background: var(--surface-sunken);
  border-color: var(--color-neutral-300);
  color: var(--text-primary);
}

/* ── Section headings ─────────────────────────────────────────────────────── */

.eyebrow {
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
}

.section h2 {
  margin-top: 12px;
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
}

.section h2 + p, .section .eyebrow + p { margin-top: 16px; }
.section p + p { margin-top: 14px; }

.section p { max-width: 56ch; color: var(--text-secondary); }
.section p strong { color: var(--text-primary); font-weight: 600; }

/* ── Wide section (the animation needs more room than prose) ─────────────── */

.section--wide .wrap { max-width: 880px; }

/* ══════════════════════════════════════════════════════════════════════════
   THE LOOP — animated depiction of the core interaction
   ══════════════════════════════════════════════════════════════════════════
   Pure CSS. No video, no library, no images — it costs nothing to download
   beyond the markup and these rules.

   Every element animates on one shared 9s timeline (--loop-dur), so keyframe
   percentages are the choreography. Percent → seconds:

     0%      0.0s   idle
     8%      0.7s   tap on the "Лагман" row
    12%      1.1s   cart count 0 → 1
    17%      1.5s   the line lands in the order
    30%      2.7s   tap "Отправить на кухню"
    32%      2.9s   button label → "Отправка на кухню…"
    38%      3.4s   the ticket travels (dot crosses the connector)
    46%      4.1s   label returns, "Заказ отправлен" appears
    50%      4.5s   the ticket has landed on the kitchen board
    50–92%   4.5–8.3s   hold — this is the state a glance should catch
    92–100%  8.3–9.0s   clear, ready for the next order

   Editing rule: change one stop and you desynchronise the story. The pairs
   that must stay ordered are (tap → count), (send tap → label → dot →
   ticket). Leave the 50–92% hold long; it is what makes the loop readable
   rather than frantic.
   ══════════════════════════════════════════════════════════════════════════ */

.loop {
  --loop-dur: 9s;
  --loop-ease: cubic-bezier(0.16, 1, 0.3, 1);
  margin: 32px 0 0;
}

/* Every animation in here obeys one switch, flipped by the observer at the
   bottom of index.html. Default `running` means it works with JS disabled. */
.loop * { animation-play-state: var(--loop-play, running); }

.loop-grid {
  display: grid;
  grid-template-columns: auto 56px 1fr;
  align-items: start; /* so both pane labels sit on one line */
  gap: 0;
}

.pane-label {
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
  margin-bottom: 12px;
}

.loop figcaption {
  margin-top: 20px;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

/* ── Device outlines ──────────────────────────────────────────────────────
   The frames are physical objects, not UI surfaces, so they take the 8px
   corner (--radius-3xl) rather than the 4px used everywhere inside them.
   ────────────────────────────────────────────────────────────────────────── */

.device {
  border: 1px solid var(--color-neutral-300);
  border-radius: 8px;
  background: var(--surface-page);
  padding: 6px;
}

.device--phone { width: 194px; }
.device--tablet { width: 100%; }

.device-bar {
  display: flex;
  justify-content: center;
  padding: 2px 0 6px;
}
.device-speaker {
  width: 34px;
  height: 3px;
  border-radius: 999px;
  background: var(--color-neutral-200);
}

.screen {
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  overflow: hidden;
}

/* ── Phone screen: the waiter's POS ───────────────────────────────────────── */

.screen--pos { background: var(--surface-page); }

.pos-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-default);
  font-size: var(--text-xs);
  font-weight: 600;
}

.pos-badge {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  font-variant-numeric: tabular-nums;
}
/* Longhands, not the `animation` shorthand: the shorthand would set
   animation-name:none here, and this selector outranks .badge-zero /
   .badge-one, so their names would never apply and both digits would show. */
.pos-badge span {
  position: absolute;
  animation-duration: var(--loop-dur);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.badge-zero { animation-name: badgeZero; }
.badge-one { animation-name: badgeOne; }

.pos-row {
  position: relative;
  display: flex;
  justify-content: space-between;
  gap: 8px;
  padding: 7px 10px;
  font-size: var(--text-xs);
  border-bottom: 1px solid var(--border-default);
}
.pos-price { color: var(--text-tertiary); font-variant-numeric: tabular-nums; }

.pos-row--target { animation: rowTap var(--loop-dur) var(--loop-ease) infinite; }

/* The tap indicator — a ring, not a cursor. Fingers, not mice. */
.tap {
  position: absolute;
  top: 50%;
  left: 24px;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border: 1.5px solid var(--color-accent-600);
  border-radius: 999px;
  opacity: 0;
  pointer-events: none;
  animation-duration: var(--loop-dur);
  animation-timing-function: var(--loop-ease);
  animation-iteration-count: infinite;
}
.tap--item { animation-name: tapItem; }
.tap--send { left: 50%; animation-name: tapSend; }

.pos-cart {
  padding: 8px 10px 10px;
  border-top: 1px solid var(--border-default);
  background: var(--surface-sunken);
}

.cart-line {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: var(--text-xs);
  font-weight: 500;
  padding-bottom: 8px;
  opacity: 0;
  animation: cartLine var(--loop-dur) var(--loop-ease) infinite;
}

.send-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 30px;
  border-radius: var(--radius-md);
  background: var(--color-ink-600);
  color: #ffffff;
  font-size: var(--text-xs);
  font-weight: 500;
  animation: sendPress var(--loop-dur) var(--loop-ease) infinite;
}
/* Longhands — see the note on .pos-badge span. */
.send-btn .label {
  position: absolute;
  white-space: nowrap;
  animation-duration: var(--loop-dur);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.label--idle { animation-name: labelIdle; }
.label--sending { animation-name: labelSending; }

.sent-note {
  margin-top: 6px;
  font-size: var(--text-xs);
  color: var(--color-success-600);
  text-align: center;
  opacity: 0;
  animation: sentNote var(--loop-dur) var(--loop-ease) infinite;
}

/* ── The connector ────────────────────────────────────────────────────────── */

.loop-flow {
  position: relative;
  align-self: center;
  height: 1px;
  background: var(--border-default);
}
.flow-dot {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 999px;
  background: var(--color-accent-600);
  opacity: 0;
  animation: flowDot var(--loop-dur) var(--loop-ease) infinite;
}

/* ── Kitchen screen ───────────────────────────────────────────────────────
   Dark on purpose: the real kitchen display at /chef/kitchen is a dark
   board (see ChefKitchenPage). Depicting it light would be a lie about the
   product, and the contrast is what separates the two panes at a glance.
   ────────────────────────────────────────────────────────────────────────── */

.screen--kds {
  background: var(--color-neutral-900);
  border-color: var(--color-neutral-900);
  color: #ffffff;
  min-height: 186px;
}

.kds-head {
  padding: 8px 10px;
  border-bottom: 1px solid rgb(255 255 255 / 0.14);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: rgb(255 255 255 / 0.65);
}

.kds-tickets {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  padding: 10px;
}

.ticket {
  border: 1px solid rgb(255 255 255 / 0.18);
  border-radius: var(--radius-md);
  padding: 8px;
  font-size: var(--text-xs);
}
.ticket--new {
  opacity: 0;
  animation: ticketIn var(--loop-dur) var(--loop-ease) infinite;
}

.ticket-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  margin-bottom: 6px;
}
.ticket-no { font-weight: 600; white-space: nowrap; }

.ticket-status {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  padding: 1px 5px;
  border: 1px solid rgb(255 255 255 / 0.25);
  border-radius: var(--radius-md);
  color: rgb(255 255 255 / 0.7);
  white-space: nowrap;
}
/* Deliberately NOT green. In the real board (ChefKitchenPage) green means
   "готово" — a dish ready to serve. Painting a just-arrived ticket green
   would misrepresent the one signal the kitchen actually reads. Newness is
   carried by arrival and contrast instead. */
.ticket-status--new {
  border-color: #ffffff;
  color: #ffffff;
}
.ticket--new { border-color: rgb(255 255 255 / 0.4); }

.ticket-item { color: rgb(255 255 255 / 0.72); line-height: 1.5; }

/* ── Keyframes ────────────────────────────────────────────────────────────── */

@keyframes rowTap {
  0%, 7%   { background: transparent; }
  9%, 15%  { background: var(--color-neutral-100); }
  22%, 100% { background: transparent; }
}

@keyframes tapItem {
  0%, 6%   { opacity: 0; transform: scale(0.4); }
  8%       { opacity: 0.9; transform: scale(1); }
  14%      { opacity: 0; transform: scale(1.6); }
  100%     { opacity: 0; transform: scale(1.6); }
}

@keyframes tapSend {
  0%, 28%  { opacity: 0; transform: scale(0.4); }
  30%      { opacity: 0.9; transform: scale(1); }
  36%      { opacity: 0; transform: scale(1.6); }
  100%     { opacity: 0; transform: scale(1.6); }
}

@keyframes badgeZero {
  0%, 10%  { opacity: 1; }
  12%, 92% { opacity: 0; }
  96%, 100% { opacity: 1; }
}

@keyframes badgeOne {
  0%, 10%  { opacity: 0; }
  12%, 92% { opacity: 1; }
  96%, 100% { opacity: 0; }
}

@keyframes cartLine {
  0%, 11%  { opacity: 0; transform: translateY(6px); }
  17%, 92% { opacity: 1; transform: translateY(0); }
  97%, 100% { opacity: 0; transform: translateY(6px); }
}

@keyframes sendPress {
  0%, 29%   { transform: scale(1); background: var(--color-ink-600); }
  31%, 33%  { transform: scale(0.97); background: var(--color-ink-900); }
  37%, 100% { transform: scale(1); background: var(--color-ink-600); }
}

@keyframes labelIdle {
  0%, 30%  { opacity: 1; }
  32%, 45% { opacity: 0; }
  47%, 100% { opacity: 1; }
}

@keyframes labelSending {
  0%, 30%  { opacity: 0; }
  32%, 45% { opacity: 1; }
  47%, 100% { opacity: 0; }
}

@keyframes flowDot {
  0%, 36%  { opacity: 0; transform: translateX(-18px); }
  39%      { opacity: 1; transform: translateX(-14px); }
  45%      { opacity: 1; transform: translateX(14px); }
  48%, 100% { opacity: 0; transform: translateX(18px); }
}

@keyframes ticketIn {
  0%, 46%  { opacity: 0; transform: translateY(8px); }
  52%, 92% { opacity: 1; transform: translateY(0); }
  97%, 100% { opacity: 0; transform: translateY(8px); }
}

@keyframes sentNote {
  0%, 46%  { opacity: 0; }
  51%, 92% { opacity: 1; }
  97%, 100% { opacity: 0; }
}

/* ── Reduced motion ───────────────────────────────────────────────────────
   Not "animate less" — no animation at all, frozen on the state the loop
   spends most of its time in (the 50–92% hold): the order sent, the ticket
   on the board. The still frame has to carry the same meaning as the motion.
   ────────────────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .loop *,
  .loop *::before,
  .loop *::after {
    animation: none !important;
    transition: none !important;
  }

  .badge-zero { opacity: 0; }
  .badge-one  { opacity: 1; }
  .cart-line  { opacity: 1; transform: none; }
  .sent-note  { opacity: 1; }
  .ticket--new { opacity: 1; transform: none; }
  .label--sending { opacity: 0; }
  .tap, .flow-dot { opacity: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   SCREENSHOTS — the real product, in device outlines
   ══════════════════════════════════════════════════════════════════════════
   Captured from the running app against the real backend (Кафе «Ала-Тоо»
   demo data). No stock photography anywhere on this page: if it looks like
   the product, it is the product.

   The outlines are deliberately thin — a hairline, an 8px corner, no glare,
   no shadow, no perspective. They exist to say "this is a phone" and then
   get out of the way. Anything more decorative would fight the screenshot
   for attention and break the system.
   ────────────────────────────────────────────────────────────────────────── */

.shot { margin-top: 44px; }
.shot:first-of-type { margin-top: 32px; }

.shot-label {
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
}

.shot h3 {
  margin-top: 10px;
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}

.shot p {
  margin-top: 6px;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  max-width: 60ch;
}

.frame {
  margin-top: 18px;
  border: 1px solid var(--color-neutral-300);
  border-radius: 8px;
  background: var(--surface-page);
  padding: 6px;
}

/* Explicit width/height on the <img> reserves the box before the file
   arrives, so nothing below it jumps on a slow connection. */
.frame img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
}

/* The scroll container for the two wide captures — see the phone rules at the
   bottom of this file. Harmless on desktop, where the image fits. */
.frame-scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

/* Phone — the waiter's own device, so it stays small and centred. */
.frame--phone {
  max-width: 286px;
  margin-left: auto;
  margin-right: auto;
}
.frame--phone .device-bar { padding: 2px 0 6px; }

/* Browser — a chrome strip above the page. */
.frame--browser { padding-top: 0; }
.browser-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 4px;
}
.browser-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  border: 1px solid var(--color-neutral-300);
}
.browser-url {
  flex: 1;
  height: 16px;
  margin-left: 6px;
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  border: 1px solid var(--border-default);
}

/* ── The loop, stated in words ────────────────────────────────────────────── */

.steps { margin-top: 28px; counter-reset: step; }

.steps li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 16px;
  padding: 18px 0;
  border-top: 1px solid var(--border-default);
}
.steps li:last-child { border-bottom: 1px solid var(--border-default); }

.steps li::before {
  content: counter(step, decimal-leading-zero);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
  padding-top: 5px;
  font-variant-numeric: tabular-nums;
}

.steps .step-title {
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: var(--tracking-tight);
}
.steps .step-note {
  margin-top: 4px;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

/* ── Placeholder marker ───────────────────────────────────────────────────
   Anything wrapped in .tbd is a value that still has to be filled in. The
   dashed hairline is deliberate — it should be impossible to ship by accident.
   Delete the class along with the placeholder text.
   ────────────────────────────────────────────────────────────────────────── */

.tbd {
  border-bottom: 1px dashed var(--color-neutral-300);
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}

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

.contact-value {
  margin-top: 16px;
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
/* The number is the page's main call to action on a phone — give it a real
   hit area rather than the 25px the text alone occupies. */
.contact-value a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

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

.site-footer {
  border-top: 1px solid var(--border-default);
  padding: 28px 0 48px;
}
.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: var(--text-sm);
  color: var(--text-tertiary);
}
/* A 20px-tall footer link is a miss on a phone. The height is hit area only;
   the text stays where it was. */
.site-footer a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* ── Legal document (privacy.html) ────────────────────────────────────────── */

.doc { padding: 48px 0 64px; }
.doc .wrap { max-width: 680px; }

.doc h1 {
  font-size: var(--text-3xl);
  font-weight: 700;
  letter-spacing: var(--tracking-display);
}

.doc-meta {
  margin-top: 12px;
  font-size: var(--text-sm);
  color: var(--text-tertiary);
}

.draft-notice {
  margin-top: 28px;
  padding: 16px 18px;
  border: 1px solid var(--border-default);
  border-left: 3px solid var(--color-ink-600);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
}
.draft-notice .eyebrow { color: var(--text-primary); }
.draft-notice p {
  margin-top: 8px;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  max-width: none;
}

.doc section {
  margin-top: 40px;
  padding-top: 28px;
  border-top: 1px solid var(--border-default);
}

.doc h2 {
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: var(--tracking-tight);
}
.doc h3 {
  margin-top: 24px;
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--text-primary);
}

.doc p, .doc li { color: var(--text-secondary); max-width: 68ch; }
.doc h2 + p, .doc h3 + p, .doc h3 + ul { margin-top: 10px; }
.doc p + p, .doc ul + p, .doc p + ul { margin-top: 14px; }

.doc ul.bullets { margin-top: 12px; }
.doc ul.bullets li {
  position: relative;
  padding-left: 18px;
  margin-top: 8px;
}
.doc ul.bullets li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.65em;
  width: 5px;
  height: 1px;
  background: var(--color-neutral-300);
}

.doc code {
  font-family: ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo, monospace;
  font-size: 0.9em;
  padding: 1px 5px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  color: var(--text-primary);
  white-space: nowrap;
}

.doc dl { margin: 16px 0 0; }
.doc dt {
  padding-top: 14px;
  border-top: 1px solid var(--border-default);
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
}
.doc dd {
  margin: 6px 0 14px;
  color: var(--text-secondary);
  max-width: 68ch;
}

/* ── Small screens ────────────────────────────────────────────────────────── */

/* Side by side stops working before the phone breakpoint — two panes in
   ~600px leaves the kitchen board unreadable. Stack, and turn the connector
   so the order still travels in the direction the eye is already moving. */
@media (max-width: 700px) {
  .loop-grid {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    gap: 0;
  }
  /* 420, not 320: between ~500 and 700 a 320px pane sat marooned in a 600px
     container. The phone keeps its own 260px cap — a phone should look like a
     phone — so the extra width goes to the kitchen board, which is the pane
     that actually benefits from it. */
  .loop-pane { width: 100%; max-width: 420px; }
  .device--phone { margin-left: auto; margin-right: auto; }
  .loop-pane + .loop-flow { margin: 0; }
  .loop-flow {
    width: 1px;
    height: 40px;
    margin: 16px 0 22px;
    background: var(--border-default);
  }

  /* Two ticket columns in a phone's width leaves neither readable. The real
     board is grid-cols-1 below lg for the same reason. */
  .kds-tickets { grid-template-columns: minmax(0, 1fr); }
  .screen--kds { min-height: 0; }

  /*
   * The kitchen board and the analytics screen are captures of a 1280px and a
   * 1440px screen. Scaled to fit a 350px phone they become grey texture — you
   * can see that a dashboard exists but not read a single figure, which
   * defeats the point of showing the real product.
   *
   * So they keep a legible size and scroll sideways inside their own frame.
   * The page itself never scrolls horizontally; only the image does.
   *
   * 760px, not 640px. At 640 the widest container in this range (~638px at a
   * 700px viewport) left 2px of scroll, and 62px at a 640px viewport — a
   * sliver that reads as a layout accident rather than as something to swipe.
   * 760 clears every container here by at least 120px, so the scroll is
   * unmistakably deliberate, and it renders the capture larger while it is at
   * it. Tied to this breakpoint: raising the breakpoint without raising this
   * width brings the sliver back.
   */
  .frame-scroll img {
    width: 760px;
    max-width: none;
  }
  @keyframes flowDot {
    0%, 36%  { opacity: 0; transform: translateY(-18px); }
    39%      { opacity: 1; transform: translateY(-14px); }
    45%      { opacity: 1; transform: translateY(14px); }
    48%, 100% { opacity: 0; transform: translateY(18px); }
  }
  .device--phone { width: 100%; max-width: 260px; }
  .pane-label { text-align: center; }
}

/* Hero stacks: text, then the product under it. The overlap into the next
   section is dropped — at this width it just crowds the heading below. */
@media (max-width: 760px) {
  .hero-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 36px;
  }
  .hero-visual {
    margin-bottom: 0;
    max-width: 260px;
  }
  .hero + .section { padding-top: 56px; }
}

@media (max-width: 480px) {
  .wrap { padding: 0 20px; }
  .hero { padding: 48px 0 40px; }
  /* 30px "Политика конфиденциальности" needs 304px and a 320px screen has
     280px. Dropped to 24px, which fits without relying on the mid-word break. */
  .doc h1 { font-size: var(--text-2xl); }
  /* 38px over 6 lines swallowed the whole first screen on a phone. */
  .hero h1 { font-size: var(--text-3xl); }
  .hero .lead { font-size: var(--text-base); }
  .section { padding: 40px 0; }
  .actions .btn { width: 100%; }
}
