Component library
Back to catalog

Dusk glow

A dark dome with a coloured glow rising around it, drawn as one oversized radial gradient — a page backdrop, a hero ground, or a layer behind content that already exists.

backgroundgradientherodarkstatic

Open preview in a new tab

Use this component

Three ways to get Dusk glow into one of your own projects. The first two carry the component's files with them, so nothing has to fetch this page.

Start here

Placement prompt

The whole thing: what to do, where it goes, what must not change, and every one of the component's 1 file appended underneath with the path each belongs at. Paste it into Claude Code inside the destination project — it fetches nothing and needs nothing else.

Read it first — the files are added underneath when you copy
Add Dusk glow from my Astro Component Library to this Astro project.

Library page, for reference only:
https://astro.baysixmedia.com/components/dusk-glow/

Place it in:
[ENTER PAGE, FILE, OR ROUTE]

Position:
[ENTER WHERE IT SHOULD APPEAR]

Every file you need is appended below, each fenced with the path it belongs at. Write them there, relative to the project root. Do not import anything from the deployed library at runtime, and do not fetch the library page — the files below are the source of truth.

Adapt its demo content, links, colors, typography, and images to this project through documented props where possible. Preserve its responsive behavior, accessibility, interaction logic, reduced-motion behavior, and support for multiple instances. Avoid changing unrelated project code.

Test it at desktop, tablet, and mobile widths. Run the project's available check and build commands. Report the files changed and any differences from the library version. Do not commit or deploy.

Install kit

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: "Dusk glow"
Library page: https://astro.baysixmedia.com/components/dusk-glow/
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/DuskGlow.astro =====
---
/**
 * Dusk glow
 *
 * A dark dome with a coloured glow rising around it: one elliptical radial
 * gradient, wider and taller than its box, centred high so the flat core
 * fills the top and the colour is pushed out to the bottom corners.
 *
 * The whole thing is a single `background-image`. There is no script, no
 * canvas, no image, no extra element and nothing to animate — which is worth
 * saying plainly, because a backdrop that costs one paint is the reason to
 * reach for this one over a field or a mesh.
 *
 * Every number in it is a prop rather than a constant, so the same component
 * is a midnight violet, a warm sunrise or a cold teal without a second copy
 * of the file.
 *
 * Self-contained: no imports, no packages, no global stylesheet, no webfont.
 * Every colour and measurement is a `--dg-*` custom property on the root.
 */

interface Props {
	/**
	 * The flat centre of the dome, and the colour the content sits on.
	 * Defaults to black, which is what makes the glow read as light rather
	 * than as a second colour.
	 */
	core?: string;
	/** The colour the gradient reaches at the far edge of the ellipse. */
	glow?: string;
	/**
	 * Text colour for whatever is in the slot.
	 *
	 * A backdrop that paints itself near-black owes its content a colour: a
	 * host's default body text is dark, and dark on this is nothing at all.
	 * It is a prop rather than a constant because `core` is one too — a pale
	 * core wants dark ink. Only `"section"` mode has content to colour.
	 */
	ink?: string;
	/**
	 * How much of the ellipse the core holds before the glow starts.
	 *
	 * The single most expressive value here. Low and the colour climbs most
	 * of the box; high and it is a rim around the bottom corners. The
	 * reference sits at 40%.
	 */
	coreStop?: string;
	/**
	 * The ellipse's radii, as a share of the box. Over 100% on purpose: the
	 * gradient is bigger than what you can see, so the visible part is the
	 * inner slope of a much larger dome rather than a circle with an edge.
	 */
	radiusX?: string;
	radiusY?: string;
	/**
	 * Where the ellipse is centred. The vertical value is what tilts the
	 * whole effect — above the middle and the glow gathers along the bottom,
	 * below it and the dome inverts into a sunrise.
	 */
	originX?: string;
	originY?: string;
	/**
	 * How it sits in the page.
	 *
	 * `"section"` is a block in the flow that holds its own slot content — a
	 * hero with the glow behind it. `"layer"` is an absolutely positioned
	 * fill of the nearest positioned ancestor, for dropping behind content
	 * that already exists; the slot is ignored. `"page"` pins it to the
	 * viewport behind everything, which is the whole-page backdrop, and the
	 * slot is ignored there too.
	 */
	mode?: "section" | "layer" | "page";
	/**
	 * Height floor in `"section"` mode when the slot gives it none.
	 *
	 * Full screen by default, because the gradient is sized as a share of its
	 * own box and a short box is a thin slice of the dome rather than the
	 * dome. `svh` rather than `vh` so a phone's collapsing address bar does
	 * not leave a strip of page showing under it.
	 */
	minHeight?: string;
	/** Added to the root. */
	class?: string;
	/** Root element id. */
	id?: string;
}

