/* ============================================================================
   Buy a Button — the whole stylesheet.

   Everything is built from five tokens plus #fff, with one exception: the
   #b4322c on a failed/expired status border. If something new needs a colour,
   add a token here; do not inline a hex.

   LAYOUT comes from Mantine primitives. STRUCTURE comes from these classes.
   There are no CSS modules, no createStyles, no Mantine `classNames`/`styles`
   props and no inline `style={{}}` anywhere in the components — one stylesheet
   of `or-` prefixed global classes is the entire system.

   WHICH IS WHY THIS FILE SITS BESIDE shop-types.ts RATHER THAN INSIDE client/.
   Being global `or-` classes and not a React concern, it is the one other
   thing EVERY stack shares: the three React hosts import it, and so does the
   no-framework host in client-vanilla/, which emits the same class names
   against hand-written DOM. That is what makes the vanilla demo look like the
   same product instead of a second design — and it keeps client/ and
   client-vanilla/ from importing each other, which is the boundary that
   matters.

   THERE IS NO DARK MODE. `background: #fff` is hard-coded in several places
   below. A later dark mode turns every one of those into a variable FIRST and
   then adds a [data-mantine-color-scheme="dark"] token block; piecemeal dark
   styles will look half-converted.
   ========================================================================= */

:root {
  --or-ink: #17231f;    /* body text; == theme.black                        */
  --or-muted: #5c665f;  /* secondary text, every "detail" line              */
  --or-paper: #fbfaf6;  /* page ground and inset panels                     */
  --or-line: #d9ded6;   /* every border                                     */
  --or-accent: #20824a; /* selection, success; == orGreen[7]. BY HAND.      */
}

body {
  margin: 0;
  color: var(--or-ink);
  background: var(--or-paper);
}

/* The page around the panel. The demo is one panel centred on a plain ground;
   the shop itself is the subject. */
.or-page {
  min-height: 100vh;
  display: grid;
  justify-items: center;
  align-content: start;
  gap: 12px;
  padding: 24px 16px 32px;
}

/* The panel is as wide as the viewport allows, up to a line length the head and
   the feed rows still read at. Everything inside lays out from THIS width — the
   checkout goes two-column, the catalog goes one row — so a desktop payer sees
   the whole checkout without scrolling. */
.or-page-inner {
  width: 100%;
  max-width: 1120px;
  display: grid;
  gap: 12px;
}

.or-eyebrow {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--or-muted);
}

.or-page-note {
  font-size: 0.8rem;
  color: var(--or-muted);
  text-align: center;
}

/* ---------------------------------------------------------------- the shop */

/* THE PANEL IS AS TALL AS ITS CONTENT. There is no fixed height and nothing
   inside the panel scrolls on its own: the page is the only scroller, so a
   viewport with room to spare shows the whole stage rather than a short box
   with a scrollbar in it.

   That trades a stable box for a taller one, so the way this stays honest is
   HORIZONTAL: the checkout splits into a summary column and a payment column at
   880px, and the QR moves beside its copy rows at 1000px. Anything new that is
   tall enough to push a desktop checkout past the fold belongs in one of those
   columns, not under them.

   Consequences for anything new inside the panel: a stage puts its content in
   an `.or-shop-stage` and its actions in an `.or-shop-footer`; empty and
   loading states still RESERVE height, because a feed that collapses to nothing
   while it loads still moves the page under the pointer. */
.or-shop {
  display: flex;
  flex-direction: column;
  overflow: hidden; /* corner clipping; the panel never scrolls */
  background: #fff;
}

/* No border-bottom: the tab strip below it owns that rule. Two hairlines 44px
   apart is what putting one here gets you. */
.or-shop-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 18px 20px 12px;
}

.or-shop-title {
  font-size: 1.15rem;
  font-weight: 800;
  line-height: 1.2;
}

.or-shop-subtitle {
  font-size: 0.85rem;
  color: var(--or-muted);
  max-width: 42ch;
}

.or-shop-tabs {
  padding: 0 20px 10px;
  border-bottom: 1px solid var(--or-line);
}

.or-shop-body {
  display: flex;
  flex-direction: column;
}

.or-shop-stage {
  padding: 16px 20px;
}

.or-shop-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 20px;
  border-top: 1px solid var(--or-line);
  background: var(--or-paper);
}

