/* Corvid Yard. Overcast, cheap paper, one green. Mobile first (§12). */

:root {
  --ground: #171c1a;
  --sky: #26312f;
  --surface: #1e2624;
  --surface-2: #263230;
  --line: #34423e;
  --line-soft: #2a3634;
  --ink: #ece5d6;
  --ink-2: #b9c2b8;
  --muted: #7f8d84;
  --accent: #7fbb9d;
  --warm: #d8c9a3;
  --hot: #cf6a4a;
  --disp: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --shadow: 0 1px 0 rgba(0, 0, 0, 0.3), 0 14px 34px rgba(0, 0, 0, 0.4);
  /* The nav is fixed, so everything that must clear it measures against this
     rather than against a number somebody guessed once. */
  --nav-h: calc(46px + env(safe-area-inset-bottom));
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--ground);
  background-image: radial-gradient(120% 60% at 50% 0%, rgba(63, 82, 76, 0.3), rgba(23, 28, 26, 0) 70%);
  background-attachment: fixed;
  color: var(--ink);
  font-family: var(--disp);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}
button { font: inherit; color: inherit; }
h1, h2, h3 { margin: 0; font-weight: 600; text-wrap: balance; }
.mono { font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; }

#app { max-width: 620px; margin: 0 auto; padding-bottom: var(--nav-h); min-height: 100%; }

/* ── top bar ─────────────────────────────────────────────────────────── */
/* On the list screens the purse is the only chrome, so it floats on the page
   rather than sitting in a bar with a rule under it. The yard writes its own
   across the picture — see .hud. */
.top {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px 12px;
  background: linear-gradient(var(--ground) 62%, rgba(23, 28, 26, 0));
}
.purse { display: flex; gap: 15px; font-family: var(--mono); font-size: 13px; font-variant-numeric: tabular-nums; }
.purse b { font-weight: 400; color: var(--warm); }
.purse .shiny b { color: var(--accent); }
.top .weather { margin-left: auto; color: var(--muted); font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; }

/* ── pinned goal (§17.3) ─────────────────────────────────────────────── */
.goal {
  display: flex; align-items: center; gap: 10px;
  margin: 12px 16px 0; padding: 10px 13px;
  border: 1px solid var(--line); border-radius: 3px; background: var(--surface);
  cursor: pointer; width: calc(100% - 32px); text-align: left;
}
.goal .name { font-size: 15px; }
.goal .bar { flex: 1; height: 5px; background: var(--line); border-radius: 3px; overflow: hidden; }
.goal .bar i { display: block; height: 100%; background: var(--accent); }
.goal .lab { font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }

/* ── the yard ────────────────────────────────────────────────────────── */
/* The yard is the screen, not a panel on it. Edge to edge, as tall as the
   plate's shape allows, and it stops just short of the nav rather than leaving
   a third of a phone empty underneath itself.

   `aspect-ratio` with a `max-height` means the tall-and-narrow case (a phone)
   fills the width, and the short-and-wide case (a desktop window) shrinks to
   fit the height and centres. Either way the plate is never cropped, which
   matters because every position in places.js is a percentage of this box. */
