/* roman.ma — the chooser. One featured book, full width and tall, then the
   other two side by side underneath. No account, no menu, no horizontal
   anything.

   The tokens below are the landing page's, repeated rather than shared. Every
   page here ships its own stylesheet (css/style.css, css/watch.css) and none
   of them import another — one more request on a page whose job is to appear
   at once. If a fourth page turns up, that is the moment to pull these into a
   tokens.css, not before. --orange and --black must match style.css: the
   button that leads here is orange, and the screen it lands on is black. */

:root {
  --black: #000000;
  --orange: #F06A1E;
  --text: #FFFFFF;
  --text-secondary: rgba(255, 255, 255, 0.70);
  --text-muted: rgba(255, 255, 255, 0.45);

  --serif: "EB Garamond", Garamond, Georgia, "Times New Roman", serif;
  --sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          Helvetica, Arial, sans-serif;

  --card-radius: 12px;
  --play-radius: 8px;               /* the small cards' icon button */
  --card-gap: 12px;

  /* Floors, not fixed sizes: the feature and the pair below it split
     whatever height is actually on the screen, and these are how far either
     is allowed to be squeezed before the split stops being fair to it. */
  --feature-min-height: 300px;
  --pair-min-height: 130px;
}

* { box-sizing: border-box; }

html {
  background: var(--black);        /* on the root, so overscroll rubber-banding
                                      on iOS shows black and not white */
}

body {
  margin: 0;
  min-height: 100%;
  background: var(--black);
  color: var(--text);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  -webkit-tap-highlight-color: transparent;   /* the card has its own :active */
}

/* A phone-width column, centred, and the exact height of the screen — no
   more, no less, because the whole point below is that nothing here scrolls.
   dvh over vh: on a phone browser, vh is the height with the address bar
   hidden, so a 100vh column is taller than what is actually on screen until
   the bar retracts, and that difference is exactly a page that scrolls by a
   few dozen pixels when it shouldn't. The vh line stays first as the
   fallback for a browser that doesn't know dvh at all, which would otherwise
   drop the whole declaration and leave .shelf unbounded. */
.shelf {
  max-width: 30rem;
  margin: 0 auto;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  padding: calc(1.75rem + env(safe-area-inset-top, 0px))
           calc(1.25rem + env(safe-area-inset-right, 0px))
           calc(2rem + env(safe-area-inset-bottom, 0px))
           calc(1.25rem + env(safe-area-inset-left, 0px));
}

/* The one line of text on the screen. Quiet on purpose: it is an instruction,
   and the covers under it are what should be looked at. flex: none so it
   keeps its own height instead of being squeezed by the grid below. */
.prompt {
  flex: none;
  margin: 0 0 1.25rem;
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--text-secondary);
}

/* Whatever height .shelf's flex column leaves after the prompt, this claims
   all of it (flex: 1 1 auto) and hands it to the two rows below as `fr`
   shares rather than fixed sizes — so the split always adds up to exactly
   what's on screen, on any device, with nothing left over to scroll. The
   feature gets the larger share (2.2fr vs 1fr); minmax's first argument is
   the floor neither row is allowed to shrink past, which is the deliberate
   answer to "the feature can't just take whatever's left" — on a very short
   screen the floors win over the ratio and something would rather overflow
   a little than get crushed unreadable.

   min-height: 0 (here and on every li) is what lets a grid actually granted
   this arrangement grow into it: a grid item's default min-height is auto,
   which refuses to shrink below its content's own height and would fight
   the fr split on the featured row in particular, whose content is a title
   long enough to want more room than 1fr might offer it.

   `.is-featured` only sets the span and which row a card lands in — it has
   to stay first in the list for that to land in row one. */
.books {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: minmax(var(--feature-min-height), 2.2fr)
                       minmax(var(--pair-min-height), 1fr);
  gap: var(--card-gap);
  margin: 0;
  padding: 0;
  list-style: none;
}

.books li { min-height: 0; }
.books li.is-featured { grid-column: 1 / -1; grid-row: 1; }

/* The card.
   `display: block`: the text is pinned to the bottom-left corner by the
   padding, and there is nothing else in the box to lay out against. Height
   comes from the grid row it sits in (100%, stretched by the row's own fr
   share) rather than being set on the card itself.

   overflow: hidden is what makes the radius mean anything — the cover is a
   ::before filling the box, and it would square off the corners otherwise. */
.book {
  position: relative;
  display: block;
  height: 100%;
  border-radius: var(--card-radius);
  overflow: hidden;
  background: #14100E;             /* warm near-black: what shows through
                                      while a cover is missing */
  color: inherit;
  text-decoration: none;
  transition: transform 140ms ease;
}

