/* ==========================================================================
   COMPONENT — .c-shop  +  .c-cover  +  .c-cart
   The Malta Guide Book vol.1. The cover is TYPESET, not photographed —
   built from the same three hues and two typefaces as the rest of the site,
   so it needs no asset and never looks like stock art.

   There is no cart. One product, one button, straight to the existing
   checkout: a basket step for a single digital download is friction, not
   commerce.
   WP Phase 2 target: template-parts/sections/shop-feature.php
   ========================================================================== */

.c-shop {
  padding-block: var(--section-pad);
  background: var(--c-bg-alt);
  color: var(--c-ink);
}

.c-shop__shell { align-items: center; row-gap: var(--sp-8); }

/* --------------------------------------------------------------------------
   The typeset cover — columns 1 to 5, tilted, lifted on hover.
   -------------------------------------------------------------------------- */

.c-cover {
  /* Narrower and vertically centred, so the book stands about as tall as the
     copy beside it instead of towering over the whole section. */
  grid-column: content-start / span 3;
  align-self: center;
  perspective: 1400px;
}

.c-cover__plate {
  position: relative;
  /* The artwork's own proportion, 1413 x 2000. It used to be 5 / 5.6, which
     was a guess made before there was a cover to measure; keeping it would
     have squashed the photograph. */
  aspect-ratio: 1413 / 2000;
  overflow: hidden;
  border: var(--bw-hair) solid color-mix(in oklab, var(--stone-50) 18%, transparent);
  box-shadow:
    0 1px 0 color-mix(in oklab, var(--stone-50) 26%, transparent) inset,
    -18px 12px 40px -22px rgba(0, 0, 0, 0.75);
  transform-origin: left center;
  will-change: transform;

  /* THE BOOK MOVES ON ITS OWN.
     A slow lean, five degrees of yaw and a hair of lift, over eighteen
     seconds. Long enough that it is never caught mid-gesture and never asks
     to be watched — it reads as an object sitting in light rather than an
     animation playing. Short enough that it is visibly alive.

     rotateY and translateY only: both are composited, so this runs on the
     GPU and costs nothing per frame. An animated box-shadow or filter here
     would re-rasterise the whole cover sixty times a second, which is
     exactly the class of thing that was stripped out of this page when it
     was stuttering on a laptop. */
  animation: aim-cover-drift 18s ease-in-out infinite;
}

@keyframes aim-cover-drift {
  0%,
  100% { transform: rotateY(-11deg) rotateX(2deg)   translateY(0); }
  50%  { transform: rotateY(-5deg)  rotateX(0.5deg) translateY(-0.55rem); }
}

/* Hover takes over: the book turns to face you and stops drifting, so the
   two motions never fight. */
.c-cover:hover .c-cover__plate,
.c-cover:focus-within .c-cover__plate {
  animation-play-state: paused;
  transform: rotateY(-2deg) rotateX(0.5deg) translateY(-0.75rem);
  transition: transform var(--dur-slow) var(--ease-out);
}

.c-cover__art {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* The spine. A dark edge down the leading side, which is what stops the
   image reading as a flat rectangle that happens to be rotated. */
.c-cover__spine {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: clamp(0.7rem, 1.8vw, 1.35rem);
  background: linear-gradient(to right,
    rgba(0, 0, 0, 0.62) 0%,
    rgba(0, 0, 0, 0.28) 45%,
    color-mix(in oklab, var(--stone-50) 14%, transparent) 100%);
  pointer-events: none;
}

/* A single band of light travelling across the face, in step with the lean.
   Paper catching a window. Kept faint — at any strength it reads as a
   video-game shine rather than a photograph. */
.c-cover__sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(105deg,
    transparent 34%,
    color-mix(in oklab, var(--stone-50) 16%, transparent) 50%,
    transparent 66%);
  background-size: 260% 100%;
  animation: aim-cover-sheen 18s ease-in-out infinite;
}

@keyframes aim-cover-sheen {
  0%,
  100% { background-position: 100% 0; }
  50%  { background-position: 0 0; }
}

/* Someone who asked for less movement gets a still book, square on, with the
   spine and the shadow intact. Nothing is hidden, nothing moves. */
@media (prefers-reduced-motion: reduce) {
  .c-cover__plate {
    animation: none;
    transform: rotateY(-4deg);
  }
  .c-cover__sheen { animation: none; opacity: 0.5; }
  .c-cover:hover .c-cover__plate,
  .c-cover:focus-within .c-cover__plate { transform: rotateY(-4deg); transition: none; }
}