.yard {
  position: relative;
  margin: 0 auto;
  overflow: hidden;
  background: linear-gradient(#2c3a37, #202a27 62%, #232a24 62%, #1c231e);
  aspect-ratio: 3 / 4;
  max-height: calc(100dvh - var(--nav-h));
  width: 100%;
}
.yard .sky { position: absolute; inset: 0; transition: opacity 1.4s ease; }
.yard.dawn { filter: saturate(0.8) brightness(0.95) sepia(0.15); }
.yard.dusk { filter: saturate(0.7) brightness(0.72); }
.yard.night { filter: saturate(0.4) brightness(0.45); }
.yard .fence {
  position: absolute; left: 0; right: 0; bottom: 34%; height: 22%;
  background: repeating-linear-gradient(90deg, #4a4034 0 13px, #3d352b 13px 15px);
  border-top: 2px solid #55483a; border-bottom: 2px solid #2b241d;
}
.yard .birds { position: absolute; inset: 0; }
/* A bird's coordinate is its feet, so it is translated up off the point it
   stands on rather than centred over it. Anything else puts a crow half
   through the fence rail. */
.yard .bird {
  position: absolute; font-size: 26px; line-height: 1;
  transform: translate(-50%, -100%);
  animation: hop 2.6s ease-in-out infinite;
}
@keyframes hop {
  0%, 100% { transform: translate(-50%, -100%); }
  45% { transform: translate(-50%, calc(-100% - 4px)); }
}
@media (prefers-reduced-motion: reduce) { .yard .bird { animation: none; } }

/* Food and objects are placed, not listed. The layer is the whole plate and
   each one carries its own coordinate, because a feeder belongs at a spot on
   the grass and a bell belongs on the hook — a row of boxes across the middle
   says the yard is a menu rather than a place. Each sits on its point rather
   than beside it. */
/* Weather, as a moving layer over a still plate rather than four more plates
   per sky. Two gradients drifting at different speeds is enough rain: the eye
   reads streaks and parallax, and the whole thing costs one element.

   It sits under the birds and the props, because rain falls in front of the
   fence and behind the crow standing on it, and nobody has ever looked closely
   enough to disagree. */
.wx { position: absolute; inset: 0; pointer-events: none; opacity: 0; }
.yard.wx-rain .wx, .yard.wx-snow .wx { opacity: 1; }

.yard.wx-rain .wx {
  background:
    repeating-linear-gradient(102deg, rgba(214,232,244,0) 0 11px, rgba(214,232,244,0.20) 11px 12px),
    repeating-linear-gradient(99deg, rgba(214,232,244,0) 0 19px, rgba(214,232,244,0.11) 19px 20px);
  background-size: 100% 44px, 100% 70px;
  animation: rain 0.55s linear infinite, rain-slow 0.9s linear infinite;
}
@keyframes rain { from { background-position-y: 0, 0; } to { background-position-y: 44px, 0; } }
@keyframes rain-slow { from { background-position-y: 0, 0; } to { background-position-y: 0, 70px; } }

.yard.wx-snow .wx {
  background:
    radial-gradient(2.5px 2.5px at 12% 10%, rgba(255,255,255,0.85) 50%, transparent 51%),
    radial-gradient(2px 2px at 68% 32%, rgba(255,255,255,0.7) 50%, transparent 51%),
    radial-gradient(3px 3px at 41% 70%, rgba(255,255,255,0.8) 50%, transparent 51%),
    radial-gradient(2px 2px at 87% 55%, rgba(255,255,255,0.6) 50%, transparent 51%);
  background-size: 120px 120px, 90px 90px, 160px 160px, 70px 70px;
  animation: snow 9s linear infinite;
}
@keyframes snow {
  from { background-position: 0 0, 0 0, 0 0, 0 0; }
  to { background-position: 14px 120px, -10px 90px, 8px 160px, -6px 70px; }
}

@media (prefers-reduced-motion: reduce) {
  .yard.wx-rain .wx, .yard.wx-snow .wx { animation: none; }
}

/* Bought features sit between the plate and everything that moves: a crow can
   stand on the birdbath, so birds are drawn after these. */
.feats { position: absolute; inset: 0; pointer-events: none; }
.feat { position: absolute; transform: translate(-50%, -100%); height: auto; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.35)); }
.slots, .hooks { position: absolute; inset: 0; pointer-events: none; }

/* A thing you have put out is a thing lying in your yard, not a thing in a box
   on a picture of your yard. Filled slots and hooks have no frame, no plate and
   no border: the seed bag sits on the grass at its own size with a contact
   shadow under it, the bell hangs on the fence, and the only chrome left is the
   count. The tap target stays a comfortable 76px and is invisible.

   Empty ones still have to say "something goes here", so they keep a soft
   dashed ring — a marker, which is a quieter shape than a panel. */
.slot, .hook {
  position: absolute; transform: translate(-50%, -50%); pointer-events: auto;
  display: grid; place-items: center; cursor: pointer;
  background: none; border: 0; padding: 0;
}
.slot { width: 76px; height: 76px; }
.hook { width: 56px; height: 56px; }

.slot::before, .hook::before {
  content: ""; position: absolute; inset: 22%;
  border: 1px dashed rgba(236, 229, 214, 0.6); border-radius: 50%;
  background: rgba(10, 14, 13, 0.42);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.45);
}
.slot.filled::before, .hook.filled::before { content: none; }
.slot.empty-food::before { border-color: rgba(207, 106, 74, 0.7); }

