Skip to content
SableInteractive preview

Sable

A material-focused artist studio with original sculptural studies, an accessible image exhibition and thoughtful local commission drafts.

Published by build.host

Charcoal sculptural exhibition

Download source + assets

7,030 words · Complete build specification

BUILD SPECIFICATIONDownload .md

Sable — the weight of an idea

Build a complete, original portfolio for a fictional sculptural-object studio named Sable. The slug was checked against the existing source and generated-demo directories and is unused. The result should feel like a small material exhibition: a charcoal canvas, precise sans-serif typography, tall object imagery, generous space, and a clear catalogue of studies. It needs an exhibition-style home page, a searchable and filterable collection, three substantial project studies, a practice/process page, an accessible image viewer, and a useful local commission-inquiry draft.

This portfolio must be visually distinct from a photographic journal or a graphic agency contact sheet. Do not begin with a full-bleed landscape photograph and a large serif overlay, and do not arrange the work as repeated horizontal strips of branding applications. Sable’s subject is the object itself: its mass, opening, edge, surface, and relation to the space around it. The site should give each form enough room to be read without burying the work inside decorative cards.

Individual artist reference

The research reference is Marylou Faure’s individual portfolio at https://maryloufaure.com/, discovered through https://minimal.gallery/marylou-faure/. The homepage, personal-work page, featured collection, and Bloom object page were inspected live. The reference has a slim, rule-based header, a direct introductory description, expansive image fields, and an object-detail layout that separates large artwork imagery from concise material and contextual information. It demonstrates how an artist’s visual work can carry the personality while the interface remains restrained.

The personal-work gallery was observed at a 1471 by 847 viewport. Its first visible row contained three image fields, each approximately 460 pixels wide and 575 pixels high, with fifteen-pixel gaps and roughly thirty-pixel outer margins. A later active image area was larger, approximately 592.8 by 741 pixels. These are rendered measurements from the live page. The visual emphasis is on generous artwork scale and simple framing rather than elaborate interface chrome.

The Bloom object page exposes a media gallery and a concise information column with title, material description, dimensions, color choices, and purchasing controls. No purchasing action was taken. Sable adapts the useful separation between image exploration and contextual reading, but it does not reproduce the reference’s work, figurative style, biography, shop, edition claims, material facts, prices, or source code. The new portfolio is not a shop and does not imply that any physical artwork is available.

The reference’s bright illustrative world is deliberately not copied. Sable moves into a dark, mineral, abstract visual direction with original generated sculpture concepts. The transferable lesson is clarity around the work: large images, concise framing, and a useful route from an overview to a closer reading. Exact animation timings were not measured, so the new site’s transitions are original decisions. The reference’s small utility type should not be copied where it would make the new interface hard to read.

Original identity and composition

Sable uses a warm charcoal background near #1d1c1a, pale ivory text near #efebe2, and muted sand accents. The primary accent is a restrained material tone rather than a saturated brand color. Supporting text should be a readable light taupe around #c6bdaf. Borders use darker warm-gray rules near #57534b. A single light material section can use a pale stone surface around #d7cdbd with dark text, giving the long page a deliberate change of atmosphere.

Use the locally licensed Geist family throughout. The wordmark is uppercase SABLE with generous tracking, not an ornate monogram or a serif signature. Large headings use light-to-regular weights and tight tracking to feel sculptural. Body paragraphs remain around sixteen to eighteen pixels with generous leading. Primary controls and navigation are at least fourteen pixels; secondary metadata is at least twelve. Do not use tiny museum-style labels for information someone needs to operate the site.

The layout should be architectural and mostly flat. Use thin rules, broad image fields, and a small number of rectangular actions. Avoid repeated rounded cards, gradient panels, fake exhibition photographs, decorative stock textures, or a glossy luxury-product template. The generated images already contain material richness. The website should provide a quiet structure around them instead of adding more visual effects.

The home page begins with a static split exhibition composition. The left side contains the studio framing, a large statement, a short introduction, and two useful links. The right side presents the complete bronze Fold image at a tall scale. This introductory split is not a persistent sidebar for the whole site. It ends after the hero and gives way to a different catalogue rhythm below, making the composition distinct from a split-screen agency portfolio.

Original image assets

Create three original generated sculptural-object images. Each is a portrait composition with the entire object visible and generous margins. The image direction must explicitly ask for invented forms rather than reproducing an identifiable artist’s work. Do not use the reference artist’s imagery, objects, characters, color treatments, or signature motifs. The original generation files should remain outside the public deliverable, while optimized WebP assets and responsive derivatives live inside the demo.

Fold is an abstract folded bronze ribbon forming an asymmetrical open loop with a narrow gap. It stands on a low dark stone plinth against a warm charcoal background. The visual direction uses oxidized bronze, rubbed golden edges, soft directional museum lighting, and tactile surface detail. The gap is the central formal idea. It should not look like a generic perfect torus or a logo rendered in metal. The full silhouette remains visible.

Hollow is a pale limestone volume organized around a deep oval cavity. Its shoulders are softly rounded, while one deliberate planar cut introduces a sharper edge. It sits on a quiet stone surface against an off-white background. The lighting is diffused and restrained, revealing pores and fine tool-like traces. The object suggests a vessel without claiming to be functional. It is a study of interior and exterior volume, not a manufactured container.

Counterform is an assemblage of a red travertine frame, a brushed steel disc, and a pale stone base. The frame has a circular opening, and the disc rests partly within it. The image explores the contrast between warm porous material and cool reflection. It should have a clear grounded shadow and a muted taupe background. The apparent balance is part of the generated composition, not an engineering claim about a real physical structure.

All three images must be described as original generated concepts. They do not document physical artworks, completed commissions, editions, or objects offered for sale. Material names describe visual directions. Detail crops and responsive files are derivatives of the same three original images and must not be counted as additional works. Do not add invented certificates of authenticity, edition numbers, dimensions, prices, or fabrication histories.

Exhibition home page

The header is approximately eighty-two pixels high on desktop. Place the tracked SABLE wordmark at the left and The collection, The practice, and Commission draft at the right. A fine warm-gray rule separates it from the page. The navigation uses normal readable text and real page links. On mobile, it may wrap into a second row, but it should not shrink below fourteen pixels or hide the collection behind an unexplained icon.

