/* r3: the composed page is built from the brain's answer */
.card:not(.composed) .results { display: none; }
.card.composed .results { display: block; }
.results p.body { margin: 0 0 .9em; font-size: .95rem; line-height: 1.6; max-width: 62ch; }
.results ul.bullets { margin: 0 0 1em; padding-left: 1.1em; font-size: .86rem; line-height: 1.55; }
.results .stays { margin-top: .4em; }
.results .stay img { aspect-ratio: 5 / 4; }
.results .sources { margin: .2em 0 .8em; }
.results .sources .lede { margin-top: .6em; }
.results p.source { margin: 0 0 .35em; font-size: .78rem; line-height: 1.5; max-width: 64ch; }
.results p.source .label { font-size: .62rem; letter-spacing: .12em; text-transform: uppercase; margin-right: .6em; opacity: .7; }
.results p.caveat { margin: 0 0 .6em; font-size: .78rem; font-style: italic; opacity: .75; }
.results .adjust button { margin-right: 1.4em; border-bottom: 1px solid rgba(217, 210, 198, .25); padding-bottom: .1em; }
.card__ink-lit .adjust button { pointer-events: none; }

/* the substitution notice: the visitor's own address stays named, and the notice sits beside the counter instead of being
   overwritten by it — in r2 it was written and replaced inside the same tick, so it never painted a single frame */
.bar .note.swap { color: rgba(255, 200, 140, .72); letter-spacing: .04em; margin-right: .9em; }
.bar .note.swap[hidden] { display: none; }
.results p.colophon.swap { margin-top: 1em; font-size: .66rem; letter-spacing: .14em; text-transform: uppercase; opacity: .6; }

/* The composed trail is measured against the window, and the card is placed in pixels by door.js from the trail's real bottom.
   Both used to be percentages of the stage — and door.js grows the stage from the card's own height, so every answer pushed
   the card lower, which pushed the ask line under the fold and let a long question overstrike the title. */
body[data-beat="composed"] .trail { top: 4vh; }

/* The ask line pins to the window only when the answer is taller than the window, so it is never sliced by the fold.
   Pinned it rests ON the page rather than under the card, so it takes a quiet dark pill instead of a bare underline -
   the same pill the Ask button already uses - and reads as a control that came with you rather than a collision. */
.ask.pinned {
  position: fixed !important; top: auto !important; bottom: 1.7rem; left: 50%; transform: translateX(-50%);
  padding: .5rem .6rem .5rem 1.15rem; border-radius: 999px;
  border: 1px solid rgba(217, 210, 198, .14); background: rgba(14, 13, 12, .9);
  box-shadow: 0 20px 54px rgba(0, 0, 0, .58); backdrop-filter: blur(10px);
}
body[data-beat="composed"] .foot { opacity: .5; }
body.ask-pinned .card.composed .card__ink { padding-bottom: 3.4rem; }      /* the last line of the answer is not hidden under the pinned control */

/* the phone: not a mobile design, only the two measured breakages fixed — the entrance copy printing through the website
   field, and the reading counter forcing the page to scroll sideways. The Eye's placement on a phone is still an open design question. */
@media (max-width: 760px) {
  .stage { display: flex; flex-direction: column; padding: 4rem 1.1rem 6rem; }
  /* RELATIVE, not static. The card must stop being absolutely placed so it flows in the phone's column, but
     `static` also stops it being a containing block — and .card__ink-lit is `position:absolute; inset:0`.
     With the card static the lit copy resolved against .stage instead and printed the whole answer a second
     time across the trail and the foot, doubling every line. Measured on the composed page at 390px.
     `relative` flows exactly like static and keeps the copy over the card where it belongs. */
  .trail, .card { position: relative !important; left: auto !important; top: auto !important; width: auto !important; transition: none; }
  .card { order: 1; } .trail { order: 2; margin-top: 1.4rem; }
  body[data-beat="composed"] .card { order: 2; margin-top: 1.2rem; } body[data-beat="composed"] .trail { order: 1; }
  .bar { flex-wrap: wrap; row-gap: .35rem; }
  .bar .note, .bar .value { white-space: normal; overflow-wrap: anywhere; }
  .ask { position: fixed !important; top: auto !important; bottom: 1rem; left: 1rem; right: 1rem; width: auto !important; transform: none !important; }
  .hint { display: none; }
  /* the trail and the card carry an explicit order, so the foot's default of 0 put the colophon ABOVE the
     answer. It is the last thing on the page, and now says so. */
  .foot { position: static; display: block; margin-top: 2rem; order: 9; }
  .foot span { display: block; margin-bottom: .3rem; }
  .results .stays { grid-template-columns: 1fr 1fr; }
  .results p.body, .results p.source { max-width: none; }
}