.slot .icon, .hook > * { position: relative; z-index: 1; }
.slot .icon { display: block; font-size: 22px; line-height: 1; color: rgba(236, 229, 214, 0.92); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8); }
.hook { font-size: 19px; color: rgba(236, 229, 214, 0.92); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8); }

/* Cut out of their cream, these props have no shadow of their own — that pass
   removed it on purpose. This puts one back, the same one on everything, so a
   bag of seed sits on the grass instead of hovering a foot above it. */
.slot.filled .icon::after {
  content: ""; position: absolute; left: 50%; bottom: -3px;
  width: 74%; height: 9px; transform: translateX(-50%);
  background: radial-gradient(closest-side, rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0));
}
.slot .units {
  position: absolute; left: 50%; bottom: -3px; transform: translateX(-50%);
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.06em;
  color: var(--ink); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
}
.slot.pulse::before { animation: pulse 1.8s ease-in-out infinite; }
@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(127, 187, 157, 0); }
  50% { box-shadow: 0 0 0 7px rgba(127, 187, 157, 0.2); }
}

/* Nothing in a yard is ever perfectly still, and a yard whose whole premise is
   that it carries on without you should not look like a photograph of one. Every
   placed thing breathes: a slow, tiny scale, too small to notice on any single
   object and the difference between a scene and a picture across all of them.

   The delays are derived from the element's own index rather than shared, so
   eight things do not inhale together. */
@keyframes breathe {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50% { transform: translate(-50%, -50%) scale(1.035); }
}
@keyframes breathe-feet {
  0%, 100% { transform: translate(-50%, -100%) scale(1); }
  50% { transform: translate(-50%, -100%) scale(1.02); }
}
.slot.filled, .hook.filled {
  animation: breathe 5.5s ease-in-out infinite;
  transform-origin: 50% 80%;
}
.feat {
  animation: breathe-feet 8s ease-in-out infinite;
  transform-origin: 50% 100%;
}
.slot.filled:nth-of-type(2) { animation-delay: -1.4s; animation-duration: 6.1s; }
.slot.filled:nth-of-type(3) { animation-delay: -2.9s; animation-duration: 5.1s; }
.slot.filled:nth-of-type(4) { animation-delay: -0.7s; animation-duration: 6.6s; }
.slot.filled:nth-of-type(5) { animation-delay: -3.6s; animation-duration: 5.8s; }
.hook.filled:nth-of-type(2) { animation-delay: -2.2s; animation-duration: 6.3s; }
.hook.filled:nth-of-type(3) { animation-delay: -3.9s; animation-duration: 5.4s; }
.hook.filled:nth-of-type(4) { animation-delay: -1.1s; animation-duration: 6.8s; }
.hook.filled:nth-of-type(5) { animation-delay: -4.4s; animation-duration: 5.9s; }
.hook.filled:nth-of-type(6) { animation-delay: -2.6s; animation-duration: 6.4s; }
.feat:nth-of-type(2) { animation-delay: -2.5s; animation-duration: 9.2s; }
.feat:nth-of-type(3) { animation-delay: -5.1s; animation-duration: 7.4s; }
.feat:nth-of-type(4) { animation-delay: -1.3s; animation-duration: 10s; }

/* Clouds the plate does not have, drifting across the sky it does. Two layers
   at different speeds and opacities so the sky has depth rather than a single
   sheet sliding over it. They live above the fence line and fade out before
   they reach it, because a cloud crossing a fence is a fog bank. */
.clouds {
  position: absolute; left: 0; right: 0; top: 0; height: 62%;
  pointer-events: none; overflow: hidden;
  -webkit-mask-image: linear-gradient(#000 62%, transparent 96%);
  mask-image: linear-gradient(#000 62%, transparent 96%);
}
.clouds i {
  position: absolute; display: block; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0));
  animation: drift linear infinite;
}
.clouds i:nth-child(1) { width: 46%; height: 20%; top: 12%; animation-duration: 96s; opacity: 0.5; }
.clouds i:nth-child(2) { width: 30%; height: 13%; top: 30%; animation-duration: 138s; opacity: 0.34; animation-delay: -40s; }
.clouds i:nth-child(3) { width: 58%; height: 16%; top: 45%; animation-duration: 176s; opacity: 0.22; animation-delay: -90s; }
@keyframes drift {
  from { transform: translateX(-70%); }
  to { transform: translateX(180%); }
}
.yard.night .clouds i, .yard.dusk .clouds i { opacity: 0.2; }

