/* Dojo 12 — paper and ink (ART.md). A sheet of washi, sumi ink, one vermilion
   seal. Nothing is plastic, glass or lit from behind: depth is a hard 2 px ink
   offset, never a blur, and red is a reward, never a warning. Colours live in
   themes.css; this file is material and layout only. */

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body {
  margin: 0; padding: 0; height: 100%;
  overflow-x: clip;
  background-color: var(--paper);
  color: var(--ink);
  font: 500 17px/1.4 "Zen Kaku Gothic New", "Hiragino Sans", system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
  overscroll-behavior: none;
  -webkit-text-size-adjust: 100%;
}
/* Paper has fibre. Flat cream with nothing in it reads as a wireframe (Okami). */
body {
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  background-image:
    radial-gradient(var(--grainA) 0.5px, transparent 0.6px),
    radial-gradient(var(--grainB) 1px, transparent 1.2px);
  background-size: 5px 5px, 17px 13px;
  background-position: 0 0, 3px 7px;
}
#app {
  position: relative; min-height: 100%;
  display: flex; flex-direction: column;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}
.screen { flex: 1; display: flex; flex-direction: column; padding: 16px 16px 14px; gap: 12px; }
/* The round, round 1 and the belt test are exactly one phone tall, so the card
   takes what the keypad leaves instead of pushing it off the bottom. */
.screen.fit {
  flex: none; min-height: 0;
  height: calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  height: calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
}
.grow { flex: 1 1 auto; min-height: 0; }
.row { display: flex; align-items: center; gap: 10px; }
.col { display: flex; flex-direction: column; }
.between { justify-content: space-between; }
.centre { align-items: center; justify-content: center; text-align: center; }
.wrapx { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.hidden { display: none !important; }

/* ---- type: 13 · 15 · 17 · 22 · 30 · 44 · 64, and nothing between ---- */
.t13 { font-size: 13px; }
.t15 { font-size: 15px; }
.t17 { font-size: 17px; }
.t22 { font-size: 22px; font-weight: 700; }
.t30 { font-size: 30px; font-weight: 900; }
.t44 { font-size: 44px; font-weight: 900; letter-spacing: -0.5px; }
.t64 { font-size: 64px; font-weight: 900; letter-spacing: -1px; }
.dim { color: var(--ink2); }
.mincho { font-family: "Shippori Mincho", "Hiragino Mincho ProN", "Yu Mincho", serif; font-weight: 600; }
.num { font-variant-numeric: tabular-nums; font-weight: 900; }
.label { font-size: 13px; color: var(--ink2); font-weight: 500; }
.lines { display: flex; flex-direction: column; gap: 7px; }

/* A screen title sits inside a black brush stroke (Ghost of Tsushima). */
.titlebar {
  background: var(--ink); color: var(--onInk);
  font-family: "Shippori Mincho", "Hiragino Mincho ProN", serif; font-weight: 600;
  font-size: 22px; line-height: 1.25; padding: 6px 16px 8px;
  width: fit-content; max-width: 100%; text-wrap: balance;
  clip-path: polygon(0 8%, 2% 0, 58% 4%, 98% 0, 100% 12%, 99% 90%, 97% 100%, 38% 96%, 1% 100%, 0 92%);
}

/* ---- keys, buttons and links ---- */
button { font: inherit; color: inherit; border: 0; background: none; touch-action: manipulation; cursor: pointer; }
.btn {
  background: var(--paper);
  color: var(--ink);
  border: 1.5px solid var(--ink);
  border-radius: 4px;
  padding: 13px 16px;
  font-weight: 700; font-size: 17px;
  box-shadow: 2px 2px 0 var(--ink);
  transition: transform 60ms ease, box-shadow 60ms ease;
  text-align: center;
}
.btn:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
.btn.wide { width: 100%; }
.btn.ink { background: var(--ink); color: var(--onInk); font-size: 22px; font-weight: 900; padding: 17px; box-shadow: none; }
.btn.ink:active { transform: translate(2px, 2px); }
.btn.shu { background: var(--shu); color: var(--onInk); border-color: var(--ink); }
.btn.quiet { background: transparent; border-color: var(--ink2); box-shadow: none; color: var(--ink2); font-weight: 500; }
.btn.dim { opacity: 0.55; }
.btn:focus-visible { outline: 2px solid var(--shu); outline-offset: 2px; }
.link {
  background: none; border: 0; padding: 4px 0; color: var(--ink); font-weight: 700; font-size: 17px;
  border-bottom: 2px solid var(--ink); border-radius: 0;
}
.link.small { font-size: 13px; font-weight: 500; color: var(--ink2); border-bottom-color: var(--ink2); }
.navrow { display: flex; gap: 18px; justify-content: space-between; }
.field {
  width: 100%; background: transparent; color: var(--ink);
  border: 0; border-bottom: 2px solid var(--ink); border-radius: 0;
  font: 700 22px/1.3 "Zen Kaku Gothic New", "Hiragino Sans", system-ui, sans-serif;
  padding: 8px 2px; outline: none;
}
.field::placeholder { color: var(--ink2); font-weight: 500; font-size: 17px; }
.tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }

