/* Field Notes.
   One sheet of paper under one lamp, up and to the left. The paper and the
   masthead are drawn by js/stock.js (the poem app's letterpress shader); every
   value below is set to agree with that lamp — a well is dark on its upper-left
   wall and catches light on its lower-right, and nothing on the page contradicts
   it. That agreement is the whole look; a shadow pointing the other way is the
   one thing that would break it. */

@font-face { font-family: 'FNSelecta'; src: url('../fonts/Selecta-Regular.otf') format('opentype'); font-weight: 400; font-display: block; }
@font-face { font-family: 'FNSelecta'; src: url('../fonts/Selecta-Medium.otf') format('opentype'); font-weight: 500; font-display: block; }
@font-face { font-family: 'FNMono'; src: url('../fonts/PlexMono-400.woff2') format('woff2'); font-weight: 400; font-display: block; }
@font-face { font-family: 'FNMono'; src: url('../fonts/PlexMono-500.woff2') format('woff2'); font-weight: 500; font-display: block; }

:root {
  --stock: #EFEADE;          /* must match stock.js's uStock */
  --ink: #221F1A;
  --ink-2: #5F594E;
  --ink-3: #9C9484;
  --brick: #8A452C;          /* the one accent, and it appears only as ink */
  --hair: rgba(34,31,26,.13);
  /* both are replaced at boot with the paper's own colour, read off the sheet */
  --bar-bg: #EDE8DC;
  --sheet-bg: #F1ECE0;
  --sans: 'FNSelecta', ui-sans-serif, system-ui, sans-serif;
  --mono: 'FNMono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* the lamp, expressed for CSS: dark up-left, light down-right */
  --lo: rgba(34,31,26,.20);
  --hi: rgba(255,253,247,.62);
  --deboss: -0.5px -0.5px 0.6px var(--lo), 0.7px 0.8px 0.7px var(--hi);
  --well: inset 1.5px 1.5px 2.5px rgba(34,31,26,.17), inset -1px -1.5px 1.5px rgba(255,253,247,.55);
  --lift: 1px 2px 2px -1px rgba(34,31,26,.12), 6px 14px 22px -14px rgba(34,31,26,.34);
}

* { box-sizing: border-box; }
/* An author `display` beats the hidden attribute — without this the bar and both
   overlays are permanently on screen. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }
/* The UA focus ring is a blue rounded rectangle, which is the one shape this
   app does not have. */
:focus-visible { outline: 1px solid rgba(138,69,44,.5); outline-offset: 4px; border-radius: 1px; }
:focus:not(:focus-visible) { outline: none; }
* { -webkit-tap-highlight-color: transparent; }
/* a dark scrollbar down the edge of a sheet of paper is a window frame */
* { scrollbar-color: rgba(34,31,26,.22) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(34,31,26,.18); border-radius: 9px; }
::-webkit-scrollbar-thumb:hover { background: rgba(34,31,26,.3); }
body {
  margin: 0;
  background: var(--desk, var(--stock));
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  letter-spacing: -.004em;
  -webkit-font-smoothing: antialiased;
}
/* ── the stage ────────────────────────────────────────────────────────────────
   #device is the app's world: the whole window, or an iPhone standing on a desk.
   Nothing inside reads the viewport or the document scroll — the sheet is sized
   to this box and the scroll offset comes from #scroll — which is what lets the
   framed view and a real phone be the same app rather than two layouts. */
#device {
  position: relative;
  width: 100vw;
  height: 100dvh;
  overflow: hidden;
  background: var(--stock);
}
#scroll {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
#stock { position: absolute; inset: 0; z-index: 0; display: block; }

.sheet-wrap {
  position: relative;
  z-index: 1;
  max-width: 968px;
  margin: 0 auto;
  padding: 0 28px 0;
}

/* ── the masthead ─────────────────────────────────────────────────────────────
   Drawn INTO the paper by the shader. The DOM keeps the words for anyone
   reading with something other than eyes, and holds the space open; the moment
   the press is up, `pressed` hands the pixels over to it. */
