The 1 file this component needs and nothing else, each fenced with the path it belongs at, followed by what the library's own verification covered and what it did not. No instructions attached — for placing it yourself, or handing it to something that has its own.
Read it first
Install kit: "Sales contact section"
Library page: https://astro.baysixmedia.com/components/sales-contact-section/
Files: 1 required, 1 supporting
Write each block below to the path named in its header, relative to the project root. A block marked (required) is one the component does not work without; (supporting) is documentation. Nothing here needs downloading except a block that says so in as many words.
===== FILE (required): src/components/SalesContactSection.astro =====
---
/**
* Sales contact section
*
* A headline and a short paragraph on one side, a bordered form card on the
* other: the shape a "talk to sales" page takes. The card's fields sit two
* to a row above the breakpoint and one below it, and the fine print under
* the button carries whatever legal and help links the page owes.
*
* Static: no script at all. Every control is a native form element, so
* validation, keyboard behaviour and submission are the browser's, and the
* whole thing works with JavaScript switched off.
*
* Self-contained: no imports, no packages, no global stylesheet, no webfont.
* Every colour and measurement is a `--scs-*` custom property on the root.
*/
export interface SalesFieldOption {
label: string;
value?: string;
}
export interface SalesField {
/** Submitted under this name. */
name: string;
/** The visible label. */
label: string;
/** Native input type, or a select. */
type?: "text" | "email" | "tel" | "url" | "select";
/** A hint, never a label. Ignored for a select. */
placeholder?: string;
required?: boolean;
/** `half` lets two fields share a row above the breakpoint. */
span?: "half" | "full";
/** Passed straight through, so a browser can fill the field. */
autocomplete?: string;
/** Select only. A string is its own value. */
options?: (string | SalesFieldOption)[];
/** Select only. The text of the empty first option. */
placeholderOption?: string;
}
export interface SalesFootLink {
label: string;
href: string;
}
interface Props {
/** The headline. Unset: none. With neither heading nor body the card takes the full width. */
heading?: string;
/** Heading level, so it fits the page outline. */
headingLevel?: "h1" | "h2" | "h3";
/** A paragraph under it. Unset or `""`: none. */
body?: string;
/** The fields, in order. */
fields?: SalesField[];
/**
* Where the form posts. Left unset the browser submits to the current
* URL — fine for a preview, wrong for a site. Point it at a handler.
*/
action?: string;
/** `post` unless you have a reason. */
method?: "get" | "post";
/** Added to the <form>, for handlers that route on it. */
formName?: string;
/** The submit button. Generic by default. */
submitLabel?: string;
/**
* The consent line under the button. Use `{0}`, `{1}` … where the links
* should go; anything else is rendered as text. Unset: none — the
* component does not assume the site has terms or a privacy page.
*/
legalText?: string;
/** The links that fill those slots, in order. */
legalLinks?: SalesFootLink[];
/** A second line under it. Same `{0}` substitution. Unset or `""`: none. */
helpText?: string;
/** The links for that line. */
helpLinks?: SalesFootLink[];
/** The section surface, edge to edge. */
background?: string;
/** Headline, labels, answers. */
ink?: string;
/** Placeholders. */
mutedInk?: string;
/** The card's edge. */
cardBorderColor?: string;
/** The card's fill. Transparent by default, as the reference's is. */
cardBackground?: string;
/** Field fill. */
fieldBackground?: string;
/** Field edges. */
fieldBorderColor?: string;
/** The submit button and the focus ring. */
accent?: string;
/** Text on the button. */
accentInk?: string;
/** Where the two columns stop widening. */
maxWidth?: string;
/** Added to the root. */
class?: string;
/** Root element id. Also seeds every generated id. */
id?: string;
}
const {
heading = "",
headingLevel = "h2",
body = "",
fields = [
{ name: "email", label: "Business email", type: "email", placeholder: "Enter your email", required: true, span: "half", autocomplete: "email" },
{
name: "companySize", label: "Company size", type: "select", required: true, span: "half",
options: ["1–50 people", "51–200 people", "201–2,500 people", "2,501–10,000 people", "10,001+ people"],
},
{
name: "support", label: "How can we help?", type: "select", required: true, span: "half",
options: ["I am evaluating options", "I have a project in mind", "I need help with an existing site", "Something else"],
},
{ name: "firstName", label: "First name", placeholder: "Enter your first name", required: true, span: "half", autocomplete: "given-name" },
{ name: "lastName", label: "Last name", placeholder: "Enter your last name", required: true, span: "half", autocomplete: "family-name" },
{ name: "company", label: "Company", placeholder: "Where do you work?", required: true, span: "half", autocomplete: "organization" },
{ name: "title", label: "Title", placeholder: "What is your job title?", required: true, span: "half", autocomplete: "organization-title" },
{
name: "country", label: "Country", type: "select", required: true, span: "half",
options: ["United States", "Canada", "United Kingdom", "Ireland", "Australia", "New Zealand", "Germany", "France", "Spain", "Somewhere else"],
},
{ name: "phone", label: "Phone number", type: "tel", placeholder: "Enter your phone number", span: "full", autocomplete: "tel" },
],
action,
method = "post",
formName,
submitLabel = "Talk to us",
legalText = "",
legalLinks = [],
helpText = "",
helpLinks = [],
background = "#080808",
ink = "#ffffff",
mutedInk = "#898989",
cardBorderColor = "#363636",
cardBackground = "transparent",
fieldBackground = "#171717",
fieldBorderColor = "#5a5a5a",
accent = "#146ef5",
accentInk = "#ffffff",
maxWidth = "1280px",
class: className,
id,
} = Astro.props;
const Heading = headingLevel;
/*
* Every control needs an id its label can point at, and two of these on one
* page must not collide. Derived from `id` when the caller gives one, random
* otherwise — an index-derived id would collide on the second instance.
*/
const uid = id ?? `scs-${Math.random().toString(36).slice(2, 9)}`;
/* `uid` can arrive from the `id` prop, which is caller data, and it goes into
id and `for` attributes; anything that is not an identifier character is
stripped before it gets there. */
const safeUid = uid.replace(/[^A-Za-z0-9_-]/g, "") || "scs";
const fid = (name: string) => `${safeUid}-${name.replace(/[^A-Za-z0-9_-]/g, "") || "f"}`;
const formFields = (fields ?? []).filter((f) => f?.name && f?.label);
/*
* Rows are assembled here rather than in the template, so a `half` with
* nothing to pair with takes a row of its own instead of sitting half-width
* beside empty space.
*/
const rows: SalesField[][] = [];
for (const field of formFields) {
const last = rows[rows.length - 1];
if (field.span !== "full" && last && last.length === 1 && last[0].span !== "full") {
last.push(field);
} else {
rows.push([field]);
}
}
const optionOf = (o: string | SalesFieldOption) =>
typeof o === "string" ? { label: o, value: o } : { label: o.label, value: o.value ?? o.label };
/* Only schemes that navigate. The hrefs often come from a settings record
rather than from the person writing the template. */
const SAFE_HREF = /^(?:https?:|mailto:|tel:|[#/.?])/i;
const safeHref = (value?: string) =>
value && SAFE_HREF.test(value.trim()) ? value.trim() : undefined;
/*
* Splits "…agree to our {0} and {1}." into text and link slots. Done here so
* the caller writes one sentence instead of three props, and so the sentence
* can be translated without the links drifting out of order.
*/
const buildLine = (text: string, links: SalesFootLink[]) => {
if (!text) return null;
const parts = text.split(/(\{\d+\})/g);
return parts
.map((part) => {
const match = /^\{(\d+)\}$/.exec(part);
if (!match) return { text: part };
const link = links?.[Number(match[1])];
const href = safeHref(link?.href);
return link && href ? { link: { label: link.label, href } } : { text: "" };
})
.filter((p) => p.link || p.text !== "");
};
const legal = buildLine(legalText, legalLinks ?? []);
const help = buildLine(helpText, helpLinks ?? []);
const style = [
`--scs-bg:${background}`,
`--scs-ink:${ink}`,
`--scs-muted:${mutedInk}`,
`--scs-card-border:${cardBorderColor}`,
`--scs-card-bg:${cardBackground}`,
`--scs-field:${fieldBackground}`,
`--scs-field-border:${fieldBorderColor}`,
`--scs-accent:${accent}`,
`--scs-accent-ink:${accentInk}`,
`--scs-max:${maxWidth}`,
].join(";");
---
<section class:list={["sales-contact-section", className]} id={id} style={style} data-sales-contact-section>
<div class="scs-inner" style={heading || body ? undefined : "grid-template-columns: minmax(0, 1fr);"}>
{(heading || body) && (
<div class="scs-intro">
{heading && <Heading class="scs-heading">{heading}</Heading>}
{body && <p class="scs-body">{body}</p>}
</div>
)}
<div class="scs-card">
<form class="scs-form" action={action} method={method} name={formName}>
{rows.map((row) => (
<div class:list={["scs-row", row.length > 1 && "scs-row--split"]}>
{row.map((field) => (
<div class="scs-field">
{/*
A real label with a real `for`, and the required mark
hidden from assistive technology — `required` on the
control is what announces it. The reference puts a
`*` in a div inside the label AND another in the text,
so a screen reader reads "star Business email star".
*/}
<label class="scs-label" for={fid(field.name)}>
{field.label}
{field.required && <span class="scs-req" aria-hidden="true">*</span>}
</label>
{field.type === "select" ? (
<select
class="scs-control scs-select"
id={fid(field.name)}
name={field.name}
required={field.required}
autocomplete={field.autocomplete}
>
{/*
`value=""` plus `required` is what makes a select
actually require a choice; without it the first
option counts as an answer.
*/}
<option value="">{field.placeholderOption ?? "Select…"}</option>
{(field.options ?? []).map((raw) => {
const option = optionOf(raw);
return <option value={option.value}>{option.label}</option>;
})}
</select>
) : (
<input
class="scs-control"
type={field.type ?? "text"}
id={fid(field.name)}
name={field.name}
placeholder={field.placeholder}
required={field.required}
autocomplete={field.autocomplete}
/>
)}
</div>
))}
</div>
))}
<button class="scs-submit" type="submit">{submitLabel}</button>
{legal && legal.length > 0 && (
<p class="scs-fine">
{legal.map((part) =>
part.link ? <a class="scs-fine-link" href={part.link.href}>{part.link.label}</a> : part.text,
)}
</p>
)}
{help && help.length > 0 && (
<p class="scs-fine">
{help.map((part) =>
part.link ? <a class="scs-fine-link" href={part.link.href}>{part.link.label}</a> : part.text,
)}
</p>
)}
</form>
</div>
</div>
</section>
<style>
.sales-contact-section {
/*
* Fluid between 320px and 1440px, and these are the reference's own
* curves rather than a guess: it runs 48px of block padding at 320 up
* to 80 at 1440, and a 32px heading up to 56. Both were solved from
* measured pairs and check out at every width between — 60.8px of
* padding and a 41.6px heading at 768, which is exactly what the
* reference reports there.
*/
--scs-pad-block: clamp(48px, 38.857px + 2.8571vw, 80px);
--scs-pad-inline: 24px;
--scs-heading-size: clamp(32px, 25.143px + 2.1429vw, 56px);
--scs-gap: 32px;
--scs-field-gap: 24px;
--scs-radius: 4px;
--scs-card-radius: 8px;
--scs-duration: 150ms;
--scs-ease: cubic-bezier(0.4, 0, 0.2, 1);
box-sizing: border-box;
display: block;
inline-size: 100%;
padding: var(--scs-pad-block) var(--scs-pad-inline);
background: var(--scs-bg);
color: var(--scs-ink);
/* A system stack on purpose: a component in this library fetches
nothing, so it can never be waiting on a webfont. */
font-family:
system-ui,
-apple-system,
"Segoe UI",
Roboto,
Helvetica,
Arial,
sans-serif;
}
.sales-contact-section *,
.sales-contact-section *::before,
.sales-contact-section *::after {
box-sizing: border-box;
}
/*
* A scoped reset, and it earns its place. Form controls do not inherit
* type from their ancestors, and a marketing page that styles `input`,
* `label`, `select` or `button` globally is the normal case rather than
* the exception.
*
* `:where()` keeps this at the specificity of the root alone, so the rules
* underneath still win on source order while a host's element selector
* loses. The `:global()` is load-bearing: Astro cannot put its scope
* attribute inside `:where()`, so without it the compiler emits a second
* attribute beside it and the whole thing outranks the class rules.
*/
.sales-contact-section
:global(:where(h1, h2, h3, p, a, label, input, select, button, form, div, span)) {
margin: 0;
padding: 0;
border: 0;
font: inherit;
color: inherit;
letter-spacing: inherit;
background: none;
}
.scs-inner {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: var(--scs-gap);
max-inline-size: var(--scs-max);
margin-inline: auto;
}
/* ---- the headline column ---------------------------------------------- */
.scs-heading {
font-size: var(--scs-heading-size);
/* 58.24 / 56 on the reference, and it holds at every step. */
line-height: 1.04;
font-weight: 600;
letter-spacing: -0.01em;
color: var(--scs-ink);
text-wrap: balance;
}
.scs-body {
margin-block-start: 24px;
max-inline-size: 46ch;
font-size: 16px;
line-height: 1.6;
color: var(--scs-ink);
}
/* ---- the card ---------------------------------------------------------- */
.scs-card {
min-inline-size: 0;
padding: 24px;
border: 1px solid var(--scs-card-border);
border-radius: var(--scs-card-radius);
background: var(--scs-card-bg);
}
.scs-form {
display: flex;
flex-direction: column;
gap: var(--scs-field-gap);
}
.scs-row {
display: flex;
flex-direction: column;
gap: var(--scs-field-gap);
}
.scs-field {
display: flex;
flex-direction: column;
gap: 8px;
/* So a field in a flex row can shrink instead of forcing the row open. */
min-inline-size: 0;
flex: 1 1 0;
}
.scs-label {
font-size: 14.4px;
line-height: 1.2;
font-weight: 550;
color: var(--scs-ink);
}
.scs-req {
/* Decoration. `required` on the control is what announces it. */
margin-inline-start: 1px;
}
.scs-control {
inline-size: 100%;
min-inline-size: 0;
padding: 24px;
border: 1px solid var(--scs-field-border);
border-radius: var(--scs-radius);
background: var(--scs-field);
color: var(--scs-ink);
/*
* 16px, and not for looks: anything smaller makes iOS Safari zoom the
* page when the field takes focus. It is the reference's value too.
*/
font-size: 16px;
line-height: 1.4;
transition: border-color var(--scs-duration) var(--scs-ease);
}
.scs-control::placeholder {
color: var(--scs-muted);
opacity: 1;
}
.scs-control:hover {
border-color: var(--scs-ink);
}
.scs-control:focus-visible {
outline: 2px solid var(--scs-accent);
outline-offset: -2px;
}
/*
* The chevron is drawn here as a data URI rather than fetched. The
* reference points at a CDN image for it, which is one more request and
* one more thing that can 404 — and it is a chevron.
*/
.scs-select {
appearance: none;
-webkit-appearance: none;
padding-inline-end: 52px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 24px center;
background-size: 16px 16px;
cursor: pointer;
}
/* The unchosen first option reads as a placeholder, not as an answer. */
.scs-select:has(option[value=""]:checked) {
color: var(--scs-muted);
}
/* ---- submit and fine print --------------------------------------------- */
.scs-submit {
align-self: flex-start;
padding: 16px 24px;
border-radius: var(--scs-radius);
background: var(--scs-accent);
color: var(--scs-accent-ink);
font-size: 16px;
line-height: 1.2;
font-weight: 500;
cursor: pointer;
transition: background-color var(--scs-duration) var(--scs-ease);
}
.scs-submit:hover {
background: color-mix(in srgb, var(--scs-accent) 86%, #000);
}
.scs-submit:focus-visible {
outline: 2px solid var(--scs-accent);
outline-offset: 2px;
}
.scs-fine {
font-size: 13px;
line-height: 1.5;
color: var(--scs-ink);
}
.scs-fine-link {
color: inherit;
text-decoration: underline;
text-underline-offset: 2px;
}
.scs-fine-link:focus-visible {
outline: 2px solid var(--scs-accent);
outline-offset: 2px;
}
/* ---- responsive --------------------------------------------------------- */
/*
* Mobile first, so the boundary lands on the same pixel as the
* reference's — it splits into two columns above 991px and stacks below.
* Written as `max-width: 991px` the rule would miss a viewport reporting a
* fractional width just under the round number, which is a mistake this
* library has already made once.
*/
@media (min-width: 992px) {
.sales-contact-section {
--scs-pad-inline: 32px;
}
.scs-inner {
/* 5 and 7 of twelve, which is what the reference's columns come to. */
grid-template-columns: 5fr 7fr;
align-items: start;
}
.scs-row--split {
flex-direction: row;
}
}
/* ---- preferences -------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
/* One token, because every transition in the file resolves through it.
Nothing rests at zero opacity or zero size, so removing the motion
leaves the section correct rather than blank. */
.sales-contact-section {
--scs-duration: 0.01ms;
}
}
@media (forced-colors: active) {
/*
* The chevron is a background image with a baked-in colour, which a
* forced palette neither repaints nor removes — so it is dropped and
* the platform's own select arrow is restored instead.
*/
.scs-select {
appearance: auto;
-webkit-appearance: auto;
padding-inline-end: 24px;
background-image: none;
}
.scs-card,
.scs-control {
border-color: CanvasText;
}
.scs-submit {
border: 1px solid CanvasText;
background: ButtonFace;
color: ButtonText;
}
}
</style>
===== END src/components/SalesContactSection.astro =====
===== FILE (supporting): src/components/SalesContactSection.md =====
# Sales contact section
A headline and a paragraph beside a bordered form card, with two-up fields,
real selects and a fine-print line that carries its own links.
Catalog page: `/components/sales-contact-section`
## Purpose
The "talk to sales" page. The left side says what the conversation is about;
the right side collects enough to route the enquiry to a person — email,
company, size, role, country.
Use something else for a general contact form. This one asks for a job title
and a company size, which is the right ask for a sales lead and the wrong one
for "there's a typo on your pricing page".
## Files required
**`SalesContactSection.astro`** — one file, the whole component.
- No imports at all, not even a type.
- No npm packages, no icon library, no React, no Tailwind, no CSS reset.
- No global stylesheet. Every colour and size is a `--scs-*` custom property
on the component's own root element.
- No webfonts and **no images** — the select chevron is an inline data URI,
so the component makes **no network request of its own**.
`SalesContactSection.md` — this file. Documentation, not required to run.
## Basic usage
```astro
---
import SalesContactSection from "../components/SalesContactSection.astro";
---
<SalesContactSection action="/api/sales" method="post" />
```
No client directive, no wrapper, no init call — the component ships **no
script at all**. Every control is native, so validation, keyboard behaviour
and submission are the browser's.
## `fields` is the content API
The component renders whatever you pass, in order. Two consecutive fields
that are not `span: "full"` share a row above 992px.
```astro
<SalesContactSection
fields={[
{ name: "email", label: "Business email", type: "email", required: true, span: "half" },
{ name: "size", label: "Company size", type: "select", required: true, span: "half",
options: ["1–50 people", "51–200 people", "201+ people"] },
{ name: "phone", label: "Phone number", type: "tel", span: "full" },
]}
/>
```
A `half` with nothing to pair with takes a row of its own rather than sitting
half-width beside empty space.
### The types
```ts
interface SalesField {
name: string;
label: string;
type?: "text" | "email" | "tel" | "url" | "select";
placeholder?: string; // a hint, never a label
required?: boolean;
span?: "half" | "full";
autocomplete?: string;
options?: (string | { label: string; value?: string })[]; // select only
placeholderOption?: string; // select only; defaults to "Select…"
}
```
A required `select` gets an empty first option, which is what makes
`required` mean anything on a select — without it the first entry counts as
an answer.
## The fine print
`legalText` and `helpText` take `{0}`, `{1}` … placeholders filled from
`legalLinks` and `helpLinks`:
```astro
<SalesContactSection
legalText="By submitting this form, you agree to our {0} and {1}."
legalLinks={[
{ label: "Terms of Service", href: "/terms" },
{ label: "Privacy Policy", href: "/privacy" },
]}
helpText=""
/>
```
The sentence stays one string, so it can be translated without the links
drifting out of order. `""` drops either line.
**Neither line is defaulted.** A consent line pointing at `/terms` and
`/privacy`, or a help-centre link, asserts pages a site may not have, so
with no props there is no fine print. The same goes for the headline and
paragraph: with no props the section is just the form card, full width. The
catalog demo passes all of them as props.
## Props
| Prop | Type | Default | What it does |
| :--- | :--- | :--- | :--- |
| `heading` | `string?` | none | The headline. With neither heading nor body the card takes the full width. |
| `headingLevel` | `"h1" \| "h2" \| "h3"?` | `"h2"` | So it fits your page outline. |
| `body` | `string?` | none | Under the headline. |
| `fields` | `SalesField[]?` | nine | The form. |
| `action` | `string?` | — | Where it posts. See below. |
| `method` | `"get" \| "post"?` | `"post"` | |
| `formName` | `string?` | — | Added to the `<form>`. |
| `submitLabel` | `string?` | `"Talk to us"` | The button. |
| `legalText` | `string?` | none | Consent line. |
| `legalLinks` | `SalesFootLink[]?` | `[]` | Fills its slots. |
| `helpText` | `string?` | none | Second line. |
| `helpLinks` | `SalesFootLink[]?` | `[]` | Fills its slots. |
| `background` | `string?` | `#080808` | The section surface. |
| `ink` | `string?` | `#ffffff` | Headline, labels, answers. |
| `mutedInk` | `string?` | `#898989` | Placeholders. |
| `cardBorderColor` | `string?` | `#363636` | The card's edge. |
| `cardBackground` | `string?` | `transparent` | The card's fill. |
| `fieldBackground` | `string?` | `#171717` | Field fill. |
| `fieldBorderColor` | `string?` | `#5a5a5a` | Field edges. |
| `accent` | `string?` | `#146ef5` | Button and focus ring. |
| `accentInk` | `string?` | `#ffffff` | Text on the button. |
| `maxWidth` | `string?` | `1280px` | Where the columns stop widening. |
| `class` | `string?` | — | Extra class on the root. |
| `id` | `string?` | — | Root id. **Also seeds every field id.** |
### A light section
Every tone is a prop, so the light version is nine of them:
```astro
<SalesContactSection
background="#f4f4f5" ink="#101014" mutedInk="#6b6b74"
cardBorderColor="#d8d8dd" cardBackground="#ffffff"
fieldBackground="#ffffff" fieldBorderColor="#c9c9d1"
accent="#1d4ed8" accentInk="#ffffff"
/>
```
There is no `prefers-color-scheme` rule in the file, on purpose: no component
in this library ships one, because a component that picks its own theme
fights the page it lands in. **The reference does exactly that** — its dark
appearance is `prefers-color-scheme`, which is why the page renders light on
a light system.
## It has no back end
**`action` is unset by default**, which means the browser submits to the
current URL. That is fine in a preview and wrong on a site. There is no
success state, no error state and no spinner: this is the form, not the
plumbing.
## Accessibility
- **Every field has a real `<label for>`** and the required mark is
`aria-hidden`; `required` on the control is what announces it. The
reference puts a `*` in a `<div>` inside the label *and* another in the
label text, so a screen reader reads "star Business email star".
- **`required` is real.** See the differences below.
- `autocomplete` is passed through per field.
- Inputs are 16px, and not for looks: anything smaller makes iOS Safari zoom
the page when a field takes focus.
- Focus rings are 2px of the accent — inside the box on fields, outside on
the button and the fine-print links.
- Under `forced-colors: active` the card, fields and button take real
borders, and the select's custom chevron is dropped in favour of the
platform's own arrow — a background image has a baked-in colour that a
forced palette neither repaints nor removes.
- The `<section>` has no accessible name, deliberately: its heading is caller
copy. Wrap it or pass an `aria-label` on a page with several landmarks.
## Reduced motion
Under `prefers-reduced-motion: reduce` the one duration token collapses to
`0.01ms`, so the border and fill transitions become cuts. Nothing rests at
zero opacity or zero size, so the section is correct rather than blank.
## Without JavaScript
Identical, and better than the reference: the fields validate and the form
submits, because nothing here depends on a script.
## Responsive
One step, at 992px — the reference's own breakpoint.
| Width | Layout | Fields | Inline padding |
| :--- | :--- | :--- | :--- |
| ≥ 992 | two columns, 5fr / 7fr | two-up | 32px |
| < 992 | stacked | one-up | 24px |
The heading and the block padding are fluid across the whole range rather
than stepped, matching the reference's own curves:
```css
--scs-heading-size: clamp(32px, 25.143px + 2.1429vw, 56px);
--scs-pad-block: clamp(48px, 38.857px + 2.8571vw, 80px);
```
Both were solved from measured pairs and check out at every width between —
60.8px of padding and a 41.6px heading at 768px, which is exactly what the
reference reports there.
## Differences from the reference
Rebuilt from a live page, measured rather than copied, in its dark theme: a
`#080808` ground, an `#363636` card edge at an 8px radius with 24px of
padding, fields on `#171717` inside a `#5a5a5a` hairline at a 4px radius with
24px of padding and 16px type, labels at 14.4px weight 550, a `#146ef5`
button at 16/24 and a 4px radius, and 13px fine print. What differs:
- **The copy is original.** None of the reference's wording is reproduced,
and the company name does not appear.
- **`required` is real.** The reference marks eight fields with a visible
`*`, sets `required` on **none** of them, and puts `novalidate` on the
form — so the asterisks promise a rule nothing enforces, and with
JavaScript off it will submit empty. Here the marks and the attribute
agree.
- **The required mark is hidden from assistive technology.** The reference
reads it out twice per field.
- **The chevron is inline.** The reference fetches it from a CDN.
- **Ten countries, not 240.** Pass your own `options`.
- **No theme is chosen for you.** The reference's dark look is
`prefers-color-scheme`; here it is the default value of nine colour props.
- The reference sets its type in a licensed face (WF Visual Sans). This uses
the system stack, because a component in this library fetches nothing.
===== END src/components/SalesContactSection.md =====
--- VERIFIED IN THE COMPONENT LIBRARY ---
Production-ready in the library.
Verified 2026-09-23 at 1600, 1440, 1280, 1100, 992, 991, 900, 834, 768, 767, 640, 480, 390, 360, 320px.
Passed: full-page context, keyboard, no javascript, reduced motion, two instances, no overflow, declarations corroborated, lifecycle.
Library source fingerprint: sha256:5287016d9daa41acbb858a509d703a0c6df900ee4b4306a0f292ed31599184a1 — MATCHES the files below.
--- NOT PROVEN ---
- ClientRouter: not applicable — this component ships no script.
--- WHAT THIS DOES NOT CERTIFY ---
Verification was performed on the unmodified component, in an isolated fixture, in the
library. It says nothing about this project's CSS, routes, layout or data, and nothing
about the component once you adapt it. A verified component is a good starting point,
not a guarantee about the installation you are about to build.
--- TEST IN THIS PROJECT AFTER INSTALLING OR CUSTOMISING ---
- Horizontal overflow at 1440, 1280, 1024, 834, 390 and 320px.
- Keyboard operation end to end, including visible focus.
- The no-JavaScript render.
- prefers-reduced-motion: reduce.
- Two instances on one page, if this project renders more than one.
- If this project uses <ClientRouter />: teardown and reinitialisation across a real navigation.