/* The bookcase, close up.
 *
 * /fun is a room you stand in. Clicking the bookcase should not drop you into a
 * list, so this page is the same room seen from a step closer: shelves, a board
 * under each one, and Shaun's five-out-of-five books standing on them under the
 * category each one belongs to. It loads fun.css for the tokens and the typefaces and
 * then builds one component, the book.
 *
 * WHY THE BOOK IS BUILT IN CSS AND NOT DRAWN AS A PLATE
 *
 * Every other object in the room is a generated graphite plate composited at a
 * percentage coordinate, which is right for four objects and impossible for 140.
 * A book is a box, CSS draws a box at any size in any weight of paper, and the
 * title stays real selectable text that a screen reader can say and a search
 * engine can index. Adding a book stays one row of data.
 *
 * WHY IT IS DRAWN IN GRAPHITE RATHER THAN FILLED WITH FLAT COLOUR
 *
 * Shaun, 2026-08-25: "why have we not designed the books like graphite pencil?"
 * He was right and the first version was wrong. Standing a flat CSS rectangle
 * with a hairline border next to a hand drawn bookcase gives you a CHART of a
 * bookcase, and the room next door is a pencil drawing on cartridge paper.
 *
 * So each face is built the way a pencil builds one. A flat tone underneath,
 * paper grain multiplied through it, a band of hatching laid across at an angle,
 * and a contour that is a drawn SVG path with a wobble in it rather than a
 * border. All of it is CSS and two data URIs, which matters because this page
 * still has to work with JavaScript switched off.
 *
 * WHY THE COVERS ARE REAL AND REDRAWN
 *
 * Shaun, same day: "i think where possible we should use the actual cover art."
 * That reverses an earlier call in the same session for drawn covers, and it
 * pulls against the request above it, since a full colour dust jacket dropped
 * onto a pencil drawing is a photograph lying on a drawing.
 *
 * Both are satisfied by passing the real cover through the room's own duotone,
 * in scripts/build-book-covers.py, which is the same treatment every plate in
 * the room gets. A duotone keeps composition and typography and throws away only
 * hue, so the cover stays completely recognisable and is unmistakably part of
 * this room. The BOOK is drawn; the COVER is the printed thing the drawn book
 * carries, which is what a real book is.
 *
 * 113 of the 140 have a cover that could be verified as the right book in
 * English. The other 27 keep the drawn face carrying the title and the author,
 * and that fallback is not a stopgap: it is also what a browser with no WebP
 * sees, because the drawn face is in the markup underneath the image rather
 * than replaced by it.
 *
 * THE TRAP IN THIS FILE
 *
 * The three faces of the box share a base rule and are then placed individually.
 * `.bk3 > span` scores 0-1-1 and `.bk-cover` scores 0-1-0, so anything the base
 * rule sets silently beats the face that needs it different. A `left` there
 * collapses the page block onto the spine; a `display` there leaves the cover as
 * a block with a flex-direction that does nothing, so the author's name runs into
 * the title. Both render, both look nearly right, and no assertion catches
 * either: only reading the pixels back does.
 *
 * So the base rule carries only what no face overrides, which today is position
 * and top. Adding anything else to it will break a face at a distance. Put it on
 * the three faces instead, even at the cost of repeating it.
 */

/* ---- the page ---- */

/* The two textures every drawn face shares, declared once so 140 books cost one
   copy of each string rather than 140. On .reading-body rather than :root so
   they cannot leak into a page that has not asked to be drawn on. */
.reading-body {
  /* Fractal noise at the scale of cartridge paper tooth. numOctaves 4 rather
     than 1, because a single octave is television static and four is a surface. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' seed='11'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.5'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='150' height='150' filter='url(%23g)'/%3E%3C/svg%3E");
  /* Pencil hatching, laid at the angle a right hand naturally rules at. */
  --hatch: repeating-linear-gradient(62deg, rgba(20, 18, 15, .10) 0 1px, transparent 1px 5px);
}

