/* ============================================================================
   THE CONTROL PANEL — one component, both rentals pages.

   Loaded after design.css on /rentals/design and after rentals.css on
   /rentals. Nothing about this component goes into an existing file, and
   nothing in this file may be consumed by a page that is not one of those two.

   Sections, in order: STATE, BUILD (canvas only), SEND, KEEP.
   Send above Keep. Darrell, 2026-08-31: with Keep first the order reads as a
   sequence — save, then send — and the failure that produces is a bride who
   saves, gets distracted, and never sends.

   ⚠️ NAMESPACE IS `cpanel`, AND EVERY SELECTOR HERE IS ONE. Verified free
   across all seven stylesheets. The names this file may NOT reach for, all
   taken and all live:

       .rail       rentals.css, the browse page's sticky room index (7 uses),
                   and design.css uses it too. An early draft of the lab export
                   emitted a bare `.rail` and would have restyled the room
                   index on /rentals the moment this file loaded.
       .dock       rentals.css, the wish tray's pill
       .edock*     design.css, the component this one replaces
       .keeplist   rentals.css, the block this one replaces
       .keep-*     rentals.css, same
       .acts       design.css, the caption's action row
       .ctrl       design.css
       .spine      design.css, the step strip — added 2026-08-31, after the
                   lab verified the list above

   design.css:5 records rentals.css and design.css fighting over
   .shelf / .workspace / .spread / .rmv. This repo has been here before.
   ============================================================================ */

/* ⚠️ DECLARED ON THE COMPONENT, NEVER AT :root. At :root these are global and
   every page loading this file inherits them. For contrast, design.css:132
   puts --fold-dur and --ease at :root today and calls them "page-locals" in
   the comment beside them. That is the thing not to repeat.

   ⚠️ --ease IS DECLARED HERE BECAUSE IT DOES NOT EXIST ON /rentals. It is
   declared once in the house, at design.css:135, and /rentals loads
   tokens → base → emerald → pages → rentals with no design.css. Reading
   var(--ease) there makes the whole `transition` declaration invalid at
   computed-value time, so the panel would animate on the canvas and sit dead
   on the wall — the same file, silently behaving differently on two pages.
   --ease-out is in tokens.css and emerald.css and is on both. */
.cpanel, .cpanel__rail {
  --panel-offset: 4px;
  --panel-width:  264px;
  --panel-pad:    26px;
  --panel-gap:    12px;
  --panel-dur:    500ms;
  --ease:         var(--ease-out);
}

/* ============================================================
   COLOUR — read from the house, never written here
   ============================================================
   The lab exports literals because it computes contrast against them. They
   are converted to tokens on the way in, and every one maps exactly:

       #0A0908 → --velvet        "the one panel"
       #B8860B → --gilt          "fills, focus rings, seed halos"
       #E8CD82 → --champagne     "gilt as type on a dark ground"
       #4C9A74 → --emerald-lit   "the stroke's velvet voice — dark grounds only"
       #45705C → --emerald-mid

   ⚠️ --emerald-lit AND --emerald-mid, NOT --wash AND --amber, even though
   rentals.css:49 re-scopes those two to exactly these values on these two
   pages. They are the same colour today and they are not the same decision:
   --wash is the branding packet's row-hover tint and --amber is its stroke,
   both of which answer to the packet. What this panel wants is the velvet
   family, which answers to the dark ground it sits on. Point the panel at
   --wash and the day the packet moves its tint, a velvet panel follows a
   decision that was never about it. Three separate bugs in one week came from
   a rule written for a token's old value; this is that shape, pre-empted.
   ============================================================ */

/* ⚠️ THE STAGE PASSES POINTERS THROUGH, ITS CHILDREN DO NOT. Same pattern the
   shipped .edock used, and it is load-bearing twice over: the canvas has to
   stay draggable under a full-viewport overlay, and askFavorite() positions
   the favourite prompt by the difference between two rects — the Send
   control's and this element's — so the stage must have a box to measure. */
/* ⚠️ THE STAGE STARTS BELOW THE SITE CHROME, AND EVERYTHING INSIDE IS
   POSITIONED AGAINST IT. The export anchors the panel at `top: 4px` and the
   rail at `top: 50%`, which is exactly right on the lab's own stage — the lab
   has no site nav. Both real pages carry a 43px topbar and a 75px sticky nav
   at z-index 70, so a panel at 4px puts its heading, its close control and its
   first list row underneath them. Found by clicking a remove button that was
   visible and unreachable.

   Inset the STAGE rather than each child, and the exported geometry survives
   untouched: `top: 4px` and `top: 50%` still mean what they meant, only now
   inside the box the panel is actually allowed to use.

   ⚠️ --panel-chrome IS MEASURED, NOT GUESSED. panel.js reads the nav's height
   at boot and on resize. The 78px here is the fallback for the moment before
   that runs and for the case where it never does; it is deliberately a hair
   over the measured 75 so the first paint cannot land under the rule. A
   hard-coded number alone would drift the first time the nav gains a link. */
.cpanel__stage {
  --panel-chrome: 78px;
  position: fixed; inset: var(--panel-chrome) 0 0 0;
  pointer-events: none; z-index: 40;
}
.cpanel__stage > * { pointer-events: auto; }

.cpanel {
  width: var(--panel-width);
  display: flex; flex-direction: column; gap: var(--panel-gap);
  padding: var(--panel-pad);
  background: var(--velvet);
  border: 2px solid var(--gilt);
  border-radius: 3px;
  box-shadow: 0 6px 22px -8px rgba(10, 9, 8, .18);
  color: var(--emerald-lit);

  /* Inset rail: full height with a gutter all round.
     ⚠️ ABSOLUTE, AS THE EXPORT SAYS, BUT AGAINST THE STAGE AND NOT THE PAGE.
     That distinction is the whole reason the stage is fixed. /rentals is about
     14,000px of grid; absolute against that document would make a 14,000px
     panel, which is what the handoff's §5 warns about for anything measured
     from a rect. Absolute against a viewport-sized fixed stage is the same
     picture on both pages and keeps every offset in this rule meaning what the
     lab dialled. */
  position: absolute; right: var(--panel-offset);
  top: var(--panel-offset); bottom: var(--panel-offset);
  z-index: 40;
}

