/* ── Deck page ────────────────────────────────────────────── */
.deck-main{display:flex;flex-direction:column;align-items:center;padding-top:20px;}
.deck-head{width:100%;max-width:440px;margin:0 0 22px;}
.deck-head h1{margin:0 0 8px;font-size:clamp(28px,6vw,36px);letter-spacing:-.02em;}
.deck-head .lede{font-size:16px;}
.deck-head .lede .zh{font-size:20px;color:var(--ink);}
.deck-head .deck-practice{margin:10px 0 0;font-size:15px;}
.deck-head .deck-practice a{color:var(--ink);text-decoration:underline;text-underline-offset:3px;}

.counter{
  width:100%;max-width:440px;display:flex;align-items:center;gap:14px;
  margin:0 0 18px;font-family:var(--mono);font-size:13px;color:var(--ink-2);
}
.counter-track{flex:1;height:4px;background:var(--surface-2);border-radius:999px;overflow:hidden;}
.counter-fill{height:100%;width:0;background:var(--accent);border-radius:999px;
  transition:width .45s var(--ease-soft);}

.stage{width:100%;max-width:440px;display:flex;justify-content:center;align-items:flex-start;perspective:1600px;}
.card{
  display:block;width:100%;aspect-ratio:4/5;position:relative;margin:0;padding:0;
  background:none;border:0;color:inherit;
  -webkit-tap-highlight-color:transparent;
}
.card-inner{
  display:block;position:relative;width:100%;height:100%;transform-style:preserve-3d;
  /* The turn eases off the hand, runs through the middle and settles with a
     small overshoot, so the card feels turned rather than flicked. */
  transition:transform var(--flip-time) var(--flip-ease);
}
.card.flipped .card-inner{transform:rotateY(180deg);}
.face{
  position:absolute;inset:0;display:flex;flex-direction:column;
  padding:18px 20px 20px;text-align:center;
  background:var(--surface);border:1px solid var(--rule-strong);border-radius:24px;
  box-shadow:var(--shadow);color:var(--ink);font:inherit;
  backface-visibility:hidden;-webkit-backface-visibility:hidden;overflow:hidden;
  transition:box-shadow var(--motion) var(--ease-soft),
             visibility 0s linear var(--flip-edge);
}
/* The face turned away also leaves the tab order and the screen reader. The
   switch waits for the halfway point, where both faces are edge-on: hide it any
   sooner and the near half of the turn shows a bare card with nothing painted. */
.back{transform:rotateY(180deg);visibility:hidden;
  transition:visibility 0s linear var(--flip-edge),
             box-shadow var(--motion) var(--ease-soft);}
.card.flipped .front{visibility:hidden;}
.card.flipped .back{visibility:visible;}
button.face{width:100%;cursor:pointer;-webkit-appearance:none;appearance:none;}
button.face:focus-visible{outline:3px solid var(--ring,var(--accent));outline-offset:3px;}
.face-top{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  font-family:var(--mono);font-size:13px;letter-spacing:.06em;color:var(--ink-2);
}
.stamp{
  font-family:var(--mono);font-size:13px;font-weight:600;letter-spacing:.04em;
  color:var(--accent);border:1px solid var(--accent);border-radius:6px;padding:2px 7px;
}
.front .face-center{position:relative;flex:1;display:flex;align-items:center;justify-content:center;}
/* The 田字格 practice grid behind the character. */
.front .face-center::before{
  content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(74%,290px);aspect-ratio:1;
  border:1px solid var(--grid);border-radius:8px;opacity:.45;
  background-image:linear-gradient(var(--grid),var(--grid)),linear-gradient(var(--grid),var(--grid));
  background-size:1px 100%,100% 1px;background-position:center,center;background-repeat:no-repeat;
  pointer-events:none;
}
.hanzi-big{
  position:relative;z-index:1;font-family:var(--han);
  font-size:clamp(56px,15vw,112px);font-weight:600;line-height:1.15;letter-spacing:.02em;
  color:var(--ink);text-align:center;max-width:84%;
}
.tap-hint{
  position:absolute;left:0;right:0;bottom:2px;z-index:1;
  font-size:13px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-2);text-align:center;
}
.back .face-top{padding-bottom:8px;border-bottom:1px solid var(--rule);}
.icon-btn{
  display:inline-flex;align-items:center;justify-content:center;
  width:32px;height:32px;padding:0;border-radius:999px;
  border:1px solid var(--rule-strong);background:var(--surface-2);color:var(--ink);
  cursor:pointer;
}
.icon-btn .i{width:16px;height:16px;}
.back-body{
  flex:1;display:flex;flex-direction:column;justify-content:flex-start;gap:8px;
  padding:10px 2px 0;overflow:auto;text-align:center;
  overscroll-behavior:contain;scrollbar-width:thin;
}
.back-hanzi{font-family:var(--han);font-size:clamp(30px,8vw,44px);font-weight:600;line-height:1.15;color:var(--ink);}
.back-meta{display:flex;align-items:baseline;flex-wrap:wrap;justify-content:center;gap:2px 10px;}
.pinyin{font-family:var(--mono);font-size:18px;color:var(--accent);}
.pos{font-size:14px;color:var(--ink-2);}
.meaning{font-size:17px;line-height:1.4;color:var(--ink);}
.trad{font-size:13px;color:var(--ink-2);}
.trad .zh{font-size:16px;color:var(--ink);}