.reading-body main { max-width: 78rem; padding: 3.25rem 1.5rem 5rem; }

.rl-top {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .8rem 1.2rem;
  margin: 0 0 1.6rem;
}
.rl-top .btn-drawn { flex: none; font-size: .95rem; padding: .7rem 1.35rem; }
.rl-top .btn-drawn i { font-style: normal; font-size: 1.05em; line-height: 1; margin-right: .45em; }

.rl-head { max-width: 40rem; }
.rl-head h1 { margin: 0 0 .7rem; }
.rl-head .lede { margin: 0; }

/* The count, sized like data rather than like prose, because it is the one fact
   on the page that a reader wants before anything else. */
.rl-count {
  font-family: var(--font-mono); font-size: .72rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-muted);
  margin: 2.6rem 0 0; padding: 0 0 .3rem;
}

/* ---- a shelf ---- */

.shelf-row { margin: 0 0 .3rem; }

.shelf-row h2 {
  display: flex; align-items: baseline; gap: .85rem;
  margin: 2.1rem 0 .5rem;
  font-family: var(--font-mono); font-size: .72rem; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-muted);
}
.shelf-row h2 em { font-style: normal; font-size: .66rem; color: var(--rule); letter-spacing: .1em; }

/* A bookcase too wide for the screen is scanned sideways, which is also what you
   do to a real one. The board scrolls with the books so they never come apart. */
.shelf-scroll { overflow-x: auto; overflow-y: hidden; padding: 0 0 .4rem; }
.shelf-inner { min-width: max-content; }

.books {
  list-style: none; margin: 0;
  /* Declared, not a fallback on the one line that reads it. Every book's height
     AND the width of its boards are computed from this, so it has to be a real
     custom property that a media query can change and have the whole shelf
     follow. --shelf-h was a var(..., 186px) fallback and nothing ever set it. */
  --shelf-h: 186px;
  display: flex; align-items: flex-end; gap: 2px;
  height: var(--shelf-h);
  padding: 0 0 0 12px;
  /* One vanishing point per board, so every book on a shelf recedes together
     the way a real shelf does rather than each book having its own camera. */
  perspective: 1500px;
  perspective-origin: 50% 40%;
}

