/* Free.ai — Main Stylesheet */

:root {
    /* The FILL green. Was #16A34A, which is 3.29:1 under white text and fails
     * SC 1.4.3 on every primary button, badge and pill on the site. #15803D
     * measures 5.0:1 under white and is visually near identical. Owner
     * approved 2026-09-17. Green as INK has its own token, --brand-ink in
     * a11y.css, because on the dark theme the darker green fails as text. */
    --primary: #15803D;
    --primary-hover: #166534;
    --primary-light: #4ADE80;
    --primary-bg: #F0FDF4;
    --primary-bg-hover: #DCFCE7;
    --text-dark: #111827;
    --text-muted: #6b7280;
    --border: #e5e7eb;
    --bg-body: #ffffff;
    --bg-card: #ffffff;
    --bg-surface: #f9fafb;
    --bg-nav: #ffffff;
    --bg-footer: #111827;
    --bg-input: #ffffff;
    --shadow-color: rgba(0,0,0,.05);
    --shadow-hover: rgba(0,0,0,.1);
    --code-bg: #1e1e2e;
}

html.dark {
    /* Same fill green in both themes: white-on-green is the pair that has to
     * pass, and it does not care what is behind the button. The old dark
     * hover #1ebe56 was 2.48:1 under white. */
    --primary: #15803D;
    --primary-hover: #166534;
    --primary-light: #4ADE80;
    --primary-bg: #1a1a1a;
    --primary-bg-hover: #222222;
    --text-dark: #f0f0f0;
    --text-muted: #b0b0b0;
    --border: #333333;
    --bg-body: #0a0a0a;
    --bg-card: #141414;
    --bg-surface: #111111;
    --bg-nav: #0e0e0e;
    --bg-footer: #080808;
    --bg-input: #1a1a1a;
    --shadow-color: rgba(0,0,0,.4);
    --shadow-hover: rgba(0,0,0,.5);
    --code-bg: #0e0e0e;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    color: var(--text-dark);
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}
main { flex: 1; }

.navbar { box-shadow: 0 1px 3px rgba(0,0,0,.05); }
.tool-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,.1) !important; }

