/* EDEN Kesef, the marketing surface.
 *
 * Owner: EICCIO Advisors.
 *
 * NO DEPENDENCIES. No CDN, no webfont, no analytics, no third-party script and
 * no tracker. That is not a preference here, it is the product's own claim, and
 * a marketing page that loaded a tracker while saying so would be the first
 * thing to disprove it. The Content Security Policy in site/_headers and in the
 * meta tag of every page is default-src 'self', the same policy the product
 * ships with, so the claim is enforced by the browser rather than asserted.
 *
 * ONE THEME, DELIBERATELY, AND THE REASON IS NOT THE PRODUCT'S REASON.
 * The Counter has no dark variant because a dark till at 468 measured nits in
 * tropical daylight is unreadable, and that is recorded as
 * LAYOUT.noDarkThemeOnCounter in src/interaction.js. This page is not a till and
 * that argument does not carry to it. It stays single-theme for a different and
 * smaller reason: the reproduction of the Counter below is the dominant object
 * on the page, its palette is a measured accessibility decision that cannot be
 * re-coloured, and a dark page wrapped around a permanently light device reads
 * as a rendering fault. Stated here so it is a decision on the record and not a
 * drift nobody noticed. Every colour is painted explicitly and nothing inherits
 * a ground from the host.
 *
 * Built at 320px first. The wide screen is the enhancement.
 */

:root {
  /* Taken unchanged from public/app.css, so the site and the product are
     recognisably one thing. */
  --ground:      #FBFAF7;   /* paper, not white. White at 468 nits is glare */
  --ground-sunk: #F2EFE8;
  --ink:         #14140F;   /* 16.8:1 on ground */
  --ink-soft:    #4A4A42;   /*  8.1:1 on ground */
  --rule:        #DCD9CF;
  --money:       #0A5C33;   /* white on this: 8.0:1 */

  --cash:        #0A5C33;
  --card:        #F2C200;
  --mobile:      #0E2A66;
  --credit:      #F5A3D0;

  /* The institutional act. A deliberate change of ground, because the page
     turns to a different reader there and the turn should be felt. */
  --deep:        #0A2A1B;
  --deep-ink:    #F2EFE8;   /* 13.4:1 on deep */
  --deep-soft:   #BFC7BD;   /*  8.9:1 on deep */
  --deep-accent: #7FD4A0;   /*  8.7:1 on deep */
  --deep-rule:   #1E4632;

  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* One spacing scale. Beats are separated by --beat, which is the cut. */
  --gap:   12px;
  --step:  20px;
  --beat:  clamp(56px, 11vw, 104px);
  --radius: 14px;
  --measure: 34rem;         /* prose never runs wider than this */

  color-scheme: light;
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.55;
  overflow-x: hidden;
}

@media (min-width: 700px) {
  body { font-size: 18px; }
}

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

/* ---- links and focus -------------------------------------------------- */

a {
  color: var(--money);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
a:hover { text-decoration-thickness: 2px; }

:focus-visible {
  outline: 3px solid var(--money);
  outline-offset: 3px;
  border-radius: 2px;
}
.act--deep :focus-visible,
.k-foot :focus-visible { outline-color: var(--deep-accent); }

.k-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 20;
  padding: 12px 16px;
  background: var(--ink);
  color: var(--ground);
  text-decoration: none;
  border-radius: 0 0 var(--radius) 0;
}
.k-skip:focus { left: 0; }

/* ---- the frame -------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: 62rem;
  margin: 0 auto;
  padding-inline: max(20px, env(safe-area-inset-left));
  padding-inline-end: max(20px, env(safe-area-inset-right));
}

.act {
  padding-block: var(--beat);
}
.act--deep {
  background: var(--deep);
  color: var(--deep-ink);
}
.act--sunk { background: var(--ground-sunk); }

/* ---- type ------------------------------------------------------------- */

h1, h2, h3 {
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 var(--step);
  font-weight: 700;
  text-wrap: balance;
}

h1 { font-size: clamp(34px, 9.5vw, 68px); }
h2 { font-size: clamp(27px, 6.6vw, 44px); }
h3 { font-size: clamp(20px, 4.4vw, 25px); letter-spacing: -0.01em; }

