/* =============================================================================
   Asiam3 components
   =============================================================================
   Semantic HTML plus classes. No framework. Every component is a contract that
   any renderer can satisfy, because the frontend framework is still open.

   Rules that hold throughout:
   - Every colour, size and space comes from a token. No literals below.
   - Focus is always visible. Never `outline: none` without a replacement.
   - Anything a finger touches is at least --a3-touch-min.
   - State is conveyed by more than colour. Colour vision is not a requirement
     for using a commerce platform.
============================================================================= */

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

body.a3 {
  margin: 0;
  background: var(--a3-bg);
  color: var(--a3-text);
  font-family: var(--a3-font-body);
  font-size: var(--a3-text-md);
  line-height: var(--a3-leading-normal);
  -webkit-text-size-adjust: 100%;
}

/* Touch devices get a larger base. 15px is comfortable with a mouse and
   marginal with a thumb, and iOS zooms any input below 16px on focus. */
@media (pointer: coarse) {
  body.a3 { font-size: 1rem; }
}

.a3-prose { max-width: var(--a3-measure); }

:where(a) { color: var(--a3-link); text-underline-offset: 0.2em; }

:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: none;
  box-shadow: var(--a3-focus-ring);
  border-radius: var(--a3-radius-sm);
}

/* Reachable only by keyboard, which is exactly who needs it. */
.a3-skip-link {
  position: absolute; left: var(--a3-space-2); top: -100vh;
  z-index: var(--a3-z-toast);
  background: var(--a3-bg-raised); color: var(--a3-text);
  padding: var(--a3-space-2) var(--a3-space-4);
  border: 1px solid var(--a3-border-strong); border-radius: var(--a3-radius-md);
}
.a3-skip-link:focus { top: var(--a3-space-2); }

.a3-visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* -----------------------------------------------------------------------------
   Authority band: the signature element
   -----------------------------------------------------------------------------
   Persistent. States which surface you are in, whose data is on screen, and by
   what right. It is the answer to "am I about to act on the wrong business?"
   before the action rather than after it.

   The three surfaces are distinguishable at a glance because confusing them is
   an authorization error, not a cosmetic one. When authority is borrowed rather
   than owned, the band says so and shows the recorded reason, so a support
   operator can never forget they are inside someone else's business.
----------------------------------------------------------------------------- */
.a3-authority {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--a3-space-3);
  padding: var(--a3-space-2) var(--a3-space-4);
  background: var(--a3-bg-raised);
  border-bottom: 1px solid var(--a3-border);
  border-top: 3px solid var(--a3-surface-accent, var(--a3-primary-600));
  font-size: var(--a3-text-sm);
  position: sticky; top: 0; z-index: var(--a3-z-sticky);
}
.a3-authority__surface {
  font-weight: var(--a3-weight-semibold);
  color: var(--a3-surface-accent, var(--a3-primary-600));
  text-transform: uppercase; letter-spacing: 0.06em;
  font-size: var(--a3-text-2xs);
}
.a3-authority__scope { color: var(--a3-text); font-weight: var(--a3-weight-medium); }
.a3-authority__basis { color: var(--a3-text-muted); }

/* Cross-boundary access is never quiet. If an operator is inside a business
   they are not a member of, the interface says so continuously and shows the
   reason that was recorded, because that reason is now part of an audit record
   they cannot alter. */
.a3-authority--borrowed {
  background: var(--a3-denied-100);
  border-top-color: var(--a3-denied-600);
}
.a3-authority--borrowed .a3-authority__basis { color: var(--a3-denied-600); font-weight: var(--a3-weight-medium); }

