/* Tobin — warm paper, ink, one accent. The palette is lifted from the portrait
   so the drawing sits on the page rather than on top of it. */

:root {
  --paper: #f7f2e6;
  --paper-deep: #efe8d8;
  --ink: #2a2724;
  --ink-soft: #6b6459;
  --rule: #d9d0bc;
  --accent: #9c4a2f;      /* terracotta — used sparingly, for links and marks */
  --ink-mid: #5c5449;     /* between ink and ink-soft: headline weight without the weight */
  --ink-light: #857c6e;   /* a step past ink-soft — for large display type over the drawing */
  --measure: 34rem;       /* reading width */
}

/* Shantell Sans — ArrowType / Shantell Martin, SIL Open Font License 1.1.
   Licence text ships beside the font at /fonts/OFL.txt, as the OFL requires.
   Self-hosted, unmodified (subsetting would count as modification, and the
   family name is Reserved, so we serve it whole).

   One variable file covers every weight plus three expressive axes. Measured
   ranges from its own fvar table, not guessed:
     wght 300..800   ital 0..1   INFM 0..100   BNCE -100..100   SPAC 0..100
   BNCE is the bounce — baseline jitter, the thing that makes it feel drawn.

   DISPLAY ONLY. It carries Tobin's voice in headings and rhymes with the line
   drawing, but it is a marker face: three long essays set in it would be a
   chore. Prose stays in the serif. font-display:swap so text paints in the
   fallback immediately — 710 KB must never hold up a sentence. */
@font-face {
  font-family: 'Shantell Sans';
  src: url('/fonts/ShantellSans.woff2') format('woff2-variations');
  font-weight: 300 800;
  font-style: normal;
  font-display: swap;
}

:root {
  --display: 'Shantell Sans', 'Bradley Hand', 'Segoe Print', var(--serif);
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 17px/1.65 var(--serif);
}

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }

h1, h2, h3 { line-height: 1.2; font-weight: 600; letter-spacing: -0.01em; }
/* Headings and the wordmark in Tobin's hand; a hair of bounce so it reads as
   drawn rather than as a font that happens to be casual. */
h1, h2, .wordmark {
  font-family: var(--display);
  font-variation-settings: 'BNCE' 8, 'INFM' 12, 'SPAC' 0;
  letter-spacing: 0;
}
h1 { font-size: 2.1rem; margin: 0 0 .4rem; }
h2 { font-size: 1.35rem; margin: 2.5rem 0 .6rem; }
h3 { font-size: 1.1rem; margin: 0 0 .2rem; }

code, pre {
  font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
  font-size: .84em;
}
pre {
  background: var(--paper-deep);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: .8rem 1rem;
  overflow-x: auto;
}
code { color: var(--ink-soft); }
pre code { color: var(--ink); }