/* Cover. Its own layer rather than a background on .book, so the dimming on
   the soon card can take the picture without taking the words with it.

   `cover` crops to whatever shape the fr split above hands each box, and
   50% 40% rather than dead centre suits any of them: a cover is normally
   composed around something in the upper middle, and the bottom third of
   the box is under the gradient and the title anyway. */
.book::before {
  content: "";
  position: absolute;
  inset: 0;
  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50% 40%;
}

/* Covers. One line each, nothing else to change — the scrim above still runs
   over every one of them, so a slow-loading image never reads as a flat
   rectangle that failed to load. */
.book--boite::before    { background-image: url("../assets/boite-a-merveilles.webp"); }
.book--antigone::before { background-image: url("../assets/Antigone.webp"); }
.book--dernier::before  { background-image: url("../assets/dernier-jour-d-un-condamne.webp"); }

/* Scrim over the bottom half. Three stops, not two: a straight linear fade
   from opaque to transparent leaves a visible band where it crosses the middle
   of a bright cover, and the eye finds the band before it finds the title. */
.book::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    rgba(0, 0, 0, 0.88) 0%,
    rgba(0, 0, 0, 0.55) 26%,
    rgba(0, 0, 0, 0.12) 44%,
    rgba(0, 0, 0, 0) 56%);
}

/* Bottom-left. Absolute rather than pushed down with the card's own layout,
   so the two lines sit on the padding box's corner whatever the card height
   becomes. z-index because ::before and ::after are positioned and would
   otherwise paint over in-flow content. */
.book-text {
  position: absolute;
  z-index: 1;
  left: 1.1rem;
  right: 1.1rem;
  bottom: 0.95rem;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.book-title {
  font-family: var(--serif);
  font-size: 1.05rem;
  line-height: 1.15;
  color: var(--text);
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.75);
  /* Half a phone is about 165px of card, so a title of any length wraps here
     and is meant to. The block is anchored to the bottom, so the second line
     grows upward into the scrim rather than off the card, and balance keeps
     the break from stranding one word on its own. */
  text-wrap: balance;
}

/* Orange is the site's "this one is live" colour — it is the landing page's
   button — so it goes on the status of a book you can actually open, and not
   on the one you cannot. That makes the accent carry the same meaning here as
   it does there, rather than being decoration. */
.book-status {
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--orange);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.85);
}

.book:active { transform: scale(0.985); }

.book:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 3px;
}

/* The feature is a different size of card, not just a wider one, so its type
   is a step up rather than the small cards' sizes stretched across it. */
.books li.is-featured .book-title  { font-size: 1.9rem; }
.books li.is-featured .book-status { font-size: 0.85rem; }

/* The play affordance. Every card gets one — the feature spells it out
   (icon and label, because it has the most room of the three), the small
   pair below get the icon alone: they're half the screen's width at most,
   and a label next to the icon would crowd the title on that width. */
.book-play {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  color: var(--text);
}

.play-icon {
  width: 1rem;
  height: 1rem;
  fill: currentColor;
  flex: none;
}

/* Sits inside .book-text's column, under the status line, rather than being
   positioned against the card the way the small icon is — the feature has
   room to let the button follow the text instead of pinning it to a corner. */
.is-featured .book-play {
  align-self: flex-start;
  margin-top: 0.7rem;
  padding: 0.6rem 1.15rem;
  border-radius: 999px;
  background: var(--orange);
}

.is-featured .play-icon {
  width: 1.1rem;
  height: 1.1rem;
}

.play-label {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}

/* The small cards: an icon on its own, pinned to the corner rather than
   living in the text column — there's no line to sit under. Square with a
   small radius rather than round, so it reads as a distinct, lighter-weight
   control next to the feature's pill instead of a smaller copy of it. */
.books li:not(.is-featured) .book-play {
  position: absolute;
  z-index: 1;
  right: 0.85rem;
  bottom: 0.85rem;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--play-radius);
  background: rgba(0, 0, 0, 0.45);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.14) inset;
}

/* Clears the corner the icon sits in, so a long title's last line wraps
   above it instead of running underneath. */
.books li:not(.is-featured) .book-text { right: 3.35rem; }

/* Not ready: the icon dims with the rest of the card instead of staying
   bright, which would read as tappable when nothing behind it is. */
.is-soon .book-play { opacity: 0.55; }

/* Not ready. The picture is what dims — the words stay legible, because
   "Bientôt" is the one thing on this card anybody needs to read.

   The card's own colour goes down with it. Dimming only the cover would mean
   that until the three images exist this card looks exactly like the two above
   it, and "not tappable" would be something you found out by tapping. */
.is-soon { background: #0D0A09; }
.is-soon::before { opacity: 0.4; }
.is-soon .book-title { color: rgba(255, 255, 255, 0.75); }
.is-soon .book-status { color: var(--text-muted); }

@media (prefers-reduced-motion: reduce) {
  .book { transition: none; }
  .book:active { transform: none; }
}
