/* eslint-disable css/no-invalid-properties -- the custom properties come from the generated tokens.css, which the CSS linter cannot resolve */
.sd-state {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: 8px;
	padding: 32px 16px;
	max-width: 420px;
	margin: 0 auto;
}

.sd-state-icon {
	width: 48px;
	height: 48px;
	border-radius: 50%;
	display: grid;
	place-items: center;
	background: var(--surface-sunken);
	color: var(--ink-muted);
	margin-bottom: 8px;
}

.sd-state-error .sd-state-icon {
	background: var(--danger-soft);
	color: var(--danger);
}

.sd-state-offline .sd-state-icon {
	background: var(--sub-soft);
	color: var(--sub);
}

.sd-state-kind {
	font-size: 0.875rem;
	font-weight: 700;
	color: var(--danger);
}

.sd-state .sd-title-3 {
	font-size: 1.125rem;
	line-height: 1.5rem;
	font-weight: 700;
	margin: 0;
}

.sd-state .sd-caption {
	font-size: 0.875rem;
	line-height: 1.25rem;
	color: var(--ink-muted);
	margin: 0;
}

.sd-state .ant-btn {
	margin-top: 8px;
}

/* eslint-disable css/no-invalid-properties -- the custom properties come from the generated tokens.css, which the CSS linter cannot resolve */
.sd-icon {
	flex: none;
	display: inline-block;
	vertical-align: middle;
}

.sd-powered {
	display: inline-flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 6px;
	font-size: 0.875rem;
	line-height: 1.25rem;
	color: var(--ink-muted);
}

.sd-powered b {
	color: var(--ink);
	font-weight: 700;
}

/* One green per logo: the wordmark is brand-pine, never the theme's pine, which turns mint in the dark theme. */
.sd-wordmark {
	display: block;
	fill: var(--brand-pine);
	flex: none;
}

[data-theme='dark'] .sd-wordmark {
	fill: var(--ink);
}

.sd-wordmark-ink {
	fill: var(--ink);
}

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

/* The mark is the same in both themes: a brand-pine tile, white ink and a harvest tin. `--on-pine` cannot be the ink,
   because it turns dark in the dark theme where pine turns mint; the white is the one deliberate fixed colour. */
.sd-mark-tile {
	fill: var(--brand-pine);
}

.sd-mark-ink {
	fill: #fff;
}

.sd-mark-tin {
	fill: var(--harvest);
}

/* eslint-disable css/no-invalid-properties -- the custom properties come from the generated tokens.css and Ant Design's theme variables (--sd-*), which the CSS linter cannot resolve */

/* The public pages (PublicChrome and its parts). Colours are the design tokens (tokens.css); sizes are Ant Design's
   theme variables (--sd-*), which remTokens.ts writes in rem, so every space and type size follows the person's text
   size. The column widths are in rem for the same reason. */

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

.sd-pub {
	min-height: 100dvh;
	display: flex;
	flex-direction: column;
	background: var(--surface);
	color: var(--ink);
	font-size: var(--sd-font-size);
	line-height: var(--sd-line-height);
}

.sd-pub-bar {
	border-color: var(--line);
	border-style: solid;
	border-width: 0;
}

.sd-pub-header {
	border-bottom-width: var(--sd-line-width);
}

.sd-pub-footer {
	border-top-width: var(--sd-line-width);
	color: var(--ink-muted);
	font-size: var(--sd-font-size-sm);
	line-height: var(--sd-line-height-sm);
}

.sd-pub-bar-inner {
	/* 1120px at the default text size: the design's widest column. */
	max-width: 70rem;
	margin: 0 auto;
	padding: var(--sd-padding-sm) var(--sd-padding-lg);
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--sd-padding-xs);
}

.sd-pub-home {
	display: inline-flex;
	align-items: center;
	min-height: var(--sd-control-height);
}

/* An address the person typed is one long word: at 375px and 200% text it ran past the screen. Any word may break
   rather than widen the page (WCAG 1.4.10). */
.sd-pub-main {
	overflow-wrap: anywhere;
	flex-grow: 1;
	width: 100%;
	margin: 0 auto;
	padding: var(--sd-padding-xl) var(--sd-padding-lg);
	display: flex;
	flex-direction: column;
	gap: var(--sd-padding-lg);
}

/* One column of reading: 720px at the default text size. */
.sd-pub-main-narrow {
	max-width: 45rem;
}

.sd-pub-main-wide {
	max-width: 70rem;
	flex-direction: row;
	flex-wrap: wrap;
	align-items: center;
	column-gap: var(--sd-margin-xxl);
	row-gap: var(--sd-margin-xxl);
}