p { margin: 0 0 var(--step); max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

.lede {
  font-size: clamp(19px, 4.6vw, 24px);
  line-height: 1.4;
  color: var(--ink);
}
.act--deep .lede { color: var(--deep-ink); }

.quiet { color: var(--ink-soft); }
.act--deep .quiet { color: var(--deep-soft); }

.small {
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-soft);
}
.act--deep .small { color: var(--deep-soft); }

/* The kicker names the beat in two or three words. It is a label, not a
   sentence, and it is what lets a reader who is skimming still feel a
   sequence rather than a shelf. */
.kicker {
  display: block;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--money);
  margin: 0 0 10px;
}
.act--deep .kicker { color: var(--deep-accent); }

/* The money line. One sentence per beat that carries the beat. */
.line {
  font-size: clamp(22px, 5.4vw, 30px);
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: -0.015em;
  max-width: 26ch;
  margin: 0 0 var(--step);
  text-wrap: balance;
}

strong { font-weight: 700; }

ul.plain { list-style: none; margin: 0 0 var(--step); padding: 0; max-width: var(--measure); }
ul.plain > li {
  position: relative;
  padding-left: 24px;
  margin-bottom: 10px;
}
ul.plain > li::before {
  content: '';
  position: absolute;
  left: 0; top: 0.62em;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--money);
}
.act--deep ul.plain > li::before { background: var(--deep-accent); }

ul.plain--no > li::before {
  border-radius: 0;
  height: 3px;
  top: 0.8em;
  width: 13px;
  background: var(--ink-soft);
}
.act--deep ul.plain--no > li::before { background: var(--deep-soft); }

/* ---- the call to action ----------------------------------------------- */

.cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 56px;             /* minTouchDp, the same floor as the product */
  padding: 14px 26px;
  border-radius: var(--radius);
  background: var(--money);
  color: #fff;
  font-size: 19px;
  font-weight: 700;
  text-decoration: none;
  transition: transform 90ms ease, filter 90ms ease;
}
.cta:hover { filter: brightness(1.1); text-decoration: none; }
.cta:active { transform: scale(0.98); }
.act--deep .cta { background: var(--deep-accent); color: var(--deep); }

.cta--quiet {
  background: transparent;
  color: var(--ink);
  border: 2px solid var(--rule);
}
.cta--quiet:hover { filter: none; border-color: var(--ink-soft); }

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
  align-items: center;
  margin-top: var(--step);
}

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

.hero {
  padding-block: clamp(36px, 9vw, 76px) var(--beat);
}

.hero__grid {
  display: grid;
  gap: clamp(28px, 7vw, 48px);
}
@media (min-width: 860px) {
  .hero__grid {
    grid-template-columns: 1fr minmax(280px, 340px);
    align-items: center;
    gap: 56px;
  }
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: clamp(28px, 7vw, 48px);
  font-weight: 700;
  letter-spacing: -0.01em;
}
.brand__mark {
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 7px solid var(--money);
  flex: none;
  align-self: center;
}
.brand__name { font-size: 20px; }
.brand {
  flex-wrap: wrap;
}
.brand__by {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-soft);
  margin-left: auto;
  text-align: right;
}
/* At 320px the name and the attribution together are wider than the column,
   and a flex row that cannot fit does not wrap by default, it overflows.
   Below 420px the attribution takes its own line instead. */
@media (max-width: 420px) {
  .brand__by {
    margin-left: 0;
    width: 100%;
    text-align: left;
    margin-top: 2px;
  }
}

/* The one concession to the second audience in the opening frame. One line,
   not a navigation bar. An institution can leave the film early; a vendor is
   not made to read past a menu to reach the product. */
.hero__aside {
  margin-top: var(--step);
  padding-top: 16px;
  border-top: 1px solid var(--rule);
  font-size: 15px;
  color: var(--ink-soft);
  max-width: var(--measure);
}

/* ---- THE COUNTER, reproduced ------------------------------------------
 * This is the real interface, not an illustration of one: the same palette,
 * the same geometry, the same fixed order of the four tender keys. It is
 * inert. Sizes are fluid because the page must work at 320px, while the
 * product itself is specified against a 360px reference device.
 */