/* ⚠️ THE SCROLL MOVED OFF .cpanel AND ONTO THE BODY, and that is the second
   departure from the export. The exported line is `overflow-y: auto` on
   .cpanel, which is correct for everything the lab could see — it measured
   internal scrolling at 1280x720 and nothing clipped. The lab has no wish
   tray. This panel's foot holds one, it is absolutely positioned and it opens
   its list UPWARDS, so a panel that scrolled as one piece would clip that list
   at its own edge. The shipped dock split body from foot for the same reason
   (design.css:1659). The behaviour the lab dialled — the panel scrolls
   internally rather than clipping at short viewport heights — is preserved
   exactly; only the element carrying it changed. */
/* ⚠️ THE INSET PADDING IS WHAT LETS THE GLOW OUT, and it is not spacing.
   Darrell, 2026-09-01: the Send button's edges are cut off when it lights up.

   `overflow-y: auto` is the cause, and CSS gives no way to ask for only one
   axis: a box that scrolls vertically computes overflow-x to `auto` too, so
   this container clipped flush against its own content edge. Every button in
   here is width:100%, which puts its edge exactly on that line — and the hover
   is `0 0 0 1px champagne, 0 0 64px -13px champagne`, a ring plus a glow
   reaching about 19px out. All of it was cut, on every button; Send was simply
   the one big enough to notice.

   Padding the scroll box and pulling it back by the same amount moves the clip
   line 22px outward while leaving the content box exactly where it was, so the
   buttons keep their width. Narrowing Send instead — which is what Darrell
   suggested — would have fixed the one he could see and left the save and
   recover buttons clipped in the same way. The panel's own 26px padding is
   what the glow now paints into; the room was already there and unused. */
.cpanel__body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding-inline: 22px; margin-inline: -22px;
  display: flex; flex-direction: column; gap: var(--panel-gap);
}
.cpanel__foot { flex: none; position: relative; padding-top: .75rem; }
.cpanel__foot #trayhost .dockwrap.inline { display: block; }

/* ⚠️ `body.em` IS ON THIS SELECTOR TO OUT-SPECIFY emerald.css, which sets the
   heading weight with `body.em h3` at (0,1,2). Every section title is an <h3>,
   so the bare `.cpanel__head` at (0,1,0) lost — the size took and the weight
   silently did not, and it measured 20px/500 with `font-weight: 600` sitting
   right there in the file. Loading later does not help when the other selector
   is more specific. Second time this exact shape has bitten in this file; the
   first was .tray-submit against `body.em .tray-submit`. */
body.em .cpanel__head {
  /* ⚠️ GARAMOND, NOT NOTO SERIF DISPLAY. Darrell, 2026-09-02: "change the
     section titles to Gara[m]ond ... no changes to the size or the color."
     Both rail panels, /rentals and /rentals/design.

     ⚠️ AND IT COLLIDES WITH HIS OWN ASK FROM THE DAY BEFORE. TWO ROWS IN THE
     SUITE ARE RED BECAUSE OF THIS RULE, DELIBERATELY, AND HERE IS WHY.

     rentals.mjs asserts `headSize >= 20 && headWeight >= 600` on both pages —
     written on 2026-09-01 after Darrell said twice that the section titles
     were hard to read. EB Garamond ships here at 400 ONLY (emerald.css:64-66;
     the 500 @font-face points at the same 400 file, and the file is a static
     cut, not a variable one). A 600 request therefore has no face to land on
     and the browser synthesises bold by smearing the outline — a smeared
     high-contrast serif at .12em of tracking on velvet is the precise failure
     the 20/600 note below exists to fix.

     So the two instructions cannot both be honoured with the files in this
     repo, and there were three ways to leave it:
       · declare 600 anyway — the row goes GREEN and the titles get worse,
         because the check reads the DECLARED number and cannot see synthesis.
         Green while wrong is the one outcome this repo is organised against.
       · keep Noto Serif Display — the row stays green and his 2026-09-02 ask
         is simply not done.
       · declare 500, which resolves to the real file, ship the family he asked
         for, and leave the row RED against a conflict that is real.

     The third. A red row naming an open question is honest; the fix is one
     genuine EB Garamond 600 woff2 in site/assets/fonts and this line back to
     600, and that is Darrell's call to make, not one to make quietly for him. */
  font-family: var(--text);
  /* ⚠️ 20/600, NOT THE EXPORT'S 18/500. Darrell, 2026-09-01, twice: the
     section titles are hard to read. They were already Noto Serif Display —
     measured, not assumed — so the family was never the problem. What makes a
     high-contrast display face hard here is everything else about the setting:
     uppercase, .12em of tracking, and light strokes on velvet, which optically
     thin further than the same strokes on paper. A point or two of size and a
     step of weight is what he asked for and is the right lever; the hairlines
     in the face have more to give at 20px than at 18. */
  font-size: 20px; font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--emerald-lit);
  /* ⚠️ `0 0 .5rem`, NOT `0`. The lab's own rule, index.html:267. Every section
     carries its own heading and the half-rem under it is what separates the
     heading from its first field. Flattening it to 0 was mine and it closed
     the panel up. */
  margin: 0 0 .5rem;
}

/* ⚠️ `.cpanel__factlabel` WAS IN THE EXPORT AND IS NOT HERE. It styled the
   facts list — "Tables in the room" and "On the floor" — which left with the
   rail's preview on 2026-08-31: both are derived figures, both are spine steps,
   and the panel holds what she types. Dropped rather than carried, because a
   rule for markup that no longer exists is dead CSS that reads as a component
   still having a part it does not. If a future export emits it again, that is
   the reason to leave it out again. */
.cpanel__label {
  font-family: var(--sans);
  /* ⚠️ 14px, AND IT IS NOW THE PANEL'S ONE BODY SIZE. Darrell, 2026-09-01:
     "the email you used" reads larger than the copy above it, and the smaller
     font is too hard to read on the dark ground — so take the larger one
     everywhere. The panel was carrying three sizes for one voice: 13 on this
     label, 12 on notes, the swap and the empty line, 11 on list captions. The
     odd one out was the label, which is why it was the one that looked wrong.
     Every rule that was 12 or 13 is now 14; the uppercase caption on a list
     row stays smaller, because it is a different role rather than the same
     text set inconsistently. */
  font-size: 14px;
  text-transform: none;
  letter-spacing: 0.06em;
  color: var(--emerald-mid);
}

