/* ============================================================
   PYTHON COACH BINARY & HEX VISUALISER — overrides on top of
   v2-challenge-layout.css
   /v2/binary-hex.html  |  body[data-v2-binary-hex]

   v2-challenge-layout.css provides: body flex column, #ch-topbar,
   #ch-viewport grid, .ch-pane show/hide, #ch-bottomnav, .ch-tab-btn,
   dark/light tokens.

   PAGE SHELL: this used to be a normal scrolling page (hero above a
   bordered two-column card). It now reuses the exact same fixed-
   viewport app-shell as Trace Table (#ch-topbar / #ch-viewport /
   .ch-pane / #ch-bottomnav) so the two tools share one page geometry:
   topbar, full-viewport grid below it, a left tool pane and a right
   info pane split by a vertical divider, no outer card, no hero.

   The one deliberate difference from Trace Table's own grid: Trace
   Table's left column is itself split into two rows (editor above
   output) because it has a code editor to show. This tool has no code
   editor -- #pane-tool is a single pane -- so the shared 3-row grid
   (v2-challenge-layout.css's `grid-template-rows: 3fr 12px 2fr`) is
   overridden below to a single row. Everything else (column split,
   pane show/hide, mobile tab bar) is the same mechanism Trace Table
   uses, unmodified.

   Shared chrome classes below (.pg-topbar-logo*, .pg-avatar-*,
   .pg-info-cta) are duplicated verbatim from playground.css/
   trace-table.css, per this codebase's established convention, rather
   than shared via an import. Everything else uses the "bh-" prefix.
   ============================================================ */

/* ── PAGE SHELL — fixed viewport, same as Trace Table ─────────── */
body[data-v2-binary-hex] {
    height: 100dvh;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* ── TOPBAR: LOGO ─────────────────────────────────────────────── */
.pg-topbar-logo {
    display: flex;
    align-items: center;
    gap: 6px;
    text-decoration: none;
    flex-shrink: 0;
}

.pg-topbar-logo-icon { font-size: 1.25rem; line-height: 1; }

.pg-topbar-logo-text {
    font-size: 0.95rem;
    font-weight: 800;
    color: var(--primary);
    letter-spacing: -0.2px;
    white-space: nowrap;
}

body[data-v2-binary-hex] #ch-title {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-muted);
    border-left: 2px solid var(--border);
    padding-left: 12px;
}

@media (max-width: 600px) {
    body[data-v2-binary-hex] #ch-title { display: none; }
}

/* ── SETTINGS MENU (avatar, top-right of topbar) — identical rules to
   playground.css's/trace-table.css's .pg-avatar-* — duplicated here,
   same convention. ── */
.pg-avatar-wrap {
    margin-left: auto;
    position: relative;
    flex-shrink: 0;
}

.pg-avatar-btn {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--surface);
    border: 2px solid var(--border);
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
    display: grid;
    place-items: center;
    transition: background 0.15s, border-color 0.15s;
}

.pg-avatar-btn:hover  { background: var(--border); border-color: var(--border-dark); }
.pg-avatar-btn:active { background: var(--border-dark); }

.pg-avatar-btn[aria-expanded="true"] {
    background: var(--border);
    border-color: var(--primary);
}

.pg-avatar-menu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    width: 220px;
    background: var(--bg);
    border: 2px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
    padding: 8px;
    z-index: 300;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.pg-avatar-menu[hidden] { display: none; }

@media (max-width: 420px) {
    .pg-avatar-menu {
        width: calc(100vw - 32px);
        right: -8px;
    }
}

.pg-avatar-item {
    display: block;
    width: 100%;
    padding: 10px 14px;
    background: var(--surface);
    color: var(--text);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-xs);
    font-family: var(--font);
    font-size: 0.875rem;
    font-weight: 600;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
    line-height: 1.3;
}

.pg-avatar-item:hover  { background: var(--border); border-color: var(--border-dark); }
.pg-avatar-item:active { background: var(--border-dark); }

.pg-avatar-item.is-active {
    border-color: var(--primary);
    color: var(--primary);
    background: var(--bg);
}

/* ── PANE: TOOL (left column) ──────────────────────────────────── */
#pane-tool {
    background: var(--bg);
}

/* Compact controls/input strip -- toolbar-like, not a form section.
   flex-shrink: 0 keeps it a fixed-height header above the stepper,
   which takes all the remaining pane height. */