@media (prefers-reduced-motion: reduce) {
  .slot.filled, .hook.filled, .feat, .clouds i { animation: none; }
}

.line { margin: 14px 16px 0; color: var(--ink-2); }
.line.small { font-size: 15px; color: var(--muted); }

/* ── the yard's own chrome ───────────────────────────────────────────── */
/* Written across the picture rather than stacked above it. Each strip carries
   its own gradient so a number stays readable over a bright dawn sky or a dark
   fence, without painting a bar over the art. */
.hud {
  position: absolute; left: 0; right: 0; z-index: 15;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; pointer-events: none;
}
.hud > * { pointer-events: auto; }
.hud.top { top: 0; background: linear-gradient(rgba(8, 12, 11, 0.55), rgba(8, 12, 11, 0)); }
.hud.bottom {
  bottom: 0; flex-direction: column; align-items: stretch; gap: 7px;
  padding: 40px 14px calc(9px + env(safe-area-inset-bottom));
  background: linear-gradient(rgba(8, 12, 11, 0), rgba(8, 12, 11, 0.55) 55%, rgba(8, 12, 11, 0.8));
}
.hud .purse b, .hud .weather, .hud .beat { text-shadow: 0 1px 3px rgba(0, 0, 0, 0.75); }
.hud .weather { margin-left: auto; }
.hud .beat { margin: 0; font-size: 15px; color: var(--ink-2); }
.hud .beat.urgent { color: var(--warm); }
.hud .goal {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 10px; width: 100%; text-align: left; cursor: pointer;
  border: 1px solid rgba(236, 229, 214, 0.22); border-radius: 3px;
  background: rgba(8, 12, 11, 0.5);
}

/* ── nav ─────────────────────────────────────────────────────────────── */
.nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  display: flex; max-width: 620px; margin: 0 auto;
  background: rgba(19, 23, 22, 0.92);
  backdrop-filter: blur(10px);
  box-shadow: inset 0 1px 0 rgba(236, 229, 214, 0.06);
  padding-bottom: env(safe-area-inset-bottom);
}
.nav button {
  flex: 1; padding: 12px 4px 11px; background: none; border: none; cursor: pointer;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); border-top: 2px solid transparent; margin-top: -1px;
}
.nav button[aria-current="true"] { color: var(--accent); border-top-color: var(--accent); }

/* ── panels ──────────────────────────────────────────────────────────── */
/* ── the screens that are not the yard ───────────────────────────────── */
/* These were a settings app bolted onto a painted world: one flat grey card
   repeated down the page, a 20px heading, and a bright green chip for the
   selected tab. Nothing about them said they belonged to the same game.

   The fix is not decoration, it is hierarchy and warmth. A real heading with
   room around it; cards that are soft objects rather than bordered boxes; art
   large enough to be the thing you read the row by; and one warm accent for
   the thing you can act on. */
.panel { padding: 22px 16px 8px; }
.panel h2 { font-size: 27px; letter-spacing: -0.01em; margin-bottom: 5px; }
.panel .sub { color: var(--muted); font-size: 15px; margin: 0 0 20px; max-width: 46ch; }

/* A segmented control, not three buttons. The selected one is a warm slab the
   colour of the yard's own light rather than a green highlighter. */
.tabs {
  display: flex; gap: 3px; margin-bottom: 18px; padding: 3px;
  background: var(--surface); border-radius: 8px;
}
.tabs button {
  flex: 1; font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em;
  text-transform: uppercase; padding: 10px 8px; border: 0; background: none;
  color: var(--muted); border-radius: 6px; cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}
.tabs button:hover { color: var(--ink-2); }
.tabs button[aria-selected="true"] {
  background: var(--surface-2); color: var(--warm);
  box-shadow: inset 0 1px 0 rgba(236, 229, 214, 0.07);
}