/* ------------------------------------------------------------------ r4: the composed page takes the window
   A 760px column floating in a 2000px window reads as a phone screenshot. The card now spans the width and the
   TEXT keeps its own measure inside it — a wide card with a narrow column and large pictures, not wide text.
   The Eye keeps the left margin, so the composition is unchanged; it simply has more page to light. */
body[data-beat="composed"] .trail { left: 15%; width: min(80vw, 1560px); }
body[data-beat="composed"] .card { left: 15%; width: min(80vw, 1560px); }
.results p.body, .results p.source, .results p.caveat { max-width: 66ch; }
.results ul.bullets { max-width: 66ch; }

/* the pictures are the reason for the width: they fill it, and they grow with it */
.results .stays { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1.2rem; margin: 1.4em 0 1.2em; }
.results .stay img { aspect-ratio: 4 / 3; width: 100%; object-fit: cover; border-radius: 3px; cursor: zoom-in; transition: filter .35s ease, transform .35s cubic-bezier(.2,.7,.2,1); }
.results .stay img:hover { filter: brightness(1.08); transform: translateY(-2px); }
.card__ink-lit .results .stay img { cursor: default; }

/* ------------------------------------------------------------------ looking closer at one picture */
.lightbox { position: fixed; inset: 0; z-index: 20; display: none; place-items: center;
  background: rgba(8, 8, 7, .93); backdrop-filter: blur(14px); opacity: 0; transition: opacity .32s ease; }
.lightbox[data-open="1"] { display: grid; opacity: 1; }
.lightbox img { max-width: 88vw; max-height: 82vh; object-fit: contain; border-radius: 3px; box-shadow: 0 40px 120px rgba(0,0,0,.6); }
.lightbox .lb-bar { position: absolute; left: 0; right: 0; bottom: 1.6rem; display: flex; justify-content: center; gap: 2.2rem;
  font-size: .68rem; letter-spacing: .16em; text-transform: uppercase; color: rgba(217,210,198,.55); }
.lightbox .lb-bar a, .lightbox .lb-bar button { color: inherit; border-bottom: 1px solid rgba(217,210,198,.25); padding-bottom: .15em; text-decoration: none; }
.lightbox .lb-bar a:hover, .lightbox .lb-bar button:hover { color: var(--warm); border-bottom-color: rgba(217,210,198,.6); }
.lightbox .lb-count { border: 0; }
.lightbox .lb-step { position: absolute; top: 50%; transform: translateY(-50%); width: 12vw; height: 60vh; background: none; border: 0; cursor: pointer; opacity: 0; }
.lightbox .lb-prev { left: 0; } .lightbox .lb-next { right: 0; }

@media (max-width: 1100px) {
  body[data-beat="composed"] .trail, body[data-beat="composed"] .card { left: 10%; width: 84vw; }
}

/* the spread: the answer keeps its measure, its evidence sits beside it, the pictures run underneath */
.results .spread { display: block; }
.results .col-side .sources { margin-top: 0; }
@media (min-width: 1200px) {
  .results .spread { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); column-gap: 3.6rem; align-items: start; }
  .results .col-side { padding-top: 2.1rem; border-left: 1px solid rgba(217, 210, 198, .12); padding-left: 2.4rem; }
  .results .col-side:empty { border-left: 0; padding-left: 0; }
  .results p.body, .results ul.bullets, .results p.source, .results p.caveat { max-width: none; }
}
/* the pinned control rests on the page, so the page ends above it rather than under it */
body.ask-pinned .card.composed .card__ink { padding-bottom: 5.2rem; }

/* ------------------------------------------------------------------ the two voice choices
   Text, not icons: a microphone glyph would read as a dev control, and arrows and HUD marks are banned.
   Both sit quietly beside the ask line and only brighten once chosen. */