.bh-toolbar {
    flex-shrink: 0;
    padding: 10px 16px 8px;
    border-bottom: 1.5px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.bh-controls-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

.bh-start-label {
    font-size: 0.6875rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-secondary);
}

.bh-start-toggle {
    display: inline-flex;
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

/* Verified contrast pair reused throughout this page for "bold text on
   primary-dark": white on #0E8FCC (light) = 3.61:1; #0F172A on #0EA5E9
   (dark) = 6.44:1 -- both meet the large-text (>=14px bold) 3:1 minimum,
   which these buttons always are. */
.bh-start-btn {
    font-family: var(--font);
    font-size: 0.75rem;
    font-weight: 800;
    padding: 6px 12px;
    background: var(--bg);
    color: var(--text);
    border: none;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}

.bh-start-btn + .bh-start-btn { border-left: 1.5px solid var(--border); }

.bh-start-btn.is-active {
    background: var(--primary-dark);
    color: var(--text-inverse);
}

.bh-action-btn {
    font-family: var(--font);
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--text);
    background: var(--bg);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-xs, 6px);
    padding: 6px 12px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
    margin-left: auto;
}

.bh-action-btn:hover {
    background: var(--border);
    border-color: var(--border-dark);
}

.bh-fields {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}

@media (max-width: 480px) {
    .bh-fields { grid-template-columns: 1fr 1fr; }
    .bh-fields .bh-field:last-child { grid-column: 1 / -1; }
}

/* min-width: 0 overrides the grid item default of min-width: auto --
   without it, this column's track sizes to the <input>'s own intrinsic
   default width rather than its 1fr share. */
.bh-field {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.bh-field-label {
    font-size: 0.6875rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-secondary);
}

.bh-field input {
    width: 100%;
    font-family: var(--mono);
    font-size: 0.9375rem;
    font-weight: 700;
    padding: 6px 10px;
    background: var(--bg);
    color: var(--text);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm);
    letter-spacing: 0.02em;
}

.bh-field input:focus {
    outline: none;
    border-color: var(--primary);
}

/* Reuses the site's existing error-amber convention verbatim (same
   colours/ratios as .pg-runtime-error in playground.css: #B35C00 on
   white = 4.6:1 WCAG AA; #EEC252 on #0F172A = 9.0:1 WCAG AA). No new
   colour introduced here. */
.bh-error {
    color: #B35C00;
    font-size: 0.8125rem;
    font-weight: 600;
    margin: 0;
}
[data-theme="dark"] .bh-error { color: #EEC252; }

/* ── STEPPER ──────────────────────────────────────────────────────
   Fills all remaining pane height below .bh-toolbar. .bh-stepper-body
   is the ONLY child that scrolls (overflow-y: auto) -- the header and
   bottom nav are flex-shrink: 0, so Previous/Next/dots stay pinned in
   view inside the pane at all times, at any zoom level, exactly like
   the lesson UI's .chl-nav. */
.bh-stepper {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 0 16px;
}

.bh-stepper-header {
    flex-shrink: 0;
    padding-top: 10px;
}

.bh-step-badge {
    display: inline-block;
    font-size: 0.6875rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-inverse);
    background: var(--primary-dark);
    border-radius: 999px;
    padding: 3px 10px;
    margin: 0 0 6px;
}

.bh-stepper-title {
    font-size: 1.0625rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    line-height: 1.25;
    color: var(--text);
    margin: 0 0 4px;
}

.bh-stepper-explain {
    font-size: 0.8125rem;
    line-height: 1.45;
    color: var(--text);
    margin: 0 0 8px;
}

/* The "work area" -- a distinct tonal panel (surface against the
   pane's own bg) so the interactive content reads as one clear focus
   area. This is the one part of the step allowed to scroll, so a
   dense step (e.g. the addition view) never pushes the nav below out
   of view. */
.bh-stepper-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    min-width: 0;
    background: var(--surface);
    border-radius: var(--radius-sm);
    padding: 10px 12px;
    margin-bottom: 10px;
}

