:root {
  color-scheme: dark;
  /* Warm dark earth rather than a neutral near-black. The old value was very
     slightly green, which is the one cast that makes gold look synthetic. */
  --night: #0a0806;
  --strata: 58, 37, 21;
  --ember: 152, 68, 26;
  --dust: 198, 122, 54;
  --ink: #f2f0e8;
  /* Nudged up from 0.48. The warmer ground is a shade lighter than the old
     near-black, which put the micro-labels at 4.49:1 — under AA by a
     hundredth. The palette moved, so the text that sits on it moves too. */
  --muted: rgba(242, 240, 232, 0.52);
  --faint: rgba(242, 240, 232, 0.14);
  --gold: #f4c323;
  --edge: rgba(242, 240, 232, 0.16);
  --sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
}

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

html,
body {
  width: 100%;
  min-height: 100%;
  margin: 0;
  overflow: hidden;
  background: var(--night);
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  text-rendering: geometricPrecision;
}

button,
input {
  font: inherit;
}

button {
  color: inherit;
}

.experience,
.stage,
.backdrop,
#wattle-canvas,
.stage__fallback {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
}

.experience {
  isolation: isolate;
  background: var(--night);
}

.stage {
  z-index: 0;
  overflow: hidden;
  outline: 0;
  cursor: grab;
  touch-action: none;
}

.stage:active {
  cursor: grabbing;
}

.stage:focus-visible {
  outline: 1px solid var(--gold);
  outline-offset: -5px;
}

/* ---------- The ground ----------
   Flat near-black is the one background that turns a golden object into a
   cut-out, and it was carrying the whole site. This is the country the wattle
   actually grows in, held at very low contrast: warm dark earth, an ember low
   in the frame where ground light would be, uneven bands like a cut through
   rock, and grain across all of it.

   The vocabulary is deliberately geological and cartographic — strata, a
   horizon, a section line, grain. Nothing here is borrowed from Aboriginal
   visual language, which encodes particular Country and story and is not a
   free pattern library; if this site ever wants that, it should commission the
   people whose it is. What it takes from this continent instead is the palette
   and the landform, which are nobody's private property.

   Every layer is pushed far enough down that you have to go looking for it.
   The bouquet stays the only thing in the frame you actually look at. */
.backdrop {
  z-index: -2;
  background-color: var(--night);
  background-image:
    /* a single datum line, the way a section drawing carries one */
    linear-gradient(
      to bottom,
      rgba(var(--dust), 0) 71.55%,
      rgba(var(--dust), 0.22) 71.75%,
      rgba(var(--dust), 0) 71.95%
    ),
    /* the air the object stands in */
    radial-gradient(
      126% 80% at 50% 60%,
      rgba(var(--dust), 0.115) 0%,
      rgba(var(--ember), 0.05) 36%,
      rgba(10, 8, 6, 0) 70%
    ),
    /* strata — irregular on purpose: no two bands the same depth or spacing,
       because evenly spaced lines read as a UI texture, not as rock */
    linear-gradient(
      to bottom,
      rgba(var(--strata), 0) 0%,
      rgba(var(--strata), 0) 12.4%,
      rgba(var(--strata), 0.15) 13.1%,
      rgba(var(--strata), 0) 13.6%,
      rgba(var(--strata), 0) 27.8%,
      rgba(var(--strata), 0.11) 29.3%,
      rgba(var(--strata), 0) 30.9%,
      rgba(var(--strata), 0) 44.1%,
      rgba(var(--strata), 0.17) 44.7%,
      rgba(var(--strata), 0) 45.1%,
      rgba(var(--strata), 0) 58.6%,
      rgba(var(--strata), 0.13) 60.4%,
      rgba(var(--strata), 0) 62.7%,
      rgba(var(--strata), 0) 71.2%,
      rgba(var(--strata), 0.2) 71.7%,
      rgba(var(--strata), 0) 72.1%,
      rgba(var(--strata), 0) 82.5%,
      rgba(var(--strata), 0.16) 84.6%,
      rgba(var(--strata), 0) 87.4%,
      rgba(var(--strata), 0) 100%
    ),
    /* the ember at the base */
    linear-gradient(
      to top,
      rgba(var(--ember), 0.17) 0%,
      rgba(var(--ember), 0.07) 11%,
      rgba(10, 8, 6, 0) 33%
    ),
    /* and the corners returned to quiet */
    radial-gradient(
      132% 104% at 50% 48%,
      rgba(10, 8, 6, 0) 44%,
      rgba(3, 2, 2, 0.6) 100%
    );
}