/* -----------------------------------------------------------------------------
   Brand slot: deliberately empty of brand
   -----------------------------------------------------------------------------
   The Asiam3 logo does not exist yet, and inventing one now would mean a
   temporary mark quietly becoming the brand because it shipped first.

   So this is a reserved box, not a logo. Its dimensions are fixed by token, and
   nothing around it measures the mark itself. When the real logo arrives it is
   dropped into a box that already occupies the right space, so navigation,
   spacing and responsive behaviour do not move.

   The placeholder is intentionally plain and visibly provisional. It should look
   like something waiting to be replaced, because it is. `data-a3-brand="pending"`
   is the marker to search for when substituting the real asset.

   Constraints the real logo must satisfy, so the swap stays a swap:
     - fits within --a3-brand-height without changing it
     - readable at --a3-brand-height-compact on small screens
     - works on --a3-bg-raised in both light and dark themes
     - has an accessible name; if it is an image, it carries meaningful alt text
----------------------------------------------------------------------------- */
:root {
  --a3-brand-height: 28px;
  --a3-brand-height-compact: 24px;
  --a3-brand-max-width: 160px;
}

.a3-brand {
  display: inline-flex; align-items: center;
  height: var(--a3-brand-height);
  max-width: var(--a3-brand-max-width);
  flex: 0 0 auto;
  overflow: hidden;
}
.a3-brand > * { max-height: 100%; max-width: 100%; }

@media (max-width: 640px) {
  .a3-brand { height: var(--a3-brand-height-compact); }
}

/* The provisional treatment. Wordmark in the display face, no device, no
   colour beyond the ink already in the system. Neutral on purpose: a neutral
   placeholder is easy to abandon, and a good-looking one is not. */
.a3-brand[data-a3-brand="pending"] {
  font-family: var(--a3-font-display);
  font-weight: var(--a3-weight-semibold);
  font-size: var(--a3-text-lg);
  letter-spacing: -0.01em;
  color: var(--a3-text);
  align-items: center;
  gap: var(--a3-space-2);
}
/* A quiet, unmistakable "not final" marker. Visible to the team, meaningless
   to a customer, and impossible to mistake for a designed device. */
.a3-brand[data-a3-brand="pending"]::after {
  content: "";
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--a3-border-strong);
  flex: 0 0 auto;
}

/* -----------------------------------------------------------------------------
   Buttons
----------------------------------------------------------------------------- */
.a3-btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--a3-space-2);
  min-height: var(--a3-touch-min);
  padding: 0 var(--a3-space-4);
  font: inherit; font-weight: var(--a3-weight-medium);
  border-radius: var(--a3-radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background var(--a3-duration-fast) var(--a3-ease);
}
.a3-btn--primary { background: var(--a3-primary-600); color: var(--a3-white); }
.a3-btn--primary:hover:not(:disabled) { background: var(--a3-primary-700); }
.a3-btn--secondary {
  background: var(--a3-bg-raised); color: var(--a3-text);
  border-color: var(--a3-border-strong);
}
.a3-btn--secondary:hover:not(:disabled) { background: var(--a3-bg-sunken); }
.a3-btn--quiet { background: transparent; color: var(--a3-link); }

/* Destructive actions are never the primary button and never sit adjacent to
   the safe one without separation. Colour alone does not carry the weight. */
.a3-btn--destructive {
  background: var(--a3-bg-raised); color: var(--a3-danger-600);
  border-color: var(--a3-danger-600);
}
.a3-btn--destructive:hover:not(:disabled) { background: var(--a3-danger-100); }

.a3-btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* Busy, not disabled. A disabled button loses its accessible name to some
   screen readers and tells the user nothing about why. */
.a3-btn[aria-busy="true"] { cursor: progress; }
.a3-btn[aria-busy="true"]::before {
  content: ""; width: 0.85em; height: 0.85em; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  animation: a3-spin 0.7s linear infinite;
}
@keyframes a3-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .a3-btn[aria-busy="true"]::before { animation-duration: 2s; }
}

/* -----------------------------------------------------------------------------
   Status
   -----------------------------------------------------------------------------
   Each status carries a shape or mark as well as a colour, so the distinction
   survives colour blindness and a bad screen in sunlight.

   Verified is deliberately not celebratory. It records a narrow claim.
----------------------------------------------------------------------------- */
.a3-status {
  display: inline-flex; align-items: center; gap: var(--a3-space-2);
  padding: var(--a3-space-1) var(--a3-space-3);
  border-radius: 999px;
  font-size: var(--a3-text-xs); font-weight: var(--a3-weight-medium);
  border: 1px solid transparent; white-space: nowrap;
}
.a3-status::before { content: attr(data-a3-mark); font-weight: var(--a3-weight-semibold); }