.till {
  width: min(320px, 84vw);
  margin-inline: auto;
  background: var(--ground);
  border: 1px solid var(--rule);
  border-radius: 26px;
  padding: 14px 12px 16px;
  box-shadow: 0 1px 2px rgba(20, 20, 15, 0.05),
              0 18px 44px -18px rgba(20, 20, 15, 0.28);
}
@media (min-width: 860px) {
  .till { width: 100%; max-width: 340px; }
}

.till__display {
  border-bottom: 2px solid var(--rule);
  padding: 2px 4px 8px;
  margin-bottom: 10px;
}

.till__status {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 20px;
  font-size: 13px;
  color: var(--ink-soft);
}

.dot {
  width: 12px; height: 12px;
  border-radius: 50%;
  border: 2px solid var(--money);
  background: var(--money);
  flex: none;
}
.dot--hollow { background: transparent; border-color: var(--ink-soft); }

.till__amount {
  display: block;
  text-align: right;
  font-size: clamp(44px, 13vw, 56px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  margin-top: 6px;
}

.till__pad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 8px;
}

.till__key {
  aspect-ratio: 5 / 4;
  border-radius: var(--radius);
  background: var(--ground-sunk);
  color: var(--ink);
  font-size: clamp(22px, 6.4vw, 26px);
  font-weight: 600;
  display: grid;
  place-items: center;
  font-variant-numeric: tabular-nums;
}
.till__key--books {
  background: var(--ground);
  border: 2px solid var(--rule);
  position: relative;
}
.till__coin {
  width: 20px; height: 20px;
  border-radius: 50%;
  border: 5px solid var(--money);
  opacity: 0.9;
}
.till__key--books::after {
  content: '';
  position: absolute;
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 2px dashed var(--money);
  opacity: 0.35;
}
.till__key--back svg { width: 24px; height: 24px; color: var(--ink-soft); }

.till__tenders {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}
.tender {
  min-height: 68px;
  border-radius: var(--radius);
  display: grid;
  grid-template-rows: auto auto;
  place-items: center;
  gap: 5px;
  padding: 8px 2px;
  font-size: 13px;
  font-weight: 600;
}
.tender__mark { width: 20px; height: 20px; }
.tender--cash   { background: var(--cash);   color: #fff; }
.tender--card   { background: var(--card);   color: var(--ink); }
.tender--mobile { background: var(--mobile); color: #fff; }
.tender--credit { background: var(--credit); color: var(--ink); }
.tender--cash   .tender__mark,
.tender--mobile .tender__mark { background: #fff; }
.tender--card   .tender__mark,
.tender--credit .tender__mark { background: var(--ink); }

.till__caption {
  width: min(320px, 84vw);
  margin: 14px auto 0;
  font-size: 14px;
  color: var(--ink-soft);
  text-align: center;
}
@media (min-width: 860px) {
  .till__caption { width: 100%; max-width: 340px; }
}

/* ---- the two-action panel --------------------------------------------- */

.steps {
  display: grid;
  gap: var(--gap);
  margin-top: var(--step);
}
@media (min-width: 620px) {
  .steps { grid-template-columns: 1fr 1fr; gap: 18px; }
}

.step {
  background: var(--ground);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 18px;
}
.act--sunk .step { background: var(--ground);}

.step__n {
  display: inline-grid;
  place-items: center;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--ink);
  color: var(--ground);
  font-size: 15px;
  font-weight: 700;
  margin-bottom: 12px;
}
.step__what { font-weight: 700; margin: 0 0 4px; }
.step__why  { margin: 0; font-size: 15px; color: var(--ink-soft); }

.step__demo {
  margin: 14px 0 0;
  padding: 14px;
  background: var(--ground-sunk);
  border-radius: 10px;
  text-align: right;
  font-size: 34px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  line-height: 1;
}
.step__demo--keys {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  padding: 10px;
  text-align: initial;
}
.step__demo--keys .tender { min-height: 52px; font-size: 11px; }
.step__demo--keys .tender__mark { width: 15px; height: 15px; }

/* ---- the figure block, used for the worked example --------------------- */

.figure {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--ground);
  padding: 18px;
  margin: var(--step) 0 0;
  max-width: 34rem;
}
.act--deep .figure {
  background: transparent;
  border-color: var(--deep-rule);
}

.figure__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  padding: 9px 0;
  border-bottom: 1px solid var(--rule);
}
.act--deep .figure__row { border-color: var(--deep-rule); }
.figure__row:last-of-type { border-bottom: 0; }
.figure__row--total {
  border-top: 2px solid var(--ink);
  border-bottom: 0;
  margin-top: 6px;
  padding-top: 12px;
  font-weight: 700;
}
.figure__k { color: var(--ink-soft); }
.act--deep .figure__k { color: var(--deep-soft); }
.figure__v {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  font-weight: 600;
  white-space: nowrap;
}
.figure__v--wrong { color: #8A1414; }
.figure__v--right { color: var(--money); }
.act--deep .figure__v--right { color: var(--deep-accent); }

.figure__note {
  margin: 14px 0 0;
  font-size: 15px;
  color: var(--ink-soft);
}
.act--deep .figure__note { color: var(--deep-soft); }

/* ---- tiers ------------------------------------------------------------- */

.tiers {
  display: grid;
  gap: var(--gap);
  margin-top: var(--step);
}
@media (min-width: 760px) {
  .tiers { grid-template-columns: repeat(3, 1fr); gap: 18px; }
}

.tier {
  border: 1px solid var(--deep-rule);
  border-radius: var(--radius);
  padding: 18px;
}
.tier__n {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--deep-accent);
  margin: 0 0 8px;
}
/* h4, not h3: these sit underneath the "What it can produce" h3, and a heading
   that reads as a sibling of its own parent is a broken outline to anyone
   navigating by headings. */
