/* Home page. Builds on site.css. The page is one colour at a time: home.js sets data-theme on the html element to
   the panel that covers the most of the screen, and the page, the bar and every line on it crossfade to that
   panel's colours over .7s. The panels themselves are clear. */

/* For the design lead to tune without a rebuild. A panel is one screen tall up to --panel-floor; on a taller
   window it takes --panel-share of the window, up to --panel-cap; a panel still grows to fit its content.
   --panel-pad is the least air above and below the content, --panel-gap extra air between two sections (half in
   each, written with a unit: 0px), --morph how long the page takes to change colour. */
:root {
  --panel-floor: 880px;
  --panel-share: .62;
  --panel-cap: 1240px;
  --panel-pad: clamp(72px, 10vh, 120px);
  --panel-gap: 0px;
  --morph: .7s;
}

html {
  --bg: #f0eee9;
  --fg: #141413;
  --soft: #56544d;
  --hair: #d6d0c1;
  --dot: #2440f0;
  --thread: #ff5b2e;
  --btn-bg: #141413;
  --btn-fg: #f0eee9;
}

html[data-theme="blue"] {
  --bg: #2440f0;
  --fg: #f0eee9;
  --soft: #c9d1ff;
  --hair: rgba(240, 238, 233, .3);
  --dot: #f0eee9;
  --thread: #ff5b2e;
  --btn-bg: #f0eee9;
  --btn-fg: #141413;
}

html[data-theme="ink"] {
  --bg: #141413;
  --fg: #f0eee9;
  --soft: #a9a79f;
  --hair: rgba(240, 238, 233, .22);
  --dot: #ff5b2e;
  --thread: #ff5b2e;
  --btn-bg: #f0eee9;
  --btn-fg: #141413;
}

html[data-theme="hot"] {
  --bg: #ff5b2e;
  --fg: #141413;
  --soft: #4d1c0d;
  --hair: rgba(20, 20, 19, .32);
  --dot: #141413;
  --thread: #141413;
  --btn-bg: #141413;
  --btn-fg: #f0eee9;
}

/* the page colour; everything that reads a colour above changes with it, over the same --morph */
html {
  background-color: var(--bg);
  transition: background-color var(--morph) ease;
}

body.home {
  color: var(--fg);
  transition: color var(--morph) ease;
}

/* the red thread: grows as the page is read, in the thread colour of the page */

.thread {
  position: fixed;
  z-index: 4;
  top: 0;
  bottom: 0;
  left: max(10px, calc((100vw - 1296px) / 2 - 34px));
  width: 2px;
  pointer-events: none;
}

.thread i {
  position: relative;
  display: block;
  height: calc(var(--scroll, 0) * 100%);
  background-color: var(--thread);
  transition: background-color var(--morph) ease;
}

.thread i::after {
  content: "";
  position: absolute;
  left: -3px;
  bottom: -4px;
  width: 8px;
  height: 8px;
  background-color: var(--thread);
  transition: background-color var(--morph) ease;
}

/* header: the bar is the page colour, so it never shows as a band of its own */

.bar {
  position: sticky;
  z-index: 5;
  top: 0;
  background-color: var(--bg);
  transition: background-color var(--morph) ease;
}

/* a link or a focus move to a panel puts its top edge right under the bar: the bar's own height */
html { scroll-padding-top: 70px; }

.home .top { padding: 20px 0; }

.home .brand svg {
  fill: var(--fg);
  transition: fill var(--morph) ease, transform .2s ease;
}

/* Hover only where a real pointer hovers: a touch browser keeps :hover at the last tap, so whatever was tapped
   would stay lit until the next tap elsewhere (UX director, 30 Sep 2026). A tap gets :active, which lasts only while
   the finger is down, and the keyboard keeps :focus-visible. :is() lists those two together without losing :active
   in Safari before 15.4, which does not know :focus-visible and would drop a plain list that names it. */
.home .brand:is(:focus-visible, :active) svg { transform: translateY(-2px); }

@media (hover: hover) and (pointer: fine) {
  .home .brand:hover svg { transform: translateY(-2px); }
}

/* the underline grows from the left and leaves to the right */
.home .top nav a,
.home .foot-row a {
  background-position: 100% 100%;
  transition: background-size .2s ease;
}

.home .top nav a:is(:focus-visible, :active, [aria-current="true"]),
.home .foot-row a:is(:focus-visible, :active) {
  background-position: 0 100%;
  background-size: 100% 1.5px;
}

@media (hover: hover) and (pointer: fine) {
  .home .top nav a:hover,
  .home .foot-row a:hover {
    background-position: 0 100%;
    background-size: 100% 1.5px;
  }
}

.home .top nav { gap: clamp(14px, 2.2vw, 28px); }

.home .langbtn {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--hair);
  color: var(--fg);
}

.home .langbtn:active {
  background: var(--fg);
  box-shadow: inset 0 0 0 1.5px var(--fg);
  color: var(--bg);
}

@media (hover: hover) and (pointer: fine) {
  .home .langbtn:hover {
    background: var(--fg);
    box-shadow: inset 0 0 0 1.5px var(--fg);
    color: var(--bg);
  }
}

/* panels: one screen tall on a laptop and a phone, 62% of a taller window up to 1240px, content in the middle */

.panel {
  position: relative;
  display: grid;
  align-items: center;
  min-height: calc(min(100vh, clamp(var(--panel-floor), var(--panel-share) * 100vh, var(--panel-cap))) + var(--panel-gap));
  padding: calc(var(--panel-pad) + var(--panel-gap) / 2) 0;
  /* clip, not a scroll box: the orbs overflow the panel, and a hidden overflow can be scrolled by scrollIntoView,
     find in page or a screen reader, which would leave the content shifted; hidden is the line for Safari 15 */
  overflow: hidden;
  overflow: clip;
  transition: opacity var(--morph) ease;
}

/* the small viewport height where there is one, so a phone's toolbars never cut a panel; in @supports because a
   line with var() in it does not fall back to the line before it */
