/* stylelint-disable no-descending-specificity -- this file intermixes global utility
   classes with scoped component overrides that legitimately carry higher specificity and
   may appear in any source order; the rule yields only false positives across the file. */

/* ============================================================
   LIBRARY CARD RECIPES — batch 4 (shipping-cod-toolkit)
   All classes land on the library Card root div via the
   `classes` prop. --card-border / --card-border-radius are
   intentionally omitted: the :root default
   (var(--border-radius-card) = 24px) applies app-wide.
   No raw hex, no --color-gray-* / --color-white.
   ============================================================ */

/* Feature-tile: clickable landing-page tiles (COD Eligibility,
   Customize COD, Configure Shipping). Reduced radius + no border
   + pointer cursor. Shadow lives on the .info-card wrapper in the
   page component (mirrors the beta's DOM structure). */
.global-card-shipping-cod-toolkit-feature-tile {
  --card-content-padding: var(--spacing-rg);

  cursor: pointer;
}

/* Flush elevated card: zero content padding + standard shadow. Generic recipe
   replacing per-feature global-card-* one-offs (config panels, metric tiles,
   wallet/jsonform wrappers). */
.global-card-flush {
  --card-content-padding: 0;
}

/* Compact row card: row padding + standard shadow (provider/estimate/zone rows). */
.global-card-row {
  --card-content-padding: var(--spacing-md) var(--spacing-rg);
}

/* Upload: pincode upload card inside the Add-Pincodes modal.
   No border (modal frame provides containment), compact padding,
   no shadow (modal context). */
.global-card-shipping-cod-toolkit-upload {
  --card-content-padding: var(--spacing-rg);
}

/* Rule-step: zone-select / pincode / rule cards in the
   ShippingRuleForm multi-step wizard (steps 0–2).
   Slightly larger vertical padding (spacing-md) + standard shadow.
   Overflow must stay visible: the rules grid embeds Dropdown cells
   (payment group, provider) whose absolutely-positioned panels open past
   the card's bottom edge — the library Card's default overflow: hidden
   cuts them mid-list and hides the lower options entirely. */
.global-card-shipping-cod-toolkit-rule-step {
  --card-content-padding: var(--spacing-md) var(--spacing-rg);
  --card-overflow: visible;
}

/* ============================================================
   END — batch 4 (shipping-cod-toolkit) card recipes
   ============================================================ */

/* Warning variant for @juspay/svelte-ui-components Banner (replaces the deleted
   project Warning component). Structural defaults (padding/cursor/position) come
   from the :root banner base in theme.css; this overrides only the warning colors,
   icon size, and corner radius. */
.global-banner-warning {
  --banner-icon-size: 18px;
}

/* Info variant for @juspay/svelte-ui-components Banner (replaces the deleted
   project Message component). Colors + structural defaults come from the :root
   banner base (info) in theme.css; this only adds the centered, rounded shape the
   onboard callouts use. */

/* Error variant for @juspay/svelte-ui-components Banner (replaces the deleted
   project ErrorMessage component). Uses the purpose-built --*-banner-error tokens
   from theme.css; overrides structural defaults so the banner sits inline (static
   position, flex-start alignment) and matches the chat error card shape. */
.global-banner-error {
  --banner-padding: var(--spacing-12) var(--spacing-md);
  --banner-gap: calc(var(--spacing-md) * 0.75);
  --banner-justify-content: flex-start;
  --banner-z-index: auto;
  --image-width: var(--banner-icon-size, 18px);
  --image-height: var(--banner-icon-size, 18px);

  box-sizing: border-box;
  max-width: var(--spacing-500);
  min-width: var(--spacing-200);
  width: 100%;
}

/* Tone-variant classes for the project Banner → library Banner migration.
   Each class sets the three CSS vars that drive background / color / border so
   the library Banner matches the project's design-token palette.
   Position / cursor / padding overrides come from the :root in theme.css. */

/* Size variants — `md` is the default bordered card strip; `sm` is the compact
   inline hint used inside modal bodies and form fields (tighter padding, no border). */
.global-banner-size-sm {
  --banner-padding: var(--spacing-sm) var(--spacing-md);
}

/* Flush modifier — strips border and border-radius so the banner sits edge-to-edge
   inside a parent container (e.g. bottom of a card). */

/* Shared layout recipe for a consumer-side banner div when the library Banner's
   `text` string prop cannot hold rich HTML children (e.g. <code>, <strong>).
   Applies the same flex layout, icon-area sizing, and gap the project Banner used.
   Pair with .global-banner-tone-* for colour. */
.global-banner-rich {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-12);

  /* Consume the tone vars set by .global-banner-tone-* (BZ-3427). Without
   * these the tone classes only defined the custom properties and the banner
   * rendered transparent with a currentColor border. The fallbacks keep
   * non-toned usage identical to the previous behaviour. */
  padding: var(--spacing-12) var(--spacing-12);

  /* Size Img tone icons placed as the first flex child to 16px. The library Img
     defaults to 24px; without this the banner icon renders oversized. */
  --image-width: var(--spacing-md);
  --image-height: var(--spacing-md);
}

/* Wrapper for @juspay/svelte-ui-components Shimmer instances. The library
   Shimmer reads `--shimmer-width` / `--shimmer-height` / `--shimmer-border-radius`
   from its ancestor. Per-instance dimensions live in the component's own
   \3c style> block; cross-file duplicates have a utility class here.

   `display: contents` makes the wrapper invisible to layout so the Shimmer
   participates in the parent flex / grid directly. */

.shimmer-wrap {
  display: contents;
}

/* 100% × 100px × 8px is the most-used skeleton shape (analytics stat cards
   and the home-view report-card row). Promoted here so both files share
   one definition. */
.shimmer-card-row {
  --shimmer-height: var(--spacing-100);
}

/* 100% × 320px × radius-sm — full-width page-section skeleton (e.g. shipping
   configuration page bootstrapping from Shopify session data). */
.shimmer-page-section {
  --shimmer-width: 100%;
  --shimmer-height: 320px;
}

/* 100% × 56px × radius-sm — product/result row skeleton in the Order Edit
   "Add Products" modal list (and any similar list-row loading state). */
.shimmer-product-row {
  --shimmer-height: var(--spacing-56);
  --shimmer-border-radius: var(--radius-sm);
}

/* Caption text rendered alongside the library Loader. Project standard
   for "spinner + descriptive caption below" loading states. Tokens
   --loading-text-margin-top and --loading-text-color live in theme.css.

   Namespaced under .global-* to avoid colliding with WebCamera.svelte's
   own scoped .loading-text class. */
.global-loader-caption {
  margin-top: var(--loading-text-margin-top);
}

/* accessibility */

.global-sr-only {
  position: absolute;
  width: var(--spacing-1);
  height: var(--spacing-1);
  padding: var(--spacing-0);
  margin: calc(-1 * var(--spacing-1));
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

/* Visually hides a @juspay/svelte-ui-components Checkbox's text label while
   keeping it in the accessibility tree (the visible context — a title/heading —
   is rendered next to the checkbox). Apply via the Checkbox `classes` prop:
   <Checkbox classes="global-checkbox-hide-label" text="…" />. */
.global-checkbox-hide-label .label {
  position: absolute;
  width: var(--spacing-1);
  height: var(--spacing-1);
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* button */

/* Icon-only back-navigation button wrapping @juspay/svelte-ui-components Button.
   Renders a transparent, borderless, square hit-target that inherits the page
   text color for the chevron icon. Default size is 16px — parity with the
   legacy BackButton's default iconSize='sm' (.global-icon-sm → --spacing-md).
   Use .global-back-btn-rg for the 20px variant (legacy iconSize='rg'). */
.global-back-btn {
  --button-padding: 0;
  --button-width: var(--spacing-md, 16px);
  --button-height: var(--spacing-md, 16px);
  --button-content-gap: 0;

  /* Icon-only back chevron: stay transparent on hover instead of flashing the
     library Button's default primary-blue fill (most visible on dark /ai). */
  --button-color: var(--color-transparent);
  --button-hover-color: var(--color-transparent);
  --button-hover-border: var(--color-transparent);
  --button-box-shadow: none;

  /* Sizes the BackChevronIcon's Image — same vars the legacy
     .global-icon-sm wrapper set for the old BackButton. */
  --image-width: var(--spacing-md, 16px);
  --image-height: var(--spacing-md, 16px);

  display: flex;
  align-items: center;
  cursor: pointer;
}

/* 20px back-button variant — parity with the legacy BackButton iconSize='rg'
   (.global-icon-rg → --spacing-rg), used by the onboarding back bar.
   Inherits all theming from .global-back-btn; only size differs. */
.global-back-btn-rg {
  --button-width: var(--spacing-rg, 20px);
  --button-height: var(--spacing-rg, 20px);
  --image-width: var(--spacing-rg, 20px);
  --image-height: var(--spacing-rg, 20px);
}

/* 24px back-button variant — used by PageHeader on desktop to match the xl
   heading size so the chevron reads as the same visual weight as the title. */
.global-back-btn-xl {
  --button-width: var(--spacing-lg, 24px);
  --button-height: var(--spacing-lg, 24px);
  --image-width: var(--spacing-lg, 24px);
  --image-height: var(--spacing-lg, 24px);
}

.global-dashed-primary-button {
  --button-width: 100%;
  --button-height: var(--spacing-60);
}

.global-dashed-primary-button.is-dragging-over,
.global-dashed-primary-button.enable-hover:hover {
  transform: scale(1.02);
  transition: all 0.2s ease-in-out;
}

.global-ai-action-button-secondary {
  --button-width: var(--spacing-40);
}

.global-ai-send-button-primary {
  --button-width: var(--spacing-40);
}

.global-transparent-primary-button {
  --button-padding: none;
}

/* Opt-in filter modifier for library Img: set on icon wrapper when the SVG
   has dark fills and needs to be readable in both light (none) and dark
   (invert to white) mode. */
.icon-dark-fill-safe {
  /* also applies to raw <img> (not just the library <Img> --image-filter chain)
     so dark-fill SVGs read in both light (none) and dark (invert) mode. */
}

.global-medium-primary-button {
  /* The global :root --disabled-font-size resolves --button-font-size at :root
     (16px) and inherits down, so disabled buttons ignored this recipe's 14px and
     rendered a size larger than their enabled state (e.g. the Tools "Update shop
     name" button shrank 16→14px the moment editing enabled it). Track the recipe's
     own button font so enabled and disabled stay the same size. */
}

.global-medium-primary-nobackground-noborder-button {
  --button-padding: 10px 16px;

  /* Keep the disabled state borderless/backgroundless too — the library Button's
   * disabled background/border resolve from :root and would otherwise box the
   * disabled control (e.g. the reorder ▲/▼ arrows), making it look broken next
   * to the enabled, boxless one. Disabled now just dims via --disabled-opacity. */
}

.global-medium-danger-button {
  --loader-foreground: var(--text-color-on-accent);
}

/* Variant of global-medium-secondary-button with secondary text color and subtle shadow */

.global-small-primary-button {
  --button-height: var(--spacing-32);

  /* project Button size='small' (global-btn-sm) padding, snapped to the 4px grid */
}

.global-ghost-button {
  --button-height: var(--spacing-32);
  --button-padding: var(--spacing-xs);
}

/* Transparent icon-only action button (edit/delete). Neutralises the global
 * blue --button-hover-* ring so the glyph stands alone in rest and hover. */

.global-large-button-configuration {
  --button-height: var(--spacing-48);
  --button-padding: var(--spacing-md) var(--spacing-20);
}

.global-offer-apply-button {
  --button-height: auto;
  --button-padding: var(--spacing-sm) var(--spacing-12);
}

.advanced-settings-toggle {
  margin-top: var(--spacing-md);

  --chevron-icon-size: var(--spacing-20);
}

/* Native download button - full width CTA style */
.global-download-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-sm);
  width: 100%;
  padding: var(--spacing-md) var(--spacing-lg);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.global-download-btn:disabled {
  cursor: not-allowed;
}

.global-height-full {
  height: 100%;
}

.global-max-full {
  max-width: 100%;
  max-height: 100%;
}

.global-loading-section-md {
  width: 100%;
  height: 200px;
}

/* Generic horizontal feature list container */
.global-feature-list-row {
  gap: var(--spacing-40);
  margin-top: var(--spacing-lg);
}

.global-list-tile {
  padding: var(--spacing-12) var(--spacing-md);
}

/* Padded surface panel on the neutral-subtle background with a small radius. */
.global-surface-panel {
  padding: var(--spacing-lg);
  box-sizing: border-box;
}

/* Caps a scrollable list to ~3 rows (row = spacing-72, gap = spacing-sm) before scroll. */
.global-list-max-height-3-rows {
  max-height: calc(3 * var(--spacing-72) + 2 * var(--spacing-sm));
}

.global-horizontal-card-layout {
  display: flex;
  overflow: hidden;
}

.global-card-media-left {
  width: var(--spacing-450);
  min-height: var(--spacing-500);
  flex-shrink: 0;
}

.global-media-full-size {
  height: 100%;

  --image-width: 100%;
  --image-height: 100%;
}

.global-card-content {
  padding: var(--spacing-40);
}

.global-card-subtitle-secondary {
  padding: var(--spacing-12) 0;
}

.global-card-cta-block {
  margin-top: var(--spacing-md);
}

.global-primary-cta-button-large {
  --button-height: var(--spacing-48);
  --button-padding: var(--spacing-md) var(--spacing-28);
}

.global-stepper-panel {
  padding: var(--spacing-40);
  padding-left: var(--spacing-60);
  width: var(--spacing-500);
  min-width: var(--spacing-500);
}

.global-stepper-heading {
  margin-bottom: var(--spacing-32);
}

.global-step-card {
  overflow: hidden;
  transition: all 0.3s ease;
  margin-bottom: var(--spacing-md);
}

/* Mobile: the horizontal install-wizard card stacks vertically so the fixed
   450px media column and 500px stepper panel don't exceed a phone viewport and
   shove the text/step content off-screen. */
@media only screen and (width <= 767px) {
  .global-horizontal-card-layout {
    flex-direction: column;
  }

  .global-card-media-left {
    width: 100%;
    min-height: var(--spacing-180);
  }

  .global-stepper-panel {
    width: 100%;
    min-width: 0;
    padding-left: var(--spacing-40);
  }
}

.global-step-card-header {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-20) var(--spacing-lg);
  cursor: default;
}

.global-step-index-pill {
  width: var(--spacing-32);
  height: var(--spacing-32);
  transition: all 0.3s ease;
  flex-shrink: 0;
}

.global-step-content {
  padding: 0 var(--spacing-lg) var(--spacing-20) var(--spacing-lg);
  animation: slide-down 0.3s ease;
}

.global-step-description {
  margin: 0 0 var(--spacing-md) 0;
}

.global-step-actions {
  align-items: center;
  gap: var(--spacing-12);
}

.global-step-primary-action-button {
  --button-padding: var(--spacing-12) var(--spacing-20);
}

.global-step-secondary-action-button {
  --button-padding: var(--spacing-12) var(--spacing-20);
}

.global-stepper-footer {
  gap: var(--spacing-12);
  margin-top: var(--spacing-lg);
  justify-content: flex-start;
}

.global-step-complete-button {
  --button-padding: var(--spacing-12) var(--spacing-lg);
}

.global-list-item-padding-xs {
  padding: 5px;
}

/* icon */
.global-icon {
  width: 24px !important;
  height: 24px !important;
  margin: auto;
}

.global-icon-small {
  display: flex;
  height: var(--common-icon-height);
  width: var(--common-icon-width);
  align-items: center;

  --image-width: var(--common-icon-width);
  --image-height: var(--common-icon-height);
}

.global-icon-lg {
  display: flex;
  height: var(--icon-size-lg);
  width: var(--icon-size-lg);
  align-items: center;
}

.global-icon-circle-primary {
  width: 45px;
  height: 45px;
}

.global-logo-circle {
  width: var(--logo-circle-width, 50px);
  height: var(--logo-circle-height, 50px);

  /* The Image/Img host inside the circle carries no scope hash; size it via
     inherited vars so callsites never need :global overrides. */
  --image-width: var(--logo-circle-width, 50px);
  --image-height: var(--logo-circle-height, 50px);
}

/* Cross-sell rules card: round the bottom of whichever child renders last
   (the DataGrid) to match the card's own radius. */

/* Canonical bottom-sheet modal: keep content clear of the home-indicator
   safe area. Use the -flush variant when the sheet manages its own padding.
   The second selector in each pair matches when the class is passed through the
   library Modal `classes=` prop (compound on the .modal element) instead of on a
   wrapper, so both application styles route through this single global rule. */
.global-modal-bottom-sheet .modal.bottom .modal-content,
.modal.bottom.global-modal-bottom-sheet .modal-content {
  padding-bottom: max(var(--safe-area-inset-bottom, 0px), env(safe-area-inset-bottom, 0px), 34px);
}

.global-modal-bottom-sheet-flush .modal.bottom .modal-content,
.modal.bottom.global-modal-bottom-sheet-flush .modal-content {
  padding-bottom: 0;
}

/* Chevron icon - rotatable icon container for expand/collapse */
.global-chevron-icon {
  width: var(--chevron-icon-size);
  height: var(--chevron-icon-size);

  --image-width: var(--chevron-icon-size);
  --image-height: var(--chevron-icon-size);

  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

.global-chevron-icon.expanded {
  transform: rotate(180deg);
}

/* Right-pointing chevron rotated down — used in accordion lists */
.global-chevron-icon.expanded-right {
  transform: rotate(90deg);
}

.global-chevron-icon-sm {
  --chevron-icon-size: var(--spacing-20);
}

/* Info icon - small informational icon */
.global-info-icon {
  --image-width: var(--spacing-12);
  --image-height: var(--spacing-12);

  flex-shrink: 0;
}

/* Offer preview coupon icon */
.global-offer-preview-icon {
  --image-width: var(--spacing-32);
  --image-height: var(--spacing-lg);

  flex-shrink: 0;
}

/* Toggle button - transparent toggle trigger */
.global-toggle-button {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  cursor: pointer;
  padding: 0;
}

/* Header divider - full-width divider with no margin */
.global-header-divider {
  width: 100%;
  margin-bottom: var(--spacing-lg);

  --horizontal-line-margin: 0;
}

/* Adds the divider line above a library Modal footer. The header divider is already
   the modal default (theme.css :root), so only the footer-top border needs enabling. */

/* Button icon - small icon container inside buttons */
.global-button-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--spacing-md);
  height: var(--spacing-md);
}

/* Button icon invert modifier - makes icon white for dark buttons */

/* Close button - icon-only close trigger */
.global-close-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--spacing-lg);
  height: var(--spacing-lg);
  padding: 0;
  cursor: pointer;
  flex-shrink: 0;
}

.global-close-button img {
  width: var(--spacing-lg);
  height: var(--spacing-lg);
}

/* heading text */
.global-heading-text-container {
  margin-top: var(--spacing-0);
  padding-top: var(--platform-padding-top);
  display: var(--platform-display);
  flex-wrap: var(--platform-flex-wrap);
  justify-content: var(--platform-justify-content);
  align-items: var(--platform-align-items);
}

.global-subheading-text-container {
  display: var(--platform-display);
  flex-wrap: var(--platform-flex-wrap);
  justify-content: var(--platform-justify-content);
  align-items: var(--platform-align-items);
}

/* elements */
.global-horizontal-line-grey {
  margin: var(--horizontal-line-grey-margin-top, 0) var(--horizontal-line-grey-margin-right, 0)
    var(--horizontal-line-grey-margin-bottom, 16px) var(--horizontal-line-grey-margin-left, 0);
}

/* status */
.global-error-message {
  margin-top: var(--spacing-xs);
}

/* Inline form-field error / validation text: danger colour with symmetric vertical
   rhythm. Unlike .global-error-message it has no !important and includes margin-bottom. */
.global-field-error-text {
  margin-top: var(--spacing-xs);
  margin-bottom: var(--spacing-xs);
}

.global-error-banner {
  padding: var(--spacing-12) var(--spacing-md);
}

/* The library Select renders its popover with `left: 0; right: 0;` relative
 * to the trigger, so the popover inherits the trigger's width. In a dot-options
 * (kebab) context the trigger collapses to a ~46px chevron, which forces the
 * popover to that width and wraps every option label one-word-per-line.
 * Detach the popover width from the trigger and pin a usable min-width. */
.global-dot-options-container .select-dropdown {
  right: auto;
  min-width: var(--max-select-width, 200px);
  width: max-content;
}

