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

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  line-height: 1.2;
}

h1,
h2,
h3,
p,
ul {
  margin: 0;
}

ul {
  padding: 0;
  list-style: none;
}

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

[hidden] {
  display: none !important;
}

/* Design tokens */
:root {
  /* Figma's "Quick" spring (mass 1, stiffness 300, damping 20) sampled over 620ms,
     as in the prototype: overshoots ~11% and settles */
  --poster-ease: linear(0, 0.052, 0.18, 0.346, 0.521, 0.686, 0.827, 0.938, 1.019, 1.071, 1.099, 1.108, 1.104, 1.091, 1.073, 1.054, 1.036, 1.02, 1.008, 0.999, 0.993, 0.989, 0.988, 0.989, 0.99, 0.992, 0.994, 0.996, 0.998, 0.999, 1, 1);
  /* The same spring as one cubic-bezier (overshoots ~10%): Safari and every iPhone browser
     (WebKit) can't run a linear() easing on the graphics chip and animate it frame by
     frame on the main thread instead, which stutters. Used for moving and scaling */
  --spring-ease: cubic-bezier(0.34, 1.56, 0.64, 1);
  --color-bg: #fafafa;
  --color-text: #1a1a1a;
  /* Pure black for the phone's status bar and bottom bar (and the canvas around them) */
  --color-bar: #000000;
  --color-orange: #ff9633;
  --color-pink: #f74980;

  /* Layout grid from Figma (frame 1512 x 982) */
  --columns: 12;
  --margin: 8px;
  --gutter: 16px;

  /* Vertical rhythm */
  --hero-top: 44px;       /* page top -> title */
  --hero-gap: 12px;       /* title -> workshop strip */
  --content-top: 50px;    /* workshop strip -> content */
  --stack-gap: 80px;      /* auto layout gap between page sections and stickers */
}

/* Canvas: what the bounce past the bottom of the page shows */
html {
  background: var(--color-bg);
}

/* Black body (hidden under the page): newer iOS Safari takes the status bar colour from it */
body {
  color: var(--color-text);
  background: var(--color-bar);
}

body::before,
body::after {
  content: "";
  left: 0;
  right: 0;
  pointer-events: none;
}

/* Behind the page, showing through the transparent black ending */
body::before {
  position: fixed;
  top: 0;
  bottom: 0;
  z-index: -1;
  background-color: var(--color-bar);
}

/* Just above the top of the page, out of scroll reach: only the bounce past the top
   reveals it */
body::after {
  position: absolute;
  bottom: 100%;
  height: 100vh;
  background-color: var(--color-bar);
}

/* A black strip pinned to the top of the screen on iOS. Safari 26 ignores theme-color and
   paints the status bar from a fixed element at the top edge instead (pseudo-elements don't
   count, and it needs 5px or more); without one it shows the page faded under the bar.
   Safari reads it as the page loads and keeps the colour, so the strip is then clipped away
   (.is-hidden) while the zigzag is at the top, where it would cover the teeth */
.status-tint {
  display: none;
}

@supports (-webkit-touch-callout: none) {
  .status-tint {
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 6px;
    z-index: 10000;
    background: var(--color-bar);
    pointer-events: none;
  }

  .status-tint.is-hidden {
    clip-path: inset(0 0 100% 0);
  }

  /* The same for Safari's bottom bar: the phone bag touches the bottom edge, and without
     this Safari would take the bar colour from the bag, which has none */
  .status-tint--bottom {
    top: auto;
    bottom: 0;
  }
}

/* Scrollbar: a square white thumb on a full-height black track */
::-webkit-scrollbar {
  width: 9px;
  height: 9px;
}

::-webkit-scrollbar-track {
  background: var(--color-text);
}

::-webkit-scrollbar-thumb {
  background: var(--color-bg);
  border-radius: 0;
}

/* Firefox has no scrollbar pseudo-elements; it takes the colours only */
@supports not selector(::-webkit-scrollbar) {
  html {
    scrollbar-color: var(--color-bg) var(--color-text);
  }
}

/* Custom cursors (retro 3D hands, taken from akademijaoxford.com): a tilted hand
   everywhere, an upright one over anything clickable. The .cur files carry their own
   hotspot; the PNG copies (for Safari) name it: the fingertip in the 32x32 image. */
:root {
  --cursor-normal: url("../assets/cursors/normal.cur"), url("../assets/cursors/normal.png") 0 0, auto;
  --cursor-link: url("../assets/cursors/hyperlink.cur"), url("../assets/cursors/hyperlink.png") 13 0, pointer;
}

html {
  cursor: var(--cursor-normal);
}

a,
[role="button"] {
  cursor: var(--cursor-link);
}

/* Nothing pokes out sideways into a horizontal scroll (on phones the big ORDER ellipse
   is wider than the screen; on tablets the crew cards don't fit yet). clip, unlike
   hidden, doesn't turn the page into its own scroll box; hidden is the fallback */
.page {
  overflow-x: hidden;
  overflow-x: clip;
  min-height: 100vh;
  background: var(--color-bg);
  padding-bottom: 98px;  /* Figma frame ends 98px below the content */
}

/* 12-column layout: place children with grid-column, e.g. `grid-column: 4 / 10` */
.grid {
  display: grid;
  grid-template-columns: repeat(var(--columns), 1fr);
  column-gap: var(--gutter);
  padding-inline: var(--margin);
}

/* Let grid items shrink below their content (the long "=====" runs) */
.grid > * {
  min-width: 0;
}

/* The main column spans columns 4-9 on desktop */
.title,
.workshop,
.stack {
  grid-column: 4 / 10;
}

/* Shared: a run of "=====" that fills the leftover width */
.rule {
  font-family: var(--font-alpha54);
  flex: 1;
  min-width: 2ch;
  overflow: hidden;
  white-space: nowrap;
}

.rule::before {
  content: "================================================================================================================================================";
}

.ruled-row {
  display: flex;
  align-items: baseline;
  gap: 1ch;
}

/* 1. Hero */
.hero {
  padding-top: var(--hero-top);
  row-gap: var(--hero-gap);
}

/* The five letter SVGs share one grid cell. Above the rest of the page,
   so a hovered letter's outline can spill over the strip and content below */
