/* Landing page: the painting rebuilt as separate layers.
 *
 * The scene is not one image. The sky, the ridge and the snow are three strips
 * that resize independently, and the four figures are cut-outs positioned on
 * top of them. That is what lets the page fill any window: the sky absorbs
 * spare height, the ridge and snow keep the horizon where it belongs, and the
 * figures scale as a group so they never crop off the side of a phone.
 *
 * All figure geometry is expressed as a fraction of --fig (the person's
 * height), taken straight from the painting, so the group keeps its original
 * proportions and spacing at every size.
 */

:root {
  /* How big the figures are. Bounded below so they stay tappable on a phone
     and above so they do not tower on a large monitor; the vh term keeps the
     person's head on screen in a short, wide window. */
  --fig: clamp(190px, min(38vw, 64vh), 660px);

  /* Ground strips. The snow is near enough uniform that stretching it is
     invisible; the ridge is kept closer to its natural proportion. */
  --ridge-h: clamp(56px, 9vw, 190px);
  --snow-h: clamp(120px, 25vh, 320px);

  /* Where the group sits across the width. */
  --px: 33vw;   /* the person's centre  */
  --sx: 70vw;   /* the sputnik's centre */
  --sky-top: clamp(14px, 7vh, 96px);

  --ink: #0f1f3d;
}

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  background: #123061;
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

.scene {
  position: fixed;
  inset: 0;
  overflow: hidden;
}

/* ---------- background strips ---------- */