.plank {
  height: 10px; border-radius: 1px;
  background: linear-gradient(180deg, #C6B99C, #A89B80 42%, #8A8069);
  box-shadow: 0 5px 9px -4px rgba(20, 20, 20, .42);
}

/* ---- the book ---- */

/* A book's slot on the board is only as wide as its spine, so a shelf packs edge
   to edge exactly as a real one does. The 3D box overflows the slot, which is
   what lets a book swing out over its neighbours when someone reaches for it.

   The link sits inside the slot and wraps the box rather than sitting beside it.
   A transformed child is still part of its anchor for hit testing, so the turned
   out cover is clickable even though it is nowhere near the slot it came from,
   which is the half of this that an overlay hit area would get wrong. */
/* A TALLER BOOK IS ALSO A WIDER BOOK, which is why --cw is computed here rather
   than being one fixed number for all 140.
 *
 * It used to be a flat 124px against heights running 160 to 186, so the face
 * came out anywhere from 0.67 to 0.78 wide over tall depending on the book. That
 * did not matter while the face was a rectangle with type on it, and it matters
 * a lot now that it carries artwork: every cover is cut to exactly 0.68 by
 * scripts/build-book-covers.py, and object-fit then quietly ate up to 15% of the
 * widest ones. Steal Like an Artist read USTIN KLEON.
 *
 * So the board is 0.68 of the book's own height, the number the builder cuts to,
 * and both come off --shelf-h. Change the shape here and it has to change there
 * too; nothing fails if they disagree, the covers just start getting cropped
 * again. --tallf is unitless for exactly this reason: a percentage could give
 * the height but could not be multiplied to give the width. */
.bk {
  --cw: calc(var(--shelf-h) * var(--tallf) * .68);
  position: relative; flex: 0 0 auto;
  width: var(--thick); height: calc(var(--shelf-h) * var(--tallf));
}
.bk-a {
  position: absolute; inset: 0; display: block;
  text-decoration: none; color: inherit; outline: none;
}

.bk3 {
  position: absolute; inset: 0;
  width: var(--cw, 124px); height: 100%;
  transform-style: preserve-3d;
  transform-origin: 0 50%;
  transform: rotateY(88deg);
  transition: transform .42s cubic-bezier(.22, .7, .24, 1);
}
.bk:hover, .bk:focus-within { z-index: 6; }
.bk:hover .bk3, .bk:focus-within .bk3 { transform: rotateY(26deg) translateZ(26px); }

/* A CLOSED BOOK MUST NOT TAKE ITS NEIGHBOUR'S CLICKS
 *
 * MEASURED, and not what it first looks like. A transform DOES affect hit
 * testing, so a closed .bk3 tests 4.4px wide rather than the 120px of --cw. The
 * thief is the next book's .bk-edge, the page-block face, which rotateY(-90deg)
 * and the shelf's shared perspective-origin of 50% project back across its
 * neighbour: probed at x=1000.5 it came back as the top element with an
 * axis-aligned rect of 1018.1 to 1047.1. That shared vanishing point is also why
 * only books on the right half of a shelf are affected, and with no z-index in
 * play the later sibling wins, so a book can only ever be robbed from its right.
 *
 * Measured on the reshelved page at 1440px before this rule: 7 of the 74 books
 * with notes could not be clicked on their own spine, and in all 7 cases the
 * thief was the next sibling's .bk3. The year shelves happened not to hit it,
 * so the fragility shipped unseen and only surfaced when the books were put in
 * a different order. Reordering them again until it stops would be luck rather
 * than a fix, since any future book can reintroduce it.
 *
 * So the overhang is switched off until the book is actually turned out, which
 * is the only state in which any of it is visible to aim at. Closed, the only
 * thing that takes a pointer is .bk-a, which fills the slot exactly, and slots
 * are flex items that cannot overlap. Open, the box comes back and the turned
 * out cover stays clickable nowhere near the slot it came from, which is what
 * the note above about hit testing through a transform is protecting.
 *
 * The pointer reaches the cover by crossing the slot first, which is what puts
 * the book in :hover in the first place, so there is no state where a reader
 * can see a cover and not be able to click it. */
.bk3 { pointer-events: none; }
/* Only a book with notes gets its reach back.
 *
 * A turned out cover overhangs the books to its right, and for a book that
 * opens that is the point: the reader aims at the cover they can see and the
 * click lands. A book with nothing to open has no such claim, and while it was
 * allowed the same reach it sat on top of its neighbour and took the hover with
 * it, so reaching for the openable book beside a dead one kept the dead one
 * turned out instead. Seen on the Memoir shelf, where the very first book has
 * no notes and the second one does. */
.bk:not(.bk-unread):hover .bk3, .bk:not(.bk-unread):focus-within .bk3 { pointer-events: auto; }

/* Only what no face overrides. See THE TRAP at the top of this file. */
.bk3 > span { position: absolute; top: 0; }
.bk-cover, .bk-spine { left: 0; }

/* HOW A FACE IS DRAWN IN GRAPHITE
 *
 * Four layers, in the order a hand would lay them: the tone of the cloth, the
 * grain of the paper multiplied through it so the tone is never flat, a band of
 * hatching at 62 degrees for the sheen down one side, and last the contour.
 *
 * The grain is one feTurbulence tile as a data URI, shared by every face on the
 * page, so 140 books cost one 300 byte string. It has to be multiplied rather
 * than laid over, or a light book gets a grey wash and a dark one gets nothing.
 *
 * The contour is the part that actually reads as drawn. A border is four
 * straight lines of one width; this is an SVG path with the corners missed and
 * the edges bowed, stretched over the face with preserveAspectRatio="none" and
 * held to an even weight by vector-effect. Stretching is deliberate: a spine is
 * a fifth the width of a cover, so the same wobble compresses into a tighter
 * jitter there, and no two books are the same size, so no two contours land
 * identically. */
.bk-cover,
.bk-spine {
  background-color: var(--tone);
  background-image: var(--grain), var(--hatch);
  background-blend-mode: multiply, multiply;
  background-size: 150px 150px, auto;
  color: var(--fg);
}
.bk-cover::after,
.bk-spine::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: var(--contour) 0 0 / 100% 100% no-repeat;
}

