/* Shared top bar: brand group + profile chip. Loaded by every room. */
/* AN EXPLICIT LAYER FOR THE NAV (Rob, 2026-09-29). It had none, which is how my
   welcome bubble painted straight over it on a phone: a z-index:74 fixed element
   against an unlayered header wins every time. Decorative things -- the room hero
   below, anything later -- now sit under a stated number instead of under nobody's.
   50 leaves room beneath for page furniture and stays under the panels (75) and
   the drawer (71), which are meant to cover the bar. */
.rfh-head{ border-bottom:1px solid var(--border); position:relative; z-index:50; }
.rfh-head-in{ max-width:var(--measure-wide); margin:0 auto; width:100%;
  display:flex; align-items:center; justify-content:space-between; gap:14px;
  padding:10px 24px; padding-left:calc(24px + var(--safe-l)); padding-right:calc(24px + var(--safe-r)); }

/* the whole left group is one tap target and always goes home */
.rfh-brand{ display:flex; align-items:center; gap:11px; min-height:44px;
  text-decoration:none; color:var(--text); white-space:nowrap;
  font-family:'Cormorant Garamond',Georgia,serif; font-weight:500;
  font-size:clamp(22px, 2.5vw + 12px, 28px); }
/* THE WORDMARK IS ONE COLOUR (Rob, 2026-09-29). .rfh-rain and .rfh-sub tinted
   Rain in --rain-blue and Fern in --fern-green, with a hover brightness on each.
   All four rules are gone with the spans they styled; the word inherits --text
   from .rfh-brand above, which is the house text colour in both themes. The
   TOKENS stay -- --rain-blue and --fern-green are still used by /weather's cards,
   the Ledger's provider pills and the actors page's chips. */
.rfh-wordmark{ color:var(--text); }

/* THE MARK IS A LINE TREE (Rob, 2026-09-29), inline in _header.html so it takes
   currentColor and follows the theme. Same 40px footprint as the Sable image it
   replaces, so the header's height and the avatars' size are untouched.

   The photo framing is gone with the photo: border-radius:50%, object-fit:cover,
   background:var(--bg-card) and the --amber-dim ring existed to make a raster
   portrait read as a circular chip. A line mark in a bordered circle would also
   compete with the two round avatars three items to its right. Reported rather
   than assumed -- if the circle should stay, it is these four declarations back.

   currentColor resolves to --amber in dark and --text in light, which is the
   ruling: house gold on the dark ground, deep ink on the light one. */
.rfh-mark{ width:40px; height:40px; display:block; flex-shrink:0;
  color:var(--amber); }
html[data-theme="light"] .rfh-mark{ color:var(--text); }
.rfh-controls{ display:flex; align-items:center; gap:9px; margin-left:auto; }

/* Promoted from landing.html 2026-08-28. Landing carried these in its own
   page CSS, left over from the header it had before it adopted this include --
   so the logo shrank on landing and stayed 40px everywhere else. One logo, one
   render: the shrink belongs to the header, not to one page. */
@media (max-width:620px){
  .rfh-mark{ width:28px; height:28px; }
  .rfh-controls{ gap:6px; }
}
@media (max-width:400px){
  .rfh-head-in{ padding-left:calc(14px + var(--safe-l)); padding-right:calc(14px + var(--safe-r)); gap:8px; }
  .rfh-brand{ gap:8px; }
  .rfh-mark{ width:26px; height:26px; }
  .rfh-controls{ gap:5px; }
}

/* ---- the old profile DROPDOWN, retired 2026-09-29 -------------------------
   .rfh-pf, .rfh-pf-wrap and .rfh-pf-menu were a 258px absolutely-positioned
   menu hanging off the chip. The chip is now one of two .rfh-av avatars and
   its contents live in the shared .rfp panel, so the whole block goes rather
   than being left to rot beside its replacement. .rfh-pf-fb (the initial, for
   a traveller with no picture) SURVIVES and is styled with .rfh-av img above:
   it is the avatar itself, not the dropdown. Checked before removing: no
   template or script outside _header.html referenced any .rfh-pf-* class. */

/* ---- the field bar, retired 2026-09-27 ------------------------------------
   Lifted out of landing.html 2026-09-15 when the bar became the only
   navigation and had to live on every room; removed on 2026-09-27 when
   navigation moved to the header's drawer (Jenny 9/27 §9). Its rules, its
   partial and its 24 includes all went together.

   The comment that stood here claimed a rename ".rff-fieldbar -> .rff-fieldbar"
   and said codex.html and profile.html used that class for form rows. Neither
   survives inspection: the rename reads as a no-op and no page uses the class
   at all. It went with the bar rather than being carried forward wrong. */