.rows { display: flex; flex-direction: column; gap: 8px; }
.row {
  display: flex; align-items: center; gap: 15px; padding: 14px 15px;
  border: 0; border-radius: 10px; background: var(--surface);
  box-shadow: inset 0 1px 0 rgba(236, 229, 214, 0.045);
}
.row .icon {
  font-size: 27px; width: 46px; height: 46px; flex: none;
  display: grid; place-items: center;
}
.row .body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.row .body b { font-weight: 600; display: block; font-size: 17px; }
.row .body span { font-size: 14px; line-height: 1.4; color: var(--muted); display: block; }
.buy {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em;
  padding: 10px 13px; border: 0; color: var(--ground);
  background: var(--warm); border-radius: 7px; cursor: pointer; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.buy:active { transform: translateY(1px); }
.buy[disabled] {
  background: none; box-shadow: inset 0 0 0 1px var(--line);
  color: var(--muted); cursor: default; transform: none;
}
.row .owned {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted); white-space: nowrap;
}

/* ── birdbook ────────────────────────────────────────────────────────── */
.birds-list { display: flex; flex-direction: column; gap: 8px; }
.bird-row {
  display: flex; gap: 15px; padding: 15px; align-items: flex-start;
  border: 0; border-radius: 10px; background: var(--surface);
  box-shadow: inset 0 1px 0 rgba(236, 229, 214, 0.045);
}
.bird-row.unseen { opacity: 0.45; }
.bird-row .glyph { font-size: 28px; width: 36px; text-align: center; filter: grayscale(1) brightness(0.5); }
.bird-row:not(.unseen) .glyph { filter: none; }
/* Every line in a row is its own line. These were inline spans, so the blurb,
   the visit count and the gift count ran into one paragraph and wrapped
   wherever they happened to meet — "17 visits ·" ending a line and a lonely
   "brought 1" starting the next. */
.bird-row .meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.bird-row .meta b { display: block; font-size: 17px; }
.bird-row .meta .blurb { display: block; font-size: 14px; line-height: 1.4; color: var(--muted); }
.bird-row .counts {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted);
}
.bird-row .hint-for { font-size: 13px; color: var(--muted); }
.bird-row .hint-for b { display: inline; font-size: 13px; color: var(--ink-2); font-weight: 400; }
.trust { display: flex; align-items: center; gap: 9px; }
.trust .trustbar { flex: 1; }
.trust .tnum {
  font-family: var(--mono); font-size: 11px; color: var(--warm);
  font-variant-numeric: tabular-nums; flex: none;
}
/* The two thresholds are the whole ladder — 60 brings you things, 100 brings
   you a bird — so they are notches you can actually see rather than a hairline
   the same colour as the track. */
.trustbar { position: relative; height: 6px; background: var(--line); border-radius: 3px; margin-top: 5px; overflow: visible; }
.trustbar i { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.trustbar u {
  position: absolute; top: -4px; width: 2px; height: 14px; border-radius: 1px;
  background: var(--ink-2); opacity: 0.55;
}
.trustbar u[data-at="60"] { left: 60%; }
.trustbar u[data-at="100"] { left: calc(100% - 2px); }

/* ── cabinet ─────────────────────────────────────────────────────────── */
.cab-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 18px; }
.cab-head .pctl { font-size: 30px; color: var(--warm); font-variant-numeric: tabular-nums; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); gap: 8px; }
/* Soft objects on a shelf, matching the cards on every other screen. Tier is a
   ring rather than a border colour, so a legendary reads as lit from behind
   instead of merely outlined. */
.tile {
  aspect-ratio: 1; border: 0; border-radius: 9px; background: var(--surface);
  box-shadow: inset 0 1px 0 rgba(236, 229, 214, 0.05);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  padding: 6px; text-align: center; cursor: pointer;
  transition: transform 0.15s ease;
}
.tile:not(.locked):active { transform: scale(0.96); }
.tile.locked { opacity: 0.26; cursor: default; }
.tile .g { font-size: 22px; }
.tile .n { font-size: 10px; line-height: 1.15; color: var(--muted); }
.tile .x { position: absolute; }
.tile.tier-rare { box-shadow: inset 0 0 0 1px rgba(127, 187, 157, 0.35); }
.tile.tier-legendary {
  box-shadow: inset 0 0 0 1px rgba(216, 201, 163, 0.55), 0 0 16px rgba(216, 201, 163, 0.09);
}
.tile .dupe { font-family: var(--mono); font-size: 9px; color: var(--warm); }

