/* A shelf, in Marginalia's own language: serif for the books, expanded
   sans for structure, ink stars, and the cover supplying the colour. */

/* The bare board a book is drawn on before its cover arrives. */
:root { --board: #ebe6dc; --cover-edge: rgba(0, 0, 0, .14); }
/* On a dark page a dark cover's edge vanishes, and a navy jacket beside a
   cream one reads as the smaller book. A light hairline keeps its size. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --board: #2a2724; --cover-edge: rgba(255, 255, 255, .16); } }
:root[data-theme="dark"] { --board: #2a2724; --cover-edge: rgba(255, 255, 255, .16); }

/* The hairlines the Marginalia and Work pages are drawn on. */
:root { --rule: rgba(0, 0, 0, .1); --rule-strong: rgba(0, 0, 0, .22); --rail-x: 48px; --top-y: 64px; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --rule: rgba(255, 255, 255, .1); --rule-strong: rgba(255, 255, 255, .26); } }
:root[data-theme="dark"] { --rule: rgba(255, 255, 255, .1); --rule-strong: rgba(255, 255, 255, .26); }

/* The margin: a rule down the left, fixed, and one across the top that
   scrolls away with the masthead, drawn in on arrival. */
.frame, .frame-top { display: none; }
@media (min-width: 900px) { .frame, .frame-top { display: block; } }
.frame { position: fixed; inset: 0; z-index: 40; pointer-events: none; }
.frame-top { position: absolute; top: 0; left: 0; right: 0; height: 0; z-index: 40; pointer-events: none; }
.f-v, .f-h { position: absolute; background: var(--rule); transition: transform 1.6s cubic-bezier(.2, .7, .1, 1); }
.f-v { top: 0; bottom: 0; left: var(--rail-x); width: 1px; transform-origin: top; transition-delay: .1s; }
.f-h { left: 0; right: 0; top: var(--top-y); height: 1px; transform-origin: left; transition-delay: .25s; }
.pre .f-v { transform: scaleY(0); }
.pre .f-h { transform: scaleX(0); }
.reg { position: absolute; width: 11px; height: 11px; margin: -5px 0 0 -5px; left: var(--rail-x); top: var(--top-y); transition: opacity .6s ease 1.1s; }
.reg::before, .reg::after { content: ""; position: absolute; background: var(--rule-strong); }
.reg::before { left: 5px; top: 0; width: 1px; height: 11px; }
.reg::after { top: 5px; left: 0; width: 11px; height: 1px; }
.pre .reg { opacity: 0; }

.shelf-page { max-width: 1100px; margin: 0 auto; padding: max(112px, env(safe-area-inset-top)) 24px 24px; }
/* Clear of the margin rule, until the page is wide enough to be clear anyway. */
@media (min-width: 900px) { .shelf-page { padding-left: max(24px, calc(112px - max(0px, (100vw - 1100px) / 2))); } }
/* Back: a chevron and where it goes, in the primary ink, pinned to the top
   left corner as the page scrolls (just past the margin's rule on a wide
   screen). */
.shelf-page .back { position: fixed; z-index: 45; top: max(14px, env(safe-area-inset-top)); left: 16px;
  display: inline-flex; align-items: center; gap: 7px; height: 40px; padding: 0 14px 0 12px; border-radius: 999px;
  font-size: 13px; font-weight: 500; color: var(--label); text-decoration: none;
  transition: color .2s ease; }