.band {
  position: absolute;
  left: 0;
  right: 0;
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

/* Each strip is drawn over the one behind it and runs a few pixels past the
   join, so sub-pixel rounding cannot open a hairline of page background
   between them.

   The strips are cut full-width from a figure-free version of the painting;
   the figures are placed by CSS rather than by where they were painted. */
.band--sky {
  top: 0;
  bottom: calc(var(--ridge-h) + var(--snow-h) - 4px);
  background-image: url("/images/landing/sky.jpg");
  /* The sky carries the aurora, which should not be squashed to fit, so it
     keeps its own aspect and is anchored to the horizon; the strip is painted
     tall enough (plain sky extended upward) to fill a phone screen, and the
     colour behind it matches its top edge in case a window is taller still. */
  background-size: 100% auto;
  background-position: center bottom;
  background-color: #102a55;
}

.band--ridge {
  height: var(--ridge-h);
  bottom: calc(var(--snow-h) - 3px);
  background-image: url("/images/landing/ridge.jpg");
}

.band--snow {
  height: var(--snow-h);
  bottom: 0;
  background-image: url("/images/landing/snow.jpg");
}

/* ---------- figures ---------- */

.obj {
  position: absolute;
  display: block;
  /* The anchor box is a rectangle; only the traced silhouette inside it should
     answer to the pointer, so the box itself stays inert and the hit path
     switches events back on. */
  pointer-events: none;
  -webkit-tap-highlight-color: transparent;
}

.obj img {
  display: block;
  /* Safari clips a transitioned drop-shadow to the image's own box, which
     cut the hover glow off in a straight line where the box ends. Pad the
     box out by the blur radius (and pull it back with a negative margin) so
     the figure stays put but the glow has room. */
  --glow: 18px;
  box-sizing: border-box;
  width: calc(100% + 2 * var(--glow));
  height: calc(100% + 2 * var(--glow));
  padding: var(--glow);
  margin: calc(-1 * var(--glow));
  transition: filter .25s ease, transform .25s ease;
}

.obj .hit {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* fill-opacity 0 still takes the pointer under pointer-events: fill */
.obj .hit path {
  fill: #000;
  fill-opacity: 0;
  pointer-events: fill;
  cursor: pointer;
}

.obj:hover img,
.obj:focus-visible img {
  filter: drop-shadow(0 0 14px rgba(255, 255, 255, .7)) brightness(1.04);
  transform: translateY(-3px);
}

.obj:focus-visible {
  outline: none;
}

.obj--person {
  z-index: 3;
  width: calc(var(--fig) * .270042);
  height: var(--fig);
  left: calc(var(--px) - var(--fig) * .135021);
  bottom: calc(var(--snow-h) - var(--fig) * .154008);
}

.obj--duck-left {
  z-index: 3;
  width: calc(var(--fig) * .348101);
  height: calc(var(--fig) * .415612);
  left: calc(var(--px) - var(--fig) * .597046);
  bottom: calc(var(--snow-h) - var(--fig) * .128692);
}

/* nearer the viewer than the person: it stands lower on the snow */
.obj--duck-right {
  z-index: 4;
  width: calc(var(--fig) * .223629);
  height: calc(var(--fig) * .369198);
  left: calc(var(--px) + var(--fig) * .162447);
  bottom: calc(var(--snow-h) - var(--fig) * .162447);
}

.obj--sputnik {
  z-index: 2;
  width: calc(var(--fig) * .755274);
  height: calc(var(--fig) * .607595);
  left: calc(var(--sx) - var(--fig) * .377637);
  top: var(--sky-top);
}

/* ---------- arrival cue ---------- */

/* On load, each object gets a soft version of the hover glow in a quick
   left-to-right sweep, holds it about a second, and lets it go. It runs
   once; hovering anything during the sweep hands over to the normal hover
   glow (see the script in the landing layout). */
@keyframes reveal {
  0%       { filter: none; transform: none; }
  22%, 62% { filter: drop-shadow(0 0 14px rgba(255, 255, 255, .55)) brightness(1.03); transform: translateY(-2px); }
  100%     { filter: none; transform: none; }
}

/* the same without the lift, for people who have asked for reduced motion */
@keyframes reveal-still {
  0%       { filter: none; }
  22%, 62% { filter: drop-shadow(0 0 14px rgba(255, 255, 255, .55)) brightness(1.03); }
  100%     { filter: none; }
}

.scene:not(.seen) .obj img { animation: reveal 2.8s ease-in-out var(--d, 0s) 1 both; }
.obj--duck-left  { --d: .35s; }
.obj--person     { --d: .50s; }
.obj--duck-right { --d: .65s; }
.obj--sputnik    { --d: .80s; }

@media (prefers-reduced-motion: reduce) {
  .scene:not(.seen) .obj img { animation-name: reveal-still; }
}

/* ---------- labels ---------- */

.tag {
  position: absolute;
  left: 50%;
  bottom: 100%;
  transform: translate(-50%, 6px);
  margin-bottom: .6em;
  padding: .42em .85em;
  border-radius: 100px;
  white-space: nowrap;
  font-size: clamp(11px, 1.15vw, 14px);
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--ink);
  background: rgba(255, 255, 255, .93);
  box-shadow: 0 2px 14px rgba(8, 20, 45, .28);
  opacity: 0;
  transition: opacity .22s ease, transform .22s ease;
}

/* the sputnik's box is mostly empty sky, so its label sits under the sphere */
.obj--sputnik .tag {
  left: 78%;
  bottom: 28%;
}

.obj:hover .tag,
.obj:focus-visible .tag {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ---------- masthead ---------- */

.masthead {
  position: absolute;
  z-index: 5;
  top: clamp(20px, 4.5vh, 52px);
  left: clamp(20px, 4vw, 68px);
}

.intro {
  margin: 0;
  font-size: clamp(20px, 2.5vw, 34px);
  font-weight: 500;
  letter-spacing: -.015em;
  color: #fff;
  text-shadow: 0 1px 20px rgba(6, 16, 38, .55);
}

/* Social links under the name: small marks, each tinted to sit in the sky
   rather than shout its brand colour, brightening on hover. */
.social {
  display: flex;
  gap: 14px;
  margin-top: 10px;
}

.social__link {
  display: block;
  width: 17px;
  height: 17px;
  color: var(--tint, #dfe6ee);
  opacity: .72;
  filter: drop-shadow(0 1px 6px rgba(6, 16, 38, .5));
  transition: opacity .2s ease, transform .2s ease;
}

.social__link svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: currentColor;
}

.social__link:hover,
.social__link:focus-visible {
  opacity: 1;
  transform: translateY(-1px);
}

.social__link:focus-visible {
  outline: 2px solid rgba(255, 255, 255, .8);
  outline-offset: 3px;
  border-radius: 3px;
}

.social__link--linkedin     { --tint: #8fbcf0; }
.social__link--x            { --tint: #e6ecf3; }
.social__link--github       { --tint: #d9d2c4; }
.social__link--researchgate { --tint: #7dd6c8; }

/* ---------- narrow screens ----------
   The group spans .98 x --fig and sits off-centre within it (the person is
   right of middle), so --px is derived from the group's centre rather than
   guessed: that keeps equal margins either side however wide the figures get.
   Below each breakpoint --fig is driven by width instead of the desktop
   default, so the figures grow to use a phone's narrow viewport instead of
   shrinking into the middle of it. */

@media (max-width: 900px) {
  :root {
    --fig: clamp(190px, min(46vw, 50vh), 460px);
    --px: calc(50vw + var(--fig) * .105485);
    --sx: 72vw;
  }
}

@media (max-width: 620px) {
  :root {
    --fig: clamp(190px, min(78vw, 40vh), 420px);
    --px: calc(50vw + var(--fig) * .105485);
    --sx: 68vw;
    --sky-top: clamp(70px, 15vh, 150px);
    --ridge-h: clamp(48px, 12vw, 120px);
    --snow-h: clamp(110px, 22vh, 260px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .obj img,
  .tag,
  .social__link {
    transition: none;
  }
  .obj:hover img,
  .obj:focus-visible img {
    transform: none;
  }
}