.setlist { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; }
.setrow { display: flex; align-items: center; gap: 10px; font-size: 14px; }
.setrow .track { flex: 1; height: 5px; background: var(--line); border-radius: 3px; }
.setrow .track i { display: block; height: 100%; background: var(--warm); border-radius: 3px; }
.setrow .n { font-family: var(--mono); font-size: 11px; color: var(--muted); }
.setrow.done .n { color: var(--warm); }

/* ── album ───────────────────────────────────────────────────────────── */
.log { display: flex; flex-direction: column; }
.log .entry { padding: 9px 0; border-bottom: 1px solid var(--line-soft); display: flex; gap: 13px; align-items: baseline; }
.log .entry:last-child { border-bottom: 0; }
/* Two short lines rather than one long one, so the column can be narrow and
   nothing wraps mid-timestamp. */
.log .entry .when {
  font-family: var(--mono); font-size: 10px; line-height: 1.35; color: var(--muted);
  width: 56px; flex: none; white-space: nowrap;
}
.log .entry .when b { display: block; font-weight: 400; color: var(--ink-2); }
.log .entry .what { flex: 1; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 8px; }
/* The bird is what happened. The verb used to be set larger than the name it
   belonged to, which made the album a list of things rather than of visitors. */
.log .entry .who { font-size: 16px; color: var(--ink); }
.log .entry .did { font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.log .entry .first {
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent); border: 1px solid rgba(127, 187, 157, 0.4); border-radius: 2px; padding: 1px 5px;
}

/* ── sheet + reveal (§17.2) ──────────────────────────────────────────── */
.sheet {
  position: fixed; inset: 0; z-index: 40; background: rgba(10, 14, 13, 0.94);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 24px; text-align: center;
}
.sheet[hidden] { display: none; }
.sheet .count { color: var(--muted); margin-bottom: 20px; }
.stack { position: relative; width: min(340px, 86vw); height: min(430px, 58vh); }
.rcard {
  position: absolute; inset: 0; border-radius: 6px; border: 1px solid var(--line);
  background: var(--surface); box-shadow: var(--shadow);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: 26px; cursor: pointer;
  transition: transform 0.34s ease, opacity 0.34s ease;
}
.rcard.back { background: var(--surface-2); }
.rcard.gone { transform: translateY(-24px) rotate(-3deg); opacity: 0; }
.rcard .kicker { font-family: var(--mono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); }
.rcard .glyph { font-size: 74px; line-height: 1; }
.rcard h3 { font-size: 26px; }
.rcard p { margin: 0; color: var(--ink-2); }
.rcard.item h3 { color: var(--warm); }
.rcard.event { border-color: var(--accent); }
.rcard .delta { font-family: var(--mono); font-size: 12px; color: var(--accent); }
.sheet .skip {
  margin-top: 22px; background: none; border: 1px solid var(--line); color: var(--muted);
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.13em; text-transform: uppercase;
  padding: 10px 15px; border-radius: 2px; cursor: pointer;
}
.sheet .tap { margin-top: 14px; color: var(--muted); font-family: var(--mono); font-size: 10px; letter-spacing: 0.13em; text-transform: uppercase; }

/* Full-screen reveal for a new bird or a new item. It has to sit ABOVE the
   onboarding overlay (z-index 70) — Kevin's reveal happens during the scripted
   session, and at a lower z-index it renders behind it. */
.reveal {
  position: fixed; inset: 0; z-index: 80; background: #0c110f;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  padding: 30px; text-align: center;
}
.reveal[hidden] { display: none; }
.reveal .glyph { font-size: 96px; animation: land 0.7s cubic-bezier(0.2, 0.9, 0.3, 1); }
@keyframes land { from { transform: translateY(-30px) scale(0.8); opacity: 0; } to { transform: none; opacity: 1; } }
.reveal h2 { font-size: 38px; letter-spacing: -0.01em; }
.reveal p { color: var(--ink-2); max-width: 30ch; margin: 0; }
.reveal .markers { width: min(320px, 80vw); }
.reveal .mk { display: flex; justify-content: space-between; font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); margin-top: 7px; }

/* ── picker + dialogs ────────────────────────────────────────────────── */
/* A sheet that comes up out of the bottom of the screen, not a panel that
   appears. It gets a grab handle, a warm surface, a soft top edge and a real
   heading, because these carry the only decisions in the game and they were
   dressed as an error dialog.

   No emoji in here. A dialog full of ✖️ and 📌 next to painted birds is the
   one place the seams show, so utility rows have no icon at all and say what
   they do in words instead. */