@media (min-width: 48em) {
	.sd-pub-main {
		padding-block: var(--sd-margin-xxl);
	}
}

/* A phone gets the 16px gutter the rest of the app uses, so 200% text still leaves room for a word. */
@media (max-width: 30em) {
	.sd-pub-main,
	.sd-pub-bar-inner {
		padding-inline: var(--sd-padding);
	}
}

/* Columns of the wide layout. The basis is in em so the columns stack sooner as the text grows. */
.sd-pub-column {
	flex: 1 1 26em;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: var(--sd-padding-lg);
}

.sd-pub-column-aside {
	flex-basis: 20em;
	gap: var(--sd-padding);
}

.sd-pub-stack {
	display: flex;
	flex-direction: column;
	gap: var(--sd-padding);
}

/* Type */
.sd-pub-h1 {
	margin: 0;
	font-size: var(--sd-font-size-heading-1);
	line-height: var(--sd-line-height-heading-1);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--ink);
}

.sd-pub-h2 {
	margin: 0;
	font-size: var(--sd-font-size-heading-3);
	line-height: var(--sd-line-height-heading-3);
	font-weight: 700;
}

.sd-pub-lead {
	margin: 0;
	max-width: 34em;
	font-size: var(--sd-font-size-lg);
	line-height: var(--sd-line-height-lg);
}

.sd-pub-p {
	margin: 0;
}

.sd-pub-caption {
	margin: 0;
	color: var(--ink-muted);
	font-size: var(--sd-font-size-sm);
	line-height: var(--sd-line-height-sm);
}

.sd-pub-fine {
	margin: 0;
	padding-top: var(--sd-padding-lg);
	border-top: var(--sd-line-width) solid var(--line);
}

.sd-pub a:not(.ant-btn) {
	color: var(--pine);
	font-weight: 700;
}

.sd-pub a:not(.ant-btn):hover {
	color: var(--pine-hover);
}

/* A link that stands alone gets the touch target, not only its line of text. */
.sd-pub-link {
	align-self: flex-start;
	min-height: var(--sd-control-height);
	display: inline-flex;
	align-items: center;
	gap: var(--sd-padding-xxs);
	text-decoration: none;
}

/* Status banner */
.sd-pub-banner {
	display: flex;
	align-items: center;
	gap: var(--sd-padding-xs);
	padding: var(--sd-padding-sm) var(--sd-padding);
	border-radius: var(--sd-border-radius);
	color: var(--ink);
	font-size: var(--sd-font-size-sm);
	line-height: var(--sd-line-height-sm);
	font-weight: 700;
}

.sd-pub-banner-compact {
	align-self: flex-start;
	padding: var(--sd-padding-xxs) var(--sd-padding-sm);
	border-radius: var(--sd-border-radius-sm);
}

.sd-pub-banner-pine {
	background: var(--pine-soft);
}

.sd-pub-banner-pine .sd-pub-banner-icon {
	color: var(--pine);
}

.sd-pub-banner-sub {
	background: var(--sub-soft);
}

.sd-pub-banner-sub .sd-pub-banner-icon {
	color: var(--sub);
}

.sd-pub-banner-danger {
	background: var(--danger-soft);
}

.sd-pub-banner-danger .sd-pub-banner-icon {
	color: var(--danger);
}

.sd-pub-banner-icon {
	flex: none;
}

/* Numbered steps */
.sd-pub-steps {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: var(--sd-padding);
}

.sd-pub-steps li {
	display: flex;
	gap: var(--sd-padding-sm);
}

.sd-pub-step-number {
	flex: none;
	width: var(--sd-control-height-sm);
	height: var(--sd-control-height-sm);
	border-radius: var(--sd-border-radius);
	background: var(--pine-soft);
	color: var(--pine);
	display: flex;
	align-items: center;
	justify-content: center;
	font-family: var(--font-mono);
	font-weight: 700;
}

/* Check list */
.sd-pub-checks {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: var(--sd-padding-xs);
}

.sd-pub-checks li {
	display: flex;
	gap: var(--sd-padding-sm);
}

.sd-pub-check-icon {
	flex: none;
	margin-top: var(--sd-padding-xxs);
	color: var(--pine);
}

.sd-pub-checks-boxed {
	gap: 0;
	padding: var(--sd-padding-xs) var(--sd-padding-lg);
	border: var(--sd-line-width) solid var(--line);
	border-radius: var(--sd-border-radius-lg);
	background: var(--surface-raised);
}

.sd-pub-checks-boxed li {
	padding: var(--sd-padding) 0;
}

.sd-pub-checks-boxed li + li {
	border-top: var(--sd-line-width) solid var(--line);
}

