/* Shared Buzz builder shell: split-panel layout (accordion form left, live preview right),
   a draggable width-adjuster between them, and the accordion/wizard step styling. Ported
   from ResumeBuzz's builder (buzzresume.com/build/, the proven reference) and made brand-
   agnostic: every color below reads a CSS custom property the including page defines in its
   own <style> block, nothing here is hardcoded to one brand's palette.
   Required vars on the including page's :root: --bg --surface --surface2 --ink --muted
   --warm --border --accent --accent-dark --field-bg --field-border --on-fill (optional,
   defaults #FFFDF8) --wiz-fill (optional, defaults --accent-dark)
   Phase 5 (mighty-twirling-micali.md): all four Buzz builders converge on this one shell.
   BuzzExec is the first brand built against it; ResumeBuzz/GradBuzz's own inline copies of
   this same layout get replaced with this file later in the sequence, not rewritten twice. */

html,body{height:100%;overflow:hidden}
body{margin:0;display:flex;flex-direction:column}

.bshell-main{flex:1;display:flex;overflow:hidden;min-height:0}

/* LEFT PANEL: the accordion form. Width is a CSS var so the resizer can drag it live.
   Default 600px (was 420px), Blake 2026-09-19: people type a lot in here, so the form
   should default to roughly half the viewer split rather than starting cramped -- a
   returning visitor's own dragged width (localStorage, see initResizer()) still wins. */
.left-panel{
  width:var(--bshell-left-w, 600px);
  flex-shrink:0;
  border-right:2px solid var(--border);
  overflow-y:auto;
  display:flex;
  flex-direction:column;
  position:relative;
  background-color:var(--surface);
  background-repeat:repeat;
  background-size:72px 41.569px;
  /* REVERSED, 2026-09-16 -- was :local since 2026-08-27 (comment above). Blake: still wants
     it fixed, redesigning elements around it, "one line change so easily reversable." This
     is a different mechanism than the earlier broken attempt above (an absolutely-positioned
     6000px pseudo-element child that inflated scrollHeight) -- :fixed paints relative to the
     VIEWPORT, adds no DOM child, and needs no explicit height, so it can't reproduce that
     specific bug. Revert to :local if a new problem shows up. */
  background-attachment:fixed;
}
/* Light honeycomb texture, 2026-08-27 -- Blake: "I do like the hex background of the left
   column though, let's apply a light honeycomb texture to all four builders." Same hex-grid
   SVG as BuzzResume's own left-panel (its build/index.html, the original this shell was
   ported from) -- structure lives here since .left-panel is fully shared, but the stroke
   color is brand-specific, so each including page's own <style> block supplies its own
   background-image on this same .left-panel selector (a data-URI SVG can't read a CSS var
   for its internal stroke attribute, so this can't be one shared image the way everything
   else in this file is; the 0.14 fade is baked into each SVG's stroke-opacity instead of a
   CSS opacity, since a plain background-image on the real element can't be dimmed without
   dimming its content too). See exec/build-page.js and vow/build-page.js for their own
   colored copy.
   First attempt (2026-08-27) put this pattern on an absolutely-positioned .left-panel::before
   with an explicit height:6000px, meant to outrun any realistic accordion length so the
   tiling wouldn't run out. That inverted the bug: .left-panel's overflow-y:auto scrollHeight
   is driven by its tallest child, and a 6000px pseudo-element IS a child, so it forced the
   panel to scroll 6000px deep even with the accordion fully collapsed (~756px of real
   content) -- Blake: "scroll down goes WAY beyond the builder." background-attachment:local
   is the built-in fix: it paints straight on the real scrolling element, tiles and scrolls
   with its actual content, and needs no explicit height at all -- it can never be taller or
   shorter than the content it's behind. */
.left-panel::-webkit-scrollbar{width:5px}
.left-panel::-webkit-scrollbar-track{background:transparent}
.left-panel::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}

/* RESIZER: a thin drag handle between the two panels. Desktop only -- mobile stacks the
   panels vertically, where a horizontal width has no meaning. Keyboard-operable (arrow
   keys) so this isn't a mouse-only accessibility dead end, same reasoning Blake gave for
   wanting the adjuster in the first place. */
.bshell-resizer{
  width:6px;flex-shrink:0;cursor:col-resize;position:relative;background:transparent;
  touch-action:none;
}
.bshell-resizer::after{
  content:"";position:absolute;top:0;bottom:0;left:2px;width:2px;background:var(--border);
  transition:background .15s;
}
.bshell-resizer:hover::after,.bshell-resizer.dragging::after{background:var(--accent)}
.bshell-resizer:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}

/* RIGHT PANEL: live preview + generate controls, always visible (not just post-generate). */
.right-panel{
  flex:1;
  display:flex;
  flex-direction:column;
  /* overflow:hidden, not auto -- 2026-08-27, matching GradBuzz/ResumeBuzz's own (separately
     built) right-panel architecture, now brought here after Blake said "make the GENERATE
     button fully visible always." The panel itself no longer scrolls; .output-wrap below is
     the ONE scrolling region, so exportRow/pptxNote/genBtn -- siblings AFTER it, still direct
     children of .right-panel -- always stay on screen regardless of how long the document is,
     the same guarantee GradBuzz/ResumeBuzz's #outputArea + .generate-wrap split already gives
     for free. Previously overflow-y:auto put the Generate button in the SAME long-scrolling
     flow as the document text, so a long Business Plan buried it at the bottom of a 5000px+
     scroll -- effectively hidden, Blake's own words. */
  overflow:hidden;
  min-width:0;
  padding:1.5rem 1.75rem 2rem;
  /* Same tint as the left panel's cards, not the plain page bg -- Blake, 2026-08-27:
     "same shade in the space around each viewer." */
  background:var(--surface2, var(--bg));
}
/* The ONE scrolling region inside .right-panel -- wraps previewEmpty/status/output so the
   controls after it (exportRow, pptxNote, genBtn) are exempt from its scroll and always
   visible. display:flex/flex-direction:column preserved so .preview-empty's own flex:1
   vertical-centering still works when the document is empty; min-height:0 is required for a
   flex child to actually shrink/scroll instead of forcing its flex-column parent taller. */
.output-wrap{
  flex:1;
  display:flex;
  flex-direction:column;
  overflow-y:auto;
  min-height:0;
}
.output-wrap::-webkit-scrollbar{width:5px}
.output-wrap::-webkit-scrollbar-track{background:transparent}
.output-wrap::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}

/* Mobile Builder/View tabs, default-hidden here so they never touch desktop layout
   or tab order; the 820px query below turns them on. See initMobileViewTabs in
   builder-shell.js. */
.bshell-viewtabs{display:none}
.bshell-doc-actions{display:none}

/* Generate, pinned to the bottom of the left panel on EVERY screen size, 2026-09-13
   -- Blake, direct: "the generate button is gonna always, always, always, even on
   desktop, live on the left hand side... pinned to the bottom... own the full
   bottom part." initMobileViewTabs (builder-shell.js) relocates the real Generate
   button into this wrapper, now appended inside .left-panel itself (was
   .right-panel) so position:sticky below has the correct scrolling ancestor.
   Flat by design -- no radius, no shadow, no inset bevel, matching the same
   flattening pass the accordion headers already got; this OVERRIDES whatever
   border-radius/box-shadow/text-shadow a brand's own Generate-button class sets,
   the single point of control for "flat, full-width, always at the bottom"
   instead of relying on five separate per-brand edits to stay in sync. */
/* CORRECTED 2026-09-13 (later the same day): the wrapper's own .7rem .9rem padding
   and border-top, below, were previously matched to #exportRow/.bottom-bar's height
   -- but Blake looked at the real render and rejected the visible gap/line that
   padding+border created around the button: "the generate button just needs to fill
   that whole bottom area, so there shouldn't even need to be any type of
   background," confirmed "ALL FIVE BUILDERS." The wrapper now carries NO padding
   and NO border of its own -- the button (100% width already) fills it completely,
   edge to edge, with zero visible framing. The bar's overall height now comes from
   the button's own native padding (each brand's existing Generate-button class),
   not a separately-matched wrapper value -- a real, accepted tradeoff against the
   old height-matching goal, not an oversight. */
.bshell-fixed-generate{
  display:block;position:sticky;bottom:0;left:0;right:0;z-index:5;
  margin-top:auto;flex-shrink:0;
  background:transparent;
}
.bshell-fixed-generate button{
  width:100% !important;border-radius:0 !important;box-shadow:none !important;
  text-shadow:none !important;transform:none !important;margin:0 !important;
}
/* Generate glow, item 19(d), 2026-09-18 -- armed by armGenerateGlow() (builder-shell.js)
   once the last real accordion section is done, stopped only by a real click on Generate
   (never a timer -- Blake, direct: "let it go indefinitely until they push it and then it
   stops"). var(--accent-dark, var(--accent)) is the same universal per-brand alias
   .bshell-sheen-btn already relies on, so this needed no new per-brand token. !important
   on box-shadow is required to win over .bshell-fixed-generate button's own
   box-shadow:none !important two rules up. */
