/* =========================================================================
   George Tolentino — personal landing page
   1. Tokens   2. Base   3. Backdrop   4. Layout   5. Memoji
   6. Satellites   7. Typography   8. Footer   9. Motion   10. Responsive
   ========================================================================= */

/* ---------------------------------------------------------- 1. Tokens --- */
:root {
  /* Type */
  --font-sans: "Gill Sans", "Gill Sans MT", "Gill Sans Nova", Calibri, sans-serif;

  /* Ink & surfaces */
  --bg: #f5f5f7;
  --ink: #1d1d1f;
  --ink-soft: #6e6e73;
  --ink-faint: #aeaeb2;
  --glass: rgba(255, 255, 255, 0.58);
  --glass-hover: rgba(255, 255, 255, 0.76);
  --glass-border: rgba(255, 255, 255, 0.75);
  --hairline: rgba(0, 0, 0, 0.055);
  --focus: #0071e3;

  /* Composition — the orbit box is a square; the Memoji sits at its centre
     and every social icon is placed as a percentage of it. */
  --orbit-size: min(540px, 84vw, 72vh);
  --orbit-size: min(540px, 84vw, 72svh);
  --orbit-ratio: 0.8;
  --memoji-y: 54%;
  --memoji-size: min(clamp(132px, 38vw, 232px), 27vh);
  --memoji-size: min(clamp(132px, 38vw, 232px), 27svh);
  --sat-size: 62px;
  --sat-icon: 27px;

  /* Shadow stacks */
  --shadow-sat:
    0 1px 1px rgba(16, 24, 40, 0.035),
    0 6px 12px -5px rgba(16, 24, 40, 0.10),
    0 16px 30px -12px rgba(16, 24, 40, 0.16);
  --shadow-sat-hover:
    0 1px 1px rgba(16, 24, 40, 0.04),
    0 10px 20px -6px rgba(16, 24, 40, 0.13),
    0 26px 46px -14px rgba(16, 24, 40, 0.20);

  /* Motion */
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-soft: cubic-bezier(0.32, 0.72, 0.24, 1);

  /* Live pointer position, -1 → 1 on each axis (written by script.js) */
  --pointer-x: 0;
  --pointer-y: 0;
}

/* ------------------------------------------------------------ 2. Base --- */
*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.5;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { max-width: 100%; }

a { color: inherit; }

:where(a, button):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 4px;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* -------------------------------------------------------- 3. Backdrop --- */
/* Barely-there radial tints over the base grey. Every stop fades to its own
   hue at zero alpha so there is no grey halo and no hard blob edge. */
.backdrop {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-color: var(--bg);
  background-image:
    radial-gradient(58vw 46vw at 18% 8%,  rgba(96, 140, 220, 0.115), rgba(96, 140, 220, 0) 68%),
    radial-gradient(52vw 44vw at 86% 14%, rgba(150, 112, 214, 0.10), rgba(150, 112, 214, 0) 66%),
    radial-gradient(64vw 50vw at 62% 96%, rgba(226, 182, 148, 0.095), rgba(226, 182, 148, 0) 70%),
    radial-gradient(46vw 38vw at 6% 82%,  rgba(120, 176, 210, 0.075), rgba(120, 176, 210, 0) 68%);
}

/* Fine grain — invisible on its own, but it stops the gradients banding. */
.backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.025;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------------------------------------------------------- 4. Layout --- */
.hero {
  flex: 1;
  display: grid;
  place-items: center;
  padding: clamp(28px, 6vh, 64px) 20px clamp(12px, 3vh, 28px);
}

.identity {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 100%;
}

.orbit {
  position: relative;
  width: var(--orbit-size);
  height: calc(var(--orbit-size) * var(--orbit-ratio));
}

/* --------------------------------------------------------- 5. Memoji --- */
.memoji {
  position: absolute;
  left: 50%;
  top: var(--memoji-y);
  z-index: 1;
  /* Pointer drift — a few pixels, deliberately almost subliminal. */
  --depth: 5;
  transform:
    translate(-50%, -50%)
    translate3d(
      calc(var(--pointer-x) * var(--depth) * 1px),
      calc(var(--pointer-y) * var(--depth) * 1px), 0);
  will-change: transform;
}

.memoji__inner {
  position: relative;
  display: grid;
  place-items: center;
  width: var(--memoji-size);
  height: var(--memoji-size);
}

/* Soft halo that lifts the figure off the grey without framing it. */
.memoji__aura {
  position: absolute;
  inset: -26%;
  pointer-events: none;
  border-radius: 50%;
  background:
    radial-gradient(closest-side, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0) 72%),
    radial-gradient(closest-side, rgba(128, 152, 232, 0.14), rgba(128, 152, 232, 0) 66%);
}