const {
	core = "#000000",
	glow = "#6633ee",
	ink = "#ffffff",
	coreStop = "40%",
	radiusX = "125%",
	radiusY = "125%",
	originX = "50%",
	originY = "10%",
	mode = "section",
	minHeight = "100svh",
	class: className,
	id,
} = Astro.props;

/*
 * Only the three the stylesheet knows what to do with. An unrecognised value
 * lands on "section" rather than on a class that matches nothing, which would
 * render an unstyled box rather than a backdrop.
 */
const layout = mode === "page" || mode === "layer" ? mode : "section";

/*
 * The gradient is assembled here rather than in the stylesheet so the whole
 * shape is one readable line, and so a consumer overriding `--dg-core` alone
 * does not have to restate the other six values to keep it.
 */
const style = [
	`--dg-core:${core}`,
	`--dg-glow:${glow}`,
	`--dg-ink:${ink}`,
	`--dg-core-stop:${coreStop}`,
	`--dg-radius-x:${radiusX}`,
	`--dg-radius-y:${radiusY}`,
	`--dg-origin-x:${originX}`,
	`--dg-origin-y:${originY}`,
	`--dg-min-height:${minHeight}`,
].join(";");
---

<div
	class:list={["dusk-glow", `dusk-glow--${layout}`, className]}
	id={id}
	style={style}
	data-dusk-glow
	data-dg-mode={layout}
	{...(layout === "section" ? {} : { "aria-hidden": "true" })}
>
	{/*
	  Only the block that holds content gets a slot. In the other two modes
	  the element is scenery — out of the accessibility tree and out of the
	  way of the pointer — and there is nothing for content to be inside.
	*/}
	{layout === "section" && <slot />}
</div>

<style>
	.dusk-glow {
		box-sizing: border-box;
		/*
		 * The component, in one declaration.
		 *
		 * `background-color` under it as well as the gradient: a gradient is
		 * an image, and an image is what a printer, a very old engine or a
		 * blocked resource can end up without. The core colour underneath
		 * means the worst case is a flat dark panel rather than a white one
		 * with light text on it.
		 */
		background-color: var(--dg-core);
		background-image: radial-gradient(
			var(--dg-radius-x) var(--dg-radius-y) at var(--dg-origin-x) var(--dg-origin-y),
			var(--dg-core) var(--dg-core-stop),
			var(--dg-glow) 100%
		);
	}

	.dusk-glow--section {
		position: relative;
		min-block-size: var(--dg-min-height);
		/*
		 * Inherited by the slot rather than imposed on it: a host rule that
		 * sets a colour on its own heading still wins, and anything that says
		 * nothing gets something readable instead of the page's dark default
		 * on a near-black ground.
		 *
		 * Only this mode. The other two hold no content, and setting a colour
		 * on an element with no children is a claim about nothing.
		 */
		color: var(--dg-ink);
	}

	/*
	 * Behind content that already exists. It fills the nearest positioned
	 * ancestor, which is the host's job to provide — without one it will
	 * climb to the nearest one it finds, or to the viewport.
	 *
	 * `z-index: 0` rather than a negative: this one is a sibling of the
	 * content it sits behind, and a negative index would put it behind the
	 * host's own background as well, where a painted background would hide
	 * it completely.
	 */
	.dusk-glow--layer {
		position: absolute;
		inset: 0;
		z-index: 0;
		pointer-events: none;
	}

	/*
	 * The whole-page backdrop. Fixed to the viewport and behind everything,
	 * which is the one job a background has.
	 *
	 * `z-index: -1` rather than a positive index under the content: it puts
	 * the glow behind the page's normal flow without the page having to know
	 * it is there. The cost is that a host which makes `body` a stacking
	 * context — a transform, a filter, `isolation` — will trap it, and that a
	 * `body` with its own opaque background will cover it. Both are in the
	 * README rather than worked around.
	 */
	.dusk-glow--page {
		position: fixed;
		inset: 0;
		z-index: -1;
		pointer-events: none;
	}

	/*
	 * No reduced-motion rule, and that is a statement rather than an
	 * omission: there is no animation, no transition and no transform in
	 * this file, so there is nothing for the preference to reduce.
	 */

	@media (forced-colors: active) {
		/*
		 * A gradient is a `background-image`, and forced colours do not
		 * replace those — so without this the purple would survive into a
		 * palette chosen to get rid of it, under text that has been forced to
		 * `CanvasText` and may now be unreadable on it. The backdrop steps
		 * aside instead.
		 */
		.dusk-glow {
			background-image: none;
			background-color: Canvas;
		}

		/* The ink goes with it. A colour chosen to sit on the glow is not the
		   colour to sit on `Canvas`, and here it would be the one thing still
		   fighting the palette the reader asked for. */
		.dusk-glow--section {
			color: CanvasText;
		}
	}

	@media print {
		/* Same reasoning, different reason: a full-bleed dark gradient is a
		   page of ink. The slot colour has to come back with it, or the words
		   print white on white. */
		.dusk-glow {
			background-image: none;
			background-color: transparent;
		}

		.dusk-glow--section {
			color: inherit;
		}
	}