.voice-bar { position: absolute; z-index: 5; left: 50%; transform: translateX(-50%); display: flex; gap: 1.8rem; margin: 0;
  font-size: .64rem; letter-spacing: .18em; text-transform: uppercase; opacity: 0; pointer-events: none; transition: opacity .5s ease; }
body[data-beat="ask"] .voice-bar, body[data-beat="composed"] .voice-bar { opacity: 1; pointer-events: auto; }
.voice-bar button { color: rgba(217, 210, 198, .34); border-bottom: 1px solid transparent; padding-bottom: .2em; transition: color .3s ease, border-color .3s ease; }
.voice-bar button:hover:not(:disabled) { color: rgba(217, 210, 198, .7); }
.voice-bar button[data-on="1"] { color: var(--warm); border-bottom-color: rgba(255, 200, 140, .45); }
.voice-bar button:disabled { opacity: .3; cursor: default; }
.voice-bar .v-mic[data-on="1"] { animation: listening 1.9s ease-in-out infinite; }
@keyframes listening { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

/* ------------------------------------------------------------------ the controls live IN the ask line
   Listen, language and speech are things a stranger must SEE, at the height of the field they sit beside —
   not a whisper underneath it. Words and a single breathing dot; no microphone glyph, no arrows, no HUD. */
.ask-controls { display: flex; align-items: center; gap: .4rem; margin-right: .5rem; }
.ask-controls button {
  display: inline-flex; align-items: center; gap: .42rem; height: 2rem; padding: 0 .82rem;
  border: 1px solid rgba(217, 210, 198, .17); border-radius: 999px; background: rgba(217, 210, 198, .05);
  color: rgba(217, 210, 198, .62); font: inherit; font-size: .7rem; letter-spacing: .1em; text-transform: uppercase;
  cursor: pointer; white-space: nowrap; transition: color .25s ease, border-color .25s ease, background .25s ease;
}
.ask-controls button:hover:not(:disabled) { color: var(--warm); border-color: rgba(217, 210, 198, .38); background: rgba(217, 210, 198, .1); }
.ask-controls button[data-on="1"] { color: var(--warm); border-color: rgba(255, 200, 140, .5); background: rgba(255, 200, 140, .1); }
.ask-controls button:disabled { opacity: .32; cursor: default; }
.ask-controls .c-lang { min-width: 3.1rem; justify-content: center; letter-spacing: .14em; }
.ask-controls .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .55; }
.ask-controls .c-mic[data-on="1"] .dot { background: #e8674f; opacity: 1; animation: hearing 1.5s ease-in-out infinite; }
@keyframes hearing { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.65); opacity: .4; } }
.ask.pinned .ask-controls button { height: 1.85rem; }
.card__ink-lit .ask-controls { display: none; }

/* the pinned pill now carries four controls: it needs the room, or it eats the question */
.ask.pinned { width: min(860px, 92vw); padding-left: 1.4rem; }
.ask.pinned input { min-width: 0; }

/* a full set of results, not a sample: the grid keeps the tiles honest as the count grows */
.results .stays { grid-template-columns: repeat(auto-fill, minmax(clamp(190px, 15vw, 270px), 1fr)); }
.results .stays .stay:nth-child(n+7) img { aspect-ratio: 1 / 1; }
.results .count { margin: 0 0 .5em; font-size: .64rem; letter-spacing: .18em; text-transform: uppercase; opacity: .5; }

/* ------------------------------------------------------------------ results are pages, not photographs
   Each card is one thing on the site: its picture, its name, one line of what the page says about it.
   With a destination the whole card is a door; the line underneath is what a listing gives you before
   you decide to open it. Bigger tiles: four across a wide window, not twelve. */