.tier h4 {
  margin: 0 0 10px;
  font-size: 19px;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.01em;
}
.tier ul { margin: 0; padding-left: 20px; font-size: 15px; color: var(--deep-soft); }
.tier li { margin-bottom: 5px; }

/* ---- the refusals ------------------------------------------------------ */

.refusals {
  display: grid;
  gap: var(--gap);
  margin-top: var(--step);
}
@media (min-width: 700px) {
  .refusals { grid-template-columns: 1fr 1fr; gap: 18px; }
}
.refusal {
  border-left: 3px solid var(--rule);
  padding: 2px 0 2px 16px;
}
.act--deep .refusal { border-left-color: var(--deep-rule); }
.refusal h3 { font-size: 18px; margin-bottom: 6px; }
.refusal p { font-size: 15px; color: var(--ink-soft); margin: 0; }
.act--deep .refusal p { color: var(--deep-soft); }

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

.k-foot {
  background: var(--deep);
  color: var(--deep-soft);
  padding-block: clamp(40px, 8vw, 64px);
  font-size: 15px;
}
.k-foot a { color: var(--deep-ink); }
.k-foot__grid {
  display: grid;
  gap: 24px;
}
@media (min-width: 700px) {
  .k-foot__grid { grid-template-columns: 1.4fr 1fr; gap: 40px; }
}
.k-foot h2 {
  font-size: 17px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--deep-soft);
  margin-bottom: 12px;
  font-weight: 700;
}
.k-foot ul { list-style: none; margin: 0; padding: 0; }
.k-foot li { margin-bottom: 10px; }
.k-foot p { max-width: 30rem; }

/* ---- legal pages -------------------------------------------------------
 * A document, not a film. These are read to answer a question, so they are
 * laid out for retrieval on purpose. Section 8 of the house rules governs
 * marketing surfaces; a policy is not one.
 */

.doc-head {
  background: var(--deep);
  color: var(--deep-ink);
  padding-block: clamp(28px, 6vw, 44px);
}
.doc-head .brand__by { color: var(--deep-soft); }
.doc-head .brand__mark { border-color: var(--deep-accent); }
.doc-head a { color: var(--deep-ink); }
.doc-head h1 { font-size: clamp(30px, 7.5vw, 46px); margin-bottom: 10px; }
.doc-head p { color: var(--deep-soft); margin-bottom: 0; }

.doc {
  padding-block: var(--beat);
}
.doc__body { max-width: 38rem; }
.doc__body h2 {
  font-size: clamp(22px, 5vw, 28px);
  margin-top: clamp(36px, 7vw, 54px);
  padding-top: 20px;
  border-top: 2px solid var(--rule);
}
.doc__body h2:first-child { margin-top: 0; border-top: 0; padding-top: 0; }
.doc__body h3 {
  font-size: 19px;
  margin-top: 30px;
  margin-bottom: 8px;
}
.doc__body p, .doc__body li { max-width: 38rem; }
.doc__body ul { padding-left: 22px; margin: 0 0 var(--step); }
.doc__body li { margin-bottom: 8px; }