/* The bar's height, and therefore every room's bottom clearance. Declared
   here, above both consumers, though custom properties resolve at computed
   value time and would work from anywhere in the sheet — a reader should not
   have to know that to follow this. Derivation is in the clearance rule at the
   foot of this file. */
:root{
  /* 0 since 2026-09-27: the bottom bar is retired and navigation moved to the
     header's drawer. The token stays because five places read it -- the body
     clearance above and Sable's floor, panel cap and keyboard clearance -- and
     one number is still better than five. */
  --fieldbar-h: 0px;
}

/* The bar's own rules -- .rff-fieldbar, .rff-f-*, .rff-fm-* and its open/closed
   states -- were removed on 2026-09-27 with the bar. Navigation is the header's
   drawer now. The token above stays at 0 because five places still read it and
   one number is better than five; the clearance rule below stays because the
   reason it was written stays.

   Checked before removing, not assumed: no template uses .rff-fieldbar or any
   .rff-f-* class any more, so nothing else falls over with these rules. */

/* ---- every room clears the field bar --------------------------------------
   The bar is position:fixed, so it sits ON the page rather than in it. A room
   with no bottom padding puts its last line behind the bar and cannot scroll
   past it — which is exactly what /lantern did to the last lines of the
   Blessing (Rob's screenshot, 2026-09-18). Confirmed as clearance and not
   truncation: the rendered page ended on the same words as the stored row.

   One rule, here, for all 25 rooms, because the alternative was what this file
   found on 9/18: four rooms padding by hand with four different numbers (150px,
   90px, 88px, and a token that had been set to 0) and eleven rooms padding not
   at all.

   --fieldbar-h is DERIVED from the bar's own rules above, not measured in a
   browser and not guessed: label row (7px + --fs-label x1.2) + item row (4px +
   --fs-lead x1.2 + 1 + --fs-label x1.2 + --fs-micro x1.2 + 9px) + 1px border.
   That is ~89px at 390px and ~93px at 720px and wider, where the clamps top
   out. 104px carries it with room for the 1.2 line-height assumption in the
   derivation; if the bar's type changes, this is the one number to change.

   !important is the cascade law: a page <style> block loads after this sheet
   and would otherwise win on equal specificity, which is how /lantern's zero
   and the landing's 88px both stood. A room may not clear the bar by less than
   the bar. Anything a page needs BELOW its content goes on its own inner
   element, not on body. */
/* --sb-clear IS GONE from this sum (Rob, 2026-09-29). Nothing writes it any
   more: it came from the narration bubble's measured height, and the bubble is
   removed. --fieldbar-h has been 0 since the bar was retired, so what is left is
   the safe area -- which is the only thing still genuinely below the content.
   The !important stays: a page <style> loads after this sheet and would win on
   equal specificity, which is how /lantern's zero and the landing's 88px both
   stood over the bar. */
body{ padding-bottom: var(--safe-b) !important; }

/* ---- the header's drawer --------------------------------------------------
   THE BOTTOM BAR IS RETIRED (Jenny 9/27 §9). --fieldbar-h above is 0 now, so
   the max() clears only Sable's bubble -- the rule stays because the reason it
   was written stays: a room may not reserve less than what stands over it. */
.rfh-menu{ appearance:none; -webkit-appearance:none; background:none; border:none;
  color:var(--text-dim); cursor:pointer; padding:6px; border-radius:8px;
  display:flex; align-items:center; justify-content:center; min-width:38px;
  min-height:38px; }
.rfh-menu:hover{ color:var(--amber); background:var(--bg-input); }
.rfh-menu:focus-visible{ outline:2px solid var(--amber); outline-offset:2px; }

.rfh-nav-scrim{ position:fixed; inset:0; background:rgba(0,0,0,.45); z-index:70;
  opacity:0; pointer-events:none; transition:opacity .2s ease; }
.rfh-nav-scrim.on{ opacity:1; pointer-events:auto; }