.memoji__img {
  position: relative;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
}

/* Contact shadow on the ground plane. */
.memoji__ground {
  position: absolute;
  pointer-events: none;
  left: 50%;
  bottom: -2%;
  width: 58%;
  height: 8%;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(38, 40, 58, 0.20), rgba(38, 40, 58, 0) 78%);
  filter: blur(4px);
}

/* ----------------------------------------------------- 6. Satellites --- */
.satellites {
  position: absolute;
  inset: 0;
  z-index: 2;
  margin: 0;
  padding: 0;
  list-style: none;
  pointer-events: none;
}

.satellite {
  position: absolute;
  left: calc(var(--x) * 1%);
  top: calc(var(--y) * 1%);
  --depth: 10;
  transform:
    translate(-50%, -50%)
    translate3d(
      calc(var(--pointer-x) * var(--depth) * 1px),
      calc(var(--pointer-y) * var(--depth) * 1px), 0);
  will-change: transform;
}

/* Depth and float timing cycle, so any number of icons stays desynchronised. */
.satellite:nth-child(5n + 1) { --depth: 11; --float: float-a; --float-dur: 9.5s; }
.satellite:nth-child(5n + 2) { --depth: 8;  --float: float-b; --float-dur: 12s; }
.satellite:nth-child(5n + 3) { --depth: 13; --float: float-c; --float-dur: 10.5s; }
.satellite:nth-child(5n + 4) { --depth: 9;  --float: float-d; --float-dur: 13s; }
.satellite:nth-child(5n + 5) { --depth: 10; --float: float-e; --float-dur: 11.5s; }

.satellite__float { position: relative; display: block; }

.satellite:has(.satellite__link:hover),
.satellite:has(.satellite__link:focus-visible) { z-index: 1; }

.satellite__link {
  position: relative;
  display: grid;
  place-items: center;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  width: var(--sat-size);
  height: var(--sat-size);
  border-radius: 50%;
  pointer-events: auto;
  text-decoration: none;
  background: var(--glass);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-sat), inset 0 1px 0 rgba(255, 255, 255, 0.85);
  transition:
    transform 0.34s var(--ease-soft),
    box-shadow 0.34s var(--ease-soft),
    background-color 0.34s var(--ease-soft);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .satellite__link {
    background: rgba(255, 255, 255, 0.42);
    -webkit-backdrop-filter: blur(22px) saturate(180%);
    backdrop-filter: blur(22px) saturate(180%);
  }
}

/* Whisper of the brand colour, so each button has its own quiet temperature. */
.satellite__link::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(closest-side, rgb(var(--brand) / 0.10), rgb(var(--brand) / 0) 100%);
  opacity: 0.7;
  transition: opacity 0.42s var(--ease-soft);
}

.satellite__icon {
  position: relative;
  display: grid;
  place-items: center;
  width: calc(var(--sat-icon) * var(--icon-trim, 1));
  height: calc(var(--sat-icon) * var(--icon-trim, 1));
}

.satellite__icon svg { width: 100%; height: 100%; display: block; }

/* Solid marks read heavier than outlined ones at the same size, so the filled
   disc and square are trimmed until every glyph carries equal optical weight. */
.satellite--facebook .satellite__icon { --icon-trim: 0.88; }
.satellite--linkedin .satellite__icon { --icon-trim: 0.86; }

.satellite__link:hover,
.satellite__link:focus-visible {
  transform: translateY(-8px) scale(1.16);
  background-color: var(--glass-hover);
  box-shadow:
    var(--shadow-sat-hover),
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 12px 34px -10px rgb(var(--brand) / 0.42);
}

.satellite__link:hover::before,
.satellite__link:focus-visible::before { opacity: 1; }

.satellite__link:active { transform: translateY(-3px) scale(1.08); }

/* Tooltip */
.satellite__tip {
  position: absolute;
  top: calc(100% + 11px);
  left: 50%;
  padding: 4px 11px 5px;
  border-radius: 999px;
  white-space: nowrap;
  font-size: 12px;
  line-height: 1.4;
  letter-spacing: 0.012em;
  color: var(--ink-soft);
  background: rgba(255, 255, 255, 0.78);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border: 1px solid var(--hairline);
  box-shadow: 0 6px 16px -8px rgba(16, 24, 40, 0.28);
  opacity: 0;
  transform: translate(-50%, -4px);
  transition: opacity 0.28s var(--ease-out), transform 0.28s var(--ease-out);
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  .satellite__link:hover + .satellite__tip { opacity: 1; transform: translate(-50%, 0); }
}

.satellite__link:focus-visible + .satellite__tip { opacity: 1; transform: translate(-50%, 0); }

