
:root {
  --bg: #ffffff;
  --fg: #141414;
  --ink: #f2efe9;
  --ink-dim: #b3afa6;
  --ink-faint: #79766e;

  --stage-w: 640px;
  --stage-h: 560px;
  --info-w: 400px;

  --jp: "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic", Meiryo, sans-serif;
  /* Match the article and canvas, with explicit Japanese fallbacks on Windows. */
  --head: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic", Meiryo, sans-serif;
  --text: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic", Meiryo, sans-serif;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  transition: background-color .6s ease, color .6s ease;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", var(--jp);
  font-size: 16px; line-height: 1.6;
  overflow-x: clip;
}
/* Embedded shelf shares the library's stationary theme background. Standalone articles keep their palette. */
html[data-library-theme] { background: transparent; color-scheme: light; }
html[data-library-theme="dark"] { color-scheme: dark; }
html[data-library-theme] body:not(.is-reading) { background: transparent !important; color: var(--fg); transition: color .6s ease; }
html[data-library-theme] body:not(.is-reading):not(.is-book-detail) { --bg: #fff !important; --fg: #141414 !important; }
html[data-library-theme] :is(.site-header, #mobile-nav) { display: none !important; }
html[data-library-theme="dark"] body:not(.is-reading):not(.is-book-detail) { --bg: #0b0b0b !important; --fg: #ededed !important; }

p, h2 { margin: 0; }

/* One canvas behind the page; each book is drawn into its own stage rectangle.
   The canvas scrolls with the page (it is not fixed): library.js moves it back to the window each time it draws,
   with a margin above and below (--overscan). A fixed canvas is redrawn a frame after the browser has already
   scrolled the titles, so on a fast scroll the books trailed behind and ran into the titles.
   .stage-layer spans the page and clips, so the canvas never makes the page longer. */
body { position: relative; }
.stage-layer { position: absolute; inset: 0; overflow: clip; pointer-events: none; z-index: 0; }
.stage-canvas {
  position: absolute; top: 0; left: 0; width: 100vw; height: 100vh;
  pointer-events: none;
  will-change: transform;
}

/* The shared public top bar (site-header.css) sits above the shelf; it steps aside while an article is open. */
:root body.is-reading .site-header { visibility: hidden; }
/* Books and their titles fade out as they reach the bar, so the menu stays readable without a bar surface.
   The titles scroll with the page, so library.js gives each one the same screen-fixed fade.
   A mask, not a painted band: nothing here has a colour that could drift from the page's.
   The canvas starts --overscan above the window, so the fade line moves down by that much. */
.stage-canvas { --o: var(--overscan, 0px); -webkit-mask-image: linear-gradient(to bottom, transparent 0, transparent calc(var(--o) + var(--fade-from)), #000 calc(var(--o) + var(--fade-to))); mask-image: linear-gradient(to bottom, transparent 0, transparent calc(var(--o) + var(--fade-from)), #000 calc(var(--o) + var(--fade-to))); }
:root { --fade-from: 64px; --fade-to: 112px; }
@media (max-width: 900px) { :root { --fade-from: 0px; --fade-to: 0px; } }
body.is-reading .stage-canvas { -webkit-mask-image: none; mask-image: none; }
.stage-canvas.is-stage-local { -webkit-mask-image: none; mask-image: none; }

.ticks {
  position: fixed; left: 24px; top: 50%; transform: translateY(-50%); z-index: 3;
  display: flex; flex-direction: column; gap: 4px;
}
.ticks[hidden] { display: none; }
.tick { display: flex; align-items: center; width: 32px; height: 9px; color: inherit; }
.tick::before { content: ""; width: 16px; height: 2px; background: currentColor; opacity: .45; transition: width .2s, opacity .2s; }
.tick.is-current::before, .tick:hover::before { width: 24px; opacity: 1; }
.tick:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

.shelf {
  position: relative; z-index: 2;
  /* A grid of books (2026-10-01): as many columns as the window holds, with wide gutters.
     Each card is the book's stage with its title under it. The book stands in the middle of the card;
     its board swings open into the gutter on the left (library.js BOOK_SCREEN_X / SWING_ROOM). */
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--card-min), 1fr));
  column-gap: var(--gutter-x); row-gap: var(--gutter-y);
  align-items: start;
  max-width: 1760px; margin: 0 auto;
  padding: 112px var(--pad-x) 200px;
}
:root { --card-min: 340px; --gutter-x: 32px; --gutter-y: 24px; --pad-x: clamp(48px, 6vw, 120px); }

.entry {
  display: flex; flex-direction: column;
  scroll-margin-top: 96px;
}
.stage {
  width: 100%; aspect-ratio: 640 / 560;
  cursor: default;                 /* the pointer cursor is set only while over the book itself */
  outline: none;
  -webkit-tap-highlight-color: transparent;
}
.stage:focus-visible { outline: 2px solid currentColor; outline-offset: -8px; }

/* Loading skeleton, one for both the public shelf and the one framed in the library.
   Until books.json arrives, .shelf-skeleton lays out placeholder cards in the shelf's own grid (same classes,
   so the same places). Then each real stage shows the book's outline until its book is drawn (body.books-drawn).
   The outline is the closed book as the stage camera sees it, measured off the drawn shelf (2026-10-01),
   in fractions of the stage: it leans, so a plain rectangle did not sit on the book. */
:root { --sk-book: polygon(25.8% 19%, 27.2% 15.5%, 66.8% 16.8%, 67.4% 19.7%, 74.6% 80%, 74.6% 82%, 72.2% 85%, 31.2% 85.7%, 30.6% 80%); }
.stage { position: relative; }
/* A plain tone that breathes (opacity only, done off the main thread). A shimmer sweeping across had every
   placeholder repainted on every frame while the books were loading, and the page stuttered. */
.stage::before, .shelf-skeleton .sk-line {
  background: color-mix(in srgb, currentColor 8%, transparent);
  animation: shelf-sk 1.1s ease-in-out infinite alternate;
  will-change: opacity;
}
.stage::before { content: ""; position: absolute; inset: 0; clip-path: var(--sk-book); pointer-events: none; transition: opacity .3s ease-out; }
body.books-drawn .stage::before { opacity: 0; animation: none; }
@keyframes shelf-sk { from { opacity: 1; } to { opacity: .5; } }
body.books-drawn .stage::before { visibility: hidden; transition: opacity .3s ease-out, visibility 0s .3s; will-change: auto; }
/* Unreleased books are drawn on the shared 3D canvas. Keep the existing responsive shelf spacing. */
.slot-stage { width: 100%; aspect-ratio: 640 / 560; outline: none; -webkit-tap-highlight-color: transparent; }
.slot-stage:focus-visible { outline: 2px solid currentColor; outline-offset: -8px; }
@media (max-width: 920px) { .shelf-slot:nth-of-type(n+4) { display: none; } }
@media (max-width: 600px) { .shelf-slot:nth-of-type(n+3) { display: none; } }
.shelf-skeleton { position: absolute; top: 0; left: 0; right: 0; z-index: 2; pointer-events: none; }
.shelf-skeleton .info { gap: 0; }
.shelf-skeleton .sk-line { display: block; height: 19px; width: 72%; margin: 4px 0; border-radius: 5px; }
.shelf-skeleton .sk-line.s { width: 48%; }
.shelf-skeleton .sk-line.a { height: 12px; width: 34%; margin-top: 12px; }

/* The title starts at the book's left edge (the book spans the middle 49% of the card). */
.info { display: flex; flex-direction: column; gap: 8px; margin-top: -10%; padding-left: 25.5%; }   /* the stage's foot below the book is empty: pull the title up to it */
/* Title and author always show; the summary joins them once the board opens.
   Its space is kept so the title never moves when it appears. */
.info-desc {
  opacity: 0; transform: translateY(8px);
  transition: opacity .35s ease, transform .5s cubic-bezier(.2, .75, .2, 1);
}
.entry.is-open .info-desc { opacity: 1; transform: none; transition-delay: .2s; }
/* Clicked: the book grows over its own title, so the title, author and summary fade out at once
   (library.js .is-zooming), and come back once the book is on the shelf again. */
.info { transition: opacity .3s ease; }
.entry.is-zooming .info { opacity: 0; transition-duration: .15s; }
.entry.is-returning .info { opacity: 0; pointer-events: none; transition: none; }
.info-title { font-family: var(--head); font-weight: 600; font-size: 22px; line-height: 1.25; text-wrap: balance; word-break: keep-all; overflow-wrap: anywhere; }   /* Japanese titles break at their space, not mid-word */
.info-author { font-family: var(--head); font-weight: 600; font-size: 14px; line-height: 1.4; }
/* レポート (Standard and up): a small label over the title */
.info-kind { display: inline-flex; align-items: center; gap: 8px; font-family: var(--head); font-weight: 600; font-size: 12px; letter-spacing: .04em; }
.info-kind span { padding: 2px 8px; border-radius: 999px; background: color-mix(in srgb, currentColor 12%, transparent); font-weight: 500; }
/* a レポート this reader cannot open yet: the lock, and the way to the plans */
.info-kind.is-locked { flex-wrap: wrap; }
.info-kind.is-locked svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.info-kind.is-locked a { color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
/* the empty places on the shelf say what they are: books still to come, not locked ones */
.slot-note { margin: -10% 0 0; padding-left: 25.5%; font-family: var(--head); font-size: 12px; font-weight: 500; letter-spacing: .04em; opacity: .5; }
.info-desc { font-family: var(--text); font-size: 14px; line-height: 1.6; margin-top: 4px; }

/* Reading: the shelf's type steps aside while the camera moves onto the page;
   the article takes over once that page fills the window. */
.shelf, .ticks, :root body .site-header { opacity: var(--shelf-fade, 1); }
body.is-reading { overflow: hidden; transition: none; }
body.is-reading .shelf { pointer-events: none; }
.reader {
  position: fixed; inset: 0; z-index: 20;
  opacity: 0; pointer-events: none;
  transition: opacity .2s ease;
}
/* Arriving: the article replaces the book's page in the same frame (no fade), so nothing shows through
   between the shelf's last drawn frame and the article. Leaving still fades (the rule above). */
.reader.is-shown { opacity: 1; pointer-events: auto; transition: none; }
.reader iframe { display: block; width: 100%; height: 100%; border: 0; background: #efefef; }

@media (max-width: 920px) {
  :root { --card-min: 280px; --gutter-x: 32px; --gutter-y: 24px; --pad-x: 24px; }
  .ticks { display: none; }
  .shelf { padding-top: 88px; }
}
@media (max-width: 600px) {
  :root { --card-min: 100%; --gutter-y: 24px; --pad-x: 16px; }
  .info { position: relative; } /* Keep the title above the overlapping book hit area. */
  .info-title { font-size: 20px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .info, .info-desc { transition: none; }
  .stage::before, .shelf-skeleton .sk-line { animation: none; }
}

/* An editorial introduction between the shelf and the reader. The same 3D book
   occupies the left column; no second canvas or article iframe is mounted. */
.book-title-link { appearance: none; border: 0; padding: 0; background: none; color: inherit; font: inherit; text-align: inherit; cursor: pointer; }
.book-title-link:focus-visible, .book-back:focus-visible, .book-read:focus-visible, .book-access-link:focus-visible { outline: 2px solid currentColor; outline-offset: 5px; }
.book-details { display: none; }
.book-back { position: absolute; top: 96px; left: clamp(24px, 5vw, 80px); z-index: 4; padding: 8px 0; border: 0; color: inherit; background: transparent; font: 500 14px var(--text); cursor: pointer; }
.book-back[hidden] { display: none; }
.book-back:hover { background: transparent; box-shadow: none; text-decoration: underline; text-underline-offset: 5px; }
.book-back:focus-visible { outline: none; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 5px; }
body.is-book-detail .ticks, body.is-book-detail .shelf-slot, body.is-book-detail .entry:not(.is-detail) { display: none; }
body.is-book-detail .shelf { display: block; max-width: 1440px; padding: 150px clamp(24px, 5vw, 80px) 100px; }
body.is-book-detail .entry.is-detail { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: clamp(36px, 5vw, 80px); align-items: start; }
body.is-book-detail .is-detail .stage { position: sticky; top: 100px; width: calc(100% + 130px); margin: 0 -65px; aspect-ratio: 640 / 660; }
body.is-book-detail .is-detail .info { margin: 0; padding: 0; gap: 0; }
body.is-book-detail .is-detail .info-title { font-size: clamp(26px, 2.6vw, 38px); font-weight: 600; line-height: 1.45; text-wrap: initial; }
body.is-book-detail .book-title-link { cursor: default; }
body.is-book-detail .info-author { margin-top: 16px; font-size: 16px; font-weight: 400; }
body.is-book-detail .info-kind { margin-bottom: 20px; opacity: .75; }
body.is-book-detail .info-kind span { background: none; padding: 0; letter-spacing: 0; }
body.is-book-detail .info-desc { opacity: 1; transform: none; margin-top: 44px; font-size: 17px; line-height: 1.95; }
body.is-book-detail .book-details { display: block; font-size: 16px; line-height: 1.95; }
.book-synopsis p { margin-top: 22px; }
.book-details h3 { font-size: 15px; font-weight: 500; margin: 0 0 16px; opacity: .7; }
.book-topics { margin-top: 32px; }
.book-topics ul { padding-left: 1.15em; margin: 0; }
.book-topics li { padding-left: 6px; margin: 5px 0; }
.book-access { margin-top: 44px; }
.book-access p { font-size: 14px; }
.book-read { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) 31px; width: 100%; min-height: 45px; margin-top: 18px; padding: 0; border: 1px solid var(--fg); border-radius: 0; background: transparent; color: var(--fg); font: 600 16px/1.5 var(--text); text-align: left; cursor: pointer; }
.book-read-label { position: relative; padding: 9px 16px; transition: transform .3s ease-out; }
.book-read-edge { position: absolute; top: 0; bottom: 0; left: 0; width: 4px; overflow: hidden; pointer-events: none; }
/* Reveal a full-size strip instead of scaling a four-pixel raster through zero.
   Its composited translation stays smooth at fractional browser zoom levels. */
.book-read-edge::before { content: ""; position: absolute; inset: 0; background: var(--fg); transform: translate3d(-100%, 0, 0); will-change: transform; transition: transform .3s ease-out; }
.book-read-arrow { display: flex; align-items: center; justify-content: center; border-left: 1px solid var(--fg); background: var(--bg); overflow: hidden; transition: background .1s; }
.book-read-arrow-pair { position: relative; width: 9px; height: 9px; }
.book-read-arrow svg { position: absolute; left: 0; top: 0; fill: var(--fg); transition: transform .4s; }
.book-read-arrow svg + svg { left: -30px; top: 30px; }
@media (hover: hover) {
  .book-read:hover .book-read-edge::before { transform: translate3d(0, 0, 0); }
  .book-read:hover .book-read-label { transform: translateX(4px); }
  .book-read:hover .book-read-arrow { background: var(--fg); }
  .book-read:hover .book-read-arrow svg { fill: var(--bg); transform: translate(30px, -30px); }
}
.book-read:active .book-read-arrow { background: var(--fg); }
.book-read:active .book-read-arrow svg { fill: var(--bg); }
@media (prefers-reduced-motion: reduce) {
  .book-read-label, .book-read-edge::before, .book-read-arrow, .book-read-arrow svg { transition: none; }
}
.book-access-link { display: inline-block; margin-top: 16px; font-size: 14px; color: inherit; text-underline-offset: 5px; }
.book-author { margin-top: 52px; padding-top: 30px; border-top: 1px solid color-mix(in srgb, currentColor 20%, transparent); }
.book-author .book-author-name { margin-bottom: 12px; font-size: 18px; font-weight: 600; }
.book-author > p:last-child { font-size: 14px; }
body.is-book-detail:not(.is-reading) .is-detail .info { animation: book-intro-in .35s .2s cubic-bezier(.23, 1, .32, 1) both; }
body.is-reading .book-back { visibility: hidden; }
@keyframes book-intro-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (max-width: 760px) {
  .book-back { top: 82px; left: 24px; }
  body.is-book-detail .shelf { padding: 120px 24px 72px; }
  body.is-book-detail .entry.is-detail { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  body.is-book-detail .is-detail .stage { position: relative; top: auto; width: calc(100% + 48px); margin: -28px -24px -40px; aspect-ratio: 640 / 620; }
  body.is-book-detail .is-detail .info-title { font-size: 28px; line-height: 1.45; }
  body.is-book-detail .info-desc { margin-top: 32px; font-size: 16px; }
  body.is-book-detail .book-details { font-size: 15px; }
  .book-access { margin-top: 32px; }
}
@media (prefers-reduced-motion: reduce) {
  body.is-book-detail:not(.is-reading) .is-detail .info { animation: none; }
}

html[data-library-theme] .book-back { top: 126px; }
html[data-library-theme] body.is-book-detail .shelf { padding-top: 182px; }
@media (max-width: 760px) { html[data-library-theme] .book-back { top: 112px; } html[data-library-theme] body.is-book-detail .shelf { padding-top: 152px; } }
/* The public footer is shared; embedded shelves already have their parent navigation. */
html[data-library-theme] :is(.public-footer,.lp-footer), body.is-reading :is(.public-footer,.lp-footer) { display: none; }

/* Public header height grows with the viewport; keep the detail controls below it. */
html:not([data-library-theme]) { --shelf-header-height: max(80px, 5.555556vw); }
html:not([data-library-theme]) .book-back { top: calc(var(--shelf-header-height) + 16px); }
html:not([data-library-theme]) body.is-book-detail .shelf { padding-top: calc(var(--shelf-header-height) + 70px); }
html:not([data-library-theme]) body.is-book-detail .is-detail .stage { top: calc(var(--shelf-header-height) + 20px); }
html:not([data-library-theme]) body.is-book-detail .site-header a.gallery-invitation { color: inherit; }
@media (max-width: 1100px) {
  html:not([data-library-theme]) { --shelf-header-height: 64px; }
}
@media (max-width: 760px) {
  html:not([data-library-theme]) body.is-book-detail .shelf { padding-top: calc(var(--shelf-header-height) + 56px); }
  html:not([data-library-theme]) body.is-book-detail .is-detail .stage { top: auto; }
}

/* Give the public bookshelf breathing room beneath the shared navigation. */
html:not([data-library-theme]) body:not(.is-book-detail) .shelf {
  padding-top: max(144px, calc(var(--shelf-header-height) + 48px));
}
@media (max-width: 1100px) {
  html:not([data-library-theme]) body:not(.is-book-detail) .shelf { padding-top: 112px; }
}

/* Live article below the transparent page face; the board still occludes it in WebGL. */
.live-sheet-layer { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: clip; }
.live-sheet-surface { position: absolute; top: 0; left: 0; transform-origin: 0 0; overflow: hidden; }
.live-sheet-surface iframe { display: block; border: 0; background: #f2f2f2; }
.live-sheet-layer.is-shown { position: fixed; z-index: 20; visibility: visible; pointer-events: auto; }
.live-sheet-layer.is-shown .live-sheet-surface { inset: 0; }

.live-sheet-content { position: absolute; top: 0; overflow: hidden; }

body:not(.is-reading):not(.is-book-detail) .live-sheet-layer { mask-image: linear-gradient(to bottom, transparent calc(var(--live-scroll, 0px) + var(--fade-from)), #000 calc(var(--live-scroll, 0px) + var(--fade-to))); }

/* Descriptions belong to the detail view; hidden summaries must not reserve shelf rows. */
body:not(.is-book-detail) .info-desc { display: none; }
