/* ------------------------------------------------------------------ covers
   Generative book covers: palette and style come from the catalogue.
   Colours arrive as --bg / --fg / --accent (a pal-* class or CSSOM). */

.cover {
  --bg: #2a1d3a; --fg: #f3e9d2; --accent: #c9a45c;
  container-type: inline-size;
  position: relative;
  aspect-ratio: 2 / 3;
  width: 100%;
  overflow: hidden;
  background-color: var(--bg);
  color: var(--fg);
  border-radius: 1px 2px 2px 1px;
  font-family: 'Bodoni Moda', 'Didot', Georgia, serif;
}
.cover-inner {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3cqw;
  padding: 14cqw 11cqw 12cqw;
  text-align: center;
}
/* The default look is a plain matte paperback: a card cover with a faint score
   line near the spine and no sheen. Hardcovers get cloth and a hinge in 3D only. */
.cover::before {
  content: '';
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background:
    linear-gradient(90deg, rgb(0 0 0 / .1) 0, transparent 1.2%, transparent 2.6%, rgb(255 255 255 / .07) 2.8%, rgb(0 0 0 / .06) 3.2%, transparent 3.8%);
}
.obj--hardcover .cover::before, .obj--special-edition .cover::before {
  background:
    linear-gradient(90deg, rgb(0 0 0 / .28) 0, rgb(255 255 255 / .1) 2%, rgb(0 0 0 / .12) 4%, transparent 8%),
    repeating-linear-gradient(0deg, rgb(255 255 255 / .022) 0 1px, transparent 1px 3px);
}
.cover--image img { width: 100%; height: 100%; object-fit: cover; display: block; }

.c-title { position: relative; z-index: 1; font-weight: 400; font-size: 11cqw; line-height: 1.04; letter-spacing: -.005em; text-wrap: balance; }
.c-title--long { font-size: 8.6cqw; }
.c-sub { position: relative; z-index: 1; font-style: italic; font-size: 5.4cqw; opacity: .85; line-height: 1.2; }
.c-author {
  position: relative; z-index: 1;
  font-family: 'Jost', 'Futura', sans-serif; font-weight: 500;
  font-size: 3.9cqw; letter-spacing: .28em; text-transform: uppercase;
  color: var(--accent);
}
.c-mark { position: relative; z-index: 1; color: var(--accent); width: 13cqw; }
.c-mark svg { width: 100%; height: auto; display: block; }
.c-rule { display: flex; align-items: center; gap: 2cqw; width: 46%; color: var(--accent); position: relative; z-index: 1; }
.c-rule span { flex: 1; height: 1px; background: currentColor; opacity: .8; }
.c-rule i { width: 2.2cqw; height: 2.2cqw; background: currentColor; transform: rotate(45deg); }

.cover--frame .c-frame { position: absolute; inset: 5.5cqw; border: .8cqw solid var(--accent); outline: .3cqw solid var(--accent); outline-offset: -2.6cqw; opacity: .9; }
.cover--frame .c-author { margin-top: 2cqw; }
.cover--band .cover-inner { justify-content: flex-start; padding-top: 18cqw; }
.cover--band .c-band {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; gap: 2cqw;
  margin: 0 -11cqw; padding: 7cqw 9cqw; width: calc(100% + 22cqw);
  background: var(--accent); color: var(--bg);
  box-shadow: 0 0 0 1cqw var(--bg), 0 0 0 1.4cqw var(--accent);
}
.cover--band .c-mark { margin-top: auto; width: 16cqw; }
.cover--band .c-author { margin-top: 4cqw; }
.cover--minimal .cover-inner { align-items: flex-start; text-align: left; justify-content: flex-end; }
.cover--minimal .c-moon {
  position: absolute; top: 12cqw; right: 12cqw; width: 22cqw; aspect-ratio: 1; border-radius: 50%;
  background: var(--accent);
  box-shadow: inset -5cqw -2cqw 0 0 color-mix(in srgb, var(--accent) 55%, var(--bg));
}
.cover--minimal .c-title { font-size: 12cqw; }
.cover--minimal .c-title--long { font-size: 9.6cqw; }
.cover--minimal .c-line { width: 20cqw; height: .6cqw; background: var(--accent); margin: 2cqw 0; }
.cover--minimal .c-author { color: var(--fg); opacity: .8; }

/* ------------------------------------------------------------------ 3D editions
   Built by public/js/covers.js renderObject(). Sizes arrive as --W --H --D (px).
   Hardcover: boards overhang the page block, rounded cloth spine with bands.
   Paperback: flush, thin, matte card cover, flat spine, no gutter depth.
   Special:   hardcover plus gilt edges and a ribbon marker.
   Ebook:     a slim reading device with the cover on its screen. */

/* ---- The 3D object (js/book3d.js). Every face is placed by script from the
   book's measurements; this sheet only dresses them. Faces are lit by script
   too: --sh darkens a face turned from the light, --sp is its sheen, which
   sits across the face at --spx. */