/* ── STEP LAYOUT WRAPPERS ─────────────────────────────────────────
   Give every single-block step (a bit table on its own, nibbles on
   their own, a narration line on its own, ...) a deliberate position
   inside .bh-stepper-body instead of sitting as a small block near the
   top of an otherwise empty work area. min-height: 100% resolves
   against .bh-stepper-body's flex-assigned height (a flex item with
   flex:1 has a definite used height, so percentage heights of its
   children resolve normally); centering only kicks in when the step's
   content is shorter than the available space -- taller content still
   just scrolls via the parent's own overflow-y: auto. ── */
.bh-step-focus {
    min-height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    text-align: center;
}

.bh-step-focus .bh-hexdigits-wrap,
.bh-step-focus .bh-hexkey {
    justify-content: center;
}

/* .bh-narration's own margin-bottom (set for its plain block-flow use in
   the summary, where there's no flex gap doing that job) would otherwise
   stack ON TOP of these containers' flex `gap`, doubling the space
   between sections -- exactly what was pushing Step 3 into needing a
   scrollbar. Neutralised specifically inside the gap-based layouts. */
.bh-step-focus > .bh-narration,
.bh-step-stack .bh-narration {
    margin-bottom: 0;
}

/* "Split into nibbles" step: a small uppercase divider between each of
   its three sections (full byte / split / nibble weights) -- reuses
   .bh-summary-label's exact look (no new colour/pattern), just with the
   top margin reset since it follows a full-width table/line rather
   than another text block. Margin trimmed from 18px so the three-
   section Step 3 board fits without a scrollbar at a normal desktop
   viewport -- see the whole "Slide 3 spacing" pass below too. */
.bh-step-split-label {
    margin-top: 10px;
    margin-bottom: 2px;
}
.bh-step-split-label:first-child {
    margin-top: 0;
}

/* The two 4-bit groups in the "Split"/grouped byte line (#bh-binary-
   readout) -- a visible vertical rule between them is "a vertical split
   line coming down the middle of the byte", per Adam's Step 3 review.
   Reuses --primary-dark (already verified elsewhere on this page), not
   a new colour. */
.bh-nibble-group {
    display: inline-block;
}

.bh-nibble-divider {
    display: inline-block;
    width: 2px;
    height: 0.85em;
    background: var(--primary-dark);
    margin: 0 0.6em;
    vertical-align: middle;
}

/* Each nibble's own weighting line -- side by side, each built from the
   exact same .bh-bit-table/.bh-place-value/.bh-bit-btn classes as the
   full 8-bit table above it, so both render at the identical desktop
   scale (the enlarge rules further down key off those class names, not
   which step they're in). A left divider + margin on the second group
   is the same "vertical split line" idea as .bh-nibble-divider above,
   reinforcing that these are two separate, reset weighting lines, not
   one continuous row. Wraps to a stacked column on narrow viewports
   rather than ever forcing horizontal overflow (the divider/margin are
   dropped when stacked, since there's nothing to divide left-to-right
   any more). */
.bh-nibble-weight-tables-wrap {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 28px;
}

.bh-nibble-weight-tables-wrap .bh-nibble-weight-group + .bh-nibble-weight-group {
    border-left: 2px solid var(--primary-dark);
    padding-left: 28px;
}

@media (max-width: 600px) {
    .bh-nibble-weight-tables-wrap .bh-nibble-weight-group + .bh-nibble-weight-group {
        border-left: none;
        padding-left: 0;
    }
}

/* min-width keeps both nibble blocks the same width regardless of how
   many digits their own calc/mapping text happens to run to (e.g.
   "8 + 4 = 12" vs "8 + 4 + 1 = 13") -- "same width, same emphasis" per
   Adam's visual-hierarchy review, so the two blocks read as one
   consistent pair rather than drifting apart in size. */
.bh-nibble-weight-group {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    min-width: 150px;
}

.bh-nibble-weight-group .bh-bit-table {
    width: auto;
}

/* Nibble weighting-line place values picked out in the primary colour
   (vs. the full byte line's plain muted grey above) -- "colour
   emphasis" on the moment the weights reset, per Adam's review. Reuses
   var(--primary), not a new colour. */
.bh-nibble-weight-group .bh-place-value {
    color: var(--primary);
    font-weight: 800;
}