The hero’s left column contains a small uppercase line identifying an exhibition of material ideas. The main headline is “The weight of an idea,” broken into two deliberate lines. At a large laptop width it can approach one hundred pixels, but its final size must respect the available column width. The supporting paragraph explains the fictional studio’s interest in surface, mass, and the quiet tension between forms. The two actions lead to the collection and the practice page.

The hero’s lower metadata row identifies studies 01–03 and the original generated-concept context. The right-hand image field contains Fold in full, using contain rather than cropping away the sculpture. Its dark background should sit naturally against the page. A clear Explore Fold button opens the image viewer. The image should feel like an object in an exhibition field, not a product thumbnail floating in a rounded card.

The introduction below the hero uses a different grid: a small label at the left and a larger statement with a paragraph at the right. The statement concerns weight, surface, and the space between. It explains the three relationships that guide the collection: a line that almost closes, a volume shaped by its hollow, and two materials held in an apparent balance. The writing should be specific to the actual studies rather than generic language about creativity.

The home collection section presents all three works as substantial horizontal catalogue bands. Each band has a large study number, an image field, and a contextual text area. The text contains material category, title, summary, material direction, form, and a link to the full study. The image itself opens the viewer. This rhythm differs from both an equal-card gallery and a branding contact sheet. Give the bands enough vertical space to let each object establish its own presence.

A pale stone material section follows, pairing an editorial statement with a simple list of Metal, Stone, and Mixed media. Each label has a short conceptual pairing such as line/reflection or mass/interior. Close with a large invitation about an object, a space, and a possibility, followed by a local commission-draft action. The footer repeats the fictional and generated context in a concise, readable form and links to the collection, process, and credits.

Collection filtering

The collection page has its own large title and introduction, then a material index. Provide a search input and a material-direction select with All materials, Metal, Stone, and Mixed media. Search should use ordinary case-insensitive text matching across each study’s title, material direction, form, and summary. The material select and query combine with AND semantics. A search for cavity while Metal is selected should produce no results rather than ignoring one control.

Show a visible result count and a useful empty state. Reset clears the query and material selection and restores all three studies. Filtering does not mutate the work records, create a recommendation, or call an external service. It simply helps the visitor navigate the small collection. The original study order remains stable unless the visitor changes the filter.

The same catalogue-band structure is used on the collection page. On mobile, each band becomes a sequence of number, image, and text. The complete object remains visible inside its image field. The reading link and image-exploration button remain separate actions, with names that describe their destination. Do not make a whole row ambiguously open either a modal or another page depending on where someone happens to click.

Project-study pages

Generate one complete page for Fold, Hollow, and Counterform. The top section combines a large title, short formal statement, metadata, and a full-object image. Metadata includes the study number, year, material direction, form, and Original generated concept status. A link to the commission page carries the current work identifier so the inquiry can preselect the relevant reference. The page must be substantial enough to explain the object rather than merely display it.

The first written section explains the starting relationship. Fold discusses a continuous surface that does not quite close. Hollow begins with an interior cavity that gives the outside its shape. Counterform describes the meeting of two materials and two geometric systems. A second paragraph explains that the image is a way of testing a visual thought, not proof of a fabricated object. Keep the language precise and connected to the image.

The detail section pairs a closer crop with a discussion of surface. Label it as a detail of the same generated image. Do not describe it as a second camera angle or a separate photograph. The viewer should still provide access to the full composition. The crop is a reading device that draws attention to oxidation, pores, reflection, or the meeting of planes. It should not become an excuse to hide the whole form.

The final written section addresses what remains unresolved. Discuss the visual tension or implied use without claiming real physical performance. A generated image cannot establish fabrication, stability, material behavior, or suitability for a real setting. Those questions would belong to a separate physical development process. This distinction is especially important for Counterform’s apparent balance. End with a useful commission-draft link and a large Next study link that moves through the three works cyclically.

Accessible image exploration

Use a native dialog for the image viewer. The dialog fills the viewport with a darker charcoal surface and contains a top utility row, a flexible image area, and a bottom caption/control row. The full image uses object-fit contain so the entire object and its base can be seen. Do not crop the default viewer merely to fill the screen. The artwork is the reason to open it, and its edges matter.

The top row contains the current image count, the view mode, and an explicit Close button. The bottom identifies the work and material direction and offers Previous, Look closer, Next, and Read the study. Previous and Next navigate the complete three-study collection, with the count making that scope clear even when the viewer was opened from a filtered page. Changing studies updates the image, alt text, title, caption, count, and study link together.

Look closer toggles a deliberate center detail view by scaling the image inside a clipped frame. The button changes to Show whole object, uses a pressed state, and updates the visible mode label to Detail view — cropped. Moving to another study resets the zoom so the next work is always introduced as a complete composition. The zoom is not a claim of a separate image or physical inspection. It is a way to examine the generated surface more closely.

ArrowLeft and ArrowRight move between images while the dialog is open. Escape closes it through native dialog behavior. Remember the button that opened the viewer and restore focus to it on close. Lock background scrolling while the viewer is open and restore it afterward. The Close control receives initial focus, and a polite live region announces image changes. Do not intercept navigation keys when the viewer is closed.

On a phone, the caption and controls stack into readable rows. Controls remain at least fourteen pixels with comfortable touch areas. The complete image may have empty space around it; that is preferable to cutting off the object. The modal must stay within the viewport, and the controls should not be hidden behind browser chrome. Reduced-motion preferences remove image transitions and zoom animation while preserving the same states.

Practice and process page

The practice page explains Sable as a fictional artist-led studio concept rather than presenting an invented real artist biography. Its opening statement concerns material thinking. A split image-and-text section uses Hollow to establish the relationship between the formal question and material direction. The text explains that a line, opening, edge, or contact point can become the beginning of a study.

Continue with three process stages: observe the relation, reduce the vocabulary, and hold the question open. Each stage should have a substantial paragraph about what it changes in the work. Avoid a generic creative-process list that could belong to any service business. The discussion should stay close to the actual objects and the limits of generated visual development.

