/* =============================================================================
   Valeria Sablina — portfolio
   The palette below is taken from the real Qonversion design-system tokens, so the
   site itself behaves like the systems the cases describe: one set of semantic
   tokens, two themes, no hard-coded colours below this block.
   ========================================================================== */

:root {
  /* Surfaces and text */
  --bg: #fafafa;
  --surface: #ffffff;
  --ink: #17181c;
  --muted: #5c5f6a;
  --border: #ececef;

  /* Accents, from Valeria's palette (17.08): crimson carries every action, lime is a
     marker only — never a text colour. Her #B7FEB6 sits at 1.2:1 on white, so it can
     only ever be a plate with dark ink on top; the crimson takes the interactive role
     and clears 4.5:1 as text and as a button ground. */
  --accent: #db175c;
  --accent-hover: #b01049;
  --marker: #b7feb6;

  /* Derived */
  --on-accent: #ffffff;
  --on-marker: #17181c;
  --shadow: 0 1px 2px rgba(23, 24, 28, .04), 0 12px 32px rgba(23, 24, 28, .06);
  --radius: 14px;
  --radius-sm: 8px;

  /* Type */
  /* Manrope, chosen by Valeria (17.08). It carries Cyrillic, so EN and RU headings are
     finally set in the same face — the old Space Grotesk had none. */
  --font-display: "Manrope", "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  /* Layout */
  --wrap: 1120px;
  --gutter: 24px;
  --section-y: 7rem;
}

[data-theme="dark"] {
  --bg: #17181c;
  --surface: #242830;
  --ink: #f4f4f6;
  --muted: #9a9daa;
  --border: #33363f;

  /* The dark theme takes a lighter tint of the same crimson — #db175c drops to 3.0:1 on
     the dark surface, #f76a97 holds 5.2:1. Same move the old violet made. */
  --accent: #f76a97;
  --accent-hover: #ffa0bf;
  --marker: #b7feb6;

  --on-accent: #17181c;

  --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 14px 36px rgba(0, 0, 0, .32);
}

/* ------------------------------------------------------------------ base */

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

html {
  scroll-behavior: smooth;
  scroll-padding-top: 96px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1.06rem;
  line-height: 1.65;
  font-weight: 400;
  overflow-x: hidden; /* the page itself never scrolls sideways; wide bands scroll inside */
  -webkit-font-smoothing: antialiased;
  transition: background-color .25s ease, color .25s ease;
}

img { display: block; max-width: 100%; height: auto; }

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

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -.02em;
  margin: 0;
}

/* Manrope covers Cyrillic, so the RU page no longer needs its own display face — the
   earlier Inter fallback is gone. Russian still runs longer, hence the tighter tracking. */
[lang="ru"] h1,
[lang="ru"] h2,
[lang="ru"] h3,
[lang="ru"] .hero__thesis {
  letter-spacing: -.025em;
}

/* Russian runs longer than English; at the EN measure the thesis broke inside
   "UX/UI-дизайнер". */
[lang="ru"] .hero__thesis { max-width: 30ch; }
[lang="ru"] .section__head h2 { max-width: 30ch; }

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

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--surface);
  color: var(--ink);
  padding: .75rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.skip-link:focus { left: 12px; top: 12px; }

/* --------------------------------------------------------------- top bar */

.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}

.topbar__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: .8rem var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: -.01em;
}
.brand:hover { color: var(--ink); text-decoration: none; }

/* Valeria's own mark, supplied 19.08 — it replaced the placeholder VS monogram. */
.brand__mark {
  width: 26px;
  height: 26px;
  flex: none;
  display: block;
}
/* Valeria's mark is a near-black silhouette: on a dark background it would disappear,
   so the dark theme shows an inverted copy of the same shape. */
html[data-theme="dark"] .brand__mark { filter: invert(1); }

.topbar__controls {
  display: flex;
  align-items: center;
  gap: 1.1rem;
}

.langs {
  display: inline-flex;
  align-items: center;
  gap: .1rem;
  font-family: var(--font-mono);
  font-size: .78rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px;
  background: var(--surface);
}
.langs__item {
  display: inline-block;
  padding: .25rem .6rem;
  border-radius: 999px;
  color: var(--muted);
}
.langs__item:hover { color: var(--ink); text-decoration: none; }
.langs__item.is-active {
  background: var(--ink);
  color: var(--bg);
}

.token-toggle {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  font-family: var(--font-mono);
  font-size: .78rem;
  color: var(--muted);
}
.token-toggle__key { letter-spacing: .02em; }
.token-toggle__values {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
}
.token-toggle__btn {
  font: inherit;
  color: var(--muted);
  background: none;
  border: 0;
  padding: .2rem .3rem;
  border-radius: 5px;
  cursor: pointer;
  transition: color .15s ease, background-color .15s ease;
}
.token-toggle__btn:hover { color: var(--ink); }
.token-toggle__btn[aria-pressed="true"] {
  color: var(--on-marker);
  background: var(--marker);
  font-weight: 500;
}
.token-toggle__sep { opacity: .5; }

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

