/* ===== Custom DaisyUI Theme ===== */
[data-theme="shipmate"] {
    --b1: 100% 0 0;            /* base-100: white */
    --b2: 97% 0.002 250;       /* base-200 */
    --b3: 93% 0.004 250;       /* base-300 */
    --bc: 25% 0.07 250;        /* base-content: navy-ish */
    --p: 30% 0.12 250;         /* primary: navy */
    --pf: 25% 0.14 250;        /* primary-focus */
    --pc: 100% 0 0;            /* primary-content: white */
    --s: 51% 0.19 90;          /* secondary: gold */
    --sf: 46% 0.17 90;         /* secondary-focus */
    --sc: 25% 0.07 250;        /* secondary-content: navy */
    --a: 44% 0.13 250;         /* accent: blue */
    --af: 38% 0.14 250;
    --ac: 100% 0 0;
    --n: 25% 0.07 250;         /* neutral */
    --nf: 20% 0.08 250;
    --nc: 100% 0 0;
    --rounded-btn: 0.5rem;
    --rounded-badge: 1rem;
    --rounded-box: 0.75rem;
}

/* ===== Base styles ===== */
html {
    scroll-behavior: smooth;
}

/*  ------------------------------------------ the footer ends the page

    Derrick, 2026-09-09, from an iPad: "on ipad these scroll way past the
    footer. we need to ensure the footer is the bottom of the page on EVERY
    PAGE. that is a ui bug."

    Two separate causes, both of them iOS, and both fixed here rather than on
    the pages — the layouts already lay this out correctly (body is a flex
    column, main is flex:1, the footer is the last child), so nothing about an
    individual page is wrong and a per-page fix would be fourteen fixes.

    1. min-h-screen is Tailwind's `min-height: 100vh`, and on iOS `100vh` is the
       LARGE viewport — the height the page would have if the address bar were
       hidden. With the bar showing, the document is taller than what you can
       see, so every page has a strip of scroll below the footer whether or not
       it has enough content to need one. `100dvh` is the height actually on
       screen right now, which is the number this wants. 100vh stays first as
       the fallback for anything that does not know dvh.

    2. Rubber banding. Past the end of the document Safari keeps scrolling and
       paints the canvas background — the light page ground — so the footer
       lifts off the bottom of the screen and a slab of grey appears under it.
       overscroll-behavior-y stops the page from doing that.

    body.min-h-screen, not body: the utility is injected by the Tailwind play
    CDN at runtime, which puts its stylesheet AFTER this one. The extra class
    is what wins the cascade against it. */
body.min-h-screen {
    min-height: 100vh;
    min-height: 100dvh;
}

html,
body {
    overscroll-behavior-y: none;
}

/* ===== GSAP animation helpers ===== */
.gsap-fade-up {
    opacity: 0;
    transform: translateY(40px);
}
.gsap-fade-in {
    opacity: 0;
}
.gsap-scale-in {
    opacity: 0;
    transform: scale(0.95);
}

/* ===== Image zoom on hover ===== */
.img-zoom {
    overflow: hidden;
}
.img-zoom img {
    transition: transform 0.7s ease-out;
}
.img-zoom:hover img {
    transform: scale(1.1);
}

/* ===== Mobile menu hamburger animation =====
   translate must come BEFORE rotate so the offset is in screen space, not the
   rotated coordinate frame (otherwise both lines shift diagonally left and the
   right side of the X gets cut off). */
.menu-open .hamburger-line:nth-child(1) {
    transform: translateY(8px) rotate(45deg);
}
.menu-open .hamburger-line:nth-child(2) {
    opacity: 0;
    transform: scaleX(0);
}
.menu-open .hamburger-line:nth-child(3) {
    transform: translateY(-8px) rotate(-45deg);
}

/* ===== Scrollbar hide for filter bar ===== */
.scrollbar-hide {
    -ms-overflow-style: none;
    scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
    display: none;
}

