/* App shell, score canvas, dialogs and base responsive rules. */
:root {
   --ink: #163a2a;
   --muted: #69756f;
   --green: #237a50;
   --dark-green: #155c3c;
   --lime: #b8e85c;
   --cream: #fcfbf5;
   --surface: #ffffff;
   --line: #d9e5dc;
   --soft: #eaf5ed;
   --app-bg: #f2f5f2;
   --shadow-sm: 0 1px 2px rgba(20, 58, 41, 0.05), 0 7px 24px rgba(20, 58, 41, 0.06);
   --shadow-md: 0 18px 55px rgba(20, 58, 41, 0.12);
   --radius-sm: 9px;
   --radius-md: 14px;
   --radius-lg: 22px;
   /* LOBBY — shared accents for the always-dark cloud gallery (the dark theme
      itself lives on .cloud-gallery / .cloud-album further down). */
   --spark: #b8e85c; /* lime — accent only, never a large surface */
   --spark-ink: #0b140e; /* text sitting ON a spark/lime fill */
   --lobby-glow: rgba(184, 232, 92, 0.14);
   --lobby-shade: rgba(4, 10, 6, 0.55);
   --lobby-ease: cubic-bezier(0.23, 1, 0.32, 1);
}

/* ============================================================================
   RESPONSIVE CONTRACT (documented during the tablet/UI modernization pass)
   ----------------------------------------------------------------------------
   The whole app keys off three width bands. Keep these in sync with src/dom.js
   (prefersTap / isPhone) and the media queries in this file:
     • Phone   : width <= 680px   → stacked score (bars vertical), no h-scroll
     • Tablet  : 681px – 1050px   → sheet auto-fits its pane (no forced h-scroll);
                                    roomier tap targets; compact My Songs toolbar
                                    (covers portrait iPads incl. iPad Pro 13" = 1024)
     • Desktop : width >= 1051px  → paper-width sheet (min 920px) + scroll
   PRINT / PDF IS INVARIANT across all three bands: its geometry lives in the
   `@media print` + `html.is-print-layout` rules and is never touched by the
   responsive rules below (all of them are scoped to `@media screen` or a width
   band). tests/unit.test.mjs pins that print contract, so a stray change that
   leaked into paper would fail the suite.
   Design-token sources (custom properties only cascade to the LAST definition):
     • styles/base/tokens.css    → legacy base tokens (shadowed by this file, loaded later)
     • styles/score/preview.css   → --print-*              (PRINT geometry — PROTECTED)
     • styles/score/chordpro.css  → --chordpro-css-version (build marker — PROTECTED)
   ============================================================================ */

/* SoundFont Download Modal Styles */
.download-modal-overlay {
   position: fixed;
   top: 0;
   left: 0;
   right: 0;
   bottom: 0;
   background: rgba(22, 58, 41, 0.6);
   backdrop-filter: blur(4px);
   display: flex;
   align-items: center;
   justify-content: center;
   z-index: 9999;
   animation: fadeIn 0.2s ease-out;
}

@keyframes fadeIn {
   from {
      opacity: 0;
   }
   to {
      opacity: 1;
   }
}

