/* ─────────────────────────────────────────────────────────────────────────
   site.css — what's behind the door: bio, work, contact, garden.
   ───────────────────────────────────────────────────────────────────────── */

/* The portrait and the poem share one measure; nothing may break this.
   The vh term matters as much as the vw one: the poem types in *below* the
   photograph, so if the pair overflows the viewport the writing happens off
   screen where nobody sees it. Height is what constrains this layout. */
:root {
  --frame: clamp(225px, min(31vw, 34vh), 420px);
}

/* ── masthead ───────────────────────────────────────────────────────────── */

#masthead {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 26px 34px;
  pointer-events: none;
}

#wordmark,
#nav a {
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity .7s var(--ease), transform .7s var(--ease),
              color .25s var(--ease);
}

body.nav-ready #wordmark,
body.nav-ready #nav a { opacity: 1; transform: translateY(0); }
body.nav-ready #masthead { pointer-events: auto; }

#wordmark {
  font-size: 11.5px;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ink);
  transition-delay: 0s;
}
#wordmark:hover { color: var(--pink-deep); }

#nav {
  display: flex;
  gap: 26px;
}
#nav a {
  position: relative;
  font-size: 12px;
  letter-spacing: .13em;
  color: var(--ink-soft);
  padding-bottom: 3px;
}
#nav a:nth-child(1) { transition-delay: .12s; }
#nav a:nth-child(2) { transition-delay: .24s; }
#nav a:nth-child(3) { transition-delay: .36s; }

#nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--pink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .35s var(--ease);
}
#nav a:hover { color: var(--ink); }
#nav a:hover::after,
#nav a.is-current::after { transform: scaleX(1); }
#nav a.is-current { color: var(--ink); }

/* ── panels ─────────────────────────────────────────────────────────────── */

#site {
  position: relative;
  z-index: 10;
  opacity: 0;
  transition: opacity .9s var(--ease);
  /* Invisible is not the same as absent: this layer sits above the ritual
     (z-index 10 vs 5) and spans the viewport, so while opacity is 0 it would
     still swallow every click meant for the drawing canvas, the tools and
     send — leaving the whole interface dead to a real pointer. */
  pointer-events: none;
}
body[data-stage="site"] #site { opacity: 1; pointer-events: auto; }

.panel {
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 96px 34px 72px;
}
.panel[hidden] { display: none; }
/* Swapping panels changes the document height; scroll anchoring reacts to
   that by scrolling to hold the old content still, which lands the new panel
   partway down. Nothing here needs anchoring. */
.panel { overflow-anchor: none; }

.panel.is-entering { animation: panel-in .7s var(--ease) both; }
@keyframes panel-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* A full-bleed panel must not slide: shifting it down 8px opens a strip of
   bare paper along the top edge for the length of the entrance. It fades
   instead. */
.panel.panel-bleed.is-entering { animation: panel-fade .7s var(--ease) both; }
@keyframes panel-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.panel-title {
  margin: 0 0 8px;
  font-family: var(--serif);
  font-size: 26px;
  font-weight: 400;
  letter-spacing: .01em;
}
.panel-lede {
  margin: 0 0 40px;
  font-size: 13.5px;
  color: var(--ink-soft);
}
.wrap { width: min(1040px, 100%); }
.wrap-narrow { width: min(520px, 100%); }

.note {
  margin-top: 44px;
  font-size: 11.5px;
  letter-spacing: .04em;
  color: var(--ink-faint);
}
.note code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px;
}

/* ── bio: the portrait and the poem, locked to one measure ──────────────── */

/* ── flowers in the margins ─────────────────────────────────────────────── */

#bio { position: relative; }

.margin-flowers {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;                  /* behind the portrait and the poem */
}

.margin-flower {
  position: absolute;
  transform: translate(-50%, -50%);
  opacity: 0;
  transition: opacity 1.1s var(--ease);
}
.margin-flower.is-in { opacity: var(--op, .7); }

.margin-flower img {
  display: block;
  width: 100%;
  height: auto;
  transform: rotate(var(--rot, 0deg));
  animation: margin-sway var(--sway, 9s) ease-in-out infinite;
}

@keyframes margin-sway {
  0%, 100% { transform: rotate(var(--rot, 0deg)); }
  50%      { transform: rotate(calc(var(--rot, 0deg) + 1.6deg)); }
}

@media (prefers-reduced-motion: reduce) {
  .margin-flower img { animation: none; }
}

#bio .frame {
  position: relative;
  z-index: 1;                  /* the portrait and poem stay on top */
  width: var(--frame);
  display: flex;
  flex-direction: column;
  align-items: stretch;   /* children inherit the exact same edges */
}

#portrait {
  margin: 0;
  width: 100%;
  opacity: 0;
  transform: scale(.98);
}
#portrait img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: 50% 45%;
}

/* The resting state is declared as well as animated: if animations are
   suppressed (an extension, a hardened browser), the photograph must still
   end up on screen rather than sitting at opacity 0 forever. */
body.bio-photo #portrait {
  opacity: 1;
  transform: none;
  animation: photo-in 1.5s var(--ease) both;
}
@keyframes photo-in {
  from { opacity: 0; transform: scale(.98); }
  to   { opacity: 1; transform: scale(1); }
}

#poem {
  width: 100%;
  margin-top: clamp(16px, 2.6vh, 28px);
}

/* the bio is the one panel that must fit in a single screen */
#bio { padding-top: 76px; padding-bottom: 46px; }

.poem-live {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(13px, min(1.02vw, 1.75vh), 16.5px);
  line-height: 1.72;
  letter-spacing: .005em;
  color: var(--ink);
  white-space: pre-wrap;
  word-break: break-word;
  min-height: 1.95em;
}

