/* Shared base styles for all windows (main + child).
   Page-specific styles go in each HTML file's <style> block.
   Dark theme overrides are in theme-dark.css. */

/* ── Fonts ── */

@font-face {
    font-family: 'IBM Plex Mono';
    src: url('/fonts/IBMPlexMono-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'IBM Plex Mono';
    src: url('/fonts/IBMPlexMono-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* ── Design tokens (light theme defaults; dark overrides in theme-dark.css) ── */

:root {
    color-scheme: light;
    --font-mono: 'Courier Prime', 'IBM Plex Mono', monospace;
    --font-ui: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --radius-sm: 2px;
    --radius-md: 4px;
    --radius-lg: 6px;
    --font-size-xs: 11px;
    --font-size-small: 12px;
    --font-size-sm: 13px;
    --font-size-base: 14px;
    --font-size-lg: 16px;
    --font-size-large: 18px;

    /* The Mill palette, light: neutral off-white/grey, contrast first
       (visually-impaired operators are a primary audience). Near-black ink
       on off-white panels over a light grey page; one quiet steel-blue
       accent. Dark counterpart in theme-dark.css. */
    --color-primary: #2f5d8a;
    --color-primary-hover: #244a70;
    --color-primary-light: #d7e3ee;
    --color-bg: #d9d9d5;
    --color-surface: #ededea;
    --color-surface-raised: #e2e2de;
    --color-surface-sunken: #d3d3cf;
    --color-text: #141414;
    --color-text-secondary: #3a3a3a;
    --color-text-muted: #5a5a5a;
    --color-text-disabled: #90908a;
    --color-text-inverse: #f5f5f2;
    --color-border: #c4c4be;
    --color-border-strong: #8f8f88;
    --color-border-subtle: #d8d8d3;
    --color-table-header: #e6e6e2;
    --color-table-row-hover: #ebebe7;
    --color-table-row-selected: #2f5d8a;
    --color-table-row-selected-text: #f5f5f2;
    --color-table-border: #d3d3cd;
    --color-focus: #0a5cad;
    --color-focus-shadow: rgba(10, 92, 173, 0.25);
    --color-link: #205b8f;
    --color-link-hover: #174569;
    --color-success: #217a2b;
    --color-error: #b3261e;
    /* TX lamp (masthead): red while code plays, green standing by (rig
       convention; WX7V, 2026-07-10). Both sit on the masthead band, so
       they are tuned against --color-primary, not the page background. */
    --color-lamp-tx: #e53935;
    --color-lamp-standby: #43a047;
    /* Warning + info families (#240 dark-mode token audit, 2026-07-07):
       previously ~37 var() references carried these as undefined tokens with
       light-only fallbacks that rendered in both themes. --color-warning is
       the amber accent (dots, icons, notice text); -strong is a filled
       control background that keeps contrast under white text; the -bg/
       -border/-text triples style pale banner boxes. */
    --color-warning: #f59e0b;
    --color-warning-strong: #d48800;
    --color-warning-bg: #fef3c7;
    --color-warning-border: #fde68a;
    --color-warning-text: #92400e;
    --color-info-bg: #eff6ff;
    --color-info-border: #bfdbfe;
    --color-info-text: #1e40af;
    /* Toast triples (#240 follow-up, 2026-07-08): toasts previously drew
       from two divergent hardcoded palettes (solid hex below for child
       windows, JS hex maps in main.js for the main window), so the same
       success toast rendered bright green in Log Entry and murky dark
       brown in the main window's dark theme. All toasts in all windows now
       share these triads. INTENTIONALLY theme-invariant: a pale pill with
       dark text pops on both light and dark surfaces; deep-fill dark
       variants read "too dark" (WX7V, 2026-07-08). Do not add dark
       overrides: the main window and child windows have different dark
       token sources (src/styles.css vs public/theme-dark.css), so an
       override in one re-splits the palette per window. check-css-rules.mjs
       Check 3 enforces base.css as the only definition site. */
    --color-toast-success-bg: #d4edda;
    --color-toast-success-border: #c3e6cb;
    --color-toast-success-text: #155724;
    --color-toast-error-bg: #f8d7da;
    --color-toast-error-border: #f5c6cb;
    --color-toast-error-text: #721c24;
    --color-toast-warning-bg: #fff3cd;
    --color-toast-warning-border: #ffeeba;
    --color-toast-warning-text: #856404;
    --color-toast-info-bg: #d1ecf1;
    --color-toast-info-border: #bee5eb;
    --color-toast-info-text: #0c5460;
    /* Skimmer needed-row tint; dark theme swaps to a blue fill (see
       theme-dark.css) so the row reads as actionable on dark surfaces. */
    --color-highlight-needed-bg: #fef3c7;
    --color-unsaved-bg: #fffacd;
    --color-unsaved-bg-hover: #fff59d;
    --color-required-bg: #ffb3b3;
    --color-invalid-bg: #FF9F9F;
    --color-dupe-bg: #2250b0;
    --color-dupe-bg-hover: #1a3f8f;
    --color-dupe-text: #ffffff;
    --color-surface-secondary: #e6e6e2;
    --color-surface-secondary-hover: #dcdcd7;
    --color-surface-secondary-active: #d1d1cb;
    --color-modal-footer: #ebebe7;
    --color-input-border: #767670;
    --color-shortcut: #718096;
    --color-backdrop: rgba(0, 0, 0, 0.35);
    --color-match-highlight: #86efac;
    --color-match-highlight-text: #0f172a;
    /* Slate-tinted shadows: adopted from the main window's palette during
       the #240 palette consolidation (2026-07-08); previously base.css
       carried heavier plain-black shadows and the two drifted silently. */
    --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.05);
    --shadow-md: 0 2px 8px rgba(15, 23, 42, 0.08);
    --shadow-lg: 0 4px 16px rgba(15, 23, 42, 0.12);
    --shadow-modal: 0 8px 32px rgba(15, 23, 42, 0.2);
    /* #240 palette consolidation (2026-07-08): base.css :root is the ONLY
       light-token source and public/theme-dark.css the ONLY dark-override
       source, for every window including the main one (src/styles.css no
       longer defines --color-* tokens; check-css-rules.mjs Check 4 gates
       this). Tokens below were previously main-window-only (styles.css) or
       dark-only (theme-dark.css / theme-init.js), which left child windows
       resolving them to nothing in light mode. Every dark override in
       theme-dark.css must have a light value here. */
    --color-menu-bar: #bfdbfe;
    --color-menu-bar-border: #93c5fd;
    --color-toolbar: #e8f0fe;
    --color-surface-overlay: rgba(0, 0, 0, 0.5);
    --color-muted-light: #999;
    --color-muted-medium: #666;
    --color-muted-dark: #555;
    --color-sprint-warning-bg: #dbeafe;
    --color-sprint-warning-border: #3b82f6;
    --color-error-bg: #f8d7da;
    --color-input-bg: #ffffff;
    --color-log-bg: #f8fafc;
    --color-log-text: #1e293b;
    --color-log-send: #0066cc;
    --color-log-recv: #15803d;
    --color-log-time: #718096;
}

/* ── Resets ── */

html {
    background: var(--color-bg);
    height: 100vh;
    overflow: hidden;
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/* The hidden attribute means hidden, whatever else is styled.
   Browsers implement it as a UA-stylesheet `[hidden] { display: none }`,
   which ANY author rule carrying a `display` declaration outranks. So
   `el.hidden = true` silently did nothing to a flex or grid container
   while still reporting hidden:true from JS, which is a bug that hides
   from the obvious check. Cost twice: .grid-bearing-display got a one-off
   patch for it, then the browser build's About dialog shipped a visible
   "Check for Updates" button that did nothing (WX7V live test,
   2026-07-28). !important is what makes this outrank author display
   rules, and it is the whole point of the declaration. */
[hidden] {
    display: none !important;
}

/* Bold font toggle — applied via html.font-bold class from settings.
   Targets body plus elements that may not reliably inherit font-weight. */
html.font-bold body,
html.font-bold .modal,
html.font-bold .modal-body,
html.font-bold label,
html.font-bold span,
html.font-bold input,
html.font-bold select,
html.font-bold textarea,
html.font-bold button,
html.font-bold th,
html.font-bold td {
    font-weight: 700;
}

/* Data-entry controls: monospace with dotted zeros */
input, select, textarea {
    font-family: var(--font-mono);
    font-feature-settings: 'zero' 1;
    border-style: solid;
}
button {
    font-family: inherit;
    font-size: var(--font-size-sm);
    padding: 2px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: 3px;
    background: var(--color-surface);
    cursor: pointer;
    white-space: nowrap;
}
button:hover { background: var(--color-surface-raised); }

body {
    font-family: var(--font-ui);
    font-size: var(--font-size-base);
    background: var(--color-bg);
    color: var(--color-text);
    height: 100%;
    display: flex;
    flex-direction: column;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Prevent text-transform: uppercase from affecting placeholder text */
input[style*="text-transform"]::placeholder {
    text-transform: none !important;
}

/* ── Window chrome ── */

.window-header {
    background: var(--color-primary);
    color: var(--color-text-inverse);
    padding: 8px 12px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-shrink: 0;
}

.window-title {
    font-weight: 600;
    font-size: var(--font-size-base);
}

/* Contextual hint / scoring-tip callout. The app encodes guidance inline right
   where it is needed (e.g. the TKA key-type decode on the Triple Key Counts
   window) instead of a global "show hints at startup" toggle, so the tip is
   relevant at the moment of use. Accent bar sets it off from computed values;
   mirrors the SSS scoring-tip look (sprint-submit.html .theme-hint) but uses
   real theme variables so it adapts to dark mode. Reusable app-wide. */
.app-hint {
    font-size: var(--font-size-sm);
    color: var(--color-text);
    background: var(--color-surface-raised);
    border-left: 3px solid var(--color-primary);
    padding: 8px 12px;
    margin: 4px 0 12px 0;
    border-radius: 4px;
}

/* ── Focus management ── */

*:focus {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

/* Remove default outline for mouse users, keep for keyboard */
*:focus:not(:focus-visible) {
    outline: none;
}

/* Enhanced focus ring for buttons */
button:focus-visible,
.le-btn:focus-visible,
.btn:focus-visible {
    outline: 3px solid var(--color-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 4px rgba(0, 120, 212, 0.25);
}

/* Focus ring for inputs */
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 0;
    border-color: var(--color-focus);
    box-shadow: 0 0 0 2px var(--color-focus-shadow);
}

/* Focus ring for checkboxes */
input[type="checkbox"]:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

/* ── Buttons ── */

.btn {
    padding: 6px 16px;
    border: 1px solid var(--color-input-border);
    color: var(--color-text);
    cursor: pointer;
    font-size: var(--font-size-base);
}

.btn-primary {
    background: var(--color-focus);
    color: white;
    border-color: var(--color-focus);
}

.btn-primary:hover {
    background: #006cbd;
}

.le-btn {
    padding: 2px 10px;
    border: 1px solid var(--color-input-border);
    background: var(--color-surface-secondary);
    color: var(--color-text);
    font-size: var(--font-size-base);
    cursor: pointer;
    min-width: 60px;
}

.le-btn-default {
    border: 2px solid var(--color-primary);
    padding: 1px 9px; /* compensate for thicker border */
    font-weight: 600;
}

.le-btn:hover {
    background: var(--color-surface-secondary-hover);
}

.le-btn:active {
    background: var(--color-surface-secondary-active);
}

.le-btn:disabled {
    opacity: 0.5;
    cursor: default;
}

.le-btn-small {
    padding: 2px 8px;
    font-size: var(--font-size-small);
    min-width: auto;
}

.le-btn-primary {
    background: var(--color-primary);
    color: white;
    border-color: var(--color-primary);
}

.le-btn-primary:hover {
    background: var(--color-primary-hover);
}

.le-btn-primary:disabled {
    background: var(--color-surface-secondary);
    color: var(--color-text-muted, #999);
    border-color: var(--color-input-border);
    opacity: 0.7;
}

.le-btn-log-it {
    margin-left: 6px;
    font-weight: 600;
}

/* ── Modals ── */

.modal-overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: var(--color-backdrop);
    z-index: 2000;
    justify-content: center;
    align-items: center;
}

.modal-overlay.active {
    display: flex;
    /* Sighted cue that the backdrop is blocking interaction. JAWS users
       get the same signal via the live-region announcement fired from
       modals.js openOverlay. See GitHub #128. */
    cursor: not-allowed;
}

/* Restore normal cursor inside the dialog itself; more-specific child
   rules (modal-header cursor: move, inputs, buttons) still win. */
.modal-overlay.active .modal {
    cursor: auto;
    /* Belt-and-suspenders: prevent wheel events inside a scrollable
       modal body from chain-scrolling to the page underneath. */
    overscroll-behavior: contain;
}

/* Light backdrop for search modals */
.modal-overlay.backdrop-light {
    background: rgba(0, 0, 0, 0.1);
}

.modal {
    background: var(--color-surface, #f0f0f0);
    color: var(--color-text, #000);
    border: 1px solid var(--color-border, #888);
    border-radius: var(--radius-lg, 6px);
    box-shadow: var(--shadow-modal, 0 4px 16px rgba(0,0,0,0.3));
    min-width: 500px;
    max-width: 90vw;
    max-height: 90vh;
    overflow: hidden;
    position: relative;
    display: flex;
    flex-direction: column;
}

/* Opt-in resizable modal. Add .resizable to .modal and ensure inline width/max-width
   styles do not pin the width (otherwise the resize handle appears but cannot grow).
   max-width/height are removed so the user's manual resize controls the size. */
.modal.resizable {
    resize: both;
    max-width: none;
    max-height: none;
}

/* Resize handle indicator in bottom-right corner — only on resizable modals */
.modal.resizable::after {
    content: '';
    position: absolute;
    bottom: 0;
    right: 0;
    width: 16px;
    height: 16px;
    cursor: se-resize;
    background: linear-gradient(135deg, transparent 50%, var(--color-text-muted, #999) 50%, var(--color-text-muted, #999) 55%, transparent 55%, transparent 65%, var(--color-text-muted, #999) 65%, var(--color-text-muted, #999) 70%, transparent 70%);
    opacity: 0.5;
}

.modal-header {
    background: var(--color-primary, #0078d4);
    color: white;
    padding: 8px 12px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: move;
    user-select: none;
    flex-shrink: 0;
}

/* Draggable modal support */
.modal-overlay.active .modal.draggable {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

.modal-title {
    font-weight: 600;
    font-size: var(--font-size-base);
}

.modal-close {
    background: transparent;
    border: none;
    color: white;
    font-size: var(--font-size-large);
    cursor: pointer;
    padding: 0 4px;
    line-height: 1;
    opacity: 0.8;
    border-radius: var(--radius-sm, 2px);
    transition: opacity 0.1s;
}

.modal-close:hover {
    opacity: 1;
    background: rgba(255,255,255,0.1);
}

.modal-body {
    padding: 12px;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    background: var(--color-surface, white);
}

.modal-footer {
    padding: 8px 12px;
    border-top: 1px solid var(--color-border, #ccc);
    background: var(--color-surface-raised, #f5f5f5);
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    flex-shrink: 0;
}

/* ── In-app file picker (macOS fallback for native file dialog) ── */

.file-picker-modal {
    width: min(820px, calc(100vw - 32px));
    height: min(620px, calc(100vh - 32px));
    min-width: 0;
}
.file-picker-body {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px;
    min-height: 0;
    flex: 1;
    overflow: hidden;
}
.file-picker-row {
    display: flex;
    gap: 6px;
    align-items: center;
}
.file-picker-row label {
    font-weight: 600;
    white-space: nowrap;
}
.file-picker-row input[type="text"],
.file-picker-row select {
    flex: 1;
    min-width: 0;
    padding: 5px 7px;
    border: 1px solid var(--color-border, #aaa);
    background: var(--color-surface, white);
    color: var(--color-text, #111);
    border-radius: var(--radius-sm, 2px);
    font: inherit;
}
.file-picker-row select { flex: 0 0 auto; }
.file-picker-list {
    flex: 1;
    min-height: 0;
    overflow: auto;
    border: 1px solid var(--color-border, #bbb);
    background: var(--color-surface, white);
}
.file-picker-entry {
    width: 100%;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 110px 140px;
    gap: 8px;
    align-items: center;
    text-align: left;
    padding: 5px 8px;
    border: 0;
    border-bottom: 1px solid var(--color-border-subtle, #eee);
    background: transparent;
    color: inherit;
    cursor: pointer;
    font: inherit;
}
.file-picker-entry > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.file-picker-entry:hover {
    background: var(--color-table-row-hover, #eff6ff);
}
.file-picker-entry:focus {
    outline: 2px solid var(--color-focus, #0078d4);
    outline-offset: -2px;
}
.file-picker-entry.is-selected {
    background: var(--color-table-row-selected, #2563eb);
    color: var(--color-table-row-selected-text, #f8fafc);
}
.file-picker-entry[disabled] {
    opacity: 0.55;
    cursor: default;
}
.file-picker-status {
    min-height: 1.4em;
    color: var(--color-text-secondary, #475569);
    font-size: var(--font-size-small, 12px);
}

/* ── Forms ── */

.form-row {
    display: flex;
    gap: 12px;
    margin-bottom: 8px;
}

.form-group {
    flex: 1;
    min-width: 0;
}

.form-group.full-width {
    flex: 1 0 100%;
}

.form-group label {
    display: block;
    font-size: var(--font-size-small);
    color: var(--color-text);
    margin-bottom: 2px;
}

.form-group input,
.form-group select {
    width: 100%;
    padding: 4px 6px;
    border: 1px solid #888;
    font-size: var(--font-size-base);
}

.form-group input:focus,
.form-group select:focus {
    outline: none;
    border-color: var(--color-focus);
    box-shadow: 0 0 0 2px var(--color-focus-shadow);
}

/* ── Notifications ── */

.notification {
    position: fixed;
    bottom: 60px;
    right: 20px;
    padding: 10px 16px;
    border-radius: 4px;
    font-size: var(--font-size-base);
    z-index: 3000;
    animation: slideIn 0.3s ease;
}

/* Toast colors: users saw the same success toast render bright green in
   child windows but murky dark green/brown in the main window (WX7V,
   2026-07-08) because two hardcoded palettes coexisted. Both toast systems
   (utils.js and main.js showNotification) now share the theme-invariant
   --color-toast-* triads defined in :root above; check-css-rules.mjs
   gates against reintroducing hex or dark overrides. */
.notification.success { background: var(--color-toast-success-bg); color: var(--color-toast-success-text); border: 1px solid var(--color-toast-success-border); }
.notification.warning { background: var(--color-toast-warning-bg); color: var(--color-toast-warning-text); border: 1px solid var(--color-toast-warning-border); }
.notification.error { background: var(--color-toast-error-bg); color: var(--color-toast-error-text); border: 1px solid var(--color-toast-error-border); }
.notification.info { background: var(--color-toast-info-bg); color: var(--color-toast-info-text); border: 1px solid var(--color-toast-info-border); }

/* Main-window toasts stack inside #notification-container (top-right,
   flex column, see main.js getNotificationContainer); neutralize the
   fixed bottom-right positioning meant for single child-window toasts. */
#notification-container .notification {
    position: static;
    max-width: 400px;
    box-shadow: var(--shadow-md);
}

@keyframes slideIn {
    from { transform: translateX(400px); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}

/* ── Window context menu ── */

.window-context-menu {
    position: fixed;
    background: var(--color-surface-raised, white);
    border: 1px solid var(--color-border, #ccc);
    box-shadow: var(--shadow-md, 0 2px 8px rgba(0,0,0,0.15));
    min-width: 180px;
    z-index: 2000;
    padding: 4px 0;
    color: var(--color-text, #000);
}

.window-context-menu button {
    display: block;
    width: 100%;
    padding: 6px 16px;
    text-align: left;
    background: transparent;
    border: none;
    cursor: pointer;
    font-size: var(--font-size-base);
    color: inherit;
}

.window-context-menu button:hover {
    background: var(--color-focus);
    color: white;
}

.window-context-menu button:focus-visible {
    background: var(--color-focus);
    color: white;
    outline: 2px solid var(--color-focus);
    outline-offset: -2px;
}

/* ── Accessibility: reduced motion ── */

@media (prefers-reduced-motion: reduce) {
    .le-btn, .btn, .modal-close {
        transition: none;
    }
    .notification {
        animation: none;
    }
}

@media (prefers-contrast: high) {
    .le-btn:focus-visible, .btn:focus-visible, button:focus-visible {
        outline: 3px solid currentColor;
        box-shadow: none;
    }
}

/* ── Alert boxes ── */

.alert-warning {
    background: #fff3cd;
    border: 1px solid #ffeeba;
    border-radius: 4px;
}
.alert-info {
    background: #d1ecf1;
    border: 1px solid #bee5eb;
    border-radius: 4px;
}
.alert-info-table-container {
    border: 1px solid #bee5eb;
    border-radius: 3px;
    background: #fff;
}
.alert-info-table-header {
    background: #e2f3f7;
}
.alert-info-table-header th {
    border-bottom: 1px solid #bee5eb;
}

/* ── Screen reader utility ── */

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ── QRZ session status indicator (overlay on Grid Square input, ALE / Edit) ──
 *
 * Rendered as an absolutely-positioned ::after on the input's wrapper so it
 * costs zero horizontal layout space (the previous inline dot span reserved
 * ~12px even when QRZ was disabled). Driven by data-qrz-state on the host:
 *   no attribute → hidden
 *   "ok"   → green   (session live)
 *   "warn" → amber   (authenticating)
 *   "err"  → red     (auth failed / config issue)
 *
 * .le-field-group is already position:relative, so the host needs no extra
 * positioning rule. The right-padding reservation on the input keeps the
 * caret from running under the dot when QRZ is enabled. */

/* Wrapper would otherwise stretch to fill its 1fr grid cell, pushing the dot
 * far to the right of the input. justify-self:start collapses it to its
 * content (the 80px GridSquare input), so `right: 5px` lands inside the
 * input's top-right corner. */
.qrz-state-host { justify-self: start; }
.qrz-state-host > .le-input { padding-right: 14px; }
.qrz-state-host[data-qrz-state]::after {
    content: '';
    position: absolute;
    top: 50%;
    right: 5px;
    transform: translateY(-50%);
    width: 6px;
    height: 6px;
    border-radius: 50%;
    pointer-events: none;
}
.qrz-state-host[data-qrz-state="ok"]::after   { background: var(--color-success, #10b981); }
.qrz-state-host[data-qrz-state="warn"]::after { background: var(--color-warning); }
.qrz-state-host[data-qrz-state="err"]::after  { background: var(--color-error,   #ef4444); }

/* ── GridSquare label + bearing/distance stack (ALE / Edit) ──
 * Wrap stretches to the grid row height. With no bearing, the label is
 * vertically centered. With a bearing, the label is top-aligned and the
 * bearing/distance is bottom-aligned. Right-aligned to keep the eye anchored
 * against the input field to the right. */

.le-grid-label-wrap {
    align-self: stretch;
    display: flex;
    flex-direction: column;
    justify-content: center;
    text-align: right;
}
.le-grid-label-wrap:has(.grid-bearing-display:not([hidden])) {
    justify-content: space-between;
}

.grid-bearing-display {
    font-size: 0.85em;
    font-weight: 700;
    line-height: 1;
    color: var(--color-text-secondary, #6b7280);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
    white-space: nowrap;
    user-select: none;
    pointer-events: none;
    /* Inside the Log Entry status bar this sits between the status text
       (which has flex:1 1 auto + ellipsis) and the Switch View button.
       Without flex-shrink:0 a long status message (e.g. "Member found:
       Dallas - SKCC #17169 - New Senator") squeezes the bearing readout
       to zero width and visually hides it. */
    flex-shrink: 0;
}