</style>

===== END src/components/DuskGlow.astro =====

===== FILE (supporting): src/components/DuskGlow.md =====
# Dusk glow

A dark dome with a coloured glow rising around it: one elliptical radial
gradient, wider and taller than its box, centred high so the flat core fills
the top and the colour is pushed out to the bottom corners.

Catalog page: `/components/dusk-glow`

## Purpose

For a hero, a section or a whole page that needs a ground with some depth in
it and nothing else — no field, no mesh, no noise, no canvas.

The whole component is **one `background-image`**. That is the reason to reach
for it over anything animated: it costs a single paint, it has nothing to
boot, nothing to tear down, and nothing a client-side router can strand. If
you want the ground to move, this is the wrong component.

Use something else if the glow needs to be a separate colour *over* an
existing background — this paints its own ground, and `core` is that ground.

## Files required

**`DuskGlow.astro`** — one file, the whole component.

- No imports at all, not even a type.
- No npm packages, no Tailwind, no CSS reset, no icon library.
- **No script.** Nothing to boot and nothing to clean up.
- No global stylesheet. Every colour and measurement is declared on the
  component's own root element as a `--dg-*` custom property.
- No webfont and no image, so the component makes **no network request of any
  kind**.
- The only assumption about the host is that Astro compiles `.astro` files.

`DuskGlow.md` — this file. Documentation, not required to run.

## Basic usage

```astro
---
import DuskGlow from "../components/DuskGlow.astro";
---

<DuskGlow>
  <h1>Ship it before Friday</h1>
  <p>Everything else is a detail.</p>
</DuskGlow>
```

No client directive, no wrapper, no init call. It fills the screen by default
and your content sits on it.

## The three modes

| `mode` | What it is |
| :--- | :--- |
| `"section"` *(default)* | A block in the flow that **holds** its slot content. A hero with the glow behind it. |
| `"layer"` | `position: absolute; inset: 0` — fills the nearest positioned ancestor, behind content that already exists. The slot is ignored. |
| `"page"` | `position: fixed; inset: 0; z-index: -1` — the whole-page backdrop. The slot is ignored. |

`"layer"` is the shape the reference is. Use it when you already have a
positioned hero and just want a ground inside it:

```astro
<div class="relative">
  <DuskGlow mode="layer" />
  <div class="relative">…your existing content…</div>
</div>
```

**`"layer"` needs a positioned ancestor.** Without one it will climb to the
nearest one it finds, or to the viewport — that is how `position: absolute`
works, and the component cannot detect it for you.

**`"page"` has two ways to go wrong in a host**, both of them properties of
`z-index: -1` rather than of this component:

- a `body` (or any ancestor) that makes itself a stacking context — a
  `transform`, a `filter`, `isolation`, `opacity` under 1 — traps it, and you
  will see nothing;
- a `body` with its own opaque `background` paints over it.