.bshell-fixed-generate.bshell-glow button{
  animation:bshell-generate-pulse 1.7s ease-in-out infinite;
}
@keyframes bshell-generate-pulse{
  0%,100%{box-shadow:0 0 0 0 var(--accent-dark, var(--accent)) !important}
  50%{box-shadow:0 0 16px 4px var(--accent-dark, var(--accent)) !important}
}
@media(prefers-reduced-motion:reduce){
  .bshell-fixed-generate.bshell-glow button{
    animation:none;box-shadow:0 0 0 3px var(--accent-dark, var(--accent)) !important;
  }
}

@media(max-width:820px){
  html,body{height:auto;overflow:visible}
  body{min-height:100%}
  .bshell-main{flex-direction:column;overflow:visible}
  .left-panel{width:100% !important;flex-shrink:1;border-right:none;border-bottom:2px solid var(--border);overflow:visible}
  .bshell-resizer{display:none}
  .right-panel{overflow:visible;min-height:50vh}
  .output-wrap{overflow:visible;min-height:0}
  .left-panel select,
  .left-panel input:not([type=radio]):not([type=checkbox]),
  .left-panel textarea,
  .left-panel button:not(.shq){min-height:44px}

  /* BUZZ EXPANSION mobile port, 2026-09-13. Real fix for a found gap: the Generate
     button is `position:static` and only reads as reachable on desktop because
     html/body are capped to viewport height above (a two-panel split with each
     panel scrolling internally) -- mobile deliberately releases that cap two rules
     up, so the whole page scrolls instead, and a merely-sticky bar can only stick
     within its own box, not float above a long scrolling form. `position:fixed`
     is required. Alongside it: Builder/View tabs replace "stack both panels and
     scroll through everything" with one visible at a time, so the document/info
     preview doesn't force a long scroll just to reach the form or vice versa.
     Export-toolbar buttons (PDF/DOCX, Improve, Copy, Download slides -- Exec/Vow
     only) deliberately stay in normal flow on the View tab, not folded into the
     fixed bar: only Generate itself needed to always be reachable, and a five-
     button floating strip would be its own new mobile-usability problem. */
  .bshell-viewtabs{
    display:flex;position:sticky;top:0;z-index:16;
    background:var(--surface);border-bottom:2px solid var(--border);
  }
  .bshell-viewtabs button{
    flex:1;border:none;background:var(--surface);font:inherit;font-weight:700;
    font-size:.78rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);
    padding:.85rem .5rem;cursor:pointer;position:relative;border-top:3px solid transparent;
    min-height:44px;
  }
  .bshell-viewtabs button+button{border-left:1px solid var(--border)}
  .bshell-viewtabs button.active{
    color:var(--accent-dark,var(--accent));background:var(--surface2,var(--bg));
    border-top-color:var(--accent);
  }
  .bshell-viewtabs .bshell-viewdot{
    position:absolute;top:8px;right:calc(50% - 34px);width:7px;height:7px;border-radius:50%;
    background:var(--accent);border:1.5px solid var(--surface);display:none;
  }
  .bshell-viewtabs .bshell-viewdot.show{display:block}

  body.bshell-mobiletabs.bshell-view-builder .right-panel > .output-wrap,
  body.bshell-mobiletabs.bshell-view-builder .right-panel > #exportRow{display:none}
  /* Excludes .bshell-fixed-generate specifically, not the whole .left-panel --
     2026-09-13, needed once that wrapper moved from .right-panel into .left-panel
     (see builder-shell.js). Download/Re-audit lives inside that same wrapper and
     must stay visible on the View tab even though the rest of the left panel
     (the form) hides; a blanket .left-panel{display:none} would have taken the
     doc-actions bar down with it. */
  body.bshell-mobiletabs.bshell-view-generate .left-panel > *:not(.bshell-fixed-generate){display:none}

  body.bshell-mobiletabs{padding-bottom:64px}
  body.bshell-mobiletabs .bshell-fixed-generate{
    position:fixed;left:0;right:0;bottom:0;z-index:20;
    box-shadow:0 -8px 20px -14px rgba(0,0,0,.3);
  }
  body.bshell-mobiletabs .bshell-fixed-generate button{min-height:46px}

  /* Sticky document actions (Download + Re-audit) -- shares this same fixed bar
     space once a document exists, replacing Generate. See initMobileViewTabs's
     own opts.documentActions in builder-shell.js. Base display:none lives outside
     this media query, alongside .bshell-viewtabs/.bshell-fixed-generate's own.
     Tab-scoped, 2026-09-13 (Blake, direct: "they only generate when it's on the
     control side... the right side should just be the download buttons" --
     previously this swapped globally on has-document alone, so Generate showed
     on the View tab too, and Download/Re-audit leaked onto the Builder tab once
     a document existed). Generate now lives ONLY on the Builder tab (so you can
     still regenerate from there after a document exists); Download/Re-audit
     live ONLY on the View tab, and only once a document exists. */
  body.bshell-mobiletabs .bshell-fixed-generate > button{display:none}
  body.bshell-mobiletabs.bshell-view-builder .bshell-fixed-generate > button{display:block}
  /* Own inset now, 2026-09-13 -- the wrapper's shared padding was removed so Generate
     can fill it edge to edge (see .bshell-fixed-generate's own comment above), but a
     multi-button Download/Re-audit row still wants real inset from the screen edge,
     unlike a single full-bleed Generate button. */
  body.bshell-mobiletabs.bshell-has-document.bshell-view-generate .bshell-doc-actions{display:flex;gap:8px;padding:.6rem .9rem}
  .bshell-doc-actions button{flex:1;min-height:46px;border:none;border-radius:8px;
    font:inherit;font-weight:700;font-size:13px;cursor:pointer;
  }
  .bshell-doc-actions .bshell-doc-download{background:var(--accent,var(--tint));color:#fff}
  .bshell-doc-actions .bshell-doc-reaudit{
    background:var(--surface,#fff);color:var(--accent-dark,var(--tint-dark));
    border:1.5px solid var(--accent,var(--tint));
  }

  /* Real bug found 2026-09-13, Blake: "make sure mobile view, no buttons are
     stacked... the view line with all the buttons on the right lines up perfectly
     with the generate button on the left." Root cause: the DESKTOP action row
     (#exportRow on Resume/Exec/Vow, #bottomBar/#reauditRow on Grad) still renders
     in normal document flow on mobile's View tab -- only the Builder tab hides it
     (see the .output-wrap/#exportRow rule above) -- so its Download/Share/Re-audit
     buttons wrap across several visibly stacked rows below the page, duplicating
     what the fixed .bshell-doc-actions bar (which DOES line up with Generate,
     since both live in the same .bshell-fixed-generate wrapper) already covers.
     Hide every stray action BUTTON in these bars on mobile, both tabs, !important
     since several of them get a real inline style="" from JS -- Page Size (a
     <select> in its own wrapper, never a bare button) is deliberately left alone,
     it doesn't "stack" the way a row of buttons does. */
  #exportRow > button, #bottomBar > button, #reauditRow > button, #shareMount{
    display:none !important;
  }

  /* Droptimize's "audited by" strip (functions/_lib/shared/oye-strip.js) is desktop-only
     on the builder pages, 2026-09-13 -- Blake, direct: "I don't want any distracting
     things in between tools for the builder... no droptimize strip" on mobile, "only on
     desktop because I think it looks okay... plenty of room... down at the very, very
     bottom." Scoped here (builder-shell.css loads on build pages ONLY, confirmed --
     nothing else on any Buzz site references it) rather than touching the shared
     component itself, which still needs to render normally on every other OYE site. */
  .oye-strip-bar{ display:none; }

  /* The desktop Share button hides on mobile -- the fixed bottom bar's own
     Download (+ Re-audit where a brand still has it) already covers this screen
     size, so this avoids a second, redundant download control. */
  .share-mount{display:none}
}

/* Download-format menu -- outside the media query since it's positioned via JS
   (fixed, computed from the trigger button's own rect) and only ever created
   when a brand supplies 2+ download triggers to opts.documentActions. */
