/* ═══════════════════════════════════════════════════════════════════════════
   The Lumen mark, as an actual three-dimensional object.
   ───────────────────────────────────────────────────────────────────────────
   The brand mark is three stacked sheets drawn in isometric projection. Every
   earlier "3D" treatment took that flat SVG and spun it with `rotateY`, which
   is why it never read as solid: a plane rotated about the screen's vertical
   axis is edge-on at 90° and 270°, so half of every turn was spent collapsed
   into an invisible sliver.

   This builds the real thing — three rounded square slabs stacked on a shared
   vertical axis, turning on that axis like a turntable. The silhouette breathes
   between the logo's diamond and an axis-aligned square, the sheets parallax
   against each other because they sit at different heights under a real
   perspective, and the light stays fixed in the world while the object turns
   beneath it. It never disappears, because we are always looking at the tops of
   three horizontal plates.

   EVERY NUMBER BELOW IS DERIVED FROM THE LOGO'S OWN PATH DATA — do not round
   them "cleaner". From `Logo.tsx` / the favicon, one sheet is:

       M15.08 5.02 Q16 4.58 16.92 5.02   → apex        (16,    4.58)
       L28.08 10.22 Q29.58 10.92 …       → right       (29.58, 10.92)
       L16.92 16.92 Q16 17.36 …          → base        (16,    17.36)
       L3.92 11.62 Q2.42 10.92 …         → left        ( 2.42, 10.92)

   so in the 32-unit design box a sheet is a rhombus of half-width 13.58 and
   half-height 6.39. Read as a square plate seen from above, that gives:

     • half-diagonal   d = 13.58                       (measured)
     • side            S = d·√2 = 19.205               (a square, rotated 45°)
     • camera tilt     θ = acos(6.39 / 13.58) = 61.93° (the flattening)
     • sheet spacing   H = 5.17 / sin(61.93°) = 5.86   (screen Δy → world height)

   Sheet centres in the logo sit at y = 10.92 / 16.09 / 21.17 — a screen step of
   5.17 — and the whole stack spans y 4.58…27.62. The reconstruction below spans
   4.44…27.56, i.e. the same mark. At spin angle 0 this IS the logo; that is the
   frame `prefers-reduced-motion` freezes on.

   Sizing: set `--l3d` to the box size. Everything else is a multiple of one
   design unit (`--l3d-u` = --l3d/32), so the mark is correct at any scale.
   ═══════════════════════════════════════════════════════════════════════════ */

.l3d {
  --l3d: 66px;
  --l3d-turn: 9s;                       /* slow enough to read as an object */
  --l3d-u: calc(var(--l3d) / 32);       /* one design unit */
  --l3d-side: calc(var(--l3d-u) * 19.205);
  --l3d-radius: calc(var(--l3d-u) * 1.6);
  --l3d-slice: calc(var(--l3d-u) * 0.42);    /* one of three rim slices */

  position: relative;
  display: inline-block;
  width: var(--l3d);
  height: var(--l3d);
  /* Long lens: enough parallax between the sheets to read as depth, not enough
     to distort the mark into a caricature of itself. */
  perspective: calc(var(--l3d) * 9);
  perspective-origin: 50% 42%;
}

/* The ground: a soft contact shadow so the stack sits on something. It does not
   rotate — light and floor belong to the world, not to the object. */
.l3d::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 74%;
  z-index: 0;
  width: calc(var(--l3d) * 0.74);
  height: calc(var(--l3d) * 0.3);
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(12, 18, 42, .34), rgba(12, 18, 42, .16) 45%, transparent 72%);
  filter: blur(calc(var(--l3d) * 0.035));
  pointer-events: none;
}

/* The camera. One static tilt — this is the isometric angle the logo is drawn
   at, so the object below it is always seen exactly as the mark is drawn. */
.l3d-stage {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transform: rotateX(61.93deg);
}