The page also distinguishes studies from editions. There are no physical pieces for sale, no numbered production run, and no claim of a completed commission. The collection is a visual exploration. A new inquiry can describe a direction, but it does not establish a scope, price, fabrication method, or agreement. This context should be clear without turning the page into a legal document.

Commission inquiry draft

The commission page is a practical local tool. Its introduction invites the visitor to begin with an object, a setting, or a material question. A reference panel shows the selected study when the URL contains a recognized work identifier. An unknown identifier is ignored, and the form starts with A new direction. Changing the reference select updates the image, title, and caption so the visual context agrees with the draft.

The form asks for name, email, a reference work, broad scale, an optional setting, the idea, and timing. Name and email are required. The idea must contain at least twenty meaningful characters and is limited to a sensible length. The setting should invite a broad description such as an entryway or gallery rather than requiring a private address. No budget, payment, shipping, legal acceptance, or real booking is needed for this demonstration.

Use native form validation with a small amount of explicit validation for whitespace-only names and ideas. Clear custom validity on input so a corrected field can be submitted normally. Narrow FormData values to strings before trimming them. Do not treat a file value as a string or interpolate user text into HTML. The prepared draft is rendered through textContent in a preformatted but readable block.

On valid submission, hide the form, reveal a labeled review panel, and move focus to it. The draft includes the entered contact details, selected reference and material direction, scale, setting, timing, and idea. It ends with an explicit local, unsent statement. It must not say that an artist has received the request, that a commission has been accepted, or that a physical object will be made.

Provide Download draft, Copy draft, and Edit details. The download uses a real Blob URL with a text filename prepared after submission. Revoke any earlier Blob URL before replacing it. Copy reports success only after the Clipboard API succeeds and offers download as a fallback if it fails. Editing restores the existing values and focuses the name field. No personal inquiry data is persisted across reloads or sent to an external service.

Responsive typography and layout

At around one thousand pixels, reduce the hero’s spacing and type scale while preserving the complete-object image. The catalogue band can use a narrower number column and smaller title. At around seven hundred and twenty pixels, stack the hero, introduction, catalogue bands, material section, study sections, process rows, and commission layout. The site should remain a readable exhibition rather than a compressed desktop page.

Long titles such as Counterform need explicit narrow-width attention. Do not allow a single word to push the document wider or disappear under overflow clipping. Adjust the heading size or wrapping deliberately after measuring the rendered result. Body reading stays around sixteen to seventeen pixels on mobile. Labels remain at least twelve, and all actual actions remain at least fourteen. Form inputs should stay at sixteen pixels for comfortable entry.

Contrast is important on the dark surfaces. Supporting text should be a light taupe with adequate contrast, not a faint gray chosen only for visual quietness. Placeholder text must also remain readable. The light material section needs its own dark hover color for links so a global gold hover treatment does not disappear against the pale background. Focus outlines should be visible on both dark and light surfaces.

Use one main landmark, one h1 per page, logical h2/h3 nesting, a skip link, visible labels, styled select controls, and meaningful button names. Decorative image affordances should not be announced twice. Image alt text identifies the original generated object and its material direction. Do not use unsupported ARIA attributes on generic decorative containers. All visual states remain understandable without relying only on color or motion.

Build contract and verification

Export buildSable from scripts/sable/build.mjs and return an object containing prompt. Generate seven complete pages: exhibition home, collection, practice, commission inquiry, and three project studies. Keep source in scripts/sable, generated pages and assets in public/demos/sable, and the distributed prompt in public/prompts/sable.md. Append the exact original work records, responsive CSS, and actual JavaScript under Reference interaction handler. Do not edit shared catalogs, application files, validators, or deployment configuration.

Deliver three original optimized WebP object images, smaller responsive derivatives, a hero preview, a local Geist font with its license, and provider-neutral credits. Preserve the generated-image disclosure and distinguish conceptual material direction from physical fabrication. Keep original generation files outside the public folder and do not include local user paths in public provenance. Do not emit a favicon, shop cart, price, real artist affiliation, or copied artwork.

Run scoped lint and verify all local links and assets. In the browser, test material and query filters together, empty and reset states, image viewer opening, next and previous navigation, zoom and reset, Escape and focus return, commission reference preselection, validation correction, draft preparation, copy feedback, download preparation, and editing. Inspect desktop and mobile compositions and measure every page for document overflow and readable controls.

Report actual outcomes rather than inferred success. A prepared Blob link is evidence of export preparation, not proof that a file was downloaded. A generated sculpture image is evidence of a visual concept, not of a physical work. The finished portfolio should be confident about its visual direction and equally clear about those boundaries.

Exact original study records

