/* ── The builder shell ───────────────────────────────────────────────────────
   One chrome for all four editors: the admin column-layout builder, the admin
   free canvas, the customer's Quick Build and the customer's free canvas.

   The shape is always the same — a thin toolbar across the top, a fixed-width
   sidebar of collapsible panels down the left, and the real newspaper filling
   whatever is left. Controls live in the sidebar, so the page you are actually
   judging gets the room.

   Everything is a `bx-` class driven by the custom properties below, which is
   what lets the admin (dark) and the customer (light) share one stylesheet:
   only the tokens change, never the rules. Add `.bx-dark` for the admin.

   Loaded on every page by `stylesheet_link_tag :app`, so every selector here is
   namespaced under a `bx-` class and can't leak into the rest of the site.
   ────────────────────────────────────────────────────────────────────────── */

.bx-shell {
  /* Surfaces */
  --bx-bg: #f1ede4;
  --bx-panel: #fffdf8;
  --bx-sunken: #fdfbf5;
  --bx-mat: #e9e6df;
  /* Lines */
  --bx-line: rgba(29, 24, 18, 0.12);
  --bx-line-strong: rgba(29, 24, 18, 0.2);
  /* Ink: body, secondary, faint labels */
  --bx-ink: #1d1812;
  --bx-ink-2: #6b6255;
  --bx-ink-3: #9a9082;
  /* Accent + the one destructive colour */
  --bx-accent: #b76e79;
  --bx-accent-ink: #8f4d57;
  --bx-accent-soft: rgba(183, 110, 121, 0.09);
  /* What reads on top of a solid accent — dark, where the accent is light. */
  --bx-on-accent: #fff;
  --bx-danger: #b4434f;
  --bx-danger-soft: rgba(180, 67, 79, 0.08);

  --bx-sidebar: 306px;
  --bx-radius: 9px;
  /* What's already pinned above the shell (the site header) and how tall the
     shell's own toolbar is. Measured by builder_shell_controller; the fallbacks
     are what a shell with no JavaScript yet gets. */
  --bx-top: 0px;
  --bx-toolbar-h: 3.3rem;

  display: flex;
  flex-direction: column;
  position: relative;
  background: var(--bx-bg);
  color: var(--bx-ink);
  font-family: "Jost", system-ui, -apple-system, sans-serif;
}

.bx-shell.bx-dark {
  --bx-bg: rgb(2 6 23);
  --bx-panel: rgb(15 23 42);
  --bx-sunken: rgb(2 6 23);
  --bx-line: rgb(30 41 59);
  --bx-line-strong: rgb(51 65 85);
  --bx-ink: rgb(226 232 240);
  --bx-ink-2: rgb(148 163 184);
  --bx-ink-3: rgb(100 116 139);
  --bx-accent: rgb(244 114 182);
  --bx-accent-ink: rgb(244 114 182);
  --bx-accent-soft: rgba(244, 114, 182, 0.1);
  --bx-on-accent: rgb(2 6 23);
  --bx-danger: rgb(248 113 113);
  --bx-danger-soft: rgba(127, 29, 29, 0.35);
}

/* A builder that owns the whole window (the customer editors) rather than
   sitting inside a page of admin chrome. */
.bx-shell.bx-full { min-height: 100vh; }
/* A builder embedded in a page of other chrome (the admin) gets a card of its
   own. The corners are rounded on the children rather than clipped on the
   shell: an `overflow` here would make it the scroll container, and the sticky
   toolbar and sidebar inside would quietly stop sticking. */
.bx-shell.bx-boxed { border: 1px solid var(--bx-line); border-radius: 14px; }
.bx-boxed > .bx-toolbar { border-radius: 13px 13px 0 0; }
.bx-boxed > .bx-body > .bx-sidebar { border-bottom-left-radius: 13px; }
.bx-boxed > .bx-body > .bx-stage { border-bottom-right-radius: 13px; }

/* ── Top toolbar ─────────────────────────────────────────────────────────────
   Deliberately thin: the mode switch, how the save is going, and the one
   destructive button. Everything else belongs in the sidebar. */
.bx-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.9rem; flex-wrap: wrap;
  padding: 0.55rem 0.95rem;
  background: var(--bx-panel);
  border-bottom: 1px solid var(--bx-line);
}
.bx-toolbar-group { display: flex; align-items: center; gap: 0.55rem; min-width: 0; }
.bx-toolbar-group.is-tight { gap: 0.3rem; }
.bx-toolbar-sep { width: 1px; align-self: stretch; margin: 0.1rem 0.2rem; background: var(--bx-line); }
.bx-toolbar-label { display: block; font-size: 0.58rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--bx-ink-3); }
.bx-toolbar-name {
  min-width: 11rem; padding: 2px 0;
  border: 0; border-bottom: 1px solid var(--bx-line-strong); background: transparent;
  font-family: "Playfair Display", Georgia, serif; font-size: 1.02rem; color: var(--bx-ink);
}
.bx-toolbar-name:focus { outline: none; border-bottom-color: var(--bx-accent); }
.bx-back {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; flex: none;
  border: 1px solid var(--bx-line); border-radius: 999px;
  color: var(--bx-ink-2); font-size: 1.05rem; text-decoration: none;
}
.bx-back:hover { border-color: var(--bx-accent); color: var(--bx-accent-ink); }

/* Which editor you're in. Two ways of building the same paper, so they read as
   one control with a side lit rather than as two rival buttons. */