/* ------------------------------------------------------ 7. Typography --- */
.intro {
  margin-top: clamp(18px, 3.4vh, 38px);
  text-align: center;
  max-width: min(100%, 44rem);
}

.intro__name {
  margin: 0;
  font-size: clamp(1.75rem, 1.28rem + 1.5vw, 2.375rem);
  font-weight: 600;
  letter-spacing: -0.014em;
  line-height: 1.14;
  color: var(--ink);
}

.intro__subtitle {
  margin: clamp(10px, 1.4vh, 15px) 0 0;
  font-size: clamp(0.875rem, 0.82rem + 0.2vw, 1rem);
  font-weight: 400;
  letter-spacing: 0.014em;
  line-height: 1.62;
  color: var(--ink-soft);
  text-wrap: balance;
  overflow-wrap: break-word;
}

/* ---------------------------------------------------------- 8. Footer --- */
.footer {
  padding: 0 20px clamp(18px, 3.4vh, 34px);
  text-align: center;
}

.footer__text {
  margin: 0;
  font-size: 12px;
  letter-spacing: 0.03em;
  color: var(--ink-faint);
}

/* ---------------------------------------------------------- 9. Motion --- */
@media (prefers-reduced-motion: no-preference) {
  .backdrop { animation: fade-in 1s var(--ease-out) both; }

  .memoji__inner { animation: memoji-in 0.95s var(--ease-out) 0.1s both; }

  .intro__name     { animation: rise-in 0.8s var(--ease-out) 0.36s both; }
  .intro__subtitle { animation: rise-in 0.8s var(--ease-out) 0.46s both; }
  .footer__text    { animation: rise-in 0.8s var(--ease-out) 0.86s both; }

  /* Entrance, then an endless drift — two animations, one transform channel,
     the second starting only once the first has settled. */
  .satellite__float {
    animation-name: sat-in, var(--float, float-a);
    animation-duration: 0.75s, var(--float-dur, 10s);
    animation-timing-function: var(--ease-out), ease-in-out;
    animation-delay: var(--enter-delay, 0.5s), calc(var(--enter-delay, 0.5s) + 1.1s);
    animation-iteration-count: 1, infinite;
    animation-fill-mode: both, none;
  }
}

@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes memoji-in {
  from { opacity: 0; transform: scale(0.94) translateY(10px); }
  to   { opacity: 1; transform: none; }
}

@keyframes rise-in {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

@keyframes sat-in {
  from { opacity: 0; transform: scale(0.86) translateY(10px); }
  to   { opacity: 1; transform: none; }
}

@keyframes float-a {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-5px); }
}

@keyframes float-b {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  50%      { transform: translate(3px, 4px) rotate(0.9deg); }
}

@keyframes float-c {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  50%      { transform: translate(-3px, -3px) rotate(-1deg); }
}

@keyframes float-d {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(4px); }
}

@keyframes float-e {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  50%      { transform: translate(-2px, 4px) rotate(0.6deg); }
}

@media (prefers-reduced-motion: reduce) {
  .contact__panel { transition: none; }

  .satellite__link {
    transition: box-shadow 0.2s ease, background-color 0.2s ease;
  }
  .satellite__link:hover,
  .satellite__link:focus-visible,
  .satellite__link:active { transform: none; }
  .satellite__tip { transition: opacity 0.2s ease; transform: translate(-50%, 0); }
}

/* --------------------------------------------------- 11. Contact card --- */
.contact {
  inset: 0;
  margin: auto;
  padding: 0;
  border: 0;
  max-width: none;
  max-height: none;
  overflow: visible;
  background: none;
  color: inherit;
}

.contact::backdrop {
  background: rgba(22, 24, 32, 0.26);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

.contact__panel {
  position: relative;
  width: min(360px, calc(100vw - 40px));
  padding: 30px 26px 26px;
  border-radius: 28px;
  text-align: center;
  background: rgba(255, 255, 255, 0.86);
  border: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow:
    0 1px 1px rgba(16, 24, 40, 0.04),
    0 18px 40px -14px rgba(16, 24, 40, 0.22),
    0 44px 80px -28px rgba(16, 24, 40, 0.32);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .contact__panel {
    background: rgba(255, 255, 255, 0.81);
    -webkit-backdrop-filter: blur(34px) saturate(180%);
    backdrop-filter: blur(34px) saturate(180%);
  }
}

.contact__close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  color: var(--ink-soft);
  background: transparent;
  transition: background-color 0.24s var(--ease-soft), color 0.24s var(--ease-soft);
}

.contact__close svg { width: 17px; height: 17px; }

