/* -----------------------------------------------------------------------
   Cork D&D – Global Styles
   Supplements compiled Tailwind. Reserved for plain CSS that doesn't need
   Tailwind processing (parchment-mode overrides, scrollbar, EasyMDE chrome).
   Tailwind @apply utilities live in tailwind.input.css.
   ----------------------------------------------------------------------- */

/* Custom scrollbar for a more immersive feel */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: #1c1917; /* stone-900 */ }
::-webkit-scrollbar-thumb { background: #57534e; border-radius: 10px; /* stone-600 */ }

/* Smooth page transitions */
html { scroll-behavior: smooth; }

/* ================================================================
   PARCHMENT LIGHT MODE
   Remaps dark Tailwind utility classes when html.dark is absent.
   No templates need modification — all overrides live here.
   ================================================================ */

html:not(.dark) body { background-color: #f5e6c8; color: #3d2b1f; }

/* --- Backgrounds --- */
html:not(.dark) .bg-stone-950     { background-color: #fdf6e3 !important; }
html:not(.dark) .bg-stone-900     { background-color: #f5e6c8 !important; }
html:not(.dark) .bg-stone-800     { background-color: #e8d5a3 !important; }
html:not(.dark) .bg-stone-700     { background-color: #d4b896 !important; }
html:not(.dark) .bg-stone-800\/95 { background-color: rgba(232,213,163,0.97) !important; }
html:not(.dark) .bg-stone-800\/80 { background-color: rgba(232,213,163,0.92) !important; }
html:not(.dark) .bg-stone-800\/50 { background-color: rgba(232,213,163,0.5) !important; }
html:not(.dark) .bg-stone-800\/40 { background-color: rgba(232,213,163,0.4) !important; }
html:not(.dark) .bg-stone-900\/80 { background-color: rgba(245,230,200,0.92) !important; }
html:not(.dark) .bg-stone-900\/50 { background-color: rgba(245,230,200,0.5) !important; }
html:not(.dark) .bg-stone-900\/40 { background-color: rgba(245,230,200,0.4) !important; }
html:not(.dark) .bg-stone-700\/60 { background-color: rgba(212,184,150,0.6) !important; }
html:not(.dark) .bg-stone-700\/50 { background-color: rgba(212,184,150,0.5) !important; }
html:not(.dark) .bg-stone-700\/20 { background-color: rgba(212,184,150,0.2) !important; }

/* --- Card & Utility Overrides --- */
html:not(.dark) .tavern-card { background-color: rgba(232,213,163,0.5) !important; border-color: rgba(196,168,130,0.6) !important; }
html:not(.dark) .tavern-card:hover { border-color: rgba(180,83,9,0.4) !important; box-shadow: 0 10px 15px -3px rgba(180,83,9,0.1) !important; }
html:not(.dark) .golden-border { border-color: rgba(180,83,9,0.3) !important; }
html:not(.dark) .btn-primary {
    background-image: linear-gradient(to bottom right, #92400e, #78350f) !important;
    color: #fdf6e3 !important;
    border: 1px solid #451a03 !important;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
}
html:not(.dark) .btn-primary:hover {
    background-image: linear-gradient(to bottom right, #b45309, #92400e) !important;
}

html:not(.dark) .btn-secondary {
    background-color: transparent !important;
    color: #92400e !important;
    border: 2px solid #92400e !important;
    font-weight: 800 !important;
}
html:not(.dark) .btn-secondary:hover {
    background-color: #92400e !important;
    color: #fdf6e3 !important;
}

/* --- Text --- */
html:not(.dark) .text-white      { color: #2c1810 !important; }
html:not(.dark) .text-stone-100  { color: #3d2b1f !important; }
html:not(.dark) .text-stone-200  { color: #3d2b1f !important; }
html:not(.dark) .text-stone-300  { color: #5c3d2e !important; }
html:not(.dark) .text-stone-400  { color: #7a5c4a !important; }
html:not(.dark) .text-stone-500  { color: #9b7b6a !important; }
html:not(.dark) .text-stone-600  { color: #b89880 !important; }
html:not(.dark) .text-amber-50   { color: #3d2b1f !important; }
html:not(.dark) .text-amber-100  { color: #3d2b1f !important; }
html:not(.dark) .text-amber-400  { color: #92400e !important; }
html:not(.dark) .text-amber-500  { color: #b45309 !important; }

/* --- Borders --- */
html:not(.dark) .border-stone-800       { border-color: #d4b896 !important; }
html:not(.dark) .border-stone-700       { border-color: #c4a882 !important; }
html:not(.dark) .border-stone-700\/60   { border-color: rgba(196,168,130,0.6) !important; }
html:not(.dark) .border-stone-700\/50   { border-color: rgba(196,168,130,0.5) !important; }
html:not(.dark) .border-stone-700\/40   { border-color: rgba(196,168,130,0.4) !important; }
html:not(.dark) .border-stone-600\/50   { border-color: rgba(168,148,118,0.5) !important; }
html:not(.dark) .border-amber-600       { border-color: #d97706 !important; }
html:not(.dark) .border-amber-600\/40   { border-color: rgba(217,119,6,0.4) !important; }
html:not(.dark) .border-amber-900\/20   { border-color: rgba(120,53,15,0.15) !important; }

/* --- Amber background washes --- */
html:not(.dark) .bg-amber-900\/60 { background-color: rgba(217,119,6,0.15) !important; }
html:not(.dark) .bg-amber-900\/50 { background-color: rgba(217,119,6,0.12) !important; }
html:not(.dark) .bg-amber-900\/40 { background-color: rgba(217,119,6,0.10) !important; }
html:not(.dark) .bg-amber-950\/40 { background-color: rgba(217,119,6,0.10) !important; }
html:not(.dark) .bg-amber-950\/20 { background-color: rgba(217,119,6,0.08) !important; }

/* --- Status: scheduled (emerald) --- */
html:not(.dark) .bg-emerald-900\/60     { background-color: rgba(16,185,129,0.15) !important; }
html:not(.dark) .text-emerald-300       { color: #065f46 !important; }
html:not(.dark) .text-emerald-400       { color: #047857 !important; }
html:not(.dark) .text-emerald-500       { color: #065f46 !important; }
html:not(.dark) .border-emerald-800\/40 { border-color: rgba(16,185,129,0.4) !important; }

/* --- Status: cancelled / danger (red) --- */
html:not(.dark) .bg-red-900\/60     { background-color: rgba(239,68,68,0.15) !important; }
html:not(.dark) .bg-red-900\/40     { background-color: rgba(239,68,68,0.12) !important; }
html:not(.dark) .bg-red-900\/30     { background-color: rgba(239,68,68,0.10) !important; }
html:not(.dark) .bg-red-900\/20     { background-color: rgba(239,68,68,0.08) !important; }
html:not(.dark) .bg-red-900\/15     { background-color: rgba(239,68,68,0.07) !important; }
html:not(.dark) .text-red-300       { color: #991b1b !important; }
html:not(.dark) .text-red-200       { color: #991b1b !important; }
html:not(.dark) .text-red-400       { color: #b91c1c !important; }
html:not(.dark) .border-red-800\/60 { border-color: rgba(239,68,68,0.35) !important; }
html:not(.dark) .border-red-800\/50 { border-color: rgba(239,68,68,0.30) !important; }
html:not(.dark) .border-red-900\/30 { border-color: rgba(239,68,68,0.20) !important; }

/* --- Flash success (green) --- */
html:not(.dark) .bg-green-900\/40      { background-color: rgba(16,185,129,0.12) !important; }
html:not(.dark) .text-green-300        { color: #065f46 !important; }
html:not(.dark) .border-green-800\/60  { border-color: rgba(16,185,129,0.35) !important; }

/* --- Flash info (blue) --- */
html:not(.dark) .bg-blue-900\/40      { background-color: rgba(59,130,246,0.12) !important; }
html:not(.dark) .bg-blue-900\/15      { background-color: rgba(59,130,246,0.07) !important; }
html:not(.dark) .text-blue-300        { color: #1e3a5f !important; }
html:not(.dark) .text-blue-200        { color: #1e3a5f !important; }
html:not(.dark) .border-blue-800\/60  { border-color: rgba(59,130,246,0.35) !important; }

/* --- Game night / session badge (purple) --- */
html:not(.dark) .bg-purple-900\/40     { background-color: rgba(139,92,246,0.12) !important; }
html:not(.dark) .bg-purple-900\/60     { background-color: rgba(139,92,246,0.15) !important; }
html:not(.dark) .text-purple-300       { color: #4c1d95 !important; }
html:not(.dark) .text-purple-400       { color: #6d28d9 !important; }
html:not(.dark) .border-purple-900\/40 { border-color: rgba(139,92,246,0.25) !important; }

/* --- Moderator role badge (sky) --- */
html:not(.dark) .bg-sky-900\/40     { background-color: rgba(14,165,233,0.12) !important; }
html:not(.dark) .text-sky-300       { color: #075985 !important; }
html:not(.dark) .border-sky-800\/50 { border-color: rgba(14,165,233,0.30) !important; }

/* --- Scrollbar --- */
html:not(.dark) ::-webkit-scrollbar-track { background: #f5e6c8; }
html:not(.dark) ::-webkit-scrollbar-thumb { background: #c4a882; }

/* --- Browser-native form chrome (datetime pickers, select dropdowns) --- */
html:not(.dark) input,
html:not(.dark) textarea,
html:not(.dark) select { color-scheme: light; }

/* --- Bulletin body Markdown content --- */
html:not(.dark) .bulletin-body h1,
html:not(.dark) .bulletin-body h2  { color: #92400e; }
html:not(.dark) .bulletin-body h3  { color: #b45309; }
html:not(.dark) .bulletin-body p,
html:not(.dark) .bulletin-body ul,
html:not(.dark) .bulletin-body ol  { color: #5c3d2e; }
html:not(.dark) .bulletin-body a   { color: #92400e; }
html:not(.dark) .bulletin-body a:hover    { color: #78350f; }
html:not(.dark) .bulletin-body strong     { color: #3d2b1f; }
html:not(.dark) .bulletin-body code       { background: #e8d5a3; color: #92400e; }
html:not(.dark) .bulletin-body pre        { background: #e8d5a3; border-color: #c4a882; }
html:not(.dark) .bulletin-body blockquote { border-left-color: #c4a882; color: #9b7b6a; }
html:not(.dark) .bulletin-body th { background: #d4b896; color: #3d2b1f; border-color: #c4a882; }
html:not(.dark) .bulletin-body td { color: #5c3d2e; border-color: #c4a882; }

/* --- FullCalendar light-mode CSS variables --- */
html:not(.dark) .fc {
    --fc-border-color: rgba(196,168,130,0.5);
    --fc-page-bg-color: #f5e6c8;
    --fc-button-bg-color: #d4b896;
    --fc-button-border-color: #c4a882;
    --fc-button-hover-bg-color: #c4a882;
    --fc-button-hover-border-color: #b89880;
    --fc-button-active-bg-color: #d97706;
    --fc-button-active-border-color: #d97706;
    --fc-button-text-color: #3d2b1f;
    --fc-today-bg-color: rgba(217,119,6,0.12);
    --fc-neutral-bg-color: rgba(245,230,200,0.6);
    --fc-neutral-text-color: #5c3d2e;
    --fc-list-event-hover-bg-color: rgba(212,184,150,0.5);
    --fc-event-text-color: #fff;
    color: #3d2b1f;
}
/* Force light backgrounds on calendar cells and elements */
html:not(.dark) .fc .fc-scrollgrid,
html:not(.dark) .fc .fc-scrollgrid-section > td,
html:not(.dark) .fc .fc-daygrid-body,
html:not(.dark) .fc .fc-daygrid-day,
html:not(.dark) .fc .fc-col-header,
html:not(.dark) .fc .fc-col-header-cell,
html:not(.dark) .fc .fc-list,
html:not(.dark) .fc .fc-list-table,
html:not(.dark) .fc .fc-list-day th,
html:not(.dark) .fc .fc-list-event td,
html:not(.dark) .fc table,
html:not(.dark) .fc td,
html:not(.dark) .fc th { background-color: #f5e6c8 !important; }
html:not(.dark) .fc .fc-daygrid-day.fc-day-today { background-color: rgba(217,119,6,0.12) !important; }
html:not(.dark) .fc .fc-col-header-cell-cushion,
html:not(.dark) .fc .fc-daygrid-day-number,
html:not(.dark) .fc .fc-list-day-text,
html:not(.dark) .fc .fc-list-day-side-text { color: #7a5c4a; }
html:not(.dark) .fc .fc-toolbar-title { color: #2c1810; }
html:not(.dark) .fc .fc-button-primary:not(:disabled).fc-button-active { color: #f5e6c8; }

/* ================================================================
   EASYMDE RICH TEXT EDITOR — DARK & LIGHT MODE OVERRIDES
   ================================================================ */

/* Keep the editor within its container on mobile. CodeMirror reserves a 50px
   right border on .CodeMirror-sizer for a scrollbar gutter and pulls the scroll
   element left with a matching negative margin; with overlay scrollbars (mobile)
   that gutter just pushes the page ~50px wider than the viewport (horizontal
   scrollbar). Neutralise the gutter and clamp the editor to its container. */
.EasyMDEContainer { max-width: 100%; }
.EasyMDEContainer .CodeMirror { max-width: 100%; overflow: hidden; }
.EasyMDEContainer .CodeMirror-sizer { border-right-width: 0 !important; }
.EasyMDEContainer .CodeMirror-scroll { margin-right: 0 !important; padding-right: 0 !important; }

/* Dark mode */
.dark .EasyMDEContainer .CodeMirror {
    background: rgb(28 25 23);
    color: rgb(214 211 209);
    border-color: rgb(87 83 78);
}
.dark .EasyMDEContainer .editor-toolbar {
    border-color: rgb(87 83 78);
}
.dark .EasyMDEContainer .editor-toolbar button {
    color: rgb(168 162 158) !important;
}
.dark .EasyMDEContainer .editor-toolbar button:hover,
.dark .EasyMDEContainer .editor-toolbar button.active {
    background: rgb(68 64 60);
    color: rgb(251 191 36) !important;
}
.dark .EasyMDEContainer .CodeMirror-cursor {
    border-left-color: rgb(251 191 36);
}
.dark .EasyMDEContainer .editor-preview {
    background: rgb(41 37 36);
    color: rgb(214 211 209);
}
.dark .EasyMDEContainer .editor-toolbar.disabled-for-preview button:not(.no-disable) {
    color: rgb(120 113 108) !important;
}

/* Light mode (parchment) */
html:not(.dark) .EasyMDEContainer .CodeMirror {
    background: #f5ead4;
    color: #3d2b1f;
    border-color: #c4a882;
}
html:not(.dark) .EasyMDEContainer .editor-toolbar {
    border-color: #c4a882;
}
html:not(.dark) .EasyMDEContainer .editor-toolbar button {
    color: #5c3d2e !important;
}
html:not(.dark) .EasyMDEContainer .editor-toolbar button:hover,
html:not(.dark) .EasyMDEContainer .editor-toolbar button.active {
    background: #e8d5a3;
    color: #92400e !important;
}

/* ================================================================
   RENDERED MARKDOWN TYPOGRAPHY — .note-body + EasyMDE preview panes
   Tailwind's preflight strips ALL default element styling (headings
   inherit body size/weight, links lose color/underline, lists lose
   bullets), so every surface that renders markdown needs these rules
   back explicitly. .note-body is the site-wide prose class (notes,
   The Story So Far, the mobile composer preview); the .editor-preview
   selectors fix EasyMDE's desktop Preview pane, which relied on
   browser defaults and showed markdown as flat text (issue #172).
   campaign_export.html carries its own copy — it must stay
   self-contained offline. Dark values first (templates are authored
   dark-first), parchment overrides below.
   ================================================================ */
.note-body h1, .EasyMDEContainer .editor-preview h1 { font-size: 1.5rem; font-weight: 700; color: #f5f5f4; margin-top: 0.75em; margin-bottom: 0.375em; }
.note-body h2, .EasyMDEContainer .editor-preview h2 { font-size: 1.25rem; font-weight: 600; color: #f5f5f4; margin-top: 0.75em; margin-bottom: 0.375em; }
.note-body h3, .EasyMDEContainer .editor-preview h3 { font-size: 1.1rem; font-weight: 600; color: #f5f5f4; margin-top: 0.75em; margin-bottom: 0.375em; }
.note-body p, .EasyMDEContainer .editor-preview p { margin-bottom: 0.5em; }
.note-body a, .EasyMDEContainer .editor-preview a { color: #f59e0b; text-decoration: underline; }
.note-body code, .EasyMDEContainer .editor-preview code { background: rgba(120, 113, 108, 0.3); padding: 0.1em 0.3em; border-radius: 0.25em; font-size: 0.875em; }
.note-body pre, .EasyMDEContainer .editor-preview pre { background: rgba(28, 25, 23, 0.6); padding: 0.75em; border-radius: 0.5em; overflow-x: auto; margin-bottom: 0.75em; }
.note-body blockquote, .EasyMDEContainer .editor-preview blockquote { border-left: 3px solid #b45309; padding-left: 1em; color: #a8a29e; font-style: italic; margin-bottom: 0.5em; }
.note-body ul, .note-body ol, .EasyMDEContainer .editor-preview ul, .EasyMDEContainer .editor-preview ol { padding-left: 1.5em; margin-bottom: 0.5em; }
.note-body ul li, .EasyMDEContainer .editor-preview ul li { list-style-type: disc; }
.note-body ol li, .EasyMDEContainer .editor-preview ol li { list-style-type: decimal; }
.note-body li, .EasyMDEContainer .editor-preview li { margin-bottom: 0.25em; }
.note-body strong, .EasyMDEContainer .editor-preview strong { font-weight: 600; }

html:not(.dark) .note-body h1, html:not(.dark) .note-body h2, html:not(.dark) .note-body h3,
html:not(.dark) .EasyMDEContainer .editor-preview h1, html:not(.dark) .EasyMDEContainer .editor-preview h2, html:not(.dark) .EasyMDEContainer .editor-preview h3 { color: #292524; }
html:not(.dark) .note-body p, html:not(.dark) .note-body li,
html:not(.dark) .EasyMDEContainer .editor-preview p, html:not(.dark) .EasyMDEContainer .editor-preview li { color: #44403c; }
html:not(.dark) .note-body a, html:not(.dark) .EasyMDEContainer .editor-preview a { color: #b45309; }
html:not(.dark) .note-body code, html:not(.dark) .EasyMDEContainer .editor-preview code { background: rgba(120, 113, 108, 0.15); color: #292524; }
html:not(.dark) .note-body pre, html:not(.dark) .EasyMDEContainer .editor-preview pre { background: #f5f5f4; color: #292524; }
html:not(.dark) .note-body blockquote, html:not(.dark) .EasyMDEContainer .editor-preview blockquote { color: #78716c; }

/* ================================================================
   PARCHMENT LIGHT MODE — extended coverage
   Light/parchment mode is a hand-maintained remap of dark utility
   classes (the templates are authored dark-first; there are no
   `dark:` variants). Because the remap is an explicit table, every
   light-toned text class and every dark background class used in a
   template must be listed here or it renders with its dark value on
   parchment (light text → invisible; dark bg → muddy). Opacity
   suffixes (`/70`, `/30`) are SEPARATE selectors from the base class,
   so they must be listed individually.
   tests/test_light_mode_contrast.py fails the build if a template
   uses a text-/bg- color class that is neither remapped here nor on
   that test's allowlist — that is the guard against silent regressions.
   ================================================================ */

/* --- Light text shades + opacity variants (would be invisible on parchment) --- */
html:not(.dark) .text-stone-50       { color: #3d2b1f !important; }
html:not(.dark) .text-amber-100\/70  { color: #7a5c4a !important; }
html:not(.dark) .text-amber-200,
html:not(.dark) .text-amber-200\/80  { color: #7a5c4a !important; }
html:not(.dark) .text-amber-300,
html:not(.dark) .text-amber-300\/80  { color: #b45309 !important; }
html:not(.dark) .text-amber-500\/60,
html:not(.dark) .text-amber-500\/70,
html:not(.dark) .text-amber-500\/80  { color: #b45309 !important; }
html:not(.dark) .text-red-50,
html:not(.dark) .text-red-100        { color: #991b1b !important; }
html:not(.dark) .text-red-300\/80    { color: #b91c1c !important; }
html:not(.dark) .text-green-100,
html:not(.dark) .text-green-200      { color: #065f46 !important; }
html:not(.dark) .text-green-400      { color: #047857 !important; }
html:not(.dark) .text-emerald-50     { color: #065f46 !important; }
html:not(.dark) .text-blue-100       { color: #1e3a5f !important; }
html:not(.dark) .text-blue-400       { color: #1e40af !important; }
html:not(.dark) .text-cyan-400       { color: #0e7490 !important; }
html:not(.dark) .text-violet-300,
html:not(.dark) .text-violet-400     { color: #6d28d9 !important; }
html:not(.dark) .text-rose-400       { color: #be123c !important; }
html:not(.dark) .text-yellow-400     { color: #a16207 !important; }
html:not(.dark) .text-orange-400     { color: #c2410c !important; }

/* --- Solid colored buttons: keep light text. The global `.text-white`
   remap above flips white → near-black, which is correct on parchment
   surfaces but destroys solid colored buttons (e.g. a red delete button
   would become dark-text-on-dark-red). The compound selectors below have
   higher specificity than the bare `.text-white` rule, so they win and
   restore white only where the text sits on a saturated button. --- */
html:not(.dark) .bg-red-500.text-white,
html:not(.dark) .bg-red-600.text-white,
html:not(.dark) .bg-red-700.text-white,
html:not(.dark) .bg-emerald-600.text-white,
html:not(.dark) .bg-indigo-600.text-white,
html:not(.dark) .bg-amber-600.text-white   { color: #fff !important; }
html:not(.dark) .bg-amber-700.text-amber-50 { color: #fdf6e3 !important; }

/* --- Translucent dark washes / chips → light parchment tints --- */
html:not(.dark) .bg-stone-800\/20  { background-color: rgba(232,213,163,0.20) !important; }
html:not(.dark) .bg-stone-800\/30  { background-color: rgba(232,213,163,0.30) !important; }
html:not(.dark) .bg-stone-800\/60  { background-color: rgba(232,213,163,0.60) !important; }
html:not(.dark) .bg-stone-800\/70  { background-color: rgba(232,213,163,0.70) !important; }
html:not(.dark) .bg-stone-700\/30  { background-color: rgba(212,184,150,0.30) !important; }
html:not(.dark) .bg-stone-700\/40  { background-color: rgba(212,184,150,0.40) !important; }
html:not(.dark) .bg-stone-700\/70  { background-color: rgba(212,184,150,0.70) !important; }
html:not(.dark) .bg-stone-900\/30  { background-color: rgba(245,230,200,0.30) !important; }
html:not(.dark) .bg-stone-900\/60  { background-color: rgba(245,230,200,0.60) !important; }
html:not(.dark) .bg-stone-900\/70  { background-color: rgba(245,230,200,0.70) !important; }
html:not(.dark) .bg-stone-600      { background-color: #c4a882 !important; }
html:not(.dark) .bg-amber-800\/60  { background-color: rgba(217,119,6,0.15) !important; }
html:not(.dark) .bg-amber-900\/10  { background-color: rgba(217,119,6,0.05) !important; }
html:not(.dark) .bg-amber-900\/20  { background-color: rgba(217,119,6,0.07) !important; }
html:not(.dark) .bg-amber-900\/30  { background-color: rgba(217,119,6,0.10) !important; }
html:not(.dark) .bg-amber-950\/10  { background-color: rgba(217,119,6,0.05) !important; }
html:not(.dark) .bg-amber-950\/30  { background-color: rgba(217,119,6,0.10) !important; }
html:not(.dark) .bg-amber-950\/50  { background-color: rgba(217,119,6,0.13) !important; }
html:not(.dark) .bg-red-800        { background-color: rgba(239,68,68,0.18) !important; }
html:not(.dark) .bg-red-900\/50    { background-color: rgba(239,68,68,0.13) !important; }
html:not(.dark) .bg-red-900\/80    { background-color: rgba(239,68,68,0.16) !important; }
html:not(.dark) .bg-red-950\/10    { background-color: rgba(239,68,68,0.05) !important; }
html:not(.dark) .bg-red-950\/30    { background-color: rgba(239,68,68,0.10) !important; }
html:not(.dark) .bg-green-900\/20  { background-color: rgba(16,185,129,0.07) !important; }
html:not(.dark) .bg-green-900\/30  { background-color: rgba(16,185,129,0.10) !important; }
html:not(.dark) .bg-green-900\/50  { background-color: rgba(16,185,129,0.13) !important; }
html:not(.dark) .bg-emerald-900\/20 { background-color: rgba(16,185,129,0.07) !important; }
html:not(.dark) .bg-emerald-900\/30 { background-color: rgba(16,185,129,0.10) !important; }
html:not(.dark) .bg-emerald-900\/50 { background-color: rgba(16,185,129,0.13) !important; }
html:not(.dark) .bg-emerald-950\/30 { background-color: rgba(16,185,129,0.10) !important; }
html:not(.dark) .bg-blue-900\/30   { background-color: rgba(59,130,246,0.10) !important; }
html:not(.dark) .bg-cyan-900\/30   { background-color: rgba(8,145,178,0.10) !important; }
html:not(.dark) .bg-purple-900\/20 { background-color: rgba(139,92,246,0.07) !important; }
html:not(.dark) .bg-purple-900\/30 { background-color: rgba(139,92,246,0.10) !important; }
html:not(.dark) .bg-purple-900\/50 { background-color: rgba(139,92,246,0.13) !important; }
html:not(.dark) .bg-purple-950\/20 { background-color: rgba(139,92,246,0.07) !important; }
html:not(.dark) .bg-violet-900\/30 { background-color: rgba(139,92,246,0.10) !important; }
html:not(.dark) .bg-rose-900\/30   { background-color: rgba(244,63,94,0.10) !important; }
html:not(.dark) .bg-orange-900\/30 { background-color: rgba(234,88,12,0.10) !important; }
html:not(.dark) .bg-yellow-900\/30 { background-color: rgba(202,138,4,0.12) !important; }

/* --- Selected/toggle buttons (translucent dark colour + light colour text):
   light tint bg so the (now-dark) text reads. Includes hover/active states. --- */
html:not(.dark) .bg-blue-700\/60,
html:not(.dark) .hover\:bg-blue-700:hover  { background-color: rgba(59,130,246,0.18) !important; }
html:not(.dark) .bg-green-700\/60,
html:not(.dark) .hover\:bg-green-700:hover { background-color: rgba(16,185,129,0.18) !important; }

/* --- Gradient stops on admin attention cards (would stay dark otherwise).
   Each `from-*` utility sets both --tw-gradient-from and --tw-gradient-stops,
   so the stops var is restated to pick up the lightened colors. --- */
html:not(.dark) .from-red-950\/40 {
    --tw-gradient-from: rgba(239,68,68,0.10) var(--tw-gradient-from-position) !important;
    --tw-gradient-to: rgba(239,68,68,0) var(--tw-gradient-to-position) !important;
    --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to) !important;
}
html:not(.dark) .hover\:from-red-950\/60:hover {
    --tw-gradient-from: rgba(239,68,68,0.16) var(--tw-gradient-from-position) !important;
    --tw-gradient-to: rgba(239,68,68,0) var(--tw-gradient-to-position) !important;
    --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to) !important;
}
html:not(.dark) .from-amber-950\/40 {
    --tw-gradient-from: rgba(217,119,6,0.10) var(--tw-gradient-from-position) !important;
    --tw-gradient-to: rgba(217,119,6,0) var(--tw-gradient-to-position) !important;
    --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to) !important;
}
html:not(.dark) .hover\:from-amber-950\/60:hover {
    --tw-gradient-from: rgba(217,119,6,0.16) var(--tw-gradient-from-position) !important;
    --tw-gradient-to: rgba(217,119,6,0) var(--tw-gradient-to-position) !important;
    --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to) !important;
}
html:not(.dark) .to-stone-900\/40 {
    --tw-gradient-to: rgba(245,230,200,0.40) var(--tw-gradient-to-position) !important;
}

/* ================================================================
   TALES CATEGORY TILES / BAND / BADGES (/tales/ feed)
   The per-category accent rides the --cat custom property, set by
   the shared cat--* classes used by the tiles, the active-category
   band and the story-type badges. Light (parchment) values are the
   base; html.dark overrides carry the dark-theme accents/surfaces.
   ================================================================ */

.cat--all            { --cat: #a16207; }
.cat--session_recap  { --cat: #2f6797; }
.cat--character_lore { --cat: #6d4fa3; }
.cat--world_lore     { --cat: #2e7d57; }
.cat--obituary       { --cat: #a94444; }
html.dark .cat--all            { --cat: #e0a233; }
html.dark .cat--session_recap  { --cat: #5b93c9; }
html.dark .cat--character_lore { --cat: #a884d0; }
html.dark .cat--world_lore     { --cat: #63b189; }
html.dark .cat--obituary       { --cat: #cf6b6b; }

/* --- Category tile deck (tab row) --- */
.cat-tiles {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}
.cat-tile {
    flex: 1 1 0;
    min-height: 116px;
    padding: 15px 17px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    border-radius: 12px;
    background: #f0e6d2;
    border: 1px solid #d3bf9c;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
html.dark .cat-tile {
    background: #1f1810;
    border-color: #322718;
}
.cat-tile:hover {
    border-color: var(--cat);
}
.cat-tile.is-active {
    background: #e9dcc0;
    border-color: var(--cat);
    box-shadow: inset 0 3px 0 var(--cat);
}
html.dark .cat-tile.is-active {
    background: #2a2116;
}
.cat-tile-dot {
    width: 8px;
    height: 8px;
    border-radius: 9999px;
    flex-shrink: 0;
    background: var(--cat);
}
.cat-tile-name {
    font-family: 'EB Garamond', Georgia, serif;
    font-size: 17px;
    font-weight: 600;
    color: #3d2b1f;
}
html.dark .cat-tile-name {
    color: #ede0c8;
}
.cat-tile-desc {
    font-size: 12.5px;
    line-height: 1.35;
    color: #7a6a55;
}
html.dark .cat-tile-desc {
    color: #9d9182;
}
.cat-tile-count {
    margin-top: auto;
    font-size: 11.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--cat);
}
@media (max-width: 640px) {
    /* Slim single-line rows on phones (name left, count right). The tall 2-up
       tiles filled the whole viewport and hid the list they filter (#156); the
       description is dropped here because the active-category band right below
       the deck repeats it. */
    .cat-tiles { gap: 6px; }
    .cat-tile {
        flex: 1 1 100%;
        min-height: 0;
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        gap: 8px;
        padding: 9px 13px;
    }
    .cat-tile-desc { display: none; }
    .cat-tile-count { margin-top: 0; white-space: nowrap; }
    .cat-tile-name { font-size: 15px; white-space: nowrap; }
}

/* --- Active-category band (title + description + search) --- */
.cat-band {
    border-left: 4px solid var(--cat);
    border-radius: 12px;
    padding: 15px 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    background: #efe4cd;
}
html.dark .cat-band {
    background: #1a140d;
}
.cat-band-title {
    font-family: 'Cinzel', serif;
    font-size: 20px;
    font-weight: 700;
    color: #3d2b1f;
}
html.dark .cat-band-title {
    color: #ede0c8;
}
.cat-band-desc {
    font-size: 12.5px;
    color: #7a6a55;
}
html.dark .cat-band-desc {
    color: #9d9182;
}
@media (max-width: 640px) {
    /* Search stacks below the title on phones. */
    .cat-band {
        flex-direction: column;
        align-items: stretch;
    }
}

/* --- Story-type badge (feed cards + My Stories) --- */
.tale-badge {
    display: inline-block;
    padding: 4px 10px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--cat);
    background: rgba(0, 0, 0, 0.06); /* fallback for browsers without color-mix */
    background: color-mix(in srgb, var(--cat) 15%, transparent);
}

/* --- Reusable admin table -> cards on mobile (#183) ------------------------
   Add class `admin-cards` to a wide admin <table>; on phones (< sm) each row
   reflows into a card (same DOM, so AJAX pagination / sorting keep working;
   desktop is unchanged). Annotate cells:
     data-card="title"   -> prominent full-width heading
     data-card="meta"    -> inline badge/short value, no label
     data-card="actions" -> full-width action row at the card foot
     data-card="hide"    -> desktop-only (hidden on mobile)
     data-label="Label"  -> full-width line prefixed with an uppercase caption
   Un-annotated cells fall back to a plain full-width line. */
@media (max-width: 639px) {
  table.admin-cards,
  table.admin-cards > tbody { display: block; }
  table.admin-cards > thead { display: none; }
  table.admin-cards { min-width: 0 !important; }
  table.admin-cards > tbody > tr {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem 0.6rem;
    margin: 0.5rem 0.75rem; padding: 0.85rem 1rem;
    border: 1px solid rgb(68 64 60 / 0.6); border-radius: 0.75rem;
  }
  table.admin-cards > tbody > tr > td {
    display: block; order: 3; flex-basis: 100%;
    width: auto !important; max-width: none !important; position: static !important;
    padding: 0; border: 0 !important; white-space: normal; font-size: 0.8rem; color: #d6d3d1;
  }
  table.admin-cards td[data-card="title"] {
    order: 0; font-weight: 700; font-size: 0.95rem; color: #e7e5e4; word-break: break-word;
  }
  table.admin-cards td[data-card="meta"] {
    order: 2; display: inline-flex; flex: 0 0 auto; flex-basis: auto; flex-wrap: wrap; gap: 0.25rem;
  }
  table.admin-cards td[data-card="hide"] { display: none; }
  table.admin-cards td[data-card="actions"] {
    order: 9; margin-top: 0.5rem; padding-top: 0.6rem;
    border-top: 1px solid rgb(68 64 60 / 0.5) !important; text-align: left !important;
  }
  table.admin-cards td[data-label]::before {
    content: attr(data-label); display: inline-block; min-width: 4.5rem;
    color: #78716c; text-transform: uppercase; font-size: 0.62rem; letter-spacing: 0.04em; margin-right: 0.4rem;
  }
  table.admin-cards td code { word-break: break-word; }
  table.admin-cards > tbody > tr:has(> td[colspan]) { display: block; border: 0; padding: 0; margin: 0; }
  table.admin-cards > tbody > tr:has(> td[colspan]) > td { display: block; order: 0; flex-basis: auto; }
}

/* ================================================================
   NOTIFICATION BELL — unread jingle (F-128)
   The bell badge reads clearly on mobile but is easy to miss on a wide
   desktop header, so an unread count gives the bell a short swing.

   Deliberately a BURST, not a loop. The unread count is computed
   server-side on every render with no polling (see
   inject_notification_context), so an infinite animation tied to
   "unread > 0" would swing on every page load for as long as the
   notification stays unread — nagging rather than nudging. Three swings
   over ~1.1s draws the eye once and then sits still.
   ================================================================ */
@keyframes bell-jingle {
  0%   { transform: rotate(0deg); }
  15%  { transform: rotate(11deg); }
  30%  { transform: rotate(-9deg); }
  45%  { transform: rotate(7deg); }
  60%  { transform: rotate(-5deg); }
  75%  { transform: rotate(3deg); }
  100% { transform: rotate(0deg); }
}

.bell-jingle {
  /* Swing from the crown, the way a real bell hangs — rotating about the
     centre reads as a wobble instead. */
  transform-origin: 50% 15%;
  animation: bell-jingle 1.1s ease-in-out 1 both;
}

/* Reduced-motion visitors get the attention cue without the movement: the bell
   simply sits in the badge's amber. Mirrors the treatment in
   main/pages/static/js/crypt/index.js.

   The colour is per-theme on purpose. Raw amber-500 (#f59e0b) is the dark-mode
   value; on the cream parchment background it washes out, which is exactly why
   the remap table above rewrites .text-amber-500 to #b45309. A hardcoded
   amber-500 here would sidestep that remap — and the light-mode contrast guard
   can't catch it, because this is a plain CSS colour, not a utility class. */
@media (prefers-reduced-motion: reduce) {
  .bell-jingle {
    animation: none;
    transform: none;
    color: #f59e0b; /* amber-500 — dark mode */
  }
  html:not(.dark) .bell-jingle {
    color: #b45309; /* amber-700 — matches the parchment remap of .text-amber-500 */
  }
}
