/* =========================================================================
   base.css -- colours, type, paper grain, buttons, and the book spines.
   Everything else builds on this.
   ========================================================================= */

:root{
  /* the dark of the shop */
  --ink:        #0a0705;
  --night:      #120d09;
  --night-soft: #1a130d;

  /* wood */
  --wood:       #2c1e14;
  --wood-lit:   #56381f;
  --wood-deep:  #150d07;
  --wood-edge:  #7a4f2b;

  /* light */
  --gold:       #d8b26a;
  --gold-soft:  #b8934f;
  --gold-dim:   #8a6c3c;
  --flame:      #ffb85c;
  --flame-hot:  #ffe0a8;

  /* text */
  --cream:      #f0e4cd;
  --cream-dim:  #c3b294;
  --cream-far:  #9a8b73;   /* was #8b7c65: 4.0:1 on the night hall, now 4.9 */

  /* paper */
  --paper:      #f3ead6;
  --paper-warm: #ece0c6;
  --paper-ink:  #251d14;
  --paper-dim:  #6b5c48;

  /*
   * The same ink, as three plain numbers.
   *
   * Forty-three rules across the writing desk and the reading page draw a
   * hairline or a faint wash in this colour at some fraction of solid --
   * rgba(37,29,20, .16) and its cousins. They are all written as
   * rgba(var(--ink-rgb), .16) now, so a person choosing dark paper turns
   * all forty-three over at once instead of thirty-nine of them turning
   * and four hairlines staying black on a black page.
   *
   * It MUST be defined here, in the file every page loads first. It was
   * only set under the dark and soft papers to begin with, which left it
   * undefined on ordinary paper -- and an undefined colour is not a
   * fallback, it is an invalid declaration that the browser throws away.
   * Forty-three borders quietly went to currentColor on the default theme.
   */
  --ink-rgb:    37,29,20;

  --red:        #c4553f;
  --green:      #7fa05f;

  --serif: 'Iowan Old Style','Palatino Linotype',Palatino,'Book Antiqua',
           'URW Palladio L','Sitka Text',Georgia,'Times New Roman',serif;
  --sans:  ui-sans-serif,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',
           Arial,sans-serif;

  --ease:   cubic-bezier(.22,.61,.36,1);
  --ease-in-out: cubic-bezier(.65,.05,.36,1);
  --spring: cubic-bezier(.34,1.56,.64,1);

  --rail: 264px;
}

*,*::before,*::after{ box-sizing:border-box; }

html,body{ height:100%; }

body{
  margin:0;
  background:var(--ink);
  color:var(--cream);
  font-family:var(--serif);
  font-size:17px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}

h1,h2,h3{ font-weight:600; letter-spacing:.01em; margin:0; }

a{ color:var(--gold); text-decoration:none; }
a:hover{ color:var(--flame-hot); }

button{ font:inherit; color:inherit; }

::selection{ background:rgba(216,178,106,.28); }

:focus-visible{
  outline:2px solid var(--gold);
  outline-offset:3px;
  border-radius:3px;
}

.only-for-screen-readers{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
}

/* --- the textures ------------------------------------------------------ */

:root{
  --noise-fine: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");

  --noise-soft: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.35' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");

  /* long streaks -- reads as wood grain */
  --grain-wood: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='240'%3E%3Cfilter id='w'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.006 .7' numOctaves='5' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='600' height='240' filter='url(%23w)'/%3E%3C/svg%3E");

  /* upright streaks -- reads as leather stretched over a spine */
  --grain-hide: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='400'%3E%3Cfilter id='h'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.5 .012' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='400' filter='url(%23h)'/%3E%3C/svg%3E");

  --weave: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath d='M0 0h8v1H0zM0 4h8v1H0z' fill='%23fff' opacity='.5'/%3E%3Cpath d='M0 0v8h1V0zM4 0v8h1V0z' fill='%23000' opacity='.5'/%3E%3C/svg%3E");
}