.muted { color: var(--ink-soft); }
.lede { font-size: 1.12rem; color: var(--ink-soft); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* ---------------------------------------------------------------- chrome */

header.site {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1.5rem; flex-wrap: wrap;
  max-width: 62rem; margin: 0 auto; padding: 1.6rem 1.5rem 1.2rem;
  border-bottom: 1px solid var(--rule);
}
.wordmark {
  /* 1.4rem × 1.5. Uppercased in CSS rather than in the markup, so the link's
     accessible name and the page title stay "Tobin" — a screen reader should
     not have to spell it out. */
  font-size: 2.1rem; font-weight: 600;
  text-transform: uppercase;
  /* Uppercase needs more room than mixed case at the same tracking; .02em that
     read as tight-but-fine on "Tobin" reads as cramped on "TOBIN". */
  letter-spacing: .05em;
  color: var(--ink); text-decoration: none;
}
header.site nav { display: flex; gap: 1.25rem; flex-wrap: wrap; }
header.site nav a {
  color: var(--ink-soft); text-decoration: none; font-size: .95rem;
}
header.site nav a:hover { color: var(--accent); }
header.site nav a[aria-current="page"] {
  color: var(--ink); border-bottom: 1px solid var(--accent);
}

main { max-width: 62rem; margin: 0 auto; padding: 2.2rem 1.5rem 3rem; }
main > h1, main > .lede, main > p, main > form, main > ul, main > .failure,
main > .answer, main > section > h1 { max-width: var(--measure); }

footer.site {
  border-top: 1px solid var(--rule);
  max-width: 62rem; margin: 0 auto; padding: 1.5rem 1.5rem 3rem;
}
/* Full container width, not the 34rem reading measure. The measure exists to
   keep long-form prose readable; the footer is a single note, and confining it
   left a short column dangling under a page whose header, masthead and columns
   all run the full width. */
footer.site p { max-width: none; font-size: .9rem; color: var(--ink-soft); margin: 0; }

/* ---------------------------------------------------------------- masthead */

/* The drawing is the header's background and the words sit on it. The image
   FADES rather than being covered: a mask takes it to real transparency toward
   the bottom, so the paper shows through instead of a band of near-matching
   colour sitting on top — which never quite matches, and shows as a seam the
   moment the palette shifts. */
.masthead {
  position: relative;
  display: flex;
  align-items: flex-end;          /* words at the bottom, per the drawing's weight */
  min-height: clamp(19rem, 33vw, 27rem);
  margin-bottom: 1rem;
  isolation: isolate;             /* keep the blend off everything behind it */
}
.masthead-art {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* Face high and right of centre in the source; this keeps him in frame as the
     band gets shorter on narrow screens. */
  object-position: 55% 12%;
  /* The art is drawn on its own cream ground — multiply drops it onto the page
     instead of sitting on it as a rectangle. */
  mix-blend-mode: multiply;
  /* Vertical fade only. I had also feathered the left/right edges to kill the
     faint rectangle the cream ground leaves under multiply — but that washed the
     warmth out of the whole band, which was the best thing about it. The soft
     box edge is the price of the colour, and the colour is worth more. */
  -webkit-mask-image: linear-gradient(to bottom,
    #000 0%, #000 44%, rgba(0,0,0,.55) 68%, rgba(0,0,0,.12) 85%, transparent 97%);
  mask-image: linear-gradient(to bottom,
    #000 0%, #000 44%, rgba(0,0,0,.55) 68%, rgba(0,0,0,.12) 85%, transparent 97%);
  z-index: 0;
  pointer-events: none;
}
.masthead-text {
  position: relative;
  z-index: 1;
  width: 100%;
  padding-bottom: .25rem;
}
.masthead-text h1 {
  /* clamp(2rem, 4.4vw, 3.1rem) originally; -30%, then -20% again.
     Net 0.56x — keep the factors visible so the next adjustment starts from
     the real baseline rather than from whatever the last number happened to be. */
  font-size: clamp(1.12rem, 2.46vw, 1.74rem);
  max-width: none;
  margin-bottom: 0;
  text-align: center;
  /* Uppercased in CSS, not in the markup: the DOM keeps sentence case, so a
     screen reader says the line normally instead of spelling it, and the text
     stays quotable if it is ever reused. Matches the TOBIN wordmark above it.
     The tracking is the part that isn't optional — caps set at a display face's
     lowercase spacing run together, and this face is a marker with its own
     bounce, so it needs more air than a text face would. */
  text-transform: uppercase;
  letter-spacing: .06em;
  /* Lighter than body headings in BOTH senses, because it sits ON the drawing
     and near-black type at heading weight fights the fine grey linework. The
     display face is variable (300–800), so dropping to 450 thins the strokes to
     something closer to the drawing's own line, and --ink-light takes the colour
     a step past --ink-soft.

     NOTE: 450 was chosen when this was set at 2–3.1rem, and that size WAS the
     legibility argument — it is now 1.12–1.74rem, a bit over half. Caps and the
     added tracking buy some of it back, but a light grey at 450 over grey
     linework is now the thinnest this has been. Kept because the size was asked
     for and the weight was not; 500 is the first move if it reads faint. */
  font-weight: 450;
  color: var(--ink-light);
}
/* ---------------------------------------------------------------- home */

.section-head { max-width: var(--measure); margin-bottom: .9rem; }
.section-head h2 { margin-top: 0; }
.section-head p { margin: .1rem 0 0; font-size: .95rem; }

section { margin-top: 3rem; }
section:first-of-type { margin-top: 0; }

/* Front page: the drawing and the line under it run the full width; everything
   below splits into two columns — writing on the left, tonight's card and the
   invitation to ask on the right. */
.home-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 24rem);
  gap: 2rem 3.5rem;
  align-items: start;
  margin-top: 2.6rem;
}
.home-grid > * { margin-top: 0; }
.home-right { display: flex; flex-direction: column; gap: 2.4rem; }
.home-right section { margin-top: 0; }
/* Inside a column the reading measure is the column, not 34rem. */
.home-grid .section-head,
.home-grid ul.pieces,
.home-grid .lead-piece,
.home-grid .ask-teaser,
.home-grid .card-embed { max-width: none; }

/* Page header: the portrait as a round crop beside the title. One asset, cropped
   to the face with object-position rather than a second export. */
.page-head {
  display: flex; align-items: center; gap: 1.25rem;
  margin-bottom: 1.8rem;
}
.page-head .avatar {
  /* A round crop of the ONE portrait, zoomed to the head. object-fit can only
     letterbox or fill — it cannot zoom in — so the source is scaled up inside an
     overflow-hidden circle and nudged into place. The numbers are derived from
     the drawing: the head sits around x=535, y=165 of a 1024x559 image, and
     --avatar-zoom is the displayed width of the whole picture, so the ~210px-wide
     head lands at circle size. Tunable in one place, and no CSS url() — the src
     stays server-rendered so it keeps its cache-busting version. */
  --avatar: 84px;
  --avatar-zoom: 420px;
  flex: 0 0 auto;
  display: block; overflow: hidden;
  width: var(--avatar); height: var(--avatar);
  border-radius: 50%;
  background: var(--paper-deep);
  mix-blend-mode: multiply;
}
.page-head .avatar img {
  display: block;
  width: var(--avatar-zoom); height: auto;
  margin-left: calc(var(--avatar-zoom) * -0.423);
  margin-top: calc(var(--avatar-zoom) * -0.081);
}
.page-head-text { min-width: 0; }
.page-head-text h1 { margin-bottom: .25rem; }
.page-head-text .lede { margin: 0; max-width: 42rem; }

.writing-list .lead-piece { max-width: var(--measure); margin-bottom: 1.4rem; }
.writing-list .lead-piece h3 { font-size: 1.3rem; }
.writing-list .lead-piece p { margin: .25rem 0; }

ul.pieces { list-style: none; padding: 0; margin: 0; max-width: var(--measure); }
ul.pieces li {
  padding: .7rem 0; border-top: 1px solid var(--rule);
  display: flex; flex-direction: column; gap: .15rem;
}
ul.pieces a { text-decoration: none; font-size: 1.05rem; }
ul.pieces a:hover { text-decoration: underline; }
ul.pieces .muted { font-size: .92rem; }
ul.pieces .date { font-size: .85rem; }

.ask-teaser { border-top: 1px solid var(--rule); padding-top: 1.5rem; max-width: var(--measure); }

/* ---------------------------------------------------------------- cards */

.card-embed { margin: 0; max-width: 34rem; }
.card-embed iframe {
  width: 100%; border: 1px solid var(--rule); border-radius: 8px;
  background: #fff; display: block;
  transition: height .18s ease;
}
.card-embed figcaption {
  margin-top: .5rem; font-size: .85rem; color: var(--ink-soft); line-height: 1.5;
}
.card-embed--empty .placeholder {
  border: 1px dashed var(--rule); border-radius: 8px;
  padding: 1.2rem 1.3rem; background: var(--paper-deep);
}
.card-embed--empty p { margin: 0 0 .6rem; font-size: .92rem; color: var(--ink-soft); }
.card-embed--empty p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- article */

.piece { max-width: var(--measure); }
.piece .dek { font-size: 1.1rem; color: var(--ink-soft); margin: 0 0 .3rem; }
.piece p { margin: 1.1rem 0; }
.sidebar {
  margin-top: 2.5rem; padding: 1.1rem 1.3rem;
  background: var(--paper-deep); border-left: 3px solid var(--accent); border-radius: 0 6px 6px 0;
}
.sidebar h2 { margin: 0 0 .4rem; font-size: 1rem; }
.sidebar p { margin: 0; font-size: .95rem; }

/* ---------------------------------------------------------------- forms */

/* The ask boxes are textareas — a question about dinner is sometimes a
   sentence and sometimes a paragraph, and a single line made the longer one
   scroll sideways as you typed it. `align-items: flex-start` keeps the button
   its own height instead of stretching down the growing box. */
form.ask { display: flex; gap: .6rem; margin: 1.4rem 0 1rem; max-width: var(--measure);
           align-items: flex-start; }
form.ask textarea {
  flex: 1; min-width: 0;
  padding: .6rem .8rem; font: inherit; font-size: .98rem; line-height: 1.45;
  background: #fff; color: var(--ink);
  border: 1px solid var(--rule); border-radius: 5px;
  /* Vertical only: a horizontal drag would break the column it sits in. */
  resize: vertical; min-height: 3.4rem;
}
form.ask textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
form.ask button {
  padding: .6rem 1.2rem; font: inherit; font-size: .95rem; cursor: pointer;
  background: var(--ink); color: var(--paper);
  border: 1px solid var(--ink); border-radius: 5px;
}
form.ask button:hover { background: var(--accent); border-color: var(--accent); }


ul.suggestions { list-style: none; padding: 0; margin: 0 0 1rem; max-width: var(--measure);
  display: flex; flex-wrap: wrap; gap: .5rem; }
ul.suggestions a {
  display: inline-block; padding: .28rem .7rem; font-size: .86rem;
  border: 1px solid var(--rule); border-radius: 999px;
  text-decoration: none; color: var(--ink-soft); background: var(--paper-deep);
}
ul.suggestions a:hover { color: var(--accent); border-color: var(--accent); }

/* ---------------------------------------------------------------- answers */

.answer { max-width: var(--measure); margin-top: 2rem; }
.answer h2 { margin-top: 0; }
.answer-body p { margin: .8rem 0; }
.provenance {
  margin-top: 1.4rem; padding-top: .8rem; border-top: 1px solid var(--rule);
  font-size: .85rem; color: var(--ink-soft);
}
.station-link { white-space: nowrap; }

.failure {
  max-width: var(--measure); margin: 1.2rem 0;
  padding: .9rem 1.1rem; border-left: 3px solid var(--accent);
  background: var(--paper-deep); border-radius: 0 6px 6px 0;
}
.failure p { margin: 0; }
.failure .debug { margin-top: .5rem; font-size: .82rem; color: var(--ink-soft); }

/* ---------------------------------------------------------------- narrow */

@media (max-width: 860px) {
  .home-grid { grid-template-columns: minmax(0, 1fr); gap: 2.6rem; }
  .home-grid .card-embed { max-width: 34rem; }
}

@media (max-width: 640px) {
  body { font-size: 16px; }
  .page-head { gap: 1rem; }
  .page-head .avatar { --avatar: 60px; --avatar-zoom: 300px; }
  h1 { font-size: 1.8rem; }
  /* STACK on a phone: drawing above, words below.
     
     The overlay works on a wide screen because the band is tall enough to have
     empty drawing beneath the face. Narrow, the image is scaled to the band's
     height and the whole figure fits inside it — so the words, anchored to the
     bottom, land across Tobin's face. Measured at 386px: a 256px band filled
     edge to edge by the art, with the headline sitting 85-158px into it.
     
     Shrinking the type or nudging object-position only moves the collision
     around; there is no arrangement where both a legible headline and a face
     fit in 256px. So the art becomes a block band and the text flows under it.
     The mask still fades its lower edge into the paper, so it reads as the same
     drawing rather than a photo in a box. */
  .masthead { display: block; min-height: 0; }
  .masthead-art { position: relative; height: 14rem; }
  .masthead-text { padding-top: .6rem; padding-bottom: 0; }
  .masthead-text h1 { font-size: 1.06rem; }   /* 1.9rem originally; -30%, then -20% */
  form.ask { flex-direction: column; align-items: stretch; }
  header.site { padding-bottom: .9rem; }
}

/* The portrait is drawn on cream; in dark mode we keep the page light rather
   than invert a hand-drawn ground into mud. A deliberate single-theme site. */
@media (prefers-color-scheme: dark) {
  :root { color-scheme: light; }
}

/* Dish results — Tobin's own markup, built from aveq data rather than from an
   aveq card. The contrast with the embedded card on the front page is the whole
   demonstration: same mesh, two very different ways to put it on a page. */
ul.dishes { list-style: none; padding: 0; margin: 1.2rem 0 0; max-width: var(--measure); }
ul.dishes li { padding: 1rem 0; border-top: 1px solid var(--rule); }
.dish-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.dish-head h3 { margin: 0; font-size: 1.1rem; }
.dish-head .price { font-size: .95rem; color: var(--ink-soft); white-space: nowrap; }
ul.dishes p { margin: .25rem 0 0; font-size: .93rem; }
a.order { text-decoration: none; font-size: .93rem; }
a.order:hover { text-decoration: underline; }
/* Nutrition page: dietary labels and the two detail links.
   Only TRUE flags become chips (see dietaryLabels) — a row of grey "not vegan"
   would bury the one label that matters. `contains` is a warning and reads
   differently from the reassuring ones on purpose. */
.badges { display: flex; flex-wrap: wrap; gap: .35rem; margin: .4rem 0 0; }
.badge {
  font-size: .72rem; letter-spacing: .02em; padding: .12rem .45rem;
  border-radius: 10px; border: 1px solid var(--rule); white-space: nowrap;
}
.badge--diet { border-color: var(--accent); color: var(--accent); }
.badge--contains { color: var(--ink-soft); font-style: italic; }
.badge--cal { color: var(--ink-soft); }
ul.dishes p.dish-links, .dish-detail p.dish-links { margin-top: .5rem; font-size: .93rem; }
p.dish-links .sep { color: var(--ink-soft); margin: 0 .35rem; }
/* The year/month index. One row per year so a second year stays scannable —
   a flat run of months gives no anchor for which December you are looking at. */
.archive-index { margin: 1.1rem 0 .4rem; max-width: var(--measure); }
.archive-year { display: flex; align-items: baseline; gap: .7rem; padding: .2rem 0; }
.archive-year .year {
  font-size: .78rem; letter-spacing: .06em; color: var(--ink-soft);
  min-width: 2.6rem; font-variant-numeric: tabular-nums;
}
.archive-year ul {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-wrap: wrap; gap: .1rem .55rem;
}
.archive-year li { font-size: .88rem; }
/* The current month is not a link — a link to where you already are is a lie
   about what clicking does. */
.archive-year .here { color: var(--ink); font-weight: 600; }

/* Previous / next. Older is LEFT, which is the direction a reader expects
   backwards to be, and the opposite of its position in the newest-first list. */
.archive-nav {
  display: flex; justify-content: space-between; gap: 1rem;
  margin-top: 1.4rem; padding-top: .8rem;
  border-top: 1px solid var(--rule); max-width: var(--measure);
  font-size: .93rem;
}
.archive-nav .next { margin-left: auto; }

/* The archive's month headings. Quieter than a page title — they are
   signposts in a list, not sections anyone came for. */
.archive-month { margin-top: 1.6rem; }
.archive-month > h2 {
  font-size: .82rem; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-soft); font-weight: 600;
  margin: 0 0 .2rem; padding-bottom: .3rem;
  border-bottom: 1px solid var(--rule); max-width: var(--measure);
}
.archive-month:first-of-type { margin-top: .8rem; }
.archive-month ul.pieces { margin-top: 0; }