.menu-container.zone-options-menu .menu-dropdown {
  --menu-dropdown-left: auto;

  right: 0;
}

/* Voice-selector dropdown — themed via library Menu CSS vars.
 * Used by the voice-switcher button in AutomaticChatHeader, conversation-fallback,
 * and conversation/v2 pages. All three pages share this single recipe.
 * Values are intentionally pinned to the AI-route gray scale (temp.css)
 * to match the original VoiceDropdown component appearance. */
.menu-container.voice-selector-menu {
  --menu-z-index: var(--z-index-voice-dropdown, 110);
  --menu-min-width: var(--voice-dropdown-min-width, 200px);
  --menu-padding: var(--spacing-sm);
  --menu-item-padding: var(--spacing-12, 10px) var(--spacing-12, 12px);
  --menu-item-gap: var(--spacing-sm);
  --menu-dropdown-left: auto;
}

/* Round the hover/focus highlight so it reads as a soft selection pill inside
   the rounded dropdown instead of a sharp-cornered block. */

.menu-container.voice-selector-menu .menu-dropdown {
  right: 0;
  animation: voice-selector-scale-in 75ms ease-out;
  transform-origin: top right;
}

@keyframes voice-selector-scale-in {
  from {
    transform: scale(0.8);
  }

  to {
    transform: scale(1);
  }
}

.global-page-section {
  padding: var(--spacing-lg);
  margin: var(--margin-long-card);
}

.global-data-grid .grid-content-button {
  padding: var(--spacing-12) var(--spacing-lg);
}

.global-data-grid .grid-content-text-text {
  min-height: var(--datagrid-header-height);
}

.global-data-grid .grid-row .grid-content,
.global-data-grid .grid-row .serial-number,
.global-data-grid .grid-row .checkbox-col {
  transition: background-color 0.15s ease;
}

.global-data-grid .grid-row:hover .grid-content-text-text {
  min-height: var(--spacing-92);
}

.global-data-grid .select-action-footer {
  padding: var(--spacing-sm);
  box-sizing: border-box;

  --button-width: 100%;
}

.global-data-grid-container {
  display: flex;
  padding: var(--spacing-rg) 0;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  align-self: stretch;
}

/* DataGrid icon-label cell — icons followed by a text label in a single row */

.global-datagrid-icon-label-cell {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  max-width: 100%;
  overflow: hidden;
}

.global-datagrid-icon-label-icons {
  display: inline-flex;
  flex-shrink: 0;
}

.global-datagrid-icon-label-img-wrapper {
  display: inline-flex;
  width: var(--spacing-20);
  height: var(--spacing-20);
  overflow: hidden;
}

.global-highchart-container {
  padding: var(--spacing-md) var(--spacing-md) 0 var(--spacing-20);
  margin: 0;
}

.global-plot-chart-container {
  width: 100%;
}

.global-flex-shrink-0 {
  flex-shrink: 0;
}

.global-flex-shrink-1 {
  flex-shrink: 1;
}

.global-full-width {
  width: 100%;
}

.global-min-width-0 {
  min-width: 0;
}

.global-min-height-0 {
  min-height: 0;
}

.global-width-max-content {
  width: max-content;
  max-width: 100%;
}

/* Fixed token-sized width utilities (mirror the .global-size-* / .global-max-width-*
   numeric-token convention). Used for aligned table-style columns. */
.global-width-32 {
  width: var(--spacing-32);
}

.global-width-90 {
  width: var(--spacing-90);
}

.global-width-110 {
  width: var(--spacing-110);
}

.global-white-space-nowrap {
  white-space: nowrap;
}

.global-m-0 {
  margin: 0;
}

.container {
  /* padding: var(--container-padding); */
}

/* A page whose root element is `<div class="container">` is a direct child of
   the layout shell's .page-content, which already owns the page gutter. The
   global `.container { padding: 16px }` in theme.css is meant for inner
   surfaces (cards, popups, stat cards), but it leaks onto these page roots and
   pushes the whole page — header and body alike — 16px past the gutter, so
   such pages sit misaligned against pages that use .global-page-container.
   Inner-surface containers nest deeper and are never direct page-content
   children, so neutralising the leak here only affects page roots. */
.page-content > .container {
  padding: 0;
}

.global-flex-1 {
  flex: 1;
}

.global-flex-grow {
  flex-grow: 1;
}

/* Lets a wrapper participate in its parent's grid/flex layout as if it
   didn't exist, so each `{#each}` iteration can contribute a fixed number
   of items to a shared grid without an extra layout level. */
.global-display-contents {
  display: contents;
}

.global-break-word {
  overflow-wrap: break-word;
  word-break: break-word;
}

/* A 4-column row grid for label / field / preview / action rows (e.g. a
   variable name, its source selector, a sample preview, and a clear
   action). Columns stay aligned across rows regardless of how much text
   each row's preview column holds. */
.global-mapping-row-grid {
  display: grid;
  grid-template-columns: var(--spacing-80) 1fr 1fr auto;
  align-items: center;
  gap: var(--spacing-sm) var(--spacing-md);
}

.global-position-absolute {
  position: absolute;
}

.global-position-fixed {
  position: fixed;
}

.global-inset-0 {
  inset: 0;
}

.global-position-relative {
  position: relative;
}

.global-flex-end {
  display: flex;
  justify-content: flex-end;
}

.global-justify-center {
  justify-content: center;
}

.global-align-center-container {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* Pair with .global-align-center-container — column direction + shipping empty-state padding */
.global-empty-state-hero-stack {
  flex-direction: column;
  padding: var(--spacing-64) var(--spacing-32) var(--spacing-80);
}

@media (width <= 1024px) {
  .global-empty-state-hero-stack {
    padding: var(--spacing-48) var(--spacing-md) var(--spacing-64);
  }
}

/* Illustration inside the EmptyState icon snippet, rendered via the library Img
 * component. Img is sized through its own --image-* custom properties (default
 * 24px), so size it to the project illustration scale here and route the
 * dark-mode inversion through --image-filter (the value the library Img reads). */
.global-empty-state-illustration {
  --image-height: auto;
  --image-width: auto;
  --image-object-fit: contain;

  display: block;
  max-width: 100%;
  max-height: var(--no-data-image-max-height, var(--spacing-200));
}

/* Restores the project NoData layout on the library EmptyState — apply via the
 * `classes` prop at NoData-migrated callsites. NoData centred its block with
 * margin:10vh and capped its description at 70% width; the library default
 * (padding:32px 16px, no width cap) top-aligns it instead. Centralised here so
 * every migrated empty state matches without per-callsite CSS. */
.global-empty-state-nodata {
  --empty-state-padding: 10vh var(--spacing-sm);
  --empty-state-icon-size: fit-content;
  --empty-state-icon-margin-bottom: var(--spacing-rg);

  /* Lay the action slot out as a centred column. The library's own
   * .empty-state-actions rule is scoped (.empty-state-actions.svelte-xxx), so it
   * ties on specificity with a `.global-empty-state-nodata .empty-state-actions`
   * rule and wins on source order — configure it through the library's own
   * variables, which always win, instead of a competing display declaration. */
  --empty-state-actions-display: flex;
  --empty-state-actions-flex-direction: column;
  --empty-state-actions-align-items: center;

  /* Library-rendered title/description divs (prop-based callsites). The
   * library defaults both to `inherit` + halves description opacity — on
   * dark surfaces that compounds into unreadable text (BZ-3555). */
}

/* Same shape rules for the library-emitted nodes as the h2/p rules below
 * give to children-pattern callsites (wallet) — keep both in sync. */
.global-empty-state-nodata .empty-state-title {
  margin-bottom: var(--spacing-sm);
}

.global-empty-state-nodata .empty-state-description {
  max-width: 28rem;
}

.global-empty-state-nodata h2 {
  margin-bottom: var(--spacing-sm);
}

.global-empty-state-nodata p {
  max-width: 28rem;

  /* Centre the multi-line description to match the icon + heading above it.
   * Flexbox on the parent centres the <p> box, not its wrapped text lines
   * (BZ-3419) — without this, builds whose EmptyState lib doesn't centre
   * text render the description left-aligned. */
}

/* Canonical empty-state CTA: every action button fills its column up to a
 * consistent cap and centres under the copy (the actions column above is
 * already flex/align-items:center). The CTA may be a bare <Button> or one
 * wrapped in a span/div, so size whichever direct child of the actions column
 * holds the button; the heading/description siblings (no button) keep their
 * natural width. The library Button reads --button-width / --button-max-width
 * for its own width, so set those too rather than the element's width. One
 * place gives every empty state the same full-width, centred CTA — callsites
 * only choose the label and (primary) variant. */
.global-empty-state-nodata .empty-state-actions > button,
.global-empty-state-nodata .empty-state-actions > :has(button) {
  inline-size: 100%;
  max-inline-size: var(--spacing-320);
  margin-inline: auto;
  margin-top: var(--spacing-sm);

  /* The library Button's inner .button-container and <button> read these for
   * their own width, so set them on the holder — they inherit down and make the
   * button fill the capped holder, whether the CTA is bare or span/div-wrapped. */
  --button-width: 100%;
  --button-max-width: var(--spacing-320);
}

.global-max-width-320 {
  max-width: var(--spacing-320);
}

.global-max-width-600 {
  max-width: var(--spacing-600);
}

.global-max-width-full {
  max-width: 100%;
}

.global-max-width-content {
  max-width: var(--spacing-978);
}

/* Caps an element's height to 60% of the viewport — pair with .global-overflow-y-auto
   for a scrollable panel (e.g. a modal's product/result list). */
.global-max-height-60vh {
  max-height: 60vh;
}

.global-mx-auto {
  margin-inline: auto;
}

.global-size-84 {
  width: var(--spacing-84);
  height: var(--spacing-84);
}

.global-size-106 {
  width: calc(var(--spacing-100) + var(--spacing-sm));
  height: calc(var(--spacing-100) + var(--spacing-sm));
  flex-shrink: 0;
}

.global-size-56 {
  width: var(--spacing-56);
  height: var(--spacing-56);
}

/* 40×40 icon-only button — sizing and shape only; add border/bg resets in component scope */
.global-icon-button-sm {
  width: var(--spacing-40);
  height: var(--spacing-40);
  padding: var(--spacing-12);
  justify-content: center;
}

/* Keep the neutral outline on hover/focus — without this the global focus/hover
   button styling painted a blue border on these icon-only buttons (e.g. the
   Shipping v2 modal close/cross buttons). */

/* Inset padding for a primary section below a page toolbar */
.global-section-inset-padded {
  padding: var(--spacing-lg) var(--spacing-32);
}

@media (width <= 1024px) {
  .global-section-inset-padded {
    padding: var(--spacing-md);
  }
}

/* Title block left, primary action right; stacks on narrow viewports */
.global-heading-toolbar-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: var(--spacing-lg);
}

@media (width <= 1024px) {
  .global-heading-toolbar-row {
    flex-direction: column;
    gap: var(--spacing-12);
  }
}

.global-flex-align-center {
  display: flex;
  align-items: center;
}

.global-flex-align-start {
  display: flex;
  align-items: flex-start;
}

.global-flex-start-space-between {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}

.global-flex-nowrap {
  flex-wrap: nowrap;
}

.global-inline-flex-align-center {
  display: inline-flex;
  align-items: center;
}

.global-inline-flex-align-start {
  display: inline-flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
}

.global-inline-icon {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
}

.global-inline-icon-sm {
  width: var(--spacing-12);
  height: var(--spacing-12);
}

.global-inline-icon-md {
  width: var(--spacing-md);
  height: var(--spacing-md);
}

.global-space-between-container {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.global-column-space-between-container {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.global-flex {
  display: flex;
}

.global-flex-column {
  display: flex;
  flex-direction: column;
}

.global-flex-column-center {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.global-flex-row-wrap {
  display: flex;
  flex-flow: row wrap;
}

.global-flex-wrap {
  flex-wrap: wrap;
}

.global-flex-zero-spacing {
  display: flex;
  margin: 0;
  padding: 0;
}

.global-cursor-pointer {
  cursor: pointer;
}

.global-cursor-grab {
  cursor: grab;
}

.global-gap-xxs {
  gap: var(--spacing-2);
}

/* gap: var(--spacing-xs) = 4px */
.global-gap-xs-4 {
  gap: var(--spacing-xs);
}

.global-gap-xs {
  gap: var(--spacing-sm);
}

.global-gap-sm {
  gap: var(--spacing-12);
}

.global-gap-md {
  gap: var(--spacing-md);
}

.global-gap-lg {
  gap: var(--spacing-lg);
}

.global-gap-xl {
  gap: var(--spacing-32);
}

.global-display-none {
  display: none;
}

.global-display-block {
  display: block;
}

.global-content-layout {
  content: layout;
}

/* text-color */

/* Success text colour — mirror of .global-text-danger (e.g. positive
   net-outstanding state). */

.global-margin-top-xxs {
  margin-top: var(--spacing-2);
}

.global-margin-top-xs {
  margin-top: var(--spacing-xs);
}

.global-margin-top-sm {
  margin-top: var(--spacing-sm);
}

.global-margin-top-xl {
  margin-top: var(--spacing-32);
}

.global-margin-top-auto {
  margin-top: auto;
}

.global-margin-bottom-xl {
  margin-bottom: var(--spacing-32);
}

.global-margin-none {
  margin: var(--spacing-0);
}

.global-padding-x-md {
  padding-left: var(--spacing-md);
  padding-right: var(--spacing-md);
}

.global-padding-x-rg {
  padding-left: var(--spacing-rg);
  padding-right: var(--spacing-rg);
}

.global-padding-x-lg {
  padding-left: var(--spacing-lg);
  padding-right: var(--spacing-lg);
}

.global-margin-y-md {
  margin-top: var(--spacing-md);
  margin-bottom: var(--spacing-md);
}

.global-margin-y-xl {
  margin-top: var(--spacing-32);
  margin-bottom: var(--spacing-32);
}

.global-padding-y-md {
  padding-top: var(--spacing-md);
  padding-bottom: var(--spacing-md);
}

.global-padding-y-lg {
  padding-top: var(--spacing-lg);
  padding-bottom: var(--spacing-lg);
}

.global-padding-left-48 {
  padding-left: var(--spacing-48);
}

.global-padding-xs {
  padding: var(--spacing-xs);
}

.global-padding-sm {
  padding: var(--spacing-sm);
}

.global-padding-none {
  padding: var(--spacing-0);
}

.global-padding-y-12 {
  padding-top: var(--spacing-12);
  padding-bottom: var(--spacing-12);
}

.global-padding-top-12-bottom-4 {
  padding-top: var(--spacing-12);
  padding-bottom: var(--spacing-4);
}

.global-form-label-title {
  margin: 0 0 6px;
}

.global-column-layout {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
}

.global-row-layout {
  display: flex;
  flex-direction: row;
  gap: var(--spacing-sm);
}

.global-action-buttons-group {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
}

/* Push a content-width block (e.g. a lone submit button) to the right edge of its row. */
.global-action-end {
  width: fit-content;
  margin-left: auto;
  margin-top: var(--spacing-rg);
}

/* Restored (regressed by BZ-3506): wide horizontal padding for the primary
   action button. Still referenced by shop config cod/partialPayment pages. */
.global-primary-button-container {
  --button-padding: 10px 80px;
}

.global-flex-align-center-gap-xs {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
}

.global-flex-column-gap-xs {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
}

/* BZ-47862: Use 767px (not 768px) to ensure iPad at 768px is treated as desktop */
@media only screen and (width <= 767px) {
  .global-action-buttons-group {
    flex-direction: column;
    width: 100%;
    gap: var(--spacing-sm);
  }

  /* Inline icon-button groups (e.g. edit/delete pairs marked with global-icon-sm)
     stay on one row — stacking tiny icons vertically wastes height and detaches
     them from the row they belong to. */
  .global-action-buttons-group.global-icon-sm {
    flex-direction: row;
    width: auto;
  }
}

.global-modal-content-container {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  padding: var(--spacing-sm) var(--spacing-20);
  width: 100%;
}

/* Drawer subtitle — text description at the top of a drawer body, separated from content by a bottom border. Used in ContentDrawer when a subtitle is provided. */
.global-drawer-subtitle {
  flex-shrink: 0;
  padding-bottom: var(--spacing-md);
  margin-bottom: var(--spacing-md);
}

/* Modal stacking layers above the portal base — e.g. a confirm popup rendered
   over an already-open modal. Level 2 sits above level 1. */
.global-modal-z-stack-1 {
  --modal-z-index: calc(var(--z-index-portal) + 1);
}

.global-modal-z-stack-2 {
  --modal-z-index: calc(var(--z-index-portal) + 2);
}

/* Right-drawer portal shell — RuleDrawer, ContentDrawer (use:portal → document.body) */
.drawer-shell {
  --modal-z-index: var(--z-index-portal);
  --modal-content-overflow: hidden;
  --modal-overflow-y: auto;
  --modal-display: block;
  --modal-header-padding: var(--spacing-md) var(--spacing-lg);
  --modal-footer-padding: var(--spacing-md) var(--spacing-lg);
  --modal-header-title-line-height: var(--line-height-sm);
}

.shipping-zones-tab-add-zone-modal .global-btn button:disabled,
.shipping-zones-tab-add-zone-modal .global-btn button:disabled:hover {
  /* Disabled submit reads as a neutral grey in both themes (gray-300 inverts
     #ededed↔#333) with theme-inverting secondary text, so it's clearly
     distinct from the enabled primary blue — not a faded-blue look-alike. */
}

/* Add/Edit Shipping Zone modal form body — JSONForm field spacing. The gap
   between fields comes from the JSONForm container token; the Input's own
   margins are zeroed so they don't double up. --input-margin and
   --input-container-margin are central tokens, so they live here, not in the
   component \3c style> block. */
.global-shipping-zone-form-body {
  padding: var(--spacing-20);
  --jsonform-field-container-margin-bottom: var(--spacing-rg);
  --input-margin: var(--spacing-0);
  --input-container-margin: var(--spacing-0);
}

/* A multi-select trigger wraps its selected-state pills; as in-flow flex children
   the dropdown chevron would wrap onto its own row, inflating the field height.
   Whenever pills are present, pin the chevron vertically-centred at the trailing
   edge (room reserved via padding) so the tags wrap cleanly and the arrow stays
   put — for every multi-select, not just one form. Scoped via :has(.pill) so
   single-selects (no pills, never wrap) are untouched. */
.select .select-trigger:has(.pill) {
  position: relative;
  padding-right: var(--spacing-32);
}

.select .select-trigger:has(.pill) .select-arrow {
  position: absolute;
  top: 50%;
  right: var(--spacing-12);
  transform: translateY(-50%);
}

/* Normalises an InputButton-based control (e.g. the Tools → Get customer
   transactions mobile-number field) to the standard single-line input height.
   The central --input-container-margin reserves an empty validation-message gap
   below the field, and --left-button-height defaults taller than the field;
   together they inflate the control well past a normal input. Both are central
   tokens, so the overrides live here, not in the consuming component's style. */
.global-input-button-single-line {
  --input-container-margin: var(--spacing-0);
  --left-button-height: var(--input-height);
}

.global-drawer-body-stack {
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 0;
}

.global-drawer-body-centered {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: var(--spacing-0);
  padding: var(--spacing-rg);
  gap: var(--spacing-rg);
}

.global-drawer-list-panel {
  flex: 1;
  min-height: var(--spacing-400);
  overflow: hidden;
}

/* Sheet-based right-drawer shell — base recipe applied via the Sheet `classes` prop.
   Sets the z-index, removes default content padding, and locks content overflow so
   each drawer controls its own internal scrolling. */
.global-sheet-drawer-shell {
  --sheet-overlay-z-index: calc(var(--z-index-portal) - 1);
  --sheet-z-index: var(--z-index-portal);
  --sheet-content-padding: 0;
  --sheet-content-overflow-y: hidden;
}

/* The library .sheet-content is only flex:1 (a flex item), not a flex container. Make it a column
   and let the body fill it so the form scrolls (AddShippingRate) and the empty/list state can
   center vertically and fill the drawer height (fulfillment + zones). */
.global-sheet-drawer-shell .sheet-content {
  display: flex;
  flex-direction: column;
}

.global-sheet-drawer-shell .global-drawer-body-stack {
  flex: 1;
  min-height: var(--spacing-0);
}

.global-sheet-drawer-shell .global-drawer-subtitle {
  padding: var(--spacing-xs) var(--spacing-rg) var(--spacing-rg);
}

.global-sheet-drawer-shell .global-drawer-list-panel {
  padding: 0 var(--spacing-rg) var(--spacing-rg);
  box-sizing: border-box;
}

/* Wide variant — fulfillment locations and shipping zones drawers. */
.global-sheet-drawer-shell-wide {
  --sheet-width: min(96vw, var(--spacing-896));
  --sheet-header-padding: var(--spacing-rg) var(--spacing-rg) var(--spacing-0);
}

.global-sheet-drawer-header-divider {
  --sheet-header-padding: var(--spacing-rg);
}

/* Narrow variant — add shipping rate drawer. */
.global-sheet-drawer-shell-narrow {
  --sheet-width: min(96vw, var(--spacing-630));
}

/* Recovery side-sheet — auto-recovery wizard. Width matches the original right-drawer
   preset; the header divider and content padding are managed by the shell base class.
   Overrides --sheet-content-overflow-y back to auto because .global-sheet-drawer-shell
   (also applied to this element) sets it to hidden. */
.global-recovery-sheet {
  --sheet-overlay-z-index: calc(var(--z-index-portal) - 1);
  --sheet-width: min(96vw, var(--spacing-480, 400px));
  --sheet-content-overflow-y: auto;
}

/* Cross-sell rule drawer shell — right-side Sheet themed for the rule editor.
   Stacks above the main app (overlay 1199, panel 1200) so nested pickers at 1300
   clear the Sheet without conflict. Content scrolls internally via the drawer-body
   padding; Sheet header/footer dividers use the design-system divider token. */
.global-cross-sell-rule-drawer {
  --sheet-overlay-z-index: 1199;
  --sheet-z-index: 1200;
  --sheet-width: min(96vw, var(--spacing-480, 480px));
  --sheet-content-padding: 0;
  --sheet-content-overflow-y: auto;
  --sheet-title-line-height: var(--line-height-sm);
}

/* Cross-sell picker shell — stacks the product/collection/recs/delete-confirm modals
   above the rule Sheet (modal z-index 1300 > sheet z-index 1200). Width is pinned so
   the modal never shifts size across loading / empty / populated states. */
.global-cross-sell-picker-shell {
  --modal-z-index: var(--z-modal-layer-2);
  --modal-medium-width: 560px;
}

/* Scrollable DataGrid — drawer + page tabs. On toolkit wrapper add:
   global-scrollable-datagrid-panel global-flex-1 global-min-height-0 global-flex-column */
.global-scrollable-datagrid-panel {
  --datagrid-inner-justify-content: flex-start;
  --datagrid-inner-position: relative;
  --datagrid-table-max-height: 100%;
  --datagrid-table-overflow-y: auto;
  --datagrid-header-position: sticky;
  --datagrid-header-sticky-top: 0;
  --datagrid-header-z-index: 1;
}

.global-scrollable-datagrid-panel .container.global-data-grid {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.global-scrollable-datagrid-panel .inner-container {
  flex: 1;
  min-height: 0;
  scroll-padding-top: var(--datagrid-header-height, var(--spacing-48));
}

.global-scrollable-datagrid-panel .datagrid-search-row {
  flex-shrink: 0;
}

/* Parent gets global-datagrid-list-search-empty when search has no matches */

.global-datagrid-list-search-empty .global-scrollable-datagrid-panel .inner-container {
  display: none;
}

/* Pair with global-empty-state global-flex-1 global-min-height-0 */
.global-datagrid-search-empty-panel {
  padding: var(--spacing-lg);
}

.global-datagrid-search-empty-panel .main-component {
  margin: 0;
}

.global-datagrid-search-empty-panel .img-tag {
  max-height: var(--spacing-120);
  padding-bottom: var(--spacing-md);
}

.global-settings-card {
  padding: var(--spacing-lg);
  overflow: hidden;
}

.global-bordered-icon-box {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: var(--spacing-12);
  overflow: hidden;
}

.global-settings-nav-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  box-sizing: border-box;
  padding: var(--spacing-12) var(--spacing-md);
  cursor: pointer;
}

.global-general-profile-title-group {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  min-width: 0;
}

.global-general-profile-card {
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  gap: var(--spacing-100);
}

.global-general-profile-card-label {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-20);
  flex: 0 0 var(--spacing-340);
  max-width: var(--spacing-340);
  min-width: 0;
}

.global-general-profile-card-control {
  flex: 0 0 var(--spacing-348);
  width: var(--spacing-348);
  max-width: var(--spacing-348);
  min-width: 0;
}

@media (width <= 1280px) {
  .global-general-profile-card {
    gap: var(--spacing-64);
  }

  .global-general-profile-card-control {
    flex-basis: var(--spacing-300);
    width: var(--spacing-300);
    max-width: var(--spacing-300);
  }
}

@media (width <= 1100px) {
  .global-general-profile-card {
    gap: var(--spacing-48);
  }

  .global-general-profile-card-label {
    flex-basis: var(--spacing-300);
    max-width: var(--spacing-300);
  }

  .global-general-profile-card-control {
    flex-basis: var(--spacing-280);
    width: var(--spacing-280);
    max-width: var(--spacing-280);
  }
}

@media (width <= 1024px) {
  .global-general-profile-header {
    flex-direction: column;
    align-items: stretch;
  }

  .global-general-profile-card {
    flex-direction: column;
    gap: var(--spacing-md);
  }

  .global-general-profile-card-label {
    flex: 0 0 auto;
    max-width: 100%;
    width: 100%;
  }

  .global-general-profile-card-control {
    flex: 0 0 auto;
    width: 100%;
    max-width: 100%;
  }
}

.shipping-v2-profile-card {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-32);
  padding: var(--spacing-lg);
}

.shipping-v2-profile-card-columns {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--spacing-lg) 0;
}