/* a film of grain over the whole page -- kills the flat-vector look */
.grain{
  position:fixed; inset:0; z-index:90;
  pointer-events:none;
  background-image:var(--noise-fine);
  opacity:.045;
  mix-blend-mode:overlay;
}

/* --- carved into the wood ---------------------------------------------- */

.carved{
  color:rgba(10,5,2,.72);
  text-shadow:
     0 1px 0   rgba(255,196,124,.20),
     0 2px 2px rgba(255,168,88,.07),
     0 -1px 1px rgba(0,0,0,.85);
  letter-spacing:.30em;
  text-transform:uppercase;
  font-size:13px;
  font-weight:700;
}

/* --- gilt, for anything stamped in foil -------------------------------- */

.gilt{
  color:var(--gold);
  text-shadow:0 1px 0 rgba(0,0,0,.6), 0 0 8px rgba(216,178,106,.16);
}

/* --- buttons ----------------------------------------------------------- */

.btn{
  display:inline-flex; align-items:center; gap:.5em;
  padding:.62em 1.15em;
  border:1px solid rgba(216,178,106,.34);
  border-radius:3px;
  background:linear-gradient(180deg, rgba(216,178,106,.13), rgba(216,178,106,.05));
  color:var(--gold);
  font-family:var(--serif);
  font-size:15px;
  letter-spacing:.04em;
  cursor:pointer;
  transition:background .22s var(--ease), border-color .22s var(--ease),
             color .22s var(--ease), transform .18s var(--spring);
}
.btn:hover{
  background:linear-gradient(180deg, rgba(255,184,92,.22), rgba(255,184,92,.08));
  border-color:rgba(255,184,92,.6);
  color:var(--flame-hot);
}
.btn:active{ transform:translateY(1px); }
.btn--quiet{
  border-color:transparent; background:none; color:var(--cream-far);
}
.btn--quiet:hover{ background:rgba(216,178,106,.08); color:var(--gold); }
.btn[disabled]{ opacity:.4; cursor:default; }

/* --- fields ------------------------------------------------------------ */

.field{
  width:100%;
  padding:.72em .9em;
  background:rgba(0,0,0,.34);
  border:1px solid rgba(216,178,106,.22);
  border-radius:3px;
  color:var(--cream);
  font-family:var(--serif);
  font-size:16px;
  transition:border-color .2s var(--ease), background .2s var(--ease);
}
.field::placeholder{ color:var(--cream-far); opacity:.65; }
.field:focus{
  outline:none;
  border-color:rgba(255,184,92,.62);
  background:rgba(0,0,0,.45);
  box-shadow:0 0 0 3px rgba(255,184,92,.09);
}

.tiny{
  font-family:var(--sans);
  font-size:11px;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--cream-far);
}

.note{ color:var(--cream-dim); font-size:14.5px; }
.warn{ color:var(--red); }

/* =========================================================================
   THE SPINES
   Every value below comes from lib/spine.php via CSS variables, so no two
   books look the same.
   ========================================================================= */

.spine{
  position:relative;
  display:block;
  flex:0 0 auto;
  width:var(--w, 44px);
  height:calc(var(--h, .9) * 100%);
  align-self:flex-end;
  border:0; padding:0; margin:0;
  border-radius:2px 4px 4px 2px / 3px 6px 6px 3px;
  background:linear-gradient(90deg,
      var(--deep) 0%,
      var(--base) 11%,
      var(--lit)  var(--gloss, 33%),
      var(--base) calc(var(--gloss, 33%) + 26%),
      var(--deep) 100%);
  box-shadow:
      inset  1px 0 0 rgba(255,255,255,.05),
      inset -2px 0 3px rgba(0,0,0,.55),
      2px 3px 7px rgba(0,0,0,.5);
  transform:rotate(var(--lean, 0deg));
  transform-origin:bottom center;
  cursor:pointer;
  isolation:isolate;
  transition:transform .34s var(--spring), filter .34s var(--ease),
             box-shadow .34s var(--ease);
  font-family:var(--serif);
  text-align:left;
  -webkit-tap-highlight-color:transparent;
}