.dish-detail { max-width: var(--measure); }
/* The dish, before the words about it. Capped by height rather than width so a
   portrait and a landscape photo occupy the same band and the text below does
   not jump as you move between the two detail pages. `onerror` removes the
   whole figure — a dish whose picture was never generated should read as having
   no photo, not as a broken one. */
figure.dish-photo { margin: .9rem 0 1.1rem; }
figure.dish-photo img {
  display: block; width: 100%; max-height: 20rem;
  object-fit: cover; border-radius: 6px;
}
.dish-detail h1 { margin-bottom: .2rem; }

/* Today's service, under the address. Smaller than the address because it
   answers a narrower question — not where, just whether tonight works. */
ul.dishes p.hours { font-size: .85rem; }

/* The booking form. Collapsed to one line until asked for, so a list of ten
   dishes still reads as a list and not as ten forms. */
details.reserve { margin-top: .25rem; }
details.reserve summary {
  font-size: .93rem; color: var(--accent); cursor: pointer;
  list-style: none; display: inline-block;
}
details.reserve summary::-webkit-details-marker { display: none; }
details.reserve summary:hover { text-decoration: underline; }
details.reserve form {
  display: flex; flex-wrap: wrap; gap: .6rem; align-items: flex-end;
  margin-top: .6rem; padding: .7rem .8rem;
  border: 1px solid var(--rule); border-radius: 6px;
}
details.reserve label {
  display: flex; flex-direction: column; gap: .2rem;
  font-size: .78rem; color: var(--ink-soft);
}
details.reserve input {
  font: inherit; font-size: .9rem; padding: .3rem .45rem;
  border: 1px solid var(--rule); border-radius: 4px; background: transparent;
  color: inherit;
}
details.reserve input[type="number"] { width: 4.5rem; }
details.reserve input[type="text"] { width: 11rem; }
details.reserve button {
  font: inherit; font-size: .85rem; font-weight: 600;
  padding: .35rem .9rem; border-radius: 14px; cursor: pointer;
  border: 1px solid var(--accent); background: transparent;
  color: var(--accent);
}
details.reserve button:hover { background: var(--accent); color: #fff; }

/* The outcome page. Deliberately plain — it is one fact and a way back. */
.reserve-outcome { max-width: var(--measure); }
.reserve-outcome .confirmation p { margin: .6rem 0; }
.reserve-outcome .failure-text { font-size: 1.05rem; }
ul.prose-list { margin: .5rem 0; padding-left: 1.1rem; }
ul.prose-list li { font-size: .93rem; margin: .15rem 0; }

@media (max-width: 640px) {
  /* Stack the fields rather than letting them wrap into ragged rows. */
  details.reserve form { flex-direction: column; align-items: stretch; }
  details.reserve input[type="text"],
  details.reserve input[type="number"] { width: 100%; }
}
.trace { font-style: italic; }

/* The rotating question. Set in Tobin's hand because it IS someone speaking —
   a different one each visit, so the page never opens the same way twice. */
.ask-teaser .asked { margin: .6rem 0 .5rem; }
.ask-teaser .asked a {
  font-family: var(--display);
  font-variation-settings: 'BNCE' 14, 'INFM' 20, 'SPAC' 0;
  font-size: 1.15rem; line-height: 1.4;
  text-decoration: none; color: var(--ink);
  border-bottom: 2px solid var(--accent);
}
.ask-teaser .asked a:hover { color: var(--accent); }
.ask-teaser p.muted { font-size: .9rem; margin: 0; }



/* Tonight's dish, built to the same shape as the aveq card below it.
   Deliberately parallel: the two sections carry the same kind of content from
   the same mesh by two different routes, and giving them the same silhouette
   makes that the comparison rather than a styling accident. What differs is
   what's IN the frame — this one Tobin assembled from REST data, the other aveq
   drew itself. */
figure.tonight {
  margin: 0;
  background: #fff;
  border: 1px solid var(--rule);
  border-radius: 8px;
  overflow: hidden;               /* clips the image to the rounded corners */
}
/* aspect-ratio reserves the space so the card doesn't jump when the lazy image
   arrives. If one ever 404s the img removes itself (onerror) rather than leaving
   that reserved space blank — the same thing aveq's own dish card does. */
figure.tonight img {
  width: 100%; height: auto; display: block;
  aspect-ratio: 4 / 3; object-fit: cover;
}
figure.tonight figcaption { padding: .85rem 1rem 1rem; }
figure.tonight h3 { font-size: 1.1rem; margin: 0 0 .1rem; }
figure.tonight .price { font-size: .95rem; color: var(--ink-soft); margin: 0 0 .5rem; }
figure.tonight p { margin: 0 0 .5rem; font-size: .92rem; line-height: 1.5; }
figure.tonight .where { font-size: .9rem; margin: 0 0 .8rem; }
figure.tonight .where .muted { display: block; font-size: .82rem; }
/* The pill echoes the card's own Order button — same affordance, same weight,
   so a reader reads them as siblings. */
figure.tonight .card-action {
  display: inline-block;
  font-size: .8rem; font-weight: 700;
  padding: .3rem .85rem;
  border: 1px solid var(--accent); border-radius: 14px;
  color: var(--accent); text-decoration: none;
}
figure.tonight .card-action:hover { background: var(--accent); color: var(--paper); }

/* ---------------------------------------------------------------- thinking */

/* Shown while a slow answer is in flight. Deliberately quiet: three dots and a
   line of copy that changes as the wait goes on, because a spinner that hasn't
   moved in twenty seconds reads as broken. */
.thinking {
  max-width: var(--measure);
  margin: 2rem 0;
  padding: 1.4rem 0;
  border-top: 1px solid var(--rule);
}
.thinking .dots { display: flex; gap: .4rem; margin-bottom: .8rem; }
.thinking .dots i {
  width: .5rem; height: .5rem; border-radius: 50%;
  background: var(--accent); opacity: .25;
  animation: simmer 1.4s ease-in-out infinite;
}
.thinking .dots i:nth-child(2) { animation-delay: .18s; }
.thinking .dots i:nth-child(3) { animation-delay: .36s; }
.thinking-line {
  margin: 0; color: var(--ink-soft);
  font-family: var(--display);
  font-variation-settings: 'BNCE' 10, 'INFM' 16;
  font-size: 1.05rem;
}
@keyframes simmer {
  0%, 100% { opacity: .25; transform: translateY(0); }
  40%      { opacity: 1;   transform: translateY(-3px); }
}
/* Someone who has asked not to see motion still gets the state, just still. */
@media (prefers-reduced-motion: reduce) {
  .thinking .dots i { animation: none; opacity: .6; }
}

/* Said when the answering route could not read the question. A confident wrong
   answer is worse than an honest partial one, so this is deliberately plain. */
.caveat {
  margin: .2rem 0 .8rem;
  padding-left: .8rem;
  border-left: 2px solid var(--accent);
  color: var(--ink-soft);
  font-size: .95rem;
}

/* ------------------------------------------------- provenance disclosure */

/* A <details> styled as a popover. The panel is lifted out of the flow when
   open so the essay below it doesn't jump — a disclosure that reflows the page
   makes the reader lose their place, which is the opposite of the point.
   Without this stylesheet it degrades to an ordinary expanding block. */
.provenance-pop {
  position: relative;
  margin: 2rem 0 0;
  font-size: .9rem;
}
.provenance-pop > summary {
  cursor: pointer;
  display: inline-block;
  color: var(--ink-soft);
  border-bottom: 1px dotted var(--ink-soft);
  list-style: none;
}
.provenance-pop > summary::-webkit-details-marker { display: none; }
.provenance-pop > summary:hover,
.provenance-pop[open] > summary { color: var(--accent); border-bottom-color: var(--accent); }

.provenance-panel {
  position: absolute;
  z-index: 5;
  top: 1.9rem;
  left: 0;
  width: min(26rem, calc(100vw - 3rem));
  padding: 1rem 1.1rem;
  background: var(--paper);
  border: 1px solid var(--paper-deep);
  border-radius: 8px;
  box-shadow: 0 8px 28px rgba(42, 39, 36, .16);
}
.provenance-panel dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .3rem .9rem;
  margin: 0 0 .8rem;
}
.provenance-panel dt { color: var(--ink-soft); }
.provenance-panel dd { margin: 0; font-variant-numeric: tabular-nums; }
.provenance-panel p { margin: 0; font-size: .85rem; max-width: none; }

@media (max-width: 40rem) {
  /* No room to float on a phone; fall back to inline so it can't hang off the
     edge of the screen. */
  .provenance-panel { position: static; width: auto; margin-top: .6rem; box-shadow: none; }
}