.caret {
  display: inline-block;
  width: 1.5px;
  height: 1.02em;
  margin-left: 1px;
  background: var(--pink);
  vertical-align: -.16em;
  animation: blink 1.05s step-end infinite;
}
.caret.is-typing { animation: none; opacity: 1; }
.caret.is-done   { animation: none; opacity: 0; transition: opacity .8s var(--ease); }

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

/* ── work ───────────────────────────────────────────────────────────────── */

.grid {
  list-style: none;
  margin: 34px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(228px, 1fr));
  gap: 34px 26px;
}

.grid li a {
  display: block;
  cursor: pointer;
}
.grid .thumb {
  aspect-ratio: 4 / 5;
  background: var(--paper-warm);
  border: 1px solid var(--rule);
  transition: transform .45s var(--ease), border-color .45s var(--ease);
}
.grid li a:hover .thumb {
  transform: translateY(-4px);
  border-color: var(--pink);
}
.grid .meta {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 11px;
  font-size: 12px;
  letter-spacing: .04em;
}
.grid .meta .yr { color: var(--ink-faint); }

/* ── contact ────────────────────────────────────────────────────────────── */

.contact-list {
  margin: 34px 0 0;
  display: grid;
  grid-template-columns: 88px 1fr;
  gap: 15px 18px;
  font-size: 13.5px;
}
.contact-list dt {
  font-size: 11px;
  letter-spacing: .16em;
  color: var(--ink-faint);
  padding-top: 3px;
}
.contact-list dd { margin: 0; }
.contact-list dd a {
  border-bottom: 1px solid var(--rule);
  padding-bottom: 2px;
  transition: border-color .25s var(--ease), color .25s var(--ease);
}
.contact-list dd a:hover { border-color: var(--pink); color: var(--pink-deep); }
.contact-list .todo { color: var(--ink-faint); font-style: italic; }

/* ── garden ─────────────────────────────────────────────────────────────── */

/* The garden is the field. Its ground is a still of the very field the
   flowers were drawn over — captured once the bloom finishes — with every
   flower standing where it was planted. */

/* Two classes deep on purpose: the narrow-screen `.panel` padding rule sits
   further down the file, and at equal specificity it would win on order.

   dvh, not svh: svh is the *small* viewport height, so once a phone's address
   bar slides away the real viewport grows past it and the field stops short of
   the bottom. A full-bleed ground has to track the window, not its smallest
   possible state. */
.panel.panel-bleed {
  padding: 0;
  display: block;
  position: relative;
  overflow: hidden;
  min-height: 100vh;
  min-height: 100dvh;
}

/* Pinned to the panel rather than stretched by it — it cannot end up shorter
   than the window whatever the layout does around it. */
.garden-field {
  position: absolute;
  inset: 0;
  background-color: var(--paper);
  background-image: var(--garden-bg, none);
  background-size: cover;
  background-position: center bottom;
}
/* until a still exists, stand in with the field's own colours */
.garden-field.no-still {
  background-image:
    linear-gradient(180deg,
      var(--sky-low) 0%,
      var(--sky-low) 34%,
      var(--treeline) 36%,
      var(--brassica-d) 39%,
      var(--brassica) 52%,
      var(--soil) 100%);
}

.planted-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* A wash of paper across the top, so the heading and the link hold up
   whatever the field happens to be doing behind them. It fades out well above
   the horizon, so nothing planted is touched by it. */
.panel-bleed::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 46%;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(250, 247, 243, .94) 0%,
    rgba(250, 247, 243, .80) 34%,
    rgba(250, 247, 243, .42) 68%,
    rgba(250, 247, 243, 0) 100%);
}

.garden-copy {
  position: relative;
  z-index: 2;
  max-width: 460px;
  margin: 0;
  padding: 104px 34px 48px;
  pointer-events: none;          /* the field shows through the empty space */
}
.garden-copy > * { pointer-events: auto; }
.garden-copy .panel-title,
.garden-copy .panel-lede,
.garden-copy .garden-empty,
.garden-copy .link-btn {
  text-shadow: 0 1px 14px rgba(250, 247, 243, .92), 0 0 30px rgba(250, 247, 243, .75);
}
.garden-copy .panel-lede { margin-bottom: 26px; }

.garden-empty {
  margin: 0 0 26px;
  font-size: 13.5px;
  color: var(--ink-soft);
  font-style: italic;
}

.link-btn {
  font-size: 12px;
  letter-spacing: .22em;
  color: var(--pink-deep);
  border-bottom: 1px solid currentColor;
  padding-bottom: 3px;
  transition: letter-spacing .3s var(--ease), color .25s var(--ease);
}
.link-btn:hover { letter-spacing: .28em; color: var(--zinnia); }

/* ── narrow screens ─────────────────────────────────────────────────────── */

@media (max-width: 767px) {
  /* The height term matters as much here as on desktop: keyed to width alone,
     a landscape phone (812x375) would size the portrait to 453px tall in a
     375px viewport. */
  :root { --frame: min(78vw, 46vh, 340px); }

  #masthead {
    padding: 18px 20px;
    flex-direction: column;
    align-items: flex-start;
    gap: 9px;
    background: linear-gradient(180deg, var(--paper) 55%, rgba(250, 247, 243, 0));
  }
  #nav { gap: 18px; }
  #nav a { font-size: 11.5px; }

  .panel { padding: 104px 20px 64px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 24px 16px; }
  .contact-list { grid-template-columns: 1fr; gap: 4px 0; }
  .contact-list dd { margin-bottom: 14px; }
}

/* ── reduced motion ─────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .panel.is-entering,
  body.bio-photo #portrait { animation-duration: .3s; }
  .caret { animation: none; }
}