.rfh-nav{ position:fixed; top:0; right:0; z-index:71; height:100%;
  width:min(280px, 86vw); background:var(--bg-card);
  border-left:1px solid var(--border); box-shadow:var(--shadow);
  transform:translateX(100%); transition:transform .22s cubic-bezier(.2,.9,.3,1);
  display:flex; flex-direction:column; overflow-y:auto;
  padding:calc(10px + var(--safe-t, 0px)) 0 calc(14px + var(--safe-b)) 0; }
.rfh-nav.open{ transform:translateX(0); }
.rfh-nav-top{ display:flex; align-items:center; justify-content:space-between;
  padding:4px 14px 10px; }
.rfh-nav-h{ font-size:var(--fs-label); letter-spacing:.14em; text-transform:uppercase;
  color:var(--text-dim); }
.rfh-nav-x{ appearance:none; background:none; border:none; color:var(--text-dim);
  font-size:var(--fs-lead); line-height:1; cursor:pointer; padding:4px 6px; }
.rfh-nav-x:hover{ color:var(--amber); }
.rfh-nav-list{ display:flex; flex-direction:column; }
.rfh-nav-it{ display:flex; align-items:center; gap:11px; min-height:var(--tap);
  padding:10px 16px; color:var(--text); text-decoration:none;
  font-size:var(--fs-body); }
a.rfh-nav-it:hover{ background:var(--bg-input); color:var(--amber); }
a.rfh-nav-it:focus-visible{ outline:2px solid var(--amber); outline-offset:-2px; }
.rfh-nav-it.on{ color:var(--amber); box-shadow:inset 3px 0 0 var(--amber); }
.rfh-nav-i{ font-size:var(--fs-lead); line-height:1; width:24px; text-align:center; }
.rfh-nav-it.soon{ color:var(--text-dim); opacity:.62; cursor:default; }
/* THE HOUSE NAMES ITS PARTS (fence "Sable's host", item 15). Tokens only, and
   --text-dim because a credit line is metadata and never body copy (§6). */
.rfh-nav-credit{ margin-top:auto; padding:14px 16px 4px; display:flex;
                 flex-direction:column; gap:3px; font-size:var(--fs-micro);
                 color:var(--text-dim); line-height:1.5; }
.rfh-nav-credit-b{ letter-spacing:.08em; }

.rfh-nav-s{ margin-left:auto; font-size:var(--fs-micro); letter-spacing:.14em;
  text-transform:lowercase; color:var(--text-dim); }
.rfh-nav-rule{ height:1px; background:var(--border-light); border:0; margin:10px 16px; }
body.nav-locked{ overflow:hidden; }

@media (prefers-reduced-motion:reduce){
  .rfh-nav{ transition:none; }
  .rfh-nav-scrim{ transition:none; }
}

/* The max() that used to be in the rule above is gone with both of its terms.
   It existed to reconcile the retired field bar's floor with the reservation
   Sable's narration bubble needed; neither the bar nor the bubble exists. §6's
   law -- nothing of hers may trap an interactive element -- is satisfied
   structurally now: the only thing of hers on screen is a panel the traveller
   opened, and it can be dragged out of the way. */

/* ==== THE TWIN PANELS ======================================================
   ONE shell, two instances (Rob, 2026-09-29). Sable's avatar and the
   traveller's sit side by side in the nav and open the same component: same
   size, frame, shadow, header bar, animation and drop position. Tapping
   between them is meant to feel like two tabs of one UI, which only holds if
   there is literally one definition of the UI -- so the shell lives here, in
   the file every one of the 26 pages already loads, and each panel supplies
   only its own contents.

   Sable's panel keeps its innards in sable.css (.sb-log, .sb-boxrow); the
   traveller's are a few lines further down this file. Neither owns a frame.

   Replaces the floating lamp, its drag, its "hold to move / tap to chat"
   caption and the "Need help?" pill, all removed. The lamp's localStorage key
   'sable.lamp.pos' is cleared on load -- see header.html's rfpForget(). */
.rfp{
  display:none; position:fixed; z-index:75;
  top:var(--rfp-t, 60px); left:var(--rfp-l, auto); right:var(--rfp-r, 12px);
  width:min(420px, calc(100vw - 24px));
  max-height:var(--rfp-max, 70vh);
  background:var(--bg-card); color:var(--text);
  border:1px solid var(--amber-dim); border-radius:16px;
  box-shadow:var(--shadow), 0 18px 48px rgba(0,0,0,.34);
  flex-direction:column; overflow:hidden;
}
.rfp.open{ display:flex; animation:rfpIn .18s cubic-bezier(.2,.9,.3,1); }
@keyframes rfpIn{ from{ opacity:0; transform:translateY(-8px) scale(.985); }
                  to{ opacity:1; transform:none; } }
