/* ═══════════════════════════════════════════════════════════
   LOADER
   The mark arrives large and settles, gold blooms through it from
   the foot of the N, a specular crosses the finished metal, a
   photograph opens behind it and is held under it, then expands
   to the frame — and that frame IS the hero. The panel dissolves
   off it rather than curtaining away.

   THREE THINGS TO KNOW BEFORE EDITING

   1. The fill is two copies of the SAME mask — one painted near
      black, one painted gold. What reveals the gold is a circle
      clip on its wrapper blooming out of the N's foot, written
      from JS. See fill-demos.html for the nineteen alternatives
      this was chosen from; any of them lifts straight in.

   2. The mark starts WHITE and fills to gold, on a deep navy
      ground. It was near-black on warm white until the stage
      inverted; if the ground ever goes back to paper, the mark has
      to go dark again or the first beat is invisible.

   3. The opening block is deliberately MUCH larger than the mark.
      When the two were the same size the photograph landed exactly
      on the letterform and swallowed it in a single frame. The
      mark now sits inside the opening with room around it, and is
      covered only once the photograph has finished opening.
   ═══════════════════════════════════════════════════════════ */

.loader {
  position: fixed;
  inset: 0;
  z-index: 300;
  /* Three layers, not one stop-to-stop ramp. A single linear
     gradient across a full screen reads as a flat sheet with a
     tint; the two radials sit off-centre and off-axis from each
     other, so the ground has a light source and a falloff and the
     eye finds depth in it. The navy is the brand's own, taken
     deeper at the corners than anywhere it appears on the site. */
  background:
    radial-gradient(120% 92% at 20% 14%, #2c3f6b 0%, rgba(44,63,107,0) 60%),
    radial-gradient(105% 85% at 84% 90%, #16223d 0%, rgba(22,34,61,0) 56%),
    linear-gradient(158deg, #1f2e52 0%, #17233c 46%, #0f1930 100%);
  overflow: hidden;
  will-change: transform;
}

/* ── Ground texture ──────────────────────────────────────
   Two layers, and they are doing different jobs.

   ::before is large-scale mottling — low-frequency fractal noise
   scaled up until it reads as cloud or stone rather than as
   noise. It is what stops a big dark field looking like a flat
   fill with a tint on it. soft-light rather than a flat overlay,
   so it modulates the gradient already there instead of laying a
   grey sheet over it.

   ::after is fine grain, and it earns its place twice: it is the
   premium finish, and it is also the fix for banding. A dark
   navy ramp across 1600px crosses very few 8-bit steps, so it
   bands into visible stripes on most screens — a little noise
   dithers those away. That is why the frequency is high and the
   opacity is tiny; grain you can SEE is a filter, grain you
   cannot is a finish.

   Both sit at z-index 0, BELOW the photograph (z 1) and the mark
   (z 2). Deliberate: the texture belongs to the loader's own
   ground, and the moment the photograph opens out to fill the
   frame it covers the texture completely. If the grain ran over
   the photograph instead, it would vanish at the handoff — the
   hero underneath has no grain — and that pop is exactly the seam
   this whole sequence exists to avoid.

   The noise is generated by SVG filters inlined as data URIs.
   feTurbulence is evaluated once, when the image decodes; there
   is no per-frame cost. */
.loader::before,
.loader::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.loader::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='700' height='700'%3E%3Cfilter id='m'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.019' numOctaves='4' seed='11'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23m)'/%3E%3C/svg%3E");
  background-size: cover;
  background-position: center;
  mix-blend-mode: soft-light;
  /* Kept low on purpose. At .55 the mottling was strong enough to
     cancel the gradient's own light source — the ground stopped
     having a direction and just looked cloudy. Texture should
     modulate the light that is there, not replace it. */
  opacity: .32;
}

.loader::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 200px 200px;
  background-repeat: repeat;
  /* NO blend mode, and that is the point.

     This was mix-blend-mode: overlay at .07 and it rendered
     nothing at all — feTurbulence output sits around mid-grey,
     and overlay against a mid-grey source barely moves a dark
     base, so seven percent of almost-nothing is nothing. Checked
     side by side on this exact gradient: overlay at .20 and
     soft-light at .30 were both still invisible; plain alpha at
     .07 is the only one that reads.

     The trade is that grey noise at plain alpha lifts the navy a
     touch. That is cheaper than the banding it removes. */
  opacity: .07;
}

.ld-stage {
  /* the mark */
  --ld-w: 30rem;
  --ld-h: calc(var(--ld-w) * 765 / 1327);   /* the artwork's own ratio */
  /* the block the photograph opens to — its own, larger box */
  --blk-w: 78rem;
  --blk-h: calc(var(--blk-w) / 1.8);

  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
}

/* ── The photograph ──────────────────────────────────────
   A centred window with a viewport-sized image inside it. The
   WINDOW is what animates — zero height, then the block, then the
   whole frame. The image never resizes: it is pinned to the
   viewport centre at 100vw x 100vh, so growing the window simply
   uncovers a picture that was always there.

   Deliberately not clip-path for this part. Interpolating inset()
   across three states did not hold — the opening ran
   non-monotonically, showing MORE photograph part-way than later. */
.ld-photo {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  margin: auto;
  z-index: 1;
  width: var(--blk-w);
  height: 0;
  overflow: hidden;
}
.ld-photo img {
  position: absolute;
  top: 50%; left: 50%;
  width: 100vw;
  height: 100vh;
  max-width: none;
  object-fit: cover;
  object-position: center 55%;
  will-change: transform;
}

/* This banner is bright cream architecture, so a gold mark laid
   straight onto it disappears. The veil holds the photograph back
   while the mark is still on top, and lifts with it — which also
   makes the reveal read as the picture brightening. */
.ld-veil {
  position: absolute;
  inset: 0;
  background: radial-gradient(78% 90% at 50% 50%,
    rgba(17,17,17,.56) 0%, rgba(17,17,17,.74) 100%);
}

/* ── The mark ────────────────────────────────────────────── */
.ld-mark {
  position: relative;
  z-index: 2;
  width: var(--ld-w);
  height: var(--ld-h);
}

.ld-base,
.ld-fill,
.ld-glint {
  position: absolute;
  inset: 0;
  display: block;
}
/* White, because the ground beneath it is now deep navy. The gold
   sweep therefore runs white → gold rather than near-black → gold,
   which is the brighter of the two reveals and the one that suits
   a dark stage. */
.ld-base { background: #ffffff; }

/* Only the FILL is clipped now. The second pass moves by
   background-position instead, so its edges stay soft. */
.ld-fillwrap,
.ld-glintwrap {
  position: absolute;
  inset: 0;
}
.ld-fillwrap { clip-path: circle(0% at 6% 94%); }

.ld-fill {
  background: linear-gradient(103deg,
    var(--gold-deep) 0%,
    var(--gold)      20%,
    #f4e3bb          40%,
    var(--gold-lift) 56%,
    var(--gold)      76%,
    var(--gold-deep) 100%);
}

/* ── The second pass ─────────────────────────────────────
   A specular travelling across the finished metal.

   NOT a clipped band of flat colour — that reads as paint being
   dragged over the mark. What makes it read as light on a
   polished surface is soft edges and a blend: a narrow intense
   core inside a broad halo, with a fainter secondary highlight
   trailing it, the way a real reflection breaks on a curved
   surface. The gradient MOVES via background-position rather
   than being clipped, so the edges stay soft the whole way.

   screen keeps the gold underneath: a white band at full alpha
   would blow the metal out to paper white, whereas screening a
   partial white over #c9a063 brightens it and holds the hue. */
.ld-glint {
  background: linear-gradient(163deg,
    rgba(255,255,255,0)     46.0%,
    rgba(255,246,226,.22)   47.6%,
    rgba(255,252,240,.66)   49.2%,
    rgba(255,255,255,.95)   50.0%,
    rgba(255,252,240,.66)   50.8%,
    rgba(255,246,226,.22)   52.4%,
    rgba(255,255,255,0)     54.0%,
    /* the trailing second highlight — what says glass rather
       than simply bright */
    rgba(255,250,236,.14)   56.4%,
    rgba(255,253,244,.42)   57.8%,
    rgba(255,250,236,.14)   59.2%,
    rgba(255,255,255,0)     61.4%);
  /* The stop span multiplied by this size is what sets the streak's
     width on screen. At 300% an 8% span is roughly a quarter of the
     mark's height — a streak. Widen the span and it stops being a
     highlight and becomes the whole mark going pale. */
  background-size: 100% 300%;
  background-repeat: no-repeat;
  background-position: 50% 210%;
  mix-blend-mode: screen;
}


/* ── Footline ─────────────────────────────────────────────── */
.ld-foot {
  position: absolute;
  left: var(--pad); right: var(--pad); bottom: 3.6rem;
  z-index: 3;
  display: flex;
  justify-content: flex-end;
  gap: 2rem;
  /* was near-black for the white ground — invisible on navy */
  color: rgba(255,255,255,.34);
}

/* ── Responsive ──────────────────────────────────────────
   Both boxes are in rem, and rem is a slice of the viewport, so
   they scale on their own. What the breakpoints change is the
   RELATIONSHIP: on a narrow screen the block has to take almost
   the full width to still read as an opening rather than a stamp,
   and the mark shrinks so it keeps its margin inside it. */
@media (max-width: 1200px) {
  .ld-stage { --ld-w: 27rem; --blk-w: 82vw; }
}
@media (max-width: 991px) {
  .ld-stage { --ld-w: 25rem; --blk-w: 84vw; --blk-h: calc(var(--blk-w) / 1.5); }
}
@media (max-width: 767px) {
  .ld-stage { --ld-w: 19rem; --blk-w: 88vw; --blk-h: calc(var(--blk-w) / 1.15); }
  .ld-foot { bottom: 2.4rem; }
}
/* Short landscape phones: the block has to be bounded by HEIGHT or
   it opens straight past the top and bottom of the screen. */
@media (max-height: 560px) {
  .ld-stage { --blk-h: 72vh; --blk-w: calc(var(--blk-h) * 1.8); --ld-w: 21rem; }
}

/* Reduced motion gets the destination, not the journey. */
@media (prefers-reduced-motion: reduce) {
  .ld-photo { width: 100vw !important; height: 100vh !important; }
  .ld-veil, .ld-mark { display: none; }
}

/* ── Progress ────────────────────────────────────────────
   A hairline under the mark that fills as the gold does.

   POSITIONED OFF THE MARK'S OWN HEIGHT, not off a guessed offset.
   .ld-stage centres the mark, so the mark's foot is always at
   50% + --ld-h/2 whatever the breakpoint does to --ld-w — and
   --ld-h is derived from --ld-w. Hard-coding a top value would
   need re-tuning at every one of the four sizes this stage takes.

   Small on purpose. This is a progress indicator on a five-second
   loader: it exists to say the wait is finite, and anything more
   emphatic than a hairline starts competing with the mark it is
   supposed to be reporting on. */
.ld-bar {
  position: absolute;
  left: 50%;
  top: calc(50% + var(--ld-h) / 2 + 3.6rem);
  transform: translateX(-50%);
  z-index: 2;
  /* The mark's own width, so the two are one object rather than a
     rule that happens to sit near a logo. --ld-w is what every
     breakpoint already adjusts, so this tracks all four sizes
     without a single override. */
  width: var(--ld-w);
  height: var(--hair);
  background: rgba(255,255,255,.18);
  overflow: hidden;
  opacity: 0;
}
.ld-bar i {
  display: block;
  width: 100%;
  height: 100%;
  /* SYMMETRIC, because the growth is. Brightest at the middle and
     falling away to both ends, which is where the fill opens from —
     a one-way ramp would have a bright end and a dull one on a bar
     that is expanding in both directions at once. */
  background: linear-gradient(90deg, var(--gold-deep), var(--gold-lift) 50%, var(--gold-deep));
  transform: scaleX(0);
  /* FROM THE CENTRE OUT. Scaling from the left edge made it a
     conventional loading bar; opening from the middle to both ends
     echoes the mark it sits under, which is itself symmetrical. */
  transform-origin: center;
}

@media (max-width: 767px) { .ld-bar { top: calc(50% + var(--ld-h) / 2 + 2.8rem); } }

@media (prefers-reduced-motion: reduce) { .ld-bar { display: none; } }
