/* =====================================================================================
   TOUCH: hover is for POINTERS ONLY (Andrew, 2026-07-26: "anytime that the user hits a tapped
   area ... it's like a weird aftereffect where you can just kind of slightly see it after you
   press. We need to go and strip that out of this whole thing.")

   A phone has no pointer to move away, so iOS and Android keep :hover applied to the LAST
   element you touched until you tap something else. Every :hover rule in this app was therefore
   a STICKY state: tap an item tile, a tip pill, a text action, and its hover tint stayed lit
   behind your finger afterwards. That is the "aftereffect", and it was never a hover at all.

   Every :hover rule in app.1-app.8 is wrapped in `@media (hover: hover)`, so it applies only
   where a real pointer exists. A device with BOTH (iPad + trackpad, touch laptop) still gets
   hover, because it genuinely can hover. :active is deliberately untouched: that IS the press
   feedback, it is instantaneous, and it releases with the finger.

   Vendored registry CSS (public/js/nimiq/**) is NOT edited here — those files are pixel-verified
   against upstream truth renders and the conformance harness diffs against them. Their hover
   states are neutralised on touch by the `@media (hover: none)` block at the end of app.8.css.
   ===================================================================================== */

/* nimiq.sale: custom layout glue on top of @nimiq/style (legacy) + nq registry components.
   8px root font-size: 1rem = 8px. Custom values written in px (or rem x2). Colors from the
   verified Nimiq table only. White-space structure, no decorative boxes/lines. */

/* Registry component CSS (each `nq add` dropped one CSS file under js/nimiq/<name>/). */
@import url("../js/nimiq/small-page/small-page.css");
@import url("../js/nimiq/page-header/page-header.css");
@import url("../js/nimiq/page-body/page-body.css");
@import url("../js/nimiq/page-footer/page-footer.css");
@import url("../js/nimiq/card/card.css");
@import url("../js/nimiq/buttons/buttons.css");
@import url("../js/nimiq/label-input/label-input.css");
@import url("../js/nimiq/amount-input/amount-input.css");
@import url("../js/nimiq/qr-code/qr-code.css");
@import url("../js/nimiq/timer/timer.css");
@import url("../js/nimiq/status-screen/status-screen.css");
@import url("../js/nimiq/transaction-list/transaction-list.css");
@import url("../js/nimiq/payment-info-line/payment-info-line.css");
@import url("../js/nimiq/copyable/copyable.css");
@import url("../js/nimiq/identicon/identicon.css");
@import url("../js/nimiq/address-display/address-display.css");
@import url("../js/nimiq/amount/amount.css");
@import url("../js/nimiq/fiat-amount/fiat-amount.css");
@import url("../js/nimiq/status-alert/status-alert.css");
@import url("../js/nimiq/close-button/close-button.css");
@import url("../js/nimiq/loading-spinner/loading-spinner.css");

/* nimiq-style sets the deprecated Muli family, override with Mulish (rule 9). */
body {
  font-family: 'Mulish', 'Muli', system-ui, sans-serif !important;
}

/* ---- Accessibility: device-local large-text mode + muted-text tokens (set by a11y.js). ----
   Because EVERY dimension in the app is in rem on an 8px root, scaling the root by one variable
   scales text, padding, buttons, inputs, and the whole card proportionally — the cleanest
   large-text mode. nimiq-style.min.css hard-sets html{font-size:8px}; app.css is imported AFTER it
   (index.html), so this later, equal-specificity rule wins the cascade (verified in-browser).
   --muted-text / --muted-text-strong / --a11y-border are the single point of control for the
   high-contrast block: faint navy text / input borders reference them, so high contrast is mostly
   one variable swap (no per-rule overrides) and the brand hues are never touched. */