.hero {
  padding: clamp(3.5rem, 9vw, 7rem) 0 clamp(3rem, 7vw, 5rem);
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: .78rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1rem;
}

.hero__name {
  font-size: clamp(2.6rem, 6vw, 4.4rem);
  margin: 0 0 .6rem;
}

.hero__thesis {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.2rem, 2.5vw, 1.75rem);
  line-height: 1.3;
  letter-spacing: -.01em;
  margin: 0 0 1.1rem;
  /* 28ch instead of 22: at 22 the English thesis broke into three lines and left
     "for B2B SaaS" hanging alone (Lera, 26.08). The nbsp inside "for B2B SaaS"
     keeps that phrase together; this gives the line room to fit. */
  max-width: 28ch;
}

.hero__sub {
  color: var(--muted);
  max-width: 52ch;
  margin: 0 0 2rem;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  margin-bottom: 3rem;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: .8rem 1.5rem;
  border-radius: 999px;
  font-weight: 500;
  font-size: .98rem;
  border: 1px solid transparent;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.btn:hover { text-decoration: none; }

.btn--primary { background: var(--accent); color: var(--on-accent); }
.btn--primary:hover { background: var(--accent-hover); color: var(--on-accent); }

.btn--ghost { border-color: var(--border); color: var(--ink); background: var(--surface); }
.btn--ghost:hover { border-color: var(--accent); color: var(--accent); }

/* The email is a button, not a mailto link: one click puts it on the clipboard. */
.btn.copy {
  cursor: copy;
  font-family: inherit;
  line-height: inherit;
}
.btn.copy.is-copied {
  background: var(--marker);
  border-color: var(--marker);
  color: var(--on-marker);
}

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

.facts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: .9rem 1.6rem;
  border-top: 1px solid var(--border);
  padding-top: 1.6rem;
}
.facts__item {
  font-family: var(--font-mono);
  font-size: .84rem;
  line-height: 1.5;
  color: var(--muted);
  padding-left: 1.1rem;
  position: relative;
}
.facts__item::before {
  content: "";
  position: absolute;
  left: 0;
  top: .5em;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--marker);
}

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

.section { padding: var(--section-y) 0; border-top: 1px solid var(--border); }
.section--about { background: var(--surface); }

.section__head { margin-bottom: 2.5rem; }
.section__head h2 {
  font-size: clamp(1.6rem, 3.6vw, 2rem);
  margin: 0 0 .9rem;
  max-width: 24ch;
}

.lede {
  color: var(--muted);
  max-width: 62ch;
  margin: 0;
  font-size: 1.06rem;
}

.prose { max-width: 66ch; margin: 2.2rem 0; }
.prose p { margin: 0 0 1.25rem; }
.prose p:last-child { margin-bottom: 0; }

/* ------------------------------------------------- prototype tiles */
/* Four prototype links as a row of preview cards: the picture is the affordance,
   the name underneath says which flow it opens. */