/* Synonym and opposite, side by side. A missing side is simply not drawn. */
.pairs{display:flex;flex-wrap:wrap;justify-content:center;gap:6px 8px;margin:8px 0 0;}
.pair{
  display:inline-flex;align-items:baseline;gap:6px;padding:3px 10px;
  border:1px solid var(--rule);border-radius:999px;font-size:14px;color:var(--ink);
  background:var(--surface-2);
}
.pair[hidden]{display:none;}
.pair-label{font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--ink-2);text-transform:uppercase;}
.pair .zh{font-family:var(--han);font-size:17px;}
.pair .pair-py{font-family:var(--mono);font-size:12px;color:var(--ink-2);}

/* Two example sentences, each with its own spoken form. The block is centred:
   the characters, their pinyin, the translation and the structure line all sit
   on the same axis, so a card reads as one column instead of a left rag. */
.sentences{display:flex;flex-direction:column;gap:20px;margin:14px 0 0;}
.sentence{
  display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center;
  padding-top:16px;border-top:1px solid var(--rule);
}
.sentence:first-child{border-top:0;padding-top:0;}
.sentence-zh{
  margin:0;font-family:var(--han);font-size:21px;line-height:1.85;
  letter-spacing:.15em;color:var(--ink);
}
.sentence-py{
  margin:0;font-family:var(--mono);font-size:14px;line-height:1.6;
  letter-spacing:.015em;color:var(--ink-2);
}
.sentence-en{margin:0;font-size:14.5px;line-height:1.55;color:var(--ink-2);}
/* The structure line carries the speaker at its end, so the sentence itself
   keeps the full width and stays centred on the card. */
.sentence-structure{
  display:flex;align-items:center;justify-content:center;gap:10px;
  margin:2px 0 0;font-family:var(--mono);font-size:11.5px;letter-spacing:.03em;color:var(--ink-2);
}
.sentence-structure:empty{display:none;}
/* A few cards carry more than the face holds at some sizes. Tighten the
   block a step at a time so both sentences stay visible, instead of hiding
   one below a scroll the card never invites. */
.back.tight .back-body{gap:6px;}
.back.tight .pairs{margin-top:0;}
.back.tight .sentences{gap:12px;margin-top:8px;}
.back.tight .sentence{padding-top:10px;gap:5px;}
.back.tight .sentence-zh{font-size:19px;line-height:1.7;letter-spacing:.12em;}
.back.tight .sentence-py{font-size:13px;line-height:1.5;}
.back.tight .sentence-en{font-size:13.5px;line-height:1.45;}
.back.tight .sentence-structure{margin-top:0;}
/* A second step for the cards whose sentences are long enough to run past the
   face even tightened. Everything stays on the card; the type only gets
   smaller, never the content. */
.back.tighter .back-body{gap:4px;padding-top:6px;}
.back.tighter .back-hanzi{font-size:26px;}
.back.tighter .pinyin{font-size:15px;}
.back.tighter .pos{font-size:13px;}
.back.tighter .meaning{font-size:15px;line-height:1.35;}
.back.tighter .pair{font-size:13px;padding:2px 8px;}
.back.tighter .pair .zh{font-size:15px;}
.back.tighter .sentences{gap:8px;margin-top:4px;}
.back.tighter .sentence{padding-top:6px;gap:3px;}
.back.tighter .sentence-zh{font-size:17px;line-height:1.6;letter-spacing:.09em;}
.back.tighter .sentence-py{font-size:12px;line-height:1.45;}
.back.tighter .sentence-en{font-size:12.5px;line-height:1.4;}
.back.tighter .sentence-structure{font-size:10px;}
/* When even that is not enough, the block scrolls. The fade says there is
   more below; it goes away at the end of the block. */