/* ---- the seal, the coin, the belt ---- */
.seal {
  background: var(--shu); color: var(--onInk);
  font-weight: 900; font-size: 13px; line-height: 1;
  padding: 5px 6px; border-radius: 3px;
  box-shadow: inset 0 0 0 2px var(--shu), inset 0 0 0 3px var(--paper);
  transform: rotate(-3deg);
}
.seal.big { font-size: 17px; padding: 8px 9px; }
/* The coin: an old Japanese coin, gold with a square hole, the same drawing everywhere (§13.3). */
.coin {
  display: inline-block; width: 15px; height: 15px; border-radius: 50%;
  border: 1.5px solid var(--ink); background: var(--kin); position: relative; vertical-align: -2px; flex: none;
}
.coin::after { content: ""; position: absolute; inset: 4px; border: 1.5px solid var(--ink); background: var(--paper); }
/* The belt drawn as a belt: two loose tips, the cloth, the black bar the stripes are taped on. */
.beltband { display: flex; align-items: stretch; height: 24px; }
.beltband.tall { height: 32px; }
.beltband > .tip { flex: 0 0 14px; background: var(--belt-white); border: 1.5px solid var(--ink); border-radius: 2px 0 0 2px; transform: skewX(-18deg); margin-right: -3px; }
.beltband > .tip:last-child { border-radius: 0 2px 2px 0; transform: skewX(18deg); margin-right: 0; margin-left: -3px; background: var(--belt-bar); }
.b-black > .tip:last-child { background: var(--shu); }
.beltband > .cloth { flex: 1 1 auto; background: var(--belt-white); border: 1.5px solid var(--ink); border-right: 0; }
.beltband > .bar { flex: 0 0 40%; background: var(--belt-bar); border: 1.5px solid var(--ink); border-left: 0; display: flex; align-items: center; gap: 5px; padding: 0 7px; }
.beltband > .bar > i { width: 7px; height: 100%; background: var(--belt-tape); }
.beltband > .bar > i.new { animation: stripeOn 520ms ease-out; }
@keyframes stripeOn { 0% { transform: scaleY(0); } 60% { transform: scaleY(1.2); } 100% { transform: scaleY(1); } }
.b-white > .tip:first-child, .b-white > .cloth { background: var(--belt-white); }
.b-blue > .tip:first-child, .b-blue > .cloth { background: var(--belt-blue); }
.b-purple > .tip:first-child, .b-purple > .cloth { background: var(--belt-purple); }
.b-brown > .tip:first-child, .b-brown > .cloth { background: var(--belt-brown); }
.b-black > .tip:first-child, .b-black > .cloth { background: var(--belt-black); }
.b-black > .bar { background: var(--shu); }
/* The bar under the belt: sealed questions solid, questions fast once pale. */
.bar-fill { height: 9px; background: var(--paper2); border: 1.5px solid var(--ink); border-radius: 2px; overflow: hidden; position: relative; }
.bar-fill > i { display: block; height: 100%; background: var(--ink); position: absolute; left: 0; top: 0; transition: width 400ms ease; }
.bar-fill > i.pale { background: var(--ink2); opacity: 0.45; }