.shipping-v2-profile-data-col {
  flex: 1 1 200px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
}

.shipping-v2-profile-data-col-divided {
  padding-left: var(--spacing-48);
}

/* The rupee + delivery-truck label icons in this column draw with currentColor;
   give them a theme-adaptive colour so they don't render near-black (invisible)
   on the dark theme. */

.shipping-v2-profile-section-header,
.shipping-v2-profile-card-header {
  align-items: flex-start;
}

@media (width <= 768px) {
  .shipping-v2-profile-section-header {
    flex-direction: column;
    align-items: stretch;
  }

  .shipping-v2-profile-data-col-divided {
    padding-left: 0;
  }
}

/* Centered numbered list — drawer/page empty states with decimal steps */
.global-centered-numbered-list {
  width: min-content;
  min-width: 100%;
  max-width: var(--spacing-400);
  margin-inline: auto;
  padding-inline-start: 0;
}

.global-centered-numbered-list-item {
  margin-inline-start: var(--spacing-20);
  padding-inline-start: var(--spacing-xs);
}

/* Removes bullet/number list markers — pair with global-m-0 and padding utilities as needed */

/* Bullet list - reusable bullet point list pattern */
.global-bullet-list {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  padding: 0;
  margin: 0;
}

.global-bullet-item {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
}

.global-bullet-dot {
  width: var(--spacing-xs);
  height: var(--spacing-xs);
  flex-shrink: 0;
}

/* Section header - flex row with icon, used for form section titles */
.global-section-header {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  margin-bottom: var(--spacing-lg);
}

/* Accordion header - unstyled button trigger for collapsible sections */
.global-accordion-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-12);
  padding: 0;
  cursor: pointer;
  user-select: none;
}

/* Accordion header using Button component - wrapper with CSS custom properties */
.global-accordion-button {
  --button-padding: var(--spacing-0);
  --button-content-gap: var(--spacing-12);
  --button-content-flex-direction: row-reverse;
  --button-justify-content: flex-end;
}

/* Accordion content - wrapper for collapsible section body */
.global-accordion-content {
  margin-top: var(--spacing-md);
}

/* Let absolutely-positioned popups (e.g. a DateRangePicker panel) escape the
   accordion's overflow:hidden clip once the section is fully open; the clip is
   still in effect while collapsed so the body hides cleanly. The `.accordion`
   prefix is required: the library sets `.accordion { overflow: hidden }`, so
   without it this two-class selector only ties and loses on source order,
   leaving the popup clipped. */
.accordion.global-accordion-content.expanded {
  overflow: visible;
}

/* Disc list - native bullet list with disc markers */
.global-disc-list {
  margin: 0;
  padding: 0;
  padding-left: var(--spacing-20);
}

.global-refund-modal {
  /* header text weight already comes from the modal default (theme.css :root) */
  --header-right-image-width: 20px;
  --header-right-image-height: 20px;
}

/* The box-sizing:border-box reset would let the close-button padding (theme.css
   :root --header-right-image-padding) eat into the icon; content-box adds the
   padding around it instead, so every modal close button reaches its ~44px tap
   target with the icon at its intended size. */
.header-right-img {
  box-sizing: content-box;
}

/* Modal header - standard modal header with title and close button */
.global-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-lg);
  padding: var(--spacing-20) var(--spacing-32);
}

/* Modal footer - standard modal footer with action buttons */
.global-modal-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--spacing-12);
  padding: var(--spacing-20) var(--spacing-lg);
}

/* Right-aligned Cancel/Confirm button row — works in both library Modal footerSnippets
   and library Sheet footers. margin-left:auto pushes the row right when its parent is a
   flex container (Modal footer); justify-content:flex-end right-aligns the buttons when
   the row spans the full width (Sheet footer). One class covers both contexts. */
.global-modal-footer-parity {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  gap: var(--spacing-12);
  margin-left: auto;
  padding: 0;
}

/* Modal header description — dense xs; set on wrapper (uses --typography-dense-xs-* from text.css, same as .txt-datagrid-cell-body). */

/* Modal white surface — optional wrapper around Modal; theme default uses --bg-color-primary (#fafafa). */

/* Canonical desktop dialog for the library Modal — THE standard modal look
   (white surfaces, header divider, md×rg paddings, radius-sm, 550px desktop
   width via --modal-desktop-content-width). Pass via the classes prop; use the
   modifier classes below for sanctioned variants instead of per-file overrides. */

/* Variant: description block under the header carries the divider instead */

/* Variant: block-flow body (forms that manage their own scroll) */
.global-modal-dialog-block {
  --modal-display: block;
}

/* Powered-by logo icon in ReportContent footer — sizes the breeze automatic
   SVG to match the surrounding label text (icon-size-lg = 20px). */
.global-powered-by-icon {
  --image-width: var(--icon-size-lg);
  --image-height: var(--icon-size-lg);
}

/* Order-items card — let the DataGrid extend edge-to-edge inside the library
   Card by zeroing the card's built-in content padding. Pass via the wrapping
   div's class so the CSS var cascades into the Card component below it. */
.global-card-content-flush {
  --card-content-padding: 0;
}

/* ---------------------------------------------------------------------------
   Offer Modal Overlay — shared fixed overlay for offer flow modals
   Used by ProductSelectionContent (via Modal), OfferReviewModal, OfferTypeSelectionModal.
   --------------------------------------------------------------------------- */

/* Base overlay: fixed fullscreen backdrop with blur */
.global-offer-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-index-portal);
}

/* Centered dialog: hides the library Modal header and resets padding/bg */
.global-offer-modal-overlay-centered {
  --modal-header-padding: var(--spacing-0);
  --modal-margin: auto;
}

/* Hide the library Modal's default header when using a custom one */
.global-offer-modal-overlay-centered [data-pw='hidden-header'] {
  display: none;
}

/* Center the Modal's .modal.center wrapper */
.global-offer-modal-overlay-centered .modal.center {
  justify-content: center;
  align-items: center;
}

/* Top-aligned variant: positions modal from top instead of vertically centered */
.global-offer-modal-overlay-top-aligned .modal.center {
  justify-content: flex-start;
  padding-top: var(--spacing-150);
}

/* Section icon - image box for section labels and nav chevrons */
.global-section-icon-sm,
.global-section-icon-md {
  flex-shrink: 0;
  overflow: hidden;

  --image-width: 100%;
  --image-height: 100%;
}

.global-section-icon-sm {
  width: var(--spacing-20);
  height: var(--spacing-20);
}

.global-section-icon-md {
  width: var(--spacing-lg);
  height: var(--spacing-lg);
}

@media only screen and (width <=767px) {
  .container {
    padding: 0;
  }
}

.global-box-sizing-border-box {
  box-sizing: border-box;
}

/* animations */

@keyframes enable-pointer-events {
  from {
    pointer-events: none;
  }

  to {
    pointer-events: auto;
  }
}

@keyframes slide-in-from-bottom {
  from {
    transform: translateY(20px);
  }

  to {
    transform: translateY(0);
  }
}

@keyframes slide-in-from-right {
  from {
    transform: translateX(100%);
  }

  to {
    transform: translateX(0);
  }
}

@keyframes slide-out-to-right {
  from {
    transform: translateX(0);
  }

  to {
    transform: translateX(100%);
  }
}

@keyframes fill-loader {
  0% {
    width: 0%;
  }

  100% {
    width: 100%;
  }
}

@keyframes fade-in-up {
  from {
    transform: translateY(100px);
  }

  to {
    transform: translateY(0);
  }
}

@keyframes slide-in {
  from {
    transform: translateY(10px) scale(0.95);
  }

  to {
    transform: translateY(0) scale(1);
  }
}

@keyframes slide-down {
  from {
    transform: translateY(-10px);
  }

  to {
    transform: translateY(0);
  }
}

/* Sticky chart header */
.global-charts-header {
  position: sticky;
  top: 0;
  z-index: 10;
  padding-top: var(--spacing-md);
  padding-bottom: var(--spacing-md);
}

/* Charts grid layout */
.global-charts-grid {
  display: flex;
  gap: var(--spacing-lg);
  flex-wrap: wrap;
}

/* Individual chart card - dark theme */
.global-chart-card-dark {
  flex: 1;
  min-width: var(--spacing-450);
  padding: var(--spacing-md);
  overflow: hidden;
}

/* BZ-47862: Use 767px (not 768px) to ensure iPad at 768px is treated as desktop */
@media (width <= 767px) {
  .global-chart-card-dark {
    min-width: 100%;
  }
}

/* ============================================
   OFFERS DASHBOARD - PAGE LAYOUT CLASSES
   ============================================ */

.global-page-container {
  /* The layout shell (.page-content) owns the page gutter; this wrapper no
     longer adds its own horizontal padding to avoid doubling it. */
  padding: 0;
}

.global-page-header-wrapper {
  padding: 0;

  --page-header-container-padding: var(--spacing-rg) var(--spacing-0) var(--spacing-0)
    var(--spacing-0);
}

@media (width >= 768px) {
  .global-page-header-wrapper {
    --page-header-container-padding: var(--spacing-0);
  }
}

/* Module page containers keep their own mobile padding; on desktop the parent
   .page-content supplies the gutter, so the container goes flush to avoid double
   spacing. !important overrides Svelte's scoped container rule (higher specificity). */
@media (width >= 768px) {
  .desktop-flush-padding {
    padding: 0 !important;
  }
}

.global-content-container {
  margin-top: var(--spacing-sm);
  margin-bottom: var(--spacing-lg);
}

.global-margin-bottom-lg {
  margin-bottom: var(--spacing-lg);
  margin-top: var(--spacing-rg);
}

.global-filter-row {
  display: flex;
  flex: 1;
  flex-flow: row nowrap;
  align-items: center;
  gap: var(--spacing-lg);

  --dropdown-width: fit-content;
  --dropdown-body-width: fit-content;
  --dropdown-header-gap: var(--spacing-12);
  --dropdown-sub-text-overflow: hidden;
  --dropdown-sub-text-text-overflow: ellipsis;
  --dropdown-sub-text-flex-shrink: 1;
}

/* Mobile: let filter controls wrap onto multiple rows instead of overflowing
   (row nowrap silently clips the last control at the viewport edge once there
   are three or more filters). */
@media only screen and (width <= 767px) {
  .global-filter-row {
    flex-flow: row wrap;
  }
}

.global-empty-state {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: var(--spacing-40);
}

.global-table-wrapper {
  --padding-table-row: var(--padding-offers-table-row);
}

/* Tag wrapper */
.global-tag-wrapper {
  --table-tag-gap: var(--spacing-xs);
  --table-tag-margin: 0;
  --table-tag-line-height: var(--line-height-xs);

  display: inline-flex;
  gap: var(--table-tag-gap);
  margin: var(--table-tag-margin);
  line-height: var(--table-tag-line-height);
}

/* Status tag base - common properties for status tags */
.global-tag-status-base {
  /* --pill-padding alias so .tag-status (raw div, not a Pill) picks up
     the same value when reading var(--pill-padding). */
  --pill-padding: var(--padding-tag);
}

/* Validity tag base - common properties for validity tags */

/* Pill chip — full-radius removable selection chips (e.g. selected products
   in a multi-select picker). Bigger than a standard tag; semibold weight;
   fully rounded. Apply to a flex container that holds Tag instances. */

/* Status tag classes - only unique properties (colors).
   --pill-background/--pill-color are added alongside the legacy --tag-*
   vars so that the raw <div class="tag-status"> in offers/[offerId]
   can read the same semantic values via --pill-* without a component swap. */

/* Validity tag classes - only unique properties (colors) */

.global-analytics-table-wrapper {
  --padding-table-row: var(--spacing-12) var(--spacing-20);

  /* Restore per-row separators dropped in the custom-Table → DataGrid migration so
     multi-row analytics metric tables (e.g. the Address validation metric table)
     read as a grid instead of a wall of text. The DataGrid opts dividers in via
     --grid-row-divider (off by default). */
  --grid-row-divider: var(--table-row-border);
}

.global-auto-layout-table {
  --grid-table-layout: auto;
  --grid-col-width: auto;
}

/* Validity tag for safe expiry (> 10 days) */

/* ============================================
   FORM LAYOUT CLASSES
   Reusable horizontal form row patterns
   ============================================ */

.global-form-card {
  padding: var(--spacing-32) var(--spacing-lg);
}

.global-sidebar-card {
  overflow: hidden;
  position: sticky;
  margin-top: var(--spacing-48);
  top: var(--spacing-32);
}

.global-sidebar-header {
  padding: var(--spacing-20) var(--spacing-lg);
}

.global-sidebar-content {
  padding: var(--spacing-lg);
}

/* Segmented control — the pill-tray variant of the library Radio. N Radios
 * sharing a name render as equal-width segments inside a bordered tray; the
 * checked segment is highlighted by background + shadow, exactly like the
 * retired project SegmentedControl (whose button-level color flips were dead
 * — the global span rule always won on the label). Every indicator property
 * is var-driven, so the circle is erased here without touching library DOM
 * layout; delete this block wholesale if the library ships a segmented
 * primitive. */
.global-radio-segmented {
  display: flex;
  width: 100%;
  padding: var(--spacing-2);
  gap: var(--spacing-2);
}

.global-radio-segmented .radio-container {
  --radio-size: 0px;
  --radio-dot-size: 0px;
  --radio-container-gap: 0;

  flex: 1;
  justify-content: center;
  height: var(--spacing-28);
  padding: var(--spacing-sm) var(--spacing-12);
  transition:
    background-color 0.15s ease,
    color 0.15s ease;
}

.global-form-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-48);
}

.global-form-row.align-top {
  align-items: flex-start;
}

.global-label-section {
  flex: 0 0 auto;
  width: clamp(var(--spacing-200), 35%, var(--spacing-420));
  min-width: 0;
}

.global-input-section {
  flex: 1 1 auto;
  min-width: 0;
}

.global-input-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-32);
}

.global-input-field {
  flex: 1 1 0;
  min-width: var(--spacing-140);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);

  --input-margin: var(--spacing-0) var(--spacing-0) var(--spacing-20) var(--spacing-0);
  --input-error-msg-margin: calc(-1 * var(--spacing-20)) var(--spacing-0) var(--spacing-2)
    var(--spacing-0);
}

/* Sticky Action Bar - Fixed bottom action bar pattern */
.global-sticky-action-bar {
  position: fixed;
  bottom: 0;
  left: var(--action-bar-left-offset, 0);
  right: 0;
  height: var(--spacing-80);
  display: flex;
  flex-direction: column;
  z-index: var(--z-index-header);
}

/* Push the debug FAB above the sticky action bar so both remain clickable. */
body:has(.global-sticky-action-bar) {
  --debug-fab-bottom-offset: calc(var(--spacing-80) + 12px);
}

.global-action-bar-divider {
  height: var(--spacing-1);
  width: 100%;
}