/* EXPANDED: near full screen on a phone, a generous card on a desktop. The
   same class on both panels, so expand means one thing in the house. */
.rfp.big{
  width:min(760px, calc(100vw - 16px));
  max-height:calc(100vh - var(--safe-t, 0px) - var(--safe-b) - 16px);
  top:calc(8px + var(--safe-t, 0px));
  right:8px; left:auto;
}
/* While dragged, left/top drive it and right is released. */
.rfp.moved{ right:auto; }

/* ---- the header bar: identical on both, right to left = ✕ · expand · move */
.rfp-bar{
  display:flex; align-items:center; gap:8px; flex:0 0 auto;
  padding:10px 10px 10px 12px; border-bottom:1px solid var(--border);
  background:var(--bg-card);
}
.rfp-ttl{ font-family:'Cormorant Garamond',Georgia,serif; font-size:var(--fs-body);
  color:var(--text); margin-right:auto; white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; }
.rfp-acts{ display:flex; align-items:center; gap:2px; flex:0 0 auto; }
/* 44px of target around a 20px glyph (§6): the law is about the target, and a
   32px visual button with 6px of padding each side clears it without three
   fat squares crowding a 360px bar. */
.rfp-ic{
  appearance:none; -webkit-appearance:none; background:none;
  border:1px solid transparent; border-radius:9px;
  color:var(--text-dim); cursor:pointer;
  min-width:34px; min-height:34px; padding:7px;
  display:flex; align-items:center; justify-content:center;
  font:inherit; line-height:1; transition:color .15s, border-color .15s, background .15s;
}
.rfp-ic:hover{ color:var(--amber); background:var(--bg-input); }
.rfp-ic:focus-visible{ outline:2px solid var(--amber); outline-offset:2px; }
.rfp-ic.x{ font-size:1.25rem; }
/* The move handle is a drag surface, not a tap target: it must not scroll the
   page under the finger while it is being held. */
.rfp-move{ cursor:grab; touch-action:none; }
.rfp-move:active{ cursor:grabbing; }
.rfp.moved .rfp-move{ color:var(--amber); }

.rfp-body{ flex:1 1 auto; min-height:0; overflow-y:auto;
  -webkit-overflow-scrolling:touch; overscroll-behavior:contain; }

/* ---- the two avatars in the nav ----------------------------------------
   Same size, same circular frame, side by side: AI and traveller. The open
   one carries a thin gold ring; closed is plain. */
.rfh-av{
  appearance:none; -webkit-appearance:none; background:none; border:none;
  padding:0; cursor:pointer; flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
  /* 34px circle, 44px target (§6) -- the ring must not grow the row, so the
     target is claimed with padding and the row's height is unchanged. */
  min-width:var(--tap, 44px); min-height:var(--tap, 44px);
  border-radius:50%;
}
.rfh-av img, .rfh-av .rfh-pf-fb{
  width:34px; height:34px; border-radius:50%; object-fit:cover;
  border:1px solid var(--amber-dim); display:block;
  box-sizing:border-box; transition:box-shadow .15s, border-color .15s;
}
.rfh-av[aria-expanded="true"] img,
.rfh-av[aria-expanded="true"] .rfh-pf-fb{
  border-color:var(--amber);
  box-shadow:0 0 0 2px var(--amber);       /* the thin gold ring = open */
}
.rfh-av:focus-visible{ outline:2px solid var(--amber); outline-offset:2px; }
.rfh-sb img{ background:var(--bg-card); }

/* ---- the traveller's panel contents (moved out of the old dropdown) ---- */
.rfp-pf-id{ padding:13px 15px 12px; border-bottom:1px solid var(--border); }
.rfp-pf-nm{ font-size:var(--fs-body); font-weight:500; color:var(--text); }
.rfp-pf-un{ font-size:var(--fs-small); color:var(--text-dim); margin-top:2px;
  word-break:break-all; }
.rfp-pf-edit{ display:inline-block; margin-top:8px; font-size:var(--fs-small);
  color:var(--amber); text-decoration:none; }
.rfp-pf-edit:hover{ text-decoration:underline; }
.rfp-pf-sec{ padding:12px 15px; border-bottom:1px solid var(--border); }
.rfp-pf-h{ font-size:var(--fs-micro); letter-spacing:.18em; text-transform:uppercase;
  color:var(--text-dim); margin-bottom:9px; }