.mast { padding: 12vh 0 9vh; }
.mast h1 {
  margin: 0 0 26px;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 12px;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.mast .line {
  margin: 0;
  font-size: clamp(25px, 4.6vw, 35px);
  line-height: 1.24;
  letter-spacing: -.018em;
  /* the measure is set in the display size's own ems, because that is the type
     the drawn block is wrapped against */
  max-width: 17.5em;
}
body.pressed .mast h1, body.pressed .mast .line { visibility: hidden; }

/* ── the way in ───────────────────────────────────────────────────────────── */
.bench { margin: 0 0 14vh; }
/* The way in is the page itself, pressed empty into the sheet: the bed where the
   photograph will lie on the left, the paper and the waiting stamp on the right.
   Nothing here is a flat fill — a blank rectangle of one colour cannot sit on
   paper that is graded by a lamp, and the mismatch is the first thing you see. */
.page-in {
  display: grid;
  grid-template-rows: 58% 42%;
  width: 100%;
  /* short window: the page shrinks rather than running off the bottom */
  max-width: min(430px, calc(var(--dev-h, 900px) * 0.56 * 3 / 4));
  aspect-ratio: 3 / 4;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-align: left;
}
.in-photo {
  display: grid;
  /* a one-column grid sizes to max-content, and the label wrapped mid-phrase */
  grid-template-columns: minmax(0, 1fr);
  align-content: center;
  justify-items: center;
  gap: 9px;
  border-radius: 1px;
  box-shadow: var(--well);
  transition: box-shadow .4s ease;
}
.page-in:hover .in-photo,
body.dragging .in-photo { box-shadow: inset 2.5px 2.5px 5px rgba(34,31,26,.2), inset -1px -2px 2px rgba(255,253,247,.6); }
.in-say {
  max-width: 24ch;
  padding: 0 6%;
  text-align: center;
  font-size: clamp(15px, 2vw, 17px);
  letter-spacing: -.01em;
  color: var(--ink-2);
  text-shadow: var(--deboss);
}
/* The second line is a caption under the page, not writing inside the bed —
   at 58% of a phone the bed is 220px wide and the sentence ran out of both
   sides of it. */
.in-cap {
  margin: 20px 0 0;
  font-family: var(--mono);
  font-size: 10.5px;
  line-height: 1.9;
  letter-spacing: .05em;
  color: var(--ink-3);
  text-shadow: var(--deboss);
}
.in-paper {
  padding: 6% 8% 7%;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 6%;
}
.in-paper .well { height: 62%; margin: 0; }
.in-paper .record { color: var(--ink-3); }
/* once the notebook has pages, the empty one is not one of them */
body.has-pages .bench { display: none; }

.add { display: none; margin: 34px 0 0; }
body.has-pages .add { display: block; }

/* ── the pages ────────────────────────────────────────────────────────────── */
.pages { display: flex; flex-direction: column; align-items: flex-start; gap: 12vh; }
.page { width: 100%; }
/* A tall page needs a narrower column than a wide one, or one page fills the
   whole window and you cannot see it. Height leads: the width follows from the
   ratio, so a short window shrinks the page instead of cropping it. Measured
   against the DEVICE, not the window — inside a phone `dvh` is the wrong box. */
.page[data-orient="portrait"] { max-width: min(560px, calc(var(--dev-h, 900px) * 0.78 * 3 / 4)); }
.page[data-orient="landscape"] { max-width: min(968px, calc(var(--dev-h, 900px) * 0.82 * 4 / 3)); }
.page { animation: lay .7s cubic-bezier(.2,.7,.2,1) both; }
@keyframes lay { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .page { animation: none; } html { scroll-behavior: auto; } }

.plate {
  position: relative;
  /* set per page from the shape it was pressed at, so a notebook holding both
     shapes shows each one as it is */
  aspect-ratio: var(--ar, 3 / 4);
  border-radius: 1px;
}
/* A pressed page is one sheet, and it gets the shadow. An unpressed one is a
   photograph lying on the notebook, so the shadow belongs to the photograph and
   the right-hand half is the notebook's own paper — painting a flat #EFEADE
   there instead puts a grey slab next to the real, lit, grained sheet, and the
   slab is the first thing you see. */
.plate:has(.poster) { overflow: hidden; box-shadow: var(--lift); }
.plate .poster { width: 100%; height: 100%; display: block; object-fit: cover; cursor: zoom-in; }

/* the page before it is pressed: the photograph on the left, bare paper on the
   right. The same layout the press is being asked for, so the wait shows the
   page you are going to get rather than a spinner. */
.mock { position: absolute; inset: 0; display: grid; }
.page[data-orient="landscape"] .mock { grid-template-columns: 58% 42%; }
/* portrait: the photograph above, the paper below — the stamp and the record
   side by side in a band that is wide and short */
.page[data-orient="portrait"] .mock { grid-template-rows: 58% 42%; }
.page[data-orient="portrait"] .mock-paper {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 6%;
  padding: 6% 8% 7%;
}
.page[data-orient="portrait"] .well { height: 62%; margin: 0; }
.page[data-orient="portrait"] .record { align-self: end; }
.page[data-orient="portrait"] .status { grid-column: 1 / -1; margin-top: 2%; }
.mock-photo { overflow: hidden; box-shadow: var(--lift); }
.mock-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mock-paper { position: relative; padding: 9% 9% 8%; display: flex; flex-direction: column; justify-content: flex-end; }
/* where the stamp will land */
.well {
  height: 34%;
  margin-bottom: 10%;
  border-radius: 1px;
  box-shadow: inset 1px 1px 2px rgba(34,31,26,.09), inset -1px -1px 1px rgba(255,253,247,.35);
  transition: box-shadow .8s ease;
}
[data-state="printing"] .well { animation: bite 3s ease-in-out infinite; }
@keyframes bite {
  0%, 100% { box-shadow: inset 1px 1px 2px rgba(34,31,26,.14), inset -1px -1px 1px rgba(255,253,247,.5); }
  50% { box-shadow: inset 3px 3px 7px rgba(138,69,44,.34), inset -1px -2px 2px rgba(255,253,247,.62); }
}
@media (prefers-reduced-motion: reduce) { [data-state="printing"] .well { animation: none; } }

.record {
  display: grid;
  font-family: var(--mono);
  font-size: clamp(7px, .95vw, 10.5px);
  line-height: 2;
  letter-spacing: .06em;
  color: var(--ink-2);
  text-shadow: var(--deboss);
}
.record .dim { color: var(--ink-3); }

/* In the flow under the record, not floated over it: absolutely positioned at
   the foot of the paper it landed on top of the year. */
.status {
  margin-top: 7%;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brick);
}
.status.bad { text-transform: none; letter-spacing: 0; color: #7d3030; max-width: 82%; line-height: 1.5; }

/* ── the line under a page ────────────────────────────────────────────────── */
.meta {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
  padding: 18px 2px 0;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--ink-3);
}
.meta .no { color: var(--ink); letter-spacing: .12em; }
.meta .src { font-size: 10px; }
.meta .acts { margin-left: auto; display: flex; gap: 14px; align-items: baseline; }
.meta .tag { color: var(--ink-3); font-size: 10px; letter-spacing: .1em; }
.meta .chip { padding: 4px 0 5px; }