.global-action-bar-content {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--spacing-32);
  padding: 0 var(--spacing-32);
  flex: 1;
}

/* Hero Card - Gradient card for landing/promotional sections */
.global-hero-card {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-48);
  overflow: hidden;
  min-height: var(--spacing-320);
  min-width: var(--spacing-900);
}

.global-hero-card-content {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-48);
  max-width: var(--spacing-600);
  z-index: 1;
  flex-shrink: 0;
}

.global-text-truncate {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
}

/* Applied via CheckListItem `classes` prop in AddShippingRateDrawer for the
   conditional-rate row label. xs (14px) vs the :root default of xxs (12px) —
   this row sits in a drawer where body-text sizing (14px) reads better than
   the compact 12px used in StatisticsCard. --color-gray-1600 is per-design
   spec; it differs from :root's text-color-secondary and PaymentMethodField's
   text-color-primary, so all three sites intentionally differ. */
.global-check-list-item-text-body {
  --check-list-item-text-size: var(--font-size-xs);
}

.global-dd-container {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  width: var(--dropdown-width);
  min-width: var(--dropdown-min-width);
}

.global-dd-body {
  display: var(--dropdown-body-display);
  position: absolute;
  top: 100%;
  left: var(--spacing-0);
  right: var(--dropdown-body-right, var(--spacing-0));
  margin-top: var(--spacing-xs);
  z-index: var(--z-index-dropdown);
  overflow: hidden;
  min-width: var(--dropdown-body-min-width, auto);
  width: var(--dropdown-body-width, auto);
  animation: global-dd-slide-in 0.2s ease-out;
}

.global-dd-header-wrapper {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  width: 100%;
}

.global-dd-header {
  display: flex;
  align-items: stretch;
  transition:
    border-color 0.2s,
    background-color 0.2s;
  height: var(--dropdown-header-height);
  min-height: var(--dropdown-header-height);
  box-sizing: border-box;
  overflow: hidden;
}

.global-dd-header-disabled {
  cursor: not-allowed;
}

.global-dd-header-content {
  gap: var(--dropdown-header-gap);
  padding: var(--dropdown-header-padding);
  flex: 1;
  cursor: var(--content-cursor);
  min-width: var(--spacing-0);
}

/* Restored (regressed by BZ-3506): centers the leading dropdown icon. Still
   referenced by Dropdown/DropdownHeader.svelte. */
.global-dd-icon {
  justify-content: center;
}

.global-dd-icon-trailing {
  transition: transform 0.2s ease;
}

.global-dd-icon-rotated {
  transform: rotate(180deg);
}

.global-dd-text-container {
  flex-direction: row;
  flex: 1;
  min-width: var(--spacing-0);
  gap: var(--spacing-xs);
}

.global-dd-sub-text {
  white-space: nowrap;
  overflow: var(--dropdown-sub-text-overflow);
  flex-shrink: var(--dropdown-sub-text-flex-shrink);
}

.global-dd-count-badge {
  justify-content: center;
  min-width: var(--spacing-rg);
  width: var(--spacing-rg);
  height: var(--spacing-rg);
}

.global-dd-clear-container {
  display: flex;
  align-items: stretch;
  align-self: stretch;
}

.global-dd-clear-divider {
  width: 1px;
}

.global-dd-clear-button-wrapper {
  display: flex;
  height: 100%;

  --button-padding: var(--spacing-sm);
  --button-height: 100%;
  --button-margin: var(--spacing-0);

  cursor: var(--clear-cursor);

  --image-width: var(--spacing-rg);
  --image-height: var(--spacing-rg);
}

.global-dd-search-container {
  padding: var(--spacing-sm);
}

.global-dd-search-input-wrapper {
  --input-padding: var(--spacing-sm) var(--spacing-12);
  --input-margin: var(--spacing-0);
  --input-container-margin: var(--spacing-0);
  --input-height: auto;
}

.global-dd-items-container {
  padding: var(--spacing-xs) var(--spacing-0);
}

.global-dd-items-scrollable {
  max-height: var(--spacing-250);
  overflow-y: auto;

  /* BZ-3305: a visible thumb so long option lists (e.g. the Payment Method
     filter — 7 methods plus a Select All row) read as scrollable instead of
     "cut off". Derived from theme tokens so it adapts to light/dark. */
  --dd-scrollbar-thumb: color-mix(in srgb, var(--text-color-tertiary) 60%, transparent);

  scrollbar-width: thin;
  scrollbar-color: var(--dd-scrollbar-thumb) transparent;
  padding: var(--spacing-2);
  padding-right: var(--spacing-12);

  /* BZ-3305: scroll-shadow affordance. Top/bottom fades appear ONLY while
     there is more content to scroll in that direction (the bg-coloured
     "cover" gradients scroll with content and hide the shadow at each end),
     so the last option no longer looks jammed under the Select footer.
     Pure CSS via background-attachment local/scroll. */
  --dd-scroll-bg: var(--dropdown-body-bg, var(--bg-color-secondary));
}

.global-dd-item {
  justify-content: space-between;
  padding: var(--spacing-sm) var(--spacing-12);
  margin: var(--spacing-2) var(--spacing-0);
  cursor: pointer;
  transition: background-color 0.15s ease;
  min-height: var(--spacing-36);
  box-sizing: border-box;
}

.global-dd-item-disabled {
  cursor: not-allowed;
}

.global-dd-checkbox-container {
  pointer-events: none;

  /* --checkbox-size is now centralized at 16px in :root (theme.css); no override needed here */
}

/* Select-all dropdown item — checkbox/label gap (layout). The muted label
   colour + semi-bold weight (appearance) are themed in theme.css. */
.global-dd-select-all-checkbox {
  --checkbox-container-gap: var(--spacing-sm);
}

.global-dd-select-all-checkbox .label {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
}

/* Library Select override — NOT a typography rule. The library hardcodes the
 * multiselect-all option label as "All"; the design system requires
 * "Select All". Since the library exposes no label-customisation prop{
  font-size: 0;
}

.select-option .select-option-label {
  font-size: var(--font-size-xs);
}

/* The library Select chevron ships at stroke-width: 2, but the project's
 * design system uses a heavier filled chevron. Bump the stroke and round
 * joins so the dropdown indicator matches the rest of the UI.
 * This rule pre-dates this PR (introduced in BZ-3074 to fix the Svelte 5
 * migration) and is intentionally left as a bare rule so all library Select
 * instances — including pre-existing ones (e.g. /settings version select) —
 * keep the same chevron weight they had on beta. */

/* Selects inside a DataGrid paginator open upward by default — they live at the
 * bottom of a table footer, so the default downward dropdown gets clipped
 * by the viewport. Scoped to the DataGrid paginator only: a bare `.pagination
 * .select` matched unrelated selects (e.g. form selects above a paginator),
 * forcing them to open upward incorrectly. */
.datagrid-paginator-wrapper .pagination .select .select-dropdown {
  top: auto;
  bottom: 100%;
  margin-top: 0;
  margin-bottom: var(--spacing-2);
}

/* Load-more "Next" button (cursor-pagination hasMore mode). The classes prop
   lands on the library Button's .button-container wrapper; the vars thread
   through to the inner <button> to swap the :root primary chrome for this
   soft tertiary look. */
.global-btn-load-more {
  cursor: pointer;
  padding: var(--spacing-xs) var(--spacing-12);
  margin-left: var(--spacing-xs);

  --button-padding: 0;
  --button-content-gap: 0;
}

/* Multi-select trigger summary. The library renders the trigger as a long
 * comma-separated list of every selected option; the design system shows
 * "<count> states selected" / "1 state selected" / "Select states" instead.
 * Hide the library label (font-size: 0) and inject the summary via ::before
 * driven by the data-state-count attribute synced from Svelte.
 *
 * Any consumer can opt in by adding the .state-select-with-count class and
 * a data-state-count attribute to the Select wrapper. */

.state-select-with-count .select-value::before {
  content: var(--state-selected-count) ' states selected';
}

.state-select-with-count[data-state-count='0'] .select-value::before {
  content: 'Select states';
}

.state-select-with-count[data-state-count='1'] .select-value::before {
  content: '1 state selected';
}

/* Wrapper class for any portalled Toast notification. Sits above the
 * library Modal overlay (--modal-z-index default = 1200) so success /
 * error toasts triggered from inside a modal aren't trapped behind it.
 * Consumers add this class to a `<div use:portal>` that contains the
 * `<Toast>` element. */
.toast-portal-wrapper {
  position: fixed;
  z-index: 1300;
}

.global-dd-apply-container {
  display: flex;
  justify-content: flex-end;
  padding: var(--spacing-sm);
}

.global-dd-apply-button-wrapper {
  width: 100%;

  --button-width: 100%;
}

@keyframes global-dd-slide-in {
  from {
    transform: translateY(calc(-1 * var(--spacing-xs)));
  }

  to {
    transform: translateY(var(--spacing-0));
  }
}

.global-row-layout-simple {
  display: flex;
  flex-direction: row;
}

.global-row-layout-simple-center {
  display: flex;
  flex-direction: row;
  align-items: center;
}

.address-stats-cards {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--spacing-md);
  width: 100%;

  --statistics-card-width: 100%;
  --stats-card-max-width: 100%;
  --stats-card-min-width: 0;
  --statistics-card-justify: space-between;
}

/* Card pattern - bordered card with shadow */
.global-card-bordered {
  overflow: hidden;
}

.global-card-section-header {
  padding: var(--spacing-rg) var(--spacing-lg);
}

.global-card-section-body {
  padding: var(--spacing-rg) var(--spacing-lg);
  gap: var(--spacing-rg);
}

.global-card-section-footer {
  padding: var(--spacing-md) var(--spacing-lg);
}

/* Split row - side-by-side segments with subtle background */
.global-split-row {
  display: flex;
  align-items: stretch;
}

.global-split-row > div {
  flex: 1;
  padding: var(--spacing-md) var(--spacing-rg);
}

/* Vertical divider */
.global-vertical-divider {
  width: var(--spacing-1);
}

/* Status badge */
.global-status-badge {
  padding: var(--spacing-sm) var(--spacing-md);
  letter-spacing: 0.3px;
  white-space: nowrap;
}

/* Action link */
.global-action-link {
  transition: color 0.15s ease;
}

/* Grid layouts */
.global-grid-3-col {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-lg);
}

.global-modal-desktop-content .modal-content {
  width: var(--modal-desktop-content-width, 550px);
  max-width: var(--modal-desktop-content-width, 550px);
}

/* Responsive Modal Container - BZ-47862 */

/* Provides bottom sheet on mobile, centered dialog on desktop */
.responsive-modal-container {
  position: fixed;
  inset: 0;
  z-index: 1100;
  display: flex;
  align-items: center;
  justify-content: center;

  --modal-width: var(--modal-mobile-width, 100vw);
  --modal-height: 100%;
}

.responsive-modal-container.desktop {
  --modal-width: var(--modal-desktop-width, 550px);
  --modal-height: auto;
}

.responsive-modal-container.desktop .modal-content {
  width: 100% !important;
  max-width: var(--modal-desktop-width, 550px) !important;

  /* The library renders snippet content inside an unstyled wrapper <div> that
     takes full modal width; without auto-margins the max-width-constrained
     content sits at the left edge of the modal box instead of centered. */
  margin-left: auto !important;
  margin-right: auto !important;
}

/* Offset modals when sidebar is open so they don't render under it */
.sidebar-open .responsive-modal-container {
  --modal-width: calc(100vw - var(--sidebar-width-open));
  --modal-margin: 0 0 0 var(--sidebar-width-open);
}

/* Push modal content above the iOS home indicator safe area */
.responsive-modal-container .modal.bottom .modal-content {
  padding-bottom: max(var(--safe-area-inset-bottom, 0px), env(safe-area-inset-bottom, 0px), 34px);
}

.responsive-modal-container.desktop .modal .modal-content {
  padding-bottom: 0;
}

/* Desktop modal centering with transform */
.responsive-modal-container.desktop .modal {
  left: 50% !important;
  transform: translateX(-50%) !important;
}

.responsive-modal-container.desktop .modal.center {
  top: 50% !important;
  left: 50% !important;
  transform: translate(-50%, -50%) !important;
}

.responsive-modal-container.desktop .modal > div {
  width: 100% !important;
}

.responsive-modal-container.desktop .slot-content {
  width: 100% !important;
}

/* ============================================
   SCREEN TRANSITIONS — iOS-style push/pop
   View Transitions API (Chromium-only; instant fallback elsewhere).
   Only triggered on mobile / iOS via onNavigate in (app)/+layout.svelte;
   desktop never calls startViewTransition so these pseudo-elements never run.
   ============================================ */

@keyframes page-enter {
  from {
    transform: translateX(100%);
  }
}

@keyframes page-exit {
  to {
    transform: translateX(-25%);
    scale: 0.97;
  }
}

@keyframes page-enter-back {
  from {
    transform: translateX(-25%);
    scale: 0.97;
  }
}

@keyframes page-exit-back {
  to {
    transform: translateX(100%);
  }
}

/* Forward (push) */
:root::view-transition-old(root),
:root::view-transition-old(main-content) {
  animation: 420ms cubic-bezier(0.52, 0, 0.24, 1) both page-exit;
}

:root::view-transition-new(root),
:root::view-transition-new(main-content) {
  animation: 420ms cubic-bezier(0.52, 0, 0.24, 1) both page-enter;
}

/* Back (pop) — reverse directions */
[data-nav-dir='back']:root::view-transition-old(root),
[data-nav-dir='back']:root::view-transition-old(main-content) {
  animation: 420ms cubic-bezier(0.52, 0, 0.24, 1) both page-exit-back;
}

[data-nav-dir='back']:root::view-transition-new(root),
[data-nav-dir='back']:root::view-transition-new(main-content) {
  animation: 420ms cubic-bezier(0.52, 0, 0.24, 1) both page-enter-back;
}

/* Sidebar stays static during page transitions */
::view-transition-old(sidebar),
::view-transition-new(sidebar) {
  animation: none;
}

@media (prefers-reduced-motion) {
  :root {
    --sidebar-transition-duration: 0s;
    --fade-transition-duration: 0s;
  }

  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* ai page header - BZ-47862 */
.ai-page-header {
  /* Fixed 40px bar paired with the sidebar header row — keep the title
     vertically centered inside it (the dashboard default is top-aligned). */
  --page-header-vertical-align: center;
  --page-header-container-padding: calc(
      max(var(--safe-area-inset-top, 0px), env(safe-area-inset-top, 0px)) + var(--spacing-sm)
    )
    var(--spacing-md) var(--spacing-xs);
  --desktop-header-bar-height: 40px;
  --page-header-margin-top: var(--spacing-xs);
  --page-header-right-view-width: auto;

  /* Zero the left-section gap so the /ai logo centers in the header bar
     (gap between the icon and the title label collapses). */
  --page-header-section-left-gap: 0;

  /* /ai routes are full-bleed (content column flush-left, padding:0, an ancestor
     sets overflow:hidden), which clips the gutter where the back chevron is
     parked by its default absolute `right:100%` position — on narrow screens the
     chevron lands off the left edge and is cut off. Render it in the title's flow
     instead so it stays fully visible on every /ai sub-route (settings, reports,
     chats, anomaly, …). The main /ai landing has no back button, so this is inert
     there. */
  --page-header-back-button-position: static;
}

/* AI sub-route header: the back-button + title align to the centered content
   column below it (global-centered-column, max-width var(--spacing-800)) instead
   of sitting flush at the page edge — so every /ai route (settings, reports,
   chats, sources, signals, …) places the back-button + title in the same spot,
   matching the voice/conversation header. Applies to the base .ai-page-header so
   no route is left flush-left; .ai-page-header-centered remains as an explicit
   alias for the same behaviour. */
.ai-page-header > .page-header-container {
  width: 100%;
  max-width: var(--spacing-800);
  margin-inline: auto;
}

/* Right-anchor the shipping zone options menu so it opens leftward instead of
   overflowing the right edge of the screen. The kebab trigger sits at the right
   edge of the zone card and the library Menu defaults to left:0 (extends right). */
.zone-options-menu .menu-dropdown {
  right: 0;
  left: auto;
}

/* Native date input calendar indicator (UA pseudo-element). Theme.css
 * owns the filter value via --date-input-indicator-filter (none in light,
 * invert(1) in dark). This rule is the global consumer — :root selectors
 * can't reach inside the UA shadow DOM, so we apply the filter from a
 * top-level selector that matches the native input. No component is
 * involved. */

/* @xyflow/svelte (Svelte Flow) — third-party library that emits
 * `.svelte-flow*` class names directly on its DOM. Themed globally so
 * every consumer (not just FlowDiagram.svelte) renders correctly in dark
 * mode. All tokens live in theme.css under the visual-audit semantic
 * block (--flow-node-bg, --flow-node-text, --flow-node-border,
 * --flow-control-bg, --flow-control-icon, --flow-minimap-bg,
 * --flow-minimap-mask). Components must never re-declare these. */

/* stylelint-disable selector-class-pattern -- third-party @xyflow/svelte
 * class names use BEM-style `__` which the project's kebab-case rule
 * rejects. We can't rename library DOM, so disable the rule for this
 * block only. */
/* stylelint-enable selector-class-pattern */

.global-data-grid .sort-indicator svg,
.global-data-grid .sort-indicator img {
  pointer-events: none;
}

/* ============================================
   BUTTON COMPONENT
   ============================================ */

.global-btn {
  /* When a project Button sits inside a flex/grid row alongside an input or
   * a long sibling, the default flex behaviour lets the button shrink and
   * wrap its label across two lines. Default to "stay at natural width,
   * never wrap" because that matches almost all CTAs. Opt out with
   * `.global-btn-allow-wrap` on the wrapper when a multi-line label is
   * intended. */
  flex-shrink: 0;
  white-space: nowrap;
}

/* Opt-out for intentional multi-line button labels. */
.global-btn.global-btn-allow-wrap {
  flex-shrink: 1;
  white-space: normal;
}

.global-btn.global-full-width {
  --button-width: 100%;
}

/* Text alignment variants */
.global-btn.global-btn-text-left {
  --button-justify-content: flex-start;
}

.global-btn.global-btn-text-right {
  --button-justify-content: flex-end;
}

.global-btn-content {
  gap: var(--button-content-gap);
  display: flex;
  flex-direction: var(--button-content-flex-direction, row);
  align-items: center;
  justify-content: var(--button-justify-content, center);

  --image-width: var(--btn-icon-size, var(--spacing-md));
  --image-height: var(--btn-icon-size, var(--spacing-md));
}

/* ---- CSS variable declarations: base types (specificity 0,1,0) ---- */

/* ---- CSS variable declarations: destructive overrides (specificity 0,2,0) ---- */

/* ---- Button text color variant: muted (specificity 0,2,0) ---- */
.global-btn-muted {
  /* Secondary keeps the muted CTA readable in both themes; the placeholder token
     collapses to a near-invisible near-black on dark surfaces. (Light is identical
     — placeholder resolves to secondary there.) */
}

/* ---- Base resting box-shadow — the default (primary) look; ghost zeroes it ---- */

/* ---- Base type states (all specificity 0,3,1) ---- */

/* Base disabled rule — universal bits plus the default (primary) disabled
 * colours; secondary / ghost / destructive override the colours at higher
 * specificity below. */
.global-btn button:disabled {
  cursor: not-allowed;
}

/* ---- Destructive states + disabled:hover overrides (all specificity 0,4,1) ---- */

/* Base disabled:hover rule — universal bits plus default (primary) colours;
 * variants override below. */

/* ---- Destructive disabled:hover overrides (specificity 0,5,1) ---- */

/* ---- Size variants ---- */
.global-btn-sm {
  --button-height: var(--spacing-32);
}

.global-btn-lg {
  --button-height: var(--spacing-48);
}

.global-btn.global-btn-icon-only {
  --button-padding: var(--spacing-0);
  --button-height: auto;
}

.edit-order-icon-btn .menu-container .menu-dropdown {
  left: auto;
  right: var(--spacing-0);
}

.zone-options-trigger-wrapper .global-btn.global-btn-icon-only {
  --button-padding: var(--spacing-12);
  --button-height: auto;
}

/* ============================================
   INPUT FIELD COMPONENT CLASSES
   ============================================ */

.global-input-field-container {
  align-items: flex-start;
}

.global-input-field-content .input-container {
  --input-container-width: 100%;

  width: 100%;
  min-width: 0;
}

.global-input-field-container--small {
  width: var(--spacing-320);
}

.global-input-field-container--medium {
  width: var(--spacing-370);
}

.global-input-field-container--large {
  width: var(--spacing-420);
}

.global-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-md);
}