/* ---- home ---- */
.home-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; }
.home-name { font-family: "Shippori Mincho", "Hiragino Mincho ProN", serif; font-weight: 600; font-size: 30px; }
.xpline { height: 5px; background: var(--paper2); border: 1px solid var(--rule); overflow: hidden; border-radius: 2px; }
.xpline > i { display: block; height: 100%; background: var(--ink); }
.plate { position: relative; border: 1.5px solid var(--ink); border-radius: 4px; padding: 13px 14px; display: flex; flex-direction: column; gap: 9px; background: var(--paper); }
.plate.lift { box-shadow: 2px 2px 0 var(--ink); }
.mark { width: 22px; height: 22px; display: inline-block; }
.mark svg { width: 100%; height: 100%; display: block; }

/* ---- the round ---- */
.runtop { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 30px; }
.runscore { font-size: 22px; font-weight: 900; }
/* The score with its word beside it: "110 points". */
.scorebox { display: flex; align-items: baseline; gap: 5px; }
.streak { display: flex; align-items: center; gap: 7px; }
.mult { background: var(--shu); color: var(--onInk); font-weight: 900; font-size: 13px; padding: 3px 6px; border-radius: 3px; }
[data-combo="ink"] .mult { background: var(--ink); }
[data-combo="round"] .mult { border-radius: 50%; padding: 5px 6px; }
[data-combo="gold"] .mult { background: var(--kin); color: var(--onKin, var(--ink)); }
/* The card dots (brush kit): a ring for a card not yet answered, the one on the screen
   in ink and a little larger, the ones to come quiet in --rule; a brush dot for a card
   answered, in ink, red when the answer counted toward a seal, --ink2 for a miss. */
.pips { display: flex; gap: 9px; flex-wrap: nowrap; justify-content: center; align-items: center; height: 19px; }
.pips > i {
  display: block; flex: none; width: 15px; height: 15px; background-color: var(--rule);
  -webkit-mask: url(../img/ring.webp) center / 100% 100% no-repeat; mask: url(../img/ring.webp) center / 100% 100% no-repeat;
}
.pips > i.done, .pips > i.fast, .pips > i.miss { -webkit-mask-image: url(../img/dot.webp); mask-image: url(../img/dot.webp); }
.pips > i.done { background-color: var(--ink); }
.pips > i.fast { background-color: var(--shu); }
.pips > i.miss { background-color: var(--ink2); }
.pips > i.now { background-color: var(--ink); width: 17px; height: 17px; }
/* The black belt test has twenty-four cards to a row. */
.pips.many { gap: 3px; height: 13px; }
.pips.many > i { width: 9px; height: 9px; }
.pips.many > i.now { width: 11px; height: 11px; }

.cardwrap { flex: 1 1 0px; min-height: 0; display: flex; align-items: center; justify-content: center; position: relative; }
.card {
  position: relative; width: 100%; max-width: min(330px, 100%); max-height: 100%; aspect-ratio: 1;
  background-color: var(--paper);
  border: 1.5px solid var(--ink); border-radius: 4px;
  box-shadow: 2px 2px 0 var(--ink);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  overflow: hidden;
}
[data-skin="grain"] .card { background-image: radial-gradient(var(--grainA) 1px, transparent 1.4px); background-size: 7px 7px; }
[data-skin="grid"] .card { background-image: linear-gradient(var(--grainB) 1px, transparent 1px), linear-gradient(90deg, var(--grainB) 1px, transparent 1px); background-size: 22px 22px; }
[data-skin="wave"] .card { background-image: radial-gradient(circle at 50% 100%, transparent 9px, var(--grainB) 9px, var(--grainB) 10px, transparent 10px); background-size: 24px 14px; }
[data-skin="hemp"] .card { background-image: linear-gradient(45deg, var(--grainB) 1px, transparent 1px), linear-gradient(-45deg, var(--grainB) 1px, transparent 1px); background-size: 18px 18px; }
[data-skin="gilt"] .card { box-shadow: 2px 2px 0 var(--ink), inset 0 0 0 3px var(--kin); }
.cardlabel { font-size: 13px; color: var(--ink2); min-height: 16px; }
.question { font-size: calc(clamp(28px, calc(var(--cs, 320px) * 0.2), 64px) * var(--qs, 1)); font-weight: 900; letter-spacing: -1px; line-height: 1.1; white-space: nowrap; }
.question.words { font-size: clamp(15px, calc(var(--cs, 320px) * 0.085), 30px); line-height: 1.25; text-align: center; padding: 0 18px; letter-spacing: 0; white-space: normal; }
/* The operators, drawn at the numerals' weight: 0.46 em square, a 0.12 em stroke
   (the stem of a 900 numeral), centred 0.35 em above the baseline (the numerals'
   cap height is 0.70 em). */