.protos { margin: 2.6rem 0; }
.protos__title { margin: 0 0 1rem; font-size: 1.05rem; }
.protos__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}
/* Three prototypes, three columns: a fourth column stood empty (Valeria's audit 8). */
.protos__grid--3 { grid-template-columns: repeat(3, 1fr); }
.protos__grid a {
  display: block;
  color: var(--ink);
  text-decoration: none;
}
.protos__grid img {
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.protos__grid span {
  display: block;
  margin-top: .5rem;
  font-family: var(--font-mono);
  font-size: .76rem;
  color: var(--muted);
}
.protos__grid a:hover span { color: var(--accent); }
.protos__grid a:hover img { border-color: var(--accent); }

/* ------------------------------------------------------- spec table */
/* The signature element: case metadata rendered like a specification sheet,
   monospaced, with dotted leaders running from the label to the value. */

.spec {
  margin: 0;
  padding: 1.4rem 1.5rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  font-family: var(--font-mono);
  font-size: .86rem;
  line-height: 1.6;
}

.spec__row {
  display: grid;
  grid-template-columns: minmax(9rem, 13rem) 1fr;
  gap: 0 1rem;
  padding: .5rem 0;
}
.spec__row + .spec__row { border-top: 1px solid var(--border); }

.spec dt {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  color: var(--muted);
  text-transform: lowercase;
  letter-spacing: .02em;
}
.spec dd {
  margin: 0;
  color: var(--ink);
  font-weight: 500;
}

.spec--contact dd a { font-weight: 500; }

.mark {
  background: var(--marker);
  color: var(--on-marker);
  padding: .05em .3em;
  border-radius: 4px;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* --------------------------------------------------------- findings list */

.findings {
  list-style: none;
  margin: 2rem 0;
  padding: 0;
  display: grid;
  gap: .8rem;
  max-width: 72ch;
}
.findings li {
  position: relative;
  padding: .9rem 1.1rem .9rem 2.4rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 1rem;
}
.findings li::before {
  content: "";
  position: absolute;
  left: 1.1rem;
  top: 1.35em;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: var(--marker);
}
/* Same treatment as .mark: lime stays a marker with dark ink on top, never a text colour.
   A translucent lime went muddy over the dark surface. */
.findings b {
  font-family: var(--font-mono);
  font-weight: 500;
  background: var(--marker);
  color: var(--on-marker);
  padding: .02em .28em;
  border-radius: 4px;
}

/* ---------------------------------------------------------------- figures */

.fig { margin: 2.4rem 0 0; }
.fig--narrow { max-width: 760px; }
/* Sheets that are much taller than they are wide: the frame hugs the artwork
   instead of stranding it in the middle of a full-width box. */
.fig--tall { max-width: 560px; }

.fig > img,
.shot img,
.grid-2 img {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}

figcaption {
  margin-top: .85rem;
  font-family: var(--font-mono);
  font-size: .78rem;
  line-height: 1.5;
  color: var(--muted);
}

.hint {
  display: inline-block;
  margin-left: .4rem;
  padding: .1rem .45rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: .72rem;
  white-space: nowrap;
}
.hint--block {
  display: block;
  width: fit-content;
  margin: .85rem 0 0;
  font-family: var(--font-mono);
  color: var(--muted);
}

/* pair — two shots side by side on desktop, stacked on mobile */
.pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  align-items: start;
}

/* stack — the same labelled comparison as .pair, but one above the other. Used when the
   two source exports have very different proportions and a side-by-side would leave a hole. */
.stack { display: grid; gap: 1.8rem; }

.shot { display: flex; flex-direction: column; gap: .6rem; }
.shot__label {
  font-family: var(--font-mono);
  font-size: .74rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
}

/* scroller — wide canvases keep their scale and scroll inside their own frame */
.scroller {
  overflow-x: auto;
  overflow-y: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  padding: 1rem;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.scroller > img {
  height: var(--band-h, 320px);
  width: auto;
  max-width: none;
  border-radius: var(--radius-sm);
}

/* tall — very tall sheets are capped and scroll vertically inside the frame */
.tall {
  max-height: 560px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  padding: 1rem;
  scrollbar-width: thin;
}
.tall img { border-radius: var(--radius-sm); margin: 0 auto; }

/* phones — a row of mobile screens at a fixed 220px width */
.phones {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
}
/* Sized by height, not width: the source exports differ slightly in aspect ratio, and a
   fixed width left the row ragged along the bottom. Lowered to 420px on 26.08, when the
   fourth EdPalm slide arrived and four of them had to fit the column. */
.phones img {
  flex: none;
  height: 420px;
  width: auto;
  max-width: none;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
}

/* ------------------------------------------------------------------ grid */
/* Close-ups laid out in equal columns. Cells align to the top: the sheets
   behind them have different proportions and stretching would lie about them. */

.grid {
  display: grid;
  gap: 1.5rem;
  align-items: start;
}
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* A wide screen next to a phone: the pair reads as one page at two breakpoints, so the
   columns are deliberately unequal and both shots are capped in height. */
.grid--bp { grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr); }
.grid--bp .shot img {
  max-height: 520px;
  object-fit: cover;
  object-position: 50% 0;
  border-radius: var(--radius-sm);
}
.grid .shot img { width: 100%; }
/* Two presentations (or landings) side by side at one height: the cells stretch, and the
   button under each one is pushed to the bottom, so both buttons sit on the same line
   however long the description above them is (Valeria's audit 8). */
.grid--even { align-items: stretch; }
.grid--even .shot > .deck-actions { margin-top: auto; padding-top: 1.4rem; }
/* Phone shots vary from one screen to a long scrolled page; inside a row they are capped
   and cropped from the top, and the viewer shows the whole thing. */
/* Phone screens are shown whole (Lera, 26.08): cropping them to a fixed height cut
   the bottom of the mock-up off, which is where the action of the screen usually is. */
.grid--phones .shot img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
}

/* Landing previews: the top of a very tall page, cropped to a fixed height with no inner
   scroll. The full sheet still opens on click through the zoom viewer (data-zoom). */
.shot--crop img {
  width: 100%;
  height: 480px;
  object-fit: cover;
  object-position: 50% 0;
  border-radius: var(--radius-sm);
  cursor: zoom-in;
}
/* Extra breathing room above the button that follows a figure (presentations, Dribbble). */
.deck-actions { margin-top: 32px; }
/* Video previews sit in a shot the way the still images do: framed, 4:3, filled. */
.shot video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

/* Sub-heading above a group of shots inside a case body. */
.fig-title {
  font-size: 1.15rem;
  font-weight: 500;
  margin: 2.6rem 0 .9rem;
}

/* --------------------------------------------------------------- gallery */