.modal {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(8, 12, 11, 0.62);
  backdrop-filter: blur(3px);
  display: flex; align-items: flex-end; justify-content: center;
  animation: veil 0.2s ease;
}
.modal[hidden] { display: none; }
@keyframes veil { from { opacity: 0; } to { opacity: 1; } }

.modal .box {
  width: 100%; max-width: 620px; background: var(--sky);
  border-radius: 18px 18px 0 0;
  box-shadow: inset 0 1px 0 rgba(236, 229, 214, 0.08), 0 -18px 50px rgba(0, 0, 0, 0.5);
  padding: 10px 16px calc(22px + env(safe-area-inset-bottom));
  max-height: 82vh; overflow-y: auto;
  animation: rise 0.26s cubic-bezier(0.2, 0.9, 0.3, 1);
}
@keyframes rise { from { transform: translateY(14px); } to { transform: none; } }

/* The handle. Nothing else in the game says "this came up and can go back
   down", and without it a sheet reads as a screen you are now stuck on. */
.modal .box::before {
  content: ""; display: block; width: 38px; height: 4px; margin: 0 auto 16px;
  border-radius: 2px; background: rgba(236, 229, 214, 0.22);
}
.modal h3 { font-size: 23px; margin-bottom: 4px; }
.modal .sub { color: var(--muted); font-size: 15px; margin: 0 0 16px; }
.modal .rows + .sub { margin: 14px 0 0; }

/* The thing the sheet is about, at the top, at a size worth looking at. */
.sheet-hero {
  display: flex; align-items: center; gap: 16px; margin-bottom: 18px;
}
.sheet-hero .art { height: 84px; width: auto; max-width: 96px; object-fit: contain;
  filter: drop-shadow(0 5px 9px rgba(0, 0, 0, 0.45)); }
.sheet-hero .glyph { font-size: 54px; line-height: 1; }
.sheet-hero .meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.sheet-hero h3 { margin: 0; }
.sheet-hero .kicker {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted);
}

/* A row with no icon, for the things that are an action rather than an object.
   Indented to the same text column so a picker still reads as one list. */
.row.plain { background: none; box-shadow: none; padding: 11px 15px; }
.row.plain .body b { font-size: 15px; color: var(--ink-2); }

.modal .close {
  margin-top: 18px; width: 100%; padding: 14px; cursor: pointer;
  background: var(--surface); border: 0; border-radius: 10px; color: var(--ink-2);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.13em; text-transform: uppercase;
}
.modal .close:active { transform: translateY(1px); }
.modal input[type="text"] {
  width: 100%; padding: 13px 14px; background: var(--surface); color: var(--ink);
  border: 0; border-radius: 10px; font: inherit; margin-bottom: 12px;
}
.modal input[type="text"]::placeholder { color: var(--muted); }

/* ── how this works ──────────────────────────────────────────────────── */
/* One idea a screen, the game's own art above it, and no cleverness. The dots
   are there so five screens read as five and not as an unknown number of them. */
.howto { text-align: center; padding: 4px 4px 0; }
.howto .plate {
  height: 128px; display: grid; place-items: center; margin-bottom: 20px;
}
.howto .plate .art {
  height: 124px; width: auto; max-width: 78%; object-fit: contain;
  filter: drop-shadow(0 7px 14px rgba(0, 0, 0, 0.5));
  animation: breathe-plain 6s ease-in-out infinite;
}
@keyframes breathe-plain {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.035); }
}
.howto .plate .glyph { font-size: 84px; line-height: 1; }
.howto h3 { font-size: 25px; margin-bottom: 10px; text-wrap: balance; }
.howto .sub {
  font-size: 16px; line-height: 1.55; color: var(--ink-2);
  margin: 0 auto 22px; max-width: 40ch; text-wrap: pretty;
}
.howto .dots { display: flex; gap: 7px; justify-content: center; margin-bottom: 18px; }
.howto .dots i {
  width: 6px; height: 6px; border-radius: 50%;
  background: rgba(236, 229, 214, 0.22); transition: background 0.2s ease;
}
.howto .dots i.on { background: var(--warm); }
.buy.wide { width: 100%; padding: 15px; font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; }

@media (prefers-reduced-motion: reduce) { .howto .plate .art { animation: none; } }

