/* Editor chrome, popovers, menus, and PDF options. */
/* ============================================================================
   PDF OPTIONS MODAL
   ----------------------------------------------------------------------------
   Export-settings sheet. Adjusts the --print-* tokens live; hidden in print via
   the @media print rule above. Centred dialog on desktop, bottom sheet on phones.
   ============================================================================ */
.pdf-options-modal {
   position: fixed;
   inset: 0;
   z-index: 60;
   display: grid;
   place-items: center;
   padding: clamp(12px, 4vw, 32px);
}
.pdf-options-modal[hidden] {
   display: none;
}
.pdf-options-backdrop {
   position: absolute;
   inset: 0;
   background: rgba(16, 38, 27, 0.5);
   opacity: 0;
   transition: opacity 0.2s ease;
}
.pdf-options-modal.is-open .pdf-options-backdrop {
   opacity: 1;
}
.pdf-options-dialog {
   position: relative;
   display: flex;
   flex-direction: column;
   /* Wider + taller than a normal dialog on purpose: the left pane shows a whole
      physical page (A4/Letter portrait), so it needs real vertical room to stay
      readable. */
   width: min(1180px, 100%);
   max-height: min(94vh, 940px);
   overflow: hidden;
   border: 1px solid var(--line);
   border-radius: var(--radius-lg);
   background: var(--surface);
   box-shadow: var(--shadow-md);
   opacity: 0;
   transform: translateY(10px) scale(0.985);
   transition:
      opacity 0.2s ease,
      transform 0.2s ease;
}
.pdf-options-modal.is-open .pdf-options-dialog {
   opacity: 1;
   transform: translateY(0) scale(1);
}
@media (prefers-reduced-motion: reduce) {
   .pdf-options-backdrop,
   .pdf-options-dialog {
      transition: none;
   }
}

/* Header */
.pdf-options-head {
   flex: none;
   display: flex;
   align-items: flex-start;
   justify-content: space-between;
   gap: 14px;
   padding: 20px 20px 14px;
   border-bottom: 1px solid var(--line);
}
.pdf-options-kicker {
   display: block;
   margin-bottom: 3px;
   color: var(--green);
   font-size: 10px;
   font-weight: 800;
   letter-spacing: 1.1px;
}
.pdf-options-head h2 {
   margin: 0;
   font-size: 19px;
   letter-spacing: -0.4px;
   color: var(--ink);
}
.pdf-options-sub {
   margin: 6px 0 0;
   max-width: 34ch;
   color: var(--muted);
   font-size: 11.5px;
   line-height: 1.45;
}
.pdf-options-close {
   flex: none;
}

/* Body */
.pdf-options-body {
   flex: 1;
   min-height: 0;
   overflow-y: auto;
   padding: 16px 20px 18px;
   display: flex;
   flex-direction: column;
   gap: 14px;
}

/* Two-pane split: paper preview on the left, controls on the right */
.pdf-options-layout {
   flex: 1;
   min-height: 0;
   display: grid;
   grid-template-columns: minmax(0, 1fr) 372px;
}
.pdf-options-preview {
   display: flex;
   flex-direction: column;
   min-width: 0;
   min-height: 0;
   border-right: 1px solid var(--line);
   background: linear-gradient(180deg, #eef3ef, #e7ede8);
}
.pdf-preview-bar {
   flex: none;
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 10px;
   padding: 10px 16px;
   border-bottom: 1px solid var(--line);
   background: rgba(255, 255, 255, 0.6);
}
.pdf-preview-title {
   color: var(--muted);
   font-size: 10px;
   font-weight: 800;
   letter-spacing: 1px;
   text-transform: uppercase;
}
.pdf-preview-scale {
   padding: 2px 8px;
   border-radius: 999px;
   background: var(--soft);
   color: var(--green);
   font-size: 10.5px;
   font-weight: 800;
   font-variant-numeric: tabular-nums;
}
.pdf-preview-scroll {
   flex: 1;
   min-height: 0;
   overflow: auto;
   padding: 16px 12px;
   display: grid;
   /* `safe` centers only while the paper fits; when a multi-page paper is taller
      than the pane it falls back to start-alignment so the TOP stays reachable
      (plain `center` would push the top out of view and clip it). */
   place-content: safe center;
}
/* The real #previewCard is moved in here. To make this preview MATCH THE PRINTED
   PDF EXACTLY we reproduce true paper geometry:
     • the host is one physical page: --pdf-page-w × --pdf-page-h (mm, set by JS
       from the chosen paper size)
     • page margins come from --pdf-page-margin-* (mm, from the chosen margin
       preset) applied as padding, exactly like the real @page box
     • the card itself gets NO padding/min-width of its own, so its content box
       equals the real printable area (paper − margins)
   The whole page is then visually scaled with --pdf-preview-scale to fit the pane. */
.pdf-preview-paper {
   --pdf-preview-scale: 1;
   --pdf-page-w: 210mm;
   --pdf-page-h: 297mm;
   --pdf-page-count: 1;
   /* Margins are locked to the "narrow" preset (see PDF_MARGINS in pdfOptions.js);
      fitPreviewToPane() overrides these inline for the live preview. */
   --pdf-page-margin-top: 7mm;
   --pdf-page-margin-x: 7mm;
   --pdf-page-margin-bottom: 9mm;
   width: calc(var(--pdf-page-w) * var(--pdf-preview-scale));
   height: calc(var(--pdf-page-h) * var(--pdf-page-count, 1) * var(--pdf-preview-scale));
   margin: 0 auto;
   filter: drop-shadow(0 8px 22px rgba(20, 58, 41, 0.18));
}
.pdf-preview-page {
   position: relative;
   box-sizing: border-box;
   width: var(--pdf-page-w);
   /* --pdf-page-count pages tall, so multi-page songs are fully visible instead
      of being clipped at page 1. */
   height: calc(var(--pdf-page-h) * var(--pdf-page-count, 1));
   padding: var(--pdf-page-margin-top) var(--pdf-page-margin-x) var(--pdf-page-margin-bottom);
   transform: scale(var(--pdf-preview-scale));
   transform-origin: top left;
   background: #fff;
   /* outline, not border: a border would consume 2px of the printable width and
      make text wrap differently from the real PDF. */
   outline: 1px solid #dfe6e0;
}
/* Neutralise the editor card chrome so only the real print rules shape it. */
.pdf-preview-page > #previewCard {
   width: 100% !important;
   min-width: 0 !important;
   max-width: none !important;
   margin: 0 !important;
   padding: 0 !important;
   border: 0 !important;
   border-radius: 0 !important;
   background: #fff !important;
   box-shadow: none !important;
   zoom: 1 !important;
}
/* Read-only preview: this is the LIVE #previewCard node, so block ALL pointer
   interaction (clicks, drags, text-field focus, contenteditable edits) while it
   lives in the preview. It's a faithful PDF mock-up, not an editing surface. */
