/* Rimaya pocket — base, geometry and layout.
 *
 * docs/POCKET_V3_CONTRACT.md §4 and §7: the runtime and THIS file own the
 * launcher, the panel's placement beside it, the tail, the phone sheet, the
 * screen switch and the fly/toast/confetti layers. A theme is a DESIGN: its
 * templates own the markup inside the panel and its sheet owns that markup's
 * look; it never moves the launcher, the panel, the tail or the sheet. The
 * look of the runtime's own DEFAULT templates is the marked block near the end
 * of this file. Every rule is scoped `.rmp`, so nothing here can reach a
 * merchant's own page.
 *
 * The served stylesheet is this file, then gift-box.css, then the four themes
 * (server/routes/widget.js §6) — this file is first so a theme always wins on a
 * tie, and the last word on geometry is never a theme's.
 *
 * Contract §3 owns the class names. Anything not listed there is an internal
 * detail and a theme must not rely on it.
 */

.rmp {
  /* Tokens the runtime writes: --rmp-accent, --rmp-accent-ink, --rmp-accent-text
     (the accent as AA text on the surface), --rmp-offset-y, --rmp-font. */
  --rmp-offset-y: 0%;
  --rmp-accent: #004D5B;
  --rmp-accent-ink: #ffffff;
  --rmp-accent-text: var(--rmp-accent);
  --rmp-font: inherit;
  --rmp-display: var(--rmp-font);
  /* One type system: the token stays for the themes that still name it, but it
     resolves to the store's own Arabic face. Every figure is set in
     `--rmp-font` with tabular figures; nothing in the pocket is monospaced. */
  --rmp-mono: var(--rmp-font);

  /* Surfaces: the panel, the sunken wells (meter tracks, chips, the ship bar),
     and the cards. Light is white / near-white; dark is near-black. */
  --rmp-surface: #ffffff;
  --rmp-surface-2: #f4f4f6;
  --rmp-card: #ffffff;
  --rmp-card-line: rgba(18, 16, 28, 0.09);
  --rmp-line: rgba(18, 16, 28, 0.09);
  --rmp-ink: #16151b;
  --rmp-ink-2: #5d5b66;
  /* The terms are body copy a shopper has to be able to read, not decoration:
     `--rmp-ink-2` is for labels, and at 13px on white it read as faint grey.
     This is the same family, a shade deeper, and every theme in
     `themes/` overwrites it. Asserted at AA against the panel's own surfaces by
     `widget-theme-contrast.test.mjs`. */
  --rmp-ink-terms: #55535e;
  --rmp-track: rgba(18, 16, 28, 0.09);
  --rmp-success: #11795a;
  --rmp-success-ink: #ffffff;
  --rmp-success-soft: #e6f4ee;
  --rmp-shadow: 0 1px 2px rgba(18, 16, 28, 0.05), 0 10px 24px -12px rgba(18, 16, 28, 0.14), 0 28px 64px -16px rgba(18, 16, 28, 0.24);
  --rmp-card-shadow: 0 1px 2px rgba(18, 16, 28, 0.05);
  --rmp-card-shadow-hover: 0 2px 4px rgba(18, 16, 28, 0.06), 0 10px 24px -10px rgba(18, 16, 28, 0.22);

  --rmp-radius: 20px;
  --rmp-radius-card: 16px;
  --rmp-radius-sm: 10px;
  --rmp-radius-btn: 12px;
  --rmp-radius-chip: 999px;
  --rmp-list-pad-end: 16px;
  --rmp-meter: 6px;
  --rmp-gutter: 16px;
  --rmp-title-weight: 600;

  --rmp-launcher-size: 60px;
  --rmp-panel-width: 410px;
  /* The drawer's cap as a plain length, for rules that cannot read a percentage
     (a percentage of an auto-height parent resolves to nothing). */
  --rmp-panel-max: 640px;
  --rmp-margin: 12px;
  /* How far the launcher stays off the screen edge, from the side it is on. A
     button flush against the edge is clipped on a rounded phone screen and is
     one thumb-width from the system gesture area, so the runtime keeps a gap and
     every box that sits beside it (panel, tail, pill, hint) is placed off THAT,
     not off the screen. 12px on a phone, 16px on a desktop. */
  --rmp-edge: 16px;
  /* How far the merchant pushed the launcher off centre, as a distance — the
     sign of `offsetY` says which way, never where it lands. */
  --rmp-lift: max(var(--rmp-offset-y), calc(0px - var(--rmp-offset-y)));
  /* Contract §4: the panel is centred on the launcher's centre FIRST, and only
     then clamped inside the viewport. That order only works if the panel can be
     short enough to reach the launcher, so the height shrinks with the lift: at
     `offsetY: 0` this is exactly `min(640px, 100vh - 48px)`, and every step away
     from centre takes 2 × lift off the height. The floor (240px — head plus one
     card) keeps a very short window usable; past it the clamp takes over. */
  --rmp-panel-height: min(640px, max(240px, calc(100% - var(--rmp-lift) * 2 - 48px)));
  --rmp-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --rmp-focus: 0 0 0 3px color-mix(in srgb, var(--rmp-accent) 45%, transparent);

  /* Contract §9 — THE stacking order, as tokens, so a theme can only pick a
     depth and can never invent a fourth one. Inside the panel: content (0) <
     sticky bars (2) < the head (3). At the root: launcher (1) < panel (2) <
     hint/toast (3) < the fly and confetti layers (4). Every rule below that used
     to carry a raw number reads one of these instead. */
  --rmp-z-content: 0;
  --rmp-z-sticky: 2;
  --rmp-z-head: 3;
  --rmp-z-launcher: 1;
  --rmp-z-panel: 2;
  --rmp-z-hint: 3;
  --rmp-z-fx: 4;

  /* Contract §11.3 — the plan, designed ONCE here: goal, basket, one next-step
     card and the prize. A theme sets these tokens and nothing else; the markup
     (`.rmp-plan` and everything under it) is identical in all four themes. */
  --rmp-plan-radius: 14px;
  --rmp-plan-surface: var(--rmp-card);
  --rmp-plan-line: var(--rmp-line);
  --rmp-plan-ink: var(--rmp-ink);
  --rmp-plan-muted: var(--rmp-ink-2);
  /* The next card's wash: the accent at 7% over the panel's own surface, so it
     is opaque and never lets a card or a photo read through it. */
  --rmp-plan-tint: color-mix(in srgb, var(--rmp-accent) 7%, var(--rmp-plan-surface));
  --rmp-plan-gap: 24px;
  --rmp-plan-pip: 38px;

  /* ------------------------------------------------------- the shared metrics ---
   * Round-2 decision 5: ONE set of numbers, read by this sheet and by all four
   * themes; a theme keeps its colours, its surfaces and its radius personality,
   * and drops its own sizes in favour of these. The type scale is
   * 12 / 13 / 14 / 16 / 18 / 20 / 22 / 28 only.
   *   --rmp-head-h        56px  list and detail header height
   *   --rmp-fs-title      18px  header title, 700
   *   --rmp-icon-btn      44px  header icon button (close / back)
   *   --rmp-ship-fs       14px  ship row label (the amount is 700)
   *   --rmp-ship-track    5px   ship track, pill, full width
   *   --rmp-chip-h        40px  filter chip visual (44px hit area)
   *   --rmp-chip-fs       13px  chip label, 600
   *   --rmp-chip-count    20px  count pill, 12px / 700
   *   --rmp-fs-card       16px  list card title, 700, at most two lines
   *   --rmp-fs-ask        14px  the ask, 600
   *   --rmp-fs-detail     20px  detail title, 700
   *   --rmp-fs-label      13px  section label, 600, muted
   *   --rmp-fs-body       14px  body copy and terms
   *   --rmp-cta-h         48px  primary CTA height
   *   --rmp-cta-fs        16px  primary CTA label, 700
   */
  --rmp-head-h: 56px;
  --rmp-fs-title: 18px;
  --rmp-icon-btn: 44px;
  --rmp-ship-fs: 14px;
  --rmp-ship-weight: 600;
  --rmp-ship-h: 62px;
  --rmp-ship-track: 5px;
  --rmp-chip-h: 40px;
  --rmp-chip-fs: 13px;
  --rmp-chip-count: 20px;
  --rmp-fs-card: 16px;
  --rmp-fs-ask: 14px;
  --rmp-fs-detail: 20px;
  --rmp-fs-label: 13px;
  --rmp-fs-body: 14px;
  --rmp-cta-h: 48px;
  --rmp-cta-fs: 16px;
  /* How far the panel stands off the launcher, and how far the tail reaches into
     that gap: the tip lands on the launcher's own edge. */
  --rmp-panel-gap: 9px;

  position: fixed;
  inset: 0;
  z-index: 2147483000;
  font-family: var(--rmp-font);
  font-size: 14px;
  line-height: 1.6;
  color: var(--rmp-ink);
  text-align: start;
  /* Nothing we own intercepts a pointer except the parts that are buttons. */
  pointer-events: none;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
}

.rmp[hidden] { display: none; }

.rmp *,
.rmp *::before,
.rmp *::after { box-sizing: border-box; }

/* Every element we render is reset to our own box, so a merchant's global
   `button { … }` or `h2 { … }` cannot reach into the pocket.

   `:where()` is load-bearing here, not a style preference. The reset has to
   out-rank the merchant's element selectors (`button`, `h2`) and nothing more:
   as `.rmp button` it also out-ranked **our own** `.rmp-launcher`, so the
   launcher's geometry was dropped. Zero-specificity `:where()` keeps the shield
   and hands the geometry back to the rules below. */
.rmp :where(button, input, textarea, select, h2, h3, h4, p, ul, li, figure, b) { margin: 0; padding: 0; font: inherit; color: inherit; letter-spacing: normal; text-transform: none; }
.rmp ul { list-style: none; }
.rmp img { display: block; max-width: 100%; border: 0; }
.rmp :where(button) { background: none; border: 0; cursor: pointer; text-align: inherit; }

/* Dark is a token swap, never a separate rule set: one block, one mode. */
.rmp[data-mode="dark"] {
  --rmp-surface: #141416;
  --rmp-surface-2: #222226;
  --rmp-card: #1c1c20;
  --rmp-card-line: rgba(255, 255, 255, 0.08);
  --rmp-line: rgba(255, 255, 255, 0.10);
  --rmp-ink: #f4f4f6;
  --rmp-ink-2: #aeadb8;
  --rmp-ink-terms: #b9b7c2;
  --rmp-track: rgba(255, 255, 255, 0.12);
  --rmp-success: #3ecf8e;
  --rmp-success-ink: #05261a;
  --rmp-success-soft: rgba(62, 207, 142, 0.13);
  --rmp-shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 24px 56px -8px rgba(0, 0, 0, 0.7);
  --rmp-card-shadow: none;
  --rmp-card-shadow-hover: 0 10px 24px -10px rgba(0, 0, 0, 0.6);
  /* The next card's wash needs more accent on a dark surface before it reads as
     a surface at all; the surface it mixes over is the dark one above. */
  --rmp-plan-tint: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-plan-surface));
  color-scheme: dark;
}

.rmp-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Keyboard focus is always visible; pointer focus is not. Never removed. */
.rmp :focus-visible {
  outline: 2px solid var(--rmp-accent);
  outline-offset: 2px;
}
/* The panel and the two screens are where focus goes when something opens or a
   screen changes (docs/ACCESSIBILITY.md, focus policy 1) — the focus TARGETS, never controls. They
   carry `tabindex="-1"` and draw no ring of their own, on `:focus` or on
   `:focus-visible` (a browser may call a programmatic focus "visible"): the
   reader is placed in the region, and the first Tab reaches the first control,
   whose ring is real. */
.rmp-panel:focus,
.rmp-panel:focus-visible,
.rmp-screen:focus,
.rmp-screen:focus-visible { outline: none; }

/* Numbers line up: counts, prices, money, the code. */
.rmp-card__count,
.rmp-progress__count,
.rmp-need__price,
.rmp-need__count,
.rmp-ship__text,
.rmp-coupon__code { font-variant-numeric: tabular-nums; }

/* ============================================================ the launcher ===
 *
 * Contract §4: fixed on the chosen side edge, vertically centred at
 * `50% + var(--rmp-offset-y)`, 60px on desktop, 52px on mobile. A drag moves
 * it (side + a share of the free height) and the position is remembered;
 * never over checkout, and the keyboard's arrows do the same move.
 *
 * `data-side` is the merchant's LOGICAL side, exactly as saved (contract §1):
 * "start" is the reading edge. Everything below is placed with
 * inset-inline-start/end, so the root's own `dir` is the ONLY resolution point
 * — start is the right in Arabic (RTL) and the left in English (LTR). */
.rmp-launcher {
  position: absolute;
  top: calc(50% + var(--rmp-offset-y));
  inset-inline-end: var(--rmp-edge);
  width: var(--rmp-launcher-size);
  height: var(--rmp-launcher-size);
  margin: calc(var(--rmp-launcher-size) / -2) 0 0;
  padding: 0;
  border-radius: 50%;
  background: var(--rmp-surface);
  color: var(--rmp-accent);
  box-shadow: var(--rmp-shadow);
  pointer-events: auto;
  z-index: var(--rmp-z-launcher);
  display: grid;
  place-items: center;
  transition: transform 180ms var(--rmp-ease), opacity 180ms var(--rmp-ease);
  /* Direct manipulation: a drag on the launcher is the pocket's own, never the
     page's scroll. A tap still opens and the arrows move it from the keyboard. */
  touch-action: none;
  cursor: grab;
}
.rmp-launcher.is-docking { cursor: grabbing; transition: none; }
.rmp[data-side="start"] .rmp-launcher {
  inset-inline-end: auto;
  inset-inline-start: var(--rmp-edge);
}
.rmp-launcher:active { transform: scale(0.94); }
.rmp[data-open="true"] .rmp-launcher { transform: scale(0.9); }

/* The gift box occupies the launcher; the plain fallback is a CSS box so a
   failed fetch still shows a box rather than an empty circle. */
.rmp-gift {
  position: relative;
  display: block;
  /* One art box for all four masks (the other launchers set the same on their own
     wrappers); the gift's SVG keeps its internal optical margin. */
  width: 80%;
  height: 80%;
  pointer-events: none;
}
.rmp-gift > svg { width: 100%; height: 100%; display: block; overflow: visible; }
.rmp-gift__plain {
  position: absolute;
  inset: 12%;
  border-radius: 6px;
  background: var(--rmp-accent);
  box-shadow: inset 0 -22% 0 color-mix(in srgb, var(--rmp-accent) 72%, black);
}
.rmp-gift__plain::before {
  content: "";
  position: absolute;
  inset: -18% -6% auto -6%;
  height: 26%;
  border-radius: 4px;
  background: var(--rmp-accent-ink);
  opacity: 0.9;
}

/* The companion theme's slim "next reward" pill, beside the closed launcher. */
.rmp-pill {
  position: absolute;
  inset-inline-end: calc(var(--rmp-edge) + var(--rmp-launcher-size) + 8px);
  top: 50%;
  transform: translateY(-50%);
  max-width: 180px;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--rmp-surface);
  color: var(--rmp-ink);
  box-shadow: var(--rmp-shadow);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.6;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}
.rmp[data-side="start"] .rmp-pill {
  inset-inline-end: auto;
  inset-inline-start: calc(var(--rmp-edge) + var(--rmp-launcher-size) + 8px);
}
.rmp[data-open="true"] .rmp-pill { opacity: 0; }

/* ------------------------------------------------------------------ nudges ---
   The launcher's two voices - the HINT (unprompted) and the TOAST (the answer to
   an add, a copy, an apply) - are one component, the NUDGE: an icon tile, a bold
   one-line title, one supporting line, an optional meter, and a close button.
   Rebuilt 2026-10-08 after the owner called the old bubbles low quality: they
   were a dark pill of bare text, nested inside the launcher button, gone in 1.7s.

   The dock sits on the launcher's own vertical centre, on its INNER side, with a
   tail on the edge that faces it, so the two read as one pair. Width is capped so
   it never reaches the far edge of a 320px screen. Decorative to a screen reader
   (announce() speaks the words). */
.rmp-nudges {
  position: absolute;
  top: calc(50% + var(--rmp-offset-y));
  inset-inline-end: calc(var(--rmp-edge) + var(--rmp-launcher-size) + 12px);
  transform: translateY(-50%);
  z-index: var(--rmp-z-hint);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  pointer-events: none;
}
.rmp[data-side="start"] .rmp-nudges {
  inset-inline-end: auto;
  inset-inline-start: calc(var(--rmp-edge) + var(--rmp-launcher-size) + 12px);
  align-items: flex-start;
}
.rmp-nudge {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  box-sizing: border-box;
  inline-size: min(296px, calc(100vw - var(--rmp-edge) * 2 - var(--rmp-launcher-size) - 28px));
  padding-block: 10px;
  padding-inline: 11px 6px;
  border: 1px solid var(--rmp-line);
  border-radius: 16px;
  background: var(--rmp-surface);
  color: var(--rmp-ink);
  box-shadow: 0 14px 34px -14px rgba(16, 24, 40, 0.42), 0 2px 6px rgba(16, 24, 40, 0.07);
  font-family: var(--rmp-font);
  font-size: 13px;
  line-height: 1.45;
  text-align: start;
  pointer-events: auto;
  cursor: default;
  opacity: 1;
  animation: rmp-nudge-in 260ms var(--rmp-ease) both;
  transition: opacity 200ms linear, transform 200ms var(--rmp-ease);
}
.rmp-nudge[hidden] { display: none; }
.rmp-nudge[data-hiding="true"] { opacity: 0; transform: scale(0.97); }
/* The tail: a small square in the card's own colours on the edge facing the
   launcher, drawn as a plain diamond so it needs no per-direction rotation. */
.rmp-nudge::after {
  content: "";
  position: absolute;
  top: 50%;
  inset-inline-end: -6px;
  width: 11px;
  height: 11px;
  margin-top: -5.5px;
  border-radius: 2px;
  background: inherit;
  box-shadow: 1px -1px 0 0 var(--rmp-line);
  transform: rotate(45deg);
}
.rmp[dir="rtl"] .rmp-nudge::after { box-shadow: -1px 1px 0 0 var(--rmp-line); }
.rmp[data-side="start"] .rmp-nudge::after { inset-inline-end: auto; inset-inline-start: -6px; box-shadow: -1px 1px 0 0 var(--rmp-line); }
.rmp[dir="rtl"][data-side="start"] .rmp-nudge::after { box-shadow: 1px -1px 0 0 var(--rmp-line); }
.rmp-nudge__ico {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  inline-size: 36px;
  block-size: 36px;
  border-radius: 11px;
  background: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-surface));
  color: var(--rmp-accent-text);
}
.rmp-nudge__ico .rmp-ico { width: 19px; height: 19px; stroke-width: 1.9; }
.rmp-nudge[data-tone="success"] .rmp-nudge__ico { background: var(--rmp-success-soft); color: var(--rmp-success); }
.rmp-nudge[data-tone="warn"] .rmp-nudge__ico { background: color-mix(in srgb, #d97706 16%, var(--rmp-surface)); color: #b45309; }
.rmp-nudge__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 1px;
  min-inline-size: 0;
}
.rmp-nudge__title {
  overflow: hidden;
  color: var(--rmp-ink);
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.35;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rmp-nudge__sub {
  display: -webkit-box;
  overflow: hidden;
  color: var(--rmp-ink-2);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.rmp-nudge__sub[hidden],
.rmp-nudge__meter[hidden] { display: none; }
.rmp-nudge__meter {
  display: block;
  inline-size: 100%;
  min-inline-size: 150px;
  block-size: 5px;
  margin-top: 6px;
  overflow: hidden;
  border-radius: 999px;
  background: var(--rmp-surface-2);
}
.rmp-nudge__meter > i {
  display: block;
  block-size: 100%;
  border-radius: inherit;
  background: var(--rmp-accent);
  transition: width 420ms var(--rmp-ease);
}
.rmp-nudge[data-tone="success"] .rmp-nudge__meter > i { background: var(--rmp-success); }
.rmp-nudge__close {
  all: unset;
  flex: 0 0 auto;
  align-self: flex-start;
  display: grid;
  place-items: center;
  box-sizing: border-box;
  inline-size: 32px;
  block-size: 32px;
  border-radius: 10px;
  color: var(--rmp-ink-2);
  cursor: pointer;
  transition: background-color 140ms var(--rmp-ease), color 140ms var(--rmp-ease);
}
.rmp-nudge__close .rmp-ico { width: 16px; height: 16px; stroke-width: 2; }
.rmp-nudge__close:hover { background: var(--rmp-surface-2); color: var(--rmp-ink); }
.rmp-nudge__close:focus-visible { outline: 2px solid var(--rmp-accent); outline-offset: 1px; }
.rmp-pill[hidden] { display: none; }
@keyframes rmp-nudge-in {
  /* A grow from its own centre, never a slide: the card is centred on the
     launcher from its first frame, which is what it is about. */
  from { opacity: 0; transform: scale(0.94); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .rmp-nudge { animation: none; transition: opacity 120ms linear; }
  .rmp-nudge[data-hiding="true"] { transform: none; }
  .rmp-nudge__meter > i { transition: none; }
}

/* While the panel is OPEN the same two messages move INSIDE it, as a toast under
   the header: beside the launcher they would be behind the panel on a desktop and
   invisible on a phone, where the launcher is hidden outright. The runtime
   reparents the same nodes, so one message can never be painted twice. */
.rmp-panel-note {
  display: none;
  position: relative;
  z-index: var(--rmp-z-head);
  flex: 0 0 auto;
  padding: 8px 10px 8px 14px;
  border-bottom: 1px solid var(--rmp-line);
  background: color-mix(in srgb, var(--rmp-accent) 6%, var(--rmp-surface));
  color: var(--rmp-ink);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.5;
  overflow: hidden;
  transition: opacity 160ms linear;
}
.rmp-panel-note[data-shown="true"] { display: block; animation: rmp-note-in 180ms var(--rmp-ease) both; }
.rmp-panel-note > .rmp-nudge {
  inline-size: auto;
  min-inline-size: 0;
  max-inline-size: none;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  animation: none;
}
/* Inside the panel the nudge is a row under the header: no tail, no launcher to
   point at, and the words may use the panel's width. */
.rmp-panel-note > .rmp-nudge::after { display: none; }
.rmp-panel-note > .rmp-nudge .rmp-nudge__title,
.rmp-panel-note > .rmp-nudge .rmp-nudge__sub { max-inline-size: none; }
.rmp-panel-note > .rmp-nudge .rmp-nudge__ico { inline-size: 32px; block-size: 32px; border-radius: 10px; }
@keyframes rmp-note-in {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}

/* ============================================================== the panel ===
 *
 * Desktop: 410px × min(640px, 100vh − 48px) BESIDE the launcher, vertically
 * centred on the launcher's centre, clamped inside the viewport with a 24px
 * margin. Below 640px it is a true bottom sheet (see the end of this file). */
.rmp-panel {
  position: absolute;
  top: max(var(--rmp-margin), min(calc(50% + var(--rmp-offset-y) - var(--rmp-panel-height) / 2), calc(100vh - var(--rmp-panel-height) - var(--rmp-margin))));
  inset-inline-end: calc(var(--rmp-edge) + var(--rmp-launcher-size) + var(--rmp-panel-gap));
  width: var(--rmp-panel-width);
  height: var(--rmp-panel-height);
  margin-top: 0;
  display: flex;
  flex-direction: column;
  /* NOT `overflow: hidden`: the tail sits OUTSIDE the panel's box, on the edge
     facing the launcher. The rounded corners are clipped by the head and the
     track instead, which are the only two things that reach them. */
  overflow: visible;
  border-radius: var(--rmp-radius);
  background: var(--rmp-surface);
  color: var(--rmp-ink);
  box-shadow: var(--rmp-shadow);
  pointer-events: auto;
  /* Contract §9: the panel is its own stacking context, so a theme painting a
     `z-index: 99` inside it cannot lift a card over the header or over a sticky
     bar — and nothing here can lift the panel over the fly layer. */
  isolation: isolate;
  z-index: var(--rmp-z-panel);
  /* Grows from the launcher, so the panel appears to come out of the box. */
  transform-origin: var(--rmp-origin, center);
  animation: rmp-panel-in 260ms var(--rmp-ease) both;
}
.rmp[data-side="start"] .rmp-panel {
  inset-inline-end: auto;
  inset-inline-start: calc(var(--rmp-edge) + var(--rmp-launcher-size) + var(--rmp-panel-gap));
}
/* The open animation grows OUT OF the launcher, so the origin is the panel edge
   facing it. That edge is physical, so it needs both the logical side and the
   language. */
.rmp[data-side="start"][dir="ltr"] .rmp-panel,
.rmp[data-side="end"][dir="rtl"] .rmp-panel { --rmp-origin: left center; }
.rmp[data-side="start"][dir="rtl"] .rmp-panel,
.rmp[data-side="end"][dir="ltr"] .rmp-panel { --rmp-origin: right center; }

.rmp-panel[hidden] { display: none; }

/* The clamp, restated for the one thing a `top` clamp cannot know: a viewport
   narrower than the panel. */
@supports (max-height: 100vh) {
  .rmp-panel {
    max-height: calc(100vh - var(--rmp-margin) * 2);
    max-width: calc(100vw - var(--rmp-margin) * 2);
  }
}

/* The head: back (offer screen only), title, close. `--rmp-head-h` tall, one
   line — the same 56px in every theme (decision 5). */
.rmp-head {
  display: flex;
  align-items: center;
  gap: 4px;
  height: var(--rmp-head-h);
  /* Both sides on the pack's 16px gutter, so the close and the back mirror the
     title's edge (A3-DEPTH-05). */
  padding: 0 16px;
  border-bottom: 1px solid var(--rmp-line);
  border-radius: var(--rmp-radius) var(--rmp-radius) 0 0;
  background: var(--rmp-surface);
  flex: 0 0 auto;
  overflow: hidden;
  position: relative;
  /* The top of the order INSIDE the panel, and opaque on purpose: the screens
     slide under it, and a translucent header would show them passing through. */
  z-index: var(--rmp-z-head);
}
/* The back control sits on the same 16px edge as the close: the two ends of a
   header mirror (A3-DEPTH-05). */
.rmp[data-screen="offer"] .rmp-head { padding-inline: 16px; }

/* The speech-bubble tail: on the panel edge facing the launcher, moved
   vertically by the runtime so it keeps pointing at the launcher's centre even
   when the panel has been clamped. Desktop only. A rotated square painted in
   the panel's OWN surface token, so it reads as part of the panel in every
   theme and in both modes. */
.rmp-tail {
  position: absolute;
  top: 50%;
  /* A 14px square rotated 45° reaches 9.9px past the panel edge, and the panel
     stands `--rmp-panel-gap` (9px) off the launcher: the tip lands ON the
     launcher's box, not three pixels short of it (A-X-17). */
  width: 14px;
  height: 14px;
  margin-top: -7px;
  background: var(--rmp-surface);
  transform: rotate(45deg);
  /* The panel's own soft shadow, following the diamond's silhouette. */
  filter: drop-shadow(0 1px 2px rgba(18, 16, 28, 0.1)) drop-shadow(0 0 6px rgba(18, 16, 28, 0.07));
  inset-inline-end: -7px;
  border-top: 1px solid var(--rmp-line);
  border-inline-end: 1px solid var(--rmp-line);
  border-top-right-radius: 3px;
  z-index: var(--rmp-z-sticky);
}
.rmp[data-side="start"] .rmp-tail { inset-inline-end: auto; inset-inline-start: -7px; }
.rmp[dir="rtl"] .rmp-tail { border-top-right-radius: 0; border-top-left-radius: 3px; }

/* =============================================================== the track ===
 *
 * Two screens in one track. The body scrolls; the head never does. A screen
 * slides in from the inline end when it is shown, mirrored in RTL. */
.rmp-track {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  /* The clipper: a screen slides in from the inline end and is cut here, so it
     can never paint over the head. Sliding is `transform` + `opacity` only —
     no layout, no z-index. */
  overflow: hidden;
  border-radius: 0 0 var(--rmp-radius) var(--rmp-radius);
}
.rmp-screen {
  position: absolute;
  inset: 0;
  z-index: var(--rmp-z-content);
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--rmp-ink) 18%, transparent) transparent;
  padding: var(--rmp-gutter) var(--rmp-gutter) 20px;
  /* Contract §10: the sheet's drag is a pointer gesture on the head only, so the
     scroller keeps its own vertical pan — nothing inside a screen is `fixed`. */
  touch-action: pan-y;
  /* A full-bleed row paints past the screen's gutters; that width must never
     become a horizontal scroller (A-grid-29). `clip` keeps the vertical one and
     leaves the focus rings whole. */
  overflow-x: clip;
}
.rmp-screen[hidden] { display: none; }
.rmp-screen--list { display: flex; flex-direction: column; gap: 12px; }
/* A-X-32: the last card sits the same distance off the sheet's foot in every
   theme — one padding token plus the phone's safe area, whatever a theme pads
   the list with. */
.rmp-screen--list,
.rmp[data-theme][data-mode] .rmp-screen--list {
  padding-block-end: calc(var(--rmp-list-pad-end) + env(safe-area-inset-bottom, 0px));
  scroll-padding-block-end: var(--rmp-list-pad-end);
}
/* The list's own content may pad itself too (grid adds a foot under the offers);
   the rhythm the shopper sees is the token, so that padding stands down. */
.rmp[data-theme][data-mode] .rmp-screen--list > *:last-child {
  padding-block-end: 0;
  margin-block-end: 0;
}
/* A list with more under the fold fades at the bottom edge instead of cutting a
   card through its text. The list only: the offer screen's sticky bar is solid
   to its last pixel. On the desktop popover the fade is deeper, because the
   drawer's own bottom edge is a hard rounded corner a card can meet at first
   paint (A-friendly-32). */
.rmp-screen--list[data-more="true"] {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 32px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 32px), transparent);
}
@media (min-width: 640px) {
  .rmp-screen--list[data-more="true"] {
    -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 44px), transparent);
    mask-image: linear-gradient(to bottom, #000 calc(100% - 44px), transparent);
  }
}
.rmp[data-screen="offer"] .rmp-screen--offer { animation: rmp-screen-in 220ms var(--rmp-ease) both; }
.rmp[data-screen="list"] .rmp-screen--list { animation: rmp-screen-back 220ms var(--rmp-ease) both; }
.rmp[dir="rtl"] { --rmp-dir: -1; }
.rmp[dir="ltr"] { --rmp-dir: 1; }


/* ================================================ motion layers (geometry) ===
 *
 * THE FLIGHT. One layer, on the BODY, empty until a product is added and gone
 * again a beat later. It is `position: fixed` rather than a child of the root
 * for two reasons that are the same reason: the clone must answer to the
 * VIEWPORT. Inside the root it would be clipped by the panel's own stacking and
 * could be lost behind the sheet on a phone; and a merchant page that puts a
 * `transform` or a `filter` on `body > div` would move an in-root layer off
 * screen entirely. A fixed box on the body is the viewport in both cases.
 *
 * It carries its own `--rmp-z-fx` because it is no longer inside the root that
 * declares the token, and it sits one step above the root's own z-index: a
 * clone in flight crosses the merchant's page, so it is above all of ours.
 */
.rmp-fly {
  --rmp-z-fx: 2147483001;
  /* The layer lives on the BODY, outside `.rmp`, so it inherits none of the
     root's tokens. The flight only needs the easing, and it is restated here
     (with the value below matching `.rmp`) so the animation shorthand always
     resolves. */
  --rmp-ease: cubic-bezier(0.22, 1, 0.36, 1);
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: var(--rmp-z-fx);
}
/* The clone: the photo at the size the shopper saw it, thrown on a gentle arc.
   `left`/`top` are written in viewport coordinates and the margin pulls the box
   back by half its own size, so the numbers in the runtime are centres and not
   corners — which is why the same two numbers work in RTL and LTR and on either
   side of the page without a conditional anywhere. */
.rmp-flyitem {
  position: fixed;
  left: 0;
  top: 0;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  border-radius: 10px;
  object-fit: cover;
  /* No accent fallback needed for a real photo, but a clone whose fetch has not
     landed must never be a hole in the page. */
  background: var(--rmp-accent, #004D5B);
  box-shadow: 0 6px 18px -6px rgba(18, 16, 28, 0.45);
  opacity: 0;
  pointer-events: none;
  /* Promoted for its own lifetime only — the clone is removed when it lands. */
  will-change: transform, opacity;
}
.rmp-flyitem.is-flying {
  /* The `var()` fallback is load-bearing: a clone measured before the layer's
     own token cascades must still start, and an unresolved easing makes the
     whole shorthand invalid — which is a flight that never leaves the ground. */
  animation: rmp-fly var(--rmp-fly-duration, 720ms) var(--rmp-ease, cubic-bezier(0.22, 1, 0.36, 1)) forwards;
}
/* The launcher catches: a small squash on the way in, one settle out. Under
   reduced motion the global 0.001ms rule below ends it on its last frame, which
   is the resting scale — the same no-op every other attention moment has. */
.rmp-launcher.is-catch { animation: rmp-catch 460ms var(--rmp-ease) 1; }
.rmp--still .rmp-launcher.is-catch { animation: none; }

/* Confetti is the friendly theme's option; the layer is ours and always empty
   when the option is off. */
.rmp-confetti {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: var(--rmp-z-fx);
}
.rmp-confetti[hidden] { display: none; }
.rmp-confetti__bit {
  position: absolute;
  top: calc(50% + var(--rmp-offset-y));
  inset-inline-end: calc(var(--rmp-launcher-size) / 2);
  width: 7px;
  height: 11px;
  border-radius: 2px;
  background: var(--rmp-accent);
  opacity: 0;
  animation: rmp-confetti 1900ms var(--rmp-ease) forwards;
  animation-delay: var(--rmp-bit-delay, 0ms);
  transform: translate(0, 0) rotate(0);
}

@keyframes rmp-panel-in {
  from { opacity: 0; transform: scale(0.86); }
  to { opacity: 1; transform: scale(1); }
}
@keyframes rmp-screen-in {
  from { opacity: 0; transform: translateX(calc(var(--rmp-dir, 1) * 28px)); }
  to { opacity: 1; transform: translateX(0); }
}
@keyframes rmp-screen-back {
  from { opacity: 0; transform: translateX(calc(var(--rmp-dir, 1) * -28px)); }
  to { opacity: 1; transform: translateX(0); }
}
/* The arc itself: three `transform`/`opacity` keyframes and nothing else, so the
   whole flight stays on the compositor. The midpoint is the runtime's bow —
   half the travel, pushed up off the straight line — which is what turns a
   straight slide into a throw. */
@keyframes rmp-fly {
  0% { opacity: 0.95; transform: translate3d(0, 0, 0) scale(1); }
  55% { opacity: 0.8; transform: translate3d(var(--rmp-fly-cx, 0px), var(--rmp-fly-cy, 0px), 0) scale(0.55); }
  100% { opacity: 0; transform: translate3d(var(--rmp-fly-x, 0px), var(--rmp-fly-y, 0px), 0) scale(0.16); }
}
@keyframes rmp-catch {
  0% { transform: scale(1); }
  32% { transform: scale(0.84); }
  62% { transform: scale(1.14); }
  100% { transform: scale(1); }
}
@keyframes rmp-confetti {
  0% { opacity: 1; transform: translate(0, 0) rotate(0); }
  100% { opacity: 0; transform: translate(var(--rmp-bit-x, 0), 120px) rotate(var(--rmp-bit-turn, 0deg)); }
}
@keyframes rmp-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* A meter a template declares with `data-rmp-meter` is animated by the
 * runtime: it writes the width, this rule moves it. Off with motion. */
.rmp [data-rmp-meter] > :first-child,
.rmp [data-rmp-meter]:empty { transition: width 600ms var(--rmp-ease); }
.rmp--still [data-rmp-meter] > :first-child,
.rmp--still [data-rmp-meter]:empty { transition: none; }

/* ======================================================= DEFAULT TEMPLATES ===
 *
 * Everything below, down to the mobile section, is the LOOK of the runtime's
 * built-in templates (pocket.js `DEFAULT_TEMPLATES`): the title, the buttons,
 * the list and the offer page. A theme that registers its own templates
 * (contract §7) renders its own markup and its own classes, so none of this
 * reaches it; a theme that registers only some templates gets these rules for
 * the rest. Nothing in this block is geometry — the launcher, the panel, the
 * tail, the sheet and the screen switch live above it and stay the runtime's. */

.rmp-title {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--rmp-display);
  font-size: var(--rmp-fs-title);
  font-weight: 700;
  line-height: 1.4;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* =============================================================== buttons ===
 *
 * `.rmp-btn` is the base; the modifiers are colour and weight only. Every one
 * keeps a 36–40px target. */
.rmp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 36px;
  min-width: 36px;
  padding: 0 14px;
  border-radius: var(--rmp-radius-btn);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  transition: background-color 140ms var(--rmp-ease), color 140ms var(--rmp-ease), box-shadow 140ms var(--rmp-ease), transform 140ms var(--rmp-ease), opacity 140ms var(--rmp-ease);
}
.rmp-btn:disabled,
.rmp-btn[aria-busy="true"] { opacity: 0.55; cursor: default; }
.rmp-btn--primary { background: var(--rmp-accent); color: var(--rmp-accent-ink); }
.rmp-btn--primary:hover { background: color-mix(in srgb, var(--rmp-accent) 88%, var(--rmp-ink)); }
.rmp-btn--ghost { background: transparent; color: var(--rmp-ink-2); }
.rmp-back,
.rmp-close { width: var(--rmp-icon-btn); height: var(--rmp-icon-btn); min-height: var(--rmp-icon-btn); padding: 0; border-radius: 50%; color: var(--rmp-ink); }
.rmp-back:hover,
.rmp-close:hover { background: var(--rmp-surface-2); }
.rmp-back[hidden] { display: none; }
.rmp-back .rmp-ico,
.rmp-close .rmp-ico { width: 20px; height: 20px; }
/* «Back» points to the reading edge: in RTL the same chevron is mirrored. */
.rmp[dir="rtl"] .rmp-back .rmp-ico { transform: scaleX(-1); }
.rmp-ico { width: 18px; height: 18px; flex: 0 0 auto; }
.rmp-btn--add { background: var(--rmp-accent); color: var(--rmp-accent-ink); padding: 0 16px; }
.rmp-btn--add:hover { background: color-mix(in srgb, var(--rmp-accent) 88%, var(--rmp-ink)); }
.rmp-btn--add.is-added { background: var(--rmp-success); color: var(--rmp-success-ink); }
.rmp-btn--browse { background: transparent; color: var(--rmp-ink); box-shadow: inset 0 0 0 1px var(--rmp-line); }
.rmp-btn--browse:hover { background: var(--rmp-surface-2); }
.rmp-btn--copy { background: var(--rmp-ink); color: var(--rmp-surface); padding: 0 16px; }
.rmp-btn--copy.is-copied { background: var(--rmp-success); color: var(--rmp-success-ink); }


/* ====================================================== the list screen === */

/* The free-shipping bar. One line and one slim meter — no clause, no chip.
   Contract §9: it is a STICKY bar (it rides the top of the scroller so what is
   left is always visible) with an opaque background, because a transparent
   sticky bar would let the cards show through it as they scroll.

   OPAQUE IS THREE THINGS, not one. A background alone is not enough for a
   sticky bar inside a padded scroller: the bar is inset by the screen's gutter
   and it has rounded corners, so a card scrolling past shows through the strip
   ABOVE it and through the two corner notches even when the bar's own paint is
   solid. The spread shadow is the backing — it paints the panel's own surface
   out to `--rmp-gutter` on all four sides, behind the bar and above the content,
   so all three leaks are shut at once. A spread of `g` covers a corner of radius
   `r` as soon as `g ≥ r(√2 − 1)`; the gutter (12–16px) is always past that, and
   it is also exactly the strip it has to cover, so one number does both jobs. */
.rmp-ship {
  position: sticky;
  top: 0;
  z-index: var(--rmp-z-sticky);
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 14px;
  border-radius: var(--rmp-radius-btn);
  background: var(--rmp-surface-2);
  box-shadow: 0 0 0 var(--rmp-gutter) var(--rmp-surface);
  flex: 0 0 auto;
}
.rmp-ship[hidden] { display: none; }
/* A-grid-24: the bar's label weight and its height are the pack's, not a skin's
   — only colour, surface and radius differ between themes. */
.rmp[data-theme][data-mode] .rmp-ship {
  min-block-size: var(--rmp-ship-h);
  padding-block: 12px;
  box-sizing: border-box;
}
.rmp[data-theme][data-mode] .rmp-ship__text { font-weight: var(--rmp-ship-weight); }
/* A-friendly-40: the row's mark keeps ONE place in both states. A theme may let
   its label grow (`flex: 1`); the done check then rides the end of the label
   instead of the far edge of a 190px void. */
.rmp[data-theme][data-mode] .rmp-ship__top > .rmp-ship__text { flex: 0 1 auto; }
/* The row is sticky, so the strip ABOVE it is part of the bar: painted in the
   list's surface, taller than the screen's own top padding, so a card scrolling
   up vanishes under an opaque row and never peeks through the gap a theme's
   margin leaves (A-friendly-02). The runtime marks whichever element the theme
   drew as the list's row (`data-rmp-row`), so a theme with its own row class is
   covered by the same two rules. */
.rmp-screen--list > [data-rmp-row="true"]::before {
  content: "";
  position: absolute;
  inset-inline: calc(var(--rmp-gutter) * -1);
  bottom: 100%;
  block-size: calc(var(--rmp-gutter) + 16px);
  background: var(--rmp-surface);
  pointer-events: none;
}
/* Decision 5 / A-X-27: below the row, a 12px fade in the ROW'S OWN colour (the
   runtime reads it into `--rmp-row-bg`), so a card scrolling out is dissolved
   into the bar instead of sliced — and a tinted bar leaves no white band. */
.rmp-screen--list[data-scrolled="true"] > [data-rmp-row="true"]::after,
.rmp[data-theme][data-mode] .rmp-screen--list[data-scrolled="true"] > [data-rmp-row="true"]::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 100%;
  /* The bar is a rounded well: its fade follows the well's foot instead of
     hanging under it as a square strip (F-depth-04). */
  border-end-start-radius: var(--rmp-radius-btn);
  border-end-end-radius: var(--rmp-radius-btn);
  /* A text line is 22–26px tall: a 12px fade left its lower half readable under
     the row («… ر.س»). 28px, opaque for the first 10, dissolves a whole line. */
  block-size: 28px;
  background-color: var(--rmp-row-bg, var(--rmp-surface));
  /* A row painted with a gradient (depth) hands its own tint to the fade; the
     computed background-colour of such a row is transparent, so a flat colour
     would have left the fade invisible over its cards. */
  background-image: inherit;
  -webkit-mask-image: linear-gradient(to bottom, #000 0 10px, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0 10px, transparent 100%);
  pointer-events: none;
}
/* One line: the truck, then the sentence with its figure emphasised. The track
   is a row of its own under both, full width, and there is no knob. */
.rmp-ship__top {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  min-inline-size: 0;
}
.rmp-ship__ico {
  display: grid;
  place-items: center;
  flex: none;
  inline-size: 20px;
  block-size: 20px;
  color: var(--rmp-ink-2);
}
.rmp-ship__ico .rmp-ico { inline-size: 18px; block-size: 18px; }
.rmp-ship__text {
  min-inline-size: 0;
  margin: 0;
  font-size: var(--rmp-ship-fs);
  font-weight: 600;
  line-height: 1.5;
  /* Two lines at 360 rather than an ellipsis mid-sentence. */
  overflow-wrap: anywhere;
}
.rmp-ship__text bdi { font-weight: 800; color: var(--rmp-ink); }
.rmp-ship[data-done="true"] .rmp-ship__text,
.rmp-ship[data-done="true"] .rmp-ship__text bdi { color: var(--rmp-success); }
.rmp-ship[data-done="true"] .rmp-ship__ico { color: var(--rmp-success); }
.rmp-ship__meter {
  display: block;
  block-size: var(--rmp-ship-track);
  border-radius: 999px;
  background: var(--rmp-track);
  overflow: hidden;
}
.rmp-ship__fill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: var(--rmp-accent);
  transition: width 400ms var(--rmp-ease);
}
.rmp-ship[data-done="true"] .rmp-ship__fill { background: var(--rmp-success); }

.rmp-offers { display: flex; flex-direction: column; gap: 12px; }
.rmp-empty { font-size: 13px; color: var(--rmp-ink-2); padding: 24px 4px; text-align: center; }
.rmp-empty[hidden] { display: none; }

/* An offer card: a full-width 2:1 banner, then 12px of body — the title on one
   line, the reward and the count on one row, a 4px meter. The card is one
   button. */
.rmp-card {
  position: relative;
  /* Contract §9: a card is its own stacking context, so the media, the badge
     and the meter stay inside it and can never cross the sticky bar. */
  isolation: isolate;
  display: block;
  border-radius: var(--rmp-radius-card);
  background: var(--rmp-card);
  box-shadow: 0 0 0 1px var(--rmp-card-line), var(--rmp-card-shadow);
  overflow: hidden;
  transition: box-shadow 200ms var(--rmp-ease), transform 200ms var(--rmp-ease);
  flex: 0 0 auto;
}
.rmp-card:hover { box-shadow: 0 0 0 1px var(--rmp-card-line), var(--rmp-card-shadow-hover); }
.rmp-card__open {
  display: block;
  width: 100%;
  padding: 0;
  text-align: start;
  color: var(--rmp-ink);
  background: transparent;
  border-radius: inherit;
}
.rmp-card__open:focus-visible { outline-offset: -2px; }
.rmp-card__media {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 2 / 1;
  overflow: hidden;
  background: var(--rmp-surface-2);
}
.rmp-card__img { width: 100%; height: 100%; object-fit: cover; }
.rmp-card__body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px;
}
.rmp-card__title {
  /* Two lines, cut by the LINE and never by the character. `-webkit-line-clamp`
     inserts its ellipsis at a character position, and in RTL that position can
     fall inside an LTR figure — «خصم 20%» was rendered «خصم 0%…» at 360, which
     misstates the offer (A-friendly-01). A two-line box that hides the third line
     keeps every visible line whole: the figure is never split, and no line is
     ever cut mid-word. The merchant's full title still reaches assistive tech
     through the card's accessible name. */
  display: block;
  font-family: var(--rmp-display);
  font-size: var(--rmp-fs-card);
  font-weight: 700;
  line-height: 1.45;
  /* The title is its own paragraph, not a bidi island: `plaintext` made Chromium
     resolve the line to LTR and park the run on the inline-END edge, so a card's
     title and the ask under it did not share the right edge (A-X-19 / A-grid-18 /
     A3-DEPTH-01). The figures are isolated where they are built, so the paragraph
     may stay a plain RTL run and align to the start. */
  unicode-bidi: isolate;
  text-align: start;
  /* A figure is never orphaned on a line of its own, and a word is never split:
     the runtime trims the last word (see `trimCardTitles`) and this line box is
     the backstop for the paint before it runs. */
  /* Decision 5: balanced breaks, so a figure never sits alone on a line. */
  text-wrap: balance;
  overflow-wrap: normal;
  word-break: normal;
  overflow: hidden;
  /* Three lines, with the standard ellipsis as the truncation cue (decision 1
     this round). The figures are isolated runs, so the ellipsis can never split
     one into «0%». */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  max-height: calc(4.8em + 2px);
  max-height: calc(3lh + 2px);
}
/* A theme may restyle the title's type, but not clamp it by character: the same
   character-level ellipsis is what corrupts a figure, so the line box above wins
   over every theme's `-webkit-line-clamp` (this selector out-ranks a theme's). */
/* A-friendly-45: a line whose only strong run is an isolated LTR figure resolves
   LTR and parks on the inline-end; physical alignment keeps every line on the
   title's start edge. */
.rmp[data-theme][data-mode][dir="rtl"] .rmp-card__title,
.rmp-card__title.rmp-card__title[dir="rtl"] { text-align: right; }
.rmp[data-theme][data-mode][dir="ltr"] .rmp-card__title { text-align: left; }
.rmp[data-theme][data-mode] .rmp-card__title {
  display: -webkit-box;
  max-height: calc(4.8em + 2px);
  max-height: calc(3lh + 2px);
  overflow: hidden;
  unicode-bidi: isolate;
  text-align: start;
  text-wrap: balance;
  overflow-wrap: normal;
  word-break: normal;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
}
.rmp-card__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  min-height: 20px;
}
.rmp-card__reward {
  min-width: 0;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.5;
  color: var(--rmp-accent-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rmp-card__count {
  flex: 0 0 auto;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--rmp-ink-2);
  direction: ltr;
  unicode-bidi: isolate;
}
.rmp-card__meter,
.rmp-progress__meter {
  display: block;
  height: var(--rmp-meter);
  margin-top: 4px;
  border-radius: 999px;
  background: var(--rmp-track);
  overflow: hidden;
}
.rmp-card__fill,
.rmp-progress__fill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: var(--rmp-accent);
  transition: width 420ms var(--rmp-ease);
}
.rmp-card[data-state="done"] .rmp-card__fill,
.rmp-progress[data-done="true"] .rmp-progress__fill { background: var(--rmp-success); }
.rmp-card[data-state="done"] .rmp-card__count { color: var(--rmp-success); }
.rmp-card__count[hidden],
.rmp-card__done[hidden],
.rmp-card__meter[hidden] { display: none; }
/* «مكتمل ✓» — a two-word state over the image corner, never a sentence. */
.rmp-card__done {
  position: absolute;
  top: 10px;
  inset-inline-start: 10px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px 3px 8px;
  border-radius: var(--rmp-radius-chip);
  background: var(--rmp-success);
  color: var(--rmp-success-ink);
  font-size: 12px;
  font-weight: 700;
  line-height: 1.6;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  pointer-events: none;
}
.rmp-card__done .rmp-ico { width: 14px; height: 14px; stroke-width: 3; }

/* The designed card art, drawn when the merchant uploaded no banner: a collage
   of the offer's own product photos with the reward figure on a chip, or — with
   no photo at all — the accent with the figure centred. Never a letter tile. */
.rmp-card__art {
  position: relative;
  display: grid;
  width: 100%;
  height: 100%;
  gap: 2px;
  background: var(--rmp-surface);
  color: var(--rmp-accent-ink);
  overflow: hidden;
}
.rmp-card__art--n1 { grid-template-columns: 1fr; }
.rmp-card__art--n2 { grid-template-columns: 1fr 1fr; }
.rmp-card__art--n3 { grid-template-columns: 3fr 2fr; grid-template-rows: 1fr 1fr; }
.rmp-card__art--n3 .rmp-card__art-photo:first-child { grid-row: 1 / span 2; }
.rmp-card__art-photo { display: block; min-width: 0; min-height: 0; overflow: hidden; background: var(--rmp-surface-2); }
.rmp-card__art-photo img { width: 100%; height: 100%; object-fit: cover; }
.rmp-card__art-big {
  position: absolute;
  bottom: 10px;
  inset-inline-end: 10px;
  display: inline-flex;
  align-items: center;
  padding: 2px 12px;
  border-radius: var(--rmp-radius-chip);
  background: var(--rmp-accent);
  color: var(--rmp-accent-ink);
  font-family: var(--rmp-display);
  font-size: 15px;
  font-weight: 800;
  line-height: 1.6;
  white-space: nowrap;
  max-width: calc(100% - 20px);
  overflow: hidden;
  text-overflow: ellipsis;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.22);
}
/* No photo: the accent, a soft light, and the figure at display size. */
.rmp-card__art--figure,
.rmp-card__art--plate {
  display: grid;
  place-items: center;
  background-color: var(--rmp-accent);
  background-image:
    radial-gradient(120% 140% at 85% 0%, rgba(255, 255, 255, 0.28) 0%, rgba(255, 255, 255, 0) 55%),
    radial-gradient(90% 120% at 0% 100%, rgba(0, 0, 0, 0.22) 0%, rgba(0, 0, 0, 0) 60%);
}
.rmp-card__art--figure .rmp-card__art-big,
.rmp-card__art--plate .rmp-card__art-big {
  position: static;
  padding: 0 16px;
  max-width: 100%;
  background: transparent;
  box-shadow: none;
  font-size: 34px;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

/* ====================================================== the offer screen === */
.rmp-hero {
  position: relative;
  isolation: isolate;
  aspect-ratio: 2 / 1;
  border-radius: var(--rmp-radius-card);
  overflow: hidden;
  background: var(--rmp-surface-2);
  box-shadow: 0 0 0 1px var(--rmp-card-line);
}
.rmp-hero__img { width: 100%; height: 100%; object-fit: contain; object-position: center; }
.rmp-hero__wash {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.4;
  filter: blur(18px) saturate(0.85);
  transform: scale(1.14);
}
.rmp-hero .rmp-card__art-photo img { object-fit: contain; object-position: center; }
.rmp-hero .rmp-card__art-big { font-size: 16px; padding: 3px 14px; bottom: 12px; inset-inline-end: 12px; }
.rmp-hero .rmp-card__art--figure .rmp-card__art-big { font-size: 52px; }
.rmp-otitle,
.rmp[data-theme][data-mode] .rmp-otitle {
  margin-top: 14px;
  font-family: var(--rmp-display);
  text-wrap: pretty;
  font-size: var(--rmp-fs-detail);
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: normal;
  /* A headline balances its two lines, so a figure never lands on a line of its
     own («… بخصم» / «25%»); `pretty` was not enough (A-grid-32). */
  text-wrap: balance;
}
.rmp-odesc {
  margin-top: 2px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--rmp-ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* The progress card: what is left and for what, the count, the meter. */
.rmp-progress {
  margin-top: 14px;
  padding: 12px 14px 14px;
  border-radius: var(--rmp-radius-card);
  background: var(--rmp-surface-2);
}
.rmp-progress__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.rmp-progress__text {
  min-width: 0;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.6;
  color: var(--rmp-ink);
}
.rmp-progress__count {
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 800;
  color: var(--rmp-accent-text);
  direction: ltr;
  unicode-bidi: isolate;
}
.rmp-progress__count[hidden] { display: none; }
.rmp-progress[data-done="true"] .rmp-progress__text,
.rmp-progress[data-done="true"] .rmp-progress__count { color: var(--rmp-success); }
.rmp-progress .rmp-progress__meter { height: 6px; margin-top: 10px; }

.rmp-section { margin-top: 20px; display: flex; flex-direction: column; gap: 8px; }
.rmp-section__title,
.rmp-terms__title {
  font-size: var(--rmp-fs-label);
  font-weight: 600;
  line-height: 1.5;
  color: var(--rmp-ink-2);
}

/* A need: 64px photo, name and price, an action at the end. A product carries
   «أضف» (or ✓ when it is in the cart); a slot carries «تصفّح» only when it has
   somewhere to go. */
.rmp-need {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  padding: 8px;
  padding-inline-end: 10px;
  border-radius: var(--rmp-radius-card);
  background: var(--rmp-card);
  box-shadow: 0 0 0 1px var(--rmp-card-line);
}
.rmp-need--slot:not(:has(.rmp-btn, .rmp-check)) { grid-template-columns: 64px minmax(0, 1fr); }
.rmp-need__img {
  display: block;
  width: 64px;
  height: 64px;
  border-radius: var(--rmp-radius-sm);
  object-fit: cover;
  overflow: hidden;
  background: var(--rmp-surface-2);
}
.rmp-need__img img { width: 100%; height: 100%; object-fit: cover; }
/* A slot with no picture of its own is drawn from the shelf's goods: one photo
   fills the tile, two sit side by side, three are one large and two small. The
   1px gap is the card line, so the collage reads as one tile rather than three. */
.rmp-need__img--stack {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 1px;
  background: var(--rmp-card-line);
}
.rmp-need__img--stack[data-count="1"] { grid-template-columns: 1fr; grid-template-rows: 1fr; }
.rmp-need__img--stack[data-count="2"] { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr; }
.rmp-need__img--stack[data-count="3"] { grid-template-columns: 2fr 1fr; }
.rmp-need__img--stack[data-count="3"] img:first-child { grid-row: 1 / -1; grid-column: 1; }
.rmp-need__img--stack img { min-width: 0; min-height: 0; }
/* Nothing to show at all: a neutral glyph tile. Never an empty grey box — that
   reads as a broken image, and the shopper has no way to tell the difference. */
.rmp-need__img--glyph {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--rmp-ink-2);
  background: var(--rmp-surface-2);
}
.rmp-need__img--glyph .rmp-ico { width: 26px; height: 26px; stroke-width: 1.6; }
.rmp-need__img-blank {
  display: block;
  width: 100%;
  height: 100%;
  background: color-mix(in srgb, var(--rmp-accent) 16%, var(--rmp-surface-2));
}
.rmp-need__info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rmp-need__name {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.rmp-need__price,
.rmp-need__count { font-size: 12.5px; font-weight: 600; color: var(--rmp-ink-2); line-height: 1.5; }
.rmp-need[data-done="true"] .rmp-need__count { color: var(--rmp-success); }
.rmp-check {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--rmp-success-soft);
  color: var(--rmp-success);
}
.rmp-check .rmp-ico { stroke-width: 2.6; }

/* ========================================================== the plan (§11) ===
 *
 * Contract §11 replaces §8's checklist. The offer page answers four questions
 * in this order, for EVERY offer type, and nothing else:
 *
 *   1. how far am I   → `.rmp-goal`   (words + pips, or a meter when pips cannot
 *                                   honestly stand for the number)
 *   2. what of mine counts → `.rmp-basket` (only the shopper's own cart lines)
 *   3. what do I do next  → `.rmp-next`   (ONE emphasised card, one clear button)
 *   4. what do I get     → `.rmp-prize`  (the prize, and only the prize)
 *
 * There is no slot row per piece, no shelf strip, no picker and no `x/y`
 * counter: the shopper's own cart is the list, and the next step is a button.
 * The design lives here so all four themes ship one look; a theme sets the
 * `--rmp-plan-*` tokens on `.rmp` and nothing else.
 *
 * Calm, roomy, one accent. 360px phone first — nothing below may overflow, and
 * no rule may paint outside its own card (§9).
 */
.rmp-plan {
  display: flex;
  flex-direction: column;
  gap: var(--rmp-plan-gap);
  margin-top: 0;
}
/* One 24px rhythm between the detail's sections (A-friendly-12). The gap above
   the plan and the terms belongs to the screen; a theme that wraps the page in
   its own column (friendly's `.rmp-offer`) supplies it and gets no second one. */
.rmp-screen--offer > .rmp-plan,
.rmp-screen--offer > .rmp-terms { margin-top: var(--rmp-plan-gap); }
/* The three section labels: 13px/600, muted, and never a rule line — a hairline
   under a 13px label reads as a table, and this is not a table. */
.rmp-plan__title {
  font-size: var(--rmp-fs-label);
  font-weight: 600;
  line-height: 1.4;
  color: var(--rmp-plan-muted);
}

/* ------------------------------------------------------------- 1. the goal --- */
.rmp-goal {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* The ask and its state share one line: the state follows the ask at the start
   edge, never a lone pill at the far end of the row (A-friendly-06). */
.rmp-goal__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  /* The state keeps ONE anchor when the ask goes away (locked → done): the row's
     inline end (F-grid-07). */
  justify-content: space-between;
  gap: 4px 8px;
}
.rmp-goal__row > p { min-width: 0; }
/* Locked: a muted outline, a lock, and one word. Done: the accent solid, a
   check, and a different word — never two homographs in a grey pill
   (A-friendly-07). */
.rmp-goal__state {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 22px;
  /* Pushed to the row's inline end in both states — with the ask beside it and
     alone when the goal is done (F-grid-07). */
  margin-inline-start: auto;
  margin-top: 1px;
  padding: 0 8px;
  border: 1px solid var(--rmp-plan-line);
  border-radius: 999px;
  background: transparent;
  color: var(--rmp-plan-muted);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}
/* The completed state is the same pill, in the success colour: «اكتمل العرض»
   with its check, solid so it reads at a glance and its ink passes AA on every
   theme's success token (A-grid-28 / A-companion-36). */
.rmp-goal__state[data-state="done"] {
  border-color: transparent;
  background: var(--rmp-success);
  color: var(--rmp-success-ink);
}
.rmp-goal__state .rmp-ico,
.rmp-goal__state svg { width: 12px; height: 12px; stroke-width: 2.2; }
.rmp-goal__text {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.45;
  color: var(--rmp-plan-ink);
  text-wrap: balance;
}
/* The number the shopper is counting toward is the one thing in the accent. */
.rmp-goal__text > b {
  font-weight: 800;
  color: var(--rmp-accent-text);
}
.rmp-plan[data-done="true"] .rmp-goal__text,
.rmp-plan[data-done="true"] .rmp-goal__text > b {
  color: var(--rmp-success);
}

/* The pips: one circle per piece the goal needs (≤ 8). A filled slot is the
   accent disc with its white check, an empty one a hollow ring; never a photo —
   a 38px crop is unreadable and repeats the hero (A-friendly-04/18). The row is a
   meter, and the tally sits beside it. Beyond five they shrink rather than wrap —
   a second row of circles reads as another offer — and they never leave the
   row's width. */
.rmp-pips {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* An empty slot is a hollow ring — its fill is the page behind it, never a grey
   disc that reads as a disabled placeholder. */
.rmp-pip {
  /* A circle keeps its shape when the row is tight, so the basis shrinks and
     `aspect-ratio` follows it. */
  position: relative;
  isolation: isolate;
  flex: 0 1 var(--rmp-plan-pip);
  width: var(--rmp-plan-pip);
  max-width: var(--rmp-plan-pip);
  aspect-ratio: 1;
  border-radius: 50%;
  background: transparent;
  color: var(--rmp-plan-muted);
}
.rmp-pips[data-n="6"],
.rmp-pips[data-n="7"] {
  --rmp-plan-pip: 34px;
  gap: 6px;
}
.rmp-pips[data-n="8"] {
  --rmp-plan-pip: 30px;
  gap: 5px;
}
.rmp-pip[data-state="empty"] {
  border: 0;
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--rmp-track);
}
/* The tally is the meter's reading, not prose: a figure beside the slots, in the
   widget's own Arabic face — the mono face made it read as a code. */
.rmp-pips__count {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  margin-inline-start: 1px;
  color: var(--rmp-plan-muted);
  font-family: var(--rmp-font);
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  letter-spacing: 0.01em;
}
.rmp-pips__count b {
  color: var(--rmp-plan-ink);
  font-weight: 700;
}
.rmp-plan[data-done="true"] .rmp-pips__count b {
  color: var(--rmp-success);
}
/* One success hue in the completed block: the chip, the tally and the filled
   pips are the same colour, never teal beside green (A-friendly-41). */
.rmp-plan[data-done="true"] .rmp-pip.rmp-pip--solid {
  background: var(--rmp-success);
  color: var(--rmp-success-ink);
}
.rmp-pip__plus {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 15px;
  font-weight: 700;
  line-height: 1;
  color: var(--rmp-plan-muted);
}
.rmp-pip__plus .rmp-ico,
.rmp-pip__plus svg { display: block; width: 17px; height: 17px; stroke-width: 1.7; opacity: 0.4; }
.rmp-pip__plus::after {
  content: none;
}
.rmp-pip__tick {
  position: absolute;
  z-index: var(--rmp-z-sticky);
  inset-block-end: -1px;
  inset-inline-end: -1px;
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--rmp-accent);
  color: var(--rmp-accent-ink);
  box-shadow: 0 0 0 2px var(--rmp-plan-surface);
  font-size: 10px;
  font-weight: 800;
  line-height: 1;
}
.rmp-pip__tick svg,
.rmp-pip__tick .rmp-ico { width: 11px; height: 11px; stroke-width: 3.2; }
/* A counted piece is a SOLID accent circle with its ✓ centred — the one filled
   face of the meter (§11.3, A-friendly-04). */
.rmp-pip--solid {
  background: var(--rmp-accent);
  color: var(--rmp-accent-ink);
}
.rmp-pip--solid .rmp-pip__tick {
  inset: 0;
  width: auto;
  height: auto;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.rmp-pip--solid .rmp-pip__tick svg,
.rmp-pip--solid .rmp-pip__tick .rmp-ico { width: 19px; height: 19px; stroke-width: 3; }
/* A photo that failed to load gives its slot over: the mark already beside it
   (the centred ✓, the «+», the tile, the figure) is what the shopper sees. One
   rule for every slot, so no fallback can be left showing a broken image. */
.rmp img[data-rmp-broken] { display: none; }

/* The meter stands in when pips cannot: a spend threshold, a high count, a
   basket of many lines. An 8px track, an accent fill, and never a figure inside
   it — the goal text above already says how far. */
.rmp-goal__meter {
  display: block;
  height: 8px;
  border-radius: 999px;
  background: var(--rmp-track);
  overflow: hidden;
}
.rmp-goal__fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--rmp-accent);
}
/* The detail's own meter is the number the screen is counting: it fills in
   400ms, slower than a tap and quicker than a page. */
.rmp .rmp-goal__meter > .rmp-goal__fill { transition-duration: 400ms; }

/* -------------------------------------------------- 2. what of mine counts --- */
.rmp-basket,
.rmp-next,
.rmp-prize {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* Plain rows, no card borders: the shopper recognises these as their own cart,
   so nothing here wears the offer's clothing. A hairline between rows is the
   only rule. */
.rmp-basket ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
.rmp-bitem {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  padding: 4px 0;
}
.rmp-basket .rmp-bitem + .rmp-bitem {
  border-top: 1px solid var(--rmp-plan-line);
}
.rmp-bitem__img {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  object-fit: cover;
  background: var(--rmp-surface-2);
}
/* No photo is not an empty box: a neutral tile with a bag, which is also what a
   photo that fails to load hands over to (§11.3). */
.rmp-bitem__ph {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--rmp-surface-2);
  color: var(--rmp-plan-muted);
}
.rmp-bitem__ph svg,
.rmp-bitem__ph .rmp-ico { width: 18px; height: 18px; stroke-width: 1.8; }
.rmp-bitem__img:not([data-rmp-broken]) + .rmp-bitem__ph { display: none; }
.rmp-bitem__name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--rmp-plan-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rmp-bitem__qty {
  flex: 0 0 auto;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--rmp-plan-muted);
  font-variant-numeric: tabular-nums;
}
.rmp-bitem__tick {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--rmp-accent);
  color: var(--rmp-accent-ink);
  font-size: 10px;
  font-weight: 800;
  line-height: 1;
}
.rmp-bitem__tick svg,
.rmp-bitem__tick .rmp-ico { width: 11px; height: 11px; stroke-width: 3.2; }
/* «+3» — the counted lines past the sixth. One muted row, not a list. */
.rmp-bitem--more {
  justify-content: center;
  min-height: 28px;
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--rmp-plan-muted);
}

/* ---------------------------------------------------- 3. what do I do next --- */
.rmp-next { gap: 10px; }
/* The one emphasised block on the page: the next step, on an accent wash. */
.rmp-next__card {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  padding: 14px;
  border-radius: var(--rmp-plan-radius);
  background: var(--rmp-plan-tint);
}
.rmp-next__icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-plan-tint));
  color: var(--rmp-accent-text);
}
.rmp-next__icon svg,
.rmp-next__icon .rmp-ico { width: 20px; height: 20px; stroke-width: 1.8; }
.rmp-next__text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.rmp-next__title {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--rmp-plan-ink);
}
.rmp-next__sub {
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--rmp-plan-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.rmp-next__sub:empty { display: none; }
/* The button is its own full-width row under the words: the card has exactly
   one thing to do, so the thing to do is the widest thing on it. */
.rmp-next__links {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.rmp-next__links:empty { display: none; }

/* A named product the goal wants: photo, name, the piece count, and a compact
   control at the inline end. One card per product, never one per piece. */
.rmp-next__card[data-kind="product"] {
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 10px;
  padding: 10px;
}
.rmp-next__img {
  width: 56px;
  height: 56px;
  border-radius: 10px;
  object-fit: cover;
  background: var(--rmp-surface-2);
}
/* The same neutral tile as a basket row's, at the next card's size: a product
   with no photo, or one whose photo will not load, still gets a face. */
.rmp-next__ph {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--rmp-plan-muted) 14%, transparent);
  color: var(--rmp-plan-muted);
}
.rmp-next__ph svg,
.rmp-next__ph .rmp-ico { width: 22px; height: 22px; stroke-width: 1.8; }
.rmp-next__img:not([data-rmp-broken]) + .rmp-next__ph { display: none; }

/* --------------------------------------------- `.rmp-cta` — designed once ---
 *
 * Contract §11.3: 44px tall, accent fill, pill radius, a chevron to the inline
 * end. The runtime draws that chevron pointing right, so RTL is one mirror and
 * only for the chevron — never for the words.
 */
.rmp-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 44px;
  max-width: 100%;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  background: var(--rmp-accent);
  color: var(--rmp-accent-ink);
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 140ms var(--rmp-ease);
}
.rmp-cta:hover { background: color-mix(in srgb, var(--rmp-accent) 86%, black); }
.rmp-cta:focus-visible {
  outline: 2px solid var(--rmp-accent);
  outline-offset: 2px;
  box-shadow: var(--rmp-focus);
}
.rmp-cta > svg,
.rmp-cta svg { flex: 0 0 auto; width: 16px; height: 16px; }
/* Beside a 56px photo the same control is compact, so the card's row is one
   44px tap target and not two fighting heights. */
.rmp-next__card[data-kind="product"] > .rmp-cta {
  min-height: 36px;
  padding-inline: 14px;
  font-size: 13px;
}
.rmp[dir="rtl"] .rmp-cta > svg,
.rmp[dir="rtl"] .rmp-cta svg { transform: scaleX(-1); }
/* A pooled goal has one link per shelf. Two or more links become equal-width
   outline pills so neither reads as the main act; `:has()` is the only way to
   count them in CSS, and a browser without it simply keeps the filled pills.
   The basis is the label, never zero: three shelf names do not fit one phone
   row, so they wrap onto lines instead of squeezing each other into a clipped
   edge (§11.3, "nothing overflows"). */
.rmp-next__links:has(> .rmp-cta + .rmp-cta) .rmp-cta {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 100%;
  background: none;
  box-shadow: inset 0 0 0 1.5px var(--rmp-accent);
  color: var(--rmp-accent-text);
}
.rmp-next__links:has(> .rmp-cta + .rmp-cta) .rmp-cta:hover {
  background: color-mix(in srgb, var(--rmp-accent) 10%, transparent);
}
/* The last line of defence: a label longer than the card ellipsises instead of
   hanging outside it. */
.rmp-cta > bdi {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --------------------------------------------------------- 4. what I get --- */
.rmp-prize__card {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  padding: 12px;
  border-radius: var(--rmp-plan-radius);
  box-shadow: inset 0 0 0 1px var(--rmp-plan-line);
}
/* The reward mark owns its state: the lock — or, unlocked, the check — sits on
   its own corner, so the card is about one object rather than two. */
.rmp-prize__mark {
  position: relative;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 12px;
}
/* The figure, in its two honest forms: a percentage or «مجاناً» on the accent, or
   the product's own photo. Never a clause — 17px/800 on 52px is a number's
   size, and it ellipsises rather than wrapping into a sentence. */
.rmp-prize__badge {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  padding: 0 4px;
  border-radius: 12px;
  background: var(--rmp-accent);
  color: var(--rmp-accent-ink);
  font-size: 17px;
  font-weight: 800;
  line-height: 1.1;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rmp-prize__badge .rmp-ico,
.rmp-prize__badge svg { width: 22px; height: 22px; }
.rmp-prize__img {
  width: 52px;
  height: 52px;
  border-radius: 12px;
  object-fit: contain;
  background: var(--rmp-surface-2);
}
/* A product reward is shown whole on a tint plate (principle 2): the studio white
   melts into the surface, no crop of the thing the shopper is getting. */
.rmp-prize__mark--photo {
  background: var(--rmp-surface-2);
  box-shadow: inset 0 0 0 1px var(--rmp-plan-line);
}
.rmp-prize__mark--photo .rmp-prize__img {
  border-radius: 12px;
  mix-blend-mode: multiply;
  padding: 2px;
}
/* A prize nobody photographed, or one whose photo will not load, is the neutral
   tile — never an empty box where a reward should be (§11.3). */
.rmp-prize__ph {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--rmp-plan-muted) 14%, transparent);
  color: var(--rmp-plan-muted);
}
.rmp-prize__ph svg,
.rmp-prize__ph .rmp-ico { width: 22px; height: 22px; stroke-width: 1.8; }
/* The figure and the tile are the badge slot's other face: they wait behind a
   photo that arrived and take over when it did not. */
.rmp-prize__img:not([data-rmp-broken]) ~ .rmp-prize__badge,
.rmp-prize__img:not([data-rmp-broken]) ~ .rmp-prize__ph { display: none; }
.rmp-prize__text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
/* The kind word rides the section heading on a wide sheet; phones show it as the
   card's first line instead (below). */
.rmp-prize__kind { display: none; font-size: 12px; font-weight: 600; line-height: 1.3; color: var(--rmp-plan-muted); }
.rmp-prize__title {
  font-size: var(--rmp-fs-card, 16px);
  font-weight: 700;
  line-height: 1.4;
  color: var(--rmp-plan-ink);
}
.rmp-prize__sub {
  font-size: var(--rmp-fs-body, 14px);
  line-height: 1.5;
  color: var(--rmp-plan-muted);
}
.rmp-prize__sub:empty { display: none; }
/* The name and its state on one line: the state is one small chip right beside
   the reward's name — never a lone disc at the far edge (decision 2,
   F-grid-04/F-depth-09/F-friendly-03/F-X-07). */
.rmp-prize__line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 6px;
  min-inline-size: 0;
}
.rmp-prize__state {
  position: static;
  inset: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 20px;
  padding: 0 7px;
  border: 1px solid var(--rmp-plan-line);
  border-radius: 999px;
  background: transparent;
  color: var(--rmp-plan-muted);
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}
.rmp-prize__state svg,
.rmp-prize__state .rmp-ico { width: 11px; height: 11px; stroke-width: 2.4; }
/* A get/gift item the shopper has to add gets the button under the card row, so
   it is a whole-width action rather than a third item in a tight row. */
.rmp-prize__card > .rmp-cta { grid-column: 1 / -1; }

/* Locked: the prize is real and it is not yours yet — the badge loses its
   saturation and the mark carries the lock. Nothing is dimmed into illegibility. */
.rmp-prize[data-state="locked"] .rmp-prize__badge { filter: saturate(0.55); }
/* Unlocked: the engine says complete, so the card is a success surface. */
.rmp-prize[data-state="unlocked"] .rmp-prize__card {
  background: color-mix(in srgb, var(--rmp-accent) 8%, var(--rmp-plan-surface));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--rmp-accent) 34%, transparent);
}
.rmp-prize[data-state="unlocked"] .rmp-prize__state {
  border-color: transparent;
  background: var(--rmp-success);
  color: var(--rmp-success-ink);
}

/* The tiers ladder: horizontal segments, the reached ones filled. Never a table
   and never a `x/y` counter — the figure is under the piece count it needs. */
.rmp-ladder {
  display: flex;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.rmp-ladder > li {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  flex: 1 1 0;
  min-width: 0;
  padding: 8px 6px;
  border-radius: var(--rmp-radius-sm);
  background: var(--rmp-surface-2);
  text-align: center;
}
.rmp-ladder > li::before {
  content: "";
  width: 100%;
  height: 4px;
  margin-bottom: 3px;
  border-radius: 999px;
  background: var(--rmp-track);
}
.rmp-ladder > li > b {
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--rmp-plan-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.rmp-ladder > li > span {
  font-size: 13px;
  font-weight: 800;
  line-height: 1.3;
  color: var(--rmp-plan-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.rmp-ladder > li[data-state="reached"] {
  background: color-mix(in srgb, var(--rmp-accent) 10%, var(--rmp-plan-surface));
}
.rmp-ladder > li[data-state="reached"]::before { background: var(--rmp-accent); }
.rmp-ladder > li[data-state="reached"] > span { color: var(--rmp-accent-text); }
.rmp-ladder > li[data-state="next"] {
  box-shadow: inset 0 0 0 1.5px var(--rmp-accent);
}
.rmp-ladder > li[data-state="next"]::before { background: var(--rmp-accent); }
.rmp-ladder > li[data-state="next"] > span { color: var(--rmp-accent-text); }
.rmp-ladder > li[data-state="later"] > span { color: var(--rmp-plan-muted); }

/* ------------------------------------------------------------- the motion ---
 *
 * Two attention moments, both once, both silent until the shopper has asked for
 * motion twice: `.rmp--still` is the motion setting off, and the media query is
 * the system setting. A browser without `:has()` simply never pulses — the pips
 * are still the whole story.
 */
@keyframes rmp-pip-pulse {
  0%, 100% { transform: scale(1); }
  40% { transform: scale(1.09); }
}
@keyframes rmp-prize-glow {
  from { box-shadow: inset 0 0 0 1px currentColor, 0 0 0 0 rgba(0, 0, 0, 0); }
  to { box-shadow: inset 0 0 0 1px currentColor, 0 0 0 8px rgba(0, 0, 0, 0); }
}
@media (prefers-reduced-motion: no-preference) {
  /* The first pip that is still empty — the next thing to do — pulses once. */
  .rmp:not(.rmp--still) .rmp-pip[data-state="empty"]:not(:has(~ .rmp-pip[data-state="filled"])) {
    animation: rmp-pip-pulse 1500ms var(--rmp-ease) 1;
  }
  .rmp:not(.rmp--still) .rmp-cta:active { transform: scale(0.98); }
  .rmp:not(.rmp--still) .rmp-prize[data-state="unlocked"] .rmp-prize__card {
    color: color-mix(in srgb, var(--rmp-success) 34%, transparent);
    animation: rmp-prize-glow 1400ms var(--rmp-ease) 1;
  }
}
.rmp-btn--add { min-height: 36px; }

/* The reward, in its two honest forms. */
.rmp-reward {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: var(--rmp-radius-card);
  background: var(--rmp-success-soft);
}
.rmp-reward__mark {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--rmp-success);
  color: var(--rmp-success-ink);
}
.rmp-reward__mark .rmp-ico { stroke-width: 2.6; }
.rmp-reward__text { display: flex; flex-direction: column; min-width: 0; color: var(--rmp-ink); }
.rmp-reward__line { font-size: 14px; font-weight: 700; line-height: 1.5; }
.rmp-reward__how { font-size: 12.5px; line-height: 1.5; color: var(--rmp-ink-2); }

/* The coupon card: locked → revealed → applied, as data-state on one node. */
.rmp-coupon {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px 12px;
  padding: 14px;
  border-radius: var(--rmp-radius-card);
  background: var(--rmp-surface-2);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--rmp-ink) 16%, transparent);
}
.rmp-coupon[data-state="locked"] { background-image: repeating-linear-gradient(-45deg, transparent 0 10px, color-mix(in srgb, var(--rmp-ink) 3%, transparent) 10px 20px); }
.rmp-coupon__lock {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--rmp-card);
  color: var(--rmp-ink-2);
  box-shadow: 0 0 0 1px var(--rmp-card-line);
}
.rmp-coupon__lock[hidden] { display: none; }
.rmp-coupon__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rmp-coupon__mask {
  font-family: var(--rmp-mono);
  font-size: 17px;
  font-weight: 800;
  letter-spacing: 0.12em;
  line-height: 1.4;
  direction: ltr;
  text-align: start;
  color: var(--rmp-ink);
  filter: blur(5px);
  opacity: 0.55;
  user-select: none;
}
.rmp[dir="rtl"] .rmp-coupon__mask { text-align: end; }
.rmp-coupon__mask[hidden] { display: none; }
.rmp-coupon__status {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--rmp-ink-2);
  display: flex;
  align-items: center;
  gap: 6px;
}
.rmp-coupon__status:empty { display: none; }
.rmp-coupon__code {
  font-family: var(--rmp-mono);
  font-size: 22px;
  font-weight: 800;
  letter-spacing: 0.08em;
  line-height: 1.3;
  direction: ltr;
  unicode-bidi: isolate;
  word-break: break-all;
  color: var(--rmp-ink);
}
.rmp-coupon__code[hidden] { display: none; }
.rmp[dir="rtl"] .rmp-coupon__code { text-align: right; }
.rmp-coupon__expiry { font-size: 12px; color: var(--rmp-ink-2); line-height: 1.5; }
.rmp-coupon__expiry[hidden] { display: none; }
.rmp-coupon .rmp-btn--unlock { grid-column: 1 / -1; min-height: 44px; width: 100%; }
.rmp-coupon[data-state="revealed"],
.rmp-coupon[data-state="applied"] {
  grid-template-columns: minmax(0, 1fr) auto;
  background: color-mix(in srgb, var(--rmp-accent) 7%, var(--rmp-card));
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--rmp-accent) 45%, transparent);
}
.rmp-coupon[data-state="applied"] .rmp-coupon__status { color: var(--rmp-success); }
.rmp-coupon__status .rmp-ico { width: 16px; height: 16px; stroke-width: 2.6; }

/* The terms are always rendered, at the very end, as a plain list, fully
   visible: the body scrolls, nothing is clipped. The gap above the label is the
   only separator — a rule here would read as a table's last row. */
.rmp-terms {
  margin-top: 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.rmp-terms ul { display: flex; flex-direction: column; gap: 8px; margin: 0; padding: 0; list-style: none; }
.rmp-terms li {
  position: relative;
  padding-inline-start: 12px;
  font-size: 14px;
  line-height: 1.6;
  /* Body copy, not a label: AA on every theme's own surface, light and dark. */
  color: var(--rmp-ink-terms, var(--rmp-ink-2));
}
.rmp-terms li::before {
  content: "";
  position: absolute;
  inset-inline-start: 1px;
  top: 0.62em;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
}

/* ------------------------------------------------- the terms, folded (D1) ---
 *
 * One 44px «الشروط» row with a chevron; the list unfolds in place. Collapsed by
 * default, so the plan fits above the action bar on the first paint; every word
 * the shopper must consent to is one tap away and `aria-expanded` says which
 * state the row is in. Styled here, not by a theme, so the control is identical
 * in all four skins. */
.rmp-disclosure { margin-top: 24px; }
.rmp-disclosure__toggle {
  display: flex;
  align-items: center;
  /* The chevron sits beside the word, not alone at the sheet edge (A6-DEPTH-04). */
  justify-content: flex-start;
  gap: 8px;
  inline-size: 100%;
  min-block-size: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--rmp-ink-2);
  font-family: inherit;
  font-size: var(--rmp-fs-label, 13px);
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
}
.rmp-disclosure__toggle:focus-visible {
  outline: 2px solid var(--rmp-accent);
  outline-offset: 2px;
  border-radius: 8px;
}
.rmp-disclosure__toggle .rmp-ico,
.rmp-disclosure__toggle svg {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  stroke-width: 2;
  transition: transform 200ms var(--rmp-ease);
}
/* A vertical state: closed points down at the list it opens, open points up.
   Never mirrored — in RTL too (A6-DEPTH-04). */
.rmp-disclosure[data-open="false"] .rmp-disclosure__toggle svg { transform: rotate(90deg); }
.rmp-disclosure[data-open="true"] .rmp-disclosure__toggle svg { transform: rotate(-90deg); }
.rmp-disclosure__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 220ms var(--rmp-ease);
}
.rmp-disclosure[data-open="true"] .rmp-disclosure__panel { grid-template-rows: 1fr; }
.rmp-disclosure__inner {
  min-block-size: 0;
  overflow: hidden;
  /* Folded means gone, not merely clipped: the list leaves text extraction and
     the accessibility tree while the height still animates (A-X-44). */
  visibility: hidden;
  transition: visibility 0s linear 220ms;
}
.rmp-disclosure[data-open="true"] .rmp-disclosure__inner {
  visibility: visible;
  transition-delay: 0s;
}
.rmp-disclosure ul {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 4px 0 2px;
  list-style: none;
}
.rmp-disclosure li {
  position: relative;
  padding-inline-start: 12px;
  font-size: var(--rmp-fs-body, 14px);
  line-height: 1.6;
  color: var(--rmp-ink-terms, var(--rmp-ink-2));
}
.rmp-disclosure li::before {
  content: "";
  position: absolute;
  inset-inline-start: 1px;
  top: 0.62em;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
}

/* ==================================================== the detail's action bar ===
 *
 * The offer screen's one primary act, pinned to the foot of the sheet: the
 * content scrolls under it and no amount of terms can hide it. It is the last
 * child of the screen and `sticky`, so a short detail leaves it at the panel's
 * own bottom edge instead of floating mid-content. Negative inline margins take
 * it out to the panel's edges, and the offer screen's own bottom padding is zero
 * (below), so the bar — not a strip of scrolling content — is the last thing on
 * the sheet.
 */
.rmp-actionbar {
  position: sticky;
  z-index: var(--rmp-z-sticky);
  inset-block-end: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 24px calc(var(--rmp-gutter) * -1) 0;
  /* The sheet's own safe-area inset lands here: the screen's foot is zeroed under
     the bar, so the bar — not a strip of padding — is what sits on the home
     indicator (V-C3). */
  padding: 12px var(--rmp-gutter) calc(12px + env(safe-area-inset-bottom, 0px));
  background: var(--rmp-surface);
  box-shadow: 0 -1px 0 var(--rmp-line), 0 -10px 22px -16px rgba(18, 16, 28, 0.42);
}
/* The title and its save button share one row's top edge: the base title carries
   a 14px top margin for screens that draw no row, and a theme that pads the row
   itself must not stack the two (A-grid-23). The labelled save is one 44px
   control at every width, like the header's (decision 5). */
.rmp[data-theme] .rmp-screen--offer .rmp-otop .rmp-otitle { margin-top: 0; }
.rmp[data-theme] .rmp-screen--offer .rmp-otop > .rmp-save--labelled { min-block-size: 44px; }

/* The detail's hero is a preview of the product, not a poster (decision 3): it
   spans the content width with a floor of 172/200px, so no offer — gift included
   — reads as a postage stamp, and the photo stays whole inside the theme's plate.
   The capped height keeps the ask, the chip and the meter above the action bar.
   The doubled attribute out-ranks a theme that lifts the cap upward: round 3
   decision 3 makes the cap binding (F-grid-03/F-X-01). */
.rmp[data-theme][data-theme] .rmp-screen.rmp-screen--offer .rmp-hero:has(img) {
  inline-size: 100%;
  max-block-size: 30dvh;
  min-block-size: 172px;
}
@media (min-width: 380px) {
  .rmp[data-theme][data-theme] .rmp-screen.rmp-screen--offer .rmp-hero:has(img) { min-block-size: 200px; }
}
/* A gift's plan is one 72px row longer than any other: its frame takes the
   decision's 200px floor so the photo and the gift's name still sit above the
   action bar (F-grid-03 keeps the size, the prize keeps the fold). */
.rmp[data-theme][data-theme] .rmp-screen.rmp-screen--offer:has(.rmp-prize) .rmp-hero:has(img) {
  max-block-size: 200px;
}
.rmp[data-theme] .rmp-screen--offer .rmp-hero:not(:has(img)) { max-block-size: 120px; }

/* The reward card is one compact row at every width: the kind word rides inside
   it and the mark is 40px, so the gift's photo and name sit above the action bar
   on first paint — 360 (A-companion-22) and the 1440 popover (A-companion-32),
   where a lone «هدية» heading used to peek. */
.rmp-prize > .rmp-plan__title { display: none; }
.rmp-prize__kind { display: block; }
.rmp-prize__card {
  padding: 8px 10px;
  gap: 10px;
  /* The section's own width, one row: the product at the inline start and its
     name + state beside it — both edges used, no chip floating in the lane
     (A-X-45, F-grid-04). */
  align-self: stretch;
  inline-size: auto;
  grid-template-columns: auto minmax(0, 1fr);
}
.rmp-prize__mark,
.rmp-prize__img,
.rmp-prize__ph,
.rmp-prize__badge { width: 56px; height: 56px; }
.rmp-prize__badge { font-size: 15px; }
.rmp-prize__title { font-size: 15px; }
/* The gift's own frame is tall; the plan keeps the same 24px rhythm on a phone,
   and the height comes from the hero cap below (A5-DEPTH-03, decision 2). */

/* A line parked at the fold fades into the sheet instead of being bisected by
   the bar's hairline (decision 2, A4-DEPTH-01 / A-X-30 / A-friendly-30): the fade
   is 28px, inside the 32px the round allows, and the bar's own surface below it
   stays opaque. */
.rmp-actionbar::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 100%;
  block-size: 28px;
  background: linear-gradient(to top, var(--rmp-surface) 24%, transparent);
  pointer-events: none;
}

.rmp-actionbar__cta {
  width: 100%;
  border-radius: 12px;
}
/* The bar owns the sheet's last 12px, so the screen itself stops where the bar
   starts — otherwise the sticky offset leaves a strip of scrolling content under
   it. A theme may set the offer screen's padding as a shorthand (friendly does),
   so the rule that zeroes its foot out-ranks one theme selector. An offer with
   no bar keeps a foot of its own. */
.rmp-screen.rmp-screen--offer { padding-block-end: 0; }
.rmp[data-theme] .rmp-screen.rmp-screen--offer { padding-block-end: 0; }
.rmp-screen.rmp-screen--offer:not(:has(.rmp-actionbar)) { padding-block-end: 16px; }
.rmp[data-theme] .rmp-screen.rmp-screen--offer:not(:has(.rmp-actionbar)) { padding-block-end: 16px; }
/* Scroll-into-view in the detail stops above the bar, not under it. */
.rmp-screen--offer { scroll-padding-block-end: 88px; }
/* The desktop screen pads to 20px whatever the theme's gutter is, so the bar's
   full-bleed edge follows the screen's own padding there. */
@media (min-width: 640px) {
  .rmp-actionbar { margin-inline: -20px; padding-inline: 20px; }
  .rmp[data-theme][data-theme] .rmp-screen.rmp-screen--offer .rmp-hero:has(img) {
    inline-size: 100%;
    max-block-size: min(280px, 25dvh);
  }
}

/* =========================================================== desktop sheet ===
 *
 * The panel is a drawer, not a screen: it hugs its content up to `--rmp-panel-max`
 * (640px), centred on the launcher (a translate of its own height, so a one-offer
 * sheet is centred with no script measuring it). The screen is the scroller. */
@media (min-width: 640px) {
  .rmp-panel {
    top: max(24px, min(calc(50% + var(--rmp-offset-y) - var(--rmp-panel-h, var(--rmp-panel-height)) / 2), calc(100vh - 24px - var(--rmp-panel-h, var(--rmp-panel-height)))));
    height: auto;
    max-height: var(--rmp-panel-height);
    border-radius: var(--rmp-radius);
  }
  .rmp-track { flex: 0 1 auto; }
  .rmp-screen {
    position: relative;
    inset: auto;
    padding: 20px 20px 20px;
    /* The pinned height places the drawer; when it is not there yet the cap is
       the same number the panel itself uses (a length, never a percentage of an
       auto-height parent — that resolves to nothing and the screen overflows). */
    max-height: calc(var(--rmp-panel-h, min(var(--rmp-panel-max), 100vh - 48px)) - var(--rmp-head-h));
  }
  .rmp-head { padding-inline-start: 20px; }
  /* A toast row takes its own height out of the scroller's budget. */
  .rmp-panel:has(.rmp-panel-note[data-shown="true"]) .rmp-screen {
    max-height: calc(var(--rmp-panel-h, min(var(--rmp-panel-max), 100vh - 48px)) - var(--rmp-head-h) - 60px);
  }
}

/* ================================================================ mobile ===
 *
 * Below 640px the panel is a TRUE bottom sheet: the full viewport width,
 * anchored to the bottom, at most 86vh tall, 20px top corners, a grabber, no
 * tail, a scrim behind it that closes it on tap, and the launcher out of the
 * way while it is open. `data-device` is written by the runtime from the same
 * breakpoint, so the two can never disagree. */
@media (max-width: 639px) {
  .rmp { --rmp-launcher-size: 56px; --rmp-radius: 20px; --rmp-edge: 12px; }
  .rmp[data-open="true"]::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(8, 8, 12, 0.42);
    pointer-events: auto;
    animation: rmp-fade-in 200ms var(--rmp-ease) both;
  }
  .rmp .rmp-panel,
  .rmp[data-side="start"] .rmp-panel {
    inset-inline: 0;
    left: 0;
    right: 0;
    top: auto;
    bottom: 0;
    width: 100%;
    max-width: none;
    height: auto;
    max-height: 88vh;
    max-height: 88dvh;
    margin: 0;
    padding-top: 16px;
    border-radius: 20px 20px 0 0;
    transform-origin: bottom center;
    animation-name: rmp-sheet-in;
    animation-duration: 280ms;
  }
  .rmp-tail { display: none; }
  .rmp-panel::before {
    content: "";
    position: absolute;
    top: 8px;
    left: 50%;
    width: 36px;
    height: 4px;
    margin-left: -18px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--rmp-ink) 20%, transparent);
    z-index: var(--rmp-z-sticky);
  }
  .rmp-head { height: var(--rmp-head-h); border-radius: 0; }
  .rmp-track { flex: 0 1 auto; border-radius: 0; }
  /* The sheet sizes to its content up to 88dvh; the screen is the scroller. Its
     budget is the sheet minus the head and the sheet's own 16px top — the same
     numbers the panel and the grabber use, so no head can push the action bar
     past the bottom edge. */
  .rmp-screen {
    position: relative;
    inset: auto;
    max-height: calc(88dvh - var(--rmp-head-h) - 17px);
    padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    scrollbar-width: none;
  }
  .rmp-screen::-webkit-scrollbar { display: none; }
  .rmp[data-open="true"] .rmp-launcher { opacity: 0; visibility: hidden; pointer-events: none; }
  .rmp[data-open="true"] .rmp-pill { display: none; }
  .rmp-pill { max-width: min(42vw, calc(100vw - var(--rmp-edge) * 2 - var(--rmp-launcher-size) - 24px)); }
  .rmp-nudge { inline-size: min(296px, calc(100vw - var(--rmp-edge) * 2 - var(--rmp-launcher-size) - 28px)); }
  /* A phone has the width: the figure on a full-width card can be larger. */
  .rmp-card__art--figure .rmp-card__art-big { font-size: 36px; }

  /* ------------------------------------------------------- drag to dismiss ---
   *
   * The grabber and the header drag the sheet with the finger. `touch-action:
   * none` is on the HANDLE AREA ONLY — the grabber strip and the header, never
   * the screen (`.rmp-screen` keeps `pan-y`) — so the body of the sheet keeps
   * scrolling under the same finger. The runtime writes `--rmp-sheet-y` as the
   * sheet follows the finger, in one `requestAnimationFrame`, and the drag
   * classes below drop the entrance animation (its filled final frame would
   * out-rank an inline transform) and put the release transition back. */
  .rmp-head,
  .rmp-panel::before { touch-action: none; }
  /* The sheet follows the finger on a transform ALONE: no transition while it
     does. The spring that lands it is on the release class below, where the
     runtime is finished writing `--rmp-sheet-y` — a transition on the resting
     rule would lag the drag by a frame and read as a stuck sheet. */
  .rmp .rmp-panel,
  .rmp[data-side="start"] .rmp-panel {
    transform: translate3d(0, var(--rmp-sheet-y, 0px), 0);
  }
  /* While the finger is down there is no transition at all and the sheet is
     promoted for the length of the gesture only. `rmp--dragging` is what the
     runtime sets today; `is-dragging` is the same state under the contract's
     wording, and both are honoured so neither name can be lost. */
  .rmp .rmp-panel.rmp--dragging,
  .rmp .rmp-panel.is-dragging,
  .rmp .rmp-panel[data-dragging="true"] {
    animation: none;
    transition: none;
    will-change: transform;
  }
  .rmp .rmp-panel.rmp--settling {
    animation: none;
    transition: transform 260ms cubic-bezier(0.2, 0.8, 0.2, 1);
  }
  .rmp .rmp-panel.rmp--closing {
    animation: none;
    transition: transform 240ms cubic-bezier(0.4, 0, 1, 1);
  }
}

@keyframes rmp-sheet-in {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}

/* ============================================================ phone chrome ===
 *
 * Keyed on the runtime's `data-device`, not on a window media query, so the
 * phone frame inside the customization preview gets exactly the phone sheet a
 * shopper gets. One shipping row, flush tap targets, and no header growth. */
.rmp[data-theme][data-device="mobile"] .rmp-ship {
  gap: 10px;
  padding-block: 12px;
  padding-inline: 14px;
  border-radius: var(--rmp-radius-btn);
}
.rmp[data-theme][data-device="mobile"] .rmp-ship__top { flex: 1 1 auto; min-inline-size: 0; }
.rmp[data-theme][data-device="mobile"] .rmp-ship__text { min-inline-size: 0; }
.rmp[data-theme][data-device="mobile"] .rmp-ship__meter { flex: none; inline-size: auto; }
.rmp[data-theme][data-device="mobile"] .rmp-filters { margin-block: 4px; }
.rmp[data-theme][data-device="mobile"] .rmp-close,
.rmp[data-theme][data-device="mobile"] .rmp-back {
  inline-size: 44px;
  block-size: 44px;
  min-inline-size: 44px;
  min-block-size: 44px;
  box-sizing: border-box;
}
.rmp[data-theme][data-device="mobile"] .rmp-close .rmp-ico,
.rmp[data-theme][data-device="mobile"] .rmp-back .rmp-ico,
.rmp[data-theme][data-device="mobile"] .rmp-close svg,
.rmp[data-theme][data-device="mobile"] .rmp-back svg { inline-size: 18px; block-size: 18px; }
.rmp[data-theme][data-device="mobile"] .rmp-save--labelled { block-size: 44px; }
.rmp[data-theme][data-device="mobile"] .rmp-nudge__close,
.rmp[data-theme][data-device="mobile"] .rmp-teaser__x {
  inline-size: 44px;
  block-size: 44px;
}
.rmp[data-theme][data-device="mobile"] .rmp-teaser__cta { min-block-size: 44px; }
.rmp[data-theme][data-device="mobile"] .rmp-teaser__x { top: 8px; inset-inline-end: 8px; }

/* ============================================================ the guardrails ===
 *
 * Attention animations are capped, pausable and optional: motion=false and
 * prefers-reduced-motion both turn every one of them off, including the panel's
 * own entrance. */
@media (prefers-reduced-motion: reduce) {
  .rmp *,
  .rmp *::before,
  .rmp *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .rmp-panel { animation: none; }
  /* The sheet still FOLLOWS the finger — it is direct manipulation, not an
     animation — it just springs back without a transition. */
  .rmp .rmp-panel { transition: none !important; }
  .rmp-cta:active { transform: none; }
  .rmp-screen { animation: none !important; }
  .rmp-fly { display: none; }
  .rmp-confetti { display: none; }
}
.rmp--still .rmp-panel { animation: none; }
.rmp--still .rmp-screen { animation: none; }
.rmp--still .rmp-fly,
.rmp--still .rmp-confetti { display: none; }
.rmp--still .rmp-card__fill,
.rmp--still .rmp-progress__fill,
.rmp--still .rmp-ship__fill { transition: none; }
.rmp--still .rmp-launcher { transition: none; }
.rmp--still .rmp-card { transition: none; }

/* =========================================================== the preview box ===
 *
 * `RimayaPocket.preview()` mounts the real panel inside a device frame drawn by
 * the merchant's customization page: a phone or a browser window at its TRUE CSS
 * size, scaled with a `transform` to fit the space it is shown in. The frame is
 * a BOX, not a viewport, and the runtime's geometry is written for a viewport —
 * so every rule that answers to the window is restated here, against the frame.
 *
 * Three facts make this work, and all three are already true of the panel:
 *
 *   1. the root is `position: fixed` over `inset: 0`. Inside a transformed
 *      ancestor a fixed box resolves against THAT ancestor, so the root is the
 *      screen and nothing outside it can be reached. `position: absolute` is
 *      written here so the frame does not have to rely on the transform.
 *   2. the panel's clamp is `100vh`-based. Inside a box, `100%` is the screen.
 *   3. the phone sheet is behind a `@media (max-width: 639px)` question about the
 *      WINDOW. A phone frame inside a wide dashboard window answers "desktop",
 *      so `data-device` — which the runtime now takes from the caller's frame —
 *      is what the preview geometry reads.
 *
 * Scoped to `.rmp--preview` / `[data-rm-preview]` throughout: a merchant's page
 * never carries either, so the storefront's own bytes cannot be reached from
 * here, and the widget still fails hidden exactly as it does there. */

.rmp--preview {
  position: absolute;
  inset: 0;
  /* The panel's own entrance is a one-off: a preview is re-pointed rather than
     re-opened, and a rise on every control press reads as a flicker. */
  --rmp-preview-anim: none;
  /* The launcher's height (`offsetY`) is a LIVE control in the design preview.
     On a storefront the panel height shrinks with it (`--rmp-lift`); in the
     preview the panel must NOT resize or re-lay-out on every frame of a drag,
     so `--rmp-lift` is pinned and the panel's only response to the height is a
     composited transform. It is still clamped inside the screen by its own
     `top`, so pinning the height cannot push it out. */
  --rmp-lift: 0px;
  --rmp-panel-height: min(640px, max(240px, calc(100% - var(--rmp-margin) * 2)));
}
.rmp--preview .rmp-panel,
.rmp--preview[data-side="start"] .rmp-panel,
.rmp--preview[data-side="start"][dir="ltr"] .rmp-panel,
.rmp--preview[data-side="end"][dir="ltr"] .rmp-panel {
  animation: none;
  max-height: calc(100% - var(--rmp-margin) * 2);
  max-width: calc(100% - var(--rmp-margin) * 2);
}
.rmp--preview .rmp-screen { animation: none; }

/* Desktop geometry, inside the box: the panel is 380px beside the launcher on
   the chosen edge, centred on the launcher's centre, clamped to the screen with
   the contract's own 12px margin, and the tail keeps pointing at the launcher
   (the runtime positions it from the two real rects, so it lands correctly). */
.rmp--preview[data-device="desktop"] {
  --rmp-launcher-size: 60px;
  --rmp-edge: 16px;
}
.rmp--preview[data-device="desktop"] .rmp-panel,
.rmp--preview[data-device="desktop"][data-side="start"] .rmp-panel {
  top: max(var(--rmp-margin), min(calc(50% + var(--rmp-offset-y) - var(--rmp-panel-h, var(--rmp-panel-height)) / 2), calc(100% - var(--rmp-margin) - var(--rmp-panel-h, var(--rmp-panel-height)))));
  inset-inline-end: calc(var(--rmp-edge) + var(--rmp-launcher-size) + var(--rmp-panel-gap));
  inline-size: var(--rmp-panel-width);
  block-size: auto;
  max-block-size: var(--rmp-panel-height);
}

/* Phone geometry, inside the box: a true bottom sheet with the grabber, no tail,
   and the launcher out of the way while it is open. Restated from the media
   query above rather than left to it — the window is the dashboard, not the
   phone. `max-height` is a share of the SCREEN, so a 390×844 frame gets a sheet
   a shopper could actually read. */
.rmp--preview[data-device="mobile"] {
  --rmp-launcher-size: 56px;
  --rmp-radius: 20px;
  --rmp-edge: 12px;
}
.rmp--preview[data-device="mobile"] .rmp-panel,
.rmp--preview[data-device="mobile"][data-side="start"] .rmp-panel {
  inset-inline: 0;
  left: 0;
  right: 0;
  top: auto;
  bottom: 0;
  translate: none;
  inline-size: 100%;
  max-inline-size: none;
  block-size: auto;
  max-block-size: min(88dvh, 100%);
  display: flex;
  flex-direction: column;
  margin: 0;
  padding-top: 16px;
  border-radius: 20px 20px 0 0;
  transform-origin: bottom center;
  transform: translate3d(0, var(--rmp-sheet-y, 0px), 0);
}
.rmp--preview[data-device="mobile"] .rmp-panel::before {
  content: "";
  position: absolute;
  top: 8px;
  left: 50%;
  width: 36px;
  height: 4px;
  margin-left: -18px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--rmp-ink) 20%, transparent);
  z-index: var(--rmp-z-sticky);
}
.rmp--preview[data-device="mobile"] .rmp-tail { display: none; }
.rmp--preview[data-device="mobile"] .rmp-head { height: var(--rmp-head-h); border-radius: 0; }
/* The track takes what is left of the 88% box and the screen scrolls INSIDE it:
   the sheet still hugs a short list, and a long one (or a detail) reaches its
   last card and the sticky CTA instead of painting past the frame. */
.rmp--preview[data-device="mobile"] .rmp-track {
  flex: 1 1 auto;
  min-block-size: 0;
  border-radius: 0;
}
.rmp--preview[data-device="mobile"] .rmp-screen {
  position: relative;
  inset: auto;
  flex: 1 1 auto;
  min-block-size: 0;
  max-height: 100%;
  padding-bottom: 16px;
  scrollbar-width: none;
}
.rmp--preview[data-device="mobile"][data-open="true"]::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(8, 8, 12, 0.42);
  pointer-events: auto;
}
.rmp--preview[data-device="mobile"][data-open="true"] .rmp-launcher {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.rmp--preview[data-device="mobile"][data-open="true"] .rmp-pill { display: none; }

/* A preview is a box, so the window-relative caps the runtime uses for the
   floating bits have no meaning in it: they are shares of the SCREEN. */
.rmp--preview .rmp-pill {
  max-width: min(70%, calc(100% - var(--rmp-edge) * 2 - var(--rmp-launcher-size) - 24px));
}

/* --- «عرض مخصص», contract §12: the package checklist and a suspended code ---
   Additive, and every theme inherits it: base rules only, no theme overrides
   required. The checklist is a list of facts (a tick, a name, a count); the
   suspended code is the plan's own coupon block, dimmed and struck. */
.rmp-section--package { margin-top: var(--rmp-plan-gap, 18px); }
.rmp-section--package .rmp-section__title {
  margin: 0 0 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--rmp-ink-2);
}
.rmp-package {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
}
/* A requirement is a status, never an input: the open mark is a hollow ring and
   the met one is the accent disc with its white check. */
.rmp-package__row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 32px;
  color: var(--rmp-ink);
}
.rmp-package__mark {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1.5px solid var(--rmp-line);
  color: var(--rmp-ink-2);
}
.rmp-package__row[data-state="done"] .rmp-package__mark {
  border-color: var(--rmp-accent);
  background: var(--rmp-accent);
  color: var(--rmp-accent-ink);
}
.rmp-package__mark .rmp-ico { width: 11px; height: 11px; stroke-width: 3.2; }
.rmp-package__name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rmp-package__row[data-state="done"] .rmp-package__name { color: var(--rmp-ink-2); }
.rmp-package__count {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  color: var(--rmp-ink-2);
}
.rmp-package__warn {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 10px 0 0;
  padding: 9px 10px;
  border-radius: var(--rmp-plan-radius, 14px);
  background: color-mix(in srgb, #d97706 10%, var(--rmp-plan-surface, transparent));
  color: var(--rmp-ink);
  font-size: 13px;
}
/* The suspended code, in the nudge language: an amber tile, the state bold, and
   the first missing requirement as its own line. */
.rmp-package__warn-ico {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  inline-size: 32px;
  block-size: 32px;
  border-radius: 10px;
  background: color-mix(in srgb, #d97706 16%, var(--rmp-plan-surface, transparent));
  color: #b45309;
}
.rmp-package__warn-ico .rmp-ico { width: 18px; height: 18px; stroke-width: 1.9; }
.rmp-package__warn-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-inline-size: 0;
}
.rmp-package__warn-body strong { color: var(--rmp-ink); font-size: 13.5px; font-weight: 700; }
.rmp-package__warn-sub {
  overflow: hidden;
  color: var(--rmp-ink-2);
  font-size: 12px;
  font-weight: 500;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rmp-coupon[data-state="suspended"] .rmp-coupon__code {
  text-decoration: line-through;
  opacity: 0.5;
}
.rmp-coupon[data-state="suspended"] .rmp-coupon__status { color: var(--rmp-ink-2); }

.rmp--preview .rmp-nudge {
  /* A fixed width, never a share of the dock: the dock is as wide as its card, so
     a percentage here resolves against itself and collapses the card. */
  inline-size: 272px;
}

/* ======================================= Arabic glyphs are never clipped ===
 *
 * Arabic sits deeper than the Latin box. A «ج», «ح», «ي» or a final «ة» carries
 * a descender below the Latin baseline, and the marks over «ّ» ride above the
 * ascender; a single-line `overflow: hidden` row sized to a tight `line-height`
 * — an ellipsis label, a chip, a ladder rung — shaves that ink off by a couple
 * of pixels and reads as a broken edge. Every such box gets a line box taller
 * than the glyphs and a hair of block padding, so nothing is ever cut in either
 * language. Latin gains a little leading it did not ask for, and loses nothing.
 *
 * These are the LAST words on the matter: the block sits at the end of the base
 * sheet, and each theme repeats the rows it re-declares at its own specificity. */
.rmp-nudge__title,
.rmp-title,
.rmp-ship__text,
.rmp-card__title,
.rmp-card__reward,
.rmp-bitem__name,
.rmp-ladder > li > b,
.rmp-ladder > li > span,
.rmp-package__name,
.rmp-cta > bdi {
  line-height: 1.6;
  padding-block: 1px;
}
/* A clamped row clamps by LINE and measures with the line box, so the padding
   sits outside the clamp and the last line keeps its descenders. */
.rmp-nudge__sub,
.rmp-need__name,
.rmp-next__sub { line-height: 1.6; padding-block-end: 2px; }
/* A chip that holds a figure at display size: the box is fixed, the line is not. */
.rmp-prize__badge { line-height: 1.6; }
/* The button is a pill 44px tall; its label is a flex child, so the line box is
   the label's own. `line-height: 1` was the measured clip. */
.rmp-cta { line-height: 1.5; }
/* The one primary action of a screen: the sticky bar's button, on the shared
   48px / 16px-700 metrics (decision 5). A compact inline «أضف» stays a pill. */
.rmp-actionbar__cta,
.rmp-actionbar > .rmp-cta {
  min-height: var(--rmp-cta-h);
  border-radius: var(--rmp-radius-btn);
  font-size: var(--rmp-cta-fs);
}
/* A focused row never tucks its first line under the sticky shipping bar: the
   scroller reserves the bar's height at the block start for scroll-into-view. */
.rmp-screen { scroll-padding-block-start: 72px; }

/* =============================== §12 · custom product reward plate + nudge ===
 *
 * «عرض مخصص» can pay a free product or a discount on one product. The prize
 * plate (the plan's own card) already carries the product photo and its figure
 * via `.rmp-prize`; this block styles the one-line nudge that asks the shopper
 * to put that product in the cart, and its «أضف» button.
 */
.rmp-giftnudge {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 10px 0 0;
  padding: 10px;
  border-radius: var(--rmp-plan-radius, 14px);
  background: color-mix(in srgb, var(--rmp-accent) 9%, var(--rmp-plan-surface, transparent));
  color: var(--rmp-ink);
  font-size: 13px;
  line-height: 1.6;
}
.rmp-giftnudge__ico {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  inline-size: 32px;
  block-size: 32px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--rmp-accent) 16%, var(--rmp-plan-surface, transparent));
  color: var(--rmp-accent-text, var(--rmp-accent));
}
.rmp-giftnudge__ico .rmp-ico { width: 18px; height: 18px; stroke-width: 1.9; }
.rmp-giftnudge__body {
  flex: 1 1 auto;
  min-inline-size: 0;
}
.rmp-giftnudge > .rmp-cta {
  flex: 0 0 auto;
  min-height: 36px;
  padding-inline: 14px;
  font-size: 13px;
}
.rmp[dir="rtl"] .rmp-giftnudge > .rmp-cta > svg,
.rmp[dir="rtl"] .rmp-giftnudge > .rmp-cta svg { transform: scaleX(-1); }

/* ======================================== §5 · discovery (v5, v5.1) ==========
 *
 * docs/POCKET_V5_DISCOVERY_CONTRACT.md §5 and the v5.1 filter/bookmark spec
 * (runtime.md §A–D): the filter row, the bookmark, the teaser card, the
 * launcher's related badge and burst, and the related card's edge. Everything
 * reads the base tokens only, so all four themes inherit it in both modes;
 * every animation sits behind the system setting AND `.rmp--still`, and the
 * only depths used are the §9 layer tokens. */

/* --------------------------------------------------------- the filters (§A) ---
 * A slim row of plain buttons where the tab bar used to be. It sits in the list
 * flow AFTER the free-shipping bar and is NEVER sticky — it scrolls away with
 * the list — so it needs no layer of its own. The chips are normal buttons:
 * normal tab stops, no roving tablist, no arrow keys. The counts are the v5 tab
 * counts (keys stay `all`/`related`/`mine`) and a 0 is never drawn. */
.rmp-filters {
  display: flex;
  align-items: center;
  gap: 8px;
  /* A 40px chip inside a 48px row: the chip's 44px hit area and its 44px focus
     ring both fit, and the row is a scroll container so the inline axis clips —
     the vertical breathing room is what keeps the ring whole. */
  padding-block: 4px;
  margin-block: 4px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  flex: 0 0 auto;
}
.rmp-filters::-webkit-scrollbar { display: none; }
.rmp-filter {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: 0 0 auto;
  block-size: var(--rmp-chip-h);
  padding-inline: 14px 8px;
  border: 1px solid var(--rmp-line);
  border-radius: var(--rmp-radius-chip);
  background: var(--rmp-surface);
  color: var(--rmp-ink-2);
  font-family: var(--rmp-font);
  font-size: var(--rmp-chip-fs);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 140ms var(--rmp-ease), color 140ms var(--rmp-ease), border-color 140ms var(--rmp-ease);
}
/* The 44px tap target a thumb needs, without a 44px chip: the expansion is
   vertical only, so two chips' targets can never overlap each other — and it
   stays inside the row's 4px of breathing room, so nothing clips it. The chip
   draws a 1px border, so -3 on the padding box is exactly 2px past the border:
   44px of target, centred on a 40px chip. */
.rmp-filter::after { content: ""; position: absolute; inset: -3px 0; }
.rmp-filter:hover { color: var(--rmp-ink); }
.rmp-filter[aria-pressed="true"] {
  border-color: transparent;
  background: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-surface));
  color: var(--rmp-accent-text);
}
.rmp-filter:focus-visible { outline: 2px solid var(--rmp-accent); outline-offset: 2px; }
.rmp-filter__label { min-width: 0; }
/* The count is a figure in a chip — never a sentence, and a full pill. */
.rmp-filter__n {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  min-inline-size: var(--rmp-chip-count);
  block-size: var(--rmp-chip-count);
  padding-inline: 5px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--rmp-ink) 8%, transparent);
  color: inherit;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.rmp-filter[aria-pressed="true"] .rmp-filter__n { background: var(--rmp-accent); color: var(--rmp-accent-ink); }
/* §C: the count bump after a save — a short scale pop, both motion guards. */
@keyframes rmp-filter-bump {
  0% { transform: scale(1); }
  40% { transform: scale(1.18); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: no-preference) {
  .rmp:not(.rmp--still) .rmp-filter.is-bump { animation: rmp-filter-bump 300ms var(--rmp-ease) 1; }
}

/* ------------------------------------------------------ a related card ---
 * §5.4: a subtle accent edge, and never a text badge. */
.rmp-card[data-related="true"] { box-shadow: 0 0 0 1.5px var(--rmp-accent), var(--rmp-card-shadow); }
.rmp-card[data-related="true"]:hover { box-shadow: 0 0 0 1.5px var(--rmp-accent), var(--rmp-card-shadow-hover); }

/* ----------------------------------------------------------- the badge ---
 * §5.1: the COUNT, a number only, on the launcher's top inline-start corner.
 * Hidden from assistive tech — the launcher's own accessible name speaks it. */
.rmp-badge {
  position: absolute;
  /* On the tile's own corner, outboard of the art's box: the drawing keeps its
     top inline-start corner (V-C9 / decision 7). */
  top: -6px;
  inset-inline-start: -6px;
  /* (A-X-41's start-side inset is its own rule below.) */
  z-index: var(--rmp-z-sticky);
  display: inline-grid;
  place-items: center;
  min-inline-size: 20px;
  block-size: 20px;
  padding-inline: 5px;
  border-radius: 999px;
  background: var(--rmp-accent);
  color: var(--rmp-accent-ink);
  font-family: var(--rmp-font);
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  text-align: center;
  box-shadow: 0 0 0 2px var(--rmp-surface);
  pointer-events: none;
}
.rmp-badge[hidden] { display: none; }
/* A-X-41: on the start side a 6px overhang put the pill 6px from the screen
   edge; it moves inboard there, while the end side keeps its overhang. */
.rmp[data-side="start"] .rmp-badge { inset-inline-start: 4px; }

/* --------------------------------------------------------- the bookmark ---
 * runtime.md §B: a ribbon on a 44px tap target, outline while unsaved and filled
 * in the accent once it is. `--labelled` is the offer screen's pill — the icon
 * plus its own word. */
.rmp-save {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: none;
  inline-size: 44px;
  block-size: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  color: var(--rmp-ink-2);
  cursor: pointer;
  transition: color 140ms var(--rmp-ease);
}
.rmp-save::before {
  content: "";
  position: absolute;
  inset: 6px;
  z-index: 0;
  border-radius: 50%;
  background: var(--rmp-surface-2);
  transition: background-color 140ms var(--rmp-ease);
}
.rmp-save .rmp-ico { position: relative; z-index: 1; inline-size: 20px; block-size: 20px; stroke-width: 1.9; }
.rmp-save:hover { color: var(--rmp-ink); }
.rmp-save[aria-pressed="true"] { color: var(--rmp-accent-text, var(--rmp-accent)); }
.rmp-save[aria-pressed="true"]::before { background: color-mix(in srgb, var(--rmp-accent) 15%, var(--rmp-surface)); }
.rmp-save[aria-pressed="true"] .rmp-ico { fill: currentColor; }
.rmp-save:focus-visible { outline: 2px solid var(--rmp-accent); outline-offset: 2px; }
/* The labelled form is a pill, not a circle: the icon and one word. It keeps a
   44px target but only 36px of height, so it rides a title row cleanly. */
.rmp-save--labelled {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  inline-size: auto;
  block-size: 36px;
  padding-inline: 12px 14px;
  border: 1px solid var(--rmp-line);
  border-radius: var(--rmp-radius-chip);
}
.rmp-save--labelled::before { content: none; }
/* In the default offer page the pill is the first thing under the title: it
   takes its own width, not the column's. */
.rmp-screen--offer > .rmp-save--labelled { align-self: flex-start; }
.rmp-save__label { position: relative; z-index: 1; font-size: 13px; font-weight: 600; color: inherit; }
.rmp-save--labelled .rmp-ico { inline-size: 18px; block-size: 18px; }
/* On a default card it is a 30px frosted circle — the surface at 88% with a blur
   and a soft shadow — at the media's top inline-end corner, inside a 44px
   target. §D: z-index 1 keeps it a LOCAL layer of the card, under the sticky bar
   and never able to cross it. */
.rmp-card > .rmp-save {
  position: absolute;
  inset-block-start: 4px;
  inset-inline-end: 4px;
  z-index: 1;
}
.rmp-card > .rmp-save::before {
  content: "";
  position: absolute;
  inset: 7px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--rmp-surface) 88%, transparent);
  backdrop-filter: blur(6px);
  box-shadow: 0 2px 8px rgba(16, 24, 40, 0.22);
}
.rmp-card > .rmp-save[aria-pressed="true"]::before { background: color-mix(in srgb, var(--rmp-accent) 15%, var(--rmp-surface)); }
/* §C: the fill lands with a short drop-and-settle, motion-safe. */
@keyframes rmp-save-pop {
  0% { transform: translateY(-2px) scale(0.85); }
  55% { transform: translateY(0) scale(1.1); }
  100% { transform: none; }
}

/* ------------------------------------------------------ the related burst ---
 * §5.1: the gift box reuses its `.is-hint` motion for the related burst; the
 * perfume art defines its own (launchers/perfume.css). */
.rmp-gift.is-related > svg { animation: gb-wiggle 1s ease-in-out 1; transform-origin: 50% 90%; }
.rmp-gift.is-related .gb-ring { animation: gb-ring 1.3s ease-out 0.1s 1; }

/* ------------------------------------------------------------ the teaser ---
 * §5.2, relaid by the orchestrator 2026-10-18: the READ is the point, so the
 * text gets the width. Grid: media tile | text block (flex 1) | the × out of the
 * flow at the top inline-end corner; the CTA on its own row under the text, at
 * the inline end. A phone tile is 48px; the card is capped so it never reaches
 * the launcher. */
.rmp-teaser {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas:
    "media text"
    "media cta";
  align-items: center;
  column-gap: 10px;
  row-gap: 8px;
  inline-size: min(340px, calc(100vw - 24px));
  /* The dock already stands off the launcher, so the card may only use what is
     left of the screen after it — the card never reaches the button. */
  max-inline-size: calc(100vw - var(--rmp-launcher-size) - var(--rmp-edge) - 24px);
  padding: 14px;
  border: 1px solid var(--rmp-line);
  border-radius: 16px;
  background: var(--rmp-surface);
  color: var(--rmp-ink);
  box-shadow: 0 14px 34px -14px rgba(16, 24, 40, 0.42), 0 2px 6px rgba(16, 24, 40, 0.07);
  font-family: var(--rmp-font);
  font-size: 13px;
  line-height: 1.45;
  text-align: start;
  pointer-events: auto;
  cursor: default;
  opacity: 1;
  transition: opacity 200ms linear, transform 200ms var(--rmp-ease);
}
.rmp-teaser[hidden] { display: none; }
.rmp-teaser[data-hiding="true"] { opacity: 0; transform: scale(0.97); }
/* The tail that ties the card to the launcher, exactly as the nudge draws it:
   the same diamond, in the card's own surface and hairline. */
.rmp-teaser::after {
  content: "";
  position: absolute;
  top: 50%;
  inset-inline-end: -6px;
  width: 11px;
  height: 11px;
  margin-top: -5.5px;
  border-radius: 2px;
  background: inherit;
  box-shadow: 1px -1px 0 0 var(--rmp-line);
  transform: rotate(45deg);
}
.rmp[dir="rtl"] .rmp-teaser::after { box-shadow: -1px 1px 0 0 var(--rmp-line); }
.rmp[data-side="start"] .rmp-teaser::after { inset-inline-end: auto; inset-inline-start: -6px; box-shadow: -1px 1px 0 0 var(--rmp-line); }
.rmp[dir="rtl"][data-side="start"] .rmp-teaser::after { box-shadow: 1px -1px 0 0 var(--rmp-line); }
.rmp-teaser__media {
  grid-area: media;
  position: relative;
  display: grid;
  place-items: center;
  align-self: center;
  inline-size: 56px;
  block-size: 56px;
  overflow: hidden;
  border-radius: 14px;
  background: var(--rmp-surface-2);
}
.rmp-teaser__media img,
.rmp-teaser__figure {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
}
.rmp-teaser__media img { object-fit: contain; object-position: center; }
/* The tile is its own object inside the card: its radius, its hairline, and a
   whole product rather than a cropped pair of shins. */
.rmp-teaser__media { box-shadow: inset 0 0 0 1px var(--rmp-line); }
.rmp-teaser__figure--mark svg,
.rmp-teaser__figure--mark .rmp-ico { width: 20px; height: 20px; }
.rmp-teaser__figure {
  display: grid;
  place-items: center;
  background: var(--rmp-accent);
  color: var(--rmp-accent-ink);
  font-size: 15px;
  font-weight: 800;
}
.rmp-teaser__text {
  grid-area: text;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-inline-size: 0;
  /* Room for the × in the top inline-end corner: the 44px target plus a gap, so
     no letter of the title ever sits under the close (F-X-06). */
  padding-inline-end: 54px;
}
/* The eyebrow is a fact, and a fact must never be cut off. */
.rmp-teaser__eyebrow {
  color: var(--rmp-ink-2);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
}
/* The title may run to two lines, and then clamps. */
.rmp-teaser__title,
.rmp[data-theme][data-mode] .rmp-teaser__title {
  display: -webkit-box;
  overflow: hidden;
  color: var(--rmp-ink);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.45;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.rmp-teaser__reward {
  overflow: hidden;
  color: var(--rmp-ink-2);
  font-size: 12.5px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rmp-teaser__reward[hidden] { display: none; }
/* Its own row under the text, at the inline start: the pill's edge is the
   title's edge, so the card is one right-aligned column (principle 5). */
.rmp-teaser__cta {
  grid-area: cta;
  position: relative;
  /* The column's full width at every breakpoint: one alignment for the card,
     not a pill that drifts between the two (F-depth-05 / F-X-06). */
  justify-self: stretch;
  min-height: 44px;
  padding-inline: 16px;
  border-radius: var(--rmp-radius-btn);
  font-size: 13px;
}
.rmp-teaser__cta::after { content: ""; position: absolute; inset: -2px; }
.rmp-teaser__x {
  all: unset;
  position: absolute;
  top: 8px;
  inset-inline-end: 8px;
  display: grid;
  place-items: center;
  box-sizing: border-box;
  inline-size: 40px;
  block-size: 40px;
  border-radius: 12px;
  color: var(--rmp-ink-2);
  cursor: pointer;
  transition: background-color 140ms var(--rmp-ease), color 140ms var(--rmp-ease);
}
.rmp-teaser__x::after { content: ""; position: absolute; inset: -2px; }
.rmp-teaser__x .rmp-ico { inline-size: 16px; block-size: 16px; stroke-width: 2; }
.rmp-teaser__x:hover { background: var(--rmp-surface-2); color: var(--rmp-ink); }
.rmp-teaser__x:focus-visible { outline: 2px solid var(--rmp-accent); outline-offset: 1px; }
@media (max-width: 639px) {
  .rmp-teaser__media { inline-size: 56px; block-size: 56px; }
  .rmp-teaser__figure { font-size: 14px; }
}
@keyframes rmp-teaser-in {
  from { opacity: 0; transform: translateX(var(--rmp-teaser-from, 10px)); }
  to { opacity: 1; transform: none; }
}
/* ------------------------------------------------- motion (both guards) ---
 * The enter slide, the press pop and the art burst all wait for BOTH the
 * system setting and the store's own motion flag. A still pocket still shows
 * the badge and a static teaser. */
@media (prefers-reduced-motion: no-preference) {
  .rmp:not(.rmp--still) .rmp-teaser:not([data-hiding]) { animation: rmp-teaser-in 260ms var(--rmp-ease) 1; }
  .rmp:not(.rmp--still) .rmp-save.is-pop .rmp-ico { animation: rmp-save-pop 380ms var(--rmp-ease) 1; }
}
@media (prefers-reduced-motion: reduce) {
  .rmp-teaser { animation: none; transition: opacity 120ms linear; }
  .rmp-teaser[data-hiding="true"] { transform: none; }
}
.rmp--still .rmp-teaser { animation: none; transition: opacity 120ms linear; }
.rmp--still .rmp-teaser[data-hiding="true"] { transform: none; }
.rmp--still .rmp-save.is-pop .rmp-ico { animation: none; }

/* Rimaya gift box — the launcher icon and its motion (docs/POCKET_V3_CONTRACT.md §5). Designed by the head designer;
   agents must not replace this file.
   States are classes on .rmp-gift (the element wrapping the inline SVG):
     .is-idle     every ~7s the lid hops, the bow wobbles, a shine sweeps — then stillness
     :hover       the lid lifts a little and the shine runs once (via the launcher's hover)
     .is-open     the panel is open: the lid tips open on its hinge, light rays rise and slowly turn
     .is-receive  a product just flew in: the box squashes, the lid pops, two sparks
     .is-hint     a hint is showing: a gentle wiggle and one ring pulse
     .is-unlock   an offer was just unlocked: the lid flies, rays flash, sparks burst
   All of it stops under prefers-reduced-motion or when the merchant turns motion off (.rmp[data-motion="false"]). */

/* The four drawings were authored on different canvases — the gift fills its
   64-unit box, the other three keep a wide margin in a 128-unit one — but they
   share one optical footprint: the same square box in the plate, with the
   gift's own box lifted 2 px so its floor shadow does not hang low. */
.rmp-gift {
  display: inline-grid;
  place-items: center;
  box-sizing: border-box;
  inline-size: 100%;
  block-size: 100%;
  padding: 9.82%;
  line-height: 0;
}
.rmp-gift svg { width: 100%; height: 100%; overflow: visible; }
.rmp-gift:not([class*="rmp-gift--"]) { padding-block: 8% 11.64%; }
/* The badge owns the top inline-start corner: while it is up, the art steps
   inboard so the count never sits on the drawing. With no badge the art is
   centred. The gift's wide bow needs the larger step. */
.rmp-launcher:has(.rmp-badge:not([hidden])) .rmp-gift { padding-inline: 11.96% 7.68%; }
.rmp-launcher:has(.rmp-badge:not([hidden])) .rmp-gift:not([class*="rmp-gift--"]) { padding-inline: 14.6% 5.04%; }
/* A gift must never be the same colour as the plate it stands on: on depth's
   accent-gradient plate the box is drawn in the plate's ink and the ribbon in
   the accent; on companion's paper plate it keeps the accent body and turns
   the ribbon to paper. */
.rmp[data-theme="companion"] .rmp-gift {
  --gb-accent: var(--rmp-accent);
  --gb-ribbon: var(--cp-card, #fff);
  --gb-edge: var(--rmp-accent);
}
.rmp[data-theme="depth"] .rmp-gift {
  --gb-accent: var(--rmp-accent-ink, #fff);
  --gb-ribbon: var(--rmp-accent);
  --gb-edge: var(--rmp-accent-ink, #fff);
}
/* Press: a short, quiet squash. Faster and shallower than the open state. */
.rmp-launcher:active { transform: scale(.96); transition-duration: 120ms; }
.rmp-gift .gb-body, .rmp-gift .gb-lid, .rmp-gift .gb-bow, .rmp-gift .gb-rays,
.rmp-gift .gb-spark, .rmp-gift .gb-ring, .rmp-gift .gb-shadow, .rmp-gift .gb-shine-bar { transform-box: fill-box; }
.rmp-gift .gb-body { transform-origin: 50% 100%; }
.rmp-gift .gb-lid { transform-origin: 6% 100%; transition: transform .45s cubic-bezier(.34, 1.56, .64, 1); }
.rmp-gift .gb-bow { transform-origin: 50% 100%; filter: drop-shadow(0 .6px .7px rgba(0, 0, 0, .32)); }
.rmp-gift .gb-shadow { transform-origin: 50% 50%; opacity: .3; }
.rmp-gift .gb-contact { transform-origin: 50% 50%; opacity: .8; }
.rmp-gift .gb-rays { transform-box: view-box; transform-origin: 32px 30px; opacity: 0; transform: scale(.4); transition: opacity .35s ease, transform .5s cubic-bezier(.34, 1.56, .64, 1); }
.rmp-gift .gb-spark { transform-origin: 50% 50%; opacity: 0; transform: scale(0); }
.rmp-gift .gb-ring { transform-origin: 50% 50%; opacity: 0; }
.rmp-gift .gb-shine-bar { transform: rotate(18deg) translateX(0); opacity: 0; }

/* idle — a 7s loop that is still 85% of the time */
.rmp-gift.is-idle .gb-lid { animation: gb-idle-lid 7s ease-in-out infinite; }
.rmp-gift.is-idle .gb-bow { animation: gb-idle-bow 7s ease-in-out infinite; }
.rmp-gift.is-idle .gb-body { animation: gb-idle-body 7s ease-in-out infinite; }
.rmp-gift.is-idle .gb-shine-bar { animation: gb-shine 7s ease-in-out infinite; }
@keyframes gb-idle-lid {
  0%, 84%, 100% { transform: none; }
  87% { transform: translateY(-2px) rotate(-3deg); }
  90% { transform: translateY(0) rotate(0); }
  93% { transform: translateY(-1px) rotate(1.5deg); }
  96% { transform: none; }
}
@keyframes gb-idle-bow {
  0%, 85%, 100% { transform: none; }
  88% { transform: rotate(-2.5deg) scale(1.04); }
  92% { transform: rotate(2deg); }
  95% { transform: rotate(-1deg); }
}
@keyframes gb-idle-body {
  0%, 89%, 94%, 100% { transform: none; }
  90.5% { transform: scale(1.03, .95); }
  92% { transform: scale(.99, 1.02); }
}
@keyframes gb-shine {
  0%, 70% { transform: rotate(18deg) translateX(0); opacity: 0; }
  71% { opacity: 1; }
  80%, 100% { transform: rotate(18deg) translateX(84px); opacity: 0; }
}

/* hover — a peek inside */
.rmp-launcher:hover .rmp-gift:not(.is-open) .gb-lid,
.rmp-launcher:focus-visible .rmp-gift:not(.is-open) .gb-lid { transform: translateY(-2.6px) rotate(-6deg); animation: none; }
.rmp-launcher:hover .rmp-gift:not(.is-open) .gb-shine-bar { animation: gb-shine-once .8s ease-out 1; }
.rmp-launcher:hover .rmp-gift:not(.is-open) .gb-rays { opacity: .35; transform: scale(.55); }
@keyframes gb-shine-once { from { transform: rotate(18deg) translateX(0); opacity: 1; } to { transform: rotate(18deg) translateX(84px); opacity: 0; } }

/* open — lid tipped on its hinge, light rising from inside */
.rmp-gift.is-open .gb-lid { transform: translate(-2px, -9px) rotate(-26deg); animation: none; }
.rmp-gift.is-open .gb-bow { animation: gb-bow-settle .9s cubic-bezier(.34, 1.56, .64, 1) 1; }
.rmp-gift.is-open .gb-rays { opacity: .9; transform: scale(1); animation: gb-rays-turn 9s linear .5s infinite; }
.rmp-gift.is-open .gb-spark { animation: gb-spark-pop .8s cubic-bezier(.2, .9, .3, 1.3) 1 both; }
.rmp-gift.is-open .gb-spark--2 { animation-delay: .06s; } .rmp-gift.is-open .gb-spark--3 { animation-delay: .12s; }
.rmp-gift.is-open .gb-spark--4 { animation-delay: .18s; } .rmp-gift.is-open .gb-spark--5 { animation-delay: .1s; }
.rmp-gift.is-open .gb-shadow { animation: gb-shadow-breathe 1.8s ease-in-out infinite; }
@keyframes gb-bow-settle { 0% { transform: none; } 40% { transform: rotate(-10deg) scale(1.08); } 70% { transform: rotate(5deg); } 100% { transform: none; } }
@keyframes gb-rays-turn { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes gb-spark-pop { 0% { opacity: 0; transform: scale(0) rotate(0); } 45% { opacity: 1; transform: scale(1.3) rotate(45deg); } 100% { opacity: 0; transform: scale(.6) rotate(90deg); } }
@keyframes gb-shadow-breathe { 0%, 100% { transform: scaleX(1); opacity: .3; } 50% { transform: scaleX(.9); opacity: .22; } }

/* receive — a product just landed */
.rmp-gift.is-receive .gb-body { animation: gb-receive-body .55s cubic-bezier(.3, 1.4, .5, 1) 1; }
.rmp-gift.is-receive .gb-lid { animation: gb-receive-lid .55s cubic-bezier(.3, 1.4, .5, 1) 1; }
.rmp-gift.is-receive .gb-spark--2, .rmp-gift.is-receive .gb-spark--4 { animation: gb-spark-pop .6s ease-out .15s 1 both; }
.rmp-gift.is-receive .gb-shadow { animation: gb-receive-shadow .55s ease-out 1; }
@keyframes gb-receive-body { 0% { transform: none; } 30% { transform: scale(1.08, .86); } 60% { transform: scale(.96, 1.06); } 100% { transform: none; } }
@keyframes gb-receive-lid { 0% { transform: none; } 25% { transform: translateY(-7px) rotate(-10deg); } 55% { transform: translateY(1px); } 100% { transform: none; } }
@keyframes gb-receive-shadow { 30% { transform: scaleX(1.12); opacity: .38; } }

/* hint — a polite tap on the shoulder */
.rmp-gift.is-hint svg { animation: gb-wiggle 1s ease-in-out 1; transform-origin: 50% 90%; }
.rmp-gift.is-hint .gb-ring { animation: gb-ring 1.3s ease-out .1s 1; }
@keyframes gb-wiggle { 0%, 100% { transform: none; } 15% { transform: rotate(-8deg); } 30% { transform: rotate(7deg); } 45% { transform: rotate(-5deg); } 60% { transform: rotate(3deg); } 75% { transform: rotate(-1deg); } }
@keyframes gb-ring { 0% { opacity: .55; transform: scale(.7); } 100% { opacity: 0; transform: scale(1.35); } }

/* unlock — the celebration */
.rmp-gift.is-unlock .gb-lid { animation: gb-unlock-lid 1.25s cubic-bezier(.2, .8, .3, 1.2) 1; }
.rmp-gift.is-unlock .gb-body { animation: gb-unlock-body 1.25s cubic-bezier(.3, 1.4, .5, 1) 1; }
.rmp-gift.is-unlock .gb-rays { animation: gb-rays-flash 1.25s ease-out 1; }
.rmp-gift.is-unlock .gb-spark { animation: gb-spark-burst 1.1s cubic-bezier(.2, .9, .3, 1.3) 1 both; }
.rmp-gift.is-unlock .gb-spark--2 { animation-delay: .05s; } .rmp-gift.is-unlock .gb-spark--3 { animation-delay: .1s; }
.rmp-gift.is-unlock .gb-spark--4 { animation-delay: .15s; } .rmp-gift.is-unlock .gb-spark--5 { animation-delay: .08s; }
.rmp-gift.is-unlock .gb-ring { animation: gb-ring 1s ease-out .2s 1; }
@keyframes gb-unlock-lid { 0% { transform: none; } 30% { transform: translate(-3px, -16px) rotate(-32deg); } 62% { transform: translate(-2px, -11px) rotate(-22deg); } 100% { transform: none; } }
@keyframes gb-unlock-body { 0% { transform: none; } 18% { transform: scale(1.1, .84); } 40% { transform: translateY(-4px) scale(.95, 1.08); } 65% { transform: scale(1.03, .97); } 100% { transform: none; } }
@keyframes gb-rays-flash { 0% { opacity: 0; transform: scale(.4) rotate(0); } 30% { opacity: 1; transform: scale(1.15) rotate(25deg); } 100% { opacity: 0; transform: scale(1) rotate(60deg); } }
@keyframes gb-spark-burst { 0% { opacity: 0; transform: scale(0); } 35% { opacity: 1; transform: scale(1.6) rotate(60deg); } 100% { opacity: 0; transform: scale(.4) rotate(140deg) translateY(-4px); } }

/* motion off — keep the meaning (open = lid lifted), drop the movement */
@media (prefers-reduced-motion: reduce) {
  .rmp-gift *, .rmp-gift svg { animation: none !important; transition: none !important; }
  .rmp-gift .gb-spark, .rmp-gift .gb-ring { opacity: 0 !important; }
}
.rmp[data-motion="false"] .rmp-gift *, .rmp[data-motion="false"] .rmp-gift svg, .rmp--still .rmp-gift *, .rmp--still .rmp-gift svg { animation: none !important; transition: none !important; }
.rmp[data-motion="false"] .rmp-gift .gb-spark, .rmp[data-motion="false"] .rmp-gift .gb-ring, .rmp--still .rmp-gift .gb-spark, .rmp--still .rmp-gift .gb-ring { opacity: 0 !important; }

/* Rimaya perfume launcher — the flacon and its motion
   (docs/POCKET_V5_DISCOVERY_CONTRACT.md §6). The art is built by
   scripts/art/perfume/build.py; every anchor (the nozzle, the cap's seat, the
   juice line) is written into the SVG as an inline transform-origin, so this
   file only says how things move.

   States are classes on .rmp-gift, exactly as the gift box has them:
     .is-idle      a 10s loop, still most of the time: the juice line drifts, two
                   bubbles rise, light runs down the glass, the cap catches a glint
     :hover        the cap lifts off its seat and the light runs once
     .is-open      the cap floats above the pump, the bottle glows
     .is-receive   a product landed: the bottle bounces, the juice sloshes, bubbles
     .is-hint      the cap lifts, the pump presses, a puff of mist and two gold
     .is-related   scent trails rise from the nozzle
     .is-unlock    the cap pops, a big spray, sparkles, a gold ring, the glass flashes
   The juice level follows --rm-p (0..1, set by the runtime on .rmp-gift), from
   a 30% floor; it rises with a little overshoot when a product lands.
   Under prefers-reduced-motion, or when the merchant turns motion off, it is a
   still product shot with the level still honest. */

.rmp-gift.rmp-gift--perfume { width: 100%; height: 100%; }
/* The cap swings aside toward the reading end: the count badge holds the
   reading-start corner (pocket.css .rmp-badge). */
.rmp-gift--perfume { --pf-side: 1; }
.rmp[dir="rtl"] .rmp-gift--perfume { --pf-side: -1; }
.rmp-gift--perfume > svg { overflow: visible; }
/* the gift box's own wiggles must not reach this art */
.rmp-gift.rmp-gift--perfume.is-hint > svg,
.rmp-gift.rmp-gift--perfume.is-related > svg { animation: none; }

.rmp-gift--perfume .pf-liq,
.rmp-gift--perfume .pf-aura,
.rmp-gift--perfume .pf-floor,
.rmp-gift--perfume .pf-bottle,
.rmp-gift--perfume .pf-pump,
.rmp-gift--perfume .pf-cap { transform-box: view-box; }
.rmp-gift--perfume .pf-mist circle,
.rmp-gift--perfume .pf-drops circle,
.rmp-gift--perfume .pf-bubble,
.rmp-gift--perfume .pf-spark { transform-box: fill-box; transform-origin: 50% 50%; }

/* resting state of everything that only appears in a moment */
.rmp-gift--perfume .pf-glow,
.rmp-gift--perfume .pf-ring,
.rmp-gift--perfume .pf-sweep,
.rmp-gift--perfume .pf-bubble,
.rmp-gift--perfume .pf-mist circle,
.rmp-gift--perfume .pf-drops circle,
.rmp-gift--perfume .pf-spark { opacity: 0; }
.rmp-gift--perfume .pf-glow { transition: opacity .6s ease; }
.rmp-gift--perfume .pf-trail { opacity: 0; stroke-dasharray: 100; stroke-dashoffset: 100; }

/* ---------------------------------------------------------- the juice level */
.rmp-gift--perfume .pf-liq {
  translate: 0 calc((1 - var(--rm-p, 0)) * var(--pf-drop, 26px));
  transition: translate 1.2s cubic-bezier(.3, 1.4, .5, 1);
}
.rmp-gift--perfume.is-idle .pf-liq,
.rmp-gift--perfume.is-open .pf-liq { animation: pf-wave 8s linear infinite; }
@keyframes pf-wave { from { transform: translateX(0); } to { transform: translateX(-14px); } }

/* ----------------------------------------------------------------- idle --- */
.rmp-gift--perfume.is-idle .pf-sweep { animation: pf-sweep 10s cubic-bezier(.45, 0, .25, 1) infinite; }
.rmp-gift--perfume.is-idle .pf-sweep--thin { animation-delay: .12s; }
.rmp-gift--perfume.is-idle .pf-sweep--cap { animation-name: pf-sweep-cap; }
.rmp-gift--perfume.is-idle .pf-bubble:nth-child(1),
.rmp-gift--perfume.is-idle .pf-bubble:nth-child(4) { animation: pf-rise-idle 10s ease-in infinite; animation-delay: var(--d, 0s); }
.rmp-gift--perfume.is-idle .pf-sparks g:first-child .pf-spark { animation: pf-twinkle-idle 10s ease-in-out infinite; }
@keyframes pf-sweep {
  0%, 55% { opacity: 0; transform: translateX(0); }
  57% { opacity: 1; }
  68% { opacity: 1; transform: translateX(104px); }
  69%, 100% { opacity: 0; transform: translateX(104px); }
}
@keyframes pf-sweep-cap {
  0%, 62% { opacity: 0; transform: translateX(0); }
  64% { opacity: 1; }
  71% { opacity: 1; transform: translateX(46px); }
  72%, 100% { opacity: 0; transform: translateX(46px); }
}
@keyframes pf-rise-idle {
  0%, 8% { opacity: 0; transform: none; }
  11% { opacity: .9; }
  40% { opacity: .85; transform: translate(var(--sway, 0), var(--rise, -30px)); }
  42%, 100% { opacity: 0; transform: translate(var(--sway, 0), var(--rise, -30px)); }
}
@keyframes pf-twinkle-idle {
  0%, 68% { opacity: 0; transform: scale(0) rotate(0); }
  71% { opacity: 1; transform: scale(1) rotate(45deg); }
  75%, 100% { opacity: 0; transform: scale(0) rotate(90deg); }
}

/* ---------------------------------------------------------------- hover --- */
.rmp-gift--perfume .pf-cap { transition: transform .55s cubic-bezier(.34, 1.4, .64, 1); }
.rmp-gift--perfume .pf-seat { transition: opacity .3s ease; }
.rmp-launcher:hover .rmp-gift--perfume:not(.is-open) .pf-cap,
.rmp-launcher:focus-visible .rmp-gift--perfume:not(.is-open) .pf-cap { transform: translateY(-3px) rotate(-3deg); }
.rmp-launcher:hover .rmp-gift--perfume:not(.is-open) .pf-sweep { animation: pf-sweep-once .9s cubic-bezier(.45, 0, .25, 1) 1; }
.rmp-launcher:hover .rmp-gift--perfume:not(.is-open) .pf-sweep--cap { animation-name: pf-sweep-cap-once; }
@keyframes pf-sweep-once { 0% { opacity: 0; transform: translateX(0); } 15% { opacity: 1; } 90% { opacity: 1; } 100% { opacity: 0; transform: translateX(104px); } }
@keyframes pf-sweep-cap-once { 0% { opacity: 0; transform: translateX(0); } 15% { opacity: 1; } 90% { opacity: 1; } 100% { opacity: 0; transform: translateX(46px); } }

/* ----------------------------------------------------------------- open --- */
.rmp-gift--perfume.is-open .pf-cap { transform: translate(calc(var(--pf-side) * 20px), -9px) rotate(calc(var(--pf-side) * 22deg)); }
.rmp-gift--perfume.is-open .pf-seat { opacity: 0; }
.rmp-gift--perfume.is-open .pf-cap-float { animation: pf-bob 3.2s ease-in-out .5s infinite; }
.rmp-gift--perfume.is-open .pf-glow { opacity: .45; }
.rmp-gift--perfume.is-open .pf-sparks g:nth-child(3) .pf-spark,
.rmp-gift--perfume.is-open .pf-sparks g:nth-child(4) .pf-spark { animation: pf-twinkle 3.6s ease-in-out infinite; animation-delay: calc(var(--d, 0s) * 4); }
@keyframes pf-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-1.6px); } }

/* -------------------------------------------------------------- receive --- */
.rmp-gift--perfume.is-receive .pf-bottle { animation: pf-squash .75s cubic-bezier(.3, 1.4, .5, 1) 1; }
.rmp-gift--perfume.is-receive .pf-floor { animation: pf-floor .75s ease-out 1; }
.rmp-gift--perfume.is-receive .pf-liq { animation: pf-slosh 1.4s ease-out 1; }
.rmp-gift--perfume.is-receive .pf-bubble { animation: pf-rise-fast 1.2s ease-in 1 both; animation-delay: calc(.1s + var(--d, 0s) * .6); }
@keyframes pf-squash {
  0% { transform: none; }
  22% { transform: scale(1.05, .93); }
  48% { transform: scale(.97, 1.04); }
  72% { transform: scale(1.01, .99); }
  100% { transform: none; }
}
@keyframes pf-floor { 22% { transform: scaleX(1.08); } 48% { transform: scaleX(.96); } }
@keyframes pf-slosh {
  0% { rotate: 0deg; scale: 1 1; }
  14% { rotate: -6deg; scale: 1 2.4; }
  32% { rotate: 4.5deg; scale: 1 2; }
  52% { rotate: -2.6deg; scale: 1 1.6; }
  74% { rotate: 1.2deg; scale: 1 1.2; }
  100% { rotate: 0deg; scale: 1 1; }
}
@keyframes pf-rise-fast {
  0% { opacity: 0; transform: none; }
  12% { opacity: .95; }
  85% { opacity: .8; }
  100% { opacity: 0; transform: translate(var(--sway, 0), var(--rise, -30px)); }
}

/* -------------------------------------------------------- hint / related --- */
/* hint: the bubble is up for seconds, so the whole ritual plays — the cap swings
   aside, the pump presses, a puff of mist, three gold scent trails, sparkles,
   and the cap comes home only once the trails have faded. */
.rmp-gift--perfume.is-hint .pf-cap { animation: pf-cap-lift 2.6s cubic-bezier(.3, .9, .3, 1) 1; }
.rmp-gift--perfume.is-hint .pf-seat { animation: pf-seat 2.6s ease 1; }
.rmp-gift--perfume.is-hint .pf-pump { animation: pf-press 2.6s ease-in-out 1; }
.rmp-gift--perfume.is-hint .pf-bottle { animation: pf-dip 2.6s ease-in-out 1; }
.rmp-gift--perfume.is-hint .pf-mist circle { animation: pf-mist 1.5s cubic-bezier(.15, .7, .3, 1) 1 both; animation-delay: calc(.48s + var(--d, 0s)); }
.rmp-gift--perfume.is-hint .pf-drops circle { animation: pf-drop .9s cubic-bezier(.1, .8, .3, 1) 1 both; animation-delay: calc(.48s + var(--d, 0s)); }
.rmp-gift--perfume.is-hint .pf-trail { animation: pf-trail 1.45s ease-out .6s 1 both; }
.rmp-gift--perfume.is-hint .pf-trail--2 { animation-delay: .7s; }
.rmp-gift--perfume.is-hint .pf-trail--3 { animation-delay: .8s; }
.rmp-gift--perfume.is-hint .pf-sparks g:nth-child(-n+5) .pf-spark { animation: pf-twinkle 1s ease-in-out 1 both; animation-delay: calc(.7s + var(--d, 0s) * 1.5); }
/* related: the runtime holds this class for 1.6s, so it is a short spritz. */
.rmp-gift--perfume.is-related .pf-cap { animation: pf-cap-spritz 1.6s cubic-bezier(.3, .9, .3, 1) 1; }
.rmp-gift--perfume.is-related .pf-seat { animation: pf-seat 1.6s ease 1; }
.rmp-gift--perfume.is-related .pf-pump { animation: pf-press-quick 1.6s ease-in-out 1; }
.rmp-gift--perfume.is-related .pf-mist circle { animation: pf-mist .95s cubic-bezier(.15, .7, .3, 1) 1 both; animation-delay: calc(.46s + var(--d, 0s) * .6); }
.rmp-gift--perfume.is-related .pf-drops circle { animation: pf-drop .7s cubic-bezier(.1, .8, .3, 1) 1 both; animation-delay: calc(.46s + var(--d, 0s) * .6); }
.rmp-gift--perfume.is-related .pf-sparks g:nth-child(-n+4) .pf-spark { animation: pf-twinkle .8s ease-in-out 1 both; animation-delay: calc(.55s + var(--d, 0s)); }
@keyframes pf-seat { 0%, 3% { opacity: 1; } 9%, 86% { opacity: 0; } 94%, 100% { opacity: 1; } }
@keyframes pf-cap-lift {
  0% { transform: none; }
  5% { transform: translate(calc(var(--pf-side) * 1px), -9px) rotate(calc(var(--pf-side) * 4deg)); }
  11% { transform: translate(calc(var(--pf-side) * 21px), -7px) rotate(calc(var(--pf-side) * 26deg)); }
  15% { transform: translate(calc(var(--pf-side) * 19.5px), -6px) rotate(calc(var(--pf-side) * 22deg)); }
  80% { transform: translate(calc(var(--pf-side) * 20px), -7px) rotate(calc(var(--pf-side) * 24deg)); }
  89% { transform: translate(calc(var(--pf-side) * 1px), -6px) rotate(calc(var(--pf-side) * 2deg)); }
  94% { transform: translate(0, .7px); }
  97% { transform: translate(0, -.8px); }
  100% { transform: none; }
}
@keyframes pf-cap-spritz {
  0% { transform: none; }
  10% { transform: translate(calc(var(--pf-side) * 1px), -8px) rotate(calc(var(--pf-side) * 4deg)); }
  20% { transform: translate(calc(var(--pf-side) * 19px), -6px) rotate(calc(var(--pf-side) * 24deg)); }
  26% { transform: translate(calc(var(--pf-side) * 18px), -5.5px) rotate(calc(var(--pf-side) * 21deg)); }
  72% { transform: translate(calc(var(--pf-side) * 18.5px), -6px) rotate(calc(var(--pf-side) * 22deg)); }
  86% { transform: translate(calc(var(--pf-side) * 1px), -5px) rotate(calc(var(--pf-side) * 2deg)); }
  93% { transform: translate(0, .6px); }
  100% { transform: none; }
}
@keyframes pf-press-quick {
  0%, 25% { transform: none; }
  29% { transform: translateY(1.8px); }
  36%, 100% { transform: none; }
}
@keyframes pf-press {
  0%, 15% { transform: none; }
  18% { transform: translateY(1.8px); }
  23%, 100% { transform: none; }
}
@keyframes pf-dip {
  0%, 15% { transform: none; }
  18% { transform: scale(1.012, .985); }
  24%, 100% { transform: none; }
}
@keyframes pf-mist {
  0% { opacity: 0; transform: translate(0, 0) scale(.15); }
  10% { opacity: .95; }
  55% { opacity: .55; }
  100% { opacity: 0; transform: translate(var(--tx, 0), var(--ty, -12px)) scale(var(--s, 2.5)); }
}
@keyframes pf-drop {
  0% { opacity: 0; transform: translate(0, 0) scale(.5); }
  12% { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--tx, 0), var(--ty, -20px)) scale(1); }
}
@keyframes pf-trail {
  0% { opacity: 0; stroke-dashoffset: 100; transform: none; }
  12% { opacity: 1; }
  58% { opacity: .95; stroke-dashoffset: 0; }
  100% { opacity: 0; stroke-dashoffset: 0; transform: translateY(-7px); }
}
@keyframes pf-twinkle {
  0% { opacity: 0; transform: scale(0) rotate(0); }
  40% { opacity: 1; transform: scale(1.15) rotate(45deg); }
  100% { opacity: 0; transform: scale(0) rotate(100deg); }
}

/* --------------------------------------------------------------- unlock --- */
.rmp-gift--perfume.is-unlock .pf-bottle { animation: pf-hop 1.3s cubic-bezier(.3, 1.2, .5, 1) 1; }
.rmp-gift--perfume.is-unlock .pf-floor { animation: pf-floor-hop 1.3s ease-out 1; }
.rmp-gift--perfume.is-unlock .pf-liq { animation: pf-slosh 1.6s ease-out .15s 1; }
.rmp-gift--perfume.is-unlock .pf-cap { animation: pf-cap-pop 2.4s cubic-bezier(.3, .9, .3, 1) 1; }
.rmp-gift--perfume.is-unlock .pf-pump { animation: pf-press-twice 2.4s ease-in-out 1; }
.rmp-gift--perfume.is-unlock .pf-mist circle { animation: pf-mist-big 1.8s cubic-bezier(.15, .7, .3, 1) 1 both; animation-delay: calc(.62s + var(--d, 0s)); }
.rmp-gift--perfume.is-unlock .pf-drops circle { animation: pf-drop-big 1.1s cubic-bezier(.1, .8, .3, 1) 1 both; animation-delay: calc(.62s + var(--d, 0s)); }
.rmp-gift--perfume.is-unlock .pf-trail { animation: pf-trail 1.4s ease-out .66s 1 both; }
.rmp-gift--perfume.is-unlock .pf-seat { animation: pf-seat 2.4s ease 1; }
.rmp-gift--perfume.is-unlock .pf-trail--2 { animation-delay: .76s; }
.rmp-gift--perfume.is-unlock .pf-trail--3 { animation-delay: .86s; }
.rmp-gift--perfume.is-unlock .pf-spark { animation: pf-twinkle 1.1s ease-in-out 1 both; animation-delay: calc(.55s + var(--d, 0s) * 1.8); }
.rmp-gift--perfume.is-unlock .pf-ring { animation: pf-ring 1.2s cubic-bezier(.2, .7, .3, 1) .5s 1 both; }
.rmp-gift--perfume.is-unlock .pf-glow { animation: pf-glow 2.2s ease-out .3s 1 both; }
.rmp-gift--perfume.is-unlock .pf-sweep { animation: pf-sweep-once 1s cubic-bezier(.45, 0, .25, 1) .4s 1 both; }
.rmp-gift--perfume.is-unlock .pf-sweep--cap { animation-name: pf-sweep-cap-once; }
@keyframes pf-hop {
  0% { transform: none; }
  14% { transform: scale(1.06, .92); }
  32% { transform: translateY(-6px) scale(.96, 1.05); }
  50% { transform: translateY(0) scale(1.05, .94); }
  66% { transform: scale(.98, 1.02); }
  100% { transform: none; }
}
@keyframes pf-floor-hop { 14% { transform: scaleX(1.1); } 32% { transform: scaleX(.8); opacity: .6; } 50% { transform: scaleX(1.08); } }
@keyframes pf-cap-pop {
  0%, 8% { transform: none; }
  18% { transform: translate(calc(var(--pf-side) * 4px), -26px) rotate(calc(var(--pf-side) * -30deg)); }
  27% { transform: translate(calc(var(--pf-side) * 18px), -20px) rotate(calc(var(--pf-side) * 40deg)); }
  34% { transform: translate(calc(var(--pf-side) * 23px), -9px) rotate(calc(var(--pf-side) * 28deg)); }
  40% { transform: translate(calc(var(--pf-side) * 22px), -8px) rotate(calc(var(--pf-side) * 24deg)); }
  84% { transform: translate(calc(var(--pf-side) * 22px), -8px) rotate(calc(var(--pf-side) * 25deg)); }
  92% { transform: translate(calc(var(--pf-side) * 1px), -6px) rotate(calc(var(--pf-side) * 2deg)); }
  96% { transform: translate(0, .8px); }
  98% { transform: translate(0, -.6px); }
  100% { transform: none; }
}
@keyframes pf-press-twice {
  0%, 25% { transform: none; }
  29% { transform: translateY(1.8px); }
  34% { transform: none; }
  40% { transform: translateY(1.8px); }
  45%, 100% { transform: none; }
}
@keyframes pf-mist-big {
  0% { opacity: 0; transform: translate(0, 0) scale(.2); }
  8% { opacity: 1; }
  50% { opacity: .6; }
  100% { opacity: 0; transform: translate(calc(var(--tx, 0) * 1.5), calc(var(--ty, -12px) * 1.6)) scale(calc(var(--s, 2.5) * 1.35)); }
}
@keyframes pf-drop-big {
  0% { opacity: 0; transform: translate(0, 0) scale(.5); }
  10% { opacity: 1; }
  100% { opacity: 0; transform: translate(calc(var(--tx, 0) * 1.4), calc(var(--ty, -20px) * 1.4)) scale(1.1); }
}
@keyframes pf-ring {
  0% { opacity: 0; transform: scale(.55); }
  20% { opacity: .9; }
  100% { opacity: 0; transform: scale(1.25); }
}
@keyframes pf-glow { 0% { opacity: 0; } 25% { opacity: .85; } 100% { opacity: 0; } }

/* --------------------------------------------------------- motion off --- */
@media (prefers-reduced-motion: reduce) {
  .rmp-gift--perfume *, .rmp-gift--perfume svg { animation: none !important; transition: none !important; }
  .rmp-gift--perfume .pf-fx, .rmp-gift--perfume .pf-ring, .rmp-gift--perfume .pf-sweep, .rmp-gift--perfume .pf-bubble { opacity: 0 !important; }
}
.rmp[data-motion="false"] .rmp-gift--perfume *, .rmp[data-motion="false"] .rmp-gift--perfume svg,
.rmp--still .rmp-gift--perfume *, .rmp--still .rmp-gift--perfume svg { animation: none !important; transition: none !important; }
.rmp[data-motion="false"] .rmp-gift--perfume .pf-fx, .rmp[data-motion="false"] .rmp-gift--perfume .pf-ring,
.rmp[data-motion="false"] .rmp-gift--perfume .pf-sweep, .rmp[data-motion="false"] .rmp-gift--perfume .pf-bubble,
.rmp--still .rmp-gift--perfume .pf-fx, .rmp--still .rmp-gift--perfume .pf-ring,
.rmp--still .rmp-gift--perfume .pf-sweep, .rmp--still .rmp-gift--perfume .pf-bubble { opacity: 0 !important; }

/* Rimaya shopping-bag launcher — the bag and its motion
   (docs/POCKET_V5_DISCOVERY_CONTRACT.md §6.2). Built by scripts/art/bag/build.py;
   every pivot is an inline transform-origin in the SVG, so this file only says
   how things move. The paper takes the store's accent through the SVG's own
   multiply filter (`--bag-color`, else `--rmp-accent`).

   States are classes on .rmp-gift, exactly as the gift box has them:
     .is-idle      a 10s loop, still most of the time: the handles sway, the tag
                   swings, the tissue breathes, light runs across the paper
     :hover        the handle lifts, the tissue peeks a little higher
     .is-open      the tissue stands up out of the bag, a warm glow
     .is-receive   something dropped in: the bag dips, the tissue bounces
     .is-hint      the bag hops and leans in, the tissue pops, the tag twirls
     .is-related   a short version of the hint (the runtime holds it 1.6s)
     .is-unlock    the tissue launches, confetti in the store's colour and gold,
                   a ring, a glow, a flash across the paper, the tag spins
   The tissue's height follows --rm-p (0..1, set by the runtime on .rmp-gift):
   it barely peeks out at 0 and stands tall at 1.
   Under reduced motion, or when the merchant turns motion off, it is still. */

.rmp-gift.rmp-gift--bag { width: 100%; height: 100%; }
.rmp-gift--bag > svg { overflow: visible; }
.rmp-gift.rmp-gift--bag.is-hint > svg,
.rmp-gift.rmp-gift--bag.is-related > svg { animation: none; }

.rmp-gift--bag .bg-aura,
.rmp-gift--bag .bg-shadow,
.rmp-gift--bag .bg-bag,
.rmp-gift--bag .bg-handle,
.rmp-gift--bag .bg-handle-back,
.rmp-gift--bag .bg-tag,
.rmp-gift--bag .bg-tag-spin,
.rmp-gift--bag .bg-tissue,
.rmp-gift--bag .bg-rustle { transform-box: view-box; }
.rmp-gift--bag .bg-confetti > *,
.rmp-gift--bag .bg-spark { transform-box: fill-box; transform-origin: 50% 50%; }

.rmp-gift--bag .bg-glow,
.rmp-gift--bag .bg-ring,
.rmp-gift--bag .bg-sweep,
.rmp-gift--bag .bg-confetti > *,
.rmp-gift--bag .bg-spark { opacity: 0; }
.rmp-gift--bag .bg-glow { transition: opacity .6s ease; }

/* ---------------------------------------------------------- the tissue --- */
.rmp-gift--bag .bg-tissue {
  translate: 0 calc((1 - var(--rm-p, 0)) * var(--bg-rise, 14px));
  transition: translate 1.1s cubic-bezier(.3, 1.45, .5, 1);
}

/* ----------------------------------------------------------------- idle --- */
.rmp-gift--bag.is-idle .bg-handle { animation: bg-sway 10s ease-in-out infinite; }
.rmp-gift--bag.is-idle .bg-handle-back { animation: bg-sway-back 10s ease-in-out infinite; }
.rmp-gift--bag.is-idle .bg-tag { animation: bg-tag-swing 10s ease-in-out infinite; }
.rmp-gift--bag.is-idle .bg-rustle { animation: bg-breathe 10s ease-in-out infinite; }
.rmp-gift--bag.is-idle .bg-sweep { animation: bg-sweep 10s cubic-bezier(.45, 0, .25, 1) infinite; }
.rmp-gift--bag.is-idle .bg-sparks g:first-child .bg-spark { animation: bg-twinkle-idle 10s ease-in-out infinite; }
@keyframes bg-sway {
  0%, 52%, 100% { transform: none; }
  56% { transform: rotate(-3deg) scaleY(.97); }
  61% { transform: rotate(2deg); }
  66% { transform: rotate(-1deg); }
  71% { transform: none; }
}
@keyframes bg-sway-back {
  0%, 54%, 100% { transform: none; }
  58% { transform: rotate(2deg); }
  64% { transform: rotate(-1.4deg); }
  70% { transform: none; }
}
@keyframes bg-tag-swing {
  0%, 53%, 100% { transform: none; }
  57% { transform: rotate(3deg); }
  62% { transform: rotate(-2.2deg); }
  67% { transform: rotate(1.2deg); }
  72% { transform: none; }
}
@keyframes bg-breathe {
  0%, 30%, 100% { transform: none; }
  36% { transform: translateY(-1.2px) scale(1.01, 1.02); }
  42% { transform: none; }
}
@keyframes bg-sweep {
  0%, 74% { opacity: 0; transform: translateX(0); }
  76% { opacity: 1; }
  86% { opacity: 1; transform: translateX(96px); }
  87%, 100% { opacity: 0; transform: translateX(96px); }
}
@keyframes bg-twinkle-idle {
  0%, 84% { opacity: 0; transform: scale(0) rotate(0); }
  87% { opacity: 1; transform: scale(1) rotate(45deg); }
  91%, 100% { opacity: 0; transform: scale(0) rotate(90deg); }
}

/* ---------------------------------------------------------------- hover --- */
.rmp-gift--bag .bg-handle { transition: transform .5s cubic-bezier(.34, 1.5, .64, 1); }
.rmp-gift--bag .bg-rustle { transition: transform .5s cubic-bezier(.34, 1.5, .64, 1); }
.rmp-launcher:hover .rmp-gift--bag:not(.is-open) .bg-handle,
.rmp-launcher:focus-visible .rmp-gift--bag:not(.is-open) .bg-handle { transform: translateY(-1.5px) scaleY(1.05); animation: none; }
.rmp-launcher:hover .rmp-gift--bag:not(.is-open) .bg-rustle,
.rmp-launcher:focus-visible .rmp-gift--bag:not(.is-open) .bg-rustle { transform: translateY(-3px); animation: none; }
.rmp-launcher:hover .rmp-gift--bag:not(.is-open) .bg-sweep { animation: bg-sweep-once .9s cubic-bezier(.45, 0, .25, 1) 1; }
@keyframes bg-sweep-once { 0% { opacity: 0; transform: translateX(0); } 15% { opacity: 1; } 90% { opacity: 1; } 100% { opacity: 0; transform: translateX(96px); } }

/* ----------------------------------------------------------------- open --- */
.rmp-gift--bag.is-open .bg-rustle { transform: translateY(-7px) scale(1.04); }
.rmp-gift--bag.is-open .bg-handle { transform: rotate(-4deg) scaleY(.94); }
.rmp-gift--bag.is-open .bg-tag { animation: bg-tag-float 3.4s ease-in-out infinite; }
.rmp-gift--bag.is-open .bg-glow { opacity: .45; }
.rmp-gift--bag.is-open .bg-sparks g:nth-child(3) .bg-spark,
.rmp-gift--bag.is-open .bg-sparks g:nth-child(4) .bg-spark { animation: bg-twinkle 3.6s ease-in-out infinite; animation-delay: calc(var(--d, 0s) * 4); }
@keyframes bg-tag-float { 0%, 100% { transform: rotate(-4deg); } 50% { transform: rotate(5deg); } }

/* -------------------------------------------------------------- receive --- */
.rmp-gift--bag.is-receive .bg-bag { animation: bg-dip .75s cubic-bezier(.3, 1.4, .5, 1) 1; }
.rmp-gift--bag.is-receive .bg-shadow { animation: bg-shadow-press .75s ease-out 1; }
.rmp-gift--bag.is-receive .bg-rustle { animation: bg-bounce .9s cubic-bezier(.3, 1.4, .5, 1) 1; }
.rmp-gift--bag.is-receive .bg-handle { animation: bg-swing 1.2s ease-out 1; }
.rmp-gift--bag.is-receive .bg-tag { animation: bg-tag-flap 1.4s ease-out 1; }
@keyframes bg-dip {
  0% { transform: none; }
  24% { transform: scale(1.04, .94); }
  50% { transform: scale(.98, 1.03); }
  74% { transform: scale(1.01, .99); }
  100% { transform: none; }
}
@keyframes bg-shadow-press { 24% { transform: scaleX(1.08); } 50% { transform: scaleX(.97); } }
@keyframes bg-bounce {
  0% { transform: none; }
  20% { transform: translateY(3px) scaleY(.95); }
  48% { transform: translateY(-4px) scaleY(1.04); }
  72% { transform: translateY(1px); }
  100% { transform: none; }
}
@keyframes bg-swing {
  0% { transform: none; }
  18% { transform: rotate(-5deg) scaleY(.93); }
  40% { transform: rotate(4deg); }
  62% { transform: rotate(-2deg); }
  82% { transform: rotate(1deg); }
  100% { transform: none; }
}
@keyframes bg-tag-flap {
  0% { transform: none; }
  16% { transform: rotate(16deg); }
  36% { transform: rotate(-12deg); }
  56% { transform: rotate(7deg); }
  76% { transform: rotate(-3deg); }
  100% { transform: none; }
}

/* -------------------------------------------------------- hint / related --- */
.rmp-gift--bag.is-hint .bg-bag { animation: bg-hop 2.2s cubic-bezier(.3, 1.2, .5, 1) 1; }
.rmp-gift--bag.is-hint .bg-shadow { animation: bg-shadow-hop 2.2s ease-out 1; }
.rmp-gift--bag.is-hint .bg-rustle { animation: bg-pop 2.2s cubic-bezier(.3, 1.3, .5, 1) 1; }
.rmp-gift--bag.is-hint .bg-handle { animation: bg-swing 1.4s ease-out .25s 1; }
.rmp-gift--bag.is-hint .bg-handle-back { animation: bg-sway-back 2.2s ease-out 1; }
.rmp-gift--bag.is-hint .bg-tag-spin { animation: bg-twirl 1.3s cubic-bezier(.3, .8, .4, 1) .35s 1; }
.rmp-gift--bag.is-hint .bg-sparks g:nth-child(-n+4) .bg-spark { animation: bg-twinkle 1s ease-in-out 1 both; animation-delay: calc(.55s + var(--d, 0s) * 1.6); }
.rmp-gift--bag.is-related .bg-bag { animation: bg-hop 1.5s cubic-bezier(.3, 1.2, .5, 1) 1; }
.rmp-gift--bag.is-related .bg-shadow { animation: bg-shadow-hop 1.5s ease-out 1; }
.rmp-gift--bag.is-related .bg-rustle { animation: bg-pop 1.5s cubic-bezier(.3, 1.3, .5, 1) 1; }
.rmp-gift--bag.is-related .bg-handle { animation: bg-swing 1.2s ease-out .2s 1; }
.rmp-gift--bag.is-related .bg-tag { animation: bg-tag-flap 1.4s ease-out .15s 1; }
.rmp-gift--bag.is-related .bg-sparks g:nth-child(-n+3) .bg-spark { animation: bg-twinkle .8s ease-in-out 1 both; animation-delay: calc(.4s + var(--d, 0s)); }
@keyframes bg-hop {
  0% { transform: none; }
  10% { transform: scale(1.05, .93); }
  24% { transform: translateY(-7px) rotate(-4deg) scale(.97, 1.04); }
  38% { transform: translateY(0) rotate(-1deg) scale(1.04, .95); }
  50% { transform: rotate(1.5deg); }
  62% { transform: rotate(-.6deg); }
  74%, 100% { transform: none; }
}
@keyframes bg-shadow-hop { 10% { transform: scaleX(1.08); } 24% { transform: scaleX(.78); opacity: .6; } 38% { transform: scaleX(1.06); } 60%, 100% { transform: none; } }
@keyframes bg-pop {
  0%, 12% { transform: none; }
  28% { transform: translateY(-9px) rotate(-3deg) scale(1.04); }
  42% { transform: translateY(-5px) rotate(2deg); }
  56% { transform: translateY(-6px) rotate(-1deg); }
  76% { transform: translateY(1px); }
  88%, 100% { transform: none; }
}
@keyframes bg-twirl {
  0% { transform: none; }
  25% { transform: scaleX(-1) rotate(4deg); }
  50% { transform: scaleX(1) rotate(-3deg); }
  72% { transform: scaleX(-.6); }
  100% { transform: none; }
}
@keyframes bg-twinkle {
  0% { opacity: 0; transform: scale(0) rotate(0); }
  40% { opacity: 1; transform: scale(1.15) rotate(45deg); }
  100% { opacity: 0; transform: scale(0) rotate(100deg); }
}

/* --------------------------------------------------------------- unlock --- */
.rmp-gift--bag.is-unlock .bg-bag { animation: bg-hop 1.6s cubic-bezier(.3, 1.2, .5, 1) 1; }
.rmp-gift--bag.is-unlock .bg-shadow { animation: bg-shadow-hop 1.6s ease-out 1; }
.rmp-gift--bag.is-unlock .bg-rustle { animation: bg-launch 2.4s cubic-bezier(.25, .9, .35, 1) 1; }
.rmp-gift--bag.is-unlock .bg-handle { animation: bg-swing 1.4s ease-out .2s 1; }
.rmp-gift--bag.is-unlock .bg-tag-spin { animation: bg-spin 1.6s cubic-bezier(.3, .8, .4, 1) .3s 1; }
.rmp-gift--bag.is-unlock .bg-confetti > * { animation: bg-confetti 1.9s cubic-bezier(.2, .7, .4, 1) 1 both; animation-delay: calc(.32s + var(--d, 0s)); }
.rmp-gift--bag.is-unlock .bg-spark { animation: bg-twinkle 1.1s ease-in-out 1 both; animation-delay: calc(.5s + var(--d, 0s) * 1.8); }
.rmp-gift--bag.is-unlock .bg-ring { animation: bg-ring 1.2s cubic-bezier(.2, .7, .3, 1) .35s 1 both; }
.rmp-gift--bag.is-unlock .bg-glow { animation: bg-glow 2.2s ease-out .2s 1 both; }
.rmp-gift--bag.is-unlock .bg-sweep { animation: bg-sweep-once 1s cubic-bezier(.45, 0, .25, 1) .45s 1 both; }
@keyframes bg-launch {
  0%, 8% { transform: none; }
  22% { transform: translateY(-20px) rotate(-6deg) scale(1.06); }
  34% { transform: translateY(-16px) rotate(5deg) scale(1.05); }
  48% { transform: translateY(-17px) rotate(-3deg) scale(1.05); }
  64% { transform: translateY(-12px) rotate(2deg); }
  82% { transform: translateY(1px); }
  92% { transform: translateY(-1px); }
  100% { transform: none; }
}
@keyframes bg-spin {
  0% { transform: none; }
  20% { transform: scaleX(-1) rotate(8deg); }
  40% { transform: scaleX(1) rotate(-6deg); }
  60% { transform: scaleX(-1) rotate(3deg); }
  80% { transform: scaleX(.8); }
  100% { transform: none; }
}
@keyframes bg-confetti {
  0% { opacity: 0; transform: translate(0, 0) rotate(0) scale(.4); }
  8% { opacity: 1; }
  38% { opacity: 1; transform: translate(calc(var(--tx, 0) * .8), var(--ty, -30px)) rotate(calc(var(--r, 180deg) * .5)) scale(1); }
  100% { opacity: 0; transform: translate(var(--tx, 0), calc(var(--ty, -30px) + var(--fall, 18px))) rotate(var(--r, 180deg)) scale(.9); }
}
@keyframes bg-ring { 0% { opacity: 0; transform: scale(.55); } 20% { opacity: .9; } 100% { opacity: 0; transform: scale(1.25); } }
@keyframes bg-glow { 0% { opacity: 0; } 25% { opacity: .85; } 100% { opacity: 0; } }

/* --------------------------------------------------------- motion off --- */
@media (prefers-reduced-motion: reduce) {
  .rmp-gift--bag *, .rmp-gift--bag svg { animation: none !important; transition: none !important; }
  .rmp-gift--bag .bg-fx, .rmp-gift--bag .bg-ring, .rmp-gift--bag .bg-sweep { opacity: 0 !important; }
}
.rmp[data-motion="false"] .rmp-gift--bag *, .rmp[data-motion="false"] .rmp-gift--bag svg,
.rmp--still .rmp-gift--bag *, .rmp--still .rmp-gift--bag svg { animation: none !important; transition: none !important; }
.rmp[data-motion="false"] .rmp-gift--bag .bg-fx, .rmp[data-motion="false"] .rmp-gift--bag .bg-ring,
.rmp[data-motion="false"] .rmp-gift--bag .bg-sweep,
.rmp--still .rmp-gift--bag .bg-fx, .rmp--still .rmp-gift--bag .bg-ring,
.rmp--still .rmp-gift--bag .bg-sweep { opacity: 0 !important; }

/* Rimaya dallah launcher — the Arabic coffee pot and its motion
   (docs/POCKET_V5_DISCOVERY_CONTRACT.md §6.3). Built by
   scripts/art/dallah/build.py; every pivot is an inline transform-origin and
   the pour's lift and tilt are custom properties on the SVG, so this file only
   says how things move.

   States are classes on .rmp-gift, exactly as the gift box has them:
     .is-idle      a 10s loop, still most of the time: steam curls off the
                   finjan, light runs across the brass, the lid settles, a glint
     :hover        the lid lifts off its seat
     .is-open      the lid floats above the open pot, steam rises from it, a glow
     .is-receive   the pot hops, the lid clinks, the coffee ripples
     .is-hint      the lid clinks twice, steam puffs from the beak, sparkles
     .is-related   one clink and a puff (the runtime holds it 1.6s)
     .is-unlock    the pot lifts and pours into the finjan, the cup fills,
                   steam, sparkles, a ring and a glow
   The coffee in the finjan follows --rm-p (0..1, set by the runtime on
   .rmp-gift): low in the cup at 0, up to the gold rim at 1.
   Under reduced motion, or when the merchant turns motion off, it is still. */

.rmp-gift.rmp-gift--dallah { width: 100%; height: 100%; }
.rmp-gift--dallah > svg { overflow: visible; }
.rmp-gift.rmp-gift--dallah.is-hint > svg,
.rmp-gift.rmp-gift--dallah.is-related > svg { animation: none; }

.rmp-gift--dallah .dl-aura,
.rmp-gift--dallah .dl-shadow,
.rmp-gift--dallah .dl-pot,
.rmp-gift--dallah .dl-body,
.rmp-gift--dallah .dl-lid,
.rmp-gift--dallah .dl-cup,
.rmp-gift--dallah .dl-coffee,
.rmp-gift--dallah .dl-fill,
.rmp-gift--dallah .dl-ripple { transform-box: view-box; }
.rmp-gift--dallah .dl-spark { transform-box: fill-box; transform-origin: 50% 50%; }

.rmp-gift--dallah .dl-glow,
.rmp-gift--dallah .dl-ring,
.rmp-gift--dallah .dl-sweep,
.rmp-gift--dallah .dl-ripple,
.rmp-gift--dallah .dl-spark,
.rmp-gift--dallah .dl-stream { opacity: 0; }
.rmp-gift--dallah .dl-glow { transition: opacity .6s ease; }
.rmp-gift--dallah .dl-steam path { opacity: 0; stroke-dasharray: 100; stroke-dashoffset: 100; }
.rmp-gift--dallah .dl-stream { stroke-dasharray: 100; stroke-dashoffset: 100; }

/* ------------------------------------------------------------ the coffee --- */
.rmp-gift--dallah .dl-coffee {
  translate: 0 calc((1 - var(--rm-p, 0)) * var(--dl-drop, 6px));
  scale: calc(1 - (1 - var(--rm-p, 0)) * .22);
  transition: translate 1.1s cubic-bezier(.3, 1.4, .5, 1), scale 1.1s cubic-bezier(.3, 1.4, .5, 1);
}

/* ----------------------------------------------------------------- idle --- */
.rmp-gift--dallah.is-idle .dl-sweep { animation: dl-sweep 10s cubic-bezier(.45, 0, .25, 1) infinite; }
.rmp-gift--dallah.is-idle .dl-steam--cup path { animation: dl-steam-idle 10s ease-out infinite; }
.rmp-gift--dallah.is-idle .dl-steam--cup path:nth-child(2) { animation-delay: .7s; }
.rmp-gift--dallah.is-idle .dl-lid { animation: dl-settle 10s ease-in-out infinite; }
.rmp-gift--dallah.is-idle .dl-sparks g:first-child .dl-spark { animation: dl-twinkle-idle 10s ease-in-out infinite; }
@keyframes dl-sweep {
  0%, 56% { opacity: 0; transform: translateX(0); }
  58% { opacity: 1; }
  70% { opacity: 1; transform: translateX(84px); }
  71%, 100% { opacity: 0; transform: translateX(84px); }
}
@keyframes dl-steam-idle {
  0%, 12% { opacity: 0; stroke-dashoffset: 100; transform: none; }
  18% { opacity: .9; }
  32% { opacity: .7; stroke-dashoffset: 0; }
  44%, 100% { opacity: 0; stroke-dashoffset: 0; transform: translateY(-6px); }
}
@keyframes dl-settle {
  0%, 82%, 100% { transform: none; }
  84% { transform: translateY(-1.2px) rotate(-2deg); }
  86% { transform: none; }
  87.5% { transform: translateY(-.5px) rotate(1deg); }
  89% { transform: none; }
}
@keyframes dl-twinkle-idle {
  0%, 66% { opacity: 0; transform: scale(0) rotate(0); }
  69% { opacity: 1; transform: scale(1) rotate(45deg); }
  73%, 100% { opacity: 0; transform: scale(0) rotate(90deg); }
}

/* ---------------------------------------------------------------- hover --- */
.rmp-gift--dallah .dl-lid { transition: transform .5s cubic-bezier(.34, 1.5, .64, 1); }
.rmp-launcher:hover .rmp-gift--dallah:not(.is-open) .dl-lid,
.rmp-launcher:focus-visible .rmp-gift--dallah:not(.is-open) .dl-lid { transform: translateY(-3px) rotate(-4deg); animation: none; }
.rmp-launcher:hover .rmp-gift--dallah:not(.is-open) .dl-sweep { animation: dl-sweep-once .9s cubic-bezier(.45, 0, .25, 1) 1; }
@keyframes dl-sweep-once { 0% { opacity: 0; transform: translateX(0); } 15% { opacity: 1; } 90% { opacity: 1; } 100% { opacity: 0; transform: translateX(84px); } }

/* ----------------------------------------------------------------- open --- */
.rmp-gift--dallah.is-open .dl-lid { transform: translate(-3px, -11px) rotate(-14deg); }
.rmp-gift--dallah.is-open .dl-glow { opacity: .45; }
.rmp-gift--dallah.is-open .dl-steam--mouth path { animation: dl-steam-loop 3.4s ease-out .4s infinite; }
.rmp-gift--dallah.is-open .dl-steam--mouth path:nth-child(2) { animation-delay: 2.1s; }
@keyframes dl-steam-loop {
  0% { opacity: 0; stroke-dashoffset: 100; transform: none; }
  15% { opacity: .85; }
  50% { opacity: .65; stroke-dashoffset: 0; }
  100% { opacity: 0; stroke-dashoffset: 0; transform: translateY(-7px); }
}

/* -------------------------------------------------------------- receive --- */
.rmp-gift--dallah.is-receive .dl-body { animation: dl-hop .7s cubic-bezier(.3, 1.4, .5, 1) 1; }
.rmp-gift--dallah.is-receive .dl-shadow { animation: dl-shadow-press .7s ease-out 1; }
.rmp-gift--dallah.is-receive .dl-lid { animation: dl-clink .7s ease-out .08s 1; }
.rmp-gift--dallah.is-receive .dl-ripple { animation: dl-ripple 1s ease-out .15s 1; }
@keyframes dl-hop {
  0% { transform: none; }
  22% { transform: scale(1.04, .94); }
  46% { transform: translateY(-3px) scale(.98, 1.03); }
  70% { transform: scale(1.01, .99); }
  100% { transform: none; }
}
@keyframes dl-shadow-press { 22% { transform: scaleX(1.07); } 46% { transform: scaleX(.92); } }
@keyframes dl-clink {
  0% { transform: none; }
  18% { transform: translateY(-2.6px) rotate(-5deg); }
  34% { transform: translateY(0) rotate(1deg); }
  48% { transform: translateY(-1px) rotate(2.5deg); }
  64% { transform: none; }
  78% { transform: translateY(-.4px) rotate(-1deg); }
  100% { transform: none; }
}
@keyframes dl-ripple { 0% { opacity: .9; transform: scale(.2); } 100% { opacity: 0; transform: scale(1.9); } }

/* -------------------------------------------------------- hint / related --- */
.rmp-gift--dallah.is-hint .dl-lid { animation: dl-clink-twice 1.6s ease-out 1; }
.rmp-gift--dallah.is-hint .dl-body { animation: dl-nod 1.6s ease-in-out 1; }
.rmp-gift--dallah.is-hint .dl-steam--spout path { animation: dl-puff 2s ease-out .35s 1 both; }
.rmp-gift--dallah.is-hint .dl-steam--spout path:nth-child(2) { animation-delay: .55s; }
.rmp-gift--dallah.is-hint .dl-steam--spout path:nth-child(3) { animation-delay: .75s; }
.rmp-gift--dallah.is-hint .dl-sweep { animation: dl-sweep-once 1s cubic-bezier(.45, 0, .25, 1) .3s 1 both; }
.rmp-gift--dallah.is-hint .dl-sparks g:nth-child(-n+4) .dl-spark { animation: dl-twinkle 1s ease-in-out 1 both; animation-delay: calc(.5s + var(--d, 0s) * 1.6); }
.rmp-gift--dallah.is-related .dl-lid { animation: dl-clink .8s ease-out 1; }
.rmp-gift--dallah.is-related .dl-body { animation: dl-nod 1.2s ease-in-out 1; }
.rmp-gift--dallah.is-related .dl-steam--spout path:nth-child(-n+2) { animation: dl-puff 1.3s ease-out .2s 1 both; }
.rmp-gift--dallah.is-related .dl-steam--spout path:nth-child(2) { animation-delay: .35s; }
.rmp-gift--dallah.is-related .dl-sparks g:nth-child(-n+3) .dl-spark { animation: dl-twinkle .8s ease-in-out 1 both; animation-delay: calc(.35s + var(--d, 0s)); }
@keyframes dl-clink-twice {
  0% { transform: none; }
  9% { transform: translateY(-3px) rotate(-6deg); }
  17% { transform: translateY(0) rotate(1deg); }
  24% { transform: translateY(-1.2px) rotate(2deg); }
  31% { transform: none; }
  40% { transform: translateY(-3.4px) rotate(5deg); }
  48% { transform: translateY(0) rotate(-1deg); }
  55% { transform: translateY(-1px) rotate(-2deg); }
  62%, 100% { transform: none; }
}
@keyframes dl-nod {
  0%, 100% { transform: none; }
  12% { transform: rotate(-2.5deg); }
  26% { transform: rotate(1.5deg); }
  40% { transform: rotate(-2deg); }
  54% { transform: rotate(1deg); }
  68% { transform: none; }
}
@keyframes dl-puff {
  0% { opacity: 0; stroke-dashoffset: 100; transform: none; }
  14% { opacity: .95; }
  48% { opacity: .75; stroke-dashoffset: 0; }
  100% { opacity: 0; stroke-dashoffset: 0; transform: translateY(-8px); }
}
@keyframes dl-twinkle {
  0% { opacity: 0; transform: scale(0) rotate(0); }
  40% { opacity: 1; transform: scale(1.15) rotate(45deg); }
  100% { opacity: 0; transform: scale(0) rotate(100deg); }
}

/* --------------------------------------------------------------- unlock --- */
/* the pour: the pot lifts and tilts about its belly so the beak is over the
   finjan, the stream runs, the cup fills, then the pot sets down */
.rmp-gift--dallah.is-unlock .dl-pot { animation: dl-pour 2.5s cubic-bezier(.4, 0, .25, 1) 1; }
.rmp-gift--dallah.is-unlock .dl-lid { animation: dl-clink .7s ease-out 1.95s 1; }
.rmp-gift--dallah.is-unlock .dl-stream { animation: dl-stream 1.3s ease-in-out .55s 1 both; }
.rmp-gift--dallah.is-unlock .dl-fill { animation: dl-fill 1.3s ease-out .7s 1 both; }
.rmp-gift--dallah.is-unlock .dl-ripple { animation: dl-ripple .7s ease-out .75s 2 both; }
.rmp-gift--dallah.is-unlock .dl-cup { animation: dl-cup-catch .5s cubic-bezier(.3, 1.4, .5, 1) .72s 1; }
.rmp-gift--dallah.is-unlock .dl-steam--cup path { animation: dl-puff 1.4s ease-out 1.6s 1 both; }
.rmp-gift--dallah.is-unlock .dl-steam--cup path:nth-child(2) { animation-delay: 1.8s; }
.rmp-gift--dallah.is-unlock .dl-spark { animation: dl-twinkle 1.1s ease-in-out 1 both; animation-delay: calc(1.1s + var(--d, 0s) * 1.8); }
.rmp-gift--dallah.is-unlock .dl-ring { animation: dl-ring 1.2s cubic-bezier(.2, .7, .3, 1) 1.2s 1 both; }
.rmp-gift--dallah.is-unlock .dl-glow { animation: dl-glow 2.2s ease-out .3s 1 both; }
.rmp-gift--dallah.is-unlock .dl-sweep { animation: dl-sweep-once 1s cubic-bezier(.45, 0, .25, 1) .2s 1 both; }
@keyframes dl-pour {
  0% { transform: none; }
  20% { transform: translate(var(--dl-pour-x, 0), var(--dl-pour-y, 0)) rotate(var(--dl-pour-a, 30deg)); }
  25% { transform: translate(var(--dl-pour-x, 0), var(--dl-pour-y, 0)) rotate(calc(var(--dl-pour-a, 30deg) - 3deg)); }
  64% { transform: translate(var(--dl-pour-x, 0), var(--dl-pour-y, 0)) rotate(var(--dl-pour-a, 30deg)); }
  80% { transform: translateY(-2px) rotate(-2deg); }
  88% { transform: translateY(.6px); }
  100% { transform: none; }
}
@keyframes dl-stream {
  0% { opacity: 0; stroke-dashoffset: 100; }
  10% { opacity: 1; }
  40% { opacity: 1; stroke-dashoffset: 0; }
  78% { opacity: 1; stroke-dashoffset: 0; }
  100% { opacity: 0; stroke-dashoffset: -100; }
}
@keyframes dl-fill { 0% { transform: translateY(var(--dl-drop, 6px)) scale(.78); } 100% { transform: none; } }
@keyframes dl-cup-catch { 0% { transform: none; } 30% { transform: scale(1.04, .95); } 60% { transform: scale(.99, 1.02); } 100% { transform: none; } }
@keyframes dl-ring { 0% { opacity: 0; transform: scale(.55); } 20% { opacity: .9; } 100% { opacity: 0; transform: scale(1.25); } }
@keyframes dl-glow { 0% { opacity: 0; } 30% { opacity: .85; } 100% { opacity: 0; } }

/* --------------------------------------------------------- motion off --- */
@media (prefers-reduced-motion: reduce) {
  .rmp-gift--dallah *, .rmp-gift--dallah svg { animation: none !important; transition: none !important; }
  .rmp-gift--dallah .dl-fx, .rmp-gift--dallah .dl-ring, .rmp-gift--dallah .dl-sweep, .rmp-gift--dallah .dl-stream { opacity: 0 !important; }
}
.rmp[data-motion="false"] .rmp-gift--dallah *, .rmp[data-motion="false"] .rmp-gift--dallah svg,
.rmp--still .rmp-gift--dallah *, .rmp--still .rmp-gift--dallah svg { animation: none !important; transition: none !important; }
.rmp[data-motion="false"] .rmp-gift--dallah .dl-fx, .rmp[data-motion="false"] .rmp-gift--dallah .dl-ring,
.rmp[data-motion="false"] .rmp-gift--dallah .dl-sweep, .rmp[data-motion="false"] .rmp-gift--dallah .dl-stream,
.rmp--still .rmp-gift--dallah .dl-fx, .rmp--still .rmp-gift--dallah .dl-ring,
.rmp--still .rmp-gift--dallah .dl-sweep, .rmp--still .rmp-gift--dallah .dl-stream { opacity: 0 !important; }

/* companion theme — prototypes/proposals/team-08 "Cart Aware".
 *
 * Scoped to `.rmp[data-theme="companion"]`. The runtime owns geometry (panel
 * size, placement, the tail, the mobile sheet, the screen track) and the gift
 * box; this file owns every pixel INSIDE the panel plus the panel's own chrome.
 *
 * Tokens are read from the runtime's own set wherever one exists
 * (--rmp-accent, --rmp-accent-ink, --rmp-ink…) so a merchant's accent and the
 * light/dark mode both flow through without a second source of truth. The
 * `--cp-*` block below is team-08's palette expressed on top of them: its
 * surfaces are warmer than the runtime defaults, and its brand colour is the
 * accent the merchant chose. `--rmp-accent` replaces team-08's hard-coded
 * emerald everywhere the original used it.
 */
.rmp[data-theme="companion"] {
/* team-08's warm paper neutrals */ --cp-bg-1: #ffffff;
--cp-bg-2: #f6f5f1;
--cp-bg-3: #efeee8;
--cp-ink-1: #15171a;
--cp-ink-2: #4d5257;
--cp-ink-3: #6b7078;
--cp-line: #e3e2db;
--cp-line-2: #d3d2c9;
--cp-card: #ffffff;
--cp-card-2: #faf9f5;
--cp-shadow: 0 1px 2px rgba(20, 22, 25, 0.06), 0 8px 24px rgba(20, 22, 25, 0.1), 0 24px 60px rgba(20, 22, 25, 0.1);
--cp-shadow-sm: 0 1px 2px rgba(20, 22, 25, 0.07), 0 4px 14px rgba(20, 22, 25, 0.07);
--cp-ok: #1a7f4b;
--cp-ok-soft: color-mix(in srgb, var(--cp-ok) 12%, transparent);
/* the ink that sits ON the ok fill — the green lightens in dark, so a fixed white would fail there */ --cp-on-ok: #ffffff;
--cp-radius: 16px;
/* one panel gutter for the header, the ship row, the chips, the cards and every
   detail section: 16 on a phone, 20 in the desktop popover (restated below) */
--cp-pad: 16px;
--cp-dur: 0.28s;
--cp-ease: cubic-bezier(0.22, 0.72, 0.26, 1);
--cp-font: var(--rmp-font);
/* Feed the runtime's own tokens so anything it styles matches this design. These repeat the `--cp-*` values as literals on purpose: the contrast gate (widget-theme-contrast) reads the shipped sheet and needs a hex it can resolve, not a `var()` alias. Two names for one colour is the price of a check that can read the file instead of a table. */ --rmp-surface: #ffffff;
--rmp-surface-2: #f6f5f1;
--rmp-card: #ffffff;
--rmp-line: #e3e2db;
--rmp-card-line: #e3e2db;
--rmp-ink: #15171a;
--rmp-ink-2: #4d5257;
/* The terms are body copy a shopper consents to, so they carry their own ink: AA on this theme's own three surfaces. Never the headline ink. */ --rmp-ink-terms: #3f4449;
--rmp-track: #efeee8;
--rmp-success: #1a7f4b;
--rmp-shadow: var(--cp-shadow);
/* the panel corners are one step rounder than the cards inside it */
--rmp-radius: 20px;
--rmp-radius-card: var(--cp-radius);
--rmp-radius-sm: 10px;
--rmp-radius-btn: 12px;
--rmp-radius-chip: 8px;
--rmp-meter: 5px;
--rmp-gutter: 16px;
--rmp-ease: var(--cp-ease);
/* Contract §11.3 — the plan's six tokens, and only those: team-08's plan is
   warm paper, a round 16px card and a hairline in its own warm grey. */
--rmp-plan-radius: 16px;
--rmp-plan-surface: var(--cp-card-2);
--rmp-plan-line: var(--cp-line);
--rmp-plan-tint: color-mix(in srgb, var(--rmp-accent) 7%, var(--cp-card-2));
--rmp-plan-ink: var(--cp-ink-1);
--rmp-plan-muted: var(--cp-ink-2);
}
.rmp[data-theme="companion"][data-mode="dark"] {
--cp-bg-1: #141517;
--cp-bg-2: #1b1d20;
--cp-bg-3: #232629;
--cp-ink-1: #f2f2ef;
--cp-ink-2: #b7bcc1;
--cp-ink-3: #878d94;
--cp-line: #2c2f33;
--cp-line-2: #3a3e43;
--cp-card: #1c1e21;
--cp-card-2: #222528;
--cp-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.45), 0 30px 70px rgba(0, 0, 0, 0.45);
--cp-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 6px 18px rgba(0, 0, 0, 0.35);
--cp-ok: #4ec98a;
--cp-ok-soft: color-mix(in srgb, var(--cp-ok) 16%, transparent);
--cp-on-ok: #0e1a14;
/* the same names, resolved for the dark surfaces — literals for the same reason as the light block above (the contrast gate reads the sheet) */ --rmp-surface: #141517;
--rmp-surface-2: #1b1d20;
--rmp-card: #1c1e21;
--rmp-line: #2c2f33;
--rmp-card-line: #2c2f33;
--rmp-ink: #f2f2ef;
--rmp-ink-2: #b7bcc1;
--rmp-ink-terms: #c8ccd1;
--rmp-track: #232629;
--rmp-success: #4ec98a;
/* the plan on dark paper: the same six tokens, read off the dark surfaces */
--rmp-plan-surface: var(--cp-card-2);
--rmp-plan-line: var(--cp-line);
--rmp-plan-tint: color-mix(in srgb, var(--rmp-accent) 13%, var(--cp-card-2));
--rmp-plan-ink: var(--cp-ink-1);
--rmp-plan-muted: var(--cp-ink-2);
}
/* ============================================================== launcher ===
 * team-08's rounded-square tile, in the theme's own paper. The gift art paints
 * its body with `--gb-accent` (the store's accent), so an accent tile would
 * swallow the box and leave only its white ribbon; paper keeps the art whole and
 * matches the other three themes' plate. The open scale is 0.94, not the base's
 * 0.9 — at 0.9 the painted launcher pulls 3px off the screen edge and the tail,
 * which points at the launcher's centre, lands 3px low. The gift itself still
 * tips open (gift-box.css owns that); only the tile answers. */
.rmp[data-theme="companion"] .rmp-launcher {
border-radius: 22px;
border: 1px solid var(--cp-line);
background: var(--cp-card);
color: var(--rmp-accent);
box-shadow: 0 2px 6px rgba(20, 22, 25, 0.08), 0 10px 26px rgba(20, 22, 25, 0.12);
transition: transform var(--cp-dur) var(--cp-ease), box-shadow var(--cp-dur) var(--cp-ease);
}
.rmp[data-theme="companion"] .rmp-launcher:hover {
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.16), 0 16px 34px rgba(0, 0, 0, 0.22);
}
.rmp[data-theme="companion"] .rmp-launcher:active {
transform: translateY(0) scale(0.97);
}
.rmp[data-theme="companion"] .rmp-launcher:focus-visible {
outline: 3px solid var(--rmp-accent);
outline-offset: 3px;
}
.rmp[data-theme="companion"][data-open="true"] .rmp-launcher {
transform: scale(0.94);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}
/* one accent ring on receive — the loudest thing this theme does, 700ms */
.rmp[data-theme="companion"] .rmp-launcher::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
border: 2px solid var(--rmp-accent);
opacity: 0;
pointer-events: none;
}
.rmp[data-theme="companion"] .rmp-launcher:has(.rmp-gift.is-receive)::after {
animation: cp-ring 0.7s var(--cp-ease) both;
}
@keyframes cp-ring {
0% {
opacity: 0.9;
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(1.45);
}
}
/* ========================================================= panel chrome === */
/* the desktop popover breathes one step wider than the sheet */
.rmp[data-theme="companion"][data-device="desktop"] .rmp-head {
padding-inline: 20px;
}
.rmp[data-theme="companion"][data-device="desktop"] .cp-media {
flex-basis: 112px;
width: 112px;
}
.rmp[data-theme="companion"][data-device="desktop"] .cp-card__open {
padding: 12px;
}
.rmp[data-theme="companion"][data-device="desktop"] .rmp-screen {
max-height: calc(var(--rmp-panel-h, var(--rmp-panel-height)) - var(--rmp-head-h) - 2px);
padding-inline: 20px;
}
.rmp[data-theme="companion"][data-device="desktop"] .cp-fs {
margin-inline: -20px;
padding-inline: 20px;
}
.rmp[data-theme="companion"] .rmp-panel {
background: var(--cp-card);
border: 1px solid var(--cp-line);
}
/* one 56px header for the list and the offer screen (decision 5), so the phone
   sheet's scroller budget (`88dvh - head - 16`) lands the action bar exactly on
   the viewport's edge. Colour and the warm paper are this theme's own. */
.rmp[data-theme="companion"] .rmp-head {
height: var(--rmp-head-h);
gap: 8px;
padding-block: 0;
padding-inline: var(--cp-pad);
background: var(--cp-card);
border-bottom: 1px solid var(--cp-line);
border-radius: var(--rmp-radius) var(--rmp-radius) 0 0;
}
.rmp[data-theme="companion"] .rmp-head .cp-head__title {
flex: 1;
min-width: 0;
font: 700 var(--rmp-fs-title)/1.3 var(--cp-font);
color: var(--cp-ink-1);
}
/* one button style in both headers (§9): the contract's 44px tile, a hairline
   and the theme's warm paper inside it */
.rmp[data-theme="companion"] .rmp-head .cp-iconbtn,
.rmp[data-theme="companion"] .rmp-head .rmp-back,
.rmp[data-theme="companion"] .rmp-head .rmp-close {
width: var(--rmp-icon-btn);
height: var(--rmp-icon-btn);
min-width: var(--rmp-icon-btn);
min-height: var(--rmp-icon-btn);
padding: 0;
border-radius: 12px;
border: 1px solid var(--cp-line);
background: var(--cp-card-2);
color: var(--cp-ink-2);
transition: background 150ms var(--cp-ease), color 150ms var(--cp-ease), border-color 150ms var(--cp-ease);
}
.rmp[data-theme="companion"] .rmp-head .cp-iconbtn svg {
width: 18px;
height: 18px;
}
.rmp[data-theme="companion"] .rmp-head .cp-iconbtn:hover {
background: var(--cp-bg-3);
color: var(--cp-ink-1);
}
/* «رجوع» points at the reading start: right in Arabic, left in English. The
   runtime's chevron points right, so RTL mirrors it. */
.rmp[data-theme="companion"][dir="rtl"] .rmp-head .rmp-back svg {
transform: scaleX(-1);
}
/* the close keeps the trailing edge even when the header carries no title */
.rmp[data-theme="companion"] .rmp-head .rmp-close {
margin-inline-start: auto;
}
.rmp[data-theme="companion"] .rmp-screen {
padding: 0 var(--cp-pad) calc(20px + env(safe-area-inset-bottom, 0px));
scrollbar-width: none;
}
.rmp[data-theme="companion"] .rmp-screen::-webkit-scrollbar {
width: 0;
height: 0;
}
/* screens slide in from the inline end, mirrored in RTL — team-08's rail */
.rmp[data-theme="companion"] .rmp-screen--offer,
.rmp[data-theme="companion"] .rmp-screen--list {
animation-duration: 300ms;
}
/* ==================================================== the shipping bar === */
.rmp[data-theme="companion"] .cp-fs {
position: sticky;
top: 0;
z-index: var(--rmp-z-sticky, 2);
margin: 0 calc(-1 * var(--cp-pad)) 8px;
padding: 12px var(--cp-pad) 14px;
background: var(--cp-card);
border-bottom: 1px solid var(--cp-line);
box-shadow: 0 6px 12px -10px rgba(20, 22, 25, 0.35);
}
.rmp[data-theme="companion"] .cp-fs::after {
content: "";
position: absolute;
inset-inline: 0;
top: 100%;
block-size: 20px;
background: linear-gradient(to bottom, var(--cp-card), transparent);
pointer-events: none;
}
.rmp[data-theme="companion"] .cp-fs__top {
display: flex;
align-items: center;
gap: 8px;
}
.rmp[data-theme="companion"] .cp-fs__top .cp-ico {
width: 18px;
height: 18px;
flex: none;
color: var(--rmp-accent);
stroke-width: 1.8;
}
.rmp[data-theme="companion"] .cp-fs__txt {
flex: 1;
min-width: 0;
font: 600 var(--rmp-ship-fs)/1.5 var(--cp-font);
color: var(--cp-ink-2);
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="companion"] .cp-fs__txt b {
color: var(--cp-ink-1);
font-weight: 700;
}
.rmp[data-theme="companion"] .cp-fs__track {
display: block;
height: var(--rmp-ship-track);
margin-top: 8px;
border-radius: 999px;
background: var(--cp-bg-3);
overflow: hidden;
}
.rmp[data-theme="companion"] .cp-fs__fill {
display: block;
height: 100%;
width: 0;
border-radius: 999px;
background: var(--rmp-accent);
transition: width 500ms var(--cp-ease);
}
.rmp[data-theme="companion"] .cp-fs.is-done .cp-fs__txt b {
color: var(--cp-ok);
font-weight: 700;
}
.rmp[data-theme="companion"] .cp-fs.is-done .cp-fs__fill {
background: var(--cp-ok);
}
.rmp[data-theme="companion"] .cp-fs.is-done .cp-fs__top .cp-ico {
color: var(--cp-ok);
}
/* ======================================================= the offer cards === */
.rmp[data-theme="companion"] .cp-cards {
display: flex;
flex-direction: column;
gap: 12px;
padding-bottom: 4px;
}
.rmp[data-theme="companion"] .cp-card {
/* contract §9: a card is its own stacking context, so a badge or a gradient painted over its media can never cross a sticky bar or the header */ position: relative;
isolation: isolate;
display: block;
width: 100%;
text-align: start;
padding: 0;
overflow: hidden;
color: inherit;
background: var(--cp-card);
border: 1px solid var(--cp-line);
border-radius: var(--cp-radius);
box-shadow: var(--cp-shadow-sm);
animation: cp-card-in 300ms var(--cp-ease) backwards;
transition: transform 180ms var(--cp-ease), box-shadow 180ms var(--cp-ease), border-color 180ms var(--cp-ease);
}
@keyframes cp-card-in {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: none;
}
}
.rmp[data-theme="companion"] .cp-card:hover {
transform: translateY(-2px);
border-color: var(--cp-line-2);
box-shadow: var(--cp-shadow);
}
/* v5.1 §D — the card is a wrapper and the open action is its own control, so the
   bookmark sits beside it and never inside another button. The bookmark rides the
   card's top inline-end corner, clear of the photo; the title keeps its room. */
.rmp[data-theme="companion"] .cp-card__open {
display: flex;
align-items: stretch;
gap: 12px;
width: 100%;
padding: 12px;
color: inherit;
border-radius: inherit;
}
.rmp[data-theme="companion"] .cp-card__open:focus-visible {
outline: 2px solid var(--rmp-accent);
outline-offset: -3px;
border-radius: inherit;
}
/* v5.1 §D: the bookmark is a LOCAL layer of its card (z-index 1), never the
   sticky depth — a card that is `isolation: isolate` can then never paint a
   ribbon over the free-shipping bar. */
.rmp[data-theme="companion"] .cp-card > .rmp-save {
position: absolute;
inset-block-start: 6px;
inset-inline-end: 6px;
z-index: 1;
}
/* v5 §5.4 — the related edge: ONE accent hairline, no ring, no badge, no words */
.rmp[data-theme="companion"] .cp-card[data-related="true"] {
border-color: color-mix(in srgb, var(--rmp-accent) 58%, var(--cp-line));
}
/* ONE photo (V-T1): the product whole, on the theme's warm stage. `multiply`
   melts the studio white into the tint, so there is no seam and no second copy
   of the picture behind it. */
.rmp[data-theme="companion"] .cp-media {
position: relative;
isolation: isolate;
flex: 0 0 104px;
width: 104px;
aspect-ratio: 1;
display: grid;
place-items: center;
overflow: hidden;
border-radius: 12px;
background: var(--cp-bg-2);
}
/* `brightness` pushes the studio's near-white to pure white, so the multiply
   lands on the stage colour exactly and the photo has no visible edge. */
.rmp[data-theme="companion"] .cp-media img {
position: absolute;
inset: 0;
display: block;
width: 100%;
height: 100%;
object-fit: contain;
object-position: center;
mix-blend-mode: multiply;
filter: brightness(1.05);
transition: transform 400ms var(--cp-ease);
}
.rmp[data-theme="companion"] .cp-card:hover .cp-media img {
transform: scale(1.03);
}
.rmp[data-theme="companion"] .cp-media.is-mark {
background:
radial-gradient(130% 120% at 50% 28%, color-mix(in srgb, var(--rmp-accent) 16%, transparent), transparent 70%),
var(--cp-bg-2);
}
.rmp[data-theme="companion"] .cp-media__mark {
display: grid;
place-items: center;
color: var(--rmp-accent);
}
.rmp[data-theme="companion"] .cp-media__mark .cp-ico {
width: 34px;
height: 34px;
stroke-width: 1.7;
}
/* On dark paper `multiply` can only darken a white studio shot into a hole, so
   the photo sits on its own white print instead — the same whole product, with
   no seam, because the plate and the studio background are the same white. */
.rmp[data-theme="companion"][data-mode="dark"] .cp-media:not(.is-mark),
.rmp[data-theme="companion"][data-mode="dark"] .cp-hero[data-media="product"] {
background: #ffffff;
}
.rmp[data-theme="companion"][data-mode="dark"] .cp-media img,
.rmp[data-theme="companion"][data-mode="dark"] .cp-hero__img {
mix-blend-mode: normal;
filter: none;
}
/* completed offers read first when scanning */
.rmp[data-theme="companion"] .cp-card.is-done .cp-media img {
filter: saturate(0.9) brightness(0.98);
}
.rmp[data-theme="companion"] .cp-card.is-done .cp-media {
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cp-ok) 40%, transparent);
}
/* the text column, centred against the photo tile */
.rmp[data-theme="companion"] .cp-body {
flex: 1 1 auto;
min-width: 0;
display: flex;
flex-direction: column;
justify-content: center;
gap: 4px;
padding-block: 2px;
}
.rmp[data-theme="companion"] .cp-title {
display: flex;
align-items: center;
gap: 8px;
padding-inline-end: 36px;
font: 700 var(--rmp-fs-card)/1.6 var(--cp-font);
color: var(--cp-ink-1);
}
.rmp[data-theme="companion"] .cp-title b {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
flex: 1;
min-width: 0;
overflow: hidden;
line-height: 1.6;
padding-block: 1px;
text-wrap: pretty;
}
/* the ask, or what the cart still needs — one line, a fact */
.rmp[data-theme="companion"] .cp-nb {
white-space: nowrap;
}
.rmp[data-theme="companion"] .cp-ask {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-inline-end: 36px;
font: 600 var(--rmp-fs-ask)/1.6 var(--cp-font);
color: var(--cp-ink-2);
font-variant-numeric: tabular-nums;
}
/* ONE completion indicator: one slim bar, drawn only once there is progress */
.rmp[data-theme="companion"] .cp-prog {
display: flex;
align-items: center;
gap: 0;
margin-top: 2px;
}
.rmp[data-theme="companion"] .cp-prog__track {
flex: 1;
height: 4px;
border-radius: 999px;
background: var(--cp-bg-3);
overflow: hidden;
}
.rmp[data-theme="companion"] .cp-prog__fill {
display: block;
height: 100%;
width: 0;
border-radius: 999px;
background: var(--rmp-accent);
transition: width 500ms var(--cp-ease);
}
/* completed: one settled line, no chip around a single word */
.rmp[data-theme="companion"] .cp-done {
display: none;
align-items: center;
gap: 6px;
font: 700 var(--rmp-fs-body)/1.6 var(--cp-font);
color: var(--cp-ok);
}
.rmp[data-theme="companion"] .cp-done svg {
flex: none;
}
.rmp[data-theme="companion"] .cp-card.is-done .cp-done {
display: flex;
}
/* ========================================================= empty state === */
.rmp[data-theme="companion"] .cp-empty {
margin-top: 14px;
text-align: center;
padding: 18px 14px 26px;
border: 1px dashed var(--cp-line-2);
border-radius: var(--cp-radius);
background: var(--cp-card-2);
}
.rmp[data-theme="companion"] .cp-empty__art {
display: block;
width: 96px;
height: 96px;
margin: 0 auto 10px;
color: var(--cp-ink-3);
}
.rmp[data-theme="companion"] .cp-empty h3 {
margin: 0 0 4px;
font: 700 16px/1.3 var(--cp-font);
color: var(--cp-ink-1);
}
.rmp[data-theme="companion"] .cp-empty p {
margin: 0;
font: 400 var(--rmp-fs-body)/1.5 var(--cp-font);
color: var(--cp-ink-2);
}
/* The card row is the same shape on a phone and in the popover: the photo is
   the product, and the text sits beside it. Only the tile shrinks a hair. */
.rmp[data-theme="companion"][data-device="mobile"] .cp-media {
flex-basis: 96px;
width: 96px;
}
.rmp[data-theme="companion"][data-device="mobile"] .cp-card__open {
padding: 10px;
gap: 10px;
}
/* ======================================================== the offer page === */
/* V-T2: the product whole, on the theme's own stage, inside a 16px frame — no
   edge strips of a second white and no blurred copy of the same photo. */
.rmp[data-theme="companion"] .cp-hero {
position: relative;
isolation: isolate;
display: grid;
place-items: center;
inline-size: fit-content;
max-inline-size: 100%;
margin: 12px auto 0;
overflow: hidden;
border-radius: var(--cp-radius);
background: var(--cp-bg-2);
box-shadow: inset 0 0 0 1px var(--cp-line);
}
.rmp[data-theme="companion"][data-device="desktop"] .cp-hero {
max-inline-size: min(100%, 320px);
}
.rmp[data-theme="companion"] .cp-hero__img {
position: relative;
z-index: var(--rmp-z-content, 0);
display: block;
inline-size: auto;
block-size: auto;
max-block-size: min(30dvh, 253px);
max-inline-size: none;
object-fit: contain;
object-position: center;
mix-blend-mode: multiply;
filter: brightness(1.05);
}
/* an offer with no product photo shows its reward mark, on the same stage */
.rmp[data-theme="companion"] .cp-hero[data-media="mark"] {
inline-size: 100%;
block-size: 120px;
background:
radial-gradient(120% 130% at 50% 32%, color-mix(in srgb, var(--rmp-accent) 18%, transparent), transparent 72%),
var(--cp-bg-2);
}
.rmp[data-theme="companion"][data-device="desktop"] .cp-hero__img {
max-block-size: 200px;
}
/* A short phone cannot hold the 30dvh plate and the gift's prize plus the terms
   row above the action bar in one paint, so the plate steps DOWN there (never
   up): the «الشروط» row keeps ≥8px of air instead of sliding under the bar. */
@media (max-height: 800px) {
.rmp[data-theme="companion"] .cp-hero__img {
max-block-size: min(26dvh, 200px);
}
}
.rmp[data-theme="companion"] .cp-hero__mark {
display: grid;
place-items: center;
width: 100%;
height: 100%;
color: var(--rmp-accent);
}
.rmp[data-theme="companion"] .cp-hero__mark .cp-ico {
width: 56px;
height: 56px;
padding: 22px;
box-sizing: content-box;
border-radius: 50%;
background: var(--cp-card);
box-shadow: var(--cp-shadow-sm);
stroke-width: 1.4;
}
/* the one noun chip: paper, on the photo's top inline-start corner, far from
   the bookmark in the title row (the hero never carries one) */
.rmp[data-theme="companion"] .cp-hero__kind {
position: absolute;
inset-inline-start: 12px;
top: 12px;
z-index: var(--rmp-z-content, 0);
color: var(--cp-ink-1);
background: color-mix(in srgb, var(--cp-card) 88%, transparent);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
border: 1px solid color-mix(in srgb, var(--cp-line) 60%, transparent);
border-radius: 8px;
padding: 3px 8px;
font: 600 12px/1.5 var(--cp-font);
}
/* v5.1 §B — the labelled bookmark rides the title row, on the trailing edge,
   as a secondary pill: the plan's next step stays the only primary control. */
.rmp[data-theme="companion"] .cp-otop {
display: flex;
align-items: flex-start;
gap: 12px;
margin: 16px 0 0;
}
.rmp[data-theme="companion"] .cp-otop .cp-otitle {
flex: 1;
min-width: 0;
margin: 0;
}
.rmp[data-theme="companion"] .rmp-save--labelled {
flex: none;
border-radius: 12px;
border-color: var(--cp-line);
background: var(--cp-card-2);
color: var(--cp-ink-2);
}
.rmp[data-theme="companion"] .rmp-save--labelled[aria-pressed="true"] {
border-color: transparent;
background: color-mix(in srgb, var(--rmp-accent) 14%, var(--cp-card));
color: var(--rmp-accent-text);
}
.rmp[data-theme="companion"] .rmp-save--labelled::before {
display: none;
}
.rmp[data-theme="companion"] .cp-otitle {
margin: 16px 0 0;
font: 700 var(--rmp-fs-detail)/1.45 var(--cp-font);
color: var(--cp-ink-1);
text-wrap: pretty;
}
.rmp[data-theme="companion"] .cp-odesc {
margin: 6px 0 0;
font: 400 var(--rmp-fs-body)/1.7 var(--cp-font);
color: var(--cp-ink-2);
}
/* section headings — one noun, quiet, and never a rule beside them */
.rmp[data-theme="companion"] .cp-sec {
margin: 24px 0 0;
}
.rmp[data-theme="companion"] .cp-sec__h {
margin: 0 0 8px;
font: 600 var(--rmp-fs-label)/1.4 var(--cp-font);
color: var(--cp-ink-3);
}
/* reward — coupon: locked is a masked placeholder, revealed is the code */
.rmp[data-theme="companion"] .cp-cw {
position: relative;
isolation: isolate;
padding: 13px 14px;
border-radius: var(--cp-radius);
overflow: hidden;
}
.rmp[data-theme="companion"] .cp-cw--locked {
display: grid;
gap: 9px;
border: 1px dashed var(--cp-line-2);
background: var(--cp-card-2);
}
.rmp[data-theme="companion"] .cp-cw__top {
display: flex;
align-items: center;
gap: 9px;
}
.rmp[data-theme="companion"] .cp-cw__lock {
width: 30px;
height: 30px;
flex: none;
display: grid;
place-items: center;
border-radius: 10px;
background: var(--cp-bg-3);
color: var(--cp-ink-3);
}
.rmp[data-theme="companion"] .cp-cw__lock svg {
width: 15px;
height: 15px;
}
.rmp[data-theme="companion"] .cp-cw__t1 {
display: block;
font: 700 16px/1.25 var(--cp-font);
color: var(--cp-ink-1);
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="companion"] .cp-cw__t2 {
display: block;
margin-top: 2px;
font: 400 12px/1.5 var(--cp-font);
color: var(--cp-ink-2);
}
.rmp[data-theme="companion"] .cp-cw__mask {
height: 38px;
display: flex;
align-items: center;
justify-content: center;
border: 1px dashed var(--cp-line-2);
border-radius: 9px;
background: repeating-linear-gradient(90deg, var(--cp-bg-3) 0 8px, transparent 8px 16px);
color: var(--cp-ink-3);
font: 600 12px/1 var(--cp-font);
letter-spacing: 0.06em;
}
.rmp[data-theme="companion"] .cp-cw__unlock {
width: 100%;
min-height: 40px;
border-radius: 10px;
font: 600 13px/1 var(--cp-font);
}
.rmp[data-theme="companion"] .cp-cw--ready {
display: grid;
gap: 9px;
border: 1px solid color-mix(in srgb, var(--cp-ok) 40%, var(--cp-line));
background: linear-gradient(180deg, color-mix(in srgb, var(--cp-ok) 10%, var(--cp-card)), var(--cp-card));
box-shadow: 0 0 0 3px color-mix(in srgb, var(--cp-ok) 12%, transparent);
animation: cp-coupon-in 420ms var(--cp-ease);
}
@keyframes cp-coupon-in {
from {
opacity: 0;
transform: translateY(6px) scale(0.985);
}
to {
opacity: 1;
transform: none;
}
}
.rmp[data-theme="companion"] .cp-cw__hd {
display: flex;
align-items: center;
gap: 7px;
font: 700 12px/1 var(--cp-font);
color: var(--cp-ok);
}
.rmp[data-theme="companion"] .cp-cw__hd svg {
width: 15px;
height: 15px;
flex: none;
}
.rmp[data-theme="companion"] .cp-cw__row {
display: flex;
align-items: center;
gap: 8px;
}
.rmp[data-theme="companion"] .cp-cw__val {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 10px 11px;
background: var(--cp-bg-2);
border: 1px solid var(--cp-line);
border-radius: 10px;
font: 700 16px/1.2 var(--cp-font);
letter-spacing: 0.06em;
color: var(--cp-ink-1);
overflow-wrap: anywhere;
}
.rmp[data-theme="companion"] .cp-cw__copy {
flex: none;
display: inline-flex;
align-items: center;
gap: 6px;
padding: 9px 13px;
border: 1px solid var(--rmp-accent);
border-radius: 10px;
background: var(--rmp-accent);
color: var(--rmp-accent-ink);
font: 600 13px/1.2 var(--cp-font);
transition: filter 150ms var(--cp-ease), transform 150ms var(--cp-ease);
}
.rmp[data-theme="companion"] .cp-cw__copy:hover {
filter: brightness(1.07);
}
.rmp[data-theme="companion"] .cp-cw__copy:active {
transform: scale(0.97);
}
.rmp[data-theme="companion"] .cp-cw__copy svg {
width: 13px;
height: 13px;
}
.rmp[data-theme="companion"] .cp-cw__foot {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.rmp[data-theme="companion"] .cp-cw__applied {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 4px 8px;
border-radius: 8px;
background: var(--cp-ok-soft);
color: var(--cp-ok);
font: 700 12px/1.3 var(--cp-font);
}
.rmp[data-theme="companion"] .cp-cw__applied svg {
width: 13px;
height: 13px;
}
.rmp[data-theme="companion"] .cp-cw__exp {
font: 400 12px/1.3 var(--cp-font);
color: var(--cp-ink-2);
}
/* ==================================================== v5 discovery (§5.1–4) ===
 * The runtime draws the filter row, the teaser, the bookmark and the launcher
 * badge (docs/POCKET_V5_DISCOVERY_CONTRACT.md, v5.1 §A–C). Their geometry is
 * pocket.css's; this block tunes only their surface, radius and type into
 * team-08's warm paper — 16px corners, one accent, the sans face. No layout or
 * position is set here: the filters are NOT sticky (v5.1 §A). Same in light and
 * dark because every value below is one of the theme's own tokens. */

.rmp[data-theme="companion"] .rmp-filter {
border-radius: 999px;
border-color: var(--cp-line);
font: 600 13px/1.2 var(--cp-font);
color: var(--cp-ink-2);
}
.rmp[data-theme="companion"] .rmp-filter[aria-pressed="true"] {
border-color: transparent;
background: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-surface));
color: var(--rmp-accent-text);
}
.rmp[data-theme="companion"] .rmp-filter__n {
border-radius: 999px;
background: var(--cp-bg-3);
color: var(--cp-ink-2);
font: 700 12px/1 var(--cp-font);
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="companion"] .rmp-filter[aria-pressed="true"] .rmp-filter__n {
background: var(--rmp-accent);
color: var(--rmp-accent-ink);
}
.rmp[data-theme="companion"] .rmp-teaser {
background: var(--rmp-surface);
border: 1px solid var(--cp-line);
border-radius: var(--cp-radius);
box-shadow: var(--cp-shadow);
font-family: var(--cp-font);
}
.rmp[data-theme="companion"] .rmp-teaser__media {
border-radius: 14px;
}
.rmp[data-theme="companion"] .rmp-teaser__eyebrow {
font: 600 12px/1.3 var(--cp-font);
color: var(--cp-ink-2);
}
.rmp[data-theme="companion"] .rmp-teaser__title {
font: 700 14px/1.3 var(--cp-font);
color: var(--cp-ink-1);
}
.rmp[data-theme="companion"] .rmp-teaser__cta {
border-radius: 12px;
}
.rmp[data-theme="companion"] .rmp-teaser__reward {
font: 600 13px/1.3 var(--cp-font);
color: var(--rmp-accent-text);
}
/* v5.1 §B — the bookmark. A ribbon glyph: the outline reads ink-2, the filled
   form takes the accent. The resting surface is the base's own circle; the
   theme only tints it. The labelled pill keeps its own 12px corners. */
.rmp[data-theme="companion"] .rmp-save:not(.rmp-save--labelled) {
border-radius: 50%;
color: var(--cp-ink-2);
}
.rmp[data-theme="companion"] .rmp-save:not(.rmp-save--labelled)::before {
background: var(--cp-card);
box-shadow: var(--cp-shadow-sm);
}
.rmp[data-theme="companion"] .rmp-save[aria-pressed="true"] {
color: var(--rmp-accent-text);
}
.rmp[data-theme="companion"] .rmp-save:not(.rmp-save--labelled)[aria-pressed="true"]::before {
background: color-mix(in srgb, var(--rmp-accent) 14%, var(--cp-card));
}
/* Over a card's media the bookmark floats on a 30px frosted circle inside the
   44px tap target: the card's own surface at 88%, a blur and a soft shadow, so
   a busy photo never eats the ribbon. */
.rmp[data-theme="companion"] .cp-card > .rmp-save {
background: transparent;
}
.rmp[data-theme="companion"] .cp-card > .rmp-save::before {
content: "";
position: absolute;
inset: 5px;
border-radius: 50%;
background: color-mix(in srgb, var(--cp-card) 88%, transparent);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
box-shadow: var(--cp-shadow-sm);
}
.rmp[data-theme="companion"] .cp-card > .rmp-save[aria-pressed="true"]::before {
background: color-mix(in srgb, var(--rmp-accent) 16%, var(--cp-card));
}
/* the meter starts under the ask, on the same reading edge (V-C7) */
.rmp[data-theme="companion"] .rmp-pips {
justify-content: flex-start;
}
.rmp[data-theme="companion"] .rmp-badge {
background: var(--rmp-accent);
color: var(--rmp-accent-ink);
border-radius: 999px;
box-shadow: 0 0 0 2px var(--cp-card);
font: 700 12px/1.5 var(--cp-font);
font-variant-numeric: tabular-nums;
}

/* ============================================================== motion === */
@media (prefers-reduced-motion: reduce) {
.rmp[data-theme="companion"] .cp-card,
.rmp[data-theme="companion"] .cp-cw--ready {
animation: none;
}
.rmp[data-theme="companion"] .cp-card:hover {
transform: none;
}
.rmp[data-theme="companion"] .cp-card:hover .cp-media img {
transform: none;
}
.rmp[data-theme="companion"] .cp-fs__fill,
.rmp[data-theme="companion"] .cp-prog__fill {
transition: none;
}
/* the launcher's own movement stops; the open scale stays, because it is the
     resting state of the tile rather than an animation */
.rmp[data-theme="companion"] .rmp-launcher:hover,
.rmp[data-theme="companion"] .rmp-launcher:active {
transform: none;
}
.rmp[data-theme="companion"] .rmp-launcher:has(.rmp-gift.is-receive)::after {
animation: none;
}
}
.rmp--still[data-theme="companion"] .rmp-launcher:hover,
.rmp--still[data-theme="companion"] .rmp-launcher:active {
transform: none;
}
.rmp--still[data-theme="companion"] .rmp-launcher:has(.rmp-gift.is-receive)::after {
animation: none;
}
/* the same switch, but driven by the merchant's own motion=false */
.rmp[data-theme="companion"].rmp--still .cp-card,
.rmp[data-theme="companion"].rmp--still .cp-cw--ready {
animation: none;
}
.rmp[data-theme="companion"].rmp--still .cp-card:hover,
.rmp[data-theme="companion"].rmp--still .cp-card:hover .cp-media img {
transform: none;
}
.rmp[data-theme="companion"].rmp--still .cp-fs__fill,
.rmp[data-theme="companion"].rmp--still .cp-prog__fill {
transition: none;
}
/* ============================================================== mobile === */
/* The sheet's own rhythm is already the phone's (the runtime keys it on
   `data-device`); nothing here needs a second, width-based copy of it. */

/* Arabic descenders: the one-line row that ellipsises in this theme keeps a
   line box taller than its glyphs, so a «ج» or a final «ة» is never cut. */
.rmp[data-theme="companion"] .cp-title b {
line-height: 1.6;
padding-block: 1px;
text-wrap: pretty;
}

/* Rimaya pocket v3 — theme: grid.
 *
 * A faithful port of prototypes/proposals/team-06 "CLEAN GRID": strict grid,
 * hairlines, tabular numerals, zero ornament. 4px base unit, one accent, one
 * shadow, mono only for counts and indices (money stays sans + tabular).
 *
 * A DESIGN, not a skin (contract §7): this sheet owns everything inside the
 * panel and the panel's own chrome. The runtime owns data, behaviour, the
 * side-middle gift-box launcher and the panel's placement — so the geometry
 * rules here are content geometry only (radii, hairlines, scrims, bands), and
 * every selector is scoped `.rmp[data-theme="grid"]`.
 *
 * Tokens are declared rather than hard-coded so the accent follows the store
 * (--rmp-accent) and the mode (--rmp-surface / --rmp-surface-2 / --rmp-ink …)
 * decide light and dark without a second palette. Nothing here applies
 * letter-spacing to anything that can hold Arabic script; the mono numerals are
 * the only tracked text and they are Latin digits by construction.
 */
.rmp[data-theme="grid"] {
--g-ease: cubic-bezier(0.22, 1, 0.36, 1);
--g-pop: cubic-bezier(0.3, 1.3, 0.5, 1);
--g-hair: var(--rmp-line);
--g-hair-2: color-mix(in srgb, var(--rmp-ink) 7%, transparent);
--g-plate: var(--rmp-accent);
--g-plate-ink: var(--rmp-accent-ink);
/* The product tile: a light plate the studio-white photos melt into. It stays
   light in both modes, so a photo never reads as a cut-out hole in the sheet. */
--g-media: #f3f1ed;
/* Contract §9 — one stacking order for every theme. The three panel layers are
   restated here so this sheet never needs a bare number. */ --rmp-z-content: 0;
--rmp-z-sticky: 2;
--rmp-z-head: 3;
/* §8.2 — the browse control is designed ONCE in pocket.css and is the same pill in all four themes. A theme sets these four tokens and nothing else; the accent ink and line are bounded mixes so a merchant-pinned accent at either end of the range still reads. */ /* The panel's own chrome. The base owns the box; this is its character. */ --rmp-surface: #ffffff;
--rmp-surface-2: #f7f6f4;
--rmp-card: #ffffff;
--rmp-card-line: rgb(16 16 18 / 0.13);
--rmp-line: rgb(16 16 18 / 0.13);
--rmp-ink: #101013;
--rmp-ink-2: #5c5c63;
--rmp-ink-terms: #4c4c54;
--rmp-track: rgb(16 16 18 / 0.13);
--rmp-shadow: 0 1px 2px rgb(16 16 18 / 0.06), 0 12px 28px -12px rgb(16 16 18 / 0.22),
    0 40px 80px -40px rgb(16 16 18 / 0.28);
/* The panel keeps the base's radius; the content takes the spec's scale. */
--rmp-radius: 20px;
--rmp-radius-card: 16px;
--rmp-radius-sm: 8px;
--rmp-radius-btn: 12px;
--rmp-radius-chip: 8px;
--rmp-title-weight: 700;
--rmp-gutter: 16px;
/* Contract §11.3 — the plan is the base's; this theme sets its six tokens and
   nothing else. */
--rmp-plan-radius: 16px;
--rmp-plan-surface: var(--rmp-surface-2);
--rmp-plan-line: rgb(16 16 18 / 0.16);
--rmp-plan-tint: color-mix(in srgb, var(--g-plate) 7%, var(--rmp-surface-2));
--rmp-plan-ink: var(--rmp-ink);
--rmp-plan-muted: var(--rmp-ink-2);
}
.rmp[data-theme="grid"][data-mode="dark"] {
--rmp-surface: #141416;
--rmp-surface-2: #1c1c1f;
--rmp-card: #141416;
--rmp-card-line: rgb(255 255 255 / 0.14);
--rmp-line: rgb(255 255 255 / 0.14);
--rmp-ink: #f2f2f0;
--rmp-ink-2: #a5a5ad;
--rmp-ink-terms: #b9b7c2;
--rmp-track: rgb(255 255 255 / 0.16);
--rmp-shadow: 0 1px 2px rgb(0 0 0 / 0.5), 0 16px 40px -12px rgb(0 0 0 / 0.7);
/* the plan on ink: the hairline lightens, the tint gains a step so the one
   emphasised block still separates from the surface */
--rmp-plan-line: rgb(255 255 255 / 0.18);
--rmp-plan-tint: color-mix(in srgb, var(--g-plate) 14%, var(--rmp-surface-2));
}
/* contract §1 — themeOptions.grid.density. Comfortable is team-06's own grid. */
.rmp[data-theme="grid"][data-opt-density="compact"] {
--rmp-gutter: 12px;
}
/* ============================================================== panel chrome */
.rmp[data-theme="grid"][data-open="true"] .rmp-launcher {
transform: none;
}
.rmp[data-theme="grid"] .rmp-panel {
background: var(--rmp-surface);
box-shadow: var(--rmp-shadow), 0 0 0 1px var(--g-hair);
}
.rmp[data-theme="grid"] .rmp-tail {
background: var(--rmp-surface);
border-color: var(--g-hair);
}
.rmp[data-theme="grid"] .rmp-back,
.rmp[data-theme="grid"] .rmp-close {
box-sizing: border-box;
inline-size: var(--rmp-icon-btn);
block-size: var(--rmp-icon-btn);
min-inline-size: var(--rmp-icon-btn);
min-block-size: var(--rmp-icon-btn);
padding: 0;
border: 1px solid var(--g-hair);
border-radius: var(--rmp-radius-btn);
color: var(--rmp-ink-2);
display: grid;
place-items: center;
transition: color 150ms linear, border-color 150ms linear, background-color 150ms linear;
}
.rmp[data-theme="grid"] .rmp-back {
color: var(--rmp-ink);
}
.rmp[data-theme="grid"] .rmp-back:hover,
.rmp[data-theme="grid"] .rmp-close:hover {
border-color: color-mix(in srgb, var(--rmp-ink) 34%, transparent);
color: var(--rmp-ink);
}
.rmp[data-theme="grid"] .rmp-back svg {
inline-size: 16px;
block-size: 16px;
}
.rmp[data-theme="grid"] .rmp-close svg {
inline-size: 16px;
block-size: 16px;
}
/* RTL: «back» points to the reading edge, so the fixed left chevron is mirrored. */
.rmp[data-theme="grid"][dir="rtl"] .rmp-back svg {
transform: scaleX(-1);
}
.rmp[data-theme="grid"] .rmp-back svg,
.rmp[data-theme="grid"] .rmp-close svg {
fill: none;
stroke: currentcolor;
stroke-width: 1.6;
}
/* One header for both screens: a title, or the way back plus the way out. The
   offer screen carries no rule — an empty bar above a full-bleed photo reads as
   a seam, not as chrome. */
.rmp[data-theme="grid"] .rmp-head {
block-size: var(--rmp-head-h);
padding: 0 var(--rmp-gutter);
border-bottom: 1px solid var(--g-hair-2);
background: var(--rmp-surface);
}
.rmp[data-theme="grid"][data-screen="offer"] .rmp-head {
border-bottom-color: transparent;
justify-content: space-between;
}
.rmp[data-theme="grid"] .rmp-title {
font-size: var(--rmp-fs-title);
line-height: 1.6;
padding-block: 1px;
font-weight: 700;
}
/* ======================================================== free-shipping row ===
 * v5.1 §D / v3 §9: this is the ONE sticky element inside the list scroller —
 * a card passes UNDER it, never through it. The base's spread shadow paints the
 * panel surface out past the screen's gutter, so no card edge shows beside it.
 * Structure (spec V-C1): the truck, one line with the amount in ink, and the
 * track full width under it. No figure label, no knob. */
.rmp[data-theme="grid"] .rmp-ship {
position: sticky;
top: 0;
isolation: isolate;
z-index: var(--rmp-z-sticky);
flex: none;
gap: 10px;
min-block-size: 62px;
justify-content: center;
padding: 12px var(--rmp-gutter);
border-block-end: 1px solid var(--g-hair-2);
border-radius: 0;
background: var(--rmp-surface-2);
box-shadow: none;
}
.rmp[data-theme="grid"] .rmp-ship__text {
display: flex;
align-items: center;
gap: 8px;
font-size: var(--rmp-ship-fs);
font-weight: 600;
line-height: 1.4;
color: var(--rmp-ink-2);
}
.rmp[data-theme="grid"] .rmp-ship__text b {
font-weight: 700;
color: var(--rmp-ink);
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="grid"] .rmp-ship__text svg {
inline-size: 15px;
block-size: 15px;
flex: none;
fill: none;
stroke: var(--g-plate);
stroke-width: 1.5;
}
.rmp[data-theme="grid"] .rmp-ship[data-done="true"] .rmp-ship__text {
color: var(--rmp-ink);
}
.rmp[data-theme="grid"] .rmp-ship__meter {
display: block;
flex: none;
block-size: var(--rmp-ship-track);
min-block-size: var(--rmp-ship-track);
border-radius: 999px;
background: var(--rmp-track);
overflow: hidden;
}
.rmp[data-theme="grid"] .rmp-ship__fill {
display: block;
block-size: 100%;
min-block-size: 100%;
border-radius: 999px;
background: var(--g-plate);
transition: width 500ms var(--g-ease);
}
.rmp[data-theme="grid"] .rmp-ship[data-done="true"] .rmp-ship__fill {
background: var(--g-plate);
}
/* ============================================================== offer cards */
/* One card: a 96px product tile on the theme's light plate, the merchant's line,
   the ask, and a 2px hairline of progress. The photo is contained and multiplied
   into the plate, so the studio white has no edge and the product is never
   cropped. The bookmark is a sibling column of the row, never a layer over it. */
.rmp[data-theme="grid"] .rmp-offers {
display: flex;
flex-direction: column;
gap: 12px;
/* The list's foot is the shell's `--rmp-list-pad-end` on the screen, once: a
   second 16px here left grid's last card 29px above the panel while the other
   themes sit at 16 (A-X-40). */
padding: 0;
}
.rmp[data-theme="grid"] .rmp-card {
position: relative;
isolation: isolate;
display: flex;
align-items: stretch;
gap: 2px;
inline-size: 100%;
padding: 12px;
border: 1px solid var(--g-hair);
border-radius: var(--rmp-radius-card);
background: var(--rmp-surface);
color: var(--rmp-ink);
box-shadow: none;
overflow: hidden;
flex: 0 0 auto;
transition: border-color 160ms linear;
}
.rmp[data-theme="grid"] .rmp-card:hover {
border-color: color-mix(in srgb, var(--rmp-ink) 32%, transparent);
transform: none;
box-shadow: none;
}
.rmp[data-theme="grid"] .rmp-card__open {
display: flex;
align-items: center;
gap: 12px;
flex: 1;
min-inline-size: 0;
padding: 0;
border: 0;
border-radius: var(--rmp-radius-btn);
background: transparent;
color: inherit;
text-align: start;
}
.rmp[data-theme="grid"] .rmp-card__open:focus-visible {
outline: 2px solid var(--g-plate);
outline-offset: 2px;
}
/* v5 §5.4 — the related edge in this theme's language: the hairline turns
   accent. No tint, no badge, no words. */
.rmp[data-theme="grid"] .rmp-card[data-related="true"] {
border-color: var(--g-plate);
}
.rmp[data-theme="grid"] .rmp-card__media {
position: relative;
flex: none;
inline-size: 96px;
block-size: 96px;
display: grid;
place-items: center;
border-radius: var(--rmp-radius-btn);
background: var(--g-media);
overflow: hidden;
}
.rmp[data-theme="grid"] .rmp-card__img {
position: absolute;
inset: 0;
display: block;
inline-size: 100%;
block-size: 100%;
object-fit: contain;
object-position: center;
mix-blend-mode: multiply;
}
.rmp[data-theme="grid"] .rmp-card__glyph svg {
inline-size: 34px;
block-size: 34px;
fill: none;
stroke: var(--rmp-accent-text);
stroke-width: 1.3;
opacity: 0.78;
}
.rmp[data-theme="grid"] .rmp-card__body {
flex: 1;
min-inline-size: 0;
display: flex;
flex-direction: column;
gap: 8px;
justify-content: center;
padding: 0 2px;
}
/* Type only: the line box, the start alignment and the three-line clamp are
   pocket.css's (decisions 1 and 2) — a theme that clamps by character corrupts
   a figure. */
.rmp[data-theme="grid"] .rmp-card__title {
font-size: var(--rmp-fs-card);
font-weight: 700;
line-height: 1.6;
padding-block: 1px;
text-wrap: pretty;
color: var(--rmp-ink);
}
/* The ask never truncates: a reward token that does not fit beside it wraps to
   its own line, at the inline end, instead of ellipsising the sentence. */
.rmp[data-theme="grid"] .rmp-card__foot {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 2px 8px;
min-inline-size: 0;
}
.rmp[data-theme="grid"] .rmp-card__count {
display: inline-flex;
align-items: center;
gap: 6px;
min-inline-size: 0;
font-size: var(--rmp-fs-ask);
font-weight: 600;
line-height: 1.35;
color: var(--rmp-ink-2);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.rmp[data-theme="grid"] .rmp-card__count svg {
inline-size: 12px;
block-size: 12px;
flex: none;
fill: none;
stroke: currentcolor;
stroke-width: 2.4;
}
.rmp[data-theme="grid"] .rmp-card[data-state="done"] .rmp-card__count {
color: var(--rmp-success);
font-weight: 600;
}
/* The reward, once: only when the title does not already carry it. */
.rmp[data-theme="grid"] .rmp-card__reward {
flex: none;
margin-inline-start: auto;
min-inline-size: 0;
font-size: var(--rmp-fs-ask);
font-weight: 700;
line-height: 1.6;
padding-block: 1px;
color: var(--rmp-accent-text);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.rmp[data-theme="grid"] .rmp-card__meter {
display: block;
inline-size: 100%;
block-size: 4px;
min-block-size: 4px;
border-radius: 999px;
background: var(--g-hair-2);
overflow: hidden;
}
.rmp[data-theme="grid"] .rmp-card__fill {
display: block;
block-size: 100%;
border-radius: inherit;
background: var(--g-plate);
transition: width 450ms var(--g-ease);
}
.rmp[data-theme="grid"] .rmp-card[data-state="done"] .rmp-card__fill {
background: var(--rmp-success);
}
/* At zero the ask is the fact; a 0% rail is a decoration, not progress. */
.rmp[data-theme="grid"] .rmp-card:not([data-started="true"]) .rmp-card__meter {
display: none;
}
/* v5.1 §B — the bookmark takes its own 44px lane at the inline end of the row,
   so it can never sit on the title, the ask or the reward. */
.rmp[data-theme="grid"] .rmp-card > .rmp-save {
position: relative;
inset: auto;
align-self: flex-start;
z-index: 1;
}
.rmp[data-theme="grid"] .rmp-card > .rmp-save::before {
content: "";
position: absolute;
inset: 4px;
border-radius: 50%;
background: var(--rmp-surface);
box-shadow: 0 0 0 1px var(--g-hair);
}
.rmp[data-theme="grid"] .rmp-card > .rmp-save[aria-pressed="true"]::before {
background: color-mix(in srgb, var(--g-plate) 14%, var(--rmp-surface));
}
/* The phone chrome keys the shipping row on the runtime's device, so this
   theme restates the one composition the spec names: truck and line, then the
   track across the full width of the row. */
.rmp[data-theme="grid"][data-device="mobile"] .rmp-ship {
flex-direction: column;
align-items: stretch;
min-block-size: 62px;
gap: 10px;
padding-block: 12px;
padding-inline: var(--rmp-gutter);
border-radius: 0;
}
.rmp[data-theme="grid"][data-device="mobile"] .rmp-ship__meter {
flex: none;
inline-size: 100%;
}
/* The list screen's band is flush under the header: the shipping row is the top
   of the list, not a card floating in it. */
.rmp[data-theme="grid"] .rmp-screen--list {
gap: 12px;
padding-block-start: 0;
/* The shipping band is full-bleed (a negative gutter on each side) and the
   shell paints a gutter-wide strip behind it, so the scroller's scrollable width
   is 16px wider than the panel. Clip the inline axis: the vertical scroller is
   untouched and a chip scrolled into view can no longer shift the whole list
   sideways (A-grid-29). */
overflow-x: clip;
}
.rmp[data-theme="grid"] .rmp-ship {
margin-inline: calc(-1 * var(--rmp-gutter));
}

/* ============================================================= empty state */
.rmp[data-theme="grid"] .rmp-empty {
display: flex;
flex-direction: column;
align-items: center;
gap: 13px;
padding: 26px 8px 24px;
text-align: center;
}
.rmp[data-theme="grid"] .rmp-empty svg {
inline-size: 92px;
block-size: 70px;
fill: none;
stroke: color-mix(in srgb, var(--rmp-ink) 34%, transparent);
stroke-width: 1.1;
}
.rmp[data-theme="grid"] .rmp-empty h3 {
font-size: 14px;
font-weight: 600;
}
.rmp[data-theme="grid"] .rmp-btn {
border-radius: var(--rmp-radius-btn);
font-size: 12px;
padding: 8px 13px;
border-color: var(--g-hair);
}
.rmp[data-theme="grid"] .rmp-btn--primary {
background: var(--g-plate);
color: var(--g-plate-ink);
border-color: transparent;
}
.rmp[data-theme="grid"] .rmp-empty__go {
margin-top: 3px;
}
/* ================================================================ offer page */
.rmp[data-theme="grid"] .rmp-screen--offer {
display: flex;
flex-direction: column;
gap: 0;
}
.rmp[data-theme="grid"] .rmp-hero {
position: relative;
isolation: isolate;
flex: none;
display: block;
background: var(--g-media);
border-radius: var(--rmp-radius-card);
box-shadow: none;
overflow: hidden;
}
/* An offer with no product photo: a compact kind band across the column (112px
   tall) with the reward's mark centred, so it reads as a designed state and not
   as a hero whose photo failed (A-grid-27). */
/* An offer with no product photo: the reward kind on a soft accent-tinted plate,
   not a flat band with a small grey mark (round-7 decision 4, F-grid-05). */
.rmp[data-theme="grid"] .rmp-hero--kind {
display: grid;
margin-inline: 0;
place-items: center;
inline-size: 100%;
block-size: 76px;
background:
radial-gradient(130% 160% at 50% 32%, color-mix(in srgb, var(--g-plate) 12%, var(--rmp-surface-2)) 0%, var(--rmp-surface-2) 74%);
}
.rmp[data-theme="grid"] .rmp-hero__mark svg {
inline-size: 56px;
block-size: 56px;
fill: none;
stroke: var(--rmp-accent-text);
stroke-width: 1.25;
opacity: 0.78;
}
.rmp[data-theme="grid"] .rmp-hero__img {
mix-blend-mode: multiply;
}
.rmp[data-theme="grid"] .rmp-otitle {
padding: 16px 0 0;
font-size: var(--rmp-fs-detail);
line-height: 1.4;
font-weight: 700;
text-wrap: pretty;
text-wrap: balance;
}
/* v5.1 §B — the offer title and its labelled bookmark share one row; the pill
   keeps the trailing edge and the title takes the rest. */
.rmp[data-theme="grid"] .rmp-otop {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 16px 0 0;
}
.rmp[data-theme="grid"] .rmp-otop .rmp-otitle {
padding: 0;
flex: 1;
min-inline-size: 0;
}
/* v5.1 §B — the labelled bookmark is a secondary chip beside the title: a
   hairline, the panel surface and the button corner. */
.rmp[data-theme="grid"] .rmp-otop > .rmp-save--labelled {
flex: none;
border-color: var(--g-hair);
border-radius: var(--rmp-radius-btn);
background: var(--rmp-surface);
color: var(--rmp-ink-2);
}
.rmp[data-theme="grid"] .rmp-otop > .rmp-save--labelled[aria-pressed="true"] {
border-color: transparent;
background: color-mix(in srgb, var(--g-plate) 12%, var(--rmp-surface));
color: var(--rmp-accent-text);
}
.rmp[data-theme="grid"] .rmp-otop > .rmp-save--labelled::before {
display: none;
}
.rmp[data-theme="grid"] .rmp-odesc {
padding: 6px 0 0;
font-size: var(--rmp-fs-body);
line-height: 1.6;
color: var(--rmp-ink-2);
}
/* §8.2: the add control is a `<button>` on a plain product and an `<a>` on a
   product that has options — «أضف» and «اختر». The base sheet resets BOTH tags
   (`background: none; border: 0`) and an anchor still carries its underline,
   so without the box below the `<a>` read as bare bold text while the
   `<button>` read as a control. One rule, both tags: the design's own hairline
   pill, 36px, no underline, the ink on the panel surface in both
   modes (--g-hair and --rmp-ink are mode tokens), and a visible focus ring. */
.rmp[data-theme="grid"] .rmp-btn--add {
display: inline-flex;
align-items: center;
justify-content: center;
white-space: nowrap;
min-inline-size: 62px;
min-block-size: 36px;
box-sizing: border-box;
color: var(--rmp-ink);
background: var(--rmp-surface);
border: 1px solid var(--g-hair);
border-radius: var(--rmp-radius-btn);
box-shadow: none;
font-size: 12px;
font-weight: 700;
line-height: 1;
text-decoration: none;
padding: 0 12px;
cursor: pointer;
transition: color 150ms linear, border-color 150ms linear, background-color 150ms linear;
}
.rmp[data-theme="grid"] .rmp-btn--add:hover {
border-color: color-mix(in srgb, var(--g-plate) 70%, var(--rmp-ink));
color: color-mix(in srgb, var(--g-plate) 78%, var(--rmp-ink));
background: var(--rmp-surface-2);
}
.rmp[data-theme="grid"] .rmp-btn--add:active {
background: color-mix(in srgb, var(--g-plate) 8%, var(--rmp-surface-2));
}
.rmp[data-theme="grid"] .rmp-btn--add:focus-visible {
outline: 2px solid var(--g-plate);
outline-offset: 2px;
}
/* a filled slot's own «is-added» state still wins over the hairline */
.rmp[data-theme="grid"] .rmp-btn--add.is-added {
border-color: transparent;
background: var(--rmp-success);
color: var(--rmp-success-ink);
}
/* reward: coupon — the code dominates, copy is a quiet inline control */
.rmp[data-theme="grid"] .rmp-coupon {
position: relative;
isolation: isolate;
padding: 14px 12px 12px;
border: 1px solid var(--g-hair);
border-radius: var(--rmp-radius-card);
background: var(--rmp-surface);
}
.rmp[data-theme="grid"] .rmp-coupon__code {
display: block;
text-align: center;
padding: 10px 8px;
border: 1px solid var(--g-plate);
border-radius: var(--rmp-radius-btn);
background: var(--rmp-surface-2);
color: var(--g-plate);
font-family: var(--rmp-font);
font-size: 18px;
font-weight: 700;
font-variant-numeric: tabular-nums;
letter-spacing: 0.08em;
}
.rmp[data-theme="grid"] .rmp-coupon__code.is-blur {
color: transparent;
text-shadow: 0 0 11px color-mix(in srgb, var(--rmp-ink) 32%, transparent);
border-style: dashed;
border-color: var(--g-hair);
user-select: none;
letter-spacing: 0.2em;
}
.rmp[data-theme="grid"] .rmp-coupon__status {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
line-height: 1.35;
color: var(--rmp-ink-2);
}
.rmp[data-theme="grid"] .rmp-coupon__status svg {
inline-size: 13px;
block-size: 13px;
flex: none;
fill: none;
stroke: currentcolor;
stroke-width: 1.6;
}
.rmp[data-theme="grid"] .rmp-coupon[data-state="locked"] .rmp-coupon__status {
justify-content: flex-start;
}
.rmp[data-theme="grid"] .rmp-coupon[data-state="revealed"] .rmp-coupon__status,
.rmp[data-theme="grid"] .rmp-coupon[data-state="applied"] .rmp-coupon__status {
color: var(--g-plate);
font-weight: 600;
}
/* the code dominates and copy is a quiet control beside it, never under it */
.rmp[data-theme="grid"] .rmp-coupon {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px 8px;
}
.rmp[data-theme="grid"] .rmp-coupon__code {
grid-area: 1 / 1 / 2 / 2;
align-self: stretch;
display: grid;
place-items: center;
}
.rmp[data-theme="grid"] .rmp-coupon[data-state="ready"] {
display: block;
padding: 12px;
}
.rmp[data-theme="grid"] .rmp-coupon__reveal {
inline-size: 100%;
justify-content: center;
}
.rmp[data-theme="grid"] .rmp-coupon__actions {
grid-area: 1 / 2 / 2 / 3;
flex-direction: column;
align-items: stretch;
justify-content: center;
gap: 6px;
}
.rmp[data-theme="grid"] .rmp-coupon__status {
grid-area: 2 / 1 / 3 / 3;
}
.rmp[data-theme="grid"] .rmp-coupon[data-state="locked"] .rmp-coupon__code {
grid-area: 2 / 1 / 3 / 3;
}
.rmp[data-theme="grid"] .rmp-coupon[data-state="locked"] .rmp-coupon__status {
grid-area: 1 / 1 / 2 / 3;
}
.rmp[data-theme="grid"] .rmp-coupon__actions .rmp-btn--copy {
flex: none;
color: var(--rmp-ink);
}
/* The copy glyph is an outline like every other mark in this sheet; left with
   the UA's fill it paints as a solid black block on the ticket. */
.rmp[data-theme="grid"] .rmp-btn--copy svg {
inline-size: 12px;
block-size: 12px;
fill: none;
stroke: currentcolor;
stroke-width: 1.6;
}
.rmp[data-theme="grid"] .rmp-coupon__actions .rmp-btn--copy:hover {
border-color: var(--g-plate);
color: var(--g-plate);
}
.rmp[data-theme="grid"] .rmp-coupon__expiry {
font-size: 12px;
color: var(--rmp-ink-2);
min-inline-size: 0;
}
/* The terms are pocket.css's disclosure (round-5 decision 1): one 44px
   «الشروط» row with a chevron, identical in every theme, so this sheet keeps no
   rule for the block. */

/* ============================================================ the checklist */
.rmp[data-theme="grid"] .rmp-section--checklist {
padding: 0;
gap: 0;
border-bottom: 0;
}
/* ============================================================== floating bits */
.rmp[data-theme="grid"] .rmp-nudge { border-color: var(--g-hair); border-radius: var(--rmp-radius-card); }
.rmp[data-theme="grid"] .rmp-pill {
border: 1px solid var(--g-hair);
border-radius: var(--rmp-radius-card);
background: var(--rmp-surface);
box-shadow: 0 1px 2px rgb(16 16 18 / 0.1), 0 8px 18px -8px rgb(16 16 18 / 0.3);
}
/* ==================================================== v5 discovery (§5.1–4) ===
 * The filter row, the teaser, the bookmark and the launcher badge are the
 * runtime's (docs/POCKET_V5_DISCOVERY_CONTRACT.md, v5.1 §A–C); their geometry
 * is pocket.css's and the filter row is NOT sticky (§A). This block tunes
 * surface, radius and type only: pill chips, a pill count, hairlines. */
/* A 40px chip in a 48px row: the 4px of row padding is the hit area the
   runtime's ::after reaches into, so the tap target and the focus ring are
   never clipped by the scroller. */
.rmp[data-theme="grid"] .rmp-filters {
block-size: 48px;
padding-block: 4px;
margin-block: 0;
}
.rmp[data-theme="grid"] .rmp-filter {
block-size: var(--rmp-chip-h);
border-radius: 999px;
border-color: var(--g-hair);
background: var(--rmp-surface);
font-size: var(--rmp-chip-fs);
font-weight: 600;
color: var(--rmp-ink-2);
}
.rmp[data-theme="grid"] .rmp-filter::after {
inset: -2px 0;
}
.rmp[data-theme="grid"] .rmp-filter[aria-pressed="true"] {
border-color: transparent;
background: color-mix(in srgb, var(--g-plate) 13%, var(--rmp-surface));
color: var(--rmp-accent-text);
}
.rmp[data-theme="grid"] .rmp-filter__n {
display: inline-grid;
place-items: center;
min-inline-size: var(--rmp-chip-count);
block-size: var(--rmp-chip-count);
border-radius: 999px;
background: color-mix(in srgb, var(--rmp-ink) 8%, transparent);
color: var(--rmp-ink-2);
font-family: var(--rmp-font);
font-size: 12px;
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="grid"] .rmp-filter[aria-pressed="true"] .rmp-filter__n {
background: var(--g-plate);
color: var(--g-plate-ink);
}
.rmp[data-theme="grid"] .rmp-teaser {
background: var(--rmp-surface);
border: 1px solid var(--g-hair);
border-radius: var(--rmp-radius-card);
box-shadow: 0 10px 24px -14px rgb(0 0 0 / 0.5);
}
.rmp[data-theme="grid"] .rmp-teaser__media {
border-radius: var(--rmp-radius-btn);
background: var(--g-media);
overflow: hidden;
}
.rmp[data-theme="grid"] .rmp-teaser__media img {
object-fit: contain;
mix-blend-mode: multiply;
}
.rmp[data-theme="grid"] .rmp-teaser__eyebrow {
font-family: var(--rmp-font);
font-size: 12px;
font-weight: 600;
letter-spacing: normal;
text-transform: none;
color: var(--rmp-ink-2);
}
.rmp[data-theme="grid"][dir="ltr"] .rmp-teaser__eyebrow {
font-family: var(--rmp-font);
letter-spacing: normal;
text-transform: none;
}
.rmp[data-theme="grid"] .rmp-teaser__title {
font-size: var(--rmp-fs-ask);
font-weight: 700;
color: var(--rmp-ink);
}
.rmp[data-theme="grid"] .rmp-teaser__reward {
font-size: 13px;
color: var(--rmp-ink-2);
}
/* v5.1 §B — the bookmark. The outline reads ink-2, the filled form takes the
   accent; the resting surface is the base's own circle, tinted here. */
.rmp[data-theme="grid"] .rmp-save {
border-radius: 50%;
color: var(--rmp-ink-2);
}
.rmp[data-theme="grid"] .rmp-save::before {
background: var(--rmp-surface);
box-shadow: 0 0 0 1px var(--g-hair);
}
.rmp[data-theme="grid"] .rmp-save[aria-pressed="true"] {
color: var(--g-plate);
}
.rmp[data-theme="grid"] .rmp-save[aria-pressed="true"]::before {
background: color-mix(in srgb, var(--g-plate) 12%, var(--rmp-surface));
}
/* The bookmark in its own lane, on the panel surface: a 32px disc inside the
   44px target, one hairline — the same control the header uses. */
.rmp[data-theme="grid"] .rmp-badge {
border-radius: 999px;
background: var(--g-plate);
color: var(--g-plate-ink);
font-family: var(--rmp-font);
font-size: 12px;
font-weight: 700;
font-variant-numeric: tabular-nums;
}

/* One card at every width: the popover is a drawer, and a list row is a list
   row — the same tile, the same lines, 20px gutters on a desktop panel. */
@media (min-width: 640px) {
  .rmp[data-theme="grid"] {
    --rmp-gutter: 20px;
  }
  .rmp[data-theme="grid"] .rmp-card__media {
    inline-size: 104px;
    block-size: 104px;
  }
  /* The popover's kind plate keeps the taller tablet/desktop height (F-grid-05)
     and a 64px mark (round-7 decision 4). */
  .rmp[data-theme="grid"] .rmp-hero--kind {
    block-size: 112px;
  }
  .rmp[data-theme="grid"] .rmp-hero__mark svg {
    inline-size: 64px;
    block-size: 64px;
  }
  /* The popover's prize hero caps its width at 190px and its height at 15dvh —
     at a 900px window that is a 190×135 frame and a 27px tint strip either side
     of the photo. Cap the width by the same height so the frame stays square
     (round-5 decision 3). */
  .rmp[data-theme="grid"] .rmp-screen--offer:has(.rmp-prize) .rmp-hero:has(img) {
    inline-size: min(100%, 190px, 15dvh);
  }
}

/* ================================================================ motion guard */
@media (prefers-reduced-motion: reduce) {
.rmp[data-theme="grid"] .rmp-card:hover {
transform: none;
}
.rmp[data-theme="grid"] .rmp-card:hover .rmp-card__media img {
transform: none;
}
}
.rmp[data-theme="grid"][data-motion="off"] .rmp-card,
.rmp[data-theme="grid"][data-motion="off"] .rmp-card__media img,
.rmp[data-theme="grid"][data-motion="off"] .rmp-ship__fill,
.rmp[data-theme="grid"][data-motion="off"] .rmp-card__fill {
transition: none;
}

/* ═══ pocket v3 · theme: depth — prototypes/proposals/team-03 «Soft Depth» ═══
 *
 * Contract §7: a theme is a DESIGN, not a skin. This is team-03's panel, taken
 * apart and rebuilt on the runtime's DOM: warm paper instead of grey plastic,
 * white cards lifted off a white stage by stacked ambient shadows and a single
 * hairline, the accent as a gradient veil over a 2:1 banner, the small bar that
 * sits beside an offer's name, the shipping well with its travelling cap, and
 * the coupon as a dashed ticket with a gold value plate.
 *
 * Nothing here touches geometry (§4): the launcher, the panel's placement, the
 * tail and the sheet stay exactly where the runtime and pocket.css put them.
 * Team-03's own launcher and panel position are deliberately NOT ported — the
 * pocket's side-middle gift box is the product.
 */
.rmp[data-theme="depth"] {
--d-ease: cubic-bezier(0.32, 0.72, 0.28, 1);
--d-spring: cubic-bezier(0.22, 1.32, 0.36, 1);
--rmp-ease: var(--d-ease);
/* team-03's paper palette: warm, never grey. */ --rmp-surface: #ffffff;
--rmp-surface-2: #f3eee5;
--rmp-card: #ffffff;
--rmp-card-line: #e7e1d7;
--rmp-line: #e7e1d7;
--rmp-line-2: #f0ebe2;
--rmp-ink: #14120e;
--rmp-ink-2: #56504a;
--rmp-ink-3: #6e665b;
--rmp-ink-terms: #56504a;
--rmp-track: rgba(20, 18, 14, 0.09);
--rmp-success: #14724b;
--rmp-success-ink: #ffffff;
--rmp-success-soft: color-mix(in srgb, #14724b 9%, #ffffff);
/* Soft depth: stacked ambient shadows, no hard edges. */ --rmp-shadow: 0 2px 4px rgba(60, 44, 20, 0.06), 0 10px 26px rgba(60, 44, 20, 0.1), 0 28px 60px rgba(60, 44, 20, 0.08);
--rmp-card-shadow: 0 1px 1px rgba(60, 44, 20, 0.04), 0 2px 6px rgba(60, 44, 20, 0.05);
--rmp-card-shadow-hover: 0 1px 1px rgba(60, 44, 20, 0.05), 0 4px 12px rgba(60, 44, 20, 0.07), 0 12px 28px rgba(60, 44, 20, 0.05);
--rmp-hi: inset 0 1px 0 rgba(255, 255, 255, 0.75);
--rmp-radius: 20px;
--rmp-radius-card: 16px;
--rmp-radius-sm: 11px;
--rmp-radius-btn: 12px;
--rmp-radius-chip: 8px;
--rmp-gutter: 16px;
--rmp-title-weight: 700;
/* The paper a product is laid on. Studio shots are white to their edge; a
   multiply blend over this plate melts that white into the theme instead of
   stacking two whites beside each other. One flat tone: a gradient mat would
   draw a step wherever the shot's own white ends. */
--d-plate: #f4eee4;
/* Contract §11.3 — team-03's plan is soft and elevated: the accent-tinted card
   sits on a raised surface, so the surface token IS the card and the line is a
   whisper. Only these six. */
--rmp-plan-radius: 16px;
--rmp-plan-surface: var(--rmp-card);
--rmp-plan-line: var(--rmp-card-line);
--rmp-plan-tint: color-mix(in srgb, var(--rmp-accent) 8%, var(--rmp-card));
--rmp-plan-ink: var(--rmp-ink);
--rmp-plan-muted: var(--rmp-ink-3);
}
/* `intensity: rich` (contract §1) is team-03's deeper stack: more shadow under
   every card. */
.rmp[data-theme="depth"][data-opt-intensity="rich"] {
--rmp-card-shadow: 0 1px 1px rgba(60, 44, 20, 0.05), 0 3px 9px rgba(60, 44, 20, 0.07), 0 10px 24px rgba(60, 44, 20, 0.06);
--rmp-card-shadow-hover: 0 2px 4px rgba(60, 44, 20, 0.06), 0 8px 20px rgba(60, 44, 20, 0.09), 0 20px 44px rgba(60, 44, 20, 0.08);
--rmp-shadow: 0 3px 6px rgba(60, 44, 20, 0.07), 0 14px 32px rgba(60, 44, 20, 0.12), 0 36px 76px rgba(60, 44, 20, 0.1);
}
.rmp[data-theme="depth"][data-mode="dark"] {
--rmp-surface: #1d1a16;
--rmp-surface-2: #211d19;
--rmp-card: #1d1a16;
--rmp-card-line: #302b25;
--rmp-line: #302b25;
--rmp-line-2: #272320;
--rmp-ink: #f4f0e9;
--rmp-ink-2: #b5ada1;
--rmp-ink-3: #a1998c;
--rmp-ink-terms: #b5ada1;
--rmp-track: rgba(244, 240, 233, 0.1);
--rmp-success: #34a877;
--rmp-success-ink: #05261a;
--rmp-success-soft: color-mix(in srgb, #34a877 14%, #1d1a16);
--rmp-shadow: 0 2px 4px rgba(0, 0, 0, 0.36), 0 10px 26px rgba(0, 0, 0, 0.42), 0 28px 60px rgba(0, 0, 0, 0.38);
--rmp-card-shadow: 0 1px 1px rgba(0, 0, 0, 0.3), 0 2px 6px rgba(0, 0, 0, 0.26);
--rmp-card-shadow-hover: 0 1px 1px rgba(0, 0, 0, 0.32), 0 4px 12px rgba(0, 0, 0, 0.3), 0 12px 28px rgba(0, 0, 0, 0.24);
/* the plan on dark: the tint gains a step so the one emphasised block lifts */
--rmp-plan-tint: color-mix(in srgb, var(--rmp-accent) 15%, var(--rmp-card));
--rmp-hi: inset 0 1px 0 rgba(255, 255, 255, 0.055);
--d-plate: #cfc6b8;
}
.rmp[data-theme="depth"][data-mode="dark"][data-opt-intensity="rich"] {
--rmp-card-shadow: 0 1px 1px rgba(0, 0, 0, 0.34), 0 3px 9px rgba(0, 0, 0, 0.3), 0 10px 24px rgba(0, 0, 0, 0.28);
--rmp-card-shadow-hover: 0 2px 4px rgba(0, 0, 0, 0.36), 0 8px 20px rgba(0, 0, 0, 0.36), 0 20px 44px rgba(0, 0, 0, 0.3);
}
/* ----------------------------------------------------------------- panel --- */
.rmp[data-theme="depth"] .rmp-panel {
background: var(--rmp-surface);
box-shadow: 0 0 0 1px var(--rmp-line), var(--rmp-shadow), var(--rmp-hi);
}
.rmp[data-theme="depth"] .rmp-head {
padding-inline: 16px;
background: var(--rmp-surface);
border-bottom-color: var(--rmp-line);
box-shadow: none;
}
.rmp[data-theme="depth"] .rmp-title {
font-size: var(--rmp-fs-title);
font-weight: 700;
letter-spacing: -0.012em;
}
/* The offer screen is headed by the merchant's own title in the body; the bar
   keeps only the two controls, one at each edge. The clipped heading above them
   is the dialog's accessible name — never a second line of type. */
.rmp[data-theme="depth"] .rmp-sr {
position: absolute;
inline-size: 1px;
block-size: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.rmp[data-theme="depth"][data-screen="offer"] .rmp-head {
justify-content: space-between;
}
/* The back and close controls are ONE button in this theme, in both screens:
   the shared 44px square (decision 5), a 12px radius, the paper surface. No
   second style for the offer screen. */
.rmp[data-theme="depth"] .rmp-back,
.rmp[data-theme="depth"] .rmp-close {
width: var(--rmp-icon-btn);
min-height: var(--rmp-icon-btn);
height: var(--rmp-icon-btn);
border-radius: var(--rmp-radius-btn);
color: var(--rmp-ink-2);
}
/* The back arrow belongs to the offer page only. The runtime hides it with the
   `hidden` attribute; this is the same statement in CSS, so the header never
   shows two arrows if a payload arrives without one. */
.rmp[data-theme="depth"][data-screen="list"] .rmp-back {
display: none;
}
.rmp[data-theme="depth"] .rmp-back:hover,
.rmp[data-theme="depth"] .rmp-close:hover {
background: var(--rmp-surface-2);
color: var(--rmp-ink);
}
.rmp[data-theme="depth"] .rmp-back .rmp-ico,
.rmp[data-theme="depth"] .rmp-close .rmp-ico {
width: 16px;
height: 16px;
}
/* Chevron points the way travel reads: mirrored in RTL. */
.rmp[data-theme="depth"][dir="rtl"] .rmp-back .rmp-ico {
transform: scaleX(-1);
}
/* ------------------------------------------------------ free shipping bar --- */
/* The row's under-fade is 12px, but the row's own 16px spread halo keeps painting
   flat white 4px past it, so the card met a hard edge. 32px — the row plus its
   halo — dissolves the first visible pixels instead (A6-DEPTH-02). The colour and
   the mask stay the runtime's: a gradient row hands the fade its own tint. */
.rmp[data-theme="depth"][data-mode] .rmp-screen--list > [data-rmp-row="true"]::after {
block-size: 32px;
}
.rmp[data-theme="depth"] .rmp-ship {
border-radius: var(--rmp-radius-card);
background: linear-gradient(165deg, color-mix(in srgb, var(--rmp-accent) 9%, var(--rmp-surface)), color-mix(in srgb, var(--rmp-accent) 3%, var(--rmp-surface)));
border: 1px solid color-mix(in srgb, var(--rmp-accent) 17%, var(--rmp-line));
box-shadow: var(--rmp-card-shadow), var(--rmp-hi), 0 0 0 var(--rmp-gutter) var(--rmp-surface);
padding: 12px 16px;
}
.rmp[data-theme="depth"] .rmp-ship__l1 {
display: flex;
align-items: center;
gap: 8px;
flex: 1 1 auto;
min-inline-size: 0;
}
.rmp[data-theme="depth"] .rmp-ship__text {
min-inline-size: 0;
}
/* On a phone the label keeps its line and the track keeps its own: the row the
   base sheet draws puts the knob on top of «المجاني», so depth stacks them. */
.rmp[data-theme="depth"][data-device="mobile"] .rmp-ship {
flex-direction: column;
align-items: stretch;
gap: 8px;
}
.rmp[data-theme="depth"][data-device="mobile"] .rmp-ship__meter {
flex: none;
inline-size: auto;
}
.rmp[data-theme="depth"] .rmp-ship__ico {
display: grid;
place-items: center;
flex: none;
color: var(--rmp-accent-text);
}
.rmp[data-theme="depth"] .rmp-ship__ico .rmp-ico {
width: 20px;
height: 20px;
}
.rmp[data-theme="depth"] .rmp-ship__text {
font-size: var(--rmp-ship-fs);
font-weight: 600;
line-height: 1.5;
color: var(--rmp-ink);
}
.rmp[data-theme="depth"] .rmp-ship__text b {
color: var(--rmp-accent-text);
font-weight: 700;
}
/* The track is a plain full-width rule under the label: 5px, a pill, the accent
   fill inside it. No cap, no knob — the truck and the figure already say where
   the shopper is. */
.rmp[data-theme="depth"] .rmp-ship__meter {
display: block;
height: 5px;
margin-top: 0;
border-radius: 999px;
background: var(--rmp-track);
overflow: hidden;
}
.rmp[data-theme="depth"] .rmp-ship__fill {
display: block;
height: 100%;
border-radius: 999px;
background: var(--rmp-accent);
box-shadow: 0 1px 4px color-mix(in srgb, var(--rmp-accent) 32%, transparent);
transition: width 400ms var(--d-ease);
}
.rmp[data-theme="depth"] .rmp-ship[data-done="true"] .rmp-ship__fill {
background: var(--rmp-success);
box-shadow: none;
}
.rmp[data-theme="depth"] .rmp-ship[data-done="true"] {
background: linear-gradient(165deg, color-mix(in srgb, var(--rmp-success) 12%, var(--rmp-surface)), color-mix(in srgb, var(--rmp-success) 4%, var(--rmp-surface)));
border-color: color-mix(in srgb, var(--rmp-success) 26%, var(--rmp-line));
}
.rmp[data-theme="depth"] .rmp-ship[data-done="true"] .rmp-ship__text,
.rmp[data-theme="depth"] .rmp-ship[data-done="true"] .rmp-ship__text b,
.rmp[data-theme="depth"] .rmp-ship[data-done="true"] .rmp-ship__ico {
color: var(--rmp-success);
}
.rmp[data-theme="depth"][data-mode="dark"] .rmp-ship[data-done="true"] {
background: linear-gradient(165deg, color-mix(in srgb, var(--rmp-success) 12%, var(--rmp-surface)), var(--rmp-surface));
}
.rmp[data-theme="depth"][data-mode="dark"] .rmp-ship[data-done="true"] .rmp-ship__text,
.rmp[data-theme="depth"][data-mode="dark"] .rmp-ship[data-done="true"] .rmp-ship__text b,
.rmp[data-theme="depth"][data-mode="dark"] .rmp-ship[data-done="true"] .rmp-ship__ico {
color: var(--rmp-success);
}
.rmp[data-theme="depth"][data-mode="dark"] .rmp-ship[data-done="true"] .rmp-ship__fill {
background: #2aa96f;
box-shadow: none;
}
/* ------------------------------------------------------------ list screen --- */
.rmp[data-theme="depth"] .rmp-sec {
display: block;
margin: 4px 0 0;
font-size: 13px;
font-weight: 600;
letter-spacing: 0;
color: var(--rmp-ink-3);
}
.rmp[data-theme="depth"] .rmp-offers {
gap: 12px;
}
/* -------------------------------------------------------------- the card --- */
.rmp[data-theme="depth"] .rmp-card {
position: relative;
isolation: isolate;
border-radius: var(--rmp-radius-card);
background: var(--rmp-card);
box-shadow: 0 0 0 1px var(--rmp-card-line), var(--rmp-card-shadow), var(--rmp-hi);
transition: transform 300ms var(--d-spring), box-shadow 300ms var(--d-ease), border-color 300ms var(--d-ease);
}
/* The pointer's own highlight. `:focus-within` used to stand here, which lit the
   card up again the moment a TAP focused its open control (docs/ACCESSIBILITY.md, focus policy 2:
   cards show their indicator under `:focus-visible` only) — the keyboard's is the
   rule below, kept separate so a browser without `:has()` still gets the hover. */
.rmp[data-theme="depth"] .rmp-card:hover {
transform: translateY(-2px);
box-shadow: 0 0 0 1px color-mix(in srgb, var(--rmp-accent) 22%, var(--rmp-card-line)), var(--rmp-card-shadow-hover), var(--rmp-hi);
}
.rmp[data-theme="depth"] .rmp-card[data-state="done"] {
box-shadow: 0 0 0 1px color-mix(in srgb, var(--rmp-success) 34%, var(--rmp-card-line)), var(--rmp-card-shadow), var(--rmp-hi);
}
.rmp[data-theme="depth"] .rmp-card:has(:focus-visible) {
box-shadow: 0 0 0 1px color-mix(in srgb, var(--rmp-accent) 46%, var(--rmp-card-line)), var(--rmp-card-shadow-hover);
}
.rmp[data-theme="depth"] .rmp-card__open {
border-radius: inherit;
}
/* v5.1 §D — the bookmark rides the media's top inline-end corner as a sibling
   of the open control, a LOCAL layer (z-index 1) of the isolated card so it can
   never cross the free-shipping bar; the done chip shares the corner and steps
   below the bookmark only when one is drawn. */
.rmp[data-theme="depth"] .rmp-card > .rmp-save {
position: absolute;
z-index: 1;
inset-block-start: 8px;
inset-inline-end: 8px;
}
.rmp[data-theme="depth"] .rmp-card:has(> .rmp-save) .rmp-card__done {
inset-block-start: calc(8px + 44px + 8px);
}
/* v5 §5.4 — the related edge: one accent ring under the card's soft shadow,
   never a badge and never a word. */
.rmp[data-theme="depth"] .rmp-card[data-related="true"] {
box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--rmp-accent) 52%, transparent), var(--rmp-card-shadow), var(--rmp-hi);
}
.rmp[data-theme="depth"] .rmp-card[data-related="true"]:hover {
box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--rmp-accent) 52%, transparent), var(--rmp-card-shadow-hover), var(--rmp-hi);
}
/* The banner: the product WHOLE on the theme's paper plate — 2.15:1 keeps two
   and a half cards on a phone, the plate shows either side of a portrait shot.
   `darken` is what melts the studio white: every pixel lighter than the plate
   becomes the plate exactly, so the photo's edge is not a line (multiply left
   it two levels off — the seam the audit measured). No scrim, no blurred twin,
   no figure over the photo: the reward is stated once, in the title. */
.rmp[data-theme="depth"] .rmp-card__media {
position: relative;
isolation: isolate;
aspect-ratio: 4 / 3;
max-block-size: 200px;
padding: 0;
background: var(--d-plate);
}
.rmp[data-theme="depth"] .rmp-card__img {
inline-size: 100%;
block-size: 100%;
object-fit: contain;
object-position: center;
mix-blend-mode: darken;
transform: none;
}
.rmp[data-theme="depth"] .rmp-card__art {
box-sizing: border-box;
padding: 12px;
background: transparent;
}
.rmp[data-theme="depth"] .rmp-card__art-photo {
border-radius: 12px;
background: transparent;
}
.rmp[data-theme="depth"] .rmp-card__art-photo img {
inline-size: 100%;
block-size: 100%;
border-radius: 12px;
object-fit: contain;
object-position: center;
mix-blend-mode: darken;
}
/* No product photo: the reward's family on the theme's paper — a truck for
   shipping, a gift for a gift, the tag for a discount — on one soft accent
   disc. A store-wide threshold never borrows a catalogue rack to look
   illustrated. */
.rmp[data-theme="depth"] .rmp-card__plate {
display: grid;
place-items: center;
inline-size: 100%;
block-size: 100%;
background: var(--rmp-surface-2);
color: var(--rmp-accent-text);
}
.rmp[data-theme="depth"] .rmp-card__plate .rmp-ico {
box-sizing: content-box;
inline-size: 34px;
block-size: 34px;
padding: 16px;
border-radius: 50%;
stroke-width: 1.4;
background: color-mix(in srgb, var(--rmp-accent) 8%, var(--rmp-surface));
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--rmp-accent) 14%, transparent), var(--rmp-card-shadow);
}
/* The reward's family, in the shadow of the photo's other corner: a truck for
   shipping, a gift for a gift, the tag for a discount. It never spells the
   reward out — that would be the second statement. */
.rmp[data-theme="depth"] .rmp-card__mark {
position: absolute;
z-index: var(--rmp-z-sticky, 2);
inset-block-end: 12px;
inset-inline-start: 12px;
display: grid;
place-items: center;
inline-size: 28px;
block-size: 28px;
border-radius: 50%;
color: var(--rmp-ink-2);
background: color-mix(in srgb, var(--rmp-card) 88%, transparent);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
box-shadow: var(--rmp-card-shadow), inset 0 0 0 1px color-mix(in srgb, var(--rmp-card-line) 72%, transparent);
}
.rmp[data-theme="depth"] .rmp-card__mark .rmp-ico {
inline-size: 16px;
block-size: 16px;
}
.rmp[data-theme="depth"] .rmp-card__done {
/* The chip hugs the corner: both inline edges must not be set, or the chip stretches across the whole card. */ inset-block-start: 8px;
inset-inline-start: auto;
inset-inline-end: 8px;
border-radius: var(--rmp-radius-chip);
padding: 4px 8px;
font-size: 12px;
font-weight: 700;
line-height: 1.5;
background: color-mix(in srgb, #14724b 10%, var(--rmp-card));
color: #0f5c3c;
box-shadow: inset 0 0 0 1px color-mix(in srgb, #14724b 30%, transparent), var(--rmp-card-shadow);
z-index: var(--rmp-z-sticky, 2);
animation: depth-pop 500ms var(--d-spring) both;
}
.rmp[data-theme="depth"][data-mode="dark"] .rmp-card__done {
background: color-mix(in srgb, #34a877 16%, var(--rmp-card));
color: #8df3c4;
box-shadow: inset 0 0 0 1px color-mix(in srgb, #34a877 36%, transparent);
}
.rmp[data-theme="depth"] .rmp-card__done .rmp-ico {
width: 12px;
height: 12px;
}
@keyframes depth-pop {
from {
transform: scale(0.5);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
/* Foot: the offer's own name (two lines at most), the reward line only when the
   title did not already say it, then the ask and its slim bar on one line —
   the bar is printed once there is something to fill, never as an empty track
   floating beside the words. */
.rmp[data-theme="depth"] .rmp-card__body {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 8px;
padding: 12px;
}
/* Type only: the box (line clamp with its ellipsis, alignment, overflow) is
   core-shell's, so a theme change there reaches depth without an override here
   (round 4). */
.rmp[data-theme="depth"] .rmp-card__title {
text-wrap: pretty;
font-size: var(--rmp-fs-card);
font-weight: 700;
letter-spacing: -0.01em;
line-height: 1.6;
padding-block: 1px;
}
.rmp[data-theme="depth"] .rmp-card__reward {
display: block;
font-size: var(--rmp-fs-label);
font-weight: 400;
line-height: 1.6;
padding-block: 1px;
margin-top: 0;
color: var(--rmp-ink-2);
}
.rmp[data-theme="depth"] .rmp-card__meter {
flex: none;
inline-size: auto;
display: block;
height: 4px;
margin: 2px 0 0;
border-radius: 999px;
overflow: hidden;
background: var(--rmp-track);
}
.rmp[data-theme="depth"] .rmp-card__fill {
display: block;
height: 100%;
border-radius: 999px;
background: var(--rmp-accent);
transition: width 400ms var(--d-ease);
}
/* A finished offer's rail is the success state, the same green as the detail's
   completed meter. */
.rmp[data-theme="depth"] .rmp-card[data-state="done"] .rmp-card__fill {
background: var(--rmp-success);
}
/* What is left, in words. The base forces `direction: ltr` on this node for
   figures; an Arabic phrase has to read the way it was written, so the theme
   takes the direction back and aligns to the start edge. Every figure in the
   theme is the Arabic face with tabular numerals — nothing is monospaced. */
.rmp[data-theme="depth"] .rmp-card__count {
display: block;
direction: inherit;
text-align: start;
font-family: var(--rmp-font);
font-size: var(--rmp-fs-ask);
font-weight: 600;
line-height: 1.45;
letter-spacing: 0;
color: var(--rmp-accent-text);
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="depth"] .rmp-card[data-state="done"] .rmp-card__count {
color: var(--rmp-success);
}
.rmp[data-theme="depth"] .rmp-card__count[hidden] {
display: none;
}
.rmp[data-theme="depth"] .rmp-card:hover {
background: color-mix(in srgb, var(--rmp-accent) 4%, var(--rmp-card));
}
/* ------------------------------------------------------------ empty state --- */
.rmp[data-theme="depth"] .rmp-empty {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
padding: 24px 16px;
text-align: center;
}
.rmp[data-theme="depth"] .rmp-empty[hidden] {
display: none;
}
.rmp[data-theme="depth"] .rmp-empty__art {
width: 128px;
height: 108px;
color: var(--rmp-accent);
opacity: 0.95;
}
.rmp[data-theme="depth"] .rmp-empty__art svg {
width: 100%;
height: 100%;
display: block;
}
.rmp[data-theme="depth"] .rmp-empty__text {
font-size: 16px;
font-weight: 700;
line-height: 1.4;
color: var(--rmp-ink);
}
/* ------------------------------------------------------------- the offer --- */
.rmp[data-theme="depth"] .rmp-hero {
position: relative;
isolation: isolate;
display: grid;
place-items: center;
overflow: clip;
inline-size: 100%;
border-radius: var(--rmp-radius-card);
background: var(--d-plate);
box-shadow: none;
}
/* Decision 3: a full-width plate, never a centred thumbnail — 219px tall at 390
   (>=200) and 192px at 360 (>=172), the gift included. The base's square/island
   frame is answered at the same weight so the photo takes the whole plate. */
.rmp[data-theme="depth"] .rmp-screen--offer .rmp-hero:has(img) {
inline-size: 100%;
margin-inline: 0;
aspect-ratio: auto;
block-size: max(172px, 26dvh);
max-block-size: none;
padding: 0;
}
.rmp[data-theme="depth"] .rmp-hero__img {
position: relative;
z-index: var(--rmp-z-content, 0);
box-sizing: border-box;
inline-size: 100%;
/* A definite height: a percentage against the grid's `max()` height fell back to
   the photo's own ratio and the contain box grew past the plate. */
block-size: max(172px, 26dvh);
max-inline-size: 100%;
border-radius: 0;
box-shadow: none;
object-fit: contain;
object-position: center;
mix-blend-mode: darken;
}
.rmp[data-theme="depth"] .rmp-hero[data-media="plate"] {
background: var(--d-plate);
overflow: hidden;
}
.rmp[data-theme="depth"] .rmp-hero .rmp-card__art {
background: transparent;
}
.rmp[data-theme="depth"] .rmp-hero .rmp-card__art--plate {
inline-size: 100%;
block-size: 100%;
}
.rmp[data-theme="depth"] .rmp-hero .rmp-card__plate--hero .rmp-ico {
inline-size: 56px;
block-size: 56px;
padding: 20px;
}
/* The base gives a gift's frame less height so its plan fits; decision 3 keeps the
   hero at 200px for every offer, so depth holds its own height there. */
.rmp[data-theme="depth"] .rmp-screen--offer:has(.rmp-prize) .rmp-hero:has(img) {
inline-size: 100%;
block-size: max(172px, 26dvh);
max-block-size: none;
}
@media (min-width: 640px) {
.rmp[data-theme="depth"] .rmp-screen--offer .rmp-hero:has(img),
.rmp[data-theme="depth"] .rmp-screen--offer:has(.rmp-prize) .rmp-hero:has(img) {
inline-size: 100%;
block-size: min(280px, 25dvh);
max-block-size: none;
}
.rmp[data-theme="depth"] .rmp-hero__img {
block-size: min(280px, 25dvh);
}
}
/* v5.1 §B — the labelled bookmark rides the title row as a soft secondary
   pill: the plan's next step keeps the one primary action. */
.rmp[data-theme="depth"] .rmp-otop {
display: flex;
align-items: flex-start;
gap: 8px;
margin-top: 16px;
}
.rmp[data-theme="depth"] .rmp-otop .rmp-otitle {
flex: 1;
min-width: 0;
margin-top: 0;
}
.rmp[data-theme="depth"] .rmp-save--labelled {
flex: none;
border-radius: 999px;
border-color: var(--rmp-line-2);
background: linear-gradient(180deg, color-mix(in srgb, var(--rmp-surface) 100%, #fff 6%), var(--rmp-surface));
color: var(--rmp-ink-2);
box-shadow: var(--rmp-card-shadow);
}
.rmp[data-theme="depth"] .rmp-save--labelled[aria-pressed="true"] {
border-color: transparent;
background: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-surface));
color: var(--rmp-accent-text);
}
.rmp[data-theme="depth"] .rmp-save--labelled::before {
display: none;
}
.rmp[data-theme="depth"] .rmp-otitle {
text-wrap: pretty;
margin-top: 16px;
font-size: var(--rmp-fs-detail);
font-weight: 700;
line-height: 1.35;
letter-spacing: -0.015em;
}
.rmp[data-theme="depth"] .rmp-odesc {
margin-top: 8px;
font-size: var(--rmp-fs-body);
line-height: 1.6;
color: var(--rmp-ink-2);
}
/* Sections: a quiet 13px label in the muted ink. No rule running off it — one
   line of type is the chrome. */
.rmp[data-theme="depth"] .rmp-section {
margin-top: 24px;
gap: 8px;
}
.rmp[data-theme="depth"] .rmp-section__title,
.rmp[data-theme="depth"] .rmp-terms__title {
display: block;
font-size: var(--rmp-fs-label);
font-weight: 600;
letter-spacing: 0;
text-transform: none;
color: var(--rmp-ink-3);
margin-bottom: 4px;
}
/* ---------------------------------------- «المطلوب» · the checklist (§8.2) ---
 * The markup is the runtime's (`h.checklist`); these are the theme's clothes on
 * its hooks. team-03's treatment: a product is a white card with one hairline
 * and two soft shadows, a doorway (a category, a brand, a tag, a pool) is the
 * same card washed with the accent, and a filled slot turns green. One section
 * label, uppercase, with the hairline running off it — the same rule the old
 * `.rmp-section__title` used, so the page reads the same as before.
 *
 * Stacking (§9): every card, slot, tile and hero is `position: relative;
 * isolation: isolate`, so a tick, a collage or a veil can only ever paint
 * inside its own row; local depths are the panel's own tokens and never above
 * the sticky bars. */
.rmp[data-theme="depth"] .rmp-section--needed {
gap: 12px;
}
/* «أضف» on a product slot: the same quiet button the design uses everywhere. */
.rmp[data-theme="depth"] .rmp-btn--add {
border-radius: var(--rmp-radius-btn);
padding: 8px 12px;
min-height: 0;
font-size: 13px;
font-weight: 600;
white-space: nowrap;
background: var(--rmp-surface-2);
border: 1px solid var(--rmp-line);
color: var(--rmp-ink);
transition: background 200ms var(--d-ease), transform 200ms var(--d-spring), color 200ms var(--d-ease), box-shadow 200ms var(--d-ease);
}
.rmp[data-theme="depth"] .rmp-btn--add:hover {
background: var(--rmp-accent);
border-color: var(--rmp-accent);
color: var(--rmp-accent-ink);
transform: translateY(-1px);
}
.rmp[data-theme="depth"] .rmp-btn--add.is-added,
.rmp[data-theme="depth"] .rmp-btn--add[disabled] {
background: var(--rmp-accent);
border-color: var(--rmp-accent);
color: var(--rmp-accent-ink);
}
/* «اختر» is the add control for a product with options, so it wears its shape. */
.rmp[data-theme="depth"] a.rmp-btn--add {
text-decoration: none;
display: inline-flex;
align-items: center;
}
/* The coupon: a ticket. Gold value plate on top, a dashed tear line, the code
   below it — blurred while it is locked, sharp and copyable once it is not. */
.rmp[data-theme="depth"] .rmp-coupon {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 0 8px;
padding: 0;
border-radius: 15px;
background: var(--rmp-card);
background-image: none;
box-shadow: 0 0 0 1px var(--rmp-line), var(--rmp-card-shadow-hover), var(--rmp-hi);
overflow: hidden;
}
.rmp[data-theme="depth"] .rmp-coupon__top {
grid-column: 1 / -1;
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
}
.rmp[data-theme="depth"] .rmp-coupon__value {
display: grid;
place-items: center;
min-width: 46px;
height: 46px;
flex: none;
padding: 0 8px;
border-radius: 12px;
white-space: nowrap;
background: linear-gradient(155deg, var(--rmp-accent), color-mix(in srgb, var(--rmp-accent) 62%, #2a1c06));
color: #fff;
font-family: var(--rmp-font);
font-size: 16px;
font-weight: 700;
letter-spacing: -0.02em;
font-variant-numeric: tabular-nums;
box-shadow: 0 2px 8px color-mix(in srgb, var(--rmp-accent) 34%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}
.rmp[data-theme="depth"] .rmp-coupon__meta {
display: flex;
flex-direction: column;
min-width: 0;
}
.rmp[data-theme="depth"] .rmp-coupon__name {
display: block;
font-size: 13px;
font-weight: 600;
line-height: 1.4;
color: var(--rmp-ink);
}
.rmp[data-theme="depth"] .rmp-coupon__line {
display: block;
font-size: 12px;
color: var(--rmp-ink-3);
margin-top: 4px;
}
/* Locked: a lock and a blurred code on one line, the sentence under it.
   Revealed: the code and its copy button, then the status line. A grid, not a
   wrapping flex row, so the ticket never reflows as the code arrives. */
.rmp[data-theme="depth"] .rmp-coupon__body {
grid-column: 1;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
align-items: center;
gap: 8px;
padding: 12px 16px;
border-top: 1px dashed var(--rmp-line);
background: color-mix(in srgb, var(--rmp-accent) 4%, var(--rmp-card));
}
.rmp[data-theme="depth"] .rmp-coupon__lock {
grid-column: 1;
grid-row: 1;
display: flex;
align-items: center;
color: var(--rmp-ink-3);
}
.rmp[data-theme="depth"] .rmp-coupon__lock .rmp-ico {
width: 15px;
height: 15px;
}
.rmp[data-theme="depth"] .rmp-coupon[data-state="revealed"] .rmp-coupon__lock,
.rmp[data-theme="depth"] .rmp-coupon[data-state="applied"] .rmp-coupon__lock {
display: none;
}
.rmp[data-theme="depth"] .rmp-coupon__mask {
grid-column: 2;
grid-row: 1;
min-width: 0;
font-size: 16px;
font-weight: 700;
letter-spacing: 0.16em;
color: var(--rmp-ink-3);
filter: blur(5px);
opacity: 0.5;
user-select: none;
}
.rmp[data-theme="depth"] .rmp-coupon__mask[hidden] {
display: none;
}
/* The code is ALWAYS in the DOM; only its sharpness is animated, so a dropped
   frame can never hide the reward. */
.rmp[data-theme="depth"] .rmp-coupon__code {
grid-column: 2;
grid-row: 1;
min-width: 0;
font-family: var(--rmp-font);
font-size: 18px;
font-weight: 700;
letter-spacing: 0.14em;
color: var(--rmp-ink);
text-align: start;
font-variant-numeric: tabular-nums;
animation: depth-code-in 420ms var(--d-ease) both;
}
.rmp[data-theme="depth"] .rmp-coupon__code[hidden] {
display: none;
}
@keyframes depth-code-in {
from {
filter: blur(7px);
opacity: 0.35;
}
to {
filter: blur(0);
opacity: 1;
}
}
.rmp[data-theme="depth"] .rmp-coupon__status {
grid-column: 1;
grid-row: 2;
min-width: 0;
font-size: 12px;
font-weight: 600;
line-height: 1.4;
color: var(--rmp-ink-2);
}
.rmp[data-theme="depth"] .rmp-coupon[data-state="applied"] .rmp-coupon__status,
.rmp[data-theme="depth"] .rmp-coupon[data-state="revealed"] .rmp-coupon__status {
color: #14724b;
}
.rmp[data-theme="depth"][data-mode="dark"] .rmp-coupon[data-state="applied"] .rmp-coupon__status,
.rmp[data-theme="depth"][data-mode="dark"] .rmp-coupon[data-state="revealed"] .rmp-coupon__status {
color: #5fd3a2;
}
.rmp[data-theme="depth"] .rmp-coupon__status:empty {
display: none;
}
.rmp[data-theme="depth"] .rmp-coupon__status .rmp-ico {
width: 12px;
height: 12px;
}
.rmp[data-theme="depth"] .rmp-coupon__expiry {
grid-column: 2;
grid-row: 2;
min-width: 0;
text-align: end;
font-size: 12px;
font-weight: 600;
color: var(--rmp-ink-3);
}
/* Locked, the sentence has no expiry beside it, so it takes the whole line. */
.rmp[data-theme="depth"] .rmp-coupon[data-state="locked"] .rmp-coupon__status {
grid-column: 1 / -1;
}
.rmp[data-theme="depth"] .rmp-coupon__expiry[hidden] {
display: none;
}
.rmp[data-theme="depth"] .rmp-coupon .rmp-btn--unlock {
grid-column: 2;
grid-row: 2;
margin-inline-end: 16px;
display: inline-flex;
align-items: center;
padding: 8px 12px;
min-height: 0;
border-radius: var(--rmp-radius-btn);
font-size: 13px;
font-weight: 700;
background: color-mix(in srgb, var(--rmp-accent) 10%, var(--rmp-card));
border: 1px solid color-mix(in srgb, var(--rmp-accent) 30%, var(--rmp-line));
color: color-mix(in srgb, var(--rmp-accent) 84%, #402a06);
transition: background 200ms var(--d-ease), transform 200ms var(--d-spring), color 200ms var(--d-ease);
}
.rmp[data-theme="depth"] .rmp-coupon .rmp-btn--unlock:hover {
background: var(--rmp-accent);
border-color: var(--rmp-accent);
color: var(--rmp-accent-ink);
transform: translateY(-1px);
}
.rmp[data-theme="depth"] .rmp-coupon .rmp-btn--unlock[aria-busy="true"] {
opacity: 0.6;
}
.rmp[data-theme="depth"] .rmp-coupon .rmp-btn--copy {
grid-column: 2;
grid-row: 2;
margin-inline-end: 16px;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
min-height: 0;
border-radius: var(--rmp-radius-btn);
font-size: 13px;
font-weight: 700;
background: color-mix(in srgb, var(--rmp-accent) 10%, var(--rmp-card));
border: 1px solid color-mix(in srgb, var(--rmp-accent) 30%, var(--rmp-line));
color: color-mix(in srgb, var(--rmp-accent) 84%, #402a06);
transition: background 200ms var(--d-ease), transform 200ms var(--d-spring), color 200ms var(--d-ease);
}
.rmp[data-theme="depth"] .rmp-coupon .rmp-btn--copy:hover {
background: var(--rmp-accent);
border-color: var(--rmp-accent);
color: var(--rmp-accent-ink);
transform: translateY(-1px);
}
.rmp[data-theme="depth"] .rmp-coupon .rmp-btn--copy.is-copied {
background: #1f8a5b;
border-color: #1f8a5b;
color: #fff;
}
.rmp[data-theme="depth"] .rmp-coupon .rmp-btn--copy .rmp-ico {
width: 13px;
height: 13px;
}
/* Locked: the value plate stays, the ticket is not yet ours to read. */
.rmp[data-theme="depth"] .rmp-coupon[data-state="locked"] .rmp-coupon__body {
background: var(--rmp-surface-2);
}
/* Unlocked: the ticket turns green, the way it does in the design. */
.rmp[data-theme="depth"] .rmp-coupon[data-state="revealed"] .rmp-coupon__body,
.rmp[data-theme="depth"] .rmp-coupon[data-state="applied"] .rmp-coupon__body {
background: color-mix(in srgb, #1f8a5b 8%, var(--rmp-card));
border-top-color: color-mix(in srgb, #1f8a5b 24%, var(--rmp-line));
}
/* The terms: a plain list on a sunken well, always fully visible. */
.rmp[data-theme="depth"] .rmp-terms {
margin-top: var(--rmp-plan-gap, 24px);
padding: 16px;
border-radius: var(--rmp-radius-card);
background: var(--rmp-surface-2);
box-shadow: inset 0 0 0 1px var(--rmp-line-2);
}
.rmp[data-theme="depth"] .rmp-terms li {
position: relative;
font-size: var(--rmp-fs-body);
line-height: 1.55;
color: var(--rmp-ink-terms);
padding-inline-start: 14px;
margin-bottom: 6px;
}
.rmp[data-theme="depth"] .rmp-terms li:last-child {
margin-bottom: 0;
}
.rmp[data-theme="depth"] .rmp-terms li::before {
content: "";
position: absolute;
inset-inline-start: 2px;
inset-block-start: 9px;
width: 4px;
height: 4px;
border-radius: 50%;
background: color-mix(in srgb, var(--rmp-ink) 34%, transparent);
}

/* --------------------------------------------------- launcher, toast, hint --- */
.rmp[data-theme="depth"] .rmp-launcher {
border-radius: 20px;
background-image: radial-gradient(120% 100% at 30% 12%, color-mix(in srgb, var(--rmp-accent) 88%, #fff) 0%, var(--rmp-accent) 46%, color-mix(in srgb, var(--rmp-accent) 74%, #2a1c06) 100%);
box-shadow: 0 1px 1px rgba(50, 32, 4, 0.16), 0 4px 10px color-mix(in srgb, var(--rmp-accent) 34%, transparent),
    0 14px 30px color-mix(in srgb, var(--rmp-accent) 26%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.34),
    inset 0 -2px 6px rgba(60, 36, 0, 0.2);
transition: transform 300ms var(--d-spring), box-shadow 240ms var(--d-ease);
}
.rmp[data-theme="depth"] .rmp-launcher:hover {
transform: scale(1.055);
}
.rmp[data-theme="depth"] .rmp-launcher:active {
transform: scale(0.955);
}
/* team-03's own open state (widget.css: `.rm-root[data-open="1"] .rm-launch`), at
   its own 0.94: at the base's 0.9 the painted tile pulls 3px off the screen edge
   and the panel's tail lands 3px below the launcher's centre. */
.rmp[data-theme="depth"][data-open="true"] .rmp-launcher {
transform: scale(0.94);
}
.rmp[data-theme="depth"] .rmp-nudge { box-shadow: 0 0 0 1px var(--rmp-line), var(--rmp-card-shadow-hover), var(--rmp-hi); }
/* ==================================================== v5 discovery (§5.1–4) ===
 * The filter row, the teaser, the bookmark and the launcher badge are the
 * runtime's (docs/POCKET_V5_DISCOVERY_CONTRACT.md, v5.1 §A–C); geometry stays
 * with pocket.css and the filter row is NOT sticky (§A). This block tunes their
 * surface, radius and type into team-03's soft depth: warm paper, 18px corners,
 * one accent, ambient shadow. */
.rmp[data-theme="depth"] .rmp-filter {
border-radius: 999px;
border-color: var(--rmp-line-2);
color: var(--rmp-ink-2);
}
.rmp[data-theme="depth"] .rmp-filter[aria-pressed="true"] {
border-color: transparent;
background: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-surface));
color: var(--rmp-accent-text);
}
.rmp[data-theme="depth"] .rmp-filter__n {
min-inline-size: var(--rmp-chip-count);
block-size: var(--rmp-chip-count);
border-radius: 999px;
background: var(--rmp-surface-2);
color: var(--rmp-ink-3);
font-size: 12px;
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="depth"] .rmp-filter[aria-pressed="true"] .rmp-filter__n {
background: var(--rmp-accent);
color: var(--rmp-accent-ink);
}
.rmp[data-theme="depth"] .rmp-teaser {
background: var(--rmp-card);
border-radius: var(--rmp-radius-card);
box-shadow: var(--rmp-shadow), var(--rmp-hi);
}
.rmp[data-theme="depth"] .rmp-teaser__media {
border-radius: var(--rmp-radius-card);
}
.rmp[data-theme="depth"] .rmp-teaser__eyebrow {
font-size: 12px;
font-weight: 700;
color: var(--rmp-ink-3);
}
.rmp[data-theme="depth"][dir="ltr"] .rmp-teaser__eyebrow {
letter-spacing: 0.12em;
text-transform: uppercase;
}
.rmp[data-theme="depth"] .rmp-teaser__title {
font-size: 14px;
font-weight: 700;
letter-spacing: -0.01em;
line-height: 1.5;
color: var(--rmp-ink);
}
.rmp[data-theme="depth"] .rmp-teaser__reward {
font-size: 12px;
font-weight: 600;
color: var(--rmp-accent-text);
}
/* v5.1 §B — the bookmark. The outline reads ink-2, the filled form takes the
   accent; the resting circle is lifted by team-03's ambient shadow. */
.rmp[data-theme="depth"] .rmp-save {
border-radius: 50%;
color: var(--rmp-ink-2);
}
.rmp[data-theme="depth"] .rmp-save::before {
background: var(--rmp-card);
box-shadow: var(--rmp-card-shadow), var(--rmp-hi);
}
.rmp[data-theme="depth"] .rmp-save[aria-pressed="true"] {
color: var(--rmp-accent-text);
}
.rmp[data-theme="depth"] .rmp-save[aria-pressed="true"]::before {
background: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-card));
}
/* Over a card's media the bookmark is a 30px frosted circle inside the 44px tap
   target: the card surface at 88%, a blur, the ambient shadow. */
.rmp[data-theme="depth"] .rmp-card > .rmp-save {
background: transparent;
}
.rmp[data-theme="depth"] .rmp-card > .rmp-save::before {
content: "";
position: absolute;
inset: 6px;
border-radius: 50%;
background: color-mix(in srgb, var(--rmp-card) 88%, transparent);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
box-shadow: var(--rmp-card-shadow), var(--rmp-hi);
}
.rmp[data-theme="depth"] .rmp-card > .rmp-save[aria-pressed="true"]::before {
background: color-mix(in srgb, var(--rmp-accent) 16%, var(--rmp-card));
}
.rmp[data-theme="depth"] .rmp-badge {
border-radius: 999px;
background: linear-gradient(155deg, var(--rmp-accent), color-mix(in srgb, var(--rmp-accent) 62%, #2a1c06));
color: var(--rmp-accent-ink);
box-shadow: 0 2px 8px color-mix(in srgb, var(--rmp-accent) 34%, transparent), 0 0 0 2px var(--rmp-surface);
}

/* --------------------------------------------------------------- motion --- */
@media (prefers-reduced-motion: reduce) {
.rmp[data-theme="depth"] .rmp-card:hover,
.rmp[data-theme="depth"] .rmp-launcher:hover,
.rmp[data-theme="depth"] .rmp-btn--add:hover,
.rmp[data-theme="depth"] .rmp-btn--browse:hover,
.rmp[data-theme="depth"] .rmp-coupon .rmp-btn--copy:hover {
transform: none;
}
.rmp[data-theme="depth"] .rmp-card__done {
animation: none;
}
.rmp[data-theme="depth"] .rmp-coupon__code {
animation: none;
}
}
.rmp--still[data-theme="depth"] .rmp-card:hover,
.rmp--still[data-theme="depth"] .rmp-launcher:hover {
transform: none;
}
.rmp--still[data-theme="depth"] .rmp-card__done,
.rmp--still[data-theme="depth"] .rmp-coupon__code {
animation: none;
}

/* V-C10: the popover's foot is 20px — the same rhythm as its top and its sides
   (A6-DEPTH-03). Phones keep 16 + the safe-area inset. */
@media (min-width: 640px) {
.rmp[data-theme="depth"] {
--rmp-list-pad-end: 20px;
}
}

/* F-depth-03: the terms are a folded disclosure now, so the depth well and its
   4px bullets live on the opened panel — the row itself stays the shared 44px
   control. */
.rmp[data-theme="depth"] .rmp-disclosure {
margin-top: var(--rmp-plan-gap, 24px);
}
.rmp[data-theme="depth"] .rmp-disclosure__inner > ul {
margin: 8px 0 4px;
padding: 12px 16px 14px;
border-radius: var(--rmp-radius-card);
background: var(--rmp-surface-2);
box-shadow: inset 0 0 0 1px var(--rmp-line-2);
}
.rmp[data-theme="depth"] .rmp-disclosure li {
font-size: var(--rmp-fs-body, 14px);
line-height: 1.6;
padding-inline-start: 14px;
color: var(--rmp-ink-terms);
}
.rmp[data-theme="depth"] .rmp-disclosure li::before {
inset-inline-start: 2px;
inset-block-start: 9px;
width: 4px;
height: 4px;
border-radius: 50%;
background: color-mix(in srgb, var(--rmp-ink) 34%, transparent);
opacity: 1;
}

/* Rimaya pocket v3 — theme: friendly.
 *
 * A PORT of prototypes/proposals/team-02 «Friendly Rewards», not a skin. Every
 * rule below exists because team-02 drew it: the warm brown ink ramp, the accent
 * wash over the photo, the double scrim, the gradient reward plate, the 2:1
 * banner card with its overlay body, the tint shipping bar, the uppercase
 * hairline section labels, the dotted slot tally, the dashed coupon, the terms
 * box. Change a number and the design changes.
 *
 * Scoped to `.rmp[data-theme="friendly"]` per contract §6. The geometry — panel
 * box, screen scroll, launcher — belongs to the base sheet and is left alone;
 * a theme owns what is INSIDE the panel and the panel's own chrome.
 *
 * Merchant colour enters only through --rmp-accent / --rmp-accent-2 /
 * --rmp-accent-ink. Nothing here hard-codes the team's #f2683c.
 */
.rmp[data-theme="friendly"] {
/* team-02's rhythm: one duration, one ease, one spring. The launcher keeps the shared gift-box spring, which belongs to the host, not to the panel. */ --fr-ease: cubic-bezier(0.22, 0.72, 0.3, 1);
--fr-spring: cubic-bezier(0.34, 1.46, 0.64, 1);
--fr-accent-2: color-mix(in srgb, var(--rmp-accent) 62%, #ff9a5b);
--fr-tint: color-mix(in srgb, var(--rmp-accent) 9%, transparent);
--fr-tint-2: color-mix(in srgb, var(--rmp-accent) 16%, transparent);
/* the plate a product photo is multiplied into: white studio backgrounds melt
   into this tint, so one photo fills the frame with no seam and no copy behind */
--fr-plate: color-mix(in srgb, var(--rmp-accent) 10%, var(--rmp-surface-2));
--fr-ok: #0f7a4d;
--fr-ok-tint: color-mix(in srgb, #0f7a4d 12%, transparent);
--rmp-surface: #ffffff;
--rmp-surface-2: #f7f2ef;
--rmp-card: #f7f2ef;
--rmp-card-line: color-mix(in srgb, var(--rmp-accent) 12%, #ece4de);
--rmp-line: #ece4de;
--rmp-ink: #241a15;
--rmp-ink-2: #6b5a50;
--rmp-ink-3: #7a675b;
--rmp-ink-terms: #6b5a50;
--rmp-track: color-mix(in srgb, var(--rmp-accent) 16%, #fff);
--rmp-accent-text: var(--rmp-accent);
--rmp-shadow: 0 2px 6px rgba(66, 36, 20, 0.06), 0 26px 48px -22px rgba(66, 36, 20, 0.34);
--rmp-card-shadow: 0 1px 2px rgba(66, 36, 20, 0.05), 0 10px 22px -14px rgba(66, 36, 20, 0.3);
--rmp-card-shadow-hover: 0 2px 6px rgba(66, 36, 20, 0.08), 0 18px 30px -18px rgba(66, 36, 20, 0.28);
--rmp-success: var(--fr-ok);
--rmp-success-ink: #ffffff;
--rmp-radius: 20px;
--rmp-radius-card: 16px;
--rmp-radius-sm: 13px;
--rmp-radius-chip: 999px;
--rmp-radius-btn: 999px;
--rmp-meter: 4px;
--rmp-gutter: 16px;
--rmp-title-weight: 700;
/* Contract §11.3 — team-02's plan is the softest of the four: 20px corners, a
   warm surface and a rounded hairline. Only these six. */
--rmp-plan-radius: 20px;
--rmp-plan-surface: var(--rmp-surface-2);
--rmp-plan-line: var(--rmp-line);
--rmp-plan-tint: color-mix(in srgb, var(--rmp-accent) 7%, var(--rmp-surface-2));
--rmp-plan-ink: var(--rmp-ink);
--rmp-plan-muted: var(--rmp-ink-2);
}
.rmp[data-theme="friendly"][data-mode="dark"] {
--fr-tint: color-mix(in srgb, var(--rmp-accent) 13%, transparent);
--fr-tint-2: color-mix(in srgb, var(--rmp-accent) 22%, transparent);
--fr-plate: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-surface-2));
--fr-ok: #4ec98d;
--fr-ok-tint: color-mix(in srgb, #4ec98d 13%, transparent);
--rmp-surface: #1d1714;
--rmp-surface-2: #241d19;
--rmp-card: #241d19;
--rmp-card-line: color-mix(in srgb, var(--rmp-accent) 18%, #322822);
--rmp-line: #322822;
--rmp-ink: #f3ece7;
--rmp-ink-2: #b8a99f;
--rmp-ink-3: #a1907f;
--rmp-ink-terms: #b8a99f;
--rmp-track: color-mix(in srgb, var(--rmp-accent) 18%, #241d19);
--rmp-shadow: 0 2px 6px rgba(0, 0, 0, 0.34), 0 26px 48px -20px rgba(0, 0, 0, 0.7);
--rmp-card-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 10px 22px -14px rgba(0, 0, 0, 0.6);
--rmp-card-shadow-hover: 0 2px 6px rgba(0, 0, 0, 0.4), 0 18px 30px -18px rgba(0, 0, 0, 0.6);
--rmp-success-ink: #10231a;
/* the plan on dark cocoa: the tint gains a step so the one emphasised block
   still reads as raised */
--rmp-plan-tint: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-surface-2));
}
/* ============================================================= launcher ===
 * team-02's launcher is a surface tile with a warm accent ring, and its open
 * state is a change of COLOUR (widget.css:66), not of size. So the base's
 * `scale(0.9)` on open is dropped here: it would pull the painted tile 3px off
 * the screen edge and land the panel's tail 3px below the launcher's centre. */
.rmp[data-theme="friendly"] .rmp-launcher {
background: var(--rmp-surface);
box-shadow: 0 0 0 1px color-mix(in srgb, var(--rmp-accent) 26%, transparent), var(--rmp-shadow);
transition: transform 0.32s var(--fr-spring), box-shadow 0.32s var(--fr-ease), background-color 0.2s var(--fr-ease);
}
.rmp[data-theme="friendly"] .rmp-launcher:hover {
transform: translateY(-3px) scale(1.04);
}
.rmp[data-theme="friendly"] .rmp-launcher:active {
transform: translateY(0) scale(0.97);
}
.rmp[data-theme="friendly"] .rmp-launcher:focus-visible {
outline: 3px solid var(--rmp-accent);
outline-offset: 3px;
}
.rmp[data-theme="friendly"][data-open="true"] .rmp-launcher {
transform: none;
background: var(--fr-tint);
box-shadow: 0 0 0 1px var(--fr-tint-2), 0 2px 6px rgba(66, 36, 20, 0.06), 0 14px 28px -18px rgba(66, 36, 20, 0.3);
}
/* ============================================================== header ==== */
.rmp[data-theme="friendly"] .rmp-head {
justify-content: space-between;
height: var(--rmp-head-h, 56px);
padding-inline: 16px;
gap: 8px;
border-bottom: 0;
}
.rmp[data-theme="friendly"] .rmp-title {
flex: 1;
min-width: 0;
margin: 0;
font-size: var(--rmp-fs-title, 18px);
font-weight: 700;
line-height: 1.6;
letter-spacing: 0;
padding-block: 1px;
color: var(--rmp-ink);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* V-T3: the detail header is two controls and no title. The heading stays in the
   document as the dialog's own name, out of sight — never a title beside the
   product the screen is already about. */
.rmp[data-theme="friendly"][data-screen="offer"] .rmp-head {
justify-content: space-between;
}
.rmp[data-theme="friendly"][data-screen="offer"] .rmp-title {
position: absolute;
inline-size: 1px;
block-size: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.rmp[data-theme="friendly"] .rmp-back,
.rmp[data-theme="friendly"] .rmp-close,
.rmp[data-theme="friendly"] .rmp-head__btn {
display: grid;
place-items: center;
flex: none;
width: var(--rmp-icon-btn, 44px);
height: var(--rmp-icon-btn, 44px);
padding: 0;
border: 1px solid var(--rmp-line);
border-radius: 50%;
background: var(--rmp-surface-2);
color: var(--rmp-ink-2);
transition: background-color 0.16s var(--fr-ease), color 0.16s var(--fr-ease), transform 0.16s var(--fr-ease);
}
.rmp[data-theme="friendly"] .rmp-back:hover,
.rmp[data-theme="friendly"] .rmp-close:hover,
.rmp[data-theme="friendly"] .rmp-head__btn:hover {
background: var(--fr-tint);
color: var(--rmp-accent);
}
.rmp[data-theme="friendly"] .rmp-back:active,
.rmp[data-theme="friendly"] .rmp-close:active,
.rmp[data-theme="friendly"] .rmp-head__btn:active {
transform: scale(0.94);
}
/* A soft halo plus a hairline, unmistakable without shouting at rest. It is the
   KEYBOARD's ring (`:focus-visible` only), per docs/ACCESSIBILITY.md, focus
   policy 1: opening the panel or walking into an offer focuses the screen
   container, never «رجوع» or «إغلاق». */
.rmp[data-theme="friendly"] .rmp-back:focus-visible,
.rmp[data-theme="friendly"] .rmp-close:focus-visible,
.rmp[data-theme="friendly"] .rmp-head__btn:focus-visible {
outline: 1.5px solid var(--rmp-accent);
outline-offset: 2px;
box-shadow: 0 0 0 5px color-mix(in srgb, var(--rmp-accent) 16%, transparent);
}
.rmp[data-theme="friendly"] .rmp-back[hidden],
.rmp[data-theme="friendly"] .rmp-close[hidden] {
display: none;
}
/* the back chevron follows the reading direction, like the browse arrow */
.rmp[data-theme="friendly"][dir="rtl"] .rmp-back svg {
transform: scaleX(-1);
}
/* ========================================================== shipping bar == */
.rmp[data-theme="friendly"] .rmp-ship {
gap: 8px;
padding: 12px;
border-radius: var(--rmp-radius-card);
background-color: var(--rmp-surface);
background-image: linear-gradient(var(--fr-tint), var(--fr-tint));
border: 1px solid color-mix(in srgb, var(--rmp-accent) 16%, transparent);
}
.rmp[data-theme="friendly"] .rmp-ship__top {
display: flex;
align-items: center;
gap: 10px;
}
.rmp[data-theme="friendly"] .rmp-ship__ico {
display: grid;
place-items: center;
flex: none;
width: 26px;
height: 26px;
border-radius: 8px;
background: var(--rmp-accent);
color: var(--rmp-accent-ink);
}
.rmp[data-theme="friendly"] .rmp-ship__text {
flex: 1;
min-width: 0;
font-family: var(--rmp-font);
font-size: var(--rmp-ship-fs, 14px);
font-weight: 600;
line-height: 1.5;
color: var(--rmp-ink);
}
.rmp[data-theme="friendly"] .rmp-ship__amount {
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="friendly"] .rmp-ship__left {
flex: none;
display: inline-flex;
align-items: center;
color: var(--fr-ok);
}
.rmp[data-theme="friendly"] .rmp-ship__left:empty {
display: none;
}
.rmp[data-theme="friendly"] .rmp-ship__meter {
display: block;
inline-size: 100%;
block-size: var(--rmp-ship-track, 5px);
margin: 0;
border: 0;
border-radius: 999px;
background: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-surface));
overflow: hidden;
}
.rmp[data-theme="friendly"] .rmp-ship__fill {
display: block;
height: 100%;
border-radius: inherit;
background: var(--rmp-accent);
transition: width 420ms var(--fr-ease);
}
.rmp[data-theme="friendly"] .rmp-ship[data-done="true"] {
background-image: linear-gradient(var(--fr-ok-tint), var(--fr-ok-tint));
border-color: color-mix(in srgb, var(--fr-ok) 26%, transparent);
}
.rmp[data-theme="friendly"] .rmp-ship[data-done="true"] .rmp-ship__ico {
background: var(--fr-ok);
color: #fff;
}
.rmp[data-theme="friendly"] .rmp-ship[data-done="true"] .rmp-ship__left {
color: var(--fr-ok);
}
.rmp[data-theme="friendly"] .rmp-ship[data-done="true"] .rmp-ship__text {
color: var(--fr-ok);
}
.rmp[data-theme="friendly"] .rmp-ship[data-done="true"] .rmp-ship__fill {
background: var(--fr-ok);
}
/* ================================================================ card ====
 * A pocket row, not a banner: the product on a tinted plate (whole, multiplied
 * into the tint), the merchant's title on two lines, one reward statement and
 * the ask with its meter. The bookmark is a real grid column, so nothing sits
 * on anything and the card is short enough for three to a phone. */
.rmp[data-theme="friendly"] .rmp-offers {
gap: 12px;
}
/* §9: a card is its own stacking context, so its media and its runtime chrome
   can never cross a sticky bar or the header. */
.rmp[data-theme="friendly"] .rmp-card {
position: relative;
isolation: isolate;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: stretch;
border: 1px solid var(--rmp-card-line);
border-radius: var(--rmp-radius-card);
background: var(--rmp-surface);
box-shadow: var(--rmp-card-shadow);
transition: transform 0.22s var(--fr-ease), box-shadow 0.22s var(--fr-ease), border-color 0.2s var(--fr-ease);
}
.rmp[data-theme="friendly"] .rmp-card:hover {
transform: translateY(-2px);
border-color: color-mix(in srgb, var(--rmp-accent) 34%, var(--rmp-line));
box-shadow: var(--rmp-card-shadow-hover);
}
.rmp[data-theme="friendly"] .rmp-card:active {
transform: translateY(0) scale(0.995);
}
.rmp[data-theme="friendly"] .rmp-card__open {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
align-items: stretch;
color: var(--rmp-ink);
}
.rmp[data-theme="friendly"] .rmp-card__open:focus-visible {
outline: 2px solid var(--rmp-accent);
outline-offset: -2px;
}
/* v5.1 §D — the bookmark rides the card's trailing edge as a sibling of the
   open control, a LOCAL layer (z-index 1) of the isolated card so it can never
   cross the free-shipping bar. It is a column of its own: it overlaps nothing. */
.rmp[data-theme="friendly"] .rmp-card > .rmp-save {
position: relative;
inset: auto;
z-index: 1;
align-self: center;
justify-self: center;
margin-inline-end: 2px;
}
/* v5 §5.4 — the related edge in team-02's language: a warm accent hairline and a
   soft inner ring. Never a badge, never a word. */
.rmp[data-theme="friendly"] .rmp-card[data-related="true"] {
border-color: color-mix(in srgb, var(--rmp-accent) 54%, var(--rmp-card-line));
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--rmp-accent) 26%, transparent), var(--rmp-card-shadow);
}
.rmp[data-theme="friendly"] .rmp-card[data-related="true"]:hover {
border-color: color-mix(in srgb, var(--rmp-accent) 54%, var(--rmp-card-line));
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--rmp-accent) 26%, transparent), var(--rmp-card-shadow-hover);
}
.rmp[data-theme="friendly"] .rmp-card__media {
position: relative;
display: grid;
place-items: center;
inline-size: 96px;
min-block-size: 96px;
align-self: stretch;
padding: 0;
overflow: hidden;
isolation: isolate;
background-color: var(--rmp-surface-2);
background-image: linear-gradient(var(--fr-plate), var(--fr-plate));
}
/* The product, whole, multiplied into the tint: the studio's white becomes the
   plate, so the photo has no edge of its own and nothing is cropped. The image
   is out of flow so it can never size the row: every card in the list has one
   media box, photo or kind plate alike. */
.rmp[data-theme="friendly"] .rmp-card__img {
position: absolute;
inset: 0;
inline-size: 100%;
block-size: 100%;
object-fit: contain;
object-position: center;
mix-blend-mode: multiply;
transition: transform 0.4s var(--fr-ease);
}
.rmp[data-theme="friendly"] .rmp-card:hover .rmp-card__img {
transform: scale(1.03);
}
.rmp[data-theme="friendly"] .rmp-card__body {
position: static;
inset: auto;
display: flex;
flex-direction: column;
justify-content: center;
gap: 6px;
padding: 12px;
z-index: auto;
align-items: stretch;
}
/* The reward plate: a real plate, the reward is the loudest thing on the card. */
.rmp[data-theme="friendly"] .rmp-card__plate {
display: inline-flex;
align-items: center;
gap: 6px;
align-self: flex-start;
padding: 5px 12px 6px;
border-radius: 13px;
background: linear-gradient(150deg, var(--fr-accent-2), var(--rmp-accent));
color: var(--rmp-accent-ink);
box-shadow: 0 8px 18px -8px rgba(0, 0, 0, 0.6);
font-family: var(--rmp-font);
font-weight: 700;
line-height: 1.1;
letter-spacing: -0.02em;
}
.rmp[data-theme="friendly"] .rmp-card__plate b {
font-size: 22px;
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="friendly"] .rmp-card__plate span {
font-size: 12px;
font-weight: 700;
opacity: 0.95;
}
/* An imageless offer's tile: the reward's kind on the tint, never a borrowed
   store photo. */
.rmp[data-theme="friendly"] .rmp-card__media--mark {
place-items: center;
}
.rmp[data-theme="friendly"] .rmp-card__glyph {
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border-radius: 50%;
color: var(--rmp-accent-text);
}
.rmp[data-theme="friendly"] .rmp-card__glyph svg {
inline-size: 34px;
block-size: 34px;
}
/* The plate hero an imageless offer gets: the kind's mark straight on the warm
   plate (no third neutral disc), and the one reward statement when the title has
   not already said it. */
.rmp[data-theme="friendly"] .rmp-hero__kind {
display: inline-flex;
flex-direction: column;
align-items: center;
gap: 8px;
color: var(--rmp-accent-text);
font-family: var(--rmp-font);
font-size: var(--rmp-fs-body, 14px);
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="friendly"] .rmp-hero__kind svg {
inline-size: 60px;
block-size: 60px;
}
.rmp[data-theme="friendly"] .rmp-prize__mark--photo {
background: var(--fr-plate);
box-shadow: none;
}
.rmp[data-theme="friendly"] .rmp-prize__img {
background: transparent;
mix-blend-mode: multiply;
}
.rmp[data-theme="friendly"] .rmp-card__title {
/* The box (three lines, ellipsis, isolates kept) is the base sheet's; this theme
   owns the type and the start edge it shares with the ask. */
font-size: var(--rmp-fs-card, 16px);
font-weight: 700;
line-height: 1.6;
padding-block: 1px;
color: var(--rmp-ink);
text-shadow: none;
text-align: start;
white-space: normal;
text-wrap: balance;
}
.rmp[data-theme="friendly"] .rmp-card__title bdi {
white-space: nowrap;
}
/* The one reward statement a card gets, and only when the title has not said
   it: a chip with the kind's mark and, at most, one short phrase. */
.rmp[data-theme="friendly"] .rmp-card__mark {
display: inline-flex;
align-items: center;
gap: 5px;
flex: none;
block-size: 22px;
padding-inline: 6px;
border-radius: 8px;
background: color-mix(in srgb, var(--rmp-accent) 10%, var(--rmp-surface));
color: var(--rmp-accent-text);
font-family: var(--rmp-font);
font-size: 12px;
font-weight: 600;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.rmp[data-theme="friendly"] .rmp-card__mark svg {
flex: none;
}
.rmp[data-theme="friendly"] .rmp-card__mark--words {
padding-inline: 6px 8px;
}
.rmp[data-theme="friendly"] .rmp-card__row {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 6px;
min-height: 22px;
}
.rmp[data-theme="friendly"] .rmp-card__meter {
inline-size: 100%;
block-size: 4px;
margin: 0;
border-radius: 999px;
background: var(--rmp-track);
box-shadow: none;
overflow: hidden;
}
.rmp[data-theme="friendly"] .rmp-card__fill {
block-size: 100%;
border-radius: inherit;
background: var(--rmp-accent);
}
.rmp[data-theme="friendly"] .rmp-card__count {
min-width: 0;
font-family: var(--rmp-font);
font-size: var(--rmp-fs-ask, 14px);
font-weight: 600;
color: var(--rmp-ink-2);
opacity: 1;
letter-spacing: 0;
text-shadow: none;
direction: inherit;
unicode-bidi: isolate;
font-variant-numeric: tabular-nums;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.rmp[data-theme="friendly"] .rmp-card__count bdi {
unicode-bidi: isolate;
}
.rmp[data-theme="friendly"] .rmp-card__done {
position: static;
inset: auto;
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px 2px 7px;
border-radius: 999px;
background: var(--fr-ok-tint);
color: var(--fr-ok);
font-family: var(--rmp-font);
font-size: 12px;
font-weight: 700;
box-shadow: none;
}
.rmp[data-theme="friendly"] .rmp-card[data-state="done"] {
border-color: color-mix(in srgb, var(--fr-ok) 32%, var(--rmp-card-line));
}
/* ========================================================== empty state === */
.rmp[data-theme="friendly"] .rmp-empty {
display: flex;
flex: 1 1 auto;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 10px 18px 40px;
color: var(--rmp-ink-2);
}
.rmp[data-theme="friendly"] .rmp-empty__art {
width: 136px;
height: 136px;
margin: 0 auto 16px;
color: var(--rmp-accent);
}
.rmp[data-theme="friendly"] .rmp-empty__art svg {
width: 100%;
height: 100%;
}
.rmp[data-theme="friendly"] .rmp-empty__title {
margin: 0 0 16px;
font-size: 16px;
font-weight: 700;
color: var(--rmp-ink);
}
/* ============================================================ buttons ===== */
.rmp[data-theme="friendly"] .rmp-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
min-height: 40px;
padding: 8px 16px;
border: 0;
border-radius: 12px;
background: linear-gradient(150deg, var(--fr-accent-2), var(--rmp-accent));
color: var(--rmp-accent-ink);
font-family: var(--rmp-font);
font-size: 13px;
font-weight: 700;
line-height: 1.4;
text-decoration: none;
cursor: pointer;
transition: transform 0.16s var(--fr-spring), filter 0.16s var(--fr-ease);
}
.rmp[data-theme="friendly"] .rmp-btn:hover {
filter: brightness(1.05);
}
.rmp[data-theme="friendly"] .rmp-btn:active {
transform: scale(0.97);
}
.rmp[data-theme="friendly"] .rmp-btn:focus-visible {
outline: 3px solid var(--rmp-accent);
outline-offset: 2px;
}
.rmp[data-theme="friendly"] .rmp-btn--ghost {
background: var(--fr-tint);
color: var(--rmp-accent);
}
/* The full-width «تصفّح» block and its own arrow are gone (§11): the browse
   action belongs to the plan's next-step card, and `.rmp-btn--ghost` covers the
   one control this theme still draws itself — the coupon reveal. */
.rmp[data-theme="friendly"] .rmp-coupon[data-state="ready"] .rmp-fr-reveal {
inline-size: 100%;
margin-block-start: 11px;
}
.rmp[data-theme="friendly"] .rmp-fr-pill {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 6px 11px;
border: 1px solid transparent;
border-radius: 999px;
font-family: var(--rmp-font);
font-size: 12px;
font-weight: 700;
line-height: 1.6;
white-space: nowrap;
cursor: pointer;
}
.rmp[data-theme="friendly"] .rmp-fr-pill--in {
background: var(--fr-ok-tint);
color: var(--fr-ok);
border-color: color-mix(in srgb, var(--fr-ok) 24%, transparent);
cursor: default;
}
.rmp[data-theme="friendly"] .rmp-fr-pill--add {
background: linear-gradient(150deg, var(--fr-accent-2), var(--rmp-accent));
color: var(--rmp-accent-ink);
box-shadow: 0 4px 12px -7px rgba(0, 0, 0, 0.5);
}
.rmp[data-theme="friendly"] .rmp-fr-pill--add:hover {
filter: brightness(1.06);
}
.rmp[data-theme="friendly"] .rmp-fr-pill--ghost {
background: var(--rmp-surface-2);
color: var(--rmp-ink-2);
border-color: var(--rmp-line);
cursor: default;
}
/* =========================================================== offer page === */
.rmp[data-theme="friendly"] .rmp-offer {
display: flex;
flex-direction: column;
gap: 24px;
}
/* One 24px rhythm: the base section's own top margin does not stack a second
   gap on top of the offer column's. */
.rmp[data-theme="friendly"] .rmp-offer > .rmp-section {
margin-block-start: 0;
}
/* The primary CTA takes the shared 12px radius; the theme keeps its pills for
   chips, the save control and the ship row. */
.rmp[data-theme="friendly"] .rmp-actionbar__cta {
border-radius: 12px;
}
.rmp[data-theme="friendly"] .rmp-hero {
position: relative;
isolation: isolate;
display: block;
/* The frame takes the photo's own square and follows the sheet's height cap, so
   a contained shot fills its plate: no side strips, no seam. The width cap is
   the same number the base caps the height with (30dvh; 26dvh when a prize card
   makes the plan taller). */
inline-size: min(100%, 30dvh);
aspect-ratio: 1 / 1;
margin-inline: auto;
border-radius: var(--rmp-radius-card);
overflow: hidden;
box-shadow: none;
background-color: var(--rmp-surface-2);
background-image: linear-gradient(var(--fr-plate), var(--fr-plate));
}
.rmp[data-theme="friendly"] .rmp-screen--offer:has(.rmp-prize) .rmp-hero {
inline-size: min(100%, 26dvh);
}
/* The base's disclosure for the terms is a `.rmp-offer` child like any section:
   one 24px gap, not two. */
.rmp[data-theme="friendly"] .rmp-offer > .rmp-disclosure {
margin-block-start: 0;
}
/* No photo: one compact band across the column, the kind mark on the theme's
   warm plate. */
.rmp[data-theme="friendly"] .rmp-hero[data-media="plate"] {
inline-size: 100%;
aspect-ratio: auto;
block-size: 88px;
background-image: radial-gradient(120% 160% at 50% 0%, color-mix(in srgb, var(--rmp-accent) 16%, transparent), transparent 70%), linear-gradient(var(--fr-plate), var(--fr-plate));
}
/* The whole product, centred on the plate and multiplied into it — never a 2:1
   window on the model's legs, and no blurred copy behind it. */
.rmp[data-theme="friendly"] .rmp-hero__img {
position: absolute;
inset: 0;
z-index: var(--rmp-z-content, 0);
width: 100%;
height: 100%;
object-fit: contain;
object-position: center;
mix-blend-mode: multiply;
}
/* No photo: the reward is the hero, and this is the one time it is stated
   outside the plan. */
.rmp[data-theme="friendly"] .rmp-hero__plate {
position: absolute;
inset: 0;
z-index: var(--rmp-z-content, 0);
display: grid;
place-items: center;
}
/* v5.1 §B — the labelled bookmark rides the title row as a soft secondary pill:
   the plan's next step keeps the one primary action. */
.rmp[data-theme="friendly"] .rmp-otop {
display: flex;
align-items: flex-start;
gap: 10px;
}
.rmp[data-theme="friendly"] .rmp-otop .rmp-otitle {
flex: 1;
min-width: 0;
}
/* The save pill is anchored to the title's first line, never to the middle of a
   three-line block. */
.rmp[data-theme="friendly"] .rmp-otop .rmp-save--labelled {
margin-block-start: 2px;
}
.rmp[data-theme="friendly"] .rmp-save--labelled {
flex: none;
border-radius: 12px;
border-color: var(--rmp-card-line);
background: var(--rmp-surface);
color: var(--rmp-ink-2);
}
.rmp[data-theme="friendly"] .rmp-save--labelled[aria-pressed="true"] {
border-color: transparent;
background: var(--fr-tint);
color: var(--rmp-accent-text);
}
.rmp[data-theme="friendly"] .rmp-save--labelled::before {
display: none;
}
.rmp[data-theme="friendly"] .rmp-otitle {
margin: 0;
font-size: var(--rmp-fs-detail, 20px);
font-weight: 700;
line-height: 1.4;
letter-spacing: 0;
text-wrap: pretty;
}
.rmp[data-theme="friendly"] .rmp-odesc {
margin: -8px 0 0;
font-size: var(--rmp-fs-body, 14px);
color: var(--rmp-ink-2);
line-height: 1.6;
}
/* one rhythm for every section label: small, quiet, no rule beside it */
.rmp[data-theme="friendly"] .rmp-section__title {
margin: 0;
font-size: var(--rmp-fs-label, 13px);
font-weight: 600;
color: var(--rmp-ink-3);
letter-spacing: 0;
}
.rmp[data-theme="friendly"] .rmp-section {
display: flex;
flex-direction: column;
gap: 10px;
}
/* add / choose: the same gradient pill the fallback row drew, sized for the row */
.rmp[data-theme="friendly"] .rmp-btn--add {
min-height: 36px;
padding: 7px 14px;
border-radius: 999px;
font-size: 12px;
}
/* the coupon: dashed until it is real, then solid */
.rmp[data-theme="friendly"] .rmp-coupon {
position: relative;
padding: 13px;
border: 1.5px dashed color-mix(in srgb, var(--rmp-accent) 46%, var(--rmp-line));
border-radius: var(--rmp-radius-card);
background: linear-gradient(160deg, var(--fr-tint), transparent 70%), var(--rmp-surface);
overflow: hidden;
}
.rmp[data-theme="friendly"] .rmp-coupon[data-state="revealed"],
.rmp[data-theme="friendly"] .rmp-coupon[data-state="ready"],
.rmp[data-theme="friendly"] .rmp-coupon[data-state="applied"] {
border-style: solid;
border-color: color-mix(in srgb, var(--rmp-accent) 34%, transparent);
}
.rmp[data-theme="friendly"] .rmp-coupon__top {
display: flex;
align-items: center;
gap: 9px;
}
.rmp[data-theme="friendly"] .rmp-coupon__lock {
display: inline-grid;
place-items: center;
flex: none;
width: 30px;
height: 30px;
border-radius: 9px;
background: var(--fr-tint-2);
color: var(--rmp-accent);
}
.rmp[data-theme="friendly"] .rmp-coupon__lock.is-on {
background: var(--fr-ok);
color: #fff;
}
.rmp[data-theme="friendly"] .rmp-coupon__t {
margin: 0;
font-size: 13px;
font-weight: 700;
color: var(--rmp-ink);
}
.rmp[data-theme="friendly"] .rmp-coupon__s {
margin: 2px 0 0;
font-size: 12px;
color: var(--rmp-ink-2);
}
.rmp[data-theme="friendly"] .rmp-coupon__s:empty {
display: none;
}
.rmp[data-theme="friendly"] .rmp-coupon__code {
display: flex;
align-items: center;
gap: 9px;
margin-block-start: 11px;
padding: 9px 10px 9px 12px;
border: 1px solid color-mix(in srgb, var(--rmp-accent) 20%, transparent);
border-radius: 11px;
background: var(--rmp-surface);
}
.rmp[data-theme="friendly"] .rmp-coupon__code b {
flex: 1;
min-width: 0;
font-family: var(--rmp-font);
font-size: 16px;
font-weight: 700;
font-variant-numeric: tabular-nums;
letter-spacing: 0.1em;
color: var(--rmp-accent);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* a locked code is not readable — it is not even screenshot-able */
.rmp[data-theme="friendly"] .rmp-coupon__code.is-locked b {
color: var(--rmp-ink-3);
filter: blur(4.5px);
user-select: none;
}
.rmp[data-theme="friendly"] .rmp-coupon__foot {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
margin-block-start: 10px;
}
.rmp[data-theme="friendly"] .rmp-coupon__status {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 12px;
font-weight: 600;
color: var(--fr-ok);
}
.rmp[data-theme="friendly"] .rmp-coupon__expiry {
font-size: 12px;
color: var(--rmp-ink-3);
}
/* terms — the legally operative copy is never the smallest text on the screen */
/* The terms are a disclosure row (decision 1): a 44px summary with the label and
   a chevron, closed by default; the list opens under it in the theme's tint box.
   The height animates where the engine can interpolate `auto`, and the content is
   `content-visibility: hidden` while closed so nothing is clipped. */
.rmp[data-theme="friendly"] .rmp-terms__d {
interpolate-size: allow-keywords;
}
.rmp[data-theme="friendly"] .rmp-terms__toggle {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
min-block-size: 44px;
margin: 0;
padding: 0;
border: 0;
cursor: pointer;
list-style: none;
color: var(--rmp-ink-3);
}
.rmp[data-theme="friendly"] .rmp-terms__toggle::-webkit-details-marker {
display: none;
}
.rmp[data-theme="friendly"] .rmp-terms__toggle:focus-visible {
outline: 2px solid var(--rmp-accent);
outline-offset: 2px;
border-radius: 8px;
}
.rmp[data-theme="friendly"] .rmp-terms__toggle svg {
flex: none;
color: var(--rmp-ink-3);
transition: transform 0.2s var(--fr-ease);
}
.rmp[data-theme="friendly"] .rmp-terms__toggle:hover svg,
.rmp[data-theme="friendly"] .rmp-terms__d[open] .rmp-terms__toggle svg {
color: var(--rmp-accent-text);
}
.rmp[data-theme="friendly"] .rmp-terms__d[open] .rmp-terms__toggle svg {
transform: rotate(180deg);
}
.rmp[data-theme="friendly"] .rmp-terms__d::details-content {
block-size: 0;
overflow: hidden;
content-visibility: hidden;
transition: block-size 0.24s var(--fr-ease), content-visibility 0.24s allow-discrete;
}
.rmp[data-theme="friendly"] .rmp-terms__d[open]::details-content {
block-size: auto;
content-visibility: visible;
}
@media (prefers-reduced-motion: reduce) {
.rmp[data-theme="friendly"] .rmp-terms__d::details-content,
.rmp[data-theme="friendly"] .rmp-terms__toggle svg {
transition: none;
}
}
.rmp[data-theme="friendly"] .rmp-disclosure__inner {
margin-block-start: 8px;
padding: 14px;
border: 1px solid var(--rmp-line);
border-radius: var(--rmp-radius-card);
background: var(--rmp-surface-2);
}
.rmp[data-theme="friendly"] .rmp-disclosure li {
font-size: var(--rmp-fs-body, 14px);
color: var(--rmp-ink-terms);
}
.rmp[data-theme="friendly"] .rmp-disclosure li::before {
inline-size: 4px;
block-size: 4px;
border-radius: 50%;
background: color-mix(in srgb, var(--rmp-accent) 60%, transparent);
}
.rmp[data-theme="friendly"] .rmp-terms {
margin: 0;
padding: 14px;
border: 1px solid var(--rmp-line);
border-radius: var(--rmp-radius-card);
background: var(--rmp-surface-2);
}
.rmp[data-theme="friendly"] .rmp-terms ul {
margin: 0;
padding: 0;
list-style: none;
display: grid;
gap: 8px;
}
.rmp[data-theme="friendly"] .rmp-terms li {
position: relative;
padding-inline-start: 16px;
font-size: 14px;
line-height: 1.6;
color: var(--rmp-ink-terms);
}
.rmp[data-theme="friendly"] .rmp-terms li::before {
content: "";
position: absolute;
inset-inline-start: 2px;
inset-block-start: 9px;
width: 4px;
height: 4px;
border-radius: 50%;
background: color-mix(in srgb, var(--rmp-accent) 60%, transparent);
}
/* ==================================================== v5 discovery (§5.1–4) ===
 * The filter row, the teaser, the bookmark and the launcher badge are the
 * runtime's (docs/POCKET_V5_DISCOVERY_CONTRACT.md, v5.1 §A–C); geometry is
 * pocket.css's and the filter row is NOT sticky (§A). This block tunes surface,
 * radius and type into team-02's language: 999px pills, a warm accent wash, one
 * card radius. */
.rmp[data-theme="friendly"] .rmp-filter {
border-radius: 999px;
border-color: var(--rmp-card-line);
font-family: var(--rmp-font);
font-size: var(--rmp-chip-fs, 13px);
font-weight: 600;
color: var(--rmp-ink-2);
}
.rmp[data-theme="friendly"] .rmp-filter[aria-pressed="true"] {
border-color: transparent;
background: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-surface));
color: var(--rmp-accent-text);
}
.rmp[data-theme="friendly"] .rmp-filter__n {
border-radius: 999px;
background: var(--rmp-surface-2);
color: var(--rmp-accent-text);
font-family: var(--rmp-font);
font-size: 12px;
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.rmp[data-theme="friendly"] .rmp-filter[aria-pressed="true"] .rmp-filter__n {
background: var(--rmp-accent);
color: var(--rmp-accent-ink);
}
.rmp[data-theme="friendly"] .rmp-teaser {
background: var(--rmp-surface);
border: 1px solid var(--rmp-card-line);
border-radius: var(--rmp-radius-card);
box-shadow: var(--rmp-shadow);
}
.rmp[data-theme="friendly"] .rmp-teaser__media {
border-radius: 14px;
}
.rmp[data-theme="friendly"] .rmp-teaser__eyebrow {
font-size: 12px;
font-weight: 600;
color: var(--rmp-ink-3);
}
.rmp[data-theme="friendly"] .rmp-teaser__title {
font-size: 14px;
font-weight: 700;
color: var(--rmp-ink);
}
.rmp[data-theme="friendly"] .rmp-teaser__reward {
font-size: 12px;
font-weight: 600;
color: var(--rmp-accent-text);
}
.rmp[data-theme="friendly"] .rmp-teaser__cta {
border-radius: 999px;
background: linear-gradient(150deg, var(--fr-accent-2), var(--rmp-accent));
color: var(--rmp-accent-ink);
font-weight: 700;
}
/* v5.1 §B — the bookmark. The outline reads ink-2, the filled form takes the
   accent; the resting circle is the white plate team-02 floats over a photo. */
.rmp[data-theme="friendly"] .rmp-save {
border-radius: 50%;
color: var(--rmp-ink-2);
}
.rmp[data-theme="friendly"] .rmp-save::before {
background: rgba(255, 255, 255, 0.94);
box-shadow: 0 4px 12px -6px rgba(0, 0, 0, 0.5);
}
.rmp[data-theme="friendly"] .rmp-save[aria-pressed="true"] {
color: var(--rmp-accent-text);
}
.rmp[data-theme="friendly"] .rmp-save[aria-pressed="true"]::before {
background: var(--fr-tint-2);
}
/* Over a card's trailing edge the bookmark is a 30px warm circle inside the 44px
   tap target: the surface tint, a hairline ring, no shadow. */
.rmp[data-theme="friendly"] .rmp-card > .rmp-save {
background: transparent;
}
.rmp[data-theme="friendly"] .rmp-card > .rmp-save::before {
content: "";
position: absolute;
inset: 5px;
border-radius: 50%;
background: var(--rmp-surface-2);
box-shadow: inset 0 0 0 1px var(--rmp-card-line);
}
.rmp[data-theme="friendly"] .rmp-card > .rmp-save[aria-pressed="true"]::before {
background: color-mix(in srgb, var(--rmp-accent) 14%, var(--rmp-surface));
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--rmp-accent) 26%, transparent);
}
.rmp[data-theme="friendly"] .rmp-badge {
border-radius: 999px;
background: linear-gradient(150deg, var(--fr-accent-2), var(--rmp-accent));
color: var(--rmp-accent-ink);
font-family: var(--rmp-font);
font-size: 12px;
font-weight: 700;
font-variant-numeric: tabular-nums;
box-shadow: 0 4px 12px -6px rgba(0, 0, 0, 0.5), 0 0 0 2px var(--rmp-surface);
}

/* ============================================================= motion ==== */
@media (prefers-reduced-motion: reduce) {
.rmp[data-theme="friendly"] .rmp-card:hover,
.rmp[data-theme="friendly"] .rmp-card:hover .rmp-card__img {
transform: none;
}
.rmp[data-theme="friendly"] .rmp-btn:active,
.rmp[data-theme="friendly"] .rmp-fr-pill:active {
transform: none;
}
.rmp[data-theme="friendly"] .rmp-launcher:hover,
.rmp[data-theme="friendly"] .rmp-launcher:active {
transform: none;
}
}
.rmp--still[data-theme="friendly"] .rmp-card:hover,
.rmp--still[data-theme="friendly"] .rmp-card:hover .rmp-card__img {
transform: none;
}
.rmp--still[data-theme="friendly"] .rmp-launcher:hover,
.rmp--still[data-theme="friendly"] .rmp-launcher:active {
transform: none;
}
/* ============================================================== mobile ==== */
@media (max-width: 639px) {
.rmp[data-theme="friendly"] .rmp-card__media {
inline-size: 88px;
min-block-size: 88px;
}
/* Decision 3: the hero is presence, not a postage stamp — the full content
   width and its own square (358px at 390, 328px at 360), gift included; the
   height cap only applies where the sheet cannot afford it. */
.rmp[data-theme="friendly"] .rmp-screen--offer .rmp-hero:has(img) {
inline-size: 100%;
aspect-ratio: 1 / 1;
max-block-size: none;
}
.rmp[data-theme="friendly"] .rmp-screen--offer:has(.rmp-prize) .rmp-hero:has(img) {
inline-size: 100%;
aspect-ratio: 1 / 1;
max-block-size: none;
}
.rmp[data-theme="friendly"] .rmp-btn {
min-height: 44px;
}
}
@media (min-width: 640px) {
.rmp[data-theme="friendly"] {
--rmp-gutter: 20px;
}
.rmp[data-theme="friendly"] .rmp-hero {
inline-size: min(100%, 280px, 25dvh);
}
.rmp[data-theme="friendly"] .rmp-screen--offer:has(.rmp-prize) .rmp-hero {
inline-size: min(100%, 200px, 20dvh);
}
.rmp[data-theme="friendly"] .rmp-screen--offer:has(.rmp-prize) .rmp-hero:has(img) {
/* The gift's plan is one row taller, so the base caps its hero: the cap must be
   a WIDTH (a square frame) and never a height (which letterboxes the photo). */
inline-size: min(100%, 15dvh);
max-block-size: none;
}
.rmp[data-theme="friendly"] .rmp-head {
padding-inline: 20px;
}
.rmp[data-theme="friendly"] .rmp-card__media {
inline-size: 112px;
}
}