@supports (height: 100svh) {
  .panel { min-height: calc(min(100svh, clamp(var(--panel-floor), var(--panel-share) * 100svh, var(--panel-cap))) + var(--panel-gap)); }
}

/* The orbs run past a panel's right edge, so a panel clips across. Down the page an orb may run into the next
   panel: only the panel holding the page colour shows its orb, so no orb is cut flat where two panels meet on one
   colour. Safari before 16 has no clip and keeps the cut. */
@supports (overflow: clip) {
  .js .panel { overflow-y: visible; }
}

/* A panel above the one that holds the page colour has been read: it dims as the page changes colour. One with
   the focus in it stays, so a keyboard never lands on a dimmed button. */
@media (prefers-reduced-motion: no-preference) {
  .panel.is-past:not(:focus-within) { opacity: .3; }
}

/* the content rises into place as it comes in from below: home.js sets --fo and --fy from where it is.
   Opacity and transform only. */
.panel > .wrap {
  position: relative;
  z-index: 1;
  opacity: var(--fo, 1);
  transform: translateY(calc(var(--fy, 0) * 1px));
}

.panel-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  padding-bottom: 22px;
  margin-bottom: clamp(32px, 5vh, 56px);
  border-bottom: 1px solid var(--hair);
  transition: border-color var(--morph) ease;
}

.home h2 {
  font-size: clamp(38px, 4.6vw, 62px);
}

.home .label,
.home .meta dt {
  color: var(--soft);
  transition: color var(--morph) ease;
}

/* under everything, straight on the page colour, whichever panel it runs into */
.home .orb {
  z-index: -1;
  fill: var(--dot);
  opacity: .55;
  transform: translateY(calc((var(--p, .5) - .5) * -140px));
  transition: fill var(--morph) ease, opacity var(--morph) ease;
  will-change: transform;
}

.home .orb .back {
  fill: var(--bg);
  transition: fill var(--morph) ease;
}

/* one orb at a time: the others fade out as the page changes colour, and the next one fades in */
.js .panel:not(.is-lead) .orb { opacity: 0; }

/* 1. intro: the statement, the story under it, the drop in the pixel face (docs/reviews/2026-10-01-hero-slogan.md).
   Each tier is one .l2 cell holding both languages in the same face, size, tracking and line height, so a switch
   changes the words and moves nothing. */

.intro { padding-top: clamp(40px, 7vh, 96px); }

/* the statement, the h1: two lines from 521px, broken at the br, three on a phone */
.intro h1 {
  max-width: 14em;
  font-size: clamp(38px, 6.2vw, 96px);
  line-height: 1.1;
  letter-spacing: -.04em;
}

/* the story and the drop, one sentence of body copy */
.intro .story { margin: clamp(22px, 2.6vw, 40px) 0 0; }

.intro .setup {
  max-width: 32em;
  font: 400 clamp(19px, 1.9vw, 28px)/1.5 var(--serif);
  letter-spacing: 0;
}

/* the language with fewer lines sits at the foot of the cell, so the drop follows the story as closely in both */
.intro .setup > [data-l] { align-self: end; }

/* the hero's cells are never wider than the page: Safari sized a cell to an unbroken Chinese run, and both
   languages ran off the screen on an iPhone (Mike, 1 Oct 2026) */
.intro .l2 { grid-template-columns: minmax(0, 1fr); }

/* the Chinese fills each line, as Mike asked of the iPhone; anywhere is the guard before the edge */
.intro .setup > [lang|="zh"] { overflow-wrap: anywhere; }

/* the drop at .56 of the statement's size, the size it had inside the old headline */
.intro .px {
  max-width: 19em;
  margin-top: .4em;
  font: 400 calc(.56 * clamp(38px, 6.2vw, 96px))/1.25 var(--pixel);
  letter-spacing: -.07em;
  color: var(--dot);
  transition: color var(--morph) ease;
}

.intro .px b {
  display: inline-block;
  width: .46em;
  height: .7em;
  margin-left: .16em;
  background-color: var(--thread);
  animation: blink 1.1s steps(1) 3;
  transition: background-color var(--morph) ease;
}

/* beside characters the cursor is narrower and taller, as before */
.intro .px [lang|="zh"] b {
  width: .3em;
  height: .82em;
  margin-left: .14em;
  vertical-align: -.06em;
}

.nb { white-space: nowrap; }

/* a phone: the statement fills each line, no line ended early (Mike, 1 Oct 2026: "why a new line after ERP, so much
   space left"); below 360px wide the type comes down with the screen so the first line still fits */
@media (max-width: 520px) {
  .intro h1 { font-size: min(38px, 10.6vw); }
}

.aside {
  margin: clamp(28px, 4vh, 48px) 0 0;
  font: 400 11px/1 var(--pixel);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--soft);
  transition: color var(--morph) ease;
}

/* the skip link, one line under the title in the .aside look */

.skip a {
  position: relative;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: color .2s ease, text-underline-offset .2s ease;
}

.skip a:is(:focus-visible, :active) {
  color: var(--fg);
  text-underline-offset: 6px;
}

@media (hover: hover) and (pointer: fine) {
  .skip a:hover {
    color: var(--fg);
    text-underline-offset: 6px;
  }
}

/* the tap area reaches 44px and more around the small line */
.skip a::before {
  content: "";
  position: absolute;
  inset: -16px -10px;
}

.orb-intro {
  position: absolute;
  width: min(40vw, 560px);
  right: -11vw;
  bottom: -30vh;
  opacity: .9;
}

/* 2. games */

.orb-games {
  position: absolute;
  width: min(30vw, 420px);
  right: 6vw;
  top: -10vh;
}

.feature {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(32px, 6vw, 96px);
}