/* --------------------------------------------------------------------------
   Product detail — columns 7 to 12.
   -------------------------------------------------------------------------- */

/* A GRID ITEM'S AUTOMATIC MINIMUM SIZE.
   
   `min-width: auto` is the default on a grid item, and it means "never
   narrower than your content". Harmless while the content is text, which
   wraps. The checkout panel put a Stripe iframe in here with a width of its
   own, and this column duly refused to go below it — 375px became 408px in a
   390px page, and every heading and paragraph in the shop section went with
   it. The document scrolled sideways on a phone.
   
   Setting it to 0 lets the column be the width the grid says it is. The
   panel below it already has overflow-x: auto, so a form too wide for the
   phone scrolls inside its own box instead of taking the page with it.
   
   Traced by walking the chain from the iframe upward: every element between
   had min-width 0 and this one said auto. */
.c-shop__detail {
  min-inline-size: 0; grid-column: col 5 / content-end; }

.c-shop__eyebrow {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-block-end: var(--sp-5);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  color: var(--c-accent-text);
}

.c-shop__eyebrow::before {
  content: "";
  inline-size: clamp(1.5rem, 4vw, 3rem);
  block-size: var(--bw-hair);
  background: currentColor;
}

.c-shop__title {
  font-family: var(--ff-display);
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 0, "WONK" 1;
  font-weight: var(--fw-light);
  font-size: var(--fs-3xl);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
}

/* Each line is its own block, so the break is where it was put and not where
   the balancer felt like putting it. `balance` comes off — it has nothing
   left to decide, and leaving it on lets it re-wrap INSIDE a line. */
.c-shop__title-line { display: block; }

.c-shop__title em {
  font-style: italic;
  font-variation-settings: "SOFT" 60, "WONK" 1;
  color: var(--c-accent-text);
}

.c-shop__copy {
  margin-block: var(--sp-5);
  max-inline-size: none;
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  color: var(--c-ink-soft);
  text-wrap: pretty;
}

/* Contents manifest — a mono ledger, two columns. */
.c-shop__contents {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-2) var(--sp-6);
  margin-block: var(--sp-6);
  padding-block: var(--sp-5);
  border-block: var(--bw-hair) solid var(--c-line);
}

.c-shop__contents li {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: var(--sp-3);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  color: var(--c-ink-soft);
  line-height: 1.7;
}

.c-shop__contents b { color: var(--c-accent-text); font-weight: var(--fw-medium); }

/* --- Price row ----------------------------------------------------------- */

.c-shop__buy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-5) var(--sp-7);
}

.c-shop__price {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
}

.c-shop__price b {
  font-family: var(--ff-display);
  font-size: var(--fs-3xl);
  font-weight: var(--fw-light);
  line-height: 1;
  letter-spacing: var(--tr-display);
}

.c-shop__price small {
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  color: var(--c-ink-muted);
}


@media (max-width: 68rem) {
  .c-cover      { grid-column: content-start / span 5; }
  .c-shop__detail { grid-column: content-start / content-end; }
}

@media (max-width: 48rem) {
  .c-cover { grid-column: content-start / span 8; }
  .c-shop__contents { grid-template-columns: minmax(0, 1fr); }
}

/* --------------------------------------------------------------------------
   The buy button before there is anything to buy from.
   Held, not hidden: the price and the product still need to read as real, so
   the button keeps its shape and loses only its affordance.
   -------------------------------------------------------------------------- */

.c-shop__buy-btn[disabled] {
  background: color-mix(in oklab, var(--c-accent) 38%, transparent);
  color: var(--c-accent-on);
  cursor: not-allowed;
}

.c-shop__soon {
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  white-space: nowrap;
}


/* --------------------------------------------------------------------------
   MOBILE: the guide book
   Cover and copy both centre, so the section reads as one column rather than
   as a desktop layout that has been squeezed.
   -------------------------------------------------------------------------- */

