/* The artifact host supplied these; a standalone page has to declare them itself. */
*{box-sizing:border-box}
/* `light dark` hands the choice to the system. A forced theme has to pin it as well,
   or the one part of the page the page does not draw — the scrollbars, the form
   controls, the UA's own focus ring — stays in the room the rest of it just left. */
html{color-scheme:light dark}
html[data-theme="light"]{color-scheme:light}
html[data-theme="dark"]{color-scheme:dark}
img{max-width:100%}
[hidden]{display:none!important}

:root{
  --desk:#D6D1C4; --desk-2:#C6C0B0;
  /* the neutral stock, before a series is printed on it. --paper and the -0 greys are
     the untinted values a series mixes into; the names without the suffix are what
     everything paints with, so a series only has to restate those. */
  --paper:#FCFAF4; --paper-2:#F5F1E6;
  --edge-0:#BDB6A4; --rule-0:#8E897D; --rule-soft-0:#C2BCAE;
  /* The tracing ghost, and the one grey a series never touches. It is near enough to
     neutral to stay grey on all three stocks — the old warm grey was mixed for cream
     and went tan on the indigo card and pink on the celadon one — and dark enough to
     stay a step under a washed stock, which is some 25 points of luminance below cream. */
  --ghost-0:#C6C5C3;
  --stock:var(--paper); --stock-2:var(--paper-2);
  --edge:var(--edge-0); --rule:var(--rule-0);
  --rule-soft:var(--rule-soft-0); --ghost:var(--ghost-0);
  --ink:#16161A; --ink-2:#55524B; --ink-3:#8B857A;
  --shadow:0 1px 2px rgba(50,44,32,.16), 0 14px 30px -10px rgba(50,44,32,.38);
  --ui:#4A453C;
  /* the deck boxes. A box is cream stock in either theme, so the seal is stated once
     and only what the box casts onto the desk changes. The 和柄 ground is the one thing
     on a box that is not — it is printed in the series' ink further down, and this is
     the grey it was printed in before there were series, kept as the fallback: where
     color-mix() is not understood every declaration below falls back to the value it
     shadows, and this is the one --pat would otherwise have nothing to fall back to. */
  --pat:rgba(22,22,26,.13); --shu:#B2402A; --box-shade:rgba(52,44,30,.42);
  /* One face throughout. Klee One is a pen/textbook design, so its letterforms agree with
     the KanjiVG skeleton the stroke strip draws — a mincho would disagree with it (花's 艹
     is one connected bar in print, separate strokes by hand). --glyph-edge adds back the
     weight a mincho had, in cqw so it scales with the card. */
  --jp:"Klee One","Hiragino Kaku Gothic ProN","Yu Gothic",YuGothic,sans-serif;
  --jp-bold:600; --glyph-edge:.235cqw;
  --latin:ui-sans-serif,-apple-system,"Helvetica Neue",Arial,sans-serif;
  /* The card's shape, off the reference photo: 1380x1000, so 1.38 wide to 1 tall. It is
     stated once here because more than the card is cut to it — the two piles, a pile's
     top card, and the box on the chooser, which is the box these cards come in and is
     drawn at their proportion rather than near it. */
  --card-ar:1.38;
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --desk:#1A1714; --desk-2:#0E0C0A;
    --paper:#F7F3EA; --paper-2:#EDE8DB; --edge-0:#A79E8A;
    --shadow:0 2px 5px rgba(0,0,0,.55), 0 26px 52px -14px rgba(0,0,0,.75);
    --ui:#BCB4A6; --box-shade:rgba(0,0,0,.66);
  }
}
:root[data-theme="dark"]{
  --desk:#1A1714; --desk-2:#0E0C0A;
  --paper:#F7F3EA; --paper-2:#EDE8DB; --edge-0:#A79E8A;
  --shadow:0 2px 5px rgba(0,0,0,.55), 0 26px 52px -14px rgba(0,0,0,.75);
  --ui:#BCB4A6; --box-shade:rgba(0,0,0,.66);
}

/* ============ the three series, each on its own stock ============
   A workbook series is the same design printed on a different coloured cover per volume,
   and that is what this is. Each series states two values: --wash, the stock it is
   printed on, and --spot, the second ink everything printed on that stock is mixed
   from — the 和柄 ground, the hairlines, the band across a card's head.
   Nothing mixes into --ink, --shu or --ghost: the words stay black, the 印 stays 朱 and
   the tracing ghost stays grey in all three, because those are what the card is. Only
   the stock changes, which is the same thing as saying only the deck changes.

   What keeps it from getting loud is that the colour is the stock and the printing on
   it, and never the thing being read. The deck label is where that shows: it is a slip
   of paper pasted onto the box, so it stays on the plain stock, and the coloured ground
   makes it read more like a pasted label than it did on cream. The tracing ghost in the
   practice strip is the other: it is a guide to draw over, so it is the same neutral
   grey in all three series — a tinted ghost read as a second ink competing with the
   stroke being taught. The desk keeps out of it too — the desk is the room the cards
   are in, not one of them.

   Two values and not one, because ink and stock are separate choices. The ink is
   saturated, since it is mixed into warm greys and a grey eats chroma: a muted ink into
   a muted grey came out as the grey. The wash is the same hue at the paper's own
   lightness, so the stock changes colour without changing how dark it is — mixing the
   ink into the paper instead made each deck's card as much darker as its ink happened
   to be, which is a difference nobody chose.

   The three inks are a progression, not three unrelated hues, because the rows are
   stacked and read in order:
     ひらがな 藍     — 青海波 has 青 in its name; the wave pattern in indigo.
     カタカナ 青磁   — celadon, the glaze 鱗 (scale armour) is drawn in.
     漢字     山吹   — gold, which is what makes 格子 read as the 方眼紙 the practice is
                       done on rather than as brown lines, and the kanji card as the
                       parchment a workbook is printed on. */
/* A card comes out of a box, so it is printed on the same stock the box is — at a
   lighter weight, for the reason given on .slot below. --stock is stated here for the
   card, and the card, the pile layers and the card in flight all take it from this one
   place. It used to be stated on .slot alone, which is what made a card cream inside a
   coloured box.

   Carrying the series in the stock is what lets the edge go back to being an edge. It
   was a .4cqw painted rim before — thick enough to read as the cut edge of coloured
   card, which it did, but on a face you look at for minutes it read as a frame drawn
   round the page, and a frame is the one thing on a card that is always in your eye
   and never what you are reading. The rim is a 1px hairline again, the same hairline
   the box's own front has. The piles still come out striped in the series' colour,
   because they are built from real offset layers and the layers are this stock. */
