/**
 * Field Journal — hunting & foraging.
 *
 * The house hex forms, ported from the approved mockup. Four of them:
 *   .c    cell — a glyph, a number, a state. NEVER a sentence.
 *   .run  n cells merged: sawtooth top/bottom, flat ends, no internal walls.
 *         n = 1 is exactly a cell — same formula, so a bar is not a new shape.
 *   .gcell gauge cell — discrete, countable, coloured by what it was spent on.
 *   .panel filled ground, for anything you READ.
 *
 * The rule that keeps it legible: hexes stay DISCRETE where you count them and
 * FILL IN where you read. That is lifted from HexProgress (size*0.92, gaps kept)
 * and HexPanel (drawSolidFill at size*0.98, no stroke) respectively.
 *
 * ⚠️ Traps this file already pays for — all of them cost a round in the mockup:
 *  1. box-sizing must be border-box, or a face with padding is WIDER than its
 *     parent and gets dragged left, which looks exactly like text clipping.
 *  2. --h must be redeclared wherever --w is, because a custom property is
 *     substituted where it is DECLARED; overriding --w alone leaves the old
 *     height and every cell renders as a lozenge.
 *  3. Never set align-items on a .comb. Centring rows independently detaches
 *     them from the lattice and the whole block goes lopsided.
 *  4. Row overlap is a DESCENDANT rule, not `.crow + .crow`. The sibling
 *     combinator stops matching the moment any wrapper sits between two rows,
 *     and the block below silently floats away from its header.
 *  5. Variant custom properties must out-specify the base rule that sets them.
 *  6. align-content on a cell face: grid auto rows default to STRETCH, which
 *     pushes a number and its caption to opposite ends of the hex.
 */

/* The lattice tokens are shared by all three surfaces; the PAGE layout below is
   not (a modal must not inherit a page's max-width and padding).

   ⚠️ THREE SCOPES NOW, AND A SELECTOR NAMING ONLY SOME LEAVES THE REST AS
   UNSTYLED PROSE INSIDE A CORRECTLY DRAWN FRAME — which reads as a broken page
   rather than a narrow selector. `.plinko-build` joined at [D-54].

   ⚠️ AND IT IS A DIFFERENT SCALE ON PURPOSE. The journal's cells ARE its
   content (a route, a gauge, a named quarry) so they are large; the Plinko
   picker is a dense grid of pieces and sits near the rest of the site's
   structural hex. Same lattice, different cell. */
.journal-page,
.quarry-field,
.plinko-build {
  --w: 54px;
  --h: 62.35px;                 /* pointy-top: h = w * 2/sqrt(3) */
  --hexclip: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
  --edge: 2px;
  font-family: 'Courier New', Courier, monospace;
}
/* ⚠️ --h MUST BE REDECLARED WHEREVER --w IS (trap 2) — a custom property is
   substituted where it is DECLARED, so overriding --w alone leaves the old
   height and every cell renders as a lozenge. */
.plinko-build { --w: 32px; --h: 36.95px; }

.journal-page {
  max-width: 1000px;
  width: 100%;
  /* ⚠️ layout.ejs puts pages inside `main.page-content`, which is a FLEX
     container. A flex item defaults to min-width:auto and therefore refuses to
     shrink below its content — so a comb wider than the phone pushed the whole
     document sideways and the sheet's own overflow never got a constrained
     width to scroll inside. Any page in this layout with unshrinkable content
     needs this. */
  min-width: 0;
  margin: 0 auto;
  padding: 0 12px 60px;
  font-family: 'Courier New', Courier, monospace;
}
.journal-page *, .journal-page *::before, .journal-page *::after,
.quarry-field *, .quarry-field *::before, .quarry-field *::after,
.plinko-build *, .plinko-build *::before, .plinko-build *::after { box-sizing: border-box; }

.jp-top { display: flex; align-items: baseline; gap: 18px; padding: 18px 0 10px; flex-wrap: wrap; }
.jp-back { color: var(--text-secondary); text-decoration: none; font-size: 13px; }
.jp-back:hover { color: var(--text-accent); }
.jp-title { font-size: 22px; letter-spacing: .06em; margin: 0; color: var(--text-primary); }

/* ⚠️ A comb is as wide as its widest row, and a row is a whole number of cells —
   it cannot reflow. So the SHEET scrolls, and the page body never does. Without
   this the whole document scrolls sideways on a phone. */
.ui-sheet {
  background: var(--bg-darkest); padding: 16px 14px 20px;
  border-top: 3px solid var(--border-gold);
  overflow-x: auto; overflow-y: hidden;
}
.ui-sheet + .ui-sheet { border-top: none; padding-top: 0; }
.jp-loading { color: var(--text-muted); font-size: 13px; padding: 20px 4px; }