.a3-status--success  { background: var(--a3-success-100);  color: var(--a3-success-600);  border-color: var(--a3-success-600); }
.a3-status--settled  { background: var(--a3-settled-100);  color: var(--a3-settled-600);  border-color: var(--a3-settled-600); }
.a3-status--verified { background: var(--a3-verified-100); color: var(--a3-verified-600); border-color: var(--a3-verified-600); }
.a3-status--pending  { background: var(--a3-pending-100);  color: var(--a3-pending-600);  border-color: var(--a3-pending-600); }
.a3-status--warning  { background: var(--a3-warning-100);  color: var(--a3-warning-600);  border-color: var(--a3-warning-600); }
.a3-status--danger   { background: var(--a3-danger-100);   color: var(--a3-danger-600);   border-color: var(--a3-danger-600); }
.a3-status--denied   { background: var(--a3-denied-100);   color: var(--a3-denied-600);   border-color: var(--a3-denied-600); }
.a3-status--neutral  { background: var(--a3-bg-sunken);    color: var(--a3-text-secondary); border-color: var(--a3-border-strong); }

/* The scope of a verification claim travels with the claim. A badge without
   its scope and date is the badge that promises more than it can support. */
.a3-status__scope { color: var(--a3-text-muted); font-weight: var(--a3-weight-regular); font-size: var(--a3-text-2xs); }