/* The turntable. Rotation about the stack's own vertical axis — the only
   rotation that keeps three horizontal plates facing the camera all the way
   round.

   Not linear. The sheets are all the same size, so at every multiple of 90° the
   silhouette is the logo's diamond and the layers step clearly past each other,
   while at the 45° angles between them the plates align into one rectangular
   block and the layered read is briefly lost. A constant-speed spin gives those
   two states equal airtime. Easing between quarter-turn keyframes instead makes
   the mark linger on the angles where it looks like itself and pass briskly
   through the ones where it doesn't — the difference between a logo turning and
   a logo being spun. */
.l3d-spin {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  animation: l3d-turn var(--l3d-turn) cubic-bezier(.5, .02, .5, .98) infinite;
}

/* ── One sheet ──────────────────────────────────────────────────────────────
   The element is the bottom rim slice; `::before` and `::after` are the two
   slices above it, and `> i` is the lit top face. Four coplanar layers, each
   0.42u apart, give the slab 1.26u of real thickness. At a 61.93° tilt that
   projects to a 1.1u shaded band along the near edge — enough to read as a cut
   face, little enough that the mark stays a stack of sheets rather than a stack
   of bricks. Thickness is the one number here NOT taken from the logo (a drawn
   sheet has none), so it is deliberately the smallest value that still reads.

   The inner `rotateZ(45deg)` is what makes a square read as the logo's diamond;
   it composes with the turntable angle, so the silhouette breathes as it turns
   instead of being a fixed outline spun in place. */
.l3d-sheet,
.l3d-sheet::before,
.l3d-sheet::after,
.l3d-sheet > i {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--l3d-side);
  height: var(--l3d-side);
  margin: calc(var(--l3d-side) / -2) 0 0 calc(var(--l3d-side) / -2);
  border-radius: var(--l3d-radius);
}

.l3d-sheet {
  transform-style: preserve-3d;
  /* set per sheet below; `left/top: 50%` is cancelled by the negative margin so
     the element's own centre is the stack axis */
}

.l3d-sheet::before,
.l3d-sheet::after {
  content: "";
  margin-top: calc(var(--l3d-side) / -2);
}

.l3d-sheet::before { transform: translateZ(var(--l3d-slice)); }
.l3d-sheet::after  { transform: translateZ(calc(var(--l3d-slice) * 2)); }

.l3d-sheet > i {
  transform: translateZ(calc(var(--l3d-slice) * 3));
  overflow: hidden;           /* clips the counter-rotating light overlay */
}

/* The sheets, at the three canonical heights. Each is offset down by the slab
   thickness so its FACE — the surface the logo actually draws — lands on the
   height the logo puts it at. */
.l3d-s1 { transform: translateZ(calc(var(--l3d-u) * -7.12)) rotateZ(45deg); }
.l3d-s2 { transform: translateZ(calc(var(--l3d-u) * -1.26)) rotateZ(45deg); }
.l3d-s3 { transform: translateZ(calc(var(--l3d-u) *  4.6))  rotateZ(45deg); }

/* ── Colour ────────────────────────────────────────────────────────────────
   The logo's ramp: deep document ink → structured indigo → luminous sea-glass.
   Each sheet's rim slices step darker as they descend, so the exposed edge
   shades like a real cut face instead of reading as a flat outline. */