.contact__close:hover,
.contact__close:focus-visible {
  background: rgba(0, 0, 0, 0.055);
  color: var(--ink);
}

/* The greeting, set in the same Gill Sans as the rest of the page. */
.contact__title { margin: 0; }

.contact__greeting {
  display: flex;
  justify-content: center;
  font-size: clamp(2.125rem, 1.7rem + 1.6vw, 2.625rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--ink);
}

.contact__letter { display: inline-block; white-space: pre; }

.contact__list {
  margin: 26px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 9px;
}

.contact__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 9px 9px 15px;
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid var(--hairline);
}

.contact__address {
  font-size: 15px;
  letter-spacing: 0.008em;
  color: var(--ink);
  text-decoration: none;
  overflow-wrap: anywhere;
  text-align: left;
}

.contact__address:hover { text-decoration: underline; }

.contact__copy {
  flex: none;
  padding: 6px 12px 7px;
  border-radius: 999px;
  font: inherit;
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  cursor: pointer;
  background: rgba(255, 255, 255, 0.85);
  border: 1px solid var(--hairline);
  transition: background-color 0.24s var(--ease-soft), color 0.24s var(--ease-soft);
}

.contact__copy:hover,
.contact__copy:focus-visible { background: #fff; color: var(--ink); }

.contact__copy[data-copied] { color: #1d8a4e; }

/* Announced to screen readers; sighted visitors get the button's own label. */
.contact__status {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------- 12. Contact motion --- */
@media (prefers-reduced-motion: no-preference) {
  .contact[open]::backdrop { animation: fade-in 0.3s var(--ease-out) both; }
  .contact[open] .contact__panel { animation: panel-in 0.42s var(--ease-out) both; }

  .contact[open] .contact__letter {
    animation: letter-in 0.52s var(--ease-out) both;
    animation-delay: calc(0.16s + var(--i) * 0.07s);
  }
  .contact[open] .contact__letter--bang {
    animation-name: bang-in;
    animation-duration: 0.46s;
  }
  .contact[open] .contact__row { animation: rise-in 0.55s var(--ease-out) both; }
  .contact[open] .contact__row:nth-child(1) { animation-delay: 0.46s; }
  .contact[open] .contact__row:nth-child(2) { animation-delay: 0.56s; }
  .contact[open] .contact__row:nth-child(3) { animation-delay: 0.66s; }

  .contact.is-closing::backdrop { animation: backdrop-out 0.2s ease both; }
  .contact.is-closing .contact__panel { animation: panel-out 0.2s ease both; }
}

@keyframes panel-in {
  from { opacity: 0; transform: translateY(14px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}

@keyframes panel-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(8px) scale(0.97); }
}

@keyframes backdrop-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}

@keyframes letter-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

/* The "!" arrives a beat later with a little more snap. */
@keyframes bang-in {
  0%   { opacity: 0; transform: translateY(16px) scale(0.7); }
  62%  { opacity: 1; transform: translateY(0) scale(1.14); }
  100% { opacity: 1; transform: none; }
}

/* ------------------------------------------------------ 10. Responsive --- */

/* Tablet — hold the desktop composition, ease the scale back. */
@media (max-width: 900px) {
  :root { --sat-size: 58px; --sat-icon: 25px; }
}

/* Phones — the icons pull in closer to the Memoji and the buttons stay
   comfortably above a 44px touch target. */
@media (max-width: 599px) {
  :root {
    --orbit-size: min(420px, 88vw, 62vh);
    --orbit-size: min(420px, 88vw, 62svh);
    --orbit-ratio: 0.86;
    --sat-size: 52px;
    --sat-icon: 23px;
  }

  .satellite {
    left: calc(var(--xm, var(--x)) * 1%);
    top: calc(var(--ym, var(--y)) * 1%);
  }

  .intro { margin-top: clamp(14px, 2.6vh, 26px); }
}

/* Very narrow phones — a slightly smaller button still clears 44px. */
@media (max-width: 359px) {
  :root {
    --memoji-size: min(126px, 27vh);
    --memoji-size: min(126px, 27svh);
    --sat-size: 48px;
    --sat-icon: 21px;
  }
}

/* Short landscape windows — keep everything on one screen. */
@media (max-height: 560px) and (min-width: 600px) {
  :root {
    --orbit-size: min(540px, 84vw, 64vh);
    --orbit-size: min(540px, 84vw, 64svh);
    --sat-size: 52px;
    --sat-icon: 23px;
  }
  .hero { padding-top: clamp(16px, 4vh, 32px); }
}

/* Narrow phones — the card keeps its margins. */
@media (max-width: 359px) {
  .contact__panel { padding: 28px 18px 22px; border-radius: 24px; }
  .contact__address { font-size: 14px; }
}