.bx-modes {
  display: inline-flex; align-items: center; gap: 2px; padding: 2px;
  border: 1px solid var(--bx-line-strong); border-radius: 999px; background: var(--bx-sunken);
}
.bx-modes form { display: contents; }
.bx-mode {
  border: 0; border-radius: 999px; background: none;
  padding: 0.34rem 0.8rem;
  font: inherit; font-size: 0.73rem; line-height: 1.2; color: var(--bx-ink-2);
  white-space: nowrap; cursor: pointer; transition: background 0.12s, color 0.12s;
}
.bx-mode:hover:not(.is-on) { color: var(--bx-ink); }
.bx-mode.is-on { background: var(--bx-accent); color: #fff; cursor: default; }
.bx-dark .bx-mode.is-on { color: rgb(15 23 42); }

.bx-status { font-size: 0.76rem; color: var(--bx-ink-2); white-space: nowrap; }

/* ── Buttons ──────────────────────────────────────────────────────────────── */
.bx-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.35rem;
  border: 1px solid var(--bx-line-strong); border-radius: 8px;
  background: var(--bx-sunken); color: var(--bx-ink);
  font: inherit; font-size: 0.78rem; line-height: 1.2; padding: 0.44rem 0.7rem;
  cursor: pointer; transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.bx-btn:hover:not(:disabled) { border-color: var(--bx-accent); color: var(--bx-accent-ink); }
.bx-btn:disabled { opacity: 0.4; cursor: default; }
.bx-btn-block { width: 100%; }
.bx-btn-primary {
  border-color: var(--bx-accent); background: var(--bx-accent); color: #fff;
}
.bx-btn-primary:hover:not(:disabled) { filter: brightness(1.07); color: #fff; border-color: var(--bx-accent); }
.bx-dark .bx-btn-primary { color: rgb(15 23 42); }
.bx-dark .bx-btn-primary:hover:not(:disabled) { color: rgb(15 23 42); }
.bx-btn-go {
  border: 0; border-radius: 999px; background: var(--bx-ink); color: var(--bx-panel);
  font-size: 0.74rem; letter-spacing: 0.12em; text-transform: uppercase; padding: 0.6rem 1.2rem;
}
.bx-btn-go:hover:not(:disabled) { background: var(--bx-accent); color: #fff; border: 0; }
.bx-btn-danger:hover:not(:disabled) { border-color: var(--bx-danger); color: var(--bx-danger); background: var(--bx-danger-soft); }
/* The one button that empties a page: never a slip, so it says what it is. */
.bx-btn-wipe { border-color: var(--bx-danger); color: var(--bx-danger); }
.bx-btn-wipe:hover:not(:disabled) { background: var(--bx-danger); border-color: var(--bx-danger); color: #fff; }
.bx-icon-btn {
  width: 2rem; height: 2rem; flex: none; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--bx-line-strong); border-radius: 8px;
  background: var(--bx-sunken); color: var(--bx-ink);
  font: inherit; font-size: 0.9rem; line-height: 1;
  cursor: pointer; transition: border-color 0.12s, color 0.12s, background 0.12s, opacity 0.12s;
}
.bx-icon-btn:hover:not(:disabled) { border-color: var(--bx-accent); color: var(--bx-accent-ink); }
.bx-icon-btn:disabled { opacity: 0.35; cursor: default; }
/* Start over. Quiet until you mean it, and set apart from its neighbours so it
   isn't what you hit reaching for the button beside it. */
.bx-icon-btn.is-quiet { opacity: 0.55; margin: 0 0.15rem; }
.bx-icon-btn.is-quiet:hover, .bx-icon-btn.is-quiet:focus-visible {
  opacity: 1; border-color: var(--bx-danger); color: var(--bx-danger); background: var(--bx-danger-soft);
}
.bx-link {
  border: 0; background: none; padding: 0; font: inherit; font-size: 0.76rem;
  color: var(--bx-ink-2); text-decoration: underline; text-underline-offset: 3px;
  cursor: pointer; white-space: nowrap;
}
.bx-link:hover { color: var(--bx-accent-ink); }
.bx-link-danger { color: var(--bx-danger); }

/* ── Body: fixed sidebar + everything else ───────────────────────────────────
   A fixed first column and minmax(0,1fr) for the rest: opening a panel or
   selecting a component can never shove the paper sideways. */
.bx-body {
  display: grid;
  grid-template-columns: var(--bx-sidebar) minmax(0, 1fr);
  align-items: start;
  flex: 1;
  min-height: 0;
}
/* The toolbar and the sidebar both stay put while the paper scrolls, each
   pinned below whatever is already stuck above it — so the save state and the
   controls are always to hand however far down the page you are. */
.bx-toolbar { position: sticky; top: var(--bx-top); z-index: 30; }
.bx-sidebar {
  position: sticky; top: calc(var(--bx-top) + var(--bx-toolbar-h)); align-self: start;
  width: var(--bx-sidebar);
  max-height: calc(100vh - var(--bx-top) - var(--bx-toolbar-h));
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--bx-panel);
  border-right: 1px solid var(--bx-line);
}
.bx-full .bx-sidebar { min-height: calc(100vh - var(--bx-top) - var(--bx-toolbar-h)); }
/* The phone sheet's furniture, built once by builder_shell and shown only by
   the phone media query — off a phone it isn't there at all. */
.bx-sheet-handle, .bx-sheet-scrim { display: none; }

/* ── The component palette ───────────────────────────────────────────────────
   One panel for every builder: type to filter, shelves you can scan, and what
   you reached for last at the top. Filtering hides tiles rather than redrawing
   them, so it never costs the focus or a flicker. */
.bx-pal-search { position: relative; margin-bottom: 0.55rem; }
.bx-pal-search-ico {
  position: absolute; left: 0.55rem; top: 50%; transform: translateY(-50%);
  font-size: 0.78rem; opacity: 0.55; pointer-events: none;
}
.bx-pal-input {
  width: 100%; padding: 0.46rem 0.6rem 0.46rem 1.85rem;
  border: 1px solid var(--bx-line-strong); border-radius: 999px;
  background: var(--bx-sunken); color: var(--bx-ink);
  font: inherit; font-size: 0.8rem;
}
.bx-pal-input:focus { outline: none; border-color: var(--bx-accent); background: var(--bx-panel); }
.bx-pal-input::-webkit-search-cancel-button { cursor: pointer; }

.bx-pal-list { display: flex; flex-direction: column; gap: 0.5rem; }
.bx-pal-shelf.is-out { display: none; }
.bx-pal-shelf-head {
  display: flex; align-items: center; gap: 0.35rem;
  margin: 0 0 0.3rem; padding: 0 0.1rem;
  font-size: 0.6rem; font-weight: 600; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--bx-ink-3);
}
.bx-pal-tiles { display: flex; flex-direction: column; gap: 0.25rem; }

.bx-pal-tile {
  display: flex; align-items: center; gap: 0.55rem; width: 100%;
  padding: 0.42rem 0.5rem;
  border: 1px solid transparent; border-radius: var(--bx-radius);
  background: none; color: var(--bx-ink); font: inherit; text-align: left;
  cursor: pointer; transition: background 0.12s, border-color 0.12s;
}
.bx-pal-tile:hover, .bx-pal-tile:focus-visible {
  background: var(--bx-accent-soft); border-color: var(--bx-accent); outline: none;
}
.bx-pal-tile.is-out { display: none; }
/* The icon in a tinted chip rather than loose against the text — it reads as a
   thing you can pick rather than a bullet. */
.bx-pal-ico {
  display: flex; align-items: center; justify-content: center; flex: none;
  width: 1.85rem; height: 1.85rem;
  border-radius: 7px; background: var(--bx-sunken); border: 1px solid var(--bx-line);
  font-size: 0.92rem; line-height: 1;
}
.bx-pal-tile:hover .bx-pal-ico { border-color: var(--bx-accent); }
.bx-pal-text { display: flex; flex-direction: column; min-width: 0; }
.bx-pal-name { font-size: 0.79rem; line-height: 1.25; }
.bx-pal-desc {
  font-size: 0.67rem; line-height: 1.3; color: var(--bx-ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bx-pal-empty { margin: 0.4rem 0.1rem; font-size: 0.72rem; color: var(--bx-ink-3); }
.bx-pal-empty.hidden { display: none; }

/* Zoom: only worth the room on a touch screen, where the page is small and
   there's no other way in. On a desktop the paper is already legible. */
.bx-zoom { display: none; }
@media (hover: none), (max-width: 1024px) {
  .bx-zoom {
    display: flex; align-items: center; gap: 0.3rem;
    margin: 0 0 0.5rem auto; padding: 0.2rem;
    border: 1px solid var(--bx-line); border-radius: 999px;
    background: var(--bx-panel); width: fit-content;
  }
  .bx-zoom button {
    min-width: 38px; min-height: 38px; padding: 0 0.5rem;
    border: 0; border-radius: 999px; background: none;
    font: inherit; font-size: 0.9rem; color: var(--bx-ink); cursor: pointer;
  }
  .bx-zoom [data-zoom="reset"] { font-size: 0.72rem; }
  .bx-zoom [data-zoom-level] { min-width: 3.1rem; text-align: center; font-size: 0.72rem; color: var(--bx-ink-2); font-variant-numeric: tabular-nums; }
  .bx-zoom.is-zoomed { border-color: var(--bx-accent); }
}

/* ── A collapsible sidebar panel ─────────────────────────────────────────────
   The head is the whole button; the body animates open on grid-template-rows,
   which is the one way to transition to a content-sized height. */
.bx-panel { border-bottom: 1px solid var(--bx-line); }
.bx-panel:last-child { border-bottom: 0; }
.bx-panel-head {
  display: flex; align-items: center; gap: 0.55rem; width: 100%;
  padding: 0.7rem 0.85rem;
  border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--bx-ink-2); text-align: left;
  transition: color 0.12s;
}
.bx-panel-head:hover { color: var(--bx-ink); }
.bx-panel.is-open > .bx-panel-head { color: var(--bx-ink); }
.bx-panel-ico { flex: none; width: 1.05rem; text-align: center; font-size: 0.85rem; opacity: 0.9; }
.bx-panel-title { flex: 1; min-width: 0; }
/* A count or a one-word summary of what's inside, for a shut panel. */
.bx-panel-note {
  flex: none; font-size: 0.6rem; letter-spacing: 0.06em; text-transform: none;
  color: var(--bx-ink-3); max-width: 8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bx-panel-chev { flex: none; font-size: 0.6rem; opacity: 0.6; transition: transform 0.24s ease; }
.bx-panel.is-open > .bx-panel-head .bx-panel-chev { transform: rotate(90deg); }
.bx-panel-body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.24s ease; }
.bx-panel.is-open > .bx-panel-body { grid-template-rows: 1fr; }
.bx-panel-clip { overflow: hidden; min-height: 0; }
.bx-panel-pad { padding: 0.15rem 0.85rem 1rem; }
/* The contextual panel: it only means anything with something selected. */
.bx-panel.is-idle > .bx-panel-head { opacity: 0.55; }
@media (prefers-reduced-motion: reduce) {
  .bx-panel-body { transition: none; }
  .bx-panel-chev { transition: none; }
}

/* ── Fields ──────────────────────────────────────────────────────────────── */
.bx-label {
  display: block; margin: 0.7rem 0 0.28rem;
  font-size: 0.63rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--bx-ink-3);
}
.bx-label:first-child { margin-top: 0; }
.bx-label .bx-label-note { text-transform: none; letter-spacing: normal; opacity: 0.85; }
.bx-input, .bx-select, .bx-textarea {
  width: 100%; border: 1px solid var(--bx-line-strong); border-radius: 8px;
  background: var(--bx-sunken); color: var(--bx-ink);
  font: inherit; font-size: 0.82rem; padding: 0.44rem 0.55rem;
}
.bx-input:focus, .bx-select:focus, .bx-textarea:focus {
  outline: none; border-color: var(--bx-accent); box-shadow: 0 0 0 1px var(--bx-accent);
}
.bx-textarea { line-height: 1.5; resize: vertical; }
.bx-select { cursor: pointer; }
.bx-row { display: flex; gap: 0.5rem; align-items: flex-end; }
.bx-row > * { flex: 1 1 0; min-width: 0; }
.bx-row > .bx-flex-none { flex: none; }
.bx-color {
  flex: none; width: 2.4rem; height: 2.1rem; padding: 2px; cursor: pointer;
  border: 1px solid var(--bx-line-strong); border-radius: 8px; background: var(--bx-sunken);
}
.bx-check {
  display: flex; align-items: flex-start; gap: 0.5rem; margin-bottom: 0.4rem;
  font-size: 0.79rem; line-height: 1.35; color: var(--bx-ink); cursor: pointer;
}
.bx-check input { flex: none; margin: 0.15rem 0 0; accent-color: var(--bx-accent); cursor: pointer; }
.bx-check small { display: block; font-size: 0.69rem; color: var(--bx-ink-3); line-height: 1.35; }
.bx-checks { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; }
.bx-hint { margin: 0.3rem 0 0; font-size: 0.7rem; line-height: 1.45; color: var(--bx-ink-3); }
.bx-hint strong { color: var(--bx-ink-2); font-weight: 600; }
.bx-rule { height: 1px; margin: 0.95rem 0 0.15rem; background: var(--bx-line); }
.bx-group { margin-top: 0.9rem; padding-top: 0.85rem; border-top: 1px solid var(--bx-line); }
.bx-group:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
/* A subtle heading inside a panel, for a second idea in the same section. */
.bx-subhead {
  display: flex; align-items: center; gap: 0.4rem; margin: 0 0 0.45rem;
  font-size: 0.6rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--bx-ink-3);
}
.bx-step { display: flex; align-items: center; gap: 0.45rem; }
.bx-step button {
  width: 2rem; height: 2rem; flex: none; padding: 0;
  border: 1px solid var(--bx-line-strong); border-radius: 8px;
  background: var(--bx-sunken); color: var(--bx-ink); font: inherit; font-size: 1rem; line-height: 1; cursor: pointer;
}
.bx-step button:hover { border-color: var(--bx-accent); color: var(--bx-accent-ink); }
.bx-step .bx-input { width: 4.4rem; flex: none; text-align: center; padding: 0.4rem 0.3rem; }
.bx-step-unit { font-size: 0.78rem; color: var(--bx-ink-3); }