export const works = [
  {
    id: 'fold',
    title: 'Fold',
    number: '01',
    material: 'Metal',
    direction: 'Oxidized bronze',
    form: 'Open loop',
    year: '2026',
    line: 'A continuous line, interrupted.',
    summary:
      'An original sculptural concept in which a folded ribbon holds an open space, with a narrow break that keeps the form unresolved.',
    idea: 'Fold begins with a simple contradiction: a continuous surface that does not quite close. The ribbon turns through space, becoming both an edge and a plane. Its opening is not an absence to fill, but the part of the object that gives the surrounding material a purpose.',
    surface:
      'The bronze direction brings a sense of accumulated time to the image. Dark oxidized areas sit beside rubbed edges that catch the light. Those changes make the same surface appear alternately heavy and thin as the eye moves around the loop.',
    reading:
      'The narrow gap prevents the silhouette from becoming a complete symbol. It leaves a small uncertainty in an otherwise grounded form. The low plinth gives the object a clear relation to the surface beneath it without pretending to resolve its balance physically.',
    alt: 'Original generated photograph of an asymmetrical folded bronze loop sculpture on a dark stone plinth',
    color: '#b49a70',
  },
  {
    id: 'hollow',
    title: 'Hollow',
    number: '02',
    material: 'Stone',
    direction: 'Pale limestone',
    form: 'Carved volume',
    year: '2026',
    line: 'The inside gives the outside its shape.',
    summary:
      'A pale stone volume organized around a deep cavity, balancing soft shoulders with one deliberate planar cut.',
    idea: 'Hollow treats the interior as the beginning of the form. The carved space pulls the eye inward, while the outer shoulders keep a sense of mass around it. A single sharp plane interrupts the softness and makes the object feel considered rather than simply worn smooth.',
    surface:
      'Pores, small marks, and tonal variation give the limestone direction its character. The image uses quiet side light so the surface can be read without theatrical contrast. The cavity remains darker, making the relationship between exposed plane and sheltered interior visible.',
    reading:
      'The object suggests a vessel without describing a practical use. Its value in this study is the tension between holding and opening. It is a visual exploration of volume, not a functional container or a manufactured product.',
    alt: 'Original generated photograph of a pale limestone sculptural vessel with a deep oval cavity and an angled cut',
    color: '#d8d2c5',
  },
  {
    id: 'counterform',
    title: 'Counterform',
    number: '03',
    material: 'Mixed media',
    direction: 'Travertine & steel',
    form: 'Balanced assembly',
    year: '2026',
    line: 'Two materials, one held moment.',
    summary:
      'A warm stone frame and a cool metal disc meet at a circular opening, making the relationship between weight and reflection the subject.',
    idea: 'Counterform begins with two forms that seem to belong to different systems. A porous rectangular stone frame establishes weight and direction. A brushed steel disc interrupts it with a reflective circular surface. The opening becomes the place where the two ideas meet.',
    surface:
      'The material contrast is deliberately narrow: warm porous stone, cool brushed metal, and a pale base. Light travels across each in a different way. The stone holds a stable texture, while the disc changes with the angle of reflection.',
    reading:
      'The apparent balance is part of the generated image, not a verified engineering condition. The study explores how an object can suggest tension through proportion and contact. Any physical realization would need its own material and structural development.',
    alt: 'Original generated photograph of a red travertine frame holding a brushed steel disc on a pale stone base',
    color: '#a5694d',
  },
];

Exact responsive CSS

