/*
  The shop floor: the pannable viewport, the bookcases, and the spines.

  Two things here are gameplay rather than decoration and should be changed with
  care:

  - `.store-viewport` is the only horizontally scrolling surface in the game.
    §6 makes panning part of the challenge, so the floor is deliberately wider
    than the screen and there is no minimap, no jump-to-section, no shortcut.

  - `--spine-w` (base.css) is shared by the model and the view: a bookcase's
    width is `--shelf-slots × --spine-w`, so a shelf that holds seven books is
    exactly seven books wide. Widening a spine widens the store; it never
    changes how many books fit.
*/

.store-viewport {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: auto;
  overflow-y: hidden;
  /* Horizontal only. Vertical panning would fight the page, and diagonal
     scrolling while dragging a book is nauseating on a phone. */
  touch-action: pan-x;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  cursor: grab;
}
.store-viewport::-webkit-scrollbar { display: none; }
.store-viewport.is-panning { cursor: grabbing; }

/*
  While a book is in hand the browser must not also be scrolling: the auto-pan
  in viewport.js drives `scrollLeft` itself, and a competing native pan makes
  the book slide out from under the finger.
*/
.store-viewport.is-carrying { touch-action: none; cursor: grabbing; }

.store-floor {
  display: flex;
  align-items: stretch;
  gap: 18px;
  min-width: min-content;
  height: 100%;
  /* Headroom, so the cases read as standing in a room rather than as a strip
     of UI welded to the top of the cart. */
  padding: 26px 16px 0;
}

/* The floorboards under the cases. */
.store-floor::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 14px;
  background:
    repeating-linear-gradient(90deg, rgba(90, 58, 32, .13) 0 1px, transparent 1px 46px),
    linear-gradient(180deg, #b98d61, #96693f);
  pointer-events: none;
}

/* ── Bookcase ───────────────────────────────────────────────────────────── */

.bookcase {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: none;
  width: calc(var(--shelf-slots) * var(--spine-w) + 24px);
  padding: 0 6px 14px;
  border-radius: 6px 6px 3px 3px;
  background:
    linear-gradient(180deg, rgba(255, 240, 214, .22), rgba(0, 0, 0, .05) 30%, rgba(0, 0, 0, .12)),
    linear-gradient(90deg, var(--oak-dark), var(--oak) 12%, var(--oak) 88%, var(--oak-deep));
  box-shadow: inset 0 0 0 1px rgba(52, 32, 16, .25), 0 12px 22px rgba(58, 36, 18, .22);
}

/* The wood grain, kept to one cheap repeating gradient. */
.bookcase::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  opacity: .35;
  background: repeating-linear-gradient(
    92deg,
    rgba(255, 236, 205, .06) 0 2px,
    rgba(60, 36, 16, .07) 2px 5px,
    rgba(255, 236, 205, .03) 5px 9px
  );
  pointer-events: none;
}

/* The hand-lettered section sign (§16). */
.bookcase-sign {
  position: relative;
  z-index: 2;
  align-self: center;
  display: flex;
  align-items: center;
  gap: .4rem;
  margin: -6px 0 8px;
  padding: .34rem .7rem .38rem;
  max-width: 100%;
  border-radius: 3px;
  background: linear-gradient(180deg, var(--paper-warm), #f4e9d4);
  box-shadow: var(--shadow-sign);
  transform: rotate(var(--sign-tilt, -.6deg));
  color: var(--ink);
}
.bookcase-sign .icon { color: var(--sign-colour, var(--oak-dark)); }

.bookcase-sign-name {
  font-family: var(--serif);
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The A–M half of a split section. Reads as part of the sign, not a badge. */
.bookcase-sign-range {
  font-family: var(--serif);
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--oak-dark);
  padding-left: .34rem;
  border-left: 1px solid rgba(90, 58, 32, .28);
  white-space: nowrap;
}

.bookcase-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  border-radius: 3px;
  background: linear-gradient(180deg, rgba(40, 22, 8, .30), rgba(40, 22, 8, .18));
  box-shadow: inset 0 2px 8px rgba(30, 16, 4, .40);
}

/* ── Shelf ──────────────────────────────────────────────────────────────── */

/*
  Rows share the case's height rather than each taking a fixed one, so a tall
  screen gets tall shelves instead of a short case floating above dead space.
  `--shelf-h` is the floor, not the size: below it, spines stop being readable.
*/
.shelf {
  position: relative;
  flex: 1 1 0;
  min-height: var(--shelf-h);
  max-height: calc(var(--shelf-h) * 1.5);
  padding: 0 8px 8px;
  display: flex;
  align-items: flex-end;
}

/* The board itself, drawn under the books with a lit front edge. */
.shelf::after {
  content: '';
  position: absolute;
  left: 2px;
  right: 2px;
  bottom: 0;
  height: 8px;
  border-radius: 1px;
  background: linear-gradient(180deg, var(--oak-light), var(--oak) 42%, var(--oak-deep));
  box-shadow: 0 2px 4px rgba(28, 14, 4, .45);
}

.shelf-books {
  position: relative;
  display: flex;
  align-items: flex-end;
  gap: var(--spine-gap);
  width: 100%;
  height: 100%;
}

/* Where the shadow under the shelf above falls on the books. */
.shelf::before {
  content: '';
  position: absolute;
  left: 2px;
  right: 2px;
  top: 0;
  height: 14px;
  background: linear-gradient(180deg, rgba(24, 12, 2, .34), transparent);
  pointer-events: none;
  z-index: 3;
}