/* ── The text toolbar ────────────────────────────────────────────────────────
   The couples' editors set a piece's type from one strip at the top of the
   panel, the way a word processor does: two small dropdowns for the face and
   the size, then buttons for everything with one answer — align, columns, the
   lines around a piece. It replaces eight labelled sections that between them
   filled the sidebar before the couple reached the words they came to type.

   Everything here is 1.85rem tall and joined into groups, so a row of ten
   buttons still fits the sidebar; rows wrap when it doesn't.
   ────────────────────────────────────────────────────────────────────────── */
.bx-tb { display: flex; flex-direction: column; gap: 0.3rem; margin-bottom: 0.8rem; }
.bx-tb-row, .bx-tb-place { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem; }
/* Where a piece sits, on the line under the toolbar. */
.bx-tb-place { margin-bottom: 0.8rem; }
.bx-tb-select {
  flex: 1 1 4.5rem; min-width: 0; height: 1.85rem;
  border: 1px solid var(--bx-line-strong); border-radius: 7px;
  background: var(--bx-sunken); color: var(--bx-ink);
  font: inherit; font-size: 0.73rem; padding: 0 0.2rem 0 0.35rem; cursor: pointer;
}
.bx-tb-select:focus-visible { outline: none; border-color: var(--bx-accent); box-shadow: 0 0 0 1px var(--bx-accent); }
.bx-tb-font { flex: 2 1 5.5rem; }
.bx-tb-size { flex: 1 1 4rem; }
/* Fine tune: smaller, the percentage, bigger — one joined control. */
.bx-tb-step {
  display: flex; align-items: center; flex: none; height: 1.85rem; overflow: hidden;
  border: 1px solid var(--bx-line-strong); border-radius: 7px; background: var(--bx-sunken);
}
.bx-tb-step button {
  width: 1.5rem; height: 100%; flex: none; padding: 0; border: 0;
  background: none; color: var(--bx-ink-2); font: inherit; font-size: 0.9rem; line-height: 1; cursor: pointer;
}
.bx-tb-step button:hover { background: var(--bx-accent-soft); color: var(--bx-accent-ink); }
.bx-tb-step span {
  min-width: 2.2rem; text-align: center; font-size: 0.66rem; font-variant-numeric: tabular-nums;
  color: var(--bx-ink-3);
}

/* A segmented group: buttons that answer one question between them. */
.bx-seg {
  display: flex; flex: none; overflow: hidden;
  border: 1px solid var(--bx-line-strong); border-radius: 7px; background: var(--bx-sunken);
}
.bx-seg-btn {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 1.7rem; height: 1.85rem; padding: 0;
  border: 0; border-left: 1px solid var(--bx-line);
  background: none; color: var(--bx-ink-2);
  font: inherit; font-size: 0.72rem; line-height: 1; cursor: pointer;
}
.bx-seg-btn:first-child { border-left: 0; }
.bx-seg-btn svg { display: block; pointer-events: none; }
.bx-seg-btn:hover { background: var(--bx-accent-soft); color: var(--bx-accent-ink); }
.bx-seg-btn:focus-visible { outline: 2px solid var(--bx-accent); outline-offset: -2px; }
/* The one that's on, in the accent — the only colour in the strip. */
.bx-seg-btn[aria-pressed="true"] {
  background: var(--bx-accent); color: var(--bx-on-accent);
}

/* The selected component's name, and the one way to remove it. */
.bx-prop-head {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  margin-bottom: 0.7rem; padding-bottom: 0.6rem; border-bottom: 1px solid var(--bx-line);
}
.bx-prop-type { font-size: 0.63rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--bx-accent-ink); }
.bx-empty { padding: 0.4rem 0 0.6rem; }
.bx-empty-title { margin: 0 0 0.3rem; font-family: "Playfair Display", Georgia, serif; font-size: 0.95rem; color: var(--bx-ink); }
.bx-empty-desc { margin: 0; font-size: 0.76rem; line-height: 1.55; color: var(--bx-ink-3); }
.bx-empty-desc strong { color: var(--bx-ink-2); }
/* A keyboard shortcut, wherever one is worth mentioning. */
.bx-keys { display: flex; flex-wrap: wrap; gap: 0.3rem 0.5rem; margin-top: 0.6rem; font-size: 0.68rem; color: var(--bx-ink-3); }
.bx-key {
  display: inline-block; padding: 0.05rem 0.32rem; border: 1px solid var(--bx-line-strong); border-radius: 4px;
  background: var(--bx-sunken); font-size: 0.64rem; color: var(--bx-ink-2);
}

/* A structured editor dropped into the panel. The partials are written for the
   order form's roomier column, so they're given a little breathing room here
   and their inputs are allowed to be compact. */
.bx-rich { margin-top: 0.15rem; }
.bx-rich [data-rf-row] { padding: 0.5rem; padding-right: 1.9rem; }
.bx-rich input[type="text"], .bx-rich input[type="date"],
.bx-rich select, .bx-rich textarea { font-size: 0.8rem; padding: 0.35rem 0.5rem; }
.bx-rich .rf-icon-swatch { width: 2rem; height: 2rem; }
/* The partials lay their fields out two-up for the order form's wide column.
   The sidebar is half that, and Tailwind's `sm:` is viewport-based so it can't
   know — stack them instead. Specificity beats the utility rather than
   !important, since Tailwind's stylesheet loads after this one. */
.bx-shell .bx-rich [data-rf-row] .grid { grid-template-columns: 1fr; }
/* …and the spans with it: a child still asking for two columns makes the grid
   grow an implicit second one, which is what kept the fields side by side even
   with a single-track template above. */
.bx-shell .bx-rich [data-rf-row] .grid > * { grid-column: auto; }
/* The dateline's venue and date are the same two-up pair, without a row around
   them — the venue needs the whole width of the panel to be readable. */
.bx-shell .bx-rich [data-dateline-fields] { grid-template-columns: 1fr; }
.bx-rich .rf-icon-menu { grid-template-columns: repeat(5, 1fr); width: 12rem; }
/* The puzzle editor builds its clue rows for the order form's wide column:
   a fixed-width answer, the clue filling the rest, then the remove button. At
   sidebar width that adds up to more than the row, and the button — the only
   way to delete a clue — gets pushed off the edge. Let the row wrap, let the
   inputs shrink (an input won't go below its intrinsic width without this),
   and drop the clue onto its own line. */
.bx-rich [data-role="rows"] > div { flex-wrap: wrap; }
.bx-rich [data-role="rows"] input { min-width: 0; }
.bx-rich [data-role="rows"] [data-role="answer"] { width: auto; flex: 1 1 6rem; }
.bx-rich [data-role="rows"] [data-role="clue"] { order: 3; flex: 1 1 100%; }
/* The panel scrolls, so an absolutely-positioned icon menu must sit above the
   fields under it rather than being clipped by the row it belongs to. */
.bx-rich [data-rf-icon-control] { position: relative; z-index: 5; }

/* A photo waiting to be uploaded, and the one that has been. */
.bx-photo {
  display: flex; align-items: center; justify-content: center;
  height: 7rem; overflow: hidden;
  border: 1px dashed var(--bx-line-strong); border-radius: var(--bx-radius);
  background: var(--bx-sunken); color: var(--bx-ink-3); font-size: 0.75rem;
}
.bx-photo img { width: 100%; height: 100%; object-fit: cover; }

