/* ============================================================
   CARDS v2 — paper world
   desk -> board (base sheet) -> pen -> content
   thick card (3D flip) / washi buttons + fountain-pen strokes /
   pencil marks / wax seal
   ============================================================ */

body.cards-v2 {
  --pv-ink: #211c15;
  --pv-muted: #7d745f;
  --pv-line: #cdbfa2;
  /* ---- pigment: meaning colours, shared across the study family, never varied.
     Green = known / correct, amber = still / almost, rust = weak / wrong. ---- */
  --pv-done: #3d6b2f;
  --pv-almost: #a5701f;
  --pv-again: #a33227;
  /* ---- accent: this feature's identity spine. CARDS is red (the wax-seal red);
     WRITE is blue. The primary commit button and the completion seal both wear
     it, so a glance tells you which app you are in. See STUDY_PAPER_UI_DESIGN. */
  --pv-accent: #9d241d;
  --pv-accent-hi: #b83127;
  --pv-accent-lo: #7c1a16;
  --pv-wax: var(--pv-accent);
  /* ---- washi: ONE neutral (greyscale) texture, shared by cards + write. It is
     colourless on purpose: multiply preserves the hue of whatever tint sits
     under it, so the same file works for red tape and blue tape alike. A warm
     texture would drag every cool tint toward khaki (measured: blue 204deg -> 48deg). */
  --pv-washi: url("/commons/img/textures/washi.jpg");
  /* chapter-tape tints (BASIC pale -> SPECIAL deep, same red spine) */
  --pv-tape-basic: #efdcd6; --pv-tape-basic-lo: #e2c4bb;
  --pv-tape-special: #dcb3a6; --pv-tape-special-lo: #c99687;
  /* One family for the whole feature, differentiated by WEIGHT, not by mixing in
     a sans. The small labels used to be `system-ui, sans-serif`, which resolves
     to Segoe UI on Windows and mis-stacks Vietnamese tone marks (ố ậ ề ữ) —
     the card body never had the problem because it was already on Lora, whose
     self-hosted build carries the vietnamese subset. Also required by
     AGENTS.md §13: Vietnamese UI must not be left to the system default. */
  --pv-font: "Lora", "Noto Serif JP", "Hiragino Mincho ProN", "Yu Mincho", serif;
  min-height: 100dvh;
  margin: 0;
  font-family: var(--pv-font);
  color: var(--pv-ink);
  background:
    repeating-linear-gradient(93deg, #ffffff05 0 2px, transparent 2px 7px),
    linear-gradient(135deg, #4a3c2d, #332619);
  overflow-x: hidden;
}

/* The pen deliberately runs off the right edge (it reaches x=469 on a 390px
   phone). `overflow-x:hidden` on <body> does not propagate to the viewport
   here, so that used to leave 79px of real horizontal scroll. `clip` cuts it
   at the screen edge — which is the intended look — without making a scroll
   container and without touching vertical flow. */
body.cards-v2 #app {
  display: flex; align-items: flex-start; padding: 9px 7px; overflow-x: clip;
  /* `safe center` matters here, not plain centering. If anything ever makes the
     stage wider than the viewport, plain `center` splits the overflow across
     BOTH sides — and with overflow-x clipped, the left half becomes unreachable:
     the whole layout looks shifted left and cut off, with no way to scroll to
     it. `safe` falls back to flex-start in exactly that case, so the left edge
     is always the one you can see. Plain `center` first as the fallback for
     engines without `safe`. */
  justify-content: center;
  justify-content: safe center;
}

/* ---- stage: board + pen + content ---- */
.pv-stage { position: relative; width: min(100%, 470px); min-height: calc(100dvh - 18px); }
/* The board is as tall as the whole scroll (2,000-7,200px depending on the level
   scope), so it must NOT be rotated: a fixed angle swings the bottom edge
   sideways in proportion to the height, and compensating to hold the swing fixed
   makes the visible slant of the top edge change instead (0.80deg at LV1 vs
   0.38deg at LV2 — LV1 alone looked crooked). Slanting the top and bottom edges
   by a fixed number of px via clip-path gives the same hand-placed look and is
   height-independent. drop-shadow, not box-shadow, because clip-path would cut
   a box-shadow off. */
.pv-board {
  position: absolute; inset: -10px -4px -2px; z-index: 0;
  background: url("assets/board.jpg") 0 0/360px, #c6b28c;
  clip-path: polygon(0 0, 100% 7px, 100% 100%, 0 calc(100% - 7px));
  filter: drop-shadow(0 10px 16px rgba(0,0,0,.42)) drop-shadow(0 2px 0 rgba(0,0,0,.15));
}
.pv-pen {
  position: absolute; z-index: 1; top: 38px; right: -62px; width: 200px;
  pointer-events: none; transform: rotate(32deg); filter: drop-shadow(0 7px 9px #00000033);
}
.pv-shell { position: relative; z-index: 2; display: flex; flex-direction: column; min-height: calc(100dvh - 18px); }

/* letterpress text */
.cards-v2 .pv-word,
.cards-v2 .pv-mean,
.cards-v2 .pv-done__title,
.cards-v2 .cw-title { text-shadow: 0 1px 0 rgba(255,255,255,.55); }

/* ---- topbar sits directly on the board ---- */
.cards-v2 .cw-topbar {
  background: transparent; border: none; box-shadow: none;
  padding: 12px 26px 6px 14px; gap: 10px;
}
.cards-v2 .cw-brand__goigoi,
.cards-v2 .cw-brand__app { color: var(--pv-ink); text-shadow: 0 1px 0 rgba(255,255,255,.35); }
/* CARDS is set by hand: five separate sorts, each its own piece of metal, stood
   next to each other to make the word. Each is tilted and seated a hair
   differently and casts its own shadow — a single flat image of the whole word
   cannot do that, which is the whole point of using real type. */
.cards-v2 .cw-brand { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; text-decoration: none; }
.cards-v2 .pv-typeword { display: flex; align-items: flex-end; gap: 1px; }
.cards-v2 .pv-type { display: block; height: 26px; width: auto; filter: drop-shadow(0 2px 2px #0000005e); }
.cards-v2 .pv-type:nth-child(1) { transform: rotate(-1.4deg) translateY(0.5px); }
.cards-v2 .pv-type:nth-child(2) { transform: rotate(0.8deg)  translateY(-1px); }
.cards-v2 .pv-type:nth-child(3) { transform: rotate(-0.5deg) translateY(1px); }
.cards-v2 .pv-type:nth-child(4) { transform: rotate(1.3deg)  translateY(-0.5px); }
.cards-v2 .pv-type:nth-child(5) { transform: rotate(-0.9deg) translateY(0.5px); }
/* Same English on every UI language — this is the product's name-line. */
/* nowrap: wrapping this to two lines made the brand column tall enough to push
   the language switcher onto its own row, which is exactly the vertical waste
   the mark was meant to remove. */
.cards-v2 .pv-brand__tag {
  font-size: 12.5px; font-weight: 600; letter-spacing: .04em; color: #6a6047;
  white-space: nowrap; text-shadow: 0 1px 0 rgba(255,255,255,.4); padding-left: 2px;
}
.cards-v2 .cw-topbar__status {
  font-family: var(--pv-font); font-weight: 800; font-size: 14px;
  color: #4c4433; text-shadow: 0 1px 0 rgba(255,255,255,.3); background: none; border: none;
}

/* ============================ LOADING ============================ */
.pv-loading { flex: 1; display: flex; align-items: center; justify-content: center; padding: 40px 14px; }
.pv-loading__sheet {
  width: min(100%, 320px); display: grid; gap: 12px; justify-items: center; text-align: center;
  padding: 30px 24px; border-radius: 4px;
  background: linear-gradient(#fbf5e6, #f4ecd8); border: 1px solid #e2d7bc;
  box-shadow: 0 3px 0 #e9dec5, 0 6px 0 #ded1b3, 0 9px 0 #d2c4a3, 0 16px 22px rgba(60,45,20,.28);
}
.pv-loading__title { font-size: 22px; font-weight: 700; letter-spacing: .08em; text-shadow: 0 1px 0 rgba(255,255,255,.55); }
.pv-loading__msg { font-family: var(--pv-font); font-size: 13px; font-weight: 600; color: #6a6152; }
.pv-loading__bar { width: 100%; height: 4px; border-bottom: 1.5px dotted #0000001f; overflow: hidden; }
.pv-loading__bar i { display: block; height: 3px; width: 38%; border-radius: 2px; background: #c0473a; animation: pv-slide 1.1s ease-in-out infinite; }
@keyframes pv-slide { 0% { transform: translateX(-40%); } 50% { transform: translateX(150%); } 100% { transform: translateX(-40%); } }

/* ============================ PRACTICE ============================ */
.pv-practice { flex: 1; display: flex; flex-direction: column; padding: 74px 8px 40px; }

.pv-card {
  position: relative; width: min(100%, 360px); margin: 0 auto; flex: 1;
  cursor: pointer; user-select: none;
  transform-style: preserve-3d; transition: transform .55s cubic-bezier(.3,.9,.3,1);
}
.pv-card:focus-visible {
  outline: 4px solid #d59b34;
  outline-offset: 7px;
}
.pv-card[data-side="back"] { transform: rotateY(180deg); }

.pv-face {
  position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden;
  background: linear-gradient(#fbf5e6, #f4ecd8);
  border: 1px solid #e2d7bc; border-radius: 5px;
  box-shadow:
    0 3px 0 #e9dec5, 0 6px 0 #ded1b3, 0 9px 0 #d2c4a3, 0 12px 0 #c8b993,
    0 20px 26px rgba(60,45,20,.3), inset 0 1px 0 #fffdf7;
  display: grid; align-content: center; justify-items: center; text-align: center;
  gap: 12px; padding: 26px;
}
.pv-face--back { transform: rotateY(180deg); }

.pv-word { font-size: clamp(34px, 12vw, 56px); font-weight: 700; line-height: 1.15; overflow-wrap: anywhere; }
.pv-tap { font-family: var(--pv-font); color: var(--pv-muted); font-size: 14px; }
.pv-label { color: var(--pv-muted); font-size: 12px; font-weight: 600; letter-spacing: .12em; }
.pv-mean { font-size: clamp(24px, 7.5vw, 40px); font-weight: 700; line-height: 1.3; overflow-wrap: anywhere; }
.pv-more { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.pv-more__item { font-size: 13px; color: #5a5445; border-bottom: 1px dotted #00000026; }
.pv-pos { color: #6a6152; font-size: 16px; }
.pv-ex { margin-top: 6px; color: #55503f; font-size: 15px; font-style: italic; line-height: 1.5; }

.pv-hint {
  text-align: center; font-family: var(--pv-font); color: #4c4433; font-size: 13px; font-weight: 600;
  line-height: 1.5; padding: 10px 4px 2px; text-shadow: 0 1px 0 rgba(255,255,255,.35);
}
.pv-hint.is-hidden { visibility: hidden; }

/* rating: washi paper tabs + fountain-pen stroke that overflows the button */
.pv-dock { display: grid; grid-template-columns: repeat(3, 1fr); gap: 11px; margin-top: 10px; visibility: hidden; }
.pv-dock.is-shown { visibility: visible; }
.pv-rate {
  position: relative; overflow: visible; min-height: 56px; cursor: pointer;
  font-family: inherit; font-weight: 700; font-size: 16px; color: #39332a; border: none; border-radius: 4px;
  --c: #d9cbb0; --ch: #e6dcc4; --rc: #6a6152;
  background: linear-gradient(180deg, var(--ch), var(--c)), var(--pv-washi), var(--pv-washi);
  background-size: cover, 170px, 72px;
  background-blend-mode: multiply, multiply, soft-light;
  box-shadow: inset 0 -10px 14px #00000022, inset 0 0 0 1px #00000012,
              0 3px 0 #cbbd9c, 0 5px 0 #c2b492, 0 8px 12px rgba(60,45,20,.22);
  transition: transform .1s ease;
}
.pv-rate:active { transform: translateY(2px); box-shadow: inset 0 -10px 14px #00000022, 0 1px 0 #cbbd9c, 0 6px 10px rgba(60,45,20,.2); }
.pv-rate--again  { --c: #dd968b; --ch: #ecb3aa; --rc: var(--pv-again); }
.pv-rate--almost { --c: #e2c257; --ch: #efd680; --rc: var(--pv-almost); }
.pv-rate--done   { --c: #9cc27f; --ch: #b7d79d; --rc: var(--pv-done); }
.pv-rate__label { position: relative; z-index: 1; }
.pv-rate__pen { position: absolute; left: -9%; top: -18%; width: 118%; height: 136%; opacity: 0; pointer-events: none; }
.pv-rate__pen path {
  fill: none; stroke: var(--rc); stroke-width: 3.2; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 140; stroke-dashoffset: 140; filter: drop-shadow(0 1px 0 #ffffff66);
}
.pv-rate.is-checked .pv-rate__pen { opacity: .9; }
.pv-rate.is-checked .pv-rate__pen path { animation: pv-pendraw .26s ease-out forwards; }
.pv-rate.is-checked { box-shadow: inset 0 0 0 2px var(--rc), inset 0 -10px 14px #00000022, 0 3px 0 #cbbd9c, 0 8px 12px rgba(60,45,20,.22); }
@keyframes pv-pendraw { to { stroke-dashoffset: 0; } }

/* ============================ RESULT (wax seal) ============================ */
.pv-done { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 30px 18px 44px; text-align: center; }
/* Real pressed-wax seal with the carved G crest (see assets/wax_seal_g.png).
   The CSS blob it replaces was a stand-in; this is a photographed matrix
   impression, so the irregular rim, satin sheen and debossed letter are in the
   artwork, not faked with gradients. */
.pv-seal {
  width: 146px; height: 146px; position: relative; display: grid; place-items: center;
  background: url("assets/wax_seal_g.png") center/contain no-repeat;
  filter: drop-shadow(0 10px 18px #00000055);
  animation: pv-stamp .4s cubic-bezier(.2,1.25,.5,1) .1s both;
}
.pv-seal__ring, .pv-seal__mark { display: none; }
@keyframes pv-stamp { 0% { transform: scale(1.7) rotate(-12deg); opacity: 0; } 55% { transform: scale(.92) rotate(3deg); opacity: 1; } 100% { transform: scale(1) rotate(-3deg); opacity: 1; } }
.pv-done__title { font-size: 27px; font-weight: 700; }
.pv-done__sub { font-family: var(--pv-font); color: #4c4433; font-size: 14px; font-weight: 600; text-shadow: 0 1px 0 rgba(255,255,255,.3); }
.pv-tally { display: grid; gap: 6px; width: min(100%, 280px); }
.pv-tally__row { display: flex; justify-content: space-between; align-items: baseline; padding: 7px 12px; border-radius: 4px;
  background: linear-gradient(#fbf5e6, #f4ecd8); border: 1px solid #e2d7bc; box-shadow: 0 2px 0 #ddd0b2; font-family: var(--pv-font); font-size: 14px; }
.pv-tally__row--done   { border-left: 4px solid var(--pv-done); }
.pv-tally__row--almost { border-left: 4px solid var(--pv-almost); }
.pv-tally__row--again  { border-left: 4px solid var(--pv-again); }
.pv-tally__value { font-size: 17px; }
.pv-again { margin-top: 6px; font-family: var(--pv-font); font-weight: 800; font-size: 14px;
  padding: 11px 20px; border-radius: 8px; cursor: pointer; border: 2px solid var(--pv-ink); background: transparent; color: var(--pv-ink); }
.pv-next-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-top: 6px; }
.pv-next-actions .pv-again { margin-top: 0; }
.pv-next-practice {
  display: inline-flex; align-items: center; justify-content: center; min-height: 44px;
  padding: 10px 18px; border-radius: 8px; background: var(--pv-ink); color: #fffdf4;
  font-family: var(--pv-font); font-size: 14px; font-weight: 800; text-decoration: none;
}
.pv-next-practice:focus-visible { outline: 4px solid #d59b34; outline-offset: 3px; }

@media (max-width: 620px) {
  .pv-next-actions { align-items: stretch; flex-direction: column; width: min(100%, 300px); }
  .pv-next-actions > * { width: 100%; }
}

/* ============================ OVERVIEW ============================ */
/* white paper stack that carries the level tabs */
.cards-v2 .cw-panel {
  position: relative; margin: 10px 6px 22px; border-radius: 2px; border: none;
  background: linear-gradient(#fdfcf7, #f5f1e8);
  box-shadow: 0 3px 0 #efe9db, 0 6px 0 #e6dfce, 0 9px 0 #ddd5c1, 0 12px 0 #d4cbb5, 0 18px 26px rgba(0,0,0,.4);
  padding: 16px 14px 20px;
}
.cards-v2 .cw-kicker { font-family: var(--pv-font); font-size: 11px; font-weight: 800; letter-spacing: .12em; color: #8a7f68; }
.cards-v2 .cw-title { font-size: 29px; font-weight: 700; }
/* With the CARDS heading moved to the topbar, the sheet now opens on this line,
   so it carries the weight the heading used to. The slip follows immediately
   after with no gap of its own: "what this tool is" then "what goes in the deck"
   should read as one block, not two stranded rows. */
.cards-v2 .cw-subtitle { margin: 2px 0 9px; color: #4c4433; font-size: 14px; font-weight: 600; line-height: 1.5; }

/* level chips -> roughly-cut washi index tabs */
.cards-v2 .cw-small-label { font-family: var(--pv-font); font-size: 12px; font-weight: 800; letter-spacing: .1em; color: #8a7f68; }
/* NOTE: .cw-choice-chip is also used by topic / count / order chips.
   The index-tab treatment must stay scoped to the level row (.pv-levels). */
.cards-v2 .pv-levels { margin-top: 22px; }
/* A torn slip of washi laid on the page just above the index tabs — a note put
   down by hand, not a form label. It replaces the old "対象レベル" small-label
   line, which cost a row and never conveyed the one rule that matters: the scope
   is CUMULATIVE. A slip has room for that sentence.
   width:fit-content so a short heading stays a small scrap while a longer note
   simply wraps and the paper grows with it — no truncation, no overflow.
   drop-shadow rather than box-shadow because clip-path would cut a box-shadow. */
.cards-v2 .pv-slip {
  position: relative; z-index: 8;
  width: fit-content; max-width: 100%;
  margin: 0 0 10px 4px; padding: 9px 17px 11px 15px;
  transform: rotate(-0.9deg); transform-origin: 0 100%;
  background: linear-gradient(180deg, #fdf8ea, #f5ecd4), var(--pv-washi);
  background-size: cover, 150px; background-blend-mode: multiply, multiply;
  filter: drop-shadow(1px 2px 3px #00000038);
  clip-path: polygon(1px 3px, 16% 5px, 33% 2px, 49% 4px, 66% 2px, 82% 5px, calc(100% - 1px) 3px,
    100% 32%, calc(100% - 1.5px) 66%, 100% 90%,
    calc(100% - 1px) calc(100% - 2px), 77% 100%, 54% calc(100% - 2px), 31% 100%, 1px calc(100% - 1px),
    0 71%, 1.5px 38%, 0 14%);
}
.cards-v2 .pv-slip__lead {
  margin-bottom: 7px; padding-bottom: 6px; font-size: 13.5px; line-height: 1.55; color: #554e3e;
  border-bottom: 1px dashed #00000021; text-wrap: pretty;
}
.cards-v2 .pv-slip__title {
  font-weight: 700; font-size: 15px; letter-spacing: .03em; color: #4a4335;
  text-shadow: 0 1px 0 rgba(255,255,255,.5);
}
.cards-v2 .pv-slip__note {
  margin-top: 3px; font-weight: 400; font-size: 13px; line-height: 1.55; color: #6f6653;
  /* keeps the last line from breaking to a lone "す。" */
  text-wrap: pretty;
}

/* flex-START, not flex-end: the tabs are stuck to the sheets, so the TOP edge of
   each one must never move. Selecting a level makes its tab reach further DOWN
   (its glue strip is now on the front sheet); with flex-end the extra height
   grew upward instead, which read as "the sticky note got bigger". */
.cards-v2 .pv-levels .cw-choice-row { position: relative; display: flex; gap: 0; flex-wrap: nowrap; align-items: flex-start; }
.cards-v2 .pv-levels .cw-choice-chip {
  flex: 1 1 0; min-width: 58px; position: relative;
  border: none; border-radius: 0; cursor: pointer; margin-left: -7px;
  padding: 10px 6px 12px; color: #3a352c; font-family: inherit; font-weight: 700; font-size: 14.5px; line-height: 1.2; text-align: center;
  display: grid; gap: 1px; opacity: .88;
  --c: #d9cbb0; --ch: #e6dcc4;
  background: linear-gradient(180deg, var(--ch), var(--c)), var(--pv-washi);
  background-size: cover, 150px; background-blend-mode: multiply, multiply;
  box-shadow: inset 0 -12px 16px #00000026, inset 0 0 0 1px #00000014;
}
/* Hand-cut on ALL FOUR edges, in px rather than %, so the cut depth stays the
   same whether the tab is 52px or 66px tall. Each tab gets its own polygon and
   its own top offset — a person tearing and sticking four tabs does not land
   them on the same line. */
.cards-v2 .pv-levels .cw-choice-chip:nth-child(1) {
  top: 4px;
  clip-path: polygon(1px 5px, 14% 3px, 27% 5px, 41% 3px, 55% 4px, 68% 3px, 82% 5px, calc(100% - 1px) 4px,
    100% 28%, calc(100% - 1.5px) 61%, 100% 87%,
    calc(100% - 1px) calc(100% - 1px), 73% 100%, 47% calc(100% - 2px), 21% 100%, 1px calc(100% - 1px),
    0 68%, 1.5px 39%, 0 13%);
}
.cards-v2 .pv-levels .cw-choice-chip:nth-child(2) {
  top: 7px;
  clip-path: polygon(0 4px, 13% 6px, 26% 3px, 40% 5px, 54% 3px, 67% 5px, 81% 3px, calc(100% - 1.5px) 5px,
    100% 33%, calc(100% - 1px) 58%, 100% 84%,
    calc(100% - 1px) 100%, 76% calc(100% - 2px), 50% 100%, 24% calc(100% - 1px), 0 100%,
    1.5px 72%, 0 44%, 1px 16%);
}
.cards-v2 .pv-levels .cw-choice-chip:nth-child(3) {
  top: 3px;
  clip-path: polygon(1.5px 3px, 15% 5px, 29% 3px, 43% 6px, 57% 3px, 70% 5px, 84% 4px, 100% 3px,
    calc(100% - 1.5px) 31%, 100% 55%, calc(100% - 1px) 82%,
    100% calc(100% - 2px), 71% calc(100% - 1px), 45% 100%, 19% calc(100% - 2px), 0.5px 100%,
    0 65%, 1px 41%, 0.5px 15%);
}
.cards-v2 .pv-levels .cw-choice-chip:nth-child(4) {
  top: 6px;
  clip-path: polygon(0.5px 6px, 12% 3px, 25% 5px, 39% 3px, 53% 5px, 66% 3px, 80% 4px, calc(100% - 1px) 3px,
    100% 26%, calc(100% - 1.5px) 53%, 100% 80%,
    calc(100% - 1.5px) calc(100% - 1px), 78% 100%, 52% calc(100% - 2px), 26% 100%, 1px calc(100% - 2px),
    0.5px 74%, 0 47%, 1.5px 18%);
}
.cards-v2 .pv-levels .cw-choice-chip:nth-child(5) {
  top: 5px;
  clip-path: polygon(1px 4px, 14% 6px, 28% 3px, 42% 5px, 56% 3px, 69% 4px, 83% 5px, 100% 4px,
    calc(100% - 1px) 29%, 100% 57%, calc(100% - 1.5px) 85%,
    100% 100%, 74% calc(100% - 2px), 48% 100%, 22% calc(100% - 1px), 0 calc(100% - 1px),
    1px 70%, 0 43%, 1px 12%);
}
.cards-v2 .pv-levels .cw-choice-chip:first-child { margin-left: 0; }
.cards-v2 .pv-levels .cw-choice-chip strong { font-size: 14px; font-weight: 700; }
.cards-v2 .pv-levels .cw-choice-chip span { font-family: var(--pv-font); font-size: 11.5px; font-weight: 700; opacity: .72; }
.cards-v2 .pv-levels .cw-choice-chip:nth-child(1) { --c: #9cc27f; --ch: #b7d79d; z-index: 6; }
.cards-v2 .pv-levels .cw-choice-chip:nth-child(2) { --c: #e0c057; --ch: #efd680; z-index: 5; }
.cards-v2 .pv-levels .cw-choice-chip:nth-child(3) { --c: #7fb0d6; --ch: #a6cbe7; z-index: 4; }
.cards-v2 .pv-levels .cw-choice-chip:nth-child(4) { --c: #c191c9; --ch: #d8b2de; z-index: 3; }
.cards-v2 .pv-levels .cw-choice-chip:nth-child(5) { --c: #e0977f; --ch: #efb7a4; z-index: 2; }
/* Selected tab: its sheet is now the front one, so the tab's glue strip lands on
   the paper and the tab reads LONGER — downward only. No `top` override here on
   purpose: the tab is stuck to its sheet, so its top edge must stay exactly
   where it was. Only padding-bottom grows, and z-index 12 lifts it over the
   sheet (z:10) so the extra length shows on the paper. */
.cards-v2 .pv-levels .cw-choice-chip[data-active="true"] {
  opacity: 1; z-index: 12; padding-bottom: 30px;
  box-shadow: inset 0 -12px 16px #00000026, inset 0 0 0 2px #00000038;
}

/* gem clip: binds the WHOLE memo stack (tabs + every sheet), so it is anchored
   to the stack's left edge and does not move when the level tab changes.
   Offset is a FIXED px from the panel top, not a %, because the panel height
   swings 2000-4600px with the level scope and % would push it off screen.
   The brass clip is 96x332 (1 : 3.458); width only, height follows, so the
   artwork is never squashed.
   z-index 20 keeps it ABOVE every tab (z<=12) and above the sheet (z:10) —
   the stack was re-clipped after the chosen sheet was pulled to the front.
   It leans slightly RIGHT and hangs off the left edge of the board onto the
   desk, the same trick the pen uses — a real object placed on the surface, not
   a decal printed inside the frame. It starts a little BELOW the top edge of
   the LV1 tab so it reads as clipping the stack, not as a title marker. */
.cards-v2 .pv-clip {
  position: absolute; z-index: 20; left: -19px; top: 152px; width: 30px; height: auto;
  pointer-events: none; transform: rotate(6deg); transform-origin: 50% 50%;
  filter: drop-shadow(2px 3px 4px #00000066);
}

/* inner sheet the index tabs are attached to.
   The pull-up has to clear the UNSELECTED tabs' bottoms, not just touch them:
   at -6px the sheet's top edge sat at 318.5 while those tabs ended at 309-313,
   so they floated above the paper with the sheet's top border drawn as a line
   underneath — the tabs read as not attached to anything. Pulling up past them
   makes the sheet cut them off (which is what the front sheet does to the tabs
   behind it) and puts the paper's top edge right where the tabs are stuck on. */
.cards-v2 .pv-sheet {
  position: relative; z-index: 10; margin: -20px 0 0; padding: 14px 12px 16px;
  border: 1px solid var(--pv-line); border-radius: 0 0 2px 2px;
  background: linear-gradient(#fffefb, #fbf8f2);
  box-shadow: inset 0 1px 0 #ffffffcc;
}

/* ---- pencil gauge (replaces the donut) ---- */
.cards-v2 .cw-progress-panel {
  display: block; margin-top: 2px; padding: 0;
  border: none; border-radius: 0; background: transparent;
}
.pv-meter__row {
  display: flex; align-items: center; gap: 13px;
  padding: 2px 2px 12px; margin-bottom: 11px; border-bottom: 1px dashed #00000018;
}
.pv-gauge { position: relative; flex: 0 0 auto; width: clamp(104px, 32vw, 132px); line-height: 0; }
.pv-gauge__face { display: block; width: 100%; height: auto; }
.pv-gauge__ink { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
/* graphite needle: the red pencil is now the `weak` band, so the pointer uses ink */
.pv-gauge__needle path { fill: #4a4034; }
.pv-gauge__needle circle { fill: #4a4034; }
.pv-meter__read { min-width: 0; }
.pv-meter__label { font-family: var(--pv-font); font-size: 12px; font-weight: 800; letter-spacing: .08em; color: #8a7f68; }
.pv-meter__big { font-size: 25px; font-weight: 700; text-shadow: 0 1px 0 rgba(255,255,255,.55); }
.pv-meter__sub { font-family: var(--pv-font); font-size: 13px; font-weight: 600; color: var(--pv-muted); }

/* text list = the exact numbers (the bands carry the impression only, so no
   minimum band angle is applied anywhere). All 5 statuses always render,
   0 included; the count must never be pushed out or clipped. */
/* auto-fit, not a viewport breakpoint: falls back to one column purely on the
   space actually available, so the count can never be squeezed out. */
.cards-v2 .cw-status-legend { grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); column-gap: 14px; }
.cards-v2 .cw-status-row { font-family: var(--pv-font); font-size: 13.5px; font-weight: 700; color: #6a6152; align-items: start; }
.cards-v2 .cw-status-row > span:nth-of-type(2) { overflow-wrap: anywhere; line-height: 1.25; }
.cards-v2 .cw-status-row strong { white-space: nowrap; font-variant-numeric: tabular-nums; }
.cards-v2 .cw-status-dot { margin-top: 2px; }
.cards-v2 .cw-status-row strong { color: var(--pv-ink); }
/* legend dots reuse the exact band colours so the meter can be read off it */
.cards-v2 .cw-status-row[data-status="mastered"] .cw-status-dot { background: #6d9455; }
.cards-v2 .cw-status-row[data-status="almost_known"] .cw-status-dot { background: #9cc27f; }
.cards-v2 .cw-status-row[data-status="shaky"] .cw-status-dot { background: #e0c057; }
.cards-v2 .cw-status-row[data-status="weak"] .cw-status-dot { background: #c96a58; }
.cards-v2 .cw-status-row[data-status="unseen"] .cw-status-dot { background: #ded3bb; }
.cards-v2 .cw-progress-tools,
.cards-v2 .cw-record-detail { grid-column: 1 / -1; }
.cards-v2 .cw-record-btn { font-family: var(--pv-font); background: #fffdf7; border-color: #dccdb0; color: #4c4433; }

/* stage rows: ruled paper + pencil progress */
.cards-v2 .cw-stage-row {
  border: none; border-bottom: 1px solid #0000000f; border-radius: 0; background: transparent;
  padding: 10px 2px; box-shadow: none;
}
.cards-v2 .cw-stage-row[data-next="true"] { background: #fff7ec; border-radius: 6px; }
.cards-v2 .cw-stage-bar { height: 5px; background: transparent; border-bottom: 1.5px dotted #0000001f; border-radius: 0; }
.cards-v2 .cw-stage-bar i { display: block; height: 3px; border-radius: 2px; background: #c0473a; }
.cards-v2 .cw-chip { background: #f3ead6; border: 1px solid #dccdb0; color: #5a5445; font-family: var(--pv-font); }

.cards-v2 .cw-btn { font-family: inherit; }
.cards-v2 .cw-btn--primary {
  border: none; color: #f7efe0;
  background: linear-gradient(180deg, var(--pv-accent-hi), var(--pv-accent-lo));
  box-shadow: 0 4px 0 #5f130f, inset 0 1px 0 #ffffff33; text-shadow: 0 1px 2px #00000055;
}
/* ---- section stamps: BASIC / SPECIAL ----
   The English slug is pressed into the paper (light above, shadow below) rather
   than printed on it, so it belongs to the same letterpress world as the CARDS
   mark without needing five more photographs of metal. It is a stamp, not a
   heading: small, widely tracked, and never translated. The localized name sits
   directly under it and does the actual telling. */
.cards-v2 .pv-sect { display: block; }

/* A strip of masking tape laid across the sheet — same washi stock as the index
   tabs, but long and low instead of tab-shaped, and it runs off the LEFT edge of
   the paper onto the board, the same trick the pen and the clip use. The ends
   are torn (clip-path), the tape is slightly translucent so the paper grain
   shows through, and it sits a fraction off square because it was put down by
   hand. drop-shadow, not box-shadow: clip-path would cut a box-shadow. */
.cards-v2 .pv-tape {
  position: relative; z-index: 3;
  display: flex; align-items: baseline; gap: 10px;
  /* -42px clears the sheet AND the panel so the torn end actually lands on the
     board: at 390 the board starts at x=3 and the panel at x=23, so this puts
     ~10px of tape on the kraft — visible as tape stuck over the edge, without
     running off the board itself. */
  margin: 0 6px 0 -42px; padding: 7px 16px 8px 44px;
  transform: rotate(-0.45deg); transform-origin: 0 50%;
  background: linear-gradient(180deg, var(--tape-hi), var(--tape)), var(--pv-washi);
  background-size: cover, 150px; background-blend-mode: multiply, multiply;
  opacity: .95;
  filter: drop-shadow(0 2px 3px #00000033);
  /* Masking tape is torn ACROSS, so the left/right ends are jagged (3-4px) while
     the top/bottom are the roll's own edge — nearly straight, ≤2px of wobble.
     The vertices are IRREGULARLY spaced with IRREGULAR depths (generated, not a
     repeating sawtooth): evenly-spaced stops of equal amplitude looked machined.
     Shallow, uneven, off-square — a hand-torn strip. */
  clip-path: polygon(
    3px 1.9px, 23.5% 0.9px, 34.5% 1.7px, 50.6% 0.8px, 62.9% 0.3px, 72.9% 1px, 81% 0.7px, 88.8% 1.6px, 100% 0.9px, calc(100% - 3px) 1.1px,
    100% 14%, calc(100% - 3.7px) 33%, 100% 52%, calc(100% - 2.9px) 71%, 100% 86%, calc(100% - 2.9px) calc(100% - 1px),
    91.6% calc(100% - 0.6px), 81.4% calc(100% - 1.1px), 69.8% calc(100% - 1.7px), 55.5% calc(100% - 1.2px), 46.1% calc(100% - 0.3px), 32.1% calc(100% - 1.6px), 22.5% calc(100% - 0.8px), 11.3% calc(100% - 1.7px), 3px calc(100% - 1.7px),
    0 86%, 3.9px 71%, 0 52%, 3.3px 33%, 0 14%);
}
/* BASIC pale -> SPECIAL deep, both on the red accent spine. SPECIAL is the same
   hue a shade down, not a different colour, so the two read as one chapter set. */
.cards-v2 .pv-tape--basic   { --tape: var(--pv-tape-basic-lo);   --tape-hi: var(--pv-tape-basic); }
.cards-v2 .pv-tape--special { --tape: var(--pv-tape-special-lo); --tape-hi: var(--pv-tape-special); }
.cards-v2 .pv-tape--practice { --tape: #dfcfaa; --tape-hi: #efe2c4; }
/* second end gets a different torn contour so two stacked tapes are not identical */
.cards-v2 .pv-tape--special {
  clip-path: polygon(
    3px 1.6px, 22.6% 1.5px, 37.8% 0.8px, 48.8% 0.7px, 56.8% 0.9px, 65.8% 1px, 75.1% 0.7px, 88.6% 0.8px, 100% 0.4px, calc(100% - 3px) 0.6px,
    100% 14%, calc(100% - 3px) 33%, 100% 52%, calc(100% - 2.5px) 71%, 100% 86%, calc(100% - 2.9px) calc(100% - 1px),
    92.7% calc(100% - 1.6px), 78.9% calc(100% - 1.1px), 67% calc(100% - 1.7px), 54.4% calc(100% - 1.8px), 39.4% calc(100% - 0.2px), 31.1% calc(100% - 0.7px), 19.3% calc(100% - 1.4px), 13.2% calc(100% - 1.3px), 3px calc(100% - 1.3px),
    0 86%, 2.6px 71%, 0 52%, 2.5px 33%, 0 14%);
}
.cards-v2 .pv-tape__mark {
  flex: none;
  font-size: 11.5px; font-weight: 700; letter-spacing: .34em; text-indent: .34em;
  color: #6d6450; text-shadow: 0 1px 0 rgba(255,255,255,.6);
}
.cards-v2 .pv-tape__name {
  font-size: 19px; font-weight: 700; color: #353026;
  text-shadow: 0 1px 0 rgba(255,255,255,.45);
}
.cards-v2 .pv-sect__desc { margin: 9px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--pv-muted); }

/* The Practice-hub entry is a real third course in the same paper-and-tape
   menu, rather than an unrelated row of app-like buttons above the sheet. */
.cards-v2 .pv-practice-course .pv-practice-choices { margin-top: 0; }
.cards-v2 .pv-practice-course .cw-choice-row { gap: 7px; }
.cards-v2 .pv-practice-course .cw-choice-chip {
  min-height: 44px;
  border: 1px solid #d9caa8;
  border-radius: 3px;
  background: #fffdf6;
  color: #4c4433;
  box-shadow: 0 1px 0 #00000014;
  font-family: var(--pv-font);
}
.cards-v2 .pv-practice-course .cw-choice-chip[data-active="true"] {
  border-color: #8c2a20;
  background: #f3ead6;
  color: #5f130f;
  box-shadow: inset 0 -2px 0 #8c2a2033, 0 1px 0 #00000014;
}

/* ---- SPECIAL: a different sheet, not a box ----
   The 1px outline said "form fieldset". What is wanted is "this is a different
   area", and paper says that by being a different sheet: a warmer stock tipped
   in under the main one, torn along the top, bleeding to the sheet's edges
   (negative margins cancel .pv-sheet's padding). The inset shadow along the tear
   is the main sheet lying over it. */
.cards-v2 .pv-special {
  position: relative;
  margin: 26px -12px -16px; padding: 20px 12px 18px;
  background: transparent;
}
/* The torn sheet is drawn on a layer of its own rather than by clipping the
   section itself: clip-path clips DESCENDANTS too, which cut 30px off the left
   end of the SPECIAL tape and left it flush with the edge while the BASIC tape
   ran onto the board. Same paper, same tear — but the tape can now hang over
   the edge on both sections. */
.cards-v2 .pv-special::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(180deg, #f6eeda, #fbf7ec);
  box-shadow: inset 0 4px 7px -2px #00000018;
  clip-path: polygon(0 7px, 11% 2px, 26% 8px, 42% 2px, 58% 7px, 74% 2px, 89% 8px, 100% 3px,
    100% 100%, 0 100%);
}
.cards-v2 .pv-special > * { position: relative; z-index: 1; }
/* no border, no radius: the sheet itself is the container now */
.cards-v2 .pv-special { gap: 6px; }
.cards-v2 .cw-extra-panel {
  border: none; border-radius: 0; background: transparent;
  /* the shared theme spaces this as a standalone card (24px margin + 18px pad);
     inside the SPECIAL sheet the head already provides the separation */
  margin-top: 4px; padding-top: 0;
}
/* The summary is now only the open/close control, so it is sized like a control
   — not the 64px white slab it was when it also had to carry the section name. */
.cards-v2 .cw-extra-summary {
  display: inline-flex; align-items: center; width: fit-content;
  margin: 4px 0 0; padding: 7px 14px; min-height: 0;
  border: 1px solid #d9caa8; border-radius: 3px; background: #fffdf6;
  box-shadow: 0 1px 0 #00000014; cursor: pointer;
}
.cards-v2 .cw-extra-summary em { font-style: normal; font-weight: 700; font-size: 13px; }

@media (prefers-reduced-motion: reduce) {
  .pv-card { transition: none; }
  .pv-seal { animation: none; }
  .pv-rate.is-checked .pv-rate__pen path { animation: none; stroke-dashoffset: 0; }
}