/* -----------------------------------------------------------------------------
   Money
   Tabular figures, currency always explicit, never a bare number.
----------------------------------------------------------------------------- */
.a3-money {
  font-family: var(--a3-font-numeric);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.a3-money__currency { color: var(--a3-text-muted); font-size: 0.85em; margin-right: 0.35em; }
.a3-money--negative { color: var(--a3-danger-600); }
td.a3-money, th.a3-money { text-align: right; }

/* -----------------------------------------------------------------------------
   Cards and layout
----------------------------------------------------------------------------- */
.a3-card {
  background: var(--a3-bg-raised);
  border: 1px solid var(--a3-border);
  border-radius: var(--a3-radius-lg);
  padding: var(--a3-space-5);
}
.a3-stack > * + * { margin-top: var(--a3-space-4); }
.a3-row { display: flex; flex-wrap: wrap; gap: var(--a3-space-3); align-items: center; }

.a3-page { padding: var(--a3-space-5); max-width: 1200px; margin: 0 auto; }
@media (max-width: 640px) { .a3-page { padding: var(--a3-space-4) var(--a3-space-3); } }

/* -----------------------------------------------------------------------------
   Forms and validation
   -----------------------------------------------------------------------------
   Every field is labelled. Errors are announced, described, and tied to the
   field with aria-describedby, so a screen reader user learns what is wrong
   without hunting for it. Error text says what to do, never just what failed.
----------------------------------------------------------------------------- */
.a3-field { display: block; }
.a3-field__label {
  display: block; margin-bottom: var(--a3-space-1);
  font-size: var(--a3-text-sm); font-weight: var(--a3-weight-medium);
}
.a3-field__hint { font-size: var(--a3-text-xs); color: var(--a3-text-muted); margin-bottom: var(--a3-space-1); }
.a3-input, .a3-select, .a3-textarea {
  width: 100%; min-height: var(--a3-touch-min);
  padding: var(--a3-space-2) var(--a3-space-3);
  font: inherit; color: var(--a3-text);
  background: var(--a3-bg-raised);
  border: 1px solid var(--a3-border-strong);
  border-radius: var(--a3-radius-md);
}
.a3-textarea { min-height: 6rem; resize: vertical; }
.a3-input[aria-invalid="true"], .a3-select[aria-invalid="true"], .a3-textarea[aria-invalid="true"] {
  border-color: var(--a3-danger-600); border-width: 2px;
}
.a3-field__error {
  display: flex; gap: var(--a3-space-2); align-items: flex-start;
  margin-top: var(--a3-space-1);
  font-size: var(--a3-text-sm); color: var(--a3-danger-600);
}
.a3-field__error::before { content: "!"; font-weight: var(--a3-weight-semibold); }
.a3-input:disabled, .a3-select:disabled, .a3-textarea:disabled {
  background: var(--a3-bg-sunken); color: var(--a3-text-muted); cursor: not-allowed;
}

/* -----------------------------------------------------------------------------
   Notices
   -----------------------------------------------------------------------------
   Four kinds, deliberately distinct, because they mean different things and
   need different next actions:

     error     something broke. It may work if retried.
     denied    you are not permitted. Retrying will not help.
     conflict  someone or something else changed this first.
     info      context, no action required.

   Denied never explains what it is protecting. Telling an unauthorised caller
   which business a record belongs to, or that it exists at all, is the
   enumeration leak the API refuses; the interface must not reintroduce it.
----------------------------------------------------------------------------- */
.a3-notice {
  display: flex; gap: var(--a3-space-3);
  padding: var(--a3-space-4);
  border-radius: var(--a3-radius-md);
  border: 1px solid;
  border-left-width: 4px;
}
.a3-notice__body { flex: 1; }
.a3-notice__title { font-weight: var(--a3-weight-semibold); margin: 0 0 var(--a3-space-1); font-size: var(--a3-text-md); }
.a3-notice__text  { margin: 0; font-size: var(--a3-text-sm); color: var(--a3-text-secondary); }
.a3-notice--error    { background: var(--a3-danger-100);  border-color: var(--a3-danger-600); }
.a3-notice--denied   { background: var(--a3-denied-100);  border-color: var(--a3-denied-600); }
.a3-notice--conflict { background: var(--a3-warning-100); border-color: var(--a3-warning-600); }
.a3-notice--info     { background: var(--a3-primary-100); border-color: var(--a3-primary-600); }

/* -----------------------------------------------------------------------------
   Tables
   Dense by default on merchant and control surfaces. Headers stay put, because
   a merchant scrolling two hundred orders should not have to remember which
   column is which.
----------------------------------------------------------------------------- */
.a3-table-wrap { overflow-x: auto; border: 1px solid var(--a3-border); border-radius: var(--a3-radius-lg); background: var(--a3-bg-raised); }
.a3-table { width: 100%; border-collapse: collapse; font-size: var(--a3-text-sm); }
.a3-table caption { text-align: left; padding: var(--a3-space-3) var(--a3-space-4); color: var(--a3-text-secondary); font-size: var(--a3-text-sm); }
.a3-table th, .a3-table td {
  padding: 0 var(--a3-space-4); height: var(--a3-density-row);
  text-align: left; border-bottom: 1px solid var(--a3-border);
}
.a3-table thead th {
  position: sticky; top: 0; background: var(--a3-bg-sunken);
  font-size: var(--a3-text-xs); text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--a3-text-secondary); font-weight: var(--a3-weight-semibold);
}
.a3-table--compact { --a3-density-row: var(--a3-density-row-compact); }
.a3-table tbody tr:last-child td { border-bottom: none; }

/* -----------------------------------------------------------------------------
   Empty, loading, and skeletons
   -----------------------------------------------------------------------------
   An empty screen is an invitation to act, never an apology. A loading state
   reserves the space the content will occupy so nothing jumps when it arrives.
----------------------------------------------------------------------------- */
.a3-empty {
  text-align: center; padding: var(--a3-space-7) var(--a3-space-4);
  border: 1px dashed var(--a3-border-strong); border-radius: var(--a3-radius-lg);
}
.a3-empty__title { font-size: var(--a3-text-lg); font-weight: var(--a3-weight-semibold); margin: 0 0 var(--a3-space-2); }
.a3-empty__text { margin: 0 auto var(--a3-space-4); max-width: 44ch; color: var(--a3-text-secondary); font-size: var(--a3-text-sm); }

.a3-skeleton {
  background: linear-gradient(90deg, var(--a3-bg-sunken) 25%, var(--a3-ink-100) 37%, var(--a3-bg-sunken) 63%);
  background-size: 400% 100%;
  animation: a3-shimmer 1.4s ease infinite;
  border-radius: var(--a3-radius-sm);
  height: 1em;
}
@keyframes a3-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) {
  .a3-skeleton { animation: none; background: var(--a3-bg-sunken); }
}