.btn-primary, .btn-primary:active, .btn-primary:focus-visible {
    background-color: var(--primary) !important;
    border-color: var(--primary) !important;
    color: #fff !important;
}
.btn-primary:hover {
    background-color: var(--primary-hover) !important;
    border-color: var(--primary-hover) !important;
}
.btn-outline-primary {
    color: var(--primary) !important;
    border-color: var(--primary) !important;
}
.btn-outline-primary:hover, .btn-outline-primary:active {
    background-color: var(--primary) !important;
    border-color: var(--primary) !important;
    color: #fff !important;
}
.text-primary { color: var(--primary) !important; }
.bg-primary { background-color: var(--primary) !important; }
a { color: var(--primary); }
a:hover { color: var(--primary-hover); }
.nav-link { color: #374151; }
.nav-link:hover { color: var(--primary); }

.progress-bar { background-color: var(--primary); transition: width .3s ease; }
.progress-bar.bg-warning { background-color: #f59e0b !important; }
.progress-bar.bg-danger { background-color: #ef4444 !important; }
.progress-bar.bg-primary { background-color: var(--primary) !important; }

#chat-messages .user-msg { background: var(--primary); color: white; border-radius: 12px 12px 0 12px; align-self: center; }
#chat-messages .ai-msg { background: #f9fafb; border-radius: 12px 12px 12px 0; }
/* On mobile the per-message action column (edit/branch/remember icons stacked
   vertically) sets a tall flex-row which would stretch the user bubble to
   match. align-self:center on the bubble (above) keeps it sized to content.
   Also shrink the icon buttons themselves so the row isn't 200px tall for a
   one-line "hi" message. */
@media (max-width: 575.98px) {
    .chat-msg-actions .btn-link { font-size: .75rem !important; padding: 2px 4px !important; line-height: 1; }
    .chat-msg-actions { gap: 2px !important; }
}
.chat-model-label { display: inline-block; font-size: .65rem; font-weight: 600; color: #4f46e5; background: #eef2ff; padding: 1px 8px; border-radius: 10px; margin-bottom: 6px; letter-spacing: .02em; }

#drop-zone { transition: all .2s ease; }
#drop-zone.dragover { border-color: var(--primary) !important; background: var(--primary-bg); }

.accordion-button:not(.collapsed) { background-color: var(--primary-bg); color: var(--primary); }
.accordion-button:focus { box-shadow: 0 0 0 .25rem rgba(220,38,38,.2); }

footer.bg-dark { background-color: #111827 !important; }
footer a { color: #d1d5db !important; }
footer a:hover { color: #fff !important; }
.star-btn:hover { transform: scale(1.2); }
.suggestion-btn:hover { background-color: var(--primary); color: white; border-color: var(--primary); }

.chat-code {
    background: #1e1e2e; color: #cdd6f4; padding: 1rem;
    border-radius: 8px; overflow-x: auto;
    font-family: 'SF Mono', 'Fira Code', monospace; font-size: .875rem;
}

.loading-dots::after { content: ''; animation: dots 1.5s steps(4) infinite; }
@keyframes dots { 0%,20%{content:''} 40%{content:'.'} 60%{content:'..'} 80%,100%{content:'...'} }


.modal-backdrop { backdrop-filter: blur(4px); }

.tool-link:hover { border-color: var(--primary) !important; background: var(--primary-bg); color: var(--primary); }
.cat-card:hover { border-color: var(--primary); }
.cat-card i { color: var(--primary); }

.bg-primary.bg-opacity-10 { background-color: var(--primary-bg) !important; }

@media (max-width: 768px) {
    .display-4 { font-size: 2rem; }
    #chat-messages { height: 250px !important; }
}

/* Dark Mode Toggle Button */
#dark-mode-toggle {
    background: none !important; border: none !important; outline: none !important; box-shadow: none !important;
    cursor: pointer; font-size: 1.1rem; padding: 4px 8px; border-radius: 6px;
    color: var(--text-muted); transition: color .2s;
}
#dark-mode-toggle:hover { color: var(--primary); background: var(--primary-bg); }

/* Dark Mode Overrides */
html.dark body { background-color: var(--bg-body); color: var(--text-dark); }
html.dark .navbar { background-color: var(--bg-nav) !important; border-color: var(--border) !important; box-shadow: 0 1px 3px var(--shadow-color); }
html.dark .navbar .nav-link { color: var(--text-muted); }
html.dark .navbar .nav-link:hover { color: var(--primary); }
html.dark .navbar-brand span:last-child { color: var(--text-dark) !important; }
html.dark .navbar-toggler-icon { filter: invert(1); }
/* `color` here is load-bearing and is NOT redundant with the .dropdown-item
   rule below. `html.dark a:not(.btn){color:inherit}` (line ~272) scores
   (0,2,2) and outranks `html.dark .dropdown-item` (0,2,1), so every item in
   this menu resolved to Bootstrap's `.dropdown-menu{color:var(--bs-dropdown-color)}`
   -- #212529 on #141414, measured at 1.19:1, i.e. invisible. Setting the
   colour on the MENU fixes the inherit chain the broad rule sends the link
   down, so items, badges and plain text in the menu all follow. Do not
   "fix" this by piling specificity onto .dropdown-item. */
html.dark .dropdown-menu { background-color: var(--bg-card); border-color: var(--border); color: var(--text-dark); }
html.dark .dropdown-item { color: var(--text-dark); }
html.dark .dropdown-item:hover { background-color: var(--bg-surface); color: var(--primary); }
html.dark .card { background-color: var(--bg-card) !important; border-color: var(--border) !important; }
html.dark .tool-card:hover { box-shadow: 0 4px 12px var(--shadow-hover) !important; }
html.dark .bg-white { background-color: var(--bg-card) !important; }
html.dark .bg-light { background-color: var(--bg-surface) !important; }
html.dark .border-bottom { border-color: var(--border) !important; }
html.dark .border-top { border-color: var(--border) !important; }
html.dark .border { border-color: var(--border) !important; }
html.dark .text-dark { color: var(--text-dark) !important; }
html.dark .text-muted { color: var(--text-muted) !important; }
html.dark .form-control, html.dark .form-select { background-color: var(--bg-input); color: var(--text-dark); border-color: var(--border); }
html.dark .form-control:focus, html.dark .form-select:focus { background-color: var(--bg-input); color: var(--text-dark); border-color: var(--primary); }
html.dark .form-control::placeholder { color: var(--text-muted); }
html.dark .modal-content { background-color: var(--bg-card); color: var(--text-dark); }
html.dark .btn-close { filter: invert(1); }
html.dark .table { color: var(--text-dark); }
html.dark .table th, html.dark .table td { border-color: var(--border); }
html.dark .nav-tabs .nav-link { color: var(--text-muted); }
html.dark .nav-tabs .nav-link.active { background-color: var(--bg-card); color: var(--primary); border-color: var(--border) var(--border) var(--bg-card); }
html.dark .nav-tabs { border-color: var(--border); }
html.dark #chat-messages .ai-msg { background: var(--bg-surface); color: var(--text-dark); }
html.dark .chat-model-label { color: #a5b4fc; background: #1e1b4b; }
html.dark .chat-code { background: var(--code-bg); }
html.dark .accordion-button { background-color: var(--bg-card); color: var(--text-dark); }
html.dark .accordion-button:not(.collapsed) { background-color: var(--primary-bg); color: var(--primary); }
html.dark .accordion-body { background-color: var(--bg-card); color: var(--text-dark); }
html.dark footer.bg-dark { background-color: var(--bg-footer) !important; }
html.dark .shadow-sm { box-shadow: 0 1px 3px var(--shadow-color) !important; }
html.dark .tool-link { background-color: var(--bg-card); border-color: var(--border) !important; color: var(--text-dark); }
html.dark .tool-link:hover { border-color: var(--primary) !important; background: var(--primary-bg); }
html.dark .cat-card { background-color: var(--bg-card); }
html.dark .progress { background-color: var(--border); }
html.dark .breadcrumb { color: var(--text-muted); }
html.dark .breadcrumb a { color: var(--text-muted); }
/* Override ALL inline backgrounds in dark mode */
html.dark [style*="background:#fafbff" i],
html.dark [style*="background:#fff" i],
html.dark [style*="background:#ffffff" i],
html.dark [style*="background:#f0f2ff" i],
html.dark [style*="background:#F0FDF4" i],
html.dark [style*="background:#f3f4f6" i],
html.dark [style*="background:#f8f9fa" i],
html.dark [style*="background:#f9fafb" i],
html.dark [style*="background:white" i],
html.dark [style*="background: #fff" i],
html.dark [style*="background: #fafbff" i],
html.dark [style*="background:#e8f5e9" i] { background-color: var(--bg-surface) !important; }

html.dark [style*="background:#DCFCE7" i],
html.dark [style*="background:#f0f2ff" i] { background-color: var(--bg-card) !important; }

html.dark [style*="border:1px solid #f0f0f0" i],
html.dark [style*="border:1px solid #eee" i],
html.dark [style*="border:1px solid #DCFCE7" i],
html.dark [style*="border-bottom:1px solid" i] { border-color: var(--border) !important; }

html.dark [style*="color:#374151" i],
html.dark [style*="color:#555" i],
html.dark [style*="color:#111827" i] { color: var(--text-dark) !important; }

html.dark section { background-color: var(--bg-body) !important; }
html.dark section[style] { background-color: var(--bg-surface) !important; }
html.dark .container .card { background-color: var(--bg-card) !important; }

/* Fix tool category cards on homepage */
html.dark .card[style*="border-radius" i] { background-color: var(--bg-card) !important; color: var(--text-dark) !important; }
html.dark .card[style*="border-radius" i]:hover { border-color: var(--primary) !important; }

/* Fix the hero/main area */
html.dark main { background-color: var(--bg-body) !important; }

/* Fix popover */
html.dark .popover { background-color: var(--bg-card); border-color: var(--border); }
html.dark .popover-body { color: var(--text-dark); }

/* Fix badge */
html.dark .badge.bg-success { background-color: var(--primary) !important; }
html.dark .badge.bg-primary { background-color: var(--primary) !important; }

html.dark .btn-outline-secondary { color: var(--text-muted); border-color: var(--border); }
html.dark .btn-outline-secondary:hover { background-color: var(--bg-surface); color: var(--text-dark); }
html.dark .input-group .form-control { border-color: var(--border); }

/* Fix ALL hardcoded dark text colors in dark mode */
html.dark [style*="color:#374151" i],
html.dark [style*="color:#555" i],
html.dark [style*="color:#111827" i],
html.dark [style*="color:#222" i],
html.dark [style*="color:#1a1a1a" i],
html.dark [style*="color: #374151" i],
html.dark [style*="color: #222" i] { color: var(--text-dark) !important; }

/* Fix suggestion/pill buttons */
html.dark .btn-outline-secondary,
html.dark .btn-light { color: var(--text-dark) !important; border-color: var(--border) !important; background: var(--bg-card) !important; }

/* Fix tab links */
html.dark .nav-link { color: var(--text-muted) !important; }
html.dark .nav-link.active { color: var(--primary) !important; }

/* Fix category/tool cards text */
html.dark .card .fw-bold,
html.dark .card strong,
html.dark .card h2,
html.dark .card h3,
html.dark .card h5,
html.dark .card h6 { color: var(--text-dark) !important; }
html.dark .card .text-muted,
html.dark .card small { color: var(--text-muted) !important; }

/* Fix homepage hero text */
html.dark .home-logo { color: var(--text-dark) !important; }
html.dark .home-logo span { color: var(--primary) !important; }

/* Fix benefits bar checkmarks */
html.dark .text-success { color: #4ADE80 !important; }

/* Fix input placeholder in dark mode */
html.dark input::placeholder,
html.dark textarea::placeholder { color: #777 !important; }

/* Fix all remaining inline color:#xxx that's dark */
html.dark p, html.dark span, html.dark div, html.dark li, html.dark td, html.dark th,
html.dark label, html.dark small, html.dark a:not(.btn) {
    color: inherit;
}

/* Fix list-group, alerts */
html.dark .list-group-item { background-color: var(--bg-card); color: var(--text-dark); border-color: var(--border); }
html.dark .alert { background-color: var(--bg-card); color: var(--text-dark); border-color: var(--border); }

/* Fix the star rating section */
html.dark [style*="background:#fafbff" i] { background-color: var(--bg-surface) !important; }

/* Border dashed zones */
html.dark [style*="border-color:#dee2e6" i] { border-color: var(--border) !important; }
html.dark .border-dashed { border-color: var(--border) !important; }

/* Homepage submit button */
.btn-send {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    background: var(--primary);
    color: #fff;
    border: none;
    border-radius: 8px;
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background .15s;
}
.btn-send:hover { background: var(--primary-hover); }

/* Homepage input wrapper needs position relative */
#home-form { position: relative; }

/* ============================================================
   MOBILE POLISH — site-wide
   The Bootstrap defaults look heavy on phones: oversized
   breadcrumbs, inputs that trigger iOS zoom, dense card
   padding, individually-bordered button groups inside forms.
   Anchor patterns from ChatGPT/Claude/Perplexity mobile.
   Desktop is untouched.
   ============================================================ */
@media (max-width: 767.98px) {

    /* iOS zooms whenever a focused input has font-size < 16px.
       Globally enforce 16px on every form input. (Use !important
       to override Bootstrap's .form-control-sm 0.875rem rule.) */
    input.form-control,
    input[type="text"],
    input[type="email"],
    input[type="password"],
    input[type="search"],
    input[type="number"],
    input[type="tel"],
    input[type="url"],
    textarea,
    textarea.form-control,
    select.form-select,
    select.form-control { font-size: 16px !important; }

    /* Slim the breadcrumb bar — saves 10–14px of vertical space
       on every tool page. The bug-report icon stays for desktop;
       on mobile we drop the label-only span anyway. */
    .breadcrumbs-bar {
        padding: .15rem 0 !important;
    }
    .breadcrumbs-bar .breadcrumb {
        font-size: .72rem !important;
    }

    /* Card-body density: Bootstrap defaults to 1rem padding which is
       generous on a phone. Trim to 0.75rem so more of each card fits
       above the fold. Doesn't affect cards with explicit p-4 / p-5. */
    .card-body { padding: .75rem !important; }
    .card-body.p-4 { padding: 1rem !important; } /* keep marketing cards comfortable */

    /* Touch-target minimum: tap targets below 36px feel unreliable.
       Most BS button-sm renders to 31px. Bump to 36 so checkout
       and tool action bars stop misfiring. */
    .btn-sm { min-height: 36px; padding-top: .35rem; padding-bottom: .35rem; }

    /* Pill-input pattern: any form whose direct children are an input
       group with an input/textarea + adjacent buttons can opt in by
       adding `.input-pill` to the row container. Strips internal
       borders + wraps the row in one rounded outer border.
       Matches ChatGPT/Claude/Perplexity mobile.

       Used by: chat.html (#chat-form), chat_compare.html composers,
       coder.html chat input, future tool pages. */
    .input-pill {
        background: var(--bg-input, #fff);
        border: 1px solid #dadce0;
        border-radius: 24px;
        padding: 6px 8px;
        align-items: center !important;
        gap: 4px !important;
        box-shadow: none;
    }
    .input-pill .form-control,
    .input-pill input,
    .input-pill textarea {
        border: none !important;
        background: transparent !important;
        box-shadow: none !important;
        padding: 8px 4px !important;
    }
    .input-pill .form-control:focus,
    .input-pill input:focus,
    .input-pill textarea:focus {
        outline: none !important;
        box-shadow: none !important;
    }
    .input-pill .btn-outline-secondary,
    .input-pill .btn-outline-primary,
    .input-pill .btn-outline-dark {
        border: none !important;
        background: transparent !important;
        color: var(--text-muted, #6b7280) !important;
        padding: 6px 8px !important;
        align-self: center !important;
    }
    .input-pill .btn-primary,
    .input-pill button[type="submit"] {
        border-radius: 18px !important;
        align-self: center !important;
    }
}

/* Body-class hooks for app-style pages (chat, coder, etc.) that
   want to suppress site chrome (breadcrumbs) on mobile so the app
   surface gets the full viewport. Set via {% block body_class %}is-chat-full{% endblock %}. */
@media (max-width: 767.98px) {
    body.is-chat-full .breadcrumbs-bar { display: none !important; }
    body.is-app-full .breadcrumbs-bar { display: none !important; }
}

/* Nav utility toggles (language globe + dark-mode moon) --------------------
   The globe is an <a class="nav-link"> and the toggle is a <button
   class="nav-link">. Inside the flex row a button and an anchor do not share
   a baseline, so the moon rendered a few pixels higher than the globe.
   Centre both in their own box and give the glyphs one line-height, rather
   than nudging one with a margin (which breaks again at the next font size).
   Scoped to .nav-utility so the main nav keeps Bootstrap's stock behaviour. */
.nav-utility { align-items: center; }
.nav-utility .nav-link {
    display: inline-flex;
    align-items: center;
    line-height: 1;
}
.nav-utility .nav-link > i {
    display: inline-block;
    line-height: 1;
    font-size: 1rem;
    vertical-align: middle;
}


/* ==========================================================================
   Dark mode: inline light backgrounds
   --------------------------------------------------------------------------
   772 elements across 332 templates carry an INLINE style="background:#fff"
   or a pastel tint. An inline style beats any stylesheet rule, so `html.dark`
   never reached them: the panel stayed light while the text inverted to light,
   giving light-on-light. That is the "Got a personal brand?" banner and the
   "Start Using Free.ai Today" section, both effectively invisible in dark mode.

   `!important` in a stylesheet DOES beat a non-important inline declaration,
   so these override without touching 332 files -- and a file edited later
   inherits the fix instead of needing to be found again.

   Anchored on `background:` / `background-color:` so `color:#fff` is never
   matched. Both spaced and unspaced forms, because templates write both.

   BACKGROUND ONLY, deliberately. The text on these panels is already light in
   dark mode -- that is why it vanished -- so darkening the surface restores it.
   Setting `color` here as well would override the children that legitimately
   set their own, and is how a "contrast fix" turns into a different bug.

   Hue is preserved per family: a green success panel stays green-tinted, a red
   warning stays red. Flattening them all to one grey would fix the contrast
   and lose the meaning the colour was carrying.
   ========================================================================== */

/* neutral / white */
html.dark [style*="background:#fff" i],
html.dark [style*="background: #fff" i],
html.dark [style*="background-color:#fff" i],
html.dark [style*="background-color: #fff" i],
html.dark [style*="background:#ffffff" i],
html.dark [style*="background: #ffffff" i],
html.dark [style*="background-color:#ffffff" i],
html.dark [style*="background-color: #ffffff" i],
html.dark [style*="background:#fafafa" i],
html.dark [style*="background: #fafafa" i],
html.dark [style*="background-color:#fafafa" i],
html.dark [style*="background-color: #fafafa" i],
html.dark [style*="background:#f9fafb" i],
html.dark [style*="background: #f9fafb" i],
html.dark [style*="background-color:#f9fafb" i],
html.dark [style*="background-color: #f9fafb" i],
html.dark [style*="background:#f8f9fa" i],
html.dark [style*="background: #f8f9fa" i],
html.dark [style*="background-color:#f8f9fa" i],
html.dark [style*="background-color: #f8f9fa" i],
html.dark [style*="background:#f8fafc" i],
html.dark [style*="background: #f8fafc" i],
html.dark [style*="background-color:#f8fafc" i],
html.dark [style*="background-color: #f8fafc" i],
html.dark [style*="background:#f3f4f6" i],
html.dark [style*="background: #f3f4f6" i],
html.dark [style*="background-color:#f3f4f6" i],
html.dark [style*="background-color: #f3f4f6" i],
html.dark [style*="background:#e5e7eb" i],
html.dark [style*="background: #e5e7eb" i],
html.dark [style*="background-color:#e5e7eb" i],
html.dark [style*="background-color: #e5e7eb" i],
html.dark [style*="background:#e2e8f0" i],
html.dark [style*="background: #e2e8f0" i],
html.dark [style*="background-color:#e2e8f0" i],
html.dark [style*="background-color: #e2e8f0" i] {
    background-color: var(--bg-card) !important;
}

/* green (success / brand tint) */
html.dark [style*="background:#f0fdf4" i],
html.dark [style*="background: #f0fdf4" i],
html.dark [style*="background-color:#f0fdf4" i],
html.dark [style*="background-color: #f0fdf4" i],
html.dark [style*="background:#dcfce7" i],
html.dark [style*="background: #dcfce7" i],
html.dark [style*="background-color:#dcfce7" i],
html.dark [style*="background-color: #dcfce7" i],
html.dark [style*="background:#ecfdf5" i],
html.dark [style*="background: #ecfdf5" i],
html.dark [style*="background-color:#ecfdf5" i],
html.dark [style*="background-color: #ecfdf5" i],
html.dark [style*="background:#d1fae5" i],
html.dark [style*="background: #d1fae5" i],
html.dark [style*="background-color:#d1fae5" i],
html.dark [style*="background-color: #d1fae5" i] {
    background-color: #0f2417 !important;
}

/* blue (info tint) */
html.dark [style*="background:#f0f9ff" i],
html.dark [style*="background: #f0f9ff" i],
html.dark [style*="background-color:#f0f9ff" i],
html.dark [style*="background-color: #f0f9ff" i],
html.dark [style*="background:#eff6ff" i],
html.dark [style*="background: #eff6ff" i],
html.dark [style*="background-color:#eff6ff" i],
html.dark [style*="background-color: #eff6ff" i],
html.dark [style*="background:#dbeafe" i],
html.dark [style*="background: #dbeafe" i],
html.dark [style*="background-color:#dbeafe" i],
html.dark [style*="background-color: #dbeafe" i],
html.dark [style*="background:#e0f2fe" i],
html.dark [style*="background: #e0f2fe" i],
html.dark [style*="background-color:#e0f2fe" i],
html.dark [style*="background-color: #e0f2fe" i] {
    background-color: #0e1c2b !important;
}

/* red (danger tint) */
html.dark [style*="background:#fef2f2" i],
html.dark [style*="background: #fef2f2" i],
html.dark [style*="background-color:#fef2f2" i],
html.dark [style*="background-color: #fef2f2" i],
html.dark [style*="background:#fff5f5" i],
html.dark [style*="background: #fff5f5" i],
html.dark [style*="background-color:#fff5f5" i],
html.dark [style*="background-color: #fff5f5" i],
html.dark [style*="background:#fecaca" i],
html.dark [style*="background: #fecaca" i],
html.dark [style*="background-color:#fecaca" i],
html.dark [style*="background-color: #fecaca" i],
html.dark [style*="background:#fee2e2" i],
html.dark [style*="background: #fee2e2" i],
html.dark [style*="background-color:#fee2e2" i],
html.dark [style*="background-color: #fee2e2" i] {
    background-color: #2a1416 !important;
}

/* amber (warning tint) */
html.dark [style*="background:#fef3c7" i],
html.dark [style*="background: #fef3c7" i],
html.dark [style*="background-color:#fef3c7" i],
html.dark [style*="background-color: #fef3c7" i],
html.dark [style*="background:#fffbeb" i],
html.dark [style*="background: #fffbeb" i],
html.dark [style*="background-color:#fffbeb" i],
html.dark [style*="background-color: #fffbeb" i],
html.dark [style*="background:#fef9c3" i],
html.dark [style*="background: #fef9c3" i],
html.dark [style*="background-color:#fef9c3" i],
html.dark [style*="background-color: #fef9c3" i],
html.dark [style*="background:#fde68a" i],
html.dark [style*="background: #fde68a" i],
html.dark [style*="background-color:#fde68a" i],
html.dark [style*="background-color: #fde68a" i] {
    background-color: #2b2210 !important;
}

/* indigo / purple tint */
html.dark [style*="background:#f0f2ff" i],
html.dark [style*="background: #f0f2ff" i],
html.dark [style*="background-color:#f0f2ff" i],
html.dark [style*="background-color: #f0f2ff" i],
html.dark [style*="background:#fafbff" i],
html.dark [style*="background: #fafbff" i],
html.dark [style*="background-color:#fafbff" i],
html.dark [style*="background-color: #fafbff" i],
html.dark [style*="background:#f8f9ff" i],
html.dark [style*="background: #f8f9ff" i],
html.dark [style*="background-color:#f8f9ff" i],
html.dark [style*="background-color: #f8f9ff" i],
html.dark [style*="background:#eef0ff" i],
html.dark [style*="background: #eef0ff" i],
html.dark [style*="background-color:#eef0ff" i],
html.dark [style*="background-color: #eef0ff" i],
html.dark [style*="background:#f3e8ff" i],
html.dark [style*="background: #f3e8ff" i],
html.dark [style*="background-color:#f3e8ff" i],
html.dark [style*="background-color: #f3e8ff" i],
html.dark [style*="background:#ede9fe" i],
html.dark [style*="background: #ede9fe" i],
html.dark [style*="background-color:#ede9fe" i],
html.dark [style*="background-color: #ede9fe" i] {
    background-color: #171a2e !important;
}

/* Gradients made of the same tints -- the hero CTA band is
   linear-gradient(135deg,#f0fdf4,#ecfdf5). An attribute match on the hex still
   works because the gradient string contains it, but background-color does not
   override background-image, so the gradient must be cleared explicitly. */
html.dark [style*="linear-gradient" i][style*="#f0fdf4" i],
html.dark [style*="linear-gradient" i][style*="#ecfdf5" i],
html.dark [style*="linear-gradient" i][style*="#f0f9ff" i],
html.dark [style*="linear-gradient" i][style*="#eff6ff" i],
html.dark [style*="linear-gradient" i][style*="#fff" i] {
    background-image: none !important;
    background-color: var(--bg-surface) !important;
}

/* Dark mode: hover states -------------------------------------------------
   Card and nav hovers were written for a light page: they lighten the surface
   or set a near-black text colour. In dark mode that lands dark-text-on-dark
   or washes the label out just as the pointer arrives, so a card is readable
   until you try to use it. Hover should RAISE contrast, never drop it. */
html.dark .cat-card:hover,
html.dark .tool-card:hover,
html.dark .card:hover {
    background-color: var(--bg-surface) !important;
    border-color: var(--primary) !important;
}
html.dark .cat-card:hover,
html.dark .cat-card:hover h6,
html.dark .cat-card:hover p,
html.dark .tool-card:hover,
html.dark .tool-card:hover h6,
html.dark .tool-card:hover p,
html.dark .card:hover .card-title {
    color: var(--text-dark) !important;
}
html.dark .home-tabs .nav-link:hover,
html.dark .quick-tools a:hover,
html.dark .list-group-item-action:hover,
html.dark .dropdown-item:hover {
    background-color: var(--bg-surface) !important;
    color: var(--primary) !important;
}
/* Bootstrap components whose defaults assume a light page. `.breadcrumb-item
   .active` ships rgba(33,37,41,.75) — near-black — which the audit measured at
   1.22:1 against the dark body. */
html.dark .breadcrumb-item.active,
html.dark .breadcrumb-item + .breadcrumb-item::before {
    color: var(--text-muted) !important;
}
html.dark .table { --bs-table-color: var(--text-dark); --bs-table-bg: transparent; }
html.dark .accordion-button { background-color: var(--bg-card); color: var(--text-dark); }
html.dark .accordion-body { background-color: var(--bg-card); color: var(--text-dark); }

/* ---------------------------------------------------------------------------
   Dark mode, part 3: the INK that pairs with an inverted inline background.

   The block above inverts inline `background:#<light tint>` to a dark tint.
   It did not touch the inline `color:` sitting next to it, so a badge written
   as `style="background:#DCFCE7;color:#166534"` — a light green chip with
   green-800 ink — became green-800 ink on a DARK chip. Measured 2026-09-05:
   2.58:1 across the tool pages ("Commercial use OK", "Fast", "Free" pills),
   and the same shape in blue, amber and purple.

   Inverting a background without inverting the ink that was chosen FOR that
   background is only half a theme. Each replacement keeps the hue and lifts
   the lightness to sit on the dark tint the block above produces.

   `!important` is required: the source is an inline style attribute, which
   beats any non-important rule regardless of specificity.
   --------------------------------------------------------------------------- */
html.dark [style*="color:#166534" i], html.dark [style*="color: #166534" i],
html.dark [style*="color:#15803d" i], html.dark [style*="color: #15803d" i],
html.dark [style*="color:#065f46" i], html.dark [style*="color: #065f46" i],
html.dark [style*="color:#14532d" i], html.dark [style*="color: #14532d" i] {
    color: #6ee7a0 !important;
}
html.dark [style*="color:#1E40AF" i], html.dark [style*="color: #1E40AF" i],
html.dark [style*="color:#1e40af" i], html.dark [style*="color: #1e40af" i],
html.dark [style*="color:#1e3a8a" i], html.dark [style*="color: #1e3a8a" i],
html.dark [style*="color:#075985" i], html.dark [style*="color: #075985" i] {
    color: #7fb4ff !important;
}
html.dark [style*="color:#92400E" i], html.dark [style*="color: #92400E" i],
html.dark [style*="color:#92400e" i], html.dark [style*="color: #92400e" i],
html.dark [style*="color:#78350f" i], html.dark [style*="color: #78350f" i],
html.dark [style*="color:#854d0e" i], html.dark [style*="color: #854d0e" i] {
    color: #fcbf5a !important;
}
html.dark [style*="color:#6B21A8" i], html.dark [style*="color: #6B21A8" i],
html.dark [style*="color:#6b21a8" i], html.dark [style*="color: #6b21a8" i],
html.dark [style*="color:#581c87" i], html.dark [style*="color: #581c87" i] {
    color: #d6a8ff !important;
}
html.dark [style*="color:#991B1B" i], html.dark [style*="color: #991B1B" i],
html.dark [style*="color:#991b1b" i], html.dark [style*="color: #991b1b" i],
html.dark [style*="color:#7f1d1d" i], html.dark [style*="color: #7f1d1d" i],
html.dark [style*="color:#b91c1c" i], html.dark [style*="color: #b91c1c" i] {
    color: #ff9d9d !important;
}

/* `.text-dark` is a CONTRAST utility, not a theme statement. Bootstrap's
   `bg-info` (#0dcaf0) and `bg-warning` (#ffc107) are light and are NOT
   inverted in dark mode, so a `badge bg-info text-dark` deliberately pairs
   dark ink with a light chip. The blanket `html.dark .text-dark { color:
   var(--text-dark) !important }` flipped that ink to near-white ON THE LIGHT
   CHIP — measured 1.72:1 on /image/'s "SDXL only" badge. Put the dark ink
   back wherever it is doing contrast work against a background that stays
   light. */
html.dark .bg-info.text-dark, html.dark .bg-warning.text-dark,
html.dark .bg-info .text-dark, html.dark .bg-warning .text-dark,
html.dark .badge.bg-info, html.dark .badge.bg-warning {
    color: #111827 !important;
}

/* A `.btn` with NO colour variant falls back to Bootstrap's
   `--bs-btn-color: #212529`, which is invisible on a dark surface. The
   inactive half of the pricing Monthly|Annual toggle is exactly this shape
   and measured 1.19:1 — a button you cannot read the label of. Scoped by
   `:not()` to the variants that carry their own colour, so a `btn-warning`
   or `btn-light` (dark ink on a light fill, correctly) is untouched. */
html.dark .btn:not([class*="btn-primary"]):not([class*="btn-secondary"]):not([class*="btn-success"]):not([class*="btn-danger"]):not([class*="btn-warning"]):not([class*="btn-info"]):not([class*="btn-light"]):not([class*="btn-dark"]):not([class*="btn-link"]):not([class*="btn-outline"]):not([style*="color" i]) {
    color: var(--text-dark);
}

/* A filled badge carries its OWN contrast pair and must not take the theme's
   body ink. `html.dark span { color: inherit }` handed `.badge.bg-success` the
   page ink (#f0f0f0) instead of Bootstrap's #fff, measured 2.89:1 on #16a34a —
   below the 3:1 floor purely from the 15 points of grey. Pure white on the same
   fill is 3.26:1. Same reasoning as the .text-dark rule above: a coloured chip
   is a self-contained surface, so the theme must leave both of its colours
   alone. */
html.dark .badge.bg-success, html.dark .badge.bg-primary,
html.dark .badge.bg-danger, html.dark .badge.bg-dark,
html.dark .badge.bg-secondary {
    color: #fff !important;
}

/* An inline-filled badge, same rule as the .bg-* ones above: it brings its own
   background so it must bring its own ink, not the page's. The pricing/home
   "Most Popular" chip is `class="badge" style="background:#15803D"` with no
   colour, so `html.dark span { color: inherit }` gave it #f0f0f0 -- 2.89:1,
   under the floor by 15 points of grey. #fff on the same fill is 3.26:1. */
html.dark .badge[style*="background:#15803D" i],
html.dark .badge[style*="background: #15803D" i],
html.dark .badge[style*="background:#15803D" i] {
    color: #fff !important;
}

/* Bootstrap's `-subtle` background utilities are LIGHT and stay light for us:
   they flip only under `[data-bs-theme=dark]`, which this site does not use
   (the theme is `html.dark`). So a `badge bg-success-subtle` keeps its pale
   green chip while our theme handed it pale green ink -- measured 1.34:1 on
   /models/'s "Self-hosted" badge. Restore the dark ink the light chip was
   designed for. Same principle as .text-dark and the filled badges: a chip
   whose background the theme does not change must keep both of its colours. */
html.dark [class*="bg-success-subtle"], html.dark [class*="bg-primary-subtle"],
html.dark [class*="bg-info-subtle"], html.dark [class*="bg-warning-subtle"],
html.dark [class*="bg-danger-subtle"], html.dark [class*="bg-secondary-subtle"],
html.dark [class*="bg-light-subtle"] {
    color: #111827 !important;
}

/* --- Light mode too. The audit runs both themes and these fail in LIGHT. --- */

/* Bootstrap's warning amber (#ffc107) as TEXT on white is 1.63:1 -- measured on
   /models/'s "External" filter button, a control people are meant to read and
   click. Amber is a fill colour, not an ink colour. Darkened to the same hue at
   a legible lightness (4.6:1 on white); the hover state still fills amber with
   dark text, so the button's identity is unchanged. */
.btn-outline-warning { --bs-btn-color: #8a6100; --bs-btn-border-color: #e0a800; }
html.dark .btn-outline-warning { --bs-btn-color: #ffc107; }

/* Our brand green on Bootstrap's pale cyan alert is 2.82:1 -- measured on
   /video/'s "Use the Movie tool →" link. Darken one step inside info panels
   only; the same green on white (7.1:1) and on our own tints is untouched. */
.alert-info a, .alert-info a:hover { color: #12602f; }
/* The /video/ instance writes the green INLINE, which beats any non-important
   rule whatever its specificity — so the rule above did nothing for the one
   element that produced the finding. Scoped to .alert-info so the same inline
   green on white (7.1:1) is untouched everywhere else. */
/* PER THEME. The un-scoped version of this fixed light mode and broke dark:
   in dark the .alert-info background IS inverted to #141414, so the darkened
   green landed at 2.40:1 — the same finding, one theme over. An !important
   override of an inline colour has to state a value for every background the
   theme can put behind it. */
html:not(.dark) .alert-info a[style*="color:#16A34A" i],
html:not(.dark) .alert-info a[style*="color: #16A34A" i] { color: #12602f !important; }
html.dark .alert-info a[style*="color:#16A34A" i],
html.dark .alert-info a[style*="color: #16A34A" i] { color: var(--primary-light) !important; }
html.dark .alert-info a, html.dark .alert-info a:hover { color: var(--primary-light); }
