/* ============================================================
   Kepu — version D, "Koma, contained"
   Version B's stylesheet, with the hybrid layered on at the end.
   Brand tokens are identical to A and B.
   ============================================================ */

:root{
  /* surfaces + ink */
  --paper:#FBF6EE; --cream:#F4E8D8; --card:#FFFDF9;
  --ink:#241A14; --ink-2:#6B5A4E; --ink-3:#776756;
  --line:#E5D7C6; --line-soft:#EFE4D6; --frame:#E9DCC9;

  /* brand orange: the cat, the gap, the next chip, the button. Nowhere else. */
  --orange:#EC6A18; --orange-txt:#B94D0C; --btn-bg:#EC6A18;

  /* volume chips, carried over from version A */
  --chip-own-bg:#F7D9C3; --chip-own-tx:#A94A16;
  --chip-miss-br:#E2A6A0; --chip-miss-tx:#B5625C; --todo-label:#A24B45;

  /* the shelf board, seen edge on */
  --board-hair:#D9C6AE; --board-a:#EFE3D2; --board-b:#DFCEB4;
  --board-shadow:rgba(74,50,28,.20);

  /* book spines: a warm neutral ladder, so the orange gap is the only colour */
  --sp1:#EADCC6; --sp2:#E2D1B5; --sp3:#EFE2CE; --sp4:#DBC8AA;
  --sp-band:rgba(36,26,20,.11);
  --sp-edge:rgba(36,26,20,.10);
  --gap-tint:rgba(236,106,24,.09);
  --gap-tint-hi:rgba(236,106,24,.22);

  --shadow-sm:0 1px 2px rgba(36,26,20,.05);
  --shadow-lg:0 1px 2px rgba(36,26,20,.05), 0 22px 46px -28px rgba(36,26,20,.45);

  --display:"Fraunces",Georgia,serif;
  --ui:"Nunito Sans","Noto Sans Thai",system-ui,-apple-system,sans-serif;

  --measure:35rem;
  --pad:clamp(1.15rem,5vw,3rem);
  --gap-sec:clamp(4rem,10vw,7.5rem);

  --ease:cubic-bezier(.2,.7,.2,1);
  --ease-pop:cubic-bezier(.34,1.5,.64,1);
}

@media (prefers-color-scheme: dark){
  :root{
    --paper:#17110D; --cream:#1E160F; --card:#1D150E;
    --ink:#F4E9DC; --ink-2:#B4A08F; --ink-3:#8F7E6B;
    --line:#37271A; --line-soft:#2A1D13; --frame:#2E2117;

    --orange:#F5822F; --orange-txt:#F5A366; --btn-bg:#EC6A18;

    --chip-own-bg:#452A1A; --chip-own-tx:#F2B486;
    --chip-miss-br:#6E423D; --chip-miss-tx:#CB938C; --todo-label:#CB938C;

    --board-hair:#4E3826; --board-a:#2C1F15; --board-b:#20160E;
    --board-shadow:rgba(0,0,0,.72);

    --sp1:#3B2B1E; --sp2:#33241A; --sp3:#42301F; --sp4:#2C2016;
    --sp-band:rgba(255,240,220,.10);
    --sp-edge:rgba(255,240,220,.07);
    --gap-tint:rgba(245,130,47,.12);
    --gap-tint-hi:rgba(245,130,47,.28);

    --shadow-sm:0 1px 2px rgba(0,0,0,.5);
    --shadow-lg:0 1px 2px rgba(0,0,0,.5), 0 22px 46px -28px rgba(0,0,0,.95);
  }
}

*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0; background:var(--paper); color:var(--ink);
  font-family:var(--ui); font-size:clamp(16px,1.05vw,17px); line-height:1.65;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  /* keeps the footer at the bottom on the short standalone pages */
  min-height:100dvh; display:flex; flex-direction:column;
}
main{flex:1 0 auto}
img{max-width:100%;display:block;height:auto}
.shell{max-width:76rem;margin-inline:auto;padding-inline:var(--pad)}

/* ---------- shared type ---------- */
.eyebrow{
  margin:0; font-size:.68rem; font-weight:800; letter-spacing:.18em;
  text-transform:uppercase; color:var(--ink-3); font-variant-numeric:tabular-nums;
}
.h-display{
  margin:0; font-family:var(--display);
  font-variation-settings:"opsz" 144,"SOFT" 40,"WONK" 0;
  font-weight:450; letter-spacing:.03em; line-height:1.08;
  text-wrap:balance; color:var(--ink);
}
h1.h-display{font-size:clamp(2.35rem,6vw,4.4rem);line-height:1.04;letter-spacing:.015em}
h2.h-display{font-size:clamp(1.85rem,4vw,3rem)}
h3.h-display{font-size:clamp(1.3rem,2.1vw,1.65rem);letter-spacing:.02em}
p{margin:0}
.lede{color:var(--ink-2);max-width:var(--measure);font-size:1.06em}
.body{color:var(--ink-2);max-width:var(--measure)}
.stack{display:flex;flex-direction:column;gap:1.15rem}
.stack-lg{display:flex;flex-direction:column;gap:1.6rem}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