/* ── SLIDE 4 VISUAL HIERARCHY ─────────────────────────────────────
   1. nibble bit tiles (.bh-bit-btn, unchanged) -- the main teaching
      object, stays the largest/most prominent thing on the slide.
   2. .bh-nibble-weight-calc ("8 + 4 + 1 = 13") -- neutral text colour,
      smaller than the bit tiles.
   3. .bh-nibble-weight-hex ("13 maps to D") -- smaller again than the
      calc line, and neutral text colour throughout except the actual
      resulting digit (.bh-nibble-weight-hex-digit), which is the only
      part still picked out in blue/bold -- "blue mainly for ... final
      hex digits", not a whole highlighted line. Previously this whole
      line read "Hex digit: D" in var(--primary) at a size LARGER than
      the bit tiles, which is what made it read as the most important
      thing on the slide when it should be the least of these three.
   Both hidden on Step 3 (.bh-nwt-hide-calc/--hide-hex) -- see the STEP
   LAYOUT WRAPPERS comment above for exactly which steps show which. */
.bh-nibble-weight-calc {
    display: block;
    font-family: var(--mono);
    font-weight: 700;
    font-size: 0.875rem;
    color: var(--text);
}

.bh-nibble-weight-hex {
    display: block;
    font-family: var(--mono);
    font-weight: 600;
    font-size: 0.8125rem;
    color: var(--text-secondary);
}

.bh-nibble-weight-hex-digit {
    color: var(--primary);
    font-weight: 800;
}

.bh-nwt-hide-calc .bh-nibble-weight-calc,
.bh-nwt-hide-hex .bh-nibble-weight-hex {
    display: none;
}

/* renderNibbleWeightTables() renders BOTH mapping-line phrasings for
   every nibble ("13 maps to D" and "D maps to 13") -- only one is ever
   visible. Default (Denary/binary-start, the final summary): value ->
   digit. Hex-start's "convert digit to nibble" step already knows the
   digit (it's the thing it's expanding), so it reads the other way --
   .bh-nwt-hex-direction-digit on the wrap swaps which one shows. Both
   variants still count as ".bh-nibble-weight-hex" for .bh-nwt-hide-hex
   above, so that modifier still hides whichever one would otherwise be
   showing. */
.bh-nwt-hex-fromdigit {
    display: none;
}
.bh-nwt-hex-direction-digit .bh-nwt-hex-fromvalue {
    display: none;
}
.bh-nwt-hex-direction-digit .bh-nwt-hex-fromdigit {
    display: block;
}

/* Simple entry transition: fade + slight rise, added just before the
   step renders and removed on the next frame so the CSS transition
   plays once. Skipped entirely under prefers-reduced-motion (see
   animateNibbleSplitIn() in binary-hex.js), in which case this section
   is simply never given the class and renders at its final, fully
   visible state immediately. */
.bh-nibble-weight-tables-wrap {
    opacity: 1;
    transform: translateY(0);
    transition: opacity 0.3s ease, transform 0.3s ease;
}
.bh-nibble-weight-tables-wrap.bh-anim-in {
    opacity: 0;
    transform: translateY(8px);
    transition: none;
}

/* Read-only variant of .bh-bit-btn for the nibble weighting lines above
   -- same box/text size (so the scale genuinely matches Step 1's
   clickable table), just non-interactive: no pointer cursor, no hover
   state change. The single editable bit surface stays Step 1/2's table. */
.bh-bit-btn--static {
    display: block;
    cursor: default;
}
.bh-bit-btn--static:hover {
    border-color: var(--border);
}

/* Vertical stack for Step 4 (nibble weighting-line tables, hex key, hex
   result), each centred in turn. */
.bh-step-stack {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    min-height: 100%;
}