/* Back cover at z=0, front cover at z=thickness, and the two narrow faces
   pivoted about their own left edge to span the gap between them. */
.bk-cover {
  display: flex; flex-direction: column; justify-content: space-between;
  width: var(--cw); height: 100%;
  transform: translateZ(var(--thick));
  border-radius: 1px 3px 3px 1px;
  padding: var(--face-pad, 13px) 11px;
  /* The shadow the boards cast into the hinge, which is the one piece of this
     that a drawn contour cannot say. */
  box-shadow: inset 3px 0 0 rgba(20, 20, 20, .14);
  --contour: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 124 186' preserveAspectRatio='none'%3E%3Cpath d='M2.6 3.4C34 1.9 74 4.6 121.3 2.4M121.3 2.4C122.6 62 120.4 124 121.6 183.4M121.6 183.4C82 185.1 42 182.2 2.2 184.4M2.2 184.4C3.6 124 1.4 62 2.6 3.4' fill='none' stroke='%232B2823' stroke-width='1.5' stroke-linecap='round' vector-effect='non-scaling-stroke' opacity='.66'/%3E%3Cpath d='M9.4 4.2C8.8 62 10.6 124 9.1 183.4' fill='none' stroke='%232B2823' stroke-width='1' stroke-linecap='round' vector-effect='non-scaling-stroke' opacity='.34'/%3E%3C/svg%3E");
}
.bk-cover b { font-family: var(--font-display); font-weight: 600; font-size: .84rem; line-height: 1.2; text-wrap: balance; }
.bk-cover i {
  font-family: var(--font-mono); font-style: normal; font-size: .54rem;
  letter-spacing: .06em; text-transform: uppercase; opacity: .74;
}

/* ---- the real cover, redrawn ---- */

/* The artwork sits ON the drawn board rather than instead of it. The title and
   the author are still in the markup underneath, which is what a browser with
   no WebP is left looking at, and the contour is lifted above the image so the
   drawn edge survives on a book that carries one. */
/* .bk3 is here for weight, not for reach, and it is THE TRAP at the top of this
   file wearing a different hat. An absolutely positioned child is laid against
   its ancestor's PADDING box, so the face's padding insets the artwork, and
   `.bk-cover.has-art` and `.book-hero .bk-cover` both score 0-2-0. Whichever is
   written second wins, which is a rule about the order of lines in a file
   rather than about what the page means. The extra class settles it. */
.bk3 .bk-cover.has-art { padding: 0; }
.bk-cover.has-art img {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; object-fit: cover;
  border-radius: 1px 3px 3px 1px;
}
/* The same paper the rest of the room is drawn on, laid back over the printed
   cover. Without it the artwork is the one perfectly smooth surface on a page
   of pencil, and a smooth surface is what gives away a photograph. */
.bk-cover.has-art::before {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: var(--grain) 0 0 / 150px 150px;
  mix-blend-mode: multiply; opacity: .5;
  border-radius: 1px 3px 3px 1px;
}
.bk-cover.has-art::after { z-index: 3; }

