/* ============================================================
   DOCK  —  the site's navigation

   Replaces the hamburger and its full-screen panel. Four links in
   a bar, with a coloured disc that TRAVELS between them: it slides
   along the bar, the bar's top edge dips around it as it goes, and
   its colour and icon change to the item it is arriving at.

   MEASURED FROM THE REFERENCE CLIP, NOT EYEBALLED

   848x192, 276 frames at 30fps. Tracking the disc's centroid frame
   by frame across one single-step move gave the timing directly:

     time    distance covered
      0%        0.0%
     25%        8.9%
     50%       48.9%
     75%       86.2%
    100%       99.0%

   Twelve frames, so 0.4s, on a curve that holds at both ends and
   runs fast through the middle — cubic-bezier(.65,0,.35,1) fits
   that table within a percent. The centroid's Y never moved (68.x
   for the whole run), which is the thing worth knowing: the disc
   does not hop down and back up between items, it slides. Building
   it as a per-item pop would have been the obvious guess and the
   wrong one.

   The accent colours are sampled, not invented:
     #BAEA3C  #F0D254  #FC9024  #FC426C
   and mid-move the clip interpolates between them (measured at
   f190-f210: F85880 -> F87850 -> F8A028 -> F0D048), which is why
   the disc's colour is a transition here rather than a swap.

   THREE THINGS THE CLIP CANNOT SHOW

   It is a recording of a pointer, so it says nothing about
   keyboards, touch, or reduced motion. All three are handled:
   :focus-visible drives exactly the same state as :hover, the
   current page holds the disc when nothing is hovered, and the
   travel collapses to an instant move when motion is reduced.
   ============================================================ */

/* The sizes live on :root rather than on .dock because the page
   has to reserve room for a bar that, being fixed, takes none.

   Measured before adding it: at the foot of the page the dock sat
   on top of the copyright line and the "terms" link — a link the
   pointer could not reach, because the bar above it is the thing
   that receives the click. */
:root {
  /* Trimmed. Everything here is one step down from the first pass
     — the bar was reading as a slab rather than a control. */
  --dock-h: 50px;
  /* Fluid, not stepped. Five items at the old fixed 68px came to
     358px with the padding, which overflows a 320px phone — and
     the bar is centred, so it would have been clipped on both
     sides rather than obviously broken. The floor is set so five
     items plus padding clear 320px with room to spare. */
  --dock-item: clamp(42px, 10vw, 60px);
  --dock-disc: 42px;
  --dock-gap: clamp(0.75rem, 2vh, 1.5rem);

  /* THE DISC'S OWN TRAVEL TIME, NOT --dur-base.

     The reference clip measured 0.4s, and that is right for what it
     showed: a pointer WANDERING along a dock, with the disc
     trailing it so the lag reads as weight. It is wrong here, where
     the disc is chasing deliberate hovers on five nav links — the
     same 0.4s reads as the control being slow to answer.

     240ms keeps the ease-in-out curve legible while arriving before
     the pointer has moved on. Its own token rather than --dur-base
     so speeding the dock up does not speed up every transition on
     the site. */
  --dock-travel: 240ms;
}

@media (max-width: 420px) {
  :root {
    --dock-h: 46px;
    --dock-disc: 36px;
    --dock-item: clamp(36px, 12vw, 44px);
  }
}

body {
  padding-block-end: calc(var(--dock-h) + var(--dock-gap) + var(--sp-lg));
}

.dock {

  /* The bite taken out of the bar is wider than the disc, so a rim
     of page shows between the two. */
  --dock-bite: calc(var(--dock-disc) / 2 + 6px);

  /* Set by dock.js from the active item's measured centre, as a
     PHYSICAL distance from the bar's left edge — the same origin
     the mask below and the disc's translate both use.

     Deliberately not a logical offset. The first attempt anchored
     the disc with inset-inline-start, which in this RTL document
     pins it to the RIGHT edge, and then added a positive
     translateX on top. The two offsets compounded instead of
     cancelling and the disc landed at x=529 inside a 354px
     viewport — off the bar entirely, while still reporting the
     right size and colour to script. */
  --dock-x: 50%;
  --dock-c: var(--c-text);

  position: fixed;
  inset-block-end: var(--dock-gap);
  inset-inline: 0;
  z-index: var(--z-menu-btn);

  display: flex;
  justify-content: center;
  pointer-events: none;   /* only the bar itself is clickable */
}

.dock__bar {
  position: relative;
  pointer-events: auto;
  isolation: isolate;

  display: flex;
  block-size: var(--dock-h);
  padding-inline: var(--sp-xs);
  border-radius: var(--r-pill);
}

/* THE SURFACE IS A LAYER, NOT THE ELEMENT.

   The notch is a mask, and a mask on an element applies to
   everything that element renders — including its children. With
   the surface on .dock__bar itself the mask punched a hole through
   the disc as well, so the disc vanished at exactly the position
   it was supposed to occupy. Measured: the disc was in the DOM,
   had a colour and an icon, and was invisible on screen.

   Moving the surface to a pseudo-element leaves the mask with only
   the bar's own paint to cut, and the disc — a sibling in the
   stacking order rather than masked content — stays whole. */