/* ---------- buttons — style: ghost, hover: glow ---------- */
/* ⚠️ THE HOVER TEXT COLOUR IS ONE RULE AND IT COMES FIRST BY SPECIFICITY, not
   by order: .cpanel__btn:hover is (0,2,0) against .cpanel__btn's (0,1,0). The
   export's comment warns it must come after the resting rule, which was true
   of the lab's other hover modes; with glow alone it wins either way. Left in
   the exported order so a diff against a future export stays readable. */
.cpanel__btn:hover, .cpanel__btn:focus-visible { color: var(--gilt); }
.cpanel__btn {
  background: none; border: 1px solid transparent; color: var(--champagne);
  border-radius: 2px;
  transition: all var(--panel-dur) var(--ease);
}

.cpanel__btn:hover {
  box-shadow: 0 0 0 1px var(--champagne),
              0 0 64px -13px var(--champagne);
}

/* ---------- fields ---------- */
/* ⚠️ NO SPINNERS ON THE NUMBER FIELDS, and the wheel is blocked in JS. Both
   halves of one decision — design.css:1570 and design.js:4126. Stepping from
   8 to 100 one click at a time is not a way to enter a guest count. */
.cpanel input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.cpanel input[type="number"]::-webkit-outer-spin-button,
.cpanel input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}
.cpanel input { background: var(--velvet); color: var(--emerald-lit); }

/* ONE FORM AT A TIME, the canvas model. The swap flips which is shown.
   ⚠️ STILL TWO FORMS WITH TWO HANDLERS. wireSave and wireRecover are under
   different security rules and must not be merged into one form with a mode
   flag — the recover path has to answer identically whether or not an address
   is known, or it becomes a way to test whether an email belongs to a
   customer. design.js says so at the call site. This is presentation and
   nothing below the surface moves. */
.cpanel__row { display: flex; flex-direction: column; gap: .4rem; }
.cpanel__row .cpanel__btn { width: 100%; }

/* ---------- the collapsed rail ---------- */
/* Items: event, add, save, find, send */

.cpanel, .cpanel__rail {
  --rail-width:  34px;
  --rail-offset: 2px;
  --rail-run:    13px;
}

.cpanel__rail {
  position: absolute; right: var(--rail-offset); top: 50%; translate: 0 -50%;
  display: flex; flex-direction: column; align-items: stretch;
  background: var(--velvet);
  border: 1px solid var(--gilt); border-right: 0;
  border-radius: 3px 0 0 3px;
  box-shadow: -4px 0 14px rgba(15, 15, 14, .07);
  overflow: hidden;
  z-index: 40;
}

.cpanel__railitem {
  width: var(--rail-width); padding: var(--rail-run) 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .5rem; background: none; border: 0; cursor: pointer;
  font-family: var(--sans);
  font-size: 13px;
  letter-spacing: 0.05em;
  text-transform: none;
  color: var(--emerald-lit);
  transition: background var(--panel-dur) var(--ease), color var(--panel-dur) var(--ease);
}

/* ⚠️ CHAMPAGNE ON GILT IS 2.09:1 AND IT SHIPS THAT WAY, ON DARRELL'S
   INSTRUCTION, 2026-09-01: "exactly what I sent over, a hundred percent." This
   is the export's own pairing (rinkhover #E8CD82 on rhover #B8860B).

   I had swapped it to --ink (6.11:1) on the strength of system.mjs §2, "gilt
   takes ink", and raised it as an open decision on 2026-08-31. It was
   overruled in favour of lab fidelity, which is a call Darrell is entitled to
   make and this comment is not relitigating.

   ⚠️ BUT IT IS THE ONE PLACE IN THIS FILE WHERE LAB-EXACT AND AA DISAGREE, so
   it is written down at full volume rather than left to be rediscovered. The
   fix, if the hover ever reads as unreadable on a real screen, is one word:
   var(--ink) in place of var(--champagne) below. Nothing else moves. */
.cpanel__railitem:hover, .cpanel__railitem:focus-visible {
  background: var(--gilt); color: var(--champagne);
  /* ⚠️ THE WEIGHT STEP IS NOT IN THE EXPORT AND IT IS NOT MINE EITHER — it is
     Darrell's, 2026-08-20: "like we bolded the hover action for 8 guests 1
     table, let's apply the same hover action for Save, Saved one? and Send."
     The lab had no dial for it, so the export could not carry it, and dropping
     it would have read as a tuning decision rather than an omission. */
  font-weight: 600;
}
/* The label sets its own weight, so it does not inherit the step above — the
   one place in the rail where a hover can look right on the box and do nothing
   to the type, which is the exact mismatch the 2026-08-20 note is about. */
.cpanel__railitem:hover .cpanel__raillabel,
.cpanel__railitem:focus-visible .cpanel__raillabel { font-weight: 600; }

/* ⚠️ THE FIGURES SET THEIR OWN COLOUR, so they do not inherit the hover colour
   above and need this second rule — the same reason the shipped rail carries
   one at design.css:1411. */
.cpanel__railfacts {
  font-family: var(--sans); font-variant-numeric: tabular-nums;
  letter-spacing: .04em; color: var(--emerald-lit);
  transition: color var(--panel-dur) var(--ease);
}
/* Same pairing, same instruction, same 2.09:1 — the export's rfigureshover. */
.cpanel__railitem:hover .cpanel__railfacts,
.cpanel__railitem:focus-visible .cpanel__railfacts { color: var(--champagne); }
.cpanel__railitem + .cpanel__railitem {
  border-top: 1px solid var(--gilt);
}

/* ⚠️ SIZE GROWS THE RAIL'S THICKNESS, NOT ITS LENGTH, because the labels run
   vertically. design.css:1367 records the same thing. */
.cpanel__raillabel { writing-mode: vertical-rl; text-orientation: mixed; white-space: nowrap; }

.cpanel__railicon { display: block; width: 15px; height: 15px; flex: none; }
.cpanel__railicon svg { width: 100%; height: 100%; display: block; }