.spine__face,.spine__grain,.spine__cord,.spine__rule,
.spine__label,.spine__head,.spine__wear,.spine__ribbon,.spine__by{
  position:absolute; display:block; pointer-events:none;
}

/* the round of the spine catching the candle */
.spine__face{
  inset:0;
  border-radius:inherit;
  background:linear-gradient(180deg,
      rgba(255,255,255,.10) 0%,
      rgba(255,255,255,0)   9%,
      rgba(0,0,0,0)        86%,
      rgba(0,0,0,.42)     100%);
}

.spine__grain{
  inset:0;
  border-radius:inherit;
  background-image:var(--grain-hide);
  background-size:100% 260px;
  opacity:calc(var(--wear, .2) * .8);
  mix-blend-mode:overlay;
}
.spine--tex1 .spine__grain{
  background-image:var(--weave);
  background-size:5px 5px;
  opacity:calc(var(--wear, .2) * .5);
}
.spine--tex2 .spine__grain{
  background-image:var(--noise-soft);
  background-size:130px 130px;
  opacity:calc(var(--wear, .2) * .9);
}

/* raised cords across the back */
.spine__cord{
  left:0; right:0; height:var(--cord, 7px);
  background:linear-gradient(180deg,
      rgba(0,0,0,.42) 0%,
      var(--lit) 34%,
      var(--base) 66%,
      rgba(0,0,0,.5) 100%);
  box-shadow:0 1px 2px rgba(0,0,0,.4);
}

/* thin gilt rules */
.spine__rule{
  left:14%; right:14%; height:1px;
  background:var(--foil);
  opacity:.5;
  box-shadow:0 0 4px rgba(216,178,106,.28);
}
.spine__rule--top{ top:11%; }
.spine__rule--bottom{ bottom:9%; }

/* the label panel a title is stamped onto.
   These four numbers and the ones on .spine--panel .spine__title below are
   a pair -- the writing has to sit INSIDE the panel, not across its edge. */
/*
 * The panel got taller. It used to run 24%..70% of the spine, and the
 * writing inside it only got 38% of the book's height to live in -- while
 * a spine with NO panel gave its title 79%. So the books with a label were
 * the ones you could not read, which is exactly backwards: the label is
 * there to make the name easier to find.
 *
 * 18%..78% now, and the writing below fills more of it.
 */
.spine__label{
  left:11%; right:11%; top:18%; height:60%;
  background:var(--panel);
  border:1px solid rgba(0,0,0,.35);
  box-shadow:
      inset 0 1px 0 rgba(255,255,255,.10),
      inset 0 0 0 1px rgba(216,178,106,.14),
      0 1px 3px rgba(0,0,0,.4);
  border-radius:1px;
  opacity:.92;
}

/* the paper block peeking over the top */
.spine__head{
  left:2px; right:2px; top:0; height:var(--cap, 4px);
  border-radius:2px 2px 0 0;
  background:linear-gradient(180deg, rgba(228,214,186,.5), rgba(228,214,186,0));
  opacity:.5;
}

/* scuffs at the corners */
.spine__wear{
  inset:0;
  border-radius:inherit;
  background:
    radial-gradient(ellipse at 50% 0%,   rgba(255,225,190,.20), transparent 42%),
    radial-gradient(ellipse at 50% 100%, rgba(255,225,190,.16), transparent 40%),
    radial-gradient(ellipse at 100% 88%, rgba(0,0,0,.35), transparent 46%);
  opacity:var(--wear, .2);
  mix-blend-mode:soft-light;
}

.spine__ribbon{
  left:50%; bottom:-9px; width:5px; height:14px;
  margin-left:-2.5px;
  background:linear-gradient(180deg, var(--ribbon), rgba(0,0,0,.6));
  border-radius:0 0 2px 2px;
  opacity:.85;
}