.pdf-preview-page > #previewCard {
   pointer-events: none !important;
   -webkit-user-select: none !important;
   user-select: none !important;
   cursor: default !important;
}
.pdf-preview-page > #previewCard * {
   pointer-events: none !important;
}
.pdf-preview-page > #previewCard input,
.pdf-preview-page > #previewCard textarea,
.pdf-preview-page > #previewCard button,
.pdf-preview-page > #previewCard [contenteditable] {
   pointer-events: none !important;
   -webkit-user-modify: read-only !important;
   user-select: none !important;
}
/* Signature footer is a REAL-PDF-only flourish. Hide it in the live preview so
   the pane shows only the actual score content (the generated PDF still keeps
   it via the @media print rules). */
.pdf-preview-page > #previewCard .pdf-signature {
   display: none !important;
}
/* ...whereas BAR NUMBERS are SCORE content (PDF options → Bars → Off / Line starts /
   Every bar), so the pane must show exactly what paper gets. The node in here is the LIVE
   #previewCard, i.e. the editor's own faint 0.34-opacity numbers would otherwise leak in and
   disagree with the export. This rule is only the BASELINE (hide the editor's numbers): the
   stamp itself comes from the `html.is-print-layout[data-pdf-bar-numbers=…]` rules in
   preview.css, which are active here too because opening the dialog switches the layout
   preview on — one single definition for paper AND pane, so they cannot drift apart. */
.pdf-preview-page > #previewCard .bar-num {
   display: none !important;
}
.pdf-options-panel {
   display: flex;
   flex-direction: column;
   min-height: 0;
   min-width: 0;
}
.pdf-field {
   display: flex;
   flex-direction: column;
   gap: 8px;
}
/* Bar numbers are a CHORD CHART-only option, so pdfOptions.js hides the divider +
   field (id=pdfBarsDivider / pdfBarNumField) with the `hidden` attribute in the
   other modes. This rule is what makes `hidden` win over the flex layouts below
   (there is no global [hidden] reset, and `display: flex` would otherwise beat the
   element's own `[hidden]` styling). */
.pdf-options-panel [hidden] {
   display: none !important;
}
.pdf-field-inline {
   flex-direction: row;
   align-items: center;
   justify-content: space-between;
   gap: 12px;
   flex-wrap: wrap;
}
.pdf-field-label {
   display: flex;
   align-items: baseline;
   justify-content: space-between;
   gap: 10px;
   font-size: 12.5px;
   font-weight: 700;
   color: var(--ink);
}
.pdf-field-label small {
   font-weight: 500;
   font-size: 10.5px;
   color: var(--muted);
}
.pdf-field-divider {
   display: flex;
   align-items: center;
   gap: 10px;
   margin-top: 2px;
   color: var(--muted);
   font-size: 10px;
   font-weight: 800;
   letter-spacing: 1px;
   text-transform: uppercase;
}
.pdf-field-divider::after {
   content: "";
   flex: 1;
   height: 1px;
   background: var(--line);
}

/* Segmented choice buttons (presets, paper, margins) */
.pdf-choice-group {
   display: flex;
   gap: 6px;
   flex-wrap: wrap;
}
.pdf-choice {
   flex: 1 1 auto;
   min-width: 68px;
   min-height: 38px;
   padding: 0 12px;
   border: 1px solid var(--line);
   border-radius: 999px;
   background: var(--surface);
   color: var(--ink);
   font-size: 12.5px;
   font-weight: 700;
   cursor: pointer;
   transition:
      border-color 0.15s ease,
      background 0.15s ease,
      color 0.15s ease;
}
.pdf-choice:hover {
   border-color: var(--green);
   background: var(--soft);
}
.pdf-choice.is-active {
   border-color: var(--green);
   background: var(--green);
   color: #fff;
}
.pdf-choice:focus-visible {
   outline: 3px solid #d9efd6;
   outline-offset: 1px;
}

/* Sliders */
.pdf-slider-value {
   min-width: 52px;
   padding: 2px 7px;
   border-radius: 999px;
   background: var(--soft);
   color: var(--green);
   font-size: 11px;
   font-weight: 800;
   font-variant-numeric: tabular-nums;
   text-align: center;
}
.pdf-slider {
   -webkit-appearance: none;
   appearance: none;
   width: 100%;
   height: 22px;
   background: transparent;
   cursor: pointer;
}
.pdf-slider::-webkit-slider-runnable-track {
   height: 6px;
   border-radius: 999px;
   background: var(--soft);
}
.pdf-slider::-webkit-slider-thumb {
   -webkit-appearance: none;
   appearance: none;
   width: 20px;
   height: 20px;
   margin-top: -7px;
   border: 3px solid #fff;
   border-radius: 50%;
   background: var(--green);
   box-shadow: 0 1px 4px rgba(20, 58, 41, 0.28);
}
.pdf-slider::-moz-range-track {
   height: 6px;
   border-radius: 999px;
   background: var(--soft);
}
.pdf-slider::-moz-range-thumb {
   width: 16px;
   height: 16px;
   border: 3px solid #fff;
   border-radius: 50%;
   background: var(--green);
}
.pdf-slider:focus-visible {
   outline: none;
}
.pdf-slider:focus-visible::-webkit-slider-thumb {
   box-shadow: 0 0 0 4px #d9efd6;
}

/* Footer */
.pdf-options-foot {
   flex: none;
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 10px;
   padding: 14px 20px 18px;
   border-top: 1px solid var(--line);
}