@media (min-width: 900px) { .shelf-page .back { left: calc(var(--rail-x) + 6px); top: calc(var(--top-y) / 2 - 20px); } }
.shelf-page .back .chevron { display: inline-flex; transition: transform .2s ease; }
.shelf-page .back .chevron svg { width: 7px; height: 12px; }
.shelf-page .back:hover { color: color-mix(in srgb, var(--label) 60%, transparent); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .shelf-page .back:hover .chevron { transform: translateX(-2px); }
}
/* The masthead comes into focus on arrival, as the other pages' heroes do. */
.masthead > * { transition: opacity 1.1s ease, filter 1.1s ease, transform 1.1s cubic-bezier(.2, .7, .1, 1); transition-delay: var(--d, 0s); }
.pre .masthead > * { opacity: 0; filter: blur(14px); transform: translateY(10px); }
.shelf-page h1 { margin: 0; font: 400 clamp(44px, 6vw, 72px)/1 var(--serif); letter-spacing: -.022em; margin-left: -.035em; }
.lede { max-width: 34em; margin: 22px 0 0; font: 400 clamp(17.5px, 1.7vw, 20px)/1.55 var(--serif); color: var(--body); }
.lede a { text-underline-offset: 3px; text-decoration-thickness: 1px; }
.as-of { margin: 14px 0 0; font-size: 12px; color: var(--secondary); }
/* A section's name: a chip sitting on a hairline across the page. */
.chip {
  display: inline-block; margin: 0; padding: 5px 9px; border-radius: 6px;
  font-size: 11px; font-weight: 500; letter-spacing: .02em; line-height: 1.3;
  color: var(--label); background: color-mix(in srgb, var(--label) 7%, var(--page));
}
.chip .count { color: var(--secondary); font-weight: 400; margin-left: 3px; font-variant-numeric: tabular-nums; }
.reading, .read { position: relative; }
.reading::before, .read::before { content: ""; position: absolute; top: 0; left: 50%; width: 100vw; margin-left: -50vw; height: 1px; background: var(--rule); }
.reading > .chip, .read-head > .chip { position: relative; top: -11px; }

/* The shelf in numbers, as the Work page counts its own. */
.stats { margin-top: 44px; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); max-width: 820px; border-top: 1px solid var(--rule); }
.stat { padding: 18px 18px 2px; border-left: 1px solid var(--rule); }
.stat:first-child { border-left: 0; padding-left: 0; }
.stat .n { display: block; font: 400 clamp(40px, 4.6vw, 56px)/1 var(--serif); letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.stat .l { display: block; margin-top: 8px; font-size: 12px; color: var(--secondary); }
.stats { transition: opacity 1.1s ease .8s, filter 1.1s ease .8s; }
.pre .stats { opacity: 0; filter: blur(10px); }
@media (max-width: 600px) {
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stat:nth-child(3) { border-left: 0; padding-left: 0; }
  .stat:nth-child(n + 3) { border-top: 1px solid var(--rule); }
}

/* A book comes into focus as it scrolls in, a beat after the one beside it. */
.grid-item, .reading-item { transition: opacity .8s ease, filter .8s ease, transform .8s cubic-bezier(.2, .7, .1, 1); transition-delay: var(--d, 0s); }
.grid-item.later, .reading-item.later { opacity: 0; filter: blur(8px); transform: translateY(20px); }
@media (prefers-reduced-motion: reduce) { .grid-item, .reading-item, .masthead > *, .stats { transition: none; } }
.loading { margin: 64px 0; font: 400 15px var(--serif); color: var(--secondary); }


/* Behind the corners' links, once the page is under way: a patch of blur
   in the section chips' shape (6px corners, close around the words), the
   page beneath faded back, so the links read over anything. Nothing more:
   no tint, rim or shadow. */
.shelf-page .back::before {
  content: ""; position: absolute; z-index: -1; inset: 6px 4px;
  border-radius: 6px;
  background: color-mix(in srgb, var(--page) 60%, transparent);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  opacity: 0; transition: opacity .35s ease;
  pointer-events: none;
}
.scrolled .shelf-page .back::before { opacity: 1; }

/* ---------- A cover, drawn as a book ---------- */
/* The cover supplies the colour; over it, only the binding (below) and a
   hairline edge. */

.book {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 2 / 3;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  container-type: inline-size;
  -webkit-tap-highlight-color: transparent;
}
.book .face {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* Card, not board: corners only just softened, a touch more at the fore-edge. */
  border-radius: 1cqi 2.4cqi 2.4cqi 1cqi;
  background: var(--board);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .08), 0 6px 18px rgba(0, 0, 0, .1);
  transition: transform .35s cubic-bezier(.2, .9, .3, 1), box-shadow .35s ease;
}
.book .face img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transition: opacity .3s ease; }
.book .face img.on { opacity: 1; }
.book .face::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 .5px var(--cover-edge);
  pointer-events: none;
}

/* Drawn as a book rather than a picture of one, as Apple Books does, but
   as the paperbacks I mostly read: a shade where the cover wraps the spine,
   the fold scored into the card a little way in, corners only just
   softened, and the sheen of a laminated cover. Each is a whisper of black
   or white, so it reads on any jacket. */