/* ── Photo filters ────────────────────────────────────────────────────────
   Six swatches of the couple's own photograph, each wearing the filter it
   offers, so the look is chosen by eye rather than by reading six words. */
.bx-filters { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.3rem; }
.bx-filter {
  display: flex; flex-direction: column; align-items: stretch; gap: 0.25rem;
  padding: 0.25rem; border: 1px solid var(--bx-line-strong); border-radius: 7px;
  background: var(--bx-sunken); color: var(--bx-ink-2);
  font: inherit; font-size: 0.66rem; text-align: center; cursor: pointer;
  transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.bx-filter:hover { border-color: var(--bx-accent); color: var(--bx-accent-ink); }
.bx-filter:focus-visible { outline: 2px solid var(--bx-accent); outline-offset: 1px; }
.bx-filter[aria-pressed="true"] {
  border-color: var(--bx-accent); background: var(--bx-accent-soft); color: var(--bx-accent-ink);
}
.bx-filter-swatch {
  display: block; overflow: hidden; border-radius: 4px; aspect-ratio: 4 / 3; background: var(--bx-line);
}
.bx-filter-swatch img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* No photo uploaded yet — a stand-in with enough colour and enough tonal range
   that every filter still reads differently on it. */
.bx-filter-stand {
  display: block; width: 100%; height: 100%;
  background:
    linear-gradient(160deg, rgba(255, 255, 255, 0.85) 0%, rgba(255, 255, 255, 0) 45%),
    linear-gradient(30deg, #2b2118 0%, #b76e79 42%, #d8c3a5 72%, #f7f2e8 100%);
}
.bx-filter-name { display: block; line-height: 1.2; }

/* ── Layout cards ─────────────────────────────────────────────────────────
   A shape you pick once, so they're small: three across, a thumbnail-sized
   diagram, and a name clamped to two lines so every card is the same height
   however long the layout is called. */
.bx-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.3rem; }
.bx-card {
  display: flex; flex-direction: column; align-items: center; gap: 0.25rem;
  padding: 0.3rem 0.25rem;
  border: 1px solid var(--bx-line-strong); border-radius: 7px;
  background: var(--bx-sunken); color: var(--bx-ink-2);
  cursor: pointer; transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.bx-card:hover { border-color: var(--bx-accent); color: var(--bx-ink); }
.bx-card.is-active { border-color: var(--bx-accent); color: var(--bx-accent-ink); background: var(--bx-accent-soft); }
.bx-card-name {
  font-size: 0.53rem; line-height: 1.15; text-align: center;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-height: 1.22rem;
}
.bx-card-diagram { width: 100%; height: 24px; }
.bx-card .pl-diagram-slot { background: currentColor; opacity: 0.32; border-radius: 2px; }
.bx-card.is-active .pl-diagram-slot { opacity: 0.6; }
/* A component card in the free canvas's "add" list — a wide row, since these
   have a name and a line about what they are. */
.bx-tiles { display: flex; flex-direction: column; gap: 0.35rem; }
.bx-tile {
  display: flex; align-items: center; gap: 0.55rem; width: 100%; text-align: left;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--bx-line); border-radius: var(--bx-radius);
  background: var(--bx-sunken); color: var(--bx-ink);
  cursor: pointer; transition: border-color 0.12s, background 0.12s, transform 0.12s;
}
.bx-tile:hover { border-color: var(--bx-accent); transform: translateY(-1px); }
.bx-tile-ico { flex: none; width: 1.5rem; text-align: center; font-size: 1.1rem; line-height: 1; }
.bx-tile-text { display: flex; flex-direction: column; min-width: 0; }
.bx-tile-name { font-size: 0.79rem; font-weight: 600; line-height: 1.25; }
.bx-tile-desc { font-size: 0.67rem; line-height: 1.25; color: var(--bx-ink-3); }
.bx-more {
  width: 100%; margin-top: 0.5rem; padding: 0.42rem;
  border: 1px dashed var(--bx-line-strong); border-radius: var(--bx-radius);
  background: none; color: var(--bx-ink-2); font: inherit; font-size: 0.74rem; cursor: pointer;
}
.bx-more:hover { border-color: var(--bx-accent); color: var(--bx-accent-ink); }

/* ── Toggle pills: the chrome bands and the rules ───────────────────────────
   Each is one switch with its own line about what it does, stacked so the
   sidebar reads as a list of decisions rather than a wall of pills. */
.bx-toggles { display: flex; flex-direction: column; gap: 0.35rem; }
.bx-toggle {
  display: flex; align-items: flex-start; gap: 0.5rem;
  padding: 0.42rem 0.55rem;
  border: 1.5px solid var(--bx-line-strong); border-radius: var(--bx-radius);
  background: var(--bx-sunken); color: var(--bx-ink-2);
  font-size: 0.74rem; line-height: 1.3; cursor: pointer;
  transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.bx-toggle:hover { border-color: var(--bx-accent); }
.bx-toggle:focus-within { border-color: var(--bx-accent); }
.bx-toggle input { flex: none; margin: 0.16rem 0 0; accent-color: var(--bx-accent); cursor: pointer; }
.bx-toggle strong { display: block; font-weight: 600; color: var(--bx-ink); }
.bx-toggle small { display: block; font-size: 0.67rem; opacity: 0.85; }
.bx-toggle.is-on { border-color: var(--bx-accent); background: var(--bx-accent-soft); }
.bx-toggle.is-on strong { color: var(--bx-accent-ink); }

/* ── Page thumbnails ─────────────────────────────────────────────────────────
   A strip of small sheets rather than a grid of large ones: which page you're
   on is a glance, not a gallery. They run along one line and scroll sideways
   when an edition has more than the sidebar can hold. */
.bx-thumbs {
  display: flex; gap: 0.3rem; align-items: flex-start;
  overflow-x: auto; overscroll-behavior-x: contain;
  padding-bottom: 0.2rem;
  scrollbar-width: thin;
}
.bx-thumb {
  position: relative; display: block; flex: 0 0 auto; width: 44px; padding: 0; overflow: hidden;
  border: 1px solid var(--bx-line-strong); border-radius: 5px;
  background: var(--bx-sunken); color: var(--bx-ink-2);
  cursor: pointer; text-decoration: none; text-align: center;
  transition: border-color 0.12s, box-shadow 0.12s, color 0.12s;
}
.bx-thumb:hover { border-color: var(--bx-accent); color: var(--bx-ink); }
.bx-thumb.is-active { border-color: var(--bx-accent); color: var(--bx-accent-ink); box-shadow: 0 0 0 2px var(--bx-accent-soft); }
.bx-thumb-sheet {
  /* A span, so it has to be told to be a block — an inline box ignores
     aspect-ratio and the sheet collapses to the height of its contents. */
  display: block; aspect-ratio: 1 / 1.414; padding: 2px;
  background: var(--bx-panel); border-bottom: 1px solid var(--bx-line);
}
.bx-thumb-sheet .bx-card-diagram { height: 100%; }
.bx-thumb-sheet .pl-diagram-slot { background: currentColor; opacity: 0.3; border-radius: 1.5px; }
.bx-thumb.is-active .bx-thumb-sheet .pl-diagram-slot { opacity: 0.55; }
/* Just the page number under each sheet — the full name is on the tooltip.
   At this size a name would only ever be three ellipsised letters. */
.bx-thumb-name {
  display: block; padding: 0.1rem 0.15rem;
  font-size: 0.55rem; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bx-thumb-add {
  display: flex; align-items: center; justify-content: center;
  flex: 0 0 auto; width: 44px; aspect-ratio: 1 / 1.414;
  border: 1px dashed var(--bx-line-strong); border-radius: 5px;
  background: none; color: var(--bx-ink-3); font-size: 0.95rem; cursor: pointer;
}
.bx-thumb-add:hover { border-color: var(--bx-accent); color: var(--bx-accent-ink); }
/* Removing a page sits beside adding one, so it says which it is on hover. */
.bx-thumb-add.is-danger:hover { border-color: var(--bx-danger); color: var(--bx-danger); background: var(--bx-danger-soft); }
/* Page count: how many sheets the edition runs to. */
.bx-counts { display: flex; gap: 0.35rem; }
.bx-count {
  width: 2.2rem; height: 2.2rem;
  border: 1.5px solid var(--bx-line-strong); border-radius: 8px;
  background: var(--bx-sunken); color: var(--bx-ink); font: inherit; font-size: 0.9rem; cursor: pointer;
}
.bx-count:hover { border-color: var(--bx-accent); }
.bx-count.is-active { border-color: var(--bx-accent); background: var(--bx-accent); color: #fff; }
.bx-dark .bx-count.is-active { color: rgb(15 23 42); }

/* ── Stage: the paper, and the pages it's one of ─────────────────────────── */
.bx-stage { display: flex; flex-direction: column; min-width: 0; padding: 1.1rem 1.2rem 1.4rem; }

/* ── The guided steps ─────────────────────────────────────────────────────
   The walkthrough, as a row of chips above the paper: your names → your words
   → your photos → the fun stuff → the details. It answers the two questions a
   fill-in-the-blanks form answered and an editor doesn't — what is there to do,
   and how much of it is left — without taking the editor away to do it.

   Above the page tabs on purpose: a step spans the edition (your photos are on
   every page), so it's the outer of the two rows. */
.bx-guide { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 0.7rem; }
.bx-guide[hidden] { display: none; }
.bx-guide-row {
  display: flex; align-items: stretch; gap: 0.35rem;
  overflow-x: auto; scrollbar-width: thin; padding: 0.1rem 0.15rem;
}
.bx-guide-step {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.4rem 0.75rem;
  border: 1px solid var(--bx-line); border-radius: 999px;
  background: var(--bx-panel); color: var(--bx-ink-2);
  font: inherit; font-size: 0.76rem; line-height: 1.3; white-space: nowrap;
  cursor: pointer; transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.bx-guide-step:hover { border-color: var(--bx-line-strong); color: var(--bx-ink); }
/* The step you're in. Filled rather than merely ringed — with a row of chips
   this size, an outline alone doesn't carry across the width of the page. */
.bx-guide-step.is-on {
  background: var(--bx-accent); border-color: var(--bx-accent); color: #fff; font-weight: 600;
}
.bx-dark .bx-guide-step.is-on { color: rgb(15 23 42); }
.bx-guide-step.is-on .bx-guide-count { background: rgba(255, 255, 255, 0.28); color: inherit; }
/* A step with nothing left to write. Quiet, not celebratory: it's a state, and
   the couple are looking at the ones that aren't. */
.bx-guide-step.is-done { color: var(--bx-ink-3); }
.bx-guide-step.is-done:not(.is-on) { background: var(--bx-sunken); }
.bx-guide-icon { font-size: 0.9rem; line-height: 1; }
.bx-guide-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5rem; padding: 0 0.3rem; height: 1.15rem;
  border-radius: 6px; background: var(--bx-line); color: var(--bx-ink-2);
  font-size: 0.63rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
/* How the whole paper is going, in one line of plain counting. */
.bx-guide-progress {
  margin: 0; padding: 0 0.2rem;
  font-size: 0.72rem; color: var(--bx-ink-3);
}
@media (max-width: 900px) {
  .bx-guide-name { display: none; }
  .bx-guide-step.is-on .bx-guide-name { display: inline; }
}

/* The page tabs, sitting right above the paper. Which page you're on is the
   move you make most often, so it's a named tab at the top of the work rather
   than a thumbnail down the sidebar. Both builders draw this same bar. */
.bx-tabs {
  display: flex; align-items: flex-end; gap: 0.25rem;
  margin-bottom: -1px; padding: 0 0.15rem;
  overflow-x: auto; scrollbar-width: thin;
}
.bx-tab {
  flex: 0 0 auto; max-width: 15rem;
  display: flex; align-items: center; gap: 0.4rem;
  padding: 0.45rem 0.85rem;
  border: 1px solid var(--bx-line); border-bottom-color: transparent;
  border-radius: 8px 8px 0 0;
  background: var(--bx-sunken); color: var(--bx-ink-2);
  font: inherit; font-size: 0.79rem; line-height: 1.3; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  cursor: pointer; transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.bx-tab:hover { background: var(--bx-panel); color: var(--bx-ink); border-color: var(--bx-line-strong); }
/* The page you're on reads as the front sheet of the pile: it carries the
   accent, and its bottom edge is open onto the mat below. */
.bx-tab.is-active {
  background: var(--bx-mat); color: var(--bx-accent-ink);
  border-color: var(--bx-line-strong); border-bottom-color: var(--bx-mat);
  font-weight: 600;
  box-shadow: inset 0 2px 0 var(--bx-accent);
}
/* The number, so a named page still says where it falls in the edition. */
.bx-tab-n {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.15rem; height: 1.15rem; padding: 0 0.25rem;
  border-radius: 5px; background: var(--bx-line); color: var(--bx-ink-2);
  font-size: 0.63rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.bx-tab.is-active .bx-tab-n { background: var(--bx-accent); color: #fff; }
.bx-dark .bx-tab.is-active .bx-tab-n { color: rgb(15 23 42); }
.bx-tab-add { border-style: dashed; color: var(--bx-ink-3); font-size: 0.9rem; padding: 0.45rem 0.7rem; }
.bx-viewport {
  border-radius: 12px; background: var(--bx-mat); padding: 16px; overflow: hidden;
}
.bx-viewport.is-roomy { display: flex; justify-content: center; padding: 20px; }
/* The stage the open paper sits on. Flex-centred so the spread stays on the
   middle of the desk while it's being measured — at full size it's wider than
   the stage, and it's that full size the scale is worked out from. */
.bx-canvas { position: relative; width: 100%; display: flex; justify-content: center; align-items: flex-start; }
.bx-canvas .np-paper { box-shadow: 0 10px 34px rgba(0, 0, 0, 0.22); margin: 0 auto; }
/* Black & white, as the press prints it. The filter goes on the whole sheet
   rather than on the photographs alone, because that's what "mono" means to a
   printer: the paper's own colour, the rules, a coloured border and the pictures
   all come off the same plate. The PDF greys itself the same way (see
   newspapers/_grid_print), so what's on the stage is what arrives.
   The editor's own handles are inside the paper and grey with it — still plain
   against the newsprint, and worth it for a preview that doesn't lie. */
.bx-canvas.is-mono .np-paper { filter: grayscale(1); }

/* ── The paper, open ─────────────────────────────────────────────────────────
   The editor shows the edition the way it's read: two facing pages at a time,
   turned by hand. Not a preview of the work — it IS the work, so both pages
   carry the builder's handles and either can be edited where it lies.

   The leaves, the crease and the turn are the book viewer's (book.css); this
   is the same object with the handles left on. --bx-book-scale is set by the
   controller once it knows how much room the spread has. */
.bx-book {
  position: relative;
  display: flex;
  /* Sized by the pages it holds, not by the stage it's on. Left to fill the
     stage it reports the stage's width, the scale works out as 1, and the
     spread runs off both sides at full size. */
  width: max-content;
  flex: 0 0 auto;
  align-items: flex-start;
  justify-content: center;
  transform: scale(var(--bx-book-scale, 1));
  transform-origin: top center;
  transform-style: preserve-3d;
}
.bx-leaf {
  position: relative;
  flex: 0 0 auto;
  transform-style: preserve-3d;
}
.bx-leaf .np-paper { box-shadow: 0 18px 45px -20px rgba(0, 0, 0, 0.5); }

/* The fold. Two facing pages of one folded sheet curve away into the spine — so
   it is drawn only where there are two of them. A page with nothing to face
   (the cover, a last odd page, one page to a screen) is a single leaf sitting
   centred on the stage, with no spine to fall into. */
.bx-book:not(.is-solo):not(.is-single) .bx-leaf::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  width: 7%;
  opacity: 0.5;
  pointer-events: none;
  z-index: 5;
}
.bx-book:not(.is-solo):not(.is-single) .bx-leaf-l::after {
  right: 0;
  background: linear-gradient(to right, rgba(29, 24, 18, 0) 0%, rgba(29, 24, 18, 0.14) 100%);
}
.bx-book:not(.is-solo):not(.is-single) .bx-leaf-r::after {
  left: 0;
  background: linear-gradient(to left, rgba(29, 24, 18, 0) 0%, rgba(29, 24, 18, 0.14) 100%);
}

/* The turn, hinged on the spine — the same movement as the reader's, and the
   same keyframes (book.css), so the two can't drift apart. */
.bx-leaf.bk-turn-away-fwd, .bx-leaf.bk-turn-in-fwd,
.bx-leaf.bk-turn-away-back, .bx-leaf.bk-turn-in-back { z-index: 6; }

/* Turning the page, from either side of the paper. */
.bx-page-arrow {
  position: absolute;
  top: 50%;
  z-index: 7;
  display: flex; height: 2.4rem; width: 2.4rem;
  transform: translateY(-50%);
  align-items: center; justify-content: center;
  border-radius: 999px;
  border: 1px solid var(--bx-line);
  background: var(--bx-panel);
  color: var(--bx-ink-2);
  box-shadow: 0 4px 14px -6px rgba(0, 0, 0, 0.5);
  cursor: pointer;
}
.bx-page-arrow:hover:not(:disabled) { border-color: var(--bx-accent); color: var(--bx-accent); }
.bx-page-arrow:disabled { opacity: 0; pointer-events: none; }
.bx-page-arrow-prev { left: 0.35rem; }
.bx-page-arrow-next { right: 0.35rem; }

/* Which pages are open, under the paper. The tabs above it still name every
   page; this says what you're looking at. */
.bx-spread-label {
  margin: 0.85rem 0 0;
  text-align: center;
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--bx-ink-3);
}
.bx-canvas-note { padding: 3rem 1rem; text-align: center; font-size: 0.82rem; color: var(--bx-ink-3); }
.bx-canvas-note.is-error { color: var(--bx-danger); }
.bx-stage-hint { margin: 0.75rem 0 0; text-align: center; font-size: 0.71rem; line-height: 1.5; color: var(--bx-ink-3); }
/* Content that won't fit its column. A slot clips whatever runs past its bottom
   edge, so this is the only warning between a too-long paragraph and a sign-off
   sliced in half on the printed paper. */
.bx-warning {
  margin: 0 0 0.75rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid #e0b34a; border-radius: var(--bx-radius);
  background: #fdf6e3; color: #7a5b1e;
  font-size: 0.76rem; line-height: 1.45;
}
.bx-warning.hidden { display: none; }
.bx-stage-hint strong { color: var(--bx-ink-2); font-weight: 600; }
.bx-notice {
  display: none;
  padding: 0.65rem 1.1rem; background: #fff4d6; color: #7a5b1e;
  border-bottom: 1px solid var(--bx-line); font-size: 0.78rem;
}

/* ── Dragging a component between slots ──────────────────────────────────────
   The page renderer draws the boxes; these are the states the builder puts on
   them. A grabbed component fades and tilts a little so it reads as picked up,
   the slot under the pointer lights, and a solid line shows the exact place it
   will land — the drop used to be a guess until you let go. */
.np-lay-item.sb-dragging { opacity: 0.35; transform: rotate(-0.6deg) scale(0.985); }
.np-lay-slot.sb-drop-over { background: var(--np-drop-tint, rgba(183, 110, 121, 0.1)); outline: 2px dashed #b76e79; outline-offset: 2px; }
.sb-drop-line {
  position: relative; height: 0; margin: 1px 0; pointer-events: none;
  border-top: 2px solid #b76e79; border-radius: 2px;
  box-shadow: 0 0 0 3px rgba(183, 110, 121, 0.18);
}
.sb-drop-line::before, .sb-drop-line::after {
  content: ""; position: absolute; top: -3px; width: 5px; height: 5px; border-radius: 50%; background: #b76e79;
}
.sb-drop-line::before { left: -2px; }
.sb-drop-line::after { right: -2px; }

/* ── The "what goes here?" picker ────────────────────────────────────────────
   Opened from a slot's ＋ (or the free canvas's category rows) and appended to
   the shell, so it takes the shell's theme wherever it's used. */
.bx-shell .sb-picker {
  position: absolute; z-index: 60; width: 300px;
  display: flex; flex-direction: column; gap: 8px; padding: 8px;
  border: 1px solid var(--bx-line-strong); border-radius: 10px;
  background: var(--bx-panel); color: var(--bx-ink);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.3);
}
.bx-shell .sb-picker.hidden { display: none; }
.bx-shell .sb-picker-head { padding: 2px 4px 0; font-size: 0.76rem; color: var(--bx-ink-2); }
.bx-shell .sb-picker-search {
  width: 100%; padding: 8px 10px; outline: none;
  border: 1px solid var(--bx-line-strong); border-radius: 8px;
  background: var(--bx-sunken); color: var(--bx-ink); font: inherit; font-size: 0.8rem;
}
.bx-shell .sb-picker-search:focus { border-color: var(--bx-accent); }
.bx-shell .sb-picker-list { display: flex; flex-direction: column; gap: 2px; max-height: 320px; overflow-y: auto; }
.bx-shell .sb-picker-group {
  padding: 8px 8px 4px; font-size: 0.6rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--bx-ink-3);
}
.bx-shell .sb-picker-item {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 7px 8px; text-align: left;
  border: 0; border-radius: 8px; background: none; color: var(--bx-ink); font: inherit; cursor: pointer;
}
.bx-shell .sb-picker-item:hover, .bx-shell .sb-picker-item.is-active { background: var(--bx-accent-soft); }
.bx-shell .sb-picker-item.hidden, .bx-shell .sb-picker-grp.hidden, .bx-shell .sb-picker-empty.hidden { display: none; }
.bx-shell .sb-picker-empty { padding: 14px 8px; text-align: center; font-size: 0.76rem; color: var(--bx-ink-3); }
.bx-shell .sb-picker-ico { flex: none; width: 22px; text-align: center; font-size: 1rem; }
.bx-shell .sb-picker-text { display: flex; flex-direction: column; min-width: 0; }
.bx-shell .sb-picker-name { font-size: 0.8rem; font-weight: 600; line-height: 1.2; }
.bx-shell .sb-picker-desc {
  font-size: 0.68rem; line-height: 1.2; color: var(--bx-ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Something the builder wants you to look at — the layout picker after a page
   has been cleared, say. Lights briefly, then gets out of the way. */
.bx-flash { animation: bxflash 0.9s ease-out; border-radius: 8px; }
@keyframes bxflash {
  0%, 45% { background: var(--bx-accent-soft); box-shadow: 0 0 0 1px var(--bx-accent); }
  100% { background: transparent; box-shadow: none; }
}

/* ── Phones and tablets ─────────────────────────────────────────────────────
   A column of controls beside the paper doesn't survive 375px: half the screen
   goes to the sidebar and the paper is too small to read. So below the desktop
   width the paper takes the whole screen and the sidebar becomes a sheet at the
   bottom of it, pulled up when it's wanted and pushed down when it isn't. Same
   panels, same order — only where they sit changes.

   It covers tablets too. They used to lay the sidebar out as a band above the
   paper, which meant scrolling past every control to reach the page you were
   trying to judge.

   The sheet is `fixed`, so it rides above the paper rather than pushing it, and
   selecting a component brings it up by itself (see builder_shell). */
@media (max-width: 1024px) {
  .bx-body { grid-template-columns: minmax(0, 1fr); }
  .bx-stage { padding: 0.6rem 0.5rem calc(var(--bx-sheet-peek, 3.1rem) + 1rem); }
  .bx-toolbar { position: sticky; top: var(--bx-top, 0px); z-index: 30; }
  .bx-viewport { padding: 8px; border-radius: 8px; }
  .bx-viewport.is-roomy { padding: 8px; }
  .bx-viewport.is-roomy .bx-canvas { max-width: none; }

  .bx-sidebar {
    position: fixed; left: 0; right: 0; bottom: 0; top: auto;
    width: auto; max-width: none; z-index: 60;
    max-height: 85vh; min-height: 0;
    border: 0; border-top: 1px solid var(--bx-line-strong);
    border-radius: 16px 16px 0 0;
    background: var(--bx-panel);
    box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.16);
    /* Shut, only the handle shows. */
    transform: translateY(calc(100% - var(--bx-sheet-peek, 3.1rem)));
    transition: transform 0.24s ease;
    overscroll-behavior: contain;
  }
  .bx-sidebar.is-sheet-open { transform: translateY(0); }

  /* The grab bar: the whole thing is the tap target, and it says what's in
     there rather than being a bare grey pill. The sidebar is already its own
     scroller, so the handle just sticks to the top of it and the panels run
     underneath — no extra wrapper, and desktop is untouched. */
  .bx-sheet-handle {
    position: sticky; top: 0; z-index: 1;
    display: flex; align-items: center; justify-content: center; gap: 0.5rem;
    width: 100%; min-height: var(--bx-sheet-peek, 3.1rem); padding: 0.5rem 1rem;
    border: 0; border-radius: 16px 16px 0 0; background: var(--bx-panel);
    font: inherit; font-size: 0.82rem; color: var(--bx-ink); cursor: pointer;
    touch-action: none;
  }
  .bx-sheet-grip { position: absolute; top: 6px; left: 50%; transform: translateX(-50%); width: 34px; height: 4px; border-radius: 999px; background: var(--bx-line-strong); }
  .bx-sheet-label { font-weight: 600; }
  .bx-sheet-hint { color: var(--bx-ink-3); font-size: 0.74rem; }
  /* Tapping off the sheet puts it away — the usual way out of a sheet. */
  .bx-sheet-scrim {
    display: block;
    position: fixed; inset: 0; z-index: 55;
    background: rgba(15, 12, 8, 0.32);
    opacity: 0; pointer-events: none; transition: opacity 0.24s ease;
  }
  .bx-sheet-scrim.is-on { opacity: 1; pointer-events: auto; }

  /* Touch targets. A 44px minimum is the difference between a toolbar you can
     use with a thumb and one you keep missing. */
  .bx-toolbar { gap: 0.5rem; padding: 0.45rem 0.6rem; }
  .bx-toolbar .bx-btn,
  .bx-toolbar .bx-icon-btn,
  .bx-back { min-height: 44px; min-width: 44px; }
  .bx-toolbar .bx-btn { padding: 0.5rem 0.8rem; font-size: 0.82rem; }
  .bx-mode { min-height: 40px; padding: 0.5rem 0.85rem; font-size: 0.8rem; }
  .bx-toolbar-name { min-width: 0; width: 100%; font-size: 1rem; }
  .bx-toolbar-label { font-size: 0.54rem; }
  /* The status text is the first thing worth losing when the bar is tight. */
  .bx-status { font-size: 0.7rem; }

  /* Page tabs: one row, swiped through, never wrapped. */
  .bx-tabs { -webkit-overflow-scrolling: touch; scroll-snap-type: x proximity; padding-bottom: 2px; }
  .bx-tab { scroll-snap-align: start; min-height: 40px; font-size: 0.8rem; }

  /* Panel innards get the full width, and anything that was two-up goes to one. */
  .bx-panel-pad { padding: 0.7rem 0.85rem 0.95rem; }
  .bx-cards { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0.4rem; }
  .bx-card-diagram { height: 34px; }
  .bx-card-name { font-size: 0.62rem; }
  .bx-thumb { width: 52px; }
  .bx-row { flex-wrap: wrap; }
  .bx-input, .bx-select, .bx-textarea { font-size: 16px; min-height: 42px; }
  .bx-btn { min-height: 40px; }
  /* The toolbar keeps its shape, at a size a thumb can hit — and 16px on its
     selects for the same reason as above. */
  .bx-tb-select { font-size: 16px; height: 40px; }
  .bx-tb-step, .bx-tb-step button, .bx-seg-btn { height: 40px; }
  .bx-tb-step button, .bx-seg-btn { width: 2.2rem; }
  /* 16px on inputs is deliberate: iOS zooms the page in on any smaller font
     when a field takes focus, and never zooms back out. */

  /* Rich editors: their rows are laid out for a sidebar twice this wide. */
  .bx-rich [data-rf-row] .grid,
  .bx-rich [data-role="rows"] > div { grid-template-columns: 1fr; }
  .bx-rich [data-role="rows"] > div { flex-wrap: wrap; gap: 0.4rem; }
  .bx-rich input, .bx-rich textarea, .bx-rich select { min-width: 0; width: 100%; font-size: 16px; }
  .bx-rich table { display: block; overflow-x: auto; }
}

/* ══ New editor UX (iteration) ═══════════════════════════════════════════════
   Clicking the paper is the primary move in both editors now: the panels react
   to what's selected rather than being the place you go first. Everything in
   this block is behind an opt-in class so the admin builders are untouched.
   ────────────────────────────────────────────────────────────────────────── */

/* A contextual panel with nothing selected simply isn't there. It used to sit
   dimmed at the foot of the sidebar, which reads as "broken" rather than
   "waiting". */
.bx-shell .bx-panel.is-vacant { display: none; }

/* ── The picker, at pill density ────────────────────────────────────────────
   Same buttons, same search, same shelves as the full palette — just chips
   instead of full-width rows, so the whole shelf is readable in one glance.
   Both editors use this density, so adding a piece looks the same in each. */
/* flex-direction has to be reset, not just wrap added: the full-density list is
   a column, and a wrapping column still stacks one per line and stretches each
   to the full width — which is the full-width row this density exists to
   replace. */
.bx-pal-list.is-compact .bx-pal-tiles { display: flex; flex-direction: row; flex-wrap: wrap; gap: 0.3rem; }
.bx-pal-tile.is-pill {
  display: inline-flex; align-items: center; gap: 0.3rem;
  width: auto; padding: 0.32rem 0.6rem;
  border: 1px solid var(--bx-line-strong); border-radius: 999px;
  background: var(--bx-sunken); color: var(--bx-ink);
  font: inherit; font-size: 0.72rem; line-height: 1.2; text-align: left;
  cursor: pointer; transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.bx-pal-tile.is-pill:hover { border-color: var(--bx-accent); color: var(--bx-accent-ink); background: var(--bx-accent-soft); }
/* The icon loses its tinted chip at this density — at pill size the chip is
   most of the pill. */
.bx-pal-tile.is-pill .bx-pal-ico {
  width: auto; height: auto; border: 0; background: none; border-radius: 0;
  font-size: 0.82rem; line-height: 1;
}
.bx-pal-tile.is-out { display: none; }

/* ── The free canvas's three-column shell ───────────────────────────────────
   A slim rail of tools on the left, the paper in the middle, and the detail
   panel on the right — so the paper keeps the centre of the screen and the
   controls sit either side of it rather than in front of it. */
.bx-shell.bx-rails > .bx-body {
  grid-template-columns: var(--bx-rail) minmax(0, 1fr) var(--bx-props);
}
.bx-shell.bx-rails { --bx-rail: 62px; --bx-props: 288px; }

.bx-rail {
  position: sticky; top: calc(var(--bx-top) + var(--bx-toolbar-h)); align-self: start;
  display: flex; flex-direction: column; align-items: center; gap: 0.25rem;
  padding: 0.6rem 0.35rem;
  height: calc(100vh - var(--bx-top) - var(--bx-toolbar-h));
  overflow-y: auto;
  background: var(--bx-panel); border-right: 1px solid var(--bx-line);
}
.bx-rail-btn {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  width: 100%; padding: 0.5rem 0.2rem;
  border: 1px solid transparent; border-radius: 10px;
  background: none; color: var(--bx-ink-2);
  font: inherit; font-size: 0.52rem; letter-spacing: 0.04em; text-transform: uppercase;
  cursor: pointer; transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.bx-rail-btn:hover { background: var(--bx-accent-soft); color: var(--bx-ink); }
.bx-rail-btn.is-on { background: var(--bx-accent-soft); border-color: var(--bx-accent); color: var(--bx-accent-ink); }
.bx-rail-ico { font-size: 1.05rem; line-height: 1; }

/* The detail panel on the right. Same panels as before, just re-homed. */
.bx-props {
  position: sticky; top: calc(var(--bx-top) + var(--bx-toolbar-h)); align-self: start;
  width: var(--bx-props);
  height: calc(100vh - var(--bx-top) - var(--bx-toolbar-h));
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--bx-panel); border-left: 1px solid var(--bx-line);
}
.bx-props-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem;
  padding: 0.7rem 0.85rem 0.5rem;
  border-bottom: 1px solid var(--bx-line);
  font-size: 0.62rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--bx-ink-3);
}
.bx-props-body { padding: 0.75rem 0.85rem 1.2rem; }
/* X / Y / W / H in one tidy block. */
.bx-quad { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem; }

/* ── The floating toolbar on the selected box ───────────────────────────────
   The edits worth making without leaving the paper. It follows the selection
   and sits just above it, flipping below when there's no room. */
.bx-float {
  position: absolute; z-index: 40;
  display: flex; align-items: center; gap: 2px;
  padding: 3px;
  border: 1px solid var(--bx-line-strong); border-radius: 999px;
  background: var(--bx-panel);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.16);
  white-space: nowrap;
}
.bx-float.hidden { display: none; }
.bx-float button, .bx-float select {
  border: 0; border-radius: 999px; background: none; color: var(--bx-ink);
  font: inherit; font-size: 0.74rem; line-height: 1;
  padding: 0.35rem 0.5rem; cursor: pointer;
}
.bx-float button:hover { background: var(--bx-accent-soft); color: var(--bx-accent-ink); }
.bx-float select { max-width: 8.5rem; padding-right: 0.2rem; }
.bx-float-grip { cursor: move; opacity: 0.55; padding: 0.35rem 0.4rem; }
.bx-float-sep { width: 1px; align-self: stretch; margin: 0.15rem 1px; background: var(--bx-line); }
.bx-float-del:hover { background: var(--bx-danger-soft); color: var(--bx-danger); }

/* Zoom, parked in the corner of the screen rather than on a line above the
   paper. Fixed, not absolute: the stage is a whole A4 sheet tall, so anything
   anchored to its bottom edge would sit a page and a half below the fold. */
.bx-stage { position: relative; }
/* On the free canvas zoom earns its place at every width — boxes are placed by
   hand there, so being able to pull back and see the whole sheet, or come in
   close to line two things up, is part of the job rather than a small-screen
   concession. The base .bx-zoom is desktop-hidden, so the styling is repeated
   here rather than inherited. */
.bx-zoom-corner {
  display: flex; align-items: center; gap: 0.3rem;
  position: fixed; right: calc(var(--bx-props) + 1.1rem); bottom: 1.4rem; z-index: 30;
  margin: 0; padding: 0.2rem; width: fit-content;
  border: 1px solid var(--bx-line-strong); border-radius: 999px;
  background: var(--bx-panel);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.14);
}
.bx-zoom-corner button {
  min-width: 34px; min-height: 34px; padding: 0 0.5rem;
  border: 0; border-radius: 999px; background: none;
  font: inherit; font-size: 0.9rem; color: var(--bx-ink); cursor: pointer;
}
.bx-zoom-corner button:hover { background: var(--bx-accent-soft); color: var(--bx-accent-ink); }
.bx-zoom-corner [data-zoom="reset"] { font-size: 0.72rem; }
.bx-zoom-corner [data-zoom-level] {
  min-width: 3.1rem; text-align: center; font-size: 0.72rem;
  color: var(--bx-ink-2); font-variant-numeric: tabular-nums;
}
.bx-zoom-corner.is-zoomed { border-color: var(--bx-accent); }

@media (max-width: 1024px) {
  /* The rail and the detail panel fold back into the bottom sheet on a phone. */
  .bx-shell.bx-rails > .bx-body { grid-template-columns: minmax(0, 1fr); }
  .bx-rail { position: static; flex-direction: row; height: auto; border-right: 0;
             border-bottom: 1px solid var(--bx-line); overflow-x: auto; }
  .bx-rail-btn { width: auto; min-width: 62px; }
  /* Stacked, the detail panel would sit below a full A4 sheet — a long scroll
     from the box you just tapped. So on a touch layout it comes up from the
     bottom instead, over the paper, and only when there's something to say. */
  .bx-props {
    position: fixed; left: 0; right: 0; bottom: 0; top: auto;
    width: auto; height: auto; max-height: 52vh; z-index: 45;
    border-left: 0; border-top: 1px solid var(--bx-line-strong);
    border-radius: 14px 14px 0 0;
    box-shadow: 0 -8px 28px rgba(0, 0, 0, 0.16);
    transform: translateY(101%); transition: transform 0.18s ease-out;
  }
  .bx-props.is-open { transform: none; }
  .bx-props-head { position: sticky; top: 0; background: var(--bx-panel); border-radius: 14px 14px 0 0; }
  /* Room to scroll the paper clear of the sheet. */
  .bx-shell.bx-rails.has-sheet .bx-stage { padding-bottom: 52vh; }
  /* Stacked, so there's no panel to sit clear of. */
  .bx-zoom-corner { right: 1.1rem; }
}

/* ── "Moving your paper…" ────────────────────────────────────────────────────
   Switching editors saves, converts and then navigates, which takes a beat.
   That used to be announced by a line of text in the top-right corner of the
   toolbar, which is the last place anyone is looking — their eyes are on the
   paper. So the paper is what gets covered.

   Fixed rather than absolute: the stage is a whole A4 sheet tall, so an
   overlay filling it would centre its spinner somewhere below the fold. Fixed
   to the window, inset past the rail and the panel, it covers exactly the
   column the paper is in and centres in what the couple can actually see. */
.bx-busy {
  position: fixed;
  top: calc(var(--bx-top) + var(--bx-toolbar-h));
  left: var(--bx-rail, 0px);
  right: var(--bx-props, 0px);
  bottom: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.9rem;
  padding: 1.5rem;
  text-align: center;
  background: color-mix(in srgb, var(--bx-bg) 82%, transparent);
  backdrop-filter: blur(2px);
  animation: bx-busy-in 0.14s ease-out;
}
/* min(), not a flat 22rem: on a narrow phone a flat cap is wider than the
   space left after the padding, and the line runs off the edge. */
.bx-busy-text, .bx-busy-sub { max-width: min(22rem, 100%); margin: 0; }
.bx-busy.hidden { display: none; }
@keyframes bx-busy-in { from { opacity: 0 } to { opacity: 1 } }

.bx-busy-ring {
  width: 2.4rem; height: 2.4rem;
  /* The track is faint and the leading segment is the accent, so what the eye
     follows is the moving part rather than the ring. */
  border: 3px solid color-mix(in srgb, var(--bx-ink) 12%, transparent);
  border-top-color: var(--bx-accent);
  border-radius: 50%;
  animation: bx-spin 0.75s linear infinite;
}
@keyframes bx-spin { to { transform: rotate(360deg) } }

.bx-busy-text {
  font-family: "Playfair Display", Georgia, serif;
  font-size: 1.05rem;
  color: var(--bx-ink);
}
.bx-busy-sub { font-size: 0.76rem; color: var(--bx-ink-2); }

/* A spinner that never stops is the one bit of motion worth turning off. */
@media (prefers-reduced-motion: reduce) {
  .bx-busy { animation: none; }
  .bx-busy-ring { animation-duration: 2.4s; }
}

/* On a touch layout the rail sits above the paper rather than beside it, and
   the toolbar wraps — so there's no reliable height to start below. The whole
   screen is covered instead, which is also the clearer thing on a phone: the
   page is about to be replaced either way. */
@media (max-width: 1024px) {
  .bx-busy { inset: 0; }
}

/* ── Focus mode ──────────────────────────────────────────────────────────────
   Click a piece on the paper and the editor gives you that piece and nothing
   else: it lights on the page and everything around it fades back. That is the
   whole of it — the dimming, the count in the steps above the paper, and the
   glow on the piece you haven't written yet. The form itself stays in the
   sidebar, where it is whether focus mode is on or not.

   There is no panel. There was one, docked over the foot of the window, and it
   covered the paper it was meant to be helping you read. Nothing here draws on
   top of the page. */

/* The paper, with one piece lit. The dimming is on the page rather than a
   scrim over it, so the faded pieces are still THERE — you can see where the
   one you're filling in sits in the edition, which is the difference between
   focus and a modal. */
.bx-canvas.qb-focus .np-lay-item:not(.sb-selected),
.bx-canvas.qb-focus .sb-slot-add,
.bx-canvas.qb-focus .np-spread-layer:not(.sb-selected) {
  opacity: 0.28;
  transition: opacity 0.18s ease;
}
/* The lit piece: full strength, and a wider halo than the ordinary selection
   so it reads as lifted off the page rather than merely ringed. */
.bx-canvas.qb-focus .np-lay-item.sb-selected {
  opacity: 1;
  box-shadow: 0 0 0 3mm color-mix(in srgb, #b76e79 12%, transparent);
  border-radius: 2px;
}
/* The rest of the step you're on: brighter than the page behind it, dimmer than
   the piece you're actually filling in. Clicking "Your photos" should show you
   your photos — all of them — not just the one that happens to be open. */
.bx-canvas.qb-focus .np-lay-item.qb-step-lit:not(.sb-selected) { opacity: 0.62; }

/* A ＋ you're pointing at is a ＋ you meant — adding a piece shouldn't need
   focus mode turned off first. */
.bx-canvas.qb-focus .sb-slot-add:hover,
.bx-canvas.qb-focus .sb-slot-add:focus-visible { opacity: 1; }
/* The next piece still waiting for words. A slow breath rather than a flash —
   it's a signpost you follow when you're ready, not an alarm. */
.bx-canvas.qb-focus .np-lay-item.qb-next {
  opacity: 0.75;
  outline: 1.5px dashed rgba(183, 110, 121, 0.85);
  outline-offset: 3px;
  border-radius: 3px;
  animation: qb-breathe 2.4s ease-in-out infinite;
}
@keyframes qb-breathe {
  0%, 100% { opacity: 0.55; outline-color: rgba(183, 110, 121, 0.4); }
  50%      { opacity: 0.95; outline-color: rgba(183, 110, 121, 0.95); }
}
@media (prefers-reduced-motion: reduce) {
  .bx-canvas.qb-focus .np-lay-item.qb-next { animation: none; opacity: 0.9; }
  .bx-canvas.qb-focus .np-lay-item:not(.sb-selected) { transition: none; }
}

/* "Done ✓" closes the panel and gives the page back undimmed — so the piece
   still waiting for words is pointed at HERE instead, on a page where the
   breathing glow above would have nothing to stand out against. Three beats
   and gone (see PULSE_MS): a signpost you're shown on the way out, not a mark
   left on the paper. */
.bx-canvas .np-lay-item.qb-pulse {
  position: relative;
  border-radius: 3px;
  animation: qb-pulse 1.1s ease-out 3;
}
@keyframes qb-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(183, 110, 121, 0.55); }
  70%  { box-shadow: 0 0 0 4mm rgba(183, 110, 121, 0); }
  100% { box-shadow: 0 0 0 0 rgba(183, 110, 121, 0); }
}
/* Without the beat, the same thing said by standing still: it's still only up
   for the few seconds the pulse would have run. */
@media (prefers-reduced-motion: reduce) {
  .bx-canvas .np-lay-item.qb-pulse {
    animation: none;
    outline: 1.5px dashed rgba(183, 110, 121, 0.85);
    outline-offset: 3px;
  }
}

/* Done, Next and the count — at the TOP of the piece's form in the sidebar,
   above the boxes. The way out of a piece belongs where the eye already is:
   the same column the words are typed in. */
.bx-prop-acts {
  display: flex; align-items: center; justify-content: space-between; gap: 0.7rem;
  margin-bottom: 0.5rem;
}
.bx-prop-acts .bx-btn { flex: none; }
.bx-prop-next { font-size: 0.72rem; white-space: nowrap; text-align: right; }
.bx-prop-progress {
  margin: 0 0 0.7rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--bx-line);
  font-size: 0.7rem; line-height: 1.5; color: var(--bx-ink-3);
}
/* A phone has no Escape key, and the panel is a sheet there rather than a
   column — the count is still worth saying, the keystroke isn't. */
@media (max-width: 1024px) { .bx-desk-only { display: none; } }

/* ── How much room is left ───────────────────────────────────────────────────
   Under the field: what this piece is setting at now and what it has room for,
   measured off the page it's actually on (see page_fit.js). Advice, not a
   limit — the paper takes what it's given and says when it won't print. */
.bx-fit {
  margin: 0.35rem 0 0;
  font-size: 0.7rem; line-height: 1.45;
  color: var(--bx-ink-3);
}
.bx-fit[hidden] { display: none; }
.bx-fit.is-full { color: #8a6d1f; }
.bx-fit.is-over { color: var(--bx-danger); font-weight: 600; }