/* ⚠️ EVERY CLASS IN THIS FILE THAT SETS `display` HAS TO SAY SO AGAIN FOR
   [hidden], AND THIS IS NOT OPTIONAL TIDINESS. The UA stylesheet's
   `[hidden] { display: none }` is a plain attribute selector at (0,1,0), and a
   class selector ties it — so the later declaration wins, and every rule here
   is later than the UA's. `.cpanel { display: flex }` beat the panel's own
   `hidden` attribute and left a 264px velvet column parked over the rail,
   swallowing the click that was supposed to open it. `#drecform` had the same
   shape: the recovery form would have sat under the save form, both on screen,
   in a pair that is deliberately one-at-a-time for security reasons.

   Neither showed up as an error. The page rendered, the attribute was set, and
   `el.hidden` read true the whole time. Found by clicking the rail, which is
   why that is worth doing before the suite. */
.cpanel[hidden],
.cpanel__rail[hidden],
.cpanel__body[hidden],
.cpanel__sec[hidden],
.cpanel__row[hidden],
.cpanel__field[hidden],
.cpanel__list[hidden],
.cpanel__railitem[hidden],
.cpanel__railicon[hidden],
.cpanel__swap[hidden],
.cpanel__divider[hidden],
.cpanel__mark[hidden] { display: none; }

/* ============================================================
   NOT FROM THE EXPORT — structure the lab did not dial
   ============================================================
   The export carries surface, offsets, buttons, glow, rail, fields and type.
   Everything below is layout the component needs to exist and the lab had no
   dial for. It reads the same tokens and adds no colour decision.
   ============================================================ */

/* lab index.html:272 — sections are plain blocks; the panel's own gap and each
   section's heading do the separating. .55rem was mine and it was inventing a
   rhythm the lab already had. */
.cpanel__sec { display: block; }

/* ⚠️ THE DIVIDER IS AN ELEMENT, NOT A BORDER, and it goes BETWEEN sections
   rather than in front of them — lab index.html:399, and the comment there
   says why the other way round was wrong: prepending one to each section puts
   a rule above whichever section happens to be first. It is a gilt hairline,
   the panel's own line colour. Missing entirely from the first pass. */
/* ⚠️ `flex: none` IS NOT DECORATION. .cpanel__body is a flex column, and a 1px
   <hr> is a flex item with a default flex-shrink of 1. The canvas panel carries
   one section more than the wall's, so its content overflowed first and the
   three rules were shrunk to 0px — present in the DOM, styled correctly, and
   exactly zero pixels tall. The wall's stayed at 1px, which is how a rule can
   look right on one page and be invisible on the other. */
.cpanel__divider { flex: none; height: 1px; background: var(--gilt); border: 0; margin: 0; }

/* ⚠️ THE MARK — lab index.html:488. Mono, small, uppercase, tracked out. It
   says what the send is about to carry ("2 tables · 14 pieces" on the canvas,
   "11 pieces" on the wall) directly under the button, which is the reassurance
   the send section is built around. Also missing from the first pass, which is
   most of why the send section "didn't have the same look and feel". */
.cpanel__mark {
  font-family: var(--mono); font-size: .58rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--emerald-mid); margin: .5rem 0 0;
}

/* ⚠️ THESE ARE THE LAB'S RULES, PORTED, NOT REDERIVED. The export is GENERATED
   — control-panel-lab/index.html:1461 builds it from the dials the lab exposes
   — so it emits the tuned decisions and none of the base stylesheet under
   them. Everything in this block was in the lab and not in the export, which
   is exactly the gap I filled with invention the first time. Source lines are
   named per rule so the next person can diff instead of guess. */
.cpanel__field { display: grid; gap: .3rem; margin-bottom: .6rem; }
.cpanel__field:last-child { margin-bottom: 0; }

/* lab index.html:291 — the resting field. THE EDGE IS GILT, not emerald. */
.cpanel__field input {
  width: 100%; min-width: 0;
  font-family: var(--text); font-size: .9rem;
  padding: .4rem .55rem;
  border: 1px solid var(--gilt); border-radius: 2px;
}

/* lab index.html:308 — the typed figure and the derived one are the same kind
   of thing, so they are set the same way: mono, tabular, right-aligned. An
   email is read left to right and stays in the text face above. */
.cpanel__field input[type="number"] {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  text-align: right; letter-spacing: .02em;
}

/* ⚠️ THE FOCUS IS A GLOW, NOT A SECOND RING — lab index.html:323, and the
   comment there is Darrell's from 2026-08-31: the global :focus-visible draws
   an outline OUTSIDE the border, so a focused field wore two lines, its own
   edge and then a ring floating off it. Keep the edge, lose the ring, take the
   buttons' glow instead.

   The border still CHANGES COLOUR, and that is the half doing the
   accessibility work: a glow alone can be dialled to nothing, and a focus
   state that can be turned invisible is not a focus state.

   Shipping this without the glow was the single biggest visual miss in the
   first pass — a muted-green outline where the lab had a gilt edge that
   flares champagne. */
.cpanel__field input:focus-visible {
  outline: none;
  border-color: var(--champagne);
  box-shadow: 0 0 64px -13px var(--champagne);
}

/* lab index.html:296 — .7, and it is the lab's number. It sits the placeholder
   under the label it repeats, which is the point; the label above carries the
   meaning and clears its own contrast bar. */
.cpanel__field input::placeholder { color: var(--emerald-mid); opacity: .7; }

.cpanel__note {
  font-family: var(--sans); font-size: 14px; line-height: 1.45;
  color: var(--emerald-mid); margin: 0;
}
.cpanel__msg { font-family: var(--sans); font-size: 14px; margin: 0; }

/* ⚠️ A CIRCLE WITH A TRIANGLE IN IT, NOT AN ×. Darrell, 2026-09-01: use the
   same collapse control the wish tray's popup uses. That one is .tray-x — a
   28px round button with a filled triangle — and a bride meets it a few inches
   below this one, so two different shapes for the same gesture were teaching
   the control twice.

   ⚠️ THE TRIANGLE POINTS RIGHT AND THE TRAY'S POINTS DOWN, on purpose. Each
   one points where its thing goes: the tray folds downward into its bar, this
   panel folds rightward into the rail. Copying the direction as well as the
   shape would have it pointing at the floor while the panel leaves sideways. */
.cpanel__x {
  position: absolute; top: 10px; right: 10px;
  width: 28px; height: 28px; display: grid; place-items: center;
  padding: 0; border: 0; border-radius: 50%;
  background: var(--silk); color: var(--champagne);
  cursor: pointer; line-height: 1;
  transition: background .18s var(--ease), color .18s var(--ease);
}
/* Gilt takes ink — system.mjs §2. Champagne on gilt is 2.09:1. */
.cpanel__x:hover, .cpanel__x:focus-visible { background: var(--gilt); color: var(--ink); }
.cpanel__x svg { display: block; }