:root {
  --a11y-text-scale: 1;
  --muted-text: rgba(31, 35, 72, 0.5);
  --muted-text-strong: rgba(31, 35, 72, 0.7);
  --a11y-border: rgba(31, 35, 72, 0.1);
  /* Shell geometry, single point of control (#36). These ARE the nq-card values: nimiq-style
     ships .nq-card-header/.nq-card-body at 4rem with a 3rem override under 450px, and
     .nq-card-header + .nq-card-body at padding-top 1rem. The app shell puts #sim-strip between
     the header and the body, which breaks that adjacency selector, so the body states its top
     padding explicitly instead of inheriting it. Anything that has to cancel the body padding
     (the full-bleed checkout panel) reads these variables rather than repeating the numbers. */
  --shell-pad: 4rem;
  --body-pad-top: 1rem;
}

/* nimiq-style's own breakpoint, mirrored so the shell tracks the card it lives in. */
@media (max-width: 450px) {
  :root {
    --shell-pad: 3rem;
  }
}

html {
  font-size: calc(8px * var(--a11y-text-scale));
}

/* Light stage (rule: never white, never navy). Center the SmallPage. */
html,
body {
  margin: 0;
  padding: 0;
  background: #F8F8F8;
  color: var(--nimiq-blue);
}

/* DYNAMIC viewport units, not `vh` (#32). On mobile Safari/Chrome `100vh` is the LARGE viewport
   (the height with the browser toolbars RETRACTED), which is taller than what the merchant can
   actually see. Sizing the stage/card in `vh` therefore pushes the card's pinned footer — the
   primary CTA on every screen — underneath the browser's bottom toolbar. `dvh` tracks the
   CURRENTLY visible viewport, so the card always fits the visible area and the footer is always
   on screen. The `vh` line stays first as the fallback for engines that do not parse `dvh`
   (they drop the second declaration). Same rule as the dock-line fix in the GDKC site work. */
.stage {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px 0;
  box-sizing: border-box;
}

/* The single white card, identical across all 5 screens. */
.small-page {
  position: relative;
  /* The card itself does NOT clip: the page-body owns the scroll (overflow-y:auto + min-height:0) and
     clips its own overflowing content, while the header/footer (rounded nq-card corners) + full-card
     overlays carry the rounded shape. Clipping HERE made every tall screen's scrolled-out body content
     report positions past the card edge, which reads as "card clips its content" (it does not, the body
     scrolls). Cap the card to the viewport so large-text mode never grows it past the screen.
     `dvh` (with the `vh` fallback) so the cap tracks the VISIBLE viewport on mobile — see the
     .stage note above (#32). */
  max-height: calc(100vh - 32px);
  max-height: calc(100dvh - 32px);
}

/* Fira Mono for technical values (rule 9). */
.mono,
.address-display .chunk,
.amount,
.copyable.mono {
  font-family: 'Fira Mono', monospace;
}

/* ---- App bar: persistent navy chrome, lockup left + wallet pill right ----
   Sits ABOVE .page-header inside the card, so it owns the card's rounded top corners (the header
   below it is now square-topped, see the override further down). `flex: none` keeps it out of the
   body's height negotiation: it costs a fixed strip, and every screen's fit logic (#50 checkout
   budget, #51 sell density, #56 pay QR) measures what is left, so nothing needs to know it exists.
   Deliberately NOT re-rendered per screen — it is chrome. */
.app-bar {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  /* Andrew's call, 2026-07-25: the brand reads too small at 44 and the bar is what gives. See the
     density note in scripts/sell-density.mjs for what this costs the menu. */
  height: 52px;
  padding: 0 var(--shell-pad);
  box-sizing: border-box;
  border-radius: 1.25rem 1.25rem 0 0;
  background-image: var(--nimiq-blue-bg);
  /* REQUIRED, not cosmetic. The fleet wallet pill is theme-adaptive by way of `currentColor` for its
     text, border and glyph, so it reads on a navy header or a light one. Without a colour set here it
     inherits the body's navy and renders navy-on-navy: mounted, measurable, and invisible. */
  color: #fff;
  overflow: hidden;
}

/* flex: none is REQUIRED. An inline SVG in a flex row shrinks below its intrinsic width by default,
   and a `height: Npx; width: auto` lockup that gets shrunk is SQUASHED, not scaled: measured 158px
   wide at 360 against an intrinsic 198px, a 20% horizontal compression of a wordmark whose whole
   spec is its letter spacing. It must never shrink; the height below is what adapts instead. */