.doc__toc {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 18px;
  margin-bottom: var(--beat);
  background: var(--ground-sunk);
  max-width: 38rem;
}
.doc__toc h2 {
  font-size: 14px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 10px;
  border: 0;
  padding: 0;
}
.doc__toc ol { margin: 0; padding-left: 20px; font-size: 16px; }
.doc__toc li { margin-bottom: 6px; }

/* The one-sentence answer, put above the detail so a reader who stops after
   the first paragraph has still been told the truth. */
.answer {
  border-left: 4px solid var(--money);
  background: var(--ground-sunk);
  padding: 16px 18px;
  border-radius: 0 var(--radius) var(--radius) 0;
  margin: 0 0 var(--step);
  max-width: 38rem;
  font-size: 18px;
  font-weight: 600;
  line-height: 1.4;
}

/* A plain table that scrolls inside itself rather than pushing the page
   sideways. Wide content is the commonest cause of a horizontal scrollbar on
   a 320px screen. */
.scroller {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 0 var(--step);
  max-width: 38rem;
}
table {
  border-collapse: collapse;
  width: 100%;
  min-width: 30rem;
  font-size: 15px;
}
th, td {
  text-align: left;
  vertical-align: top;
  padding: 10px 14px 10px 0;
  border-bottom: 1px solid var(--rule);
}
th {
  font-weight: 700;
  border-bottom: 2px solid var(--ink);
  white-space: nowrap;
}
td code, p code, li code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.92em;
  background: var(--ground-sunk);
  padding: 1px 5px;
  border-radius: 4px;
  word-break: break-word;
}

.updated {
  font-size: 15px;
  color: var(--ink-soft);
  border-top: 1px solid var(--rule);
  padding-top: 18px;
  margin-top: var(--beat);
  max-width: 38rem;
}

/* ---- reveal ------------------------------------------------------------
 * Motion reveals, it does not decorate. Each beat rises once, a little, as it
 * arrives, and nothing loops, drifts or parallaxes.
 *
 * THE DEFAULT STATE IS VISIBLE. The hidden state is applied by script, so a
 * reader with JavaScript off, or on a handset where the script did not
 * arrive, gets the whole page rather than a blank one. That failure mode is
 * the reason this is written the way round it is.
 */
.anim .reveal {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition:
    opacity   420ms cubic-bezier(0.16, 0.84, 0.44, 1) calc(var(--d, 0) * 70ms),
    transform 420ms cubic-bezier(0.16, 0.84, 0.44, 1) calc(var(--d, 0) * 70ms);
}
.anim .reveal.is-in {
  opacity: 1;
  transform: none;
}

/* Stagger is a CLASS, never an inline style attribute. Two reasons, and the
   second is the harder one: a Content Security Policy of style-src 'self'
   blocks an inline style attribute outright, so `style="--d:1"` would simply
   not apply and the failure would be silent. And a class can be overridden by
   a breakpoint, where an inline style is an argument the stylesheet has to
   win twice. */
.d1 { --d: 1; }
.d2 { --d: 2; }
.d3 { --d: 3; }
.d4 { --d: 4; }

/* TWO GATES, FACING OPPOSITE DIRECTIONS, and that is deliberate.
 *
 * The primary gate is in the head script: where reduced motion is asked for,
 * or IntersectionObserver is missing, the `anim` class is never added, so the
 * hidden state is never authored in the first place. An opt-out media query
 * cannot express "do not hide it at all"; it can only undo a hiding that has
 * already been written, and it undoes it a frame late.
 *
 * This block is the backstop for the case where the class got on anyway. Per
 * CLAUDE.md section 0f, an allow-list and a denylist each fail in exactly one
 * direction, so both are here on purpose rather than by duplication.
 *
 * The failure direction of both is VISIBLE CONTENT, never a blank page.
 */