.subcase { margin-top: 3.5rem; }
.subcase:first-of-type { margin-top: 0; }
.subcase h3 {
  font-size: 1.25rem;
  font-weight: 500;
  margin: 0 0 .6rem;
}
.subcase__note {
  color: var(--muted);
  max-width: 62ch;
  margin: 0 0 1.4rem;
}
.subcase .pair { margin-top: 1.2rem; }

/* ----------------------------------------------------------------- about */

.about {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: 3rem;
  align-items: start;
}
.about .prose { margin-top: 0; }

.about__subtitle {
  font-family: var(--font-mono);
  font-size: .78rem;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1rem;
}

.chips {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}
.chips li {
  font-family: var(--font-mono);
  font-size: .8rem;
  padding: .35rem .7rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--muted);
  background: var(--bg);
}

.contact { margin-top: 3.5rem; }
.contact__title {
  font-size: 1.25rem;
  font-weight: 500;
  margin: 0 0 1.2rem;
}
.spec--contact { background: var(--bg); }

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

.footer {
  border-top: 1px solid var(--border);
  padding: 2.5rem 0 3.5rem;
}
/* One row: signature on the left, links on the right. The back-to-top button is not part
   of it — it is fixed to the viewport (see .to-top). */
.footer__inner {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 1rem 2rem;
}
.footer__name { grid-area: 1 / 1; }
.footer__links { grid-area: 1 / 2; justify-self: end; }


.footer__name {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .8rem;
  color: var(--muted);
}
.footer__year {
  color: var(--muted);
  opacity: .8;
  margin-left: .35rem;
}
/* Back to top: fixed to the viewport and hidden on the first screen, per Valeria (20.08).
   It appears once the reader has scrolled roughly one screen down. Without JS the button
   stays visible rather than disappearing for good. */
.to-top {
  position: fixed;
  right: var(--gutter);
  bottom: calc(var(--gutter) + .4rem);
  z-index: 40;
  font-family: var(--font-mono);
  font-size: .78rem;
  color: var(--muted);
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: .45rem 1rem;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: color .15s ease, border-color .15s ease, opacity .2s ease, transform .2s ease;
}
.to-top:hover { color: var(--ink); border-color: var(--accent); }

/* JS decides when it shows; the class is added only after the first screen. */
.js .to-top {
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
}
.js .to-top.is-visible {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* While the viewer is open the page behind it is frozen, so a floating button that
   scrolls that page has nothing to do — and it must not catch the focus either. */
body.is-locked .to-top,
body.is-locked .to-top.is-visible {   /* must outrank .js .to-top.is-visible */
  opacity: 0;
  pointer-events: none;
}


/* ============================================================================
   v2 — multi-page structure: case pages, cards, the before/after slider and
   the viewer. Everything below reuses the same tokens as the blocks above.
   ========================================================================= */

/* ------------------------------------------------------------ case intro */

.case-intro {
  padding: clamp(2.5rem, 6vw, 4.5rem) 0 clamp(2rem, 4vw, 3rem);
}

.crumbs {
  font-family: var(--font-mono);
  font-size: .78rem;
  letter-spacing: .04em;
  color: var(--muted);
  margin: 0 0 1.4rem;
}
.crumbs span { margin: 0 .4rem; opacity: .6; }

/* ------------------------------------------------------------- hero photo */
.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 2rem 3rem;
}
.hero__photo {
  display: block;
  width: 100%;
  max-width: 380px;   /* Valeria's cap for the new portrait (20.08) */
  height: auto;
  justify-self: end;
}
@media (max-width: 900px) {
  .hero__grid { grid-template-columns: 1fr; gap: 1.6rem; }
  .hero__photo { max-width: 300px; justify-self: start; }
}

/* Lera's rule (audit of 23.08): the text under an h1 sits 32px below it, and
   paragraphs are 20px apart. Before this the hierarchy was inverted — 16px under
   the title, 40px between the two paragraphs of the lede. */
.case-title {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -.02em;
  font-size: clamp(2.1rem, 4.6vw, 3.2rem);
  margin: 0 0 2rem;
  max-width: 20ch;
}
[lang="ru"] .case-title { font-family: var(--font-body); letter-spacing: -.025em; max-width: 24ch; }

.case-lede {
  color: var(--muted);
  max-width: 62ch;
  font-size: 1.12rem;
  margin: 0 0 2.5rem;
}
/* Between two paragraphs of the lede — 20px; the last one keeps its gap to the
   block that follows. */
.case-lede:has(+ .case-lede) { margin-bottom: 1.25rem; }

/* ------------------------------------------------------------- result block */
/* The number of the case, before any visual. Market scan says most portfolios
   bury it at the end; this one opens with it. */

.result {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  padding: 1.8rem 1.8rem 1.6rem;
  margin-bottom: 1.6rem;
}

.result__headline {
  display: flex;
  align-items: baseline;
  gap: 1.1rem;
  flex-wrap: wrap;
  padding-bottom: 1.2rem;
  border-bottom: 1px solid var(--border);
}

