/* =========================================================================
   THE PROMO SLOTS — js/ads.js owns the markup, this owns the look.
   Everything is scoped to .promo or carries the component's own .promo-*
   prefix, so it cannot leak into any screen. Tokens only: there is not one
   colour, size or timing literal in this file.

   WHAT A PROMO IS. Our own card, pointing at our own store — see the header
   of js/ads.js, which says at length why that distinction matters.

   THIS STYLESHEET DRESSES NO THIRD-PARTY ADVERTISING, AND CANNOT. Everything
   here is scoped to .promo / .promo-* — markup js/ads.js builds node by node
   — so it reaches nothing Google or any other network would inject. js/ads.js
   does carry an AdSense loader, currently switched off behind its
   ADSENSE_ENABLED flag; if it is ever switched back on, the frames it places
   are same-origin-opaque iframes this file has no selector for and must not
   grow one. Sizing somebody else's ad frame from here is how a reserved box
   and the thing that lands in it start disagreeing.

   IT MUST NOT PASS FOR GAME UI, AND THAT IS THE WHOLE BRIEF OF THIS FILE.
   Three things carry it, and none of them is a colour anybody has to be able
   to see:

     THE MARK. A band across the top reading PROMO, in the same size, weight,
     tracking and ink as a .panel-head — a shape every screen in the app has
     already taught the reader to read as "this is what the box below is".
     It is real text, it is the <aside>'s accessible name, and it is above a
     hairline so it is a band and not a caption.

     IT IS FLAT AND THE PAGE'S OWN OBJECTS ARE NOT. A .panel takes
     `box-shadow:var(--edge),var(--e2)` — the rim AND neutral depth — because
     the SURFACE contract says a panel is a piece sitting on a table. A promo
     takes the rim and NO depth, so it reads as printed on the page rather
     than resting on it. That one missing token is the difference, it costs
     nothing, and it survives both themes and High contrast because --e2 is a
     token in all three.

     QUIETER INK. The heading is --ink-2, not --ink, and the line is --ink-3.
     The loudest ink on any screen belongs to what the game is telling you.

   NO --violet AND NO GOLD. The hero is one per screen and it is never this;
   gold is money at rest and a gold headline here would dress a promo as a
   balance. The control is the plainest .btn in the system, at .btn-sm.

   NO HALO. The COLOUR contract gives --glow to a control describing its own
   state and to nothing else. A promo describes no state; the one control
   inside it brings its own shadows from styles.css. So there is not one
   composed shadow list in this file — one token per declaration, everywhere,
   which is also why `none` arriving from a token in High contrast (where
   --edge becomes `0 0 0 0 transparent`) can never void a declaration here.

   NO MOTION, NO backdrop-filter, NO @keyframes. Nothing on a promo moves;
   there is nothing to cancel under body.no-anim or prefers-reduced-motion.
   ========================================================================= */

/* ---- the slot -------------------------------------------------------------
   The slot is whatever element the shell handed CR.ads.mount(). It carries
   nothing of its own — no padding, no border, no minimum height — so a
   collapsed slot leaves the layout exactly as it would be if the slot had
   never been placed. That is the entire promise "No Ads" makes: a reserved
   gap would break it as surely as a blank card would.

   Both halves are needed. js/ads.js sets [hidden] on an entitled slot, and
   the UA sheet's [hidden]{display:none} is beaten by ANY class rule that
   sets display — a slot sits inside a flex column on every placement we
   have, so that is not hypothetical. :empty covers the other half: a slot
   the shell placed and nothing ever mounted into.
   Neither can leave a gap in a flex or grid parent either: a display:none
   child is out of the layout entirely, so it contributes no `gap`. */
.promo-slot[hidden]{display:none}
.promo-slot:empty{display:none}

/* ---- the card -------------------------------------------------------------
   ONE bordered container and nothing bordered inside it but the button —
   which is a real control, and the only kind of bordered thing the SURFACE
   rule allows inside one. Never place a slot INSIDE a .panel: that would be
   a card in a card. See the insertion points recorded with this component. */
.promo{
  display:flex;align-items:center;flex-wrap:wrap;
  gap:var(--s2) var(--s3);
  padding:var(--s3);
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  /* the rim, and deliberately not --e2 — see the header */
  box-shadow:var(--edge);
}

/* ---- the mark -------------------------------------------------------------
   Same size, weight, tracking and ink as .panel-head h2, on purpose: the
   reader already knows that band means "here is what this box is". It takes
   the full width of the flex line so the card can never be read starting
   from the copy. */
.promo-mark{
  flex:1 0 100%;
  display:flex;align-items:center;gap:6px;
  padding-bottom:var(--s2);
  border-bottom:1px solid var(--line-soft);
  font-size:var(--t-xs);font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-3);
}
.promo-mark .ic{width:13px;height:13px}

/* ---- what is being pointed at ---------------------------------------------
   The same 34px well .inv-mark uses, for the same reason it uses it: the
   honest mark is what KIND of thing this is, and a picture of the item would
   be a second copy of the store's own preview vocabulary. Not interactive,
   so it takes the lit rim and never a halo. */
.promo-icon{
  flex:none;width:34px;height:34px;border-radius:var(--r-sm);
  display:grid;place-items:center;
  background:var(--surface-2);color:var(--ink-3);
  box-shadow:var(--edge);
}

/* ---- the copy -------------------------------------------------------------
   A short flex-basis on purpose: it is what keeps the heading, the sentence
   and the control on one line down to a very narrow card, so the button only
   wraps when it genuinely cannot fit rather than at an arbitrary width. */
.promo-copy{flex:1 1 12ch;min-width:0;display:flex;flex-direction:column;gap:2px}
.promo-head{
  font-family:var(--font-display);font-size:var(--t-sm);font-weight:700;
  color:var(--ink-2);line-height:1.25;
}
.promo-line{font-size:var(--t-xs);color:var(--ink-3);text-wrap:pretty;line-height:1.35}

/* Logical, not left/right, so RTL follows for free. When the button does wrap
   to its own line the auto margin keeps it at the end of the card, which is
   where the eye already expects it. */
.promo-go{flex:none;margin-inline-start:auto}

/* ---- High contrast --------------------------------------------------------
   body.contrast takes .panel, .btn, .input, .tag and .tile to a 2px border
   because that mode's premise is that a boundary should not need measuring.
   A promo is a bordered container too, and it is the one thing on the screen
   that most needs to be unmistakable, so it takes the same step. The mode's
   own token swaps do the rest: --line and --line-soft go to ink weight,
   --ink-2 and --ink-3 collapse into --ink, and --edge becomes the valid
   `0 0 0 0 transparent` no-op rather than `none`. */
body.contrast .promo{border-width:2px}

/* ---- narrow ---------------------------------------------------------------
   1240, 1000 and 720 need nothing, and that is a property of the component
   rather than an omission: a promo is one wrapping flex line inside whatever
   measure its host already has (420px inside the home card, --page-wide on
   the store, --page on browse), so those three steps change the card's width
   and nothing about its shape. The one real step is where the sentence and
   the control stop being able to share a line — a phone — and there the
   control takes a line of its own rather than squeezing the copy into a
   column two words wide.

   No pointer:coarse block: the only control here is a shared .btn.btn-sm,
   which the coarse block in styles.css already raises to 44px. This file
   defines no control height of its own, so per the responsive contract it
   owes no target of its own either. */
@media (max-width:420px){
  .promo{padding:var(--s3) var(--s3) var(--s2)}
  .promo-go{width:100%;margin-inline-start:0;margin-top:var(--s1)}
}