/* The contour field, on its own layer so it can be taken away from the middle
   of the frame. Held at the edges and faded out behind the bouquet — the same
   thing a photographer's depth of field does, and the reason the drawing can be
   this present without competing with the object. */
.backdrop::before {
  content: "";
  position: absolute;
  inset: 0;
  background: url("./assets/ground-contours.svg") center 62% / cover no-repeat;
  -webkit-mask-image: radial-gradient(
    58% 54% at 50% 45%,
    rgba(0, 0, 0, 0) 0%,
    rgba(0, 0, 0, 0.45) 54%,
    rgba(0, 0, 0, 1) 80%
  );
  mask-image: radial-gradient(
    58% 54% at 50% 45%,
    rgba(0, 0, 0, 0) 0%,
    rgba(0, 0, 0, 0.45) 54%,
    rgba(0, 0, 0, 1) 80%
  );
  pointer-events: none;
}

/* Grain, on its own layer so the blend mode reaches nothing else. Generated
   rather than fetched — the page stays self-contained. */
.backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  background-repeat: repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
  opacity: 0.055;
  mix-blend-mode: soft-light;
  pointer-events: none;
}

#wattle-canvas {
  z-index: 0;
  display: block;
  outline: 0;
}

/* The still is a transparent render of the bouquet alone, with no ground baked
   into it — so it contains at any aspect ratio and composites onto the same
   earth, contours and ember the live page draws. It used to carry its own black
   background, which was invisible against flat black and showed as two seams
   the moment the ground had anything drawn on it. */
.stage__fallback {
  z-index: -1;
  display: block;
  object-fit: contain;
}

.stage__fallback[hidden] {
  display: none;
}

/* A hook that was sitting at display:none. It is the light the object stands
   in — screened, so it lifts the ground behind the bouquet without ever
   lightening the bouquet itself. */
.stage__light {
  z-index: -1;
  display: block;
  pointer-events: none;
  background: radial-gradient(
    44% 38% at 50% 45%,
    rgba(244, 195, 35, 0.075) 0%,
    rgba(244, 195, 35, 0.028) 46%,
    rgba(244, 195, 35, 0) 72%
  );
  mix-blend-mode: screen;
}

.interface-layer {
  position: fixed;
  z-index: 10;
  pointer-events: none;
}

/* The descendant form alone misses a layer that is itself the control — the
   ground switch is both — so it needs the element too, or the canvas behind it
   swallows every click. */
.interface-layer :is(a, button, input),
.interface-layer:is(a, button, input) {
  pointer-events: auto;
}

.hero {
  top: max(1.5rem, env(safe-area-inset-top));
  left: max(1.5rem, env(safe-area-inset-left));
  display: grid;
  grid-template-columns: auto auto;
  align-items: baseline;
  column-gap: 1rem;
}

.wordmark,
.hero h1,

.wordmark {
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.2em;
}

.hero h1 {
  font-family: var(--mono);
  font-size: 0.6rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}


/* ---------- The grounds ----------
   The backdrop above is drawn entirely from four variables — --night, --strata,
   --ember and --dust — so a ground is just a new set of those four, and every
   gradient, band and ember re-tints together. Nothing is swapped in as an
   image.

   Earth is the authored one. Ochre and Dusk are palette shifts: this
   continent's colour, which the ground's own note calls nobody's private
   property. Night sky pulls the earth layers off so the star field the 3D
   scene already renders becomes the whole background.

   There is no dot-painting ground, and its absence is a decision, not an
   omission. That visual language encodes particular Country and story and
   belongs to the artists and communities it comes from; generating an
   imitation of it here would be exactly the borrowing this file set out not to
   do. The honest version is a commission — a named artist, licensed, paid and
   credited on the page. When that artwork exists, it lands as one more entry
   in GROUNDS in index.html plus a rule here that paints it, and the artist's
   name goes beside it. */