.sd-pub-checks-boxed .sd-pub-check-icon {
	color: var(--ink-muted);
}

/* Card section */
.sd-pub-card {
	padding: var(--sd-padding-lg);
	border: var(--sd-line-width) solid var(--line);
	border-radius: var(--sd-border-radius-lg);
	display: flex;
	flex-direction: column;
	gap: var(--sd-padding-xs);
}

.sd-pub-card-raised {
	background: var(--surface-raised);
}

.sd-pub-card-section {
	gap: var(--sd-padding);
}

.sd-pub-card-title {
	margin: 0;
	font-size: var(--sd-font-size-heading-4);
	line-height: var(--sd-line-height-heading-4);
	font-weight: 700;
}

.sd-pub-card-section .sd-pub-card-title {
	font-size: var(--sd-font-size-heading-3);
	line-height: var(--sd-line-height-heading-3);
}

.sd-pub-card p {
	margin: 0;
}

.sd-pub-card-link {
	align-self: flex-start;
	min-height: var(--sd-control-height);
	display: inline-flex;
	align-items: center;
}

/* Two cards side by side where they fit (Closed beta). */
.sd-pub-cards {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 17.5em), 1fr));
	gap: var(--sd-padding);
}

/* Forms: fields side by side where they fit, the action and its note on one line where they fit. */
.sd-pub-fields {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 15em), 1fr));
	gap: var(--sd-padding);
	align-items: start;
}

.sd-pub-fields-wide {
	grid-column: 1 / -1;
}

.sd-pub-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--sd-padding);
}

/* The waitlist's one-line form: the field grows, the button keeps its words on one line where it can. */
.sd-pub-inline-form {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	gap: var(--sd-padding-xs);
	max-width: 35em;
}

.sd-pub-inline-form > .ant-form-item {
	flex: 1 1 16em;
}

.sd-pub-inline-form > .ant-btn {
	flex: 0 1 auto;
}

/* Errors under a field come from antd; a form-level one sits in the flow like this. */
.sd-pub-error {
	margin: 0;
	color: var(--danger);
}

/* Override: Ant Design keeps a button's label on one line at a fixed height. On a phone at 200% text a public page's
   buttons ("Send to Sundries", "Back to sundries.ca") are wider than the screen, so they wrap like the block buttons in
   global.css do, keeping each size's height as the minimum (WCAG 1.4.4 and 1.4.10). */
.sd-pub .ant-btn {
	max-width: 100%;
	white-space: normal;
	height: auto;
	min-height: var(--sd-control-height);
	padding-block: var(--sd-padding-xxs);
}

.sd-pub .ant-btn.ant-btn-lg {
	min-height: var(--sd-control-height-lg);
}

/* A phone: cards and boxed lists take the 16px gutter inside too (after their own rules, so this wins). */
@media (max-width: 30em) {
	.sd-pub-card,
	.sd-pub-checks-boxed {
		padding-inline: var(--sd-padding);
	}
}

/* eslint-disable css/no-invalid-properties -- the custom properties are Ant Design's theme variables (--sd-*), which the CSS linter cannot resolve */

/* The widget sizes itself (Cloudflare's flexible size: the container's width, at least 300px); the message below it
   keeps the page's rhythm. */
.sd-turnstile {
	display: grid;
	gap: var(--sd-padding-xs);
	max-width: 100%;
}

/* atkinson-hyperlegible-next-latin-400-normal */
@font-face {
  font-family: 'Atkinson Hyperlegible Next';
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url(c510f25d4fe696cb1464.woff2) format('woff2'), url(ea73f7abe86ff3cd1a50.woff) format('woff');
}
/* atkinson-hyperlegible-next-latin-700-normal */
@font-face {
  font-family: 'Atkinson Hyperlegible Next';
  font-style: normal;
  font-display: swap;
  font-weight: 700;
  src: url(0b5e7bd6f8f8c4523fba.woff2) format('woff2'), url(3e87494964cc05731faa.woff) format('woff');
}
/* atkinson-hyperlegible-mono-latin-600-normal */
@font-face {
  font-family: 'Atkinson Hyperlegible Mono';
  font-style: normal;
  font-display: swap;
  font-weight: 600;
  src: url(6863ab363e8ad1d7efbe.woff2) format('woff2'), url(4fe4ea40ee3358515959.woff) format('woff');
}
/* atkinson-hyperlegible-mono-latin-700-normal */
@font-face {
  font-family: 'Atkinson Hyperlegible Mono';
  font-style: normal;
  font-display: swap;
  font-weight: 700;
  src: url(86f83bc077d3a0d57649.woff2) format('woff2'), url(130bc671adc782614e79.woff) format('woff');
}
/* Generated by scripts/generate-palette.mjs from tokens.json. Do not edit. */
:root[data-theme='light'] {
	--surface: #f6f4ef;
	--surface-raised: #ffffff;
	--surface-sunken: #ece9e1;
	--line: #dedad0;
	--line-strong: #857f73;
	--ink: #1c211d;
	--ink-muted: #535953;
	--pine: #1d5a40;
	--pine-hover: #164832;
	--pine-soft: #e1eee6;
	--on-pine: #ffffff;
	--brand-pine: #1d5a40;
	--harvest: #f0b43c;
	--on-harvest: #1c211d;
	--estimate: #7b4a00;
	--estimate-soft: #fbf0d9;
	--short: #a3361a;
	--short-soft: #fbe7e0;
	--sub: #1f5aa6;
	--sub-soft: #e3edfa;
	--danger: #b0221a;
	--danger-soft: #fce6e4;
	--focus: #1f5aa6;
	--plate: #ffffff;
	--scrim: rgba(13,15,13,0.48);
	--shadow-float: 0 1px 2px rgba(28,33,29,0.08), 0 4px 12px rgba(28,33,29,0.08);
	--shadow-overlay: 0 8px 32px rgba(28,33,29,0.18);
}