.bh-step-stack-nibbleeq,
.bh-step-stack-hexkey {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.bh-step-stack-hexresult {
    width: 100%;
    max-width: 480px;
}

/* ── BOTTOM NAV: arrow · dots · arrow — pinned at the bottom of the
   pane (flex-shrink: 0 on .bh-stepper-nav; only .bh-stepper-body above
   it scrolls), so it's visible at 100% zoom without scrolling the
   page. Mirrors .chl-nav's arrangement: a border-top separator, two
   circular icon buttons either side of a flexible dot strip. ── */
.bh-stepper-nav {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 0 max(10px, env(safe-area-inset-bottom, 0px));
    border-top: 1.5px solid var(--border);
}

/* Circular nav buttons -- reuses the same translucent-overlay
   technique as .chl-prev-btn (rgba(0,0,0,0.08) light / rgba(255,255,
   255,0.12) dark) -- not a new colour, just an alpha over the existing
   surface. */
.bh-nav-arrow {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: 1.125rem;
    font-weight: 800;
    border: none;
    cursor: pointer;
    transition: filter 0.15s, opacity 0.15s, transform 0.1s;
    background: rgba(0, 0, 0, 0.08);
    color: var(--text-secondary);
}

[data-theme="dark"] .bh-nav-arrow {
    background: rgba(255, 255, 255, 0.12);
    color: var(--text);
}

.bh-nav-arrow:hover:not(:disabled)  { filter: brightness(1.15); }
.bh-nav-arrow:active:not(:disabled) { transform: scale(0.93); }

.bh-nav-arrow:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

/* Prominent "Next" -- var(--primary-dark)/var(--text-inverse), the
   same verified accessible pair used throughout this page. */
.bh-nav-arrow-next {
    background: var(--primary-dark);
    color: var(--text-inverse);
}

.bh-nav-arrow-next:hover:not(:disabled) { filter: brightness(1.08); }

.bh-nav-arrow-next:disabled {
    opacity: 0.4;
}

/* Dot progress indicator -- directly mirrors #chl-slide-dots/
   .chl-slide-dot: a tappable area with a smaller visual dot as a
   ::before pseudo-element. Same three states (visited/current/
   unvisited), same translucent-overlay technique for visited/
   unvisited (no new colour), --primary-dark for current. The final
   summary is always the last dot. */
.bh-step-dots {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    overflow: hidden;
    padding: 0 4px;
}

.bh-step-dot {
    width: 20px;
    height: 20px;
    min-width: 20px;
    border-radius: 50%;
    background: transparent;
    border: none;
    cursor: pointer;
    display: grid;
    place-items: center;
    padding: 0;
    flex-shrink: 0;
}

.bh-step-dot::before {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: 50%;
    display: block;
    transition: background-color 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}

.bh-step-dot--visited::before {
    background-color: rgba(0, 0, 0, 0.25);
}
[data-theme="dark"] .bh-step-dot--visited::before {
    background-color: rgba(255, 255, 255, 0.35);
}

.bh-step-dot--current::before {
    background-color: var(--primary-dark);
    transform: scale(1.4);
}

.bh-step-dot--unvisited {
    pointer-events: none;
    cursor: default;
}

.bh-step-dot--unvisited::before {
    background: transparent;
    border: 1.5px solid rgba(0, 0, 0, 0.12);
}
[data-theme="dark"] .bh-step-dot--unvisited::before {
    border-color: rgba(255, 255, 255, 0.15);
}

@media (prefers-reduced-motion: reduce) {
    .bh-step-dot::before {
        transition: none;
    }
}

/* ── FINAL STEP: FULL SUMMARY ─────────────────────────────────────
   Small section labels separating the reused blocks (weights,
   addition, nibbles, hex result) when they all appear together on
   the final step. */
.bh-summary-label {
    font-size: 0.6875rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin: 14px 0 6px;
}

.bh-summary-label:first-child {
    margin-top: 0;
}

/* ── BIT TABLE ────────────────────────────────────────────────── */
#bh-bit-table-wrap {
    overflow-x: auto;
    margin-bottom: 0;
}

.bh-bit-table {
    border-collapse: collapse;
    width: 100%;
}

.bh-bit-table th,
.bh-bit-table td {
    padding: 3px;
    text-align: center;
}

.bh-place-value {
    font-size: 0.625rem;
    font-weight: 700;
    color: var(--text-muted);
    font-family: var(--mono);
    white-space: nowrap;
}

.bh-bit-btn {
    width: 100%;
    min-width: 28px;
    font-family: var(--mono);
    font-size: 0.9375rem;
    font-weight: 800;
    padding: 6px 4px;
    background: var(--bg);
    color: var(--text);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-xs);
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}

.bh-bit-btn:hover {
    border-color: var(--border-dark);
}

.bh-bit-btn.is-on {
    background: var(--primary-dark);
    color: var(--text-inverse);
    border-color: var(--primary-dark);
}

@media (max-width: 480px) {
    .bh-bit-table th,
    .bh-bit-table td {
        padding: 2px;
    }

    .bh-place-value {
        font-size: 0.5625rem;
    }

    .bh-bit-btn {
        min-width: 20px;
        font-size: 0.75rem;
        padding: 5px 2px;
    }
}