.result__num {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.8rem, 7vw, 4.2rem);
  line-height: 1;
  letter-spacing: -.03em;
  background: var(--marker);
  color: var(--on-marker);
  padding: .1em .18em;
  border-radius: 10px;
}

.result__label {
  font-size: 1.06rem;
  line-height: 1.45;
  max-width: 34ch;
  color: var(--ink);
}

.result__extras {
  list-style: none;
  margin: 1.2rem 0 0;
  padding: 0;
  display: grid;
  gap: .7rem;
}
.result__extras li {
  position: relative;
  padding-left: 1.2rem;
  font-size: .98rem;
  color: var(--muted);
}
.result__extras li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .62em;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--accent);
}
.result__extras b { color: var(--ink); font-weight: 600; }

.result__note {
  margin: 1.1rem 0 0;
  font-family: var(--font-mono);
  font-size: .74rem;
  line-height: 1.5;
  color: var(--muted);
}

/* -------------------------------------------------------------- case cards */

.cases {
  display: grid;
  gap: 1.5rem;
}

.case-card {
  display: grid;
  grid-template-columns: minmax(0, 400px) minmax(0, 1fr);
  gap: 2rem;
  align-items: center;
  padding: 1.4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  transition: border-color .15s ease, transform .15s ease;
}
.case-card:hover { border-color: var(--accent); }

/* The title link is stretched over the whole card, so any point of the card opens
   the case (Valeria's audit, 18.08). The media link keeps its own hit area. */
.case-card { position: relative; }
/* The NEW badge sits in the card's own top-right corner, not over the picture
   (Valeria's audit 8, 06.09). */
.case-card__badge { top: 1.4rem; right: 1.4rem; }
.case-card__title a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.case-card__title a { position: static; }

.case-card__media {
  display: block;
  position: relative;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--bg);
  border: 1px solid var(--border);
}

.case-card__badge {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 1;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  pointer-events: none;
  animation: badge-glow 2.8s ease-in-out infinite;
}
@keyframes badge-glow {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  50% { box-shadow: 0 0 14px 1px var(--accent); }
}
.case-card__media img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: 50% 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
/* Lit and crypto-wallet covers: centre the mock-ups vertically inside the frame so their
   bottoms are not cropped. Scoped by file name, so the other case covers keep the top crop. */
.case-card__media img[src*="covers/lit.webp"],
.case-card__media img[src*="covers/crypto-wallet.webp"] {
  object-position: 50% 50%;
}

.case-card__body .eyebrow { margin-bottom: .6rem; }
.case-card__title {
  font-size: clamp(1.3rem, 2.4vw, 1.6rem);
  margin: 0 0 .7rem;
}
.case-card__title a { color: var(--ink); }
.case-card__title a:hover { color: var(--accent); text-decoration: none; }
.case-card__teaser { color: var(--muted); margin: 0 0 1rem; max-width: 56ch; }
.case-card__metric { margin: 0 0 .8rem; font-family: var(--font-mono); font-size: .82rem; }
.case-card__more {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .78rem;
  color: var(--accent);
}

/* ------------------------------------------------- case head with a CTA
   Valeria asked for the Figma button to sit level with the case title and to be
   repeated under the case body, so the title row becomes a two-part header. */

.case-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 1.5rem;
}
.case-head .case-title,
.case-head h3 { flex: 1 1 22ch; margin: 0; }
/* .case-title carries the 32px gap to the lede; inside .case-head its margin is
   cleared for vertical alignment, so the row itself carries the gap instead. */
.case-head { margin-bottom: 2rem; }
.case-head__cta { flex: 0 0 auto; }

.case-outro {
  margin-top: 2.5rem;
  padding-top: 1.8rem;
  border-top: 1px solid var(--border);
}
.case-outro__note {
  margin: .7rem 0 0;
  color: var(--muted);
  font-size: .92rem;
}

/* ----------------------------------------------------------- case chapters
   The builder case carries three chapters (redesign, design system, onboarding) on one
   page, so the bar below the intro works like tabs but scrolls instead of hiding
   content: everything stays in the document, in one link, for one reader. */

.chapters {
  position: sticky;
  top: 57px;              /* directly under the topbar */
  z-index: 20;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}
.chapters__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: .6rem var(--gutter);
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}
.chapters__item {
  font-family: var(--font-mono);
  font-size: .82rem;
  color: var(--muted);
  padding: .4rem .8rem;
  border: 1px solid transparent;
  border-radius: 999px;
}
.chapters__item:hover { color: var(--ink); text-decoration: none; border-color: var(--border); }
.chapters__item.is-current {
  background: var(--marker);
  color: var(--on-marker);
  border-color: var(--marker);
}

.chapter { scroll-margin-top: 112px; }
.chapter__head { margin-bottom: 2rem; }
.chapter__head h2 { margin: .3rem 0 .6rem; }

/* ----------------------------------------------------- also-shipped tags */