:root {
  --binding:
    linear-gradient(90deg, rgba(0, 0, 0, .16) 0, rgba(0, 0, 0, 0) 1.8%, rgba(0, 0, 0, 0) 3%,
      rgba(0, 0, 0, .18) 3.5%, rgba(255, 255, 255, .26) 4.1%, rgba(255, 255, 255, 0) 5.4%),
    linear-gradient(270deg, rgba(0, 0, 0, .08) 0, transparent 1.5%),
    linear-gradient(115deg, rgba(255, 255, 255, .16) 0, rgba(255, 255, 255, 0) 32%,
      rgba(255, 255, 255, 0) 70%, rgba(255, 255, 255, .06) 100%);
}
.book .face::before, .flow-cover::before {
  content: "";
  position: absolute;
  z-index: 1;
  inset: 0;
  border-radius: inherit;
  background: var(--binding);
  pointer-events: none;
}
.book .placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 14% 12%;
  font: 500 clamp(12px, 1.6vw, 16px)/1.25 var(--serif);
  color: var(--label);
  text-align: left;
}
.book .placeholder small { font: 500 10px var(--sans); font-stretch: 125%; color: var(--secondary); }
@media (hover: hover) {
  .book:hover .face { transform: translateY(-3px); box-shadow: 0 2px 4px rgba(0, 0, 0, .08), 0 14px 30px rgba(0, 0, 0, .16); }
}
.book:active .face { transform: scale(.97); }
@media (prefers-reduced-motion: reduce) {
  .book .face { transition: none; }
  .book:hover .face, .book:active .face { transform: none; }
}

/* The wash: the book you're reading, bloomed out behind the top of the
   page as the Library draws it in the app, and fading out to the page as
   you go down. One fade, long and eased, so it never ends in an edge. */
.page-wash {
  position: absolute;
  inset: 0 0 auto;
  height: max(1100px, 140vh);
  overflow: hidden;
  pointer-events: none;
  z-index: -1;
  -webkit-mask-image: linear-gradient(180deg, #000 0, rgba(0, 0, 0, .85) 18%, rgba(0, 0, 0, .55) 40%,
    rgba(0, 0, 0, .28) 62%, rgba(0, 0, 0, .1) 82%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0, rgba(0, 0, 0, .85) 18%, rgba(0, 0, 0, .55) 40%,
    rgba(0, 0, 0, .28) 62%, rgba(0, 0, 0, .1) 82%, transparent 100%);
}
.page-wash img {
  position: absolute;
  inset: -80px;
  width: calc(100% + 160px);
  height: calc(100% + 160px);
  object-fit: cover;
  opacity: 0;
  filter: blur(70px) saturate(var(--wash-sat)) brightness(var(--wash-bright));
  transition: opacity .6s ease;
}
.page-wash img.on { opacity: var(--wash-strength); }

.stars { letter-spacing: .08em; color: var(--label); }
.stars .off { color: var(--quaternary); }

/* ---------- Reading now ---------- */

.reading { margin-top: 72px; }
/* The same columns as the Read grid, so a book is the same size in both. */
.reading-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 40px 28px;
  margin-top: 10px;
}
/* Every title takes two lines and every author one, whatever their length,
   so the bars line up across the row - as the app's shelf caption does. */