.title {
  /* Hover timing for the letters (see "Hover" below) */
  --lift: -10px;
  --lean: 8px; /* the end letters also lean out sideways: S left, d right */
  --lift-ms: 160ms;
  --swap-delay: 0ms; /* the swap happens the moment the mouse touches the letter */
  --hold-ms: 300ms;
  position: relative;
  z-index: 2;
  display: grid;
}

.title__word {
  grid-area: 1 / 1;
  position: relative;
  z-index: 1;
  /* Only the letters themselves catch the mouse, not each full-width SVG box */
  pointer-events: none;
  transition: z-index 0s var(--hold-ms);
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
  fill: var(--color-text);
  font-size: 210px;
  font-weight: 400;
}

/* Hover: the letter lifts a little and at once swaps to its look from the
   Figma components (s/a/l/a/d, Variant2): the letter tilted, in another font, with
   a thick colored outline. Angles and letter positions in index.html are taken
   from those components. After the mouse leaves, the card stays a moment, then
   the letter sinks back the same way. */
.title__letter {
  pointer-events: visiblePainted;
  cursor: default;
  /* Mirrors the way up: starts sinking just before the card goes away, so it swaps back halfway down */
  transition: translate var(--lift-ms) cubic-bezier(0.3, 0, 0.3, 1) calc(var(--hold-ms) - var(--swap-delay));
}

.title__card {
  visibility: hidden;
  font-size: 210.855px;
  font-weight: 400;
  text-transform: none;
}

