@layer reset, tokens, base, layout, components, motion;

@font-face {
  font-family: "Erode";
  src: url("fonts/erode-variable.woff2") format("woff2");
  font-weight: 300 700;
  font-display: swap;
}

@font-face {
  font-family: "Erode Middot";
  src: url("fonts/source-sans-3-latin.woff2") format("woff2");
  font-weight: 200 900;
  unicode-range: U+00B7;
}

@font-face {
  font-family: "Source Code Pro";
  src: url("fonts/source-code-pro-latin.woff2") format("woff2");
  font-weight: 200 900;
  font-display: swap;
}

@font-face {
  font-family: "Erode Fallback";
  src: local("Georgia");
  size-adjust: 90.99%;
  ascent-override: 102.21%;
  descent-override: 24.18%;
  line-gap-override: 0%;
}

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }

  html {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
  }

  body, p, h1, h2 { margin: 0; }
}

@layer tokens {
  :root {
    --bg: #fdfcfa;
    --fg: #454b54;
    --muted: #666c74;
    --rule: rgb(0 0 0 / 0.09);
    --highlight: #fbf1b0;
    --pink: #d687a6;
    --zh: color-mix(in srgb, var(--muted) 41.25%, var(--bg));

    --wash: color-mix(in srgb, var(--highlight) 55%, var(--bg));
    --wash-text: var(--fg);

    --font-text: "Erode Middot", "Erode", "Erode Fallback", Georgia, serif;
    --font-zh: "Noto Serif SC", "Songti SC", serif;
    --font-mono: "Source Code Pro", ui-monospace, monospace;

    --text-body: 16.5px;
    --text-small: 14.5px;
    --leading-body: 27px;
    --tracking-body: -0.004em;
    --weight-body: 400;
    --weight-bold: 495;

    --column: 590px;
    --gutter: 24px;
    --space-top: 120px;
    --space-bottom: 32px;

    --avatar: 84px;
    --space-avatar-greeting: 6px;
    --space-intro: 24px;
    --space-block: 24px;
    --space-footer-min: 40px;

    --card-pad: 17px;
    --card-radius: 4px;
    --line-offset: 4px;
  }

  :root[data-theme="dark"] {
    --bg: #121314;
    --fg: #dee2e7;
    --muted: #c8cbd0;
    --rule: rgb(255 255 255 / 0.11);
    --pink: #e39bb8;

    --wash: color-mix(in srgb, var(--highlight) 12%, var(--bg));
    --wash-text: color-mix(in srgb, var(--highlight) 70%, var(--fg));
  }
}