.field {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--ink);
  background: transparent;
  border: 0;
  padding: 3px 0 4px;
  box-shadow: 0 1px 0 var(--hair);
  min-width: 0;
}
.field:hover { box-shadow: 0 1px 0 rgba(34,31,26,.28); }
.field:focus { outline: none; box-shadow: 0 1px 0 var(--brick); }
.field.place { width: 24ch; }
.field.year { width: 5ch; }
.field::placeholder { color: var(--ink-3); }

/* ── things you can press ─────────────────────────────────────────────────── */
/* Ink, not a box: a word inked onto the sheet, which goes down into it when you
   press it. No fills, no borders, no rounded rectangles. */
.ink {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brick);
  background: none;
  border: 0;
  padding: 4px 0 5px;
  cursor: pointer;
  box-shadow: 0 1px 0 rgba(138,69,44,.3);
  transition: color .15s ease, box-shadow .15s ease, transform .08s ease;
}
.ink:hover { box-shadow: 0 1px 0 var(--brick); }
.ink:active { transform: translateY(.5px); color: #6f3722; }
.ink:disabled { color: var(--ink-3); box-shadow: none; cursor: default; }

.chip {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-2);
  background: none;
  border: 0;
  padding: 6px 9px;
  border-radius: 2px;
  cursor: pointer;
  text-shadow: var(--deboss);
  transition: color .15s ease, box-shadow .2s ease;
}
.chip:hover { color: var(--ink); }
.chip[aria-pressed="true"] { color: var(--ink); box-shadow: var(--well); }
.chip.quiet { color: var(--ink-3); }
.chip.quiet:hover { color: var(--ink-2); }
.seg { display: inline-flex; gap: 2px; }