[data-cat]{
  --stock:color-mix(in srgb,var(--wash) 40%,var(--paper));
  --stock-2:color-mix(in srgb,var(--wash) 48%,var(--paper-2));
  --edge:color-mix(in srgb,var(--spot) 70%,var(--edge-0));
  --rule:color-mix(in srgb,var(--spot) 52%,var(--rule-0));
  --rule-soft:color-mix(in srgb,var(--spot) 46%,var(--rule-soft-0));
  /* the ground the head band is printed on: the wash pulled a step past full strength
     towards the ink, so the band reads as printed on the card's own colour rather than
     applied to it — and stays a clear step darker than a card at 40% of that wash */
  --band:color-mix(in srgb,var(--spot) 13%,var(--wash));
}
/* The box keeps the wash at full strength; the card takes it at 40%. They are the same
   colour at two weights, because they are not the same object: a box is packaging, seen
   once from across a grid of sixteen, where the wash is what carries the series across
   the screen. A card is read for minutes at a time, and the wash that reads as a
   printed cover reads as a coloured surface once it is the page. 40% is where the stock
   still says plainly which deck this is, the black type keeps its bite, and the band
   stays well clear of the card it is printed on. */
[data-cat] .slot{
  --stock:color-mix(in srgb,var(--wash) 82%,var(--paper));
  --stock-2:color-mix(in srgb,var(--wash) 90%,var(--paper-2));
}
[data-cat="hiragana"]{--spot:#1B4F8A; --wash:#CCDDEB}
[data-cat="katakana"]{--spot:#2E7F66; --wash:#CDE6DA}
[data-cat="kanji"]   {--spot:#B07A16; --wash:#F3E1B6}

*{box-sizing:border-box}
/* A minimum, not a height. The body centres its content, and a centred flex container
   that is shorter than what it holds overflows in both directions — on a phone the
   chooser is twice the height of the screen, and a fixed height put its title and its
   first row above the top of the document where no scroll could reach them. */
html{height:100%}
body{min-height:100%}
html{overflow-x:clip}
body{overflow-x:clip}
body{
  margin:0; padding-block:36px 40px;
  /* viewport-fit=cover is declared, so a landscape notch is this page's problem */
  padding-left:max(16px,env(safe-area-inset-left));
  padding-right:max(16px,env(safe-area-inset-right));
  background:linear-gradient(168deg,var(--desk),var(--desk-2)); background-attachment:fixed;
  color:var(--ui); font-family:var(--latin);
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:30px;
  -webkit-font-smoothing:antialiased;
}

/* ============ the switches ============
   The desk is the room the cards are in and the flights are what the table does with a
   card rather than anything a card is, so neither switch is on the table. They are
   children of <body> rather than of either screen, which is what keeps them in one place
   while the chooser gives way to the table and back — and in the flow rather than fixed
   to a corner, because the card is min(94vw,680px) and a corner on a phone is the corner
   of the card. They cost a row at the top of the page and never land on anything.

   The row sizes itself to the chooser's 1248px and not to the table's 680px so that it
   does not move when a deck is picked: the two screens are different widths and the
   switches belong to neither. The lamp is last, so it keeps the corner it has always had
   and the second switch is the one that moved in beside it.

   Set like `change deck`, because they are the same kind of thing — small, off to one
   side, and asking to be found rather than looked at. Each face is the 昼/夜 or 動/静 of
   the state you are not in, in the card's own face, next to the word for it, the way a
   pile carries both 済 and 済み. The focus ring is currentColor and not --ink: --ink is
   the near-black the words on a card are printed in, and it is the same near-black in
   both rooms, which is invisible against a dark desk. */
.room{display:flex; justify-content:flex-end; gap:8px; width:100%; max-width:1248px}
/* One class for both, because they are one object in two jobs: same size, same face,
   same tracking, so the pair reads as a row of switches rather than as two controls that
   happen to be next to each other. */
.sw{
  display:flex; align-items:center; gap:7px;
  font-family:var(--latin); font-size:9.5px; letter-spacing:.15em; text-transform:uppercase;
  background:transparent; color:var(--ui); border:1px solid currentColor; border-radius:2px;
  padding:6px 10px; cursor:pointer; opacity:.5; transition:opacity .12s ease;
  -webkit-tap-highlight-color:transparent;
}
.sw:hover{opacity:.9}
.sw:focus-visible{outline:2px solid currentColor; outline-offset:3px; opacity:.9}
/* letter-spacing is the label's, not the character's: an em of tracking after a single
   kanji is a gap the flex gap has already left. */
.sw-mark{font-family:var(--jp); font-size:12px; letter-spacing:0; line-height:1}

/* ============ the card ============
   Geometry taken from the reference photo, perspective-corrected to 1380x1000.
   Every measurement below is that pixel value / 13.8, i.e. % of the card's width,
   so the whole card scales as one drawing. */
.table{
  --card-w:min(94vw,680px); --pile-w:calc(var(--card-w) * .4);
  display:flex; flex-direction:column; align-items:center; gap:26px;
}
/* The chooser is replaced in one frame, so without this the deal starts on a hard cut
   from a shelf of boxes to a bare table. Fading the table up under the cards already in
   flight makes the box the thing they came out of. */
.table.dealing{animation:dealin .3s ease both}
@keyframes dealin{from{opacity:0} to{opacity:1}}
.stage{position:relative; width:var(--card-w)}
/* perspective on .dealer so the flip still reads as 3D while .dealer carries the flight */
.dealer{perspective:1700px; position:relative; z-index:1}
/* an extra lift shadow, invisible at rest — height is what sells weight */
.drop{
  position:absolute; inset:4% 3%; border-radius:18px; z-index:0; opacity:0;
  background:rgba(48,40,26,.42); filter:blur(26px); pointer-events:none;
}
@keyframes lift{
  0%{opacity:0; transform:scale(1.08)}
  40%{opacity:.46; transform:scale(1.04)}
  100%{opacity:0; transform:scale(1)}
}

/* ============ the table: draw pile, card, discard ============ */
.piles{display:flex; justify-content:space-between; width:var(--card-w); gap:16px}
.pile{
  position:relative; width:var(--pile-w); aspect-ratio:var(--card-ar);
  background:none; border:none; padding:0; font:inherit; color:var(--ui);
  flex:none;
}
.pile.draw{cursor:pointer}
/* the discard is live too — its top card comes back to the table — but only while there
   is a card on it to take back */
.pile.used:not(:disabled){cursor:pointer}
.stack{position:absolute; inset:0}
/* each layer sits a shade up-left of the one above, so the pile reads as thickness */
.stack .layer:nth-last-child(1){transform:none}
.stack .layer:nth-last-child(2){transform:translate(-1.5px,-1.5px)}
.stack .layer:nth-last-child(3){transform:translate(-3px,-3px)}
.stack .layer:nth-last-child(4){transform:translate(-4.5px,-4.5px)}
.stack .layer:nth-last-child(5){transform:translate(-6px,-6px)}
.pile.draw:hover .stack .layer:last-child,
.pile.used:not(:disabled):hover .stack .layer:last-child{transform:translateY(-4px)}
.pile.draw:active .stack .layer:last-child,
.pile.used:not(:disabled):active .stack .layer:last-child{transform:translateY(-1px)}
.pile:focus-visible{outline:2px solid var(--ink); outline-offset:6px; border-radius:6px}
.layer{
  position:absolute; inset:0; border-radius:6px; overflow:hidden;
  background:linear-gradient(157deg,var(--stock),var(--stock-2));
  border:1px solid var(--edge);
  box-shadow:0 1px 2px rgba(50,44,32,.2), 0 6px 12px -6px rgba(50,44,32,.34);
  transition:transform .16s ease;
}
/* the deck's face-down pattern: a plain ruled panel, the way drill-card stock is printed */
.pile .mark{
  position:absolute; inset:0; display:grid; place-items:center; z-index:2; opacity:0;
  font-family:var(--jp); font-size:calc(var(--pile-w) * .17); color:var(--ink-3);
  letter-spacing:.14em; pointer-events:none;
}
.pile.empty .stack{opacity:0}
.pile.empty .mark{opacity:.3}
.pile.empty{border:1px dashed var(--rule-soft); border-radius:6px}
.pile .tag{
  position:absolute; left:0; right:0; top:calc(100% + 7px); text-align:center;
  font-family:var(--latin); font-size:10px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--ui); opacity:.6; white-space:nowrap;
}
.pile .tag b{font-weight:500; opacity:.9; font-variant-numeric:tabular-nums}

/* the outgoing card, cloned and flown to the discard pile */
/* the flyer is a real card clone, so whatever it shows in flight is the same object
   the pile and the table show — there is no stand-in graphic anywhere */
.card.flyer{position:fixed; z-index:40; pointer-events:none; cursor:default; transition:none}
/* a pile's top card is a full-size face scaled down, so its container queries still
   resolve against a real card width and the layout matches exactly */
.mini{
  position:absolute; top:0; left:0; width:var(--card-w); aspect-ratio:var(--card-ar);
  transform:scale(.4); transform-origin:top left; pointer-events:none;
  transition:opacity .15s ease;
}
/* A pile in motion has no top card to show. The face the gather left on the pile goes as
   the riffle starts and the one the shuffle chose arrives when it stops, so what the pile
   shows is only ever what is actually lying on top of it. */
.pile.shuffling .mini{opacity:0}
.mini .face{box-shadow:none; border:none; border-radius:16px}
.card.hidden{visibility:hidden}

.card{
  position:relative; width:100%; aspect-ratio:var(--card-ar);
  background:none; border:none; padding:0; cursor:pointer; display:block;
  transform-style:preserve-3d; transition:transform .55s cubic-bezier(.3,.85,.35,1);
}
.card.flipped{transform:rotateY(180deg)}
.card:focus-visible{outline:2px solid var(--ink); outline-offset:6px}
.face{
  position:absolute; inset:0; container-type:inline-size;
  backface-visibility:hidden; -webkit-backface-visibility:hidden;
  background:linear-gradient(157deg,var(--stock),var(--stock-2));
  border:1px solid var(--edge); border-radius:16px;
  box-shadow:var(--shadow); color:var(--ink);
  font-family:var(--jp); text-align:left; overflow:hidden;
}
.back{transform:rotateY(180deg)}

/* ---- the head band ----
   The box's own 和柄 printed in a band across the top of the card, on both faces, so a
   card carries the ground its box does and not only the colour. The stock says which of
   the three series this is; the band says which volume of it, because the tile steps
   through the volumes exactly as the box's does — the 拗音 card is printed with the
   coarser wave the 拗音 box is.

   It is one strip at the head rather than a field over the whole card, and that is the
   whole of why it can be there at all: a ground behind the type is a ground you read
   through, and 青海波 behind 天気予報 is a texture in the way. At the head there is
   nothing to be in the way of — every card, front and back, leaves its top clear, so the
   band lands on the one part of the stock the printing had already left empty.

   Full bleed, so the face's own border-radius crops it; the hairline underneath is the
   rule at the head of a printed page, which is also what stops the band reading as a
   title bar. --ps is the tile, set on the body by deal() the way the box sets its own,
   in the card's cqw rather than the box's — and kept under this height there, because
   a band is one course of the pattern and a tile taller than it is a strip of cropped
   halves rather than 鱗. */
.band{
  position:absolute; left:0; right:0; top:0; height:3.2cqw; z-index:2;
  pointer-events:none; background-color:var(--band);
  border-bottom:.14cqw solid var(--rule-soft);
}
.turn{
  position:absolute; right:3.6cqw; bottom:3cqw;
  font-family:var(--jp); font-size:2.6cqw; color:var(--ink-3);
  border:.14cqw solid var(--rule-soft); border-radius:50%;
  width:5.4cqw; height:5.4cqw; display:grid; place-items:center;
  opacity:.75; transition:opacity .15s;
}
.card:hover .turn{opacity:1}

/* card back — the same six words, but grouped by which reading they use.
   The kanji's readings appear once, as the group headings, so nothing repeats the front.

   The header sits 1.4cqw lower than it did, which is the head band being the top of the
   card now rather than the stock's own edge — at 5cqw, the same height the kana back
   starts its own character at, because both backs are the same card. All of that came
   from the air above the rule, none from the list below it: 弄 (#2382) is the tightest
   card in the set and leaves .bk-groups 3cqw of slack — and only because build_cards.py
   caps a card at two wrapped rows; before that cap the fullest card left 0.83cqw. The
   rule and everything under it stay where they were. What is left above the rule is
   about 1.2cqw of clear stock against 1.8cqw under the band, which is the band being a solid
   and the rule a hairline: the heavier edge takes the wider gap. */
.back .bk-k{
  position:absolute; left:6.5cqw; top:5cqw; font-family:var(--jp);
  font-size:9.5cqw; font-weight:var(--jp-bold); line-height:1;
  -webkit-text-stroke:calc(var(--glyph-edge) * .4) currentColor;
}
.back .bk-m{
  position:absolute; left:19cqw; top:10.8cqw; font-family:var(--latin);
  font-size:2.7cqw; letter-spacing:.12em; text-transform:uppercase; color:var(--ink-2);
}
.back hr{
  position:absolute; left:6.5cqw; right:6.5cqw; top:15cqw;
  border:none; border-top:.16cqw solid var(--rule-soft); margin:0;
}
.back .bk-groups{
  position:absolute; left:6.5cqw; right:6.5cqw; top:16cqw; bottom:1.8cqw;
  display:flex; flex-direction:column; gap:.9cqw;
}
.bk-head{
  display:flex; align-items:baseline; gap:2.4cqw; line-height:1.15; margin-bottom:.7cqw;
}
.bk-head b{
  font-weight:400; font-family:var(--jp); font-size:2.5cqw;
  color:var(--ink-3); letter-spacing:.14em; min-width:9cqw;
}
.bk-head span{font-family:var(--jp); font-size:3.9cqw; line-height:1}
/* Leaded tight, and for a second reason on top of the kana back's: a long gloss wraps, and
   at the font's own leading a wrapped row cost nearly two full rows of the block. 冗's six
   compounds wrap five times between them and ran off the bottom of the card; at 1.25 they
   fit. The row is still free to grow — a gloss that wraps has to be allowed to. */
.bk-row{
  display:grid; grid-template-columns:21cqw 17cqw 1fr; align-items:baseline;
  gap:1.5cqw; line-height:1.25; padding:.42cqw 0 .42cqw 2cqw;
  border-bottom:.14cqw dotted var(--rule-soft);
}
/* A floor rather than a height, because a wrapped gloss has to be able to push past it,
   and the kanji card's alone: the kana back reuses this row but states its own height,
   and a floor set here would quietly win over that one. */
.back:not(.kn) .bk-row{min-height:5cqw}
.bk-row:last-child{border-bottom:none}
.bk-row .r{font-family:var(--jp); font-size:3cqw; color:var(--ink)}
.bk-row .w{font-family:var(--jp); font-size:3cqw; color:var(--ink-2)}
.bk-row .g{font-family:var(--latin); font-size:2.5cqw; color:var(--ink-2)}

.no{
  position:absolute; top:5.4cqw; right:3.4cqw;
  font-family:var(--latin); font-weight:300; font-size:4.1cqw; letter-spacing:.04em;
  color:var(--ink); font-variant-numeric:tabular-nums; line-height:1;
}

.glyph{
  position:absolute; left:9.6cqw; top:9.4cqw; width:31cqw; height:30cqw;
  display:grid; place-items:center;
  font-family:var(--jp); font-size:29cqw; font-weight:var(--jp-bold); line-height:1; color:var(--ink);
  -webkit-text-stroke:var(--glyph-edge) currentColor;
}

.vocab{
  position:absolute; left:44.2cqw; top:6.2cqw; width:34cqw;
  margin:0; padding:0; list-style:none;
  font-family:var(--jp); font-size:3.95cqw; line-height:6.3cqw; font-weight:400; color:var(--ink);
}
.vocab li{display:flex; gap:1.5cqw; white-space:nowrap}
.vocab .n{
  font-family:var(--latin); font-weight:300; font-size:3.5cqw;
  color:var(--ink); min-width:3.4cqw; font-variant-numeric:tabular-nums;
}

/* cross-reference box: kanji built from the same component, with their own card numbers */
.related{
  position:absolute; left:80.2cqw; top:12.6cqw; width:15.4cqw; height:33.4cqw;
  border:.16cqw solid var(--rule); border-radius:.9cqw;
  display:flex; flex-direction:column;
}
.rel{flex:1; position:relative; display:flex; flex-direction:column;
     align-items:center; justify-content:center; gap:.45cqw;
     /* clear the number above and the gloss below, both absolutely placed */
     padding:1.6cqw 0 3.2cqw}
.rel + .rel{border-top:.16cqw solid var(--rule-soft)}
.rel .rn{
  position:absolute; top:.7cqw; right:1cqw; font-family:var(--latin); font-weight:300;
  font-size:2.05cqw; color:var(--ink-2); font-variant-numeric:tabular-nums; line-height:1;
}
.rel .rk{font-family:var(--jp); font-size:7.4cqw; font-weight:var(--jp-bold); line-height:1}
/* printed only when this relative shares the main kanji's on-reading — i.e. the shared
   component is phonetic, not just a lookalike. Its absence is as informative as its presence. */
.rel .rs{
  font-family:var(--jp); font-size:2.1cqw; line-height:1; color:var(--ink-2);
  border-top:.14cqw solid var(--rule-soft); padding-top:.7cqw; margin-top:.2cqw;
  letter-spacing:.04em; white-space:nowrap;
}
.rel .rg{
  position:absolute; bottom:.8cqw; left:.6cqw; right:.6cqw; text-align:center;
  font-family:var(--latin); font-size:1.85cqw; color:var(--ink-2); letter-spacing:.01em;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

.code{
  position:absolute; left:6.4cqw; top:45.4cqw;
  font-family:var(--latin); font-weight:300; font-size:2.95cqw; letter-spacing:.09em;
  color:var(--ink); display:flex; align-items:baseline; gap:1.3cqw;
}
.code .rad{font-family:var(--jp); font-weight:var(--jp-bold); font-size:3.3cqw; letter-spacing:0}

/* practice strip: one cell per stroke. Each cell holds a grey ghost of the finished
   kanji with the cumulative build painted over it — a tracing guide, not a diagram. */
.strip{
  position:absolute; left:6.2cqw; top:50.6cqw; width:88.8cqw; height:13.9cqw;
  border:.16cqw solid var(--rule); border-radius:.7cqw;
  display:flex; overflow:hidden;
}
.cell{flex:1 1 0; min-width:0; position:relative; padding:.3cqw}
.cell + .cell{border-left:.16cqw dotted var(--rule-soft)}
/* letterbox inside the cell — an intrinsic width here overflows into the next cell */
.cell svg{display:block; width:100%; height:100%}
/* Strokes are KanjiVG paths, not type: a font can't be taken apart into strokes, and
   masking a glyph by them only stays accurate while it's too thin to read. Round caps
   and an even weight match Klee One's low-contrast pen character. */
.cell svg{stroke-linecap:round; stroke-linejoin:round; fill:none}
/* The guide must stay lighter than the answer: at equal weight it competes with the
   stroke being taught and fringes out around it. Grey in every series, and the same
   grey — a guide is the one thing on the card you draw over rather than read, and a
   tinted one read as a second ink laid over the stroke instead of under it. */
/* --s is the scale a kana card's stroke was placed at; dividing it out keeps one pen
   width across a composed glyph, where the small kana is drawn at .42 of the big one. */
.cell .gh path{stroke:var(--ghost); stroke-width:calc(3 / var(--s,1))}
.cell .dr path{stroke:var(--ink); stroke-width:calc(5 / var(--s,1))}

.swap{animation:swap .34s ease}
@keyframes swap{from{opacity:0} to{opacity:1}}

/* ============ controls ============
   There was a Draw button here once, styled `.draw` — black, padded, 2px corners. It
   went when the pile itself became the thing you click, but its rules stayed, and the
   draw pile is `class="pile draw"`: same specificity as `.pile`, further down the file,
   so it won. Every one of those declarations was landing on the pile, and the black was
   showing through the moment the pile emptied — which is exactly the pile you are
   looking at when the deck runs out. The two piles are one object in two states and now
   compute as one. */
.controls{display:flex; flex-direction:column; align-items:center; gap:13px}
.hint{font-size:9.5px; letter-spacing:.15em; text-transform:uppercase; color:var(--ui); opacity:.6}
.hint kbd{font:inherit; border:1px solid currentColor; border-radius:2px; padding:1px 5px}
.picker{display:grid; grid-template-columns:auto 1fr; align-items:center; gap:9px 12px; max-width:700px}
.picker > .caption{text-align:right; white-space:nowrap}
.fonts{display:flex; flex-wrap:wrap; gap:6px}
.fbtn{
  font-family:var(--latin); font-size:10.5px; letter-spacing:.06em;
  background:transparent; color:var(--ui); border:1px solid currentColor; border-radius:2px;
  padding:6px 10px; cursor:pointer; opacity:.55; display:flex; align-items:center; gap:6px;
  transition:opacity .12s, background .12s, color .12s;
}
.fbtn .cat{font-size:9px; opacity:.7}
.fbtn:hover{opacity:.85}
.fbtn[aria-pressed="true"]{opacity:1; background:var(--ink); color:var(--stock); border-color:var(--ink)}
.fbtn:focus-visible{outline:2px solid var(--ink); outline-offset:2px}
.caption{font-size:10px; letter-spacing:.1em; text-transform:uppercase; color:var(--ui); opacity:.5}
/* ============ deck chooser ============
   Shown before any deck is loaded. A deck is a box of cards, so it is drawn as one:
   every box the same size, differing only in what is printed on the lid. */
.chooser{display:flex; align-items:center; justify-content:center; padding:10px 0; width:100%}
/* Wide enough for the longest row — カタカナ's six decks — to stay on one line:
   74px of name column, then six 180px boxes and the gaps between them. Stated as a
   maximum over a full width rather than left to shrink-to-fit: the boxes divide the row
   between them, so what the row would be at its widest no longer says anything about how
   wide the screen is.

   It is 1248px and not more because of what is under it rather than what is beside it: a
   180px box is a 142px row, and three of those plus the heading is the whole chooser on a
   768px-tall laptop, which is the point — all sixteen boxes at once, without scrolling. */
.chooser-box{width:100%; max-width:1248px; text-align:center}
.chooser-kicker{
  font-family:var(--jp); font-size:15px; letter-spacing:.32em; margin:0 0 14px;
  color:var(--ui); opacity:.6;
}
.chooser-title{
  font-family:var(--latin); font-size:13px; font-weight:500; letter-spacing:.2em;
  text-transform:uppercase; color:var(--ui); margin:0 0 12px;
}
.chooser-sub{
  font-family:var(--latin); font-size:12.5px; line-height:1.65; color:var(--ui);
  opacity:.65; margin:0 auto 26px; max-width:40ch;
}
.groups{display:flex; flex-direction:column; gap:15px}
/* The name is centred against its row rather than set down from the top of it by a
   fixed amount. It used to be 40px, which was the middle of a 104px-tall box and is
   nothing in particular now that the box is a sixth of the row and its height comes
   out of that. */
.group{display:grid; grid-template-columns:74px 1fr; align-items:center; gap:14px}
.group-name{
  display:flex; flex-direction:column; align-items:flex-end; gap:4px;
  font-family:var(--jp); font-size:12px; letter-spacing:.18em; text-align:right;
  color:var(--ui); opacity:.6;
}
/* The category in English, set the way the romaji on a box is set — the script's name
   is the one word on this screen a reader who cannot yet read the screen needs. */
.group-name .en{
  font-family:var(--latin); font-size:8.5px; letter-spacing:.2em; text-transform:uppercase;
  opacity:.8;
}
.levels{display:flex; flex-wrap:wrap; gap:26px 16px}

/* ---- the box ----
   Two details do the work of saying "box" rather than "card": the tuck flap folded
   over the top, and the sliver of the box's own front face along the bottom. The
   box lies flat and square so nothing printed on it is foreshortened, and the whole
   object lifts on hover, leaving its shadow behind.

   The slot holds the shadow, because the shadow is what the box lifts away from.
   Nothing here is a 3D context - no perspective, no rotation, no compositing layer
   per box - so a hover is one transform on the compositor and no script at all.

   Every measurement printed on a box below is in cqw against the slot, the way the card
   is measured against its own width: the slot is 100cqw, so 11px of margin on a 132px box
   is 8.33cqw and the whole box is one drawing that can be printed at any size. It is a
   sixth of the row on a desktop, where six fit a line, and half the screen on a phone,
   where two do - and the second is the first, larger, rather than the same small box with
   the type left behind at the size it was set for a mouse.

   The width is divided out of the row rather than fixed at 132px, which is what it used
   to be and what the 和柄 and the block of type were set against. 132px is a box you can
   see and a label you cannot read: 第1–46番 came out at 6.4px. Six to a row, so the box
   is a sixth of the row's width and the five 16px gaps come off first — 180px at the
   chooser's full 1248px, and everything printed on it 36% larger with it. The 132px floor
   is what it was: below about a 1000px screen six no longer fit a line at that size and
   the row wraps, exactly as it did, rather than the boxes shrinking to keep one line. */
.slot{
  /* The projected depth: --bx-d across, and that over the card's ratio up. Receding on
     the ratio is what lets the whole solid stand at the card's shape as well as its
     printed front — the front is (100cqw − 6.5) over (100cqw − 6.5) / 1.38, and the
     depth adds 6.5 and 6.5/1.38 back to them, so both come out at 1.38. */
  --bx-d:6.5cqw; --bx-dy:calc(var(--bx-d) / var(--card-ar));
  /* the printed front's height: the card's shape, since that is the face they come out of */
  --bx-fh:calc((100cqw - var(--bx-d)) / var(--card-ar));
  position:relative; width:max(132px,calc((100% - 80px) / 6)); flex:0 0 auto;
  /* the solid — 100cqw over 100cqw / 1.38 — plus 6.38cqw under its foot, which is where
     the shadow it lifts away from lies */
  aspect-ratio:calc(100 / (100 / var(--card-ar) + 6.38));
  container-type:inline-size;
}
.box{
  position:absolute; left:0; top:0; width:100%;
  /* the solid, and 3.5cqw of the shadow's ground under it, so the press is taken on a
     little more than the drawing */
  height:calc(var(--bx-dy) + var(--bx-fh) + 3.5cqw);
  background:none; border:none; padding:0; cursor:pointer; color:inherit;
  -webkit-tap-highlight-color:transparent;
  transform:translateY(0);
  transition:transform .17s cubic-bezier(.2,.86,.3,1), opacity .32s;
}
/* A finger cannot hover. On a touchscreen :hover sticks to whatever was tapped last,
   so the lift is a pointer's feedback and the press below is everyone's. */
@media (hover:hover){
  .slot:hover .box{transform:translateY(-6.82cqw)}
}
.box:active{transform:translateY(-1.5cqw); transition-duration:.07s}
.box:focus-visible{outline:none}
.box:focus-visible .bx-face{outline:2px solid var(--ink); outline-offset:3px}

/* ---- the box as a solid ----
   A card box is a box, so it is drawn as one: the printed front, the top, and the left
   wall, in cabinet projection. The front gives up the projected depth in width and in
   height — --bx-d across, --bx-dy up — so the whole solid still occupies the slot's
   full width, and both the front and the silhouette come out at the card's 1.38. A box
   holds these cards, so its face is cut to them, and the depth recedes on that ratio
   too rather than at 45°, which would leave the solid squarer than what is inside it.

   It recedes up and to the left because that is the direction the deck recedes on the
   table: the piles stack their layers up-left, so a pile shows its card edges along its
   top and left. A box that showed them on the right would be the same object turned two
   different ways on two screens.

   The two walls are 2D skews, not 3D rotations, and that is the whole reason this is
   usable. Rotating the front in 3D was tried first and it is the obvious way to do it —
   but a 3D-transformed element is rasterised once and resampled, and at the size a box
   is printed 漢字ドリル and 第1133–2524番 came out as mush. Skewing only the walls leaves the front untouched,
   so every glyph on it is drawn at the device's own resolution. It also keeps what was
   true before: no perspective, no 3D context, no compositing layer per box, and a hover
   that is still one translate. */
.bx-face{
  position:absolute; left:var(--bx-d); top:var(--bx-dy); width:calc(100% - var(--bx-d));
  height:var(--bx-fh);
  container-type:inline-size;   /* the printing is measured against the front, not the slot */
  border-radius:.8cqw; overflow:hidden;
  background:linear-gradient(157deg,var(--stock),var(--stock-2));
  border:1px solid var(--edge);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.55);
  font-family:var(--jp); color:var(--ink); text-align:left; line-height:1;
}
.bx-top,.bx-side{position:absolute; border:1px solid var(--edge); background-color:var(--stock)}
/* the top, sheared back and to the left off the front's top edge */
.bx-top{
  left:var(--bx-d); top:0; width:calc(100% - var(--bx-d)); height:var(--bx-dy);
  /* atan(1.38): the shear that carries the back edge --bx-d to the left over --bx-dy
     of height, so the top recedes along the same axis the left wall does */
  transform-origin:0% 100%; transform:skewX(54.07deg);
  background-image:linear-gradient(to top,rgba(255,255,255,.34),rgba(255,255,255,.06));
}
/* the left wall, sheared to meet it. Shaded warm rather than with neutral black, so a
   turned-away face is the same box in shadow and not a grey one. */
.bx-side{
  left:0; top:var(--bx-dy); width:var(--bx-d); height:var(--bx-fh);
  transform-origin:100% 0%; transform:skewY(35.93deg);   /* atan(1 / 1.38), the same axis */
  background-image:linear-gradient(to left,rgba(58,42,18,.15),rgba(58,42,18,.33));
}
/* the tuck flap: a second thickness of card folded over the top. Tinting it and
   giving its edge a hairline plus a sliver of cast shadow is the whole trick, and
   unlike a thumb notch it crosses the printing the way a real flap does rather
   than cutting a hole in it. */
.bx-flap{
  position:absolute; left:0; right:0; top:0; height:23%; z-index:3; pointer-events:none;
  background:linear-gradient(180deg,rgba(0,0,0,.05),rgba(0,0,0,.014) 66%,transparent);
  border-bottom:1px solid var(--rule-soft);
  box-shadow:0 1px 0 rgba(255,255,255,.72), 0 4px 5px -4px rgba(40,32,18,.55);
}

/* a gradient, not a blur filter: a blur is re-rasterised every time the thing above
   it moves, a gradient is painted once and then only scaled and faded. */
.bx-shade{
  position:absolute; left:-8%; width:116%; height:18.2cqw; bottom:1.5cqw;
  background:radial-gradient(50% 50% at 50% 50%,var(--box-shade),transparent 70%);
  transform:scaleX(.9) scaleY(.6); opacity:.9; transform-origin:50% 35%;
  transition:transform .17s cubic-bezier(.2,.86,.3,1), opacity .17s;
}
@media (hover:hover){
  .slot:hover .bx-shade{transform:scaleX(1.08) scaleY(1.34); opacity:.55}
}

/* ---- what is printed on the lid ----
   A 和柄 ground, one per script, and the drill workbook's block of type on a label
   pasted over it. The series line stays outside the label, up on the flap, so the
   pattern reads as the box rather than as a border drawn round a card. */
.bx-pat{position:absolute; inset:0; z-index:0}
/* The ground itself is .wagara, which the card's head band wears too: one pattern per
   series, printed on both the packaging and what comes out of it. The element it is on
   says how much of itself to cover and at what tile — .bx-pat the whole lid at the box's
   --ps, .band a strip at the card's — and the three rules below say only what the
   pattern is.
   Each ground states its own ink strength rather than the three sharing one, because
   they do not cover the box equally: 青海波 is a field of thin arcs, 鱗 is solid
   triangles that fill half of it, and 格子 is a grid of single pixels. At one alpha the
   katakana boxes printed twice as heavy as the kanji ones, which read as the series
   being louder rather than as the pattern being denser — and the pattern being denser
   was the only thing true. What is matched here is how dark the box looks, not what
   the ink is set to. */
/* 青海波 - two arc layers offset by half a tile, which is how the pattern is laid */
[data-cat="hiragana"] .wagara{
  --pat:color-mix(in srgb,var(--spot) 38%,transparent);
  --arc:repeating-radial-gradient(circle at 50% 100%,
    transparent 0 calc(var(--ps) * .17), var(--pat) calc(var(--ps) * .17) calc(var(--ps) * .205),
    transparent calc(var(--ps) * .205) calc(var(--ps) * .5));
  background-image:var(--arc),var(--arc);
  background-size:var(--ps) calc(var(--ps) * .5);
  background-position:0 0, calc(var(--ps) / 2) calc(var(--ps) / 4);
}
/* 鱗 */
[data-cat="katakana"] .wagara{
  --pat:color-mix(in srgb,var(--spot) 19%,transparent);
  background-image:
    linear-gradient(135deg,var(--pat) 25%,transparent 25%),
    linear-gradient(225deg,var(--pat) 25%,transparent 25%);
  background-size:var(--ps) var(--ps);
}
/* 格子 - which on the kanji boxes reads as 方眼紙, the paper the practice is done on */
[data-cat="kanji"] .wagara{
  --pat:color-mix(in srgb,var(--spot) 36%,transparent);
  background-image:
    repeating-linear-gradient(to right,var(--pat) 0 1px,transparent 1px var(--ps)),
    repeating-linear-gradient(to bottom,var(--pat) 0 1px,transparent 1px var(--ps));
}
.bx-series{
  position:absolute; left:8.33cqw; top:6.8cqw; z-index:2;
  font-size:5.7cqw; letter-spacing:.16em; color:var(--ink-2);
}
/* The label is a slip of paper pasted onto the box, not part of the box, so it is
   printed on the plain stock while the ground around it carries the series' tint. That
   is also what keeps every deck name black on cream: the colour never gets under type. */
.bx-plate{
  position:absolute; left:9.85cqw; right:9.85cqw; top:33%; bottom:6.06cqw; z-index:2;
  background:linear-gradient(180deg,var(--paper),var(--paper-2));
  border:1px solid var(--rule);
  /* the workbook cover's double rule, and the lift of a label pasted on */
  box-shadow:inset 0 0 0 1.14cqw var(--paper), inset 0 0 0 1.9cqw var(--rule-soft),
             0 1px 3px rgba(40,32,18,.24);
}
.bx-nm{
  position:absolute; left:0; right:0; top:15%; text-align:center;
  font-size:14.4cqw; font-weight:var(--jp-bold); letter-spacing:.07em;
}
.bx-nm.lng{font-size:11.4cqw}
.bx-nm.solo{top:24%}          /* a kanji box prints no romaji, so its name centres */
.bx-rom{
  position:absolute; left:0; right:0; top:55%; text-align:center;
  font-family:var(--latin); font-size:4.9cqw; letter-spacing:.24em;
  text-transform:uppercase; color:var(--ink-3);
}
.bx-foot{
  position:absolute; left:6.06cqw; right:6.06cqw; bottom:3cqw;
  display:flex; justify-content:space-between; align-items:baseline;
  border-top:1px solid var(--rule-soft); padding-top:2.65cqw;
  font-size:5.3cqw; letter-spacing:.03em; color:var(--ink-2);
}
/* 印 - the volume numeral, stamped. The only colour in the whole app, and only here. */
.bx-seal{
  position:absolute; right:5.3cqw; top:5.3cqw; z-index:5;
  width:11.4cqw; height:11.4cqw; display:grid; place-items:center;
  border:.9cqw solid var(--shu); border-radius:1.14cqw;
  color:var(--shu); font-size:7.2cqw; line-height:1; opacity:.92;
}

.groups.busy .box{cursor:progress}
.groups.busy .slot:not(.loading) .box{opacity:.45}
/* Picking a deck opens the box rather than removing it: the top lifts off along the axis
   the box recedes on, and the deck that was inside is what carries on to the table —
   dealFromBox in app.js flies it from here to the pile. The box itself never goes
   anywhere; the chooser it is standing in is simply replaced once the lid is off. */
.bx-top{transition:transform .26s cubic-bezier(.3,.75,.35,1), opacity .26s}
.slot.loading .bx-top{transform:translate(-5cqw,-11cqw) skewX(54.07deg); opacity:0}
/* ---- the chooser at phone width ----
   Two changes, and the second is the one that matters. The name column goes, because
   74px of it out of 343 is a quarter of the screen spent on three characters. And the
   row stops dividing itself six ways, which on a phone is a box the size of a stamp:
   two boxes divide the row between them, so a phone shows two the size of a thumb
   instead of six the size of a mouse pointer. 148px is the smallest
   box worth printing on, which makes it two boxes on every phone and three by the width
   at which the name column comes back. */
@media (max-width:560px){
  body{padding-block:24px 30px}
  .chooser-sub{margin-bottom:20px}
  .groups{gap:18px}
  .group{grid-template-columns:1fr; gap:8px}
  .group-name{
    flex-direction:row; align-items:baseline; gap:9px; text-align:left;
  }
  /* 148px, or half the row on a screen too narrow to give two boxes that much —
     one box per row is a lot of scrolling and a box bigger than it needs to be. */
  .levels{
    display:grid; gap:17px 12px;
    grid-template-columns:repeat(auto-fill,minmax(min(148px,calc(50% - 6px)),1fr));
  }
  .slot{width:auto}
}
.chooser-note{
  font-family:var(--latin); font-size:10px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--ui); opacity:.6; margin:22px 0 0; min-height:1em;
}
.relevel{
  font-family:var(--latin); font-size:9.5px; letter-spacing:.15em; text-transform:uppercase;
  background:transparent; color:var(--ui); border:1px solid currentColor; border-radius:2px;
  padding:6px 12px; cursor:pointer; opacity:.5; transition:opacity .12s ease;
}
.relevel:hover{opacity:.9}
.relevel:focus-visible{outline:2px solid var(--ink); outline-offset:3px; opacity:.9}

/* ============ the kana card ============
   Same stock, same practice strip, same shadow as a kanji card — it is the same physical
   card — but it asks a far smaller question, so the front is far emptier. A kanji card's
   front has to be dense: six compounds, a cross-reference box and a radical code are all
   part of asking which reading each compound takes. A kana card asks what one character
   sounds like. The character and how to write it is the whole question; the words, the
   lookalikes and the syllabary position are the answer, and the answer is on the back. */
/* The box begins below the band rather than under it — the glyph is centred in here, so
   it was never actually painted over, but a box the band overlaps is one bad font away
   from being clipped by it. The foot stays where it was, so the character keeps its
   place between the band and the practice strip. */
.kn-glyph{
  position:absolute; left:0; right:0; top:4cqw; height:40cqw;
  display:flex; align-items:center; justify-content:center; white-space:nowrap;
  font-family:var(--jp); font-size:38cqw; font-weight:var(--jp-bold); line-height:1;
  color:var(--ink);
  -webkit-text-stroke:var(--glyph-edge) currentColor;
}
/* きゃ is two characters written as one beat, so it is set as one run. A small kana still
   takes a full em of advance, so the pair is two ems wide whatever it looks like — the
   size has to come down to fit, not just the glyph. */
.kn-glyph.two{font-size:30cqw; letter-spacing:-.03em}

/* One square per stroke, centred under the character, and the box ends where the strokes
   do. A kanji card can spread its cells across the full width because it has eight to
   twenty of them; し has one, and padding the row out with repeats of the finished
   character taught nothing and read as an empty strip. */
.kn .strip{
  left:50%; transform:translateX(-50%); top:auto; bottom:10cqw;
  width:max-content; max-width:84cqw; height:auto;
}
/* Square cells, so a nine-stroke ぎゃ compresses to nine small squares rather than nine
   tall slivers with the drawing letterboxed inside. The strip is anchored by its bottom
   because its height now follows the cell size. */
.kn .cell{flex:0 1 17cqw; aspect-ratio:1}

/* ---- kana back ----
   The header block is the character itself: the glyph, the sound it makes, and — for the
   dozen kana whose behaviour neither of those explains — a note, in the space a kanji
   card's back leaves empty. Then the facts, then the same six words with their romaji. */
.kn-c{
  position:absolute; left:6.5cqw; top:5cqw;
  font-family:var(--jp); font-size:11cqw; font-weight:var(--jp-bold); line-height:1;
  -webkit-text-stroke:calc(var(--glyph-edge) * .4) currentColor;
}
.kn-c.two{font-size:8cqw; top:6.6cqw}
.kn-rom{
  position:absolute; left:22.5cqw; top:5.5cqw;
  font-family:var(--latin); font-weight:300; font-size:6.8cqw; line-height:1;
  letter-spacing:.05em; text-transform:uppercase; color:var(--ink);
}
.kn-rom.long{font-size:4.3cqw; top:7.8cqw}
.kn-alt{
  position:absolute; left:23cqw; top:13.2cqw;
  font-family:var(--latin); font-size:2.3cqw; letter-spacing:.12em; color:var(--ink-3);
}
.kn-note{
  position:absolute; left:47cqw; right:12cqw; top:5.6cqw;
  font-family:var(--latin); font-size:2.15cqw; line-height:3.2cqw; color:var(--ink-2);
}
/* The header block, this rule and the body below it all move down together by 1.6cqw,
   so the kana back keeps its proportions and only its head margin changes. The body can
   afford it: the fullest card in either syllabary leaves it 3.95cqw of slack. */
.back.kn hr{top:17.8cqw}
/* facts then words, in flow rather than pinned: ー has no row in the gojuon table, no
   源 kanji and no counterpart, so its card should close the gap rather than leave a hole.
   The box itself is pinned top and bottom, though, so every row that goes in it states its
   own height rather than taking one from the font — see the note on .kn-words. */
.kn-body{
  position:absolute; left:6.5cqw; right:6.5cqw; top:19.2cqw; bottom:2.4cqw;
  display:flex; flex-direction:column; gap:2.4cqw;
}
.kn-facts{display:flex; flex-direction:column; gap:.35cqw}
.kn-facts:empty{display:none}
/* A fact row is 4.5cqw tall, stated, not inferred — see the note on .kn-words. The cells
   are leaded tight (1.15) so that what baseline alignment has to reconcile is the letters
   themselves rather than three different fonts' ideas of leading, and the row is then tall
   enough to hold the deepest of them: a 段 in 3.1cqw kana, a gloss in 2.15cqw latin, or
   the gojuon thumbnail, which is cut to 3.2cqw so that it sits in the row instead of
   setting its height. */
.kn-fact{
  display:grid; grid-template-columns:11cqw auto 1fr; align-items:baseline; gap:1.6cqw;
  line-height:1.15; height:4.5cqw;
  padding-bottom:.4cqw; border-bottom:.14cqw dotted var(--rule-soft);
}
.kn-fact:last-child{border-bottom:none}
.kn-fact > b{
  font-weight:400; font-family:var(--jp); font-size:2.3cqw;
  letter-spacing:.12em; color:var(--ink-3); white-space:nowrap;
}
.kn-fact .v{font-family:var(--jp); font-size:3.1cqw; color:var(--ink)}
.kn-fact .h{
  font-family:var(--latin); font-size:2.15cqw; color:var(--ink-2);
  display:flex; align-items:center; justify-content:flex-end; gap:1.5cqw;
}
/* The gojuon table in miniature, one cell inked, printed the way the table is printed:
   a 行 is a column, the columns run right to left, and ん sits off on its own. */
.kn-fact .map{height:3.2cqw; width:auto; flex:none; overflow:visible}
.kn-fact .map .on{fill:var(--ghost)}
.kn-fact .map .here{fill:var(--ink)}
.kn-fact .mmark{font-family:var(--jp); font-size:2.4cqw; color:var(--ink); line-height:1}
.kn-fact .sim{
  display:inline-flex; align-items:baseline; gap:.7cqw; margin-right:2.4cqw;
  font-family:var(--latin); font-size:2.15cqw; color:var(--ink-2);
}
.kn-fact .sim b{font-family:var(--jp); font-weight:var(--jp-bold); font-size:3.1cqw; color:var(--ink)}

.kn-words:empty{display:none}
/* A row's height is stated here rather than left to the font. Every other measurement on
   this card is a share of the card's width, so the whole thing scales as one drawing —
   line-height:normal was the one thing still coming from the font file, and Klee One leads
   taller than the system faces it falls back to. Four facts and six words at its leading
   stood taller than the box they are pinned inside, and .face{overflow:hidden} then cut
   the last word in half; む, which carries the most of both, lost its sixth word outright.
   Stated, the whole stack is 48.5cqw of the 52.5cqw the box gives it, on every card, in
   any font, at any width — and the reading a card is meant to answer cannot fall off it. */
.kn-wh{
  font-family:var(--jp); font-size:2.3cqw; line-height:2.9cqw; letter-spacing:.12em;
  color:var(--ink-3); margin-bottom:.4cqw;
}
/* 25.5cqw of word column because エンピツビャクシン is nine kana wide and a kana is a full
   em: at 23cqw it wrapped, and a wrapped row is the one thing a stated height can't hold. */
.kn-words .bk-row{
  grid-template-columns:25.5cqw 18cqw 1fr; line-height:1.15; height:3.95cqw;
  padding:.2cqw 0 .2cqw 1.4cqw;
}
.kn-words .bk-row .r,.kn-words .bk-row .w{font-size:2.7cqw}
.kn-words .bk-row .w{font-family:var(--latin); letter-spacing:.02em}
.kn-words .bk-row .g{font-size:2.25cqw}

/* ============ stillness ============
   Everything that moves, stopped in one place. The flights are JavaScript and skip
   themselves — `still()` in app.js asks the same question this does — so what is left
   here is the CSS half: the card's turn, the lid coming off a box, the hover lift, the
   fade the table comes up on.

   Two ways in, and the switch is the one that wins. The system's preference is scoped
   `:not([data-motion="full"])` exactly as the dark desk is scoped
   `:not([data-theme="light"])`, so a reader who asks for the cards to be dealt gets
   them dealt on a machine that would rather they were not; and `[data-motion="none"]`
   stops them on a machine that has never asked for anything. No attribute is the third
   state — the system's preference, live — and it is the one the page starts in.

   Durations rather than `animation:none`, which is how this block was already written:
   an animation that carries its end state forward — `.table.dealing` fades the table up
   with `both` — still arrives at it, instead of never starting and holding whatever it
   was given to start from. */
@media (prefers-reduced-motion:reduce){
  :root:not([data-motion="full"]),:root:not([data-motion="full"]) *{
    animation-duration:.01ms!important; transition-duration:.01ms!important;
  }
}
:root[data-motion="none"],:root[data-motion="none"] *{
  animation-duration:.01ms!important; transition-duration:.01ms!important;
}
