/* ✉️ THE MAILBOX — the post office's card (20 Sep 2026, docs/town-jobs-plan.md §6).
 *
 * ⚠️ 261 × 440 CSS px is the budget: the measured content box of a town card at 360×640, the narrowest
 * phone the house supports. Everything below is sized against 261.
 *
 * ⚠️ NOTHING HERE IS ROTATED, and that is a decision rather than a shortcut. The plan names the caret
 * inside a tilted, torn, clipped sheet as the one risk no test can discharge — iOS puts the caret where
 * it likes inside a transformed box and drops the selection handles outside it. The paper look is the
 * box AROUND a plain <textarea>, so the native caret, selection and keyboard all behave.
 */

.tw-post { display: grid; gap: 0.5rem; }
.tw-post h2 { margin: 0; }
.tw-post__who { font-family: "Archivo Black", sans-serif; font-size: 0.72rem; letter-spacing: 0.02em; }
/* ⚠️ the peek is ONE line and it is clipped, never wrapped: three letters each three lines deep push
   the stack past the card and turn a mailbox into a scroller */
.tw-post__peek { display: block; font-size: 0.78rem; line-height: 1.35; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: 0.85; }

/* ---- the new post: SEALED ENVELOPES, and the seal is the art rather than a badge ---------------- */
/* the pack ships two envelopes, one with a red wax seal and one without, so "new" is a thing you can
   see from across a room instead of a dot you have to read. 52px each, side by side, wrapping. */