@font-face {
  font-family: Sable;
  src: url('assets/geist-variable.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
}
* {
  box-sizing: border-box;
}
html {
  scroll-behavior: smooth;
  scroll-padding-top: 90px;
}
body {
  margin: 0;
  background: #1d1c1a;
  color: #efebe2;
  font:
    16px/1.7 Sable,
    Arial,
    sans-serif;
  -webkit-font-smoothing: antialiased;
}
h1,
h2,
h3,
p,
figure {
  margin: 0;
}
h1,
h2,
h3 {
  font-weight: 430;
  letter-spacing: -0.045em;
  line-height: 1.1;
}
a {
  color: inherit;
  text-decoration: none;
}
button,
input,
select,
textarea {
  font: inherit;
}
button {
  cursor: pointer;
  color: inherit;
}
img {
  display: block;
  max-width: 100%;
  height: auto;
}
button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid #e1bb7f;
  outline-offset: 5px;
}
::selection {
  background: #bda580;
  color: #1d1c1a;
}
.skip {
  position: fixed;
  top: -90px;
  left: 20px;
  z-index: 90;
  background: #efebe2;
  color: #1d1c1a;
  padding: 14px;
}
.skip:focus {
  top: 0;
}
.header {
  height: 82px;
  padding: 0 4%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #57534b;
  gap: 30px;
}
.brand {
  font-size: 32px;
  letter-spacing: 6px;
  line-height: 1;
  font-weight: 450;
}
.header nav {
  display: flex;
  gap: 34px;
  font-size: 14px;
}
.header nav a:hover,
.footer nav a:hover {
  text-decoration: underline;
  text-underline-offset: 5px;
}
.eyebrow {
  font-size: 12px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: #c2b9a9;
  display: block;
  line-height: 1.7;
}
.hero {
  display: grid;
  grid-template-columns: 1fr 1.05fr;
  min-height: 710px;
  border-bottom: 1px solid #57534b;
}
.hero-copy {
  padding: 65px 8% 50px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.hero h1 {
  font-size: clamp(60px, 6.8vw, 100px);
  line-height: 1.02;
  letter-spacing: -0.06em;
  margin: 40px 0 30px;
  max-width: 610px;
}
.hero-copy p {
  max-width: 420px;
  font-size: 17px;
  color: #c6bdaf;
  line-height: 1.85;
}
.hero-actions {
  display: flex;
  gap: 25px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 35px;
}
.text-link {
  display: inline-block;
  border-bottom: 1px solid #b4a58e;
  padding: 8px 0;
  font-size: 14px;
  line-height: 1.5;
}
.text-link:hover {
  color: #e1bb7f;
}
.button {
  display: inline-flex;
  justify-content: space-between;
  align-items: center;
  gap: 30px;
  border: 1px solid #b1a18a;
  background: #e9e2d5;
  color: #24221e;
  padding: 13px 18px;
  min-height: 47px;
  font-size: 14px;
  line-height: 1.5;
}
.button.secondary {
  background: transparent;
  color: #efebe2;
  border-color: #918678;
}
.button:hover {
  background: #cdb38c;
  color: #24221e;
}
.hero-art {
  position: relative;
  min-width: 0;
  background: #24221e;
  border-left: 1px solid #57534b;
  display: grid;
  place-items: center;
  overflow: hidden;
}
.hero-art img {
  width: 100%;
  height: 710px;
  object-fit: contain;
}
.hero-art button {
  position: absolute;
  right: 25px;
  bottom: 25px;
}
.hero-bottom {
  display: flex;
  justify-content: space-between;
  gap: 30px;
  margin-top: 35px;
  font-size: 12px;
  color: #c2b9a9;
}
.intro {
  padding: 80px 5%;
  display: grid;
  grid-template-columns: 1fr 1.8fr;
  gap: 12%;
  border-bottom: 1px solid #57534b;
}
.intro h2 {
  font-size: clamp(38px, 4.6vw, 66px);
  margin-bottom: 28px;
  max-width: 850px;
}
.intro p {
  font-size: 18px;
  color: #c6bdaf;
  line-height: 1.9;
  max-width: 650px;
}
.section {
  padding: 65px 5%;
}
.section-head {
  display: flex;
  justify-content: space-between;
  align-items: end;
  gap: 30px;
  margin-bottom: 38px;
}
.section-head h2 {
  font-size: 43px;
}
.collection-list {
  border-top: 1px solid #57534b;
}
.work-row {
  display: grid;
  grid-template-columns: 120px 1.15fr 1fr;
  gap: 50px;
  align-items: center;
  padding: 42px 0;
  border-bottom: 1px solid #57534b;
}
.work-number {
  font-size: 65px;
  font-weight: 300;
  letter-spacing: -3px;
  color: #b6a993;
  align-self: start;
  padding-top: 15px;
}
.work-image {
  display: block;
  border: 0;
  padding: 0;
  background: #25221e;
  width: 100%;
  position: relative;
  overflow: hidden;
}
.work-image img {
  width: 100%;
  height: auto;
  aspect-ratio: 1.08;
  object-fit: contain;
  transition: transform 0.5s;
}
.work-image:hover img {
  transform: scale(1.025);
}
.work-image .image-open {
  position: absolute;
  bottom: 13px;
  right: 13px;
  background: #efebe2;
  color: #24221e;
  padding: 7px 11px;
  font-size: 14px;
}
.work-copy h3 {
  font-size: 48px;
  margin: 17px 0 22px;
}
.work-copy p {
  font-size: 17px;
  line-height: 1.9;
  color: #c6bdaf;
  max-width: 420px;
  margin-bottom: 25px;
}
.work-specs {
  display: flex;
  gap: 25px;
  flex-wrap: wrap;
  font-size: 12px;
  color: #c2b9a9;
  margin-bottom: 25px;
}
.work-specs span {
  display: block;
}
.material-band {
  background: #d7cdbd;
  color: #25231f;
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 10%;
  align-items: center;
}
.material-band .eyebrow {
  color: #575044;
}
.material-band h2 {
  font-size: clamp(40px, 4.7vw, 70px);
  margin: 22px 0 28px;
}
.material-band p {
  font-size: 18px;
  line-height: 1.9;
  color: #514b41;
}
.material-lines {
  border-top: 1px solid #8e8270;
}
.material-lines div {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  padding: 23px 0;
  border-bottom: 1px solid #8e8270;
  font-size: 19px;
}
.material-lines small {
  font-size: 12px;
}
.closing {
  padding: 70px 5%;
  display: flex;
  justify-content: space-between;
  align-items: end;
  gap: 40px;
  border-bottom: 1px solid #57534b;
}
.closing h2 {
  font-size: clamp(42px, 5.5vw, 80px);
  max-width: 850px;
}
.closing p {
  font-size: 16px;
  line-height: 1.8;
  color: #c6bdaf;
  max-width: 350px;
  margin-bottom: 25px;
}
.footer {
  padding: 32px 4%;
  display: flex;
  justify-content: space-between;
  align-items: start;
  gap: 30px;
}
.footer nav {
  display: flex;
  gap: 26px;
  font-size: 14px;
}
.footer p {
  font-size: 12px;
  color: #c2b9a9;
  max-width: 700px;
  line-height: 1.85;
}
.page-intro {
  padding: 55px 5% 35px;
}
.page-intro h1 {
  font-size: clamp(54px, 7vw, 105px);
  line-height: 1.03;
  letter-spacing: -0.055em;
  margin: 27px 0;
  max-width: 1100px;
}
.page-intro p {
  font-size: 18px;
  line-height: 1.9;
  color: #c6bdaf;
  max-width: 720px;
}
.filters {
  display: flex;
  align-items: end;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: 28px;
}
.filters label {
  font-size: 14px;
  display: grid;
  gap: 8px;
}
.filters input,
.filters select {
  min-height: 47px;
  background: #292621;
  color: #efebe2;
  border: 1px solid #8f8471;
  padding: 11px 13px;
  border-radius: 0;
  font-size: 16px;
  max-width: 100%;
}
.filters input {
  width: 310px;
}
.filters select {
  min-width: 220px;
}
.count-line {
  font-size: 14px;
  color: #c6bdaf;
  margin: 22px 0;
}
.empty {
  padding: 35px;
  background: #292621;
  border: 1px solid #686051;
}
.empty h2,
.empty h3 {
  font-size: 31px;
  margin-bottom: 20px;
}
.empty p {
  font-size: 16px;
  line-height: 1.8;
  color: #c6bdaf;
}
.study-head {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 7%;
  padding: 55px 5%;
  align-items: center;
  border-bottom: 1px solid #57534b;
}
.study-head h1 {
  font-size: clamp(85px, 10vw, 150px);
  font-weight: 350;
  letter-spacing: -0.07em;
  line-height: 1;
  margin: 30px 0;
}
.study-head p {
  font-size: 23px;
  line-height: 1.6;
  max-width: 550px;
  color: #d2c8b8;
}
.study-head dl {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 15px 25px;
  margin: 35px 0;
  font-size: 16px;
  max-width: 500px;
}
.study-head dt {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: #bfb39f;
}
.study-head dd {
  margin: 0;
}
.study-head .work-image img {
  aspect-ratio: 4/5;
  object-fit: contain;
}
.study-text {
  display: grid;
  grid-template-columns: 1fr 1.65fr;
  gap: 12%;
  padding: 65px 7%;
}
.study-text h2 {
  font-size: 42px;
  max-width: 410px;
}
.study-text p {
  font-size: 18px;
  color: #c6bdaf;
  line-height: 1.9;
  margin-bottom: 27px;
}
.study-detail {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 9%;
  padding: 0 7% 65px;
  align-items: center;
}
.detail-image {
  overflow: hidden;
  background: #28251f;
}
.detail-image img {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  transform: scale(1.1);
}
.study-detail h2 {
  font-size: 46px;
  margin: 22px 0 25px;
}
.study-detail p {
  font-size: 17px;
  color: #c6bdaf;
  line-height: 1.9;
}
.next-work {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 30px;
  border-top: 1px solid #57534b;
  padding: 45px 5%;
}
.next-work strong {
  font-size: clamp(45px, 6vw, 90px);
  font-weight: 350;
  line-height: 1.1;
  letter-spacing: -0.05em;
  display: block;
  margin-top: 15px;
}
.next-work > span {
  font-size: 45px;
}
.practice-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10%;
  padding: 15px 5% 65px;
  align-items: center;
}
.practice-split img {
  width: 100%;
  height: auto;
  aspect-ratio: 4/5;
  object-fit: contain;
  background: #d4cfc4;
}
.practice-split h2 {
  font-size: 44px;
  margin-bottom: 25px;
}
.practice-split p {
  font-size: 18px;
  line-height: 1.9;
  color: #c6bdaf;
  margin-bottom: 25px;
}
.process {
  padding: 55px 5%;
  border-top: 1px solid #57534b;
}
.process > h2 {
  font-size: 46px;
  margin-bottom: 35px;
}
.process article {
  display: grid;
  grid-template-columns: 70px 1fr 1.4fr;
  gap: 35px;
  padding: 30px 0;
  border-top: 1px solid #57534b;
}
.process article > span {
  font-size: 14px;
  color: #c2b9a9;
}
.process h3 {
  font-size: 30px;
}
.process p {
  font-size: 17px;
  color: #c6bdaf;
  line-height: 1.9;
}
.commission {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: 10%;
  padding: 20px 5% 75px;
  align-items: start;
}
.reference-panel {
  padding: 24px;
  background: #25221e;
  border: 1px solid #575044;
}
.reference-panel img {
  width: 100%;
  height: auto;
  max-height: 420px;
  object-fit: contain;
}
.reference-panel h2 {
  font-size: 30px;
  margin: 25px 0 13px;
}
.reference-panel p {
  font-size: 16px;
  line-height: 1.9;
  color: #c6bdaf;
}
.reference-panel .caption {
  font-size: 12px;
  margin-bottom: 22px;
  color: #c2b9a9;
}
.commission-form label {
  font-size: 14px;
  display: block;
  margin-bottom: 25px;
}
.commission-form input,
.commission-form select,
.commission-form textarea {
  display: block;
  width: 100%;
  min-width: 0;
  margin-top: 9px;
  min-height: 48px;
  padding: 12px;
  background: #292621;
  color: #efebe2;
  border: 1px solid #8f8471;
  border-radius: 0;
  font-size: 16px;
}
.commission-form textarea {
  min-height: 140px;
  resize: vertical;
}
.commission-form .button {
  width: 100%;
}
.form-note {
  font-size: 12px;
  color: #c2b9a9;
  line-height: 1.85;
  margin-top: 20px;
}
.draft {
  padding: 28px;
  background: #292621;
  border: 1px solid #8f8471;
  min-width: 0;
}
.draft h2 {
  font-size: 34px;
  margin: 20px 0;
}
.draft pre {
  font:
    16px/1.85 Sable,
    sans-serif;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.draft-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 25px;
}
.draft-actions .button {
  font-size: 14px;
  padding: 11px 14px;
}
.draft output {
  font-size: 14px;
  line-height: 1.8;
  display: block;
  margin-top: 15px;
}
.viewer {
  border: 0;
  margin: 0;
  width: 100vw;
  height: 100svh;
  max-width: none;
  max-height: none;
  padding: 0;
  background: #121210;
  color: #efebe2;
  overflow: hidden;
}
.viewer::backdrop {
  background: #121210;
}
.viewer-inner {
  height: 100%;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: 17px;
  padding: 23px 30px;
}
.viewer-top,
.viewer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 25px;
}
.viewer-top {
  font-size: 12px;
}
.viewer-top button,
.viewer-bottom button {
  font-size: 14px;
  min-height: 44px;
  padding: 10px 15px;
  border: 1px solid #9f927e;
  background: transparent;
  color: #efebe2;
}
.viewer-frame {
  overflow: hidden;
  min-height: 0;
  display: grid;
  place-items: center;
}
.viewer-frame img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  min-height: 0;
  transition: transform 0.35s;
}
.viewer-frame.detail-view img {
  transform: scale(1.4);
}
.viewer-caption h2 {
  font-size: 28px;
  margin-bottom: 6px;
}
.viewer-caption p {
  font-size: 12px;
  color: #c8bdab;
  line-height: 1.7;
}
.viewer-controls {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
}
.viewer-controls .text-link {
  font-size: 14px;
}
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
[hidden] {
  display: none !important;
}
@media (max-width: 1000px) {
  .hero {
    min-height: 630px;
  }
  .hero-copy {
    padding: 45px 7%;
  }
  .hero h1 {
    font-size: 75px;
  }
  .hero-art img {
    height: 630px;
  }
  .work-row {
    grid-template-columns: 75px 1.1fr 1fr;
    gap: 30px;
  }
  .work-number {
    font-size: 48px;
  }
  .work-copy h3 {
    font-size: 40px;
  }
  .intro,
  .material-band {
    gap: 8%;
  }
  .study-head {
    gap: 5%;
  }
  .study-head h1 {
    font-size: 105px;
  }
  .study-head p {
    font-size: 21px;
  }
  .study-text {
    gap: 8%;
    padding: 55px 5%;
  }
  .study-detail {
    padding: 0 5% 55px;
    gap: 6%;
  }
  .commission {
    gap: 6%;
  }
  .viewer-inner {
    padding: 22px;
  }
}
@media (max-width: 720px) {
  .header {
    height: auto;
    min-height: 78px;
    padding: 23px 5%;
    flex-wrap: wrap;
    gap: 23px;
  }
  .brand {
    font-size: 29px;
    letter-spacing: 5px;
  }
  .header nav {
    width: 100%;
    justify-content: space-between;
    gap: 18px;
    font-size: 14px;
  }
  .hero {
    grid-template-columns: 1fr;
    min-height: 0;
  }
  .hero-copy {
    padding: 38px 5%;
    gap: 30px;
  }
  .hero h1 {
    font-size: 65px;
    line-height: 1.04;
    margin: 27px 0;
  }
  .hero-copy p {
    font-size: 17px;
  }
  .hero-actions {
    margin-top: 28px;
  }
  .hero-bottom {
    margin-top: 26px;
    font-size: 12px;
  }
  .hero-art {
    border-left: 0;
    border-top: 1px solid #57534b;
  }
  .hero-art img {
    height: auto;
    max-height: 650px;
    object-fit: contain;
  }
  .hero-art button {
    right: 20px;
    bottom: 20px;
  }
  .intro {
    grid-template-columns: 1fr;
    gap: 25px;
    padding: 48px 5%;
  }
  .intro h2 {
    font-size: 40px;
  }
  .intro p {
    font-size: 17px;
  }
  .section {
    padding: 45px 5%;
  }
  .section-head {
    align-items: start;
    flex-direction: column;
    gap: 20px;
    margin-bottom: 28px;
  }
  .section-head h2 {
    font-size: 36px;
  }
  .work-row {
    grid-template-columns: 1fr;
    gap: 23px;
    padding: 30px 0;
  }
  .work-number {
    font-size: 30px;
    padding: 0;
    letter-spacing: -1px;
  }
  .work-image img {
    aspect-ratio: 1;
    object-fit: contain;
  }
  .work-copy h3 {
    font-size: 38px;
    margin: 13px 0 20px;
  }
  .work-copy p {
    font-size: 16px;
  }
  .work-specs {
    font-size: 12px;
    gap: 18px;
  }
  .material-band {
    grid-template-columns: 1fr;
    gap: 30px;
  }
  .material-band h2 {
    font-size: 41px;
  }
  .material-band p {
    font-size: 17px;
  }
  .material-lines div {
    font-size: 17px;
  }
  .closing {
    padding: 45px 5%;
    align-items: start;
    flex-direction: column;
    gap: 30px;
  }
  .closing h2 {
    font-size: 46px;
  }
  .closing p {
    font-size: 16px;
  }
  .footer {
    padding: 27px 5%;
    flex-direction: column;
    gap: 24px;
  }
  .footer nav {
    gap: 24px;
    font-size: 14px;
    flex-wrap: wrap;
  }
  .page-intro {
    padding: 36px 5% 28px;
  }
  .page-intro h1 {
    font-size: 54px;
    letter-spacing: -0.05em;
  }
  .page-intro p {
    font-size: 17px;
  }
  .filters {
    align-items: stretch;
    gap: 17px;
    flex-direction: column;
  }
  .filters input,
  .filters select {
    width: 100%;
    min-width: 0;
  }
  .study-head {
    grid-template-columns: 1fr;
    padding: 35px 5%;
    gap: 30px;
  }
  .study-head h1 {
    font-size: 81px;
    margin: 23px 0;
  }
  .study-head p {
    font-size: 20px;
  }
  .study-head dl {
    font-size: 16px;
    margin: 25px 0;
  }
  .study-head .work-image img {
    aspect-ratio: 4/5;
  }
  .study-text {
    grid-template-columns: 1fr;
    padding: 43px 5%;
    gap: 25px;
  }
  .study-text h2 {
    font-size: 37px;
  }
  .study-text p {
    font-size: 17px;
    margin-bottom: 22px;
  }
  .study-detail {
    grid-template-columns: 1fr;
    padding: 0 5% 48px;
    gap: 28px;
  }
  .study-detail h2 {
    font-size: 38px;
  }
  .study-detail p {
    font-size: 16px;
  }
  .next-work {
    padding: 35px 5%;
    gap: 20px;
  }
  .next-work strong {
    font-size: 45px;
  }
  .practice-split {
    grid-template-columns: 1fr;
    padding: 5px 5% 45px;
    gap: 30px;
  }
  .practice-split img {
    max-height: 480px;
  }
  .practice-split h2 {
    font-size: 37px;
  }
  .practice-split p {
    font-size: 17px;
  }
  .process {
    padding: 40px 5%;
  }
  .process > h2 {
    font-size: 37px;
  }
  .process article {
    grid-template-columns: 30px 1fr;
    gap: 20px;
  }
  .process article p {
    grid-column: 2;
    font-size: 16px;
  }
  .process h3 {
    font-size: 28px;
  }
  .commission {
    grid-template-columns: 1fr;
    padding: 10px 5% 55px;
    gap: 35px;
  }
  .reference-panel {
    padding: 20px;
  }
  .reference-panel img {
    max-height: 300px;
  }
  .commission-form input,
  .commission-form select,
  .commission-form textarea {
    font-size: 16px;
  }
  .draft {
    padding: 23px;
  }
  .draft h2 {
    font-size: 30px;
  }
  .viewer-inner {
    padding: 17px 16px;
    gap: 14px;
  }
  .viewer-bottom {
    align-items: start;
    flex-direction: column;
    gap: 17px;
  }
  .viewer-caption h2 {
    font-size: 26px;
  }
  .viewer-controls {
    width: 100%;
    gap: 9px;
    justify-content: space-between;
  }
  .viewer-controls .text-link {
    width: 100%;
    text-align: center;
  }
  .viewer-top button,
  .viewer-bottom button {
    padding: 10px 12px;
    font-size: 14px;
  }
  .viewer-top {
    gap: 15px;
    align-items: center;
  }
}
@media (max-width: 420px) {
  .hero h1 {
    font-size: 59px;
  }
  .page-intro h1 {
    font-size: 49px;
  }
  .study-head h1 {
    font-size: 72px;
  }
  .viewer-controls button {
    padding: 10px;
    font-size: 14px;
  }
}
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *:before,
  *:after {
    animation: none !important;
    transition: none !important;
  }
}
input::placeholder,
textarea::placeholder {
  color: #b7ad9e;
  opacity: 1;
}
.material-band .text-link:hover {
  color: #5b3e22;
}