/* Same base layout as global-header-row, kept separate because it stacks to a
   column on tablet via the @media (width <= 1024px) override below. */
.global-general-profile-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--spacing-md);
}

.global-toolbar-control-group {
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  gap: var(--spacing-sm);
  flex: 1 1 var(--spacing-600);
  min-width: 0;
}

.global-toolbar-control-group-start {
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  gap: var(--spacing-sm);
  flex: 0 0 auto;
  min-width: 0;
}

/* Canonical toolbar control height. A filter row mixes four primitives —
   library Select, project Dropdown, InputField and DateRangePicker — whose
   default trigger heights differ (32–48px), so the row read as a set of
   slightly-misaligned boxes. Pin one shared height across all of them. These
   custom properties inherit, so they reach controls nested inside per-page
   wrapper divs (e.g. .orders-date-filter, .orders-status-filter,
   .orders-search-field) that the direct-child rules below cannot match. */
.global-toolbar-control-group,
.global-toolbar-control-group-start {
  --select-trigger-min-height: var(--spacing-44);
  --dropdown-header-height: var(--spacing-44);

  /* InputField reads --input-font-size for its <input>; set it here so the
     search field's text matches the other controls (the input element itself
     does not respond to a raw font-size due to the component's cascade). */
}

/* DateRangePicker renders a library Button as its trigger (~32px by default).
   Pin it to the shared height; scoped to the trigger so the open panel's
   Apply/Cancel buttons keep their own sizing. */
.global-toolbar-control-group .drp-trigger,
.global-toolbar-control-group-start .drp-trigger {
  --button-height: var(--spacing-44);

  min-height: var(--spacing-44);
}

/* InputField box: pin to the shared height. min-height alone let a leading icon
   (taller than the text line) push the box to ~46px while icon-less controls
   stayed at 44px; a fixed height keeps every toolbar field exactly 44px. */
.global-toolbar-control-group .global-input-field-box,
.global-toolbar-control-group-start .global-input-field-box {
  min-height: var(--spacing-44);
  height: var(--spacing-44);
}

/* Harmonise the control text size. Each primitive renders its label at a
   different token by default — DateRangePicker 12px (its own .drp-trigger-label
   style), Select 14px, Dropdown 16px — so the row read as mismatched type even
   once the heights matched. Pin every control's visible label to the standard
   control size (--font-size-xs); scoped to the triggers so dropdown panels /
   select options keep their own sizing. */

.global-toolbar-control-group > .global-dd-container,
.global-toolbar-control-group-start > .global-dd-container {
  flex: 0 0 auto;
  width: fit-content;
}

/* Library Select sits directly inside the toolbar group — mirror the project
 * Dropdown constraint so it does not stretch to fill the full group width.
 * --select-trigger-min-height is pinned to 44px to match the InputField box
 * height (padding: 12px top + 12px bottom + 20px line-height = 44px), so the
 * Select and InputField controls are visually the same height in toolbar rows. */
.global-toolbar-control-group > .select,
.global-toolbar-control-group-start > .select {
  --select-trigger-min-height: 44px;

  flex: 0 0 auto;
  width: fit-content;
}

.global-toolbar-control-group > .global-input-field-container,
.global-toolbar-control-group-start > .global-input-field-container {
  flex: 0 1 var(--spacing-240);
  min-width: var(--spacing-180);
  width: var(--spacing-240);
}

@media (width <= 767px) {
  .global-header-row,
  .global-toolbar-control-group,
  .global-toolbar-control-group-start {
    align-items: stretch;
    justify-content: flex-start;
    flex: 0 0 auto;
    flex-direction: column;
  }

  .global-header-row > *,
  .global-toolbar-control-group > .global-dd-container,
  .global-toolbar-control-group > .global-input-field-container,
  .global-toolbar-control-group-start > .global-dd-container,
  .global-toolbar-control-group-start > .global-input-field-container {
    flex: 0 0 auto;
    width: 100%;
  }

  .global-toolbar-control-group > .select,
  .global-toolbar-control-group-start > .select {
    --select-width: 100%;

    flex: 0 0 auto;
    width: 100%;
  }
}

.global-input-field-container--disabled {
  cursor: not-allowed;
}

.global-input-field-label-text {
  line-height: var(--line-height-xs);
}

.global-input-field-mandatory {
  margin-left: var(--spacing-2);
}

.global-input-field-box {
  gap: var(--spacing-sm);
  padding: var(--spacing-12) var(--spacing-md);
  box-sizing: border-box;
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

.global-input-field-box--disabled {
  cursor: not-allowed;
}

.global-input-field-content {
  min-width: 0;
  gap: var(--spacing-0);

  --input-margin: var(--spacing-0);
  --input-padding: var(--spacing-0);
  --input-height: auto;
  --input-container-margin: var(--spacing-0);
  --input-container-padding: var(--spacing-0);
}

/* The txt-label wrapper sets font-weight: medium (500) on the InputField container,
 * which inherits into the <input> element and from there into ::placeholder — making
 * placeholder text as heavy as typed text. Explicitly set placeholder to regular
 * weight so it is visually lighter than real input data in both themes. */

/* @juspay/svelte-ui-components <Input> nests its <input> inside an
   .input-container wrapper that's a flex item with default `flex: 0 1 auto`,
   so it collapses to the native input's size=20 default (~187px). When the
   caller opts into fullWidth on InputField, force the wrapper to grow and
   the inner element to fill it. */
.global-input-field-container.global-full-width .global-input-field-content > * {
  flex: 1 1 0%;
  min-width: 0;
}

.global-input-field-container.global-full-width .global-input-field-content input,
.global-input-field-container.global-full-width .global-input-field-content textarea {
  width: 100%;
}

.global-input-field-box--disabled .global-input-field-content {
  pointer-events: none;
}

/* In dark mode --text-color-primary resolves to a dimmer grey than the
   placeholder token, inverting the typed-vs-placeholder hierarchy (typed text
   rendered fainter than the placeholder). Use the bright text token for typed
   input text in dark only; light mode keeps its existing colour. */

.global-input-field-icon-container {
  flex-shrink: 0;
  width: var(--spacing-rg);
  height: var(--spacing-rg);

  --button-width: var(--spacing-rg);
  --button-height: var(--spacing-rg);
  --button-padding: var(--spacing-0);
  --button-icon-display: flex;
  --image-width: var(--spacing-rg);
  --image-height: var(--spacing-rg);
}

.global-input-field-box--disabled .global-input-field-icon-container {
  pointer-events: none;
}

.global-input-field-message {
  align-items: flex-start;
  gap: var(--spacing-12);
}

.global-input-field-hint-text {
  line-height: var(--line-height-xs);
}

.global-input-field-error-text {
  line-height: var(--line-height-xs);
}

/* Video Player */
.global-video-player-container {
  max-width: var(--ai-video-player-max-width);
}

.global-video-player-container-portrait {
  max-width: var(--ai-video-player-max-width-portrait);
}

.global-video-wrapper {
  overflow: hidden;
}

.global-video-element {
  display: block;
  height: auto;
  max-height: var(--ai-video-player-max-height);
  cursor: pointer;
  aspect-ratio: 16 / 9;
  object-fit: contain;
}

.global-video-element-portrait {
  aspect-ratio: 9 / 16;
  object-fit: cover;
}

.global-video-controls-overlay {
  position: absolute;
  bottom: var(--spacing-0);
  left: var(--spacing-0);
  right: var(--spacing-0);
  gap: var(--spacing-sm);
  padding: var(--spacing-sm) var(--spacing-md);
  transition: opacity 0.3s ease;
}

.global-video-control-btn {
  justify-content: center;
  flex-shrink: 0;
  cursor: pointer;
  transition: background 0.2s ease;

  --button-padding: var(--spacing-0);
  --button-width: var(--spacing-36);
  --button-height: var(--spacing-36);
  --icon-height: var(--spacing-20);
  --icon-width: var(--spacing-20);
}

.global-video-progress-container {
  flex: 1;
  height: var(--spacing-lg);
  cursor: pointer;
  padding: var(--spacing-sm) var(--spacing-0);
}

.global-video-progress-track {
  height: var(--spacing-xs);
}

.global-video-progress-filled {
  position: absolute;
  top: var(--spacing-0);
  left: var(--spacing-0);
  height: 100%;
  will-change: width;
}

.global-video-progress-thumb {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: var(--spacing-12);
  height: var(--spacing-12);
  will-change: left;
  transition: opacity 0.2s ease;
}

.global-video-time-display {
  white-space: nowrap;
  user-select: none;
  min-width: fit-content;
}

.global-video-time-separator {
  margin: var(--spacing-0) var(--spacing-1);
}

.global-video-right-controls {
  gap: var(--spacing-xs);
}

.global-video-action-buttons {
  --button-padding: var(--spacing-0);
  --button-width: var(--icon-size-3xl);
}

.video-generation-placeholder {
  max-width: var(--ai-video-player-max-width);
  aspect-ratio: 16 / 9;
  overflow: hidden;
  margin-top: var(--spacing-md);
}

.video-generation-placeholder.portrait {
  max-width: var(--ai-video-player-max-width-portrait);
  aspect-ratio: 9 / 16;
}

@media (width <= 768px) {
  .global-video-action-icon {
    width: var(--icon-size-xl);
    height: var(--icon-size-xl);
  }
}

@media (width <= 480px) {
  .global-video-controls-overlay {
    gap: var(--spacing-xs);
    padding: var(--spacing-xs) var(--spacing-sm);
  }

  .global-video-control-btn {
    --button-width: var(--spacing-32);
    --button-height: var(--spacing-32);
    --icon-height: var(--spacing-md);
    --icon-width: var(--spacing-md);
  }
}

/* ============================================
   CONFIRMATION MODAL LAYOUT
   ============================================ */

.global-confirmation-modal-container {
  --modal-header-padding: var(--spacing-0);
  --modal-margin: auto;
}

.global-confirmation-modal-content {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
  padding: var(--spacing-lg);
  width: var(--spacing-600);
  max-width: min(var(--spacing-600), 100%);
}

.global-confirmation-modal-close-btn {
  position: absolute;
  top: var(--spacing-md);
  right: var(--spacing-md);
}

.global-confirmation-modal-header {
  padding-right: var(--spacing-md);
}

.global-confirmation-modal-body {
  margin: 0;
  padding-bottom: var(--spacing-sm);
}

.global-confirmation-modal-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--spacing-md);
}

/* ============================================
   LOADER VARIANTS
   ============================================ */

/* @juspay/svelte-ui-components Loader sizing bridge for page-level loader
 * wrappers. The library Loader uses --loader-width / --loader-height for
 * size and --loader-background for the centre-cutout (without it the
 * spinner renders as a filled disk). Its ::before / ::after defaults are
 * absolute pixels (10px / 15px) that don't scale, so for our 50px disk
 * we also override them proportionally to keep a thin ring.
 *
 * Scoped to wrapper classes (NOT :root) so the library Loader nested
 * inside library Button's `.button-loader` keeps its own 20px defaults —
 * a :root mapping leaked the 50px page-loader size into every in-button
 * spinner, which dwarfed the button.
 *
 * Add a wrapper class here if a new page-loader callsite needs sizing.
 */
.loader-container,
.loading-container,
.shopify-loading-overlay {
  --loader-width: var(--loader-size);
  --loader-height: var(--loader-size);
  --loader-before-width: calc(var(--loader-size) / 2);
  --loader-before-height: calc(var(--loader-size) / 2);
  --loader-after-width: calc(var(--loader-size) * 0.78);
  --loader-after-height: calc(var(--loader-size) * 0.78);
}

/* For our Loader component - small inline loader (horizontal flow) */
.global-loader-inline-sm {
  --loader-flex-direction: row;
  --loading-text-margin-top: 0;
}

/* For Button component loader - light loader on settings/modal backgrounds */
.global-loader-light {
  --loader-foreground: var(--bg-color-secondary);
  --loader-foreground-end: var(--bg-color-inverted);
}

/* For Button component loader - loader on primary/accent color backgrounds */
.global-loader-primary {
  --loader-foreground: var(--bg-color-secondary);
  --loader-foreground-end: var(--bg-color-inverted);
}

/* For Button component loader - inverse theme (light on inverted background) */
.global-loader-inverse {
  --loader-foreground: var(--bg-color-secondary);
  --loader-foreground-end: var(--bg-color-inverted);
}

/* The library renders the in-button spinner as a bare <Loader> that inherits
   whatever --loader-foreground is in scope — so on an accent-filled button it can
   pick up a dark page-loader colour (e.g. from a .global-loader-* wrapper) and
   vanish. Set on .button-loader (nearer the spinner than any wrapper, so it wins)
   and tie it to the button's own text colour, so the spinner stays legible on
   every button tone — primary on-accent, secondary tertiary, ghost blue — with no
   per-button overrides. */
.button-loader {
  --loader-foreground: var(--button-text-color);
}

/* ──────────────────────────────────────────────────────────────────────────────
   Centered confirmation modal — reusable overlay + card pattern for
   delete / structural-change / confirmation modals across mandate pages.
   ────────────────────────────────────────────────────────────────────────────── */

.global-confirmation-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-index-modal, 100000);

  --modal-width: 100vw;
  --modal-height: 100vh;
  --modal-content-padding: 0;
  --global-confirmation-modal-card-width: var(--modal-confirmation-width, 440px);
}

.global-confirmation-modal-overlay .modal-content {
  width: var(--global-confirmation-modal-card-width);
  max-width: var(--global-confirmation-modal-card-width);
}

.global-confirmation-modal-overlay .global-confirmation-modal-content {
  gap: var(--spacing-lg);

  /* In beta the project Modal's slot-content (padding: 20px) wrapped the content div
     (padding: 20px), so the visible card had 40px effective vertical padding per side.
     The library Modal's slot-content has no padding rule, so we compensate here. */
  padding: var(--spacing-40) var(--spacing-rg);
}

/* Headerless dialogue variant: these dialogues render their title inside the
   content block, but the project Modal still paints its (empty) header strip
   above the content, leaving more space above the title than on the other
   three sides. Dialogues that pass no header title/close button opt in via
   this class to get uniform padding on all sides. */
.global-confirmation-modal-overlay.global-confirmation-modal-headerless .modal-content > .header {
  display: none;
}

.global-confirmation-modal-overlay.global-confirmation-modal-headerless
  .global-confirmation-modal-actions {
  margin-bottom: 0;
}

.global-confirmation-modal-icon {
  width: var(--spacing-64, 64px);
  height: var(--spacing-64, 64px);
  margin-bottom: var(--spacing-xs);

  /* The inlined info SVG paints with currentColor — resolve it to the theme
   * text colour so the icon stays visible in dark mode (BZ-3557). */

  --image-width: var(--spacing-28, 28px);
  --image-height: var(--spacing-28, 28px);
}

/* Applies the error-state filter to img/svg rendered inside a destructive modal
   icon container (logout, data-source delete). Named class avoids :global() in
   component \3c style> blocks. */

.global-confirmation-modal-overlay .global-confirmation-modal-title {
  margin: 0;
}

.global-confirmation-modal-message {
  margin: 0;
  padding-bottom: var(--spacing-xs);
}

.global-confirmation-modal-actions {
  gap: var(--spacing-12, 12px);
  margin-top: var(--spacing-xs);
  margin-bottom: var(--spacing-xs);
}

/* Toggle layout token — display is a layout property; lives here, not in theme.css */
:root {
  --toggle-container-display: inline-flex;
}

/* toggle pill */

.global-toggle-pill {
  display: inline-flex;
  align-items: center;
  padding: var(--spacing-12) var(--spacing-rg);
  transition: background-color 0.3s ease;

  --toggle-container-gap: var(--spacing-sm);
  --toggle-switch-width: var(--spacing-36);
  --toggle-switch-height: var(--spacing-rg);
  --toggle-ball-height: var(--spacing-md);
  --toggle-ball-width: var(--spacing-md);
  --toggle-slider-before-left: var(--spacing-2);
  --toggle-slider-before-bottom: var(--spacing-2);
  --toggle-slider-before-top: var(--spacing-2);
}

/* Reset global .container padding leak from theme.css onto Toggle's internal .container */
.global-toggle-pill .container {
  padding: 0;
}

.global-fixed-fullscreen {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

/* button */
.global-btn-plain {
  padding: var(--spacing-xs);

  --button-padding: var(--spacing-0);
}

/* ──────────────────────────────────────────────────────────────────────────────
   Organization selector (Bifrost needs_org_id flow) — inline searchable dropdown.
   NOTE: Prefixed class names to avoid collisions with other app modals.
   ──────────────────────────────────────────────────────────────────────────── */

.global-overflow-y-auto {
  overflow-y: auto;
}

.global-scrollbar-width-thin {
  scrollbar-width: thin;
}

.global-interactive-reset {
  all: unset;
  box-sizing: border-box;
  cursor: pointer;
}

.global-text-ellipsis {
  white-space: nowrap;
  overflow: hidden;
}

/* Product Widget - Shared styles for ProductCard component */
.global-product-widget-item {
  display: flex;
  flex-direction: column;
  padding: var(--spacing-md);
}

.global-product-widget-info {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
}

.global-product-widget-thumbnail {
  width: var(--spacing-64);
  height: var(--spacing-64);
  overflow: hidden;
}

.global-product-widget-thumbnail.placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--spacing-md);
}

.global-product-widget-title {
  max-width: var(--spacing-220);
  overflow: hidden;
  white-space: nowrap;
}

/* Inline organization selector (searchable dropdown) */
.global-organization-org-selector {
  margin-top: var(--spacing-xs);
  padding: var(--spacing-xs);
}

.global-organization-org-label-row {
  margin-bottom: var(--spacing-xs);
}

.global-organization-org-search-container {
  position: relative;
  margin-bottom: var(--spacing-xs);
}

.global-organization-org-search-input {
  width: 100%;
  padding: var(--spacing-xs) var(--spacing-xs);
  transition: all 0.2s;
}

.global-organization-org-search-input:disabled {
  cursor: not-allowed;
}

.global-organization-org-dropdown {
  position: absolute;
  top: calc(100% + var(--spacing-xs));
  left: 0;
  right: 0;
  max-height: 130px;
  overflow: hidden auto;
  z-index: var(--z-index-dropdown);
}

.global-organization-org-dropdown::-webkit-scrollbar {
  width: var(--spacing-sm);
}

.global-organization-org-dropdown-item {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-xs) var(--spacing-xs);
  cursor: pointer;
  transition: background-color 0.15s;
}

.global-organization-org-details {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-1);
  flex: 1;
}

.global-organization-org-dropdown-empty {
  padding: var(--spacing-xs);
}

/* Step progress tracker additions (inline retry + org selector slot) */
.retry-btn-inline {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  padding: var(--spacing-xs) var(--spacing-sm);
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: nowrap;
}

.retry-btn-inline:disabled {
  cursor: not-allowed;
}

.org-selector-container {
  margin-top: var(--spacing-md);
  overflow: visible;
  position: relative;
  z-index: 10;
}

/* data grid */
.global-data-grid-bg {
  --datagrid-summary-row-bg: var(--color-blue-50);
}

/* Dense list / analytics-style DataGrid — add on wrapper around DataGrid (see text.css .txt-datagrid-* for leaf utilities). Header: headerLabelExtraClass (e.g. global-font-size-xxs). Body cells: gridCellExtraClass (e.g. txt-datagrid-cell-body). */

.global-data-grid-header {
  --datagrid-header-bg: var(--bg-color-tertiary);
}

/* table */
.global-table-cell-scroll,
.global-table-cell-hidden {
  margin: var(--spacing-md) 0;

  --table-header-padding: var(--spacing-0);
  --scrollable-table-height: 900px;
  --scrollable-column-height: 36px;
}

.global-datagrid-with-row-dividers {
  /* DataGrid rows read --grid-row-divider (default none) for their top/bottom
   * border; set it so dense log tables get horizontal grid lines. */
  --grid-row-divider: 1px solid var(--border-color-divider);
}

/* toggle */
.global-toggle-dark {
  --toggle-switch-height: var(--spacing-rg);
  --toggle-switch-width: var(--spacing-48);
  --toggle-ball-height: var(--spacing-20);
  --toggle-ball-width: var(--spacing-lg);
}

/* image */

.global-icon-xxxs {
  --image-width: var(--spacing-12);
  --image-height: var(--spacing-12);
}