:root[data-theme='dark'] {
	--surface: #131613;
	--surface-raised: #1c201c;
	--surface-sunken: #0d0f0d;
	--line: #2e342e;
	--line-strong: #79817a;
	--ink: #eceee8;
	--ink-muted: #a9b0a8;
	--pine: #79cfa1;
	--pine-hover: #95dcb5;
	--pine-soft: #173325;
	--on-pine: #0b1a12;
	--brand-pine: #1d5a40;
	--harvest: #f0b43c;
	--on-harvest: #1c211d;
	--estimate: #f2c46b;
	--estimate-soft: #33280f;
	--short: #ff9a76;
	--short-soft: #3a1d14;
	--sub: #8fbaff;
	--sub-soft: #16253d;
	--danger: #ff8c84;
	--danger-soft: #3b1714;
	--focus: #8fbaff;
	--plate: #f4f2ec;
	--scrim: rgba(0,0,0,0.64);
	--shadow-float: 0 1px 2px rgba(0,0,0,0.5), 0 4px 12px rgba(0,0,0,0.4);
	--shadow-overlay: 0 8px 32px rgba(0,0,0,0.6);
}

/* eslint-disable css/no-invalid-properties -- the custom properties come from the generated tokens.css, which the CSS linter cannot resolve */

:root {
	--font-sans: "Atkinson Hyperlegible Next", system-ui, -apple-system, "Segoe UI", sans-serif;
	--font-mono: "Atkinson Hyperlegible Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

body {
	/* No browser default margin: the shell and the public pages draw their own gutters (the staff portal's staff.css
	   already did this; the shopper app had an 8px frame around every page). */
	margin: 0;
	background: var(--surface);
	color: var(--ink);
	font-family: var(--font-sans);
}

:focus-visible {
	outline: 2px solid var(--focus);
	outline-offset: 2px;
	box-shadow: none;
}

/* eslint-disable css/no-important -- reduced motion must beat component-level durations */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0s !important;
		transition-duration: 0s !important;
	}
}

.sd-skip {
	position: absolute;
	inset-inline-start: -9999px;
	top: 8px;
}

.sd-skip:focus {
	inset-inline-start: 8px;
	z-index: 10;
	padding: 8px 12px;
	background: var(--surface);
}

/* Full-width buttons wrap their label rather than clip it: at a large text size, or on a narrow screen, the label
   grows past one line (WCAG 1.4.4 and 1.4.10). Each size keeps its usual height as the minimum. */
.ant-btn.ant-btn-block {
	white-space: normal;
	height: auto;
	min-height: var(--sd-control-height);
	padding-block: var(--sd-padding-xxs);
}

.ant-btn.ant-btn-block.ant-btn-lg {
	min-height: var(--sd-control-height-lg);
}

.ant-btn.ant-btn-block.ant-btn-sm {
	min-height: var(--sd-control-height-sm);
}

/* The theme toggle: a touch target at least, but never wider than the column it sits in (the staff rail is 80px), and
   its label wraps rather than runs out of it at a large text size. Icon-only, it gives up its side padding first. */
.ant-btn.sd-theme-toggle {
	min-width: min(var(--sd-control-height), 100%);
	max-width: 100%;
	min-height: var(--sd-control-height);
	height: auto;
	white-space: normal;
	padding-block: var(--sd-padding-xxs);
}

.ant-btn.sd-theme-toggle.ant-btn-icon-only {
	padding-inline: 0;
}