@media (max-width: 68rem) {
  .c-shop__shell { justify-items: center; }

  /* `margin-inline: auto` was not enough. The cover is a GRID ITEM, and it
     was still sitting in a five-column area of a twelve-column rail — auto
     margins centre it inside that area, which is itself off to the left. It
     has to take the full content width first, and then centre within it. */
  .c-cover {
    grid-column: content-start / content-end;
    justify-self: center;
    inline-size: min(100%, 20rem);
  }

  /* Centred on the page, so the lean has to pivot on its middle. Hinged on
     the left edge — right for a book sitting in a column beside text — it
     swings the whole cover to the right of where it is supposed to be. */
  .c-cover__plate { transform-origin: center center; }

  .c-shop__detail { text-align: center; }
  .c-shop__eyebrow { justify-content: center; }
  .c-shop__buy { justify-content: center; }

  /* Each row centred, number and title together.

     I set this as a proper contents page first — numbers in their own column,
     titles ranged off one axis — and was told to centre it. Fair: on a phone
     the eight lines sit under a centred head, a centred cover and a centred
     lede, and one left-ranged block in the middle of that read as a mistake
     rather than as a convention. */
  .c-shop__contents {
    display: grid;
    justify-content: stretch;
  }

  .c-shop__contents li {
    display: flex;
    justify-content: center;
    gap: var(--sp-3);
    text-align: center;
  }

  .c-shop__contents b { flex: none; }

  /* The price block is a narrow centred column now, which is small enough to
     sit beside the button rather than above it. On a phone that reads as two
     unrelated things on one line, so the row is stacked on purpose instead
     of by accident of width. */
  .c-shop__buy { flex-direction: column; }
  .c-shop__price b { white-space: nowrap; }
}

/* --------------------------------------------------------------------------
   THE HEADING IS SIZED TO ITS OWN LONGEST LINE

   Two composed lines only help if both of them fit. "over coffee, written
   down." is the longer of the two and at the full display size it needed
   429px of the 372 a phone gives it, so it wrapped anyway and put the comma
   back on a line of its own.

   The expression is derived, not guessed: measured at 440px the line needs
   0.0882px of type size for every pixel of available width, and the column
   is the viewport less two 34px margins. 8.55vw - 5.8px is that ratio with
   three per cent taken off for safety, and `min` keeps the full size on any
   screen wide enough to carry it.

   No `nowrap` to go with it. If a font ever loads at different metrics I
   would rather this wrap than push the page sideways.
   -------------------------------------------------------------------------- */

@media (max-width: 48rem) {
  .c-shop__title { font-size: min(var(--fs-3xl), calc(8.55vw - 5.8px)); }
}


/* --------------------------------------------------------------------------
   THE PRICE BLOCK SITS IN THE MIDDLE OF ITSELF

   Price above, terms below, the pair centred on both axes rather than hung
   off the left edge of the buy row.
   -------------------------------------------------------------------------- */

.c-shop__buy { justify-content: center; align-items: center; }

/* The Stripe button is wrapped in a <form> because starting a payment must be
   a POST — see render_buy(). `display: contents` makes the wrapper vanish as
   far as layout is concerned, so the button stays a direct flex item of
   .c-shop__buy and sits beside the price exactly as the bare <button> did. */
/* The form holds the button AND the line under it, stacked.
   
   `display: contents` before, so the button became a direct flex item of
   .c-shop__buy and sat beside the price. The note was a sibling of that whole
   row, so it wrapped onto its own line and centred itself under the PRICE AND
   BUTTON TOGETHER — which put it visibly left of the button it belongs to.
   
   A column instead: the form is the flex item, the button and its note are
   stacked inside it, and the note is under the button at every width by
   construction rather than by coincidence. */
.c-shop__buy-form {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
}

/* It lives inside the form now, so the margin that used to separate it from
   the row above is the flex gap's job. */
.c-shop__buy-form .c-shop__soon { margin: 0; text-align: center; }

.c-shop__price {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--sp-2);
}

/* --------------------------------------------------------------------------
   THE CHECKOUT PANEL

   Stripe's own form, drawn in an iframe, inside the page rather than on
   Stripe's domain. The buyer never leaves alexinmalta.com and never sees a
   redirect — which is worth real money at the exact moment people abandon.

   Everything here styles the frame AROUND the iframe. What is inside it is
   Stripe's and cannot be reached by our CSS at all; the only control we have
   over its appearance is the `appearance` object passed from JavaScript.
   -------------------------------------------------------------------------- */