.rfp-pf-line{ display:flex; align-items:center; justify-content:space-between;
  gap:10px; font-size:var(--fs-small); padding:3px 0; color:var(--text); }
.rfp-pf-line .rfh-k{ color:var(--text-dim); }
.rfp-pf-line .rfh-g{ color:var(--amber); margin-right:5px; }
.rfp-pf-note{ margin-top:8px; font-size:var(--fs-label); line-height:1.45;
  color:var(--text-dim); }
.rfp-pf-await{ font-size:var(--fs-small); color:var(--text); margin-bottom:10px; }
.rfp-pf-nav{ display:flex; flex-wrap:wrap; gap:14px; }
.rfp-pf-go{ font-size:var(--fs-small); color:var(--text); text-decoration:none;
  min-height:var(--tap, 44px); display:inline-flex; align-items:center; }
.rfp-pf-go:hover{ color:var(--amber); }
.rfp-pf-out{ display:flex; align-items:center; padding:12px 15px;
  min-height:var(--tap, 44px); font-size:var(--fs-small);
  color:var(--text-dim); text-decoration:none; transition:.2s; }
.rfp-pf-out:hover{ color:var(--amber); background:var(--bg-input); }

@media (prefers-reduced-motion:reduce){
  .rfp.open{ animation:none; }
  .rfp{ transition:none; }
}

/* ---- 360px: the toggle moves into the drawer -----------------------------
   Rob's ruling, 2026-09-29: if the wordmark does not fit, the theme toggle
   goes into the menu drawer, and neither avatar is ever shrunk.

   The fixed furniture on the right was 134px (toggle 52 + avatar 34 + menu 38
   + two 5px gaps). Sable adds 39px, making 173px, which leaves 117px for
   "RainFern" at 360 -- it had 156px. I could not measure the glyph width
   without a browser, so this applies the remedy at the width where it is in
   doubt rather than asserting a fit I never saw. Below 420px the toggle is in
   the drawer and the header carries Sable + traveller + menu = 121px, so the
   wordmark keeps 169px -- MORE than it has today. Above 420px the toggle
   stays in the bar where there is room for all four.
   If a browser later shows 117px was fine, this block is the one thing to
   delete; nothing else depends on it. */
.rfh-nav-theme{ display:none; }
@media (max-width:419px){
  .rfh-head .rf-theme{ display:none; }
  .rfh-nav-theme{ display:flex; }
}
.rfh-nav-theme{ align-items:center; justify-content:space-between; gap:10px;
  padding:10px 16px; min-height:var(--tap); }
.rfh-nav-theme span{ font-size:var(--fs-body); color:var(--text); }

/* Shown but inert: /chat IS the chat, so her avatar is not a door there. Dimmed
   enough to read as unavailable without going invisible -- the nav must not
   change shape from room to room. */
.rfh-av[disabled]{ cursor:default; opacity:.45; }
.rfh-av[disabled] img{ border-color:var(--border); }

/* HER LAMP, GLOWING (§31, Rob 2026-10-06). Narration lights this; it never
   opens the panel. The ring is the signal and the dot is the count -- one is
   enough, because the panel holds the words and the traveller decides when to
   read them. Before this, any narration opened the panel over whatever room the
   traveller was standing in. */
.rfh-av.rfh-sb.glow img, .rfh-av.rfh-sb.glow .rfh-pf-fb{
  box-shadow:0 0 0 2px var(--amber), 0 0 10px 1px var(--amber-dim);
}
.rfh-av.rfh-sb.glow{ position:relative; }
.rfh-av.rfh-sb.glow::after{
  content:''; position:absolute; top:-1px; right:-1px;
  width:8px; height:8px; border-radius:50%;
  background:var(--amber); border:1.5px solid var(--bg);
}
@media (prefers-reduced-motion: no-preference){
  .rfh-av.rfh-sb.glow img, .rfh-av.rfh-sb.glow .rfh-pf-fb{
    animation:rfhLamp 2.4s ease-in-out infinite;
  }
  @keyframes rfhLamp{
    0%,100%{ box-shadow:0 0 0 2px var(--amber), 0 0 6px 0 var(--amber-dim); }
    50%    { box-shadow:0 0 0 2px var(--amber), 0 0 13px 2px var(--amber-dim); }
  }
}