.results .stays { grid-template-columns: repeat(auto-fill, minmax(clamp(240px, 21vw, 360px), 1fr)); gap: 1.6rem 1.4rem; }
.results .stay { display: block; position: relative; color: inherit; text-decoration: none; }
.results .stay img { aspect-ratio: 4 / 5; width: 100%; object-fit: cover; border-radius: 3px; transition: filter .4s ease, transform .4s cubic-bezier(.2,.7,.2,1); }
.results .stay.noimg img { display: none; }
.results .stay h3 { margin: .8em 0 .2em; font-weight: 500; font-size: .92rem; letter-spacing: .01em; line-height: 1.3; color: var(--warm); }
.results .stay p.note { margin: 0; font-size: .78rem; line-height: 1.5; color: rgba(217, 210, 198, .6); }
.results .stay .goes { display: block; margin-top: .45em; font-size: .6rem; letter-spacing: .18em; text-transform: uppercase; color: rgba(255, 200, 140, .0); transition: color .3s ease; }
.results .stay.linked { cursor: pointer; }
.results .stay.linked:hover img { filter: brightness(1.1); transform: translateY(-3px); }
.results .stay.linked:hover .goes { color: rgba(255, 200, 140, .75); }
.results .stay:not(.linked) img { cursor: zoom-in; }
.card__ink-lit .results .stay { pointer-events: none; }

/* four across a wide window, and a card without its own photograph still reads as a card */
.results .stays { grid-template-columns: repeat(auto-fill, minmax(clamp(220px, 17vw, 300px), 1fr)); }
.results .stay img { aspect-ratio: 3 / 4; }
.results .stay.noimg, .results .stay:not(:has(img)) { padding: .9rem 1rem; border: 1px solid rgba(217, 210, 198, .12); border-radius: 3px; }
.results .stay:not(:has(img)) h3 { margin-top: 0; }

/* the listing arrives after the answer; the wait says so rather than leaving a hole */
.results .count.waiting { opacity: .42; animation: layingout 1.7s ease-in-out infinite; }
@keyframes layingout { 0%, 100% { opacity: .42; } 50% { opacity: .18; } }

/* a card without a photograph must not stretch to the height of one that has: each stands its own height */
.results .stays { align-items: start; align-content: start; }
.results .stay:not(:has(img)) { min-height: 0; }

/* ------------------------------------------------------------------ the front door
   A prospect used to land on a bare field with somebody else's address sitting in it as a placeholder, and
   nothing on the page saying what would happen if they filled it in. The door now says it in one line and
   offers three addresses to watch it read, for anyone who arrived curious rather than prepared. */
.fine { margin: .55rem .2rem 0; max-width: 46ch; font-size: .7rem; line-height: 1.65; color: var(--ink-faint); opacity: .8; }
.fine[hidden] { display: none; }
.offer { margin: .15rem .2rem 0; font-size: .74rem; line-height: 1.8; color: var(--ink-faint); }
.offer[hidden] { display: none; }
.offer button, .refusal p.after button {
  color: rgba(217, 210, 198, .62); border-bottom: 1px solid rgba(217, 210, 198, .22); padding-bottom: .1em;
  transition: color .3s ease, border-color .3s ease;
}
.offer button:hover, .refusal p.after button:hover { color: var(--warm); border-bottom-color: rgba(255, 200, 140, .5); }

/* ------------------------------------------------------------------ a refusal is composed, not flashed
   Four different pieces of news used to arrive as one red line under the title. Each now lands in the same
   card an answer would have used, in the same voice, and says whose doing it was. */
.card.refused .results { display: block; }
.card.refused .entrance, .card.refused .colophon { display: none; }
body[data-beat="door"] .card.refused { top: 24%; }
.refusal .lede { color: rgba(255, 200, 140, .58); }
.refusal[data-kind="thin"] .lede, .refusal[data-kind="reader"] .lede, .refusal[data-kind="busy"] .lede { color: var(--ink-faint); }
.refusal h2.query { margin-bottom: .75em; }
.refusal p.body { margin: 0 0 1.15em; max-width: 48ch; font-size: .88rem; line-height: 1.65; color: var(--ink-dim); }
.refusal p.after { margin: 0; max-width: 48ch; font-size: .78rem; line-height: 1.8; color: var(--ink-faint); }
.card__ink-lit .refusal button, .card__ink-lit .offer button { pointer-events: none; }

/* a nudge is not an error: the Eye asking for an address should not wear the colour of a failure */
.status[data-level="note"] { color: rgba(217, 210, 198, .62); opacity: 1; }

/* the third measured phone breakage, still not a mobile design.
   The pinned ask bar overhung the right edge of a 390px window: measured 16..427 in a 390px viewport. It
   resolves its width against a 448px containing block rather than the viewport, so left/right alone do not
   hold it in; capping it against the viewport itself does. Measured after: 16..374. */