.obj {
  --edge: var(--bg);
  --noise-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .55 0 0 0 0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  --noise-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.7' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 .5 0 0 0 0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  position: relative; width: var(--W); height: var(--H);
  perspective: calc(var(--W) * 4.6);
  perspective-origin: 50% 42%;
}
.b3-body { position: absolute; inset: 0; transform-style: preserve-3d; transform: rotateX(-9deg) rotateY(-27deg); }
.b3-face { position: absolute; left: 0; top: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; transform-origin: 50% 50%; }
.b3-face:not(.b3-flat) { overflow: hidden; }
.b3-face:not(.b3-flat)::before, .b3-face:not(.b3-flat)::after { content: ''; position: absolute; inset: 0; pointer-events: none; }
/* Sheen, then shade over it. */
.b3-face:not(.b3-flat)::before { z-index: 4; background: linear-gradient(100deg, transparent calc(var(--spx, 50%) - 55%), rgb(255 251 242 / var(--sp, 0)) var(--spx, 50%), transparent calc(var(--spx, 50%) + 55%)); }
.b3-face:not(.b3-flat)::after { z-index: 5; background: rgb(12 8 16 / var(--sh, 0)); }
/* Narrow strips of a curve: each takes its own light, evenly. */
.b3-spine::before, .b3-pages--fore::before { background: rgb(255 251 242 / var(--sp, 0)); }

/* Shadows on the floor: tight where the book stands, soft away from the light. */
.b3-shadow { pointer-events: none; }
.b3-shadow--contact { background: rgb(22 14 22 / .5); border-radius: 3px; filter: blur(2.2px); }
.b3-shadow--cast { background: radial-gradient(closest-side, rgb(22 14 22 / .34), rgb(22 14 22 / .16) 55%, transparent); filter: blur(10px); }

