@font-face { font-family: 'Noto Serif SC'; src: url('assets/unearth/fonts/noto-serif-sc.woff2?v=3') format('woff2'); font-weight: 200 900; font-display: swap; }
@font-face { font-family: 'LXGW WenKai TC'; src: url('assets/unearth/fonts/lxgw-wenkai-tc.woff2?v=2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Cormorant'; src: url('assets/fonts/cormorant.woff2') format('woff2'); font-weight: 300 700; font-style: normal; font-display: swap; }
@font-face { font-family: 'Cormorant'; src: url('assets/fonts/cormorant-italic.woff2') format('woff2'); font-weight: 300 700; font-style: italic; font-display: swap; }

:root {
  --bg: #07080a;
  --ivory: #f3ead8;
  --ivory-2: rgba(243, 234, 216, .9);
  --ivory-3: rgba(243, 234, 216, .66);
  --hair: rgba(243, 234, 216, .3);
  --gold: #e6c58a;
  --zh: 'Noto Serif SC', 'Songti SC', serif;
  --en: 'Cormorant', 'Cormorant Garamond', Georgia, serif;
  --ease: cubic-bezier(.2, .7, .1, 1);
  --top: 68px;
  color-scheme: dark;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: var(--bg); }
body { color: var(--ivory); font-family: var(--en); font-size: 18px; -webkit-font-smoothing: antialiased; overflow: hidden; overscroll-behavior: none; }
button, input { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; }
button:focus-visible { outline: 1px solid var(--gold); outline-offset: 5px; border-radius: 8px; }
[hidden] { display: none !important; }

.app { position: fixed; inset: 0; overflow: hidden; background: var(--bg); }

/* ---------- Header ---------- */
.top { position: absolute; z-index: 10; inset: 0 0 auto; height: calc(var(--top) + env(safe-area-inset-top)); padding: env(safe-area-inset-top) max(18px, env(safe-area-inset-right)) 0 max(18px, env(safe-area-inset-left));
  display: flex; align-items: center; justify-content: center; }
/* The title is part of the landing page and scrolls away with it; the header bar only holds the back arrow. */
.mark { flex: none; margin: 0; display: flex; align-items: baseline; gap: .55rem; font-size: 2.1rem; font-weight: 500; white-space: nowrap; letter-spacing: .01em; color: var(--ivory); transition: opacity .4s; }
.mark span { position: relative; top: -.06em; font-family: var(--zh); font-size: .69em; letter-spacing: 0; color: var(--gold); }
.back { position: absolute; left: max(8px, env(safe-area-inset-left)); width: 44px; height: 44px; display: grid; place-items: center; opacity: 0; pointer-events: none; transition: opacity .4s; }
.back svg { width: 22px; height: 22px; fill: none; stroke: var(--ivory-2); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.app:not([data-phase="field"]) .back { opacity: 1; pointer-events: auto; transition-delay: .2s; }
.app:not([data-phase="field"]) .mark { opacity: 0; pointer-events: none; }
.clock { margin: 0; font-size: clamp(1.6rem, 3.6vh, 2.1rem); font-weight: 300; line-height: 1; letter-spacing: .02em; font-variant-numeric: lining-nums tabular-nums; color: var(--ivory); opacity: 0; transition: opacity .5s, color .5s; }
.clock::after { content: 's'; font-size: .7em; color: var(--ivory-3); margin-left: 2px; }
.app[data-phase="digging"] .clock { opacity: 1; }
.clock.is-hit { animation: hit .7s ease; }
@keyframes hit { 0% { color: var(--ivory); } 20% { color: #e08a72; scale: 1.15; } 100% { color: var(--ivory); scale: 1; } }
.app[data-phase="solved"] .era, .app[data-phase="solved"] .date, .app[data-phase="solved"] .clock { visibility: hidden; }

/* ---------- Field ---------- */
.field-view { position: absolute; inset: 0; padding: calc(env(safe-area-inset-top) + 14px) 24px calc(28px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; align-items: center; justify-content: safe center; gap: clamp(20px, 4vh, 44px); overflow-y: auto;
  --g: clamp(1.9rem, min(7vh, 3.6vw), 4rem); transition: opacity .3s var(--ease), transform .4s var(--ease); }
.app:not([data-phase="field"]) .field-view { opacity: 0; transform: scale(.97); pointer-events: none; transition-duration: .35s; }
.intro { margin: 0; font-variant-numeric: lining-nums; font-style: italic; font-weight: 400; font-size: clamp(1.1rem, 2.4vw, 1.45rem); color: var(--ivory); text-align: center; animation: rise 1.2s var(--ease) both .2s; }
.field { display: grid; gap: clamp(30px, 5vh, 56px); }
.field-group { display: grid; gap: clamp(4px, 1vh, 10px); }
.field-level { margin: 0; padding-left: 8px; font-size: 1rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: #f0d6a2; animation: rise 1.1s var(--ease) backwards .1s; }
.field-grid { display: grid; grid-template-columns: repeat(15, 1fr); gap: clamp(2px, 0.8vh, 14px) clamp(6px, 1.3vw, 26px); }
.tile { display: grid; justify-items: center; gap: 2px; padding: 6px 8px; border-radius: 12px; animation: rise 1.1s var(--ease) backwards; animation-delay: calc(var(--i) * 18ms + 120ms); }
.tile.is-chosen { visibility: hidden; }
.field.has-entered .tile, .field.has-entered .field-level { animation: none; }
.tile-char { font-family: var(--zh); font-weight: 300; font-size: var(--g); line-height: 1; color: var(--ivory); transition: scale .5s var(--ease), color .5s; }
.tile-time { min-height: 1em; font-size: 1rem; font-weight: 600; letter-spacing: .02em; font-variant-numeric: lining-nums tabular-nums; color: #f0d6a2; }
.tile.is-solved .tile-char { color: var(--gold); }
.credit { margin: 0; font-size: .9rem; font-weight: 500; letter-spacing: .02em; color: rgba(243, 234, 216, .78); text-align: center; animation: rise 1.2s var(--ease) both .4s; }
.result .credit { margin-top: 28px; animation: none; }
.feedback-link { font: inherit; color: var(--ivory); text-decoration: underline; text-decoration-color: rgba(243, 234, 216, .3); text-underline-offset: 3px; }
.credit a { color: var(--ivory); text-decoration: underline; text-decoration-color: rgba(243, 234, 216, .3); text-underline-offset: 3px; }
@media (hover: hover) { .credit a:hover { color: var(--ivory); } }
/* Wide, tall screens don't scroll the field, so the credit sits on the bottom edge; elsewhere it follows the field. */
@media (min-width: 641px) and (min-height: 980px) { .field-view .credit { position: absolute; left: 0; right: 0; bottom: calc(16px + env(safe-area-inset-bottom)); } }
/* Desktop: the subtitle a little larger, with half as much space again before the grid (the gap is the field-view's). */
@media (min-width: 641px) { .field-view { padding-top: calc(env(safe-area-inset-top) + 54px); } .field-view .mark { font-size: 2.8rem; margin-bottom: 28px; } }
@media (min-width: 641px) { .intro { font-size: clamp(1.25rem, 2.6vw, 1.65rem); margin: 10px 0 calc(clamp(20px, 4vh, 44px) / 2 + 60px); } }
.intro b { font-weight: 500; color: var(--gold); font-style: normal; }
@media (hover: hover) { .tile:hover .tile-char { scale: 1.07; } }
/* ---------- Feedback ---------- */
.feedback { width: min(92vw, 460px); padding: 26px 24px 22px; border: 1px solid rgba(243, 234, 216, .3); border-radius: 16px; background: #101216; color: var(--ivory); }
.feedback::backdrop { background: rgba(4, 5, 7, .72); }
.feedback form { display: grid; gap: 12px; }
.feedback h2 { margin: 0 0 4px; font-size: 1.5rem; font-weight: 500; }
.feedback textarea, .feedback input { width: 100%; padding: 10px 12px; font: inherit; font-size: 1.05rem; color: var(--ivory); background: #07080a; border: 1px solid rgba(243, 234, 216, .35); border-radius: 10px; }
.feedback textarea { resize: vertical; min-height: 7em; }
.feedback textarea::placeholder, .feedback input::placeholder { color: rgba(243, 234, 216, .6); }
.feedback textarea:focus, .feedback input:focus { outline: 1px solid var(--gold); border-color: var(--gold); }
.feedback .trap { position: absolute; left: -9999px; width: 1px; height: 1px; }
.feedback-status { min-height: 1.3em; margin: 0; font-size: 1rem; color: #f0d6a2; }
.feedback-actions { display: flex; justify-content: flex-end; gap: 10px; }
.feedback .primary:disabled { opacity: .6; cursor: default; }

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

/* ---------- Play ---------- */
.play { position: absolute; inset: 0; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; grid-template-columns: minmax(0, 1fr);
  padding: calc(var(--top) + env(safe-area-inset-top)) 20px calc(18px + env(safe-area-inset-bottom)); }
.app[data-phase="leaving"] .play { opacity: 0; transition: opacity .2s; }
.stage { position: relative; min-height: 0; margin: 0 -20px; }
.canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* While the first form loads, the stage stays empty; everything fades in together once it's ready. */
.dig-meta, .guess { transition: opacity .6s var(--ease); }
.app[data-phase="lifting"] .dig-meta, .app[data-phase="lifting"] .guess { opacity: 0; }

/* After the dig: every form in a row, oldest on the left, each dated beneath. */
.canvas { transition: opacity .6s var(--ease); }
.canvas.is-gone { opacity: 0; }
.lineage { position: absolute; inset: 0; margin: 0 auto; padding: 0 clamp(14px, 3vw, 56px); max-width: 1320px; list-style: none;
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); align-content: center; align-items: start; gap: clamp(6px, 1.4vw, 26px); }
.lineage li { display: grid; justify-items: center; align-content: start; gap: 4px; text-align: center; animation: rise 1s var(--ease) backwards; animation-delay: calc(var(--i) * 110ms + 250ms); }
.lineage li.is-held { animation: none; }

/* The reveal is one scrolling page: the meaning and its note first, then the history, then the actions and footer.
   The stage and result wrappers step aside (display: contents) so their pieces can be ordered within the page. */
.app[data-phase="solved"] .play { display: flex; flex-direction: column; align-items: center; overflow-y: auto; overscroll-behavior: contain;
  padding: calc(var(--top) + env(safe-area-inset-top) + 8px) 20px calc(28px + env(safe-area-inset-bottom)); }
.app[data-phase="solved"] .dig-meta, .app[data-phase="solved"] .canvas { display: none; }
.app[data-phase="solved"] .stage, .app[data-phase="solved"] .result { display: contents; }
.app[data-phase="solved"] .top { background: linear-gradient(var(--bg) 60%, rgba(7, 8, 10, 0)); }
.app[data-phase="solved"] .result > * { animation: rise .9s var(--ease) both; }
.app[data-phase="solved"] .result-word { order: 1; text-align: center; }
.app[data-phase="solved"] .result-time { order: 2; margin-top: 10px; }
.app[data-phase="solved"] .result-note { order: 3; text-align: center; }
.app[data-phase="solved"] .result-story { order: 4; text-align: center; }
.app[data-phase="solved"] .lineage { order: 5; position: static; flex: none; width: 100%; margin: 44px auto 0; }
.app[data-phase="solved"] .result-actions { order: 6; margin-top: 44px; }
.app[data-phase="solved"] .result .credit { order: 7; margin-top: 32px; }
@media (min-width: 641px) { .app[data-phase="solved"] .result-actions { margin-top: 72px; } .app[data-phase="solved"] .result .credit { margin-top: 56px; } }
.lineage-art { display: block; width: 100%; max-width: 220px; aspect-ratio: 1; margin-bottom: 8px; }
.lineage-era { margin: 0; font-size: .84rem; font-weight: 600; letter-spacing: .14em; line-height: 1.35; text-transform: uppercase; color: #f0d6a2; }
.lineage-date { margin: 0; font-size: 1.15rem; font-weight: 500; line-height: 1.25; font-variant-numeric: lining-nums; color: var(--ivory); }

/* Above the character: the script name over its date, centered, with room for both lines always kept, so nothing
   moves as the forms change. The timer sits apart, in the top-right corner level with the back arrow. */
.dig-meta { display: grid; justify-items: center; row-gap: 2px; text-align: center; }
.clock { position: absolute; top: calc(env(safe-area-inset-top) + var(--top) / 2); right: max(20px, env(safe-area-inset-right)); transform: translateY(-50%); text-align: right; }
.era { margin: 0; min-height: 1.2em; font-size: .92rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: #f0d6a2; }
.date { margin: 0; min-height: 1.2em; font-size: 1.4rem; font-weight: 500; font-variant-numeric: lining-nums; color: var(--ivory); }
.era, .date { transition: opacity .18s ease, transform .18s ease; }
.is-out { opacity: 0; transform: translateY(3px); }

.guess { display: grid; justify-items: center; gap: 12px; margin: 26px auto 0; width: min(100%, 380px); transition: opacity .5s; }
.guess-input { width: 100%; height: 52px; padding: 0 24px; border-radius: 999px; border: 1px solid rgba(243, 234, 216, .1); background: rgba(243, 234, 216, .03);
  font-size: 1.35rem; font-style: italic; text-align: center; letter-spacing: .02em; outline: none; transition: border-color .3s, background .3s; }
.guess-input::placeholder { color: var(--ivory-3); letter-spacing: .08em; }
.guess-input:focus { border-color: rgba(230, 197, 138, .6); background: rgba(243, 234, 216, .06); }
.guess-input.is-wrong { animation: nudge .45s ease; }
@keyframes nudge { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-6px); } 60% { transform: translateX(5px); } }
.misses { order: 2; display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; min-height: 30px; }
.miss { display: inline-flex; gap: 8px; align-items: baseline; padding: 4px 14px; border-radius: 999px; border: 1px solid rgba(230, 197, 138, .28); font-size: 1.1rem; font-style: italic; color: var(--ivory-2);
  animation: miss .6s var(--ease) both; }
.miss s { text-decoration-color: rgba(243, 234, 216, .4); }
.miss b { font-style: normal; font-weight: 500; font-size: .8rem; color: var(--gold); }
/* Every wrong guess is equally faded; they are a record, not news. */
.miss { opacity: .5; }
@keyframes miss { from { opacity: 0; transform: translateY(-14px) scale(.9); } }
.app[data-phase="solved"] .guess { display: none; }
/* Floats above the right end of the input, at the clock's height, so appearing never moves anything. */
.guess { position: relative; }
/* The submit arrow sits inside the right end of the box and fades in once something is typed. */
.guess-input { padding: 0 58px; }
.guess-submit { position: absolute; top: 6px; right: 6px; width: 40px; height: 40px; display: grid; place-items: center; border-radius: 50%; background: var(--gold);
  opacity: 0; transform: scale(.85); pointer-events: none; transition: opacity .25s ease, transform .25s var(--ease); }
.guess-submit svg { width: 20px; height: 20px; fill: none; stroke: #0e0b06; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.guess:has(.guess-input:not(:placeholder-shown)) .guess-submit { opacity: 1; transform: none; pointer-events: auto; }
/* Floats above the right end of the guess box, so its arrival moves nothing. */
.give-up { position: absolute; right: 8px; bottom: calc(100% + 6px); padding: 12px 16px; font-size: 1.05rem; font-weight: 600; letter-spacing: .02em; color: var(--ivory);
  text-decoration: underline; text-decoration-color: rgba(243, 234, 216, .6); text-underline-offset: 4px; animation: rise 1.2s var(--ease) both; }
@media (hover: hover) { .give-up:hover { color: var(--gold); text-decoration-color: var(--gold); } }
.result.is-given-up .result-time { display: none; }

.result { display: grid; justify-items: center; gap: 4px; text-align: center; margin-top: 4px; animation: rise .9s var(--ease) both; }
.result-time { margin: 18px 0 0; font-size: clamp(1.9rem, 4.6vh, 2.5rem); font-weight: 300; line-height: 1; color: var(--gold); font-variant-numeric: lining-nums tabular-nums; }
.result-time small { font-size: .45em; margin-left: 3px; color: var(--ivory-3); }
/* Upright and quieter than the italic meaning above it. */
.result-took { font-size: .5em; font-weight: 500; letter-spacing: .04em; color: var(--ivory-2); margin-right: 4px; vertical-align: .15em; }
.result-word { margin: 0; font-style: italic; font-size: clamp(2.8rem, 7.5vh, 4.2rem); line-height: 1.05; color: #fff; font-variant-numeric: lining-nums; }
/* Solved (not given up): a small circled check after the meaning. */
.result:not(.is-given-up) .result-word::after { content: ''; display: inline-block; width: .52em; height: .52em; margin-left: .3em; vertical-align: .02em;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e6c58a' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10.2'/%3E%3Cpath d='M7.4 12.4l3.1 3.1 6.1-6.6'/%3E%3C/svg%3E") center / contain no-repeat; }
.result-word.is-list { font-size: clamp(2rem, 5.5vh, 3.2rem); text-wrap: balance; }
.result-note { margin: 6px 0 0; font-size: 1.25rem; font-weight: 500; font-style: italic; color: var(--ivory); font-variant-numeric: lining-nums; }
.result-story { max-width: 44ch; margin: 14px auto 0; font-size: 1.25rem; font-weight: 500; line-height: 1.5; color: var(--ivory); text-wrap: pretty; }
.lineage-type { display: grid; place-items: center; font-family: var(--zh); font-weight: 300; line-height: 1; color: var(--ivory); user-select: text; -webkit-user-select: text; cursor: text; }
.lineage-type::selection { background: rgba(230, 197, 138, .35); color: #fff; }
.result-actions { display: flex; gap: 10px; margin-top: 40px; }
.ghost, .primary { min-height: 48px; padding: 0 24px; border-radius: 999px; font-size: 1.2rem; font-weight: 600; letter-spacing: .02em; display: inline-flex; align-items: center; gap: 8px; }
.ghost { border: 1px solid rgba(243, 234, 216, .55); color: var(--ivory); }
.primary { background: var(--gold); color: #0e0b06; }
.primary:focus:not(:focus-visible), .ghost:focus:not(:focus-visible) { outline: none; }
@media (hover: hover) { .ghost:hover { border-color: var(--ivory-3); } .primary:hover { filter: brightness(1.07); } }

@media (min-width: 641px) and (max-width: 1000px) { .field-grid { grid-template-columns: repeat(10, 1fr); } .field-view { --g: min(6.4vw, 5.6vh); } }
/* Wide screens: art, era and controls form one composition in the middle of the screen. */
@media (min-width: 641px) {
  /* The stage is never taller than the character can use (it is limited by width too), so the art, its labels and
     the guess box stay together as one block in the middle of the screen. */
  .play { grid-template-rows: auto minmax(0, min(66vh, 680px, 88vw)) auto; align-content: center; }
  /* While guessing, everything sits in a 900px column, so the timer and the back arrow stay near the character. */
  .app:not([data-phase="solved"]) .play { max-width: 900px; margin: 0 auto; }
  .app:not([data-phase="solved"]) .back { left: max(8px, calc(50% - 450px + 8px)); }
}
@media (max-width: 640px) {
  .mark { font-size: 1.6rem; }
  /* Phones: the history is a vertical list, the picture first and today's form last. */
  .lineage { display: flex; flex-direction: column; justify-content: flex-start; gap: 28px; max-width: none; padding: 0 12px; }
  .lineage li { width: min(100%, 300px); align-self: center; grid-template-columns: 112px 1fr; grid-template-rows: auto auto; column-gap: 20px; row-gap: 4px; align-items: center; justify-items: start; text-align: left; }
  .lineage-art { grid-row: 1 / span 2; width: 112px; margin: 0; }
  .lineage .lineage-era { align-self: end; font-size: .84rem; letter-spacing: .14em; }
  .lineage .lineage-date { align-self: start; font-size: 1.2rem; }
  .lineage li:has(.lineage-era:only-of-type) .lineage-era { grid-row: 1 / span 2; align-self: center; }
  .result .result-word { font-size: 2.3rem; }
  .result .result-word.is-list { font-size: 1.75rem; }
  /* Keyboard open: the app covers only the visible area above it; the guess box sits at its bottom and the
     character, scaled down rather than redrawn, rests right on top of the box. */
  .app.is-typing { top: var(--vv-top); bottom: auto; height: var(--vv-height); }
  .app.is-typing .play { grid-template-rows: auto minmax(0, 1fr) auto; align-content: stretch; padding-top: calc(env(safe-area-inset-top) + 6px); padding-bottom: 8px; }
  .app.is-typing .stage { height: auto; }
  .app.is-typing .canvas { object-fit: contain; object-position: center bottom; }
  .app.is-typing .guess { margin-top: 4px; }
  .app.is-typing .misses { min-height: 0; }
  .dig-meta { margin-top: 14px; }
  .credit { font-size: .8rem; letter-spacing: 0; }

  :root { --top: 60px; }
  /* Phones: four large characters across; the field scrolls under a solid header. */
  .field { width: 100%; }
  .field-grid { grid-template-columns: repeat(4, 1fr); column-gap: 8px; row-gap: 6px; }
  .intro { margin-bottom: 36px; font-size: 1.25rem; }
  .field-view { --g: 15vw; gap: 18px; justify-content: flex-start; padding-top: calc(env(safe-area-inset-top) + 15px); -webkit-overflow-scrolling: touch; }
  .field-view .mark { margin-bottom: 43px; }
  .tile { padding: 8px 6px 4px; }
  .tile-time { font-size: .95rem; }
  /* Phones: a square stage, centered with its controls as one block, rather than a tall void. */
  .play { grid-template-rows: auto auto auto; align-content: start; }
  .stage { height: min(100vw, 52vh); }
  /* Some illustrations reach the bottom of the stage, so the box keeps a small gap below it. */
  .guess { margin-top: 10px; }
  .result-actions { flex-direction: row; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .2s !important; }
}