.bk-edge {
  display: block;
  width: var(--thick); height: 100%; left: var(--cw);
  transform-origin: 0 50%; transform: rotateY(-90deg);
  /* A page block is a stack of leaves, so it is hatched rather than filled. The
     ruling is a degree off square, because a hand ruling a hundred leaves does
     not get them parallel and a stack of pages that IS parallel reads as a
     printed swatch. */
  background:
    repeating-linear-gradient(91deg, #EFE7D6 0 1px, #D6CBB2 1px 2px),
    linear-gradient(180deg, #F0E9DC, #CFC4AA);
  border-radius: 0 2px 2px 0;
}

/* The face a reader actually sees, 139 times out of 140. Everything the cover
   gets, plus the two raised bands a bound spine carries at head and tail, which
   here are drawn lines in the contour rather than inset shadows. */
.bk-spine {
  display: flex; align-items: center; justify-content: center;
  width: var(--thick); height: 100%;
  transform-origin: 0 50%; transform: rotateY(-90deg);
  border-radius: 2px 0 0 2px;
  padding: 11px 0;
  --contour: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 186' preserveAspectRatio='none'%3E%3Cpath d='M2.4 3C11 1.8 21 4 27.6 2.6M27.6 2.6C28.7 62 26.5 124 27.8 183.6M27.8 183.6C20 185.2 10 182.4 2 184.6M2 184.6C3.2 124 1.2 62 2.4 3' fill='none' stroke='%232B2823' stroke-width='1.5' stroke-linecap='round' vector-effect='non-scaling-stroke' opacity='.7'/%3E%3Cpath d='M2.5 13.6C11 12.2 21 14.5 27.6 13M2.5 172.4C11 171 21 173.3 27.6 171.8' fill='none' stroke='%232B2823' stroke-width='1.1' stroke-linecap='round' vector-effect='non-scaling-stroke' opacity='.5'/%3E%3C/svg%3E");
}
.bk-spine b {
  writing-mode: vertical-rl;
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--sfs, .72rem); line-height: 1.12;
  /* A long title wraps into a second column, which is what a real spine does.
     Truncating to an ellipsis is what a database does. */
  white-space: normal; overflow: hidden;
  max-height: 100%; text-align: center;
}

/* A book Shaun rated five out of five but has not written about yet still stands
   on the shelf, because he read it and rated it. It is simply not a link, the
   same way the cupboard in the room is furniture rather than a promise. When he
   writes the notes in Notion, the next fetch turns it into one on its own.

   IT STILL HAS TO SAY THAT IT IS NOT ONE

   Opacity alone said it, at .8 on the spine, and that is a fifth of a shade on
   a shelf of graphite where every spine already carries its own tone: measured
   against the books either side of it, nothing about a closed one reads as
   different. So 66 of the 140 turned out to face the reader exactly as an
   openable book does, and then did nothing whatever when clicked. The first
   book on the first shelf is one of them, which is the first thing anyone
   clicks, and the reasonable conclusion from that is that the page is broken.

   These books keep the turn, because 52 of them carry real cover art and the
   shelf is meant to be a picture of what he has read rather than an index of
   what he has written. What they give up is the CLAIM: the cover says there is
   nothing to open, and the lift and the shadow that read as "this one responds
   to you" belong to the books that do. */
/* AT REST, WHICH IS THE ONLY STATE A PHONE HAS
 *
 * The band below needs the book turned out, and a touch screen never turns one
 * out, so on a phone the band alone would change nothing: the reader would tap
 * a book, get nothing, and be exactly where they started. The spine is what is
 * actually on screen on every device, so the spine is where the difference has
 * to be legible, and .8 was not it. */
.bk-unread .bk-spine { opacity: .58; }
.bk-unread .bk-spine b { font-weight: 400; opacity: .72; }

/* THE BAND'S HEIGHT AND THE ROOM MADE FOR IT ARE ONE NUMBER
 *
 * .bk-cover is space-between, so on a drawn face the author's name is pinned to
 * the exact edge the band covers, and the band painted across the foot of that
 * name on 12 of the 14 drawn faces. The other two are unaffected only because
 * their author is an empty string, not because they clear it. The name is set
 * in uppercase, so what was being cut was the base of the letterforms rather
 * than any descender. How far the band reached depends on what you measure,
 * which is why no figure is quoted here: the type's own line box overlapped by
 * 2.78px and the element's border box by 4.59px, both at a 16px root.
 * The 52 unread books carrying artwork never showed any of it, because the
 * image is positioned over the drawn name rather than beside it.
 *
 * The band takes its height from --band-h instead of summing a padding and a
 * line-height, and the face reserves that same variable, so the two cannot
 * drift apart the way they would if the clearance were a number typed twice. */
/* --face-pad is the face's own padding, declared once and used by both the
   shorthand below and the reserve above the band, so changing it moves both. */
.bk-cover { --face-pad: 13px; }
.bk-unread { --band-h: 1.1rem; }
.bk-nonotes {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 4;
  display: flex; align-items: center; justify-content: center;
  height: var(--band-h, 1.1rem); padding: 0 .2rem;
  font-family: var(--font-mono); font-size: .46rem; line-height: 1;
  letter-spacing: .12em; text-transform: uppercase; text-align: center;
  color: var(--paper); background: rgba(20, 18, 15, .74);
  /* Only once the book is actually turned out. Closed, the cover is 4px of
     edge and a band of type across it would be four pixels of noise. */
  opacity: 0; transition: opacity .3s ease .12s;
}
/* Only the drawn faces need the room, and the name keeps the same gap it always
   had, now measured from the band rather than from the foot of the cover. */
.bk-unread .bk-cover:not(.has-art) {
  padding-bottom: calc(var(--face-pad, 13px) + var(--band-h, 1.1rem));
}
.bk-unread:hover .bk-nonotes, .bk-unread:focus-within .bk-nonotes { opacity: 1; }

.bk-a:focus-visible .bk-spine { box-shadow: inset 0 0 0 2px var(--orange); }
/* The lift is the shelf saying "there is something here", so it is spent only
   on the books that have something. */
.bk:not(.bk-unread):hover .bk-cover {
  box-shadow: inset 3px 0 0 rgba(20, 20, 20, .14),
    0 16px 30px -14px rgba(20, 20, 20, .5);
}

/* ---- one book's page ---- */

.book-page main { max-width: 52rem; }

.book-hero {
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: 2.4rem 3rem;
  margin: 0 0 2.6rem; padding: 0 0 2.2rem;
  border-bottom: 1px solid var(--rule);
}

/* The same component, standing still and turned toward the reader, because on
   this page the book is the subject rather than one of 140.

   The height is computed from the width by the same 0.68 the shelf uses and the
   builder cuts to, rather than being a second hand measured number. It was 268
   against a width of 188, which is 0.701, and that three hundredths was enough
   to crop a strip off every cover on every book page. */
.book-hero .bk {
  --cw: 188px; --thick: 40px;
  width: 188px; height: calc(188px / .68); flex: none;
  margin: .3rem 3.2rem .3rem .4rem;
  perspective: 1400px;
}
.book-hero .bk3 { transform: rotateY(-26deg); }
.book-hero .bk:hover .bk3 { transform: rotateY(-16deg); }
.book-hero .bk-cover { padding: 20px 17px; }
.book-hero .bk-cover b { font-size: 1.12rem; }
.book-hero .bk-cover i { font-size: .62rem; }
.book-hero .bk-spine b { font-size: .8rem; }

.book-meta { flex: 1 1 20rem; min-width: 0; }
.book-meta h1 { margin: 0 0 .35rem; font-size: 2.1rem; }
.book-meta .by { margin: 0 0 1.1rem; font-size: 1.05rem; color: var(--ink-muted); font-family: var(--font-display); }
.book-facts { display: flex; flex-wrap: wrap; gap: .45rem; margin: 0; padding: 0; list-style: none; }
.book-facts li {
  font-family: var(--font-mono); font-size: .66rem; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-muted); border: 1px solid var(--rule); border-radius: 2px; padding: .38em .6em;
}
.book-facts li.rated { color: var(--orange-deep); border-color: var(--orange); }