.back::after{
  content:"";position:absolute;left:1px;right:1px;bottom:1px;height:32px;
  background:linear-gradient(to bottom,rgba(0,0,0,0),var(--surface));
  border-radius:0 0 23px 23px;opacity:0;transition:opacity .18s ease;pointer-events:none;
}
.back.has-more::after{opacity:1;}
.say{
  display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;padding:0;border-radius:999px;flex:none;
  border:1px solid var(--rule-strong);background:var(--surface-2);color:var(--ink);cursor:pointer;
}
.say .i{width:14px;height:14px;}
.say:hover:not(:disabled){border-color:var(--accent);color:var(--accent);}
.say[hidden]{display:none;}
/* Grammar roles: one colour per job, carried by the characters, their pinyin
   and the English word that answers to them. On the red card a text colour
   has to stay pale to clear 4.5:1 (subject 4.77, adverb 4.77, verb 5.22,
   object 4.50, time 4.80), which leaves the hues close together, so the
   structure line under each sentence names the roles in words as well.
   The characters carry the colour alone: no underline. */
.g-s{color:#BFE2FF;}
.g-a{color:#FFD98A;}
.g-v{color:#B9F5CE;}
.g-o{color:#FFC9DE;}
.g-t{color:#E6D8FF;}
.controls{display:flex;align-items:center;justify-content:center;gap:10px;margin:20px 0 6px;width:100%;max-width:440px;}
.controls button{
  min-height:48px;min-width:56px;padding:0 20px;border-radius:999px;white-space:nowrap;
  border:1px solid var(--rule-strong);background:var(--surface);color:var(--ink);
  font-family:var(--font);font-size:15px;font-weight:600;cursor:pointer;
}
.controls button:hover{background:var(--surface-2);}
.controls button:active{transform:scale(.97);}
.controls button:disabled{opacity:.45;cursor:default;}
.controls .speak{
  min-width:0;padding:0 16px;background:var(--surface-2);
  display:inline-flex;align-items:center;gap:8px;
}
.controls .speak:hover:not(:disabled){border-color:var(--accent);color:var(--accent);}
.controls .speak[hidden]{display:none;}
.key-hint{margin:6px 0 0;font-size:13px;color:var(--ink-2);text-align:center;}
.key-hint kbd{
  font-family:var(--mono);font-size:12px;border:1px solid var(--rule);border-radius:4px;
  padding:1px 5px;background:var(--surface);color:var(--ink-2);
}
/* The test follows the deck: it appears on the last card, once the 50 words
   have been turned, never under the first one. */
.deck-end{display:flex;flex-direction:column;align-items:center;gap:8px;margin:20px 0 0;}
.deck-end[hidden]{display:none;}
.deck-end-label{
  margin:0;font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-2);
}
.deck-end .note{margin:0;font-size:13px;color:var(--ink-2);}

@media (max-width:420px){
  /* A phone card is a portrait page, not a square: the back carries two
     sentences, their translations and their controls. */
  .card{aspect-ratio:auto;height:min(80vh,620px);}
  .face{padding:14px;border-radius:20px;}
  /* Keep the grid clear of the hint line. */
  .front .face-center{padding-bottom:26px;}
  .back-hanzi{font-size:30px;}
  .meaning{font-size:16px;}
  .hanzi-big{font-size:clamp(52px,17vw,96px);}
  .sentence-zh{font-size:19px;letter-spacing:.12em;}
  .sentence-py{font-size:13px;line-height:1.5;}
  .sentence-en{font-size:14px;line-height:1.45;}
  /* Three controls on one line at 320px: smaller type, tighter padding. */
  .controls{gap:6px;}
  .controls button{font-size:14px;padding:0 11px;min-width:0;}
  .controls .speak{padding:0 9px;gap:6px;}
}
@media (max-width:560px){
  /* A phone has no keyboard, and the words Prev and Next already say which
     way they go, so the hint line and the two arrow glyphs come off. */
  .key-hint{display:none;}
  #prevBtn .i,#nextBtn .i{display:none;}
}
@media (max-height:700px) and (max-width:420px){
  .card{height:min(74vh,540px);}
}