.dock__bar::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;

  background-color: rgb(var(--rgb-media) / 0.92);
  border: 1px solid rgb(var(--rgb-ink) / 0.10);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  box-shadow: 0 16px 34px rgb(var(--rgb-shadow) / 0.45);

  /* The dip. A hole punched with a mask rather than an SVG path
     that would have to be re-drawn every frame — the centre is a
     custom property, so the notch follows the disc for free and
     the browser does the geometry.

     The 1px inset on the transparent stop closes the hair of
     background that antialiasing leaves around the rim. */
  -webkit-mask-image: radial-gradient(circle var(--dock-bite) at var(--dock-x) 0,
                        transparent calc(100% - 1px), #000 100%);
  mask-image: radial-gradient(circle var(--dock-bite) at var(--dock-x) 0,
                transparent calc(100% - 1px), #000 100%);
}

/* ---- the items ------------------------------------------------ */

.dock__list {
  position: relative;
  z-index: 1;
  display: flex;
  margin: 0;
  padding: 0;
  list-style: none;
}

.dock__link {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: var(--dock-item);
  block-size: 100%;
  color: rgb(var(--rgb-on-media) / 0.55);
  text-decoration: none;
  transition: color var(--dock-travel) var(--ease);
}

.dock__link svg {
  inline-size: 19px;
  block-size: 19px;
  transition: opacity var(--dock-travel) var(--ease),
              transform var(--dock-travel) var(--ease);
}

/* The icon of the item the disc is sitting on is hidden, because
   the disc is carrying a copy of it. Scaled rather than switched
   off so it drops back into place instead of blinking on. */
.dock__link.is-active svg {
  opacity: 0;
  transform: scale(0.6);
}

.dock__link:hover,
.dock__link:focus-visible {
  color: rgb(var(--rgb-on-media) / 0.9);
}

.dock__link:focus-visible {
  outline: 2px solid var(--dock-c);
  outline-offset: -4px;
  border-radius: var(--r-tile);
}

/* ---- the label -------------------------------------------------
   One element, not one per item: it crossfades its text the way the
   clip does, and a row of five labels each fading on its own would
   overlap during the swap.

   UNDER THE DISC, NOT UNDER THE BAR

   Centring it on the whole bar was the first attempt and it is
   wrong — in the clip the word sits directly beneath the disc and
   travels with it (f50, f100 and f130 all put the label's centre
   within a pixel or two of the disc's).

   It does NOT animate across, though: the clip fades the old word
   out and the new one in at its own position rather than sliding
   it. So the transform carries no transition — the jump happens
   while the label is at opacity 0, under cover of the same
   midpoint swap that changes the disc's icon. */
.dock__label {
  position: absolute;
  z-index: 1;
  inset-block-end: calc(var(--dock-h) * -0.02);
  left: 0;
  transform: translateX(var(--dock-x)) translateX(-50%);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  color: var(--dock-c);
  white-space: nowrap;
  pointer-events: none;
  transition: opacity calc(var(--dock-travel) * 0.5) var(--ease),
              color   var(--dock-travel) var(--ease);
}

/* ---- the travelling disc -------------------------------------- */

.dock__disc {
  position: absolute;
  z-index: 2;
  top: calc(var(--dock-disc) / -2);
  /* `left` and `margin-left`, not their logical twins: --dock-x is
     measured from the physical left edge, so the anchor has to be
     too or the two disagree in RTL. */
  left: 0;
  margin-left: calc(var(--dock-disc) / -2);
  inline-size: var(--dock-disc);
  block-size: var(--dock-disc);

  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background-color: var(--dock-c);
  color: rgb(var(--rgb-media));
  pointer-events: none;

  /* The halo. Same colour, so it reads as the disc's own light
     rather than a shadow under it. */
  box-shadow:
    0 0 22px rgb(var(--rgb-shadow) / 0.5),
    0 6px 18px color-mix(in srgb, var(--dock-c) 45%, transparent);

  /* `left` is the anchor and `translateX` is the motion, so the
     browser composites the travel instead of laying it out — this
     bar sits over the hero canvas, which already repaints on every
     scroll frame. */
  transform: translateX(var(--dock-tx, 0px));

  transition:
    transform        var(--dock-travel) cubic-bezier(.65, 0, .35, 1),
    background-color var(--dock-travel) var(--ease),
    box-shadow       var(--dock-travel) var(--ease);
}

.dock__disc svg {
  inline-size: 19px;
  block-size: 19px;
  transition: opacity calc(var(--dock-travel) * 0.5) var(--ease);
}

/* Set by dock.js at the midpoint of the move, so the icon swaps
   while the disc is between two items rather than at either end. */
.dock__disc.is-swapping svg { opacity: 0; }

/* ---- narrow screens --------------------------------------------
   Four items at 84px plus padding is 352px, which overflows a
   320px phone. The items shrink; the disc does not, because it is
   the thing the eye tracks. */
@media (max-width: 420px) {
  .dock__link svg,
  .dock__disc svg {
    inline-size: 17px;
    block-size: 17px;
  }
}

/* ---- reduced motion --------------------------------------------
   The disc still marks the active item — that is information, not
   decoration — but it stops travelling to get there. */
@media (prefers-reduced-motion: reduce) {
  .dock__disc,
  .dock__bar,
  .dock__label,
  .dock__link,
  .dock__link svg,
  .dock__disc svg {
    transition-duration: 1ms;
  }
}