a{color:inherit}
a:focus-visible,button:focus-visible{outline:2px solid var(--orange);outline-offset:3px;border-radius:2px}
.skip{
  position:absolute;left:-999px;top:0;background:var(--card);color:var(--ink);
  padding:.7rem 1rem;z-index:20;border:1px solid var(--line);
}
.skip:focus{left:.75rem;top:.75rem}

/* anchored sections must clear the sticky masthead */
[id]{scroll-margin-top:5.5rem}

/* an underline that draws itself, for links inside running text */
.link{
  color:var(--ink);text-decoration:none;padding-bottom:2px;
  background-image:linear-gradient(var(--ink-3),var(--ink-3));
  background-repeat:no-repeat;background-position:0 100%;background-size:100% 1px;
  transition:color .2s var(--ease),background-size .2s var(--ease);
}
.link:hover{color:var(--orange-txt);background-image:linear-gradient(var(--orange),var(--orange))}

/* ---------- the shelf board ---------- */
.board{height:1px;border:0;margin:0;background:var(--line)}
/* only the hero shelf is drawn as a plank */
.board--shelf{
  position:relative;height:4px;background:linear-gradient(var(--board-a),var(--board-b));
  border-top:1px solid var(--board-hair);
  box-shadow:0 6px 13px -10px var(--board-shadow);
}

/* ---------- masthead ---------- */
.nav{
  position:sticky;top:0;z-index:10;background:var(--paper);
  border-bottom:1px solid transparent;transition:border-color .25s var(--ease);
}
.nav.stuck{border-bottom-color:var(--line)}
.nav-in{display:flex;align-items:center;justify-content:space-between;gap:1rem;height:68px}
.lockup{display:inline-flex;align-items:center;gap:.55rem;text-decoration:none}
.lockup img{width:26px}
.lockup span{
  font-family:var(--display);font-variation-settings:"opsz" 144,"SOFT" 70,"WONK" 1;
  font-weight:800;font-size:1.3rem;letter-spacing:-.015em;
}
.nav-link{
  font-size:.85rem;font-weight:700;color:var(--ink-2);text-decoration:none;
  padding-bottom:3px;
  background-image:linear-gradient(var(--ink-3),var(--ink-3));
  background-repeat:no-repeat;background-position:0 100%;background-size:100% 1px;
  transition:color .2s var(--ease),background-size .2s var(--ease);
}
.nav-link:hover{color:var(--orange-txt);background-image:linear-gradient(var(--orange),var(--orange))}

/* ---------- the reading column ----------
   Two rules for the whole page: prose sits in a centred column with its text
   still left aligned, and objects (the shelf, the volume card, the numbers,
   the feature row) run the full width. */
.prose{max-width:var(--measure);margin-inline:auto}
.stack > .eyebrow{margin-bottom:-.35rem}
.stack-lg > .eyebrow{margin-bottom:-.75rem}

/* ---------- hero ---------- */
/* no divider under the hero now, so the next section's own top padding
   provides the whole gap rather than stacking two */
.hero{padding-top:clamp(2rem,5vw,4rem);padding-bottom:0}
.shelf-scroll{
  overflow-x:auto;overflow-y:hidden;scrollbar-width:none;
  margin-inline:calc(var(--pad) * -1);padding-inline:var(--pad);
}
.shelf-scroll::-webkit-scrollbar{display:none}
.shelf{display:flex;align-items:flex-end;gap:.28rem;width:100%;min-width:min-content;padding-top:1rem}

.spine{
  position:relative;flex:none;
  width:clamp(20px,2.1vw,29px);height:clamp(126px,17vw,190px);
  border-radius:2px 2px 0 0;
  background:var(--sp2);
  border:1px solid var(--sp-edge);border-bottom:0;
  display:flex;flex-direction:column;align-items:center;
  box-shadow:inset -2px 0 0 rgba(0,0,0,.045),inset 2px 0 0 rgba(255,255,255,.12);
  transition:transform .5s var(--ease);
}
/* up with no delay, down slowly: sweeping the mouse across sends a wave along the shelf */
.spine:hover{transform:translateY(-10px);transition-duration:0s}
.spine.lean:hover{transform:translateY(-10px) rotate(3.5deg)}
.spine.t1{background:var(--sp1)} .spine.t2{background:var(--sp2)}
.spine.t3{background:var(--sp3)} .spine.t4{background:var(--sp4)}
.spine .title{
  writing-mode:vertical-rl;margin-top:16%;
  font-family:var(--display);font-variation-settings:"opsz" 24,"SOFT" 40,"WONK" 0;
  font-weight:500;font-size:clamp(7px,.82vw,9.5px);letter-spacing:.06em;
  color:var(--ink-2);white-space:nowrap;
}
.spine .no{
  /* the band on a real spine: a rule directly above the volume number */
  position:absolute;bottom:6px;left:0;right:0;text-align:center;
  border-top:2px solid var(--sp-band);padding-top:5px;
  font-family:var(--display);font-variation-settings:"opsz" 24,"SOFT" 40,"WONK" 0;
  font-weight:600;font-size:clamp(8px,.9vw,11px);color:var(--ink);
  font-variant-numeric:tabular-nums;
}
/* the last volume on the shelf leans into the gap, the way books do, and
   sits in front of it rather than behind */
.spine.lean{transform:rotate(3.5deg);transform-origin:bottom right;z-index:2}
.spine.lean:hover{transform:translateY(-10px) rotate(3.5deg)}