:root[data-ground="ochre"] {
  --night: #0d0704;
  --strata: 92, 38, 18;
  --ember: 178, 66, 20;
  --dust: 214, 116, 44;
}

:root[data-ground="rose"] {
  --night: #0d0509;
  --strata: 86, 34, 52;
  --ember: 164, 58, 84;
  --dust: 209, 115, 143;
}

:root[data-ground="moss"] {
  --night: #050806;
  --strata: 34, 62, 40;
  --ember: 58, 118, 72;
  --dust: 127, 174, 122;
}

:root[data-ground="dusk"] {
  --night: #07060d;
  --strata: 44, 34, 72;
  --ember: 92, 54, 132;
  --dust: 150, 120, 196;
}

:root[data-ground="night"] {
  --night: #04060d;
  --strata: 26, 34, 62;
  --ember: 38, 52, 104;
  --dust: 122, 148, 210;
}

/* Night sky is the one ground that changes the drawing and not just its
   colour: the strata and the contour field come off, so the stars that were
   always being rendered behind them have the frame to themselves. */
:root[data-ground="night"] .backdrop {
  background-image:
    radial-gradient(
      120% 84% at 50% 58%,
      rgba(var(--dust), 0.085) 0%,
      rgba(var(--ember), 0.06) 40%,
      rgba(4, 6, 13, 0) 72%
    ),
    linear-gradient(
      to top,
      rgba(var(--ember), 0.13) 0%,
      rgba(4, 6, 13, 0) 30%
    ),
    radial-gradient(
      132% 104% at 50% 46%,
      rgba(4, 6, 13, 0) 42%,
      rgba(1, 2, 6, 0.68) 100%
    );
}

:root[data-ground="night"] .backdrop::before {
  opacity: 0;
}

/* Wash is the other ground that changes the drawing rather than its colour.
   The geology comes off — no strata, no datum line, no contour field — and in
   its place are soft overlapping blooms at wide radii, the way colour sits on
   wet paper. It is an abstract painting ground: no pattern language, nothing
   quoted, nobody's but the page's. */
:root[data-ground="wash"] {
  --night: #0a0709;
  --strata: 78, 48, 62;
  --ember: 150, 74, 92;
  --dust: 201, 143, 156;
}

:root[data-ground="wash"] .backdrop {
  background-image:
    radial-gradient(68% 52% at 26% 30%, rgba(184, 108, 128, 0.17) 0%, rgba(10, 7, 9, 0) 68%),
    radial-gradient(58% 46% at 78% 22%, rgba(126, 116, 176, 0.15) 0%, rgba(10, 7, 9, 0) 66%),
    radial-gradient(76% 58% at 62% 76%, rgba(198, 132, 92, 0.16) 0%, rgba(10, 7, 9, 0) 70%),
    radial-gradient(52% 44% at 16% 82%, rgba(112, 138, 142, 0.13) 0%, rgba(10, 7, 9, 0) 68%),
    radial-gradient(132% 104% at 50% 48%, rgba(10, 7, 9, 0) 40%, rgba(4, 3, 4, 0.62) 100%);
}

:root[data-ground="wash"] .backdrop::before {
  opacity: 0;
}

/* The wash reads as paint only if the grain sits up where pigment would. */
:root[data-ground="wash"] .backdrop::after {
  opacity: 0.085;
}

/* ---------- The ground switch ----------
   Small, dim, and top right — findable if you look for it, and quiet enough
   that it never competes with the object. The name only appears on approach. */
.ground-switch {
  top: max(1.5rem, env(safe-area-inset-top));
  right: max(1.5rem, env(safe-area-inset-right));
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.6rem;
}

