/*
 * Embedded admin styles.
 *
 * Built on Polaris design tokens (spacing scale, type scale, colour roles) rather than
 * on the Polaris web components. App Bridge only registers those components inside the
 * Shopify admin frame, so they cannot be exercised outside it, and shipping an admin
 * whose entire UI could not be tested before submission is the wrong trade for one
 * night's work. See the HANDOFF note in TODO.md.
 */

:root {
  --p-space-100: 4px;
  --p-space-200: 8px;
  --p-space-300: 12px;
  --p-space-400: 16px;
  --p-space-500: 20px;
  --p-space-600: 24px;
  --p-space-800: 32px;
  --p-space-1200: 48px;

  --p-radius-200: 8px;
  --p-radius-300: 12px;

  --p-bg-app: #f1f1f1;
  --p-bg-surface: #ffffff;
  --p-bg-surface-secondary: #f7f7f7;
  --p-bg-surface-hover: #f1f1f1;
  --p-bg-fill-brand: #303030;
  --p-bg-fill-brand-hover: #1a1a1a;
  --p-bg-fill-success: #cdfee1;
  --p-bg-fill-warning: #ffd6a4;
  --p-bg-fill-critical: #fee9e8;
  --p-bg-fill-info: #d6f0ff;

  --p-text: #303030;
  --p-text-secondary: #616161;
  --p-text-brand-on-fill: #ffffff;
  --p-text-success: #0c5132;
  --p-text-warning: #5e4200;
  --p-text-critical: #8e1f0b;

  --p-border: #e3e3e3;
  --p-border-strong: #b5b5b5;
  --p-border-critical: #e0b3b2;

  --p-shadow-card: 0 1px 0 rgba(26, 26, 26, 0.07);
  --p-focus: 0 0 0 2px #ffffff, 0 0 0 4px #005bd3;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--p-bg-app);
  color: var(--p-text);
  font: 14px/1.4285 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, ul, ol, figure { margin: 0; }
ul { padding: 0; list-style: none; }

/* ------------------------------------------------------------------- layout --- */

.page { max-width: 1000px; margin: 0 auto; padding: var(--p-space-500) var(--p-space-400) var(--p-space-1200); }
.page__header { display: flex; align-items: flex-start; gap: var(--p-space-400); margin-bottom: var(--p-space-500); flex-wrap: wrap; }
.page__title { font-size: 20px; font-weight: 650; letter-spacing: -0.01em; }
.page__subtitle { color: var(--p-text-secondary); margin-top: var(--p-space-100); }
.page__actions { margin-left: auto; display: flex; align-items: center; gap: var(--p-space-200); }

.card {
  background: var(--p-bg-surface);
  border-radius: var(--p-radius-300);
  box-shadow: var(--p-shadow-card);
  padding: var(--p-space-400);
  margin-bottom: var(--p-space-400);
}
.card__title { font-size: 14px; font-weight: 650; margin-bottom: var(--p-space-100); }
.card__hint { color: var(--p-text-secondary); margin-bottom: var(--p-space-400); }
.card__section + .card__section { margin-top: var(--p-space-400); padding-top: var(--p-space-400); border-top: 1px solid var(--p-border); }

.grid { display: grid; gap: var(--p-space-400); }
@media (min-width: 720px) { .grid--2 { grid-template-columns: 1fr 1fr; } .grid--preview { grid-template-columns: 1fr 320px; } }
/* Three plan cards. Two up at tablet width, three only when there is room for the
   feature lists to breathe, so a card never collapses to one word per line. */
@media (min-width: 720px) { .grid--3 { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1020px) { .grid--3 { grid-template-columns: 1fr 1fr 1fr; } }

.row { display: flex; gap: var(--p-space-300); align-items: center; flex-wrap: wrap; }
/* Feature bullets. .row wraps, so a feature longer than one line dropped its text onto a
   new line underneath a stranded bullet. These align to the top and let the text take the
   remaining width instead. */
.feature { display: flex; gap: var(--p-space-200); align-items: flex-start; flex-wrap: nowrap; }
.feature > span:last-child { flex: 1; min-width: 0; }
.row--between { justify-content: space-between; }
.stack > * + * { margin-top: var(--p-space-300); }
.muted { color: var(--p-text-secondary); }
.small { font-size: 12px; }
.nowrap { white-space: nowrap; }

/* --------------------------------------------------------------------- tabs --- */

.tabs { display: flex; gap: var(--p-space-100); margin-bottom: var(--p-space-400); flex-wrap: wrap; }
.tab {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  padding: var(--p-space-200) var(--p-space-300); border-radius: var(--p-radius-200);
  font: inherit; font-weight: 550; color: var(--p-text-secondary);
}
.tab:hover { background: var(--p-bg-surface-hover); }
.tab[aria-selected='true'] { background: var(--p-bg-surface); color: var(--p-text); box-shadow: var(--p-shadow-card); }
.tab:focus-visible { outline: 0; box-shadow: var(--p-focus); }

/* ------------------------------------------------------------------ controls --- */

.btn {
  appearance: none; cursor: pointer; font: inherit; font-weight: 600;
  border-radius: var(--p-radius-200); padding: 7px 14px;
  border: 1px solid var(--p-border-strong); background: var(--p-bg-surface); color: var(--p-text);
  display: inline-flex; align-items: center; gap: var(--p-space-200);
}
.btn:hover:not(:disabled) { background: var(--p-bg-surface-hover); }
.btn:focus-visible { outline: 0; box-shadow: var(--p-focus); }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }
.btn--primary { background: var(--p-bg-fill-brand); border-color: var(--p-bg-fill-brand); color: var(--p-text-brand-on-fill); }
.btn--primary:hover:not(:disabled) { background: var(--p-bg-fill-brand-hover); }
.btn--plain { border-color: transparent; background: transparent; padding: 4px 6px; text-decoration: underline; font-weight: 500; }
.btn--critical { color: var(--p-text-critical); border-color: var(--p-border-critical); }
.btn--small { padding: 4px 10px; font-size: 12px; }
/* A plain button on its own line: its padding would push its text past the card edge below. */
.btn--back { margin-left: -6px; }

/* Plan cards share a row height; the button sits at the bottom so all three line up. */
.card--plan { display: flex; flex-direction: column; }
.card--plan__cta { margin-top: auto; padding-top: var(--p-space-400); }

.field { display: block; margin-bottom: var(--p-space-300); }
.field__label { display: block; font-size: 13px; font-weight: 550; margin-bottom: var(--p-space-100); }
.field__hint { color: var(--p-text-secondary); margin-top: var(--p-space-100); }
.field__error { color: var(--p-text-critical); margin-top: var(--p-space-100); }

.input, .select, textarea.input {
  width: 100%; font: inherit; color: var(--p-text);
  padding: 7px 10px; border: 1px solid var(--p-border-strong);
  border-radius: var(--p-radius-200); background: var(--p-bg-surface);
}
/*
 * Our own chevron: the browser's sits inside the 10px padding, flush against the border.
 * Padding on the right keeps a long collection name from running under it.
 */
.select {
  appearance: none; -webkit-appearance: none;
  padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5 6 7.5l3-3' fill='none' stroke='%234a4a4a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; background-size: 12px;
  text-overflow: ellipsis;
}
.input:focus, .select:focus { outline: 0; box-shadow: var(--p-focus); }
.input--invalid { border-color: var(--p-text-critical); }
.input--short { width: 7rem; }

/* The .checkbox rules are gone: checkboxes are Polaris <s-checkbox> components now, which
   carry their own label, help text, focus ring and checked styling. The native control
   they replaced rendered in the browser's blue accent, next to Polaris's black buttons. */

/* ------------------------------------------------------------------- banners --- */

.banner { border-radius: var(--p-radius-200); padding: var(--p-space-300) var(--p-space-400); margin-bottom: var(--p-space-400); }
.banner--success { background: var(--p-bg-fill-success); color: var(--p-text-success); }
.banner--warning { background: var(--p-bg-fill-warning); color: var(--p-text-warning); }
.banner--critical { background: var(--p-bg-fill-critical); color: var(--p-text-critical); }
.banner--info { background: var(--p-bg-fill-info); }
.banner__title { font-weight: 650; }

.badge { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 550; background: var(--p-bg-surface-secondary); }
.badge--success { background: var(--p-bg-fill-success); color: var(--p-text-success); }
.badge--warning { background: var(--p-bg-fill-warning); color: var(--p-text-warning); }
.badge--attention { background: var(--p-bg-fill-info); }

/* ----------------------------------------------------------------- checklist --- */

.check { display: flex; gap: var(--p-space-300); padding: var(--p-space-300) 0; align-items: flex-start; }
.check + .check { border-top: 1px solid var(--p-border); }
.check__mark {
  flex: 0 0 20px; width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center; font-size: 12px; font-weight: 700; margin-top: 1px;
  background: var(--p-bg-surface-secondary); color: var(--p-text-secondary); border: 1px solid var(--p-border);
}
.check--done .check__mark { background: #0c5132; color: #fff; border-color: #0c5132; }
.check__body { flex: 1; min-width: 0; }
.check__title { font-weight: 550; }

/* ------------------------------------------------------------------ products --- */

.product { display: flex; gap: var(--p-space-300); padding: var(--p-space-300) 0; align-items: flex-start; }
.product + .product { border-top: 1px solid var(--p-border); }
.product__main { flex: 1; min-width: 0; }
.product__title { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.product__fields { display: grid; gap: var(--p-space-200); grid-template-columns: 5rem 1fr 1fr auto; align-items: start; margin-top: var(--p-space-200); }
@media (max-width: 720px) { .product__fields { grid-template-columns: 1fr 1fr; } }

/* ------------------------------------------------------------------- preview --- */

.preview { position: sticky; top: var(--p-space-400); }
.preview__frame { background: var(--p-bg-surface-secondary); border-radius: var(--p-radius-200); padding: var(--p-space-400); display: grid; gap: var(--p-space-400); justify-items: center; }
.preview__notice img { display: block; width: 100%; height: auto; max-width: 260px; }
.preview__label svg { display: block; width: 100%; height: auto; max-width: 220px; }
.preview__label--nested svg { max-width: 280px; }

/* --------------------------------------------------------------------- misc --- */

.boot { min-height: 60vh; display: grid; place-items: center; }
.spinner {
  width: 28px; height: 28px; border-radius: 50%;
  border: 3px solid var(--p-border); border-top-color: var(--p-text-secondary);
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 3s; } }

.empty { text-align: center; padding: var(--p-space-800) var(--p-space-400); color: var(--p-text-secondary); }

.toast {
  position: fixed; left: 50%; bottom: var(--p-space-500); transform: translateX(-50%);
  background: #303030; color: #fff; padding: var(--p-space-300) var(--p-space-400);
  border-radius: var(--p-radius-200); box-shadow: 0 4px 12px rgba(0,0,0,.2); z-index: 40;
  max-width: 90vw;
}
.toast--error { background: #8e1f0b; }

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

/*
 * Column widths for the GARAN worklist, on wrapper divs: Polaris fields are
 * display: contents and ignore a width of their own. Fixed widths, so a validation
 * message wraps under its field instead of widening the column and squeezing the others.
 */
.garan-col--years { width: 120px; }
.garan-col--text { width: 180px; }

/* The loading line under the first-load spinner. */
.boot__inner { display: grid; justify-items: center; gap: var(--p-space-300); }
.boot__text { color: var(--p-text-secondary); font-size: 13px; }

/* The GARAN column guide: folded away once the merchant has a first complete label. */
.guide { margin-bottom: var(--p-space-400); padding: var(--p-space-300); border-radius: var(--p-radius-200); background: var(--p-bg-surface-secondary); }
.guide summary { cursor: pointer; font-weight: 600; }
.guide ul { margin-top: var(--p-space-300); }

/* ------------------------------------------------------------ bulk changes --- */

.badge--critical { background: var(--p-bg-fill-critical); color: var(--p-text-critical); }

/* Failed products: louder than an ordinary banner, because nothing else announces them. */
.banner--loud { border-left: 4px solid var(--p-border-critical, #c70a24); box-shadow: 0 1px 0 rgba(0, 0, 0, .05); }

/*
 * The running job, in the lower right corner of the app on every screen. Fixed to the
 * app's frame, outside the page, so a re-render never removes it. Shopify's Sidekick bar
 * sits at the bottom centre of the admin, so the panel keeps to the corner.
 */
.job-panel {
  /* Clear of the admin's own bottom-right bars (Sidekick, dev previews), which sit over the
     app's frame and hid the progress bar at 16px. Seen on assay-dev, 4 October 2026. */
  position: fixed; right: 16px; bottom: 72px; z-index: 50;
  width: 300px; max-width: calc(100vw - 32px);
  display: flex; flex-direction: column; gap: 4px; text-align: left;
  padding: 12px 14px; border-radius: var(--p-radius-300, 12px);
  background: #fff; color: inherit; border: 1px solid var(--p-border, #e3e3e3);
  box-shadow: 0 4px 16px rgba(0, 0, 0, .12); cursor: pointer; font: inherit;
}
.job-panel:hover { box-shadow: 0 6px 20px rgba(0, 0, 0, .16); }
.job-panel:focus-visible { outline: 2px solid #005bd3; outline-offset: 2px; }
.job-panel__title { font-weight: 650; }
.job-panel__line { font-size: 13px; color: var(--p-text-secondary, #616161); }
.job-panel__error { font-size: 13px; color: var(--p-text-critical, #8e1f0b); }
.job-panel__bar { height: 4px; border-radius: 2px; background: var(--p-bg-surface-secondary, #f1f1f1); overflow: hidden; }
.job-panel__fill { display: block; height: 100%; background: #005bd3; transition: width .4s ease; }
/* While Shopify gives no count, the bar moves rather than standing still and reading as stuck. */
.job-panel__fill--busy { width: 30% !important; animation: job-busy 1.4s ease-in-out infinite; }
@keyframes job-busy { 0% { transform: translateX(-100%); } 100% { transform: translateX(340%); } }
@media (prefers-reduced-motion: reduce) { .job-panel__fill--busy { animation: none; width: 100% !important; opacity: .5; } }

/* ------------------------------------------------- a producer's guarantee --- */
.chips { display: flex; flex-wrap: wrap; gap: 6px; min-height: 28px; }
.chip {
  appearance: none; cursor: pointer; font: inherit; font-size: 13px; font-weight: 550;
  border: 0; border-radius: 999px; padding: 4px 10px;
  background: var(--p-bg-fill-info-secondary, #eaf4ff); color: var(--p-text-info, #00527c);
}
.chip:hover { filter: brightness(0.97); }
.chip:focus-visible { outline: 0; box-shadow: var(--p-focus); }
.chip small { font-size: 11.5px; font-weight: 450; opacity: .8; margin-left: 5px; }

/* The years and Save stay in view at the bottom of the screen while the list scrolls. */
.producer-bar, .sticky-bar {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; flex-wrap: wrap; gap: var(--p-space-300); align-items: flex-end; justify-content: flex-end;
  margin: var(--p-space-300) calc(-1 * var(--p-space-400)) calc(-1 * var(--p-space-400));
  padding: var(--p-space-300) var(--p-space-400);
  background: var(--p-bg-surface); border-top: 1px solid var(--p-border);
  border-radius: 0 0 var(--p-radius-300) var(--p-radius-300);
}
.producer-bar__years { width: 15rem; }
/* Its own line above the years and Save, so ticking it never pushes Save out of place. */
.producer-bar__email { flex-basis: 100%; }
.producer-change { color: var(--p-text-secondary); }
.producer-change[data-kind="new"] { color: var(--p-text-success, #0c5132); }
.producer-change[data-kind="no_model"], .producer-change[data-kind="too_long"] { color: var(--p-text-warning, #5e4200); }

/* The bulk form's three fields, labelled above, side by side when there is room. */
.bulk-grid { display: grid; grid-template-columns: minmax(0, 14rem) minmax(0, 1fr) minmax(0, 13rem); gap: var(--p-space-300); align-items: start; }
@media (max-width: 640px) { .bulk-grid { grid-template-columns: minmax(0, 1fr); } }
.bulk-grid .select, .bulk-grid .input { max-width: none; width: 100%; }
/* .field sets display: block, which would otherwise win over the hidden attribute. */
.field[hidden] { display: none; }

/* ------------------------------------------------------------------------ home --- */
/* The answer first: one line each for the notice, the labels and the last bulk change. */
.status { display: grid; margin-top: var(--p-space-300); }
.status-row {
  display: grid; grid-template-columns: minmax(0, 14rem) minmax(0, 1fr) auto; gap: var(--p-space-300);
  align-items: center; padding: var(--p-space-300) 0; border-top: 1px solid var(--p-border);
}
.status-row:first-child { border-top: 0; }
.status-row__label { font-weight: 600; }
@media (max-width: 560px) { .status-row { grid-template-columns: minmax(0, 1fr) auto; } .status-row__label { grid-column: 1 / -1; } }

.setup-auto { color: var(--p-text-secondary); }
.setup-auto > span { color: var(--p-text-success, #0c5132); font-weight: 700; }
.setup-warning { margin-top: var(--p-space-200); font-size: 13px; color: var(--p-text-warning, #5e4200); }
.setup-labels { border-top: 1px solid var(--p-border); padding-top: var(--p-space-400); }
.setup-done summary { cursor: pointer; font-weight: 650; }
.setup-done summary > span { color: var(--p-text-success, #0c5132); }

/* The two ways to show the notice, side by side, so they read as one choice. */
.option { border: 1px solid var(--p-border); border-radius: var(--p-radius-200); padding: var(--p-space-300); }

/* Numbered steps, one action at a time: done steps tick off, the current one is the dark button. */
.steps { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--p-space-200); }
.step { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; gap: var(--p-space-200); align-items: center; font-size: 13px; color: var(--p-text-secondary); }
.step__mark {
  width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 700;
  border: 1px solid var(--p-border-strong); background: var(--p-bg-surface);
}
.step--current { color: var(--p-text); font-weight: 600; }
.step--current .step__mark { border-color: var(--p-text); }
.step--done .step__mark { background: var(--p-text-success, #0c5132); border-color: transparent; color: #fff; }

/* The plan in the header opens the Plan page. */
.badge--link { border: 0; cursor: pointer; font: inherit; font-size: 12px; font-weight: 550; }
.badge--link:hover { filter: brightness(0.96); }
.badge--link:focus-visible { outline: 0; box-shadow: var(--p-focus); }
.setup-step-title { font-size: 14px; font-weight: 600; margin: 0 0 var(--p-space-200); }
.sticky-bar[hidden] { display: none; }
.sticky-bar__text { margin-right: auto; align-self: center; font-weight: 600; }
.badges { display: flex; flex-wrap: wrap; gap: 4px; }