.slot{
  position:relative;flex:none;
  width:clamp(20px,2.1vw,29px);height:clamp(126px,17vw,190px);
  border:1.5px dashed var(--chip-miss-br);border-bottom:0;border-radius:2px 2px 0 0;
}
.slot .no{
  position:absolute;bottom:6px;left:0;right:0;text-align:center;
  font-family:var(--display);font-variation-settings:"opsz" 24,"SOFT" 40,"WONK" 0;
  font-weight:600;font-size:clamp(8px,.9vw,11px);color:var(--chip-miss-tx);
  font-variant-numeric:tabular-nums;
}
.slot.next{
  border:2px dashed var(--orange);border-bottom:0;background:var(--gap-tint);
  animation:breathe 3.2s ease-in-out infinite alternate;
}
.slot.next .no{color:var(--orange-txt);font-weight:800}
@keyframes breathe{
  from{background-color:var(--gap-tint);box-shadow:none}
  to{background-color:var(--gap-tint-hi);box-shadow:0 0 0 3px var(--gap-tint)}
}

.cat-wrap{
  position:relative;flex:none;display:block;width:clamp(84px,10.5vw,140px);
  margin-right:clamp(.7rem,2.2vw,2rem);
  transform-origin:bottom center;transition:transform .32s var(--ease);
}
/* The logo is one solid shape. Cutting the arm out as its own layer left a
   visible seam, so the whole cat leans instead, pivoted near its back foot. */
.cat-wrap img{display:block;width:100%;transform-origin:26% 100%}
.cat-wrap:hover{transform:translateY(-6px)}
/* a wave, then a long pause, then another */
@keyframes wave{
  0%,70%{transform:rotate(0)}
  74%{transform:rotate(-6deg)}
  78%{transform:rotate(4deg)}
  82%{transform:rotate(-5deg)}
  86%{transform:rotate(3deg)}
  90%,100%{transform:rotate(0)}
}

.shelf-note{
  display:flex;flex-wrap:wrap;gap:.1rem 1.1rem;margin-top:.85rem;
  font-size:.76rem;color:var(--ink-3);
}
.hero-copy{
  display:flex;flex-direction:column;align-items:center;gap:1.15rem;
  text-align:center;margin:0 auto clamp(2.75rem,7vw,4.5rem);
}
/* 8em breaks it after "important" at every screen size, so the two lines
   stay the same two lines everywhere */
.hero-copy h1{max-width:8em;line-height:1.08}
/* balance stops the last line dropping to a stray word or two */
.hero-copy .lede{max-width:34rem;text-wrap:balance}
.hero-cta{margin-top:.6rem}
.shelf-note b{
  color:var(--ink-2);font-weight:800;letter-spacing:.16em;
  text-transform:uppercase;font-size:.68rem;
}
.shelf-note span{font-variant-numeric:tabular-nums}
/* one hint, worded for the device: "click" where there is a pointer that can
   hover, "tap" on touch screens and on phone widths regardless */
.shelf-note .try-tap{display:none}
@media (hover:none),(max-width:36rem){
  .shelf-note .try-click{display:none}
  .shelf-note .try-tap{display:inline}
}
/* On phones the row would wrap wherever it ran out of room, leaving a stray
   half-line. Stack it on purpose instead: title, count, edition, hint — tight
   enough to read as one block. Desktop keeps the single row. */
@media (max-width:36rem){
  .shelf-note{flex-direction:column;align-items:flex-start;gap:.12rem;margin-top:.75rem}
  .shelf-note b{margin-bottom:.1rem}
}

/* On narrower screens the shelf is cropped rather than squeezed: the cat leads,
   then as much of the end of the row as fits, so the gap is always in view. */
@media (max-width:26rem){
  .shelf .spine:nth-child(-n+15){display:none}
  .shelf{gap:2px}
  .cat-wrap{width:76px}
}
@media (min-width:26.01rem) and (max-width:36rem){ .shelf .spine:nth-child(-n+12){display:none} }
@media (min-width:36.01rem) and (max-width:48rem){ .shelf .spine:nth-child(-n+11){display:none} }
@media (min-width:48.01rem) and (max-width:55.99rem){ .shelf .spine:nth-child(-n+7){display:none} }

/* ---------- sections ---------- */
.section{padding-block:var(--gap-sec)}
/* the feature row belongs to the section above it, so it does not add a second
   full gap on top of that section's bottom padding */
.section.joined{padding-top:0}
.about .thai{color:var(--ink);font-weight:600}
.about .thai span{font-family:var(--ui)}