/* The notes are Shaun's own, straight out of Notion, so they get ordinary
   reading measure and nothing else. */
.notes { max-width: 36rem; }
.notes p { margin: 0 0 1.1rem; }
.notes ul, .notes ol { margin: 0 0 1.2rem; padding-left: 1.35rem; }
.notes li { margin: .38rem 0; }
.notes li > ul, .notes li > ol { margin: .38rem 0 .1rem; }
.notes h3 { font-family: var(--font-display); font-size: 1.18rem; margin: 1.9rem 0 .6rem; }
.notes code { font-family: var(--font-mono); font-size: .88em; background: var(--paper-2); padding: .1em .3em; border-radius: 2px; }

.book-nav {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1rem;
  margin: 3rem 0 0; padding: 1.3rem 0 0; border-top: 1px solid var(--rule);
  font-size: .95rem;
}
.book-nav a { text-decoration: none; }
.book-nav a:hover { text-decoration: underline; }
.book-nav .nxt { text-align: right; margin-left: auto; }

@media (max-width: 34rem) {
  .book-hero .bk { --cw: 148px; --thick: 32px; width: 148px; height: calc(148px / .68); margin-right: 2.4rem; }
  .book-meta h1 { font-size: 1.7rem; }
}

/* ---- the pop-out ----
 *
 * The notes for one book, opened over the shelf by fun/_shared/bookcase.js.
 * It borrows .book-hero, .notes and .book-nav from the book page above rather
 * than restyling them, which is why those three selectors are unscoped: the
 * same writing has to read the same way in both places, and a second set of
 * rules for the pop-out would be a second thing to keep in step.
 *
 * The panel is sized in viewport units and scrolls inside itself, because the
 * longest note on the site is taller than a laptop viewport and a dialog that
 * grows past the screen puts its own close button out of reach. */