/* ---------- the lattice ---------- */
.comb { display: flex; flex-direction: column; align-items: flex-start; }
.crow { display: flex; align-items: flex-start; }
.comb .crow { margin-top: calc(var(--h) * -0.25); }        /* trap 4 */
.comb > .crow:first-child,
.comb > :first-child > .crow:first-child { margin-top: 0; }
.crow.off { margin-left: calc(var(--w) * .5); }

/* ---------- FORM 1: the cell ---------- */
.c {
  width: var(--w); height: var(--h); clip-path: var(--hexclip);
  background: var(--border-light); display: grid; place-items: center;
  flex: none; position: relative; cursor: default;
}
.c > .f {
  width: calc(100% - var(--edge) * 2); height: calc(100% - var(--edge) * 2.31);
  clip-path: var(--hexclip); background: var(--bg-medium);
  display: grid; place-items: center; align-content: center;   /* trap 6 */
  text-align: center; padding: 0 10%; font-size: 11px; line-height: 1.2;
}
.c.ground { background: #241e17; }
.c.ground > .f { background: #1e1912; color: #332b22; font-size: 9px; }
.c.dark > .f { background: var(--bg-darkest); color: var(--text-muted); }
.c.void { background: var(--bg-dark); }
.c.void > .f { background: var(--bg-darkest); color: var(--border-medium); }
.c.ghost { background: var(--border-medium); }
.c.ghost > .f { background: var(--bg-darkest); color: var(--text-muted); }
.c.live { background: var(--border-gold); }
.c.live > .f { background: var(--gold); color: var(--bg-darkest); font-weight: 700; }
.c.done { background: #2d55a0; }
.c.done > .f { background: var(--color-mana); color: var(--text-primary); font-size: 15px; }
.c.risk { background: var(--color-hunger); }
.c.risk > .f {
  background: repeating-linear-gradient(135deg, rgba(204,136,51,.9) 0 5px, var(--bg-darkest) 5px 10px);
  color: var(--text-primary); font-size: 15px;
}
.c.quarry { background: var(--border-gold); }
.c.quarry > .f { background: var(--bg-dark); color: var(--text-accent); font-weight: 700; }
.c.click { cursor: pointer; }
.c.click:hover > .f { filter: brightness(1.25); }
.c.click:focus-visible { outline: 3px solid var(--text-accent); outline-offset: 2px; }
.c .glyph { font-size: 18px; line-height: 1; color: var(--text-accent); }
.c .num { font-size: 19px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.c .cap {
  font-size: 8.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-secondary); display: block; margin-top: 1px;
}
.c.live .cap { color: rgba(26, 21, 16, .72); }

/* abundance: six wedges, because a hexagon has six */
.wedge { position: absolute; inset: var(--edge); clip-path: var(--hexclip); }
.w-teeming  { background: conic-gradient(#7fbf4d 0 360deg); }
.w-abundant { background: conic-gradient(#44aa44 0 300deg, #221c15 300deg 360deg); }
.w-steady   { background: conic-gradient(#c9a227 0 240deg, #221c15 240deg 360deg); }
.w-thin     { background: conic-gradient(#cc8833 0 180deg, #221c15 180deg 360deg); }
.w-scarce   { background: conic-gradient(#cc5533 0 120deg, #221c15 120deg 360deg); }
.w-picked   { background: conic-gradient(#8a6a55 0 60deg,  #221c15 60deg 360deg); }
.c.ab > .f {
  background: transparent; position: relative; z-index: 1;
  text-shadow: 0 1px 2px #000, 0 0 5px #000, 0 0 5px #000;
}

/* familiarity: how many of the six edges are lit; the COLOUR is abundance */
.c.fam { background: var(--border-dark); --lit: var(--gold); }
.c.fam > .f { width: 70%; height: 70%; font-size: 10px; padding: 0 4%; }
.c.fam::before { content: ""; position: absolute; inset: var(--edge); clip-path: var(--hexclip); }
.c.fam.a-teeming  { --lit: #7fbf4d; }   /* trap 5: must out-specify .c.fam */
.c.fam.a-abundant { --lit: #44aa44; }
.c.fam.a-steady   { --lit: #c9a227; }
.c.fam.a-thin     { --lit: #cc8833; }
.c.fam.a-scarce   { --lit: #cc5533; }
.c.fam.a-picked   { --lit: #8a6a55; }
.c.fam.f0::before { background: var(--border-medium); }
.c.fam.f1::before { background: conic-gradient(var(--lit) 0 60deg,  var(--border-medium) 60deg 360deg); }
.c.fam.f2::before { background: conic-gradient(var(--lit) 0 120deg, var(--border-medium) 120deg 360deg); }
.c.fam.f3::before { background: conic-gradient(var(--lit) 0 180deg, var(--border-medium) 180deg 360deg); }
.c.fam.f4::before { background: conic-gradient(var(--lit) 0 240deg, var(--border-medium) 240deg 360deg); }
.c.fam.f5::before { background: conic-gradient(var(--lit) 0 300deg, var(--border-medium) 300deg 360deg); }
/* Six of six — a MAXED quarry, which the old fixed five-level scale could never
   draw: it stopped at f5, so finished still looked one short of finished. */
.c.fam.f6::before { background: var(--lit); }

/* ---------- FORM 2: the run ---------- */
.run { position: relative; height: var(--h); background: var(--border-light); flex: none; }
.run > .f {
  position: absolute; inset: var(--edge); background: var(--bg-medium);
  display: flex; align-items: center; gap: 10px;
  padding-inline: calc(var(--w) * .55); padding-block: 0;
  overflow: hidden;
}
.run.dark > .f { background: var(--bg-darkest); }
.run.gold { background: var(--border-gold); }
.run.gold > .f { background: var(--bg-dark); }
.run.mid > .f { background: var(--bg-light); }
.run .t { font-size: 14px; font-weight: 700; letter-spacing: .03em; white-space: nowrap; }
.run .s { font-size: 12px; color: var(--text-secondary); white-space: nowrap; }
.run .lbl2 {
  font-size: 10px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--text-muted); white-space: nowrap;
}
/* a button that is two joined cells, so two lines read as ONE control */
.run.btn { cursor: pointer; }
.run.btn > .f {
  flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  padding-inline: calc(var(--w) * .28);
}
/* ⚠️ A BUTTON LABEL MUST FOLLOW THE CELL, like every other label here (trap 8).
   These were flat 12/10px, which held only because the journal never goes below
   a 34px cell. The in-field reading view solves its cell from the PROSE width
   and lands near 24px on a phone — at which point a two-line label printed
   straight through its own polygon. The multipliers are set so nothing changes
   at 42px and above; they only bite on a small cell. */
.run.btn .t { font-size: clamp(9px, calc(var(--w) * 0.29), 12px); }
.run.btn .s { font-size: clamp(8px, calc(var(--w) * 0.24), 10px); }

/**
 * ⚠️ THE SPACE BETWEEN A BUTTON'S TWO LINES IS LEADING, NOT THE FLEX GAP.
 *
 * `.run.btn > .f` already sets `gap: 1px`, so the obvious knob was at its floor
 * and the lines still sat far apart: the page's inherited `line-height: 1.5` put
 * a 12px title in an 18px box and a 10px subtitle in a 15px box, and HALF of
 * each of those 6px and 5px of leading lands between the glyph rows. Measured
 * glyph-to-glyph that is ~6.5px from a nominal 1px gap — chasing the gap
 * property would never have found it.
 *
 * 1.5 → 1.2 halved it to 3.2px; 1.2 → 1.05 halves it again to ~1.6px. The two
 * lines now occupy ~24px of a 58px face instead of 34px, so the pair also sits
 * further off the top and bottom edges — which is what "cramped" was.
 *
 * ⚠️ Do not go below 1: at line-height under 1 the glyph rows overlap, and the
 * run's `overflow: hidden` would start shaving ascenders rather than spacing.
 */
.run.btn .t,
.run.btn .s,
.run.stack .t,
.run.stack .s { line-height: 1.05; }

/**
 * A STACKED LABEL IN A NON-BUTTON RUN.
 *
 * ⚠️ A RUN'S `padding-inline` OF 0.55w IS THE SAWTOOTH CLEARANCE, NOT DECORATION.
 * The polygon narrows to a POINT at each end and only reaches full height half a
 * cell in, so content must start there or it rides over the tip. That makes a
 * 2-cell run only ~45px of usable box out of 108px — and the header's
 * "1/3 trails" needed 80px, so it was clipped by 35px (rendering as "trail")
 * and, being flex-start after a 30px pad, its ink sat 17.5px RIGHT of the run's
 * centre. That is one bug that looks like two.
 *
 * Widening to 3 cells would have made that header row 6 cells, which overflows a
 * 390px phone and reintroduces sideways pan. Stacking two short lines fits the
 * same text in the same 2 cells, and centres it.
 */
.run.stack > .f {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
}
.run.stack .t { font-size: clamp(11px, calc(var(--w) * 0.26), 14px); }
.run.stack .s { font-size: clamp(8px, calc(var(--w) * 0.19), 11px); }
/* Small enough that two stacked lines collide inside the row — see the note on
   the `tight` toggle in quarry-field.js. Title only; the cost is stated above. */
.comb.tight .run.btn .s { display: none; }
.run.btn.on { background: var(--border-gold); }
.run.btn.on > .f { background: var(--gold); color: var(--bg-darkest); }
.run.btn.on .s { color: rgba(26, 21, 16, .75); }
.run.btn:hover > .f { filter: brightness(1.18); }
.run.btn:focus-visible { outline: 3px solid var(--text-accent); outline-offset: 2px; }
.run.btn[aria-disabled="true"] { cursor: not-allowed; opacity: .45; }
.run.btn[aria-disabled="true"]:hover > .f { filter: none; }

/* ---------- FORM 3: the gauge ---------- */
/* Each cell keeps a rim so neighbours of the SAME colour stay countable — the
   job HexProgress does with a gap, which would break the tessellation here. */
.gcell {
  width: var(--w); height: var(--h); clip-path: var(--hexclip); flex: none;
  background: var(--border-dark); display: grid; place-items: center;
}
.gcell > i { width: calc(100% - 3px); height: calc(100% - 3.5px); clip-path: var(--hexclip); background: var(--bg-medium); display: block; }
.gcell.on > i { background: var(--gold); }
.gcell.hunt > i { background: var(--color-mana); }
.gcell.forage > i { background: #44aa44; }
.gcell.lost > i { background: var(--color-hunger); }

/* ---------- FORM 4: the panel ---------- */
.panel { position: relative; flex: none; }
.panel > canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* Clearance is a WHOLE cell vertically: a border hex spans y = 0..h, and the
   offset rows push the ring another half cell inward, hence ~1.6w. */
.panel > .body {
  position: relative;
  padding-block: calc(var(--h) * 1.06);
  padding-inline: calc(var(--w) * 1.62);
}
.panel .ptitle { font-size: 17px; font-weight: 700; letter-spacing: .04em; margin-bottom: 3px; }
.panel .psub { font-size: 11.5px; color: var(--theme-secondary); margin-bottom: 12px; }
.panel p { margin: 0 0 10px; font-size: 13px; line-height: 1.55; color: var(--text-secondary); max-width: 62ch; }
/* ⚠️ `minmax(0, 1fr)`, NOT `1fr` — a grid item's default `min-width: auto`
   refuses to shrink below its longest word, so one unbroken id (`aqua_magia_
   common`) silently widens the track and pushes the list out over the ring. */
.panel dl { display: grid; grid-template-columns: 120px minmax(0, 1fr); gap: 7px 14px; margin: 0; font-size: 13px; }
.panel dt { color: var(--text-muted); font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase; padding-top: 3px; }
.panel dd { margin: 0; color: var(--text-primary); overflow-wrap: anywhere; }

/* --------------------------------------------------------------------------
 * QUESTS mounted in the Field Journal ([D-53]).
 *
 * The cards themselves are `quest-cards.css`, shared with the quest board. What
 * belongs HERE is only what changes because they are mounted on this page.
 *
 * ⚠️ RELEASE THE LIST'S OWN SCROLL. `.quest-list` is `max-height: 380px;
 * overflow-y: auto`, which is right on the board — two fixed-height parchment
 * pages side by side — and wrong here, where it makes a second scrolling box
 * inside a page that already scrolls. Two nested scroll surfaces on a phone is
 * the thing you cannot flick out of.
 */
.jp-quests .quest-list { max-height: none; overflow-y: visible; padding-right: 0; }

/* An entry carries its objectives here, where the board keeps them in its
   detail pane — so the list needs to sit tight inside the card. */
.jp-quests .quest-entry .objective-list { margin: 6px 0 0; }
.jp-quests .quest-entry { cursor: default; }
.jp-quests .page-header { margin-bottom: 12px; }
.jp-quests .notes-hint { margin-top: 14px; }


/* a censored fact: a short run of joined dark cells */
.censor {
  --w: 14px; --h: 16.16px;
  display: inline-block; vertical-align: -3px; background: var(--border-light); position: relative;
}
.censor > .f { position: absolute; inset: 1px; background: #211b14; }

/* --------------------------------------------------------------------------
 * A REDACTED FACT INSIDE PROSE ([D-19], [D-30])
 *
 * ⚠️ Sized in CHARACTERS, not cells. `.censor` is a run — a lattice form — and
 * a lattice form inside a sentence has no business being there: it is measured
 * in a pitch the sentence does not share. This one is `--n` characters wide, so
 * the bar is exactly as long as the fact it hides. That length is deliberate:
 * seeing HOW MUCH you are missing is most of what makes a redaction inviting
 * rather than annoying.
 *
 * ⚠️ THERE IS NOTHING TO REVEAL IN THE DOM. The hidden text never leaves the
 * server (see lib/quarry-reveal.js) — this element has no content to un-hide,
 * which is what stops devtools being a cheat menu.
 */
/* ⚠️ The RUN wraps; the bars inside it do not. One bar per hidden word, so a
   long fact breaks across lines exactly where the sentence it replaced would
   have — rather than clipping to the column and losing its honest width. */
.redact-run { cursor: help; }
.redact {
  display: inline-block;
  width: calc(var(--n, 6) * 1ch);
  max-width: 100%;
  height: 1em;
  vertical-align: -0.16em;
  background: #211b14;
  box-shadow: inset 0 0 0 1px var(--border-medium);
  /* a hexagon's ends, so a redaction is visibly the same family as everything
     else on the page without pretending to sit on the lattice */
  clip-path: polygon(0.35em 0, 100% 0, calc(100% - 0.35em) 100%, 0 100%);
}
.journal-page .q-desc,
.quarry-field .q-desc {
  margin: 0 0 12px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-secondary);
}

.jp-label { font-size: 10px; letter-spacing: .13em; text-transform: uppercase; color: var(--text-muted); margin: 0 0 6px; }
.jp-note { font-size: 12px; color: var(--text-secondary); margin: 10px 0 0; max-width: 68ch; line-height: 1.5; }
/**
 * ⚠️ IT HAS TO OUTRANK A HexUI MODAL BACKDROP, WHICH SITS AT 10000. This was
 * z-index 400, which is fine on the journal page and useless in the in-field
 * panel — every refusal raised from that modal ("too hungry to work for it",
 * "no tracking energy left", the ready cap) was rendering BEHIND the backdrop.
 * The player pressed a button and, as far as they could tell, nothing happened.
 * A message that cannot be seen is the same as no message at all.
 */
.jp-toast {
  position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%);
  background: var(--bg-dark); border: 3px solid var(--border-gold); color: var(--text-primary);
  padding: 10px 20px; font-size: 13px; z-index: 10050; max-width: 90vw; text-align: center;
}

/* ---------- mobile: same joins, narrower lattice ---------- */
@media (max-width: 760px) {
  /* trap 2 — BOTH, always */
  .journal-page { --w: 46px; --h: 53.12px; padding: 0 8px 50px; }
  .quarry-field { --w: 42px; --h: 48.5px; }
  .plinko-build { --w: 24px; --h: 27.71px; }
  /**
   * ⚠️ A 96px LABEL COLUMN INSIDE A 122px BOX.
   *
   * A panel's ring inset is 1.62 cells on EACH side, so at the page's 54px cell
   * a phone panel has about 122px of content — barely wider than the label
   * column alone, and a fixed grid track cannot shrink. The grid laid itself out
   * at 232px regardless and put every VALUE 110px to the right of anywhere it
   * could legally be drawn: the whole column printed across the border ring and
   * off the far edge. Narrowing the fixed track (120 → 96) only moved the cliff.
   *
   * A label ABOVE its value costs one line and can never overflow, so on a phone
   * the list stacks. Judge this from the panel's INNER width, never the
   * viewport's — the ring is the thing eating the space.
   */
  .panel dl { grid-template-columns: minmax(0, 1fr); gap: 0; font-size: 12px; }
  .panel dt { padding-top: 10px; }
  .panel dl > dt:first-child { padding-top: 0; }
  .jp-title { font-size: 18px; }
}
@media (prefers-reduced-motion: reduce) {
  .journal-page *, .quarry-field *, .plinko-build * { animation: none !important; transition: none !important; }
}


/* ==================== In-field pursuit panel ====================
   Lives inside a HexUI.Modal on the map. Same four forms; the only new idea is
   the FLOWER — you are the centre cell and your options are your neighbours,
   which makes "six" an honest cap that the geometry enforces rather than a
   number we invented. Past six, ring 2 opens and the place is visibly bigger. */
.quarry-field { font-family: 'Courier New', Courier, monospace; }
.quarry-field .qf-signs {
  font-size: 12.5px; line-height: 1.5; color: var(--text-secondary);
  font-style: italic; margin: 0 0 12px; max-width: 60ch;
}
.quarry-field .qf-flower { display: flex; justify-content: center; margin: 4px 0 12px; }
.quarry-field .qf-foot { display: flex; flex-wrap: wrap; gap: 10px 18px; font-size: 12px; color: var(--text-secondary); margin-top: 10px; }
.quarry-field .qf-foot b { color: var(--text-accent); font-weight: 700; }
.quarry-field .c.you { background: var(--border-gold); }
.quarry-field .c.you > .f { background: var(--gold); color: var(--bg-darkest); font-weight: 700; }
/* an empty neighbour is information too: a thin corner of the map looks thin */
.quarry-field .c.empty { background: var(--bg-dark); }
.quarry-field .c.empty > .f { background: var(--bg-darkest); color: var(--border-medium); }

/* --------------------------------------------------------------------------
 * TAUGHT, not found (Water Marks, lv 8)
 *
 * Trap 7: this must out-specify `.c.fam` for the same reason the abundance
 * tints do — `.c.fam` sets the background, so a bare `.taught` loses.
 *
 * A taught entry is NAMED but never worked, so it reads as an outline: the
 * name is solid, the cell behind it is not. Familiarity 0 already renders
 * unlit, and the dashed ring is what says "hearsay" rather than "empty".
 */
.c.fam.taught { background: transparent; box-shadow: inset 0 0 0 1px var(--border-medium); }
.c.fam.taught > .f { opacity: 0.82; font-style: italic; }
.journal-page .psub.taught-note {
  color: var(--text-muted);
  font-style: italic;
  margin-top: 2px;
}

/* --------------------------------------------------------------------------
 * Tracking v2 — the sign and its readings
 *
 * ⚠️ Readings are PANELS, not runs. A run is one hex-row tall and cannot wrap,
 * so a sentence in a run either clips or shrinks the cell past legibility. This
 * is also what makes the pursuit UI tall enough to use on a phone: prose grows
 * downward, so the panel is sized by its content rather than by a row count.
 */
/* ⚠️ THE SIGN IS RENDERED ON TWO SURFACES. It began as a journal-only view and
   every rule below was scoped to `.journal-page`; the in-field TRACK modal now
   hosts the same markup, and a rule that names only one surface silently drops
   half its styling on the other — unstyled prose inside a correctly drawn panel,
   which reads as "the modal is broken" rather than "a selector is too narrow".
   Anything the SIGN needs is scoped to both. */
/**
 * The eyebrow that says WHICH FACT this is — "On the trail of", "What you found",
 * "Your best guess so far".
 *
 * ⚠️ IT HAS TO LOOK LIKE A LABEL, NOT LIKE CONTENT. The whole ambiguity was two
 * facts rendered in the same voice, so an eyebrow that competed with the value
 * under it would only add a third. Small, uppercase, tracked out and in the
 * secondary colour: read once, then skipped on the twentieth trail.
 *
 * ⚠️ NOT `.c .cap` — that one is scoped to CELLS and sized from `--w`, which on
 * this surface is solved from the prose and would swing the label's size with it.
 */
.journal-page .sign-eyebrow,
.quarry-field .sign-eyebrow {
  font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700;
  color: var(--theme-secondary, var(--text-secondary)); line-height: 1.2;
  margin-bottom: 2px;
}
/* Its own value sits directly under it, so the gap belongs ABOVE the next eyebrow. */
.journal-page .sign-text + .sign-eyebrow,
.quarry-field .sign-text + .sign-eyebrow,
.journal-page .psub + .sign-eyebrow,
.quarry-field .psub + .sign-eyebrow { margin-top: 10px; }

/**
 * The label for the readings, which are SEPARATE PANELS below this one.
 *
 * ⚠️ IT IS THE LAST THING IN THE SIGN PANEL, NOT A RUN OF ITS OWN. A run is one
 * hex-row tall and loses 1.1 cells to sawtooth clearance — at this view's 3-cell
 * budget that is ~45px of usable face, which would clip this to "What you m…".
 * Prose belongs in a panel; this is the panel it belongs to.
 */
.journal-page .sign-choose,
.quarry-field .sign-choose {
  margin-top: 12px; font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
  font-weight: 700; color: var(--gold, #c9a227); line-height: 1.25;
}

.journal-page .sign-text,
.quarry-field .sign-text {
  font-size: 15px; line-height: 1.5; color: var(--text-primary); font-style: italic;
}

.journal-page .reading-text,
.quarry-field .reading-text { font-size: 14px; line-height: 1.45; color: var(--text-primary); }
.journal-page .reading-names,
.quarry-field .reading-names {
  margin-top: 4px; font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--gold, #c9a227);
}
/* Not yet decodable — say so plainly rather than leaving a gap that reads as a bug. */
.journal-page .reading-names.none,
.quarry-field .reading-names.none { color: var(--text-muted); text-transform: none; letter-spacing: 0; font-style: italic; }
.journal-page .reading-flag,
.quarry-field .reading-flag { margin-top: 3px; font-size: 11px; color: var(--text-secondary); font-style: italic; }
/* Cut Sign marks it, never removes it — a player may still back their own read. */
.journal-page .panel.reading.unlikely .reading-text,
.quarry-field .panel.reading.unlikely .reading-text { opacity: .55; }



/* --------------------------------------------------------------------------
 * Labels scale with the cell (trap 8)
 *
 * ⚠️ The cell size is DERIVED from the available width now, so a fixed label
 * size no longer holds: on a narrow sheet the hexagon shrinks under the word and
 * the text clips against the clip-path — measured on "TRAILS" and the stacked
 * "Tracking / Energy" label. A hexagon's usable width is only about 70% of its
 * box, so the type has to follow --w rather than sit at a constant.
 *
 * clamp() keeps it readable at the small end and stops it ballooning on a wide
 * desktop cell.
 */
.c > .f { font-size: clamp(9px, calc(var(--w) * 0.15), 12px); padding: 0 8%; }
.c .cap { font-size: clamp(7px, calc(var(--w) * 0.115), 9px); letter-spacing: .05em; }
.run .lbl2 { font-size: clamp(8px, calc(var(--w) * 0.13), 11px); }
/* A word that still cannot fit breaks rather than spilling past the ring. */
.c > .f, .run > .f { overflow-wrap: anywhere; }

/* ⚠️ Two `lbl2` spans in one run are authored to STACK — "Tracking" over
 * "Energy". Inline, they sit side by side and need ~141px of face in a run that
 * is only 131px wide once the cell is fitted to a narrower sheet, so the label
 * clipped mid-word. Blocking them is what the markup already meant. */
.run .lbl2 { display: block; }

/* --------------------------------------------------------------------------
 * The ladder on a phone: a rung is a PANEL (trap 9)
 *
 * ⚠️ Two lessons are baked in here. First, PROSE CANNOT LIVE IN A RUN — a run is
 * one hex-row tall and clipped to that polygon, so wrapped text grows straight
 * out over its own border. Second, EMITTING TWO ROWS PER RUNG BREAKS THE
 * LATTICE: rows must alternate offset strictly, and deriving the offset from the
 * rung index while writing two rows produced `off, off` back to back, so the
 * rows stopped nestling. Panels sidestep both — they are sized by their content
 * and paintPanel already fixes the parity of whatever follows.
 */
.journal-page .rung-head { display: flex; align-items: baseline; gap: 8px; }
.journal-page .rung-lv {
  font-family: var(--font-mono, monospace); font-size: 12px; font-weight: 700;
  color: var(--text-muted); min-width: 22px;
}
.journal-page .rung-name {
  font-size: 14px; font-weight: 700; letter-spacing: .04em; color: var(--text-secondary);
}
.journal-page .rung-desc {
  margin-top: 3px; font-size: 12.5px; line-height: 1.45; color: var(--text-muted);
}
/* Reached rungs read as earned; the next one up is signposted. */
.journal-page .panel.rung.reached .rung-lv,
.journal-page .panel.rung.reached .rung-name { color: var(--gold, #c9a227); }
.journal-page .panel.rung.reached .rung-desc { color: var(--text-secondary); }
.journal-page .panel.rung.next .rung-name { color: var(--text-primary); }

/* ⚠️ Run text must scale with the cell too (same reason as trap 8). A run is
 * n cells wide but its type was fixed at 14px, so on a phone "QUARRY LOG" and
 * "◀ BACK" overflowed faces that had shrunk under them. */
.run .t { font-size: clamp(10px, calc(var(--w) * 0.27), 14px); }
.run .s { font-size: clamp(9px, calc(var(--w) * 0.23), 12px); }

/* Log entry text (cells are 2x the page size — see comb-2x). */
.journal-page .c.fam .log-name { font-size: 12.5px; line-height: 1.25; font-weight: 600; }
.journal-page .c.dark .log-mark { font-size: 11px; line-height: 1.3; color: var(--text-muted); }

.journal-page .c.fam.taught .log-name { font-style: italic; opacity: .85; }

/* ⚠️ `overflow-wrap: anywhere` is a last resort for arbitrary strings; on a
 * quarry NAME it splits "Moonpetal" across two lines mid-word, which reads as a
 * rendering fault. Names get a slightly smaller face and normal wrapping. */
.journal-page .c.fam .log-name { overflow-wrap: normal; font-size: 12px; }
.journal-page .c.dark .log-mark { overflow-wrap: normal; }

/* --------------------------------------------------------------------------
 * Panels sit ON the lattice (trap 10)
 *
 * ⚠️ A panel takes the same half-cell offset a row does. Without it a panel
 * following an offset row starts flush against the lattice instead of nestling
 * into it — visible as "the sign section does not nestle to anything".
 *
 * ⚠️ AND DO NOT OVERRIDE THE BODY PADDING. That padding is the border
 * RING clearance (1.62 cells across, 1.06 down); replacing it with a flat few
 * pixels is what put the reading text on top of the outermost hexes. If a panel
 * needs to be tighter, change the type size, never the inset.
 */
.journal-page .panel.off,
.quarry-field .panel.off { margin-left: calc(var(--w) * .5); }

/* The readings are the primary control here, so give their text room to
   breathe inside the ring rather than clinging to it. */
.journal-page .panel.reading .reading-text,
.quarry-field .panel.reading .reading-text { margin-bottom: 2px; }


/* The rule of the loop, stated where the loop happens. Quieter than the sign
   itself — it is reference, not narration. */
/* The disclosure for the rule. Quiet — it is a control on a note, not on the
   decision, and it must not compete with the readings below it. */
.journal-page .sign-rule-head,
.quarry-field .sign-rule-head {
  margin-top: 8px;
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
  cursor: pointer;
  user-select: none;
  display: inline-block;
}
.journal-page .sign-rule-head:hover,
.quarry-field .sign-rule-head:hover { color: var(--text-secondary); }
.journal-page .sign-rule-head:focus-visible,
.quarry-field .sign-rule-head:focus-visible { outline: 2px solid var(--text-accent); outline-offset: 2px; }
.journal-page .sign-rule-head + .sign-rule,
.quarry-field .sign-rule-head + .sign-rule { margin-top: 4px; }

.journal-page .sign-rule,
.quarry-field .sign-rule {
  margin-top: 8px;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text-muted);
}
.journal-page .sign-rule b,
.quarry-field .sign-rule b { color: var(--text-secondary); font-weight: 700; }

/* --------------------------------------------------------------------------
 * Panels overlap their neighbour, exactly as rows do (trap 11)
 *
 * ⚠️ THIS IS WHY NOTHING "LOCKED TOGETHER". A row carries
 * `margin-top: calc(var(--h) * -0.25)` so its hexes bite into the row above —
 * that overlap IS the interlock. Panels never had it, so every panel sat a full
 * row-step below whatever came before and the seam between them stayed open,
 * however correct the parity was. Parity decides WHICH WAY they mesh; this
 * decides THAT they mesh at all.
 */
/* A panel after a ROW continues the lattice: a quarter-row bite, same as any row. */
.comb > .panel { margin-top: calc(var(--h) * -0.25); }

/**
 * ⚠️ A panel after a PANEL SHARES its last row instead of following it.
 *
 * Every panel draws its own border ring, so butting two together stacks two
 * bands of ring hexes at the seam — a thick double edge that reads as "these
 * do not join up". Overlapping by a FULL row lands the next panel's top ring
 * exactly on the previous one's bottom ring, so the seam is a single row of
 * hexes and the column reads as one honeycomb. paintPanel matches the parity
 * of that shared row.
 */
.comb > .panel + .panel { margin-top: calc(var(--h) * -1); }

/* The first child of a comb has nothing to bite into. */
.comb > .panel:first-child,
.comb > .crow:first-child { margin-top: 0; }

/* The commit button, at the foot of the reading it commits to. Sized to the
   panel's inner width by fitPanelCtas() — see the note there. */
/**
 * ⚠️ The button is positioned by paintPanel against the panel's own lattice —
 * it is absolute, not in the flow. In the flow the body's bottom padding (the
 * ring clearance) always kept it a row short of the border.
 */
.journal-page .panel-cta,
.quarry-field .panel-cta { position: absolute; }

/* Reserve the button's row so the prose above cannot run into it. The panel
   is sized from body.scrollHeight, and padding counts toward that. */
.journal-page .panel.has-cta > .body,
.quarry-field .panel.has-cta > .body { padding-bottom: calc(var(--h) * 1.95); }
.journal-page .panel-cta > .run,
.quarry-field .panel-cta > .run { cursor: pointer; }
.journal-page .panel-cta > .run .t,
.quarry-field .panel-cta > .run .t { font-size: clamp(9px, calc(var(--w) * 0.2), 12px); }
.journal-page .panel-cta > .run .s,
.quarry-field .panel-cta > .run .s { font-size: clamp(8px, calc(var(--w) * 0.16), 10px); }

/* --------------------------------------------------------------------------
 * The take result ([D-41]) — what you actually came away with.
 * Lives in a HexUI modal on both the journal and the map, so it is styled here
 * (journal.css is loaded by both).
 */
.quarry-result { font-family: 'Courier New', Courier, monospace; text-align: center; padding: 4px 2px; }
.quarry-result .qr-title {
  margin: 0 0 10px; font-size: 17px; letter-spacing: .04em; color: var(--text-primary);
}
.quarry-result.is-drift .qr-title { color: var(--color-hunger, #cc8833); }
.quarry-result .qr-drift {
  margin: 0 0 10px; font-size: 13px; line-height: 1.5; color: var(--text-primary);
}
.quarry-result .qr-line { margin: 0 0 8px; font-size: 15px; color: var(--text-primary); }
.quarry-result .qr-note { margin: 0 0 4px; font-size: 11.5px; color: var(--text-muted); }
/* The HexUI button mounts a canvas here; centre it and give it the row it needs. */
.quarry-result .qr-go-host { display: flex; justify-content: center; margin-top: 14px; }

/* Fallback only — used if HexUI.Button is somehow unavailable. */
.quarry-result .qr-go {
  padding: 9px 22px; cursor: pointer;
  font-family: inherit; font-size: 13px; font-weight: 700; letter-spacing: .05em;
  color: var(--bg-darkest); background: var(--gold, #c9a227);
  border: 2px solid var(--border-gold, #8a6a1f);
  clip-path: polygon(10px 0, 100% 0, calc(100% - 10px) 100%, 0 100%);
}
.quarry-result .qr-go:hover { filter: brightness(1.15); }
.quarry-result .qr-go:focus-visible { outline: 3px solid var(--text-accent); outline-offset: 2px; }
.quarry-result .qr-level { margin: 6px 0 0; font-size: 12.5px; color: var(--gold, #c9a227); font-weight: 700; }
/* A tracking encounter is the rarest thing this panel will ever show — it gets
   its own framed block so it cannot read as another cost/xp footnote. */
.quarry-result .qr-encounter {
  margin: 12px 4px 2px; padding: 9px 10px;
  font-size: 13px; line-height: 1.55; text-align: left; color: var(--text-primary);
  border: 1px solid var(--border-gold, #8a6a1f);
  background: rgba(201, 162, 39, 0.08);
}