.eye {
  position: relative;
  display: block;
  width: 100%;
  padding: 7% 5%;
  border: 0;
  border-radius: 24px;
  background: #2440f0;
  color: inherit;
  font: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.eye-lid {
  display: block;
  transition: transform .25s cubic-bezier(.2, .7, .2, 1);
}

.eye-art {
  display: block;
  width: 100%;
  height: auto;
  clip-path: inset(calc((1 - var(--open, 1)) * 47%) 0);
}

.eye:is(:focus-visible, :active) .eye-lid { transform: scale(1.04); }

@media (hover: hover) and (pointer: fine) {
  .eye:hover .eye-lid { transform: scale(1.04); }
}

.feature-copy h3 {
  margin: 16px 0 14px;
  font-size: clamp(34px, 3.8vw, 54px);
}

.pitch {
  max-width: 22em;
  margin: 0;
  font-size: 22px;
  line-height: 1.4;
}

.feature-copy .meta,
.feature-copy .meta div {
  border-color: var(--hair);
  transition: border-color var(--morph) ease;
}

.feature-copy .meta { margin: 30px 0 34px; }

.home .btn {
  background: var(--btn-bg);
  color: var(--btn-fg);
  transition: background-color .25s ease, color .25s ease;
}

.home .btn:is(:focus-visible, :active) {
  background: #ff5b2e;
  color: #141413;
}

.home .btn:is(:focus-visible, :active) svg { transform: translateX(4px); }

@media (hover: hover) and (pointer: fine) {
  .home .btn:hover {
    background: #ff5b2e;
    color: #141413;
  }
}

/* the next game, one line under the button in the .aside look */

.next {
  max-width: 44em;
  line-height: 1.8;
}

/* 3, 4, 5: a line and a slip */

/* the dots after Coming soon and Building it: still text in the pixel face and the thread colour, the words after
   them on a new line (Mike: "i just want new line and dun want it pull things later") */
.dots {
  font: 400 .62em/1 var(--pixel);
  letter-spacing: 0;
  color: var(--thread);
  transition: color var(--morph) ease;
}

.status {
  max-width: 15em;
  margin: 0;
  font: 700 clamp(38px, 6vw, 92px)/1.02 var(--display);
  letter-spacing: -.04em;
}

/* two lines of characters stand a little apart; the .l2 block keeps the taller language's height */
.status > [lang|="zh"] { line-height: 1.25; }

.slip {
  width: min(340px, 100%);
  margin-top: clamp(36px, 6vh, 64px);
  border: 2px solid #141413;
  background: #f0eee9;
  box-shadow: 8px 8px 0 rgba(0, 0, 0, .3);
  color: #141413;
  font: 400 11px/1.2 var(--pixel);
  letter-spacing: .04em;
  text-transform: uppercase;
}

.slip-bar {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 28px;
  padding: 0 9px;
  background: #141413;
  color: #f0eee9;
}

.slip-bar i {
  width: 10px;
  height: 10px;
  border: 2px solid #f0eee9;
}

.slip-body {
  display: grid;
  gap: 12px;
  padding: 16px 14px;
}

.slip-body p {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
}

.slip-body p > i {
  flex: 1;
  border-bottom: 2px dotted #8a877d;
}

.slip .pips {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 3px;
}

.slip .pips i {
  height: 12px;
  background: #e1dbcc;
}

/* Posts: the Tokens slip and three hot takes side by side, the Tokens slip where it always was; on a phone the takes
   go under it. Three of the Editor's ten on every load (home.js), in the reading face; each take holds both languages
   in one cell, so a switch shows the same three and moves nothing. */
.posts-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 28px 32px;
  margin-top: clamp(36px, 6vh, 64px);
}

.posts-row > .slip { margin-top: 0; }

.slip.takes { width: min(440px, 100%); }

.takes-list {
  display: grid;
  gap: 12px;
  margin: 0;
  padding: 14px 16px 16px;
  list-style: none;
  font: 400 17px/1.45 var(--serif);
  letter-spacing: 0;
  text-transform: none;
}

.takes-list > li + li {
  padding-top: 12px;
  border-top: 2px dotted #8a877d;
}

/* Until the Worker answers, three empty rows hold the slip at the usual height of three takes, so a slow answer
   moves nothing (UX review, docs/reviews/2026-10-01-home-api-ux.md): two lines a take beside the Tokens slip, seven
   lines under it on a phone, eight below 381px (the median of every three of the ten). Without scripts, no slip. */
.takes-list > .take-wait { min-height: calc(2 * 1.45em); }

html:not(.js) .slip.takes { display: none; }

@media (max-width: 520px) {
  .takes-list > .take-wait:first-child { min-height: calc(3 * 1.45em); }
}

@media (max-width: 380px) {
  .takes-list > .take-wait:nth-child(2) { min-height: calc(3 * 1.45em); }
}

.slip .insert {
  display: grid;
  justify-items: center;
  gap: 9px;
  width: 100%;
  margin: 0;
  padding: 12px 0 8px;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}

.js .panel.in .slip .insert .swap-a { animation: blink 1.2s steps(1) 1.1s 3; }

.orb-demos {
  position: absolute;
  width: min(34vw, 460px);
  right: 4vw;
  bottom: -14vh;
  opacity: .5;
}

.orb-posts {
  position: absolute;
  width: min(36vw, 500px);
  right: -6vw;
  bottom: -16vh;
  opacity: .35;
}

.orb-about {
  position: absolute;
  width: min(30vw, 420px);
  right: 5vw;
  top: -6vh;
  opacity: .8;
}

/* On a desktop the orbs are placed from the panel's centre, where the content is, so they stay by it at any window
   height; the games and about orbs sit clear of their labels. Below 861px they keep their edges, the games and
   about orbs raised off the labels. (UX decisions, 30 Sep 2026.) */
@media (min-width: 861px) {
  .home .orb-intro { bottom: auto; top: calc(50% + 160px); }
  .home .orb-games { top: calc(50% - 610px); right: calc(max(var(--gutter), (100% - 1296px) / 2) + 14px); }
  .home .orb-demos { bottom: auto; top: calc(50% + 116px); }
  .home .orb-posts { bottom: auto; top: calc(50% + 94px); }
  .home .orb-about { top: calc(50% - 328px - min(30vw, 420px)); right: max(var(--gutter), (100% - 1296px) / 2); }
}