/* ── Spines ─────────────────────────────────────────────────────────────── */

.spine {
  position: relative;
  flex: none;
  width: var(--spine-w);
  /* --lift is the cover's height byte: a shelf of books all exactly as tall as
     each other is the single fastest way to make this look like a grid. */
  height: calc(72% + var(--lift, .5) * 26%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 6px 2px 5px;
  border-radius: 2px 2px 1px 1px;
  color: var(--spine-ink, #f3e7d4);
  background:
    linear-gradient(90deg, rgba(0, 0, 0, .28), rgba(255, 255, 255, .12) 22%, rgba(255, 255, 255, .04) 62%, rgba(0, 0, 0, .30)),
    hsl(var(--hue) var(--sat) var(--lit));
  box-shadow: 0 1px 2px rgba(20, 10, 2, .5);
  transform: rotate(calc((var(--lean, .5) - .5) * 1.6deg));
  transform-origin: bottom center;
  /* The spread (§5) drives --slide; the transition is what makes books part
     rather than jump. */
  transition: transform .16s cubic-bezier(.22, .8, .32, 1);
  will-change: transform;
}

.shelf-books.is-spreading .spine {
  transform: translateX(var(--slide, 0px)) rotate(calc((var(--lean, .5) - .5) * 1.6deg));
}

/* Cover treatments, so a shelf is a run of related books rather than swatches. */
.spine[data-spine='bands']::before,
.spine[data-spine='panel']::before,
.spine[data-spine='rule']::before,
.spine[data-spine='gilt']::before {
  content: '';
  position: absolute;
  left: 3px;
  right: 3px;
  pointer-events: none;
}
.spine[data-spine='bands']::before {
  top: 18%; bottom: 24%;
  background:
    linear-gradient(180deg,
      rgba(255, 246, 226, .48) 0 3px,
      transparent 3px calc(100% - 3px),
      rgba(255, 246, 226, .48) calc(100% - 3px) 100%);
}
.spine[data-spine='panel']::before {
  top: 16%; bottom: 22%;
  border: 1px solid rgba(255, 244, 220, .34);
  border-radius: 1px;
}
.spine[data-spine='rule']::before {
  top: 8px; bottom: 8px; left: 5px; right: auto; width: 1px;
  background: rgba(255, 244, 220, .4);
}
.spine[data-spine='gilt']::before {
  top: 12%; height: 2px;
  background: var(--brass-bright);
  opacity: .85;
}

.spine-text {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  writing-mode: vertical-rl;
  text-orientation: mixed;
  font-family: var(--serif);
  font-size: 10px;
  line-height: 1.05;
  letter-spacing: .01em;
  white-space: nowrap;
  text-shadow: 0 1px 1px rgba(0, 0, 0, .35);
  padding-top: 3px;
  overflow: hidden;
}

/* Never abridged: this is the word the player is sorting by. */
.spine-name {
  flex: none;
  font-weight: 700;
}

/* Whatever room is left over. Cut without an ellipsis, because a trailing "…"
   on a book spine looks like damage rather than like a design. */
.spine-title {
  flex: 0 1 auto;
  min-height: 0;
  overflow: hidden;
  font-weight: 500;
  opacity: .82;
}
.spine-title::before { content: ' · '; opacity: .7; }

@media (min-width: 720px) { .spine-text { font-size: 11.5px; } }

/* The genre mark at the foot of the spine — the thing §4 makes the player
   match. It sits on a lightened plate so it reads on any cover colour. */
.spine-mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 17px;
  height: 17px;
  border-radius: 3px;
  background: rgba(255, 246, 230, .90);
  color: var(--mark-colour, var(--oak-dark));
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}
.spine-mark .icon { width: 12px; height: 12px; }

/* ── States ─────────────────────────────────────────────────────────────── */

.spine.is-carried { opacity: .18; }
.spine.is-landing { animation: settle 320ms cubic-bezier(.2, .9, .3, 1); }
.spine.is-rejected { animation: wobble 340ms ease-in-out; z-index: 4; }

/* §13C/D: a book being taken off the shelf. */
.spine.is-leaving { animation: lift-out 200ms ease-in forwards; }

@keyframes settle {
  0%   { transform: translateY(-16px) scaleY(1.06); }
  60%  { transform: translateY(2px) scaleY(.985); }
  100% { transform: none; }
}
@keyframes wobble {
  0%, 100% { transform: rotate(calc((var(--lean, .5) - .5) * 1.6deg)); }
  20%  { transform: translateY(-3px) rotate(-5deg); }
  50%  { transform: translateY(-1px) rotate(4deg); }
  78%  { transform: rotate(-2deg); }
}
@keyframes lift-out {
  to { transform: translateY(-18px) scale(.92); opacity: 0; }
}

/*
  A section that has just refused a book. §8 wants "a small physical bounce"
  rather than a red X, so the *case* flinches — the whole shelf, not the book.
*/
.shelf.is-refusing { animation: refuse 260ms ease-out; }
@keyframes refuse {
  0%, 100% { transform: none; }
  30% { transform: translateX(-3px); }
  65% { transform: translateX(2px); }
}

/*
  The one place a shelf is highlighted: a Big Order or a Shelf Check tells the
  player *what* to look for, never *where* it is (§13D). This is the hover
  affordance while carrying, and it is deliberately faint and applied to every
  shelf under the pointer regardless of whether the book belongs there.
*/
.shelf.is-target::after { box-shadow: 0 2px 4px rgba(28, 14, 4, .45), 0 0 0 1px rgba(255, 240, 210, .5); }
