/* love-board.css — the Love Board's Rolodex (notes.html) and one-page-per-note (/notes/<id>) (2026-10-15).
   Shared by BOTH pages so there is one copy, not two.
   ⛔ THE BLOCK BETWEEN THE TWIN MARKERS IS A VERBATIM COPY of rexburg-report-FINAL.html's love-note
      paper/ink/pin/handwriting rules (LANDMINE #2/#106). scripts/love-board-twin-test.mjs fails if the
      two differ by one byte. Change the reader → paste the new block here, same commit. */
:root {
  --font-body: 'Nunito', system-ui, sans-serif;
  --font-display: 'Fraunces', Georgia, serif;
  --font-mono: 'IBM Plex Mono', 'Courier New', monospace;
  /* The tokens the twin block reads, at the reader's own defaults (rexburg-report-FINAL.html :root). */
  --brand-primary: #006eb6; --brand: var(--brand-primary); --gold: #ffc93c;
  --love-ink: #101c26; --love-ink-soft: #54616d;
  --lb-page: #f4efe6; --lb-ink: #101c26; --lb-muted: #424c56; --lb-line: rgba(16,28,38,.12);   /* muted darkened 2026-10-15: these pages now sit on the wall photo */
}
/* Per-city pins and ink — the SAME values as the reader's html[data-skin] blocks (gold is fixed everywhere). */
html[data-skin="uvu"] { --brand-primary: #008a40; --love-ink: #121a14; --love-ink-soft: #5e6a60; }
html[data-skin="slc"] { --brand-primary: #cc0000; --love-ink: #1d1414; --love-ink-soft: #708e99; }
html[data-skin="isu"] { --brand-primary: #c2570a; --love-ink: #1A1A18; --love-ink-soft: #6B6B67; }

/* LOVE-NOTE-TWIN-BEGIN */
    :root {
      --love-paper-0: #fffdf6;   /* warm cream  — hand-0, Caveat */
      --love-paper-1: #fdf6f2;   /* blush       — hand-1, Kalam */
      --love-paper-2: #f8f6fd;   /* lavender    — hand-2, Shadows Into Light */
    }
    /* Pinned-paper love note (covers BOTH seed + fetched). Paper tint + handwriting rotate together
       per i%3 (cream+Caveat / blush+Kalam / lavender+Shadows) so each note reads as one object. */
    /* ⛔⛔ PARAGRAPH BREAKS SURVIVE ONLY BECAUSE OF THIS RULE (2026-09-08).
       The operator types blank lines in the admin textarea, the database stores them exactly
       (\n\n, verified on live rows), and every render below escapes the text and drops it into
       innerHTML — where HTML collapses ALL whitespace, including newlines, to a single space.
       escEv() escapes five characters and deliberately does not touch \n; converting there would
       mean five more replace() calls that must each run AFTER escaping, and getting that order
       wrong once is an injection hole.
       ⭐ `.event-desc` has carried this rule since the Events section was built and is why that one
       section never had the bug. This is the same fix, applied to the five that were missed.
       ⛔ DO NOT "SIMPLIFY" BY REMOVING THESE. There is no JS newline handling to fall back on —
       delete a selector here and that section silently reverts to one continuous block.
       ⚠️ pre-wrap preserves ALL whitespace, not only newlines: trailing spaces and runs of blank
       lines render exactly as typed. That is faithful, and occasionally more visible than intended.
       KEEP IN SYNC with admin/styles.css, which must render identically (LANDMINE #2). */
    .opener-text,
    .food-desc,
    .love-note,
    .rec-body,
    .deal-body { white-space: pre-wrap; }

    .love-note {
      position: relative;                        /* anchors the ::before pushpin */
      background: var(--love-paper-0);           /* default cream; hand-1/-2 override below */
      border: 1px solid rgba(0,0,0,0.06);
      border-radius: 4px;                        /* paper corner, not the 14px glass pill */
      box-shadow: 0 2px 8px rgba(40,50,60,0.10); /* soft lift */
      padding: 18px;
      margin-bottom: 20px;                       /* anti-collision spacing for the tilt */
      font-family: var(--font-body);
      font-size: 15px; line-height: 1.5;
      color: var(--love-ink);                    /* FIXED writing colour — the paper is fixed, so this is too (see :root) */
    }
    /* Pushpin — absolutely-positioned dot at top-center; var(--brand) so it reskins per city. */
    .love-note::before {
      content: "";
      position: absolute;
      top: -7px; left: 50%;
      transform: translateX(-50%);
      width: 13px; height: 13px;
      border-radius: 50%;
      border: 1.5px solid transparent;   /* keeps all pins equal size; hand-1 sets border-color */
      background: var(--brand);
      box-shadow: 0 2px 3px rgba(40,50,60,0.35), inset 0 -1.5px 1.5px rgba(0,0,0,0.22), inset 0 1.5px 1.5px rgba(255,255,255,0.45);
    }
    /* Pin color rotates with the hand/paper (i%3): blue / white / gold. var(--brand)+var(--gold) reskin per city. */
    .love-hand-0::before { background: var(--brand); }                           /* blue */
    .love-hand-1::before { background: #fff; border-color: rgba(0,0,0,0.18); }   /* white — border makes it read on cream */
    .love-hand-2::before { background: var(--gold); }                            /* yellow */
    /* Alternating tilt so notes nestle rather than stack-lean (small angles). */
    .love-note:nth-child(odd)  { transform: rotate(-1.3deg); }
    .love-note:nth-child(even) { transform: rotate(1.1deg); }
    /* Rotating handwriting + matching paper tint. love-hand-N is on BOTH seeds (hardcoded) and
       fetched notes (renderLoveBoard). System-font hand fallback so a failed webfont degrades to a
       readable hand-ish face, not broken text. Sizes tuned so the three faces read at ~equal weight. */
    .love-hand-0 { font-family: 'Caveat', 'Segoe Print', 'Bradley Hand', cursive; font-size: 22px; line-height: 1.35; background: var(--love-paper-0); }
    .love-hand-1 { font-family: 'Kalam', 'Segoe Print', 'Comic Sans MS', cursive; font-size: 16px; line-height: 1.5; background: var(--love-paper-1); }
    .love-hand-2 { font-family: 'Shadows Into Light', 'Segoe Print', cursive; font-size: 19px; line-height: 1.45; background: var(--love-paper-2); }
/* LOVE-NOTE-TWIN-END */

/* ── page ─────────────────────────────────────────────────────────────────────────────────── */
* { box-sizing: border-box; }
html, body { margin: 0; overflow-x: hidden; }
/* ── THE WALL (2026-10-15) — the sunlit hallway photo (assets/across-the-hall-bg-*-v1.webp, 887×1774, William's).
   Four layers, bottom up, all inside one fixed, full-viewport .lb-wall (so Chrome treats the photo as a BACKGROUND
   and the note stays the Largest Contentful Paint):
     1. the cream — the wall's OWN colours, sampled top to bottom from the photo (x 150–450, leaves skipped), so it
        paints instantly and continues the wall where the photo stops;
     2. a placeholder — the photo's colours in a few gradients, under the photo in the same box, until it arrives;
     3. the photo — PHONE: fills the width; DESKTOP: anchored to the right edge at full height, never stretched
        (its box has the photo's own 1:2 shape), the left ~150 px faded into the cream so the leaves dissolve;
     4. a warm cream wash + a soft light glow behind the text column (.lb-wall::after) — what keeps every line of
        text ≥ 4.5 (scripts/love-board-design-probe.ts measures the real pixels).
   ⛔ Asset law (#84): a new picture gets a new -vN name; these files are never overwritten. */
:root {
  --lb-wall: linear-gradient(180deg, #edd2ae 0%, #f9e5c4 15%, #f8e4c5 25%, #f5e1c4 35%, #f0dbbe 45%, #f6e1c2 55%, #f7e0c0 65%, #f4dbbb 75%, #f2d9b7 85%, #ecd2ab 100%);
}
body { background: #f6e1c2 var(--lb-wall) fixed; color: var(--lb-ink); font-family: var(--font-body); }
.lb-wall { position: fixed; inset: 0; z-index: -1; pointer-events: none; background: var(--lb-wall); }
/* The photo layer covers the WHOLE viewport (inset 0) and draws the photo inside it at the photo's own 1:2 shape —
   a full-viewport layer is background to Chrome, so it can never be the Largest Contentful Paint.
   ⛔ The photo itself is only requested AFTER the note's final paint (love-board.js adds .lb-wall-ready: load →
   fonts ready → 700 ms with no new largest-contentful-paint). Fetched alongside the fonts, Lighthouse counted its download against the note
   (measured on production: LCP ~2.1 → ~4.1 s, score 96 → 75). Until then the placeholder below — the photo's own
   colours — is what shows; then the photo fades in. */
.lb-wall-photo { position: absolute; inset: 0; background-repeat: no-repeat;
  --lb-ph: linear-gradient(180deg, #eedbc4 0%, #e2c9ad 14%, #efd1aa 28%, #efcda2 42%, #d4b998 56%, #ecd8c1 70%, #f0d4b2 84%, #965a23 100%), linear-gradient(180deg, #e1caa1 0%, #eedab5 14%, #f5dfc2 28%, #f2dcbf 42%, #f4dfc2 56%, #f4ddbc 70%, #e7d0ab 84%, #a38f5b 100%);
  background-image: var(--lb-ph); }
/* The photo itself is a ::before layer over the placeholder: no image until .lb-wall-ready, then it fades in. */
.lb-wall-photo::before { content: ""; position: absolute; inset: 0; background-repeat: no-repeat; opacity: 0; transition: opacity .6s ease; }
.lb-wall-ready .lb-wall-photo::before { opacity: 1; }
@media (max-width: 719px) {
  /* PHONE: the photo fills the width (887:1774 → 200vw tall), from the top; its foot fades into the cream. */
  .lb-wall-photo { background-size: 21% 200vw, 100% 200vw; background-position: 100% 0, 0 0;
    -webkit-mask-image: linear-gradient(180deg, #000 164vw, transparent 200vw); mask-image: linear-gradient(180deg, #000 164vw, transparent 200vw); }
  .lb-wall-ready .lb-wall-photo::before { background-image: url("/assets/across-the-hall-bg-phone-v1.webp"); background-size: 100% 200vw; background-position: 0 0; }
}
@media (min-width: 720px) {
  /* DESKTOP: anchored to the RIGHT edge at full height (50vh wide — its own shape, never stretched); the left 150px
     of the photo fades into the cream so the leaves dissolve. */
  .lb-wall-photo { background-size: 10.5vh 100%, 50vh 100%; background-position: 100% 0, 100% 0;
    -webkit-mask-image: linear-gradient(90deg, transparent calc(100% - 50vh), #000 calc(100% - 50vh + 150px));
            mask-image: linear-gradient(90deg, transparent calc(100% - 50vh), #000 calc(100% - 50vh + 150px)); }
  .lb-wall-ready .lb-wall-photo::before { background-image: url("/assets/across-the-hall-bg-desktop-v1.webp"); background-size: 50vh 100%; background-position: 100% 0; }
}
.lb-wall::after { content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(ellipse var(--lb-glow-w, 62%) 85% at 50% var(--lb-glow-y, 42%), rgba(252,244,230,var(--lb-glow, .62)) 0%, rgba(252,244,230,calc(var(--lb-glow, .62) * .6)) 60%, rgba(252,244,230,0) 100%),
    linear-gradient(rgba(250,240,222,.30), rgba(250,240,222,.30)); }
/* On a phone the text runs edge to edge over the photo — leaves and all — so the light glow is wider and stronger. */
@media (max-width: 719px) { .lb-wall { --lb-glow-w: 120%; --lb-glow: .72; --lb-glow-y: 34%; } }

.lb-wrap { max-width: 680px; margin: 0 auto; padding: 0 16px 48px; }
.lb-head { text-align: center; padding: 14px 16px 0; }
.lb-back { display: inline-block; font-size: 13px; line-height: 18px; font-weight: 800; color: var(--brand); color: color-mix(in srgb, var(--brand) 72%, #000); text-decoration: none; margin-bottom: 6px; }
.lb-kicker { font-family: var(--font-mono); font-size: 11px; line-height: 16px; letter-spacing: .2em; text-transform: uppercase; color: var(--lb-muted); }
.lb-title { font-family: var(--font-display); font-weight: 900; font-size: clamp(30px, 8vw, 44px); line-height: 1.05; margin: 2px 0 0; }
/* The hand-drawn Campus Gold stroke under the title (inline SVG in notes.html + api/note.mjs — two copies, tested equal). */
.lb-underline { display: block; width: min(250px, 64vw); height: 14px; margin: 0 auto 6px; overflow: visible; }
.lb-underline path { fill: none; stroke: var(--gold); stroke-width: 5; stroke-linecap: round; stroke-linejoin: round; }
.lb-sub { font-size: 15px; color: var(--lb-muted); margin: 0 auto; max-width: 30em; }
.lb-status { text-align: center; color: var(--lb-muted); font-size: 14px; padding: 24px 0; }

/* The stack: a SWIPE row on a phone, a scrolling column on a laptop. */
.rolo-stack { display: flex; gap: 18px; padding: 16px 4px 26px; }
@media (max-width: 719px) {
  .rolo-stack { overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; padding-left: 7vw; padding-right: 7vw; scrollbar-width: none; }
  .rolo-stack::-webkit-scrollbar { display: none; }
  .rolo-item { flex: 0 0 84%; scroll-snap-align: center; }
  .rolo-month { flex: 0 0 auto; scroll-snap-align: center; writing-mode: vertical-rl; transform: rotate(180deg); }
}
@media (min-width: 720px) {
  .rolo-stack { flex-direction: column; }
  .rolo-month { border-top: 1px solid var(--lb-line); padding-top: 14px; }
}
.rolo-month { font-family: var(--font-mono); font-size: 12px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; color: var(--lb-muted); align-self: center; }
.rolo-sentinel { flex: 0 0 1px; min-height: 1px; }
.lb-swipe-hint { text-align: center; font-size: 12px; color: var(--lb-muted); margin-top: -8px; }
@media (min-width: 720px) { .lb-swipe-hint { display: none; } }

/* One card: the note on its paper, then its date, actions, replies and reply box. */
.lb-card { display: flex; flex-direction: column; gap: 10px; }
.lb-card .love-note { margin-bottom: 4px; }
/* THE NOTE ON THESE TWO PAGES (2026-10-15): it leans by its short_id (the SAME angle as on the drum — lbTiltDeg),
   sits on a two-layer shadow (a tight contact shadow + a soft ambient one), catches light on its top edge, and the
   pin gets its own drop shadow and a highlight. Same paper and pinned --love-ink as everywhere. */
.love-note.lb-tilt { transform: rotate(var(--lb-tilt)); }
.lb-note-page { padding-top: 14px; }   /* the pin clears the title's gold stroke */
.lb-card .love-note {
  border-color: rgba(70,52,24,.08);
  box-shadow: 0 1px 1.5px rgba(70,52,24,.20), 0 2px 4px rgba(70,52,24,.10), 0 14px 30px -10px rgba(70,52,24,.30), inset 0 1px 0 rgba(255,255,255,.95), inset 0 -1px 0 rgba(70,52,24,.05);
}
.lb-card .love-note::before {
  width: 15px; height: 15px; top: -8px;
  background-image: radial-gradient(circle at 35% 30%, rgba(255,255,255,.85) 0 16%, rgba(255,255,255,0) 46%);
  box-shadow: 0 3px 4px rgba(50,36,14,.38), 0 1px 1px rgba(0,0,0,.25), inset 0 -1.5px 1.5px rgba(0,0,0,.22);
}
.lb-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; color: var(--lb-muted); }
.lb-date { font-family: var(--font-mono); font-size: 12px; letter-spacing: .04em; }
.lb-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.lb-btn { appearance: none; border: 1.5px solid var(--lb-line); background: #fff; color: var(--lb-ink); font: 800 14px/1 var(--font-body); padding: 10px 14px; border-radius: 99px; min-height: 44px; min-width: 44px; justify-content: center; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; text-decoration: none; }
.lb-btn[aria-pressed="true"] { border-color: #e0245e; color: #c81e52; background: #fff0f4; }
.lb-btn:disabled { opacity: .55; cursor: default; }
.lb-link { font-size: 13px; font-weight: 700; color: var(--lb-muted); text-decoration: underline; text-underline-offset: 3px; }
.lb-replies { list-style: none; margin: 0; padding: 0 0 0 14px; border-left: 2px solid var(--lb-line); display: flex; flex-direction: column; gap: 8px; }
.lb-reply { background: #fff; border-radius: 10px; padding: 10px 12px; font-size: 14px; line-height: 1.45; white-space: pre-wrap; box-shadow: 0 1px 3px rgba(40,50,60,.08); }
.lb-reply .lb-date { display: block; margin-top: 4px; color: var(--lb-muted); }
.lb-reply-form { display: flex; flex-direction: column; gap: 8px; background: #fff; border-radius: 12px; padding: 12px; box-shadow: 0 1px 3px rgba(40,50,60,.08); }
.lb-rule { font-size: 13px; font-weight: 800; color: var(--lb-ink); }
.lb-reply-form textarea { font: 15px/1.45 var(--font-body); padding: 10px; border: 1.5px solid var(--lb-line); border-radius: 8px; resize: vertical; min-height: 70px; width: 100%; }
.lb-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.lb-count { font-size: 12px; color: var(--lb-muted); text-align: right; }
.lb-msg { font-size: 13px; font-weight: 700; }
.lb-closed { font-size: 13px; color: var(--lb-muted); font-style: italic; }

/* The subscribe box — email only; it posts to the SAME /api/subscribe the subscribe page uses. */
.lb-sub-box { background: #fff; border-radius: 16px; padding: 22px 18px; text-align: center; border: 1px solid rgba(70,52,24,.06); box-shadow: 0 1px 2px rgba(70,52,24,.08), 0 14px 34px -10px rgba(70,52,24,.24); margin-top: 18px; }
.lb-sub-box h2 { font-family: var(--font-display); font-weight: 900; font-size: 22px; margin: 0 0 6px; }
.lb-sub-box p { margin: 0 0 14px; color: var(--lb-muted); font-size: 14px; }
.lb-sub-form { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.lb-sub-form input[type="email"] { flex: 1 1 220px; min-width: 0; font: 16px var(--font-body); padding: 12px; border: 1.5px solid var(--lb-line); border-radius: 10px; }
.lb-sub-form button { background: var(--brand); color: #fff; border: 0; border-radius: 10px; padding: 12px 18px; font: 900 15px var(--font-body); cursor: pointer; min-height: 46px; }
.lb-foot { text-align: center; font-size: 12px; color: var(--lb-muted); margin-top: 28px; }
.lb-foot a { color: inherit; }

/* THE WHOLE CARD IS THE TAP TARGET (2026-10-15) — on the Rolodex a tap anywhere opens the note's page
   (love-board.js lbTrackTaps). A pointer cursor and a gentle press on a laptop; the counts are DISPLAY. */
.lb-tap { cursor: pointer; border-radius: 10px; transition: transform .08s ease, box-shadow .08s ease; -webkit-tap-highlight-color: transparent; }
.lb-tap:active { transform: scale(.985); }
@media (hover: hover) { .lb-tap:hover .love-note { box-shadow: 0 4px 14px rgba(40,50,60,0.16); } }
.lb-tap:focus-visible { outline: 3px solid var(--brand); outline-offset: 4px; }
.lb-stats { min-height: 44px; display: flex; align-items: center; font: 800 15px/1 var(--font-body); color: var(--lb-ink); }