Both are worth knowing before you debug them. `"section"` has neither problem.

## Props

Everything has a default, and the defaults are the reference.

| Prop | Type | Default | What it does |
| :--- | :--- | :--- | :--- |
| `core` | `string?` | `"#000000"` | The flat centre of the dome, and the ground the content sits on. |
| `glow` | `string?` | `"#6633ee"` | The colour at the far edge of the ellipse. |
| `ink` | `string?` | `"#ffffff"` | Text colour for slot content. `"section"` mode only. |
| `coreStop` | `string?` | `"40%"` | How much of the ellipse the core holds before the glow starts. |
| `radiusX` | `string?` | `"125%"` | The ellipse's horizontal radius, as a share of the box. |
| `radiusY` | `string?` | `"125%"` | The vertical radius. |
| `originX` | `string?` | `"50%"` | Where the ellipse is centred, horizontally. |
| `originY` | `string?` | `"10%"` | Vertically. This is what tilts the whole effect. |
| `mode` | `"section" \| "layer" \| "page"?` | `"section"` | See above. An unrecognised value falls back to `"section"`. |
| `minHeight` | `string?` | `"100svh"` | Height floor in `"section"` mode when the slot gives it none. |
| `class` | `string?` | — | Added to the root element. |
| `id` | `string?` | — | Root element id. |

## Tuning it

The four values worth playing with, in the order they change the most:

- **`coreStop`** — low and the colour climbs most of the box; high and it is a
  rim around the bottom corners. Everything between 20% and 60% is usable.
- **`originY`** — above the middle and the glow gathers along the bottom;
  below it and the dome inverts into a sunrise coming up from the floor.
- **`radiusY`** — under 100% tightens the dome into a visible arc; well over
  it flattens the whole thing toward a linear fade.
- **`glow`** — the one that changes the mood rather than the shape.

A warm sunrise, for example:

```astro
<DuskGlow
  core="#0b1d2a"
  glow="#f2a65a"
  ink="#0b1d2a"
  coreStop="28%"
  radiusX="160%"
  radiusY="95%"
  originX="30%"
  originY="88%"
/>
```

The radii are over 100% on purpose. The gradient is bigger than what you can
see, so the visible part is the inner slope of a much larger dome rather than
a circle with an edge in the middle of your page.

## Height

`minHeight` is `100svh` rather than a fraction of the viewport, because the
ellipse is sized as a **share of its own box**: a short box is a thin slice of
the dome rather than the dome. `svh` rather than `vh` so a phone with a
collapsing address bar does not leave a strip of page showing underneath.

A shorter hero should pass its own value *and* expect to re-tune `radiusY`
and `coreStop` — the shape is proportional, so halving the height halves the
dome rather than cropping it.

## Layout

The component does not lay out your content. It is a ground, not a grid: no
padding, no centring, no max-width. Wrap what goes in the slot the way you
would wrap it on any other section.

That is a deliberate difference from the reference, whose layer carries
`px-5 py-24` and `items-center` — values that do nothing there, because the
layer has no children.

## Accessibility and preferences

- In `"layer"` and `"page"` modes the root is `aria-hidden` and takes no
  pointer events: it is scenery, and there is nothing inside it.
- `ink` exists so the default is legible. A dark backdrop under a host's
  default dark body text is invisible content, and the component knows what
  colour its own ground is.
- **No reduced-motion rule, because there is nothing to reduce.** No
  animation, no transition, no transform anywhere in the file.
- `forced-colors: active` drops the gradient and falls back to `Canvas` and
  `CanvasText`. A gradient is a `background-image`, and forced colours do not
  replace those — so without this the purple would survive into a palette
  chosen to get rid of it, underneath text that has been forced to
  `CanvasText` and may now be unreadable on it.
- `@media print` drops it too, and returns the slot colour to inherited. A
  full-bleed dark gradient is a page of ink, and white text on white paper is
  nothing at all.
- A `background-color` sits under the gradient as well. A gradient is an
  image, and an image is what a very old engine or a blocked resource can end
  up without; the fallback is a flat dark panel rather than a white one with
  light text on it.

## Known differences from the reference

- **The reference is only the `"layer"` form** — one absolutely positioned
  `div` with the gradient on it. `"section"` and `"page"` are this
  component's.