@media (prefers-reduced-motion: reduce) {
  .anim .reveal,
  .anim .reveal.is-in {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}

/* THE ONE MOVING THING ON THE PAGE, and it moves because something is being
 * shown: the signal drops, the dot empties, the words appear, and the till
 * carries on unchanged around it. That is the whole argument of the page
 * performed once in three and a half seconds.
 *
 * IT RUNS ONCE AND STOPS, and that is not a taste decision. WCAG 2.2 SC 2.2.2
 * requires a pause, stop or hide control for anything that moves or blinks for
 * longer than five seconds. A looping dot would have needed one. A gesture that
 * completes and rests needs nothing, and it also reads better: a loop says
 * "decoration", a single change says "something happened".
 *
 * The resting state is authored in the markup as `dot--hollow` with the words
 * present, so with no animation at all, under reduced motion, or if the
 * stylesheet arrives late, the scene is simply already in its end state. */
.dot--switch    { animation: hollow  2.8s ease 0.9s 1 both; }
.till__status--late { animation: appear 2.8s ease 0.9s 1 both; }

@keyframes hollow {
  0%, 59%   { background: var(--money); border-color: var(--money); }
  60%, 100% { background: transparent;  border-color: var(--ink-soft); }
}
@keyframes appear {
  0%, 59%   { opacity: 0; }
  60%, 100% { opacity: 1; }
}

.print-only { display: none; }
@media print {
  body { background: #fff; }
  .k-skip, .cta { display: none; }
  .print-only { display: block; }
  .anim .reveal { opacity: 1; transform: none; }
  .act--deep, .k-foot, .doc-head { background: #fff; color: #000; }
  .act--deep .kicker, .doc-head .brand__by, .k-foot a { color: #000; }
}

/* Table caption. A class rather than an inline style attribute: style-src
   'self' blocks an inline style outright, and it fails silently. */
.tcap {
  text-align: left;
  padding-bottom: 10px;
  font-size: 15px;
  color: var(--ink-soft);
}

/* ---- THE HERO ON A PHONE ------------------------------------------------
 * On a wide screen the copy and the till sit side by side, so the product is
 * on the first screen either way. On a phone, stacking them in source order
 * puts roughly 700px of type above the till, and the first screen becomes an
 * index of sentences: exactly the library the house rule forbids.
 *
 * So below 860px the copy column is DISSOLVED with display:contents and its
 * children are re-ordered around the device, which slots in after the
 * headline. The promise, then the thing itself, then the detail.
 *
 * The grid gap goes to zero at the same time, because with the column
 * dissolved the gap would apply between every individual paragraph. Spacing
 * is carried by the elements' own margins, which is where it already was.
 */
@media (max-width: 859px) {
  .hero__grid { gap: 0; }
  .hero__copy { display: contents; }

  .hero__copy .kicker   { order: 1; }
  .hero h1              { order: 2; }
  .hero__device         { order: 3; margin: 4px 0 26px; }
  .hero__copy .lede     { order: 4; }
  .hero__copy .cta-row  { order: 5; margin-top: 4px; }
  .hero__copy .hero__aside { order: 6; margin-top: 26px; }
}

/* A horizontally scrolling region must be reachable from the keyboard, or the
   rows past the fold are unreadable to anyone not using a pointer. WCAG 2.2
   SC 2.1.1. tabindex="0" and a name are on the element in the markup; this
   makes the focus visible when it lands there. */
.scroller:focus-visible {
  outline: 3px solid var(--money);
  outline-offset: 4px;
}

/* ---- DARK GROUNDS REMAP THE TOKENS, THEY DO NOT OVERRIDE CLASS BY CLASS ----
 *
 * Found by looking at the rendered footer rather than at the stylesheet: the
 * disclaimer under the footer brand was `.small`, which is --ink-soft, which is
 * #4A4A42 on #0A2A1B. That measures 1.73:1. It fails AA outright, never mind
 * the 7.0 house floor, and it failed because `.act--deep .small` existed while
 * `.k-foot .small` did not.
 *
 * The lesson, per CLAUDE.md section 0f: a list of per-class overrides is a
 * denylist of the things somebody remembered, and it fails silently on the one
 * nobody thought of. Every new element added to a dark ground would have needed
 * its own line, and the day one is forgotten nothing goes red.
 *
 * So the dark grounds redefine the TOKENS instead. Any rule written for the
 * paper ground is then automatically correct here, including rules written
 * after this one. Measured on the served bytes: --deep-ink 13.4:1,
 * --deep-soft 8.9:1, --deep-accent 8.7:1, all against --deep.
 */
.act--deep,
.k-foot,
.doc-head {
  --ink:         var(--deep-ink);
  --ink-soft:    var(--deep-soft);
  --money:       var(--deep-accent);
  --rule:        var(--deep-rule);
  --ground:      var(--deep);
  --ground-sunk: var(--deep);
}

/* The one thing the remap cannot do on its own: a filled button takes its text
   colour from a literal white, which is wrong on a light green. */
.act--deep .cta,
.k-foot .cta { background: var(--deep-accent); color: var(--deep); }

.k-foot .brand__name { color: var(--deep-ink); }

/* Footer navigation links are one per line, so they are targets rather than
   links inside a sentence, and the inline exception to WCAG 2.2 SC 2.5.8 does
   not cover them. At 15px and line-height 1.55 each measured 23.25px high,
   which is under the 24x24 minimum by three quarters of a pixel. Padding takes
   them to 31px. (24x24 is the AA figure, SC 2.5.8. 44x44 is AAA, SC 2.5.5.) */
.k-foot li { margin-bottom: 4px; }
.k-foot li a {
  display: inline-block;
  padding: 4px 0;
}

/* The back link in a document header is the only navigation on that page, so
   it is a target and not a link inside a sentence. Measured at 109x23, three
   quarters of a pixel under the 24x24 minimum. */
.doc-head .brand__name a {
  display: inline-block;
  padding: 3px 0;
}

/* =====================================================================
   PHOTOGRAPHY. Added 11 September 2026.

   The page shipped with nine sections and not one photograph, which is a
   library and not a film. Two kinds of picture, doing two different jobs:

     .scene   a full-bleed photograph of the world this product is for.
              It opens an act. The eye lands on it before it reads.
     .shot    the product itself, photographed rather than drawn: a real
              screenshot of the running application, in a phone-shaped
              frame, at the size a phone actually is.

   The alternation is the pacing. Scene, then product, then scene: the
   page shows you the counter it is talking about, then what the counter
   holds. White space between them is the cut.
   ===================================================================== */

.scene {
  margin: 0 0 var(--beat);
  position: relative;
  overflow: hidden;
  border-radius: 14px;
  background: var(--ground-sunk);
}
.scene img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}
/* Wide viewports get a letterbox rather than a square, because a square
   photograph on a desktop is a hole in the page. */
@media (min-width: 720px) {
  .scene img { aspect-ratio: 16 / 9; }
}
.scene figcaption,
.shot figcaption {
  margin-top: 10px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-soft);
}
.act--deep .scene figcaption,
.act--deep .shot figcaption { color: var(--deep-soft); }

/* The product, at the size it is really used. Never wider than a phone,
   because a screenshot blown up to fill a desktop column is a lie about
   how big the type is. */
.shot {
  margin: 0 0 var(--beat);
  max-width: 300px;
}
.shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 18px;
  border: 1px solid var(--rule);
  background: var(--ground);
}
.act--deep .shot img { border-color: var(--deep-rule); }

/* Side by side once there is room: the photograph of the world on one
   side and the product on the other, which is the whole argument in one
   glance. Below that they stack and the order still reads. */
.pair {
  display: grid;
  gap: var(--gap);
  align-items: start;
}
@media (min-width: 860px) {
  .pair { grid-template-columns: 1.35fr 1fr; gap: 28px; }
  .pair .scene, .pair .shot { margin-bottom: 0; }
  .pair .shot { max-width: 280px; justify-self: center; }
}

/* THE ESTABLISHING SHOT.

   The first attempt put the photograph BEHIND the hero under a scrim heavy
   enough to hold 7:1 text over it, and at that weight the picture was all but
   invisible: a 171 KB image spent on a texture nobody could see. A scrim that
   protects contrast and destroys the photograph has failed at the only job it
   had.

   So the photograph is not behind the words. It is BEFORE them, full bleed,
   the way a film opens on a place before anybody speaks. Contrast stops being
   a problem because no text sits on it, and the picture gets to be a picture. */
.establish {
  margin: 0;
  width: 100%;
  overflow: hidden;
  background: var(--ground-sunk);
}
.establish img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: 50% 46%;
}
@media (min-width: 720px) {
  .establish img { aspect-ratio: 21 / 9; object-position: 50% 42%; }
}

@media (prefers-reduced-motion: reduce) {
  .scene img, .shot img { transition: none; }
}