/* ---------- volume figure ---------- */
.volblock{
  margin:clamp(2.5rem,6vw,4rem) 0 0;padding:clamp(1.1rem,3vw,1.75rem);
  background:var(--card);border:1px solid var(--line-soft);border-radius:4px;
  box-shadow:var(--shadow-sm);
}
.volhead{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:.5rem}
.volhead .title{
  font-family:var(--display);font-variation-settings:"opsz" 72,"SOFT" 40,"WONK" 0;
  font-weight:500;font-size:1.25rem;letter-spacing:.02em;
}
.volhead .count{font-size:.8rem;color:var(--ink-3);font-variant-numeric:tabular-nums}
.legend{display:flex;gap:1.1rem;flex-wrap:wrap;font-size:.74rem;color:var(--ink-2);margin-top:.9rem}
.legend i{width:.85rem;height:.85rem;border-radius:2px;display:inline-block;vertical-align:-2px;margin-right:.35rem;border:1.5px solid transparent}
.sw.own{background:var(--chip-own-bg)}
.sw.miss{border-color:var(--chip-miss-br);border-style:dotted}
.sw.next{border-color:var(--orange)}
.vgrid{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:1.1rem}
.chip{
  min-width:2.1rem;padding:.3rem .1rem;text-align:center;border-radius:4px;
  border:1.5px solid transparent;font-size:.78rem;font-weight:700;
  font-variant-numeric:tabular-nums;color:var(--ink-3);
}
.chip.own{background:var(--chip-own-bg);color:var(--chip-own-tx)}
.chip.miss{border-color:var(--chip-miss-br);border-style:dotted;color:var(--chip-miss-tx)}
.chip.next{border-color:var(--orange);color:var(--orange-txt);font-weight:800}
.volblock figcaption{margin-top:1rem;font-size:.8rem;color:var(--ink-3)}

/* ---------- numbers ---------- */
.numbers{
  display:grid;gap:1.25rem 2.5rem;margin:clamp(2.5rem,6vw,4rem) 0 0;
  grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));align-items:end;
  border-top:1px solid var(--line);padding-top:1.6rem;
}
.numbers dl{margin:0}
.numbers dt{
  font-size:.68rem;font-weight:800;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-3);
}
.numbers dd{
  margin:.2rem 0 0;font-family:var(--display);
  font-variation-settings:"opsz" 144,"SOFT" 40,"WONK" 0;font-weight:450;
  font-size:clamp(3rem,7vw,5rem);line-height:.92;font-variant-numeric:tabular-nums;
  letter-spacing:-.01em;
}
.numbers .aside{color:var(--ink-3);font-size:.85rem;padding-bottom:.4rem}

/* ---------- features ---------- */
/* Three equal columns, in the order you would actually use the app:
   look at the collection, open a series, then go shopping. */
.trio{display:grid;gap:clamp(2.25rem,5vw,3rem)}
@media (min-width:46rem){.trio{grid-template-columns:repeat(3,minmax(0,1fr))}}
.feat{display:flex;flex-direction:column;gap:.9rem}
.feat .body{max-width:none}
.feat h3{margin-top:.1rem}
.shot{
  border:1px solid var(--frame);border-radius:20px;background:var(--card);
  padding:6px;box-shadow:var(--shadow-lg);overflow:hidden;
  width:100%;margin-bottom:.6rem;
}
.shot img{border-radius:15px}
@media (max-width:45.99rem){.feat .shot{max-width:17rem}}

/* ---------- cta ---------- */
.cta-row{display:flex;flex-wrap:wrap;align-items:center;gap:1rem 1.5rem;margin-top:clamp(2.5rem,6vw,3.5rem)}
.btn{
  display:inline-block;background:var(--btn-bg);color:#fff;text-decoration:none;
  font-weight:800;font-size:1.2rem;letter-spacing:.01em;padding:.8rem 1.7rem;border-radius:4px;
  box-shadow:0 1px 2px rgba(36,26,20,.18);
  transition:transform .12s var(--ease),box-shadow .12s var(--ease),filter .12s var(--ease);
}
.btn:hover{transform:translateY(-1px);box-shadow:0 6px 14px -6px rgba(236,106,24,.6);filter:saturate(1.06)}
.btn:active{transform:translateY(1px);box-shadow:0 1px 1px rgba(36,26,20,.2)}
.btn:focus-visible{outline-color:var(--ink);outline-offset:4px}
.cta-note{font-size:.85rem;color:var(--ink-3)}