Reference interaction handler

const works = JSON.parse(document.getElementById('sable-data').textContent);
const workMap = new Map(works.map((work) => [work.id, work]));
const reduced = matchMedia('(prefers-reduced-motion: reduce)');
const search = document.querySelector('#work-search');
function filterWorks() {
  const query = search.value.trim().toLowerCase();
  const material = document.querySelector('#material-filter').value;
  let count = 0;
  document.querySelectorAll('[data-work]').forEach((article) => {
    const work = workMap.get(article.dataset.work);
    article.hidden =
      !`${work.title} ${work.direction} ${work.form} ${work.summary}`
        .toLowerCase()
        .includes(query) ||
      (material && work.material !== material);
    if (!article.hidden) count++;
  });
  document.querySelector('#work-count').textContent =
    `${count} ${count === 1 ? 'study' : 'studies'} in this view`;
  document.querySelector('#empty-works').hidden = count > 0;
}
if (search) {
  search.addEventListener('input', filterWorks);
  document
    .querySelector('#material-filter')
    .addEventListener('change', filterWorks);
  document.querySelector('#reset-filters').addEventListener('click', () => {
    search.value = '';
    document.querySelector('#material-filter').value = '';
    filterWorks();
  });
  filterWorks();
}
const viewer = document.querySelector('#image-viewer');
let activeImage = 0;
let zoomed = false;
let opener = null;
function renderImage() {
  const work = works[activeImage];
  document.querySelector('#viewer-image').src = 'assets/' + work.id + '.webp';
  document.querySelector('#viewer-image').alt = work.alt;
  document.querySelector('#viewer-title').textContent = work.title;
  document.querySelector('#viewer-caption').textContent =
    work.direction + ' / Original generated study';
  document.querySelector('#viewer-count').textContent =
    `${activeImage + 1} / ${works.length}`;
  document.querySelector('#viewer-study').href = work.id + '.html';
  zoomed = false;
  reflectZoom();
  document.querySelector('#viewer-announcement').textContent =
    `Study ${activeImage + 1} of ${works.length}: ${work.title}`;
}
function reflectZoom() {
  document
    .querySelector('#viewer-frame')
    .classList.toggle('detail-view', zoomed);
  const button = document.querySelector('#zoom-image');
  button.setAttribute('aria-pressed', String(zoomed));
  button.textContent = zoomed ? 'Show whole object' : 'Look closer';
  document.querySelector('#view-mode').textContent = zoomed
    ? 'Detail view · cropped'
    : 'Whole composition';
}
function moveImage(direction) {
  activeImage = (activeImage + direction + works.length) % works.length;
  renderImage();
}
document.querySelectorAll('[data-open-work]').forEach((button) =>
  button.addEventListener('click', () => {
    activeImage = works.findIndex(
      (work) => work.id === button.dataset.openWork,
    );
    opener = button;
    renderImage();
    viewer.showModal();
    document.body.style.overflow = 'hidden';
  }),
);
document
  .querySelector('#close-viewer')
  ?.addEventListener('click', () => viewer.close());