- **Every value is a prop.** The reference hard-codes all seven inside one
  Tailwind arbitrary-property class.
- **`ink`, the forced-colors rule, the print rule and the
  `background-color` fallback are this component's.** The reference has none
  of them.
- The gradient itself is not a difference. Rendered at 1440 × 900 against the
  reference, the two are identical pixel for pixel — see the verification
  record on the catalog page.

===== END src/components/DuskGlow.md =====

--- VERIFIED IN THE COMPONENT LIBRARY ---
Production-ready in the library.
Verified 2026-09-19 at 1920, 1440, 768, 320px.
Passed: full-page context, keyboard, no javascript, reduced motion, two instances, no overflow, declarations corroborated, lifecycle.
Library source fingerprint: sha256:60a6c899dc04392cd0cbe530753bd1d068202e2378177797e3327f851cde20b5 — 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.

Component reference

A fragment for a request you write yourself, e.g. “I want to add [paste] to Section 3 of my homepage.” It names the component, links its page, and fixes what must not change — the design build and its effects — while leaving branding and content open. It does not carry the code.

Read it first
“Dusk glow” from my Astro Component Library:
https://astro.baysixmedia.com/components/dusk-glow/

Use the existing library component as the implementation source. Preserve its design structure, layout, proportions, spacing system, responsive behavior, visual effects, animations, transitions, hover states, interactions, and accessibility.

The copy, colors, typography, images, and other content may be adapted to match the destination website. Do not redesign, simplify, or reinterpret the component’s underlying design build or effects.

Component readiness

Judged on recorded evidence, not on how it looks in the frame above. A description of a component is not a result.

Interactivity
Static
Profile
core only
Installation files
1 required + 1 supporting
Verified
2026-09-19
Client navigation
Not applicable — ships no script
Source fingerprint
Matches the verified source
Production ready
Yes

Production-ready component

Every required check passed against the code below, and the recorded fingerprint still matches it.

Verified 2026-09-19 at 1920, 1440, 768, 320px

  • Full-page contextpass
  • Keyboard — declared to contain nothing focusablenot-applicable
  • No JavaScriptpass
  • Reduced motion — declared to have no motionnot-applicable
  • Two instancespass
  • No overflowpass
  • Declarations corroboratedpass
  • Lifecycle — declared to ship no scriptnot-applicable