.tagblock {
  margin-top: 1.5rem;
  padding: 1.4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.tagblock h3 { font-size: 1.2rem; font-weight: 500; margin: 0 0 .5rem; }
.tagblock__note { margin: 0 0 1.1rem; color: var(--muted); max-width: 62ch; }

.tags {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
}
.tags li {
  font-family: var(--font-mono);
  font-size: .84rem;
  padding: .4rem .85rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
}

/* ------------------------------------------------------------ other works
   Two columns, as Valeria asked, so the block stays short. Every card leaves the
   site: there is no inner page behind them. */

.works {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem;
}
.work-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  overflow: hidden;
  transition: border-color .15s ease;
}
.work-card:hover { border-color: var(--accent); }
.work-card__media {
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.work-card__media img,
.work-card__media video {
  display: block;
  width: 100%;
  height: auto;      /* <video> maps its height attribute to a real CSS height */
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* The arrow that marks an outbound button needs air after the label. */
.btn span[aria-hidden] { margin-left: .4em; }
.work-card__body {
  padding: 1.1rem 1.2rem 1.3rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .55rem;
}
.work-card__title { font-size: 1.1rem; font-weight: 500; margin: 0; }
.work-card__note { margin: 0 0 .3rem; color: var(--muted); font-size: .95rem; }

.btn--sm { padding: .55rem 1rem; font-size: .88rem; }

/* ---------------------------------------------------------------- callout */

.callout {
  margin: 2.6rem 0 0;
  padding: 1.6rem 1.7rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface);
  max-width: 72ch;
}
.callout h3 {
  font-size: 1.1rem;
  font-weight: 500;
  margin: 0 0 .8rem;
}
.callout p { margin: 0 0 .9rem; }
.callout p:last-child { margin-bottom: 0; }
/* A list inside a callout: the features Lera itemised, one line each. */
.callout__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .7rem;
}
.callout__list li {
  color: var(--muted);
  padding-left: 1.1rem;
  position: relative;
}
.callout__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .62em;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--accent);
}
.callout__list b { color: var(--ink); font-weight: 500; }

/* --------------------------------------------------- cross-functional block */

.crossfn {
  margin: 3rem 0 0;
  padding: 1.6rem 1.7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  max-width: 72ch;
}
.crossfn__title {
  font-family: var(--font-mono);
  font-size: .78rem;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1rem;
}
.crossfn__list { list-style: none; margin: 0 0 1rem; padding: 0; display: grid; gap: .6rem; }
.crossfn__list li { position: relative; padding-left: 1.2rem; }
.crossfn__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .62em;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--marker);
}
.crossfn__note { margin: 0; color: var(--muted); font-size: .96rem; }

/* --------------------------------------------------------- contact and nav */

.contact-cta {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  padding: 2rem;
}
.contact-cta__title { font-size: 1.5rem; margin: 0 0 .6rem; }
.contact-cta__lede { color: var(--muted); margin: 0 0 1.4rem; max-width: 52ch; }
.contact-cta__actions { display: flex; flex-wrap: wrap; gap: .7rem; }

.pagenav { margin-top: 2rem; }
.pagenav__link {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  padding: 1.3rem 1.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
}
.pagenav__link:hover { border-color: var(--accent); text-decoration: none; color: var(--ink); }
.pagenav__key {
  font-family: var(--font-mono);
  font-size: .74rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.pagenav__title { font-family: var(--font-display); font-size: 1.2rem; font-weight: 500; }
[lang="ru"] .pagenav__title { font-family: var(--font-body); }

.linklist { list-style: none; margin: 0; padding: 0; display: grid; gap: .8rem; font-family: var(--font-mono); font-size: .92rem; }
/* A list of links right after a paragraph needs air (Lera, 26.08): they were sitting
   flush against the text above them. */
.lede + .linklist { margin-top: 2rem; }
.backlink { margin: 2rem 0 0; font-family: var(--font-mono); font-size: .85rem; }
.about__subtitle--spaced { margin-top: 2rem; }
.hero__name--sm { font-size: clamp(1.5rem, 3vw, 2rem); }
.fig--phone { max-width: 220px; }
.fig--phone .tall { padding: .5rem; }

.footer__links {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  font-family: var(--font-mono);
  font-size: .8rem;
}

/* --------------------------------------------------- before / after slider */
/* The signature interaction: two identically sized exports, one wiped over the
   other. Works with a mouse, a finger and the arrow keys. */

.fig--ba {
  margin-top: 3.5rem;
  margin-bottom: 3.5rem;
}
.fig--ba .ba { margin-inline: auto; }

.ba {
  position: relative;
  max-width: 880px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow);
  touch-action: pan-y;
  user-select: none;
  cursor: ew-resize;
}
.ba__base { display: block; width: 100%; height: auto; }

.ba__clip {
  position: absolute;
  inset: 0;
  width: 50%;
  overflow: hidden;
}
.ba__clip img {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: auto;
  max-width: none;
  /* Both exports share the same pixel size, so height:100% reproduces the
     full-width image exactly and the wipe stays aligned. */
}