/* ── the strip along the bottom ───────────────────────────────────────────────
   Paper, not glass: a torn strip of the same stock lying over the sheet, lit by
   the same lamp. A blurred translucent bar is the one thing that would announce
   this as an app. */
.bar {
  position: sticky;
  bottom: 0;
  z-index: 4;
  margin-top: 12vh;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 14px max(20px, calc(50% - 484px)) calc(14px + env(safe-area-inset-bottom));
  background: var(--bar-bg);
  box-shadow: 0 -1px 0 rgba(255,253,247,.45), 0 -14px 30px -20px rgba(34,31,26,.55);
}
.bar .count {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-shadow: var(--deboss);
}
.bar-acts { margin-left: auto; display: flex; align-items: center; gap: 20px; }
.ink.press { font-size: 11.5px; }

/* ── the foot ─────────────────────────────────────────────────────────────── */
.foot { margin: 16vh 0 0; padding-top: 26px; box-shadow: 0 -1px 0 var(--hair); }
.foot-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.foot-note {
  margin: 22px 0 0;
  max-width: 68ch;
  font-family: var(--mono);
  font-size: 10.5px;
  line-height: 2;
  letter-spacing: .02em;
  color: var(--ink-3);
}
.foot-note a, .credit a { color: var(--brick); text-decoration: none; box-shadow: 0 1px 0 rgba(138,69,44,.3); }
.foot-note em { font-style: normal; color: var(--ink-2); }

/* ── overlays ─────────────────────────────────────────────────────────────── */
.overlay {
  position: absolute; inset: 0; z-index: 20;
  background: rgba(26,24,20,.62);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  animation: fade .25s ease both;
}
@keyframes fade { from { opacity: 0 } to { opacity: 1 } }
.overlay .card {
  background: var(--sheet-bg);
  max-width: 720px; width: 100%; max-height: 84vh;
  display: flex; flex-direction: column;
  box-shadow: 0 40px 80px -30px rgba(0,0,0,.6);
}
.card-head { display: flex; align-items: center; gap: 12px; padding: 16px 20px; box-shadow: 0 1px 0 var(--hair); }
.card-head .which { font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); }
.card-head .close { margin-left: auto; }
.overlay pre {
  margin: 0; padding: 22px 24px; overflow: auto;
  font-family: var(--mono); font-size: 11.5px; line-height: 1.95;
  white-space: pre-wrap; color: var(--ink-2);
}
.credit { margin: 0; padding: 14px 24px 20px; box-shadow: 0 -1px 0 var(--hair); font-family: var(--mono); font-size: 10px; line-height: 1.9; color: var(--ink-3); }