.global-icon-sm {
  --image-width: var(--spacing-md);
  --image-height: var(--spacing-md);
}

.global-icon-md {
  --image-width: var(--spacing-20);
  --image-height: var(--spacing-20);
}

.global-icon-rg {
  --image-width: var(--spacing-rg);
  --image-height: var(--spacing-rg);
}

.global-icon-large {
  --image-width: var(--spacing-lg);
  --image-height: var(--spacing-lg);
}

.global-icon-xl {
  --image-width: var(--spacing-32);
  --image-height: var(--spacing-32);
}

.global-icon-2xl {
  --image-width: var(--spacing-40);
}

.global-icon-2xl-sq {
  --image-width: var(--spacing-40);
  --image-height: var(--spacing-40);
}

.global-icon-3xl {
  --image-width: var(--spacing-52);
  --image-height: var(--spacing-52);
}

/* list item */
.global-list-item-static {
  --list-item-margin: var(--spacing-0);
  --list-item-padding: var(--spacing-0);
}

.global-list-item-bordered {
  --list-item-margin: 10px 0px;
}

/* select */

.global-select-dropdown {
  margin-bottom: var(--spacing-32);
  padding-left: var(--spacing-xs);

  --item-padding: var(--spacing-12) var(--spacing-20);
}

.global-checkbox-dropdown {
  --label-container-margin-bottom: 3px;

  /* Default to fit the placeholder text instead of shrinking to fit-content.
   * The library Select defaults to fit-content which collapses multi-word
   * placeholders ("Breeze supported countries", etc.) into a narrow trigger. */
}

/* Filter selects show a short static label/count ("Status", "3 selected"), so they
 * follow the theme's content-width default — no fixed width, no dead space. */

/* Make a library Select trigger the same height as the InputField box (44px)
 * so Select + InputField controls line up in toolbar rows. */
.global-select-match-input {
  --select-trigger-min-height: 44px;
}

/* Align a PageHeader's left edge with the section-card left edge (card margin =
 * --spacing-md). Defined centrally so the page-header padding token is not
 * redefined inside the consuming component. */
.global-page-header-card-aligned {
  --page-header-container-padding: var(--spacing-rg) var(--spacing-0) var(--spacing-0)
    var(--spacing-md);
}

/* Compact button text (12px) for buttons embedded in dense table headers. */

/* 12px icon for dense table-row action controls. */
.global-icon-xs {
  --image-width: var(--spacing-12);
  --image-height: var(--spacing-12);
}

.global-select-granularity {
  /* Hug the label ("Daily"/"Weekly"/"Group by") instead of a fixed 200px that
     leaves a large empty gap between the text and the chevron. */
  --select-width: max-content;

  /* Match the chevron stroke to the trigger text colour (set just below for
     .select-value/.select-placeholder) so the arrow is not visibly darker. */
  --select-arrow-color: var(--text-color-secondary);
}

/* Global Select trigger text size fix: the bare `span { font-size: var(--font-size-xxs) }`
 * rule in text.css (specificity 0-0-1) overrides the 14px inherited from the library
 * Select container on every span inside a Select trigger. Restore 14px at class
 * specificity (0-1-0) so all library Select trigger text (placeholder and selected value)
 * renders at the intended 14px across the dashboard in both light and dark themes. */

/* JSONForm plain-layout enum fields: the global bare `span` rule in text.css
 * sets font-size to 12px on every span, overriding inheritance from the Select
 * component's 14px container. These selectors restore the intended 14px by
 * matching at class-selector specificity (0-2-0), which beats the bare tag
 * selector (0-0-1). */

/* The library Select renders the multi-select tick as a ☑/☐ glyph inside a bare
 * <span class="select-option-indicator">. The global bare-span rule in text.css
 * forces font-size: 12px on every span, which shrinks the glyph next to the 14px
 * option label; --select-option-gap also defaults to 0, leaving it flush against
 * the text ("□India"). Restore a legible checkbox glyph and a gap so multi-select
 * options read as proper checkboxes. Matches at class specificity (0-1-0), beating
 * the bare tag selector (0-0-1). */
.select-option.multi {
  --select-option-gap: var(--spacing-sm);
}

.global-select-country {
  /* The library draws a 1px divider under the multi-select "Select all" row
   * (border-bottom: var(--select-all-border-bottom, 1px solid #eee)); the
   * Breeze design does not use it, so the variable is cleared here and
   * inherits down to the option rather than fighting the library on
   * selector specificity. */

  /* Cap the select at its field width so the selected-country pills wrap (the
     trigger already sets flex-wrap) instead of the content-sized select growing
     off-screen. max-width (not width) is used because the library's scoped
     `.select { width: max-content }` rule outranks a plain `width` override;
     max-width has no library competitor, so it reliably caps the box. */
  max-width: 100%;
}

.global-select-no-scroll {
  --select-dropdown-max-height: none;
}

/* Library Menu (@juspay/svelte-ui-components) dropdown positioning — anchors the
   panel relative to its trigger, following the .menu-container.<modifier> pattern
   used by .zone-options-menu above. bottom-left is the library default (no class). */
.menu-container.popup-pos-bottom-right .menu-dropdown {
  --menu-dropdown-left: auto;

  right: 0;
}

.menu-container.popup-pos-top-right .menu-dropdown {
  --menu-dropdown-left: auto;
  --menu-dropdown-top: auto;

  right: 0;
  bottom: 100%;
}

.global-dropdown-small {
  --item-padding: var(--spacing-xs) var(--spacing-sm) var(--spacing-xs) var(--spacing-xs);
}

.global-product-widget-remove {
  cursor: pointer;
  padding: var(--spacing-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.2s;

  --image-width: var(--spacing-20);
  --image-height: var(--spacing-20);
}

/* Product Selector Widget */
.global-product-widget-container {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  width: 100%;
}

.global-product-widget-list {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  margin-top: var(--spacing-sm);
}

.global-offer-page-container {
  /* Reserve space for the fixed-position StickyActionBar */
  padding-bottom: var(--spacing-80);
}

/* Offer create sticky action bar + review modal footer — library Button has no
   --button-min-width token; enforce the 140px floor on the inner button element. */

.global-offer-action-button-wrap button {
  min-width: var(--spacing-140);
}

/* Product Selection Modal container */
.global-offer-modal-container {
  position: fixed;
  inset: 0;
  z-index: var(--z-index-portal);
  display: flex;
  align-items: flex-end;
  justify-content: center;

  --modal-height: 100%;
  --modal-content-overflow: hidden;

  /* Footer layout styling */
  --modal-footer-padding: var(--spacing-md);
  --modal-footer-gap: var(--spacing-sm);

  /* Primary button (Add / Publish) */
  --modal-footer-primary-button-width: var(--spacing-140);

  /* Secondary button (Cancel) */
  --modal-footer-secondary-button-width: var(--spacing-140);
}

/* Modal */
.global-modal-container {
  position: fixed;
  inset: 0;
  z-index: var(--z-index-modal);
  display: flex;
  align-items: flex-end;
  justify-content: center;

  --modal-height: 100%;
}

/* Modals that rely on the library Modal's own overlay as their backdrop (rather than
   a .global-modal-container wrapper) opt into the design-system blur with this marker.
   The library overlay dims the background but does not blur it, so re-apply the token. */

/* App-wide standard: bottom-aligned (mobile) library modals keep their content clear
   of the device safe area (home indicator). Every bottom modal inherits this — do NOT
   re-declare it per component. Value lives in theme.css (--modal-bottom-safe-padding). */
.modal.bottom .modal-content {
  padding-bottom: max(
    var(--safe-area-inset-bottom, 0px),
    env(safe-area-inset-bottom, 0px),
    var(--spacing-36)
  );
}

.global-modal-container .modal.bottom .modal-content {
  padding-bottom: max(var(--safe-area-inset-bottom, 0px), env(safe-area-inset-bottom, 0px), 34px);
}

/* ManageItemListModal host — portal-teleported wrapper that owns the single
   backdrop (the library Modal runs showOverlay=false, so it renders no overlay
   of its own). The wrapper z-index inherits the design-system token
   --z-index-modal (10000). --modal-z-index: 1200 cascades into the library
   component so its inner fixed div does not compete with the wrapper. */
.global-item-list-modal-container {
  position: fixed;
  inset: 0;
  z-index: var(--z-index-modal, 10000);
  display: flex;
  align-items: flex-end;
  justify-content: center;

  --modal-z-index: var(--z-modal-layer-1);
}

.global-modal-footer-cta {
  --button-width: 100%;
  --button-padding: var(--spacing-md);
}

.global-modal-actions-split {
  --button-width: 42vw;
  --button-padding: var(--spacing-20, 20px) 0;
}

.global-modal-overflow-visible {
  --modal-overflow-y: visible;
}

.global-modal-content-overflow-visible {
  --modal-content-overflow: visible;
}

/* Force slot-content to column layout so children stretch to full width
   (Modal library defaults slot-content to flex-direction: row) */
.global-offer-modal-container .slot-content {
  flex-direction: column;
}

.global-offer-modal-container.desktop .modal-content {
  width: var(--spacing-800);
  max-width: var(--spacing-800);
}

.global-offer-modal-container.review-modal {
  --modal-height: auto;
  --modal-width: auto;
  --modal-margin: auto;
}

/* ============================================
   CHECKOUT DETAIL PAGE
   ============================================ */

.checkout-detail-columns {
  display: flex;
  gap: var(--spacing-lg);
  align-items: flex-start;
}

.checkout-detail-col-main {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
  flex: 1;
  min-width: 0;
}

.checkout-detail-col-side {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
  width: var(--spacing-320);
  flex-shrink: 0;
}

.checkout-price-grid {
  display: flex;
  gap: var(--spacing-lg);
}

/* ============================================================
   LIBRARY CARD RECIPE — checkout-section (abandoned-checkout detail page)
   Applied via the Card `classes` prop. Reproduces CheckoutCard's
   visual contract: secondary background, muted border, md radius,
   headed header with bottom divider, and a flex-column body with
   spacing-rg gap between rows.
   ============================================================ */
.global-card-checkout-section {
  --card-header-padding: var(--spacing-rg) var(--spacing-lg);
  --card-content-padding: var(--spacing-lg);
}

.global-card-checkout-section .card-content {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-rg);
}

/* LIBRARY CARD RECIPE — breakdown-panel (abandoned-checkout cart-details grid)
   Applied via the Card `classes` prop. Each panel sits in a flex row inside
   checkout-price-grid; the outer wrapper supplies flex:1/min-width:0 sizing.
   ============================================================ */
.global-card-breakdown-panel {
  --card-content-padding: 0;
}

.global-card-breakdown-panel .card-content {
  padding: var(--spacing-rg);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-rg);
}

/* analyticsFilterBar */
.global-select-container-padding {
  --item-padding: var(--spacing-12) var(--spacing-md);
}

.global-filter-bar-spacing {
  margin-top: var(--spacing-lg);
  gap: var(--spacing-md);
}

/* ConnectionErrorState */
.global-button-inverted-bordered {
  width: var(--spacing-200);
  cursor: pointer;
  padding: 20px 0;
}

.global-text-link {
  cursor: pointer;
}

/* Onboarding Status */
.global-onboard-container {
  width: var(--spacing-500);
  margin: 0 auto;
}

.global-text-gray-no-margin {
  margin: 0;
}

/* CopyButton */
.global-copy-message {
  line-height: 1;
  margin: 0;
}

/* Inline ghost variant of the library Button: transparent, borderless,
   zero-padding/auto-height — an icon or text trigger that blends into any
   surface. Pure --button-* var mappings, no hardcoded colors. */
.global-btn-ghost-inline {
  --button-padding: 0;
  --button-height: auto;
}

/* divider */
.global-divider-horizontal {
  margin: var(--horizontal-line-margin);
}

/* Hairline top border, no margin — inline separator between stacked content. */

/* noDataView */

/* processingIndicator */
.global-avatar-icon {
  width: var(--spacing-lg);
  height: var(--spacing-lg);
}

.global-thinking-summary {
  padding-block: var(--spacing-sm);
  box-sizing: border-box;
  margin-bottom: var(--spacing-md);
}

.global-status-text-shimmer {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  margin-right: var(--spacing-xs);
  animation: shimmer 2s linear infinite;
}

.global-status-text-static {
  animation: none;
}

.global-config-container {
  padding: var(--spacing-lg);
}

.global-feature-disabled {
  pointer-events: none;
}

.global-config-divider {
  height: var(--spacing-1);
  margin: 12px 0;
}

.global-config-input-wrapper {
  width: var(--cart-design-input-width);
}

.global-config-row {
  padding: var(--spacing-sm) var(--spacing-0);
}

.global-config-input {
  padding: var(--cart-design-input-padding);
  width: 100%;
  box-sizing: border-box;

  /* Provide a valid placeholder color token so the library Input's
   * ::placeholder { color: var(--input-placeholder-color) } rule resolves
   * correctly instead of falling back to the element's own color. Also set
   * placeholder weight to regular so placeholder is visually lighter than
   * typed text (color-gray-1800) in both light and dark themes. */
}

.global-config-color-box {
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--cart-design-input-padding);
  width: var(--cart-design-input-width);
}

.global-config-color-picker {
  width: var(--cart-design-color-picker-size);
  height: var(--cart-design-color-picker-size);
  padding: var(--spacing-0);
}

.global-config-hex-input {
  flex: 1;
  min-width: 0;

  --input-padding: 0;
  --input-margin: 0;
  --input-height: auto;
}

.global-column-layout-gap-sm {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
}

.global-column-layout-gap-md {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.global-column-layout-gap-lg {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
}

.global-column-layout-gap-xl {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-32);
}

/* insights */
.global-icon-circle {
  width: var(--icon-size-3xl);
  height: var(--icon-size-3xl);
}

.global-content-padding {
  padding: 0 var(--spacing-lg) var(--spacing-md);
}

.global-stat-cards-grid {
  display: grid;
  gap: var(--spacing-20);
  grid-template-columns: repeat(auto-fit, minmax(var(--spacing-250), 1fr));

  --card-width: 100%;
  --custom-card-padding: var(--spacing-20) var(--spacing-lg);
}

.global-download-wrapper {
  max-width: var(--spacing-220);
  margin-right: var(--spacing-32);
}

.global-scrollable-table-full-height {
  --scrollable-table-height: 100%;
}

@media (width <= 768px) {
  .global-flex-column-on-mobile {
    flex-direction: column;
    align-items: stretch;
  }

  .global-download-wrapper {
    max-width: 100%;
    margin-left: 0;
    margin-right: 0;
  }
}

/* =============================================================
   Svelte 5 migration additions
   ============================================================= */

/* @juspay/svelte-ui-components Button wrapper.
 *
 * `.button-container` is both the library Button's own internal element AND a
 * class that feature widgets put on the <div> they wrap a library Button in
 * (e.g. SearchCustomer, UpdateShopName, payment link, migration — 16 call
 * sites) precisely to inject these disabled-state custom properties down into
 * the button. The selector must therefore match the bare class, NOT just the
 * library's `.svelte-4w6aid` hash — scoping it to the hash silently stripped
 * the disabled fill from every wrapper div.
 *
 * Filled buttons signal "disabled" by rendering a faded version of their own
 * fill, so the background falls back to --button-color (the variant's fill)
 * and the whole control is dimmed to 0.4. Fallbacks are semantic tokens —
 * keeps the design system as the single source of truth for color. */
.button-container {
  /* Library Button consumes `border: var(--disabled-border);` (full CSS
   * shorthand). The shorthand is COMPOSED here from two atomic tokens so
   * consumers wanting to tweak just the color (most common case) only
   * touch --button-disabled-border-color, never this composed var. The
   * width and style remain hard-coded because they are constants across
   * every variant in the design system. */
}

/* Button ripple effect */
.global-ripple {
  position: absolute;
  transform: scale(0);
  animation: ripple-in var(--ripple-duration-in) ease-in forwards;
  pointer-events: none;
}

.global-ripple.ripple-out {
  animation: ripple-out var(--ripple-duration-out) ease-out forwards;
}

/* Modal portaling rules consolidated above (lines 2248-2319, 4079-4097) */

/* ---------------------------------------------------------------------------
   DataGrid toolkit area — wrap DataGrid when toolbar search + dense rows apply
   (Placed after base .global-input-field* rules for stylelint specificity order.)
   --------------------------------------------------------------------------- */

.global-datagrid-toolkit-area .datagrid-search-row .global-input-field-box {
  min-height: var(--spacing-40);
  height: var(--spacing-40);
  padding: var(--spacing-12) var(--spacing-md);
}

.global-modal-overflow-visible .global-input-field-container--small,
.global-modal-overflow-visible .global-input-field-container--medium,
.global-modal-overflow-visible .global-input-field-container--large {
  width: 100% !important;
  max-width: 100% !important;
}

/* Toolbar search: InputField size classes use fixed widths — stretch to full row width */
.global-datagrid-toolkit-area .datagrid-search-row .global-input-field-container--small,
.global-datagrid-toolkit-area .datagrid-search-row .global-input-field-container--medium,
.global-datagrid-toolkit-area .datagrid-search-row .global-input-field-container--large {
  width: 100% !important;
  max-width: 100% !important;
}

.global-datagrid-toolkit-area .global-data-grid {
  margin: 0;

  --horizontal-line-grey-margin-top: 0;
  --horizontal-line-grey-margin-bottom: 0;
  --datagrid-cell-min-height: calc(var(--spacing-100) + var(--spacing-xs));
  --padding-offers-table-row: calc(var(--spacing-20) + var(--spacing-2)) var(--spacing-lg);
  --grid-col-width: fit-content;
}

.global-datagrid-toolkit-area .global-data-grid .inner-container {
  margin-top: 0;
}

.global-datagrid-toolkit-area .global-data-grid .grid-row .grid-content:last-child {
  width: calc(var(--spacing-100) + var(--spacing-sm));
  min-width: calc(var(--spacing-100) + var(--spacing-sm));
  max-width: calc(var(--spacing-100) + var(--spacing-sm));
  padding: var(--spacing-12) var(--spacing-lg);
}

.global-datagrid-popup-menu-cell {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}

.global-datagrid-toolkit-area .global-datagrid-popup-menu-cell {
  justify-content: center;
}

.global-datagrid-toolkit-area .global-data-grid .sort-indicator {
  display: none;
}

.global-modal-overflow-visible .global-dd-body {
  z-index: var(--z-index-portal);
}

.global-no-scrollbar {
  scrollbar-width: none;
}

.global-no-scrollbar::-webkit-scrollbar {
  display: none;
}

/* Position, z-index and opacity are owned by the consumer so the same
   visual works for both fixed full-viewport and absolute-inset overlays. */

.global-page-shell {
  position: relative;
  height: 100%;
  width: 100%;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  box-sizing: border-box;
}

.global-page-shell-section {
  padding: var(--spacing-md);
  gap: var(--spacing-md);
  overflow: hidden;
  min-height: 0;
}

.global-centered-column {
  max-width: var(--spacing-800);
  width: 100%;
  margin: 0 auto;
}

.global-centered-column-scroll {
  max-width: var(--spacing-800);
  width: 100%;
  margin: 0 auto;
  min-height: 0;
  overflow-y: auto;
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + var(--spacing-40));
}

/* Base = position + colors + radius + shadow. The -text modifier layers
   typography and a hover lift on top so icon-only consumers can opt out
   without resetting padding/transform. */
.global-fab-pill {
  right: var(--spacing-lg);
  bottom: calc(env(safe-area-inset-bottom, 0px) + var(--spacing-lg));
  cursor: pointer;
}

.global-fab-pill-text {
  padding: var(--spacing-sm) var(--spacing-md) var(--spacing-sm) var(--spacing-12);
  white-space: nowrap;
  transition: transform var(--fade-transition-duration) ease;
}

.global-fab-pill-text:hover,
.global-fab-pill-text:focus-visible {
  transform: translateY(calc(-1 * var(--spacing-1)));
}

/* @juspay/svelte-ui-components Progress — segmented overlay.
   Cuts the continuous library bar into N discrete segments using mask-image on
   the library's internal .track element. Apply via the Progress component's
   `classes` prop. Library code is NOT modified.

   Segment count (N) is supplied per instance as an inline `--progress-segments`
   CSS variable on a host ancestor — the Progress component exposes no `style`
   prop, and custom properties inherit down into .track. The mask calc falls
   back to 12 when no host sets it. Deliberately NOT declared here: a value on
   this selector would land on .container and shadow the host's inherited value,
   forcing every bar to the same count (the bug this dynamic form replaced).

   Depends on library Progress 2.19.x's internal DOM (.container > .track > .bar).
   If the library refactors that structure, this rule must be updated to match
   the new selector path. */