/* ---------- more coming ---------- */
.more{background:var(--cream);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.empty-wrap{margin-top:clamp(2.25rem,5vw,3.25rem)}
.empty-shelf{display:flex;align-items:flex-end;gap:.3rem;height:clamp(76px,10vw,112px)}
.empty-shelf .slot{height:100%;border-color:var(--ink-3);border-style:dashed;opacity:.55}

/* ---------- contact ---------- */
.addresses{display:grid;gap:1.4rem 2.5rem;margin:.7rem 0 0}
@media (min-width:34rem){.addresses{grid-template-columns:1fr 1fr}}
.addresses > div{display:flex;flex-direction:column;gap:.3rem}
.addresses dt{
  font-size:.68rem;font-weight:800;letter-spacing:.18em;
  text-transform:uppercase;color:var(--ink-3);
}
.addresses dd{margin:0}

/* ---------- standalone pages ---------- */
.page{padding-block:clamp(2.75rem,6vw,4.5rem) var(--gap-sec)}
.page-head{display:flex;flex-direction:column;gap:1rem;margin-bottom:clamp(2.25rem,5vw,3.25rem)}
.page-head > .eyebrow{margin-bottom:-.4rem}
.page h1.h-display{font-size:clamp(2.1rem,5vw,3.4rem);line-height:1.06}
.page section + section{margin-top:clamp(2.25rem,5vw,3.25rem)}
.page h2.h-display{font-size:clamp(1.2rem,2.3vw,1.55rem);margin-bottom:.65rem}
.page p{color:var(--ink-2)}
.page p + p{margin-top:.85rem}
.page ul,.page ol{margin:.85rem 0 0;padding-left:1.35rem;color:var(--ink-2)}
.page .updated{font-size:.8rem;color:var(--ink-3);margin-top:-.4rem}
.page li + li{margin-top:.4rem}
.page ul + p,.page ol + p{margin-top:.85rem}
.page code{font-size:.92em}
.page .meta{font-size:.8rem;color:var(--ink-3);margin-top:2.5rem}

/* a working note: this block has to be answered before the page goes public */
.todo{
  border:1.5px dashed var(--chip-miss-br);border-radius:4px;
  padding:1rem 1.15rem;margin-top:.9rem;background:var(--card);
}
.todo > b{
  display:block;font-size:.68rem;font-weight:800;letter-spacing:.18em;
  text-transform:uppercase;color:var(--todo-label);margin-bottom:.45rem;
}
.todo p{font-size:.95em}
.todo p + p{margin-top:.6rem}

.notice{
  border-left:3px solid var(--orange);padding:.2rem 0 .2rem 1.1rem;
  margin-bottom:clamp(2rem,4vw,2.75rem);color:var(--ink-2);
}
.notice strong{color:var(--ink)}

/* ---------- footer ---------- */
.foot-nav{display:flex;flex-wrap:wrap;gap:.55rem 1.6rem;padding-block:2.5rem 1.6rem}
/* Six links wrapped as 3 + 2 + 1 on a phone, with Terms alone on its own line.
   Three columns sized to their text keeps it 3 + 2 rows on purpose, with
   Support / Privacy / Terms sitting under Manga Shelf / About / Contact. */
@media (max-width:36rem){
  .foot-nav{display:grid;grid-template-columns:repeat(3,max-content);justify-content:start}
}
.foot-nav a{font-size:.85rem;color:var(--ink-2)}
.foot{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:1rem;padding-block:1.6rem 2.5rem;
}
.who{display:flex;align-items:center;gap:.6rem}
/* The wordmark (Fraunces, 1.1rem) and the phrase (Nunito, .8rem) used to be
   centred as boxes, which left the phrase's baseline sitting above the
   wordmark's. They now share a baseline; the icon centres on the pair. */
.who .sig{display:inline-flex;align-items:baseline;gap:.6rem;flex-wrap:wrap}
.who img{width:22px}
.who b{
  font-family:var(--display);font-variation-settings:"opsz" 144,"SOFT" 70,"WONK" 1;
  font-weight:800;font-size:1.1rem;letter-spacing:-.015em;
}
.foot small{color:var(--ink-3);font-size:.8rem}

/* ---------- motion ---------- */
.js .reveal{opacity:0;transform:translateY(12px)}
.js .reveal.in{
  opacity:1;transform:none;
  transition:opacity .5s var(--ease),transform .5s var(--ease);
  transition-delay:calc(var(--i,0) * 60ms);
}
/* The shelf fills itself in. Done as an animation rather than a transition so
   that it leaves the hover transform free once it has finished. */
.js .shelf .spine,.js .shelf .slot,.js .shelf .cat-wrap{opacity:0}
.js .shelf.in .spine,.js .shelf.in .slot{
  opacity:1;animation:rise .38s var(--ease) backwards;
  animation-delay:calc(var(--i,0) * 22ms);
}
.js .shelf.in .spine.lean{animation-name:rise-lean}
.js .shelf.in .cat-wrap{opacity:1;animation:rise .5s var(--ease) .5s backwards}
.js .shelf.in .cat-wrap img{animation:wave 6.4s ease-in-out 2s infinite}
@keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
@keyframes rise-lean{
  from{opacity:0;transform:translateY(14px) rotate(3.5deg)}
  to{opacity:1;transform:rotate(3.5deg)}
}

.js .chip{opacity:0;transform:scale(.82)}
.js .vgrid.in .chip{
  opacity:1;transform:none;
  transition:opacity .26s var(--ease),transform .26s var(--ease-pop);
  transition-delay:calc(var(--i,0) * 28ms);
}

@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms !important;animation-iteration-count:1 !important;
    transition-duration:.001ms !important;transition-delay:0 !important;
  }
  .js .reveal,.js .shelf .spine,.js .shelf .slot,.js .chip,.js .shelf .cat-wrap{opacity:1;transform:none}
  .js .empty-shelf .slot{opacity:.55}
  .js .spine.lean{transform:rotate(3.5deg)}
}


/* ============================================================================
   VERSION D — "Koma, contained"

   Everything above this line is version B, unchanged. Everything below is the
   hybrid, kept in one block so the difference from B stays legible.

   The governing idea: the panel vocabulary belongs to MANGA SHELF, not to KEPU.
   Kepu's own sections stay open, warm and unruled, the way B has them. The
   product section is an island of ruled panels inside that. When the second
   little thing arrives it gets its own graphic language in its own section, and
   the parent brand does not have to be a comic to accommodate it.

   So the page reads: open, open, ISLAND, open, open. One thing leads.
   ============================================================================ */

:root{
  --gut-d:14px;               /* the island's internal gutter. One value */
  --rule-d:2px;               /* the speech bubble's stroke */
  --rule-box:1px;             /* the panels: same ink, hairline weight, so the
                                 boxes hold the content instead of competing */
  --night:#171310;            /* the one dark beat. Fixed, not a token — it is
                                 dark in the dark theme too, on purpose */
  --night-ink:#F6EBDD;
  --night-ink-2:#BFAC98;
  --ghost-ink:#7A6A5B;        /* a missing volume's number. Measured, see below */
}