.bk-modal {
  border: 0; padding: 0; background: transparent;
  width: min(52rem, calc(100vw - 2rem));
  max-height: calc(100vh - 3rem);
  overflow: visible;
  color: var(--ink);
}
.bk-modal::backdrop { background: rgba(20, 18, 15, .55); }

.bk-modal-inner {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 3px;
  box-shadow: 0 24px 60px rgba(20, 18, 15, .28);
  max-height: calc(100vh - 3rem);
  display: flex; flex-direction: column;
}

.bk-modal-body {
  overflow-y: auto;
  padding: 2.4rem 2.4rem 2.2rem;
  font-family: var(--font-sans);
}
.bk-modal-body:focus { outline: none; }
.bk-modal-body .book-hero { margin-top: 0; }
/* The book page gives .notes a 36rem measure against a 52rem page. Inside the
   pop-out the panel IS 52rem at its widest, so the same measure would leave a
   16rem gutter of nothing down the right of every note. */
.bk-modal-body .notes { max-width: none; }
.bk-modal-body .book-nav { margin-top: 2.2rem; }

.bk-modal-wait { margin: 0; color: var(--ink-muted); font-family: var(--font-sans); }
.bk-modal-body.is-loading { opacity: .55; }

/* Over the panel rather than in the flow of it, so a long note scrolling under
   the button never takes the way out with it. */
.bk-modal-x {
  position: absolute; top: .5rem; right: .6rem; z-index: 2;
  width: 2.1rem; height: 2.1rem; padding: 0;
  border: 1px solid var(--rule); border-radius: 50%;
  background: var(--paper);
  color: var(--ink-muted); font: 1.35rem/1 var(--font-sans);
  cursor: pointer;
}
.bk-modal-x:hover { color: var(--ink); border-color: var(--ink-muted); }
.bk-modal-x:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }

@media (max-width: 34rem) {
  .bk-modal { width: calc(100vw - 1rem); max-height: calc(100vh - 1.5rem); }
  .bk-modal-inner { max-height: calc(100vh - 1.5rem); }
  .bk-modal-body { padding: 1.9rem 1.2rem 1.6rem; }
}

@media (prefers-reduced-motion: reduce) {
  /* The band goes with the turn. With the turn instant, a label that still
     fades over .3s after a .12s wait arrives after the book it belongs to. */
  .bk3, .bk-nonotes { transition: none; }
}
