/* ==========================================================================
   Licheng Lin — personal link page
   Flat and monochrome: marks are drawn as translucent strokes straight onto
   the background. No cards, no shadows. The only colour anywhere is the
   ambient wash behind everything.

   Dark is the default. Light applies only when the visitor asks for it, so a
   browser expressing no preference lands on dark.
   ========================================================================== */

/* ---------- Tokens: dark (default) ---------- */
:root {
  --bg:          #000000;
  --label:       #f5f5f7;
  --label-2:     rgba(235, 235, 245, 0.50);
  --label-3:     rgba(235, 235, 245, 0.26);

  --line:        rgba(255, 255, 255, 0.46);   /* mark stroke, at rest */
  --line-hover:  rgba(255, 255, 255, 0.95);
  --ring:        rgba(255, 255, 255, 0.15);   /* avatar outline */
  --focus:       rgba(255, 255, 255, 0.75);

  --blob-a:      #4c5bd4;
  --blob-b:      #b7407a;
  --blob-c:      #1f8f86;
  --blob-alpha:  0.26;

  --spring:      cubic-bezier(0.16, 1, 0.3, 1);

  color-scheme: dark;
}

/* ---------- Tokens: light (opt-in) ---------- */
@media (prefers-color-scheme: light) {
  :root {
    --bg:          #f5f5f7;
    --label:       #1d1d1f;
    --label-2:     rgba(60, 60, 67, 0.55);
    --label-3:     rgba(60, 60, 67, 0.30);

    --line:        rgba(0, 0, 0, 0.40);
    --line-hover:  rgba(0, 0, 0, 0.90);
    --ring:        rgba(0, 0, 0, 0.13);
    --focus:       rgba(0, 0, 0, 0.65);

    --blob-a:      #7d8cff;
    --blob-b:      #ff9ec4;
    --blob-c:      #6fe3d2;
    --blob-alpha:  0.20;

    color-scheme: light;
  }
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  color: var(--label);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
               "Helvetica Neue", "Segoe UI Variable Text", "Segoe UI",
               "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
               Roboto, Inter, system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.47;
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* ---------- Ambient wash — the page's only colour ---------- */
.ambient {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

.blob {
  position: absolute;
  display: block;
  border-radius: 50%;
  opacity: var(--blob-alpha);
  filter: blur(120px);
  will-change: transform;
}

.blob-a {
  width: 46vmax; height: 46vmax;
  top: -20vmax; left: -16vmax;
  background: var(--blob-a);
  animation: drift-a 26s ease-in-out infinite alternate;
}
.blob-b {
  width: 38vmax; height: 38vmax;
  top: -10vmax; right: -16vmax;
  background: var(--blob-b);
  animation: drift-b 32s ease-in-out infinite alternate;
}
.blob-c {
  width: 36vmax; height: 36vmax;
  bottom: -18vmax; left: 30%;
  background: var(--blob-c);
  animation: drift-c 38s ease-in-out infinite alternate;
}

@keyframes drift-a { to { transform: translate3d(6vmax, 5vmax, 0) scale(1.12); } }
@keyframes drift-b { to { transform: translate3d(-7vmax, 7vmax, 0) scale(1.08); } }
@keyframes drift-c { to { transform: translate3d(4vmax, -6vmax, 0) scale(0.92); } }

/* ---------- Page ---------- */
.page {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 30rem;
  text-align: center;
  padding:
    calc(env(safe-area-inset-top, 0px) + 40px)
    calc(env(safe-area-inset-right, 0px) + 24px)
    calc(env(safe-area-inset-bottom, 0px) + 40px)
    calc(env(safe-area-inset-left, 0px) + 24px);
}

/* ---------- Hero ---------- */
.avatar {
  width: 74px;
  height: 74px;
  margin: 0 auto 20px;
  border: 1px solid var(--ring);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.avatar-mono {
  font-size: 24px;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--label-2);
  user-select: none;
}

.name {
  margin: 0 0 5px;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue",
               "Segoe UI Variable Display", "Segoe UI", "PingFang SC",
               "Microsoft YaHei", system-ui, sans-serif;
  font-size: clamp(27px, 7vw, 34px);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.handle {
  margin: 0;
  font-size: 15px;
  font-weight: 400;
  color: var(--label-2);
  letter-spacing: -0.005em;
}

/* ---------- Marks ---------- */
/* A grid rather than a wrapping flex row: the column count is chosen outright
   at each breakpoint, so the marks step 6×1 → 3×2 → 2×3 → 1×6 and never land
   on a lopsided 5+1 or 4+2. Breakpoints below are derived from the mark and
   gap sizes, not guessed. */
.links {
  margin-top: 46px;
  display: grid;
  grid-template-columns: repeat(6, auto);
  justify-content: center;
  justify-items: center;
  align-items: center;
  gap: 12px 16px;
}

/* The <a> is a 48px hit target; the mark inside stays 30px. */
.link {
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: var(--line);
  -webkit-tap-highlight-color: transparent;
  transition: color 0.32s ease, transform 0.42s var(--spring);
}

.mark {
  width: 30px;
  height: 30px;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Two things stay filled rather than stroked: the LinkedIn "i" dot, where a 1px
   ring would read as noise, and X's mark, which its brand guidelines require be
   solid. Both still take the same translucent currentColor as everything else. */
.mark .dot,
.mark .solid {
  fill: currentColor;
  stroke: none;
}

/* Letterforms sit inside a page outline, so they read better slightly lighter.
   Mitred joins keep 中's 口 a square rather than a rounded tile. */
.mark .letter {
  stroke-width: 1.25;
  stroke-linejoin: miter;
}

@media (hover: hover) and (pointer: fine) {
  .link:hover {
    color: var(--line-hover);
    transform: translateY(-2px);
  }
}

.link:active {
  transform: scale(0.92);
  transition-duration: 0.09s;
}

.link:focus-visible {
  outline: 1.5px solid var(--focus);
  outline-offset: 2px;
}

/* ---------- Footer ---------- */
.foot {
  margin-top: 46px;
}
.foot p {
  margin: 0;
  font-size: 12px;
  color: var(--label-3);
  letter-spacing: 0;
}

/* ---------- Entrance ---------- */
.reveal {
  opacity: 0;
  transform: translateY(10px);
  animation: rise 0.7s var(--spring) forwards;
  animation-delay: var(--delay, 0s);
}
@keyframes rise {
  to { opacity: 1; transform: none; }
}

/* ---------- Responsive ---------- */
/* Phones: tighten the row so all six still fit on one line. 6×48+5×16+48 of
   padding needs 416px; at 44/8/18 the same six fit down to 340px. */
@media (max-width: 420px) {
  .page  {
    padding-left:  calc(env(safe-area-inset-left, 0px) + 18px);
    padding-right: calc(env(safe-area-inset-right, 0px) + 18px);
  }
  .links { gap: 12px 8px; }
  .link  { width: 44px; height: 44px; }
  .mark  { width: 27px; height: 27px; }
}

/* 3 × 2 — below 340px six across no longer fit (3×44 + 2×8 + 36 = 184). */
@media (max-width: 339px) {
  .links { grid-template-columns: repeat(3, auto); }
}

/* 2 × 3 — below 184px (2×44 + 8 + 36 = 132). */
@media (max-width: 183px) {
  .links { grid-template-columns: repeat(2, auto); }
}

/* 1 × 6 — the last resort, for anything narrower still. */
@media (max-width: 131px) {
  .links { grid-template-columns: auto; }
  .page  { padding-left: 8px; padding-right: 8px; }
}

/* Below roughly 200px the name is what overflows, not the grid — the clamp
   floor of 27px is wider than the viewport. Let it shrink and wrap. */
@media (max-width: 200px) {
  .name   { font-size: 21px; letter-spacing: -0.015em; }
  .handle { font-size: 13px; }
  .foot p { font-size: 11px; }
}

@media (max-height: 560px) and (orientation: landscape) {
  .avatar { width: 58px; height: 58px; margin-bottom: 14px; }
  .avatar-mono { font-size: 19px; }
  .links { margin-top: 30px; }
  .foot  { margin-top: 30px; }
}

/* ---------- Accessibility & print ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .reveal { opacity: 1; transform: none; }
}

@media (prefers-contrast: more) {
  :root {
    --line:    rgba(255, 255, 255, 0.85);
    --label-2: rgba(235, 235, 245, 0.80);
    --label-3: rgba(235, 235, 245, 0.60);
  }
  .ambient { display: none; }
}
@media (prefers-contrast: more) and (prefers-color-scheme: light) {
  :root {
    --line:    rgba(0, 0, 0, 0.85);
    --label-2: rgba(60, 60, 67, 0.85);
    --label-3: rgba(60, 60, 67, 0.65);
  }
}

@media print {
  .ambient { display: none !important; }
  body { background: #fff; color: #000; }
  .link { color: #000; }
  .link::after { content: " (" attr(href) ")"; font-size: 10px; }
}