.ba__tag {
  position: absolute;
  top: .8rem;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .04em;
  padding: .25rem .6rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  color: var(--ink);
  border: 1px solid var(--border);
  pointer-events: none;
}
.ba__tag--before { left: .8rem; }
.ba__tag--after { right: .8rem; }

.ba__handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 44px;
  margin-left: -22px;
  cursor: ew-resize;
  touch-action: none;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ba__handle::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 21px;
  width: 2px;
  background: var(--marker);
}
.ba__grip {
  position: relative;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: var(--marker);
  border: 2px solid var(--on-marker);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .25);
}
.ba__grip::before,
.ba__grip::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 0;
  height: 0;
  margin-top: -5px;
  border: 5px solid transparent;
}
.ba__grip::before { left: 6px; border-right-color: var(--on-marker); }
.ba__grip::after { right: 6px; border-left-color: var(--on-marker); }
.ba__handle:focus-visible { outline: none; }
.ba__handle:focus-visible .ba__grip { outline: 3px solid var(--accent); outline-offset: 3px; }

.ba.is-animated .ba__clip,
.ba.is-animated .ba__handle { transition: width .18s ease, left .18s ease; }

/* ------------------------------------------------------------------ viewer */

[data-zoom] { cursor: zoom-in; }

/* Wide and tall canvases scroll inside their frame; the caption says so, and this
   adds the second half of the sentence in the page's own language. */
html[lang="en"] .fig:has(.scroller) figcaption::after,
html[lang="en"] .fig:has(.tall) figcaption::after { content: " Click to open it full size."; }
html[lang="ru"] .fig:has(.scroller) figcaption::after,
html[lang="ru"] .fig:has(.tall) figcaption::after { content: " Кликом открывается полный размер."; }
html[lang] .fig--tall:has(.tall) figcaption::after { content: none; }

/* The overlay keeps its own dark palette in both themes: it is a room with the
   lights off, not a part of the page. */
.viewer {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  /* Nearly opaque: what is left of the page behind a picture only competes with it. */
  background: rgba(10, 11, 14, .99);
  --viewer-ink: #f4f4f6;
  --viewer-mark: #ff7aa8;
}
.viewer.is-open { display: block; }

.viewer__stage {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4.5rem 1.5rem 4rem;
  overflow: auto;
  overscroll-behavior: contain;
}
/* In detail mode the stage gives up its padding to the picture, and stops centring
   it on the axis that overflows — a centred flex child cuts off its own top and
   left when it is larger than its scroll container. An axis the picture fits on
   stays centred, so a wide strip does not hang from the top edge. */
.viewer.is-detail .viewer__stage {
  padding: 0;
  cursor: grab;
}
.viewer.is-detail.is-over-x .viewer__stage { justify-content: flex-start; }
.viewer.is-detail.is-over-y .viewer__stage { align-items: flex-start; }
.viewer__img {
  display: block;
  flex: none;
  /* The page caps every picture at the width of its column; here the width is set
     in pixels on purpose and must win. */
  max-width: none;
  max-height: none;
  border-radius: 20px;
  /* The viewer is a dark room in both themes, so the picture sits on that dark
     backdrop rather than a light surface — otherwise the rounded corners show a
     light ring against the room. Opaque screenshots cover it either way. */
  background: transparent;
}
.viewer.is-detail .viewer__img { border-radius: 20px; cursor: grab; }
/* Fitted and with room to grow: the picture itself is the zoom control. */
.viewer.is-fitted .viewer__img { cursor: zoom-in; }
.viewer.is-dragging .viewer__stage,
.viewer.is-dragging .viewer__img { cursor: grabbing; }

/* One row of controls in the top-left corner: close, zoom, fit. The minimap keeps
   the opposite corner to itself. */