.app-bar-brand {
  flex: none;
  display: flex;
  align-items: center;
}

/* Height-driven, width auto: the lockup's own viewBox carries the signet-to-wordmark proportion,
   so pinning the height is the only measurement that may be applied to it. The lockup is 7.94x wider
   than it is tall, so height is really a WIDTH budget: 28px costs 222px of the bar. */
.app-bar-brand .brand-lockup {
  display: block;
  flex: none;
  height: 28px;
  width: auto;
}

.app-bar-wallet {
  flex: none;
  display: flex;
  align-items: center;
}

/* The fleet pill ships at 40px, which is the whole bar. Scale it to sit inside instead. These are
   nimiq-app-shell's own class names (see public/js/wallet-pill.js) and it self-injects its styles,
   so this block has to come after them in the cascade — it does, the shell injects at runtime. Only
   the box is touched: colour, border and states stay the component's, which is what keeps the pill
   identical to the rest of the fleet. */
.app-bar-wallet .nq-connect,
.app-bar-wallet .nq-wallet__btn {
  height: 30px;
  font-size: 12.5px;
  padding: 0 12px;
}

.app-bar-wallet .nq-wallet__btn {
  padding: 3px 10px 3px 4px;
}

.app-bar-wallet .nq-wallet__icon {
  width: 22px;
  height: 22px;
}

.app-bar-wallet .nq-connect__icon {
  width: 15px;
  height: 15px;
}

/* Narrow phones: the two halves stop fitting on one row. Measured at 390 the lockup is 159px and the
   pill 142px, which with the 12px gap and 2x24px of card padding needs 361px of a 360px card. The
   brand gives way first, not the pill's label: 18px still reads and losing "Connect wallet" would
   turn a labelled control into a mystery glyph. */
/* The 420px card (>= 450px viewport) is NARROWER than a large phone's card, so the lockup steps
   down there rather than up: 25px is 198px, which is what fits beside the labelled pill in 356px. */
@media (min-width: 450px) {
  .app-bar-brand .brand-lockup {
    height: 25px;
  }
}

/* On a PHONE the pill drops its label so the brand can have the width. This is the trade Andrew
   chose: the lockup reading clearly beats the word "wallet" next to a wallet glyph. A labelled pill
   would cap the lockup at 20px on a 360 phone, which is where this started. Above 450px the card is
   fixed at 420 and both fit, so the label comes back. */
@media (max-width: 449px) {
  .app-bar-wallet .nq-connect {
    font-size: 0;
    padding: 0 9px;
    gap: 0;
  }
  .app-bar-wallet .nq-connect__icon {
    width: 17px;
    height: 17px;
  }
}

/* The header no longer sits at the top of the card, so it must not keep the rounded top corners
   (they would cut a white notch out of the navy bar above it). */
.page-header.nq-card-header {
  border-radius: 0;
}

/* ---- Header: 5-step progress + back arrow + centered title (NO logo) ---- */
/* The header lives on white, so the back arrow and title inherit navy. */
.page-header .nq-h1 {
  font-size: 3rem;
}

/* The header keeps nimiq-style's own nq-card-header padding untouched (32px, 24px under 450px).
   An earlier build cut the bottom to 8px for a tighter title-to-content gap; the #36 conformance
   pass put it back on the registry value, so the header now measures identical to the truth
   render at both widths. */

/* ---- page-body shared spacing ---- */
/* page-body owns its own scroll (flex-grow + overflow-y:auto from page-body.css). The padding is
   the registry nq-card-body rhythm expressed through the shell variables: the sides/bottom track
   the card (32px, 24px under 450px) and the top restates the 1rem the header+body adjacency rule
   would give, which the #sim-strip between them prevents from firing. */