20 verification notes
  • Every check below was run against the production build served by `astro preview`, not the dev server.
  • Rebuilt from a live page by measurement, and this one can be stated exactly rather than approximately: rendered at 1440 x 900 against the reference at the same size, the two images are identical pixel for pixel. Zero of 3,888,000 subpixels differ, SSIM 1.000000 on all three channels. The reference's own declaration reads `radial-gradient(125% 125% at 50% 10%, #000 40%, #63e 100%)` and this component's computed `background-image` resolves to the same `radial-gradient(125% 125% at 50% 10%, rgb(0, 0, 0) 40%, rgb(102, 51, 238) 100%)` - same engine, same declaration, same box, so the paint is identical by construction and was then confirmed by comparison rather than assumed from it.
  • The first comparison was NOT clean, and what it caught is worth recording because it was not the component. 3,191 subpixels differed, all of them inside a 182 x 19 box at x 629-810, y 881-899 - the Astro dev toolbar sitting at the bottom centre of the dev-server screenshot. Re-run against the production build, where the toolbar is absent, the difference went to zero. A 99.75% match would have been reported as 'near-identical'; the actual answer is identical, and the 0.25% was the measuring apparatus.
  • The reference is one absolutely positioned layer. This component is that layer plus two other ways to use it, and all three were verified on the built preview route rather than reasoned about. `layer`: position absolute, inset 0, z-index 0, pointer-events none, aria-hidden true, slot suppressed, and it fills a 400 x 300 positioned ancestor at exactly 400 x 300. `page`: position fixed, inset 0, z-index -1, pointer-events none, aria-hidden true, slot suppressed, pinned to the viewport at 1440 x 900. `section`: in flow, relative, holds its slot, and stays in the accessibility tree.
  • An unrecognised `mode` falls back to `section` rather than to a class that matches nothing. Verified by building the demo with `mode: "nonsense"`: the root emitted `dusk-glow dusk-glow--section`, `data-dg-mode="section"`, and no aria-hidden. An unstyled full-bleed box would have been the alternative, and it would have looked like a missing component rather than a typo.
  • Without JavaScript the component is unchanged, because there is no JavaScript. The built preview route and the built fixture route each contain zero `<script>` elements and the component's own file has none. The scripting-disabled render is the only render, which is also what corroborates the `static` declaration and licenses the lifecycle check.
  • Reduced motion is recorded not-applicable and the declaration licenses it honestly: there is no animation, no transition and no transform anywhere in the file. There is nothing for the preference to reduce, and a `@media (prefers-reduced-motion)` block here could only hide a thing that never moved.
  • Keyboard is recorded not-applicable on the same footing: the component contributes nothing focusable. Measured on the fixture, both instances contain zero tab stops; in layer and page modes the root is aria-hidden and takes no pointer events. Anything focusable on a page using this belongs to the slot content, not to the component.
  • A real defect was found by looking at the rendered fixture rather than at the code, and it would have shipped as a component that works and content that cannot be read. The backdrop painted itself near-black and set no colour, so the fixture's slot text rendered in the host's dark default on a black ground - present, correct, invisible. `ink` was added for it, defaulting to white, applied only in section mode because the other two hold no content, and it is a prop rather than a constant because `core` is one too: a pale core wants dark ink. The fixture now carries both halves, white on the black instance and #0b1d2a on the pale navy one.
  • Forced colours drop the gradient rather than surviving it. This needed a rule rather than a note: forced-colors replaces `background-color` but NOT `background-image`, so without one the purple would have persisted into a palette chosen to get rid of it, underneath text that had been forced to CanvasText. Observed under emulation on both instances: background-image resolves to `none`, background-color to Canvas, colour to CanvasText.
  • Print does the same for a different reason - a full-bleed dark gradient is a page of ink - and has to put the slot colour back or white text prints on white paper. Observed under print emulation on both instances: background-image `none`, background-color transparent, and the colour back to the document's inherited `rgb(22, 21, 27)` rather than the component's white.
  • A `background-color` sits under the gradient as well as beside it, so the worst case for an engine or a context that drops background images is a flat dark panel rather than a white one with light text on it.
  • Two instances on one page are independent and differ in state rather than in identity: all seven gradient values differ, the ink differs, and the height differs - 1440 x 900 against 1440 x 495 at the same viewport, because the second is 55svh to the first's 100svh. The second also inverts the shape rather than recolouring it, with its origin at 88% below the midpoint instead of 10% above, which exercises the dome in the other direction. Zero duplicate ids, no page overflow.
  • Responsive at 1920 x 1080, 1440 x 900, 768 x 1024 and 320 x 640. `scrollWidth === clientWidth` at every one, the slot content stays visible at all of them, and both gradients resolve unchanged - which is the point of sizing the ellipse as a share of its own box rather than in pixels. There is no breakpoint in this component and no media query except the two preference blocks.
  • `minHeight` is 100svh rather than a fraction of the viewport, and the reason is the shape rather than the fashion: the ellipse is sized as a share of its own box, so a short box renders a thin slice of the dome rather than the dome. `svh` rather than `vh` so a phone with a collapsing address bar does not show a strip of page underneath it. A shorter hero passes its own value and should expect to re-tune `radiusY` and `coreStop` with it; that is in the README.
  • Install kit confirmed from the component's own page: two blocks, the component with its destination path and the README as supporting, both carried inline. No assets, because there are none - no image, no webfont, no icon, so the component issues no network request of any kind.
  • Zero console messages and zero page errors across the preview route, the fixture route and the component page.
  • No demo copy was reproduced. The reference's layer carries no text at all; the one line of fixture content is original to this library.
  • Two things in the reference were deliberately not carried over. Its layer sets `px-5 py-24` and `items-center`, which do nothing there because the layer has no children - copying them would have made this component lay out content it should not have an opinion about. And its seven gradient values are hard-coded inside one Tailwind arbitrary-property class; here every one of them is a prop, which is the difference between a picture and a component.
  • Chromium only. No WebKit or Gecko build was available in this session, and no claim is made about either. The gradient itself is the oldest CSS in this library - an elliptical `radial-gradient` with percentage radii and an explicit position - and the two preference blocks are `forced-colors` and `print`; all three are long settled across engines, but settled is not the same as observed.