/* ── NARRATION ────────────────────────────────────────────────────── */
/* Also reused verbatim for the hex-digit-values narration and the
   binary-string readout (both share this same "bordered monospace text
   box" look). The previous vertical column-addition view (.bh-addition/
   .bh-addition-wrap and friends) has been removed -- it isn't part of
   the current teaching sequence or final summary, both of which now use
   this narration box's inline "174 = 128 + 32 + 8 + 4 + 2" pill instead. */
.bh-narration {
    font-family: var(--mono);
    font-size: 0.875rem;
    font-weight: 700;
    color: var(--text);
    background: var(--bg);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 8px 12px;
    margin: 0 0 10px;
    word-break: break-word;
}

/* Step 2's calculation pill -- the same .bh-narration box, picked out
   with the page's own primary-colour border/tint (no new colour:
   verbatim reuse of --primary/--primary-dark, same colour-mix fallback
   pattern as .ch-skip-banner in v2-challenge-layout.css) so it reads as
   the step's headline "174 = 128 + 32 + 8 + 4 + 2" rather than a plain
   supporting note. */
.bh-narration-pill {
    display: inline-block;
    margin: 4px 0 0;
    border-color: var(--primary-dark);
}
@supports (color: color-mix(in srgb, red 1%, transparent)) {
    .bh-narration-pill {
        background: color-mix(in srgb, var(--primary) 10%, var(--bg));
    }
}

/* The full, unbroken byte string ("00010110") shown above the grouped-
   into-nibbles view -- wider letter-spacing makes each of the 8 digits
   read as its own column, echoing the weighting line above it. */
.bh-full-byte {
    display: inline-block;
    font-size: 1.125rem;
    letter-spacing: 0.2em;
    padding-inline: 16px;
}

/* ── HEX RESULT ───────────────────────────────────────────────────
   The dashed "nibble card" visual previously here (.bh-nibble-card and
   friends, plus #bh-nibbles-wrap), and later the plain-text nibble-
   equations boxes, have both been removed as dead code -- every step
   and the final summary now share the one nibble weighting-line table
   component (.bh-nibble-weight-tables-wrap). ── */
.bh-hex-result {
    font-family: var(--mono);
    font-size: 0.9375rem;
    font-weight: 700;
    color: var(--text);
    background: var(--bg);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 8px 14px;
    text-align: center;
    margin: 0;
}

.bh-hex-result strong {
    color: var(--primary);
    font-size: 1.125rem;
}

/* ── FINAL SUMMARY: BINARY -> HEX -> DENARY CONVERSION GRID ────────
   Horizontal table, one column per nibble -- overflow-x:auto is the
   same "give every potentially-wide block its own scroll container"
   approach used for the bit table/addition block. */
.bh-conversion-grid-wrap {
    overflow-x: auto;
    margin-bottom: 4px;
}

.bh-conversion-grid {
    border-collapse: collapse;
    font-family: var(--mono);
    width: 100%;
}

.bh-conversion-grid th,
.bh-conversion-grid td {
    padding: 6px 12px;
    text-align: center;
    border: 1.5px solid var(--border);
    white-space: nowrap;
}

.bh-conversion-grid th {
    text-align: left;
    font-size: 0.625rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--text-secondary);
    background: var(--bg);
}

.bh-conversion-grid td {
    font-weight: 700;
    color: var(--text);
    background: var(--surface);
}

/* ── HEX-START STEP 1: HEX DIGIT SPLIT ───────────────────────────── */
.bh-hexdigits-wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 4px;
}

.bh-hexdigit-chip {
    display: grid;
    place-items: center;
    min-width: 34px;
    height: 34px;
    padding: 0 6px;
    font-family: var(--mono);
    font-weight: 800;
    font-size: 1.0625rem;
    color: var(--text);
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm);
}

/* ── HEX DIGIT KEY (0-F) ───────────────────────────────────────────── */
.bh-hexkey {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.bh-hexkey-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    min-width: 30px;
    padding: 4px 2px;
    font-family: var(--mono);
    color: var(--text);
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-xs);
}

.bh-hexkey-letter {
    font-size: 0.875rem;
    font-weight: 800;
}

.bh-hexkey-value {
    font-size: 0.625rem;
    font-weight: 700;
    color: var(--text-muted);
}

.bh-hexkey-cell.is-used {
    background: var(--primary-dark);
    border-color: var(--primary-dark);
}