/* -----------------------------------------------------------------------------
   Destructive confirmation
   -----------------------------------------------------------------------------
   Irreversible actions state the consequence in specific terms and require an
   intentional act rather than a reflex. What is retained and for how long is
   shown here, not in a policy page nobody opens, because a deletion the user
   did not understand is a deletion they did not consent to.
----------------------------------------------------------------------------- */
.a3-confirm { border: 1px solid var(--a3-danger-600); border-radius: var(--a3-radius-lg); padding: var(--a3-space-5); background: var(--a3-bg-raised); }
.a3-confirm__title { margin: 0 0 var(--a3-space-3); font-size: var(--a3-text-xl); }
.a3-confirm__consequences { margin: 0 0 var(--a3-space-4); padding-left: var(--a3-space-5); font-size: var(--a3-text-sm); color: var(--a3-text-secondary); }
.a3-confirm__consequences li + li { margin-top: var(--a3-space-1); }
.a3-confirm__actions { display: flex; gap: var(--a3-space-3); flex-wrap: wrap; }
/* The safe action comes first in the DOM and is the default. */
.a3-confirm__actions .a3-btn--destructive { margin-left: auto; }
@media (max-width: 480px) {
  .a3-confirm__actions .a3-btn { width: 100%; }
  .a3-confirm__actions .a3-btn--destructive { margin-left: 0; order: 2; }
}

/* -----------------------------------------------------------------------------
   Discovery: shops and products
   -----------------------------------------------------------------------------
   The customer's mental model is shops and products, not merchants. A shop is a
   destination with an identity; a merchant is the business operating it and does
   not appear here at all.

   Both cards are links to a place, not tiles with buttons in them. A card with
   an action inside it makes the whole card ambiguous to a keyboard user and to
   anyone using a screen reader.
----------------------------------------------------------------------------- */
.a3-grid {
  display: grid;
  gap: var(--a3-space-4);
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
/* One column on a narrow phone. Two cramped columns is worse than one clear one. */
@media (max-width: 400px) { .a3-grid { grid-template-columns: 1fr; } }

.a3-card-link {
  display: flex; flex-direction: column; gap: var(--a3-space-3);
  padding: var(--a3-space-4);
  background: var(--a3-bg-raised);
  border: 1px solid var(--a3-border);
  border-radius: var(--a3-radius-lg);
  text-decoration: none; color: inherit;
  min-height: var(--a3-touch-min);
}
.a3-card-link:hover { border-color: var(--a3-border-strong); }

/* The shop's mark. Reserved space, so a shop without a logo does not reflow the
   grid, and a shop with one cannot make its card taller than its neighbours. */
.a3-shop-mark {
  width: 40px; height: 40px; flex: 0 0 auto;
  border-radius: var(--a3-radius-md);
  background: var(--a3-bg-sunken);
  display: grid; place-items: center;
  font-family: var(--a3-font-display); font-weight: var(--a3-weight-semibold);
  color: var(--a3-text-secondary);
  overflow: hidden;
}
.a3-shop-mark img { width: 100%; height: 100%; object-fit: cover; }

.a3-card-link__title { font-weight: var(--a3-weight-semibold); font-size: var(--a3-text-md); }
.a3-card-link__meta { color: var(--a3-text-muted); font-size: var(--a3-text-xs); }

/* Product image. A fixed aspect box, so a merchant's tall photograph cannot
   stretch a row and a missing one leaves a placeholder rather than a collapse. */
.a3-product-image {
  aspect-ratio: 4 / 3; width: 100%;
  background: var(--a3-bg-sunken);
  border-radius: var(--a3-radius-md);
  display: grid; place-items: center;
  color: var(--a3-text-muted); font-size: var(--a3-text-xs);
  overflow: hidden;
}
.a3-product-image img { width: 100%; height: 100%; object-fit: cover; }

/* -----------------------------------------------------------------------------
   Reputation
   -----------------------------------------------------------------------------
   The first place where a design choice can undo a security guarantee.

   The domain publishes a band and a volume bucket, and refuses to publish a mean
   or an exact count, because a mean plus a count is solvable: watch the pair
   change and the newly added score falls out exactly.

   So this component renders a band and a bucket, and there is deliberately no
   element for a numeric average, no element for a review count, and no
   "most recent review" slot. Each of those would be a natural thing to add and
   each reintroduces the leak. A star row is also absent: five stars with one
   half-filled is a mean with extra steps.
----------------------------------------------------------------------------- */
.a3-reputation { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--a3-space-2); }
.a3-reputation__band {
  font-family: var(--a3-font-numeric);
  font-variant-numeric: tabular-nums;
  font-weight: var(--a3-weight-medium);
  font-size: var(--a3-text-md);
  color: var(--a3-text);
}
.a3-reputation__volume { color: var(--a3-text-muted); font-size: var(--a3-text-xs); }