.title__word:nth-child(1) .title__card { --ink: #ff66ca; --outline: #1164ff; --outline-w: 25px; font-family: var(--font-altenglisch); }
.title__word:nth-child(2) .title__card { --ink: #00aa58; --outline: #00d4fe; --outline-w: 28px; font-family: var(--font-helvetica-rounded); font-weight: 700; }
.title__word:nth-child(3) .title__card { --ink: #0083fe; --outline: #6a4336; --outline-w: 28px; font-family: var(--font-schoenschrift); }
.title__word:nth-child(4) .title__card { --ink: #fb5e24; --outline: #fe9ace; --outline-w: 28px; font-family: var(--font-alpha54); }
.title__word:nth-child(5) .title__card { --ink: #18c1f0; --outline: #7200fe; --outline-w: 21px; font-family: var(--font-brush-script); font-style: italic; font-size: 344.62px; }

/* Figma's outside stroke: twice as wide and painted under the fill, with round corners */
.title__card text {
  fill: var(--ink);
  stroke: var(--outline);
  stroke-width: calc(2 * var(--outline-w));
  stroke-linejoin: round;
  paint-order: stroke;
}

/* Swapped in one go; the plain letter only goes transparent so it keeps the hover */
.title__plain,
.title__card {
  transition: opacity 0s var(--hold-ms), visibility 0s var(--hold-ms);
}

/* Lifts a little and stays up while hovered, moving off right away (ease-out).
   .is-lit plays the same look from js/script.js: the quick wave on page load, and a tap
   on touch screens. Hover itself only counts with a mouse: a tap's hover would stick
   until the next tap somewhere else */
.is-lit .title__letter {
  translate: var(--side, 0px) var(--lift);
  transition-delay: 0s;
  transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
}

.title__word:first-child { --side: calc(-1 * var(--lean)); }
.title__word:last-child { --side: var(--lean); }

.is-lit .title__plain,
.is-lit .title__card {
  transition-delay: var(--swap-delay);
}

/* The hovered letter comes to the front, and stays there while it holds its look */
.title__word.is-lit {
  z-index: 2;
  transition-delay: 0s;
}

.is-lit .title__plain { opacity: 0; }

.is-lit .title__card { visibility: visible; }

@media (hover: hover) {
  .title__letter:hover {
    translate: var(--side, 0px) var(--lift);
    transition-delay: 0s;
    transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
  }

  .title__letter:hover > .title__plain,
  .title__letter:hover .title__card {
    transition-delay: var(--swap-delay);
  }

  .title__word:hover {
    z-index: 2;
    transition-delay: 0s;
  }

  .title__letter:hover > .title__plain { opacity: 0; }

  .title__letter:hover .title__card { visibility: visible; }
}

/* During the wave a letter lets go right away instead of holding its look */
.title.is-waving {
  --hold-ms: var(--swap-delay);
}

/* Phone-only art (see the phone section) */
.title__tomato {
  display: none;
}

.workshop {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-family: var(--font-alpha54);
  font-size: 20px;
  line-height: 20px;
  text-transform: uppercase;
}

.workshop .rule {
  width: 100%;
}

/* Spacing from Figma: rules at y 0 and 40, label at y 22 (it overlaps the lower rule slightly) */
.workshop__label {
  margin-block: 2px -5px;
  line-height: 23px;
}

/* 2. Content: the Figma auto layout, a vertical flex stack */
.content {
  padding-top: var(--content-top);
}

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--stack-gap);
  font-family: var(--font-pressura-mono);
  font-weight: 500;
  font-size: 16px;
  line-height: 15px;
  text-transform: uppercase;
}

.stack .rule {
  font-size: 21px;
  line-height: 21px;
}

/* What a poster and an olivier have in common: the [ title ], the dates, then centred
   text. The header is the week sections' one */
.olive {
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 100%;
}

/* Plain centred text, not a flex row: every word is its own span (the idle glitch), and
   a flex row wouldn't wrap them, so on narrow screens the title wraps onto two lines */
.olive .week__title {
  display: block;
  text-align: center;
}

/* 30/11 — 13/12 with a column of three stars at each end. Everything is set in Figma px
   times --u, so the whole row shrinks together once the column gets narrower than 740px */
.dates {
  --u: min(1px, 100cqw / 740);
  position: relative;
  display: flex;
  align-items: center;
  padding: calc(10 * var(--u)) 0 calc(20 * var(--u));
  text-transform: none;
}

.dates__day {
  flex: 1 0 0;
  min-width: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.dates__day:not(.dates__day--end) {
  margin-right: calc(-60 * var(--u));
}

/* The numbers and the dash in Knorke, each box exactly as tall as the caps (0.752em),
   like Figma's cap trim: a line height that puts the cap tops on the box's top edge and
   the baseline on its bottom (worked out from the font's 0.768 ascent / 0.24 descent) */
.dates__num,
.dates__dash {
  height: 0.752em;
  font-family: var(--font-knorke);
  font-weight: 400;
  line-height: 0.976;
  white-space: nowrap;
}

.dates__num {
  margin-right: -0.047em;
  font-size: calc(170 * var(--u));
}

.dates__day--end .dates__num {
  margin-right: -0.029em;
}

/* /11, /12: sits on the number's baseline */
.dates__month {
  font-size: calc(23 * var(--u));
  line-height: 0.826;
  letter-spacing: -0.02em;
}

.dates__dash {
  position: absolute;
  left: calc(50% + 0.5 * var(--u));
  top: calc(7 * var(--u));
  transform: translateX(-50%);
  font-size: calc(160 * var(--u));
}

/* Centred on the row's height */
.dates__stars {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  width: calc(31.267 * var(--u));
  height: calc(135 * var(--u));
  max-width: none;
}

.dates__stars--end {
  left: auto;
  right: 0;
}

.olive__text {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  text-align: center;
}

.olive__group {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
}

.olive__big {
  font-size: 20px;
  line-height: 20px;
}

/* 46px, unless the longest word («ингредиентами», 15 letters of 0.55em) would be wider
   than the column: then just small enough to fit (phones) */
.olive__about {
  max-width: 654.207px;
  font-size: min(46px, 100cqw / 8.4);
  line-height: 0.87;
}

.olive__plus {
  font-family: var(--font-alpha54);
  font-size: 20px;
  line-height: 20px;
}

.intro {
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.intro__group {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.topics {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--gutter);
}

/* The two topics sit at the ends of the row; as it narrows, the space between them
   shrinks first (down to the gutter), then their text gets narrower and wraps */
.topic {
  display: flex;
  align-items: center;
  min-width: 0;
  gap: 4px;
  font-weight: 500;
  font-size: 23px;
  line-height: 19px;
  letter-spacing: -0.02em;
}

.topic__text {
  flex: 0 1 330px;
  min-width: 0;
}

.topic--end {
  text-align: right;
}

/* When the two topics can't have the same number of lines side by side (JS), they stack
   as on phones: the second tucked 20px up and pushed to the right */
.topics.is-stacked {
  flex-direction: column;
  align-items: stretch;
  gap: 0;
}

.topics.is-stacked .topic--end {
  justify-content: flex-end;
  margin-top: -20px;
}

/* The black "!" capsules are Monofett's [ and ] */
.bracket {
  padding-bottom: 6px;
  font-family: var(--font-monofett);
  font-size: 54px;
  line-height: 54px;
}

.callout {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 81px;
  padding: 10px;
  border: 2px solid var(--color-text);
  text-align: center;
}

.callout__text {
  width: 363px;
}

.experiments__list li {
  /* Rows sit 20px apart in Figma; the = rules hang a little below */
  height: 20px;
}

.experiments__list li:last-child {
  height: 21px;
}

.experiments__list li > span:not(.rule) {
  font-size: 20px;
  line-height: 20px;
}

/* Each word steps a little further right, as in Figma */
.experiments__list li:nth-child(1) .rule:first-child { flex-grow: 0.42; }
.experiments__list li:nth-child(2) .rule:first-child { flex-grow: 0.5; }
.experiments__list li:nth-child(3) .rule:first-child { flex-grow: 0.6; }
.experiments__list li:nth-child(4) .rule:first-child { flex-grow: 0.7; }

.plus-row {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-alpha54);
  font-size: 20px;
  line-height: 20px;
}

.result__row {
  align-items: center;
  gap: 7px;
  margin-top: -2px;
}

.result__dish {
  font-size: 20px;
  line-height: 20px;
}

/* Order stickers (Figma SVGs: Today sale, Order now!!!, GO), centred,
   the stack's 80px gap above and below.
   The box is the sticker's Figma group; the SVG's outlines spill past it a little, so
   the art is placed by its offset from the group, in % so it scales on narrow phones. */
.order {
  --w: 267.095;
  --h: 147.968;
  --art-x: 0;
  --art-y: 0;
  --art-w: var(--w);
  --art-h: var(--h);
  position: relative;
  align-self: center;
  width: min(calc(var(--w) * 1px), 100%);
  aspect-ratio: var(--w) / var(--h);
}

.order__art {
  position: absolute;
  left: calc(var(--art-x) / var(--w) * 100%);
  top: calc(var(--art-y) / var(--h) * 100%);
  width: calc(var(--art-w) / var(--w) * 100%);
  height: calc(var(--art-h) / var(--h) * 100%);
  max-width: none;
}

/* Order now!!! and Today sale: the burst's art (Figma 450:2204 / 450:2326), fitted into
   the page sticker's box and centred (the SVG keeps its own proportions) */
.order--order-now {
  --w: 329.891;
  --h: 179.939;
}

.order--today-sale {
  --w: 304.888;
  --h: 166;
}

/* F-U-C-K U! on pink diamonds (Figma 470:985), right after the dates */
.order--fuck-u {
  --w: 189.855;
  --h: 139.692;
}

.order--go {
  --w: 276.005;
  --h: 160.527;
  --art-w: 276;
  --art-h: 161;
}

/* Week sections */
.week {
  display: flex;
  flex-direction: column;
  gap: 27px;
  width: 100%;
}

.week__head {
  display: flex;
  align-items: flex-start;
  /* 40px in Figma: the = rule under the title overflows it by 3px. It grows when a
     narrow screen wraps the title */
  margin-bottom: -3px;
  gap: 4px;
}

.week__bracket {
  width: 24px;
  font-family: var(--font-monofett);
  font-size: 48px;
  line-height: 40px;
  text-align: center;
}

.week__heading {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding-top: 8px;
}

.week__title {
  display: flex;
  justify-content: space-between;
  gap: 6px;
  margin-bottom: -4px;
  font-weight: 500;
  font-size: 23px;
  line-height: 19px;
  letter-spacing: -0.02em;
}

.week__title--center {
  justify-content: center;
}

/* Week titles with two parts: they close up as the row narrows. The second part wraps
   first, set against the right bracket; the first keeps its line until the second can't
   get any narrower (a grid: the first column grows to its full width only out of what
   the second doesn't need for its longest word) */
.week__title:not(.week__title--center) {
  display: grid;
  grid-template-columns: minmax(min-content, max-content) minmax(min-content, 1fr);
}

.week__title span:last-child:not(:first-child) {
  justify-self: end;
  text-align: right;
}

.week__heading .rule {
  font-size: 20px;
  line-height: 20px;
}

.week__days {
  display: flex;
  flex-direction: column;
  gap: 50px;
}

.day {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: center;
}

.day__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  padding: 10px 10px 16px;
  border: 2px solid var(--color-text);
}

.day__name {
  font-family: var(--font-brush-script);
  font-style: italic;
  font-size: 56px;
  line-height: 56px;
  letter-spacing: 0.07em;
}

.day__note {
  line-height: 17px;
}

.day__card .rule {
  flex: none;
  width: 100%;
  margin-top: 4px;
}

.day__title {
  margin-top: 4px;
  font-weight: 500;
  font-size: 46px;
  line-height: 40px;
}

.day__details {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  width: min(488px, 100%);
}

.day__list {
  height: 123px;
  font-size: 20px;
  line-height: 20px;
}

/* Steps are separated by +++ */
.day__steps li:last-child {
  line-height: 14px;
}

.day__steps li + li::before {
  content: "+++";
  display: block;
  margin-bottom: 1px;
  font-family: var(--font-alpha54);
  font-size: 20px;
  line-height: 20px;
}

/* Week 2: giant day letters on black blocks. As the page narrows the blocks shrink with
   the row (236 x 180 at its full 740px) and the text beside them gets narrower and wraps */
.week__days--big {
  container-type: inline-size;
  gap: 36px;
}

.wday {
  --wday-block: min(236px, 31.892cqw);
  display: flex;
  align-items: flex-start;
  gap: 16px;
  /* The text column pokes 6px past the block; the row still counts as the block's height */
  margin-bottom: -6px;
}

.wday__name,
.wday__range span {
  display: block;
  width: var(--wday-block);
  height: calc(var(--wday-block) * 180 / 236);
  background: var(--color-text);
  color: var(--color-bg);
  font-weight: 500;
  font-size: calc(var(--wday-block) * 243 / 236);
  letter-spacing: var(--tracking, -0.07em);
  text-align: center;
  /* A letter pair is a little wider than the box, and CSS start-aligns overflowing
     text instead of centring it: the indent centres it as in Figma */
  padding-right: calc(-1 * var(--tracking, -0.07em));
  text-indent: calc(-0.029em + var(--nudge, 0px));
  /* Fallback without text-box trimming: a line height that puts the caps
     5px from the top of the box, worked out from the font's ascent/descent */
  line-height: 0.617;
}

/* The single dash fits, so it centres by itself */
.wday__range span:nth-child(2) {
  text-indent: 0;
}

/* Like Figma: trim the line to cap height, then centre it in the 180px box */
@supports (text-box: trim-both cap alphabetic) {
  .wday__name,
  .wday__range span {
    padding-top: 5px;
    line-height: normal;
    text-box: trim-both cap alphabetic;
  }
}

/* As tall as the block beside it, plus the 6px the dashed rule hangs below it (Figma:
   186 next to 180); the note sits at the top, the title at the bottom, with whatever
   space is left between them. When the text doesn't fit, JS drops the note's +++
   (.is-tight), and if that's still not enough lets the column grow (.is-tall) */
.wday__body {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  flex: 0 1 488px;
  min-width: 0;
  height: calc(var(--wday-block) * 180 / 236 + 6px);
}

.wday__body.is-tight .wday__note::before {
  display: none;
}

.wday__body.is-tall {
  height: auto;
  min-height: calc(var(--wday-block) * 180 / 236 + 6px);
}

.wday__note {
  max-width: 362px;
  line-height: 17px;
}

.wday__note::before {
  content: "+++";
  display: block;
  margin-bottom: 2px;
  font-family: var(--font-alpha54);
  font-size: 20px;
  line-height: 20px;
}

/* Title (and optional subtitle) above a dashed rule */
.wday__end::after,
.wday__below::after {
  content: "-------------------------------------------------------------";
  display: block;
  font-family: var(--font-alpha54);
  font-size: 20px;
  line-height: 20px;
  white-space: nowrap;
  overflow: hidden;
}

/* 46px until the row gets narrower than ~575px, then smaller, so the longest words
   still fit beside the shrinking blocks */
.wday__title {
  max-width: 362px;
  font-weight: 500;
  font-size: clamp(30px, 8cqw, 46px);
  line-height: calc(1em * 40 / 46);
}

.wday__title--wide {
  max-width: none;
}

.wday__sub {
  margin-top: 10px;
  font-size: 14px;
  line-height: 14px;
}

/* вт - чт: one black bar, then the details underneath */
.wday--span {
  flex-direction: column;
  align-items: stretch;
  margin-bottom: 0;
}

.wday__range {
  display: flex;
  gap: min(16px, 2.162cqw);
  background: var(--color-text);
}

.wday__below {
  display: flex;
  flex-wrap: wrap;
  column-gap: 18px;
}

/* The dashed rule runs under the whole вт - чт row */
.wday__below::after {
  content: "----------------------------------------------------------------------------------------------";
  flex-basis: calc(100% + 2px);
  margin-inline: -1px;
}

.wday__below .wday__note {
  width: 235px;
  max-width: 100%;
}

/* Beside the note while the title and drawing fit there (about 420px), else under it */
.wday__wide {
  flex: 1 1 420px;
  height: 80px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.wday__art {
  height: 80px;
  width: auto;
}

.wday-chill {
  height: 30px;
  align-items: center;
  font-size: 20px;
  line-height: 20px;
}

.wday-chill .rule {
  font-size: 20px;
  line-height: 20px;
}

/* By who: two outlined cards, one per studio, side by side; once either can't fit its
   longest word, they wrap into one column */
.crew {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.crew__card {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 20px 16px;
  border: 2px solid currentColor;
  text-align: center;
}

.crew__card--shoplift {
  color: var(--color-orange);
}

.crew__card--kaik {
  color: var(--color-pink);
}

.crew__about {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.crew__name {
  font-weight: 400;
  font-size: 72px;
  line-height: 70px;
}

.crew__card--shoplift .crew__name {
  font-family: var(--font-berolina);
}

.crew__card--kaik .crew__name {
  font-family: var(--font-altenglisch);
  text-transform: none;
}

.crew__name::after {
  content: "+++";
  display: block;
  margin-top: 2px;
  font-family: var(--font-alpha54);
  font-size: 20px;
  line-height: 20px;
}

.crew__link {
  color: inherit;
  font-size: 46px;
  line-height: 40px;
  text-decoration: none;
}

/* Buy: big ORDER NOW, buy link + QR, ask button, stacked with no gaps (Figma) */
.buy {
  display: flex;
  flex-direction: column;
  width: 100%;
}

/* Big ORDER NOW: a black banner with stars and the 130 € burst, one Figma SVG.
   60px of room above it. The box is Figma's 270px-tall slot; the art starts 39.5px above
   the slot and its burst hangs 88px down over the buy row, as in Figma. The art lets
   clicks through, so the buy link under the burst still works */
.buy__top {
  padding-top: 60px;
}

.big-order {
  position: relative;
  z-index: 1;
  width: 100%;
  aspect-ratio: 740 / 270;
}

.big-order__art {
  position: absolute;
  top: calc(-39.479 / 270 * 100%);
  left: 0;
  width: calc(742 / 740 * 100%);
  height: auto;
  max-width: none;
  pointer-events: none;
}

.big-order__art--phone {
  display: none;
}

/* The buy link and the QR split the row and stay square as it narrows; the label gets
   smaller once the row is under ~430px, so it still fits its half */
.buy__pay {
  container-type: inline-size;
  display: flex;
}

.buy__qr {
  flex: 1;
  overflow: hidden;
}

/* The QR art is cropped by 8% on every side, as in Figma */
.buy__qr img {
  width: 116.33%;
  max-width: none;
  margin: -8.16%;
  image-rendering: pixelated;
}

.buy__link {
  flex: 1;
  min-width: 0;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-text);
  color: var(--color-bg);
  font-size: min(46px, 10.5cqw);
  line-height: 40px;
  text-decoration: none;
}

/* Ask button */
.ask {
  display: grid;
  place-items: center;
  height: 200px;
  border: 2px solid var(--color-text);
  color: var(--color-text);
  font-size: 46px;
  line-height: 40px;
  text-align: center;
  text-decoration: none;
}

/* Buttons swap their text (Figma hover state): >инстик< to ❀❀❀ / ✰✰✰, >купить< to the
   €(130)€ tag, >задать вопрос< to ✎﹏﹏﹏﹏. Both texts sit in the same grid
   cell, so the button keeps its size. With a mouse: on hover. With a keyboard: on focus.
   On phones (no hover): while the button has focus or is pressed */
.swap {
  display: inline-grid;
  place-items: center;
}

.swap > span {
  grid-area: 1 / 1;
}

.swap__alt {
  visibility: hidden;
  white-space: nowrap;
}

/* ❀❀❀, ✰✰✰ and ✎﹏﹏﹏﹏ are Figma's own drawing of the glyphs (the site font has none, and each
   browser would borrow them from a different font). Placed where Figma's text box puts
   their ink: a few px below the middle of the 40px line */
.swap__glyph {
  display: block;
  position: relative;
  max-width: none;
}

.swap__glyph--flowers {
  width: 121px;
  height: 36px;
  top: 3.4px;
}

.swap__glyph--stars {
  width: 122px;
  height: 34px;
  top: 2.8px;
}

.swap__glyph--pencil {
  width: 229px;
  height: 35px;
  top: 6.5px;
  left: 1.5px;
}

a:focus-visible .swap__label {
  visibility: hidden;
}

a:focus-visible .swap__alt {
  visibility: visible;
}

@media (hover: hover) {
  a:hover .swap__label {
    visibility: hidden;
  }

  a:hover .swap__alt {
    visibility: visible;
  }
}

@media (hover: none) {
  a:is(:focus, :active) .swap__label {
    visibility: hidden;
  }

  a:is(:focus, :active) .swap__alt {
    visibility: visible;
  }
}

/* 3. Shopping bag (Figma "paket", 149 x 187): fixed one gutter right of the main
   content (columns 4-9) and 24px above the bottom of the screen. In a fixed element 100%
   is the viewport width without the scrollbar, the same width the page grid uses. */
.bag {
  --column: calc((100% - 2 * var(--margin) - 11 * var(--gutter)) / 12);

  position: fixed;
  left: calc(var(--margin) + 9 * (var(--column) + var(--gutter)));
  bottom: 24px;
  z-index: 10;
  width: 149px;
  height: 187px;
}

/* The poster sticks out of the bag's top, behind it. On hover it grows up and to the
   left and spins half a turn onto its back face, which carries the same image, so it
   lands the right way round. Timing from the Figma prototype (Smart Animate, Quick, 620ms). */
.bag__poster {
  position: absolute;
  top: 0;
  left: 2px;
  width: 106px;
  height: 141px;
  transform-style: preserve-3d;
  transform: perspective(1200px) rotateY(0deg);
  transition-property: top, left, width, height, transform;
  transition-duration: 0.62s;
  transition-timing-function: var(--poster-ease);
}

.bag__poster-face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  border: 2px solid var(--color-text);
  backface-visibility: hidden;
}

.bag__poster-face--back {
  transform: rotateY(180deg);
}

.bag.is-open .bag__poster {
  /* A bit bigger than in Figma (471 x 628), keeping the same bottom edge and centre */
  top: -654px;
  left: -195.5px;
  width: 500px;
  height: 667px;
  transform: perspective(1200px) rotateY(180deg);
}

/* No growing or flipping for people who turned animations off */
@media (prefers-reduced-motion: reduce) {
  .bag__poster {
    transition-duration: 0.01s;
  }

  .bag.is-open .bag__poster {
    transform: none;
  }

  .bag__burst {
    transition: none;
  }

  .bag.is-open .bag__body,
  .bag.is-open .bag__sale,
  .bag.is-open .bag__burst {
    animation: none;
  }

  .title__letter:hover {
    translate: none;
  }

  .title__letter:hover > .title__plain,
  .title__letter:hover .title__card {
    transition-delay: 0s;
  }
}

.bag__body {
  position: absolute;
  top: 26px;
  left: 0;
  width: 110px;
  height: 161px;
}

.bag__sale {
  position: absolute;
  top: 26px;
  left: 122px;
}

.bag__sale li {
  display: grid;
  place-items: center;
  width: 27px;
  height: 27px;
  /* Lifts the lowercase letters so their ink sits in the middle of the circle */
  padding-bottom: 5.75px;
  border-radius: 20px;
  background: var(--color-text);
  color: var(--color-bg);
  font-family: var(--font-pressura-mono);
  font-weight: 400;
  font-size: 18px;
  line-height: 16px;
}

/* The moment the bag is hovered it hops: up and straight back down in 200ms */
.bag.is-open .bag__body,
.bag.is-open .bag__sale,
.bag.is-open .bag__burst {
  animation: bag-hop 200ms cubic-bezier(0.3, 0, 0.3, 1);
}

@keyframes bag-hop {
  40% { translate: 0 -8px; }
}

/* a and l are a touch off-centre sideways, and the tall l needs less lift */
.bag__sale li:nth-child(2) { padding-left: 0.4px; }
.bag__sale li:nth-child(3) { padding-bottom: 1.9px; padding-right: 0.6px; }

/* !!!(€) on a starburst at the bag's bottom edge */
.bag__burst {
  position: absolute;
  top: 159px;
  left: 81px;
  display: flex;
  align-items: flex-start;
  color: var(--color-bg);
  font-family: var(--font-arial-narrow);
  font-style: italic;
  line-height: 0.77;
  letter-spacing: -0.43px;
  text-transform: none;
  /* Same spring and timing as the poster, so they move together */
  transition: scale 0.62s var(--spring-ease), rotate 0.62s var(--spring-ease);
}

/* The badge springs up a little and turns 5deg while the bag is hovered */
.bag.is-open .bag__burst {
  scale: 1.28;
  rotate: 5deg;
}

.bag__burst-shape {
  position: absolute;
  top: calc(50% - 0.57px);
  left: calc(50% + 1.34px); /* the star centred under the text, with the space before (€) */
  width: 88px;
  height: 71px;
  max-width: none;
  transform: translate(-50%, -50%) rotate(-23.87deg);
}

.bag__burst-big,
.bag__burst-small {
  position: relative;
}

.bag__burst-big {
  font-size: 32px;
}

.bag__burst-small {
  font-size: 14px;
}

/* Phones: the bag sits in the middle of the screen's bottom edge, 130px wide (Figma frame
   "iPhone 13 & 14 - 2"), its top 116.74px above the bottom of the screen and the rest
   hidden below it. Its parts are set at that size (scaling the bag instead blurs it in
   Safari); it opens on tap. The poster grows to the screen width (less the margins, and
   short enough to fit above the bag), centred on the screen, its bottom edge 27px above
   the bag. The black ending slides over the bag: the part below its top edge is cut
   away (--bag-cut, set in JS) */
@media (max-width: 770px) {
  .bag {
    --bag-peek: 116.74px;   /* how much of the bag shows above the bottom of the screen */
    --poster-gap: 27px;     /* open poster's bottom edge -> the bag's top */
    /* Open poster width; on short screens no taller than fits above the bag up to 8px
       below the top of the screen */
    --poster-w: min(100vw - 2 * var(--margin), (100dvh - var(--bag-peek) - var(--poster-gap) - 8px) * 0.75);

    left: calc(50% - 130px / 2);
    bottom: calc(var(--bag-peek) - 221px);
    width: 130px;
    height: 221px;
    clip-path: inset(-100vh -100vw var(--bag-cut, -100vh) -100vw);
  }

  .bag__poster {
    left: 2.364px;
    width: 125.568px;
    height: 167.424px;
  }

  .bag__body {
    top: 30.727px;
    width: 130px;
    height: 190.273px;
  }

  .bag__sale {
    display: none;
  }

  .bag__burst {
    top: 187.909px;
    left: 95.727px;
    letter-spacing: -0.508px;
  }

  .bag__burst-shape {
    top: calc(50% - 0.674px);
    left: calc(50% + 1.584px);
    width: 104px;
    height: 83.909px;
  }

  .bag__burst-big {
    font-size: 37.818px;
  }

  .bag__burst-small {
    font-size: 16.545px;
  }

  .bag.is-open .bag__poster {
    top: calc(0px - var(--poster-gap) - var(--poster-w) * 4 / 3);
    left: calc((130px - var(--poster-w)) / 2);
    width: var(--poster-w);
    height: calc(var(--poster-w) * 4 / 3);
  }

  /* The rest of the phone layout (Figma frame "iPhone 13 & 14", 390px): everything
     spans the full width and stacks; vertical spacing stays as on desktop */
  .title,
  .workshop,
  .stack {
    grid-column: 1 / -1;
  }

  /* Spacing from the mobile frame (390px, y from under its 59px status bar, which the
     browser draws itself): the white sheet from y 16, title box from y 48, the strip's
     rules at y 166 and 201, content from y 293 */
  :root {
    --hero-top: 32px;
    --hero-gap: 15.4px;
    --content-top: 71.7px;
  }

  /* The page is a white sheet on the black canvas, torn into a zigzag along the top */
  /* The zigzag sits inside the sheet's top 11.1px, left unpainted so the black shows
     between the teeth: Safari's overflow-x: clip cuts the top too, so it can't hang above */
  .page {
    position: relative;
    margin-top: 4.9px;
    padding-top: 11.1px;
    background: linear-gradient(var(--color-bg), var(--color-bg)) 0 11.1px / 100% 100% no-repeat;
  }

  .page::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 11.1px;
    background: url("../assets/images/zigzag.svg?v=20261108-1") 0 0 / 100% 100%;
  }

  /* SALAD: the letters are bigger and shuffled from the desktop places, each with an
     8px white outline, stacked s, A, L, a, d, tomato from back to front.
     Each letter SVG moves and scales around its letter's old top-left corner; the
     percentages are of the title box (374 x 102.6 at 390px), so it all scales together */
  .title__word {
    transform-origin: var(--ox) var(--oy);
    transform: translate(var(--dx), var(--dy)) scale(1.10444);
  }

  .title__word:nth-child(1) { --ox: 0%; --oy: 10.431%; --dx: 0%; --dy: 2.423%; z-index: 1; }
  .title__word:nth-child(2) { --ox: 14.555%; --oy: 13.87%; --dx: -0.652%; --dy: 6.197%; z-index: 5; }
  .title__word:nth-child(3) { --ox: 33.154%; --oy: 6.01%; --dx: -0.957%; --dy: 1.916%; z-index: 4; }
  .title__word:nth-child(4) { --ox: 56.739%; --oy: -14.133%; --dx: -0.394%; --dy: 1.319%; z-index: 3; }
  .title__word:nth-child(5) { --ox: 75.337%; --oy: 8.466%; --dx: -1.506%; --dy: 5.531%; z-index: 6; }

  /* Stronger than the per-letter order above, so the hovered letter comes to the front */
  .title .title__word:hover,
  .title .title__word.is-lit {
    z-index: 10;
  }

  /* 8px on screen, outside the letter (the SVG units are scaled down to ~0.56) */
  .title__plain {
    stroke: var(--color-bg);
    stroke-width: 28.66px;
    stroke-linejoin: round;
    paint-order: stroke;
  }

  /* Above every letter, even a lit one (10) */
  .title__tomato {
    display: block;
    position: absolute;
    max-width: none;
    height: auto;
    pointer-events: none;
    z-index: 11;
    left: 79.718%;
    top: 83.826%;
    width: 16.548%;
  }

  /* Strip: rules 35px apart, the label 19px under the first */
  .workshop__label {
    margin-block: -0.66px -7px;
  }

  /* The split title starts against the [ like the week titles (centred only on desktop) */
  .olive .week__title {
    text-align: left;
  }

  /* Dates: no star columns, so the numbers grow to fill the row (the rest of it is 600px
     wide in Figma): the row keeps its desktop proportions (740) with the empty star
     margins hanging 70 off each side. The /11 and /12 stay readable */
  .dates {
    --u: min(1px, 100cqw / 600);
    width: calc(740 * var(--u));
    margin-inline: calc(-70 * var(--u));
    align-self: center;
  }

  .dates__stars {
    display: none;
  }

  .dates__month {
    font-size: max(14px, calc(23 * var(--u)));
  }

  /* Callout -> "экспериментируем с" */
  .intro {
    gap: 50px;
  }

  /* Topics -> callout */
  .callout {
    margin-top: -8px;
  }

  /* The two topic lines stack, the second tucked 20px up and pushed to the right edge */
  .topics {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }

  /* Full width with its content pushed right (Safari sizes a shrunk line by its text's
     full one-line width, so moving the line itself doesn't reach the edge there) */
  .topic--end {
    justify-content: flex-end;
    margin-top: -20px;
  }

  .callout__text {
    width: auto;
  }

  /* The words sit further right than on desktop and almost touch the rules:
     the left rule's share of the row is taken from the mobile frame (of 374px) */
  .experiments__list li {
    gap: 2px;
  }

  .experiments__list li:nth-child(1) .rule:first-child { flex: none; width: 44.4%; }
  .experiments__list li:nth-child(2) .rule:first-child { flex: none; width: 48.8%; }
  .experiments__list li:nth-child(3) .rule:first-child { flex: none; width: 54.15%; }
  .experiments__list li:nth-child(4) .rule:first-child { flex: none; width: 58.15%; }

  /* "разрозненных ингредиентов" gets its own line, the rule and dish go below */
  .result__row {
    flex-wrap: wrap;
    row-gap: 0;
    margin-top: 0;
  }

  .result__row > span:first-child {
    flex-basis: 100%;
  }

  /* As close to what follows as the topics are to the callout: 19px from the lowest ink
     to the content (the week titles' grid and the by-who rule leave room under the text) */
  .week__head {
    margin-bottom: -11px;
  }

  .week__head--split {
    margin-bottom: -19px;
  }

  .week__title--center {
    align-items: center;
  }

  /* Week titles, set like the topics at the top: "[ first part" on one line, then
     "the rest ]" right-aligned on the next, its 60px row starting 24px lower, no rule.
     The brackets and both parts sit straight in a grid (the wrappers step aside) */
  .week__head--split {
    display: grid;
    grid-template-columns: 27px 1fr 27px;
    grid-template-rows: 24px 36px 24px;
    gap: 0 4px;
    align-items: center;
  }

  .week__head--split .week__heading,
  .week__head--split .week__title {
    display: contents;
  }

  .week__head--split .rule {
    display: none;
  }

  .week__head--split .week__bracket {
    width: auto;
    padding-bottom: 6px;
    font-size: 54px;
    line-height: 54px;
  }

  .week__head--split .week__bracket:first-child {
    grid-area: 1 / 1 / 3 / 2;
  }

  .week__head--split .week__bracket:last-child {
    grid-area: 2 / 3 / 4 / 4;
  }

  .week__title span:first-child {
    grid-area: 1 / 2 / 3 / 4;
  }

  .week__title span:last-child {
    grid-area: 2 / 1 / 4 / 3;
    justify-self: end;
    max-width: 330px;
    text-align: right;
  }

  /* A title that wraps onto two lines starts 10px lower, clear of the first part */
  .week__head--tall {
    grid-template-rows: 24px 36px 34px;
  }

  .week__head--tall .week__bracket:last-child,
  .week__head--tall .week__title span:last-child {
    margin-top: 10px;
  }

  .day__details {
    width: 100%;
  }

  /* Week 2: the day blocks shrink to 82px and sit beside the text, 6px shorter than it
     (as on desktop); the dashed rule runs under the text only */
  .wday {
    align-items: stretch;
    margin-bottom: 0;
  }

  /* Each day's letters start where Figma puts them (--m-x from the block's left edge),
     with its own tracking (--m-tracking), both set on the element in index.html */
  .wday__name,
  .wday__range span {
    width: 82px;
    height: auto;
    padding-right: 0;
    font-size: 81px;
    letter-spacing: var(--m-tracking, -0.07em);
    text-align: left;
    text-indent: var(--m-x, 0px);
  }

  /* The dash sits centred */
  .wday__range span:nth-child(2) {
    text-align: center;
  }

  .wday__name {
    flex-shrink: 0;
    margin-bottom: 6px;
  }

  @supports (text-box: trim-both cap alphabetic) {
    .wday__name {
      padding-top: 4px;
    }

    .wday__range span {
      padding-top: 0;
    }
  }

  .wday__body {
    flex: 1;
    min-width: 0;
    height: auto;
    min-height: 157px;
    gap: 18px;
  }

  .wday__below .wday__note {
    width: auto;
  }

  .wday__sub {
    margin-top: 6px;
  }

  .wday__title {
    font-size: 41px;
    line-height: 40px;
    overflow-wrap: anywhere;
  }

  /* вт - чт: the letters stack in one black column, the details beside it */
  .wday--span {
    flex-direction: row;
    gap: 16px;
  }

  .wday__range {
    flex-direction: column;
    flex-shrink: 0;
    gap: 3.475px;
    width: 82px;
    margin-bottom: 7px;
    padding: 4px 0;
  }

  .wday__range span:nth-child(2) {
    height: 69px;
  }

  .wday__below {
    flex: 1;
    min-width: 0;
    flex-direction: column;
    flex-wrap: nowrap;
  }

  /* Long enough to reach the right edge on wide phones and small tablets too */
  .wday__end::after,
  .wday__below::after {
    content: "------------------------------------------------------------------------------------------------------------------------------------------------------";
  }

  .wday__below::after {
    flex-basis: auto;
    margin-inline: 0;
  }

  /* The title drops to the bottom, onto the dashed rule */
  .wday__wide {
    flex: none;
    height: auto;
    margin-top: auto;
    padding-top: 18px;
  }

  .wday__art {
    display: none;
  }

  .crew {
    flex-direction: column;
  }

  /* Phone big ORDER NOW: its own SVG (two lines, the burst under NOW), sitting right on
     the buy button. Its top is as far below "by who" as on desktop (100.5px); the art
     reaches 4.7px past the left edge and 5.3px past the right, as in Figma */
  .buy__top {
    padding-top: 20.5px;
  }

  .big-order {
    width: calc(384 / 374 * 100%);
    margin-left: calc(-4.659 / 374 * 100%);
    aspect-ratio: 384 / 228;
  }

  .big-order__art--desk {
    display: none;
  }

  .big-order__art--phone {
    position: static;
    display: block;
    width: 100%;
  }

  /* Buy: the buy button and ask button stack as squares */
  .buy__pay {
    flex-direction: column;
  }

  .buy__link,
  .ask {
    flex: none;
    aspect-ratio: 1;
  }

  .buy__link {
    font-size: 46px;
  }

  /* No QR on phones: the ask button sits right under the buy button */
  .buy__qr {
    display: none;
  }

  .ask {
    height: auto;
    padding: 20px;
  }
}

/* 4. Full-screen black ending: edge to edge, exactly one screen tall on every device */
.blackout {
  width: 100%;
  height: 100vh;   /* fallback for older browsers */
  height: 100dvh;  /* follows the visible screen on phones as the browser bars show and hide */
  /* Transparent: the black layer behind the page (body::before) shows through */
}

/* Sticker burst (built by js/script.js): stickers over the whole screen, above the bag
   (17 on desktop, 9 on phones).
   Hidden, each one sits shrunk and turned inside the hovered sticker (--dx/--dy); shown,
   it springs out to its Figma spot one after another (--i). Going back is the same
   spring, in reverse order (the last one out goes back first), each fading only as it
   lands in the sticker. The hovered sticker stays on top of the pile */
.burst {
  position: fixed;
  inset: 0;
  z-index: 20;
  pointer-events: none;
}

.burst__item {
  position: absolute;
  opacity: 0;
  transform: translate(var(--dx, 0), var(--dy, 0)) scale(0.15) rotate(var(--turn, 0deg));
  --back: calc((var(--last) - var(--i)) * 22ms);
  transition:
    transform 0.45s var(--spring-ease) var(--back),
    opacity 0.12s linear calc(var(--back) + 0.29s);
}

.burst__item > * {
  display: block;
  width: 100%;
  height: 100%;
}

.burst.is-on .burst__item {
  opacity: 1;
  transform: none;
  transition:
    transform 0.45s var(--spring-ease) calc(var(--i) * 22ms),
    opacity 0.12s linear calc(var(--i) * 22ms);
}

.order.is-bursting {
  z-index: 21;
}

@media (prefers-reduced-motion: reduce) {
  .burst__item,
  .burst.is-on .burst__item {
    transform: none;
    transition: opacity 0.2s linear;
  }
}

/* Typing intro (from the typing-intro branch): on load the workshop strip and intro text
   type themselves in, letter by letter in a loose, shuffled order (js/script.js splits
   the text into .type-char). .is-typing is set in the <head> */
.is-typing .workshop,
.is-typing .olive,
.is-typing .intro {
  visibility: hidden;
}

.type-char {
  opacity: 0;
  /* shows up at its moment, in its colour (--tint) for 200ms (TYPE_TINT_MS), then the
     tint animation ends and the letter takes the text colour */
  animation:
    type-in 1ms linear var(--delay) forwards,
    type-tint 200ms steps(1) var(--delay);
}

@keyframes type-tint {
  from, to { color: var(--tint); }
}

/* The = rules are drawn by CSS, so they type left to right in steps instead, starting
   80% drawn, like the letters that are already there */
.is-typing-run .workshop .rule,
.is-typing-run .olive .rule,
.is-typing-run .intro .rule {
  animation: rule-type 0.3s steps(4) var(--delay, 0s) both;
}

@keyframes type-in {
  to { opacity: 1; }
}

@keyframes rule-type {
  from { clip-path: inset(0 20% 0 0); }
  to   { clip-path: inset(0); }
}


/* Idle stickers (js/script.js): the pile that lands while nobody touches the page, over
   the content and the bag, under the sticker burst. Each pops in with the spring; at the
   first touch they all fall off the bottom of the screen, speeding up like a drop, each
   with its own delay, time and spin (--fall-delay / --fall-ms / --fall-turn) */
.idle-stickers {
  position: fixed;
  inset: 0;
  z-index: 19;
  overflow: hidden;
  pointer-events: none;
}

.idle-sticker {
  position: absolute;
  max-width: none;
  height: auto;
  translate: -50% -50%;
  rotate: var(--turn);
  animation: idle-pop 0.35s var(--spring-ease) both;
}

@keyframes idle-pop {
  from {
    opacity: 0;
    scale: 0.4;
  }
}

.idle-stickers.is-leaving .idle-sticker {
  animation: idle-fall var(--fall-ms, 700ms) cubic-bezier(0.55, 0, 1, 0.45) var(--fall-delay, 0ms) forwards;
}

@keyframes idle-fall {
  to {
    translate: -50% calc(-50% + 120vh);
    rotate: calc(var(--turn) + var(--fall-turn, 0deg));
  }
}

@media (prefers-reduced-motion: reduce) {
  .idle-sticker,
  .idle-stickers.is-leaving .idle-sticker {
    animation: none;
  }

  .idle-stickers.is-leaving {
    opacity: 0;
  }
}