.bh-hexkey-cell.is-used .bh-hexkey-letter,
.bh-hexkey-cell.is-used .bh-hexkey-value {
    color: var(--text-inverse);
}

/* ── PANE: INFO (right column) — same top-of-funnel info-panel
   pattern as Trace Table's #pane-trace-info (tv-howto-heading/
   tv-howto/pg-info-cta), renamed with this page's "bh-" prefix so a
   future shared extraction can standardise on either name. ──────── */
.bh-howto-heading {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin-top: 8px;
    margin-bottom: 10px;
}

.bh-howto {
    margin: 0 0 24px;
    padding-left: 20px;
    color: var(--text-secondary);
    font-size: 0.875rem;
    line-height: 1.6;
}

.bh-howto li { margin-bottom: 6px; }
.bh-howto strong { color: var(--text); }

/* Verbatim reuse of Trace Table's .pg-info-cta (var(--primary)/#fff --
   already established site-wide for this exact CTA, not a new colour). */
.pg-info-cta {
    display: block;
    padding: 13px 18px;
    background: var(--primary);
    color: #fff;
    font-size: 0.9375rem;
    font-weight: 700;
    text-align: center;
    text-decoration: none;
    border-radius: var(--radius-sm, 6px);
    transition: opacity 0.15s;
    margin-top: 4px;
}

.pg-info-cta:hover { opacity: 0.88; }

/* ── DESKTOP CONTENT DENSITY ────────────────────────────────────
   The left pane has real width/height to spare at >=1024px (the split-
   pane desktop layout below). Scale up the actual teaching content --
   bit tiles, nibble weighting lines, hex chips, the narration text, the
   conversion grid -- rather than leaving it at phone-sized tiles inside
   a much bigger work area. Below this breakpoint (including the <1024
   "mobile tab" view, which can still be a full-width tablet) content
   keeps the more conservative sizing defined above. ── */
@media (min-width: 1024px) {
    .bh-stepper-title    { font-size: 1.375rem; }
    .bh-stepper-explain  { font-size: 0.9375rem; }

    .bh-bit-table th,
    .bh-bit-table td { padding: 5px; }

    .bh-place-value { font-size: 0.8125rem; }

    /* Vertical padding trimmed from 14px -> 10px (per Adam's "slightly
       reduce internal panel padding" allowance for Step 3) -- box/font
       size is unchanged, so the bit tiles stay just as readable, they're
       simply not as tall. */
    .bh-bit-btn {
        min-width: 48px;
        font-size: 1.375rem;
        padding: 10px 8px;
    }

    .bh-narration {
        font-size: 1.125rem;
        padding: 10px 20px;
    }

    .bh-full-byte {
        font-size: 1.5rem;
        letter-spacing: 0.25em;
    }

    /* Slide 4 visual hierarchy, desktop scale: bit tiles (1.375rem, above)
       stay the largest; the calc line is next; the "maps to" mapping
       line is smaller again -- was 1.75rem (bigger than the bit tiles
       themselves), which is exactly what made it read as the most
       important thing on the slide. */
    .bh-nibble-weight-calc { font-size: 1.0625rem; }
    .bh-nibble-weight-hex  { font-size: 0.9375rem; }

    /* "Hex result" is the slide's conclusion, not a second title --
       reduced from 1.25rem/1.75rem so it doesn't out-compete the nibble
       blocks above it. */
    .bh-hex-result {
        font-size: 1rem;
        padding: 10px 18px;
    }

    .bh-hex-result strong { font-size: 1.25rem; }

    /* Hex key: supporting reference, not a main teaching object --
       reduced scale (was min-width 48px/letter 1.375rem for the chip
       row above, and 42px/1.125rem for this key) so it reads as
       secondary to the nibble blocks while the highlighted cells
       (.bh-hexkey-cell.is-used) stay just as legible. */
    .bh-hexdigit-chip {
        min-width: 48px;
        height: 48px;
        font-size: 1.375rem;
    }

    .bh-hexkey-cell   { min-width: 34px; padding: 6px 3px; }
    .bh-hexkey-letter { font-size: 0.9375rem; }
    .bh-hexkey-value  { font-size: 0.6875rem; }

    .bh-conversion-grid th,
    .bh-conversion-grid td {
        padding: 10px 20px;
        font-size: 1rem;
    }
}