.global-progress-segmented {
  --progress-segment-gap: var(--spacing-1-5);
  --progress-track-height: var(--spacing-12);
  --progress-bar-transition: none;

  /* Restore the vertical breathing room the deleted project ProgressBar
     baked into its own .progress-bar selector. Token comes from theme.css
     (--bar-vertical-margin: 16px default). Per-widget overrides set this
     CSS var on an ancestor — see SubscriptionPlanProgress's .progress-card. */
  margin-block: var(--bar-vertical-margin);
}

.global-progress-segmented .track {
  /* stylelint-disable-next-line property-no-vendor-prefix -- no autoprefixer in the pipeline; -webkit- is required for Safari <15.4 / Chrome <120, where unprefixed mask-image is unsupported and segmentation would silently degrade to a continuous bar */
  -webkit-mask-image: repeating-linear-gradient(
    to right,
    black 0,
    black calc(100% / var(--progress-segments, 12) - var(--progress-segment-gap)),
    transparent calc(100% / var(--progress-segments, 12) - var(--progress-segment-gap)),
    transparent calc(100% / var(--progress-segments, 12))
  );
  mask-image: repeating-linear-gradient(
    to right,
    black 0,
    black calc(100% / var(--progress-segments, 12) - var(--progress-segment-gap)),
    transparent calc(100% / var(--progress-segments, 12) - var(--progress-segment-gap)),
    transparent calc(100% / var(--progress-segments, 12))
  );
}

/* Equivalent of the deleted project ProgressBar's `enableDivider: false` mode:
   render as one fused bar by setting the gap width to 0. Use composed with
   `.global-progress-segmented`. */
.global-progress-no-gap {
  --progress-segment-gap: var(--spacing-0);
}

/* Segmented pill recipe for library Tabs (analogous to .global-progress-segmented above).
   Apply via Tabs classes="global-tabs-segmented". Themes the library component into the
   project's boxed-pill segmented look using only --tabs-* vars wired to semantic tokens.
   NO raw hex — all values reference palette tokens from theme.css :root / [theme='dark'].
   The underline indicator is hidden (height→0); each item gets pill border-radius;
   the active pill rises to the secondary surface with primary text.
   INTERIM: a first-class variant="segmented" is being added to library Tabs; once it
   publishes, fold these consumers onto it and delete this recipe. */
.global-tabs-segmented {
  --tabs-bar-padding: var(--spacing-2);
  --tabs-bar-gap: var(--spacing-xs);
  --tabs-item-padding: var(--spacing-sm) var(--spacing-12);
  --tabs-indicator-height: 0px;
}

/* Library Tabs — sidebar pill/chip fill model (no bottom indicator). Drives the
   sidebar nav tabs off sidebar semantic tokens; apply via Tabs classes="global-tabs-sidebar".
   Replaces the former per-component :global(.sidebar-lib-tabs) override in SideBar.svelte. */
.global-tabs-sidebar {
  --tabs-bar-padding: var(--spacing-xs);
  --tabs-bar-gap: 0;
  --tabs-item-padding: 2px var(--spacing-sm);
  --tabs-indicator-height: 0;
  --tabs-transition: background 0.2s ease, color 0.2s ease;
}

/* Standard (underline) tabs render their label inside a data-pw <span>, which the
   global `span` rule would shrink to --font-size-xxs (12px) — smaller than no-snippet
   tabs, which render a raw text node at the library's .tabs-item size (14px). Inherit
   the tab's own size so every standard tab matches, regardless of how its label is
   rendered. Segmented/sidebar variants opt out: they style their inner spans on purpose. */
.tabs-wrapper:not(.global-tabs-segmented):not(.global-tabs-sidebar) .tabs-item span {
  font-size: inherit;
}

.global-phone-shell {
  overflow: hidden;
}

.global-overflow-hidden {
  overflow: hidden;
}

.global-color-picker-row {
  /* The library swatch Button is border-box, so pin --button-height to 38px to
   * sit flush with the hex Input's border-box 38px (its default renders 40px,
   * protruding 2px past the input). */
  --button-height: 38px;

  display: flex;
  align-items: center;
}

/* The library Input inside the color picker reserves a bottom margin for its
   validation-message slot, which inflates the hex-input cell taller than the
   38px swatch button — so the swatch floats above the input instead of sitting
   flush beside it. The picker shows no message here, so collapse that margin to
   align the swatch and hex input as one control. */
.global-color-picker-row .input-container.color-picker-text-input {
  margin-bottom: 0;
}

.global-typing-loader {
  --loading-dots-gap: var(--spacing-xs);
}

/* Pill status recipe — replaces the deleted project tag component. Each
   global-pill-<type> maps a BadgeType status to the library Pill's color vars.
   Default shape (font-size, padding, border-radius=16px, cursor, dismiss-color)
   is set in :root in theme.css. Color stays per-status here.
   global-pill-sm overrides border-radius to var(--radius-full) for callsites
   that were originally fully-rounded (e.g. wallet RewardRulesView). */

.global-pill-subtle {
  --pill-padding: 0;
}

/* Elevates a library Modal to z-index 1200 for contexts where the default
   z-index (15) is insufficient, e.g. inside portal-mounted overlays. */
.global-popup-z-1200 {
  --modal-z-index: var(--z-modal-layer-1);
}

/* Library Modal for the settings-page reinstall confirmation. Adds a secondary
   border to both footer buttons to match the original .reinstall-popup style. */

/* Library Modal wrapper for danger-action confirmation dialogs.
   Sets the primary footer button to the danger (red) color and removes its border,
   matching the old Popup component's .delete-popup CSS-variable pattern. */
.global-popup-danger-modal {
  /* The library Modal's secondary (Cancel) button falls back to a hardcoded
     #3a4550, invisible on a dark modal surface. Render it as an outlined button
     (transparent fill + semantic border + primary text) so it reads clearly in
     both light and dark themes. */
}

/* The library Modal scopes --button-color per footer button container but never
   sets --button-hover-color or --button-hover-text-color. Without these, the :root
   primary-button defaults (blue bg, white text) leak into every footer button on
   hover. These rules restore the correct hover appearance for each button role. */

/* Danger modals: primary button is red at rest — keep red on hover, no blue flash. */

/* Subheading text inside a library Modal used as a confirmation popup.
   Equal padding on all sides gives the header's bottom divider breathing room below
   it — the header padding already spaces it above — so the divider isn't flush against
   this text. No typography props set — inherits from the <p> semantic tag in text.css. */
.global-popup-subheading {
  margin: 0;
  padding: var(--spacing-rg);
}

/* ── Library Menu theming for row-action popovers ───────────────────────────
 *
 * .global-row-action-menu          — base recipe (emphasis item tone)
 * .global-row-action-menu-secondary — secondary item tone (shipping accordion)
 *
 * Apply the class via `classes="global-row-action-menu"` on the library <Menu>.
 * Item color is the only distinction between the two variants; all structural
 * tokens (z-index, background, border, shadow, padding, danger colours) are
 * shared and defined once here.
 * ─────────────────────────────────────────────────────────────────────────── */
.global-row-action-menu {
  --menu-z-index: 1100;
  --menu-min-width: var(--spacing-200);
  --menu-padding: var(--spacing-xs) 0;
  --menu-item-icon-width: var(--spacing-md);
  --menu-item-icon-height: var(--spacing-md);
}

/* Secondary-tone variant: item labels use the muted secondary text token
 * (equivalent to the old RowActionsMenu menuItemLabelTone="secondary"). */

/* ── Row-action trigger recipes (library Button) ─────────────────────────────
 *
 * .global-row-action-trigger          — small 28 × 28 icon button (default)
 * .global-row-action-trigger-datagrid — wider pill variant for DataGrid cells
 *
 * Applied via the `classes` prop on the library <Button> (which renders them on
 * its .button-container). Theming is done entirely through the library Button's
 * CSS-variable interface so no per-callsite styles are needed: transparent
 * icon-only buttons with a neutral-subtle hover.
 * ─────────────────────────────────────────────────────────────────────────── */
.global-row-action-trigger {
  --button-width: var(--spacing-28);
  --button-height: var(--spacing-28);
  --button-padding: 0;
  --image-width: var(--spacing-20);
  --image-height: var(--spacing-20);
}

.global-row-action-trigger-datagrid {
  --button-width: auto;
  --button-height: var(--button-height-md);
  --button-padding: var(--spacing-12) var(--spacing-rg);
  --image-width: var(--icon-size-lg);
  --image-height: var(--icon-size-lg);
}

/* Preserve the original min-width floor for the datagrid pill variant; the
 * library Button has no --button-min-width var, so target its inner button. */
.global-row-action-trigger-datagrid button {
  min-width: var(--spacing-52);
}

/* Pill-shaped search bar wrapping a library Input component.
   Used in the AI chats and reports sidebars. The Input is rendered
   in "ghost" mode (transparent, no border/shadow/radius) so only the
   outer pill container provides the visual chrome.
   Background uses --bg-color-secondary so it auto-themes (white in
   light, #121212 in dark) without any hardcoded hex. */
.global-search-bar {
  gap: var(--spacing-sm);
  padding: var(--spacing-12) var(--spacing-md);
  box-sizing: border-box;
}

/* Sets CSS custom properties on the library Input so it renders as
   a transparent ghost field inside the pill — no background, border,
   shadow, or radius of its own. */
.global-search-bar-input {
  flex-grow: 1;
  min-width: 0;

  --input-padding: 0;
  --input-margin: 0;
  --input-height: auto;
  --input-container-margin: 0;
  --input-container-padding: 0;
}

/* Library Sheet used as a right-side report/progress panel.
   Applied via classes="global-report-sheet" on every Sheet that renders a report or
   progress panel in panel mode. Centralises all Sheet CSS-variable overrides so they
   are defined once and reused across AnalyticsReportModal and ProgressDetailsModal. */
.global-report-sheet {
  /* Bespoke-only. The shared Sheet look — title colour/size/weight, header/content/
     footer padding, and theme-aware default background + borders — now comes from the
     --sheet-* base in theme.css (:root). These overrides are the report panel's
     AI-specific surface (custom width, AI background, light AI border, elevated z-index). */
  --sheet-width: var(--report-panel-width, min(50vw, 600px));
  --sheet-z-index: 1050;
}

/* Highcharts layout overrides inside a .global-report-sheet panel.
   Forces charts to fill the panel's single-column width and keeps sticky headings
   positioned correctly relative to the scrollable content area. */
.global-report-sheet .sheet-content .sticky-section-heading,
.global-report-sheet .sheet-content .global-charts-header {
  top: calc(-1 * var(--spacing-lg));
  z-index: 5;
}

.global-report-sheet .sheet-content .global-charts-grid {
  flex-direction: column;
  gap: var(--spacing-md);
}

.global-report-sheet .sheet-content .global-chart-card-dark {
  width: 100%;
  min-width: 0;
  overflow: hidden;
}

.global-report-sheet .sheet-content .global-chart-card-dark > div {
  width: 100%;
  min-width: 0;
}

.global-report-sheet .sheet-content .highcharts-container,
.global-report-sheet .sheet-content .highcharts-root {
  width: 100%;
  max-width: 100%;
}

/* WebCamera modal — full-viewport solid backdrop with camera UI centered.
   Uses showOverlay=true so the outer .modal div is pointer-events:auto and receives
   the background color. --background-color overrides the library default (#00000066)
   with the solid design-system surface color so the camera fills the whole screen.
   The modal-content wrapper is transparent so only the camera box floats on top. */
.webcamera-modal {
  --modal-z-index: var(--z-modal-fullscreen);
  --modal-width: 100vw;
  --modal-height: 100vh;
  --modal-overflow-y: hidden;
  --modal-display: flex;
}

/* The library Tooltip renders its label as <span class="tooltip-text"> and relies on the
   span inheriting the bubble's light color. The dashboard's global `span { color }` rule
   (text.css) sets an explicit theme-following color on every span, which wins over the
   inherited value — so in light theme the label rendered dark-on-dark and was invisible.
   Pin the label to the bubble's text color (white in both themes, since the bubble stays
   dark in both) so it matches the original project tooltip. */

/* The library bubble is position:absolute with no explicit width, so its shrink-to-fit
   width is constrained by the narrow trigger container (often just the info icon) and
   collapses long text to roughly one word per line. The original project tooltip was
   position:fixed, so its max-width applied against the viewport and text wrapped normally.
   Size the bubble to its content (still capped by --tooltip-max-width) to restore that. */
.tooltip-bubble {
  width: max-content;
}

/* Vertically centre the label and its info icon. The library .tooltip-container is
   inline-flex with no align-items (defaults to stretch), so the icon rode the top of
   the taller text line instead of its optical centre. */
.tooltip-container {
  align-items: center;
}

/* The info-icon trigger sits immediately after its label (inside the tooltip for the
   text-triggered callsites, or beside a sibling title for the icon-only ones). The old
   project tooltip spaced the icon with margin-left: var(--spacing-sm); keep that gap so
   the glyph never touches the preceding text, and centre the glyph within its box. */
.tooltip-trigger {
  display: inline-flex;
  align-items: center;
  margin-left: var(--spacing-sm);

  --image-width: 14px;
  --image-height: 14px;
}

/* Select trigger with a leading download-report icon.
 * The background-image approach embeds the SVG at its original fill (#525252),
 * which is invisible in dark mode. Instead, use a mask-image pseudo-element
 * with a colour token so the icon adapts to light/dark mode — same technique
 * as the existing progress-segment recipe. -webkit-mask-* prefixes are kept
 * for Safari <15.4 / Chrome <120 compatibility. */
.global-select-download {
  /* Reserve 36px on the left for the ::before download icon.
   * Using the CSS variable (not a direct padding-left override) ensures
   * the library's Svelte-scoped trigger rule picks up this value
   * instead of falling back to its default 12px left padding. */
  --select-trigger-padding: var(--spacing-sm) var(--spacing-12) var(--spacing-sm) var(--spacing-36);
}

.global-select-download .select-trigger {
  position: relative;
}

.global-select-download .select-trigger::before {
  content: '';
  position: absolute;
  left: var(--spacing-12);
  top: 50%;
  transform: translateY(-50%);
  width: var(--spacing-md);
  height: var(--spacing-20);

  /* stylelint-disable-next-line property-no-vendor-prefix -- no autoprefixer in the pipeline; -webkit- is required for Safari <15.4 / Chrome <120 */
  -webkit-mask-image: url('/icons/download-report.svg');
  mask-image: url('/icons/download-report.svg');

  /* stylelint-disable-next-line property-no-vendor-prefix -- no autoprefixer in the pipeline; -webkit- is required for Safari <15.4 / Chrome <120 */
  -webkit-mask-size: contain;
  mask-size: contain;

  /* stylelint-disable-next-line property-no-vendor-prefix -- no autoprefixer in the pipeline; -webkit- is required for Safari <15.4 / Chrome <120 */
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;

  /* stylelint-disable-next-line property-no-vendor-prefix -- no autoprefixer in the pipeline; -webkit- is required for Safari <15.4 / Chrome <120 */
  -webkit-mask-position: center;
  mask-position: center;
}

/* Button icon rendered as a trailing element (after the text label).
 * The library Button default places the icon snippet first (order 2) and
 * the text second (order 3). Setting --button-icon-order to 4 moves the
 * icon after the text without changing any other layout. */
.global-button-trailing-icon {
  --button-icon-order: 4;
}

/* Generic modifier: renders the first option of a Select as disabled.
 * Library gap — SelectItem has no disabled flag (library PR queued); until
 * then this is the only way to show a non-functional leading option (e.g.
 * the mandate page's "Platform Order ID", which is display-only). */
.global-select-first-option-disabled .select-dropdown .select-option:first-child {
  pointer-events: none;
  cursor: not-allowed;
}

/* LIBRARY CARD RECIPES — batch 1.
   --card-border / --card-border-radius are NOT overridden: theme.css :root already
   defines both (the same values the project Card consumed), and the library Card
   reads the same variable names, so inheriting them preserves pixel parity. */

/* Activity row: used by StepCard (circleBasedProgress=true branch).
   No border, no shadow, secondary bg — matches the former --card-* overrides
   on .activity-content. Consumer .step-activity-body wrapper handles layout. */
.global-card-activity-row {
  --card-content-padding: 0;
}

/* LIBRARY CARD RECIPES — batch 2 (wallet) */

/* Stat cards on /mandate/upcoming — same primary bg, different padding */
.global-card-mandate-upcoming-stat {
  --card-content-padding: var(--spacing-20) 0 var(--spacing-20) var(--spacing-lg);
}

/* Inner-panel cards on /mandate/order/[id] and /mandate/subscription/[id] —
   unified to standard card appearance (inherits bg/border/radius from :root).
   Content padding stays zero because the wrapper divs (.card-left / .card-right /
   .card-top-right) already carry their own structural padding. */
.global-card-mandate-inner-panel {
  --card-content-padding: 0;
}

/* ============================================================
   LIBRARY CARD RECIPES — batch 5 (settings-integration-platform-jsonform)
   All recipes apply classes="" on library Card from @juspay/svelte-ui-components.
   Doctrine: --card-border and --card-border-radius are auto-inherited from theme.css :root.
   Box-shadow has no library hook so is applied directly on the recipe class (doctrine rule 2).
   ============================================================ */

/* TOGGLE: settings page go-live and international-checkout cards */
.global-card-settings-integration-platform-jsonform-toggle {
  --card-content-padding: var(--card-icon-header-padding);
}

/* PLATFORM: clickable platform image tile cards (wrapper carries onclick).
   display:flex + flex-direction:column lets .card-content (library internal) stretch
   to full tile height, so platform-center can vertically center the logo. */
.global-card-settings-integration-platform-jsonform-platform {
  display: flex;
  flex-direction: column;

  --card-content-padding: 0;

  width: 100%;
  height: 100%;
}

.global-card-settings-integration-platform-jsonform-platform .card-content {
  flex: 1;
}

/* SVG/raster logo inside the platform tile — constrain to the logo box. */
.global-card-settings-integration-platform-jsonform-platform .platform-center svg,
.global-card-settings-integration-platform-jsonform-platform .platform-center img {
  max-width: var(--spacing-160);
  max-height: var(--spacing-110);
  object-fit: contain;
}

/* JSONFORM: card-layout JSONForm field cards (width 100%, content padding from token) */
.global-card-settings-integration-platform-jsonform-jsonform {
  --card-content-padding: var(--card-padding-expanded);

  width: 100%;
}

/* Delete button inside integration icon-card header — zero chrome, just the icon. */

/* Settings script-attributes editor: bare ✕ remove button (library Button via classes) */
.global-settings-script-attr-remove {
  --button-padding: 0 var(--spacing-sm);

  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.global-icon-card-action-btn {
  padding: 0;
  cursor: pointer;
}

/* Delete icon image inside the action button — circular padded surface. */
.global-icon-card-action-img {
  padding: var(--spacing-12);

  --image-width: auto;
  --image-height: auto;
}

/* Cross-sell base-variant multi-select. Reproduces the retired select-compat
   patch UX on the library Select via optionIndicator + bottomContent snippets:
   per-option checkboxes, an "All" toggle, and a "Select (N)" close button.
   Checkbox visuals reuse the design-system checkbox tokens so light/dark flip
   automatically. The library has no top slot, so the "All" toggle groups with
   the close button in bottomContent rather than sitting above the options. */
/* Selects whose dropdown panel should size to its widest option instead of the
   library default (which pins the panel to the trigger width and then clips
   longer labels — e.g. SCHEDULED / EXPIRED — behind a horizontal scrollbar).
   Single shared knob for the filter-bar selects and the download select; the
   library's inner list already defaults --select-dropdown-min-width to 100%, so
   no second override is needed. */
.global-select-filter,
.global-select-download {
  --select-dropdown-width: max-content;
}

/* Form-field selects fill their column like the InputFields beside them. The
   theme default --select-width is max-content (content-width, for filters /
   toolbars); this single utility restores 100% for a labelled form Select.
   Apply via the library Select's `classes` prop: a directly-set custom property
   on the `.select` element overrides the inherited :root max-content default.
   Usage: <Select classes="global-select-full-width" ... /> */
.global-select-full-width {
  --select-width: 100%;
}

.global-select-variant-picker {
  --select-option-gap: var(--spacing-sm);
}

.global-select-variant-picker-checkbox {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  inline-size: var(--checkbox-size);
  block-size: var(--checkbox-size);
}

.global-select-variant-picker-checkbox.checked::after {
  content: '';
  inline-size: var(--spacing-xs);
  block-size: var(--spacing-sm);
  transform: translateY(calc(-1 * var(--spacing-1))) rotate(45deg);
}

.global-select-variant-picker-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
}