/* ---- catalog */

.or-shop-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 14px;
}

.or-shop-card {
  border: 1px solid var(--or-line);
  border-radius: 12px;
  padding: 10px;
  display: grid;
  gap: 6px;
  justify-items: center;
  background: #fff;
}

/* Selection is an inset ring, never a background change — a background would
   fight the product photography. */
.or-shop-card[data-in-cart] {
  border-color: var(--or-accent);
  box-shadow: 0 0 0 1px var(--or-accent) inset;
}

.or-shop-card-image {
  width: 100%;
  max-width: 120px;
  aspect-ratio: 1 / 1;
  object-fit: contain;
}

.or-shop-card-name {
  font-size: 0.85rem;
  font-weight: 700;
}

.or-shop-card-price {
  font-size: 0.85rem;
  color: var(--or-muted);
}

.or-shop-card-qty {
  min-width: 22px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

/* ---- checkout */

/* Summary on the left, the thing the payer has to act on on the right. Below
   880px it is one column in source order, so the order and its status stay
   above the QR code. */
.or-checkout {
  display: grid;
  gap: 16px;
  align-items: start;
}

/* A grid item's automatic minimum size is its content; a bolt11 would blow the
   track out without this. */
.or-checkout-summary,
.or-checkout-pay,
.or-checkout-return,
.or-checkout-record {
  min-width: 0;
}

@media (min-width: 880px) {
  .or-checkout {
    grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
    gap: 24px;
  }

  .or-checkout-record {
    grid-column: 1 / -1;
  }

  /* The return link follows payment controls on mobile and in reading order.
     A desktop sidebar keeps it directly below the summary. */
  .or-checkout:has(> .or-checkout-return) {
    grid-template-rows: min-content 1fr auto;
  }

  .or-checkout:has(> .or-checkout-return) > .or-checkout-pay {
    grid-column: 2;
    grid-row: 1 / span 2;
  }

  .or-checkout-return {
    grid-column: 1;
    grid-row: 2;
  }
}

/* The packaged checkout prints the order description above its own panel. In
   the stack that embeds it (node-express) the summary column beside it already
   shows the product — its picture, its name and its price — so the library's
   line is the same sentence twice on one screen. Hidden through the two seams
   the packages expose for exactly this: the data attribute React stamps on it,
   and the shadow part the element wrappers expose. */
.or-checkout-pay [data-openreceive-order-description],
.or-checkout-pay openreceive-checkout::part(order-description) {
  display: none;
}

/* A QR code and the values beside it, rather than under them: stacked, the pair
   is ~380px of height that a desktop checkout does not have to spend. The `auto`
   track is the QR at its natural size. */
.or-shop-payload {
  display: grid;
  gap: 12px;
  align-items: start;
}

.or-shop-payload > * {
  min-width: 0;
}

/* A rail whose payload has no QR code (or a QR that has not rendered yet) gets
   the whole width rather than the narrow `auto` track meant for the code. */
.or-shop-payload > :only-child {
  grid-column: 1 / -1;
}

@media (min-width: 1000px) {
  .or-shop-payload {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 16px;
  }
}

.or-shop-order-strip {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--or-line);
  border-radius: 10px;
  background: var(--or-paper);
}

.or-shop-order-thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  flex-shrink: 0;
}

.or-shop-order-thumbs img {
  width: 34px;
  height: 34px;
  object-fit: contain;
  border-radius: 4px;
  border: 1px solid var(--or-line);
  background: #fff;
}

.or-shop-order-title {
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.3;
}

.or-shop-order-total {
  font-size: 1.05rem;
  font-weight: 800;
}

.or-shop-status {
  border: 1px solid var(--or-line);
  border-left: 3px solid var(--or-muted);
  border-radius: 8px;
  padding: 10px 12px;
}

.or-shop-status[data-phase="settled"] {
  border-left-color: var(--or-accent);
}

.or-shop-status[data-phase="expired"],
.or-shop-status[data-phase="failed"],
.or-shop-status[data-phase="cancelled"] {
  border-left-color: #b4322c;
}

.or-shop-status-title {
  font-weight: 700;
  font-size: 0.95rem;
}