Open the verification fixture

src/components/library/DuskGlow.astro

one fileNo imports, no companion files, no packages. Copy DuskGlow.astro into any Astro project's components folder and render it.

---
/**
 * Dusk glow
 *
 * A dark dome with a coloured glow rising around it: one elliptical radial
 * gradient, wider and taller than its box, centred high so the flat core
 * fills the top and the colour is pushed out to the bottom corners.
 *
 * The whole thing is a single `background-image`. There is no script, no
 * canvas, no image, no extra element and nothing to animate — which is worth
 * saying plainly, because a backdrop that costs one paint is the reason to
 * reach for this one over a field or a mesh.
 *
 * Every number in it is a prop rather than a constant, so the same component
 * is a midnight violet, a warm sunrise or a cold teal without a second copy
 * of the file.
 *
 * Self-contained: no imports, no packages, no global stylesheet, no webfont.
 * Every colour and measurement is a `--dg-*` custom property on the root.
 */

interface Props {
	/**
	 * The flat centre of the dome, and the colour the content sits on.
	 * Defaults to black, which is what makes the glow read as light rather
	 * than as a second colour.
	 */
	core?: string;
	/** The colour the gradient reaches at the far edge of the ellipse. */
	glow?: string;
	/**
	 * Text colour for whatever is in the slot.
	 *
	 * A backdrop that paints itself near-black owes its content a colour: a
	 * host's default body text is dark, and dark on this is nothing at all.
	 * It is a prop rather than a constant because `core` is one too — a pale
	 * core wants dark ink. Only `"section"` mode has content to colour.
	 */
	ink?: string;
	/**
	 * How much of the ellipse the core holds before the glow starts.
	 *
	 * The single most expressive value here. Low and the colour climbs most
	 * of the box; high and it is a rim around the bottom corners. The
	 * reference sits at 40%.
	 */
	coreStop?: string;
	/**
	 * The ellipse's radii, as a share of the box. Over 100% on purpose: the
	 * gradient is bigger than what you can see, so the visible part is the
	 * inner slope of a much larger dome rather than a circle with an edge.
	 */
	radiusX?: string;
	radiusY?: string;
	/**
	 * Where the ellipse is centred. The vertical value is what tilts the
	 * whole effect — above the middle and the glow gathers along the bottom,
	 * below it and the dome inverts into a sunrise.
	 */
	originX?: string;
	originY?: string;
	/**
	 * How it sits in the page.
	 *
	 * `"section"` is a block in the flow that holds its own slot content — a
	 * hero with the glow behind it. `"layer"` is an absolutely positioned
	 * fill of the nearest positioned ancestor, for dropping behind content
	 * that already exists; the slot is ignored. `"page"` pins it to the
	 * viewport behind everything, which is the whole-page backdrop, and the
	 * slot is ignored there too.
	 */
	mode?: "section" | "layer" | "page";
	/**
	 * Height floor in `"section"` mode when the slot gives it none.
	 *
	 * Full screen by default, because the gradient is sized as a share of its
	 * own box and a short box is a thin slice of the dome rather than the
	 * dome. `svh` rather than `vh` so a phone's collapsing address bar does
	 * not leave a strip of page showing under it.
	 */
	minHeight?: string;
	/** Added to the root. */
	class?: string;
	/** Root element id. */
	id?: string;
}

const {
	core = "#000000",
	glow = "#6633ee",
	ink = "#ffffff",
	coreStop = "40%",
	radiusX = "125%",
	radiusY = "125%",
	originX = "50%",
	originY = "10%",
	mode = "section",
	minHeight = "100svh",
	class: className,
	id,
} = Astro.props;

/*
 * Only the three the stylesheet knows what to do with. An unrecognised value
 * lands on "section" rather than on a class that matches nothing, which would
 * render an unstyled box rather than a backdrop.
 */
const layout = mode === "page" || mode === "layer" ? mode : "section";

/*
 * The gradient is assembled here rather than in the stylesheet so the whole
 * shape is one readable line, and so a consumer overriding `--dg-core` alone
 * does not have to restate the other six values to keep it.
 */