.ground-switch__toggle {
  display: inline-flex;
  align-items: center;
  padding: 0.4rem;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.ground-switch__name {
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: 0;
  transform: translateX(0.4rem);
  transition:
    opacity 320ms cubic-bezier(0.16, 1, 0.3, 1),
    transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
}

.ground-switch__dot {
  width: 9px;
  height: 9px;
  border: 1px solid var(--edge);
  border-radius: 50%;
  background: rgba(var(--dust), 0.55);
  opacity: 0.55;
  transition:
    opacity 320ms cubic-bezier(0.16, 1, 0.3, 1),
    background-color 420ms ease,
    box-shadow 320ms ease;
}

.ground-switch:hover .ground-switch__name,
.ground-switch:focus-within .ground-switch__name {
  opacity: 1;
  transform: translateX(0);
}

.ground-switch:hover .ground-switch__dot,
.ground-switch:focus-within .ground-switch__dot {
  opacity: 1;
  box-shadow: 0 0 0 3px rgba(var(--dust), 0.12);
}

.ground-switch__toggle:focus-visible {
  outline: 1px solid var(--gold);
  outline-offset: 0.2rem;
}

/* The tray. Opens leftward from the dot, so it never leaves the frame. */
.ground-switch__swatches[hidden] {
  display: none;
}

.ground-switch__swatches {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  order: -1;
  padding-right: 0.2rem;
}

.ground-swatch {
  width: 11px;
  height: 11px;
  padding: 0;
  border: 1px solid var(--edge);
  border-radius: 50%;
  background: var(--swatch);
  opacity: 0.62;
  cursor: pointer;
  transition:
    opacity 260ms ease,
    box-shadow 260ms ease,
    transform 260ms cubic-bezier(0.16, 1, 0.3, 1);
}

.ground-swatch:hover,
.ground-swatch:focus-visible {
  opacity: 1;
  transform: scale(1.18);
}

.ground-swatch[aria-pressed="true"] {
  opacity: 1;
  box-shadow: 0 0 0 2px var(--night), 0 0 0 3px var(--gold);
}

.ground-swatch:focus-visible {
  outline: 1px solid var(--gold);
  outline-offset: 3px;
}

/* ---------- The client rail ----------
   The studio's whole outbound surface, laid along the foot of the screen.
   It is the only thing on the page that answers a pointer, so it is the only
   thing allowed to move: each name is split into glyphs that lift in a
   staggered wave, and the stagger runs on exit too, so the word settles back
   the way it rose. Everything here is CSS on static spans — if script.js
   never loads, the rail still works and still animates. */
.client-rail {
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.25rem clamp(1.5rem, 6vw, 5rem);
  padding: 0 max(1.75rem, env(safe-area-inset-right))
    calc(1.75rem + env(safe-area-inset-bottom))
    max(1.75rem, env(safe-area-inset-left));
}

/* Clients sit together at the left so the contact link can hold the right
   corner on its own. Both groups wrap as one before either splits. */
.client-rail__group {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 1.25rem clamp(1.5rem, 4vw, 3rem);
  min-width: 0;
}

.client {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
  padding-bottom: 0.5rem;
  color: var(--muted);
  font-family: var(--mono);
  font-size: clamp(1.05rem, 0.72rem + 1.5vw, 2.1rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

/* A hairline that draws itself under the name, left to right. */
.client::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 520ms cubic-bezier(0.16, 1, 0.3, 1);
}

.client__name span {
  display: inline-block;
  transition:
    transform 420ms cubic-bezier(0.16, 1, 0.3, 1),
    color 420ms cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--i) * 26ms);
}

.client__arrow {
  display: inline-block;
  font-style: normal;
  font-size: 0.62em;
  color: rgba(242, 240, 232, 0.34);
  transition:
    transform 420ms cubic-bezier(0.16, 1, 0.3, 1),
    color 420ms cubic-bezier(0.16, 1, 0.3, 1);
}

.client:hover .client__name span,
.client:active .client__name span,
.client:focus-visible .client__name span {
  transform: translateY(-0.34em);
  color: var(--gold);
}

.client:hover::after,
.client:active::after,
.client:focus-visible::after {
  transform: scaleX(1);
}

.client:hover .client__arrow,
.client:active .client__arrow,
.client:focus-visible .client__arrow {
  transform: translate(0.3em, -0.3em);
  color: var(--gold);
}

.client--contact {
  margin-left: auto;
  color: rgba(244, 195, 35, 0.68);
}