/* ── FINAL SUMMARY: SCALED-DOWN VISUAL RECAP ─────────────────────
   .bh-stepper-body--summary is toggled by renderStepPanel() only while
   the final summary is showing. The summary reuses the exact same
   visual components every step uses (the bit table, the nibble
   weighting-line tables, narration boxes, the conversion grid, the hex
   key, ...) rather than a separate text/table layout -- these overrides
   just pull their sizing back down to roughly this page's base
   (pre-desktop-enlarge) scale, a "slightly smaller summary scale" per
   Adam's review, so the whole recap reads as a compact set of the same
   graphics rather than a few of them blown up to full teaching size.
   Two-class specificity beats the >=1024px enlarge rules above
   regardless of viewport width, so this applies consistently on both
   mobile and desktop -- no separate media query needed. ── */
.bh-stepper-body--summary .bh-bit-btn {
    min-width: 28px;
    font-size: 0.9375rem;
    padding: 6px 4px;
}

.bh-stepper-body--summary .bh-place-value {
    font-size: 0.625rem;
}

.bh-stepper-body--summary .bh-narration {
    font-size: 0.875rem;
    padding: 8px 12px;
}

.bh-stepper-body--summary .bh-full-byte {
    font-size: 1.125rem;
    letter-spacing: 0.15em;
}

.bh-stepper-body--summary .bh-nibble-weight-calc {
    font-size: 0.8125rem;
}

.bh-stepper-body--summary .bh-nibble-weight-hex {
    font-size: 0.6875rem;
}

.bh-stepper-body--summary .bh-nibble-weight-tables-wrap {
    gap: 16px;
}

.bh-stepper-body--summary .bh-nibble-weight-tables-wrap .bh-nibble-weight-group + .bh-nibble-weight-group {
    padding-left: 16px;
}

.bh-stepper-body--summary .bh-hex-result {
    font-size: 0.9375rem;
    padding: 8px 14px;
}

.bh-stepper-body--summary .bh-hex-result strong {
    font-size: 1.125rem;
}

.bh-stepper-body--summary .bh-conversion-grid th,
.bh-stepper-body--summary .bh-conversion-grid td {
    padding: 6px 12px;
    font-size: 0.8125rem;
}

.bh-stepper-body--summary .bh-hexkey-cell {
    min-width: 30px;
    padding: 4px 2px;
}

.bh-stepper-body--summary .bh-hexkey-letter {
    font-size: 0.875rem;
}

.bh-stepper-body--summary .bh-hexkey-value {
    font-size: 0.625rem;
}

/* ── DESKTOP LAYOUT ─────────────────────────────────────────────
   Same mechanism as trace-table.css's own "DESKTOP LAYOUT ADJUSTMENTS"
   block: v2-challenge-layout.css already supplies the #ch-viewport
   grid/.ch-pane display switch at >=1024px. The only override needed
   here is collapsing the shared 3-row (editor/handle/output) grid down
   to a single row, since #pane-tool has no editor+output split to
   show -- and assigning #pane-tool/#pane-info to their columns, exactly
   as trace-table.css assigns #pane-trace-info to column 2. ── */
@media (min-width: 1024px) {

    body[data-v2-binary-hex] #ch-desktop-tabs { display: none; }
    body[data-v2-binary-hex] #ch-bottomnav { display: none; }

    body[data-v2-binary-hex] #ch-viewport {
        grid-template-rows: 1fr;
    }

    body[data-v2-binary-hex] #pane-tool {
        grid-column: 1;
        grid-row: 1;
        border-right: 2px solid var(--border);
    }

    body[data-v2-binary-hex] #pane-info {
        grid-column: 2;
        grid-row: 1;
        overflow: hidden;
    }

    body[data-v2-binary-hex] #pane-tool,
    body[data-v2-binary-hex] #pane-info {
        display: flex !important;
    }

    /* Fluid spacing + readable line length for the info pane, mirrors
       v2-challenge-layout.css's own #ch-objective-scroll desktop rule. */
    body[data-v2-binary-hex] #ch-objective-scroll {
        max-width: 560px;
        width: 100%;
        margin-inline: auto;
        padding: clamp(20px, 0.89vw + 10.9px, 28px)
                 clamp(24px, 1.79vw + 5.7px,  40px)
                 clamp(24px, 1.79vw + 5.7px,  40px);
    }
}