.l3d-s1            { background: #191e45; }
.l3d-s1::before    { background: #1e2450; }
.l3d-s1::after     { background: #252c5c; }
.l3d-s1 > i        { background: #323a73; }

.l3d-s2            { background: #354095; }
.l3d-s2::before    { background: #3d48a8; }
.l3d-s2::after     { background: #4854bf; }
.l3d-s2 > i        { background: #5965d8; }

.l3d-s3            { background: #43a09b; }
.l3d-s3::before    { background: #4fb3ad; }
.l3d-s3::after     { background: #5fc7c0; }
/* The top sheet is the mark's light source: the bloom lives in its surface,
   exactly as the SVG paints it with a radial gradient plus a blurred ellipse. */
.l3d-s3 > i {
  background:
    radial-gradient(ellipse 46% 34% at 50% 46%, rgba(255, 255, 255, .5), transparent 70%),
    radial-gradient(circle at 50% 48%, #e2f7ff 0%, #b2e8f6 28%, #78d5ce 68%, #5fc7c0 100%);
}

/* ── The light ─────────────────────────────────────────────────────────────
   `b` counter-rotates against the turntable, which pins its gradient to world
   space: the highlight stays where the light is while the sheet turns under it.
   The overlay must cancel the sheet's own 45° as well as the spin, hence
   keyframes that run -45° → -405° rather than 0° → -360°. Scaled by √2 so a
   square overlay still covers the face at every angle. */
.l3d-sheet > i > b {
  position: absolute;
  inset: 0;
  display: block;
  transform-origin: 50% 50%;
  animation: l3d-unturn var(--l3d-turn) cubic-bezier(.5, .02, .5, .98) infinite;
  background: linear-gradient(
    160deg,
    rgba(255, 255, 255, .34) 0%,
    rgba(255, 255, 255, .1) 26%,
    transparent 48%,
    rgba(8, 12, 28, .13) 76%,
    rgba(8, 12, 28, .26) 100%
  );
  pointer-events: none;
}

/* The top sheet is already the brightest surface in the mark, so it takes a
   gentler modelling pass — otherwise the bloom greys over. */
.l3d-s3 > i > b {
  background: linear-gradient(
    160deg,
    rgba(255, 255, 255, .4) 0%,
    rgba(255, 255, 255, .12) 30%,
    transparent 52%,
    rgba(10, 42, 58, .1) 80%,
    rgba(10, 42, 58, .2) 100%
  );
}

/* Quarter-turn keyframes so the easing applies per quarter — the mark settles on
   each diamond angle and accelerates through the square ones. */
@keyframes l3d-turn {
  0%   { transform: rotateZ(0deg); }
  25%  { transform: rotateZ(90deg); }
  50%  { transform: rotateZ(180deg); }
  75%  { transform: rotateZ(270deg); }
  100% { transform: rotateZ(360deg); }
}
/* -45° → -405°: cancels the turntable AND the sheet's built-in 45°, so the light
   overlay is world-fixed. It MUST mirror `l3d-turn` keyframe for keyframe — same
   duration, same easing, same quarter stops — or the highlight drifts out of
   phase and starts sliding across the faces. */
@keyframes l3d-unturn {
  0%   { transform: rotateZ(-45deg) scale(1.42); }
  25%  { transform: rotateZ(-135deg) scale(1.42); }
  50%  { transform: rotateZ(-225deg) scale(1.42); }
  75%  { transform: rotateZ(-315deg) scale(1.42); }
  100% { transform: rotateZ(-405deg) scale(1.42); }
}

/* ── Halo ──────────────────────────────────────────────────────────────────
   An optional bloom behind the mark, for the hero placements where it stands
   alone on a dark field. Add `.l3d-halo`. */
.l3d-halo::after {
  content: "";
  position: absolute;
  inset: -18%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(216, 244, 255, .22), rgba(89, 101, 216, .16) 48%, transparent 72%);
  animation: l3d-breathe 6.5s ease-in-out infinite;
  pointer-events: none;
}
@keyframes l3d-breathe {
  0%, 100% { opacity: .8;  transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.07); }
}

/* Dark pages: lift the contact shadow, which would otherwise be a black smudge
   on a near-black field, and warm the halo slightly. */
:root[data-theme="dark"] .l3d::before {
  background: radial-gradient(ellipse at center, rgba(3, 6, 18, .5), rgba(3, 6, 18, .22) 45%, transparent 72%);
}

/* ── Reduced motion ────────────────────────────────────────────────────────
   Freeze on angle 0. That frame is the logo as drawn — same rhombi, same
   spacing, same ramp — so nothing is lost by holding still. */
@media (prefers-reduced-motion: reduce) {
  .l3d-spin,
  .l3d-sheet > i > b,
  .l3d-halo::after {
    animation: none !important;
  }
  .l3d-sheet > i > b { transform: rotateZ(-45deg) scale(1.42); }
}