/* Boards: the cover outside, the case material turned in inside. */
.b3-board { background: var(--bg); }
.b3-board .cover { position: absolute; inset: 0; height: 100%; aspect-ratio: auto; border-radius: 0; }
.b3-board img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; display: block; }
.b3-inside { background: color-mix(in srgb, var(--edge) 58%, #000); }
.b3-edge, .b3-case { background: var(--noise-dark), color-mix(in srgb, var(--edge) 80%, #000); background-size: 140px 140px, auto; }
/* The joint: the groove where the board hinges at the spine. */
.b3-groove { position: absolute; top: 0; bottom: 0; left: var(--groove, 4px); width: 6px; z-index: 3; pointer-events: none;
  background: linear-gradient(90deg, rgb(0 0 0 / .05), rgb(0 0 0 / .34) 35%, rgb(255 255 255 / .16) 62%, rgb(0 0 0 / .08)); }
.b3-board--back .b3-groove { left: auto; right: var(--groove, 4px); transform: scaleX(-1); }

/* Spine: the art laid across the strips; each strip shows its slice. */
.b3-spine { background: var(--bg); }
.b3-spine-art {
  position: absolute; left: 0; top: 0; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  padding: 10px 0; box-sizing: border-box;
  background: var(--bg); color: var(--fg);
}
.b3-spine-art .s-title { writing-mode: vertical-rl; font-family: 'Bodoni Moda', Georgia, serif; font-size: min(15px, calc(var(--D) * .42)); line-height: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-height: 70%; }
.b3-spine-art .s-author { writing-mode: vertical-rl; font-family: 'Jost', sans-serif; font-size: min(8px, calc(var(--D) * .26)); letter-spacing: .2em; text-transform: uppercase; color: var(--accent); }
.b3-spine-art .s-band { width: 100%; height: 3px; background: var(--accent); box-shadow: 0 5px 0 -1px var(--bg), 0 6px 0 0 var(--accent); }
.b3-spine-art--image { padding: 0; }
.b3-spine-art--image img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; display: block; }

/* The page block: the edges of hundreds of sheets, a little uneven, shaded where the boards overhang. */
.b3-pages--fore {
  background:
    linear-gradient(180deg, rgb(40 30 20 / .16), transparent 5%, transparent 95%, rgb(40 30 20 / .18)),
    var(--noise-dark),
    repeating-linear-gradient(90deg, #fbf8f0 0 .55px, #e3dccb .55px .9px, #f4efe3 .9px 1.5px, #ebe5d6 1.5px 1.8px);
  background-size: auto, 140px 140px, auto;
  background-blend-mode: normal, soft-light, normal;
}
.b3-pages--head, .b3-pages--tail {
  background:
    var(--noise-dark),
    repeating-linear-gradient(180deg, #fbf8f0 0 .55px, #e3dccb .55px .9px, #f4efe3 .9px 1.5px, #ebe5d6 1.5px 1.8px);
  background-size: 140px 140px, auto;
  background-blend-mode: soft-light, normal;
}
.b3-headband { background: repeating-linear-gradient(0deg, var(--accent) 0 1.2px, color-mix(in srgb, var(--fg) 70%, var(--accent)) 1.2px 2.4px); }

/* Special edition: gilt edges. */
.obj--special-edition .b3-pages--fore { background: linear-gradient(180deg, rgb(60 40 10 / .25), transparent 6%, transparent 94%, rgb(60 40 10 / .28)), linear-gradient(0deg, #8a6a2a, #e3c67e 28%, #b08a3e 52%, #f0dca0 74%, #9a7630); }
.obj--special-edition .b3-pages--head, .obj--special-edition .b3-pages--tail { background: linear-gradient(90deg, #8a6a2a, #e3c67e 30%, #b08a3e 55%, #f0dca0 78%, #9a7630); }
.b3-ribbon { display: none; background: linear-gradient(90deg, #6f1422, #9e2536 45%, #7a1826); }
.obj--special-edition .b3-ribbon { display: block; }
.b3-ribbon--tail { clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 82%, 0 100%); }

/* Hardcover: cloth over boards, with the weave faintly showing. */
.obj--hardcover .b3-spine-art, .obj--special-edition .b3-spine-art,
.obj--hardcover .b3-board--back, .obj--special-edition .b3-board--back {
  background-image: var(--noise-light), repeating-linear-gradient(0deg, rgb(255 255 255 / .025) 0 1px, transparent 1px 3px);
  background-size: 140px 140px, auto; background-blend-mode: soft-light;
}
.obj--hardcover .b3-board--front .cover::after, .obj--special-edition .b3-board--front .cover::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: var(--noise-light); background-size: 140px 140px; mix-blend-mode: soft-light; opacity: .8;
}
/* Paperback: a card cover, flush with the pages; its edges show the card's pale core. */
.obj--paperback .b3-groove { display: none; }
.obj--paperback .b3-edge, .obj--paperback .b3-case { background: color-mix(in srgb, var(--edge) 35%, #efe9dd); }
.obj--paperback .b3-inside { background: #efe9dd; }
.obj--paperback .b3-spine-art .s-band, .obj--paperback .b3-headband { display: none; }

/* ---- Ebook: a flat e-reader, seen straight on (no 3D) */
.device { position: relative; width: var(--W); height: var(--H); user-select: none; -webkit-user-select: none; }
.device::after { /* soft shadow on the surface it lies on */
  content: ''; position: absolute; left: 8%; right: 8%; bottom: -4%; height: 8%;
  background: radial-gradient(closest-side, rgb(20 16 24 / .3), transparent);
  filter: blur(8px); z-index: -1;
}
.device-body {
  position: absolute; inset: 0; box-sizing: border-box;
  padding: 8.5% 7.5% 15.5%;
  border-radius: calc(var(--W) * .07);
  background:
    radial-gradient(120% 70% at 18% 0%, rgb(255 255 255 / .07), transparent 60%),
    linear-gradient(160deg, #36353b 0%, #232227 40%, #19181c 100%);
  box-shadow:
    0 0 0 1px #0e0d11,                        /* outer rim */
    inset 0 1px 0 rgb(255 255 255 / .14),     /* chamfer catching the light */
    inset 0 -1px 0 rgb(0 0 0 / .5),
    inset 0 0 0 1.5px rgb(255 255 255 / .035),
    0 2px 3px rgb(20 16 24 / .18),
    0 18px 28px -12px rgb(20 16 24 / .4),
    0 40px 60px -30px rgb(20 16 24 / .35);
}
.device-screen {
  position: relative; height: 100%; overflow: hidden;
  border-radius: calc(var(--W) * .008);
  background: #eeebe3;
  /* The screen sits a hair below the glass. */
  box-shadow: 0 0 0 1px rgb(0 0 0 / .55), inset 0 1px 3px rgb(0 0 0 / .25);
}
.device-screen .cover { height: 100%; aspect-ratio: auto; border-radius: 0; box-shadow: none; filter: saturate(.92) contrast(.98); }
.device-screen .cover::before { display: none; }
/* Glass: a faint diagonal reflection. */
.device-screen::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 4;
  background: linear-gradient(118deg, rgb(255 255 255 / .13) 0%, rgb(255 255 255 / .04) 32%, transparent 33%, transparent 100%);
}
.device-mark { position: absolute; left: 50%; bottom: 5.2%; width: 6.5%; translate: -50% 0; color: rgb(255 255 255 / .22); line-height: 0; }
.device-mark svg { width: 100%; height: auto; }
/* Appears, then the e-ink screen refreshes (a brief dark flash) to show the cover. */
.device.is-entering { animation: device-in 1.2s cubic-bezier(.2, .8, .2, 1) both; }
.device.is-entering .device-screen .cover { animation: eink-refresh 1.1s linear both; }
@keyframes device-in { from { opacity: 0; transform: translateY(18px) scale(.985); } }
@keyframes eink-refresh {
  0%, 38% { opacity: 0; }
  39% { opacity: 1; filter: invert(1) grayscale(1); }
  47% { filter: grayscale(1) contrast(1.3); }
  100% { filter: saturate(.92) contrast(.98); }
}

@media (prefers-reduced-motion: reduce) {
  .device.is-entering, .device.is-entering .device-screen .cover { animation: none; }
}

/* ------------------------------------------------------------------ barcode */
.barcode { width: 100%; height: auto; display: block; border-radius: 1px; }
.barcode text { font-family: 'Jost', system-ui, sans-serif; }