/* Below the threshold. Says what is true without implying anything bad: a new
   shop has no ratings because it is new, not because it is poor. */
.a3-reputation--withheld { color: var(--a3-text-muted); font-size: var(--a3-text-sm); }

/* An individual published rating. No author, no date beyond the month, and no
   ordinal position, because "first" or "latest" is attribution. */
.a3-rating { padding: var(--a3-space-3) 0; border-bottom: 1px solid var(--a3-border); }
.a3-rating:last-child { border-bottom: none; }
.a3-rating__head { display: flex; align-items: baseline; gap: var(--a3-space-3); }
.a3-rating__score { font-family: var(--a3-font-numeric); font-weight: var(--a3-weight-semibold); }
.a3-rating__period { color: var(--a3-text-muted); font-size: var(--a3-text-xs); }
.a3-rating__body { margin: var(--a3-space-2) 0 0; font-size: var(--a3-text-sm); color: var(--a3-text-secondary); }

/* -----------------------------------------------------------------------------
   Shop header
   -----------------------------------------------------------------------------
   The shop's own identity: its mark, name, summary, where it trades, its trust
   signals and whoever it has chosen to name publicly. The operating business is
   not shown, because a customer came for the shop.
----------------------------------------------------------------------------- */
.a3-shop-header { display: flex; flex-wrap: wrap; gap: var(--a3-space-4); align-items: flex-start; }
.a3-shop-header .a3-shop-mark { width: 64px; height: 64px; font-size: var(--a3-text-xl); }
.a3-shop-header__body { flex: 1 1 16rem; min-width: 0; }
.a3-shop-header__name { margin: 0; font-family: var(--a3-font-display); font-size: var(--a3-text-2xl); }
.a3-shop-header__summary { margin: var(--a3-space-1) 0 0; color: var(--a3-text-secondary); max-width: var(--a3-measure); }

/* Named by choice, never because they operate the shop. */
.a3-operator { display: flex; align-items: baseline; gap: var(--a3-space-2); font-size: var(--a3-text-sm); }
.a3-operator__role { color: var(--a3-text-muted); font-size: var(--a3-text-xs); }

/* -----------------------------------------------------------------------------
   Two-column detail, collapsing to one
   -----------------------------------------------------------------------------
   A product beside its purchase panel on a wide screen; stacked on a phone with
   the panel after the detail, because a thumb reaching the bottom of the screen
   should find the action.
----------------------------------------------------------------------------- */
.a3-detail { display: grid; gap: var(--a3-space-5); grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); align-items: start; }
@media (max-width: 720px) { .a3-detail { grid-template-columns: 1fr; } }

/* Sticky only where there is room for it to help. */
@media (min-width: 721px) {
  .a3-detail__aside { position: sticky; top: calc(var(--a3-space-6) + 2rem); }
}

.a3-breadcrumb { display: flex; flex-wrap: wrap; gap: var(--a3-space-2); font-size: var(--a3-text-sm); color: var(--a3-text-muted); }
.a3-breadcrumb a { color: var(--a3-link); }