/* Dark theme */
html[data-theme="dark"] .pdf-options-dialog {
   border-color: var(--line);
   background: #151715;
}
html[data-theme="dark"] .pdf-options-backdrop {
   background: rgba(4, 8, 6, 0.62);
}
html[data-theme="dark"] .pdf-choice {
   border-color: var(--line);
   background: #101110;
   color: var(--ink);
}
html[data-theme="dark"] .pdf-choice:hover {
   border-color: #55b982;
   background: #1d211e;
   color: #f1f4f2;
}
html[data-theme="dark"] .pdf-choice.is-active {
   border-color: var(--green);
   background: var(--green);
   color: #08130d;
}
html[data-theme="dark"] .pdf-slider::-webkit-slider-runnable-track,
html[data-theme="dark"] .pdf-slider::-moz-range-track {
   background: #23271f;
}
html[data-theme="dark"] .pdf-slider::-webkit-slider-thumb,
html[data-theme="dark"] .pdf-slider::-moz-range-thumb {
   border-color: #151715;
}
html[data-theme="dark"] .pdf-slider-value {
   background: #1d211e;
   color: #7fd3a4;
}
html[data-theme="dark"] .pdf-options-preview {
   border-color: var(--line);
   background: linear-gradient(180deg, #0e100e, #121412);
}
html[data-theme="dark"] .pdf-preview-bar {
   border-color: var(--line);
   background: rgba(255, 255, 255, 0.03);
}
html[data-theme="dark"] .pdf-preview-scale {
   background: #1d211e;
   color: #7fd3a4;
}

/* Tablets / small laptops: stack the preview above the controls */
@media (max-width: 900px) {
   .pdf-options-dialog {
      width: min(560px, 100%);
   }
   .pdf-options-layout {
      grid-template-columns: minmax(0, 1fr);
      grid-template-rows: minmax(140px, 34vh) minmax(0, 1fr);
   }
   .pdf-options-preview {
      border-right: 0;
      border-bottom: 1px solid var(--line);
   }
}

/* Phones: present as a bottom sheet with comfortable touch targets. The live
   PDF preview is HIDDEN here — on a phone there isn't room to render a full page
   usefully, so we show only the PDF options controls. The card is still adopted
   into the (hidden) host and restored on close, so nothing breaks. */
@media (max-width: 560px) {
   .pdf-options-modal {
      place-items: end stretch;
      padding: 0;
   }
   .pdf-options-dialog {
      width: 100%;
      max-height: 88vh;
      border-width: 1px 0 0;
      border-radius: var(--radius-lg) var(--radius-lg) 0 0;
      transform: translateY(16px);
   }
   .pdf-options-modal.is-open .pdf-options-dialog {
      transform: translateY(0);
   }
   /* Options-only layout: drop the preview row entirely. */
   .pdf-options-preview {
      display: none !important;
   }
   .pdf-options-layout {
      grid-template-columns: minmax(0, 1fr);
      grid-template-rows: minmax(0, 1fr);
   }
   .pdf-choice {
      min-height: 44px;
   }
   .pdf-field-inline {
      flex-direction: column;
      align-items: stretch;
   }
   .pdf-options-foot .button {
      min-height: 44px;
   }
   /* base/tokens.css hides .button-ghost on phones to declutter the topbar; the
      modal's own actions must stay visible. */
   .pdf-options-foot .button-ghost {
      display: inline-flex !important;
      align-items: center;
      justify-content: center;
   }
}

/* ============================================================
   Inline chord editor (type → pick a suggestion) + the matching
   beat-hover field preview. A single width token keeps the hover
   affordance and the popover input pixel-identical.
   ============================================================ */
:root {
   --chord-field-w: 84px; /* shared: hover preview footprint == popover input */
   --chord-field-h: 30px;
}

/* Floating popover, positioned by JS (fixed to the viewport). */
.chord-popover {
   position: fixed;
   z-index: 1400;
   width: max-content;
   min-width: calc(var(--chord-field-w) + 20px);
   max-width: min(92vw, 260px);
   padding: 8px;
   background: var(--surface);
   border: 1px solid var(--line);
   border-radius: var(--radius-md);
   box-shadow: var(--shadow-md);
   animation: chord-pop-in 0.13s ease-out both;
}
@keyframes chord-pop-in {
   from {
      opacity: 0;
      transform: translateY(4px) scale(0.98);
   }
}
/* Little arrow pointing at the anchored beat. */
.chord-popover::after {
   content: "";
   position: absolute;
   left: var(--arrow-x, 50%);
   bottom: -6px;
   width: 12px;
   height: 12px;
   background: var(--surface);
   border-right: 1px solid var(--line);
   border-bottom: 1px solid var(--line);
   transform: translateX(-50%) rotate(45deg);
}
.chord-popover.is-below::after {
   bottom: auto;
   top: -6px;
   border: 0;
   border-left: 1px solid var(--line);
   border-top: 1px solid var(--line);
}
.chord-popover-input {
   width: var(--chord-field-w);
   height: var(--chord-field-h);
   box-sizing: border-box;
   border: 1.5px solid var(--green);
   border-radius: var(--radius-sm);
   padding: 0 10px;
   background: var(--surface);
   color: var(--ink);
   font:
      700 14px/1 Inter,
      ui-sans-serif,
      sans-serif;
   text-align: center;
   letter-spacing: 0.02em;
   outline: 0;
   transition: box-shadow 0.15s;
}
.chord-popover-input:focus {
   box-shadow: 0 0 0 3px rgba(35, 122, 80, 0.18);
}
.chord-popover-input::placeholder {
   color: var(--muted);
   font-weight: 500;
}
/* Half-step chips (♮ ♯ ♭) — shown only while the query is a Nashville NUMBER, so a touch
   user can raise/lower the degree without hunting for `#`/`b` on the symbol keyboard.
   Laid out as a compact segmented control, matching the ribbon's accidental picker. */
.chord-popover-accidentals {
   display: flex;
   justify-content: center;
   gap: 4px;
   margin-top: 8px;
}
.chord-popover-accidentals[hidden] {
   display: none;
}
.chord-popover-acc {
   width: 30px;
   height: 26px;
   padding: 0;
   border: 1px solid var(--line);
   border-radius: var(--radius-sm);
   background: var(--surface);
   color: var(--ink);
   font:
      700 15px/1 Inter,
      ui-sans-serif,
      sans-serif;
   cursor: pointer;
   transition:
      background 0.12s,
      border-color 0.12s,
      color 0.12s;
}
.chord-popover-acc:hover {
   border-color: var(--green);
}
.chord-popover-acc.is-active {
   border-color: var(--green);
   background: var(--green);
   color: #fff;
}
.chord-popover-list {
   list-style: none;
   margin: 8px 0 0;
   padding: 0;
   max-height: 232px;
   overflow-y: auto;
   display: grid;
   gap: 2px;
}
.chord-popover-list[hidden] {
   display: none;
}
.chord-suggestion {
   display: flex;
   align-items: center;
   min-height: 34px;
   padding: 5px 10px;
   border-radius: var(--radius-sm);
   cursor: pointer;
   color: var(--ink);
   transition: background 0.1s;
}
.chord-suggestion:hover,
.chord-suggestion.is-active {
   background: var(--soft);
}
.chord-suggestion.is-active {
   box-shadow: inset 0 0 0 1.5px rgba(35, 122, 80, 0.35);
}
.chord-suggestion-label {
   font:
      700 15px/1 Inter,
      ui-sans-serif,
      sans-serif;
   color: var(--dark-green);
}
.chord-popover-msg {
   margin: 8px 2px 2px;
   padding: 6px 8px;
   border-radius: var(--radius-sm);
   background: rgba(200, 90, 70, 0.08);
   color: #b25542;
   font:
      600 12.5px/1.3 Inter,
      ui-sans-serif,
      sans-serif;
   text-align: center;
}
.chord-popover-msg[hidden] {
   display: none;
}
/* Raw-commit action — “Use custom chord  Bmaj9”. Only rendered when nothing matched
   and the cell opted into custom chords (Chord Chart beats + the chord row). */
.chord-popover-custom {
   width: 100%;
   margin: 6px 0 0;
   padding: 7px 9px;
   display: flex;
   align-items: baseline;
   justify-content: center;
   gap: 6px;
   border: 1px dashed #b7d3be;
   border-radius: var(--radius-sm);
   background: rgba(31, 112, 74, 0.06);
   color: var(--dark-green);
   font:
      600 12.5px/1.3 Inter,
      ui-sans-serif,
      sans-serif;
   text-align: center;
   cursor: pointer;
   transition:
      background 0.15s ease,
      border-color 0.15s ease;
}
.chord-popover-custom:hover {
   background: rgba(31, 112, 74, 0.12);
   border-color: #8eb99a;
}
.chord-popover-custom[hidden] {
   display: none;
}
.chord-popover-custom-value {
   font-weight: 800;
   color: var(--dark-green);
}
html[data-theme="dark"] .chord-popover-custom {
   border-color: #3f6a52;
   background: rgba(120, 220, 160, 0.08);
   color: #a6e3c0;
}
html[data-theme="dark"] .chord-popover-custom:hover {
   background: rgba(120, 220, 160, 0.16);
}
html[data-theme="dark"] .chord-popover-custom .chord-popover-custom-value {
   color: #d9f5e3;
}
/* Anchor beat highlight while its editor is open. Uses the SAME inset box as the
   hover affordance (preview.css) so the hover preview and the active/clicked
   target are pixel-identical — a solid ring drawn a few px inside the cell. */
html:not(.is-print-layout) .drop-target.chord-editing {
   position: relative;
}
html:not(.is-print-layout) .drop-target.chord-editing::after {
   content: "";
   position: absolute;
   z-index: 5;
   inset: 21px 16px 3px;
   border: 1.5px solid rgba(35, 122, 80, 0.6);
   border-radius: 5px;
   background: rgba(35, 122, 80, 0.06);
   pointer-events: none;
}
/* Hide the placeholder dot inside the beat that's currently being edited. */
html:not(.is-print-layout) .drop-target.chord-editing .beat-dot {
   opacity: 0;
}

html[data-theme="dark"] .chord-popover-msg {
   background: rgba(255, 100, 85, 0.12);
   color: #ff9b8f;
}
html[data-theme="dark"] .chord-suggestion.is-active {
   box-shadow: inset 0 0 0 1.5px rgba(120, 220, 160, 0.4);
}

/* ============================================================
   Beat rhythm context menu (right-click / long-press).
   ============================================================ */
.beat-menu {
   position: fixed;
   z-index: 1450;
   min-width: 200px;
   padding: 6px;
   background: var(--surface);
   border: 1px solid var(--line);
   border-radius: var(--radius-md);
   box-shadow: var(--shadow-md);
   animation: chord-pop-in 0.12s ease-out both;
}
.beat-menu-item {
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 12px;
   width: 100%;
   padding: 9px 11px;
   border: 0;
   border-radius: var(--radius-sm);
   background: transparent;
   color: var(--ink);
   font:
      600 14px/1 Inter,
      ui-sans-serif,
      sans-serif;
   text-align: left;
   cursor: pointer;
   transition: background 0.1s;
}
.beat-menu-item:hover {
   background: var(--soft);
}
.beat-menu-item[aria-disabled="true"] {
   opacity: 0.4;
   cursor: not-allowed;
}
.beat-menu-item[aria-disabled="true"]:hover {
   background: transparent;
}
.beat-menu-item.is-danger {
   color: #b25542;
}
.beat-menu-item.is-danger:hover {
   background: rgba(200, 90, 70, 0.08);
}
.beat-menu-hint {
   display: grid;
   place-items: center;
   min-width: 20px;
   height: 20px;
   padding: 0 5px;
   border-radius: 6px;
   background: var(--soft);
   color: var(--muted);
   font:
      700 11px/1 Inter,
      ui-sans-serif,
      sans-serif;
}
html[data-theme="dark"] .beat-menu-item.is-danger {
   color: #ff9b8f;
}
html[data-theme="dark"] .beat-menu-item.is-danger:hover {
   background: rgba(255, 100, 85, 0.12);
}

/* ============================================================
   Fermata popover (how many extra beats to hold). Mirrors the
   chord popover's surface, arrow and pop-in so the two read as
   one family.
   ============================================================ */
.fermata-popover {
   position: fixed;
   z-index: 1400;
   width: max-content;
   min-width: 234px;
   max-width: min(92vw, 272px);
   padding: 12px;
   background: var(--surface);
   border: 1px solid var(--line);
   border-radius: var(--radius-md);
   box-shadow: var(--shadow-md);
   animation: chord-pop-in 0.13s ease-out both;
}
.fermata-popover::after {
   content: "";
   position: absolute;
   left: var(--arrow-x, 50%);
   bottom: -6px;
   width: 12px;
   height: 12px;
   background: var(--surface);
   border-right: 1px solid var(--line);
   border-bottom: 1px solid var(--line);
   transform: translateX(-50%) rotate(45deg);
}
.fermata-popover.is-below::after {
   bottom: auto;
   top: -6px;
   border: 0;
   border-left: 1px solid var(--line);
   border-top: 1px solid var(--line);
}
.fermata-popover-head {
   display: flex;
   align-items: center;
   gap: 10px;
   margin-bottom: 12px;
}
.fermata-popover-badge {
   flex: none;
   display: grid;
   place-items: center;
   width: 30px;
   height: 30px;
   border-radius: 9px;
   background: var(--soft);
   color: var(--green);
}
.fermata-popover-badge svg {
   width: 18px;
   height: 16px;
}
.fermata-popover-title {
   margin: 0;
   color: var(--ink);
   font:
      800 14px/1.15 Inter,
      ui-sans-serif,
      sans-serif;
}
.fermata-popover-sub {
   margin: 2px 0 0;
   color: var(--muted);
   font:
      600 11px/1.2 Inter,
      ui-sans-serif,
      sans-serif;
}
.fermata-popover-row {
   display: flex;
   align-items: center;
   gap: 8px;
}
.fermata-step {
   width: 36px;
   height: 40px;
   border: 1px solid var(--line);
   border-radius: var(--radius-sm);
   background: var(--surface);
   color: var(--green);
   font:
      800 20px/1 Inter,
      ui-sans-serif,
      sans-serif;
   cursor: pointer;
   transition:
      background 0.12s,
      border-color 0.12s;
}
.fermata-step:hover {
   background: var(--soft);
   border-color: var(--green);
}
.fermata-popover-input {
   width: 74px;
   height: 40px;
   box-sizing: border-box;
   border: 1.5px solid var(--green);
   border-radius: var(--radius-sm);
   padding: 0 8px;
   background: var(--surface);
   color: var(--ink);
   font:
      800 18px/1 Inter,
      ui-sans-serif,
      sans-serif;
   text-align: center;
   outline: 0;
   appearance: textfield;
   -moz-appearance: textfield;
   transition: box-shadow 0.15s;
}
.fermata-popover-input::-webkit-outer-spin-button,
.fermata-popover-input::-webkit-inner-spin-button {
   -webkit-appearance: none;
   margin: 0;
}
.fermata-popover-input:focus {
   box-shadow: 0 0 0 3px rgba(35, 122, 80, 0.18);
}
.fermata-popover-unit {
   color: var(--muted);
   font:
      700 12px/1 Inter,
      ui-sans-serif,
      sans-serif;
}
.fermata-popover-hint {
   margin: 10px 0 0;
   color: var(--muted);
   font:
      600 12px/1.35 Inter,
      ui-sans-serif,
      sans-serif;
}
.fermata-popover-actions {
   display: flex;
   justify-content: flex-end;
   gap: 8px;
   margin-top: 14px;
}
.fermata-popover-cancel,
.fermata-popover-apply {
   height: 38px;
   padding: 0 16px;
   border-radius: var(--radius-sm);
   font:
      800 13px/1 Inter,
      ui-sans-serif,
      sans-serif;
   cursor: pointer;
   transition:
      filter 0.12s,
      background 0.12s,
      border-color 0.12s;
}
.fermata-popover-cancel {
   border: 1px solid var(--line);
   background: var(--surface);
   color: var(--ink);
}
.fermata-popover-cancel:hover {
   background: var(--soft);
}
.fermata-popover-apply {
   border: 0;
   background: var(--green);
   color: #fff;
}
.fermata-popover-apply:hover {
   filter: brightness(0.96);
}
html[data-theme="dark"] .fermata-step,
html[data-theme="dark"] .fermata-popover-cancel {
   background: var(--surface);
   color: #d9f5e3;
}
@media (hover: none) and (pointer: coarse) {
   .fermata-step,
   .fermata-popover-cancel,
   .fermata-popover-apply {
      min-height: 44px;
   }
}

/* ==================== MODE PICKER DIALOG (New Song) ==================== */
.mode-picker-card {
   width: min(90vw, 520px);
   max-height: 80vh;
   text-align: left;
   align-items: stretch;
   overflow-y: auto;
}
.mode-picker-card .confirm-dialog-icon {
   align-self: center;
}
.mode-picker-close {
   position: absolute;
   top: 16px;
   right: 16px;
   z-index: 2;
   border: none;
   background: transparent;
   font-size: 24px;
   line-height: 1;
   cursor: pointer;
   color: var(--muted);
   padding: 4px;
   border-radius: 4px;
   transition: color 0.18s ease;
}
.mode-picker-close:hover {
   color: var(--ink);
   background: rgba(0, 0, 0, 0.04);
}
/* Version name input in the New Song / add-first-version dialog. */
.new-song-name {
   margin: 18px 0 2px;
}
.new-song-name-label {
   display: block;
   font-size: 11px;
   text-transform: uppercase;
   letter-spacing: 0.08em;
   font-weight: 800;
   color: var(--muted);
   margin: 0 0 7px;
}
.new-song-name-label em {
   font-style: normal;
   text-transform: none;
   letter-spacing: 0;
   font-weight: 600;
   color: var(--muted);
}
.new-song-name-input {
   width: 100%;
   min-height: 46px;
   padding: 10px 14px;
   border: 1.5px solid var(--line);
   border-radius: 10px;
   background: var(--surface);
   color: var(--ink);
   font: 600 15px inherit;
   outline: none;
   transition:
      border-color 0.16s ease,
      box-shadow 0.16s ease;
}
.new-song-name-input:focus-visible {
   border-color: var(--green);
   box-shadow: 0 0 0 3px rgba(35, 122, 80, 0.14);
}
.new-song-name-input.is-invalid {
   border-color: #c9403a;
   box-shadow: 0 0 0 3px rgba(201, 64, 58, 0.14);
}
.new-song-name-hint {
   font-size: 12px;
   line-height: 1.45;
   color: var(--muted);
   margin: 7px 0 0;
}
.new-song-name-error {
   font-size: 12.5px;
   font-weight: 700;
   color: #c9403a;
   margin: 7px 0 0;
}
.mode-picker-grid {
   display: grid;
   grid-template-columns: 1fr;
   gap: 14px;
   margin: 20px -2px -2px;
   padding: 0 2px;
}
@media (min-width: 640px) {
   .mode-picker-grid {
      grid-template-columns: repeat(2, 1fr);
      gap: 18px;
      margin: 24px -4px -4px;
   }
}
.mode-card {
   display: flex;
   flex-direction: column;
   gap: 14px;
   padding: 18px;
   border: 1.5px solid rgba(0, 0, 0, 0.1);
   border-radius: 14px;
   background: #fff;
   box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
   cursor: pointer;
   transition:
      transform 0.18s ease,
      box-shadow 0.18s ease,
      border-color 0.18s ease,
      background 0.18s ease;
   outline: none;
   text-align: left;
}
.mode-card:focus-visible {
   box-shadow: 0 0 0 3px rgba(184, 232, 92, 0.6);
   border-color: rgba(47, 125, 79, 0.6);
}
.mode-card:hover {
   transform: translateY(-3px);
   box-shadow: 0 8px 18px rgba(0, 0, 0, 0.1);
   border-color: rgba(47, 125, 79, 0.4);
   background: linear-gradient(180deg, #fff 0%, color-mix(in srgb, var(--green) 3%, #fff) 100%);
}
.mode-card-visual {
   height: 80px;
   border-radius: 10px;
   background: rgba(0, 0, 0, 0.02);
   display: grid;
   place-items: center;
   overflow: hidden;
   border: 1px solid rgba(0, 0, 0, 0.06);
}
.mode-card-anim {
   display: flex;
   align-items: center;
   justify-content: center;
   gap: 8px;
   font-size: 16px;
   font-weight: 700;
   font-family:
      system-ui,
      -apple-system,
      sans-serif;
}
.mode-anim-chords {
   animation: chordFlow 2s ease-in-out infinite;
}
@keyframes chordFlow {
   0%,
   100% {
      transform: translateX(0);
   }
   50% {
      transform: translateX(-8px);
   }
}
.mca-chord {
   background: var(--dark-green);
   color: #fff;
   padding: 4px 10px;
   border-radius: 6px;
   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.mca-chord-1 {
   animation-delay: 0ms;
}
.mca-chord-2 {
   animation-delay: 200ms;
}
.mca-chord-3 {
   animation-delay: 400ms;
}
.mca-chord-4 {
   animation-delay: 600ms;
}
.mode-anim-numbers {
   animation: numBounce 1.8s ease-in-out infinite;
}
@keyframes numBounce {
   0%,
   100% {
      transform: scale(1);
   }
   50% {
      transform: scale(1.08);
   }
}
.mca-num {
   display: inline-block;
   width: 28px;
   height: 28px;
   line-height: 26px;
   text-align: center;
   background: var(--green);
   color: #fff;
   border-radius: 50%;
   font-size: 14px;
   font-weight: 800;
   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
.mca-num-lyric {
   display: inline-flex;
   align-items: center;
   justify-content: center;
   min-width: 40px;
   height: 28px;
   padding: 0 10px;
   background: color-mix(in srgb, var(--dark-green) 12%, #fff);
   color: var(--dark-green);
   font-size: 12px;
   border-radius: 8px;
   font-weight: 800;
   letter-spacing: 0.08em;
   border: 1.5px solid color-mix(in srgb, var(--dark-green) 25%, transparent);
}
.mode-card-body {
   display: flex;
   flex-direction: column;
   gap: 10px;
}
.mode-card-header {
   display: flex;
   align-items: center;
   gap: 12px;
}
.mode-card-icon {
   display: inline-flex;
   align-items: center;
   justify-content: center;
   width: 52px;
   height: 52px;
   flex: none;
   border-radius: 14px;
   background: linear-gradient(
      140deg,
      color-mix(in srgb, var(--green) 22%, #fff) 0%,
      color-mix(in srgb, var(--dark-green) 16%, #fff) 100%
   );
   color: var(--dark-green);
   box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--dark-green) 18%, transparent);
   transition:
      transform 0.18s ease,
      box-shadow 0.18s ease;
}
.mode-card:hover .mode-card-icon {
   transform: scale(1.06) rotate(-3deg);
   box-shadow:
      inset 0 0 0 1.5px color-mix(in srgb, var(--dark-green) 32%, transparent),
      0 4px 12px rgba(47, 125, 79, 0.18);
}
.mode-card-title {
   margin: 0;
   font-size: 18px;
   font-weight: 700;
   letter-spacing: -0.02em;
   color: var(--ink);
}
.mode-card-sub {
   margin: 0;
   font-size: 13px;
   color: var(--muted);
}
.mode-card-points {
   margin: 4px 0 0;
   padding: 0;
   list-style: none;
   display: flex;
   flex-wrap: wrap;
   gap: 8px 10px;
}
.mode-card-points li {
   font-size: 12.5px;
   font-weight: 600;
   display: inline-flex;
   align-items: center;
   gap: 6px;
   padding: 4px 10px;
   border-radius: 999px;
   border: 1px solid transparent;
}
.mode-card-points li span:first-child {
   font-weight: 800;
   font-size: 13px;
}
/* Pros = green, Cons = soft red — clear affirmative/negative semantics */
.mode-card-points li.is-pro {
   background: color-mix(in srgb, var(--green) 12%, #fff);
   border-color: color-mix(in srgb, var(--green) 28%, transparent);
   color: var(--dark-green);
}
.mode-card-points li.is-pro span:first-child {
   color: #1f9d55;
}
.mode-card-points li.is-con {
   background: color-mix(in srgb, #e5484d 10%, #fff);
   border-color: color-mix(in srgb, #e5484d 26%, transparent);
   color: #b02a2f;
}
.mode-card-points li.is-con span:first-child {
   color: #e5484d;
}
html[data-theme="dark"] .mode-card {
   background: #1a2e23;
   border-color: rgba(255, 255, 255, 0.08);
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}
html[data-theme="dark"] .mode-card:hover {
   background: linear-gradient(180deg, #1a2e23 0%, color-mix(in srgb, var(--green) 8%, #1a2e23) 100%);
}
html[data-theme="dark"] .mode-card-visual {
   background: rgba(255, 255, 255, 0.04);
   border-color: rgba(255, 255, 255, 0.08);
}
html[data-theme="dark"] .mode-card-points li {
   background: rgba(100, 255, 218, 0.12);
   border-color: rgba(100, 255, 218, 0.25);
   color: #aaddcc;
}
html[data-theme="dark"] .mca-chord {
   background: #7ee0b3;
   color: #0a2a1e;
}
html[data-theme="dark"] .mca-num {
   background: #7ee0b3;
   color: #0a2a1e;
}

/* ---- Editor mode (chords vs numbers) visibility ------------------------
   body[data-editor-mode] is set by render.js on every render. These rules
   drive mode-specific UI without touching JS layout logic. */

/* Lyrics toggle lives inside .song-meta but only makes sense in numbers mode.
   Hide it in chords mode (lyrics feature is off for chord-progression songs).
   Rendered as the first item so it sits to the LEFT of KEY. */
.song-meta-lyrics-toggle {
   display: none;
   align-items: center;
   gap: 8px;
   cursor: pointer;
   user-select: none;
   padding-right: 14px;
   margin-right: 2px;
   border-right: 1px solid var(--line, rgba(0, 0, 0, 0.12));
}
body[data-editor-mode="numbers"] .song-meta-lyrics-toggle {
   display: inline-flex;
}
/* NOTE: the chord row above the numbers is a PER-SECTION feature — the only switch
   is .section-chord-above-toggle (see styles/score/preview.css); the old per-bar toggle
   was removed. */
.song-meta-lyrics-caption {
   font-size: 11px;
   font-weight: 700;
   letter-spacing: 0.06em;
   color: var(--muted, #6b7280);
}
.song-meta-lyrics-switch {
   display: inline-flex;
   align-items: center;
   gap: 7px;
}
/* Hide the native checkbox but keep it accessible/focusable. */
.song-meta-lyrics-switch input {
   position: absolute;
   opacity: 0;
   width: 1px;
   height: 1px;
   pointer-events: none;
}
.song-meta-lyrics-track {
   position: relative;
   display: inline-block;
   width: 34px;
   height: 20px;
   border-radius: 999px;
   background: var(--line, #d1d5db);
   transition: background 0.2s ease;
   flex: none;
}
.song-meta-lyrics-thumb {
   position: absolute;
   top: 2px;
   left: 2px;
   width: 16px;
   height: 16px;
   border-radius: 50%;
   background: #fff;
   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
   transition: transform 0.2s ease;
}
.song-meta-lyrics-switch input:checked + .song-meta-lyrics-track {
   background: var(--green, #10b981);
}
.song-meta-lyrics-switch input:checked + .song-meta-lyrics-track .song-meta-lyrics-thumb {
   transform: translateX(14px);
}
.song-meta-lyrics-switch input:focus-visible + .song-meta-lyrics-track {
   box-shadow: 0 0 0 3px rgba(184, 232, 92, 0.55);
}
.song-meta-lyrics-switch b {
   font-size: 12px;
   font-weight: 700;
   color: var(--ink);
   min-width: 20px;
}

/* Mode badge — sits to the LEFT of "Save to Cloud" in the topbar actions.
   Clean pill with a small mode glyph + label; adapts color/icon per mode. */
.editor-mode-badge {
   display: inline-flex;
   align-items: center;
   gap: 7px;
   padding: 6px 12px 6px 8px;
   border-radius: 999px;
   font-size: 12px;
   font-weight: 700;
   letter-spacing: 0.01em;
   border: 1px solid color-mix(in srgb, var(--dark-green, #2f7d4f) 22%, transparent);
   color: var(--dark-green, #2f7d4f);
   background: color-mix(in srgb, var(--green, #10b981) 10%, #fff);
   white-space: nowrap;
   transition:
      background 0.18s ease,
      border-color 0.18s ease;
}
.editor-mode-badge-icon {
   display: inline-flex;
   align-items: center;
   justify-content: center;
   width: 22px;
   height: 22px;
   border-radius: 50%;
   background: color-mix(in srgb, var(--green, #10b981) 20%, #fff);
   color: var(--dark-green, #2f7d4f);
   font-size: 12px;
   flex: none;
}
/* ---- YouTube chip (topbar) -------------------------------------------------
   The OPEN arrangement's own video, visible in every writing mode.
     data-state="link" → thumbnail + start time (+ ✎)
     data-state="none" → a quiet "🎬 No video" pill that is itself the action
   Visibility is driven by these states — NEVER the `hidden` attribute, which
   loses against `display` and used to leave the previous version's thumbnail on
   screen. Sits in the topbar, which @media print hides anyway. */
.youtube-chip {
   display: inline-flex;
   align-items: center;
   gap: 2px;
   padding: 3px 4px 3px 3px;
   border-radius: 999px;
   border: 1px solid color-mix(in srgb, #e11d48 22%, transparent);
   background: color-mix(in srgb, #e11d48 8%, #fff);
   white-space: nowrap;
}
.youtube-chip[data-state="none"] .youtube-chip-open {
   display: none;
}
.youtube-chip[data-state="link"] .youtube-chip-none {
   display: none;
}
/* Empty state: the container gets out of the way (no fill, no padding) and a single dashed
   pill carries both the message and the action — clicking it opens the link dialog. */
.youtube-chip[data-state="none"] {
   padding: 0;
   border-color: transparent;
   background: transparent;
}
.youtube-chip[data-state="none"] .youtube-chip-edit {
   display: none;
}
.youtube-chip-none {
   display: inline-flex;
   align-items: center;
   gap: 6px;
   padding: 5px 11px;
   border: 1px dashed color-mix(in srgb, var(--dark-green, #2f7d4f) 30%, transparent);
   border-radius: 999px;
   background: transparent;
   color: color-mix(in srgb, #6b7280 88%, #111);
   font-size: 12px;
   font-weight: 700;
   font-family: inherit;
   letter-spacing: 0.01em;
   cursor: pointer;
   transition:
      background 0.18s ease,
      border-color 0.18s ease,
      color 0.18s ease;
}
.youtube-chip-none > span[aria-hidden="true"] {
   font-size: 13px;
   line-height: 1;
   filter: grayscale(1);
   opacity: 0.75;
}
.youtube-chip-none:hover {
   border-color: color-mix(in srgb, var(--dark-green, #2f7d4f) 55%, transparent);
   background: color-mix(in srgb, var(--green, #10b981) 8%, #fff);
   color: var(--dark-green, #2f7d4f);
}
.youtube-chip-none:focus-visible {
   outline: 2px solid color-mix(in srgb, var(--green, #10b981) 55%, transparent);
   outline-offset: 2px;
}
.youtube-chip-open {
   display: inline-flex;
   align-items: center;
   gap: 7px;
   padding: 0;
   border: 0;
   background: transparent;
   color: #be123c;
   font-size: 12px;
   font-weight: 750;
   font-family: inherit;
   cursor: pointer;
}
.youtube-chip-thumb {
   width: 44px;
   height: 24px;
   border-radius: 6px;
   object-fit: cover;
   background: color-mix(in srgb, #e11d48 14%, #fff);
   display: block;
}
.youtube-chip-label {
   letter-spacing: 0.01em;
}
.youtube-chip-edit {
   display: inline-grid;
   place-items: center;
   width: 24px;
   height: 24px;
   border: 0;
   border-radius: 50%;
   background: transparent;
   color: #be123c;
   font-size: 12px;
   cursor: pointer;
}
.youtube-chip-edit:hover,
.youtube-chip-open:hover .youtube-chip-label {
   background: color-mix(in srgb, #e11d48 14%, #fff);
}
html[data-theme="dark"] .youtube-chip {
   border-color: color-mix(in srgb, #fb7185 30%, transparent);
   background: color-mix(in srgb, #fb7185 14%, #111);
}
html[data-theme="dark"] .youtube-chip-open,
html[data-theme="dark"] .youtube-chip-edit {
   color: #fda4af;
}
/* Empty state, dark: a softly mint outline instead of the red accent (nothing to warn about). */
html[data-theme="dark"] .youtube-chip-none {
   border-color: color-mix(in srgb, #6ee7b7 26%, transparent);
   color: color-mix(in srgb, #d1d5db 88%, #fff);
}
html[data-theme="dark"] .youtube-chip-none:hover {
   border-color: color-mix(in srgb, #6ee7b7 52%, transparent);
   background: color-mix(in srgb, #10b981 16%, #111);
   color: #a7f3d0;
}
html[data-theme="dark"] .youtube-chip-edit:hover,
html[data-theme="dark"] .youtube-chip-open:hover .youtube-chip-label {
   background: color-mix(in srgb, #fb7185 22%, #111);
}
/* Read-only album member: watching is fine, editing the arrangement is not. */
.youtube-chip[data-readonly="true"] .youtube-chip-edit {
   display: none;
}
/* Small screens: keep the affordance, drop the words (same idea as the topbar
   buttons, which lose their labels at this breakpoint). */
@media (max-width: 720px) {
   .youtube-chip-label {
      display: none;
   }
   .youtube-chip {
      padding: 2px 3px;
   }
}
/* Mobile + tablet: the mode badge keeps ONLY its mark — the icon already encodes
   the mode and the label costs precious topbar width. The label stays in the DOM
   for assistive tech. Also give the touch-only affordances a real target (no hover
   on a finger) and keep the versions popover inside a narrow screen. */
@media screen and (max-width: 1050px) {
   .editor-mode-badge-text {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border: 0;
   }
   .editor-mode-badge {
      justify-self: start;
      align-self: center;
   }
   .version-item-edit {
      opacity: 1;
      width: 38px;
      height: 38px;
   }
   .version-popover {
      width: min(280px, calc(100vw - 24px));
   }
   .youtube-chip-edit {
      width: 30px;
      height: 30px;
      font-size: 14px;
   }
}
/* ---------------------------------------------------------------------------
   MEMBER READ-ONLY ALBUM MODE (role = member)
   A member may only change Key, Time signature, BPM and Transpose. Everything
   that edits the arrangement is dimmed + inert here. The rules hang off <body>
   for two reasons: the flag is set once by cloudUI (syncAlbumContextUI), and it
   survives renderPreview() rebuilding the whole preview. JS ALSO disables the
   in-preview controls (applyReadOnlyAffordances in events.js) as
   defence-in-depth — the CSS just makes the state visible.

   Deliberately NOT listed (they stay usable): #keySelect, #timeSignature,
   #bpmInput, #previewKey, #previewMeter, #transposeDown, #transposeUp,
   #playBtn, #exportBtn, undo/redo.
--------------------------------------------------------------------------- */
body[data-member-readonly="1"] .drop-target,
body[data-member-readonly="1"] .placed-chord {
   cursor: default;
}
body[data-member-readonly="1"] .ribbon-tabs,
body[data-member-readonly="1"] .ribbon-panel,
body[data-member-readonly="1"] .section-menu,
body[data-member-readonly="1"] .song-meta-lyrics-toggle,
body[data-member-readonly="1"] #resetSheetBtn,
body[data-member-readonly="1"] #addSectionBtn,
body[data-member-readonly="1"] .add-section,
body[data-member-readonly="1"] .add-bar,
body[data-member-readonly="1"] .delete-bar,
body[data-member-readonly="1"] .copy-bar,
body[data-member-readonly="1"] .paste-bar,
body[data-member-readonly="1"] .section-title,
body[data-member-readonly="1"] .section-lyrics-toggle,
body[data-member-readonly="1"] .section-chord-above-toggle,
body[data-member-readonly="1"] .bar-selection-copy {
   opacity: 0.45;
   pointer-events: none;
   cursor: not-allowed;
}
/* A locked section title is text, not a rename affordance. */
body[data-member-readonly="1"] .section-title {
   cursor: default;
}
/* Lyrics / chord-above fields stay selectable + copyable for a reader, so they
   only look "flat" — events.js sets them readOnly. */
body[data-member-readonly="1"] .lyric-input,
body[data-member-readonly="1"] .chord-above-input {
   cursor: text;
}

/* ---------------------------------------------------------------------------
   PHONE VIEW-ONLY EDITOR (isPhone())
   Same idea as the member block above, but for phones: arranging a score needs
   room, so the phone canvas is view-only. A phone user MAY still change Title,
   Artist, Key, Time signature, Transpose and BPM, and Play / Export — everything
   that edits the arrangement is inert, and Undo/Redo (editor history) is refused
   too. The flag is set by applyReadOnlyAffordances() in events.js.
--------------------------------------------------------------------------- */
body[data-view-only="1"] .drop-target,
body[data-view-only="1"] .placed-chord {
   cursor: default;
}
body[data-view-only="1"] .ribbon-tabs,
body[data-view-only="1"] .ribbon-panel,
body[data-view-only="1"] .section-menu,
body[data-view-only="1"] .song-meta-lyrics-toggle,
body[data-view-only="1"] #resetSheetBtn,
body[data-view-only="1"] #addSectionBtn,
body[data-view-only="1"] .add-section,
body[data-view-only="1"] .add-bar,
body[data-view-only="1"] .delete-bar,
body[data-view-only="1"] .copy-bar,
body[data-view-only="1"] .paste-bar,
body[data-view-only="1"] .section-title,
body[data-view-only="1"] .section-lyrics-toggle,
body[data-view-only="1"] .section-chord-above-toggle,
body[data-view-only="1"] .bar-selection-copy,
body[data-view-only="1"] #undoBtn,
body[data-view-only="1"] #redoBtn {
   opacity: 0.45;
   pointer-events: none;
   cursor: not-allowed;
}
/* A phone canvas is view-only, so edit history cannot change anything. Hide the
   whole topbar control (rather than leaving two dead arrows) and keep the row
   free for BPM / mode / Save. */
body[data-view-only="1"] .history-toolbar {
   display: none;
}
/* A locked section title is text, not a rename affordance. */
body[data-view-only="1"] .section-title {
   cursor: default;
}
/* Per-bar edit chrome is meaningless in a view-only canvas — hide it entirely
   (dimming still left a column of red × buttons that could only ever refuse). */
body[data-view-only="1"] .bar-tools,
body[data-view-only="1"] .delete-bar {
   display: none;
}
/* Time signature is locked on a phone as well (Key / Transpose / BPM stay live).
   SCREEN-ONLY: #previewMeter is PRINTED sheet content, so this dim must never
   reach paper — the JS guard is the real gate, this only makes the state read. */
@media screen {
   body[data-view-only="1"] #timeSignature,
   body[data-view-only="1"] #previewMeter {
      opacity: 0.45;
      pointer-events: none;
      cursor: not-allowed;
   }
}
/* Lyrics / chord-above fields stay selectable + copyable, just not editable. */
body[data-view-only="1"] .lyric-input,
body[data-view-only="1"] .chord-above-input {
   cursor: text;
}