.cpanel__btn {
  font-family: var(--sans); font-size: 14px; letter-spacing: .06em;
  padding: .5rem .7rem; cursor: pointer; text-align: center;
}
/* ⚠️ FULL WIDTH, AND THE EXPORT COULD NOT SAY SO. The lab sets these on
   .sendbtn (index.html:392) and .addbtn (index.html:395) in its base sheet,
   which the generator never emits — it only exports the dials. Both buttons
   ran to their text instead, which is the "buttons aren't full across" of
   2026-09-01. The save/recover buttons were already right because THEIR width
   comes from .cpanel__row above, which IS in the export. */
.cpanel__btn--send { width: 100%; justify-content: center; text-align: center; }
.cpanel__btn--add {
  width: 100%; display: inline-flex;
  align-items: center; justify-content: center; gap: .5rem;
}
/* lab index.html:396 — sized in em so it tracks the label beside it. */
.cpanel__btn .cpanel__plus { width: 1em; height: 1em; flex: none; }

/* ---------- the wish list, on the wall ----------
   /rentals loses its floating pill to this. Darrell, 2026-08-31. The tray's
   own rows, remove and undo are reused rather than rebuilt — a second list
   renderer is a second thing to keep in step with the catalogue. */
.cpanel__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.cpanel__list li {
  display: flex; align-items: center; gap: .5rem;
  padding: .45rem 0; font-family: var(--sans); font-size: 14px;
  color: var(--emerald-lit);
}
.cpanel__list li + li { border-top: 1px solid var(--emerald-mid); }
.cpanel__list .cpanel__listname { flex: 1; min-width: 0; }
/* ⚠️ 500, NOT 400, AND 400 WAS AGAINST A HOUSE RULE. The system's "What never
   ships" list carries "Noto Serif Display at 400 — it stops reading as display
   and starts reading as body copy", and this set the display face at exactly
   that. Darrell, 2026-09-01, reading the inventory rail: "the current font is
   too hard to read." He read it as the wrong FAMILY; it is the right family at
   the one weight the house forbids.

   ⚠️ THE SUITE DID NOT CATCH IT, AND THAT IS THE MORE USEFUL HALF. system.mjs
   §7 reads `h1,h2,h3` only, so the rule has never applied to anything that is
   not a heading — and a product name is a <b> in a list row. The check is
   widened in the same commit; this is the defect it was widened to find. */
.cpanel__listname b {
  display: block; font-family: var(--serif); font-weight: 500;
  font-size: .95rem; line-height: 1.2; color: var(--emerald-lit);
}
.cpanel__listname span {
  /* The one that stays smaller: an uppercase tracked caption under a product
     name is a different role, not the same copy at a different size. 12 rather
     than 11 so it is not the hardest thing on the panel to read. */
  font-family: var(--sans); font-size: 12px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--emerald-mid);
}

/* ⚠️ THE THUMB'S GROUND IS PAPER, NOT VELVET, AND THAT IS THE ONE PLACE THIS
   PANEL PAINTS LIGHT. A cutout is a photograph of a real object shot on white;
   on a near-black tile it reads as a hole with an object floating in it. The
   tray's own thumb sits on --ground for the same reason. */
.cpanel__thumb {
  width: 40px; height: 40px; flex: none; border-radius: 2px;
  background: var(--paper); display: grid; place-items: center; overflow: hidden;
}
.cpanel__thumb img { width: 100%; height: 100%; object-fit: contain; }
.cpanel__thumb span {
  font-family: var(--sans); font-size: .65rem; letter-spacing: .06em; color: var(--muted);
}
/* A linen shade in the list is the shade itself. The inset rule is what keeps
   Chalk White from reading as an empty square. */
.cpanel__thumb.cpanel__shade {
  background: var(--cloth); box-shadow: inset 0 0 0 1px rgba(29, 29, 27, .12);
}

/* ⚠️ ROUND, LIKE ITS THREE SIBLINGS ELSEWHERE. rentals.css:152 records the
   argument and it holds here: a 24px round icon button is a different object
   from a rounded rectangle, and the system's square-corner rule is about
   panels, cards and controls that carry a label. */
.cpanel__rm {
  background: none; border: 1px solid var(--emerald-mid); border-radius: 999px;
  width: 24px; height: 24px; flex: none; cursor: pointer;
  color: var(--emerald-lit); font-size: .9rem; line-height: 1;
}
.cpanel__rm:hover, .cpanel__rm:focus-visible { border-color: var(--gilt); color: var(--champagne); }

.cpanel__empty { font-family: var(--sans); font-size: 14px; color: var(--emerald-mid); margin: 0; }
.cpanel__empty[hidden] { display: none; }

/* ---------- the swap, inside the panel ----------
   ⚠️ VELVET-FAMILY, NOT --amber. The shipped .edockswap underlined in --amber
   and coloured to --amber-deep on hover, which was right on the panel it lived
   in: that one was paper. This one is velvet, and on velvet --amber-deep is
   1.63:1 — an invisible control — while --amber, which these two pages re-scope
   to #45705C, is 3.53:1. Carrying the old rule across is exactly the
   token-under-a-rule bug this file's colour note is about, and it would have
   looked deliberate. Champagne is 12.78:1, velvet-text on hover is 17.64:1. */
/* ⚠️ ITS OWN LINE, WITH AIR ABOVE IT. Darrell, 2026-09-01: the way back needs
   breathing room from the sentence it follows. It was set `inline` and sat at
   the end of the replace-rule sentence, so it read as the tail of that
   sentence rather than as the other thing she can do. Both pages; the markup
   moves it out of the <p> in the same commit. */