@media (max-width: 860px) {
  .home .orb-games { top: calc(-10vh - 60px); }
  .home .orb-about { top: calc(-6vh - 90px); }
}

@media (min-width: 600px) and (max-width: 860px) {
  .home .orb-games, .home .orb-about { width: 34vw; right: -12vw; }
}

.about-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: clamp(28px, 5vw, 72px);
}

.outlinks {
  flex: 1 1 260px;
  max-width: 420px;
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--hair);
  transition: border-color var(--morph) ease;
}

.outlinks a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 17px 0;
  border-bottom: 1px solid var(--hair);
  font: 600 19px/1.2 var(--display);
  letter-spacing: -.015em;
  text-decoration: none;
  transition: border-color var(--morph) ease;
}

.outlinks a > span,
.outlinks svg { transition: transform .2s ease; }

.outlinks a:is(:focus-visible, :active) > span { transform: translateX(8px); }

/* the arrow leaves the way it points */
.outlinks a:is(:focus-visible, :active) svg { transform: translate(3px, -3px); }

@media (hover: hover) and (pointer: fine) {
  .outlinks a:hover > span { transform: translateX(8px); }

  .outlinks a:hover svg { transform: translate(3px, -3px); }
}

.outlinks svg {
  width: 12px;
  height: 12px;
}

/* the footer is on the page colour too; it only shows while About, on paper, covers most of the screen */

.home .foot {
  border-color: var(--hair);
  transition: border-color var(--morph) ease;
}

.home .foot-row {
  color: var(--soft);
  transition: color var(--morph) ease;
}

.home .foot-row a:last-child { margin-left: auto; }

/* the focus ring takes the ink of the band it sits in, so it shows on the blue, ink and persimmon bands */

.panel :focus-visible,
.bar :focus-visible { outline-color: var(--fg); }

/* things rise into place as their panel arrives */

.js .rv {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.2, .7, .2, 1);
}

.js .panel.in .rv {
  opacity: 1;
  transform: none;
}

.js .panel.in .rv:nth-child(2) { transition-delay: .12s; }
.js .panel.in .rv:nth-child(3) { transition-delay: .24s; }
.js .panel.in .feature .rv:nth-child(2) { transition-delay: .2s; }
.js .panel.in .next { transition-delay: .45s; }

/* small screens */

@media (max-width: 860px) {
  .feature { grid-template-columns: minmax(0, 1fr); }

  .eye { padding: 9% 12%; }

  .pitch { font-size: 20px; }

  .orb-intro { width: 78vw; right: -34vw; bottom: -20vh; opacity: .5; }
  .orb-games, .orb-demos, .orb-posts, .orb-about { width: 60vw; right: -22vw; opacity: .3; }

  .thread { left: 5px; }
}

@media (max-width: 520px) {
  html { scroll-padding-top: 67px; }

  .home .top { padding: 11px 0; }

  .home .top nav { font-size: 14px; gap: 0; }

  /* 6px either side keeps the 12px between words; the underline stays under the word */
  .home .top nav a {
    padding: 15px 6px;
    background-origin: content-box;
    background-position: 100% calc(100% + 6px);
  }

  .home .top nav a:is(:focus-visible, :active) { background-position: 0 calc(100% + 6px); }

  @media (hover: hover) and (pointer: fine) {
    .home .top nav a:hover { background-position: 0 calc(100% + 6px); }
  }

  .home .brand span { display: none; }

  /* a clear 9px border above and below makes the button 45px tall (Chrome draws borders in whole pixels);
     the ring and the fill keep to the 27px pill */
  .home .langbtn {
    min-width: 44px;
    margin-left: 6px;
    padding: 7px 9px;
    border: solid transparent;
    border-width: 9px 0;
    border-radius: 13.5px / 22.5px;
    font-size: 13px;
  }

  .home .langbtn,
  .home .langbtn:hover,
  .home .langbtn:active { background-clip: padding-box; }
}

@media (prefers-reduced-motion: reduce) {
  /* the page changes colour at once */
  html, body.home, .bar, .thread i, .thread i::after, .panel, .panel-head, .home .label, .home .meta dt,
  .home .orb, .home .orb .back, .intro .px, .intro .px b, .aside, .feature-copy .meta,
  .feature-copy .meta div, .dots, .outlinks, .outlinks a, .home .foot, .home .foot-row { transition: none; }

  .home .orb { transform: none; }

  /* content is always at full, where it sits */
  .panel > .wrap {
    opacity: 1;
    transform: none;
  }

  .js .rv {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .js .panel.in .slip .insert .swap-a,
  .intro .px b { animation: none; }

  .eye-art { clip-path: none; }
}

/* ---------------------------------------------------------------- reactions
   One per element, each wired in home.js and marked data-fx. Pixel art from assets/fx is drawn at 2x. */

.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* the slips that hold something to press lift off their shadow, and press into it */

.js .slip.rv {
  transition: opacity .7s ease, transform .7s cubic-bezier(.2, .7, .2, 1), translate .2s ease, box-shadow .2s ease;
}

.js .panel.in .slip.rv:nth-child(3) { transition-delay: .24s, .24s, 0s, 0s; }

.slip:has([data-fx]:focus-visible) {
  translate: -2px -2px;
  box-shadow: 10px 10px 0 rgba(0, 0, 0, .3);
}

@media (hover: hover) and (pointer: fine) {
  .slip:has([data-fx]:hover) {
    translate: -2px -2px;
    box-shadow: 10px 10px 0 rgba(0, 0, 0, .3);
  }
}

.slip:has([data-fx]:active) {
  translate: 2px 2px;
  box-shadow: 6px 6px 0 rgba(0, 0, 0, .3);
}

/* without :has (Safari before 15.4, Firefox before 121, Samsung Internet before 20) the two slips that hold
   something to press lift as a whole. :focus-within is behind the pointer test too: Firefox and Samsung Internet
   focus a tapped button, so the slip would stay lifted after a tap. */
@supports not selector(:has(*)) {
  @media (prefers-reduced-motion: no-preference) {
    @media (hover: hover) and (pointer: fine) {
      #posts .tokens:hover,
      #posts .tokens:focus-within {
        translate: -2px -2px;
        box-shadow: 10px 10px 0 rgba(0, 0, 0, .3);
      }
    }

    #posts .tokens:active {
      translate: 2px 2px;
      box-shadow: 6px 6px 0 rgba(0, 0, 0, .3);
    }
  }
}