viewer?.addEventListener('close', () => {
  document.body.style.overflow = '';
  opener?.focus();
});
document
  .querySelector('#previous-image')
  ?.addEventListener('click', () => moveImage(-1));
document
  .querySelector('#next-image')
  ?.addEventListener('click', () => moveImage(1));
document.querySelector('#zoom-image')?.addEventListener('click', () => {
  zoomed = !zoomed;
  reflectZoom();
});
viewer?.addEventListener('keydown', (event) => {
  if (event.key === 'ArrowRight') {
    event.preventDefault();
    moveImage(1);
  }
  if (event.key === 'ArrowLeft') {
    event.preventDefault();
    moveImage(-1);
  }
});
const form = document.querySelector('#commission-form');
let draft = '';
let draftUrl = '';
function textField(data, key) {
  const value = data.get(key);
  return typeof value === 'string' ? value.trim() : '';
}
function reflectReference() {
  const work = workMap.get(document.querySelector('#reference-work').value);
  document.querySelector('#reference-name').textContent = work
    ? work.title
    : 'An open starting point';
  document.querySelector('#reference-image').src =
    'assets/' + (work ? work.id : 'fold') + '-600.webp';
  document.querySelector('#reference-image').alt = work
    ? work.alt
    : works[0].alt;
  document.querySelector('#reference-caption').textContent = work
    ? work.direction + ' / Concept reference'
    : 'A material study from the collection, not a selected commission.';
}
if (form) {
  const requested = new URLSearchParams(location.search).get('work');
  if (workMap.has(requested))
    document.querySelector('#reference-work').value = requested;
  reflectReference();
  document
    .querySelector('#reference-work')
    .addEventListener('change', reflectReference);
  form.addEventListener('input', () => {
    document.querySelector('#commission-name').setCustomValidity('');
    document.querySelector('#commission-idea').setCustomValidity('');
  });
  form.addEventListener('submit', (event) => {
    event.preventDefault();
    const name = document.querySelector('#commission-name'),
      idea = document.querySelector('#commission-idea');
    name.setCustomValidity(name.value.trim() ? '' : 'Add your name.');
    idea.setCustomValidity(
      idea.value.trim().length >= 20
        ? ''
        : 'Describe the idea in at least 20 characters.',
    );
    if (!form.reportValidity()) return;
    const data = new FormData(form);
    const reference = workMap.get(textField(data, 'work'));
    draft = `SABLE — COMMISSION INQUIRY DRAFT\n\nName: ${textField(data, 'name')}\nEmail: ${textField(data, 'email')}\nReference: ${reference ? reference.title + ' / ' + reference.direction : 'A new direction'}\nScale: ${textField(data, 'scale')}\nSetting: ${textField(data, 'setting') || 'To be explored'}\nTiming: ${textField(data, 'timing')}\n\nThe idea\n${textField(data, 'idea')}\n\nLocal, unsent draft for a fictional artist studio. No physical artwork, commission, price, or agreement is offered.`;
    document.querySelector('#draft-text').textContent = draft;
    if (draftUrl) URL.revokeObjectURL(draftUrl);
    draftUrl = URL.createObjectURL(
      new Blob([draft], { type: 'text/plain;charset=utf-8' }),
    );
    document.querySelector('#download-draft').href = draftUrl;
    form.hidden = true;
    const result = document.querySelector('#draft-result');
    result.hidden = false;
    result.focus();
  });
}
document.querySelector('#edit-draft')?.addEventListener('click', () => {
  document.querySelector('#draft-result').hidden = true;
  form.hidden = false;
  document.querySelector('#commission-name').focus();
});
document.querySelector('#copy-draft')?.addEventListener('click', async () => {
  try {
    await navigator.clipboard.writeText(draft);
    document.querySelector('#copy-status').textContent =
      'Commission draft copied.';
  } catch {
    document.querySelector('#copy-status').textContent =
      'Copy is unavailable. Download the draft instead.';
  }
});
if (reduced.matches) document.documentElement.classList.add('reduced-motion');