.page-body.nq-card-body {
  padding: var(--body-pad-top) var(--shell-pad) var(--shell-pad);
  /* min-height:0 is REQUIRED for a flex-grow child to scroll: without it the flex item's default
     min-height:auto refuses to shrink below its content, so `overflow-y:auto` never engages and tall
     content (dashboard, close-out, long receipts) overflows the fixed-height .small-page (overflow:hidden)
     and gets CLIPPED. With it, the body scrolls internally and the footer/content stay reachable. */
  min-height: 0;
}

.lead {
  color: var(--muted-text);
  font-size: 2rem;
  line-height: 1.4;
  margin: 0 0 24px;
}

.empty-note {
  color: var(--muted-text);
  font-size: 2rem;
  text-align: center;
  margin: 32px 0;
}

/* SIMULATED strip: a flex sibling between header and body (flex-shrink:0 so it never
   gets squished, unlike the old page-body reuse which collapsed it to a thin bar). */
.sim-strip {
  flex-shrink: 0;
  padding: 6px var(--shell-pad) 0;
  box-sizing: border-box;
}

/* Compact one-line simulated banner, the short form of the receipt's status alert.
   The app shows "simulated" in two densities: the full registry .nq-status-alert.warning where
   there is room (the receipt), and this one-liner where there is not (the pay screen, the split
   shares, the refund overlay), because the full alert pushed the pay QR past the card fold. Both
   carry the SAME warning palette, because a buyer and a merchant walk pay -> receipt in one
   sitting and one signal must not change color halfway.

   Those colors are nimiq-css's warning pair, written here in sRGB rather than the oklch the
   vendored status-alert.css uses, so the conformance linter can actually read them: surface
   --colors-orange-400 = oklch(0.951 0.0221 74.1), text --colors-orange = oklch(0.7387 0.179 56.67)
   = var(--nimiq-orange). Measured honestly that pair is 2.11:1, which is what upstream ships and
   what the receipt alert renders; it is triaged by exact pair in scripts/conformance/lint.mjs with
   the reason, and the word SIMULATED plus the message text carry the signal without the color. */
.sim-banner {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 6px;
  background: rgb(248, 237, 223);
  font-size: 1.5rem;
  line-height: 1.35;
  color: var(--nimiq-orange);
}

.sim-banner .sim-tag {
  flex: 0 0 auto;
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* status-alert: undo the upstream docs full-bleed quirk inside our padded body/strip. */
.page-body .nq-status-alert,
.sim-strip .nq-status-alert {
  transform: none;
  width: 100%;
  margin: 16px 0 0;
}

.page-body .nq-status-alert p,
.sim-strip .nq-status-alert p {
  font-size: 1.75rem;
  line-height: 1.4;
}

/* ---- Import screen ---- */
/* #57: ONE primary pill, its note, then the quiet alternates. The old three-pill stack (32px apart,
   each with its own note) read as three equal choices plus a fourth greyed one in the footer. */
.import-paths {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: 24px;
}

/* The two secondary import paths (a CSV, the demo catalog) share one row under the primary. */
.import-alts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 24px;
  margin-top: 8px;
}

/* The CSV button is a <label> wrapping a hidden file input. */
.file-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.file-button input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.path-note {
  color: var(--muted-text);
  font-size: 1.625rem;
  text-align: center;
  max-width: 320px;
}

/* ---- Setup screen (screen 0): merchant register setup, outside the 5-step flow ---- */
.setup-screen {
  display: flex;
  flex-direction: column;
  gap: 28px;
  margin-top: 8px;
  /* enough bottom clearance that the verification caption (the feature's core instruction)
     scrolls fully clear of the pinned footer on the standard 420x564 card. */
  padding-bottom: 16px;
}

/* First-run welcome step (#10): the three steps ahead, as a clean numbered list. The number is a
   light-blue accent disc; structure-by-whitespace, no decorative kicker/eyebrow. */