.cpanel__swap {
  display: block; margin: .7rem 0 0;
  border: 0; background: none; padding: 0;
  /* ⚠️ `font: inherit` IS A SHORTHAND AND RESETS font-size, so anything set
     before it is thrown away. The first version of this rule put the 14px
     above it and the swap kept rendering at its inherited size — invisible in
     a diff, obvious in a measurement. Size and family go after the shorthand.
     ⚠️ POPPINS BY NAME, NOT BY INHERITANCE. Darrell, 2026-09-02: "the links
     for 'Saved one before' and 'Save a new one instead' need to be the same
     Poppins font as the rest of that section and the size needs to match the
     text just above it." `font: inherit` took the family from whatever the
     swap happened to sit inside, which after it moved out of the <p> on
     2026-09-01 was the panel root — and the panel root is not .cpanel__note.
     The text just above it IS .cpanel__note: var(--sans) at 14px. Both the
     same two values now, written out rather than inherited, so moving the
     button again cannot silently change how it is set. */
  font: inherit; font-family: var(--sans); font-size: 14px;
  font-weight: 500; color: var(--champagne); cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: 3px; text-decoration-color: var(--gilt);
}
.cpanel__swap:hover, .cpanel__swap:focus-visible {
  color: var(--velvet-text); text-decoration-color: var(--champagne);
}

/* ---------- two states the rail wears ----------
   Ported from design.css with the ground changed under them, which is the
   whole reason they are written out rather than moved.

   ⚠️ EVERY COLOUR IN BOTH RULES HAD TO CHANGE, AND NONE OF THE MOTION DID.
   They were authored for a paper rail. On velvet:
       --amber-deep   1.63:1   the nudge's label, and half the save glow
       --ink          1.00:1   the other half of the save glow — ink IS velvet
   Carried across unedited, the first-visit nudge would have pulsed a border
   around an invisible word, and the save reminder would have glowed a control
   the colour of the panel behind it. Both would have looked deliberate and
   neither would have been findable, which is the one job each of them has.
   The gilt in the pulse is already gilt and stays exactly as it was. */
@keyframes cpanelpulse {
  0%   { box-shadow: 0 0 0 0 rgba(184, 134, 11, .55); }
  70%  { box-shadow: 0 0 0 13px rgba(184, 134, 11, 0); }
  100% { box-shadow: 0 0 0 0 rgba(184, 134, 11, 0); }
}
.cpanel__stage.nudge .cpanel__rail {
  border-color: var(--gilt);
  animation: cpanelpulse 2.4s var(--ease-out) infinite;
}
.cpanel__stage.nudge #cp-event .cpanel__raillabel { color: var(--champagne); }

/* ⚠️ `cpanelsaveglow` AND `.reminding` WERE HERE AND ARE GONE, 2026-09-02.
   They pulsed #cp-save for as long as the save reminder card was on screen
   beside it — "a word that glows all day is decoration, and this one is only
   true while there is an unanswered reminder beside it", which was the right
   rule and is exactly why the glow could not outlive the card. The card was
   removed on Darrell's note; see "the save reminder, retired" in design.js.
   The rule the old block recorded is still live below, in what the SEND glow
   is allowed to do: no fill next to Send, because a wash behind a neighbouring
   section made the rail look like it had two Sends. */

/* ---------- the rail invites another table style ----------
   ⚠️ THE SAVE GLOW WITH A GROUND UNDER IT. Darrell, 2026-09-02: + Table style
   should glow "like the Save popup section of the rail, but more impactful on
   the glow effect within the + Table style rail container".

   "More impactful" and "within the container" are the same instruction read
   twice: the save glow is a text-shadow, so it lights the WORD and the rail
   item around it stays dark. Adding an inset gilt wash gives the light
   somewhere to land, which is what makes it read as the section glowing rather
   than the label. The note on cpanelsaveglow — no fill, because a wash behind
   the save section put it within a few percent of Send's resting state — does
   not apply here: this is an animated glow that returns to nothing, not a
   resting ground, and + Table style sits at the top of the rail rather than
   next to Send.

   panelSync() adds `inviting` once TWO table cards have pieces on them. The
   gate is the point; see the note there. */
@keyframes cpaneladdglow {
  0%, 100% {
    color: var(--emerald-lit);
    text-shadow: 0 0 6px color-mix(in srgb, var(--gilt) 24%, transparent);
    box-shadow: inset 0 0 0 0 transparent;
  }
  50% {
    color: var(--champagne);
    text-shadow: 0 0 16px color-mix(in srgb, var(--gilt) 78%, transparent);
    box-shadow: inset 0 0 26px -5px color-mix(in srgb, var(--gilt) 58%, transparent);
  }
}
.cpanel__stage.inviting #cp-add { animation: cpaneladdglow 3.2s ease-in-out infinite; }
/* The label carries its own colour, so the animated one has to be handed down
   or only the icon would light. */
.cpanel__stage.inviting #cp-add .cpanel__raillabel { color: inherit; }
/* Under the pointer it is being used, so it stops asking. Same as the save. */
.cpanel__stage.inviting #cp-add:hover,
.cpanel__stage.inviting #cp-add:focus-visible { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .cpanel__stage.inviting #cp-add {
    animation: none;
    color: var(--champagne);
    box-shadow: inset 0 0 26px -5px color-mix(in srgb, var(--gilt) 40%, transparent);
  }
}

/* ---------- and the rail asks to be sent ----------
   ⚠️ THE SAME GLOW, NOT A SECOND ONE. Darrell, 2026-09-02: "the glow style
   should match the + Table style collapsed rail section — I 100% love this!!"
   So it reuses `cpaneladdglow` by name rather than being copied into a
   near-identical keyframe set. Two 3.2s glows on one rail have to be the same
   glow: copies drift by a percentage point and then the rail has a bug nobody
   can describe.

   ⚠️ ONE CONCERN THE OLD SAVE GLOW RAISED, AND WHY IT DOES NOT APPLY. That
   rule refused a fill because a wash behind the SAVE section put it within a
   few percent of Send's resting state, and the rail read as having two Sends.
   The fill is on Send itself here, so the thing it could be confused with is
   the thing it is.

   ⚠️ IT CANNOT LIGHT A DEAD CONTROL. panelSync() disables #cp-send on an empty
   board, and its gate needs two started cards — so the two states cannot
   coexist. `:disabled` is belt and braces: if the gate is ever loosened, a
   greyed-out button that pulses gold is the worst possible thing to ship. */
.cpanel__stage.urging #cp-send { animation: cpaneladdglow 3.2s ease-in-out infinite; }
.cpanel__stage.urging #cp-send .cpanel__raillabel { color: inherit; }
.cpanel__stage.urging #cp-send:hover,
.cpanel__stage.urging #cp-send:focus-visible,
.cpanel__stage.urging #cp-send:disabled { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .cpanel__stage.urging #cp-send {
    animation: none;
    color: var(--champagne);
    box-shadow: inset 0 0 26px -5px color-mix(in srgb, var(--gilt) 40%, transparent);
  }
  .cpanel__stage.urging #cp-send:disabled { color: inherit; box-shadow: none; }
}