@layer base {
  body {
    background: var(--bg);
    color: var(--fg);
    font-family: var(--font-text);
    font-size: var(--text-body);
    font-weight: var(--weight-body);
    line-height: var(--leading-body);
    letter-spacing: var(--tracking-body);
    transition: background-color 220ms ease, color 220ms ease;
  }

  b { font-weight: var(--weight-bold); }

  a {
    color: inherit;
    text-decoration-line: underline;
    text-decoration-color: color-mix(in srgb, var(--muted) 35%, transparent);
    text-decoration-thickness: 1px;
    text-underline-offset: var(--line-offset);
    transition: text-decoration-color 70ms ease;
  }

  a:is(:hover, [aria-expanded="true"]) {
    text-decoration-color: transparent;
  }

  .lt { position: relative; }

  .lt::after {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    inset-block-start: calc(0.9642em + var(--line-offset));
    inline-size: 0;
    block-size: 0;
    border-block-start: 1px solid currentColor;
    pointer-events: none;
    transition: inline-size 80ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  a:is(:hover, [aria-expanded="true"]) .lt::after { inline-size: 100%; }

  a:focus-visible {
    outline: 2px solid var(--muted);
    outline-offset: 2px;
    border-radius: 2px;
  }

  .visually-hidden {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@layer layout {
  .page {
    display: flex;
    flex-direction: column;
    max-inline-size: var(--column);
    min-block-size: 100svh;
    margin-inline: auto;
    padding: var(--space-top) var(--gutter) var(--space-bottom);
  }

  .page > p,
  .page > .avail {
    margin-block-end: var(--space-block);
  }

  .page > :is(p, .avail):has(+ .contact) {
    margin-block-end: var(--space-footer-min);
  }
}

@layer components {
  .intro {
    display: flex;
    align-items: center;
    gap: var(--space-avatar-greeting);
    margin-block-end: var(--space-intro);
  }

  .avatar {
    flex: none;
    display: grid;
    place-items: end center;
    inline-size: var(--avatar);
    block-size: var(--avatar);
  }

  .portrait {
    inline-size: 100%;
    block-size: 100%;
    overflow: visible;
    fill: #000;
  }

  .portrait__dark,
  .portrait__edge { display: none; }

  :root[data-theme="dark"] .portrait__ink { display: none; }
  :root[data-theme="dark"] .portrait__dark { display: inline; }
  :root[data-theme="dark"] .portrait__edge { display: inline; opacity: 0.75; }

  .greeting {
    position: relative;
    inset-inline-start: 2px;
    inset-block-start: 24px;
    color: var(--muted);
  }

  .greeting__zh {
    font-family: var(--font-zh);
    font-size: 0.9em;
    font-weight: 300;
    color: var(--zh);
  }

  .avail {
    padding: calc(var(--card-pad) * 0.75) var(--card-pad) calc(var(--card-pad) * 0.7);
    border: 1px solid color-mix(in srgb, var(--fg) 16%, transparent);
    border-radius: var(--card-radius);
    box-shadow: 0 1px 1.5px rgb(0 0 0 / 0.04), 0 3px 9px rgb(0 0 0 / 0.045);
  }

  :root[data-theme="dark"] .avail {
    box-shadow: 0 1px 2px rgb(0 0 0 / 0.35), 0 4px 12px rgb(0 0 0 / 0.4);
  }

  .avail__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 24px;
    align-items: baseline;
  }

  .avail__text { text-wrap: pretty; }

  .avail__statement {
    background-color: var(--wash);
    box-shadow: 0 0 0 2px var(--wash);
    color: var(--wash-text);
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
  }

  .avail__date {
    grid-column: 2;
    grid-row: 1;
    font-size: var(--text-small);
    font-weight: 300;
    color: var(--muted);
    text-align: end;
    white-space: nowrap;
    position: relative;
    cursor: default;
    outline: none;
  }

  .avail__date::after {
    content: attr(data-tip);
    position: absolute;
    inset-block-end: calc(100% + 7px);
    inset-inline-end: 0;
    padding: 3px 8px 4px;
    border: 1px solid var(--rule);
    border-radius: 5px;
    background: var(--bg);
    color: var(--muted);
    font-size: 12.5px;
    font-style: normal;
    line-height: 1.4;
    white-space: nowrap;
    box-shadow: 0 1px 2px rgb(0 0 0 / 0.05), 0 4px 12px rgb(0 0 0 / 0.06);
    opacity: 0;
    translate: 0 2px;
    pointer-events: none;
    transition: opacity 120ms ease 250ms, translate 120ms ease 250ms;
  }

  :root[data-theme="dark"] .avail__date::after {
    box-shadow: 0 1px 2px rgb(0 0 0 / 0.35), 0 4px 12px rgb(0 0 0 / 0.4);
  }

  .avail__date:is(:hover, :focus-visible)::after {
    opacity: 1;
    translate: 0 0;
  }

  .avail__links {
    margin-block-start: 4px;
    font-size: var(--text-small);
    line-height: 1.5;
  }

  .sep {
    margin-inline: 0.4em;
    opacity: 0.7;
  }

  .avail__links .mark--mail,
  .avail__links .chevron { opacity: 0.75; }
  .avail__links .mark--li { color: inherit; opacity: 0.75; }
  .avail__links .mark--tray { color: inherit; }

  .avail__links .year { opacity: 0.8; }

  .avail__beside { display: none; }

  @media (max-width: 520px) {
    .avail__grid { display: block; }
    .avail__date { display: none; }
    .avail__dated {
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      align-items: baseline;
      gap: 4px 16px;
    }
    .avail__dated > p { flex: 1 1 auto; min-inline-size: 0; }
    .avail__beside {
      display: inline;
      margin-inline-start: auto;
      font-size: var(--text-small);
      font-weight: 300;
      color: var(--muted);
      white-space: nowrap;
    }
  }

  .mark, .chevron {
    display: inline-block;
    inline-size: auto;
    color: var(--muted);
  }

  .mark--mail {
    block-size: 0.66em;
    aspect-ratio: 16 / 13;
    margin-inline-end: 0.34em;
    vertical-align: -0.02em;
    translate: 0 0.25px;
  }

  .mark--li {
    block-size: 0.9em;
    aspect-ratio: 1;
    margin-inline-end: 0.27em;
    vertical-align: -0.115em;
    translate: 0 0.75px;
  }

  .mark--tray {
    block-size: 0.72em;
    aspect-ratio: 16 / 15;
    margin-inline-end: 0.32em;
    vertical-align: -0.02em;
    translate: 0 0.25px;
  }

  .chevron {
    block-size: 0.6em;
    aspect-ratio: 1;
    margin-inline-start: 0.22em;
    vertical-align: -0.04em;
    transition: rotate 160ms cubic-bezier(0.3, 0.7, 0.4, 1);
  }

  .contact {
    margin-block-start: auto;
    padding-block-start: 8px;
    border-block-start: 1px solid var(--rule);
    font-size: var(--text-small);
  }

  .contact p {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 8px;
    line-height: 1.5;
    color: color-mix(in srgb, var(--muted) 72%, var(--bg));
  }

  :root[data-theme="dark"] .contact p {
    color: color-mix(in srgb, var(--muted) 83%, var(--bg));
  }

  .contact .sp { margin-inline-start: 2px; }

  .contact .made { margin-inline-start: auto; }

  .contact a { text-decoration-line: none; }

  .contact a[rel="license"] {
    font-size: 12px;
    letter-spacing: 0.05em;
    color: color-mix(in srgb, currentColor 70%, var(--fg));
  }

  .contact a[rel="license"]:hover {
    text-decoration-line: underline;
    text-decoration-color: currentColor;
  }

  .contact .chevron { color: inherit; opacity: 0.8; }

  .heart {
    display: inline-block;
    inline-size: auto;
    block-size: 0.78em;
    aspect-ratio: 1;
    margin-inline: 0.06em;
    vertical-align: -0.08em;
    color: var(--pink);
  }

  .theme-toggle {
    position: fixed;
    inset-block-start: 20px;
    inset-inline-end: 20px;
    display: grid;
    place-items: center;
    inline-size: 30px;
    block-size: 30px;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    transition: color 140ms ease, background-color 140ms ease;
  }

  .theme-toggle:hover {
    color: var(--fg);
    background: var(--rule);
  }

  .theme-toggle:focus-visible {
    outline: 2px solid var(--muted);
    outline-offset: 2px;
  }

  .contact-menu {
    position: fixed;
    inset: auto;
    margin: 0;
    min-inline-size: 13rem;
    padding: 4px;
    border: 1px solid color-mix(in srgb, var(--fg) 14%, transparent);
    border-radius: 8px;
    background: var(--bg);
    color: var(--fg);
    font: 15px/1.35 var(--font-text);
    box-shadow: 0 1px 2px rgb(0 0 0 / 0.06), 0 8px 24px rgb(0 0 0 / 0.1);
    opacity: 0;
    translate: 0 -4px;
    transition: opacity 120ms ease, translate 120ms ease, overlay 120ms allow-discrete, display 120ms allow-discrete;
  }

  .contact-menu:popover-open { opacity: 1; translate: 0 0; }

  @starting-style {
    .contact-menu:popover-open { opacity: 0; translate: 0 -4px; }
  }

  @supports (anchor-name: --a) {
    .contact-menu {
      position-anchor: --contact-link;
      inset-block-start: calc(anchor(bottom) + 6px);
      inset-inline-start: anchor(left);
      position-try-fallbacks: flip-block, flip-inline;
    }
  }

  .contact-menu__address {
    padding: 6px 10px 4px;
    color: var(--muted);
    font-size: 13px;
  }

  .contact-menu button {
    display: flex;
    align-items: center;
    gap: 10px;
    inline-size: 100%;
    padding: 7px 10px;
    border: 0;
    border-radius: 5px;
    background: none;
    color: inherit;
    font: inherit;
    text-align: start;
    cursor: pointer;
  }

  .contact-menu button:is(:hover, :focus-visible) {
    background: color-mix(in srgb, var(--fg) 8%, transparent);
    outline: none;
  }

  .contact-menu svg {
    flex: none;
    inline-size: 15px;
    block-size: 15px;
    color: var(--muted);
  }

  .contact-menu .done { color: var(--muted); }

  .contact-dialog {
    inline-size: min(28rem, 100vw - 32px);
    padding: 22px 24px 24px;
    border: 1px solid color-mix(in srgb, var(--fg) 12%, transparent);
    border-radius: var(--card-radius);
    background: var(--bg);
    color: var(--fg);
    font: 16px/1.45 var(--font-text);
    box-shadow: 0 20px 60px rgb(0 0 0 / 0.18);

    overflow: hidden auto;
    opacity: 0;
    translate: 0 8px;
    transition: opacity 160ms ease, translate 160ms ease, overlay 160ms allow-discrete, display 160ms allow-discrete;
  }

  .contact-dialog[open] { opacity: 1; translate: 0 0; }

  @starting-style {
    .contact-dialog[open] { opacity: 0; translate: 0 8px; }
  }

  .contact-dialog::backdrop {
    background: rgb(20 22 26 / 0.32);
    backdrop-filter: blur(2px);
  }

  .contact-dialog h2 {
    margin: 0 0 4px;
    padding-inline-end: 28px;
    font-size: 18px;
    font-weight: var(--weight-bold);
  }

  .contact-dialog .intro-line {
    margin: 0 0 16px;
    color: var(--muted);
    font-size: 14.5px;
  }

  .contact-dialog .close {
    position: absolute;
    inset: 12px 12px auto auto;
    inline-size: 28px;
    block-size: 28px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: none;
    color: var(--muted);
    cursor: pointer;
  }

  .contact-dialog .close:hover {
    background: color-mix(in srgb, var(--fg) 8%, transparent);
    color: var(--fg);
  }

  .contact-dialog form { display: grid; gap: 12px; }

  .contact-dialog label {
    display: grid;
    gap: 4px;
    color: var(--muted);
    font-size: 13.5px;
  }

  .contact-dialog .optional { opacity: 0.75; }

  .contact-dialog :is(input, textarea) {
    inline-size: 100%;
    padding: 8px 10px;
    border: 1px solid color-mix(in srgb, var(--fg) 20%, transparent);
    border-radius: 6px;
    background: color-mix(in srgb, var(--fg) 2%, var(--bg));
    color: var(--fg);
    font: 15.5px/1.4 var(--font-text);
  }

  .contact-dialog textarea {
    min-block-size: 8rem;
    max-block-size: 50vh;
    resize: vertical;
    field-sizing: content;
  }

  .contact-dialog :is(input, textarea):focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--fg) 55%, transparent);
  }

  .contact-dialog :is(input, textarea):user-invalid { border-color: #c2410c; }

  .contact-dialog .trap {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  .contact-dialog .actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-block-start: 4px;
  }

  .contact-dialog .actions button,
  .contact-dialog .done button {
    padding: 7px 14px;
    border: 1px solid transparent;
    border-radius: 6px;
    font: 15px/1.3 var(--font-text);
    cursor: pointer;
  }

  .contact-dialog .secondary { background: none; color: var(--muted); }

  .contact-dialog .secondary:hover {
    color: var(--fg);
    background: color-mix(in srgb, var(--fg) 8%, transparent);
  }

  .contact-dialog .primary {
    background: var(--fg);
    color: var(--bg);
    font-weight: var(--weight-bold);
  }

  .contact-dialog .primary:disabled { opacity: 0.6; cursor: progress; }

  .contact-dialog .turnstile { min-block-size: 65px; }

  .contact-dialog .turnstile:has(> div) {
    min-block-size: 0;
    overflow: hidden;
    line-height: 0;
    border: 1px solid color-mix(in srgb, var(--fg) 20%, transparent);
    border-radius: 6px;
  }
  .contact-dialog .turnstile > div { margin: -1px; }

  :root[data-theme="dark"] .contact-dialog :is(input, textarea, .turnstile) { border-color: color-mix(in srgb, var(--fg) 32%, transparent); }

  :root[data-theme="dark"] .contact-dialog :is(input, textarea):focus-visible { border-color: color-mix(in srgb, var(--fg) 62%, transparent); }

  .contact-dialog .status { font-size: 14.5px; }
  .contact-dialog .status.error { color: #c2410c; }

  .contact-dialog .done { display: grid; gap: 16px; padding-block: 8px 0; }
  .contact-dialog .done button { justify-self: end; }

  .contact-dialog [hidden] { display: none !important; }

  .contact-toast {
    position: fixed;
    inset: auto auto 24px 50%;
    translate: -50% 0;
    margin: 0;
    padding: 8px 14px;
    border: 0;
    border-radius: 999px;
    background: var(--fg);
    color: var(--bg);
    font: 14px/1.3 var(--font-text);
    opacity: 0;
    transition: opacity 160ms ease, overlay 160ms allow-discrete, display 160ms allow-discrete;
  }

  .contact-toast:popover-open { opacity: 1; }

  @starting-style {
    .contact-toast:popover-open { opacity: 0; }
  }
}

@layer motion {
  .page > :not(.intro) {
    animation: rise 800ms cubic-bezier(0.22, 1, 0.36, 1) both;
    animation-delay: calc(var(--type-done, 1200ms) + var(--i, 0) * 90ms);
  }

  @keyframes rise {
    from { opacity: 0; translate: 0 14px; }
  }

  .greeting__en.is-typing::after {
    content: "|";
    margin-inline-start: 1px;
    font-weight: 300;
  }

  .greeting__en.is-typing.is-done::after {
    animation: caret 1s linear 2 forwards;
  }

  @keyframes caret {
    0%, 49% { opacity: 1; }
    50%, 100% { opacity: 0; }
  }

  .greeting__zh { transition: opacity 500ms ease; }
  .greeting.is-typing .greeting__zh { opacity: 0; }

  .pt-ghost, .pt-eye, .pt-eyes, .pt-ghost-eyes {
    transform-box: fill-box;
    transform-origin: center;
  }

  .pt-ghost { animation: float 4.6s ease-in-out infinite; }

  @keyframes float {
    25% { translate: 0.6px -2.2px; rotate: -4deg; }
    75% { translate: -0.6px 0.8px; rotate: 4deg; }
  }

  .pt-eye { animation: blink 5.4s infinite; }
  .pt-eye--r { animation-delay: 60ms; }

  @keyframes blink {
    0%, 92%, 100% { scale: 1 1; }
    95% { scale: 1 0.08; }
  }

  .pt-eyes, .pt-ghost-eyes { transition: translate 120ms ease-out; }

  .contact-menu:popover-open button { animation: fade 260ms both; }

  @keyframes fade {
    from { opacity: 0; }
  }

  .heart { animation: beat 2.4s ease-in-out infinite; }

  @keyframes beat {
    0%, 100% { scale: 1; }
    18% { scale: 1.1; }
    36% { scale: 1; }
    54% { scale: 1.06; }
  }

  @media (prefers-reduced-motion: reduce) {
    .page > :not(.intro),
    .greeting__en.is-typing.is-done::after,
    .pt-ghost, .pt-eye, .heart,
    .contact-menu:popover-open button { animation: none; }
    .greeting__en.is-typing::after { content: none; }
    .greeting.is-typing .greeting__zh { opacity: 1; }
    .greeting__zh, .pt-eyes, .pt-ghost-eyes, .chevron, .lt::after, .avail__date::after, body { transition: none; }
  }
}