.or-shop-status-detail,
.or-shop-status-countdown {
  font-size: 0.85rem;
  color: var(--or-muted);
}

.or-shop-status-countdown {
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}

.or-shop-section-title {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--or-muted);
}

.or-shop-methods {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
}

.or-shop-method {
  border: 1px solid var(--or-line);
  border-radius: 10px;
  padding: 10px;
  display: grid;
  gap: 2px;
  justify-items: center;
  text-align: center;
  background: #fff;
}

.or-shop-method[data-selected] {
  border-color: var(--or-accent);
  box-shadow: 0 0 0 1px var(--or-accent) inset;
}

.or-shop-method:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.or-shop-method-title {
  font-size: 0.9rem;
  font-weight: 700;
}

.or-shop-method-detail {
  font-size: 0.75rem;
  color: var(--or-muted);
  line-height: 1.3;
}

/* A <fieldset>: these are mutually exclusive choices, and `aria-labelledby`
   means nothing on an element with no grouping role. The three resets below
   undo the browser's default fieldset chrome — in particular
   `min-inline-size: min-content`, which would stop it shrinking inside the
   panel. */
.or-shop-networks {
  margin: 0;
  min-inline-size: 0;
  border: 1px solid var(--or-line);
  border-radius: 10px;
  padding: 10px 12px;
}

.or-shop-network {
  display: flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--or-line);
  border-radius: 999px;
  padding: 6px 12px;
  background: #fff;
}

.or-shop-network[data-selected] {
  border-color: var(--or-accent);
  color: var(--or-accent);
}

.or-shop-qr {
  display: grid;
  place-items: center;
  padding: 12px;
  background: #fff;
  border: 1px solid var(--or-line);
  border-radius: 10px;
}

.or-shop-qr svg {
  width: 208px;
  height: 208px;
}

/* Every value the payer has to reproduce: a label, the value, a copy button.
   `overflow-wrap: anywhere` because a bolt11 is one 300-character word. */
.or-shop-copyrow {
  display: grid;
  gap: 3px;
}

/* A grid item's automatic minimum size is its CONTENT, so the nowrap value row
   below would size the track to a 300-character invoice and push the copy
   button off the panel. Grid items opt out of that with min-width: 0. */
.or-shop-copyrow > * {
  min-width: 0;
}

.or-shop-copyrow-label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--or-muted);
}

.or-shop-copyrow-value {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: 0.8rem;
  padding: 5px 8px;
}

/* THE ELLIPSIS IS CSS, NEVER THE STRING. A bolt11 is 300 characters and does
   not get five lines of the panel, but shortening it in JavaScript puts a `…`
   in the middle of the text a payer can select — and with `user-select: all`
   below, one click hands them a broken invoice that looks like a whole one.
   The full value stays in the DOM and the overflow is hidden, so a selection
   copies the real string whatever is on screen. */
.or-shop-copyrow-value[data-truncate] {
  overflow: hidden;
  overflow-wrap: normal;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A deposit address or an invoice should select whole on one click. */
.or-shop-copyrow-value[data-selectable] {
  user-select: all;
}

.or-shop-wallets {
  border-top: 1px solid var(--or-line);
  padding-top: 12px;
}

.or-shop-wallet-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 8px;
}

.or-shop-wallet {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--or-line);
  border-radius: 8px;
  padding: 8px 10px;
  background: #fff;
  text-decoration: none;
  color: inherit;
}

/* Several registry marks are white-on-transparent, so they need something
   behind them to be visible at all on a white panel. */
.or-shop-wallet img {
  flex: none;
  border-radius: 4px;
  background: var(--or-paper);
}

.or-shop-fees,
.or-shop-refund,
.or-shop-keeplink {
  border: 1px solid var(--or-line);
  border-radius: 10px;
  padding: 10px 12px;
}

/* ---- the way back into an order

   The order id is the only thing a payer with no account can use to reach
   their payment again, so it gets a panel of its own on the checkout screen
   and a full-width alert on the refund screen. */

.or-shop-keeplink {
  display: grid;
  gap: 6px;
  background: var(--or-paper);
}

/* A refund REPLACES the deposit panel — no QR, no address, no amount — so the
   column it takes over is the whole width it had. */
.or-shop-refund-stage {
  min-width: 0;
}