/* two lines in one place: the box keeps the size of the longer, so nothing moves */

.swap {
  display: inline-grid;
  justify-items: center;
}

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

/* 1. the coin slot */

.slot {
  position: relative;
  width: 40px;
  height: 6px;
  background: #141413;
}

.slot-light {
  position: absolute;
  top: 0;
  left: calc(100% + 8px);
  width: 6px;
  height: 6px;
  background: #e1dbcc;
}

.insert.is-lit .slot-light { animation: slot-blink .5s steps(1) both; }

@keyframes slot-blink {
  0% { background: #ff5b2e; }
  50%, 100% { background: #e1dbcc; }
}

/* the coin falls inside a lane that ends halfway into the slot, so it goes in rather than past */
.coin-lane {
  position: absolute;
  left: 4px;
  bottom: 3px;
  width: 32px;
  height: calc(var(--fall, 240px) + 40px);
  overflow: hidden;
  pointer-events: none;
}

.coin {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 32px;
  height: 32px;
  background: url("/assets/fx/coin.png") 0 0 / 256px 32px no-repeat;
  image-rendering: pixelated;
  visibility: hidden;
}

.insert.is-dropping .coin {
  visibility: visible;
  animation: coin-fall .6s linear both, coin-spin .3s steps(8) 2;
}

/* a queued coin, after a burst of presses: the same fall in a third of the time */
.insert.is-dropping.is-quick .coin { animation-duration: .2s, .1s; }

/* the coins still queued, +n to the left of the slot as the light is to its right */
.slot[data-queued]:not([data-queued=""])::before {
  content: attr(data-queued);
  position: absolute;
  top: 50%;
  right: calc(100% + 8px);
  transform: translateY(-50%);
  color: #141413;
  font: 400 11px/1 var(--pixel);
  letter-spacing: .04em;
  white-space: nowrap;
}

@keyframes coin-fall {
  0% { transform: translateY(calc(var(--fall, 240px) * -1)); animation-timing-function: cubic-bezier(.55, 0, 1, .6); }
  58% { transform: translateY(0); animation-timing-function: cubic-bezier(0, .45, .45, 1); }
  74% { transform: translateY(-12px); animation-timing-function: cubic-bezier(.55, 0, 1, .6); }
  88% { transform: translateY(0); animation-timing-function: linear; }
  100% { transform: translateY(36px); }
}

@keyframes coin-spin { to { background-position: -256px 0; } }

.insert .swap-b { visibility: hidden; }

.insert[data-state="paid"] .swap-a { visibility: hidden; }

.insert[data-state="paid"] .swap-b { visibility: visible; }

.slip .pips i.on { background: #ff5b2e; }

/* 2. the eye looks at the pointer, one pixel step at a time, and blinks when pressed */

.eye-iris { transform: translate(calc(var(--lx, 0) * 1px), calc(var(--ly, 0) * 1px)); }

.eye.is-blinking .eye-lid { animation: eye-blink .22s steps(1, end); }

@keyframes eye-blink {
  0% { clip-path: inset(23% 0 15% 0); }
  18% { clip-path: inset(46% 0 50% 0); }
  64% { clip-path: inset(23% 0 15% 0); }
  82%, 100% { clip-path: inset(0); }
}

/* 3. About: a pile of RAM to buy, a stick a press, hold to buy faster. Six sticks a pile, each pile dearer than
   the last, without end; a slip keeps the count and the line under it says what the money would have bought. The
   sticks are ram.png at 3x, stacked 16px apart; each new pile's price tag slaps over the last one. */

.shop {
  display: grid;
  grid-template-columns: auto minmax(0, 300px);
  align-items: end;
  gap: 20px 32px;
  margin-top: clamp(36px, 6vh, 64px);
}

.pile {
  position: relative;
  display: block;
  width: 276px;
  height: 178px;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* the sticks stand in the top 146px; Buy and the price sit under them */
.sticks {
  position: absolute;
  inset: 0 0 32px;
  transition: translate .15s ease;
}

.stick {
  position: absolute;
  bottom: var(--y, 0px);
  left: var(--j, 0px);
  width: 252px;
  height: 54px;
  background: url("/assets/fx/ram.png") 0 0 / 100% 100% no-repeat;
  image-rendering: pixelated;
}

/* the pile answers the hand: up a pixel under a mouse or the keyboard, down a pixel while pressed */
.pile:focus-visible .sticks { translate: 0 -2px; }

.pile:active .sticks { translate: 0 1px; }

@media (hover: hover) and (pointer: fine) {
  .pile:hover .sticks { translate: 0 -2px; }

  .pile:hover:active .sticks { translate: 0 1px; }
}

/* a stick bought flies off toward the count; a new pile drops in from the bottom stick up */
.stick.is-gone { animation: stick-off .26s steps(4, end) forwards; }

@keyframes stick-off { to { opacity: 0; transform: translate(64px, -72px); } }

.stick.is-new { animation: stick-drop .24s steps(3, end) calc(var(--i, 0) * 45ms) both; }

@keyframes stick-drop { from { opacity: 0; transform: translateY(-80px); } }

/* what the stick cost rises off the pile and fades, on a paper chip like the tags so it reads over the sticks */
.gain {
  position: absolute;
  z-index: 2;
  bottom: calc(var(--y, 0px) + 90px);
  left: calc(120px + var(--k, 0) * 30px);
  padding: 4px 6px 3px;
  border: 2px solid #141413;
  background: #f0eee9;
  color: #141413;
  font: 400 11px/1 var(--pixel);
  letter-spacing: .04em;
  white-space: nowrap;
  pointer-events: none;
  animation: gain-up .7s steps(7, end) forwards;
}

@keyframes gain-up { to { opacity: 0; transform: translateY(-40px); } }

/* the price tags sit low on the front of the pile */
.shelf {
  position: absolute;
  bottom: 42px;
  left: 40px;
}

/* Buy and the price of the next stick, under the pile */
.pile-buy {
  position: absolute;
  bottom: 0;
  left: 0;
  display: flex;
  align-items: baseline;
  gap: 8px;
  font: 400 11px/1 var(--pixel);
  letter-spacing: .06em;
  text-transform: uppercase;
}

.pile-buy .pile-price { color: var(--soft); }

.shelf .tag {
  top: auto;
  bottom: 0;
}

/* the count, a slip like the others */
.shop .tally {
  width: min(300px, 100%);
  margin-top: 0;
}

.tally .ram-n,
.tally .ram-spent { display: inline-block; }

.tally .is-bump { animation: tally-bump .14s steps(2, end); }

@keyframes tally-bump { 50% { translate: 0 -2px; } }

/* what the money would have bought: two lines kept free, so a longer line never moves the page */
.ram-line {
  grid-column: 1 / -1;
  max-width: 34em;
  min-height: calc(2 * 1.4em);
  margin: 0;
  font: 400 17px/1.4 var(--serif);
}

.ram-line.is-new > [data-l] { animation: line-in .35s ease both; }

@keyframes line-in { from { opacity: 0; transform: translateY(6px); } }

@media (max-width: 520px) {
  .shop {
    flex: 1 1 100%;
    grid-template-columns: minmax(0, 1fr);
  }
}

/* a phone narrower than 380px keeps three lines for it: the Editor's longest lines take three at 320px */
/* the Editor's pool has lines that take three at a phone's width: the line stays whole, the slot grows */
@media (max-width: 440px) {
  .ram-line { min-height: calc(3 * 1.4em); }
}

.tag {
  position: absolute;
  top: 0;
  left: 0;
  padding: 6px 8px 5px;
  border: 2px solid #141413;
  background: #f0eee9;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, .35);
  color: #141413;
  font: 400 11px/1 var(--pixel);
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
  transform: translate(var(--x, 0px), var(--y, 0px)) rotate(var(--r, -3deg));
}

.tag[data-n="1"] { --x: 12px; --y: -5px; --r: 4deg; background: #ff5b2e; }

.tag[data-n="2"] { --x: -5px; --y: 6px; --r: -6deg; }

.tag[data-n="3"] { --x: 20px; --y: 2px; --r: 2deg; background: #ff5b2e; }

.tag-out {
  --x: 34px;
  --y: -3px;
  --r: -9deg;
  padding: 8px 10px 7px;
  border-color: #ff5b2e;
  background: #141413;
  color: #f0eee9;
  font-size: 22px;
}

.tag-back {
  border-color: #141413;
  background: #ff5b2e;
  color: #141413;
}

.tag-out[hidden] { display: none; }

.tag.is-new { animation: tag-slap .18s steps(3, end); }

@keyframes tag-slap {
  from {
    opacity: 0;
    transform: translate(var(--x, 0px), calc(var(--y, 0px) - 16px)) rotate(calc(var(--r, -3deg) * 3)) scale(1.4);
  }
}

/* 4. the stub: printed out from behind the button, a line at a time */

.feature-copy { position: relative; }

.home .btn[data-fx="ticket"] {
  position: relative;
  z-index: 2;
}

.stub {
  position: absolute;
  z-index: 1;
  top: var(--y, 0);
  left: var(--x, 0);
  overflow: hidden;
  visibility: hidden;
  pointer-events: none;
}

.stub.is-out { visibility: visible; }

.stub-paper {
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 42px;
  padding: 0 12px;
  border: solid transparent;
  border-width: 0 20px;
  border-image: url("/assets/fx/stub.png") 0 10 fill / 0 20px stretch;
  image-rendering: pixelated;
  color: #141413;
  font: 400 11px/1.2 var(--pixel);
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
  transform: translateX(-100%);
}

.stub[data-side="below"] .stub-paper { transform: translateY(-100%); }

.stub.is-out .stub-paper {
  transform: none;
  transition: transform .24s steps(6, end);
}

.stub-long [data-l] > span { display: block; }

.stub[data-fit="long"] .stub-short,
.stub[data-fit="short"] .stub-long { display: none; }

/* 5. the dragon: type "audit" */

.dragon {
  position: fixed;
  z-index: 6;
  bottom: var(--lift, 16px);
  left: 0;
  width: 96px;
  height: 96px;
  background: url("/assets/fx/dragon.png") 0 0 / 768px 96px no-repeat;
  image-rendering: pixelated;
  visibility: hidden;
  pointer-events: none;
  transform: translateX(-100%);
}

.dragon.is-flying { visibility: visible; }

.dragon.is-still { transform: translateX(16px); }

/* reduced motion: every reaction is a change of state in place, nothing travels */

@media (prefers-reduced-motion: reduce) {
  .home .brand svg,
  .home .top nav a,
  .home .foot-row a,
  .skip a,
  .eye-lid,
  .js .slip.rv,
  .outlinks a > span,
  .outlinks svg,
  .sticks,
  .stub.is-out .stub-paper { transition: none; }

  .pile:is(:hover, :focus-visible, :active) .sticks { translate: none; }

  .stick.is-gone,
  .stick.is-new,
  .tally .is-bump,
  .ram-line.is-new > [data-l],
  .tag.is-new { animation: none; }

  .home .brand:is(:hover, :focus-visible, :active) svg,
  .eye:is(:hover, :focus-visible, :active) .eye-lid,
  .outlinks a:is(:hover, :focus-visible, :active) > span,
  .outlinks a:is(:hover, :focus-visible, :active) svg { transform: none; }

  .slip:has([data-fx]:hover),
  .slip:has([data-fx]:focus-visible),
  .slip:has([data-fx]:active) { translate: none; }

  /* a blink is one closed frame; the slot light stays on while the token counts */
  .eye.is-blinking .eye-lid {
    animation: none;
    clip-path: inset(46% 0 50% 0);
  }

  .insert.is-lit .slot-light {
    animation: none;
    background: #ff5b2e;
  }
}

/* ---------------------------------------------------------------- 6. the daily fortune
   An easter egg behind ten tokens in a row (fortune/box.js). Nothing on the page hints at it: the Tokens slip stays
   as it is (Mike, 1 Oct 2026: "it should be a easter egg for someone who click to 10 token and get a fortune"). The
   box opens over the page as a modal, so nothing on the page moves. The box is drawn as a slip: ink bar, paper, the
   hard shadow, pixel labels over serif lines. */

/* sized from the window less any scroll bar (a modal's containing block), 16px clear of each side; the top edge
   stays where it is while the box grows or shrinks between steps, so nothing in it jumps */
.fortune {
  --top: max(16px, 7vh);
  width: min(560px, calc(100% - 32px));
  max-width: none;
  max-height: calc(100% - var(--top) - 16px);
  margin: var(--top) auto auto;
  padding: 0;
  overflow: hidden;
  border: 2px solid #141413;
  background: #f0eee9;
  box-shadow: 8px 8px 0 rgba(0, 0, 0, .3);
  color: #141413;
  font: 400 18px/1.45 var(--serif);
}

@supports (height: 100dvh) {
  .fortune {
    --top: max(16px, 7dvh);
    max-height: calc(100dvh - var(--top) - 16px);
  }
}

.fortune[open] {
  display: flex;
  flex-direction: column;
}

.fortune::backdrop { background: rgba(20, 20, 19, .72); }

.fortune :focus-visible {
  outline: 2px solid #2440f0;
  outline-offset: 2px;
  border-radius: 0;
}

.fortune-bar {
  display: flex;
  flex: none;
  align-items: center;
  gap: 9px;
  height: 36px;
  padding-left: 11px;
  background: #141413;
  color: #f0eee9;
  font: 400 11px/1.2 var(--pixel);
  letter-spacing: .04em;
  text-transform: uppercase;
}

.fortune-bar > i {
  width: 10px;
  height: 10px;
  border: 2px solid #f0eee9;
}

/* a 44px tall target in a 36px bar: the button's hit area reaches 4px past the bar above and below */
.fortune-close {
  position: relative;
  display: grid;
  place-items: center;
  width: 44px;
  height: 36px;
  margin-left: auto;
  padding: 0;
  border: 0;
  background: none;
  color: #f0eee9;
  cursor: pointer;
}

.fortune-close::before {
  content: "";
  position: absolute;
  inset: -4px 0;
}

.fortune-close svg {
  width: 12px;
  height: 12px;
  fill: currentColor;
}

/* lit by the keyboard or a press; by hover only where a real pointer hovers, as for the page's own links */
.fortune-close:is(:focus-visible, :active) {
  background: #ff5b2e;
  color: #141413;
}

@media (hover: hover) and (pointer: fine) {
  .fortune-close:hover {
    background: #ff5b2e;
    color: #141413;
  }
}

.fortune .fortune-close:focus-visible {
  outline: 2px solid #f0eee9;
  outline-offset: -4px;
}

.fortune-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 22px 20px 24px;
}

/* one step on the box at a time: ask for the name, shake, read */
.fortune [data-show] { display: none; }

.fortune[data-step="ask"] [data-show~="ask"],
.fortune[data-step="shake"] [data-show~="shake"],
.fortune[data-step="result"] [data-show~="result"] { display: block; }

/* the tube: a PixelLab sheet of 12 frames, 48px square, drawn at 2x; it shakes once and a stick rises. jump-none
   holds each of its 12 values for a twelfth of the time, from the first frame at 0 to the last at -1056px */
.fortune-tube {
  width: 96px;
  height: 96px;
  margin: 0 auto 18px;
  background: url("/assets/fortune/tube.png") 0 0 / 1152px 96px no-repeat;
  image-rendering: pixelated;
}

.fortune[data-step="shake"] .fortune-tube { animation: tube-shake 1.5s steps(12, jump-none) both; }

@keyframes tube-shake { to { background-position: -1056px 0; } }

.fortune-label {
  display: block;
  margin: 0 0 8px;
  color: #56544d;
  font: 400 11px/1.3 var(--pixel);
  letter-spacing: .04em;
  text-transform: uppercase;
}

/* the ask step's one line, Mike's sentence, labels the name field: read as a sentence, not as a pixel caption */
.fortune-label.fortune-ask-line {
  margin-bottom: 12px;
  color: #141413;
  font: 600 18px/1.3 var(--display);
  letter-spacing: normal;
  text-transform: none;
}

html[data-lang="zh"] .fortune-label.fortune-ask-line {
  font-size: 18px;
  letter-spacing: .02em;
}

.fortune-row {
  display: flex;
  gap: 8px;
}

/* 16px and over, so a phone does not zoom into the field */
.fortune-field {
  flex: 1 1 auto;
  min-width: 0;
  height: 44px;
  margin: 0;
  padding: 0 12px;
  border: 2px solid #141413;
  border-radius: 0;
  background: #fff;
  color: #141413;
  font: 500 17px/1 var(--display);
}

.fortune-btn {
  flex: none;
  min-width: 88px;
  height: 44px;
  padding: 0 16px;
  border: 0;
  border-radius: 0;
  background: #141413;
  color: #f0eee9;
  font: 400 12px/1 var(--pixel);
  letter-spacing: .06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color .2s ease, color .2s ease;
}

.fortune-btn:is(:focus-visible, :active):not(:disabled) {
  background: #ff5b2e;
  color: #141413;
}

@media (hover: hover) and (pointer: fine) {
  .fortune-btn:hover:not(:disabled) {
    background: #ff5b2e;
    color: #141413;
  }
}

/* Draw rests while the tube shakes */
.fortune-btn:disabled { cursor: default; }

.fortune-note {
  margin: 10px 0 0;
  color: #56544d;
  font: 400 11px/1.5 var(--pixel);
  letter-spacing: .04em;
  text-transform: uppercase;
}

/* an alert in ink with a persimmon mark: persimmon text on paper is too faint to read */
.fortune-alert { color: #141413; }

.fortune-alert::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 8px;
  background: #ff5b2e;
}

.fortune-who {
  margin: 0 0 14px;
  font: 700 22px/1.2 var(--display);
  letter-spacing: -.01em;
  overflow-wrap: anywhere;
}

/* the result takes the focus so a screen reader starts there; it is not a control, so no ring */
.fortune .fortune-who:focus { outline: none; }

.fortune-lines { margin: 0; }

.fortune-lines > div {
  padding: 11px 0 12px;
  border-top: 2px dotted #8a877d;
}

.fortune-lines > div:last-child { border-bottom: 2px dotted #8a877d; }

.fortune-lines dt {
  margin: 0 0 4px;
  color: #56544d;
  font: 400 11px/1.3 var(--pixel);
  letter-spacing: .04em;
  text-transform: uppercase;
}

.fortune-lines dd {
  margin: 0;
  overflow-wrap: break-word;
}

.fortune-lines [data-cat="overall"] dd {
  font-size: 21px;
  line-height: 1.35;
}

.fortune-lines dd p {
  display: flex;
  gap: 12px;
  margin: 0;
}

.fortune-lines dd p + p { margin-top: 2px; }

.fortune-lines dd b {
  flex: none;
  width: 4.2em;
  color: #56544d;
  font: 400 11px/2.4 var(--pixel);
  letter-spacing: .04em;
  text-transform: uppercase;
}

/* the sealed part: pixel glyphs in grey where the words will be. They break at any glyph, so the lines wrap the same
   whatever the glyphs are as they turn over: with ordinary breaking, symbols such as % ? + moved the break points
   and a row grew or shrank a line while the visitor read it (UI check, 2 Oct 2026) */
.fortune-glyphs {
  color: #8a877d;
  font: 400 .78em/1 var(--pixel);
  letter-spacing: .06em;
  word-break: break-all;
  overflow-wrap: anywhere;
}

/* under Overall while the rest is sealed: on a phone the gates are below the fold and an iPhone shows no scrollbar,
   so this takes the visitor down to them (the UX/UI review, 1 Oct 2026) */
.fortune-jump {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  margin-top: 4px;
  padding: 0;
  border: 0;
  background: none;
  color: #141413;
  font: 400 12px/1.3 var(--pixel);
  letter-spacing: .04em;
  text-transform: uppercase;
  text-align: left;
  text-decoration: underline 1.5px;
  text-underline-offset: 4px;
  cursor: pointer;
}

.fortune-jump svg {
  flex: none;
  width: 11px;
  height: 11px;
}

.fortune[data-seal="open"] .fortune-jump,
.fortune[data-seal="opening"] .fortune-jump { display: none; }

/* the gates: the friend's password, the tip */
.fortune-gates { margin-top: 22px; }

/* locked out for the day: the field and its Unlock rest */
.fortune-field:disabled,
.fortune-gate .fortune-btn:disabled { opacity: .45; cursor: not-allowed; }

.fortune .fortune-alert:focus { outline: none; }

.fortune-gate + .fortune-gate { margin-top: 14px; }

/* the password's hint, Mike's own words: kept as he typed them, never in capitals, wrapped anywhere on a phone */
.fortune-hint { margin-top: 6px; overflow-wrap: anywhere; }
.fortune-hint [data-l="en"] { margin-inline-end: .5em; }
.fortune-hint-text { text-transform: none; }

.fortune[data-seal="open"] .fortune-gates,
.fortune[data-seal="opening"] .fortune-gates { display: none; }

/* what came back from a payment check, at the top of the box whatever the step */
.fortune-paid { margin: 0 0 16px; }

.fortune-field.is-wrong { animation: field-wrong .3s steps(4, end); }

@keyframes field-wrong {
  25% { transform: translateX(-4px); }
  50% { transform: translateX(4px); }
  75% { transform: translateX(-2px); }
}

.fortune-pay { margin: 16px 0 0; }

.fortune-pay a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  font: 600 17px/1.2 var(--display);
  text-decoration: underline 1.5px;
  text-underline-offset: 4px;
}

.fortune-pay svg {
  width: 11px;
  height: 11px;
}

.fortune-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 4px 16px;
  margin-top: 14px;
}

.fortune-again {
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: #141413;
  font: 600 16px/1 var(--display);
  text-decoration: underline 1.5px;
  text-underline-offset: 5px;
  cursor: pointer;
}

.fortune-foot .fortune-note { margin: 0; }

html[data-lang="zh"] .fortune-bar,
html[data-lang="zh"] .fortune-label,
html[data-lang="zh"] .fortune-note,
html[data-lang="zh"] .fortune-jump,
html[data-lang="zh"] .fortune-lines dt,
html[data-lang="zh"] .fortune-lines dd b {
  font-size: 13px;
  letter-spacing: .08em;
}

html[data-lang="zh"] .fortune-btn {
  font-size: 14px;
  letter-spacing: .12em;
}

html[data-lang="zh"] .fortune-lines dd {
  font-size: 17px;
  line-height: 1.75;
}

html[data-lang="zh"] .fortune-lines [data-cat="overall"] dd {
  font-size: 20px;
  line-height: 1.6;
}

html[data-lang="zh"] .fortune-lines dd b { line-height: 2.3; }

html[data-lang="zh"] .fortune-glyphs {
  font-size: .94em;
  letter-spacing: 0;
}

@media (max-width: 520px) {
  .fortune-body { padding: 18px 16px 20px; }

  .fortune-who { font-size: 20px; }

  .fortune-lines [data-cat="overall"] dd { font-size: 19px; }
}

/* reduced motion: the tube stands still with the stick up, nothing shakes */
@media (prefers-reduced-motion: reduce) {
  .fortune-btn { transition: none; }

  .fortune[data-step="shake"] .fortune-tube {
    animation: none;
    background-position: -1056px 0;
  }

  .fortune-field.is-wrong { animation: none; }
}