/* ---------- 1. Black micro-labels ----------
   Kepu's section labels are stated, not whispered. The sub-labels inside the
   feature row stay quiet, so the two levels never compete. */
.tag{
  display:inline-block;align-self:flex-start;
  background:var(--ink);color:var(--paper);
  padding:.44rem .62rem .38rem;border-radius:2px;
  font-size:.62rem;font-weight:800;letter-spacing:.17em;text-transform:uppercase;
  font-variant-numeric:tabular-nums;
}
.stack > .tag,.stack-lg > .tag{margin-bottom:-.2rem}

/* ---------- 2. Mr Kepu speaks ----------
   The bubble lives inside the shelf's scroll box, so the shelf gains headroom
   rather than the bubble escaping and being clipped. */
/* The floor is 5rem, not 3.2rem: between the phone rule (36rem) and about
   55rem, 7vw came out under what the 62px bubble needs above Mr Kepu, and the
   scroll box cut its top off — at iPad-portrait width by 13px. At desktop
   widths 7vw is larger than the floor anyway, so nothing there moves. */
.shelf{padding-top:clamp(5rem,7vw,5.4rem)}
.cat-wrap{overflow:visible}

.bubble{
  /* clear of the spine tops — at 56%/-14px it sat on top of volumes 1 to 3 and
     hid their titles. The shelf's extra padding-top is what it rises into. */
  position:absolute;left:46%;bottom:calc(100% + 62px);
  width:max-content;max-width:16rem;
  background:var(--card);color:var(--ink);
  border:var(--rule-d) solid var(--ink);
  /* a slightly longer oval, and not quite symmetrical, so it reads as drawn */
  border-radius:47% 53% 51% 49% / 60% 42% 58% 40%;
  padding:.72rem 1.45rem .78rem 1.4rem;
  font-size:.82rem;font-weight:800;letter-spacing:.02em;text-transform:uppercase;
  line-height:1.2;text-align:center;
  z-index:3;
}
/* the tail: a small square, two sides inked, turned so its inked corner is the
   tip. Its paper half sits inside the oval and covers the oval's own outline
   where they meet, so the ink runs out of the oval and into the tail as one
   line instead of a triangle parked underneath. Skewed, so it leans towards
   Mr Kepu rather than pointing politely straight down. */
/* The tail is a small drawing: a paper shape whose top sits inside the oval and
   covers the oval's outline between the two tail lines, and two inked curves
   — one concave, one convex — that leave the outline and meet at a tip leaning
   towards Mr Kepu. Curves rather than the old square corner, so it looks
   drawn with the same pen as the oval instead of glued on. */
.bubble .tail{
  /* the svg's top sits 10px up inside the oval: the outline is ~7px above the
     bottom edge at the tail's left, ~3px at its right, so both ink lines can
     start on it and the paper covers it in between */
  position:absolute;left:16px;bottom:-20px;
  width:28px;height:30px;display:block;overflow:visible;
}
.bubble .tail-paper{fill:var(--card)}
.bubble .tail-ink{
  fill:none;stroke:var(--ink);stroke-width:var(--rule-d);
  stroke-linecap:round;stroke-linejoin:round;
}
.bubble.said{animation:said .3s var(--ease-pop) both}
@keyframes said{from{transform:scale(.94)}to{transform:none}}

/* On phones the bubble gets a little more air above the spine tops, and the
   shelf's headroom grows by the same amount so the scroll box (overflow-y:
   hidden) never slices its top stroke. This block must come AFTER the base
   .bubble rule: same specificity, so the later one wins — an earlier version
   sat above it and its bottom offset never applied. Nothing else about the
   bubble changes. */
@media (max-width:36rem){
  .shelf{padding-top:5.5rem}
  .bubble{bottom:calc(100% + 70px)}
}

/* ---------- 3. The live shelf ----------
   Same spines as B, but each one is a button now. */
.vslot{
  position:relative;flex:none;display:block;
  width:clamp(20px,2.1vw,29px);height:clamp(126px,17vw,190px);
  padding:0;margin:0;border:0;background:none;font:inherit;color:inherit;
  cursor:pointer;-webkit-appearance:none;appearance:none;
}
.vbody{
  position:absolute;inset:auto 0 0 0;height:100%;
  display:flex;flex-direction:column;align-items:center;
  border-radius:2px 2px 0 0;
  transition:transform .5s var(--ease);
}
/* owned — B's spine, exactly */
.vslot[data-state="own"] .vbody{
  background:var(--sp2);
  border:1px solid var(--sp-edge);border-bottom:0;
  box-shadow:inset -2px 0 0 rgba(0,0,0,.045),inset 2px 0 0 rgba(255,255,255,.12);
}
.vslot.t1[data-state="own"] .vbody{background:var(--sp1)}
.vslot.t3[data-state="own"] .vbody{background:var(--sp3)}
.vslot.t4[data-state="own"] .vbody{background:var(--sp4)}