.global-select-variant-picker-all {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: 0;
  cursor: pointer;
}

.global-select-variant-picker-apply {
  padding: var(--spacing-xs) var(--spacing-12);
  cursor: pointer;
}

/* Page-header → Tabs gap — use this wrapper on any page that places a Tabs bar
   directly beneath a PageHeader, so the spacing is driven by a single token. */
.global-page-tabs-wrapper {
  margin-top: var(--page-section-tabs-margin-top);
}

/* ── FileInput shared layout helpers ────────────────────────────────────────
   These accompany the FileInput library recipes and are used by callsites
   that need a logo preview tile next to the upload button.
   ─────────────────────────────────────────────────────────────────────────── */

/* Row that pairs a logo preview tile with a FileInput button */
.global-fileinput-preview-row {
  display: grid;
  column-gap: 5%;
  grid-template-columns: 0.45fr 0.55fr;
}

/* Logo preview tile — shows the current image or a placeholder background */
.global-fileinput-preview-tile {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--button-padding);
  height: var(--spacing-60);
}

/* Image inside the preview tile */
.global-fileinput-preview-img {
  object-fit: contain;
  max-width: 100%;
  max-height: 100%;
}

/* ── FileInput library recipes ──────────────────────────────────────────────
   Usage: pass via the `classes` prop on <FileInput> from @juspay/svelte-ui-components.
   The library applies these classes to its outer .file-input wrapper which
   drives all --file-input-* CSS variables used internally.
   ──────────────────────────────────────────────────────────────────────────── */

/* Dropzone variant — full-width centred drop zone used for CSV/PDF uploads */
.global-fileinput-dropzone {
  --file-input-display: flex;
  --file-input-flex-direction: column;
  --file-input-align-items: center;
  --file-input-justify-content: center;
  --file-input-padding: var(--spacing-32) var(--spacing-lg);
  --file-input-gap: var(--spacing-xs);
  --file-input-text-align: center;
  --file-input-transition: border-color 0.15s ease, background-color 0.15s ease;

  width: 100%;
}

/* Dropzone on a secondary surface (inside a card/modal) */

/* ── Dropzone trigger internals ─────────────────────────────────────────────
   These are the children rendered inside the .global-fileinput-dropzone trigger
   snippet. They must be global because the snippet markup lives in callsite files. */

/* Wrapper for the upload icon in a dropzone trigger */
.global-fileinput-dropzone-icon {
  width: var(--spacing-32);
  height: var(--spacing-32);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Upload icon image inside a dropzone trigger */
.global-fileinput-dropzone-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Hint / meta text inside the dropzone trigger */
.global-fileinput-dropzone-meta {
  margin: 0;
}

/* Inner button that fills the dropzone area — strips browser button defaults so
   the entire dropzone surface is clickable (used in AddCustomerModal file upload). */
.global-fileinput-dropzone-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-sm);
  width: 100%;
  cursor: pointer;
  padding: 0;
}

/* ── Inner trigger button rendered inside .global-fileinput-button — fills the wrapper,
   strips browser button defaults, and forwards the hover/focus ring to the wrapper. */
.global-fileinput-trigger-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-xs);
  width: 100%;
  height: 100%;
  cursor: pointer;
  padding: 0;
}

/* Button variant — dashed primary button used for generic file selection */
.global-fileinput-button {
  --file-input-display: inline-flex;
  --file-input-flex-direction: row;
  --file-input-align-items: center;
  --file-input-justify-content: center;
  --file-input-padding: 0;
  --file-input-gap: var(--spacing-xs);
  --file-input-text-align: center;
  --file-input-transition: transform 0.2s ease-in-out;

  width: 100%;
  height: var(--spacing-60);
}

/* Inner button for logo-tile — fills wrapper, strips browser defaults */
.global-fileinput-logo-tile-btn {
  padding: 0;
  cursor: pointer;
  box-sizing: border-box;
}

/* Hover overlay label on top of logo preview */
.global-fileinput-logo-overlay {
  transition: opacity 0.15s ease;
}

/* Logo-tile variant — fixed-size image tile with hover-overlay used for logo uploads */
.global-fileinput-logo-tile {
  --file-input-display: inline-flex;
  --file-input-flex-direction: column;
  --file-input-align-items: center;
  --file-input-justify-content: center;
  --file-input-padding: var(--spacing-xs) var(--spacing-md);
  --file-input-gap: 0;
  --file-input-text-align: center;
  --file-input-transition: none;

  box-sizing: border-box;
  width: var(--spacing-150);
  height: var(--spacing-48);
  overflow: hidden;
  position: relative;
}

/* ============================================================
   LIBRARY DateRangePicker RECIPES — dashboard-wide
   All classes land on the library DateRangePicker root via
   the `classes` prop. Token values live in theme.css :root
   and [theme='dark']. No raw hex, no font overrides.
   ============================================================ */

/* Standard range picker used on analytics / orders / wallet pages.
   Matches the min-height and spacing of the project's calendar-trigger. */
.global-daterange-standard {
  min-height: var(--spacing-40);

  /* The library forces the trigger to min-width 200px; our triggers are
     content-sized (e.g. "Today"), so the 200px floor left a large dead gap
     between the date pickers. Size the trigger to its content instead. */
  --drp-trigger-min-width: fit-content;

  /* Give the open panel ~140px headroom over the global 800px max so the
     preset sidebar + calendar don't read as congested. */
  --drp-panel-max-width: 960px;
}

/* Shared date-range trigger content (calendar icon + label + chevron) so every
   date picker reads as the same control across pages (analytics, supercoins, …). */
.global-daterange-trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-sm);
}

.global-daterange-trigger img {
  width: var(--spacing-md);
  height: var(--spacing-md);
  flex-shrink: 0;
}

.global-daterange-trigger img.global-daterange-trigger-chevron {
  width: calc(var(--spacing-sm) + var(--spacing-xs));
  height: calc(var(--spacing-sm) + var(--spacing-xs));
}

/* The library bridges --drp-trigger-* onto the trigger Button's --button-* vars but
   not the hover background, so the trigger inherited the global --button-hover-color
   (accent blue) and flashed blue on hover. Pin the trigger's hover background to its
   resting background so hovering changes nothing. Scoped to the trigger wrapper so
   the panel's Apply/Cancel buttons keep their own hover styling. */

/* Layout wrapper for two adjacent DateRangePicker components (e.g. primary date +
 * compare date on the analytics filter bar). Each picker renders as its own
 * standalone pill (same as a single picker elsewhere) with a gap between them.
 *
 * Usage: <div class="global-daterange-pair">
 *          <DateRangePicker classes="global-daterange-standard" ... />
 *          <DateRangePicker classes="global-daterange-standard" ... />
 *        </div>
 *
 * No outer border, divider, or `overflow: hidden` here: clipping the overflow
 * would hide the absolutely-positioned dropdown panel, and the joined-frame
 * treatment is intentionally dropped in favour of two distinct buttons. */
.global-daterange-pair {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-sm);
}

/* Compact time-of-day fields shown beside the primary date dropdown on the analytics
 * filter bar (From time / To time). Each library Input is pinned to a compact width and
 * the default validation-message gap below the field is removed so the fields line up
 * flush with the date dropdown instead of reserving an empty error row.
 *
 * Usage: <div class="global-filter-time-pair">
 *          <div class="global-filter-time-field"><Input ... /></div>
 *          <div class="global-filter-time-field"><Input ... /></div>
 *        </div>
 */
.global-filter-time-pair {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-sm);
}

.global-filter-time-field {
  --input-container-width: var(--spacing-140);
  --input-container-margin: var(--spacing-0);

  /* Read as a sibling of the date dropdown: same border, radius and height. */
  --input-height: var(--spacing-40);
}

/* Bare preset-group dividers — opt-in alongside .global-daterange-standard for
   pickers whose presets carry group keys (the analytics filters). The in-house
   picker separated preset clusters (intraday · single days · multi-day ranges ·
   calendar periods) with a plain rule. The library splits each divider into two
   short leaders around a centred group key; hide the key and expand the first
   leader into a single continuous line. The .drp-root/.drp-panel chain outweighs
   the library's :has()-based internal rules so the override actually lands. */
.global-daterange-grouped.drp-root .drp-panel .drp-preset-group-label {
  display: none;
}

.global-daterange-grouped.drp-root .drp-panel .drp-preset-divider::before {
  width: auto;
  flex: 1 1 auto;
}

.global-daterange-grouped.drp-root .drp-panel .drp-preset-divider::after {
  display: none;
}

/* Single-date variant — used on GrantPointsModal and JSONForm.
   Makes the trigger full-width inside its parent. */
.global-daterange-single {
  display: block;
  width: 100%;
}

.global-daterange-single .drp-trigger-wrapper {
  width: 100%;
}

/* Centre each dual-month calendar label over its month. The library nests the
   prev/next nav buttons in the same flex row as the two labels and distributes them
   with space-around, which insets the label band ~40px from the calendars below and
   pulls both labels toward the centre (the left label sat right of its grid, the
   right label left of its grid). Take the nav buttons out of flow so the label band
   spans the full calendar width, then give each label an equal share with the
   calendars' own gap so it lines up with its month. Scoped to .drp-root so it only
   affects dual-month pickers — the .drp-dual-header element only exists there. */
.drp-root .drp-dual-header {
  position: relative;
  min-height: var(--drp-nav-btn-size, 32px);
}

.drp-root .drp-dual-header .drp-nav-btn {
  position: absolute;
  top: 50%;
  z-index: 1;
  transform: translateY(-50%);
}

.drp-root .drp-dual-header .drp-nav-btn:first-of-type {
  left: 0;
}

.drp-root .drp-dual-header .drp-nav-btn:last-of-type {
  right: 0;
}

.drp-root .drp-dual-month-labels {
  gap: var(--drp-months-gap, 24px);
}

.drp-root .drp-month-label {
  flex: 1;
  text-align: center;
}

/* Two-column sticky-sidebar layout recipe — replaces OfferPageLayout two-col branch.
   Used by offer create/edit/gift pages and mandate create/edit pages. */
.global-offer-two-col-layout {
  display: flex;
  flex-flow: row nowrap;
  flex: 1 1 auto;
  gap: var(--spacing-32);
  min-height: 0;
}

.global-offer-two-col-form {
  flex: 1 1 0;
  min-width: var(--spacing-400);

  --input-container-margin: 0;
}

.global-offer-two-col-sidebar {
  width: var(--spacing-360);
  flex: 0 0 var(--spacing-360);
  min-width: 0;
  align-self: flex-start;
  position: sticky;
  top: var(--spacing-32);
}

@media (width <= 1200px) {
  .global-offer-two-col-sidebar {
    width: var(--spacing-300);
    flex: 0 0 var(--spacing-300);
  }
}

@media (width <= 900px) {
  .global-offer-two-col-sidebar {
    width: var(--spacing-280);
    flex: 0 0 var(--spacing-280);
  }
}

@media (width <= 768px) {
  .global-offer-two-col-layout {
    flex-direction: column;
  }

  .global-offer-two-col-sidebar {
    width: 100%;
    flex: 0 0 auto;
  }
}

/* Single-column detail layout recipe — replaces OfferPageLayout detail-layout branch.
   Used by shop/offers/[offerId] page (no sidebar). */
.global-offer-detail-layout {
  display: flex;
  flex-direction: column;
  flex: 1;

  --container-padding: var(--spacing-0);
  --page-header-container-padding: var(--spacing-0);
  --action-bar-left-offset: var(--spacing-0);
}

/* GradientBlur — progressive 8-layer backdrop-filter blur for chat header */
.gradient-blur {
  position: absolute;
  z-index: 2;
  inset: 0;
}

.gradient-blur > div,
.gradient-blur::before,
.gradient-blur::after {
  position: absolute;
  inset: 0;
}

.gradient-blur::before {
  content: '';
  z-index: 30;
  mask: linear-gradient(
    to top,
    rgb(0 0 0 / 0%) 0%,
    rgb(0 0 0 / 100%) 12.5%,
    rgb(0 0 0 / 100%) 25%,
    rgb(0 0 0 / 0%) 37.5%
  );
}

.gradient-blur > div:nth-of-type(1) {
  z-index: 32;
  mask: linear-gradient(
    to top,
    rgb(0 0 0 / 0%) 12.5%,
    rgb(0 0 0 / 100%) 25%,
    rgb(0 0 0 / 100%) 37.5%,
    rgb(0 0 0 / 0%) 50%
  );
}

.gradient-blur > div:nth-of-type(2) {
  z-index: 33;
  mask: linear-gradient(
    to top,
    rgb(0 0 0 / 0%) 25%,
    rgb(0 0 0 / 100%) 37.5%,
    rgb(0 0 0 / 100%) 50%,
    rgb(0 0 0 / 0%) 62.5%
  );
}

.gradient-blur > div:nth-of-type(3) {
  z-index: 34;
  mask: linear-gradient(
    to top,
    rgb(0 0 0 / 0%) 37.5%,
    rgb(0 0 0 / 100%) 50%,
    rgb(0 0 0 / 100%) 62.5%,
    rgb(0 0 0 / 0%) 75%
  );
}

.gradient-blur > div:nth-of-type(4) {
  z-index: 35;
  mask: linear-gradient(
    to top,
    rgb(0 0 0 / 0%) 50%,
    rgb(0 0 0 / 100%) 62.5%,
    rgb(0 0 0 / 100%) 75%,
    rgb(0 0 0 / 0%) 87.5%
  );
}

.gradient-blur > div:nth-of-type(5) {
  z-index: 36;
  mask: linear-gradient(
    to top,
    rgb(0 0 0 / 0%) 62.5%,
    rgb(0 0 0 / 100%) 75%,
    rgb(0 0 0 / 100%) 87.5%,
    rgb(0 0 0 / 0%) 100%
  );
}

.gradient-blur > div:nth-of-type(6) {
  z-index: 37;
  mask: linear-gradient(
    to top,
    rgb(0 0 0 / 0%) 75%,
    rgb(0 0 0 / 100%) 87.5%,
    rgb(0 0 0 / 100%) 100%
  );
}

.gradient-blur::after {
  content: '';
  z-index: 38;
  mask: linear-gradient(to top, rgb(0 0 0 / 0%) 87.5%, rgb(0 0 0 / 100%) 100%);
}

/* iPhone X device-frame mockup — recipe replacement for src/lib/components/Preview.
   Used by ConfigController to show a static demo image inside a phone shell.
   Child elements: <i> renders the speaker bar, <b> renders the camera dot. */
.global-device-frame-iphone {
  position: relative;
  margin-left: var(--spacing-rg);
  width: 95%;
  height: 100%;
}

.global-device-frame-iphone::before,
.global-device-frame-iphone::after {
  content: '';
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

.global-device-frame-iphone::after {
  bottom: var(--spacing-sm);
  width: var(--spacing-140);
  height: var(--spacing-xs);
}

.global-device-frame-iphone::before {
  top: 0;
  width: 56%;
  height: var(--spacing-32);
}

.global-device-frame-iphone i,
.global-device-frame-iphone b {
  position: absolute;
  display: block;
}

.global-device-frame-iphone i {
  top: 0;
  left: 50%;
  transform: translate(-50%, var(--spacing-sm));
  height: var(--spacing-sm);
  width: 15%;
}

.global-device-frame-iphone b {
  left: 10%;
  top: 0;
  transform: translate(var(--spacing-180), var(--spacing-xs));
  width: var(--spacing-12);
  height: var(--spacing-12);
}

.global-device-frame-iphone b::after {
  content: '';
  position: absolute;
  width: var(--spacing-sm);
  height: var(--spacing-sm);
  top: var(--spacing-xs);
  left: var(--spacing-xs);
}

.global-device-frame-media {
  --image-width: 100%;
  --image-height: auto;
  --image-margin: var(--spacing-2) 0;
}

.global-device-frame-no-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  gap: var(--spacing-xs);
  padding: var(--spacing-lg);
}

/* Account-settings dropdown: absolute panel anchored below the app top bar.
   Used by (app)/+layout.svelte after SettingsPanel component elimination. */
.account-settings-backdrop {
  position: fixed;
  inset: 0;
  z-index: 999;
}

.account-settings-panel {
  position: absolute;
  top: var(--app-top-bar-height, var(--spacing-56));
  right: var(--spacing-md);
  width: var(--spacing-320);
  z-index: 1000;
  overflow: visible;
}

.account-settings-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--padding-input-secondary);
}

.account-settings-close {
  cursor: pointer;
  padding: 0 var(--spacing-sm);
  display: inline-flex;
  align-items: center;
}

.account-settings-content {
  padding: var(--padding-card);
}

.account-settings-item {
  margin-bottom: var(--spacing-rg);
}

.account-settings-item:last-child {
  margin-bottom: 0;
}

.account-settings-item label {
  display: block;
  margin-bottom: var(--spacing-sm);
}

@media (width <= 767px) {
  .account-settings-panel {
    top: var(--spacing-60);
    right: 0;
    left: 0;
    width: 100%;
  }
}

/* ConfigController retry-icon inside the error modal retry button. */
.global-config-retry-icon {
  --image-width: var(--spacing-md);
  --image-height: var(--spacing-md);
  --image-margin: 0 var(--spacing-xs) 0 0;

  vertical-align: middle;
}

/* ThemeConfig checkout background swatches */
.checkout-swatch {
  width: var(--spacing-40);
  height: var(--spacing-40);
  cursor: pointer;
  transition: border-color var(--ripple-duration-in) ease;
}

.checkout-swatch-check {
  top: calc(var(--spacing-sm) * -1);
  right: calc(var(--spacing-sm) * -1);
  width: var(--spacing-md);
  height: var(--spacing-md);
}

.checkout-swatch-check::after {
  content: '';
  display: block;
  width: var(--spacing-xs);
  height: var(--spacing-sm);
  margin-top: calc(var(--spacing-2) * -1);
  transform: rotate(45deg);
}

/* ThemeConfig full-height nav menu */
.theme-config-layout {
  --menu-primary-height: var(--full-height);
}

/* ConfigController card width for non-scrollable JSONForm layout */
.global-settings-card-width {
  --card-width: var(--spacing-330);
}

/* Settings-tab toggle-card wrapper — shared recipe for /order, /shop/offers, and
   /supercoins settings tabs. All four vars are IDENTICAL across the three pages and
   differ from the :root defaults, so they live here rather than at each call site.
   Card radius + shadow are now UNIFORM for every card app-wide via :root
   (--card-border-radius: var(--border-radius-card); --card-box-shadow:
   var(--box-shadow)) — no per-card override. Only the in-card CONTENT layout
   below is specific to the settings-toggle card type:
     --card-icon-subtext-padding: uniform 24px on all sides (vs the :root
       asymmetric 0px 16px 16px 16px used by stat/analytics cards).
     --horizontal-line-margin: insets the in-card divider by 24px left/right
       to match the header padding.
   Per-page extras (--card-icon-header-padding, --card-height, etc.) remain
   scoped in each page's own \3c style> block because they differ across pages. */
.global-card-settings-toggle-tab {
  --card-icon-subtext-padding: var(--spacing-lg);
  --horizontal-line-margin: 0 var(--spacing-lg);
}

@media (width <= 767px) {
  .global-settings-card-width {
    --card-width: auto;
  }
}

/* ──────────────────────────────────────────────────────────────────────────────
   Migrated standalone :global overrides (BZ-4022 Bucket A).
   These were originally written as standalone :global() rules inside component
   \3c style> blocks. Moving them here is appearance-preserving: a bare
   :global(.x){} inside a component \3c style> is already applied app-wide with
   no scope token, so the compiled output is identical.
   ────────────────────────────────────────────────────────────────────────────── */

/* SideBar — Pill token wiring (sidebar-demo-pill).
   Per-instance colour mapping for the single demo-mode badge pill in the sidebar;
   maps the --demo-badge-* colour tokens to the --pill-* colour slots. Shape
   (padding, border-radius, cursor) comes from the :root pill defaults in theme.css.
   Migrated from src/lib/components/SideBar/SideBar.svelte */