/* ---------- the first-visit callout ----------
 * ⚠️ THE RULES THAT WERE HERE ARE GONE, 2026-09-07 — the same shape as the
 * save reminder's retirement in design.css, and for a related reason.
 * `.cpanel__call`, its beak, its dismiss and its @keyframes cpanelcallin: a
 * paper card floating on the canvas at the rail's midpoint, saying "Start
 * here. Guest count, your table math, and saving your design." Darrell asked
 * for it out because the sentence had stopped being true — it read as an
 * order of operations, and nothing on the board waits for a guest count any
 * more. index.html carries the full note where the markup stood.
 *
 * ⚠️ WHAT DID NOT GO WITH IT, AND MUST NOT. `.cpanel__stage.nudge` above is
 * the glow on the collapsed rail, and it is the thing that now does the
 * callout's actual job of making a 24px sliver findable. It shares the word
 * "nudge" with the card that left, which is exactly how a deletion by
 * association happens. It is live. Darrell, 2026-09-02, on that glow: "I 100%
 * love this!!"
 *
 * ⚠️ WORTH CARRYING FORWARD IF A CARD IS EVER PROPOSED HERE AGAIN: it stayed
 * on paper rather than taking the panel's colours, deliberately — it sat
 * outside the panel, on the canvas ground, so it took the canvas's palette.
 * The same finding the save reminder left behind applies too: a quiet border
 * and a soft halo, never a crisp edge that blinks, beside a canvas somebody
 * is trying to design on.
 */

/* ⚠️ THE PACKET'S "MOTION 50%" DOES NOT REACH THIS FILE and neither does this
   file reach it. What is guarded here is only what this component animates. */
@media (prefers-reduced-motion: reduce) {
  .cpanel, .cpanel__rail, .cpanel__btn, .cpanel__railitem, .cpanel__railfacts {
    transition: none !important;
  }
  /* `.cpanel__call` was in this list until it was deleted, 2026-09-07. */
  .cpanel { animation: none; }
  /* ⚠️ THE RING STAYS. Removing the animation must not remove the signal, or
     the one thing that makes the rail findable disappears for exactly the
     people most likely to be using a keyboard to find it. */
  .cpanel__stage.nudge .cpanel__rail {
    animation: none; box-shadow: 0 0 0 3px rgba(184, 134, 11, .3);
  }
  /* The save reminder's reduced-motion rule sat here and left with the glow
     on 2026-09-02. Send's replacement carries its own, beside the animation
     it neutralises, which is where this one should have been too. */
}

/* ============================================================
   CONTRAST, computed on this ground — keep these true if a value moves
   ============================================================
     heading      --emerald-lit on --velvet    5.86:1   ✓
     figures      --emerald-lit on --velvet    5.86:1   ✓
     input text   --emerald-lit on --velvet    5.86:1   ✓
     button       --champagne   on --velvet   12.78:1   ✓
     button hover --gilt        on --velvet    6.11:1   ✓  (not in the export)
     rail hover   --ink         on --gilt      6.11:1   ✓  (was 2.09:1, above)

     label        --emerald-mid on --velvet    3.53:1   ✗  UNDER AA

   ⚠️ THE LABEL FAILS AND IT SHIPS THAT WAY, ON PURPOSE. 13px is normal text,
   so 4.5:1 applies and 3.53:1 does not clear it. It is recorded rather than
   patched, which is the treatment §1.5 of the handoff gives the two controls
   already shipping at 3.60:1 — .addcard and .tray-full — and this sits in the
   same band. The fix, if it reads badly in the browser, is one declaration:
   --velvet-soft is 12.08:1 on velvet and is declared for exactly this role.
   That is a call to make while looking at the page, not now.

   Recorded because a failing label on a working control is the kind of thing
   that otherwise gets found six months later and treated as a bug nobody
   chose.
   ============================================================ */


/* ============================================================
   THE WISH TRAY, INSIDE THIS PANEL
   ============================================================
   ⚠️ THE TRAY IS NOT THIS COMPONENT'S AND THESE RULES ARE SCOPED SO IT STAYS
   THAT WAY. .dock, .tray and their parts belong to rentals.css and are shared
   with whatever else mounts a tray; every selector below is under
   .cpanel__foot so nothing here can reach a tray mounted anywhere else.

   ⚠️ THE POPUP KEEPS ITS PAPER GROUND. Darrell, 2026-09-01: "I do like the
   paper background to set it apart." It is a list of photographed products,
   and cutouts are shot on white — the same argument .cpanel__thumb makes
   above. Only the FOOT of it changes, which is chrome rather than content.
   ============================================================ */

/* ⚠️ THE FOOT WAS --wash, WHICH THESE TWO PAGES RE-SCOPE TO #4C9A74 — the
   green bar under the list. On a paper popup hanging off a velvet panel it was
   the one surface belonging to neither. Velvet ties it to the rail it hangs
   from, which is what Darrell asked for, and it makes the two controls on it
   dark-ground controls — so they can take the panel's own gold vocabulary
   instead of the page's green one. */
.cpanel__foot .tray-foot {
  background: var(--velvet);
  border-top: 1px solid var(--gilt);
}

/* The tray's send takes the panel button's shape and its glow, so the two
   sends a bride can reach from this panel look like one kind of thing. Ghost
   at rest, gilt on hover, the champagne ring and the 64px bloom — the same
   three declarations .cpanel__btn carries, restated rather than shared because
   .tray-submit is not a .cpanel__btn and must not start inheriting from one. */
/* ⚠️ `body.em` IS ON THESE TWO SELECTORS AND IT IS NOT DECORATION. rentals.css
   sets `body.em .tray-submit { background: var(--amber); color: var(--paper) }`
   at (0,2,1); `.cpanel__foot .tray-submit` is (0,2,0) and loses, so the first
   version of this rule was written, shipped and had no effect — the button
   stayed white-on-green inside a velvet foot. Measured, not assumed: the
   computed background came back rgb(69,112,92) with every declaration below
   already in the file. Matching the scope is what wins it, and it is the
   honest scope anyway, since the rule it overrides is emerald-only too. */