.vslot .title{
  writing-mode:vertical-rl;margin-top:16%;
  font-family:var(--display);font-variation-settings:"opsz" 24,"SOFT" 40,"WONK" 0;
  font-weight:500;font-size:clamp(7px,.82vw,9.5px);letter-spacing:.06em;
  color:var(--ink-2);white-space:nowrap;overflow:hidden;
}
.vslot .no{
  position:absolute;bottom:6px;left:0;right:0;text-align:center;
  border-top:2px solid var(--sp-band);padding-top:5px;
  font-family:var(--display);font-variation-settings:"opsz" 24,"SOFT" 40,"WONK" 0;
  font-weight:600;font-size:clamp(8px,.9vw,11px);color:var(--ink);
  font-variant-numeric:tabular-nums;
}

/* missing — a gap looks like a gap. Three dashed outlines in a row read as a
   fence and stole attention from the one gap that matters, so the outline only
   appears when you point at the space. */
.vslot[data-state="miss"] .vbody{
  height:86%;background:none;
  border:1.5px dashed transparent;border-bottom:0;
  transition:border-color .18s var(--ease),transform .5s var(--ease);
}
.vslot[data-state="miss"] .title{visibility:hidden}
.vslot[data-state="miss"] .no{border-top:0;color:var(--ghost-ink)}
.vslot[data-state="miss"]:hover .vbody,
.vslot[data-state="miss"]:focus-visible .vbody{border-color:var(--chip-miss-br)}

/* next — the gap. Orange, one of the four. */
.vslot[data-state="next"] .vbody{
  height:93%;
  border:2px dashed var(--orange);border-bottom:0;background:var(--gap-tint);
  animation:breathe 3.2s ease-in-out infinite alternate;
}
.vslot[data-state="next"] .title{visibility:hidden}
.vslot[data-state="next"] .no{border-top:0;color:var(--orange-txt);font-weight:800}

/* B's asymmetry, kept: instant up, slow down, so sweeping the mouse along the
   shelf sends a wave down it rather than popping books one at a time */
.vslot[data-state="own"]:hover .vbody{transform:translateY(-10px);transition-duration:0s}
.vslot[data-state="own"]:focus-visible .vbody{transform:translateY(-10px)}
/* the last book before the gap leans into it, as B has it — but which book that
   is now depends on what is on the shelf, so JS moves the class */
.vslot.lean .vbody{transform:rotate(3.5deg);transform-origin:bottom right;z-index:2}
.vslot.lean[data-state="own"]:hover .vbody{transform:translateY(-10px) rotate(3.5deg)}
.vslot.just-added .vbody{animation:pop .34s var(--ease-pop) both}
@keyframes pop{from{transform:translateY(24px) scaleY(.92)}to{transform:none}}

/* ---------- 4. The เก็บอยู่ band ----------
   Not a panel. A quiet full-width field, so the word is the only thing in it. */
.keeping{
  background:var(--cream);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  text-align:center;padding-block:clamp(3rem,7vw,5rem);
}
.keeping .word{
  font-family:"Noto Sans Thai",var(--ui);font-weight:600;
  font-size:clamp(3.2rem,8vw,6rem);line-height:1.3;color:var(--ink);
  letter-spacing:-.01em;
}
.keeping .gloss{
  margin-top:.5rem;font-size:.68rem;font-weight:800;letter-spacing:.18em;
  text-transform:uppercase;color:var(--ink-3);
}

/* ---------- 5. The island ----------
   Ruled panels, one gutter, and they appear here and nowhere else on the page. */
.koma{
  border:var(--rule-box) solid var(--ink);
  background:var(--card);
  padding:clamp(1.5rem,3.2vw,2.3rem);
  position:relative;
}
.beat{display:grid;grid-template-columns:1fr 1fr;gap:var(--gut-d);margin-top:clamp(1.6rem,3.5vw,2.4rem)}
.beat .koma{display:flex;align-items:center;min-height:8.5rem}
.beat .h-display{font-size:clamp(1.5rem,2.6vw,2.05rem);max-width:none}

/* the volume block stops being a soft card and becomes a panel */
.volblock{
  border:var(--rule-box) solid var(--ink);border-radius:0;
  box-shadow:none;background:var(--card);
  margin-top:var(--gut-d);
  padding:clamp(1.5rem,3.2vw,2.3rem);
}
.volhead .count{font-variant-numeric:tabular-nums}
/* 24 columns, so volume 24 never orphans onto a line of its own */
.vgrid{display:grid;grid-template-columns:repeat(24,1fr);gap:6px;margin-top:1.1rem}
.chip{
  min-width:0;border-radius:2px;border-width:1.5px;
  padding:.34rem .1rem;
  transition:background-color .18s var(--ease),border-color .18s var(--ease),color .18s var(--ease);
}
/* B's tertiary #9A897B failed AA at 3.1:1, and a missing volume's number says
   WHICH volumes you don't have — information, not decoration. Measured on this
   paper: #7A6A5B is 4.7:1. */
.chip.miss{color:var(--ghost-ink)}

/* three panels, still B's three equal columns and B's reading order */
.trio{gap:var(--gut-d)}
.feat{gap:0}
.feat.koma{padding:0;display:flex;flex-direction:column}
/* The stage takes its height from the screenshot, not the other way round: the
   screenshot fills the card's width inside a narrow night frame and is shown
   whole at its own ratio. Narrow dark frame, large legible screen, then the
   description. All three sources share a ratio, so the three cards stay level. */