const style = [
	`--dg-core:${core}`,
	`--dg-glow:${glow}`,
	`--dg-ink:${ink}`,
	`--dg-core-stop:${coreStop}`,
	`--dg-radius-x:${radiusX}`,
	`--dg-radius-y:${radiusY}`,
	`--dg-origin-x:${originX}`,
	`--dg-origin-y:${originY}`,
	`--dg-min-height:${minHeight}`,
].join(";");
---

<div
	class:list={["dusk-glow", `dusk-glow--${layout}`, className]}
	id={id}
	style={style}
	data-dusk-glow
	data-dg-mode={layout}
	{...(layout === "section" ? {} : { "aria-hidden": "true" })}
>
	{/*
	  Only the block that holds content gets a slot. In the other two modes
	  the element is scenery — out of the accessibility tree and out of the
	  way of the pointer — and there is nothing for content to be inside.
	*/}
	{layout === "section" && <slot />}
</div>

<style>
	.dusk-glow {
		box-sizing: border-box;
		/*
		 * The component, in one declaration.
		 *
		 * `background-color` under it as well as the gradient: a gradient is
		 * an image, and an image is what a printer, a very old engine or a
		 * blocked resource can end up without. The core colour underneath
		 * means the worst case is a flat dark panel rather than a white one
		 * with light text on it.
		 */
		background-color: var(--dg-core);
		background-image: radial-gradient(
			var(--dg-radius-x) var(--dg-radius-y) at var(--dg-origin-x) var(--dg-origin-y),
			var(--dg-core) var(--dg-core-stop),
			var(--dg-glow) 100%
		);
	}

	.dusk-glow--section {
		position: relative;
		min-block-size: var(--dg-min-height);
		/*
		 * Inherited by the slot rather than imposed on it: a host rule that
		 * sets a colour on its own heading still wins, and anything that says
		 * nothing gets something readable instead of the page's dark default
		 * on a near-black ground.
		 *
		 * Only this mode. The other two hold no content, and setting a colour
		 * on an element with no children is a claim about nothing.
		 */
		color: var(--dg-ink);
	}

	/*
	 * Behind content that already exists. It fills the nearest positioned
	 * ancestor, which is the host's job to provide — without one it will
	 * climb to the nearest one it finds, or to the viewport.
	 *
	 * `z-index: 0` rather than a negative: this one is a sibling of the
	 * content it sits behind, and a negative index would put it behind the
	 * host's own background as well, where a painted background would hide
	 * it completely.
	 */
	.dusk-glow--layer {
		position: absolute;
		inset: 0;
		z-index: 0;
		pointer-events: none;
	}

	/*
	 * The whole-page backdrop. Fixed to the viewport and behind everything,
	 * which is the one job a background has.
	 *
	 * `z-index: -1` rather than a positive index under the content: it puts
	 * the glow behind the page's normal flow without the page having to know
	 * it is there. The cost is that a host which makes `body` a stacking
	 * context — a transform, a filter, `isolation` — will trap it, and that a
	 * `body` with its own opaque background will cover it. Both are in the
	 * README rather than worked around.
	 */
	.dusk-glow--page {
		position: fixed;
		inset: 0;
		z-index: -1;
		pointer-events: none;
	}

	/*
	 * No reduced-motion rule, and that is a statement rather than an
	 * omission: there is no animation, no transition and no transform in
	 * this file, so there is nothing for the preference to reduce.
	 */

	@media (forced-colors: active) {
		/*
		 * A gradient is a `background-image`, and forced colours do not
		 * replace those — so without this the purple would survive into a
		 * palette chosen to get rid of it, under text that has been forced to
		 * `CanvasText` and may now be unreadable on it. The backdrop steps
		 * aside instead.
		 */
		.dusk-glow {
			background-image: none;
			background-color: Canvas;
		}

		/* The ink goes with it. A colour chosen to sit on the glow is not the
		   colour to sit on `Canvas`, and here it would be the one thing still
		   fighting the palette the reader asked for. */
		.dusk-glow--section {
			color: CanvasText;
		}
	}

	@media print {
		/* Same reasoning, different reason: a full-bleed dark gradient is a
		   page of ink. The slot colour has to come back with it, or the words
		   print white on white. */
		.dusk-glow {
			background-image: none;
			background-color: transparent;
		}

		.dusk-glow--section {
			color: inherit;
		}
	}
</style>