.download-modal {
   background: var(--surface);
   border-radius: var(--radius-lg);
   padding: 28px;
   max-width: 420px;
   width: 90%;
   box-shadow: var(--shadow-md);
   animation: slideUp 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes slideUp {
   from {
      opacity: 0;
      transform: translateY(30px);
   }
   to {
      opacity: 1;
      transform: translateY(0);
   }
}

.download-modal-header {
   display: flex;
   align-items: center;
   gap: 14px;
   margin-bottom: 18px;
}

.download-icon {
   font-size: 32px;
   width: 48px;
   height: 48px;
   display: flex;
   align-items: center;
   justify-content: center;
   background: var(--soft);
   border-radius: 12px;
}

.download-modal-title {
   font-size: 18px;
   font-weight: 600;
   color: var(--ink);
   margin: 0;
}

.download-modal-content {
   display: flex;
   flex-direction: column;
   gap: 16px;
   margin-bottom: 24px;
}

.info-row {
   display: flex;
   align-items: center;
   gap: 10px;
   font-size: 14px;
   color: var(--ink);
}

.info-label {
   font-weight: 500;
   min-width: 70px;
}

.info-value {
   color: var(--muted);
}

.progress-container {
   background: var(--soft);
   border-radius: var(--radius-md);
   padding: 8px 12px;
   overflow: hidden;
}

.progress-bar {
   height: 8px;
   background: linear-gradient(90deg, var(--green), var(--lime));
   border-radius: 4px;
   transition: width 0.15s ease-out;
   width: 0%;
}

.progress-text {
   text-align: center;
   font-size: 13px;
   color: var(--muted);
   margin-top: 8px;
   font-family: monospace;
}

.download-actions {
   display: flex;
   gap: 12px;
   justify-content: flex-end;
}

.download-btn {
   padding: 10px 20px;
   border-radius: var(--radius-sm);
   font-size: 14px;
   font-weight: 500;
   cursor: pointer;
   transition: all 0.15s ease;
   border: none;
   outline: none;
}

.btn-cancel {
   background: var(--soft);
   color: var(--muted);
}

.btn-cancel:hover {
   background: var(--line);
   color: var(--ink);
}

.btn-download {
   background: var(--green);
   color: white;
}

.btn-download:hover:not(:disabled) {
   background: var(--dark-green);
   transform: scale(1.02);
}

.btn-download:disabled {
   opacity: 0.6;
   cursor: not-allowed;
   transform: none;
}

.btn-download.loading {
   pointer-events: none;
   opacity: 0.8;
}

.btn-download .spinner {
   display: inline-block;
   width: 16px;
   height: 16px;
   border: 2px solid transparent;
   border-top-color: white;
   border-radius: 50%;
   animation: spin 0.8s linear infinite;
   margin-right: 8px;
   vertical-align: middle;
}

@keyframes spin {
   to {
      transform: rotate(360deg);
   }
}

html {
   scroll-behavior: smooth;
}
body {
   min-height: 100vh;
   background: radial-gradient(circle at 8% 4%, rgba(184, 232, 92, 0.12), transparent 25rem), var(--app-bg);
   color: var(--ink);
}
button,
input,
select {
   font-family: inherit;
}
button,
label,
[draggable="true"] {
   -webkit-tap-highlight-color: transparent;
}
.sr-only {
   position: absolute !important;
   width: 1px !important;
   height: 1px !important;
   padding: 0 !important;
   margin: -1px !important;
   overflow: hidden !important;
   clip: rect(0, 0, 0, 0) !important;
   white-space: nowrap !important;
   border: 0 !important;
}

/* Application shell */
.topbar {
   position: relative;
   z-index: 10;
   height: 68px;
   padding: 0 clamp(20px, 4vw, 64px);
   border-bottom: 1px solid rgba(217, 229, 220, 0.9);
   background: rgba(255, 255, 255, 0.92);
   box-shadow: 0 1px 0 rgba(22, 58, 42, 0.03);
   backdrop-filter: blur(16px);
}
.brand {
   gap: 12px;
   font-size: 19px;
   letter-spacing: -0.45px;
}
.brand-icon {
   width: 38px;
   height: 38px;
   border-radius: 12px;
   background: linear-gradient(145deg, #2b875b, #145b3b);
   box-shadow: 0 7px 16px rgba(35, 122, 80, 0.2);
   overflow: hidden;
}
.brand-icon img {
   display: block;
   width: 100%;
   height: 100%;
   border-radius: inherit;
}
.brand small {
   color: #819088;
   font-size: 9px;
   letter-spacing: 0.13em;
}
.topbar-actions {
   align-items: center;
   gap: 7px;
}
/* Save to Cloud + Export .pdf are wrapped in this group so they always sit side by
   side and wrap as a pair (see the <=680px rule in the phone block below). */
.topbar-action-group {
   display: flex;
   align-items: center;
   gap: 7px;
}
.autosave-status {
   display: inline-flex;
   align-items: center;
   gap: 7px;
   margin-right: 5px;
   color: var(--muted);
   font-size: 11px;
   white-space: nowrap;
}
.autosave-status i {
   width: 7px;
   height: 7px;
   border-radius: 50%;
   background: #55a976;
   box-shadow: 0 0 0 4px rgba(85, 169, 118, 0.11);
}
.button {
   min-height: 38px;
   border: 1px solid transparent;
   border-radius: 10px;
   padding: 9px 14px;
   font-size: 12px;
   transition:
      transform 0.16s ease,
      box-shadow 0.16s ease,
      background 0.16s ease,
      border-color 0.16s ease;
}
.button span[aria-hidden="true"] {
   margin-right: 5px;
   font-size: 14px;
}
/* Inline stroke glyphs inside labelled buttons — sized from the button's own
   line box so emoji-size spans and SVG spans align the same way. */
.button .btn-icon {
   display: inline-grid;
   place-items: center;
   margin-right: 5px;
}
.button .btn-icon svg {
   display: block;
   width: 15px;
   height: 15px;
}
.button:hover {
   transform: translateY(-1px);
   filter: none;
}
.button-primary {
   background: var(--green);
   box-shadow: 0 6px 14px rgba(35, 122, 80, 0.18);
}
.button-primary:hover {
   background: #1e6e47;
   box-shadow: 0 8px 18px rgba(35, 122, 80, 0.24);
}
.button-ghost {
   border-color: #dbe8df;
   background: #f8fbf9;
}
.button-ghost:hover {
   border-color: #bfd7c6;
   background: #eef7f0;
}
/* Editor topbar's two prominent actions. Both are filled (so they clearly read
   as primary), but carry distinct accents so their purpose is unmistakable:
   Save to Cloud = brand green (the safety action users look for first), and
   Export .pdf = a deep charcoal (the output action). */
.button-save {
   background: var(--green);
   color: #fff;
   box-shadow: 0 6px 14px rgba(35, 122, 80, 0.2);
}
.button-save:hover {
   background: #1e6e47;
   box-shadow: 0 8px 18px rgba(35, 122, 80, 0.26);
}
.button-save.is-saving {
   opacity: 0.75;
   pointer-events: none;
}
/* Unsaved-changes indicator (#4). A small amber dot rides the top-right corner
   of Save to Cloud whenever the open document has edits not yet persisted to
   the cloud. A soft pulse draws the eye without being noisy. */
.button-save.is-unsaved {
   position: relative;
}
.button-save.is-unsaved::after {
   content: "";
   position: absolute;
   top: -3px;
   right: -3px;
   width: 11px;
   height: 11px;
   border-radius: 50%;
   background: #f5a623;
   border: 2px solid var(--surface, #fff);
   box-shadow: 0 0 0 0 rgba(245, 166, 35, 0.5);
   animation: saveUnsavedPulse 2s ease-out infinite;
}
@keyframes saveUnsavedPulse {
   0% {
      box-shadow: 0 0 0 0 rgba(245, 166, 35, 0.5);
   }
   70% {
      box-shadow: 0 0 0 6px rgba(245, 166, 35, 0);
   }
   100% {
      box-shadow: 0 0 0 0 rgba(245, 166, 35, 0);
   }
}
@media (prefers-reduced-motion: reduce) {
   .button-save.is-unsaved::after {
      animation: none;
   }
}
.button-dark {
   background: #223029;
   color: #fff;
   box-shadow: 0 6px 14px rgba(16, 40, 28, 0.22);
}
.button-dark:hover {
   background: #2c3e34;
   box-shadow: 0 8px 18px rgba(16, 40, 28, 0.28);
}
html[data-theme="dark"] .button-dark {
   background: #e7ece8;
   color: #10231b;
}
html[data-theme="dark"] .button-dark:hover {
   background: #f3f6f3;
}
.theme-toggle {
   min-width: 76px;
}
.theme-toggle-icon {
   width: 14px;
   margin-right: 5px !important;
   text-align: center;
}

main {
   max-width: 1560px;
   padding: 30px clamp(20px, 4vw, 64px) 72px;
}
.workspace,
.ribbon-workspace,
.editor-card,
.preview-stage {
   min-width: 0;
   max-width: 100%;
}
.intro {
   margin: 0 0 24px;
}
.intro .eyebrow {
   display: inline-flex;
   align-items: center;
   gap: 7px;
}
.intro .eyebrow::before {
   content: "";
   width: 18px;
   height: 2px;
   border-radius: 2px;
   background: var(--lime);
}
.intro h1 {
   max-width: 760px;
   margin: 8px 0 6px;
   font-size: clamp(27px, 3vw, 38px);
   line-height: 1.08;
   letter-spacing: -1.5px;
}
.intro p {
   font-size: 13px;
}

/* Ribbon */
.ribbon-workspace .editor-card {
   top: 0;
   z-index: 20;
   margin-bottom: 22px;
   padding: 12px 18px 14px;
   border-color: rgba(207, 224, 212, 0.95);
   border-radius: var(--radius-lg);
   background: rgba(255, 255, 255, 0.96);
   box-shadow: var(--shadow-sm);
   backdrop-filter: blur(18px);
   transition:
      padding 0.2s ease,
      border-radius 0.2s ease,
      box-shadow 0.2s ease;
}
.ribbon-workspace .editor-card.is-scrolled {
   padding-top: 9px;
   border-radius: 15px;
   box-shadow: 0 12px 35px rgba(20, 58, 41, 0.13);
}
/* Arrangement-tools ribbon is hidden: chord entry now happens inline on each
   beat (click → popover) and rhythm via the right-click / long-press menu. The
   aside stays in the DOM (JS still references its inputs for meta + lyrics
   state); we only remove it visually and from layout. */
.ribbon-workspace .editor-card {
   display: none;
}
/* Topbar global lyrics toggle (replaces the ribbon Lyrics panel switch). */
.topbar-lyrics-toggle {
   margin-right: 4px;
}
.ribbon-heading {
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 16px;
   min-height: 38px;
   padding: 0 2px 9px;
}
.ribbon-heading > div {
   display: flex;
   align-items: baseline;
   gap: 9px;
}
.ribbon-kicker {
   color: var(--green);
   font-size: 9px;
   font-weight: 900;
   letter-spacing: 0.13em;
}
.ribbon-heading strong {
   color: var(--muted);
   font-size: 11px;
   font-weight: 650;
}
.icon-button {
   display: inline-grid;
   place-items: center;
   border: 1px solid #d5e3d8;
   border-radius: 8px;
   background: #fff;
   color: var(--dark-green);
   cursor: pointer;
   transition:
      background 0.15s ease,
      border-color 0.15s ease,
      transform 0.15s ease;
}
.icon-button:hover {
   border-color: #a9c9b3;
   background: var(--soft);
}
.icon-button:active {
   transform: translateY(1px);
}
.icon-button:disabled {
   border-color: #e0e8e2;
   background: #f5f7f5;
   color: #9ba8a0;
   cursor: not-allowed;
   transform: none;
}
.ribbon-toggle {
   width: 30px;
   height: 30px;
}
.ribbon-toggle > span[aria-hidden="true"] {
   display: block;
   font-size: 16px;
   transition: transform 0.2s ease;
}
.editor-card.is-collapsed .ribbon-toggle > span[aria-hidden="true"] {
   transform: rotate(180deg);
}
.editor-card.is-collapsed .ribbon-panels {
   display: none;
}
.editor-card.is-collapsed {
   padding-bottom: 10px;
}
.editor-card.is-collapsed .ribbon-heading {
   padding-bottom: 6px;
}
.editor-card.is-collapsed .ribbon-tabs {
   border-bottom-color: transparent;
}
.ribbon-tabs {
   gap: 3px;
   overflow-x: auto;
   scrollbar-width: none;
}
.ribbon-tab[hidden],
.ribbon-panel[hidden] {
   display: none !important;
}
.ribbon-tabs::-webkit-scrollbar {
   display: none;
}
.ribbon-tab {
   position: relative;
   border-radius: 9px 9px 0 0;
   padding: 9px 14px 11px;
   font-size: 11px;
   font-weight: 750;
   transition:
      color 0.15s ease,
      background 0.15s ease;
}
.ribbon-tab:hover {
   background: #f4f8f5;
   color: var(--dark-green);
}
.ribbon-tab.active {
   background: #eef7f0;
   box-shadow: none;
}
.ribbon-tab.active::after {
   content: "";
   position: absolute;
   right: 12px;
   bottom: 0;
   left: 12px;
   height: 3px;
   border-radius: 3px 3px 0 0;
   background: var(--lime);
}
.ribbon-panels {
   min-height: 108px;
   padding-top: 11px;
}
.ribbon-panel.active {
   gap: 12px;
}
.ribbon-panel .palette-group {
   border-color: #dce9df;
   border-radius: 12px;
   background: #f9fcfa;
}
.ribbon-panel .nashville-builder {
   min-width: 1000px;
   grid-template-columns: max-content 1px minmax(420px, 1fr) 150px;
}
.ribbon-panel .nashville-number-row {
   grid-template-columns: repeat(7, 36px);
}
.ribbon-panel .nashville-number-row.nashville-zero-row {
   grid-template-columns: 36px;
}
.palette-label {
   color: #668171;
}
.chord,
.duration-option {
   transition:
      transform 0.14s ease,
      background 0.14s ease,
      border-color 0.14s ease,
      box-shadow 0.14s ease;
}
.chord:hover,
.duration-option:hover {
   transform: translateY(-2px);
   border-color: #a9ceb4;
   box-shadow: 0 5px 12px rgba(35, 122, 80, 0.09);
}
.chord:focus-visible,
.duration-option:focus-visible {
   outline: 3px solid rgba(184, 232, 92, 0.55);
   outline-offset: 2px;
}
.chord.palette-selected,
.duration-option.palette-selected {
   border-color: var(--green);
   background: #dff2e4;
   box-shadow: 0 0 0 3px rgba(35, 122, 80, 0.1);
}
.chord.is-dragging,
.duration-option.is-dragging {
   opacity: 0.58;
   transform: scale(0.96);
}

/* Canvas */
.preview-stage {
   position: relative;
   width: 100%;
   overflow: hidden;
   border: 0;
   border-radius: 0;
   background: transparent;
   box-shadow: none;
}
html.is-print-layout body {
   background: #dfe6e1;
}
html.is-print-layout .topbar,
html.is-print-layout .intro,
html.is-print-layout .editor-card {
   /* Keep chrome available, but de-emphasize while inspecting score paper. */
   opacity: 0.92;
}

/* The SITE footer is deliberately NOT in that list: paper never contains it (@media print
   drops it on purpose) and it is a full-width band, so the moment the layout preview
   compacts the editor it slides up into view behind the PDF options dialog — reported as a
   giant footer suddenly covering the page. Screen-only on purpose: a real print job sets
   this very class too, and there the @media print rules above must keep winning. */
@media screen {
   html.is-print-layout .site-footer {
      display: none;
   }
}
html.is-print-layout .preview-stage {
   border-color: #c9d5cc;
   background: #edf1ee;
   box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.75);
}
html.is-print-layout .preview-viewport {
   padding: 18px 16px 28px;
   background: linear-gradient(180deg, rgba(255, 255, 255, 0.35), transparent 48px), #e7ece8;
}
html.is-print-layout .preview-stage .preview-card {
   min-width: min(920px, 100%);
   margin: 0 auto;
   border: 0;
   border-radius: 0;
   padding: 9mm 9mm 12mm;
   background: #fff;
   box-shadow: none;
   zoom: 1 !important;
}
html.is-print-layout .scroll-affordance,
html.is-print-layout .editor-skeleton {
   display: none;
}
html.is-print-layout[data-editor-loading="1"] #previewCard {
   display: block;
}
/* The manual "PDF layout" preview must look exactly like the paper, so the
   interactive bar-selection chrome (translucent green fill, the #1f9d55 ring and
   the ✓ badge — see .bar.is-selected above) is hidden here for the same reason
   the @media print block below neutralises it. */
html.is-print-layout .bar.is-selected,
html.is-print-layout .preview-section.is-selecting .bar.is-selected,
html.is-print-layout .preview-section.is-selecting .bar.is-selectable {
   background: transparent !important;
   outline: 0 !important;
   box-shadow: none !important;
}
html.is-print-layout .preview-section.is-selecting .bar.is-selected::after {
   content: none !important;
}
.preview-viewport {
   position: relative;
   overflow: auto;
   max-width: 100%;
   padding: 0;
   outline: none;
   scrollbar-color: #a8beb0 transparent;
   scrollbar-width: thin;
}
.preview-viewport::-webkit-scrollbar {
   width: 9px;
   height: 9px;
}
.preview-viewport::-webkit-scrollbar-track {
   background: transparent;
}
.preview-viewport::-webkit-scrollbar-thumb {
   border: 2px solid transparent;
   border-radius: 10px;
   background: #a8beb0;
   background-clip: padding-box;
}
.preview-viewport:focus-visible {
   box-shadow: inset 0 0 0 3px rgba(35, 122, 80, 0.18);
}
.preview-stage .preview-card {
   width: 100%;
   /* Fit the pane: never smaller than 920px UNLESS the pane itself is narrower,
      in which case the sheet fills it (so a portrait tablet needs no forced
      horizontal scroll). Print / is-print-layout keep their own geometry via
      `html.is-print-layout .preview-stage .preview-card` (higher specificity). */
   min-width: min(920px, 100%);
   margin: 0 auto;
   border: 1px solid #e5e5df;
   border-radius: 5px;
   background: var(--cream);
   box-shadow: var(--shadow-md);
   transform-origin: top left;
}
.preview-header h1 {
   margin: 5px 0 4px;
   font-size: 31px;
   letter-spacing: -1px;
   line-height: 1.08;
}
.preview-editable {
   border-radius: 6px;
   transition:
      background 0.15s ease,
      color 0.15s ease,
      box-shadow 0.15s ease;
}
.preview-editable:hover {
   background: rgba(232, 244, 235, 0.72);
   box-shadow: 0 0 0 4px rgba(232, 244, 235, 0.72);
}
.song-meta {
   align-items: flex-start;
}
.transpose-buttons button {
   transition:
      transform 0.14s ease,
      background 0.14s ease,
      border-color 0.14s ease;
}
.metronome-btn {
   display: inline-flex;
   align-items: center;
   justify-content: center;
   width: 30px;
   height: 30px;
   border: none;
   border-radius: 50%;
   background: transparent;
   color: var(--ui-text-dim, #888);
   cursor: pointer;
   font-size: 0.9rem;
   transition: color 0.14s ease, background 0.14s ease;
}
.metronome-btn:hover {
   background: rgba(0, 0, 0, 0.05);
   color: var(--ui-text, #333);
}
.metronome-btn:focus-visible {
   outline: 2px solid var(--ui-accent, #4caf50);
   outline-offset: 2px;
}
.metronome-btn[aria-pressed="true"] {
   color: var(--ui-accent, #4caf50);
}
/* Playback highlight — marks the beat currently being played. */
.beat.beat-playing,
.sub-beat.beat-playing {
   background: rgba(76, 175, 80, 0.25);
   border-radius: 4px;
   box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.5);
   transition:
      background 0.05s ease,
      box-shadow 0.05s ease;
}
/* History control — one segmented pair in the editor topbar. The wrapper owns
   the border and the buttons share it, so undo/redo read as one tool instead of
   two competing primary buttons. */
.preview-meta-col {
   display: flex;
   flex-direction: column;
   align-items: flex-end;
}
.history-toolbar {
   display: inline-flex;
   align-items: stretch;
   height: 28px;
   min-height: 0;
   border: 1px solid var(--editor-line);
   border-radius: 8px;
   background: var(--editor-surface);
   overflow: hidden;
}
.history-btn {
   display: inline-grid;
   place-items: center;
   width: 30px;
   min-height: 0;
   padding: 0;
   border: 0;
   border-radius: 0;
   background: transparent;
   color: var(--editor-ink);
   cursor: pointer;
   transition:
      background 0.16s ease,
      color 0.16s ease,
      opacity 0.16s ease;
   line-height: 1;
}
.history-btn + .history-btn {
   border-left: 1px solid var(--editor-line);
}
.history-btn svg {
   display: block;
   width: 16px;
   height: 16px;
   flex-shrink: 0;
   stroke-width: 2;
}
.history-btn:not(:disabled):hover {
   background: var(--editor-raised);
   color: var(--editor-ink);
}
.history-btn:not(:disabled):active {
   background: var(--editor-line);
}
.history-btn:focus-visible {
   position: relative;
   z-index: 1;
   outline: 2px solid var(--editor-accent);
   outline-offset: -2px;
}
.history-btn:disabled {
   opacity: 0.32;
   cursor: not-allowed;
   color: var(--editor-muted);
}
.btn-label {
   font-weight: 600;
}
.scroll-affordance {
   position: absolute;
   right: 18px;
   bottom: 13px;
   z-index: 4;
   display: none;
   align-items: center;
   gap: 8px;
   padding: 6px 9px;
   border: 1px solid rgba(196, 213, 201, 0.9);
   border-radius: 999px;
   background: rgba(255, 255, 255, 0.92);
   color: var(--muted);
   box-shadow: 0 5px 16px rgba(22, 58, 42, 0.1);
   font-size: 9px;
   pointer-events: none;
}
.preview-stage.is-overflowing:not(.at-scroll-end) .scroll-affordance {
   display: flex;
}
.scroll-affordance b {
   color: var(--green);
   font-size: 14px;
}

/* Sections and interaction feedback */
.preview-section {
   border-bottom-color: #dfe7e1;
}
.section-preview-heading {
   min-height: 34px;
}
.section-tools {
   padding: 4px 7px;
   border: 1px solid transparent;
   border-radius: 10px;
   transition:
      opacity 0.16s ease,
      background 0.16s ease,
      border-color 0.16s ease,
      transform 0.16s ease;
}
.preview-section:not(.is-active):not(:hover):not(:focus-within) .section-tools {
   opacity: 0;
   transform: translateY(-2px);
   pointer-events: none;
}
.preview-section.is-active .section-tools,
.preview-section:hover .section-tools,
.preview-section:focus-within .section-tools {
   border-color: #e0ebe3;
   background: rgba(249, 252, 250, 0.86);
}
.section-title {
   border-radius: 6px;
   padding: 4px 6px;
   transition: background 0.15s ease;
}
.section-title:hover {
   background: #eef7f0;
   text-decoration: none;
}
.section-lyrics-toggle,
.section-chord-above-toggle,
.text-button {
   transition:
      background 0.15s ease,
      color 0.15s ease,
      border-color 0.15s ease;
}
.section-lyrics-toggle:hover,
.section-chord-above-toggle:hover {
   border-color: #9fcbaa;
   background: #e8f5eb;
}
.text-button {
   border-radius: 6px;
   padding: 5px 7px;
}
.text-button:hover {
   background: #eaf5ed;
   text-decoration: none;
}

.section-menu {
   position: relative;
}
.section-menu summary {
   width: 29px;
   height: 29px;
   display: grid;
   place-items: center;
   border-radius: 7px;
   color: var(--muted);
   font-weight: 900;
   letter-spacing: 1px;
   cursor: pointer;
   list-style: none;
}
.section-menu summary::-webkit-details-marker {
   display: none;
}
.section-menu summary:hover,
.section-menu[open] summary {
   background: #eaf5ed;
   color: var(--dark-green);
}
.section-menu-popover {
   position: absolute;
   top: calc(100% + 6px);
   right: 0;
   z-index: 8;
   width: 150px;
   padding: 6px;
   border: 1px solid #dbe7de;
   border-radius: 9px;
   background: #fff;
   box-shadow: 0 10px 28px rgba(20, 53, 36, 0.15);
}
.delete-section {
   width: 100%;
   border: 0;
   border-radius: 6px;
   padding: 8px 9px;
   background: transparent;
   color: #a1433d;
   font: 750 11px inherit;
   text-align: left;
   cursor: pointer;
}
.delete-section:hover {
   background: #fff0ef;
}
.delete-section:disabled {
   color: #acb7b0;
   cursor: not-allowed;
}
/* Copy / paste entries share the section menu layout but read as neutral. */
.copy-section,
.paste-section {
   width: 100%;
   border: 0;
   border-radius: 6px;
   padding: 8px 9px;
   background: transparent;
   color: var(--dark-green, #1f704a);
   font: 750 11px inherit;
   text-align: left;
   cursor: pointer;
}
.copy-section:hover,
.paste-section:hover {
   background: #e5f4e8;
}
.paste-section:disabled {
   color: #acb7b0;
   cursor: not-allowed;
}
.bar {
   position: relative;
   -webkit-user-select: none;
   user-select: none;
   -webkit-touch-callout: none;
}
.bar .lyric-input {
   -webkit-user-select: text;
   user-select: text;
   -webkit-touch-callout: default;
}
.delete-bar {
   position: absolute;
   top: 3px;
   right: 4px;
   z-index: 5;
   width: 22px;
   height: 22px;
   display: grid;
   place-items: center;
   border: 1px solid #ead8d5;
   border-radius: 6px;
   padding: 0;
   background: rgba(255, 255, 255, 0.94);
   color: #a1433d;
   font:
      800 16px/1 Inter,
      ui-sans-serif,
      sans-serif;
   cursor: pointer;
   opacity: 0;
   transform: translateY(-2px);
   transition:
      opacity 0.15s ease,
      transform 0.15s ease,
      background 0.15s ease;
   -webkit-user-select: none;
   user-select: none;
   -webkit-touch-callout: none;
   touch-action: manipulation;
}
.bar:hover .delete-bar,
.bar:focus-within .delete-bar {
   opacity: 1;
   transform: none;
}
.delete-bar:hover {
   background: #fff0ef;
}
/* Per-bar copy/paste tools, revealed on hover next to the delete affordance. */
.bar-tools {
   position: absolute;
   top: 3px;
   right: 30px;
   z-index: 5;
   display: inline-flex;
   gap: 3px;
   opacity: 0;
   transform: translateY(-2px);
   transition:
      opacity 0.15s ease,
      transform 0.15s ease;
}
.bar:hover .bar-tools,
.bar:focus-within .bar-tools {
   opacity: 1;
   transform: none;
}
.copy-bar,
.paste-bar {
   width: 22px;
   height: 22px;
   display: grid;
   place-items: center;
   border: 1px solid #cfe0d3;
   border-radius: 6px;
   padding: 0;
   background: rgba(255, 255, 255, 0.94);
   color: var(--dark-green, #1f704a);
   font:
      800 13px/1 Inter,
      ui-sans-serif,
      sans-serif;
   cursor: pointer;
   -webkit-user-select: none;
   user-select: none;
   -webkit-touch-callout: none;
   touch-action: manipulation;
}
.copy-bar:hover:not(:disabled),
.paste-bar:hover:not(:disabled) {
   background: #e5f4e8;
   border-color: #8eb99a;
}
.paste-bar:disabled {
   opacity: 0.4;
   cursor: default;
}
/* Multi-bar selection mode highlights */
.bar.is-selectable {
   cursor: pointer;
   position: relative;
}
/* The whole bar is one big click target while selecting: block pointer events
   on inner controls so hovering a chord/beat/lyric never shows edit affordances
   and every click lands on the bar itself. */
.preview-section.is-selecting .bar.is-selectable * {
   pointer-events: none;
}
/* Keep the bar number readable but non-interactive. */
.preview-section.is-selecting .bar .bar-num {
   pointer-events: none;
}
/* Hide ALL hover/edit affordances while selecting: copy/paste/delete tools,
   the per-chord × remove badge, add-bar buttons, section menu, etc.
   NOTE: .beat-dot is intentionally NOT hidden here — the beat/ketukan dots
   must stay visible while Copy Bars is active so the bar's rhythm remains
   readable during selection. */
.preview-section.is-selecting .bar-tools,
.preview-section.is-selecting .delete-bar,
.preview-section.is-selecting .chord-remove,
.preview-section.is-selecting .add-bar {
   display: none !important;
}
/* Neutralise every hover state inside a selecting section. */
.preview-section.is-selecting .beat.drop-target:hover,
.preview-section.is-selecting .sub-beat.drop-target:hover,
.preview-section.is-selecting .placed-chord:hover,
.preview-section.is-selecting .duration-line:hover,
.preview-section.is-selecting .nested-duration-line:hover,
.preview-section.is-selecting .lyric-input:hover {
   background: transparent !important;
   box-shadow: none !important;
   cursor: pointer !important;
}
.preview-section.is-selecting .beat.drop-target:hover::before,
.preview-section.is-selecting .beat.drop-target:hover::after,
.preview-section.is-selecting .sub-beat.drop-target:hover::before,
.preview-section.is-selecting .sub-beat.drop-target:hover::after {
   content: none !important;
}
/* A selectable (not yet selected) bar gets a soft dashed outline so the user
   sees the clickable regions, without hiding the content underneath. */
.preview-section.is-selecting .bar.is-selectable {
   border-radius: 8px;
   outline: 1px dashed rgba(31, 112, 74, 0.35);
   outline-offset: -3px;
   transition:
      outline-color 0.12s ease,
      box-shadow 0.12s ease,
      background 0.12s ease;
}
.preview-section.is-selecting .bar.is-selectable:hover {
   outline-color: rgba(31, 112, 74, 0.6);
   background: rgba(31, 112, 74, 0.05);
}
/* A SELECTED bar: translucent green tint + ring so the chords/lyrics inside
   stay fully visible (previously a solid white fill hid the content). */
.bar.is-selected,
.preview-section.is-selecting .bar.is-selected {
   background: color-mix(in srgb, #1f9d55 16%, transparent) !important;
   border-top: none;
   outline: 2px solid #1f9d55 !important;
   outline-offset: -3px;
   box-shadow:
      inset 0 0 0 9999px color-mix(in srgb, #1f9d55 8%, transparent),
      0 2px 8px rgba(31, 157, 85, 0.18);
}
/* A small check badge in the corner of each selected bar. */
.preview-section.is-selecting .bar.is-selected::after {
   content: "✓";
   position: absolute;
   top: 4px;
   right: 6px;
   width: 16px;
   height: 16px;
   display: flex;
   align-items: center;
   justify-content: center;
   font-size: 11px;
   font-weight: 800;
   color: #fff;
   background: #1f9d55;
   border-radius: 50%;
   pointer-events: none;
   z-index: 3;
}
.bar-selection-bar {
   display: flex;
   align-items: center;
   gap: 16px;
   padding: 10px 14px;
   background: linear-gradient(135deg, #1f9d55, #178048);
   border-radius: 12px;
   margin: 12px 0 10px 0; /* Added top margin for spacing from section title */
   color: #fff;
   font-size: 12px;
   user-select: none;
   box-shadow: 0 6px 18px rgba(31, 157, 85, 0.28);
}
.bar-selection-count {
   font-weight: 700;
   display: inline-flex;
   align-items: center;
   gap: 6px;
}
.bar-selection-hint {
   margin-left: auto;
   color: rgba(255, 255, 255, 0.82);
   font-size: 11px;
}
.bar-selection-copy,
.bar-selection-cancel {
   padding: 5px 12px;
   border-radius: 8px;
   border: 1px solid rgba(255, 255, 255, 0.55);
   background: rgba(255, 255, 255, 0.12);
   color: #fff;
   font: 700 11px inherit;
   cursor: pointer;
   transition:
      background 0.12s ease,
      transform 0.12s ease;
}
.bar-selection-copy {
   background: #fff;
   color: #178048;
   border-color: #fff;
}
.bar-selection-copy:hover,
.bar-selection-cancel:hover {
   transform: translateY(-1px);
}
.bar-selection-copy:hover {
   background: #f0fff6;
}
.bar-selection-cancel:hover {
   background: rgba(255, 255, 255, 0.22);
}
.bar-selection-copy:disabled {
   opacity: 0.5;
   cursor: default;
   transform: none;
}
.select-bars {
   width: 100%;
   border: 0;
   border-radius: 6px;
   padding: 8px 9px;
   background: transparent;
   color: var(--dark-green, #1f704a);
   font: 750 11px inherit;
   text-align: left;
   cursor: pointer;
}
.select-bars:hover {
   background: #e5f4e8;
}
.pdf-signature {
   display: none;
}
body.is-dragging .drop-target {
   background: rgba(234, 245, 237, 0.5);
   box-shadow: inset 0 0 0 1px rgba(35, 122, 80, 0.08);
}
body.is-dragging .drop-target::after {
   content: "";
   position: absolute;
   inset: 5px;
   border: 1px dashed rgba(35, 122, 80, 0.28);
   border-radius: 5px;
   pointer-events: none;
}
.drop-target.dragover {
   z-index: 3;
   background: #def2e3 !important;
   outline: 2px solid #63a77a !important;
   outline-offset: -2px;
}
/* Uniform drag ghost: a fixed-size chip used as the drag image for every
   palette item (chords and rhythm symbols alike) so the "+"/symbol no longer
   render at wildly different sizes while dragging. */
.drag-ghost {
   box-sizing: border-box;
   min-width: 44px;
   height: 40px;
   padding: 0 14px;
   display: flex;
   align-items: center;
   justify-content: center;
   font:
      700 16px/1 Inter,
      ui-sans-serif,
      sans-serif;
   color: #fff;
   background: var(--green, #237a50);
   border-radius: 10px;
   box-shadow: 0 6px 16px rgba(35, 122, 80, 0.35);
   white-space: nowrap;
}
.drop-target.drop-success {
   animation: dropPulse 0.42s ease;
}
@keyframes dropPulse {
   0% {
      box-shadow: 0 0 0 0 rgba(35, 122, 80, 0.42);
   }
   100% {
      box-shadow: 0 0 0 10px rgba(35, 122, 80, 0);
   }
}
.placed-chord {
   transition:
      transform 0.14s ease,
      filter 0.14s ease;
}
.placed-chord:hover {
   transform: translateY(-1px);
   filter: saturate(1.08);
}
.lyric-input:focus {
   box-shadow: 0 0 0 3px rgba(35, 122, 80, 0.14);
}
.preview-footer {
   margin-top: 4px;
   color: #7a8a80;
   display: flex;
   justify-content: flex-end; /* Align actions to the right (Help moved to topbar) */
   align-items: center;
}

/* Help button is now in topbar, not footer */
.preview-help-btn {
   display: inline-flex;
   align-items: center;
   gap: 7px;
   padding: 6px 12px 6px 8px;
   border: 1px solid var(--line);
   border-radius: 999px;
   background: color-mix(in srgb, var(--green) 6%, var(--surface));
   color: var(--dark-green);
   font-size: 13px;
   font-weight: 600;
   line-height: 1;
   cursor: pointer;
   transition:
      background 0.18s ease,
      border-color 0.18s ease,
      transform 0.12s ease;
}
.preview-help-btn:hover {
   background: color-mix(in srgb, var(--green) 12%, var(--surface));
   border-color: color-mix(in srgb, var(--green) 40%, var(--line));
}
.preview-help-btn:active {
   transform: translateY(1px);
}
.preview-help-icon {
   display: grid;
   place-items: center;
   width: 18px;
   height: 18px;
   border-radius: 50%;
   background: var(--green);
   color: #fff;
   font-size: 12px;
   font-weight: 800;
   line-height: 1;
}
html[data-theme="dark"] .preview-help-btn {
   color: #cdeede;
}

/* How-to dialog: reuses .confirm-dialog chrome but is wider and left-aligns a
   scrollable list of editing tips. Selectors are scoped under #howToDialog to
   win over the base .confirm-dialog-card rules regardless of source order. */
#howToDialog .howto-dialog-card {
   width: min(480px, 100%);
   max-height: min(80vh, 640px);
   text-align: left;
   align-items: stretch;
}
#howToDialog .confirm-dialog-icon {
   align-self: center;
}
#howToDialog .confirm-dialog-title,
#howToDialog .confirm-dialog-desc {
   text-align: center;
}
.howto-list {
   list-style: none;
   margin: 6px 0 4px;
   padding: 0;
   display: flex;
   flex-direction: column;
   gap: 12px;
   overflow-y: auto;
   width: 100%;
}
/* Group label inside the help dialog (e.g. "☁ Your cloud library"). The list is
   long, so it is split into labelled sections instead of one flat run. */
.howto-group {
   margin-top: 6px;
   font-size: 10.5px;
   font-weight: 800;
   letter-spacing: 0.09em;
   text-transform: uppercase;
   color: var(--muted);
}
.howto-group:first-child {
   margin-top: 0;
}
.howto-item {
   display: flex;
   align-items: flex-start;
   gap: 12px;
   font-size: 14px;
   line-height: 1.45;
   color: var(--ink);
}
.howto-item-icon {
   flex: 0 0 auto;
   display: grid;
   place-items: center;
   width: 30px;
   height: 30px;
   border-radius: 9px;
   background: color-mix(in srgb, var(--green) 12%, transparent);
   font-size: 15px;
   line-height: 1;
}
.howto-item-text {
   flex: 1 1 auto;
   padding-top: 3px;
}
.howto-item-text strong {
   font-weight: 700;
   color: var(--ink);
}
.howto-item-text code {
   font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
   font-size: 12.5px;
   padding: 1px 5px;
   border-radius: 5px;
   background: color-mix(in srgb, var(--green) 10%, var(--surface));
   color: var(--dark-green);
}
html[data-theme="dark"] .howto-item-text code {
   color: #cdeede;
}

/* Accessible focus treatment */
:where(button, input, select, [tabindex]):focus-visible {
   outline: 3px solid rgba(184, 232, 92, 0.7);
   outline-offset: 2px;
}
.toast {
   /* Must sit above the My Songs home overlay (.cloud-modal, z-index 130) and
      the device hint (160) so copy/save feedback is visible on every screen —
      including when triggered from a card action inside the gallery. */
   z-index: 200;
   border: 1px solid rgba(255, 255, 255, 0.12);
   box-shadow: 0 12px 35px rgba(15, 45, 30, 0.23);
}

/* Desktop-recommendation hint. Rendered on small/touch devices only (JS gates
   it with prefersTap()). Shown on every load/refresh — no persistence. Centered
   modal card over a blurred backdrop. Purely informational — dismiss to use the
   app. */
.device-hint {
   position: fixed;
   inset: 0;
   /* Must sit above every full-screen surface — the login page (140) and the My
      Songs home overlay (130) — so the hint is visible no matter which screen
      the phone user refreshes on. */
   z-index: 160;
   display: grid;
   place-items: center;
   padding: 24px;
   background: rgba(12, 28, 20, 0.42);
   -webkit-backdrop-filter: blur(8px);
   backdrop-filter: blur(8px);
   opacity: 0;
   transition: opacity 0.28s ease;
}
/* When hidden, fully remove it from the layout so its full-screen backdrop can
   never trap clicks — a bare `.device-hint{display:grid}` outranks the built-in
   [hidden] rule, leaving an invisible click-blocking overlay behind. */
.device-hint[hidden] {
   display: none;
}
.device-hint.is-open {
   opacity: 1;
}
.device-hint-card {
   width: min(360px, 100%);
   display: flex;
   flex-direction: column;
   align-items: center;
   gap: 12px;
   padding: 26px 24px 22px;
   text-align: center;
   border: 1px solid var(--line);
   border-radius: var(--radius-lg);
   background: var(--surface);
   box-shadow: var(--shadow-md);
   transform: translateY(12px) scale(0.98);
   transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
.device-hint.is-open .device-hint-card {
   transform: translateY(0) scale(1);
}
.device-hint-icon {
   flex: 0 0 auto;
   font-size: 40px;
   line-height: 1;
}
.device-hint-copy {
   min-width: 0;
}
.device-hint-copy strong {
   display: block;
   font-size: 17px;
   font-weight: 700;
   color: var(--ink);
}
.device-hint-copy p {
   margin: 6px 0 0;
   font-size: 13px;
   line-height: 1.45;
   color: var(--muted);
}
.device-hint-close {
   flex: 0 0 auto;
   width: 100%;
   min-height: 44px;
   margin-top: 4px;
   padding: 0 16px;
   border: 0;
   border-radius: 999px;
   background: var(--green, #1f7a4d);
   color: #fff;
   font-size: 14px;
   font-weight: 700;
   cursor: pointer;
   transition: filter 0.15s ease;
}
.device-hint-close:hover {
   filter: brightness(1.06);
}
.device-hint-close:focus-visible {
   outline: 2px solid var(--green, #1f7a4d);
   outline-offset: 2px;
}

/* Themed confirm dialog — a drop-in replacement for window.confirm(). Sits above
   every full-screen surface (login 140, home 130) so it's usable from any
   screen. Backdrop click, Cancel and Escape all resolve as "cancelled". */
.confirm-dialog {
   position: fixed;
   inset: 0;
   z-index: 170;
   display: grid;
   place-items: center;
   padding: 24px;
   opacity: 0;
   transition: opacity 0.24s ease;
}
.confirm-dialog[hidden] {
   display: none;
}
.confirm-dialog.is-open {
   opacity: 1;
}
.confirm-dialog-backdrop {
   position: absolute;
   inset: 0;
   background: rgba(12, 28, 20, 0.44);
   -webkit-backdrop-filter: blur(8px);
   backdrop-filter: blur(8px);
}
.confirm-dialog-card {
   position: relative;
   z-index: 1;
   width: min(400px, 100%);
   display: flex;
   flex-direction: column;
   align-items: center;
   gap: 10px;
   padding: 28px 26px 22px;
   text-align: center;
   border: 1px solid var(--line);
   border-radius: var(--radius-lg);
   background: var(--surface);
   box-shadow: var(--shadow-md);
   transform: translateY(12px) scale(0.98);
   transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
/* Wider variant used by the version dialogs (Create New Version / Version
   Details) so the version-name and YouTube fields have room to breathe. */
.confirm-dialog-card.version-dialog-card {
   width: min(600px, 94vw);
   max-height: 84vh;
   align-items: stretch;
   text-align: left;
}
/* Version dialogs: header icon on the LEFT, title + subtitle on the RIGHT. */
.vd-dialog-head {
   display: flex;
   align-items: center;
   gap: 14px;
   width: 100%;
}
.vd-dialog-head .confirm-dialog-icon {
   flex: 0 0 auto;
}
.vd-dialog-head-text {
   flex: 1;
   min-width: 0;
   text-align: left;
}
.vd-dialog-head-text .confirm-dialog-title {
   margin: 0;
}
.vd-dialog-head-text .confirm-dialog-desc {
   margin: 3px 0 0;
}
.confirm-dialog.is-open .confirm-dialog-card {
   transform: translateY(0) scale(1);
}
.confirm-dialog-icon {
   display: grid;
   place-items: center;
   width: 48px;
   height: 48px;
   border-radius: 50%;
   background: color-mix(in srgb, var(--green) 14%, transparent);
   color: var(--dark-green);
   font-size: 26px;
   line-height: 1;
}
/* In dark theme the deep --dark-green sits too close to the dark card bg, so
   brighten the glyph (use --green) and strengthen the pill background. */
html[data-theme="dark"] .confirm-dialog-icon {
   color: var(--green);
   background: color-mix(in srgb, var(--green) 24%, transparent);
}
/* Inline stroke glyphs replacing emoji in dialog heads. */
.confirm-dialog-icon svg {
   display: block;
   width: 24px;
   height: 24px;
}
.confirm-dialog-title {
   margin: 4px 0 0;
   font-family: "Sora", "Inter", system-ui, sans-serif;
   font-size: 19px;
   font-weight: 700;
   letter-spacing: -0.01em;
   color: var(--ink);
}
.confirm-dialog-desc {
   margin: 0;
   font-size: 13.5px;
   line-height: 1.5;
   color: var(--muted);
}
/* Free-text field for the Attach Link dialog (paste a share link/payload). */
.attach-link-input {
   width: 100%;
   margin-top: 12px;
   padding: 10px 12px;
   font-size: 13px;
   font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
   line-height: 1.4;
   color: var(--ink);
   background: var(--surface);
   border: 1px solid var(--line);
   border-radius: 10px;
   resize: vertical;
   min-height: 68px;
   box-sizing: border-box;
   word-break: break-all;
}
.attach-link-input:focus-visible {
   outline: none;
   border-color: var(--green);
   box-shadow: 0 0 0 3px color-mix(in srgb, var(--green) 22%, transparent);
}
.confirm-dialog-actions {
   display: flex;
   gap: 10px;
   width: 100%;
   margin-top: 14px;
}
.confirm-dialog-actions .button {
   flex: 1 1 0;
   justify-content: center;
   min-height: 44px;
}
/* Destructive confirm (e.g. Sign out) reads red rather than the brand green. */
.confirm-dialog-actions .button.is-danger {
   background: #b42318;
   border-color: #b42318;
   color: #fff;
}
.confirm-dialog-actions .button.is-danger:hover {
   filter: brightness(1.06);
}
/* Three-choice dialogs (e.g. unsaved changes) stack full-width buttons so the
   labels never truncate and the recommended primary action reads first. */
.confirm-dialog-actions.confirm-dialog-actions-stacked {
   flex-direction: column;
   width: 100%;
   gap: 8px;
}
.confirm-dialog-actions.confirm-dialog-actions-stacked .button {
   flex: none;
   width: 100%;
}

/* Site footer */
.site-footer {
   border-top: 1px solid rgba(201, 219, 206, 0.9);
   background: linear-gradient(180deg, rgba(255, 255, 255, 0.5), rgba(235, 244, 237, 0.92));
}
.site-footer-inner {
   width: 100%;
   max-width: 1560px;
   min-height: 112px;
   margin: 0 auto;
   padding: 24px clamp(20px, 4vw, 64px);
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 28px;
}
.footer-identity {
   min-width: 0;
   display: flex;
   align-items: center;
   gap: 12px;
}
.footer-mark {
   width: 38px;
   height: 38px;
   flex: 0 0 auto;
   overflow: hidden;
   border-radius: 12px;
   box-shadow: 0 7px 16px rgba(10, 20, 14, 0.18);
}
.footer-mark img {
   display: block;
   width: 100%;
   height: 100%;
}
.footer-identity strong {
   display: block;
   margin-bottom: 4px;
   color: var(--ink);
   font-size: 14px;
   letter-spacing: -0.2px;
}
.footer-identity p {
   margin: 0;
   color: var(--muted);
   font-size: 11px;
   line-height: 1.5;
}
.footer-identity p b {
   color: var(--dark-green);
   font-weight: 800;
}
.footer-meta {
   display: flex;
   align-items: center;
   justify-content: flex-end;
   gap: 12px;
   color: var(--muted);
   font-size: 10px;
   text-align: right;
}
.open-source-badge {
   min-height: 32px;
   display: inline-flex;
   align-items: center;
   gap: 7px;
   padding: 6px 10px;
   border: 1px solid #cfe3d4;
   border-radius: 999px;
   background: rgba(255, 255, 255, 0.72);
   color: var(--dark-green);
   font-weight: 800;
   white-space: nowrap;
}
.open-source-badge i {
   width: 7px;
   height: 7px;
   border-radius: 50%;
   background: var(--lime);
   box-shadow: 0 0 0 3px rgba(184, 232, 92, 0.2);
}