.c-checkout {
  grid-column: content-start / content-end;
  margin-block-start: var(--sp-7);

  /* A GRID ITEM WILL NOT SHRINK BELOW ITS CONTENT unless told to. Stripe's
     iframe has a minimum width of its own, and because this panel sits inside
     .c-shop__detail — itself a grid item — that minimum was propagating
     upward and forcing the whole text column wider than the page. Every
     heading and paragraph in the shop section inherited an 18px overhang and
     the document scrolled sideways on a phone.
     
     min-inline-size: 0 lets the column shrink again; max-inline-size caps
     this panel at whatever the column actually is. */
  min-inline-size: 0;
  max-inline-size: 100%;

  /* interpolate-size is what lets a height animate from nothing to auto. The
     relocation cards use the same trick; see services.css for the note on
     what it costs and where it is unsupported. */
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.55s var(--ease-panel, ease-in-out);
}

.c-checkout[data-open] { grid-template-rows: 1fr; }

.c-checkout__inner {
  overflow: hidden;
  min-block-size: 0;
  min-inline-size: 0;
  background: var(--c-bg-alt);
  border: var(--bw-hair) solid var(--c-line);
  border-radius: 6px;
}

.c-checkout__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border-block-end: var(--bw-hair) solid var(--c-line);
}

.c-checkout__title {
  margin: 0;
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--c-ink-muted);
}

.c-checkout__title span {
  color: var(--c-ink);
  font-weight: 500;
}

.c-checkout__close {
  display: grid;
  place-items: center;
  inline-size: 2rem;
  block-size: 2rem;
  padding: 0;
  background: none;
  border: var(--bw-hair) solid var(--c-line);
  border-radius: 4px;
  color: var(--c-ink-muted);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

.c-checkout__close svg { inline-size: 0.85rem; }
.c-checkout__close:hover { color: var(--c-ink); border-color: var(--c-line-strong); }

/* Stripe's iframe lands in here and sizes itself. The padding is ours; the
   form's own margins are not, which is why this looks tighter than the rest
   of the page and should be left alone. */
.c-checkout__stage {
  padding: var(--sp-5);
  min-block-size: 6rem;

  /* If Stripe's form ever insists on being wider than the phone — it does
     not today, but its layout is theirs to change — it scrolls inside this
     box rather than taking the page with it. */
  min-inline-size: 0;
  overflow-x: auto;
}

.c-checkout__wait {
  margin: 0;
  padding: var(--sp-6) 0;
  text-align: center;
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  letter-spacing: var(--tr-normal);
  color: var(--c-ink-muted);
}

/* Someone who asked for less movement gets the panel appearing rather than
   unfolding. Nothing is hidden either way. */
@media (prefers-reduced-motion: reduce) {
  .c-checkout { transition: none; }
}

@media (max-width: 44rem) {
  .c-checkout__stage { padding: var(--sp-4) var(--sp-3); }
}

/* --------------------------------------------------------------------------
   THE EXPRESS WALLET BUTTONS

   Apple Pay and Google Pay, drawn by Stripe, above the ordinary Buy button.
   Hidden in the markup and revealed by script only once Stripe has confirmed
   the device can actually pay that way — so an Android with no Google Pay
   card, or a desktop Firefox, sees nothing at all rather than a button that
   fails when pressed.

   The buttons themselves are Stripe's and their appearance is Apple's and
   Google's to dictate: both brands require their own exact styling, which is
   why there is nothing here trying to restyle them. What is ours is the space
   around them and the rule underneath.
   -------------------------------------------------------------------------- */

.c-express {
  inline-size: 100%;
  max-inline-size: 22rem;
  margin-block-end: var(--sp-5);
}

/* The buttons come out full-width of whatever they are given. 22rem keeps
   them the same visual weight as the Buy button below rather than becoming a
   banner across the whole column. */
.c-express__slot { min-block-size: 2.75rem; }

/* "or pay by card", with a rule either side. It is doing real work: without
   it the wallet button and the Buy button read as two competing primary
   actions, and a buyer who has Apple Pay wonders which one is the real one. */
.c-express__or {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin-block: var(--sp-5) 0;
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  white-space: nowrap;
}

.c-express__or::before,
.c-express__or::after {
  content: "";
  flex: 1;
  block-size: var(--bw-hair);
  background: var(--c-line);
}

/* Centred on a phone and wherever the shop stacks, matching the button and
   the price above it. */
@media (max-width: 68rem) {
  .c-express { margin-inline: auto; }
}