body.em .cpanel__foot .tray-submit {
  background: none;
  border: 1px solid transparent;
  color: var(--champagne);
  border-radius: 2px;
  transition: all var(--panel-dur) var(--ease);
}
body.em .cpanel__foot .tray-submit:hover,
body.em .cpanel__foot .tray-submit:focus-visible {
  background: none;
  color: var(--gilt);
  transform: none;
  box-shadow: 0 0 0 1px var(--champagne),
              0 0 64px -13px var(--champagne);
}

/* ⚠️ GOLD TYPE ON A DARK GROUND IS --champagne, NOT --gilt, and that is the
   token's own job description: "gilt as type on a dark ground". Raw gilt here
   would be 3.31:1; champagne is 12.78:1.

   ⚠️ THE ACTION IS THE HOUSE TEXT LINK, restated for this ground — Darrell
   asked for "that type of link/button action from the KM Brands motion suite".
   base.css's .text-link is that suite's .km-link as it ships here: the rule
   draws left to right, the arrow nudges 5px, and the whole thing scales 1.12
   from its left edge so the first letter stays under the eye already reading
   it. Timings and easing are copied from it exactly — two links moving
   differently on one page reads as a mistake. The underline takes gilt rather
   than champagne so the rule reads as an underline and not as a second word. */
.cpanel__foot .tray-full {
  position: relative;
  background: none; border: 0; border-bottom: 0;
  padding: 0 0 1px;
  color: var(--champagne);
  display: inline-flex; align-items: center; gap: .5rem;
  transition: transform .28s var(--ease-out);
  transform-origin: left center;
}
.cpanel__foot .tray-full::after {
  content: ""; position: absolute;
  left: 0; right: 100%; bottom: 0; height: 1px;
  background: var(--gilt);
  transition: right .28s ease;
}
.cpanel__foot .tray-full:hover,
.cpanel__foot .tray-full:focus-visible { color: var(--champagne); transform: scale(1.12); }
.cpanel__foot .tray-full:hover::after,
.cpanel__foot .tray-full:focus-visible::after { right: 0; }
.cpanel__foot .tray-full .arrow { display: inline-block; transition: transform .28s var(--ease-out); }
.cpanel__foot .tray-full:hover .arrow,
.cpanel__foot .tray-full:focus-visible .arrow { transform: translateX(5px); }

/* The way into the list gets the panel's own hover — Darrell, 2026-09-01,
   asked for the glow here too. It needs a box to glow around, and .dock-open
   ships with no padding at all, so it takes the same padding and corner the
   panel's buttons wear. The three shadow values are .cpanel__btn's exactly. */
.cpanel__foot .dock-open {
  padding: .35rem .5rem; border-radius: 2px;
  transition: color var(--panel-dur) var(--ease),
              box-shadow var(--panel-dur) var(--ease);
}
.cpanel__foot .dock-open:hover,
.cpanel__foot .dock-open:focus-visible {
  color: var(--gilt);
  box-shadow: 0 0 0 1px var(--champagne),
              0 0 64px -13px var(--champagne);
}

/* ============================================================
   THE RAIL BECOMES THE CARD
   ============================================================
   ⚠️ THE RAIL WAS STILL ON SCREEN BEHIND THE OPEN PANEL. Darrell, 2026-09-01.
   Measured: the rail's box is 1403-1438 and the panel's is 1172-1436, so two
   pixels of it stood proud of the panel's right edge and the whole strip sat
   under a panel that happens to be opaque. It reads as two objects, one hiding
   the other, when the thing it should read as is one object opening.

   ⚠️ SO THE PANEL GROWS OUT OF THE RAIL'S OWN BOX. panel.js measures the rail
   at open and writes --rail-t / --rail-b / --rail-l onto the stage; the closed
   state below clips the panel to exactly that band, and .on releases it. The
   defaults in the var() fallbacks are only for a first paint before any
   measurement — they are approximately the rail and deliberately not exact,
   because an exact-looking constant is the kind of thing that gets trusted
   after the rail's height changes.

   ⚠️ THE OPEN STATE USES NEGATIVE INSETS AND MUST. The wish tray hangs off
   this panel's foot and is WIDER than the panel — 23rem against 264px — so it
   overflows to the left. Clipping the settled panel to inset(0) would cut the
   tray in half the moment it opened, which is a worse bug than the one this
   fixes and would only appear two clicks in. Negative insets keep the shape
   animating from the rail's band while leaving the settled panel clipping
   nothing at all. */
.cpanel {
  clip-path: inset(var(--rail-t, 42%) 0 var(--rail-b, 42%) var(--rail-l, 87%));
  transition: clip-path .40s var(--ease), opacity .24s var(--ease);
  opacity: 0;
}
.cpanel__stage.on .cpanel { clip-path: inset(0 -60vw -40vh -60vw); opacity: 1; }

/* And the rail steps aside while the card it became is on screen. */
.cpanel__rail { transition: opacity .22s var(--ease); }
.cpanel__stage.on .cpanel__rail { opacity: 0; pointer-events: none; }

/* ⚠️ REDUCED MOTION GETS THE STATES AND NONE OF THE TRAVEL. The panel still
   has to be clipped-to-nothing when open and the rail still has to get out of
   the way; what goes is the growing. Removing the transition alone would leave
   the closed clip-path as a starting state that never animates away, so the
   closed state is neutralised too. */
@media (prefers-reduced-motion: reduce) {
  .cpanel { clip-path: none; transition: none; opacity: 1; }
  .cpanel__stage.on .cpanel { clip-path: none; }
  .cpanel__rail { transition: none; }
}

/* ⚠️ THE COLLAPSED BAR SITS ON VELVET AND STOPS PAINTING ITS OWN. .dock rests
   on --ink with a drop shadow, which is a floating pill's costume — correct
   when it floated over the page, and a second near-black rectangle with a
   shadow now that it lives inside a velvet panel. It gives up both and keeps
   a gilt hairline instead, so the foot reads as part of the panel. */
.cpanel__foot .dock {
  background: none;
  box-shadow: none;
  border-top: 1px solid var(--gilt);
  border-radius: 0;
  color: var(--emerald-lit);
  padding: .55rem 0 0;
}
.cpanel__foot .dock b { color: var(--champagne); }
.cpanel__foot .dock-open { color: var(--champagne); transition: color var(--panel-dur) var(--ease); }
.cpanel__foot .dock-open:hover,
.cpanel__foot .dock-open:focus-visible { color: var(--gilt); }