.viewer__tools {
  position: absolute;
  z-index: 3;
  top: 1rem;
  left: 1rem;
  display: flex;
  align-items: center;
  gap: .5rem;
}
.viewer__btn {
  border: 1px solid rgba(255, 255, 255, .25);
  background: rgba(20, 21, 26, .8);
  color: var(--viewer-ink);
  border-radius: 999px;
  height: 44px;
  min-width: 44px;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.viewer__btn:hover { background: rgba(60, 62, 72, .9); }
.viewer__btn[hidden] { display: none; }
.viewer__fit {
  padding: 0 1rem;
  font-family: var(--font-mono);
  font-size: .76rem;
}

/* Minus, the current scale, plus — one pill, because they are one control. */
.viewer__zoom {
  display: flex;
  align-items: center;
  height: 44px;
  border: 1px solid rgba(255, 255, 255, .25);
  background: rgba(20, 21, 26, .8);
  border-radius: 999px;
  overflow: hidden;
}
.viewer__step,
.viewer__percent {
  background: none;
  border: 0;
  color: var(--viewer-ink);
  height: 100%;
  cursor: pointer;
  font-family: var(--font-mono);
}
.viewer__step {
  width: 38px;
  font-size: 1.1rem;
  line-height: 1;
}
.viewer__percent {
  min-width: 4.2rem;
  font-size: .76rem;
  border-left: 1px solid rgba(255, 255, 255, .16);
  border-right: 1px solid rgba(255, 255, 255, .16);
}
.viewer__step:hover,
.viewer__percent:hover { background: rgba(60, 62, 72, .9); }
.viewer__step[disabled] { opacity: .35; cursor: default; }
.viewer__step[disabled]:hover { background: none; }

/* The minimap: the whole sheet at a glance, with the frame marking the part that
   is on screen. Pointing at it travels there. */
.viewer__map {
  position: absolute;
  z-index: 3;
  top: 1rem;
  right: 1rem;
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: 4px;
  background: rgba(20, 21, 26, .85);
  box-shadow: 0 10px 34px rgba(0, 0, 0, .5);
  overflow: hidden;
  cursor: crosshair;
  touch-action: none;
}
.viewer__map[hidden] { display: none; }
.viewer__map-img {
  display: block;
  width: 100%;
  height: 100%;
  opacity: .5;
}
.viewer__map-frame {
  position: absolute;
  top: 0;
  left: 0;
  min-width: 8px;
  min-height: 8px;
  border: 2px solid var(--viewer-mark);
  background: rgba(255, 255, 255, .16);
  pointer-events: none;
}

.viewer__bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: .9rem 1.5rem 1.2rem;
  display: flex;
  gap: 1rem;
  align-items: baseline;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: .76rem;
  color: rgba(244, 244, 246, .75);
  background: linear-gradient(to top, rgba(10, 11, 14, .92), transparent);
  pointer-events: none;
}
.viewer__caption { max-width: 70ch; }
.viewer__hint { flex: none; opacity: .7; }

body.is-locked { overflow: hidden; }

/* --------------------------------------------------------------- motion */
/* One restrained reveal on scroll. Nothing else moves. */

.js .reveal {
  opacity: 0;
  transform: translateY(14px);
}
.js .reveal.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity .5s ease, transform .5s cubic-bezier(.22, .61, .36, 1);
}

@media (prefers-reduced-motion: reduce) {
  .case-card__badge { animation: none; }
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; }
  .js .reveal.is-visible { transition: none; }
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  /* The slider keeps working — only the eased jump on keyboard input goes away. */
  .ba.is-animated .ba__clip,
  .ba.is-animated .ba__handle { transition: none; }
}

/* -------------------------------------------------------------- adaptive */

@media (max-width: 900px) {
  :root { --section-y: 4.5rem; }
  .about { grid-template-columns: 1fr; gap: 2rem; }
  .case-card { grid-template-columns: 1fr; gap: 1.4rem; }
  .grid--3, .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid--bp { grid-template-columns: 1fr; }
}

@media (max-width: 720px) {
  :root { --gutter: 18px; }
  body { font-size: 1rem; }

  .works { grid-template-columns: 1fr; }
  .case-head__cta { width: 100%; justify-content: center; }

  /* Wrapped onto two rows the sticky chapter bar ate a third of the screen, so on a phone
     it scrolls sideways instead. */
  .chapters__inner {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .chapters__inner::-webkit-scrollbar { display: none; }
  .chapters__item { white-space: nowrap; }
  .chapter { scroll-margin-top: 104px; }

  .pair, .grid-2, .grid--2, .grid--3 { grid-template-columns: 1fr; gap: 1.6rem; }
  .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }

  .result { padding: 1.3rem; }
  .result__headline { gap: .8rem; }
  .contact-cta { padding: 1.4rem; }
  .callout, .crossfn { padding: 1.3rem; }
  .ba__grip { width: 34px; height: 34px; }
  .ba__handle { width: 40px; margin-left: -20px; }
  .ba__handle::before { left: 19px; }
  .viewer__stage { padding: 4rem .8rem 3.5rem; }
  .viewer__bar { padding: .8rem 1rem 1rem; }
  /* A finger is not dragged with a mouse, so the hint is desktop-only. */
  .viewer__hint { display: none; }

  .protos__grid { grid-template-columns: repeat(2, 1fr); }
  .spec { padding: 1.1rem 1.1rem; }
  .spec__row { grid-template-columns: 1fr; gap: .1rem; padding: .6rem 0; }

  .topbar__inner { flex-wrap: wrap; row-gap: .6rem; }
  .brand__name { font-size: .95rem; }

  .hero__thesis { max-width: none; }
  .facts { grid-template-columns: 1fr; }

  .tall { max-height: 420px; }
  .phones img { height: 400px; }

  .footer__inner { grid-template-columns: 1fr; gap: 1.1rem; }
  .footer__name,
  .footer__links { grid-area: auto; justify-self: start; }
}

@media (max-width: 400px) {
  :root { --gutter: 14px; }
  .topbar__controls { gap: .7rem; }
  .token-toggle { font-size: .72rem; }
  .langs { font-size: .72rem; }
  .btn { padding: .7rem 1.15rem; font-size: .92rem; }
}