.question .op { display: inline-block; position: relative; width: 0.46em; height: 0.46em; margin: 0 0.24em; vertical-align: 0.12em; }
.question .op svg { display: block; width: 100%; height: 100%; overflow: visible; }
.question .op path { fill: none; stroke: currentColor; stroke-width: 26; }
.question .op circle { fill: currentColor; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.typed { font-size: clamp(22px, calc(var(--cs, 320px) * 0.13), 44px); font-weight: 900; min-height: 1.2em; color: var(--ink); }
.slots { display: flex; gap: 8px; height: 14px; align-items: flex-end; }
.slots > i { width: 26px; height: 3px; background: var(--rule); }
.slots > i.on { background: var(--ink); }
/* The answer on a round card: the digits in ink at the numerals' weight, set together
   on one short ink line right under the sum. The line is as long as the answer, so it
   still shows how many digits to type (review 2026-09-24). */
.answer { display: flex; align-items: flex-end; justify-content: center; gap: 0.42em;
  font-size: clamp(22px, calc(var(--cs, 320px) * 0.13), 44px); font-weight: 900; line-height: 1.12; }
.answer .slots { height: auto; gap: 0; align-items: flex-end; padding: 0 0.12em; border-bottom: 0.085em solid var(--ink); }
.answer .slots > i {
  display: block; width: 0.52em; height: 1.12em; background: none; text-align: center; font-style: normal; color: var(--ink);
}
.answer .slots > i.on { background: none; }
/* The shown answer in pencil, inked over digit by digit as it is typed. */
.answer .slots > i[data-hint]:not(.on)::before, .answer .typed[data-hint]:empty::before {
  content: attr(data-hint); color: var(--ink2); opacity: 0.45;
}
.answer .typed { display: none; min-height: 0; }
.answer.free .slots { display: none; }
.answer.free .typed { display: block; min-width: 1.3em; height: 1.12em; padding: 0 0.1em; text-align: center; border-bottom: 0.085em solid var(--ink); }
/* A miss: what was typed stays, and one dry stroke goes through it in 90 ms. */
.answer .wrong { display: none; position: relative; height: 1.12em; color: var(--ink2); }
.answer.missed .wrong { display: block; }
.answer.missed .slots, .answer.missed .typed { display: none; }
.answer.missed.reveal .slots { display: flex; }
.answer.missed.reveal.free .typed { display: block; }
/* The kit's strike keeps its own proportions (512:96) and runs 16 % past the number each
   side, but never shorter than 1.5 em, so a one-digit answer still gets a whole stroke
   rather than a stub. Centred on the numerals' cap height (0.65 em down the line). */
.answer .wrong .strike {
  position: absolute; left: 50%; top: 0.65em; width: max(1.5em, 132%); aspect-ratio: 512 / 96;
  transform: translate(-50%, -46%); background-color: var(--ink);
  -webkit-mask: url(../img/strike.webp) center / 100% 100% no-repeat; mask: url(../img/strike.webp) center / 100% 100% no-repeat;
  animation: strike 90ms linear both;
}
@keyframes strike { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
.stepline { font-size: 17px; font-weight: 700; text-align: center; padding: 0 14px; }


/* The ensō timer (brush kit, art/kit/out/brush/README.md, tested in Chrome 153 and iOS
   18.6 Safari). Two layers of one brush mask: .trail, the whole stroke faint, the time
   already spent; .left, the stroke in solid ink from the head to the cut, the time left.
   One custom property drives it, --left from 1 (full) to 0 (empty). The cut is a
   conic-gradient intersected with the brush mask: the timer runs clockwise from 124.5 deg
   (maths angle) for 336 deg, the conic starts in the stroke's gap (bearing 313.5 deg) so the
   cut sits 12 deg into it at --left 0 and 348 deg at 1, and the ink fades over 2.5 deg either
   side of the cut. The box must be square (the card is): the mask fills it 100 x 100 %,
   and mask-size: contain leaves a band on iOS. Never red; the streak no longer thickens it. */
.enso-t { position: absolute; inset: 7%; pointer-events: none; }
.enso-t > i {
  position: absolute; inset: 0; display: block;
  -webkit-mask-size: 100% 100%; -webkit-mask-repeat: no-repeat; -webkit-mask-position: center;
  mask-size: 100% 100%; mask-repeat: no-repeat; mask-position: center;
}
.enso-t > .trail { background-color: var(--ink2); opacity: 0.22; }
.enso-t > .left {
  background-color: var(--ink);
  --cut: calc(12deg + 336deg * var(--left, 1));
  --cutmask: conic-gradient(from 313.5deg, #000 calc(var(--cut) - 2.5deg), transparent calc(var(--cut) + 2.5deg));
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
/* One pair of rules a timer, the url written out each time (a url kept in a custom
   property can resolve against the page). Brush is the free timer and the default. */
.enso-t > .trail { -webkit-mask-image: url(../img/enso-brush.webp); mask-image: url(../img/enso-brush.webp); }
.enso-t > .left { -webkit-mask-image: url(../img/enso-brush.webp), var(--cutmask); mask-image: url(../img/enso-brush.webp), var(--cutmask); }
[data-ring="thin"] .enso-t > .trail { -webkit-mask-image: url(../img/enso-pen.webp); mask-image: url(../img/enso-pen.webp); }
[data-ring="thin"] .enso-t > .left { -webkit-mask-image: url(../img/enso-pen.webp), var(--cutmask); mask-image: url(../img/enso-pen.webp), var(--cutmask); }
[data-ring="double"] .enso-t > .trail { -webkit-mask-image: url(../img/enso-double.webp); mask-image: url(../img/enso-double.webp); }
[data-ring="double"] .enso-t > .left { -webkit-mask-image: url(../img/enso-double.webp), var(--cutmask); mask-image: url(../img/enso-double.webp), var(--cutmask); }
[data-ring="dotted"] .enso-t > .trail { -webkit-mask-image: url(../img/enso-dotted.webp); mask-image: url(../img/enso-dotted.webp); }
[data-ring="dotted"] .enso-t > .left { -webkit-mask-image: url(../img/enso-dotted.webp), var(--cutmask); mask-image: url(../img/enso-dotted.webp), var(--cutmask); }
[data-ring="gold"] .enso-t > .left { background-color: var(--kin); }
/* The ticks, on the same box as the mask: the gold one where fast ends, the small ink one
   at the child's best time. On the Gold timer the gold mark is edged in ink, so it is
   still the gold mark the child knows and does not sink into the gold stroke. */
.enso-ticks { position: absolute; inset: 7%; width: 86%; height: 86%; pointer-events: none; overflow: visible; }
.enso-ticks line { stroke-linecap: butt; }
.enso-ticks .gold { stroke: var(--kin); stroke-width: 1.7; }
.enso-ticks .best { stroke: var(--ink); stroke-width: 1.1; }
.enso-ticks .gold-edge { display: none; stroke: var(--ink); stroke-width: 2.9; }
[data-ring="gold"] .enso-ticks .gold-edge { display: inline; }

.diagline { min-height: 40px; font-size: 15px; display: flex; align-items: center; justify-content: center; text-align: center; }
.missbtns { display: flex; gap: 9px; }
.missbtns > button { flex: 1; }
.missbtns.idle { visibility: hidden; }

/* ---- keypad ---- */
.padwrap { display: flex; flex-direction: column; gap: 7px; }
.keypad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; }
.keyrow { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; }
.keyrow.big { grid-template-columns: repeat(2, 1fr); }
.key {
  background: var(--paper2); color: var(--ink);
  border: 1.5px solid var(--ink); border-radius: 4px;
  box-shadow: 2px 2px 0 var(--ink);
  font-weight: 900; font-size: 22px; padding: 12px 0;
  transition: transform 60ms ease, box-shadow 60ms ease;
}
.key:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
.key.fn { font-size: 17px; font-weight: 700; background: var(--paper); }
.key.go { background: var(--ink); color: var(--onInk); }
.key.no { background: var(--paper); color: var(--ink); }

/* ---- the end of a round ---- */
.sumline { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 15px; }
.sumline .v { font-weight: 900; }

/* ---- the grid ---- */
table.grid { border-collapse: collapse; }
table.grid th { font-size: 13px; font-weight: 500; color: var(--ink2); padding: 2px 4px; }
/* One square a question, reading left to right: blank, an outline, half, the seal (§13.3). */
table.grid td { width: 26px; height: 26px; padding: 0; background: transparent; border: 1px solid var(--rule); position: relative; }
table.grid td::after { content: ""; position: absolute; inset: 5px; border-radius: 50%; }
table.grid td.na::after { display: none; }
/* A question no open table covers yet (2026-09-26), as the child's Grid draws it. */
table.grid td.later { border-style: dotted; border-color: var(--ink2); }
table.grid th.later { opacity: 0.55; }
table.grid td:not(.na):not(.s-fast):not(.s-sealed)::after { border: 1.5px solid var(--ink2); }
table.grid td.s-fast::after { border: 1.5px solid var(--ink); background: linear-gradient(90deg, var(--ink) 50%, transparent 50%); }
table.grid td.s-sealed::after { background: var(--shu); box-shadow: inset 0 0 0 2px var(--shu), inset 0 0 0 3.5px var(--paper); }
table.grid td.pick { border: 2px solid var(--ink); }
table.grid th:first-child { white-space: nowrap; }
.legend { display: flex; flex-wrap: wrap; gap: 12px; font-size: 13px; color: var(--ink2); align-items: center; }
.legend span { display: flex; align-items: center; gap: 6px; }
.legend i { width: 15px; height: 15px; border-radius: 50%; border: 1.5px solid var(--ink2); display: block; }
.legend i.na { border: 1px solid var(--rule); border-radius: 0; }
.legend i.s-fast { border-color: var(--ink); background: linear-gradient(90deg, var(--ink) 50%, transparent 50%); }
.legend i.s-sealed { background: var(--shu); border-color: var(--shu); box-shadow: inset 0 0 0 2px var(--shu), inset 0 0 0 3.5px var(--paper); }
.seg { display: flex; gap: 9px; }
.seg > button { flex: 1; }
.seg > button.on { background: var(--ink); color: var(--onInk); }

/* ---- the belt ladder ---- */
.rung { display: flex; align-items: center; gap: 12px; padding: 9px 0; border-top: 1px solid var(--rule); }
.rung:first-child { border-top: 0; }
.rung .name { font-size: 17px; font-weight: 700; width: 5.2rem; }
.rung .band { flex: 1 1 auto; }
.rung.now .name { color: var(--shu); }
.rung.done { opacity: 0.55; }

/* ---- the shop ---- */
.shopitem { display: flex; align-items: center; justify-content: space-between; gap: 11px; width: 100%; text-align: left; }
.shopitem .right { font-size: 13px; color: var(--ink2); white-space: nowrap; }
.shopitem.on { border-left: 6px solid var(--shu); }
.swatch { width: 26px; height: 26px; border: 1.5px solid var(--ink); border-radius: 3px; display: inline-block; flex: none; background: var(--paper2); }

/* ---- effects ---- */
@keyframes pop { 0% { transform: scale(1); } 45% { transform: scale(1.06); } 100% { transform: scale(1); } }
.pop { animation: pop 140ms ease-out; }
@keyframes splat { 0% { transform: scale(0.2); opacity: 0.9; } 60% { transform: scale(1.1); opacity: 0.75; } 100% { transform: scale(1); opacity: 0; } }
.splat { position: fixed; border-radius: 50%; background: var(--ink); pointer-events: none; z-index: 40; animation: splat 320ms ease-out forwards; }
@keyframes fade { to { opacity: 0; } }
@keyframes slam { 0% { transform: scale(1.6) rotate(-6deg); opacity: 0; } 60% { transform: scale(0.96) rotate(-3deg); opacity: 1; } 100% { transform: scale(1) rotate(-3deg); opacity: 1; } }
.floatnum { position: fixed; font-weight: 900; font-size: 26px; z-index: 40; pointer-events: none;
  transition: transform 560ms ease-out, opacity 560ms ease-out; }
.toast {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: calc(22px + env(safe-area-inset-bottom));
  background: var(--ink); color: var(--onInk); padding: 10px 14px; border-radius: 4px;
  font-size: 15px; z-index: 50; max-width: calc(100% - 32px); text-align: center;
}
.holdbar { position: relative; overflow: hidden; }
/* Holding to leave draws an ink line along the button's foot: never a see-through red
   fill (ART.md: no translucent panels, red is never a warning). */
.holdbar > .fill { position: absolute; left: 0; bottom: 0; width: 0; height: 2px; background: var(--ink); }

/* ---- the install screen ---- */
.shot { color: var(--ink); }

@media (prefers-reduced-motion: reduce) {
  .splat, .answer .wrong .strike, .cardseal.press.fast .hanko-pencil { animation: none; }
}

/* ---- shop swatches ---- */
.swatch.sw-skin.v-grain { background-image: radial-gradient(var(--grainA) 1px, transparent 1.4px); background-size: 6px 6px; }
.swatch.sw-skin.v-grid { background-image: linear-gradient(var(--grainB) 1px, transparent 1px), linear-gradient(90deg, var(--grainB) 1px, transparent 1px); background-size: 8px 8px; }
.swatch.sw-skin.v-wave { background-image: radial-gradient(circle at 50% 100%, transparent 4px, var(--grainB) 4px, var(--grainB) 5px, transparent 5px); background-size: 10px 6px; }
.swatch.sw-skin.v-hemp { background-image: linear-gradient(45deg, var(--grainB) 1px, transparent 1px), linear-gradient(-45deg, var(--grainB) 1px, transparent 1px); background-size: 8px 8px; }
.swatch.sw-skin.v-gilt { box-shadow: inset 0 0 0 3px var(--kin); }
.swatch.sw-combo.v-ink { background: var(--ink); }
.swatch.sw-combo.v-round { background: var(--shu); border-radius: 50%; }
.swatch.sw-combo.v-gold { background: var(--kin); }
.swatch.sw-sound { background: var(--paper2); }

/* ---- the seal on a card (review 2026-09-24): the kit's hanko stack at the card's top
   right, turned -3deg (art/kit/out/seal/README.md). Halfway: the pencil square where the
   seal will go, in pencil, and in full ink when a fast answer now would seal it: never a
   red border, red is only ever the seal itself. Sealed: the icon's stone with the ensō cut
   in it (never the "12", which read as an answer) on its pencil square, slammed down with the thump. A lost seal lifts off and leaves the pencil
   square; a halfway mark lost to a miss is rubbed out. Every seal file holds its stone at
   10/13 of the box, so the stamp lands inside its square. ---- */
.cardseal { position: absolute; top: 6%; right: 6%; pointer-events: none; }
.cardseal .hanko-stack {
  position: relative; display: block; transform: rotate(-3deg);
  width: clamp(32px, calc(var(--cs, 330px) * 0.145), 48px); height: clamp(32px, calc(var(--cs, 330px) * 0.145), 48px);
}
.cardseal .hanko-stack > i {
  position: absolute; inset: 0; width: auto; height: auto; visibility: hidden;   /* kit.css sizes .hanko at 52 px */
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
}
.cardseal .hanko-pencil { background-color: var(--ink2); -webkit-mask-image: url(../img/seal-outline.webp); mask-image: url(../img/seal-outline.webp); }
.cardseal .hanko { background-color: var(--shu); -webkit-mask-image: url(../img/seal-enso.webp); mask-image: url(../img/seal-enso.webp); }
.cardseal.fast .hanko-pencil, .cardseal.sealed .hanko-pencil, .cardseal.erase .hanko-pencil { visibility: visible; }
.cardseal.sealed .hanko { visibility: visible; }
.cardseal.fast.lit .hanko-pencil { background-color: var(--ink); }
.cardseal.press.sealed .hanko { animation: hanko-slam 120ms ease-out both; }
.cardseal.press.fast .hanko-pencil { animation: pencil-in 200ms ease-out both; }
.cardseal.lift .hanko { animation: hanko-lift 460ms ease-in forwards; }
.cardseal.erase .hanko-pencil { animation: pencil-out 380ms ease-in forwards; }
/* The kit's slam for a seal inside the already turned stack: on the page it still goes
   1.6x to 1x and -6deg to -3deg in 120 ms (ART.md), and comes to rest square in its frame. */
@keyframes hanko-slam { 0% { transform: scale(1.6) rotate(-3deg); opacity: 0; }
  60% { transform: scale(0.96) rotate(0deg); opacity: 1; } 100% { transform: none; opacity: 1; } }
@keyframes hanko-lift { 0% { transform: none; opacity: 1; } 100% { transform: translate(6px, -16px) rotate(8deg) scale(1.06); opacity: 0; } }
@keyframes pencil-in { from { opacity: 0; transform: scale(1.12); } to { opacity: 1; transform: none; } }
@keyframes pencil-out { to { opacity: 0; } }
.cardtime { font-size: 15px; font-weight: 700; color: var(--ink2); min-height: 20px; }
.cardtime.fast { color: var(--shu); }
.cardtime .pb { color: var(--ink2); font-size: 13px; font-weight: 500; margin-left: 8px; }
.key:disabled { cursor: default; }
/* While the card shows its result the keys stay exactly as they are and a tap does
   not even press in. At a miss the pad is dead and says so calmly: the keys lie flat
   on the paper, no offset, the digits in pencil, so the two buttons are the only
   raised, inked thing left (§13.2 #10). */
.padwrap.hold .key:active { transform: none; box-shadow: 2px 2px 0 var(--ink); }
.padwrap.off .key { box-shadow: none; transform: none; background: transparent; border-color: var(--rule); color: var(--ink2); }
.padwrap.off .key.go { background: transparent; color: var(--ink2); }
.shopitem .right.ask { color: var(--shu); font-weight: 700; }
.howto { display: flex; flex-direction: column; gap: 16px; }
.howrow { display: flex; gap: 12px; align-items: flex-start; }
.howglyph { flex: 0 0 96px; }
.howglyph svg { width: 96px; height: 40px; display: block; }
.fastticks { display: flex; gap: 3px; }
.fastticks > i { width: 5px; height: 14px; background: var(--shu); border-radius: 1px; }
.floatcoin { display: flex; align-items: center; gap: 4px; font-size: 17px; color: var(--ink); }
.floatcoin .coin { width: 20px; height: 20px; }   /* the seal kit's size for the coin that floats off the card */
@keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }
.shake { animation: shake 240ms ease-in-out; }
.howto h3 { margin: 0 0 3px; font: 600 17px/1.3 "Shippori Mincho", "Hiragino Mincho ProN", serif; }
.howto p { margin: 0; font-size: 15px; line-height: 1.5; }

/* words agent, 2026-09-24 ------------------------------------------------------------
   Plain structure for the review's words; the art pass restyles these. */
/* The ? on Home that opens How it works. Round, since only circles and dots are round. */
.helpbtn {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  border: 1.5px solid var(--ink); background: var(--paper); color: var(--ink);
  font-weight: 900; font-size: 17px; line-height: 1; padding: 0;
  box-shadow: 2px 2px 0 var(--ink);
}
.helpbtn:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
.home-head .home-name { overflow-wrap: anywhere; }
/* The bar under the belt: one cell a seal between the last stripe and the next,
   sealed solid, halfway half filled (D.belt.bar). */
.sealbar { display: flex; gap: 3px; height: 11px; }
.sealbar > i { flex: 1 1 0; position: relative; overflow: hidden; background: var(--paper2);
  border: 1.5px solid var(--ink); border-radius: 2px; }
.sealbar > i.sealed { background: var(--ink); }
.sealbar > i.half::after { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 50%;
  background: var(--ink2); opacity: 0.45; }
/* A score and its word, side by side. */
.row.scorerow { align-items: baseline; gap: 9px; }
/* What each belt takes, under its band on the Belt screen. */
.rungcol { flex: 1 1 auto; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.rungcol > .at { font-size: 13px; color: var(--ink2); text-align: right; }
/* The week's recap on Home, put away with OK. */
.plate.recap > .btn { align-self: flex-start; padding: 8px 18px; font-size: 15px; }
/* How it works: five panels. */
.howto > .howpanel { padding-bottom: 14px; border-bottom: 1px solid var(--rule); }
.howto > .howpanel:last-child { border-bottom: 0; padding-bottom: 0; }