.light { flex-direction: column; gap: 16px; cursor: zoom-out; }
.light img { max-width: 100%; max-height: 82vh; box-shadow: 0 40px 80px -30px rgba(0,0,0,.7); }
.light .cap { margin: 0; font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: #CFC7B6; }

/* ── the phone ────────────────────────────────────────────────────────────────
   iPhone 17 Pro, 402 × 874 logical points. Offered only where there is room and
   a real pointer — on an actual phone the app is already the phone.

   Height drives width through the aspect so a short window scales both axes
   together instead of going squat, and every measurement on the device is
   written `length × ratio`: CSS cannot divide a length by a length to get a
   number, and a `--ph-h / 874` factor silently collapses to zero. */
#view { display: none; }
@media (min-width: 780px) and (min-height: 640px) and (pointer: fine) {
  #view {
    display: block;
    position: fixed;
    right: 20px;
    bottom: 18px;
    z-index: 30;
    text-shadow: none;
  }
}
body.phone {
  --desk: #2A2723;
  display: grid;
  place-items: center;
  min-height: 100dvh;
}
body.phone #device {
  --ph-h: min(874px, 92dvh);
  width: calc(var(--ph-h) * 402 / 874);
  height: var(--ph-h);
  border-radius: calc(var(--ph-h) * 56 / 874);
  /* Two casts, not one: a tight contact shadow that says the phone is resting on
     something, and a wide ambient one that gives it height. One alone reads as a
     sticker on a dark page. */
  box-shadow:
    0 26px 50px -26px rgba(0,0,0,.6),
    0 62px 130px -30px rgba(0,0,0,.7),
    0 0 0 calc(var(--ph-h) * 11 / 874) #1b1e22,
    0 0 0 calc(var(--ph-h) * 13 / 874) #3d434b,
    0 0 0 calc(var(--ph-h) * 14 / 874) #14171a;
}
body.phone #view { color: #B7AFA0; }
body.phone #view:hover { color: #EFEADE; }
/* The sheet runs under the phone's top edge, as it would on a real one — but a
   headline sliced in half by an opaque black pill reads as a hole in the paper,
   not as a notch. So the paper's own colour fades in over the last centimetre
   and the type dissolves into it before it gets there. */
.topfade, .island, .homebar { display: none; }
body.phone .topfade {
  display: block;
  position: absolute;
  top: 0; left: 0; right: 0;
  height: calc(var(--ph-h) * 62 / 874);
  background: linear-gradient(var(--top-bg, #EFEADE) 42%, transparent);
  z-index: 20;
  pointer-events: none;
}
body.phone .island {
  display: block;
  position: absolute;
  top: calc(var(--ph-h) * 11 / 874);
  left: 50%;
  transform: translateX(-50%);
  width: calc(var(--ph-h) * 124 / 874);
  height: calc(var(--ph-h) * 35 / 874);
  border-radius: 999px;
  background: #000;
  z-index: 25;
  pointer-events: none;
}
body.phone .homebar {
  display: block;
  position: absolute;
  bottom: calc(var(--ph-h) * 9 / 874);
  left: 50%;
  transform: translateX(-50%);
  width: calc(var(--ph-h) * 140 / 874);
  height: calc(var(--ph-h) * 5 / 874);
  border-radius: 999px;
  background: rgba(34,31,26,.35);
  z-index: 25;
  pointer-events: none;
}
/* the app keeps clear of the island and the home indicator */
body.phone .mast { padding-top: calc(var(--ph-h) * 74 / 874); }
body.phone .bar { padding-bottom: calc(var(--ph-h) * 26 / 874); }
/* a phone has no scrollbar down the side of the paper */
body.phone #scroll { scrollbar-width: none; }
body.phone #scroll::-webkit-scrollbar { display: none; }

/* ── narrow ───────────────────────────────────────────────────────────────── */
@media (max-width: 680px) {
  .sheet-wrap { padding-inline: 20px; }
  .mast { padding: 11vh 0 9vh; }
  .pages { gap: 8vh; }
  .page-in { max-width: none; }
  .meta { gap: 10px; }
  .meta .acts { margin-left: 0; width: 100%; padding-top: 4px; }
  .field.place { flex: 1 1 14ch; width: auto; }
  .bar { padding-inline: 20px; gap: 10px; }
  .bar .count { width: 100%; }
  .bar-acts { margin-left: 0; width: 100%; }
}