/* the title, running up the spine */
.spine__title{
  position:absolute;
  /* No panel: nearly the whole spine, the way a real one is used. */
  inset:11% 13% 10% 13%;
  display:grid; place-content:center;
  writing-mode:vertical-rl;
  text-orientation:mixed;
  font-size:var(--fs, 13px);
  line-height:1.08;
  letter-spacing:.05em;
  text-align:center;
  color:var(--foil);
  text-shadow:
      0 1px 0 rgba(0,0,0,.7),
      0 0 6px rgba(216,178,106,.22);
  overflow:hidden;
  /* A long name wraps onto a second line across the spine, which is what
     a bookbinder would do. It does not get cut off. */
  white-space:normal;
  overflow-wrap:break-word;
  transition:text-shadow .3s var(--ease);
}
/* With a panel, the writing lives inside the panel's border and nowhere
   else. It used to run out over the bare leather, across the gilt edge.
   21%..75% sits inside the panel's 18%..78% with three per cent of clear
   leather top and bottom, and gives the name 54% of the spine instead of
   the 38% it had. */
.spine--panel .spine__title{ inset:21% 15% 25% 15%; }

/* The writer's name, earned at 1,000 words (lib/spine.php puts it there;
   under that, the span is not in the markup at all).
   It runs ACROSS the spine, not up it: a spine is 30-70px wide, and a
   name of eight letters standing up would eat most of the height and
   force the title to shrink. Lying flat at 7px it fits the empty band
   between the title and the bottom gilt rule (rule at 9%; this band is
   10.5%..22.5%, just under a label panel's bottom edge at 22%).
   Same foil as the title, a notch quieter. A long name wraps and what
   does not fit is clipped -- never a dot-dot-dot, same as titles. */
.spine__by{
  left:12%; right:12%; bottom:10.5%; height:12%;
  display:grid; place-content:center;
  font-family:var(--serif);
  font-size:7px;
  line-height:1.1;
  letter-spacing:.04em;
  text-align:center;
  color:var(--foil);
  opacity:.85;
  text-shadow:
      0 1px 0 rgba(0,0,0,.7),
      0 0 6px rgba(216,178,106,.22);
  white-space:normal;
  overflow-wrap:anywhere;
  overflow:hidden;
}
/* Only when the name is there, a no-panel title stops at 25% instead of
   10% so the two never overlap. 25% is the room a panel title already
   lives in, so nothing new has to be proven to fit. Panel spines change
   nothing. */
.spine--by:not(.spine--panel) .spine__title{ bottom:25%; }

/* reaching for a book */
.spine:hover,.spine:focus-visible{
  transform:translateY(-13px) rotate(var(--lean, 0deg));
  filter:brightness(1.22) saturate(1.06);
  box-shadow:
      inset  1px 0 0 rgba(255,255,255,.08),
      inset -2px 0 3px rgba(0,0,0,.5),
      4px 12px 22px rgba(0,0,0,.62),
      0 0 26px rgba(255,184,92,.16);
  z-index:3;
}
.spine:hover .spine__title{
  text-shadow:0 1px 0 rgba(0,0,0,.7), 0 0 14px rgba(255,214,140,.7);
}

/* --- kindness to people who get motion sick ---------------------------- */

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
  .spine:hover{ transform:none; }
}

/* =========================================================================
   MOVING BETWEEN PAGES

   The browser does all of this itself. There is no JavaScript behind it and
   nothing to download -- the browser takes a picture of the page you are
   leaving, a picture of the one you are arriving at, and fades between them.
   On a browser that has never heard of it, the pages simply swap, exactly
   as they did before.
   ========================================================================= */

@view-transition{ navigation:auto; }

::view-transition-old(root){
  animation:leaving .18s cubic-bezier(.4,0,1,1) both;
}
::view-transition-new(root){
  animation:coming .34s cubic-bezier(0,0,.2,1) both;
}
@keyframes leaving{ to{ opacity:0 } }
@keyframes coming{
  from{ opacity:0; transform:scale(1.012) }
  to  { opacity:1; transform:none }
}

@media (prefers-reduced-motion: reduce){
  @view-transition{ navigation:none; }
}