/* ── onboarding ──────────────────────────────────────────────────────── */
.ob { position: fixed; inset: 0; z-index: 70; background: var(--ground); display: flex; flex-direction: column; }
.ob[hidden] { display: none; }
.ob .stage { flex: 1; display: flex; flex-direction: column; justify-content: center; padding: 20px; max-width: 620px; margin: 0 auto; width: 100%; }
.ob .say { font-size: 20px; text-align: center; margin: 22px 0 0; min-height: 2em; }
.ob .say.small { font-size: 15px; color: var(--muted); }
.ob .go {
  margin: 20px auto 0; padding: 14px 26px; background: var(--accent); color: var(--ground);
  border: none; border-radius: 2px; cursor: pointer;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
}
.ob .go[hidden] { display: none; }
.ob .skip { position: absolute; top: 14px; right: 16px; background: none; border: none; color: var(--muted); font-family: var(--mono); font-size: 10px; letter-spacing: 0.13em; text-transform: uppercase; cursor: pointer; }

/* ── share pages ─────────────────────────────────────────────────────── */
body.share { display: flex; align-items: center; justify-content: center; padding: 24px; }
.card { max-width: 480px; text-align: center; }
.card h1 { font-size: 34px; margin-bottom: 8px; }
.card .kicker { font-family: var(--mono); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); }
.card .stat { color: var(--warm); font-family: var(--mono); font-size: 13px; }
.card .note { color: var(--ink-2); font-style: italic; }
.card .latest { list-style: none; padding: 0; margin: 18px 0; color: var(--ink-2); }
.card .sets { color: var(--muted); font-size: 15px; }
.card .cta {
  display: inline-block; margin-top: 22px; padding: 14px 22px; background: var(--accent);
  color: var(--ground); text-decoration: none; border: none; border-radius: 2px; cursor: pointer;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
}

/* ── painted art ─────────────────────────────────────────────────────────
   Every art key falls back to a glyph, so these rules have to make an <img>
   and a <span> occupy the same space. */
.art { display: block; object-fit: contain; }
.yard.painted { background-size: cover; background-position: center; }
.yard.painted .fence { display: none; }
/* Height, not a square. The cut-outs are all different shapes, and a 46x46 box
   with object-fit: contain letterboxes a wide bird — which puts empty pixels
   under its feet, and the feet are what the yard positions by. A crow sat
   visibly above the fence rail until this stopped being width AND height. */
.yard .bird .art { height: 48px; width: auto; max-width: 66px; filter: drop-shadow(0 3px 4px rgba(0, 0, 0, 0.45)); }
.slot .icon .art { width: 48px; height: 48px; filter: drop-shadow(0 3px 4px rgba(0, 0, 0, 0.4)); }
.hook .art { width: 40px; height: 40px; filter: drop-shadow(0 3px 4px rgba(0, 0, 0, 0.45)); }
.bird-row .art { width: 64px; height: 64px; flex: none; object-fit: contain; }
.bird-row.unseen .art { filter: grayscale(1) brightness(0.45); }
.tile .g .art { width: 44px; height: 44px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.4)); }
.tile.locked .g .art { filter: grayscale(1) brightness(0.4); }
/* Height, not a square, for the same reason the birds needed it: these are
   cut-outs of every shape and a square box letterboxes the wide ones into a
   stamp in the middle of a large empty card. */
.rcard .art {
  height: 152px; width: auto; max-width: 80%;
  filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.45));
}
.reveal .art.big {
  width: auto; height: min(300px, 42vh); max-width: 82vw;
  animation: land 0.7s cubic-bezier(0.2, 0.9, 0.3, 1);
}
.row .icon .art { width: 44px; height: 44px; object-fit: contain; }

/* The painted yards already carry their own light, so the tint filters that
   fake time of day for the placeholder must not stack on top of them. */
.yard.painted.dawn, .yard.painted.day, .yard.painted.dusk, .yard.painted.night { filter: none; }

/* The close-up portraits sit on a painted plate rather than a flat cream, so
   they do not key out cleanly. Frame them instead — a portrait card is the
   right read for them anyway. */
.reveal .art.big, .rcard .art { border-radius: 8px; }
.reveal .art.big { box-shadow: 0 18px 50px rgba(0, 0, 0, 0.55); }
