/* Oswald (OFL) — closest free match to the condensed grotesque used on the real hazard signs;
   used for the live custom-wording preview (SC-20260914-05 v0.6). The same font is embedded as a
   base64 @font-face inside the generated SVG itself for anything rendered detached from this page
   (cart thumbnail, Node/ImageMagick catalogue renders) — see sign-render.js. */
@font-face {
  font-family: 'Oswald';
  font-weight: 700;
  font-style: normal;
  src: url('/fonts/Oswald-Bold.woff') format('woff'),
       url('/fonts/Oswald-Bold.ttf') format('truetype');
  font-display: block;
}
/* Visually hides an element while keeping it in the accessibility tree (screen-reader-only label
   text) — SC-20260914-12 audit item 7, e.g. the #hz-freetext precaution input's label. */
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
:root {
  /* Brand tokens (SC-20260914-17, "Go Green 3 Lives" identity, see /home/claude/briefs/brand-ref).
     --brand/--brand-dark/--bg/--font/--radius etc. keep their original NAMES so every existing
     rule below stays wired up; only the values changed to the brand palette. The --sc-* tokens are
     the brand kit's own names, added alongside for anything written straight against the kit. */
  --brand: #0e4423;
  --brand-dark: #082d17;
  --brand-soft: #eef7e4;
  --ink: #1e2621;
  --ink-2: #35423a;
  --muted: #52605a;
  --line: #dfe6da;
  --bg: #fbfaf6;
  --card: #ffffff;
  --ok: #1a8f4c;
  --warn: #b7791f;
  --red: #c0271b;
  --radius: 16px;
  --shadow: 0 1px 2px rgba(8,45,23,.05), 0 6px 20px rgba(8,45,23,.08);
  --shadow-lg: 0 20px 60px rgba(8,45,23,.22);
  --font: 'Poppins', 'Inter', -apple-system, 'Segoe UI', Arial, sans-serif;

  /* selected/active accent (lime) - kept separate from --brand (dark green, used for headings and
     text) so selected states in cards/forms read as lime per the brand kit, not dark green. */
  --accent: #70bc1f;
  --accent-dark: #5ab025;
  --accent-ring: rgba(112,188,31,.25);

  /* ---- Sign Central brand tokens (brand-tokens.css), same values, sc- prefixed ---- */
  --sc-green: #0e4423;
  --sc-green-deep: #082d17;
  --sc-green-mid: #216921;
  --sc-lime: #70bc1f;
  --sc-lime-dark: #5ab025;
  --sc-lime-deep: #3f8f1a;
  --sc-lime-bright: #8ad42f;
  --sc-paper: #fbfaf6;
  --sc-tint: #eef7e4;
  --sc-ink: #1e2621;
  --sc-muted: #52605a;
  --sc-border: rgba(30,38,33,0.14);
  --sc-on-dark: #ffffff;
  --sc-on-dark-soft: #d9ead1;
  --sc-on-dark-muted: #a9c9a0;
  --sc-font: "Poppins", "Inter", -apple-system, "Segoe UI", Arial, sans-serif;
  --sc-radius: 16px;
  --sc-radius-pill: 999px;
  --sc-shadow: 0 10px 30px rgba(8,45,23,0.12);
  --sc-hero-bg:
    radial-gradient(60% 70% at 30% 40%, rgba(112,188,31,0.20) 0%, rgba(112,188,31,0) 70%),
    linear-gradient(165deg, #12552b 0%, #0e4423 45%, #082d17 100%);

  /* SC-20260914-09 (Sam's restyle note, round 2 - "go properly dark"): a deep-slate card for the
     HAZCHEM wizard's fillable steps, with light text and a bright-green accent for focus rings,
     selected tiles/radios and primary buttons - scoped to the HAZCHEM page only (see below), never
     redefines --card/--bg globally.
     SC-20260914-17: moved from slate to the brand greens (Sam kept this panel dark on purpose,
     just wants it in the Go Green palette) - panel/rows are brand dark greens, accent is the
     brand lime, so it now matches the rest of the site instead of sitting apart from it. */
  --hz-panel-bg: #0e4423;
  --hz-panel-border: #216921;
  --hz-text: #f9fafb;
  --hz-muted: #cfe3c9;
  --hz-row-bg: #164a27;
  --hz-field-border: #4f7a5c;
  --hz-accent: #70bc1f;
  --hz-accent-dark: #5ab025;
  --hz-accent-text: #0b2e18;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body { font-family: var(--font); color: var(--ink); background: var(--bg); font-size: 15px; line-height: 1.45; -webkit-font-smoothing: antialiased; }
h1, h2, h3 { margin: 0; line-height: 1.2; letter-spacing: -0.01em; }
h1 { font-size: 30px; font-weight: 800; }
h2 { font-size: 24px; font-weight: 800; }
h3 { font-size: 17px; font-weight: 700; }
p { margin: 0 0 12px; }
a { color: inherit; }
.muted { color: var(--muted); }
.hint { font-size: 13px; color: var(--muted); margin: 6px 0 0; }
[hidden] { display: none !important; }

/* ---- Inputs & buttons ---- */
label { display: block; font-size: 13px; font-weight: 600; color: var(--ink-2); margin-bottom: 6px; }
input[type=text], input[type=email], input[type=search], input[type=tel], input[type=number], input:not([type]), textarea, select {
  width: 100%; font: inherit; padding: 11px 13px; border: 1px solid #cfcfd6; border-radius: 9px; background: #fff; color: var(--ink);
  transition: border-color .15s, box-shadow .15s;
}
input:focus, textarea:focus, select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
textarea { resize: vertical; }
.btn { font: inherit; font-weight: 600; border: 1px solid transparent; border-radius: 9px; padding: 11px 18px; cursor: pointer; background: #fff; color: var(--ink); transition: background .15s, transform .05s, box-shadow .15s; text-decoration: none; display: inline-block; }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .55; cursor: default; }
.btn-primary { background: var(--accent); color: #0b2e18; border-radius: var(--sc-radius-pill); }
.btn-primary:hover:not(:disabled) { background: var(--sc-lime-bright); box-shadow: 0 8px 26px rgba(112,188,31,.35); }
.btn-secondary { background: var(--brand); color: #fff; border-radius: var(--sc-radius-pill); }
.btn-secondary:hover:not(:disabled) { background: var(--brand-dark); }
.btn-ghost { background: transparent; border-color: #cfcfd6; border-radius: var(--sc-radius-pill); }
.btn-ghost:hover { background: #fff; }
.btn-link { background: none; color: var(--muted); padding: 8px; text-decoration: underline; font-weight: 500; }
.btn-block { width: 100%; text-align: center; }
.btn-sm { padding: 7px 12px; font-size: 13px; }
.icon-btn { background: none; border: 0; font-size: 26px; line-height: 1; cursor: pointer; color: var(--muted); padding: 4px 8px; border-radius: 8px; }
.icon-btn:hover { background: var(--bg); color: var(--ink); }
.msg { margin-top: 14px; padding: 10px 12px; border-radius: 8px; font-size: 14px; background: #fdecec; color: #9b1c1c; }
.msg.ok { background: #e6f6ec; color: #16693a; }
.msg.warn { background: #fff5dd; color: #7a5200; }

/* ---- Launch promo banner (SC-20260915-02, Sam confirmed 15 Sep 2026) ---- */
/* Sits ABOVE .topbar-inner, inside the same sticky <header class="topbar">, so it scrolls with
   the header as one unit without changing the gap main.page reserves for the hanging logo (that
   gap is measured from .topbar-inner's own bottom edge, which this banner sits above, not below -
   see the comment on main.page). Shown/hidden by app.js from pricing.js's promoFor(), both on
   load and on a light interval, so it disappears on its own the instant the promo's `ends` time
   passes (the server enforces the real cutoff regardless of what the browser shows). */
.promo-banner {
  background: var(--sc-green-deep); color: var(--sc-lime-bright);
  text-align: center; font-weight: 600; font-size: 12.5px; letter-spacing: .01em;
  padding: 7px 14px; border-bottom: 1px solid rgba(255,255,255,.08);
}
.promo-banner .promo-note { font-weight: 500; color: var(--sc-on-dark-muted); margin-left: 8px; }
@media (max-width: 860px) { .promo-banner { font-size: 11.5px; padding: 6px 10px; } .promo-banner .promo-note { display: block; margin: 2px 0 0; } }

/* Promo pill on product cards / Print your own / HAZCHEM price areas. */
.promo-pill { display: inline-block; font-size: 10px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; background: var(--accent); color: #0b2e18; padding: 2px 8px; border-radius: 999px; margin-left: 8px; vertical-align: middle; }
.card-price .promo-pill { margin-left: 6px; }

/* Cart drawer / cart / checkout summary promo line + struck pre-promo subtotal. */
.promo-line { background: var(--accent); color: #0b2e18; font-weight: 700; }
.promo-strike { color: var(--muted); font-weight: 500; margin-right: 6px; }

/* ---- Top bar (SC-20260914-17: Go Green header - dark green bar, hanging cut-out logo) ---- */
.topbar {
  position: sticky; top: 0; z-index: 30; overflow: visible;
  background: rgba(8,45,23,0.94); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(255,255,255,.08);
}
.topbar-inner { max-width: 1280px; margin: 0 auto; padding: 0 24px; height: 64px; display: flex; align-items: center; gap: 28px; }
.brand-group { display: flex; align-items: center; gap: 10px; flex: none; }
/* The logo is taller than the bar and hangs down over the page below it (brand kit "Header
   pattern"): the link box only reserves the bar-height space; the image is absolutely positioned
   inside it, wider than the box, with a drop shadow so it reads as a cut-out over the page. */
.brand-plate { position: relative; display: block; width: clamp(150px, 15vw, 214px); height: 50px; flex: none; }
.brand-logo {
  position: absolute; left: 0; top: -4px; width: 100%; height: auto; display: block;
  filter: drop-shadow(0 8px 14px rgba(0,0,0,.45));
  transition: transform .25s ease;
}
.brand-plate:hover .brand-logo { transform: translateY(2px) scale(1.02); }
.brand-sub { font-weight: 600; font-size: 11px; color: var(--sc-on-dark-muted); letter-spacing: .08em; text-transform: uppercase; white-space: nowrap; }
.tabs { display: flex; gap: 4px; margin-left: auto; align-items: center; }
.tab { text-decoration: none; padding: 8px 14px; border-radius: 8px; font-weight: 600; font-size: 14px; color: #cfe3c9; }
.tab:hover { background: rgba(255,255,255,.08); color: #fff; }
.tab.active { color: #fff; background: rgba(255,255,255,.12); }
.tab-external { color: var(--sc-on-dark-muted); font-weight: 500; font-size: 13px; }
.tab-external:hover { background: none; color: #cfe3c9; }
.topbar-right { display: flex; align-items: center; gap: 16px; }
.topbar .btn-ghost { background: transparent; color: #fff; border: 1.5px solid rgba(255,255,255,.4); }
.topbar .btn-ghost:hover { border-color: #fff; background: rgba(255,255,255,.08); }
.cart-btn { display: flex; align-items: center; gap: 8px; font: inherit; font-weight: 600; font-size: 14px; background: var(--accent); color: #0b2e18; border: 0; border-radius: var(--sc-radius-pill); padding: 9px 16px; cursor: pointer; }
.cart-btn:hover { background: var(--sc-lime-bright); }
.badge { background: #0b2e18; color: #fff; font-size: 12px; font-weight: 700; min-width: 20px; height: 20px; border-radius: 10px; display: inline-grid; place-items: center; padding: 0 6px; }

/* ---- Page ---- */
/* Top padding cleared to ~100px (SC-20260914-17) so nothing sits under the header's hanging
   logo - applied here rather than per-view since every route renders inside this one <main>. */
main.page { max-width: 1280px; margin: 0 auto; padding: 100px 24px 80px; }
.page-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; flex-wrap: wrap; margin-bottom: 22px; }
.page-head .muted { margin: 6px 0 0; max-width: 560px; }
.filters { display: flex; flex-direction: column; gap: 10px; align-items: flex-end; }
.chips { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.chip { font: inherit; font-size: 13px; font-weight: 600; padding: 6px 12px; border-radius: 999px; border: 1px solid #d5d5dc; background: #fff; color: var(--ink-2); cursor: pointer; }
.chip.active { background: var(--ink); color: #fff; border-color: var(--ink); }

/* ---- Home hero (SC-20260914-17: dark green band, brand kit --sc-hero-bg) ---- */
.eyebrow { text-transform: uppercase; letter-spacing: .14em; font-size: 12.5px; font-weight: 600; color: var(--sc-lime-deep); margin: 0 0 10px; }
.hero .eyebrow { color: var(--sc-lime); }
.hero {
  max-width: none; margin: -100px -24px 30px; padding: 132px 24px 40px;
  background: var(--sc-hero-bg); color: #fff; border-radius: 0 0 28px 28px;
}
.hero h1 { color: #fff; max-width: 720px; }
.hero .muted { font-size: 16px; color: var(--sc-on-dark-soft); max-width: 640px; }
.hero .btn-primary { margin-top: 18px; }
@media (max-width: 860px) { .hero { margin: -24px -14px 24px; padding: 40px 14px 32px; border-radius: 0 0 20px 20px; } }

/* ---- Brand strip (canon "PRINT + RETURN + RECREATE" lines, brand-ref/BRAND-KIT.md) ---- */
.brand-strip { max-width: 900px; margin: 0 0 34px; }
.brand-strip-line { font-family: var(--font); font-weight: 800; font-size: clamp(20px, 3vw, 28px); text-transform: uppercase; letter-spacing: .01em; color: var(--brand); margin: 0 0 6px; }
.brand-strip-line .plus-mark { color: var(--accent); margin: 0 6px; }
.brand-strip-sub { color: var(--muted); font-weight: 600; margin: 0 0 14px; }
.brand-strip-lives { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
@media (max-width: 700px) { .brand-strip-lives { grid-template-columns: 1fr; } }
.brand-strip-lives li { display: flex; gap: 10px; align-items: flex-start; font-size: 13.5px; color: var(--ink-2); background: var(--brand-soft); border-radius: 10px; padding: 10px 12px; }
.brand-strip-lives .num { flex: none; display: inline-grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; background: var(--accent); color: #0b2e18; font-weight: 800; font-size: 11px; }
.brand-strip-lives a { color: var(--sc-lime-deep); font-weight: 600; text-decoration: underline; }

.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.tile { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 26px 22px; text-decoration: none; color: inherit; display: flex; flex-direction: column; gap: 8px; border: 1px solid transparent; transition: border-color .15s, box-shadow .15s, transform .1s; }
.tile:hover { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); transform: translateY(-2px); }
.tile-icon { width: 52px; height: 52px; border-radius: 12px; background: var(--brand-soft); color: var(--brand-dark); display: grid; place-items: center; margin-bottom: 6px; }
.tile-go { font-weight: 700; font-size: 13px; color: var(--sc-lime-deep); margin-top: auto; }
@media (max-width: 800px) { .tiles { grid-template-columns: 1fr; } }

.info-card { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 26px 28px; max-width: 720px; }
.thankyou-card { text-align: center; max-width: 480px; margin: 40px auto; }
.done-icon { width: 64px; height: 64px; border-radius: 50%; background: #e6f6ec; color: var(--ok); font-size: 32px; font-weight: 800; display: grid; place-items: center; margin: 0 auto 16px; }

/* ---- Sign / product grid ---- */
.grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
@media (max-width: 1100px) { .grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 800px) { .grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .grid { grid-template-columns: 1fr; } }
.card { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; display: flex; flex-direction: column; border: 1px solid transparent; transition: border-color .15s, box-shadow .15s; }
.card.in-cart { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.card-img { position: relative; aspect-ratio: 4 / 3; background: #fff; border-bottom: 1px solid var(--line); overflow: hidden; }
.card-img img { width: 100%; height: 100%; object-fit: contain; display: block; }
.card-img .placeholder-tag { position: absolute; top: 8px; left: 8px; background: rgba(27,27,31,.82); color: #fff; font-size: 10px; font-weight: 700; letter-spacing: .05em; padding: 3px 7px; border-radius: 5px; text-transform: uppercase; }
.card-body { padding: 12px 14px 14px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.card-title { font-weight: 700; font-size: 15px; }
.card-cat { font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--brand-dark); }
.card-row { display: flex; gap: 8px; }
.card-row select { flex: 1; padding: 9px 8px; font-size: 13px; }
.card-price { font-weight: 700; font-size: 16px; }
.card-price small { font-weight: 500; color: var(--muted); font-size: 12px; margin-left: 4px; }
.card-price.tbc { color: var(--warn); font-weight: 600; font-size: 13px; }
.price-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; background: #fff5dd; color: #7a5200; padding: 2px 7px; border-radius: 999px; margin-left: 6px; }
.card-foot { display: flex; align-items: center; gap: 10px; margin-top: 4px; }
.qty { display: inline-flex; align-items: stretch; border: 1px solid #cfcfd6; border-radius: 9px; overflow: hidden; background: #fff; }
.qty select, .qty input[type=number] { border: 0; padding: 9px 8px; font-weight: 700; font-size: 14px; width: 72px; text-align: center; }
.btn-add { margin-left: auto; flex: 1 1 auto; white-space: nowrap; padding: 10px 12px; font-size: 14px; }
.btn-add.added { background: var(--ok); }
.empty { grid-column: 1 / -1; text-align: center; color: var(--muted); padding: 60px 0; }

/* ---- material_notes (SC-20260914-05 section 6): short, bold, unmissable, not fine print ---- */
.material-note { font-weight: 700; font-size: 12.5px; color: var(--ink); background: var(--brand-soft); border-radius: 7px; padding: 7px 10px; margin: 0; }
.material-note-warn { background: #fff5dd; color: #7a5200; }
.material-note-compact { font-weight: 700; font-size: 11.5px; color: #7a5200; background: #fff5dd; border-radius: 6px; padding: 5px 8px; margin-top: 4px; }

/* ---- custom-wording catalogue signs (SC-20260914-05 section 4) ---- */
.card-wording textarea { width: 100%; font: inherit; padding: 9px 10px; border: 1px solid #cfcfd6; border-radius: 8px; resize: vertical; font-size: 13px; }
.sign-svg-preview { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
.sign-svg-preview svg { width: 100%; height: 100%; display: block; }

/* ---- Custom print form ---- */
.custom-layout { display: grid; grid-template-columns: 1fr 280px; gap: 24px; align-items: start; }
@media (max-width: 900px) { .custom-layout { grid-template-columns: 1fr; } }
.custom-form { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 22px 24px; display: flex; flex-direction: column; gap: 14px; }
.field { margin: 0; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 560px) { .field-row { grid-template-columns: 1fr; } }
.field.span-2 { grid-column: span 2; }
.sqm-readout { font-weight: 700; font-size: 15px; color: var(--brand-dark); background: var(--brand-soft); border-radius: 8px; padding: 8px 12px; display: inline-block; }
.sqm-readout.oversize { color: var(--red); background: #fdecec; }
.area-note { color: var(--muted); font-size: 11.5px; margin-top: 2px; }
.cf-rush-label { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 14px; color: var(--ink-2); margin-bottom: 6px; }
.cf-rush-label input { width: auto; accent-color: var(--accent); }
.custom-price { border-top: 1px solid var(--line); padding-top: 12px; font-size: 15px; }
.custom-price .row { display: flex; justify-content: space-between; padding: 2px 0; }
.custom-price .total { font-weight: 800; font-size: 17px; }
.custom-side { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 20px; }
.custom-side ul { margin: 0; padding-left: 18px; color: var(--ink-2); font-size: 13px; line-height: 1.6; }

/* "Print your own" condensed two-column layout (SC-20260915-04, Sam 15 Sep 2026: "condense the
   page a bit more so there is no scrolling, the whole sign fits on the page, and all the details
   on the left bit... helpful hints on the right instead of in the builder on the left"). Every
   CONTROL (upload, size + lock, material, panels, bleed tick, blur badge, sides, quantity, price,
   Add to cart) lives in the LEFT (.custom-form) column in compact form; explanatory text lives in
   the "Helpful hints" panel (#cf-tips, light green tint) under the preview in the RIGHT column, so
   the preview (#cf-stage) gets whatever vertical room is left - see fitCfStage() in app.js, which
   sizes it to calc(available viewport height), min 320px, on desktop/laptop widths. On phone,
   stack with the preview FIRST (order: -1), drop the sticky positioning and the height cap
   (scrolling is fine there - nothing needs to fit one screen). */
.cf-layout { grid-template-columns: 340px 1fr; }
@media (max-width: 900px) { .cf-layout { grid-template-columns: 1fr; } }
.cf-preview-side { display: flex; flex-direction: column; gap: 12px; position: sticky; top: 16px; }
@media (max-width: 900px) { .cf-preview-side { order: -1; position: static; } }
/* The preview card and the hints panel are two separate cards stacked in this column (rather than
   one big .custom-side card wrapping both, as before) - overridden here, scoped to .cf-preview-side
   only, so .custom-side's shared styling (used by the HAZCHEM builder's own preview column too)
   is untouched. */
.custom-side.cf-preview-side { background: transparent; box-shadow: none; padding: 0; }
#cf-preview { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 8px; }
.cf-page-head { margin-bottom: 8px; }
.cf-page-head h2 { font-size: 19px; margin: 0 0 2px; }
.cf-page-head p.muted { font-size: 12.5px; margin: 0; }
/* SC-20260915-04: on the "Print your own" view only (body.view-tight, toggled in app.js's
   routeFromHash() - cleared again the instant the customer navigates elsewhere), claw back
   main.page's generous top/bottom padding (reserved site-wide for the header's hanging logo and
   for breathing room above the footer) and hide the site-wide footer, which together are most of
   why a normal-height viewport can't otherwise show this whole page without scrolling. Every
   other view keeps its normal padding and footer untouched. */
body.view-tight main.page { padding-top: 70px; padding-bottom: 14px; }
body.view-tight .site-footer { display: none; }
@media (min-width: 901px) {
  /* Helpful-hints panel: capped and internally scrollable on desktop so its own (variable, per
     material/blur-state) content length never pushes the page's total height past the viewport -
     the important stuff (preview + every control) already gets priority for the space that's
     left, per fitCfStage() in app.js. Left uncapped on phone, where the whole page scrolls anyway. */
  .cf-tips { max-height: 150px; overflow-y: auto; }
}

/* Left column: compact controls (SC-20260915-04) - smaller labels/inputs, tighter gaps, so every
   control fits in a short column regardless of viewport height. Scoped to .cf-layout's own form so
   the shared .custom-form/.field/.delivery-opt rules (checkout, cart, HAZCHEM) are untouched. */
.cf-layout .custom-form { padding: 8px 11px; gap: 4px; }
.cf-layout .custom-form label { font-size: 11px; margin-bottom: 2px; }
.cf-layout .custom-form input[type=number], .cf-layout .custom-form select { padding: 3px 7px; font-size: 13.5px; }
.cf-layout #cf-details { display: flex; flex-direction: column; gap: 4px; }
.cf-compact-hint { font-size: 10.5px; margin: 2px 0 0; line-height: 1.25; }
.cf-size-row { display: flex; align-items: flex-end; gap: 8px; }
.cf-size-cell { flex: 1 1 0; min-width: 0; }
.cf-size-cell input { width: 100%; text-align: center; }
.cf-size-x { padding-bottom: 7px; font-weight: 700; color: var(--muted); }
.cf-size-field .cf-lock-row { margin-top: 3px; }
.cf-lock-row { display: flex; align-items: center; gap: 10px; }
.cf-lock-btn { font: inherit; font-size: 11.5px; font-weight: 600; border: 1px solid #cfcfd6; border-radius: 999px; padding: 3px 8px; background: #fff; cursor: pointer; color: var(--ink-2); }
.cf-lock-btn[aria-pressed="true"] { background: var(--brand-soft); border-color: var(--accent); color: var(--sc-lime-deep); }
.cf-unlock-link { font-size: 12px; font-weight: 600; color: var(--muted); text-decoration: underline; }
.cf-panels-block { padding: 6px 9px; border-radius: 9px; background: var(--brand-soft); }
.cf-panels-block select { margin-top: 3px; }
/* Bleed tick box: a plain compact checkbox row (not the bordered .delivery-opt card style, which
   is sized for the bigger Sides options), so it reads as a small tick, not a whole control card. */
.cf-bleed-check { display: flex; align-items: center; gap: 7px; font-weight: 600; font-size: 12px; cursor: pointer; margin: 0; }
.cf-bleed-check input { margin: 0; accent-color: var(--accent); }
.cf-blur-block { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; padding: 2px 6px; border-radius: 9px; background: var(--bg); }
.cf-blur-badge { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; padding: 2px 8px; border-radius: 999px; flex: none; }
.cf-blur-badge.green { background: #e6f6ec; color: var(--ok); }
.cf-blur-badge.amber { background: #fff5dd; color: var(--warn); }
.cf-blur-badge.red { background: #fdecec; color: var(--red); }
.cf-blur-block .cf-compact-hint { margin: 0; flex: 1 1 auto; }
.cf-blur-block .btn-sm { margin-left: auto; padding: 4px 9px; font-size: 11.5px; }
.cf-sides-field .delivery-opts-compact { gap: 5px; }
.cf-sides-field .delivery-opt { padding: 5px 8px; font-size: 11.5px; }
.cf-row-2 { display: flex; gap: 8px; align-items: flex-start; }
.cf-row-2-main { flex: 1 1 auto; min-width: 0; }
.cf-row-2-side { flex: 0 0 64px; }
.cf-row-2-side input { width: 100%; text-align: center; }
.cf-layout .custom-price { font-size: 11.5px; padding-top: 5px; }
.cf-layout .custom-price .row { padding: 0; }
.cf-layout .custom-price .total { font-size: 13.5px; }
.cf-layout #cf-add { padding: 7px 16px; font-size: 13.5px; }

/* ---- Print your own: upload-first flow (SC-20260914-03) ---- */
.cf-dropzone { border: 2px dashed #cfcfd6; border-radius: 10px; padding: 6px 10px; text-align: center; background: var(--bg); transition: border-color .15s, background .15s; }
.cf-dropzone.drag-over { border-color: var(--accent); background: var(--brand-soft); }
.cf-dropzone input[type=file] { width: 100%; }
.cf-dropzone-hint { margin: 5px 0 0; font-size: 11px; color: var(--muted); }
.cf-progress { height: 6px; border-radius: 4px; background: var(--line); overflow: hidden; margin-top: 8px; }
.cf-progress-bar { height: 100%; width: 0%; background: var(--accent); transition: width .15s; }

/* SC-20260915-04: the preview stage (#cf-stage) sizes ITSELF (both dimensions, via fitCfStage() in
   app.js) to fit the vertical room actually left on screen (min 320px), scaling the sign to fit
   inside while keeping its own aspect ratio - a tall sign and a wide sign both show in full,
   without the page scrolling. Scoped to the #cf-stage id (not the shared .cf-stage class) so the
   HAZCHEM builder's own preview stage (.hazchem-stage, same class) is completely unaffected. On
   phone (<=900px) this is skipped entirely - full width, natural aspect-derived height, scrolling
   is fine there (see the media query below). */
.cf-preview-block { display: flex; flex-direction: column; align-items: stretch; gap: 6px; margin-top: 0; }
.cf-stage-row { display: flex; align-items: center; justify-content: center; width: 100%; }
@media (min-width: 901px) {
  #cf-stage { width: auto; height: auto; max-width: 100%; flex: none; margin: 0 auto; }
}
.cf-stage { position: relative; flex: 1 1 auto; width: 100%; min-width: 0; aspect-ratio: 4 / 3; background: repeating-conic-gradient(#f0f0f3 0% 25%, #fff 0% 50%) 50% / 16px 16px; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; display: grid; place-items: center; }
.cf-stage canvas { max-width: 100%; max-height: 100%; display: block; }
.cf-eps-placeholder { position: absolute; inset: 0; display: grid; place-items: center; text-align: center; padding: 16px; font-size: 13px; color: var(--muted); background: var(--bg); }
.cf-cutline { position: absolute; border: 2px dashed rgb(255,0,127); border-radius: 2px; pointer-events: none; }
.cf-cutline-label { position: absolute; left: 4px; bottom: 4px; font-size: 10px; color: rgb(255,0,127); background: rgba(255,255,255,.85); padding: 1px 5px; border-radius: 4px; pointer-events: none; }
/* Panels (SC-20260914-08): thin dashed join lines + panel numbers drawn over the artwork
   preview, positioned to match #cf-cutline's own inset (see renderCfPanelLines() in app.js) —
   panels butt-join, no overlap, so the lines sit exactly on the finished-size cut lines. */
.cf-panel-lines { position: absolute; pointer-events: none; }
.cf-panel-line { position: absolute; }
.cf-panel-line-v { top: 0; bottom: 0; border-left: 2px dashed rgba(20,20,20,.6); transform: translateX(-1px); }
.cf-panel-line-h { left: 0; right: 0; border-top: 2px dashed rgba(20,20,20,.6); transform: translateY(-1px); }
.cf-panel-num { position: absolute; transform: translate(-50%, -50%); font-size: 11px; font-weight: 700; color: rgba(20,20,20,.7); background: rgba(255,255,255,.85); padding: 1px 6px; border-radius: 999px; }

/* ---- A4 sample crop picker (SC-20260915-02) ---- */
.cf-a4-picker-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 0; padding: 6px 0 0; }
.cf-a4-instruction { font-weight: 600; color: var(--ink-2); margin: 0 0 4px; font-size: 12.5px; }
.cf-a4-overlay { position: absolute; inset: 0; cursor: move; }
.cf-a4-dim { position: absolute; background: rgba(20,20,30,.55); pointer-events: none; }
.cf-a4-box {
  position: absolute; border: 2px solid var(--accent); background: rgba(112,188,31,.12);
  box-shadow: 0 0 0 1px rgba(0,0,0,.35); cursor: move; touch-action: none; display: flex;
  align-items: flex-start; justify-content: center;
}
.cf-a4-box-label {
  margin-top: 6px; font-size: 11px; font-weight: 700; letter-spacing: .02em; text-align: center;
  color: #0b2e18; background: var(--accent); padding: 3px 9px; border-radius: 999px;
  white-space: nowrap; pointer-events: none; box-shadow: 0 2px 8px rgba(0,0,0,.25);
}

/* ---- "Helpful hints" panel (SC-20260915-04): light green tint, small type, holds every piece of
   explanatory copy that used to sit in the left column (material notes, the bleed paragraph,
   "print smaller instead", the artwork-tips list). */
.cf-tips { background: var(--brand-soft); border-radius: var(--radius); box-shadow: none; padding: 10px 14px; font-size: 0.85rem; }
.cf-tips h3 { margin: 8px 0 4px; font-size: 13px; }
.cf-tips h3:first-child { margin-top: 0; }
.cf-tips p.hint { font-size: 0.85rem; line-height: 1.4; color: var(--ink-2); margin: 0 0 6px; }
.cf-tips p.hint:empty { display: none; }
.cf-tips ul { font-size: 0.85rem; line-height: 1.4; margin: 0; padding-left: 16px; }
.cf-tips li { margin-bottom: 2px; }
.cf-tips .btn-link { font-size: 0.85rem; }

@media (max-width: 560px) {
  .cf-size-row { gap: 6px; }
}

/* ---- Delivery options ---- */
.delivery-opts { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.delivery-opt { display: flex; gap: 10px; align-items: flex-start; border: 1px solid #cfcfd6; border-radius: 9px; padding: 10px 12px; cursor: pointer; font-weight: 500; margin: 0; }
.delivery-opt:has(input:checked) { border-color: var(--accent); background: var(--brand-soft); box-shadow: 0 0 0 3px var(--accent-ring); }
.delivery-opt input { margin-top: 3px; accent-color: var(--accent); }
.delivery-opt span { display: flex; flex-direction: column; line-height: 1.3; }
.delivery-opt small { color: var(--muted); font-weight: 500; }
@media (max-width: 600px) { .delivery-opts { grid-template-columns: 1fr; } }
.addr-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; margin-top: 4px; padding: 12px 14px; border: 1px solid var(--line); border-radius: 9px; background: var(--bg); }
@media (max-width: 600px) { .addr-grid { grid-template-columns: 1fr; } .addr-grid .span-2 { grid-column: span 1; } }

/* ---- Cart / checkout layout ---- */
.cart-layout { display: grid; grid-template-columns: 1fr 320px; gap: 24px; align-items: start; }
@media (max-width: 900px) { .cart-layout { grid-template-columns: 1fr; } }
.cart-items { display: flex; flex-direction: column; gap: 12px; }
.cart-item { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 14px 16px; display: grid; grid-template-columns: 64px 1fr auto; gap: 14px; align-items: center; }
.cart-item img { width: 64px; height: 48px; object-fit: contain; border-radius: 6px; border: 1px solid var(--line); background: #fff; }
.cart-item-swatch, .cart-line-swatch { width: 64px; height: 48px; border-radius: 6px; background: var(--brand-soft); color: var(--brand-dark); display: grid; place-items: center; font-weight: 800; font-size: 11px; letter-spacing: .03em; }
.cart-line-swatch { width: 56px; height: 42px; font-size: 10px; }
.cart-item .name { font-weight: 700; font-size: 14px; }
.cart-item .sub { font-size: 12px; color: var(--muted); }
.cart-item .price-col { text-align: right; }
.cart-item .price-col .line-total { font-weight: 700; }
.cart-item .remove { background: none; border: 0; color: var(--muted); font-size: 12px; cursor: pointer; text-decoration: underline; padding: 4px 0; }
.cart-summary, aside.cart-summary { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 20px; display: flex; flex-direction: column; gap: 16px; }
.summary-lines { display: flex; flex-direction: column; gap: 6px; font-size: 14px; border-top: 1px solid var(--line); padding-top: 12px; }
.summary-lines .row { display: flex; justify-content: space-between; }
.summary-lines .total { font-weight: 800; font-size: 17px; border-top: 1px solid var(--line); padding-top: 8px; margin-top: 4px; }
.discount-note { font-size: 12px; color: var(--brand-dark); background: var(--brand-soft); border-radius: 6px; padding: 6px 8px; }

/* ---- Drawer ---- */
.drawer-backdrop { position: fixed; inset: 0; background: rgba(20,20,30,.4); z-index: 40; }
.drawer { position: fixed; top: 0; right: 0; bottom: 0; width: min(420px, 100vw); background: #fff; z-index: 41; display: flex; flex-direction: column; box-shadow: var(--shadow-lg); }
.drawer-head { display: flex; align-items: center; justify-content: space-between; padding: 18px 20px; border-bottom: 1px solid var(--line); }
.drawer-body { flex: 1; overflow: auto; padding: 8px 20px; }
.drawer-foot { padding: 16px 20px 20px; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 10px; }
.cart-total { display: flex; justify-content: space-between; font-weight: 700; font-size: 15px; }
.cart-total .muted { font-weight: 500; font-size: 13px; }
.cart-line { display: grid; grid-template-columns: 56px 1fr auto; gap: 12px; align-items: center; padding: 12px 0; border-bottom: 1px solid var(--line); }
.cart-line img { width: 56px; height: 42px; object-fit: contain; border-radius: 6px; border: 1px solid var(--line); background: #fff; }
.cart-line .name { font-weight: 600; font-size: 13px; }
.cart-line .sub { font-size: 11.5px; color: var(--muted); }
.cart-empty { text-align: center; color: var(--muted); padding: 50px 10px; }

/* ---- Lightbox & toast ---- */
.toast { position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%); background: var(--ink); color: #fff; padding: 12px 18px; border-radius: 10px; font-weight: 600; font-size: 14px; z-index: 70; box-shadow: var(--shadow-lg); }

.site-footer { text-align: center; padding: 34px 24px; color: var(--sc-on-dark-soft); font-size: 13px; background: var(--sc-green-deep); }
.site-footer a { color: var(--sc-on-dark-soft); font-weight: 600; text-decoration: none; }
.site-footer a:hover { color: #fff; }
.footer-brand { display: inline-block; width: 170px; margin-bottom: 14px; }
.footer-brand img { width: 100%; height: auto; display: block; }
.footer-tag { font-weight: 600; color: #fff; margin: 0 0 10px; letter-spacing: .01em; }
.footer-contact { margin: 0; }
.footer-contact .dot { margin: 0 6px; opacity: .6; }

/* ---- Responsive ---- */
@media (max-width: 860px) {
  .topbar-inner { gap: 10px; padding: 0 12px; height: auto; flex-wrap: wrap; padding-top: 8px; padding-bottom: 8px; }
  .brand-plate { width: 126px; height: 40px; }
  .brand-logo { top: -2px; }
  .brand-sub { display: none; }
  .cart-btn { margin-left: auto; padding: 8px 12px; }
  .cart-btn span:not(.badge) { display: none; }
  /* The wrapped tabs row sits directly under the bar, in the space the hanging logo overhangs
     into (this SPA wraps nav inline rather than a hamburger dropdown) - the extra top padding
     here is the same "give the drop-down room" rule the main site applies to its own mobile menu. */
  .tabs { order: 10; width: 100%; margin-left: 0; padding-top: 34px; flex-wrap: wrap; }
  .tab { flex: 1 1 auto; text-align: center; padding: 8px 6px; white-space: nowrap; }
  .tab-external { flex-basis: 100%; order: 5; }
  /* The wrapped tabs row (above) already gives the hanging logo room inside the header itself on
     phone, so main content doesn't need the desktop's ~100px clearance underneath it. */
  main.page { padding: 24px 14px 80px; }
  .filters { align-items: stretch; width: 100%; }
  .chips { justify-content: flex-start; }
}

/* ---- Account menu (SC-20260914-02) ---- */
.account-menu { position: relative; }
.account-btn { display: flex; align-items: center; gap: 4px; font: inherit; font-weight: 600; font-size: 14px; background: var(--brand-soft); color: var(--brand-dark); border: 0; border-radius: 9px; padding: 9px 12px; cursor: pointer; }
.account-btn:hover { background: #d8ecdf; }
.account-dropdown { position: absolute; top: calc(100% + 8px); right: 0; background: #fff; border-radius: 10px; box-shadow: var(--shadow-lg); border: 1px solid var(--line); min-width: 170px; display: flex; flex-direction: column; padding: 6px; z-index: 35; }
.account-dropdown a, .account-dropdown button { display: block; width: 100%; text-align: left; font: inherit; font-size: 14px; font-weight: 500; padding: 9px 10px; border-radius: 7px; border: 0; background: none; color: var(--ink); cursor: pointer; text-decoration: none; }
.account-dropdown a:hover, .account-dropdown button:hover { background: var(--bg); }

/* ---- Modal (sign-in) ---- */
.modal-backdrop { position: fixed; inset: 0; background: rgba(20,20,30,.45); z-index: 50; }
.modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: min(400px, calc(100vw - 32px)); background: #fff; border-radius: var(--radius); box-shadow: var(--shadow-lg); z-index: 51; }
.modal-head { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; border-bottom: 1px solid var(--line); }
.modal-body { padding: 20px; }
.signin-step { display: flex; flex-direction: column; gap: 12px; }

/* ---- Order status badges ---- */
.status-badge { display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; padding: 3px 9px; border-radius: 999px; }
.status-pending_payment { background: #fff5dd; color: #7a5200; }
.status-paid { background: #e6f0ff; color: #1a4f9b; }
.status-in_production { background: #f0e8ff; color: #5a2fa8; }
.status-ready { background: #fff0d6; color: #a85b00; }
.status-shipped { background: #e6f6ec; color: #16693a; }
.status-cancelled { background: #fdecec; color: #9b1c1c; }

/* ---- Your orders ---- */
.order-card { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px 20px; margin-bottom: 14px; }
.order-card-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid var(--line); }
.order-card-head .order-number { font-weight: 800; font-size: 15px; }
.order-card-head .order-date { color: var(--muted); font-size: 13px; }
.order-card-head .order-total { margin-left: auto; font-weight: 800; }
.order-meta { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 12.5px; color: var(--muted); margin: -4px 0 12px; }
.order-lines { display: flex; flex-direction: column; gap: 10px; margin-bottom: 12px; }
.order-line { display: grid; grid-template-columns: 56px 1fr auto; gap: 12px; align-items: center; }
.order-line img, .order-line .cart-item-swatch { width: 56px; height: 42px; }
.price-changed-note { font-size: 12px; color: var(--warn); background: #fff5dd; border-radius: 6px; padding: 5px 8px; margin-top: 4px; }

/* ---- Account page / address book (SC-20260914-14) ---- */
.account-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start; }
@media (max-width: 900px) { .account-layout { grid-template-columns: 1fr; } }
.account-card h3 { margin: 0 0 4px; }
.account-card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 4px; }
.account-card-head h3 { margin: 0; }
#acc-email { color: var(--muted); background: var(--bg); cursor: not-allowed; }
.address-card { border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; margin-bottom: 10px; }
.address-card-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.address-label { font-weight: 700; font-size: 13.5px; }
.badge-default { font-size: 10.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--brand-dark); background: var(--brand-soft); border-radius: 999px; padding: 2px 8px; }
.address-lines { font-size: 13px; color: var(--ink-2); line-height: 1.5; }
.address-actions { display: flex; gap: 14px; margin-top: 8px; flex-wrap: wrap; }
.address-actions button { background: none; border: 0; padding: 0; font: inherit; font-size: 12.5px; font-weight: 600; color: var(--sc-lime-deep); text-decoration: underline; cursor: pointer; }
.address-actions button[data-addr-delete] { color: var(--red); }
.account-address-form { display: flex; flex-direction: column; gap: 14px; border-top: 1px solid var(--line); margin-top: 14px; padding-top: 14px; }

/* ---- Admin ---- */
.admin-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 22px; }
@media (max-width: 800px) { .admin-stats { grid-template-columns: repeat(2, 1fr); } }
.stat-tile { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 16px 18px; }
.stat-tile .stat-value { font-size: 26px; font-weight: 800; }
.stat-tile .stat-label { font-size: 12px; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: .03em; margin-top: 2px; }
.admin-toolbar { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.admin-toolbar input[type=search] { max-width: 280px; }
.admin-toolbar select { max-width: 200px; }
.admin-table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; }
.admin-table th, .admin-table td { padding: 10px 12px; text-align: left; font-size: 13.5px; border-bottom: 1px solid var(--line); vertical-align: top; }
.admin-table th { background: var(--bg); font-size: 11px; text-transform: uppercase; letter-spacing: .03em; color: var(--muted); }
.admin-table tr:last-child td { border-bottom: 0; }
.admin-table .clickable { cursor: pointer; color: var(--sc-lime-deep); font-weight: 600; text-decoration: underline; background: none; border: 0; font: inherit; padding: 0; }
.status-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.admin-back { margin-bottom: 14px; }
.spec-line { font-size: 11px; color: var(--muted); margin-top: 2px; }
.spec-line-check { color: var(--warn); font-weight: 700; }

@media (max-width: 700px) {
  .admin-table thead { display: none; }
  .admin-table, .admin-table tbody, .admin-table tr, .admin-table td { display: block; width: 100%; }
  .admin-table tr { border-bottom: 6px solid var(--bg); padding: 10px 0; }
  .admin-table td { border-bottom: 0; padding: 4px 12px; }
  .admin-table td::before { content: attr(data-label); display: block; font-size: 10px; text-transform: uppercase; color: var(--muted); font-weight: 700; }
}

input[type=file] { font-size: 13px; }
input[type=file]::file-selector-button { font: inherit; font-size: 13px; font-weight: 600; padding: 7px 12px; border: 1px solid #cfcfd6; border-radius: 8px; background: #fff; cursor: pointer; margin-right: 10px; }
input[type=file]::file-selector-button:hover { border-color: var(--accent-dark); color: var(--sc-lime-deep); }

/* ===== HAZCHEM builder (SC-20260914-07) — fields on the left, a big live preview on the right
   (the reverse column order of "print your own", where the stage sits inside the form column).
   SC-20260914-09 restyle round 2 (Sam: "go properly dark... the fillable areas must be
   unmistakable at a glance"): the form column (.hazchem-layout .custom-form) is a deep-slate card
   with light text — scoped to .hazchem-layout so "print your own"'s identical .custom-form class,
   and every other page, are untouched. The preview stage and hints/compliance cards stay light on
   purpose, so the sign preview still pops against the dark form beside it. */
.hazchem-layout { grid-template-columns: 420px 1fr; align-items: start; }
@media (max-width: 900px) { .hazchem-layout { grid-template-columns: 1fr; } }
.hazchem-layout .custom-form { background: var(--hz-panel-bg); border: 1px solid var(--hz-panel-border); color: var(--hz-text); }
.hazchem-layout .custom-form label { color: var(--hz-text); }
.hazchem-layout .custom-form .hint, .hazchem-layout .custom-form .muted { color: var(--hz-muted); }
.hazchem-layout .custom-form .custom-price { border-top-color: var(--hz-panel-border); color: var(--hz-text); }
.hazchem-layout .custom-form .card-price small { color: var(--hz-muted); }
.hazchem-layout .custom-form .discount-note { background: rgba(112,188,31,.25); color: #d9ead1; }
/* SC-20260921-02 (Sam: "compact it all"): tighter padding/gaps/labels than the base .custom-form,
   now that everything (substances, suggestion, fine-tune, size/qty) shares this one left column -
   same idea as .cf-layout's own compacting below, tuned a bit looser since this column scrolls
   internally (see the no-scroll block right after this one) rather than needing to fit unaided. */
.hazchem-layout .custom-form { padding: 14px 16px; gap: 8px; }
.hazchem-layout .custom-form label { font-size: 12px; margin-bottom: 3px; }
.hazchem-layout .custom-form input[type=text], .hazchem-layout .custom-form input[type=number],
.hazchem-layout .custom-form select, .hazchem-layout .custom-form textarea { padding: 6px 9px; font-size: 13px; }
.hazchem-layout .field-row { gap: 8px; }
.hazchem-layout .wiz-step-heading { margin-top: 6px; font-size: 15px; }
.hazchem-layout .wiz-step-heading:first-child { margin-top: 0; }
/* SC-20260921-02 (Sam: "I want it so we dont need to scroll on the page ... bring the hazchem
   proof image to the top of the page"): same shape as "Print your own" (.cf-layout) - the proof
   is the first thing in the right column, and the whole two-column area is capped to the viewport
   (fitHzLayout() in app.js sets #wiz-builder-anchor's height) so the page itself never scrolls on
   desktop/laptop. The LEFT column scrolls internally instead (it's the one with everything to
   fill in); the right column's own height is spent on the stage first, caption/warning next, and
   the hints panel last, scrolling internally itself if its content doesn't fit what's left. */
@media (min-width: 901px) {
  .hazchem-layout { align-items: stretch; }
  /* position: relative here matters, not just cosmetics: without a positioned ancestor, an
     absolutely-positioned descendant (e.g. the visually-hidden <label> on #hz-freetext) is
     positioned against the initial containing block instead of this scroller, so it escapes
     overflow-y's clipping and its static-position offset (computed from its place in the FULL,
     un-scrolled flow) was blowing out document.documentElement.scrollHeight even though nothing
     was visibly wrong. Making .custom-form the containing block keeps it - and any future
     absolutely-positioned descendant - properly clipped/scrolled with everything else. */
  .hazchem-layout .custom-form { overflow-y: auto; min-height: 0; position: relative; }
  .hazchem-preview-side { min-height: 0; overflow: hidden; position: static; }
}
.hazchem-preview-side { display: flex; flex-direction: column; gap: 10px; }
@media (max-width: 900px) { .hazchem-preview-side { order: -1; } }
/* SC-20260921-01 (Sam: "put the sizes on the proof page too"). Light area (matches the rest of
   .hazchem-preview-side), sits right under the live SVG preview. */
.hz-size-caption { margin: 0; font-size: 13px; font-weight: 600; color: var(--muted); text-align: center; flex: none; }
.hz-picto-warning { margin: 0; padding: 10px 12px; border-radius: 10px; background: #fff7ed; border: 2px solid #f59e0b; color: #92400e; font-size: 12.5px; font-weight: 600; line-height: 1.4; flex: none; }
.hazchem-stage { aspect-ratio: unset; min-height: 200px; background: repeating-conic-gradient(#f0f0f3 0% 25%, #fff 0% 50%) 50% / 16px 16px; padding: 16px; }
@media (min-width: 901px) {
  .hazchem-stage { flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; overflow: hidden; }
}
/* SC-20260921-03: the readability line always shows under the caption (guidance, never a
   compliance statement); the site/panel note below it only shows sometimes (see hzRenderSizeInfo
   in app.js) - both flex:none so they never eat space from the stage above them. */
.hz-readability { margin: 0; font-size: 12px; font-weight: 500; color: var(--muted); text-align: center; flex: none; }
.hz-svg-preview { width: 100%; max-width: 420px; }
/* Direct-child selector only - a HAZCHEM SVG nests further <svg> elements for its pictograms
   (site/public/sign-render.js's pictogramMarkup()), each with its own explicit width/height
   already sized to its grid cell; a bare `svg` descendant selector here would also match those
   and force each one to 100% width, blowing every pictogram up to the full preview width. */
.hz-svg-preview > svg { width: 100%; height: auto; display: block; box-shadow: 0 2px 10px rgba(0,0,0,.15); }
/* SC-20260921-02: on desktop, .hazchem-stage is now a flex box with a fixed (flex-grown) cross
   size, not an aspect-ratio box sized off the sign's own width - so the sign has to "contain"-fit
   both ways (a tall portrait sign shouldn't blow past the stage's height, a wide one shouldn't
   blow past its width). The classic replaced-element contain trick: both width and height auto,
   clamped by max-width/max-height against the stage's own definite size. */
@media (min-width: 901px) {
  /* .hz-svg-preview's own width AND height must both be DEFINITE here (not auto): a shrink-to-fit
     wrapper whose only child sizes itself with percentage max-width/max-height back against that
     same wrapper is a circular reference the spec treats as no constraint at all - width:auto
     alone left the wrapper (and the svg inside it) collapsing to 0 width, and height:auto alone
     (the very first fix here) let the svg render at its full intrinsic size (e.g. 1000x1333px),
     invisibly clipped by .hazchem-stage's overflow:hidden instead of actually scaling down, which
     blew out document.documentElement.scrollHeight and failed the no-page-scroll requirement.
     Filling the wrapper to the stage's full (definite) box on both axes gives the svg's own
     max-width/max-height:100% a real reference on both axes, so the classic replaced-element
     "contain" fit (auto width/height clamped by max-width/max-height, ratio preserved via the
     svg's viewBox) actually has something to resolve against. */
  .hz-svg-preview { width: 100%; height: 100%; max-width: 100%; max-height: 100%; min-width: 0; min-height: 0; display: flex; align-items: center; justify-content: center; }
  .hz-svg-preview > svg { width: auto; height: auto; max-width: 100%; max-height: 100%; }
}
.hazchem-disclaimer { font-size: 12.5px; background: var(--hz-row-bg); border: 2px solid #f59e0b; border-radius: 10px; padding: 12px 14px; margin: 14px 0; color: var(--hz-text); }
.hazchem-disclaimer p { margin: 0 0 10px; color: var(--hz-text); }
.hz-ack-check { display: flex; gap: 8px; align-items: flex-start; font-size: 13px; font-weight: 600; cursor: pointer; color: var(--hz-text); }
.hz-ack-check input { margin-top: 2px; accent-color: var(--hz-accent); width: 18px; height: 18px; flex: none; }
/* Pictograms/precautions/layout radios/"add substance" button: white boxes on the dark card, 2px
   border, bright-green focus/active ring - never a solid dark-on-dark control. */
.hz-picto-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(74px, 1fr)); gap: 8px; max-height: 260px; overflow-y: auto; padding: 8px; border: 1px solid var(--hz-panel-border); border-radius: 8px; background: rgba(0,0,0,.15); }
.hz-chip { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 6px 4px; border: 2px solid var(--hz-field-border); border-radius: 8px; background: #fff; cursor: pointer; text-align: center; }
.hz-chip img { width: 40px; height: 40px; object-fit: contain; }
.hz-chip span { font-size: 10px; line-height: 1.2; color: var(--ink-2); }
.hz-chip.active { border-color: var(--hz-accent); background: #fff; box-shadow: 0 0 0 2px var(--hz-accent) inset; }
.hz-chip:disabled, .hz-chip.disabled { opacity: .4; cursor: not-allowed; }
.hz-check-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
@media (max-width: 560px) { .hz-check-grid { grid-template-columns: 1fr; } }
.hz-check { display: flex; gap: 8px; align-items: flex-start; font-size: 13px; font-weight: 500; cursor: pointer; color: var(--hz-text); }
.hz-check input { margin-top: 2px; accent-color: var(--hz-accent); width: 17px; height: 17px; }
/* Every fillable control inside the HAZCHEM builder is a white box with a strong border and an
   amber/green focus ring - never dark-on-dark, so it reads as "fill this in" at a glance. */
.hazchem-layout .custom-form input[type=text], .hazchem-layout .custom-form input[type=number],
.hazchem-layout .custom-form input:not([type]), .hazchem-layout .custom-form textarea,
.hazchem-layout .custom-form select {
  background: #fff; color: var(--ink); border: 2px solid var(--hz-field-border);
}
.hazchem-layout .custom-form input:focus, .hazchem-layout .custom-form textarea:focus, .hazchem-layout .custom-form select:focus {
  border-color: var(--hz-accent); box-shadow: 0 0 0 4px rgba(112,188,31,.45), 0 0 0 1px var(--hz-accent-dark); }
.hazchem-layout .custom-form .btn-ghost { background: #fff; color: var(--ink); border: 2px solid var(--hz-field-border); }
.hazchem-layout .custom-form .btn-link { color: var(--hz-muted); }
.hazchem-layout .custom-form .icon-btn { color: var(--hz-muted); }
.hazchem-layout .custom-form .icon-btn:hover { color: #fff; background: rgba(255,255,255,.08); }
/* Layout radio (site placard / substance panel): white unselected, bright-green fill + dark text
   when checked - the exact "bright green fill" treatment Sam asked for on the selected option. */
.hazchem-layout .custom-form .delivery-opt { background: #fff; color: var(--ink); border: 2px solid var(--hz-field-border); }
.hazchem-layout .custom-form .delivery-opt small { color: var(--muted); }
.hazchem-layout .custom-form .delivery-opt:has(input:checked) { background: var(--hz-accent); border-color: var(--hz-accent-dark); color: var(--hz-accent-text); }
.hazchem-layout .custom-form .delivery-opt:has(input:checked) small { color: var(--hz-accent-text); opacity: .8; }
.req { color: #fca5a5; font-weight: 800; }
.hazchem-layout .custom-form .req { color: #fca5a5; }
/* SC-20260921-02 (Sam: "remove the 'where is it going' that can be done in number 3 layout") -
   the site/panel cards are gone; this compact two-option toggle is now the ONE place layout is
   set, inside "Fine-tune your sign". Same "white unselected, bright-green fill when picked"
   treatment as every other fillable-looking control in this dark form. */
.hz-layout-toggle { display: flex; gap: 8px; }
.hz-layout-opt, .hz-orient-opt { flex: 1 1 0; font: inherit; font-weight: 700; font-size: 12.5px; padding: 9px 8px; border-radius: 10px; border: 2px solid var(--hz-field-border); background: #fff; color: var(--ink); cursor: pointer; text-align: center; }
.hz-layout-opt:hover, .hz-orient-opt:hover { border-color: var(--hz-accent-dark); }
.hz-layout-opt.active, .hz-orient-opt.active { background: var(--hz-accent); border-color: var(--hz-accent-dark); color: var(--hz-accent-text); }
.hz-layout-rule { margin: 6px 0 0; font-size: 11.5px; font-weight: 600; color: var(--hz-muted); line-height: 1.35; }
/* SC-20260921-03: "make the first choice Site sign or Substance panel" - the Layout control is
   now the very first thing in the left column, so it gets a bit more breathing room below it than
   a normal .field, and the vehicle tick box (substance panel only) sits right under its rule
   line, styled like the disclaimer's own checkbox row. */
.wiz-layout-field { margin-bottom: 4px; }
.hz-vehicle-check { display: flex; gap: 8px; align-items: flex-start; font-size: 12.5px; font-weight: 600; cursor: pointer; color: var(--hz-text); margin-top: 8px; }
.hz-vehicle-check input { margin-top: 2px; accent-color: var(--hz-accent); width: 16px; height: 16px; flex: none; }

/* ===== HAZCHEM guided wizard (SC-20260914-09) — "What you're storing" fields and the inline
   suggestion banner, now merged into the same left column as the builder below them
   (SC-20260921-02) rather than sitting in their own full-width cards above it. */
.wiz-step-heading { margin: 0 0 4px; font-size: 15px; font-weight: 700; color: var(--hz-text); }

/* SC-20260921-02 (Sam: "the quantity needs to be under the substance, compact it all") - the
   substance select sits on its own line, full width of the narrow left column; quantity+unit and
   the remove (×) button share a second, tighter line under it. */
.wiz-sub-row { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.wiz-sub-row-2 { display: flex; gap: 8px; align-items: flex-end; }
.wiz-sub-row-2 .wiz-sub-qty { flex: 1 1 auto; min-width: 0; }
.wiz-sub-field label { display: block; font-size: 12px; font-weight: 600; color: var(--hz-text); margin-bottom: 3px; }
/* SC-20260914-15: a plain <select> per substance row (Sam: "should be a drop-down") replaced the
   old type-ahead text box + dropdown list. */
.wiz-sub-select { width: 100%; background: #fff; color: var(--ink); border: 2px solid var(--hz-field-border); }
.wiz-sub-select:focus { border-color: var(--hz-accent); box-shadow: 0 0 0 4px rgba(112,188,31,.45), 0 0 0 1px var(--hz-accent-dark); }
.wiz-qty-row { display: flex; gap: 6px; }
.wiz-qty-row input { flex: 1 1 auto; min-width: 0; background: #fff; color: var(--ink); border: 2px solid var(--hz-field-border); }
.wiz-qty-row select { flex: none; width: 62px; background: #fff; color: var(--ink); border: 2px solid var(--hz-field-border); }
.wiz-qty-row input:focus, .wiz-qty-row select:focus { border-color: var(--hz-accent); box-shadow: 0 0 0 4px rgba(112,188,31,.45), 0 0 0 1px var(--hz-accent-dark); }
.wiz-sub-remove { flex: none; }

/* SC-20260921-03 (Sam: "Remove - use this suggestion. and just fill out the hazchem chart as it
   goes") - no more rows/button, just a quiet one-line note (what got filled in, and that it's all
   still editable) plus the threshold verdict, in the same slim slate panel as before. */
.wiz-suggestion-inline { border: 2px solid var(--hz-accent-dark); border-radius: 10px; padding: 10px 12px; background: var(--hz-row-bg); margin: 2px 0; }
#wiz-suggestion-note { margin: 0 0 8px; font-size: 12.5px; font-weight: 500; color: var(--hz-muted); font-style: italic; }
.wiz-suggestion-inline .wiz-threshold { margin: 0; }
.wiz-threshold { margin: 4px 0 16px; padding: 10px 12px; border-radius: 9px; background: rgba(0,0,0,.12); border-left: 4px solid var(--hz-accent); font-size: 13px; font-weight: 500; color: #fff; }
.wiz-threshold.warn { background: #3f2323; border-left-color: #f87171; color: #fecaca; }
.wiz-picto-preview { display: flex; gap: 8px; flex-wrap: wrap; }
.wiz-picto-preview img { width: 34px; height: 34px; object-fit: contain; background: #fff; border-radius: 4px; padding: 2px; }
/* Prominent primary action: solid bright green, dark text - "Add to cart" must read as THE thing
   to click next. */
.hz-add-btn {
  background: var(--hz-accent); color: var(--hz-accent-text); border-color: var(--hz-accent-dark);
  padding: 15px 20px; font-size: 16px; font-weight: 800; box-shadow: 0 6px 18px rgba(112,188,31,.45);
}
.hz-add-btn:hover:not(:disabled) { background: #8ad42f; box-shadow: 0 8px 22px rgba(112,188,31,.55); }
.hz-add-btn:disabled { background: #6b7280; color: #d1d5db; box-shadow: none; cursor: not-allowed; }
/* SC-20260914-12 (audit item 6): the button is now GENUINELY disabled (real `disabled` +
   `aria-disabled`, set in hzRefreshAll in app.js) whenever the acknowledgement isn't ticked, a
   field's missing/invalid, or the size/material combo is oversize — this class just keeps the
   same look it always had for that state. Because a disabled button doesn't dispatch a click,
   #hz-add-wrap (the padded box around it) carries its own click listener so clicking anywhere in
   that surrounding area still surfaces the "tick the box first" message and focuses the checkbox. */
.hz-add-btn.hz-needs-ack { background: #6b7280; color: #d1d5db; box-shadow: none; cursor: not-allowed; }
.hz-add-wrap { padding: 8px; margin: 0 -8px; }

/* SC-20260921-03 (Sam: "Helpful hints can be exploded on the bottom, listing all the sources,
   that part and be scrolled to on the page") - hints/links/sources moved out of the two-column
   layout entirely into one closed-by-default <details> block below it, plain light card styling
   (Sam: "the preview stage and the hints panel stay light"). Closed by default so it never counts
   against the builder's own no-page-scroll requirement; the page is free to scroll down to reach
   it, same as any other section. */
.hazchem-hints-details { max-width: 900px; margin: 18px auto 0; background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 4px 20px; }
.hazchem-hints-details summary { padding: 14px 0; font-weight: 700; font-size: 15px; cursor: pointer; color: var(--ink); list-style: none; display: flex; align-items: center; gap: 8px; }
.hazchem-hints-details summary::-webkit-details-marker { display: none; }
.hazchem-hints-details summary::before { content: '▸'; display: inline-block; transition: transform .15s ease; color: var(--muted); }
.hazchem-hints-details[open] summary::before { transform: rotate(90deg); }
.hazchem-hints-body { padding-bottom: 18px; }
.hazchem-hints-body ul { margin: 0 0 14px; padding-left: 18px; font-size: 13px; line-height: 1.6; color: var(--ink-2); }
.hazchem-hints-body h3 { font-size: 14px; margin: 0 0 8px; }
.wiz-links-list { list-style: none !important; padding-left: 0 !important; }
.wiz-links-list li { margin-bottom: 8px; }
.wiz-links-list a { font-weight: 600; }
.wiz-links-list small { display: block; color: var(--muted); font-weight: 400; font-size: 11.5px; }

/* SC-20260921-01: the header is sticky and the logo hangs below it, so anything we scroll to
   (the builder, a wizard step, a form with an error) has to stop short of it or it lands under
   the bar. One rule for every scrollIntoView target on the site. */
.view, .page-head, .custom-layout, #wiz-builder-anchor, .hazchem-hints-details,
.view h2, .view h3, form { scroll-margin-top: 124px; }
@media (max-width: 900px) { .view, .page-head, .custom-layout, #wiz-builder-anchor, .hazchem-hints-details, .view h2, .view h3, form { scroll-margin-top: 96px; } }

/* SC-20260921-02: #form-hazchem wraps the fine-tune/size/qty/disclaimer/Add-to-cart fields so
   Enter in a substance quantity field above it (outside this <form>) can never submit Add to cart
   early - but visually its fields need to lay out as plain flex children of the surrounding
   .custom-form card (same padding/gap as everything else in that column), not as their own nested
   box. display:contents removes the <form> element's own box while keeping its submit semantics. */
#form-hazchem { display: contents; }