.feat .shot{
  border:0;border-bottom:var(--rule-box) solid var(--ink);border-radius:0;
  padding:6px;box-shadow:none;background:var(--night);margin:0;
}
.feat .shot img:not(.reach){border-radius:0;display:block;width:100%;height:auto}
/* B capped a stacked screenshot at 17rem; inside a ruled panel that left the
   night ground narrower than its own card. The panel spans the card. */
.feat.koma .shot{max-width:none;width:100%}
.feat-copy{padding:clamp(1.15rem,2.4vw,1.5rem);display:flex;flex-direction:column;gap:.75rem}

/* the one broken frame on the page. Mr Kepu's pose is reaching for the top
   shelf, which is what a shopping list is, so he stands on the panel that is
   about what you have not got yet — and only that one. */
/* He sits in the lower-right corner of the description panel, toes just over
   the card's bottom rule, so he belongs to the whole card. The panel keeps
   enough room beneath its text that he never sits on the last line. */
.feat--reach .feat-copy{position:relative;padding-bottom:calc(clamp(1.15rem,2.4vw,1.5rem) + 3.5rem)}
.feat--reach .reach{
  position:absolute;right:12px;bottom:-10px;
  width:clamp(58px,6vw,82px);height:auto;z-index:2;
  transform-origin:26% 100%;
}
.js .feat--reach.in .reach{animation:wave 6.4s ease-in-out 1.2s infinite}

/* ---------- 5b. The three panels on a phone ----------
   Below the three-column breakpoint the panels become one row you swipe,
   snapping a panel at a time, with the next one peeking in at the right so it
   is obvious there is more. Native scroll-snap, no script needed to move it;
   the dots underneath only report and jump. Desktop is untouched. */
@media (max-width:45.99rem){
  .trio{
    display:flex;gap:var(--gut-d);
    overflow-x:auto;overflow-y:hidden;
    scroll-snap-type:x mandatory;
    scrollbar-width:none;
    padding-bottom:14px;            /* room for Mr Kepu's toes over the rule */
    -webkit-overflow-scrolling:touch;
  }
  .trio::-webkit-scrollbar{display:none}
  .trio > .feat{flex:0 0 86%;min-width:0;scroll-snap-align:start}
  /* trailing space so the last panel can snap to the same left edge */
  .trio::after{content:"";flex:0 0 calc(14% - var(--gut-d))}
  .feat .shot{max-width:none}
}
@media (prefers-reduced-motion:reduce){.trio{scroll-behavior:auto}}

.dots{display:none;justify-content:center;gap:.35rem;margin-top:1.1rem}
@media (max-width:45.99rem){.dots{display:flex}}
.dot{
  width:1.5rem;height:1.5rem;padding:0;border:0;background:none;
  display:grid;place-items:center;cursor:pointer;-webkit-appearance:none;appearance:none;
}
.dot::before{
  content:"";width:6px;height:6px;border-radius:50%;
  background:var(--ink-3);opacity:.4;transition:opacity .2s var(--ease),transform .2s var(--ease);
}
.dot[aria-current="true"]::before{background:var(--ink);opacity:1;transform:scale(1.25)}
.dot:focus-visible{outline:2px solid var(--orange);outline-offset:0;border-radius:50%}

/* ---------- 6. The night beat ----------
   One band, inside the product section, where the page stops describing and
   states.

   The beat is a REVERSAL of the page, not a fixed colour. Setting it dark in
   both themes was the first attempt and it failed: against the dark theme's
   #17110D body it measured almost identical and simply disappeared, which is
   the opposite of a beat. So in the dark theme the same band is the one lit
   thing on the page instead. */
.night-band{
  background:var(--night);color:var(--night-ink);
  border-block:var(--rule-d) solid var(--night);
  margin-top:var(--gut-d);
}
.night-band .numbers{
  display:flex;flex-wrap:wrap;align-items:flex-end;
  border-top:0;padding-top:0;margin:0;
  padding-block:clamp(2.75rem,6vw,4.25rem);
  gap:1.25rem clamp(2.5rem,6vw,5rem);
  grid-template-columns:none;
}
.night-band .numbers .aside{margin-left:auto;padding-bottom:.55rem;text-align:right}
.night-band .numbers dt{color:var(--night-ink-2)}
.night-band .numbers dd{color:var(--night-ink)}
.night-band .numbers .aside{color:var(--night-ink-2)}

@media (prefers-color-scheme: dark){
  .night-band{
    background:#F6EBDD;color:#241A14;
    border-block-color:#F6EBDD;
  }
  .night-band .numbers dt,.night-band .numbers .aside{color:#6B5A4E}
  .night-band .numbers dd{color:#241A14}
}

/* ---------- 7. Trims ---------- */
.shelf-note b{color:var(--ink)}
.shelf-note .try{color:var(--ink);font-weight:700}
.section.island{padding-bottom:0}
.after-island{padding-top:var(--gap-sec)}

@media (max-width:60rem){
  .beat{grid-template-columns:1fr}
  .vgrid{grid-template-columns:repeat(12,1fr)}
}

@media (prefers-reduced-motion: reduce){
  .js .vslot .vbody{opacity:1;transform:none}
  .js .vslot.lean .vbody{transform:rotate(3.5deg)}
}