.reading-item .title {
  margin: 14px 0 0;
  font: 500 16px/1.3 var(--serif);
  height: 2.6em;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.reading-item .author { margin: 3px 0 0; font: 400 12px var(--sans); font-stretch: 125%; color: var(--secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A thin rule of progress, like the page's hairlines, not the app's 10pt bar:
   at a third of the width that read as a slab, and a few pages in as a dot. */
.progress { margin-top: 12px; height: 3px; border-radius: 1.5px; background: var(--quaternary); overflow: hidden; }
.progress span { display: block; height: 100%; min-width: 3px; background: var(--ink); border-radius: 1.5px; }
.reading-item .page { margin: 6px 0 0; font: 400 12px var(--sans); font-stretch: 125%; color: var(--secondary); }

/* ---------- Marginalia ---------- */
/* The page's footer, after the App Store's own artwork: the line in the
   screenshots' caption face (Archivo 380, expanded) and three phones level
   and running off the foot of the page. It has no background of its own:
   by here the page's wash has faded out, so it doesn't end in a band. */

/* base.css styles every footer as a column of small print; this one isn't. */
footer.home {
  position: relative;
  display: block;
  max-width: none;
  margin: 56px 0 0;
  padding: 0;
  overflow: hidden;
  isolation: isolate;
  color: var(--label);
  font-size: inherit;
}

.home-head { max-width: 1100px; margin: 0 auto; padding: clamp(48px, 7vw, 80px) 24px 0; text-align: center; }
.home-title {
  margin: 0;
  font: 380 clamp(24px, 3.4vw, 40px)/1.12 var(--sans);
  font-stretch: 125%;
  letter-spacing: -.01em;
  text-wrap: balance;
}
.home-sub { max-width: 30em; margin: 12px auto 0; text-wrap: balance; font: 400 16px/1.5 var(--serif); color: var(--body); }
.home-cta { display: flex; justify-content: center; align-items: center; gap: 20px; margin-top: 20px; }
.home-cta .store img { height: 36px; width: auto; }
.home-more { font: 500 13px var(--sans); font-stretch: 125%; color: var(--label); text-decoration: none; }
.home-more:hover { text-decoration: underline; text-underline-offset: 3px; }

/* The Marginalia page's hero, at the foot of this one: the phone in front
   of a Cover Flow that carries on behind it and out to the edges - here
   made of my own shelf. The phone is cut off at the foot and faded, and the
   flow's centre cover is hidden behind it, so its screen is the one in front. */
.home-stage {
  --pw: min(440px, 78vw);
  position: relative;
  height: calc(var(--pw) * 1.628 * .8);
  margin-top: clamp(32px, 4.5vw, 52px);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 150px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 150px), transparent);
}
.home-stage .flow-stage { position: absolute; left: 0; right: 0; top: 0; }
.home-phone { position: absolute; z-index: 20000; left: 50%; top: 0; width: var(--pw); height: auto;
  margin-left: calc(var(--pw) / -2); pointer-events: none; }
.flow-stage {
  overflow: hidden;
  touch-action: pan-y;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.flow-stage.dragging { cursor: grabbing; }
.flow-stage:focus-visible { outline: none; }
.flow-cover {
  position: absolute;
  top: 48px;
  left: 0;
  width: var(--cw);
  height: calc(var(--cw) * 1.5);
  padding: 0;
  border: 0;
  background: var(--board);
  border-radius: calc(var(--cw) * .01) calc(var(--cw) * .024) calc(var(--cw) * .024) calc(var(--cw) * .01);
  will-change: transform, opacity;
  cursor: inherit;
}
.flow-cover img { display: block; width: 100%; height: 100%; border-radius: inherit; object-fit: cover;
  pointer-events: none; -webkit-user-drag: none; }
.flow-cover::after { content: ""; position: absolute; z-index: 2; inset: 0; border-radius: inherit;
  box-shadow: inset 0 0 0 .5px var(--cover-edge); pointer-events: none; }

@media (max-width: 600px) {
  .home-head { padding-left: 16px; padding-right: 16px; }
}


/* ---------- Read ---------- */

.read { margin-top: 80px; }
.read-head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 16px 32px; }
.filters { display: flex; flex-wrap: wrap; gap: 8px; }
.filters label {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: 999px;
  background: var(--card);
  border: .5px solid var(--glass-line);
  font-size: 12px;
  color: var(--secondary);
}
.filters select {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  background: none;
  padding: 0 14px 0 0;
  font: 500 12px var(--sans);
  font-stretch: 125%;
  color: var(--label);
  cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 4px center, right 0 center;
  background-size: 4px 4px;
  background-repeat: no-repeat;
}
.filters select:focus-visible { outline: none; }
.filters label:focus-within { outline: 2px solid var(--ink); outline-offset: 2px; }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 40px 28px;
  margin-top: 20px;
}
/* The filters sit on the rule beside the chip. */
.read-head { align-items: flex-start; }
.read-head .filters { position: relative; top: -16px; }
.grid-item .caption { margin: 12px 0 0; display: flex; justify-content: space-between; gap: 8px; font: 400 11px var(--sans); font-stretch: 125%; color: var(--secondary); }
.empty { margin: 32px 0; font: 400 15px var(--serif); color: var(--secondary); }