/* -----------------------------------------------------------------------------
   Layout utilities the surfaces actually need
   -----------------------------------------------------------------------------
   These exist because the content policy sets style-src 'self' with no
   unsafe-inline, so a style attribute is dropped by the browser and the layout
   it was holding up collapses. Silently, and only on the real product: markup
   tests still see the attribute in the string.

   So every layout decision a surface makes has to be nameable here. The list is
   short on purpose. When it stops being short, that is the signal that a
   component is missing rather than that another utility is needed.
----------------------------------------------------------------------------- */

/* A list of records. Semantically a list, without the marker and indent that
   turn a card list into a bulleted one. */
.a3-list { list-style: none; padding: 0; margin: 0; }

/* Label on one side, status on the other, stacking rather than overflowing when
   the viewport cannot hold both. This is the phone case, which is the common
   case, so it is the one the rule is written for. */
.a3-row--spread { justify-content: space-between; }

/* Secondary text that explains a control or its absence. Not a notice: a notice
   is something that happened, a hint is something to know beforehand. */
.a3-hint {
  margin: 0;
  color: var(--a3-text-secondary);
  font-size: var(--a3-text-sm);
}

/* Supporting line inside an empty state. Distinct from .a3-empty__text, which
   is the centred explanatory paragraph; this one sits under a title. */
.a3-empty__body {
  margin: 0;
  color: var(--a3-text-secondary);
  font-size: var(--a3-text-sm);
}

/* Page and section headings, so a surface never reaches for an inline
   font-size. */
.a3-heading { margin: 0; font-size: var(--a3-text-xl); font-weight: var(--a3-weight-semibold); }
.a3-subheading { margin: 0; color: var(--a3-text-secondary); font-size: var(--a3-text-sm); }

/* The payment strip: a bounded band above and below, rather than a card. */
.a3-strip {
  padding: var(--a3-space-3) 0;
  border-top: 1px solid var(--a3-border);
  border-bottom: 1px solid var(--a3-border);
}

/* A quantity input is a number, and a number does not need to be as wide as a
   name. Capped in rem rather than px so it grows with the user's text size. */
.a3-input--quantity { max-width: 6rem; }

/* A skeleton row fills its container. */
.a3-skeleton--row { width: 100%; margin-top: var(--a3-space-3); }

/* -----------------------------------------------------------------------------
   Search
   -----------------------------------------------------------------------------
   The search field takes the space the button does not, on every width, rather
   than at a breakpoint. A search box that is narrower than its own placeholder
   on a phone is the most common way a marketplace loses the customer who was
   ready to type.
----------------------------------------------------------------------------- */
.a3-search__field { flex: 1 1 12rem; min-width: 0; }

/* A card's own supporting line. Clamped, because a merchant's summary is
   merchant-written text of unpredictable length, and one long summary must not
   make its card twice the height of every neighbour in the grid. */
.a3-card-link__summary {
  margin: 0;
  color: var(--a3-text-secondary);
  font-size: var(--a3-text-sm);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* -----------------------------------------------------------------------------
   Share
   -----------------------------------------------------------------------------
   A shop's URL is its web address, and a customer who wants to send it to
   someone should not have to fish it out of the browser chrome, which is
   awkward on a phone and impossible to describe over the phone.

   A disclosure rather than a dialog, because a dialog needs script and these
   pages emit none. Closed by default so it costs nothing to the majority who
   are not sharing, and open on demand for those who are.

   The address sits in a read-only input rather than as text, because an input
   selects in full on a tap and text does not. -------------------------------- */
.a3-share {
  border: 1px solid var(--a3-border);
  border-radius: var(--a3-radius-md);
  padding: var(--a3-space-3) var(--a3-space-4);
  background: var(--a3-bg-raised);
}
.a3-share > summary {
  cursor: pointer;
  font-weight: var(--a3-weight-medium);
  font-size: var(--a3-text-sm);
  /* A summary is the control, so it obeys the same minimum target as a button. */
  min-height: var(--a3-touch-min);
  display: flex; align-items: center;
}
.a3-share > summary:focus-visible { outline: 2px solid var(--a3-focus); outline-offset: 2px; }
.a3-share[open] > summary { margin-bottom: var(--a3-space-3); }
/* Long addresses stay readable rather than forcing the page sideways. */
.a3-share .a3-input { font-size: var(--a3-text-sm); }