.tw-post__new { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tw-post__env {
  appearance: none; font: inherit; cursor: pointer;
  display: grid; justify-items: center; gap: 2px; padding: 0.4rem 0.45rem 0.35rem;
  background: #2a2119; color: #fffdf5; border: 3px solid #000; box-shadow: 3px 3px 0 #000;
  min-width: 78px; max-width: 118px;
}
.tw-post__env:active { transform: translate(1px, 1px); box-shadow: 2px 2px 0 #000; }
.tw-post__env .tw-post__who { font-size: 0.64rem; text-align: center; overflow: hidden; text-overflow: ellipsis; max-width: 100%; white-space: nowrap; }
.tw-post__stamp {
  width: 52px; height: 52px; image-rendering: pixelated;
  background: center/contain no-repeat url('/assets/town/s-letterseal-0.png');
}
.tw-post__stamp.is-open { width: 30px; height: 30px; background-image: url('/assets/town/s-letteropen-0.png'); }

/* ---- the kept post: ONE ROW PER PERSON, never one per letter ------------------------------------ */
.tw-post__of { display: block; font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.72; font-weight: 800; margin-top: 0.15rem; }
.tw-post__stack { display: grid; gap: 0.4rem; }
.tw-post__thread {
  appearance: none; text-align: left; cursor: pointer; width: 100%;
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 0.45rem;
  padding: 0.4rem 0.55rem; min-height: 44px;
  background: #fbf3dd; color: #241c0e; border: 3px solid #000; box-shadow: 3px 3px 0 #000;
  font: inherit;
}
.tw-post__thread:active { transform: translate(1px, 1px); box-shadow: 2px 2px 0 #000; }
.tw-post__thread.is-new { background: #fff8e2; }
.tw-post__row { display: grid; gap: 1px; min-width: 0; }

/* ---- an open letter, and the envelope it came out of ------------------------------------------- */
/* ⭐ THE ENVELOPE COMES OPEN AND THE LETTER COMES OUT (Trym, 20 Sep). Two one-shot animations on
   TRANSFORM AND OPACITY ONLY (design library §21.4): the envelope lifts off the top of the card and
   fades, and the sheet rises out from behind where it was. Both run once and then the card is still —
   nothing animates while you are reading, which is the whole point of a letter. */
.tw-post__open { position: relative; display: grid; gap: 0.45rem; background: #fbf3dd; color: #241c0e; border: 3px solid #000; box-shadow: 3px 3px 0 #000; padding: 0.6rem; }
.tw-post__flap {
  position: absolute; left: 50%; top: 6px; width: 52px; height: 52px; margin-left: -26px; z-index: 2;
  image-rendering: pixelated; pointer-events: none;
  background: center/contain no-repeat url('/assets/town/s-letterseal-0.png');
  animation: twPostFlap 520ms cubic-bezier(0.3, 0, 0.2, 1) forwards;
}
@keyframes twPostFlap {
  0% { opacity: 1; transform: scale(1) translateY(0); }
  45% { opacity: 1; transform: scale(1.18) translateY(-6px); }
  100% { opacity: 0; transform: scale(1.5) translateY(-30px); }
}
.tw-post__open.is-opening .tw-post__sheetin { animation: twPostOut 520ms cubic-bezier(0.2, 0.9, 0.2, 1) both; }
@keyframes twPostOut {
  0% { opacity: 0; transform: translateY(26px) scaleY(0.82); }
  40% { opacity: 1; }
  100% { opacity: 1; transform: translateY(0) scaleY(1); }
}
.tw-post__sheetin { display: grid; gap: 0.3rem; transform-origin: 50% 100%; }
.tw-post__feet { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 0.5rem; }
.tw-post__back {
  appearance: none; font: inherit; cursor: pointer;
  background: #2a2119; color: #fffdf5; border: 3px solid #000; box-shadow: 2px 2px 0 #000;
  padding: 0.3rem 0.6rem; font-size: 0.72rem; white-space: nowrap;
}
.tw-post__back:active { transform: translate(1px, 1px); box-shadow: 1px 1px 0 #000; }
/* ⚠️ break-word, not just wrap: a letter is player-typed and one 400-character word is a letter a
   player CAN send — it would otherwise run straight off the side of the card */
.tw-post__body { margin: 0; font-size: 0.84rem; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
.tw-post__open .tw-btn--in { margin-top: 0.15rem; }
/* reporting is a normal thing to do, so it is quiet: a plain line, not a red button shouting at you */
.tw-post__flag {
  appearance: none; font: inherit; cursor: pointer; width: 100%;
  background: none; border: 0; padding: 0.3rem 0; margin: 0;
  font-size: 0.72rem; text-decoration: underline; opacity: 0.6; color: inherit;
}
.tw-post__flag:active { opacity: 1; }

/* writing back */
.tw-post__write { display: grid; gap: 0.4rem; }
.tw-post__to { margin: 0; font-size: 0.72rem; letter-spacing: 0.04em; text-transform: uppercase; opacity: 0.72; font-weight: 800; }
.tw-post__sheet {
  width: 100%; box-sizing: border-box; resize: none;
  background: #fbf3dd; color: #241c0e; border: 3px solid #000; box-shadow: inset 0 2px 0 rgba(0, 0, 0, 0.12);
  padding: 0.5rem 0.6rem; font: inherit; font-size: 0.84rem; line-height: 1.5;
  /* ruled paper, drawn rather than fetched: one repeating gradient, no file, nothing to load late */
  background-image: repeating-linear-gradient(#fbf3dd 0 calc(1.5em - 1px), rgba(40, 60, 90, 0.16) calc(1.5em - 1px), rgba(40, 60, 90, 0.16) 1.5em);
  background-attachment: local;
}
.tw-post__sheet:focus { outline: 3px solid #ffe135; outline-offset: 1px; }

.tw-post__none { margin: 0; font-size: 0.84rem; line-height: 1.5; opacity: 0.85; }

@media (prefers-reduced-motion: reduce) {
  /* ⚠️ the envelope still GOES — it just does not fly. A player who asked for stillness must still end
     up looking at the letter rather than at an envelope parked on top of it. */
  .tw-post__flap { animation: none; opacity: 0; }
  .tw-post__open.is-opening .tw-post__sheetin { animation: none; }
  .tw-post__env:active, .tw-post__thread:active, .tw-post__back:active { transform: none; }
}

/* ---- 📮 THE POSTCARD ---------------------------------------------------------------------------
 *
 * ⭐ A CARD IS AN OBJECT, NOT A MESSAGE (docs/town-jobs-plan.md §6). So it is drawn as a THING with a
 * border and a shadow, sitting on the card the way a photograph sits on a desk — never as a row in a
 * list. The picture is a baked 600×400 template; the banana standing in it is a canvas on top, drawn
 * live from the recipe that travelled.
 *
 * ⚠️ image-rendering: pixelated, and the picture is shown at a MULTIPLE of its own size wherever it
 * can be. A 600 px plate smoothed down to 261 turns hand-placed pixels into porridge.
 */
.tw-pc {
  position: relative; border: 3px solid #000; box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.55);
  background: #0d0904; overflow: hidden; aspect-ratio: 3 / 2;
}
.tw-pc__bg { display: block; width: 100%; height: 100%; object-fit: cover; image-rendering: pixelated; }
/* the banana stands on the lower middle of every one of the three, which is why all three were
   cropped with that spot clear — the plaza, the road, the floor */
.tw-pc__me {
  position: absolute; left: 50%; bottom: 14%; transform: translateX(-50%);
  width: 34%; height: auto; image-rendering: pixelated;
}
.tw-pc__place {
  position: absolute; left: 0; top: 0; padding: 0.2rem 0.45rem;
  font-family: "Archivo Black", sans-serif; font-size: 0.55rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: #ffe135; background: rgba(0, 0, 0, 0.55);
}
.tw-pc__line {
  position: absolute; left: 0; right: 0; bottom: 0; margin: 0; padding: 0.3rem 0.5rem;
  font-size: 0.7rem; line-height: 1.3; color: #fffdf5; background: rgba(0, 0, 0, 0.62);
  text-align: center;
}
.tw-pc.is-big { margin: 0.1rem 0 0.4rem; }

/* ---- the sheet: three places, eight lines ------------------------------------------------------ */
.tw-post__make { display: grid; gap: 0.35rem; }
/* ⚠️ A ROW, NOT A GRID, and the same reason the dressing room's rails are: 261 px holds three
   thumbnails across and nothing else, so a fourth template would have to scroll rather than wrap. */
.tw-pc__row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.3rem; }
.tw-pc__pick {
  appearance: none; padding: 0; border: 2px solid #000; background: #241811; cursor: pointer;
  line-height: 0;
}
.tw-pc__pick img { display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: cover; image-rendering: pixelated; }
.tw-pc__pick.is-on { border-color: #ffb347; box-shadow: 0 0 0 2px #ffb347; }
/* the deck: every line the world has, one tap each. ⚠️ it scrolls on a phone and the mask says so —
   the same fade the dressing room's rails use, so "there is more" reads the same way twice. */
.tw-pc__deck {
  display: grid; gap: 0.18rem; max-height: 132px; overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: #ffd21f rgba(0, 0, 0, 0.34);
  -webkit-mask-image: linear-gradient(#000 0 calc(100% - 16px), rgba(0, 0, 0, 0.15) 100%);
  mask-image: linear-gradient(#000 0 calc(100% - 16px), rgba(0, 0, 0, 0.15) 100%);
}
.tw-pc__deck::-webkit-scrollbar { width: 8px; }
.tw-pc__deck::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.34); border-radius: 999px; }
.tw-pc__deck::-webkit-scrollbar-thumb { background: #ffd21f; border: 1px solid #1a1408; border-radius: 999px; }
.tw-pc__say {
  appearance: none; text-align: left; font: inherit; font-size: 0.74rem; line-height: 1.3;
  padding: 0.3rem 0.45rem; border: 2px solid #3a2718; background: #1f150e; color: #fffdf5; cursor: pointer;
}
.tw-pc__say.is-on { border-color: #ffb347; background: #2f2013; color: #ffd98a; }

/* ---- two ways to answer -------------------------------------------------------------------- */
/* ⚠️ buttons in this world never line-break, so two side by side get equal thirds of the row and the
   longer label ellipses rather than wrapping the card open. */
.tw-post__two { display: grid; grid-template-columns: 1fr 1fr; gap: 0.3rem; }
.tw-post__two .tw-btn--in { width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- a postcard in the box --------------------------------------------------------------------- */
.tw-post__pcrow {
  appearance: none; display: flex; align-items: center; gap: 0.5rem; width: 100%;
  padding: 0.3rem; border: 2px solid #3a2718; background: #1f150e; color: #fffdf5; cursor: pointer;
  text-align: left;
}
.tw-post__pcrow.is-new { border-color: #ffb347; }
.tw-post__pcthumb { flex: none; width: 62px; aspect-ratio: 3 / 2; object-fit: cover; border: 2px solid #000; image-rendering: pixelated; }

/* ---- 📇 THE ADDRESS BOOK -------------------------------------------------------------------- */
/* ⭐ THE ANSWER TO THE FIRST LETTER (Trym, 21 Sep). The rail shipped reply-only, so a player with an
 * empty box could not write to anybody at all — and no page in this world held another player's
 * address. This is the book: everyone with a Pass and a Homestead who still plays, searchable, with
 * "a small profile image of the actual users' banana with their name and Homestead-name".
 *
 * ⚠️ 261 px wide like everything else on this card, so a row is a 44-px face, a name and a house —
 * and the house is CLIPPED rather than wrapped, or a long one turns the book into a ladder. */
.tw-folk { display: grid; gap: 0.5rem; min-width: 0; }
.tw-folk__find {
  appearance: none; font: inherit; font-size: 16px;   /* ⚠️ 16px or iOS zooms the whole page on focus */
  width: 100%; box-sizing: border-box; padding: 0.42rem 0.55rem; min-height: 44px;
  background: #fbf3dd; color: #241c0e; border: 3px solid #000; box-shadow: 3px 3px 0 #000;
}
.tw-folk__find::placeholder { color: #241c0e; opacity: 0.55; }
/* the list scrolls inside the card, never the card inside the page — and it wears the world's own
   bar, the same gold thumb the deck above it uses */
.tw-folk__stack {
  /* ⚠️ MEASURED, not guessed: at 46vh the card came to 448 px inside a 445 px frame on a 360×640
     phone and the Go back button sat 3 px BELOW the fold — a control that works and is never on
     screen, which is the trap this house has been caught by before. 38vh leaves real room. */
  display: grid; gap: 0.35rem; max-height: min(38vh, 264px); overflow-y: auto; overflow-x: hidden;
  overscroll-behavior: contain; -webkit-overflow-scrolling: touch; padding-right: 4px;
  scrollbar-width: thin; scrollbar-color: #ffd21f rgba(0, 0, 0, 0.34);
}
.tw-folk__stack::-webkit-scrollbar { width: 8px; }
.tw-folk__stack::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.34); border-radius: 999px; }
.tw-folk__stack::-webkit-scrollbar-thumb { background: #ffd21f; border: 1px solid #1a1408; border-radius: 999px; }
.tw-folk__row {
  appearance: none; text-align: left; cursor: pointer; width: 100%; font: inherit;
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 0.5rem;
  padding: 0.3rem 0.5rem; min-height: 48px;
  background: #fbf3dd; color: #241c0e; border: 3px solid #000; box-shadow: 3px 3px 0 #000;
}
.tw-folk__row:active { transform: translate(1px, 1px); box-shadow: 2px 2px 0 #000; }
/* the face: the canvas is 150 square and the banana stands in the middle of it, so the box crops in
   rather than scaling the whole sprite down to a smudge */
.tw-folk__pic { display: block; width: 40px; height: 40px; overflow: hidden; position: relative; }
.tw-folk__pic canvas {
  position: absolute; width: 150%; height: 150%; left: -25%; top: -18%;
  image-rendering: pixelated;
}
.tw-folk__who { display: grid; gap: 1px; min-width: 0; }
/* 🔤 A PLAYER'S NAME IS ISOLATED WHEREVER IT IS SHOWN. src/lib/player-name.js strips the bidi
   OVERRIDES, which stops a name reordering the row it sits in — but a genuinely right-to-left name
   (Arabic, Hebrew) still drags neighbouring punctuation around without this. Both halves are
   needed, and this half belongs to the surface. Trym, 21 Sep: “fallback font is fine, let them
   render” — so they do, and they render in their own direction without disturbing the card. */
.tw-folk__who b, .tw-folk__who small, .tw-post__who { unicode-bidi: isolate; }
.tw-folk__who b { font-family: "Archivo Black", sans-serif; font-size: 0.74rem; letter-spacing: 0.02em; }
.tw-folk__who small {
  font-size: 0.7rem; opacity: 0.75;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* the way out of the mailbox: a full-width action under the post, never a chip beside it */
.tw-post__write { margin-top: 0.2rem; }
