(()=>{for(const root of document.querySelectorAll('[data-snippet="project-brief-contact"]')){if(root.dataset.initialized)continue;root.dataset.initialized='true';for(const form of root.querySelectorAll('[data-demo-form]')){form.querySelector('fieldset').disabled=false;form.addEventListener('submit',e=>{e.preventDefault();form.querySelector('[role=status]').textContent='Demo only: no information was sent. Connect and test your own backend for real delivery.';});}}})();
---
// Generated, escaped static markup. Use a distinct prefix for each instance.
const markup = "\u003csection class=\"fct-project-brief-contact s-contact s-brief\" data-snippet=\"project-brief-contact\" aria-labelledby=\"fct-project-brief-contact-heading\"\u003e\u003cdiv class=\"s-wrap\"\u003e\u003ch2 id=\"fct-project-brief-contact-heading\" class=\"s-visually-hidden\"\u003eProject brief contact section\u003c/h2\u003e\u003cdiv class=\"s-contact-layout\"\u003e\u003cdiv\u003e\u003cp class=\"s-kicker\"\u003eStart a conversation\u003c/p\u003e\u003ch2\u003eA good project\u003cbr\u003estarts here.\u003c/h2\u003e\u003cp\u003eShare the idea, the context and what you need. Project sizes are optional and are not calculated quotes.\u003c/p\u003e\u003ca href=\"mailto:projects@example.com\"\u003eprojects@example.com\u003c/a\u003e\u003c/div\u003e\u003cform data-demo-form action=\"#\" method=\"post\" aria-label=\"Contact enquiry\"\u003e\u003cfieldset disabled\u003e\u003clegend class=\"s-visually-hidden\"\u003eYour enquiry details\u003c/legend\u003e\u003clabel for=\"fct-project-brief-contact-name\"\u003eName (required)\u003c/label\u003e\u003cinput id=\"fct-project-brief-contact-name\" name=\"name\" type=\"text\" required autocomplete=\"name\" maxlength=\"100\"\u003e\u003clabel for=\"fct-project-brief-contact-email\"\u003eEmail (required)\u003c/label\u003e\u003cinput id=\"fct-project-brief-contact-email\" name=\"email\" type=\"email\" required autocomplete=\"email\" maxlength=\"254\"\u003e\u003clabel for=\"fct-project-brief-contact-service\"\u003eService (optional)\u003c/label\u003e\u003cselect name=\"service\" id=\"fct-project-brief-contact-service\"\u003e\u003coption value=\"\"\u003ePlease choose\u003c/option\u003e\u003coption\u003eWebsite design\u003c/option\u003e\u003coption\u003eBrand identity\u003c/option\u003e\u003coption\u003eConsulting\u003c/option\u003e\u003c/select\u003e\u003clabel for=\"fct-project-brief-contact-budget\"\u003eProject size (optional)\u003c/label\u003e\u003cselect name=\"budget\" id=\"fct-project-brief-contact-budget\"\u003e\u003coption\u003eNot sure yet\u003c/option\u003e\u003coption\u003eSmall project\u003c/option\u003e\u003coption\u003eLarger project\u003c/option\u003e\u003c/select\u003e\u003clabel for=\"fct-project-brief-contact-message\"\u003eProject brief (required)\u003c/label\u003e\u003ctextarea id=\"fct-project-brief-contact-message\" name=\"message\" rows=\"4\" maxlength=\"3000\" required\u003e\u003c/textarea\u003e\u003cbutton type=\"submit\" class=\"s-button\"\u003eSend enquiry\u003c/button\u003e\u003c/fieldset\u003e\u003cp class=\"s-demo-note\" role=\"status\"\u003eDemonstration only. Connect your backend before collecting information.\u003c/p\u003e\u003c/form\u003e\u003c/div\u003e\u003c/div\u003e\u003c/section\u003e";
---
<Fragment set:html={markup} />
<style is:global>
.fct-project-brief-contact{--s-bg:#202620;--s-ink:#ffffff;--s-accent:#d8e7bb;font:16px/1.65 system-ui,sans-serif;color:var(--s-ink);background:var(--s-bg)}.fct-project-brief-contact,.fct-project-brief-contact *{box-sizing:border-box}.fct-project-brief-contact :is(h2,h3,p,ul,figure){margin:0}.fct-project-brief-contact h2,.fct-project-brief-contact h3{line-height:1.2;letter-spacing:-.035em}.fct-project-brief-contact h2{font-size:clamp(1.8rem,4vw,3.5rem)}.fct-project-brief-contact a{color:inherit;text-underline-offset:5px;overflow-wrap:anywhere}.fct-project-brief-contact :is(a,button,input,textarea,select,summary):focus-visible{outline:3px solid var(--s-accent);outline-offset:4px}.fct-project-brief-contact button,.fct-project-brief-contact input,.fct-project-brief-contact textarea,.fct-project-brief-contact select{font:inherit}.fct-project-brief-contact a,.fct-project-brief-contact button{touch-action:manipulation}.fct-project-brief-contact .s-wrap{max-width:1200px;margin-inline:auto;padding:40px 28px}.fct-project-brief-contact .s-kicker{font-size:.8125rem;letter-spacing:.13em;text-transform:uppercase;margin-bottom:18px}.fct-project-brief-contact .s-button{display:inline-flex;align-items:center;justify-content:center;min-height:46px;padding:11px 21px;border:1px solid currentColor;text-decoration:none;background:transparent;color:inherit;cursor:pointer;border-radius:2px;font-weight:600}.fct-project-brief-contact .s-muted{opacity:.82}.fct-project-brief-contact .s-links{display:flex;gap:8px 26px;flex-wrap:wrap}.fct-project-brief-contact .s-links a{display:inline-flex;align-items:center;min-height:44px}.fct-project-brief-contact .s-rule{border-top:1px solid currentColor;padding-top:20px;margin-top:30px}.fct-project-brief-contact .s-grid{display:grid;gap:28px;grid-template-columns:repeat(3,minmax(0,1fr))}.fct-project-brief-contact img{max-width:100%;height:auto;display:block}.fct-project-brief-contact .s-brand{font-size:1.3rem;font-weight:700;letter-spacing:-.05em;text-decoration:none}@media(max-width:640px){.fct-project-brief-contact .s-wrap{padding:30px 20px}.fct-project-brief-contact .s-grid{grid-template-columns:1fr}}
.fct-project-brief-contact form{min-width:0}.fct-project-brief-contact fieldset{border:0;margin:0;padding:0;min-width:0;display:grid;gap:10px}.fct-project-brief-contact label{font-size:.9375rem;font-weight:600}.fct-project-brief-contact :is(input,textarea,select){width:100%;min-height:46px;border:1px solid currentColor;border-radius:2px;background:var(--s-bg);color:var(--s-ink);padding:11px 12px}.fct-project-brief-contact textarea{resize:vertical}.fct-project-brief-contact form .s-button{justify-self:start;margin-top:10px}.fct-project-brief-contact .s-demo-note{font-size:.875rem;margin-top:18px}.fct-project-brief-contact .s-visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.fct-project-brief-contact .s-contact-layout{display:grid;grid-template-columns:1fr 1fr;gap:clamp(30px,7vw,100px);align-items:start}.fct-project-brief-contact .s-contact-layout>div>p{margin-top:24px;max-width:42ch}.fct-project-brief-contact address{font-style:normal;margin:35px 0 20px}.fct-project-brief-contact.s-minimal .s-contact-layout{display:block;max-width:640px;margin:auto}.fct-project-brief-contact.s-minimal form{margin-top:40px}.fct-project-brief-contact.s-appointment h2{font-family:Georgia,serif;font-weight:400}.fct-project-brief-contact.s-directory .s-contact-layout{grid-template-columns:1fr}.fct-project-brief-contact .s-directory{display:grid;grid-template-columns:repeat(3,1fr);gap:30px;border-bottom:1px solid currentColor;padding-bottom:35px}.fct-project-brief-contact .s-directory h3{font-size:1.2rem;margin-bottom:15px}.fct-project-brief-contact.s-directory form{max-width:720px}@media(max-width:720px){.fct-project-brief-contact .s-contact-layout,.fct-project-brief-contact .s-directory{grid-template-columns:1fr;gap:30px}}
</style>
<script is:inline>
(()=>{for(const root of document.querySelectorAll('[data-snippet="project-brief-contact"]')){if(root.dataset.initialized)continue;root.dataset.initialized='true';for(const form of root.querySelectorAll('[data-demo-form]')){form.querySelector('fieldset').disabled=false;form.addEventListener('submit',e=>{e.preventDefault();form.querySelector('[role=status]').textContent='Demo only: no information was sent. Connect and test your own backend for real delivery.';});}}})();
</script>
Where this design fits
The extra service and project-size fields provide context for a first conversation. They are optional choices and do not calculate a quote or create a project record.
Service selection
Optional project size
Project brief textarea
What is included
The HTML ZIP includes a standalone demo, reusable markup, scoped CSS, its small JavaScript runtime, a license and setup notes. The Astro ZIP includes Snippet.astro. It can be imported into an existing Astro page or layout.
Connect a real form backend
These forms demonstrate layout and native browser validation. No messages are sent. Configure the form action, remove the demo interception and disabled fieldset, then implement delivery, server validation and spam handling on your backend. Test actual success and error responses before publishing. An appointment request does not confirm availability.
Add it to an HTML website
Copy snippet.html into the relevant page section.
Load snippet.css after your existing site stylesheet. The class prefix identifies this design.
Load snippet.js once with defer. Keep the included keyboard behavior when adapting interactions.
Replace example content and check mobile widths, zoom, links and keyboard focus in your actual website.
Use it in Astro
Copy Snippet.astro into src/components/, import it into your page or shared layout, and insert the component where the section belongs. Keep each generated prefix unique if you duplicate a component on one page.
Keep the section maintainable
Start with the variables at the top of the CSS for background, text and accent colors. Preserve semantic labels and focus styles. Existing site selectors can still affect imported markup, so test the combined result. Read the complete setup notes.