/* ===== Line clamp utilities ===== */
.line-clamp-1 {
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.line-clamp-2 {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* ===== DaisyUI card overrides to match original ===== */
.card-compact .card-body {
    padding: 1rem 1.5rem;
}

/* Override DaisyUI defaults that conflict */
.btn {
    text-transform: none;
}

/* ===== Submission Guidelines (rendered from TinyMCE HTML) ===== */
.guidelines-content { font-size: 0.875rem; color: #6b7280; line-height: 1.6; }
.guidelines-content h3 { font-family: 'Oswald', system-ui, sans-serif; font-size: 1rem; font-weight: 600; color: #062160; margin-bottom: 1rem; }
.guidelines-content h4 { font-size: 0.875rem; font-weight: 600; color: #062160; margin-bottom: 0.25rem; margin-top: 0; }
.guidelines-content h5 { font-size: 0.8rem; font-weight: 600; color: #062160; margin-bottom: 0.25rem; }
.guidelines-content p { margin-bottom: 0.75rem; }
.guidelines-content hr { border: none; border-top: 1px solid #e5e7eb; margin: 0.75rem 0; }
.guidelines-content a { color: #1E5DAB; text-decoration: none; }
.guidelines-content a:hover { text-decoration: underline; }
.guidelines-content table { width: 100%; font-size: 0.8rem; margin-bottom: 0.5rem; }
.guidelines-content table td { padding: 0.15rem 0.5rem 0.15rem 0; }
.guidelines-content table td:last-child { font-weight: 500; color: #062160; }
.guidelines-content ul, .guidelines-content ol { padding-left: 1.25rem; margin-bottom: 0.75rem; }
.guidelines-content li { margin-bottom: 0.25rem; }
.guidelines-content strong { color: #062160; }

/* ===== Form banner (shipmate-alert) =====
   A refined callout used at the top of the submission forms. Soft tinted
   background, left accent bar, muted typography that sits alongside the form
   card rather than shouting over it. */
.shipmate-alert {
    display: flex;
    align-items: flex-start;
    gap: 0.85rem;
    padding: 0.9rem 1.15rem;
    border-radius: 0.6rem;
    border: 1px solid var(--alert-border, #dbeafe);
    border-left-width: 4px;
    border-left-color: var(--alert-accent, #1E5DAB);
    background: var(--alert-bg, #f1f7ff);
    color: #1f2937;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
}
.shipmate-alert__icon {
    flex-shrink: 0;
    width: 1.25rem;
    height: 1.25rem;
    color: var(--alert-accent, #1E5DAB);
    margin-top: 2px;
}
.shipmate-alert__body {
    flex: 1;
    font-size: 0.9rem;
    line-height: 1.55;
    color: #374151;
}
.shipmate-alert__body > *:first-child { margin-top: 0; }
.shipmate-alert__body > *:last-child { margin-bottom: 0; }
.shipmate-alert__body p { margin: 0 0 0.4rem; }
.shipmate-alert__body strong { color: var(--alert-accent, #1E5DAB); font-weight: 600; }
.shipmate-alert__body a {
    color: var(--alert-accent, #1E5DAB);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
    font-weight: 600;
}
.shipmate-alert__body a:hover { text-decoration-thickness: 2px; }

.shipmate-alert--info     { --alert-accent: #1E5DAB; --alert-bg: #f1f7ff; --alert-border: #c9dcf7; }
.shipmate-alert--success  { --alert-accent: #0f766e; --alert-bg: #eefaf5; --alert-border: #b7e4cf; }
.shipmate-alert--warning  { --alert-accent: #b45309; --alert-bg: #fff8e7; --alert-border: #fadfa0; }
.shipmate-alert--error    { --alert-accent: #b91c1c; --alert-bg: #fff0f0; --alert-border: #f5c6c6; }

/* ===== TinyMCE fullscreen escape hatch =====
   `position: fixed` gets anchored to the nearest ancestor with a transform/filter,
   not the viewport, so any parent that Tailwind/GSAP has transformed will clip the
   fullscreen editor. When the fullscreen class is active we flatten ancestor
   transforms, lift overflow, and pin the editor container to the actual viewport. */
html.tox-fullscreen,
html.tox-fullscreen body {
    overflow: hidden !important;
}
html.tox-fullscreen .container,
html.tox-fullscreen .card,
html.tox-fullscreen .card-body,
html.tox-fullscreen aside,
html.tox-fullscreen .submit-form,
html.tox-fullscreen .scribe-form,
html.tox-fullscreen .scribe-sidebar,
html.tox-fullscreen .obit-form,
html.tox-fullscreen fieldset,
html.tox-fullscreen #form-fields,
html.tox-fullscreen #form-fields > * {
    transform: none !important;
    filter: none !important;
    perspective: none !important;
    overflow: visible !important;
}
.tox.tox-tinymce.tox-fullscreen {
    position: fixed !important;
    inset: 2.5rem !important;
    width: auto !important;
    height: auto !important;
    z-index: 2147483000 !important;
    border-radius: 0.5rem !important;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.35) !important;
}
html.tox-fullscreen body::before {
    content: "";
    position: fixed;
    inset: 0;
    background: rgba(6, 33, 96, 0.45);
    z-index: 2147482999;
    pointer-events: none;
}

/* ===== Submission loading overlay =====
   Shown when the user clicks Submit and validation passes. Blocks the entire
   viewport, signals progress, and reassures the user that the wait is normal.
   Toggled from the form submit handler in Submit.cshtml. */
.submit-overlay {
    position: fixed; inset: 0;
    display: flex; align-items: center; justify-content: center;
    padding: 1.25rem;
    background:
        radial-gradient(circle at 30% 0%, rgba(30,93,171,0.55) 0%, transparent 55%),
        linear-gradient(135deg, rgba(4,21,72,0.96) 0%, rgba(6,33,96,0.96) 50%, rgba(10,50,128,0.96) 100%);
    backdrop-filter: blur(4px);
    z-index: 2147482000;
    animation: submit-overlay-in 0.2s ease both;
}
@keyframes submit-overlay-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
.submit-overlay__card {
    background: #fff;
    border-radius: 16px;
    padding: 2rem 2.25rem 1.85rem;
    width: 100%; max-width: 420px;
    text-align: center;
    box-shadow: 0 30px 60px -15px rgba(0,0,0,0.45), 0 0 0 1px rgba(255,255,255,0.06);
    animation: submit-overlay-card 0.4s cubic-bezier(.2,.8,.2,1) both;
}
@keyframes submit-overlay-card {
    from { opacity: 0; transform: translateY(12px) scale(0.98); }
    to   { opacity: 1; transform: none; }
}
.submit-overlay__logo {
    height: 36px; width: auto; margin: 0 auto 1.25rem; display: block;
}
.submit-overlay__spinner {
    width: 56px; height: 56px;
    margin: 0 auto 1rem;
    animation: submit-overlay-spin 1.1s linear infinite;
}
.submit-overlay__spinner svg { width: 100%; height: 100%; display: block; }
@keyframes submit-overlay-spin {
    to { transform: rotate(360deg); }
}
.submit-overlay__title {
    font-family: 'Oswald', system-ui, sans-serif;
    font-size: 1.25rem; font-weight: 600; color: #062160;
    margin: 0 0 0.4rem;
}
.submit-overlay__sub {
    font-size: 0.875rem; color: #4b5563; margin: 0 0 0.6rem; line-height: 1.5;
}
.submit-overlay__hint {
    font-size: 0.7rem; color: #9ca3af; margin: 0;
    letter-spacing: 0.02em; text-transform: uppercase; font-weight: 500;
}

/* ===== SOP link (used in the Submit-page guidelines sidebar) ===== */
.sop-link {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.65rem 0.85rem;
    background: #eef5ff;
    border: 1px solid #c9dcf7;
    border-radius: 8px;
    color: #062160;
    font-size: 0.825rem;
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}
.sop-link:hover { background: #dceaff; border-color: #1E5DAB; }
.sop-link strong { color: #062160; font-weight: 600; }
.sop-link span { flex: 1; }
.sop-link__chev { color: #1E5DAB; }

/* ===== SOP page (markdown render + edit) =====
   Renders the markdown returned from /api/sop/{page}. Styling matches the
   rest of the magazine — Inter body, Oswald headings, navy/blue accents. */
.sop-doc {
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 8px 24px -8px rgba(6, 33, 96, 0.15);
    padding: 2rem 2.25rem;
    color: #1f2937;
    font-size: 0.95rem;
    line-height: 1.7;
}
@media (max-width: 640px) {
    .sop-doc { padding: 1.25rem 1.25rem; font-size: 0.9rem; }
}
.sop-doc h1, .sop-doc h2, .sop-doc h3, .sop-doc h4, .sop-doc h5 {
    font-family: 'Oswald', system-ui, sans-serif;
    color: #062160;
    font-weight: 600;
    line-height: 1.25;
}
.sop-doc h1 {
    font-size: 1.85rem;
    border-bottom: 3px solid #1E5DAB;
    padding-bottom: 0.6rem;
    margin: 0 0 1rem;
}
.sop-doc h2 {
    font-size: 1.4rem;
    margin: 2.25rem 0 0.75rem;
    padding-bottom: 0.4rem;
    border-bottom: 1px solid #e5e7eb;
}
.sop-doc h3 {
    font-size: 1.15rem;
    margin: 1.75rem 0 0.5rem;
    color: #0A3280;
}
.sop-doc h4 {
    font-size: 0.95rem;
    margin: 1.25rem 0 0.4rem;
    color: #374151;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.sop-doc p { margin: 0 0 1rem; }
.sop-doc strong { color: #062160; font-weight: 600; }
.sop-doc em { color: #374151; }
.sop-doc a {
    color: #1E5DAB; text-decoration: underline;
    text-underline-offset: 2px; text-decoration-thickness: 1px;
    font-weight: 500;
}
.sop-doc a:hover { color: #062160; text-decoration-thickness: 2px; }
.sop-doc ul, .sop-doc ol { margin: 0 0 1rem; padding-left: 1.5rem; }
.sop-doc li { margin-bottom: 0.35rem; }
.sop-doc li > p { margin-bottom: 0.35rem; }
.sop-doc hr {
    border: none; border-top: 1px solid #e5e7eb;
    margin: 2.25rem 0;
}
.sop-doc blockquote {
    border-left: 4px solid #FFD700;
    background: #fffbe6;
    padding: 0.85rem 1.1rem;
    margin: 1.25rem 0;
    border-radius: 0 8px 8px 0;
    color: #4b3a00;
    font-size: 0.9rem;
}
.sop-doc blockquote p { margin: 0 0 0.4rem; }
.sop-doc blockquote p:last-child { margin: 0; }
.sop-doc blockquote strong { color: #b45309; }
.sop-doc code {
    background: #eef5ff;
    color: #062160;
    padding: 0.1rem 0.4rem;
    border-radius: 4px;
    font-family: 'SF Mono', Consolas, Menlo, monospace;
    font-size: 0.85em;
}
.sop-doc pre {
    background: #062160; color: #e0ecff;
    padding: 1rem 1.15rem;
    border-radius: 8px;
    overflow-x: auto;
    font-size: 0.85rem;
    margin: 1.25rem 0;
}
.sop-doc pre code { background: transparent; padding: 0; color: inherit; }

.sop-doc table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    margin: 1.25rem 0;
    font-size: 0.875rem;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    overflow: hidden;
    background: #fff;
}
.sop-doc table thead th {
    background: #062160; color: #fff;
    text-align: left;
    font-family: 'Oswald', system-ui, sans-serif;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    font-size: 0.75rem;
    padding: 0.7rem 0.95rem;
}
.sop-doc table th, .sop-doc table td {
    padding: 0.65rem 0.95rem;
    border-bottom: 1px solid #f1f5f9;
    vertical-align: top;
}
.sop-doc table tr:last-child td { border-bottom: none; }
.sop-doc table tbody tr:nth-child(even) td { background: #fafbfc; }
.sop-doc table tbody tr:hover td { background: #eef5ff; }

.sop-loading {
    display: inline-flex; align-items: center; gap: 0.5rem;
    color: #6b7280; font-size: 0.9rem;
}
.sop-empty { text-align: center; padding: 2.5rem 1rem; color: #6b7280; }
.sop-empty h2 { color: #062160; margin: 0 0 0.5rem; font-family: 'Oswald', sans-serif; }

/* Toolbar buttons (header + editor toolbar share styles) */
.sop-btn {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.45rem 0.9rem;
    border-radius: 8px; border: 1px solid transparent; cursor: pointer;
    font-family: inherit; font-size: 0.82rem; font-weight: 600;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.05s ease;
}
.sop-btn:active { transform: translateY(1px); }
.sop-btn:disabled { opacity: 0.6; cursor: not-allowed; }
.sop-btn-ghost {
    background: rgba(255,255,255,0.08);
    border-color: rgba(255,255,255,0.18);
    color: #fff;
}
.sop-btn-ghost:hover { background: rgba(255,255,255,0.15); }
.sop-btn-gold {
    background: #FFD700; color: #062160;
    border-color: #C5A600;
}
.sop-btn-gold:hover { background: #ffe04a; }
.sop-btn-navy {
    background: #062160; color: #fff;
    border-color: #062160;
}
.sop-btn-navy:hover { background: #1E5DAB; border-color: #1E5DAB; }

/* Edit toolbar */
.sop-edit-toolbar {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.65rem 0.85rem;
    background: #f8fafc;
    border: 1px solid #e5e7eb;
    border-radius: 10px 10px 0 0;
    border-bottom: 0;
}
.sop-edit-toolbar .sop-btn-ghost {
    background: #fff; color: #4b5563; border-color: #d1d5db;
}
.sop-edit-toolbar .sop-btn-ghost:hover { background: #f3f4f6; color: #062160; }
.sop-status {
    margin-left: auto;
    font-size: 0.8rem; color: #6b7280;
}
.sop-status--ok { color: #047857; font-weight: 500; }
.sop-status--error { color: #b91c1c; font-weight: 500; }
.sop-edit-hint {
    font-size: 0.75rem; color: #9ca3af;
    margin: 0.5rem 0 0;
}

/* EasyMDE container override to match the toolbar */
.EasyMDEContainer {
    border: 1px solid #e5e7eb !important;
    border-radius: 0 0 10px 10px !important;
    background: #fff;
}
.EasyMDEContainer .CodeMirror {
    border: 0 !important;
    border-radius: 0 !important;
    font-family: 'SF Mono', Consolas, Menlo, monospace;
    font-size: 0.9rem;
    min-height: 520px;
}
.editor-toolbar {
    border: 0 !important; border-bottom: 1px solid #e5e7eb !important;
    background: #fafbfc !important;
}
.editor-toolbar button { color: #4b5563 !important; border-radius: 6px !important; }
.editor-toolbar button:hover, .editor-toolbar button.active {
    background: #eef5ff !important; border-color: #c9dcf7 !important;
}

@media print {
    header, footer, #view-as-dock, .sop-header button, #sop-editor-shell { display: none !important; }
    section.relative { padding: 0 !important; }
    section.relative .absolute { display: none !important; }
    .sop-header { color: #062160 !important; }
    .sop-header h1, .sop-header p { color: #062160 !important; }
    .sop-doc { box-shadow: none; border: 1px solid #e5e7eb; }
}

/* ===== Word count badge =====
   Pill-style indicator that sits below the story editor. Default styling
   uses the navy/blue palette; flips to amber when within 10% of the limit
   and red when over. Color is driven by classes so callers can stay out of
   inline styles. */
.word-count-badge {
    display: inline-flex;
    align-items: center;
    padding: 0.4rem 0.85rem;
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.2;
    border-radius: 9999px;
    background: #eef5ff;
    color: #062160;
    border: 1px solid #c9dcf7;
    letter-spacing: 0.01em;
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.word-count-badge.is-warning {
    background: #fff8e7;
    color: #92400e;
    border-color: #fadfa0;
}
.word-count-badge.is-error {
    background: #fff0f0;
    color: #b91c1c;
    border-color: #f5c6c6;
}
.word-count-details {
    font-size: 0.8rem;
    color: #4b5563;
    font-weight: 500;
}
.word-count-details.is-error { color: #b91c1c; }

/* ===== Attachments dropzone =====
   Drag-and-drop card used on the submit/obituary forms. Hidden <input type="file">
   sits inside; the visible UI is driven by attachments.js. */
.attachments-dropzone {
    position: relative;
    border: 2px dashed #cbd5e1;
    border-radius: 0.75rem;
    background: #fafbfc;
    padding: 1rem;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
.attachments-dropzone.is-dragover {
    border-color: #1E5DAB;
    background: #eef5ff;
}
.attachments-dropzone .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;
}
.attachments-prompt {
    text-align: center;
    padding: 1.5rem 0.75rem;
    cursor: pointer;
    border-radius: 0.5rem;
    transition: background-color 0.15s ease;
}
.attachments-prompt:hover { background: rgba(30, 93, 171, 0.04); }
.attachments-prompt__icon {
    width: 2.5rem; height: 2.5rem;
    margin: 0 auto 0.5rem;
    color: #1E5DAB;
    opacity: 0.7;
}
.attachments-prompt__title {
    font-size: 0.95rem; font-weight: 600;
    color: #062160; margin: 0 0 0.15rem;
}
.attachments-prompt__sub { font-size: 0.8rem; color: #6b7280; margin: 0; }
.attachments-prompt__hint { font-size: 0.7rem; color: #9ca3af; margin: 0.4rem 0 0; }
.attachments-browse-link {
    color: #1E5DAB; font-weight: 600;
    background: none; border: 0; padding: 0; cursor: pointer;
    text-decoration: underline; text-underline-offset: 2px;
}
.attachments-browse-link:hover { color: #062160; }
.attachments-prompt--compact { padding: 0.5rem 0.75rem; }
.attachments-prompt--compact .attachments-prompt__icon { width: 1.5rem; height: 1.5rem; margin-bottom: 0.25rem; }
.attachments-prompt--compact .attachments-prompt__title { font-size: 0.8rem; font-weight: 500; color: #6b7280; }
.attachments-prompt--compact .attachments-prompt__sub { font-size: 0.75rem; }
.attachments-prompt--compact .attachments-prompt__hint { display: none; }

.attachments-list {
    list-style: none; padding: 0; margin: 0 0 0.75rem;
    display: flex; flex-direction: column; gap: 0.5rem;
}
.attachment-item {
    display: grid;
    grid-template-columns: 36px 1fr auto;
    gap: 0.75rem;
    align-items: center;
    padding: 0.6rem 0.75rem;
    background: #ffffff;
    border: 1px solid #e5e7eb;
    border-radius: 0.5rem;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
.attachment-item--error {
    border-color: #fca5a5;
    background: #fff7f7;
}
.attachment-icon {
    display: flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    border-radius: 0.4rem;
    background: #eef5ff;
    color: #1E5DAB;
}
.attachment-item--error .attachment-icon { background: #fef2f2; color: #b91c1c; }
.attachment-body { min-width: 0; }
.attachment-title {
    display: flex; align-items: baseline; gap: 0.5rem;
    font-size: 0.875rem; font-weight: 500; color: #1f2937;
    min-width: 0;
}
.attachment-name {
    flex: 1; min-width: 0;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.attachment-size {
    font-size: 0.7rem; color: #9ca3af; flex-shrink: 0;
}
.attachment-status { display: block; font-size: 0.72rem; margin-top: 0.1rem; }
.attachment-status--muted { color: #6b7280; }
.attachment-status--ok    { color: #047857; }
.attachment-status--error { color: #b91c1c; font-weight: 500; }
.attachment-progress {
    display: block; width: 100%; height: 4px; margin-top: 0.4rem;
    appearance: none; -webkit-appearance: none;
    border: 0; border-radius: 9999px; overflow: hidden;
    background: #e5e7eb;
}
.attachment-progress::-webkit-progress-bar { background: #e5e7eb; border-radius: 9999px; }
.attachment-progress::-webkit-progress-value { background: #1E5DAB; transition: width 0.2s ease; border-radius: 9999px; }
.attachment-progress::-moz-progress-bar { background: #1E5DAB; border-radius: 9999px; }
.attachment-remove {
    background: none; border: 0; cursor: pointer;
    padding: 0.4rem; border-radius: 0.4rem;
    color: #9ca3af;
    display: flex; align-items: center; justify-content: center;
    transition: color 0.15s ease, background-color 0.15s ease;
}
.attachment-remove:hover { color: #b91c1c; background: #fef2f2; }
.attachment-remove:focus-visible { outline: 2px solid #1E5DAB; outline-offset: 2px; }

@media (max-width: 480px) {
    .attachment-item {
        grid-template-columns: 32px 1fr auto;
        gap: 0.5rem;
        padding: 0.55rem 0.6rem;
    }
    .attachment-icon { width: 32px; height: 32px; }
    .attachment-title { flex-wrap: wrap; }
    .attachment-size { font-size: 0.65rem; }
}

/* ===== GSAP fallback: ensure elements are visible if animation doesn't fire ===== */
@keyframes ensure-visible { to { opacity: 1; } }
.page-header, .info-card, .form-card, .login-header, .login-card,
.submit-header, .submit-form, .success-content, .article-image,
.scribe-header, .scribe-sidebar, .scribe-form,
.memorial-header, .memorial-card, .memorial-hero, .memorial-paragraph, .memorial-image, .memorial-body,
.issues-header, .issue-featured, .issues-archive, .issue-card,
.sop-header, .sop-content {
    animation: ensure-visible 0s 1.5s forwards;
}

/* Skip link — first thing in the tab order, invisible until focused.
   Lives in site.css because _SiteHeader is shared by every layout. */
.site-skiplink {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    background: #FFD700;
    color: #062160;
    font: 600 13px 'Inter', system-ui, sans-serif;
    padding: .6rem 1rem;
    text-decoration: none;
    border-radius: 0 0 6px 0;
}

.site-skiplink:focus {
    left: 0;
}

/* ===== Obituary form — destination choice =====
   The two cards on /submit-obituary. LAYOUT is done in Tailwind utilities on the element itself,
   not here: Tailwind comes from the CDN and is always current, while this file can be a cached
   copy, and a card whose flex row has not arrived collapses into a radio stacked above its own
   label. What is left here is only the selected/hover tint, which degrades to nothing. */
.obit-choice { transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease; }
.obit-choice:hover { border-color: #c7cdd6; background: #fcfcfd; }
.obit-choice:has(input:checked) {
  border-color: #062160;
  background: rgba(6, 33, 96, 0.04);
  box-shadow: inset 0 0 0 1px #062160;
}
.obit-choice:has(input:focus-visible) { outline: 2px solid rgba(6, 33, 96, .4); outline-offset: 2px; }
.obit-choice em { font-style: italic; }

/* ===== Obituary proof — the draft a family reads before it runs =====
   Set the way it will actually be published, because the point of showing it is that they can see
   what will appear. The print variant carries the house style: Times New Roman, italics, and ship
   names in small caps with the USS dropped — "if that's not there, you lose the visual that
   indicates it's a ship". */
.obit-proof { font-size: 1rem; line-height: 1.7; color: #1a1a1a; }
.obit-proof p { margin: 0 0 1rem 0; }
.obit-proof p:last-child { margin-bottom: 0; }
.obit-proof--print {
  font-family: 'Times New Roman', Times, serif;
  font-size: 1.05rem;
  border: 1px solid #e5e7eb;
  border-left: 3px solid #062160;
  background: #fcfcfd;
  padding: 1.25rem 1.5rem;
}
.obit-proof .obit-smallcaps,
.obit-proof--print .obit-smallcaps {
  font-variant-caps: small-caps;
  font-variant: small-caps;
  letter-spacing: .02em;
}

/*  The obituary form with its sidebar scoped away.

    The sidebar holds the Last Call house rules, which only apply to a print submission, so on the
    website branch it is hidden. The grid it left behind is still five columns wide with the form
    pinned to three of them — so without this the form renders hard against a 500px hole where the
    sidebar used to be, which reads as a broken page rather than a shorter one.

    It takes the full grid back and re-centres at a readable measure. Not stretched: a form field
    the width of a 2560px monitor is worse than the hole was. */
@media (min-width: 1024px) {
  .obit-layout--solo > .obit-form {
    grid-column: 1 / -1;
    max-width: 54rem;
    width: 100%;
    /*  justify-self, not margin-inline:auto. A grid item defaults to justify-self:stretch, and a
        max-width that stops it stretching leaves it packed at the start of the track rather than
        centred — which just moves the empty column from the left to the right. */
    justify-self: center;
  }
}

/*  The obituary chooser — the step before the form.

    Timothy and Luke replaced the in-form destination toggle with this on 2026-08-21: the choice
    governs half the questions, so it belongs before them rather than as the first of them. Cards
    rather than radios because these are two different errands, not two settings. */
.obit-path { text-decoration: none; color: inherit; }
.obit-path-kicker {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: .68rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  /*  Was #8a8f98, which is 3.25:1 on white and fails WCAG 1.4.3 at this size.
      These two kickers - "Most people start here" and "Just letting us know" -
      are the labels that tell a family which of the two paths to take, on the
      form whose address is being printed in the magazine. Uppercase at .68rem
      with .18em tracking is already hard work to read; faint as well is worse.
      #5c6169 clears 4.5:1 and keeps the same cool grey. */
  color: #5c6169;
}
.obit-path-go {
  display: inline-block;
  margin-top: 1rem;
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: .78rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #062160;
}
.obit-path:hover .obit-path-go { color: #1E5DAB; }

/*  Where they are, once they have chosen. A statement with a way back, not a control — the value
    is re-derived server-side on every post, so this cannot be argued with from the page. */
.obit-chosen {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .85rem 1.1rem;
  background: #f4f6f9;
  border: 1px solid #e3e6ea;
  border-radius: .5rem;
}
.obit-chosen-kicker {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: .62rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: #8a8f98;
}
.obit-chosen-title { font-weight: 600; color: #062160; }
/*  "Change" — the way back out of a chosen path. Measured 48x20 on a phone, under WCAG 2.2
    SC 2.5.8's 24px minimum, and it is the control somebody reaches for when they realise they
    picked the wrong form. Padded to 24px rather than set larger: it should stay quieter than the
    destination it sits beside. The negative inline-end margin keeps the text on the same optical
    edge it had before the padding. */
.obit-chosen-change {
  margin-left: auto;
  margin-right: -.4rem;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: .25rem .4rem;
  font-size: .82rem;
  color: #1E5DAB;
  text-decoration: underline;
}

/*  "Also post on the website". Sits under the destination because it is the one place the two
    destinations still meet. */
.obit-also {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  margin-top: .9rem;
  padding: .85rem 1.1rem;
  border: 1px solid #e3e6ea;
  border-radius: .5rem;
  cursor: pointer;
}
.obit-also:hover { border-color: #062160; }
.obit-also-title { display: block; font-weight: 600; color: #062160; }
.obit-also-note {
  display: block;
  font-size: .84rem;
  color: #6b7280;
  line-height: 1.45;
  margin-top: .15rem;
}

/*  The obituary form as one column.

    It was a two-column grid with the rules in a sticky sidebar. Scoping the sidebar to the print
    branch left the form pinned beside an empty third of the page, which then needed its own rule to
    reclaim the space — a lot of machinery to make a column vanish tidily. Reading the guidance
    first is simpler and better: the rules that decide what somebody should write belong before the
    box they write it in. */
.obit-single {
  max-width: 52rem;
  margin-inline: auto;
}

/*  Guidance, set as a quiet preface rather than a card competing with the form. The left rule is
    the same navy used for the section headings, so it reads as part of the same document. */
.obit-guide {
  margin-bottom: 2rem;
  padding: 1.35rem 1.5rem;
  background: #f7f9fc;
  border-left: 3px solid #062160;
  border-radius: 0 .5rem .5rem 0;
}
.obit-guide-title {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: .78rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #062160;
  margin: 0 0 .75rem;
}
/*  The copy is editor-authored HTML from Bridge, so it is styled by tag rather than by class —
    whatever headings and lists they write have to land somewhere sensible. */
.obit-guide-body > *:first-child { margin-top: 0; }
.obit-guide-body > *:last-child  { margin-bottom: 0; }
.obit-guide-body h3 {
  font-family: 'Oswald', system-ui, sans-serif;
  font-size: .95rem;
  font-weight: 600;
  color: #062160;
  margin: 1rem 0 .4rem;
}
.obit-guide-body h3:first-child { margin-top: 0; }

/* ==========================================================================
   The 2026-09-01 client review — shared page furniture

   Four of that meeting's asks are not page-level at all; they are one piece of
   furniture used everywhere, and each was being re-declared per page. They live
   here so there is a single place to change them:

     the bounding box      the one content box every page sits inside
     the page ground       off pure white
     the colophon          one minimal footer, site-wide
     back / title states   one padded back control, one hover colour

   Every colour below is measured against WCAG 2.2 SC 1.4.3 (4.5:1 for body
   text) rather than eyeballed; the ratios are written next to each one.
   ========================================================================== */

/*  ---------------------------------------------------------- bounding box

    Derrick, 2026-09-01: "one thing we're doing is scooting this here, this
    edge, to align with this home here. That's going to be our sort of bounding
    box across the board."

    The main site has always had that box — Tailwind's `.container mx-auto px-4
    lg:px-8`, which is what the header, the footer and every page section use.
    What did not sit on it was anything written outside Tailwind, the Never
    Forgotten section most of all: it built its own box from a clamp() gutter
    and a single 1536px cap, so at a 1400px window the memorial's content
    started at x=40 while the chrome above it started at x=92. Same page, two
    left edges.

    Tailwind's container is not a clamp — it is a max-width that STEPS at each
    breakpoint — so nothing that approximates it with a smooth function can line
    up with it at more than one width. These custom properties restate the real
    steps, so a plain stylesheet can sit on the identical grid by construction.

    --page-content is the box itself: min(available, the step) less the same
    padding the container applies. Applied with margin-inline:auto rather than
    padding, so the element's own box IS the content box — anything positioned
    against it (the memorial's back link is absolute) still lands on the edge. */
:root {
    --page-max: 100%;
    --page-pad: 1rem; /* Tailwind px-4 */
    --page-content: min(100% - var(--page-pad) * 2, calc(var(--page-max) - var(--page-pad) * 2));
}

@media (min-width: 640px) {
    :root {
        --page-max: 640px;
    }
}

@media (min-width: 768px) {
    :root {
        --page-max: 768px;
    }
}

@media (min-width: 1024px) {
    :root {
        --page-max: 1024px;
        --page-pad: 2rem; /* Tailwind lg:px-8 */
    }
}

@media (min-width: 1280px) {
    :root {
        --page-max: 1280px;
    }
}

@media (min-width: 1536px) {
    :root {
        --page-max: 1536px;
    }
}

/*  Anything outside Tailwind that wants the site's bounding box asks for it
    here rather than re-deriving it. */
.site-page {
    width: var(--page-content);
    margin-inline: auto;
}

/*  --------------------------------------------------------- the page ground

    Alex, 2026-09-01: "that white kind of hurts my eyes a little... maybe they
    get a little bit more gray than bright white."

    #F2F3F5 rather than the existing usna.gray #F5F5F5, which is barely off
    white; this is a step further and still reads as paper rather than as a
    panel. Cards keep `bg-white`, so the grey is the ground BETWEEN them, which
    is what gives the page its separation.

    Measured against everything that sits directly on it:
      #062160 navy body text      13.57:1   (AA and AAA)
      #4b5563 gray-600             6.80:1
      #626b7a (see below)          4.85:1

    The one casualty was Tailwind's gray-500 #6b7280. It clears 4.5:1 on pure
    white by a hair — 4.86:1 — and nothing else, so ANY move off white fails it:
    it needs a ground of at least L=0.9215 (about #F6F6F6) to hold AA, and that
    is not a grey anyone would notice. Rather than pick an invisible grey,
    gray-500 is darkened one notch instead. It is a single rule, it applies
    everywhere the class is used, and it is darker — so it also improves the
    white cards it appears on, where it was 4.86:1 and is now 5.38:1. */
:root {
    --page-ground: #F2F3F5;
}

/*  On <body>, replacing the `bg-white` both layouts carried. A class rather
    than a Tailwind arbitrary value so the token stays the single source. */
.site-ground {
    background-color: var(--page-ground);
}

/*  Beats the Tailwind Play CDN's own `.text-gray-500` on specificity rather
    than on document order: the CDN injects its stylesheet into <head> at
    runtime, so it lands after this file and would win a tie. */
body .text-gray-500 {
    color: #626b7a;
}

/*  ------------------------------------------------------------- the colophon

    Derrick, 2026-09-01: "I made this new footer here to match the Never
    Forgotten... that will be consistent across everything." Luke: "should
    change the footer across the entire [site]."

    So the memorial's minimal charcoal row is now the site's only footer, and
    the navy block with the logo, the tagline, the link row and the divider is
    gone. The links it carried — Articles, Contribute, Issues, In Memoriam —
    are every one of them in the header nav under the same permissions, so
    nothing became unreachable by losing them here.

    Derrick also asked for the thumbnail to go: "I think we can even remove that
    small thumbnail." That was the 28px shipmate-logo-white.png, and it is what
    made the old footer read as chrome rather than as a colophon.

    One layout at every width. The old footer had a responsive variant and so
    arrived as a 256px centred stack on a phone and a 188px spread row on a
    desktop — the same element reading as two different objects. This is small
    enough at any width that it never needs to become something else.

    Colours are the memorial's own tokens, restated here because this sheet
    loads on pages that never see never-forgotten.css. On #1b1e24:
      #a6a294 copy    6.53:1
      #948f83 links   5.18:1
      #c9a24b hover   6.96:1  */
:root {
    --colophon-ground: #1b1e24;
    --colophon-ink: #a6a294;
    --colophon-link: #948f83;
    --colophon-link-hover: #c9a24b;
}

.site-colophon {
    flex: 0 0 auto;
    display: flex;
    flex-wrap: wrap;
    gap: 0 1.5rem;
    justify-content: center;
    padding: .55rem clamp(1rem, 4vw, 2.5rem);
    background: var(--colophon-ground);
    font: 400 12px/1.6 'Inter', system-ui, -apple-system, sans-serif;
    letter-spacing: .04em;
    color: var(--colophon-ink);
}

/*  WCAG 2.2 SC 2.5.8 wants a 24x24 target. At 12px these links measured 17px
    tall in the geometry audit, so the BOX is padded up to the minimum rather
    than the type being enlarged — the type size is fine, the hit area was not.
    Vertical padding only, so the row keeps its height and reads as before.

    Dropping the thumbnail made this more important, not less: what is left is
    text-only links with nothing tall beside them to set the row height. */
.site-colophon > span,
.site-colophon a {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
    padding-block: .45rem;
}

.site-colophon a {
    color: var(--colophon-link);
    text-decoration: none;
    transition: color .2s ease;
}

    .site-colophon a:hover,
    .site-colophon a:focus-visible {
        color: var(--colophon-link-hover);
    }

/*  --------------------------------------------------------- the home hero

    Luke, 2026-09-01: "can we also shorten the hero image so that way... I just
    want to make sure that they see there's content underneath of it."
    Derrick's answer is the spec: "We can adjust this based on viewport
    height... right now I believe it's based on pixels. We can make it so that
    it forces to be say, viewport height is like the percentage of this. So this
    is like 55, 60 percent."

    It was indeed pixels — the hero had no height of its own, so it was however
    tall the logo (h-16/h-24/h-32) plus the copy and the buttons happened to be.
    On a tall monitor that left it short and floating; on a laptop it filled the
    fold. Either way its relationship to the fold was accidental.

    58% of the viewport, with the header's 112px above it, puts the bottom of
    the hero about two-thirds of the way down whatever screen it is on, so there
    is always something visible below it. That is the whole ask.

    dvh, not vh: on a phone vh is the LARGEST viewport — the one with the
    browser chrome retracted — so a vh-sized hero is taller than the space
    actually on screen until you scroll. vh is declared first as the fallback
    for anything that does not know dvh.

    Clamped at both ends. 58dvh on its own collapses to 217px on a landscape
    phone, shorter than the content inside it; the 20rem floor and the 34rem
    ceiling keep it a hero at both extremes. min-height rather than height, so
    the content can always grow past it instead of being clipped. */
.home-hero {
    display: grid;
    align-content: center;
    min-height: clamp(20rem, 58vh, 34rem);
}

@supports (height: 1dvh) {
    .home-hero {
        min-height: clamp(20rem, 58dvh, 34rem);
    }
}

/*  ------------------------------------------------------- the back control

    Luke, 2026-09-01: "We also standardized the spacing of the back button."

    Every back link on the site had its own padding, or none: the article hero's
    was a pill at px-3/py-1, the one at the foot of the article was bare text
    with no box at all, and the memorial's was bare text too. One shape and one
    padding wherever the word "back" appears.

    The padding is also what makes it a real target — bare 13px text is a 17px
    tall hit area, under the 24x24 that SC 2.5.8 asks for.

    Shape and spacing only, deliberately: colour stays with the call site,
    because the same control sits on a photograph in one place and on paper in
    another. A hover background here would win on specificity over the
    `bg-black/20` the article-hero pill sets and wash it out over the image. */
.site-back {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    min-height: 24px;
    padding: .5rem .85rem;
    border-radius: 9999px;
    text-decoration: none;
    transition: color .2s ease, background-color .2s ease;
}

/*  ---------------------------------------------------------- title on hover

    Derrick, 2026-09-01: "when we hover here, make the title gold as well."
    Card and list titles hovered to usna-blue; they go gold now.

    #B8860B is the site's gold and it is already in use — Pages/InMemoriam.cshtml
    sets it on .lastcall-title — but it measures 3.25:1 on white and 2.93:1 on
    the new ground. These titles are 16-18px semibold, which is not "large
    scale" under WCAG 2.2 (that needs 18.66px BOLD, or 24px), so they need the
    full 4.5:1 and #B8860B cannot give it. A hover state is text like any other;
    the success criterion has no exemption for it.

    --shipmate-gold-ink is the same colour two steps down the X11 darkgoldenrod
    ramp that #B8860B itself comes from, so it is that gold rather than a new
    one invented for the occasion:
      #8B6508 on white    5.30:1
      #8B6508 on #F2F3F5  4.77:1
    #B8860B stays as the token for display-size and decorative use, which is
    what it was already doing. */
:root {
    --shipmate-gold: #B8860B;
    --shipmate-gold-ink: #8B6508;
}

.title-gold {
    transition: color .25s ease;
}

.group:hover .title-gold,
.group:focus-visible .title-gold,
.group:focus-within .title-gold {
    color: var(--shipmate-gold-ink);
}

/*  The memorial's serif, owned here.

    site.css is the one stylesheet BOTH layouts load, so a token both the
    memorial and the main site need belongs in it — the same reasoning that put
    --shipmate-gold here. never-forgotten.css reads --nf-serif from this rather
    than declaring the stack a second time. The face itself is requested by
    _MemorialLayout. A token is not a font. */
:root {
    --memorial-serif: 'EB Garamond', Georgia, 'Times New Roman', serif;
}

/* ===== Article reading column =====
   Everything tools/import-issue can emit into an article's body. The values are
   the ones the hand-set article template used (paragraph: text-sm/base/lg,
   leading-7/8, navy at 85%; figure: rounded-lg, shadow-lg, centred caption with
   the credit in grey italic), moved here because the body is now generated HTML
   rather than markup in the page. */
.article-prose {
    color: rgb(6 33 96 / 0.85);
    font-size: 0.875rem;
    line-height: 1.75rem;
}
@media (min-width: 640px)  { .article-prose { font-size: 1rem;     line-height: 2rem; } }
@media (min-width: 1024px) { .article-prose { font-size: 1.125rem; line-height: 2rem; } }

.article-prose p,
.article-prose ul,
.article-prose ol { margin: 0 0 1.25rem; }
@media (min-width: 640px) { .article-prose p, .article-prose ul, .article-prose ol { margin-bottom: 1.5rem; } }

.article-prose ul { list-style: disc;    padding-left: 1.5rem; }
.article-prose ol { list-style: decimal; padding-left: 1.5rem; }
.article-prose li { margin-bottom: 0.5rem; }
.article-prose strong { color: #062160; font-weight: 600; }
/* Addresses and emails print spelled out; the importer turns them into links. */
.article-prose a,
.article-hero-caption a {
    color: #1E5DAB;
    text-decoration: underline;
    text-underline-offset: 2px;
    overflow-wrap: anywhere;
}
.article-prose a:hover,
.article-hero-caption a:hover { color: #062160; }

/* A sponsor ad (Pages/Articles/_ArticleAd) is one link around a designed block: not a text link. */
.article-prose .article-ad a { color: inherit; text-decoration: none; overflow-wrap: normal; }

.article-prose h2 {
    font-family: 'Oswald', system-ui, sans-serif;
    font-weight: 600;
    font-size: 1.25rem;
    line-height: 1.3;
    color: #062160;
    margin: 2.25rem 0 0.75rem;
}
@media (min-width: 640px) { .article-prose h2 { font-size: 1.5rem; } }

.article-prose h3,
.article-prose h4 {
    font-weight: 600;
    color: #062160;
    line-height: 1.35;
    margin: 1.75rem 0 0.5rem;
}
.article-prose h3 { font-size: 1.125rem; }
.article-prose h4 { font-size: 1rem; }

/* Ship names: print sets them in small caps, and so does the web. */
.article-prose .smallcaps,
.article-hero-caption .smallcaps { font-variant: small-caps; }

/* Editor's note and series standfirst: above the copy, italic, ruled. */
.article-prose .article-note {
    font-style: italic;
    color: rgb(6 33 96 / 0.75);
    border-left: 3px solid #FFD700;
    padding-left: 1rem;
    margin: 0 0 1.75rem;
}
.article-prose .article-note p { margin: 0; }

.article-prose .article-quote {
    border-left: 3px solid #1E5DAB;
    padding: 0.25rem 0 0.25rem 1.25rem;
    margin: 1.75rem 0;
}
.article-prose .article-quote p { margin: 0 0 0.5rem; color: #062160; }
.article-prose .article-quote footer { font-size: 0.875rem; line-height: 1.5; color: rgb(6 33 96 / 0.7); }

/* A quote with its speaker's headshot beside it. */
.article-prose .article-quote.has-portrait {
    display: flex;
    gap: 1rem;
    align-items: flex-start;
}
.article-prose .article-portrait {
    width: 4.5rem;
    height: 4.5rem;
    flex-shrink: 0;
    border-radius: 9999px;
    object-fit: cover;
    object-position: top;
}
@media (min-width: 640px) { .article-prose .article-portrait { width: 5.5rem; height: 5.5rem; } }

/* width:100% is load-bearing, as on the memorial: a lazy image with no definite
   width computes to 0x0, never intersects the viewport and is never fetched.
   A portrait gets a narrower definite width instead of a max-height, which would
   squash it; its width/height attributes still give the browser the ratio. */
.article-prose .article-figure { margin: 2rem auto; clear: both; text-align: center; }
.article-prose .article-figure img {
    display: block;
    width: 100%;
    height: auto;
    margin-inline: auto;
    border-radius: 0.5rem;
    box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
}
.article-prose .article-figure img.is-square   { width: min(100%, 30rem); }
.article-prose .article-figure img.is-portrait { width: min(100%, 24rem); }
.article-prose .article-sidebar .article-figure img.is-square,
.article-prose .article-sidebar .article-figure img.is-portrait { width: min(100%, 20rem); }

/* Several photos at one spot: a row, each cell sized by the grid. */
.article-prose .article-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: 1rem;
    margin: 2rem 0;
}
.article-prose .article-gallery .article-figure { margin: 0; }
.article-prose .article-gallery .article-figure img { width: 100%; }
/* Portraits in one row share a shape, so a narrower original does not stand taller than its neighbours. */
.article-prose .article-gallery .article-figure img.is-portrait { aspect-ratio: 4 / 5; object-fit: cover; object-position: top; }
.article-prose .article-figure figcaption,
.article-hero-caption {
    margin-top: 0.75rem;
    font-size: 0.75rem;
    line-height: 1.4;
    color: rgb(6 33 96 / 0.7);
}
@media (min-width: 640px) {
    .article-prose .article-figure figcaption,
    .article-hero-caption { font-size: 0.875rem; }
}
.article-prose .article-credit,
.article-hero-caption .article-credit {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.6875rem;
    font-style: italic;
    color: #626b7a; /* 4.85:1 on the page ground (#F2F3F5), 5.38:1 on white; #6b7280 measured 4.35:1 (WCAG 1.4.3) */
}
.article-hero-caption { margin: -1rem 0 2rem; padding: 0 0.25rem; }

/* Article banner. The photograph keeps its colour: a short navy shade at the top
   keeps the white back link legible on a bright sky, and the bottom third
   blends into the page ground, where the header card overlaps it. The fade is
   eased through several stops; a straight two-stop ramp reads as a hard band.
   Derrick, 2026-10-27: the first cut (14%) was "too narrow". The card's
   overlap was cut at the same time (-mt-32 to -mt-20 at desktop) so less of the
   picture sits behind it. */
.article-hero-scrim {
    background:
        linear-gradient(to bottom, rgb(6 33 96 / 0.45) 0%, rgb(6 33 96 / 0) 22%),
        linear-gradient(to top,
            var(--page-ground) 0%,
            color-mix(in srgb, var(--page-ground) 85%, transparent) 10%,
            color-mix(in srgb, var(--page-ground) 50%, transparent) 22%,
            color-mix(in srgb, var(--page-ground) 15%, transparent) 32%,
            transparent 40%);
}

/* ===== Listen to this story =====
   The one dark object on a light page: a navy plate in the site's own colours,
   gold for everything that moves. A plain timeline, with a tick on the rail for
   each section. The dock shares the plate's colours. */
.listen,
.listen-dock {
    --listen-ink: #fff;
    --listen-dim: rgb(255 255 255 / 0.62);
    --listen-rail: rgb(255 255 255 / 0.4); /* ~3.4:1 on the navy plate: the slider must be visible before it is used (WCAG 1.4.11) */
    --listen-gold: #FFD700;
}
/* clip, not hidden: section labels must not widen a phone's page, and clip does
   not make the plate a scroll container. */
.listen {
    overflow: clip;
    background:
        radial-gradient(120% 140% at 0% 0%, #0A3280 0%, transparent 55%),
        #062160;
    color: var(--listen-ink);
    border-radius: 1rem;
    padding: 1.1rem 1.1rem 0.9rem;
    box-shadow: 0 18px 40px -18px rgb(6 33 96 / 0.55);
}
@media (min-width: 640px) { .listen { padding: 1.4rem 1.6rem 1.1rem; } }

.listen-row { display: flex; align-items: center; gap: 0.9rem; }
@media (min-width: 640px) { .listen-row { gap: 1.1rem; } }

.listen-play {
    flex-shrink: 0;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: 9999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--listen-gold);
    color: #062160;
    box-shadow: 0 0 0 0 rgb(255 215 0 / 0.45);
    transition: transform .18s ease, box-shadow .3s ease;
}
.listen-play:hover { transform: scale(1.05); }
.listen-play:active { transform: scale(0.96); }
.listen-play svg[data-audio-play-icon] { margin-left: 2px; }
/* While it plays, one slow ring breathes out from the button: the only motion on
   the plate that is not answering a click. */
.listen.is-playing .listen-play { animation: listen-breathe 2.4s ease-out infinite; }
@keyframes listen-breathe {
    0%   { box-shadow: 0 0 0 0 rgb(255 215 0 / 0.45); }
    100% { box-shadow: 0 0 0 14px rgb(255 215 0 / 0); }
}
.listen-play--small { width: 2.5rem; height: 2.5rem; }

.listen-meta { flex: 1; min-width: 0; }
.listen-title {
    font-family: 'Oswald', system-ui, sans-serif;
    font-weight: 500;
    font-size: 1.05rem;
    line-height: 1.2;
    letter-spacing: 0.01em;
}
@media (min-width: 400px) { .listen-title { font-size: 1.2rem; } }
@media (min-width: 640px) { .listen-title { font-size: 1.35rem; } }
.listen-sub {
    display: flex;
    flex-wrap: wrap;
    column-gap: 0.9rem;
    margin-top: 0.15rem;
    font-size: 0.75rem;
    color: var(--listen-dim);
}

.listen-tools { display: flex; gap: 0.4rem; flex-shrink: 0; }
.listen-tool {
    min-width: 2.6rem;
    height: 2.25rem;
    padding: 0 0.6rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.2rem;
    border-radius: 9999px;
    border: 1px solid rgb(255 255 255 / 0.22);
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    transition: background-color .2s ease, border-color .2s ease;
}
.listen-tool:hover { background: rgb(255 255 255 / 0.08); border-color: rgb(255 255 255 / 0.4); }
@media (max-width: 420px) { .listen-tool[data-audio-back] span { display: none; } }

.listen-play:focus-visible,
.listen-tool:focus-visible,
.listen-track:focus-visible,
.listen-mark:focus-visible { outline: 2px solid #FFD700; outline-offset: 3px; }

/* The timeline: a 5px rail, gold up to the play position, a knob at the head.
   28px of hit area around it (WCAG 2.5.8). Section ticks sit on the rail and
   turn gold once the narration has passed them. */
.listen-timeline { position: relative; margin-top: 1.1rem; }
.listen-track {
    position: relative;
    height: 28px;
    cursor: pointer;
}
.listen-rail {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 5px;
    margin-top: -2.5px;
    border-radius: 9999px;
    background: var(--listen-rail);
    overflow: hidden;
}
.listen-fill {
    height: 100%;
    width: 0;
    background: var(--listen-gold);
    border-radius: 9999px;
}
.listen-knob {
    position: absolute;
    top: 50%;
    left: 0;
    width: 14px;
    height: 14px;
    margin: -7px 0 0 -7px;
    border-radius: 9999px;
    background: #fff;
    box-shadow: 0 0 0 3px rgb(255 215 0 / 0.9), 0 2px 6px rgb(0 0 0 / 0.35);
    opacity: 0;
    transform: scale(.6);
    transition: opacity .2s ease, transform .2s ease;
    pointer-events: none;
}
.listen.is-started .listen-knob,
.listen-track:hover .listen-knob,
.listen-track:focus-visible .listen-knob { opacity: 1; transform: scale(1); }
.listen-track:hover .listen-rail { background: rgb(255 255 255 / 0.55); }

/* Ticks are their own 24px buttons centred on the rail, above the track's hit area. */
.listen-chapters { position: absolute; inset: 0; pointer-events: none; }
.listen-mark {
    position: absolute;
    top: 50%;
    width: 24px;
    height: 24px;
    margin: -12px 0 0 -12px;
    display: grid;
    place-items: center;
    pointer-events: auto;
}
.listen-mark::before {
    content: "";
    width: 3px;
    height: 13px;
    border-radius: 2px;
    background: rgb(255 255 255 / 0.55);
    box-shadow: 0 0 0 2px #062160;
    transition: background-color .2s ease, transform .15s ease;
}
.listen-mark.is-past::before { background: var(--listen-gold); }
.listen-mark:hover::before,
.listen-mark:focus-visible::before { transform: scaleY(1.35); background: #fff; }
.listen-mark::after {
    content: attr(data-title);
    position: absolute;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    white-space: nowrap;
    max-width: 16rem;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 0.3rem 0.55rem;
    border-radius: 0.4rem;
    background: #fff;
    color: #062160;
    font-size: 0.72rem;
    font-weight: 600;
    box-shadow: 0 6px 18px -6px rgb(0 0 0 / 0.35);
    opacity: 0;
    pointer-events: none;
    transition: opacity .15s ease, transform .15s ease;
}
.listen-mark:hover::after,
.listen-mark:focus-visible::after { opacity: 1; transform: translateX(-50%) translateY(0); }
/* Near either end, the label hangs inward instead of off the plate. */
.listen-mark.is-late::after { left: auto; right: 0; transform: translateY(4px); }
.listen-mark.is-late:hover::after,
.listen-mark.is-late:focus-visible::after { transform: translateY(0); }
.listen-mark.is-early::after { left: 0; transform: translateY(4px); }
.listen-mark.is-early:hover::after,
.listen-mark.is-early:focus-visible::after { transform: translateY(0); }


.listen-now:empty { display: none; }
.listen-now {
    margin-top: 0.4rem;
    font-size: 0.75rem;
    color: var(--listen-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Read-along: the paragraph being spoken, lit in the article itself. */
/* The tint is mixed solid against the page rather than laid on translucent: the
   pad that extends it left of the text sits over the gold rule, and a see-through
   pad let the rule show through as a thick block. */
.article-prose .is-narrating {
    --lit: color-mix(in srgb, #FFD700 20%, var(--page-ground));
    background: linear-gradient(90deg, var(--lit), color-mix(in srgb, #FFD700 5%, var(--page-ground)));
    box-shadow: -0.7rem 0 0 0 var(--lit), -0.85rem 0 0 0 #C5A600;
    border-radius: 0 0.35rem 0.35rem 0;
    transition: background-color .4s ease, box-shadow .4s ease;
}

/* The dock: once the player scrolls away, a slim bar keeps the story in reach. */
.listen-dock {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 45;
    background: rgb(6 33 96 / 0.97);
    backdrop-filter: blur(8px);
    color: #fff;
    box-shadow: 0 -10px 30px -12px rgb(0 0 0 / 0.4);
    animation: listen-dock-in .25s ease-out;
}
.listen-dock[hidden] { display: none; }
@keyframes listen-dock-in { from { transform: translateY(100%); } to { transform: translateY(0); } }
.listen-dock-progress {
    height: 3px;
    background: var(--listen-gold);
    transform: scaleX(0);
    transform-origin: left;
}
/* The control sits at the right end: the accessibility widget owns the bottom-left
   corner of every page, so the row's left edge is padded clear of it. */
.listen-dock-row {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    max-width: 1280px;
    margin: 0 auto;
    padding: 0.55rem 1rem 0.65rem 4.75rem;
}
@media (min-width: 1024px) { .listen-dock-row { padding-right: 2rem; } }
.listen-dock-meta { flex: 1; min-width: 0; }
.listen-dock-title {
    font-family: 'Oswald', system-ui, sans-serif;
    font-size: 0.95rem;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.listen-dock-sub {
    font-size: 0.72rem;
    color: rgb(255 255 255 / 0.62);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.listen-dock-time { font-size: 0.75rem; color: rgb(255 255 255 / 0.75); }
body.has-listen-dock { padding-bottom: 4rem; }
/* Keyboard focus scrolled to the bottom edge would land under the fixed dock (WCAG 2.4.11). */
html.has-listen-dock { scroll-padding-bottom: 5rem; }

@media (prefers-reduced-motion: reduce) {
    .listen.is-playing .listen-play { animation: none; }
    .listen-dock { animation: none; }
    .article-prose .is-narrating { transition: none; }
}
/* Boxed material that ran beside the story in print: bios, "Did You Know?". */
.article-prose .article-sidebar {
    background: #fff;
    border: 1px solid rgb(6 33 96 / 0.1);
    border-top: 4px solid #FFD700;
    border-radius: 0.75rem;
    box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.08);
    padding: 1.25rem 1.25rem 0.25rem;
    margin: 2.5rem 0;
    font-size: 0.9375rem;
    line-height: 1.65;
}
@media (min-width: 640px) { .article-prose .article-sidebar { padding: 1.75rem 2rem 0.5rem; } }
.article-prose .article-sidebar > h3:first-child { margin-top: 0; }
.article-prose .article-sidebar .article-figure { margin: 1.25rem auto; }

/* ── Share and feedback under an article (Pages/Articles/Detail.cshtml) ──────────
   Outline pills in the site's navy/blue, the same weight as the listen plate's tools.
   Pressed feedback fills navy so the reader can see what they answered. */
.article-actions {
    display: grid;
    gap: 1.5rem;
    margin-top: 2.5rem;
    padding: 1.5rem 0 0;
    border-top: 1px solid rgb(6 33 96 / 0.15);
}
@media (min-width: 768px) {
    .article-actions { grid-template-columns: 1fr auto; align-items: start; }
}
.article-actions-label {
    font-family: 'Oswald', system-ui, sans-serif;
    font-size: 0.95rem;
    font-weight: 600;
    color: #062160;
    margin: 0 0 0.6rem;
}
.article-actions-row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.article-action {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 2.5rem;            /* 40px target, comfortably over WCAG 2.5.8's 24px */
    padding: 0 0.9rem;
    border: 1px solid rgb(30 93 171 / 0.45);
    border-radius: 999px;
    background: #fff;
    color: #1E5DAB;
    font-size: 0.85rem;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    transition: background-color .15s, color .15s, border-color .15s;
}
.article-action:hover { background: #1E5DAB; border-color: #1E5DAB; color: #fff; }
.article-action:focus-visible { outline: 2px solid #1E5DAB; outline-offset: 2px; }
.article-action svg {
    width: 1rem;
    height: 1rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.article-action[aria-pressed="true"] { background: #062160; border-color: #062160; color: #fff; }
.article-actions-thanks { min-height: 1.25rem; margin: 0.5rem 0 0; font-size: 0.8rem; color: #4b5563; }