@media (max-width: 600px) {
  .shelf-page { padding-left: 16px; padding-right: 16px; }
  /* minmax(0, …): a long author line would otherwise widen its column, and the page. */
  .reading-row, .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px 14px; }
  /* At a third of a phone, the expanded face wrapped "Page 198 of 334". */
  .reading-item .page { font-stretch: 100%; white-space: nowrap; }
  .grid-item .caption { flex-direction: column; gap: 2px; }
  .read-head { align-items: start; }
}

/* ---------- The foot of the page ---------- */
/* The Marginalia footer above is its own band; this is the site's small print. */
footer.site-foot {
  position: relative; max-width: 1100px; margin: 0 auto;
  padding: 30px 24px max(48px, env(safe-area-inset-bottom));
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 12px 28px;
}
@media (min-width: 900px) { footer.site-foot { padding-left: max(24px, calc(112px - max(0px, (100vw - 1100px) / 2))); } }
footer.site-foot::before { content: ""; position: absolute; top: 0; left: 50%; width: 100vw; margin-left: -50vw; height: 1px; background: var(--rule); }
footer.site-foot .small { margin: 0; flex-basis: 100%; }
@media (max-width: 600px) { footer.site-foot { padding-left: 16px; padding-right: 16px; } }

/* ---------- A book's card ---------- */

.book-card {
  width: min(760px, calc(100vw - 32px));
  max-height: min(86vh, 900px);
  padding: 0;
  border: .5px solid var(--glass-line);
  border-radius: 28px;
  background: var(--page);
  color: var(--label);
  box-shadow: 0 30px 80px rgba(0, 0, 0, .28);
  overflow: hidden;
}
.book-card[open] { display: flex; flex-direction: column; animation: card-in .32s cubic-bezier(.2, .8, .2, 1); }
.book-card.zoomed[open] { animation: none; }
.book-card::backdrop { background: var(--scrim); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
/* The cover's zoom into the card, where the browser can draw one. */
::view-transition-group(zooming) { animation-duration: .42s; animation-timing-function: cubic-bezier(.2, .9, .3, 1); }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .3s; }
@keyframes card-in { from { opacity: 0; transform: translateY(12px) scale(.98); } }
@media (prefers-reduced-motion: reduce) { .book-card[open] { animation: none; } }

/* The wash: the cover shrunk and bloomed out behind the card, as in the app. */
.card-wash { position: absolute; inset: -60px; pointer-events: none; overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 0, #000 30%, transparent 75%);
  mask-image: linear-gradient(180deg, #000 0, #000 30%, transparent 75%); }
.card-wash img { width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity .4s ease;
  filter: blur(60px) saturate(var(--wash-sat)) brightness(var(--wash-bright)); }
.card-wash img.on { opacity: var(--wash-strength); }

.card-bar { position: relative; display: flex; align-items: center; gap: 4px; padding: 12px 12px 0; }
.card-bar .spacer { flex: 1; }
.icon {
  width: 36px; height: 36px;
  border-radius: 50%;
  border: .5px solid var(--glass-line);
  background: var(--glass);
  -webkit-backdrop-filter: blur(14px) saturate(1.6);
  backdrop-filter: blur(14px) saturate(1.6);
  font: 400 15px var(--sans);
  cursor: pointer;
}
.icon:disabled { opacity: .35; cursor: default; }

.card-body { position: relative; display: grid; grid-template-columns: 180px 1fr; gap: 28px; padding: 16px 32px 36px; overflow-y: auto; }
.card-cover .book { cursor: default; }
.card-cover .face img { transition: none; }
.card-author { margin: 0; font: 400 12px var(--sans); font-stretch: 125%; color: var(--secondary); }
.card-title { margin: 6px 0 0; font: 500 26px/1.2 var(--serif); }
.card-meta { margin: 10px 0 0; display: flex; flex-wrap: wrap; gap: 4px 14px; font: 400 12px var(--sans); font-stretch: 125%; color: var(--secondary); }
.card-review { margin-top: 20px; }
.card-review p { margin: 0 0 12px; font: 400 17px/1.6 var(--serif); color: var(--body); }

@media (max-width: 600px) {
  .book-card { width: 100vw; max-width: 100vw; max-height: 92vh; margin: auto 0 0; border-radius: 28px 28px 0 0; }
  .card-body { grid-template-columns: 1fr; padding: 8px 20px max(28px, env(safe-area-inset-bottom)); gap: 20px; }
  .card-cover { width: 132px; }
}