.welcome-steps {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.welcome-step {
  display: flex;
  align-items: center;
  gap: 16px;
}

.welcome-step-num {
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 500px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.875rem;
  font-weight: 700;
  color: #fff;
  background-image: var(--nimiq-light-blue-bg, radial-gradient(100% 100% at bottom right, #265dd7, #0582ca));
}

.welcome-step-label {
  font-size: 2.25rem;
  font-weight: 600;
  color: var(--nimiq-blue, #1f2348);
}

/* The first-run "ring your first sale" coach (#10) used to be a soft info card above the menu. It
   said the same sentence the empty-cart line already said, and on a phone that block cost the
   cashier a row of items on every sale, so the copy now lives on the empty-cart line alone (#51).
   FIRSTRUN_GUIDE_KEY still gates it and showReceipt still clears it. */

/* Returning-buyer "Welcome back" line on the receipt (#7): a quiet light-blue accent, not green
   (green = success only) and not a pill/glow. Merchant-only, opt-in, default off. */
.receipt-returning {
  margin: 0 0 4px;
  font-size: 1.75rem;
  font-weight: 600;
  color: var(--nimiq-light-blue, #0582ca);
}

/* a label + input stack, mirroring .add-item-block / .row-name rhythm */
.setup-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.setup-field .setup-label {
  font-size: 1.75rem;
  font-weight: 600;
  color: var(--muted-text);
}

.setup-field .nq-input {
  width: 100%;
  box-sizing: border-box;
}

/* monospace receive-address input (the address is technical, like other addresses: rule 9).
   Reuses the Fira Mono stack already loaded in index.html. Sized down from the default input
   font so more of the ~42-char NQ address is visible at once and the START of the address is
   not scrolled out of view (Defect: clipping). The chunked fingerprint below is the
   AUTHORITATIVE full readback — the merchant verifies against it, not the single-line input. */
.nq-input.mono {
  font-family: 'Fira Mono', monospace;
  font-size: 1.25rem;
  letter-spacing: 0;
}

.setup-field .setup-help {
  text-align: left;
  margin: 4px 0 0;
  font-size: 1.625rem;
}

/* the live verification block reuses .merchant-fingerprint; keep it left-aligned and give
   it breathing room from the help line above. Empty (no children) until the shape gate passes.
   A bottom margin guarantees the caption clears the pinned footer when the body is scrolled
   to the end (Defect: caption occluded). */
.setup-verify {
  margin-top: 8px;
  margin-bottom: 8px;
}

.setup-verify:empty {
  margin: 0;
}

.setup-verify .merchant-fingerprint {
  align-items: flex-start;
  margin-top: 0;
}

/* keep the verification compact so the identicon + chunked address + caption clear the
   pinned footer on the standard card (the body still scrolls as a safety net). The chunked
   address is the authoritative full readback, so keep it readable but not oversized. */
.setup-verify .merchant-fingerprint .address-display {
  font-size: 1.375rem;
}

.setup-verify .merchant-fingerprint .fingerprint-caption {
  text-align: left;
  font-weight: 600;
}

/* Server-rejected-address line (bad checksum). Nimiq red, left-aligned with the field. */
.setup-error {
  color: #d94432;
  font-size: 1.5rem;
  margin: 6px 0 0;
  text-align: left;
}

.setup-error[hidden] {
  display: none;
}

/* ---- Sell screen "Paid to" reassurance strip (re-verify the destination each session) ----
   It reads immediately above the Cart, so it is structured by white space and a single hairline
   rule rather than boxed: one more outlined box stacked on the cart's own surfaces is the kind of
   ornament the brand's prime directive removes (#51). */
.sell-merchant {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
  margin: 4px 0 8px;
  border-top: 1px solid var(--a11y-border);
}

.sell-merchant .identicon {
  flex: 0 0 auto;
}

.sell-merchant .sell-merchant-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1 1 auto;
}

.sell-merchant .sell-merchant-name {
  font-size: 1.75rem;
  font-weight: 600;
  color: var(--nimiq-blue);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sell-merchant .sell-merchant-addr {
  font-size: 1.5rem;
  color: var(--muted-text);
}

.sell-merchant .sell-merchant-change {
  flex: 0 0 auto;
  font-size: 1.625rem;
}