@media (max-width: 760px) {
  .ask.pinned { left: 1rem !important; right: auto !important; width: auto !important; max-width: calc(100vw - 2rem) !important; transform: none !important; padding-left: .9rem; }
  .ask-controls { gap: .3rem; margin-right: .3rem; }
  .ask-controls button { padding: 0 .55rem; font-size: .64rem; letter-spacing: .06em; }
  .ask-controls .c-lang { min-width: 2.4rem; }
  .ask input { min-width: 0; }

  /* The composed answer scrolled sideways on a phone - 476px of page in a 390px window. Found by removing
     every element in turn and measuring: the card is implicated, but the card is 355px wide with
     overflow:hidden and scrollWidth 353, and NO child of it overflows. Scrolled fully right, nothing is
     painted out there at all - body measures 0..390 and the band is empty. The number is also unstable run
     to run (470, 434, 476), which is the relic's per-frame transform, not layout.
     So the band is empty space, and the fix is to stop it being scrollable rather than keep hunting a
     phantom. `clip` rather than `hidden`: it creates no scroll container, so the pinned ask bar and the
     fixed relic canvas are untouched. Vertical scrolling is explicitly preserved. */
  .stage { overflow-x: clip; }
  body { overflow-x: clip; overflow-y: auto; }
}
/* STILL OPEN, measured not guessed: on a phone the COMPOSED answer page scrolls sideways, 448px of page in
   a 390px window. It is not the ask bar (fixed above) and not the engine's dust (clipped by its own parent).
   Four attempts did not find the element responsible. The front door and every failure state are clean at
   390px; only the answer view is affected. Mobile is an undesigned surface here in any case. */

/* ------------------------------------------------------------------ the invitation
   The door is a sales object and it used to end on a colophon: a prospect watched their own site perform
   and then had nowhere to go. One line, the same quiet register as the foot, shown only when the Eye
   actually answered — an invitation under a refusal would be selling on the back of a failure. */
.results p.invite {
  margin: 1.6em 0 0; padding-top: 1.1em; border-top: 1px solid rgba(217, 210, 198, .1);
  max-width: 62ch; font-size: .78rem; line-height: 1.7; color: var(--ink-faint);
}
.results p.invite a {
  color: rgba(255, 200, 140, .78); text-decoration: none; white-space: nowrap;   /* never break "Put the Eye on it" */
  border-bottom: 1px solid rgba(255, 200, 140, .3); padding-bottom: .12em; margin-left: .2em;
  transition: color .3s ease, border-color .3s ease;
}
.results p.invite a:hover { color: var(--warm); border-bottom-color: rgba(255, 200, 140, .75); }
.card__ink-lit .results p.invite a { pointer-events: none; }

/* ------------------------------------------------------------------ the answer, printed twice
   Measured on the live phone: 48 result cards in the DOM for a 24-result answer, the lit copy fully
   opaque and 33px out of register with the real ink. The cause is a missing fallback —
   `opacity: var(--lit)` in relic-3d.css. The engine sets --lit per frame while the beam plays; on a
   phone the beam never fires, --lit is never defined, the declaration is INVALID, and opacity falls
   back to its initial value of 1. So the reveal copy sat on top of the answer at full strength.
   A fallback of 0 is the correct default in every case: the lit copy exists to be revealed by light,
   so with no light it should not be there at all. Overridden here rather than in the engine's own
   sheet, which r4 does not own. */
.card__ink.card__ink-lit { opacity: var(--lit, 0); }

/* and on a phone the beam is not part of the composition at all — the Eye is barely on screen — so the
   second copy is pure cost: 24 duplicate cards laid out and painted for nothing. */
@media (max-width: 760px) {
  .card__ink.card__ink-lit { display: none; }
}

/* ------------------------------------------------------------------ the question needs a whole line
   On a 390px phone the four controls left about 90px for the question itself, so "show me your campaigns"
   read as "ur campaig". The field is the point of the bar; it gets its own row and the controls sit under it. */
@media (max-width: 760px) {
  .ask, .ask.pinned { flex-wrap: wrap; row-gap: .55rem; }
  .ask input { flex: 1 0 100%; order: -1; font-size: 16px; }   /* 16px: anything smaller makes iOS zoom the page on focus */
  .ask-controls { margin-right: auto; }
}