/* The "already have an order id?" footnote under the catalog. Deliberately
   quiet: it is a way back for the payer who needs one, not a second entrance
   competing with the cart. */
.or-shop-resume {
  border-top: 1px solid var(--or-line);
  margin-top: 4px;
  padding-top: 10px;
  display: grid;
  gap: 6px;
}

.or-shop-resume-input {
  flex: 1;
  min-width: 0;
}

.or-shop-resume-hint {
  color: var(--or-muted);
  font-size: 0.75rem;
  margin: 0;
}

/* ---- transaction details, collapsed behind a caret */

.or-shop-details {
  border-top: 1px solid var(--or-line);
  padding-top: 10px;
}

.or-shop-details-toggle {
  width: 100%;
  text-align: left;
}

.or-shop-details-chevron {
  transition: transform 120ms ease;
}

.or-shop-details-chevron[data-open] {
  transform: rotate(90deg);
}

.or-shop-details-link {
  display: inline-block;
  margin-top: 2px;
}

/* ---- receipt */

.or-shop-paid-icon {
  color: var(--or-accent);
  flex: none;
}

.or-shop-receipt-line {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--or-line);
  border-radius: 10px;
  padding: 8px 10px;
}

.or-shop-receipt-copy {
  flex: 1;
  min-width: 0;
}

/* ---- the recent-orders feed */

.or-shop-feed {
  display: grid;
  gap: 8px;
}

.or-shop-feed-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--or-line);
  border-radius: 10px;
  padding: 8px 10px;
  background: #fff;
}

/* Same inset ring the cart card and the method tile use, for the same reason:
   "this one is yours" is the same kind of statement as "this one is chosen". */
.or-shop-feed-row[data-you] {
  border-color: var(--or-accent);
  box-shadow: 0 0 0 1px var(--or-accent) inset;
}

.or-shop-feed-thumbs {
  display: flex;
  gap: 4px;
  flex: none;
}

.or-shop-feed-thumbs img {
  width: 28px;
  height: 28px;
  border-radius: 4px;
  border: 1px solid var(--or-line);
  background: #fff;
  object-fit: contain;
}

/* min-width:0 is what lets the title ellipsize inside a 1fr grid track. */
.or-shop-feed-main {
  min-width: 0;
}

.or-shop-feed-title {
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.or-shop-feed-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
  font-size: 0.75rem;
  color: var(--or-muted);
}

/* The buyer's public uuid. Monospace so eight hex characters are comparable at
   a glance across rows; the full value lives in the title attribute. */
.or-shop-feed-buyer {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.72rem;
  letter-spacing: 0.02em;
}

.or-shop-feed-you {
  border: 1px solid var(--or-accent);
  color: var(--or-accent);
  border-radius: 999px;
  padding: 0 6px;
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1.6;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.or-shop-feed-amount {
  font-size: 0.95rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Reserves height rather than collapsing, so switching to an empty feed does
   not change the panel's inner geometry. */
.or-shop-feed-empty {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 4px;
  min-height: 180px;
  text-align: center;
  font-size: 0.9rem;
  color: var(--or-muted);
}

/* Same box as a real row, so the first paint and the loaded paint are the same
   shape. Three of these while loading. */
.or-shop-feed-skeleton {
  height: 46px;
  border: 1px solid var(--or-line);
  border-radius: 10px;
  background: linear-gradient(90deg, var(--or-paper), #fff, var(--or-paper));
  background-size: 200% 100%;
  animation: or-shop-feed-shimmer 1.4s linear infinite;
}

@keyframes or-shop-feed-shimmer {
  from {
    background-position: 200% 0;
  }
  to {
    background-position: -200% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .or-shop-feed-skeleton {
    animation: none;
  }

  .or-shop-details-chevron {
    transition: none;
  }
}

.or-shop-feed-totals {
  font-size: 0.8rem;
  color: var(--or-muted);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 600px) {
  .or-shop-qr svg {
    width: 168px;
    height: 168px;
  }

  /* At 360px the thumbnails cost more than they say. The row still carries the
     product name, the buyer and the amount. */
  .or-shop-feed-row {
    grid-template-columns: 1fr auto;
  }

  .or-shop-feed-thumbs {
    display: none;
  }
}


/*# sourceMappingURL=buttons-aa97df99.css.map*/