.bshell-doc-menu{
  position:fixed;z-index:30;background:var(--surface,#fff);border:1px solid var(--border);
  border-radius:10px;box-shadow:0 12px 32px rgba(0,0,0,.25);padding:6px;display:none;
  min-width:160px;
}
.bshell-doc-menu.open{display:block}
.bshell-doc-menu button{
  display:block;width:100%;text-align:left;padding:8px 10px;border:none;background:none;
  font:inherit;font-size:13px;color:var(--ink);border-radius:6px;cursor:pointer;
}
.bshell-doc-menu button:hover{background:var(--surface2,var(--bg))}

/* Share button + menu (desktop right panel), 2026-09-13 -- replaces the old row of
   separate Copy/PDF/DOCX/PPTX buttons. Flat, no radius/shadow, matching the same
   "take away bevels and round corners" pass the Generate button already got.
   .bshell-share-menu extends .bshell-doc-menu's own positioning/surface/shadow
   verbatim, just adds labeled groups (min-width bumped for the longer "Share to
   email or social — Full Hive feature" locked-state copy). */
/* The Share button's mount point in each brand's own exportRow markup --
   display:contents so it has zero box-model effect, letting the button itself
   participate directly in the parent toolbar's flex row (matching flex:1 on
   .bshell-share-btn below) rather than being squeezed into one wrapper-sized cell. */
.share-mount{display:contents}
/* Regular button size, 2026-09-13 -- Blake, direct, after seeing it stretched
   full-width in a real render: "make it look like every other fucking button on
   that page." flex:0 0 auto (not flex:1) -- Download and Share sit at their own
   natural size next to each other and Page Size, never stretched to fill the bar. */
/* White text, always, on the DARKER accent shade -- 2026-09-13, Blake, direct,
   after rejecting the black-on-light-accent approach outright: "black on pink
   doesn't look good, and you can't read it." That combo was numerically
   AA-passing (5.3:1) per the 2026-09-09 design-audit precedent this component
   first copied, but passing a number isn't the same as looking right to him --
   deferred to the direct call, not the math. --accent-dark is dark enough for
   white at a real, comfortable margin on every brand (matches
   --accent-text-hover's own 6.96:1 measurement), so this drops the whole
   --accent-text/-hover swap this component used to need -- one background, one
   text color, always legible, no state-dependent swap to get wrong again. */
.bshell-share-btn{
  flex:0 0 auto;min-height:44px;min-width:128px;padding:11px 22px;border:none;border-radius:0;
  font:inherit;font-weight:700;font-size:13.5px;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  background:var(--accent-dark,var(--accent,var(--tint)));color:#fff;
}
.bshell-share-btn svg{width:16px;height:16px;flex-shrink:0}
/* Text color swaps on hover too, not just background -- 2026-09-09's own design-
   audit sweep (see the --accent-text-hover comment above in this file) already
   found that ONE text color can't stay legible against both --accent and
   --accent-dark for brands like BuzzVow (black passes on the lighter --accent,
   fails at 3.02:1 on the darker hover shade) -- same pattern every other
   accent-colored button in this family already uses (.bshell-line-add and
   .bshell-proj-pill below), this one had just been built without it. Real bug, not
   cosmetic: Blake caught it live ("black text on pink button, you can't see it"). */
.bshell-share-btn:hover{filter:brightness(1.12)}
/* Faded, not hidden, 2026-09-14 -- Blake, direct: "ALL BUTTONS SHOULD BE SHOWING
   AT ALL TIME JUST FADED WHEN NOTHING IS GENERATED... ONLY SOLID AND ACCESSIBLE
   WHEN THERE IS SOMETHING." Same rectangle, same size, same brand color; real
   :disabled (not just a class) so it's genuinely non-interactive and correctly
   announced by AT. NOT opacity, corrected same day after the design-audit gate
   caught a real failure it: CSS opacity fades the WHOLE element uniformly,
   text included, toward whatever's behind it -- text and background converge
   toward the same color as opacity drops, so contrast only ever gets WORSE, never
   stays readable (measured: even 90% opacity only reached 3.74:1, needs 4.5:1,
   and BuzzResume's own accent-dark [154,123,46] failed even at full brightness
   before any fade at all -- 4.00:1 baseline). A semi-transparent black overlay
   darkens ONLY the background layer (background-image stacks with
   background-color; color is untouched) -- text stays full-opacity white always,
   contrast only ever goes UP as the background darkens. Verified across every
   brand's real --accent-dark: worst case (Resume) 7.02:1 at 30%, every other
   brand 10.8-14:1. */
.bshell-share-btn:disabled{background-image:linear-gradient(rgba(0,0,0,.3),rgba(0,0,0,.3));cursor:not-allowed}
.bshell-share-btn:disabled:hover{filter:none}
/* Every brand's own pre-initShareMenu download/re-audit buttons (pdfBtn, docxBtn,
   pptxBtn, reauditBtn, payOnceBtn, btnDownload, ...) stay real, fully-functional
   elements -- initShareMenu proxies their own .click()/disabled/label -- but must
   never be independently visible, or a brand ends up with TWO differently-styled
   button rows once a document exists (the real bug Blake caught live: Exec/Vow/
   Grad's own legacy buttons were still being un-hidden by old style.display=''
   toggles nobody removed when this shared bar shipped). display:none would also
   break visibleTriggers()'s own getComputedStyle(display) check, so this hides
   visually only (verbatim BuzzWriting's own .wb-proxy-btn, now shared). */
.bshell-proxy-btn{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* Re-audit's own "+🐝" badge, 2026-09-16 -- Blake: space it out from "Re-audit" the
   same as the Generate buttons below. A real flex item (not baked into the mirrored
   label text any more, see initShareMenu's syncReaudit in builder-shell.js). Not
   exposed to the button's accessible name (generated content isn't read as button
   text), matching the aria-hidden intent the old inline span used to carry by hand.
   CORRECTED same day, found rendering at mobile width: this originally relied on
   inheriting .bshell-share-btn's own gap:8px between flex items, which silently
   stopped applying wherever a MORE SPECIFIC rule elsewhere overrides display:flex to
   display:block (found on .bshell-generate-btn's own mobile Generate-button case,
   see its own sibling rule below -- same risk applies here) -- an explicit
   margin-left is layout-mode-independent, same 8px either way, never silently lost
   to a specificity fight this file doesn't control end to end. */
.bshell-reaudit-btn::after{content:"+🐝";margin-left:8px}
/* Pin flush to the bottom of .right-panel's flex column, 2026-09-14 -- Blake,
   direct, from a real screenshot showing page-colored space below the bar on
   BuzzWriting/BuzzResume: "get rid of that bottom space... MAKE IT STICK TO THE
   BOTTOM OF THE VIEW SCREEN." margin-top:auto on a flex child absorbs ALL slack
   above it, so this bar always lands flush against the panel's real bottom edge
   (flush with the audit-strip footer) regardless of how much or little content
   sits above it -- robust to any viewport height or ready/not-ready content
   mix, not just the one case reproduced while fixing it. One shared rule so
   this can't drift back to a per-brand fix on only two brands. */
.bottom-bar,#exportRow{margin-top:auto}
.bshell-share-menu{min-width:220px}
.bshell-share-group + .bshell-share-group{border-top:1px solid var(--border);margin-top:6px;padding-top:6px}
.bshell-share-label{font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);padding:6px 10px 4px}
.bshell-share-locked{
  display:block;padding:8px 10px;font-size:12.5px;color:var(--muted);text-decoration:none;
  line-height:1.4;
}
.bshell-share-locked:hover{color:var(--accent-dark,var(--accent))}
/* The "give us money" line -- one shared style, every gated/metered action reuses
   it (Download's pollen cost, Share's Pro lock) rather than each getting its own
   one-off treatment. Not a warning/error tone -- gold/accent, matching an upsell,
   not a mistake. */
.bshell-money-prompt{
  padding:6px 10px 2px;font-size:11.5px;font-weight:700;color:var(--gold,#F59E0B);
  letter-spacing:.01em;
}
a.bshell-money-prompt{padding:8px 10px;display:block}

/* FORM SECTIONS / ACCORDION (the "wiz-" prefix is the established name from ResumeBuzz's
   original build, kept for continuity across the family rather than renamed on a whim). */
.form-section{padding:1rem 1.25rem;border-bottom:1px solid var(--border)}
.section-header{
  font-family:'DM Sans',sans-serif; /* NOT 'DM Sans',monospace -- see file header note */
  font-size:0.78rem;
  font-weight:700;
  letter-spacing:0.08em;
  text-transform:uppercase;
  color:var(--warm);
  margin:0 0 0.875rem; /* explicit margin-top:0 -- it's a real <h2>, and only margin-bottom
    was ever overridden here, so the browser's default h2 top margin was pushing the text
    down inside the flex row instead of centering it (Blake: "close to hugging the bottom") */
  padding-left:0.55rem;
  border-left:2.5px solid var(--accent);
}
/* Solid, flat, brand-colored header bar -- 2026-09-13, reversing the embossed/bevelled/
   rounded card treatment this block used to carry (Blake's own 2026-08-27 spec: "make
   them embossed and glowing a bit... bevelled/embossed, with a glow effect"). Corrected
   against BuzzWriting's own .ol-act-row (assets/writing-board.js), a flat solid-fill
   block with square corners, once it existed side by side for comparison: "buzzwriting
   has a nice beautiful solid square dropdown and buzzresume is rounded and all dark.
   Needs to be solid, block, and a brighter brand specific color. Same treatment across
   all builders, byte for byte just different color and content." --wiz-fill/--on-fill
   default to each brand's own --accent-dark/#FFFDF8, already correct for Grad/Exec/Vow
   (their --accent-dark already equals their dashboard tab's own active-fill color, see
   hub-landing.js's BRANDS.dark); BuzzResume overrides --wiz-fill/--on-fill in its own
   :root, since its --accent-dark is a separately-tuned text-contrast value, not its
   dashboard tab's brighter panelFill color -- see resume/build-page.js. */
.wiz-step.form-section{padding:0}
.wiz-step.form-section:first-of-type{margin-top:0}
.wiz-header{
  display:flex;align-items:center;gap:0.6rem;cursor:pointer;user-select:none;
  padding:0.7rem 1.25rem;
  background:var(--wiz-fill, var(--accent-dark));
  transition:background .15s;
}
.wiz-header:hover{background:var(--accent, var(--wiz-fill))}
.form-section > .wiz-header + .wiz-body{padding:0.75rem 1.25rem 1rem}
.wiz-header .section-header{margin-bottom:0 !important;flex:1;border-left:none;padding-left:0;color:var(--on-fill, #FFFDF8)}
.wiz-check{
  flex-shrink:0;width:20px;height:20px;border-radius:50%;border:1.5px solid var(--on-fill, #FFFDF8);
  display:inline-flex;align-items:center;justify-content:center;font-size:0.68rem;line-height:1;
  color:transparent;transition:all .22s;background:transparent;opacity:.75;
}
.wiz-step.done .wiz-check{background:var(--on-fill, #FFFDF8);border-color:var(--on-fill, #FFFDF8);color:var(--wiz-fill, var(--accent-dark));opacity:1}
.wiz-step.open .wiz-check{opacity:1}
.wiz-chev{flex-shrink:0;color:var(--on-fill, #FFFDF8);transition:transform .2s;font-size:0.65rem;opacity:.85}
.wiz-step.open .wiz-chev{transform:rotate(180deg);opacity:1}
.wiz-body{display:none;padding-top:0.3rem}
.wiz-step.open .wiz-body{display:block}

/* Shared sheen/bevel button treatment -- used by .wiz-continue here and .generate-btn in
   each brand's own <style> (the actual most-important CTA, Blake: "this is the most
   important button here"). A bright gradient band up top (sheen), a dark inset at the
   bottom (bevel), a plain neutral drop shadow for lift -- never a color-tinted outer blur. */
/* Darker base (accent -> accent-dark, was accent-light -> accent) -- Blake, 2026-08-27:
   "generate buttons slightly darker shade." The sheen highlight on top still reads as a
   lit surface; it's the base fill underneath that reads too pale/washed out at the
   original lighter range. */
/* Flattened, 2026-09-13 -- Blake, direct: "take away any bevels and round
   corners," then caught this specific miss live ("why is the generate button
   that color... change it to the normal color"). This shared class (Vow/Exec's
   own Generate button, via a second class on the same element, plus
   initAccordion's "Continue" button family-wide) still had the old gradient-
   sheen + inset-bevel treatment -- the earlier flattening pass only touched each
   brand's own .generate-btn/.btn-generate rule, never this one, even though it
   was the one actually winning on background. Flat fill, real color unchanged
   (still var(--accent)), plain hover darken instead of a lift+shine trick. */
.bshell-sheen-btn{
  position:relative; border:none; cursor:pointer; overflow:hidden;
  background:var(--accent, var(--accent-dark));
  transition:filter .15s;
}
.bshell-sheen-btn:hover{filter:brightness(1.08)}
.bshell-sheen-btn:active{filter:brightness(0.95)}

/* ONE shared Generate-button size/shape/case family, 2026-09-14 -- Blake, direct,
   comparing real screenshots of all five: "all generate buttons are different
   cases, different sizes... MAKE ALL GENERATE BUTTONS THE SAME... GIVE THEM THE
   SAME CSS FAMILY SO THEY DON'T DRIFT EVER AGAIN." Each brand's own .btn-generate/
   .generate-btn/#genBtn had separately drifted (Resume/Grad: 0.95rem+0.85-0.9rem
   padding, DM Sans; Exec/Vow: 19px+15px padding+uppercase, via .bshell-sheen-btn's
   OWN local .generate-btn size rule; Writing: whatever .wb-btn's base size is) --
   this is the one place that ever sets size/case/font-family again. Background/
   text color stay brand-owned (added alongside this class, never inside it) since
   Resume's bright gold gradient needs dark ink text while the other four's darker
   fills need white -- forcing one text color here would fail contrast on at least
   one brand. */
.bshell-generate-btn{
  width:100%;min-height:50px;padding:14px 16px;
  font-family:'DM Sans',-apple-system,sans-serif;font-weight:700;font-size:15px;
  letter-spacing:0.02em;text-transform:none;
  border:none;border-radius:0;cursor:pointer;
  display:flex;align-items:center;justify-content:center;gap:0.5rem;
  transition:filter .15s,opacity .15s;
}
.bshell-generate-btn:hover{filter:brightness(1.08)}
.bshell-generate-btn:active{filter:brightness(0.95)}
.bshell-generate-btn:disabled{opacity:.5;cursor:not-allowed}
/* "+🐝" on every Generate button, 2026-09-16, same reasoning as Re-audit's own
   badge above: Blake wants it flagged as a 1-pollen action, same as Re-audit already
   is. Survives Exec/Vow's own genBtn.textContent rewrites untouched (it isn't part
   of the element's text) since it's generated content, not a real DOM node.
   CORRECTED same day, found rendering at mobile width (500px): this originally
   relied on inheriting this class's own gap:0.5rem between flex items, which
   silently breaks on mobile specifically -- the mobile fixed-bottom-bar Generate
   button toggle (body.bshell-mobiletabs.bshell-view-builder
   .bshell-fixed-generate > button{display:block}, this file's own
   @media(max-width:820px) block) is a MORE SPECIFIC selector than
   .bshell-generate-btn alone, so it legitimately overrides display:flex to
   display:block on every brand's mobile Generate button -- gap only applies
   between flex items, so it silently stopped applying there, and only there
   (desktop, where display:flex wins, was never affected). An explicit margin-left
   is layout-mode-independent: same 8px either way, verified against this exact
   override instead of assumed safe from it. */
.bshell-generate-btn::after{content:"+🐝";margin-left:8px}

/* ONE shared Page-Size control family, 2026-09-14 -- Blake, direct: "MAKE THE
   PAGE SIZE STYLE MATCH THE OTHERS." Each brand had its own one-off: Resume
   shrank it to 11.5px/12px+3px-6px inside .bottom-bar specifically, Grad used
   rem-based 0.7rem/0.75rem with its own arrow-position padding, Exec/Vow's
   .field-help/.field-caption (shared with OTHER unrelated fields on those
   pages, so never touched directly) happened to already match each other at
   13px/6px-8px/5px-radius -- that pair is the real reference this matches.
   Selector specificity (0,1,1) on the select/label beats a single class alone
   (0,1,0) like .field-help, so this wins there without editing those shared
   classes; brands whose own local rule is a class+class combo (Resume's
   ".bottom-bar .pagesize-inline select", Grad's ".pagesize-inline select")
   have to actually lose their conflicting properties, not just get out-
   specificity'd -- see each brand's own copy of this comment. */
/* flex-shrink:0 on the whole row, 2026-09-14 -- Blake, from a real screenshot,
   measured live: Resume's select computed at 38px wide (barely wider than its
   own padding, "Auto" nearly clipped) because this row had no flex-shrink of
   its own, so the bar's other siblings (Download/Share/Re-audit) squeezed it
   as real content instead of letting it size to what it actually needs. */
.bshell-pagesize-row{display:inline-flex;align-items:center;gap:6px;flex-shrink:0}
.bshell-pagesize-row label{font-size:13px;color:var(--muted);white-space:nowrap}
/* CORRECTED 2026-09-14 (same day, 3rd pass) -- real regression, not a taste
   call: this used var(--surface)/var(--border)/var(--ink), which correctly
   matches the SURROUNDING PANEL per brand -- fine for Resume's own dark
   panel, wrong for a form FIELD. Resume's own text inputs (the doc-type
   search box, etc.) all use --field-bg/--field-border/--field-text instead,
   a deliberately brand-neutral white-field set every other input on the page
   already uses regardless of how dark that brand's own panel gets -- this
   select is a field, not a panel, and needed the same tokens. Using --surface
   here is what put a dark box around "Auto" on Resume while the other four
   (whose --surface already happens to be white) looked fine, which is what
   Blake was actually pointing at ("its dropdown STYLE"), not the arrow glyph
   from the immediately preceding pass. Writing has no --field-* set, so the
   plain #fff/var(--border)/var(--ink) fallbacks are what carry it -- correct,
   since its own --surface is already white there. */
/* No-JS/screen-reader fallback only -- with JS on, upgradeSelect() (builder-shell.js)
   hides this real <select> and wires the shared .bshell-dd widget below in its place. */
.bshell-pagesize-row select{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  font-size:13px;padding:6px 28px 6px 8px;
  border:1px solid var(--field-border,var(--border));border-radius:5px;
  background-color:var(--field-bg,#fff);color:var(--field-text,var(--ink));
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%2364748B'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 10px center;background-size:10px 6px;
}
/* width:104px (a fixed width, not just a floor), CORRECTED 2026-09-14, 2nd pass --
   real bug, caught live from a real screenshot: min-width alone on the BUTTON and
   LIST separately let the control visibly resize per selection ("Auto" narrow,
   "US Letter" wide) since .bshell-dd-list stretches to match its wrap's current
   width (left:0;right:0), which itself tracks the BUTTON's current content width
   -- so whichever option happened to be selected when the list last opened set
   how much room the LIST ITEMS got, independent of their own text. Measured
   live: "US Letter" at the list's own 14px font + its own 8px/10px option
   padding + the list's own padding needs ~91px of content room; 104px on the
   WRAP (not the button or list separately -- both inherit from it via
   width:100%/left:0;right:0) covers that with room to spare and, being fixed
   rather than min, keeps the control a constant size no matter which option is
   showing. Scoped to .bshell-pagesize-row so only Page Size gets a fixed width
   -- upgradeSelect() (builder-shell.js) wraps every OTHER select on the page
   (Country, Language, Speaker Type, Tone, Purpose...) in this exact same
   .bshell-dd-btn-inline/.bshell-dd-list widget and none of those want this. */
.bshell-pagesize-row .bshell-dd-inline{width:104px}
/* Opens UP, not down -- 2026-09-14. .bshell-dd-list's shared default
   (top:calc(100% + 6px)) is right for every OTHER upgraded <select> on the
   page (Country, Language, Speaker Type...), which all sit mid-form with
   room below them. Page Size never does -- it's always the last control in
   the bottom action bar -- so the shared default either clips the list
   against the viewport edge or forces the page to scroll to show it, which
   read as "the button row moves." Scoped to .bshell-pagesize-row so this is
   the ONE control on the page that flips direction; nothing else changes. */
.bshell-pagesize-row .bshell-dd-list{top:auto;bottom:calc(100% + 6px)}

.wiz-continue{
  /* white, not var(--bg) -- that was ResumeBuzz's bright gold pattern (dark text reads fine
     on gold); BuzzExec's blue accent is darker, so dark text here was low-contrast, the
     same bug class as the dropdown/hover text fixes above. Blake, 2026-08-27: "dark text on
     dark color... still an issue from before." */
  /* display:block, 2026-09-15 -- a <button> is inline-block by default, so margin-top only
     drops it to its own line when something BLOCK-level happens to precede it in the DOM.
     Resume/Exec's own sections usually wrap their trailing "+ Add" button in a .lock-frame
     div (block-level, forces the line break); a section with no such wrapper -- found live
     on Grad's Leadership, whose "+ Add Leadership Role" button sits as a bare sibling --
     left this button flowing inline right next to it instead of stacking below. Explicit
     display:block makes this correct regardless of what the section's own markup looks
     like, rather than requiring every section to happen to end in a block-level wrapper. */
  display:block;width:fit-content;margin-top:0.85rem;color:#fff;border-radius:11px;padding:0.55rem 1.2rem;
  font-family:'DM Sans',sans-serif;font-weight:700;font-size:0.82rem;
}

/* CUSTOM DROPDOWN ("What are we writing for you?"). Replaces native <select> so a solid
   background and a brand-colored highlight actually render -- native <select> can't take
   either reliably (confirmed transparency/legibility bug on ResumeBuzz and BuzzVow, plan
   doc Phase 4 item 3). A hidden <input type=hidden> carries the real value so every existing
   docKind-reading call site keeps working unchanged; this widget only ever writes to that
   input and dispatches 'change' on it. */
/* z-index:5, not the ambient 1 every .left-panel child gets (for the honeycomb watermark
   layering) -- .docmount and the accordion form are SIBLING direct children of #leftPanel,
   so equal z-index means DOM order wins and the form would paint over the dropdown's open
   list despite its own z-index:40, since that only wins within ITS OWN stacking context.
   Found live 2026-08-27 rendering BuzzExec's rebuilt shell: the "LINK TO A BUSINESS"
   section painted through the open dropdown list instead of the list covering it.
   Same trap caught .topcontrols (Language/Region/etc select bar) the same day, on
   BuzzVow: opening the Language dropdown painted the "LINK TO A STORY" section over
   it and the list itself rendered behind the whole form -- same fix, same reason.
   REGRESSION found immediately after, same day: giving .docmount and .topcontrols the
   SAME flat z-index:5 just moved the tie one level up -- .topcontrols comes after
   .docmount in the DOM, so it now ALWAYS won, and opening the docKind dropdown got its
   own list painted over by the Language row instead ("the what are we doing dropdown
   mixes with the language"). A fixed hierarchy between two siblings that can each have
   an open floating list can only ever privilege one of them. Fixed with :focus-within:
   opening either widget focuses one of its own options (both open() implementations in
   builder-shell.js already do this for keyboard nav), so whichever one is actually open
   gets bumped above the other, in either direction, instead of a static ranking. */
.docmount,.topcontrols{position:relative;z-index:5}
.docmount:focus-within,.topcontrols:focus-within{z-index:20}
.bshell-dd{position:relative}
/* Native checkboxes (e.g. the phonetic-guide toggle) got no brand styling at all and
   rendered as the plain OS-default box next to on-brand custom dropdowns. accent-color
   is a real, broadly supported CSS property for native checkbox/radio controls -- no
   need to build a custom widget just for this. */
.left-panel input[type=checkbox]{accent-color:var(--accent-dark, var(--accent))}
/* Bold, authoritative "what's being built" label. Blake, 2026-08-27, second pass: "keep the
   text the same size and collapse the top and bottom of the white space onto it" -- text
   back to 17px, padding trimmed further so the box hugs it with just a little room, not
   grown around bigger text. */
/* Tinted, not plain white -- Blake, 2026-08-27: "add the color tints to the 'what are we
   building' dropdown too... the colored tabs will indicate that the user has the ability to
   select something important." Same --surface2 tint as the accordion cards, signaling this
   control the same way. */
.bshell-dd-btn{
  width:100%;display:flex;align-items:center;justify-content:space-between;gap:0.5rem;
  background:var(--surface2, var(--field-bg));border:1px solid var(--field-border);border-radius:8px;
  color:var(--field-text, var(--ink));padding:7px 14px;font:inherit;font-size:17px;font-weight:700;cursor:pointer;
  text-align:left;
}
.bshell-dd-btn:hover,.bshell-dd-btn[aria-expanded="true"]{border-color:var(--accent)}
.bshell-dd-btn:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
/* Sized like a normal field, not the big bold "what are we building" one -- every OTHER
   native <select> scattered through the form (Speaker Type, Story link, Occasion, Tone,
   Purpose...) upgraded to this same on-brand look. Blake, 2026-08-27: "these internal
   dropdowns look default to the browser? can we make them brand colored like the other
   dropdowns?" */
.bshell-dd-btn-inline{
  padding:0.45rem 0.65rem;font-size:0.82rem;font-weight:400;border-radius:5px;
  border-color:var(--field-border);
}
/* --dd-muted-text (renamed from --dd-chev-text, 2026-09-16, now also used by
   .bshell-dd-opt below -- same "dim dropdown chrome" purpose, no longer chevron-only)
   defaults to --muted (unchanged everywhere that already passes); Grad/Exec/Vow
   override it below -- at 14px real list-item text (needs 4.5:1, not the 3:1 an icon
   like the chevron gets away with), their own --muted measures 4.42/4.00/3.93:1 on
   their own dropdown surface2 fill. Same hue, darkened just enough to clear 4.5:1,
   measured against each brand's real surface2, not guessed. */
.bshell-dd-chev{flex-shrink:0;color:var(--dd-muted-text, var(--muted));transition:transform .15s;font-size:0.7rem}
.bshell-dd-btn[aria-expanded="true"] .bshell-dd-chev{transform:rotate(180deg)}
.bshell-dd-list{
  position:absolute;left:0;right:0;top:calc(100% + 6px);z-index:40;
  background:var(--surface2, var(--surface));border:1.5px solid var(--field-border);
  border-radius:10px;padding:0.35rem;max-height:min(360px,60vh);overflow-y:auto;
  box-shadow:0 12px 32px rgba(0,0,0,0.4);
  /* Stop scroll chaining -- 2026-08-27, Blake: scrolling past the last option was
     handing the scroll off to whatever sits behind the list (the left panel, or the
     page). overscroll-behavior:contain keeps the scroll gesture inside this list once
     it hits either end, instead of leaking into the parent. */
  overscroll-behavior:contain;
}
/* Muted until picked, 2026-09-16 -- Blake: since the search box now displays the ACTUAL
   selected doc type (see .bshell-search-input below), full-strength text there no longer
   reads as an example -- so the passive/unmuted treatment moved from the search box to
   here instead, the unpicked list. Highlighted/hovered/selected options stay full-strength
   white-on-accent below, unchanged. */
.bshell-dd-opt{
  padding:8px 10px;border-radius:6px;font-size:14px;color:var(--dd-muted-text, var(--muted));cursor:pointer;
}
.bshell-dd-opt:hover,.bshell-dd-opt[aria-selected="true"]{background:var(--accent);color:#fff}
.bshell-dd-opt:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
/* A real <option disabled> (tier-locked choices, e.g. ResumeBuzz's free-tier doc types)
   stays visibly present but unselectable through this custom UI too -- 2026-08-27. */
.bshell-dd-opt.bshell-dd-opt-disabled{
  cursor:not-allowed;color:var(--muted);opacity:0.55;
}
.bshell-dd-opt.bshell-dd-opt-disabled:hover{background:none;color:var(--muted)}
/* Bolder/darker, 2026-09-02 -- Blake: "make categories a little bolder so they are
   noticeable." Was font-weight:700 already, but --muted's low contrast made that
   invisible; --warm (same dark ink as headings) is what actually reads as bold. */
.bshell-dd-group{
  padding:0.65rem 0.75rem 0.25rem;font-size:0.72rem;font-weight:800;letter-spacing:0.08em;
  text-transform:uppercase;color:var(--warm);
}
.bshell-dd-group:not(:first-child){margin-top:0.3rem;border-top:1px solid var(--field-border);padding-top:0.6rem}
/* Searchable combobox input, 2026-08-27 -- Blake: "consistent language and country search
   across the other three brands... shame" + "fix the parity". A type-to-filter <input>
   sitting over a visually-hidden real <select>, same on-brand look as .bshell-dd-btn-inline
   (every other upgraded <select> on the page) rather than a separate visual treatment --
   the chevron is a background-image since a plain <input> has no child element to hold
   .bshell-dd-chev's own span. Dropdown list reuses .bshell-dd-list/.bshell-dd-opt/
   .bshell-dd-group verbatim (initSearchCombo below), so the rendered results look
   identical to every other themed dropdown, not a second style. */
/* font-size/weight raised to match .bshell-dd-btn's own established 17px/700 scale
   (reused verbatim, not a new value), 2026-09-16 -- BuzzWriting parity punch-list item 5,
   explicitly FAMILY-WIDE: Blake, off live screenshots, on the selected-type text this
   search box shows passively (e.g. "Screenplay" under "Search all project types"): needs
   to render "bigger and bolder, across ALL FIVE builders." Was 0.82rem/400 (normal
   weight) -- noticeably smaller/lighter than .bshell-dd-btn, the other on-brand control
   family that shows a chosen value the same way, which was already the real inconsistency
   Blake was reacting to. Typing (the un-muted state) gets the same bump; consistent size
   reads better than a wobble between "picked" and "searching." */
.bshell-search-input{
  width:100%;background:var(--surface2, var(--field-bg));border:1px solid var(--field-border);
  border-radius:5px;color:var(--field-text, var(--ink));padding:0.45rem 2rem 0.45rem 0.65rem;
  font:inherit;font-size:17px;font-weight:700;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%2364748B'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 0.65rem center;
}
.bshell-search-input:focus{outline:none;border-color:var(--accent)}
/* REVERSED, 2026-09-16 -- was muted from 2026-09-02 through today (mirroring the current
   selection in full-strength ink read as a filled dropdown, not a search box). Blake's own
   correction: since this box is defaulting to an actual, real doc type, it should display
   full-strength like any other real value -- the "looks like an example, not a firm pick"
   problem moved to the UNPICKED dropdown list instead (.bshell-dd-opt above), which is
   genuinely provisional until clicked. The .bshell-search-input--muted class/rule this
   comment used to document is fully removed, not just unused -- syncDisplay() in
   builder-shell.js no longer applies it. */

/* Inline project search bar (Restore's replacement) + project title bar (Delete's new
   home), BUZZ EXPANSION 2026-09-16 -- see initProjectSearchBar/initProjectTitleBar in
   builder-shell.js. Deliberately NOT a new visual language: the search field reuses
   .bshell-search-input verbatim (same box the doc-type search above it already uses,
   same font-size/weight/shape), and its results reuse .bshell-dd-list/.bshell-dd-opt
   verbatim (same list chrome as every other themed dropdown on the page) -- the family-
   wide parity ask this shipped for was "share font size, shape, text," not a matching
   palette. Only the per-row two-line content (title + doc-type pill + date) and the
   title bar itself are genuinely new. */
/* top margin removed entirely, BUZZ EXPANSION parity 2026-09-16 -- Blake, direct: "Load
   saved project" sat noticeably farther from its own search box than "Search all
   document types" sits from ITS OWN dropdown. Root cause: this margin (adjacent-sibling
   margin collapse, no border/padding between them) was overriding the label's own tight
   0.22rem margin-bottom every global label{} already uses, since 1rem > 0.22rem. The
   group-to-group gap above this label is already supplied by the wrapping container
   (.pinned-subgroup / .docmount / .pb-0-6, all 1rem) -- this widget needs none of its
   own on top, only bottom margin, for the proj-search-to-title gap below it. */
/* Exact values from Blake's own spacing tool (claude.ai/artifact/GTaTF2hvVUjzK1PaZwZbz4),
   dragged live and read back verbatim, not guessed: close gap 11px. */
.bshell-proj-search{position:relative;margin:0 0 11px}
.bshell-proj-opt{display:block}
.bshell-proj-title{display:block;font-weight:700}
.bshell-proj-meta{display:block;font-size:0.78em;opacity:0.8;margin-top:2px}
.bshell-dd-opt:hover .bshell-proj-meta,.bshell-dd-opt[aria-selected="true"] .bshell-proj-meta{opacity:0.9}
/* One pill style, reused as-is by Phase 3's dashboard list -- a small on-brand badge,
   never a second color system (same "on-brand accent fill" token pattern this file's
   own initLineList/.bshell-line-add rule already uses). */
.bshell-proj-pill{
  display:inline-block;background:var(--accent);color:var(--accent-text,#fff);
  border-radius:999px;padding:1px 8px;font-size:0.85em;font-weight:700;
  margin-right:0.4em;vertical-align:middle;
}
/* Title bar: editable title (initEditableTitle, unchanged) + a small delete-X, same row.
   Sits right below the project search per the approved order (doc-type search, project
   search, project title) -- hidden via initProjectTitleBar's own show/hide until a
   project actually exists, never an empty row taking up space before then. */
/* :not([hidden]), not a bare .bshell-proj-titlebar{display:flex} -- found live: a plain
   class-selector display rule has the SAME specificity as the browser's own default
   [hidden]{display:none} and loads later, so it silently WON, showing the row (delete-X
   included) even while .hidden=true. Scoping the rule so it simply doesn't match a
   hidden element is the fix, not !important. */
/* bottom margin matched to .bshell-proj-search's own 0.6rem (was 0.9rem), BUZZ
   EXPANSION parity 2026-09-16 -- Blake, direct: every stacked field in this pinned
   block needs equal spacing between them; the larger gap into whatever follows (the
   accordion) already comes from the outer .pinned-top/.docmount wrapper's own
   margin-bottom, a deliberately bigger "breathing room" gap from an earlier session,
   not this one. */
/* top/bottom split, BUZZ EXPANSION parity 2026-09-16 -- Blake, direct, furious: cutting
   every gap in this stack to the same tight value also crushed the gap into the
   ACCORDION down to nothing, which he never asked for ("I DIDN'T SAY MAKE THE BOTTOM
   MARGIN CLOSER"). The two are different in kind: two same-looking search fields
   stacked close together vs. the transition into a differently-colored section needs
   its own real breathing room, not zero. Top stays tight (matches the search-to-search
   gap above it); bottom restored to a real, visible gap. */
/* Exact values from Blake's own spacing tool, dragged live and read back verbatim:
   close gap 11px (top), breathing room 21px (bottom). */
.bshell-proj-titlebar:not([hidden]){display:flex;align-items:center;gap:8px;margin:11px 0 21px}
/* Real bordered field, not plain text on the honeycomb background -- BUZZ EXPANSION
   2026-09-16, Blake, direct: it "blends into the background" as bare text, and should
   look like the other fields in this pinned block, not a separate lighter-weight
   pattern. Same box as .bshell-search-input (verbatim: background/border/radius/
   padding-block), a left-aligned pencil icon replacing that field's right-aligned
   chevron since this isn't a dropdown, and single-line ellipsis truncation kept exactly
   as before -- a long title clips with "...", it never wraps or pushes the delete-X. */
.bshell-proj-title-text{
  flex:1;min-width:0;font-size:1.05rem;font-weight:800;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer;
  background:var(--surface2, var(--field-bg));border:1px solid var(--field-border);
  border-radius:5px;padding:0.45rem 0.65rem 0.45rem 2rem;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2364748B' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20h9'/%3E%3Cpath d='M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4Z'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:left 0.65rem center;
}
.bshell-proj-title-text:hover,.bshell-proj-title-text:focus-visible{border-color:var(--accent)}
.bshell-proj-delete-x{
  flex-shrink:0;width:24px;height:24px;min-width:24px;min-height:24px;border-radius:50%;
  border:none;background:transparent;color:var(--muted);font-size:18px;line-height:1;
  cursor:pointer;display:flex;align-items:center;justify-content:center;
}
.bshell-proj-delete-x:hover{background:var(--accent-glow, rgba(0,0,0,.08));color:#B3261E}

/* initLineList (2026-09-12): addable/removable/reorderable short-text rows (resume
   bullets, etc.), replacing a single free-text box split on newlines. The remove "X"
   sits INSIDE the field as an overlay, never as a separate element at the row's outer
   edge -- that's the exact spot a top-of-list help badge would otherwise collide with,
   the overlap BuzzWriting's Epic board had before this same convention was applied there. */
.bshell-line-head{display:flex;align-items:center;margin-bottom:6px}
.bshell-line-head-label{font-size:0.82rem;font-weight:600;color:var(--ink);letter-spacing:0.01em}
.bshell-line-list{display:flex;flex-direction:column;gap:6px}
.bshell-line-row{display:flex;align-items:flex-start;gap:6px}
.bshell-line-row.dragging{opacity:0.5}
.bshell-line-grip{flex-shrink:0;color:var(--muted);opacity:0.6;font-size:11px;cursor:grab;align-self:center;padding-top:8px}
.bshell-line-field{position:relative;flex:1;min-width:0}
.bshell-line-input{padding-right:28px;resize:none;display:block;min-height:0}
.bshell-line-input::placeholder{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bshell-line-remove{position:absolute;right:2px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--muted);cursor:pointer;font-size:12px;padding:4px;min-width:24px;min-height:24px}
.bshell-line-remove:hover{color:var(--accent-dark, var(--accent))}
/* Solid fill, 2026-09-16 -- BuzzWriting parity punch-list item 8, explicitly FAMILY-WIDE
   (not BuzzWriting-only): Blake, off live screenshots, on the dashed-outline ghost
   "+ Add ___" style every brand's own initLineList() button used to share: "too faint...
   needs a solid color, visible state, across ALL builders." Same on-brand accent-fill
   token pattern .bshell-proj-pill above already uses, not a new color system -- so
   every brand sharing this ONE class (Resume/Grad/Exec/
   Vow/Writing, wherever Achievements/Volunteer/Leadership/etc. use initLineList) picks
   this up for free, the correct single-source-of-truth fix rather than 5 separate edits. */
.bshell-line-add{margin-top:2px;background:var(--accent);border:1px solid var(--accent);border-radius:5px;color:var(--accent-text,#fff);font:inherit;font-size:0.78rem;font-weight:700;padding:5px 10px;cursor:pointer;min-height:24px}

/* initTagInput (2026-09-15): a comma/Enter-splitting tag box for Skills -- each entry a
   real, individually deletable pill instead of one comma-joined string, same reasoning
   as .bshell-line-* just above but for a single-line field. */
.bshell-tag-wrap{display:flex;flex-wrap:wrap;align-items:center;gap:6px;padding:6px 8px;border:1px solid var(--field-border,var(--border));border-radius:6px;background-color:var(--field-bg,#fff)}
.bshell-tag-pill{display:inline-flex;align-items:center;gap:4px;background:var(--surface2);border:1px solid var(--field-border,var(--border));border-radius:999px;padding:3px 4px 3px 10px;font-size:0.8rem;color:var(--field-text,var(--ink));max-width:100%}
.bshell-tag-pill-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bshell-tag-remove{flex-shrink:0;background:none;border:none;color:var(--muted);cursor:pointer;font-size:10px;padding:4px;min-width:20px;min-height:20px;border-radius:999px}
.bshell-tag-remove:hover{color:var(--accent-dark, var(--accent));background:var(--surface)}
.bshell-tag-input{flex:1;min-width:120px;border:none;background:none;color:var(--field-text,var(--ink));font:inherit;font-size:0.85rem;padding:3px 2px;outline:none}
.bshell-tag-input::placeholder{color:var(--muted)}

/* initFieldResizer / autoUpgradeFieldResizers (2026-09-13): a grabber below any
   textarea, for a manual drag-resize, a growing height while you type, and a
   double-click to fit-content/collapse-to-one-line. Ported from BuzzWriting's
   own Script tool, which already had the manual-only version of this same
   handle (its own inline styles, unchanged, since it never loads this file) --
   this is the byte-for-byte shared copy for the other four brands, using the
   same --accent/--accent-dark tokens every brand here already defines. */
.wb-resize-handle{height:9px;margin-top:1px;cursor:row-resize;position:relative;touch-action:none}
.wb-resize-handle::after{content:"";position:absolute;left:0;right:0;top:3px;height:2px;background:var(--border);transition:background .15s}
.wb-resize-handle:hover::after,.wb-resize-handle.dragging::after{background:var(--accent)}
.wb-resize-handle:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.wb-resize-readout{position:absolute;right:0;top:-15px;font-size:9.5px;color:var(--accent-dark, var(--accent));background:var(--surface2);padding:1px 5px;border-radius:4px;display:none}
.wb-resize-handle.dragging+.wb-resize-readout{display:block}
.bshell-line-add:hover{background:var(--accent-dark, var(--accent));border-color:var(--accent-dark, var(--accent));color:var(--accent-text-hover, var(--accent-text,#fff))}

/* Small data-trust line (2026-09-18, replaces the pulled top-of-builder trust-cue
   bar) -- one plain line, top of the left panel, right above the doc-type search.
   Deliberately small: Blake's own correction to the prior version, which took up
   too much space and read as threatening ("everything here is yours... never...
   target you"). Static markup per brand, no JS mount needed.
   Centered + spacing tuned, 2026-09-18 (a further session, from a real screenshot):
   centered (was left-flush against .left-panel's own zero padding), a small top
   margin so it isn't hugging the nav border, and margin-bottom dropped to 0 --
   .docmount's own existing padding-top:1rem (functions/_lib/<brand>/build-page.js,
   every brand) already supplies the gap down to "Search all document types" below,
   so this only needed to stop ADDING to it, not introduce a second spacing rule.
   REAL BUG caught fixing this comment, 2026-09-18: an earlier draft wrote the path
   as a glob (lib, star, slash, build-page.js) -- a star immediately followed by a
   slash is the CSS comment-close token, so it closed THIS comment right there mid-
   sentence. Everything after, including .doc-trust-line itself, silently parsed as
   garbage and got dropped until the parser resynced much later in the file.
   Confirmed via CSSStyleSheet().replaceSync() truncation testing, not guessed.
   Never let a star sit immediately before a slash inside a CSS comment, including
   as an accidental byproduct of a glob path -- write out the brand name, or add a
   space between the two characters, instead. */
.doc-trust-line{display:flex;align-items:center;justify-content:center;gap:5px;font-size:11px;line-height:1.3;color:var(--muted);margin:10px 0 0}

/* initAuditFixPanel (2026-09-18) -- the per-finding fix-it controls (Wording/Fact/
   Skill), shared across BuzzResume + BuzzGrad's own audit leader-line panels
   (functions/_lib/resume/build-page.js's buildFixPanel(), functions/_lib/grad/
   build-page.js's renderEssayAuditMarkup()). Approved interactive mockup:
   /private/tmp/claude-501/.../audit-fix-panel-mockup.html. Structural classes only
   -- every color is one of each brand's OWN real tokens (--gold/--warm/--border/
   --text/--muted/--surface already exist on every brand that loads this file; the
   two NEW ones, --fx-ok/--fx-ok-bg, are each brand's own real success-green,
   defined once in that brand's own :root, not invented here). The leader-line
   connector math (.cm-layout/.cm-connector-svg/.cm-note positioning) is NOT
   touched or duplicated -- this only styles what now renders INSIDE a .cm-note
   and inside the new inline mobile chip/drop. */
.fx-note{transition:opacity .15s, border-color .15s, background .15s}
.fx-note[data-state="included"]{border-left-color:var(--fx-ok, var(--gold))!important;background:var(--fx-ok-bg, var(--surface2))}
.fx-note[data-state="dismissed"]{opacity:.58}
.fx-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:5px}
.fx-dim{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--gold)}
.fx-kind-pill{font-size:9.5px;padding:2px 7px;border-radius:99px;background:var(--surface2, var(--bg));color:var(--muted);font-weight:600;white-space:nowrap}
.fx-body{margin:0 0 8px;font-size:12px;line-height:1.5;color:var(--text)}
.fx-reword{display:flex;flex-direction:column;gap:3px;background:var(--surface2, var(--bg));border-radius:6px;padding:7px 9px;margin-bottom:8px;font-size:11.5px;line-height:1.45}
.fx-reword del{color:var(--muted);text-decoration:line-through}
.fx-reword ins{color:var(--fx-ok, var(--gold));text-decoration:none;font-weight:600}
.fx-fact-field{width:100%;border:1px solid var(--border);border-radius:6px;padding:7px 8px;font:inherit;font-size:11.5px;background:var(--bg);color:var(--text);margin-bottom:8px;resize:vertical;min-height:40px}
.fx-fact-field:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
.fx-fact-field::placeholder{color:var(--muted);font-style:italic}
.fx-row{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.fx-row button{font:inherit;cursor:pointer;border-radius:6px;padding:6px 10px;font-size:11px;font-weight:700;border:1px solid transparent;min-height:30px}
.fx-btn-include{background:var(--fx-ok, var(--gold));color:#fff}
.fx-btn-include:disabled{background:var(--surface2, var(--bg));color:var(--muted);cursor:not-allowed;border-color:var(--border)}
.fx-btn-dismiss,.fx-btn-undo{background:transparent;color:var(--muted);border-color:var(--border)}
.fx-btn-dismiss:hover,.fx-btn-undo:hover{background:var(--surface2, var(--bg))}
.fx-btn-skill{background:var(--surface2, var(--bg));color:var(--text);border-color:var(--border);width:100%;justify-content:center;display:flex;gap:6px;align-items:center;margin-bottom:8px}
.fx-btn-skill:hover{filter:brightness(0.96)}
.fx-status-line{font-size:11px;font-weight:700}
.fx-status-line.included{color:var(--fx-ok, var(--gold))}
.fx-status-line.dismissed{color:var(--muted)}
[data-fx-action],.fx-fact-field{min-height:24px}

/* fx-wiz-* (2026-09-18, sequential-accordion fix): ONE card open at a time, same
   visual language as the real left-panel accordion (.wiz-header/.wiz-body/
   .wiz-chev/.wiz-check, initAccordion() in builder-shell.js / the .wiz-* rules
   above) -- same transition timing (chevron rotate .2s/180deg, checkmark fill
   transition .22s), same display:none/block collapse mechanism -- but its own
   fx-wiz-* classes, never the literal .wiz-* names, since this is a DIFFERENT DOM
   shape (one tiny accordion PER CARD, nested inside each existing .cm-note/
   .fx-note card, not one accordion for the whole panel). Real bug this fixes:
   every card used to render expanded/visible at once, so positionNotes()'s
   packing math didn't always give each one enough room and one card's label could
   sit on top of ANOTHER card's Include button (confirmed live via
   elementFromPoint -- ~1/3 of buttons unreachable on a real 13-finding essay).
   With this, only the OPEN card's .fx-wiz-body is ever display:block -- every
   other card is header-only (checkmark + title + chevron, no buttons in the
   layout at all) -- so two cards' INTERACTIVE controls can structurally never
   overlap, not just "less likely to." Color values are adapted, not copied
   verbatim, since .wiz-header/.wiz-check sit on a solid dark fill row
   (var(--wiz-fill)/var(--on-fill)) while these cards are small white/surface
   cards with a gold left border -- var(--gold) (already this file's shared fx-*
   accent alias, see .fx-dim/.fx-reword ins above) stands in for --wiz-fill as
   the "filled" color, inverted (light glyph on a colored disc, not a colored
   glyph on a light disc) since the surrounding chrome is light here, not dark. */
.fx-wiz-header{display:flex;align-items:center;gap:0.6rem;cursor:pointer;user-select:none;padding:2px 0 6px;transition:opacity .15s}
.fx-wiz-header:hover{opacity:.8}
.fx-wiz-header:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.fx-wiz-title{flex:1;font-size:12px;font-weight:700;color:var(--text)}
.fx-wiz-check{flex-shrink:0;width:20px;height:20px;border-radius:50%;border:1.5px solid var(--gold);display:inline-flex;align-items:center;justify-content:center;font-size:0.68rem;line-height:1;color:transparent;transition:all .22s;background:transparent;opacity:.75}
.fx-wiz-step.fx-done .fx-wiz-check{background:var(--gold);border-color:var(--gold);color:#fff;opacity:1}
.fx-wiz-step.fx-open .fx-wiz-check{opacity:1}
.fx-wiz-chev{flex-shrink:0;color:var(--muted);transition:transform .2s;font-size:0.65rem;opacity:.85}
.fx-wiz-step.fx-open .fx-wiz-chev{transform:rotate(180deg);opacity:1}
.fx-wiz-body{display:none;padding-top:0.3rem}
.fx-wiz-step.fx-open .fx-wiz-body{display:block}

/* Audit-highlight aggregate state, on the SAME .audit-hl anchor element each brand's
   existing leader-line code already marks -- data-fx-state is set by build-page.js's
   own redraw step from fixPanel.aggregateStateFor(el), never by this factory
   directly (it owns state, not the resume/essay DOM). */
.output-content .audit-hl[data-fx-state="included"]{background:var(--fx-ok-bg, rgba(63,107,46,.15));box-shadow:inset 0 -2px 0 var(--fx-ok, var(--gold))}
.output-content .audit-hl[data-fx-state="dismissed"]{opacity:.55;box-shadow:none}

/* Mobile inline group, "right where the thing is" -- replaces the old detached
   end-of-document <details> list on narrow viewports (Blake, on the mockup
   review: rejected a version that put findings only in a side column with
   nothing inline). Inserted directly after each anchor element inside the real
   resume/essay content, so it's shown/hidden by each brand's own layoutMode()
   alongside the desktop notes column/connector SVG, not by a raw CSS breakpoint.
   CORRECTED 2026-09-18 (sequential-accordion fix): this used to be its own
   independent "N changes suggested ▾" toggle wrapping a hidden .fx-inline-drop --
   a SECOND, competing expand/collapse layer on top of each card's own. Removed;
   each finding now renders as its own fx-wiz-header/body card directly inside
   this wrap (same noteHTML() used on desktop), so mobile gets the identical
   one-open-at-a-time, auto-advance rule for free, and a collapsed card's header
   already IS the real title -- no separate chip text needed. The card-chrome
   rule these grouped cards need (border/background/padding -- .cm-note already
   owns this for the desktop notes-column combo, .cm-note.fx-note, via each
   brand's own <style>) moves here, scoped to this wrapper only, so the desktop
   combo and the unstyled general-findings box are both untouched. */
.fx-inline-toggle-wrap{margin:2px 0 10px}
.fx-inline-toggle-wrap .fx-note{background:var(--surface);border:1px solid var(--border);border-left:3px solid var(--gold);border-radius:6px;padding:9px 11px;margin-bottom:8px}
.fx-inline-toggle-wrap .fx-note:last-child{margin-bottom:0}

/* Sticky bottom bar -- "N of M fixes ready" + Rebuild & re-audit. */
.fx-bar-wrap{position:sticky;bottom:14px;margin-top:18px;display:flex;justify-content:center;z-index:3}
.fx-bar{background:var(--surface);border:1px solid var(--border);border-radius:99px;padding:8px 8px 8px 16px;display:flex;align-items:center;gap:14px;box-shadow:0 8px 20px rgba(0,0,0,.18);max-width:100%}
.fx-bar-count{font-size:12px;color:var(--muted);white-space:nowrap}
.fx-bar-count b{color:var(--text)}
.fx-bar-rebuild-btn{font:inherit;cursor:pointer;border:none;border-radius:99px;padding:9px 16px;font-size:12.5px;font-weight:700;white-space:nowrap;background:var(--gold);color:#fff;min-height:34px}
.fx-bar-rebuild-btn:disabled{background:var(--surface2, var(--bg));color:var(--muted);cursor:not-allowed}
.fx-bar-cost{opacity:.85;font-weight:600;margin-left:6px}
@media(max-width:520px){
  .fx-bar{padding:7px 7px 7px 12px;gap:10px}
  .fx-bar-count{font-size:11px}
}