.client--contact .client__arrow {
  color: rgba(244, 195, 35, 0.42);
}

.client--contact::after {
  transform-origin: right center;
}

.client:focus-visible {
  outline: 1px solid var(--gold);
  outline-offset: 0.5rem;
}

.scene-error button {
  min-width: 5.2rem;
  border: 0;
  border-left: 1px solid var(--edge);
  border-radius: 0;
  background: transparent;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 160ms ease, background-color 160ms ease;
}

.scene-error button:hover,
.scene-error button:focus-visible {
  color: var(--ink);
  background: rgba(242, 240, 232, 0.06);
}

:where(button, input):focus-visible {
  outline: 1px solid var(--gold);
  outline-offset: -3px;
}

button:disabled,
input:disabled {
  cursor: default;
  opacity: 0.32;
}

.loader,
.scene-error {
  position: fixed;
  z-index: 20;
  top: 50%;
  left: 50%;
  width: min(18rem, calc(100vw - 3rem));
  transform: translate(-50%, -50%);
  text-align: center;
}

.loader {
  transition: opacity 500ms ease, visibility 500ms step-end;
}

.loader p,
.scene-error__title,
.scene-error__copy {
  margin: 0;
}

.loader p,
.scene-error__copy {
  font-family: var(--mono);
  font-size: 0.625rem;
  line-height: 1.6;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.loader__track {
  display: block;
  width: 100%;
  height: 1px;
  margin-top: 1rem;
  overflow: hidden;
  background: var(--faint);
}

.loader__track span {
  display: block;
  width: 34%;
  height: 100%;
  background: var(--gold);
  animation: load 1.6s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}

.is-ready .loader {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.scene-error[hidden] {
  display: none;
}

/* Every other overlay on this site is read against the night. This one is
   read against the poster — and because it is centred, it lands on exactly
   the brightest part of it, the flower mass. Near-white at 48 per cent over
   golden wattle is not a low-contrast heading, it is an invisible one, and
   the reload button was an outline over the same. So the panel carries its
   own ground: the same night, the same hairline, square like everything
   else. */
.scene-error {
  width: min(22rem, calc(100vw - 3rem));
  padding: 1.5rem 1.5rem 1.375rem;
  border: 1px solid var(--edge);
  background: rgba(10, 8, 6, 0.94);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

.scene-error__title {
  font-size: 0.88rem;
  font-weight: 500;
}

.scene-error__copy {
  margin-top: 0.5rem;
}

.scene-error button {
  min-height: 2.75rem;
  margin-top: 1.25rem;
  padding: 0 1rem;
  border: 1px solid var(--edge);
}

.has-error #wattle-canvas {
  display: none;
}

.noscript-message {
  position: fixed;
  z-index: 30;
  inset: auto 1.5rem 1.5rem;
  margin: 0;
  color: var(--ink);
  font-family: var(--mono);
  font-size: 0.68rem;
}

.sr-only {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

.poster-mode .interface-layer,
.poster-mode .loader,
.poster-mode .scene-error {
  display: none !important;
}

@keyframes load {
  0% { transform: translateX(-120%); }
  50% { transform: translateX(100%); }
  100% { transform: translateX(310%); }
}

@media (max-width: 720px) {
  .hero {
    top: max(1.15rem, env(safe-area-inset-top));
    left: max(1.15rem, env(safe-area-inset-left));
  }

}


@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
  }
}

@media (prefers-contrast: more) {
  :root {
    --muted: rgba(242, 240, 232, 0.82);
    --edge: rgba(242, 240, 232, 0.44);
  }
}

@media (forced-colors: active) {
  .backdrop {
    forced-color-adjust: auto;
  }

  #wattle-canvas {
    display: none;
  }

  .stage__fallback {
    display: block !important;
  }
}
/* On a tall screen the still and the panel are both centred, so the panel lands
   squarely on the bouquet and the reader is told a still is shown while looking
   at almost none of it. Drop the panel into the lower third and the still has
   the frame. */
@media (max-aspect-ratio: 3 / 4) {
  .scene-error {
    top: auto;
    bottom: 19%;
    transform: translateX(-50%);
  }
}
