/* Keywords Everywhere Tools - homepage styles
 *
 * Visual identity matches keywordseverywhere.com:
 *  - Poppins type
 *  - Red/maroon hero background (matches the "stripes" hero)
 *  - White cards on a light grey body
 */

:root {
    /* Brand */
    --brand-red:       #a63534;
    --brand-red-dark:  #8e2c2b;
    --brand-red-light: #cb5f59;
    --brand-red-soft:  #fdecec;
    --brand-red-tint:  rgba(166, 53, 52, 0.10);

    /* Ink */
    --ink:        #14181d;
    --ink-700:    #41494f;
    --ink-500:    #6b7280;
    --ink-400:    #9ca3af;
    --ink-300:    #d1d5db;
    --ink-200:    #e5e7eb;
    --ink-100:    #eef0f3;
    --ink-50:     #f4f6f9;
    --ink-25:     #fafbfd;

    /* Layered shadow stack */
    --shadow-xs: 0 1px 2px rgba(20, 24, 29, 0.04);
    --shadow-sm: 0 1px 2px rgba(20, 24, 29, 0.04), 0 2px 6px rgba(20, 24, 29, 0.04);
    --shadow-md: 0 1px 3px rgba(20, 24, 29, 0.05), 0 6px 16px rgba(20, 24, 29, 0.06);
    --shadow-lg: 0 1px 3px rgba(20, 24, 29, 0.06), 0 12px 32px rgba(20, 24, 29, 0.08);
    --shadow-xl: 0 1px 3px rgba(20, 24, 29, 0.08), 0 20px 50px rgba(20, 24, 29, 0.12);

    /* Type / numeric helpers */
    --tnum: "tnum" 1, "kern" 1;
    --mono: SFMono-Regular, ui-monospace, Menlo, Consolas, "Roboto Mono", monospace;

    /* Accent (links inside tool content) */
    --link:       #1858a8;
    --link-dark:  #0d3a76;

    /* Semantic palette (used by score/status badges and the errors region) */
    --good-bg:    #d1fae5;
    --good-fg:    #065f46;
    --mid-bg:     #fef3c7;
    --mid-fg:     #92400e;
    --bad-bg:     #fee2e2;
    --bad-fg:     #991b1b;

    /* Focus ring used by every form input */
    --focus-ring: 0 0 0 4px rgba(166, 53, 52, 0.18);

    /* Radii */
    --r-sm: 6px;
    --r:    10px;
    --r-lg: 14px;
}

* {
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
}
html, body {
    margin: 0;
    padding: 0;
}

body {
    font-family: Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    font-weight: 300;
    font-size: 16px;
    line-height: 1.5;
    color: var(--ink-700);
    background-color: #f7f8fa;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    .progress-fill { animation: none; }
}

a {
    color: #007bff;
    text-decoration: none;
}

a:hover {
    color: #0056b3;
}

.container {
    width: 100%;
    max-width: 1140px;
    margin: 0 auto;
    padding: 0 20px;
}

/* Header
 *
 * Fixed-size hero - same height on every page (homepage, tool, future
 * tools). The min-height + 2-line lead clamp guarantees pages with short
 * leads don't shrink and pages with long leads don't grow. Total visible
 * height ~200px, set in one place so future pages stay consistent
 * without per-page CSS. Shrink content sizes here too rather than
 * per-page. */
/* The red header is now a slim top bar that only carries the brand
   lockup (logo + wordmark) and the login / user-bar. The page-level
   heading and lead live below in `.page-hero` on a light background,
   matching the pattern on keywordseverywhere.com. */
.site-header {
    position: relative;
    background-color: #a63534;
    background-image:
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'><filter id='n'><feTurbulence baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.06 0'/></filter><rect width='256' height='256' filter='url(%23n)'/></svg>"),
        linear-gradient(180deg, #b03a39 0%, #a63534 60%, #8e2c2b 100%);
    background-size: 256px 256px, auto;
    background-blend-mode: overlay, normal;
    color: #fff;
    padding: 12px 0;
    overflow: hidden;
}

/* Container is the layout child so the flex parent can position it.
   `align-items: flex-start` (above) keeps the logo, h1, and lead at the
   same Y position on every page; pages with shorter copy let the unused
   slack fall at the bottom of the red instead of distributing it
   symmetrically (which would otherwise push the logo down further on
   short pages than on long ones).

   `max-width: none` drops the shared 1140px cap so the header content
   extends edge-to-edge, matching `.tool-main > .container` below.
   Without this, on wide viewports the header would visibly narrow while
   the tool body (form card, results table) extended further out, which
   reads as a layout bug. */
.site-header > .container {
    width: 100%;
    max-width: none;
}

/* Hairline accent at the very bottom of the red bar. Reads as a
   deliberate seam between the branded top bar and the light hero
   section below. */
.site-header::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 1px;
    background: linear-gradient(90deg,
        transparent 0%,
        rgba(255, 255, 255, 0.18) 18%,
        rgba(255, 255, 255, 0.28) 50%,
        rgba(255, 255, 255, 0.18) 82%,
        transparent 100%);
    pointer-events: none;
}

.site-header .container {
    position: relative;
    z-index: 1;
}

/* Top row inside the red header: brand on the left, account/login widget
   on the right. The red bar holds nothing else, so there is no bottom
   margin here; the entire bar's height is controlled by `.site-header`'s
   padding plus this row's intrinsic content height. */
.site-header-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}


/* Account / user bar - rendered by includes/header.php only when the
   visitor is authenticated. Sits at the top-right of the brand-red hero
   so account context follows the user across every tool. */
.user-bar {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    padding: 6px 12px;
    background: rgba(255, 255, 255, 0.12);
    border: 1px solid rgba(255, 255, 255, 0.20);
    border-radius: 999px;
    color: #fff;
    font-size: 12.5px;
    font-weight: 400;
    line-height: 1.2;
    backdrop-filter: blur(2px);
    max-width: 100%;
}

.user-bar-icon {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    opacity: 0.9;
    margin-right: 5px;
    vertical-align: -2px;
}

.user-bar-email {
    display: inline-flex;
    align-items: center;
    color: rgba(255, 255, 255, 0.96);
    font-feature-settings: var(--tnum);
    font-weight: 500;
    min-width: 0;
}

.user-bar-plan {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    font-weight: 700;
    font-size: 10px;
    letter-spacing: 0.6px;
    text-transform: uppercase;
}

/* Plan colors on the dark red bg. Free reads as a soft white chip; paid
   plans keep their identifying hues. */
.user-bar-plan--free     { background: rgba(255, 255, 255, 0.22); color: #fff; }
.user-bar-plan--bronze   { background: #cd7f32; color: #fff; }
.user-bar-plan--silver   { background: #d6d6d6; color: #1a1a1a; }
.user-bar-plan--gold     { background: #f5c542; color: #2a1a00; }
.user-bar-plan--platinum {
    background: linear-gradient(135deg, #e7eaee 0%, #b9c1cb 100%);
    color: #1a1a1a;
}

.user-bar-credits {
    color: rgba(255, 255, 255, 0.95);
    font-feature-settings: var(--tnum);
    white-space: nowrap;
}
.user-bar-credits strong {
    font-weight: 700;
    color: #fff;
}

.user-bar-logout {
    color: rgba(255, 255, 255, 0.85);
    font-weight: 600;
    font-size: 12px;
    letter-spacing: 0.2px;
    text-decoration: none;
    border-left: 1px solid rgba(255, 255, 255, 0.30);
    padding-left: 12px;
}
.user-bar-logout:hover {
    color: #fff;
    text-decoration: underline;
}

/* Login link in the top-right of the red header when the visitor is
   anonymous. Outline-button feel that reads on the dark bg. */
.login-link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 14px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.45);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.2px;
    text-decoration: none;
    transition: background 0.15s ease, border-color 0.15s ease;
}
.login-link:hover {
    background: rgba(255, 255, 255, 0.18);
    border-color: rgba(255, 255, 255, 0.7);
    color: #fff;
}
.login-link-icon {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
}

/* Mobile overrides for the red top bar live in the @media block lower
   down (after the `.site-header .brand-*` base rules), because CSS
   source order resolves equal-specificity rules and putting mobile
   overrides BEFORE the base rules would not win. */

/* ========================================================================
   Project-wide inline icon. Sized for buttons / labels at body type. The
   negative vertical-align nudges it onto the text baseline when sitting
   inside an inline-flex parent.
   ======================================================================== */
.icon {
    display: inline-block;
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    vertical-align: -2px;
}

/* ========================================================================
   Project-wide primary button. Used in tool forms and the login page.
   ======================================================================== */
.primary-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: linear-gradient(180deg, var(--brand-red-light) 0%, var(--brand-red) 100%);
    color: #fff;
    border: 0;
    border-radius: var(--r-sm);
    padding: 11px 20px;
    font: inherit;
    font-weight: 600;
    letter-spacing: 0.1px;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(20, 24, 29, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.18);
    transition: transform 0.12s, box-shadow 0.18s, filter 0.15s;
}
.primary-btn .icon { transition: transform 0.18s; }
.primary-btn:hover:not(:disabled) {
    filter: brightness(1.05);
    box-shadow: 0 4px 12px rgba(166, 53, 52, 0.30), inset 0 1px 0 rgba(255, 255, 255, 0.22);
}
.primary-btn:hover:not(:disabled) .icon { transform: translateX(2px); }
.primary-btn:active:not(:disabled) {
    transform: translateY(1px);
    box-shadow: 0 1px 2px rgba(20, 24, 29, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
.primary-btn:disabled {
    background: var(--ink-300);
    color: #fff;
    cursor: not-allowed;
    box-shadow: none;
    filter: none;
}

/* ========================================================================
   Login page (/tools/login/)
   ======================================================================== */
.login-card {
    max-width: 520px;
    margin: 28px auto 64px;
    padding: 32px 32px 28px;
    background: #fff;
    border: 1px solid var(--ink-100);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-md);
}

.login-heading {
    font-size: 20px;
    font-weight: 700;
    margin: 0 0 8px;
    color: var(--ink);
    letter-spacing: -0.2px;
}

.login-intro {
    font-size: 14px;
    line-height: 1.55;
    color: var(--ink-700);
    margin: 0 0 20px;
}

.login-error {
    background: var(--brand-red-soft);
    border: 1px solid rgba(166, 53, 52, 0.30);
    color: var(--brand-red-dark);
    padding: 10px 14px;
    border-radius: var(--r-sm);
    font-size: 13.5px;
    line-height: 1.5;
    margin-bottom: 16px;
}

.login-form { margin: 0; }

.login-label {
    display: block;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    color: var(--ink-500);
    margin-bottom: 6px;
}

.login-input {
    display: block;
    width: 100%;
    padding: 12px 14px;
    font-family: inherit;
    font-size: 15px;
    color: var(--ink);
    background: #fff;
    border: 1.5px solid var(--ink-200);
    border-radius: var(--r);
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    /* Long opaque keys benefit from a monospace stack so they line up. */
    font-feature-settings: var(--tnum);
}
.login-input:focus {
    border-color: var(--brand-red-light);
    box-shadow: 0 0 0 3px rgba(166, 53, 52, 0.15);
}

.login-submit {
    margin-top: 18px;
    width: 100%;
    justify-content: center;
}

.login-help {
    margin: 18px 0 0;
    font-size: 13px;
    color: var(--ink-500);
    text-align: center;
}
.login-help a { color: var(--brand-red); font-weight: 600; }
.login-help a:hover { color: var(--brand-red-dark); }

.login-terms {
    margin: 18px 0 0;
    font-size: 12.5px;
    color: var(--ink-500);
    text-align: center;
    line-height: 1.55;
}
.login-terms a { color: var(--ink-700); text-decoration: underline; }
.login-terms a:hover { color: var(--brand-red); }

/* "Where do I find my API key?" help card. Lives BELOW the login
   card; same max-width so they line up visually. */
.login-helpcard {
    max-width: 520px;
    margin: 18px auto 64px;
    padding: 24px 32px 22px;
    background: #fff;
    border: 1px solid var(--ink-100);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-md);
}
.login-helpcard-title {
    font-size: 16px;
    font-weight: 700;
    margin: 0 0 10px;
    color: var(--ink);
    letter-spacing: -0.2px;
}
.login-helpcard-body {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--ink-700);
    margin: 0 0 14px;
}
.login-helpcard-body:last-child { margin-bottom: 0; }
.login-helpcard-body a { color: var(--brand-red); font-weight: 600; }
.login-helpcard-body a:hover { color: var(--brand-red-dark); }
.login-helpcard-image {
    display: block;
    width: 100%;
    height: auto;
    max-width: 100%;
    margin: 0 0 14px;
    border: 1px solid var(--ink-100);
    border-radius: var(--r);
}

@media (max-width: 640px) {
    .login-card {
        margin: 18px 8px 40px;
        padding: 22px 18px 18px;
    }
}

.site-header .brand {
    display: inline-flex;
    align-items: center;
    color: #fff;
    text-decoration: none;
}

.site-header .brand img {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    margin-right: 12px;
    /* Hairline white ring + warm shadow gives the logo a "minted coin" feel
       on the red field instead of looking pasted in. The inset 0 0 0 1px on
       white blends with the gradient and only registers as definition at
       the edge. */
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.25),
        0 6px 18px rgba(60, 12, 12, 0.32);
}

.site-header .brand-name {
    font-weight: 700;
    font-size: 24px;
    line-height: 1;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.92);
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.site-header .brand-suffix {
    font-size: 12px;
    font-weight: 400;
    opacity: 0.85;
    letter-spacing: 0;
    text-transform: none;
}

/* Page hero, sits directly under the red top bar on the light page
   background. Carries only the page-level H1 so the section has the
   same height on every page (homepage, every tool). Goes edge-to-edge
   so a long title is not constrained to the 1140px content column;
   horizontal breathing room comes from `.container`'s own 20px side
   padding. The per-page lead descriptor (set via $hero_lead) is no
   longer rendered here, keeping the header band visually consistent
   across the site. */
.page-hero {
    background: transparent;
    padding: 20px 0 10px;
}
.page-hero > .container {
    width: 100%;
    max-width: none;
}
.page-hero h1 {
    font-weight: 700;
    font-size: 24px;
    line-height: 1.25;
    letter-spacing: -0.3px;
    margin: 0;
    color: #962F2E;
}
.page-hero-description {
    margin: 4px 0 0;
    font-size: 15px;
    line-height: 1.4;
    color: var(--ink-700, #4a5260);
    max-width: 920px;
}

@media (max-width: 640px) {
    .site-header {
        padding: 8px 0;
    }
    .site-header-top {
        gap: 8px;
        row-gap: 8px;
    }
    /* Compact brand so the wordmark fits cleanly alongside the login
       link or user-bar. Without these mobile overrides, "FREE MARKETING
       TOOLS" at 24px / 1.5px tracking wraps to 3 lines and the right-
       side widget breaks to its own row, eating 90-130px of vertical
       space. */
    .site-header .brand img {
        width: 30px;
        height: 30px;
        margin-right: 8px;
    }
    .site-header .brand-name {
        font-size: 15px;
        letter-spacing: 0.5px;
        gap: 0;
    }
    /* The "by Keywords Everywhere" tagline is cosmetic on a screen this
       narrow; the logo + wordmark already brand the page. Hiding it
       gives the wordmark room to fit on one line. */
    .site-header .brand-suffix {
        display: none;
    }
    .user-bar {
        gap: 8px;
        padding: 4px 10px;
        font-size: 11.5px;
    }
    .user-bar-icon {
        width: 12px;
        height: 12px;
    }
    .user-bar-plan {
        padding: 1px 6px;
        font-size: 9px;
        letter-spacing: 0.4px;
    }
    .user-bar-logout {
        border-left: none;
        padding-left: 0;
        font-size: 11.5px;
    }
    .login-link {
        padding: 5px 12px;
        font-size: 12px;
    }
    .page-hero {
        padding: 14px 0 6px;
    }
    .page-hero h1 {
        font-size: 20px;
    }
    .page-hero-description {
        font-size: 14px;
    }
    /* Mobile column hiding. A `<th>` tagged with `col-mobile-hide` (and
       the matching `<td>` cells underneath, propagated by shared
       `mobile-columns.js`) drops out of the layout at <= 640px so a
       9-column table doesn't crush to 38px per column. Per-tool decides
       which columns are headline metrics worth keeping on a narrow
       viewport and which are secondary. */
    .results-table .col-mobile-hide {
        display: none;
    }
    /* Slightly tighter cell padding on mobile so the columns that
       remain don't waste horizontal space on chrome. */
    .results-table th,
    .results-table td {
        padding: 10px 10px;
    }
}

@media (max-width: 420px) {
    /* At iPhone-SE width (375px) and similar, the user-bar's four chips
       (email + plan + credits + logout) still feel tight. Drop the
       " credits" label so the number stands alone, and step the
       wordmark down once more so it always wins the row. */
    .site-header .brand-name {
        font-size: 14px;
        letter-spacing: 0.3px;
    }
    .user-bar-credits-label {
        display: none;
    }
    /* Extra-narrow viewport: hide a second tier of columns tagged
       `col-mobile-hide-sm`. Tools that have 5+ columns can use this
       to step the table down from 3-4 visible columns at 480-640px to
       2-3 visible columns under 420px. */
    .results-table .col-mobile-hide-sm {
        display: none;
    }
}

/* Category quick-nav (table of contents card) */
.tools-nav {
    position: relative;
    z-index: 3;
    margin-top: 16px;
}

.tools-nav-card {
    position: relative;
    background: #fff;
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    padding: 24px 28px;
    border: 1px solid var(--ink-100);
}

/* Hairline brand stripe on the top edge - same accent the form card uses
   on the tool page so the two surfaces feel like one product. */
.tools-nav-card::before {
    content: "";
    position: absolute;
    inset: -1px -1px auto -1px;
    height: 3px;
    background: linear-gradient(90deg, var(--brand-red) 0%, var(--brand-red-light) 100%);
    border-top-left-radius: var(--r-lg);
    border-top-right-radius: var(--r-lg);
    pointer-events: none;
}

.tools-nav-heading {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 20px;
    padding-bottom: 18px;
    border-bottom: 1px solid var(--ink-100);
}

.tools-nav-eyebrow {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1.4px;
    text-transform: uppercase;
    color: var(--brand-red);
}

.tools-nav-total {
    font-size: 12px;
    font-weight: 600;
    color: var(--ink-500);
    font-feature-settings: var(--tnum);
    letter-spacing: 0.2px;
}

.tools-nav-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.tools-nav-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    border-radius: var(--r);
    background: var(--ink-50);
    border: 1px solid transparent;
    color: inherit;
    transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease, color 0.18s ease;
}

.tools-nav-link::before {
    /* Brand accent stripe on the left edge that fades in on hover. */
    content: "";
    position: absolute;
    left: 4px;
    top: 10px;
    bottom: 10px;
    width: 2px;
    background: var(--brand-red);
    border-radius: 2px;
    opacity: 0;
    transition: opacity 0.18s;
}

.tools-nav-link:hover {
    background: #fff;
    border-color: rgba(166, 53, 52, 0.18);
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
    color: inherit;
}
.tools-nav-link:hover::before { opacity: 1; }

.tools-nav-icon {
    width: 36px;
    height: 36px;
    border-radius: 8px;
    background: linear-gradient(135deg, #fdecec 0%, #fbd7d6 100%);
    color: var(--brand-red);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    flex-shrink: 0;
    transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.tools-nav-link:hover .tools-nav-icon {
    transform: scale(1.04);
    box-shadow: 0 4px 10px rgba(166, 53, 52, 0.18);
}

.tools-nav-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    line-height: 1.2;
}

.tools-nav-name {
    font-weight: 700;
    font-size: 14px;
    color: var(--ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    letter-spacing: -0.1px;
}

.tools-nav-count {
    font-size: 12px;
    color: var(--ink-500);
    font-weight: 500;
    font-feature-settings: var(--tnum);
}

@media (max-width: 640px) {
    .tools-nav-card {
        padding: 18px;
    }
    .tools-nav-heading {
        margin-bottom: 14px;
        padding-bottom: 12px;
    }
    .tools-nav-list {
        grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
        gap: 8px;
    }
    .tools-nav-link {
        padding: 8px 10px;
        gap: 10px;
    }
    .tools-nav-icon {
        width: 32px;
        height: 32px;
        font-size: 16px;
    }
    .tools-nav-name {
        font-size: 13px;
    }
    .tool-category-header {
        flex-wrap: wrap;
        gap: 10px;
        padding-bottom: 14px;
    }
    .tool-category-num {
        order: -1;
        flex-basis: 100%;
        min-width: 0;
    }
    .tool-category-name {
        font-size: 18px;
    }
    .tool-category {
        margin-top: 48px;
    }
}

/* Category section header */
.tool-category {
    margin-top: 64px;
    scroll-margin-top: 24px;
}

.tool-category:first-of-type {
    margin-top: 40px;
}

.tool-category-header {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 24px;
    padding-bottom: 18px;
    border-bottom: 1px solid var(--ink-200);
}

.tool-category-num {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1.4px;
    color: var(--brand-red);
    text-transform: uppercase;
    font-feature-settings: var(--tnum);
    line-height: 1;
    flex-shrink: 0;
    min-width: 56px;
}

.tool-category-icon {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    background: linear-gradient(135deg, #fdecec 0%, #fbd7d6 100%);
    color: var(--brand-red);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    flex-shrink: 0;
}

.tool-category-name {
    font-weight: 700;
    font-size: 22px;
    color: var(--ink);
    margin: 0;
    flex-grow: 1;
    letter-spacing: -0.3px;
    line-height: 1.2;
}

.tool-category-count {
    font-size: 11px;
    font-weight: 700;
    color: var(--ink-400);
    text-transform: uppercase;
    letter-spacing: 1.4px;
    font-feature-settings: var(--tnum);
    flex-shrink: 0;
}

/* Tool grid */
.tools-section {
    padding: 0 0 80px;
    position: relative;
    z-index: 2;
}

/* Homepage sections drop the shared 1140px cap, matching the
 * `.tool-main > .container` override and the `.site-header > .container`
 * override above so the homepage's nav strip and tool grid extend
 * edge-to-edge on wide viewports instead of looking visibly narrower
 * than every tool page. The auto-fill grid (above) absorbs the extra
 * width as additional columns rather than stretching cards. */
.tools-nav > .container,
.tools-section > .container {
    max-width: none;
}

.tools-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 20px;
}

.tool-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: #fff;
    border-radius: var(--r);
    padding: 24px;
    box-shadow: var(--shadow-sm);
    transition: transform 0.22s cubic-bezier(0.4, 0, 0.2, 1),
                box-shadow 0.22s cubic-bezier(0.4, 0, 0.2, 1),
                border-color 0.18s ease;
    color: inherit;
    border: 1px solid var(--ink-100);
    overflow: hidden;
    /* Subtle staggered reveal on first paint - the first few cards
       fade up in sequence, the rest land together at ~200ms. */
    opacity: 0;
    animation: tool-card-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@keyframes tool-card-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

.tools-grid .tool-card:nth-child(1) { animation-delay: 0ms; }
.tools-grid .tool-card:nth-child(2) { animation-delay: 50ms; }
.tools-grid .tool-card:nth-child(3) { animation-delay: 100ms; }
.tools-grid .tool-card:nth-child(4) { animation-delay: 150ms; }
.tools-grid .tool-card:nth-child(n+5) { animation-delay: 200ms; }

/* Brand-red accent stripe across the card top, wipes in on hover. */
.tool-card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 2px;
    background: linear-gradient(90deg, var(--brand-red), var(--brand-red-light));
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1);
}

.tool-card:not(.tool-card--disabled):hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow-lg);
    border-color: var(--brand-red-tint);
    color: inherit;
}
.tool-card:not(.tool-card--disabled):hover::before { transform: scaleX(1); }

.tool-card .tool-header {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 14px;
}

.tool-card .tool-icon {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: 10px;
    background: linear-gradient(135deg, #fdecec 0%, #fbd7d6 100%);
    color: var(--brand-red);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    transition: transform 0.22s ease, box-shadow 0.22s ease;
}

.tool-card:not(.tool-card--disabled):hover .tool-icon {
    transform: scale(1.05);
    box-shadow: 0 4px 12px rgba(166, 53, 52, 0.22);
}

.tool-card .tool-name {
    font-weight: 700;
    font-size: 16px;
    color: var(--ink);
    margin: 0;
    line-height: 1.3;
    letter-spacing: -0.1px;
}

.tool-card .tool-description {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--ink-500);
    margin: 0 0 16px;
    flex-grow: 1;
}

.tool-card .tool-cta {
    display: inline-flex;
    align-items: center;
    color: var(--brand-red);
    font-weight: 600;
    font-size: 13px;
    letter-spacing: 0.1px;
}

.tool-card .tool-cta::after {
    content: "→";
    margin-left: 6px;
    display: inline-block;
    transition: transform 0.2s ease;
}

.tool-card:hover .tool-cta::after { transform: translateX(4px); }

.tool-card--disabled { cursor: default; }
.tool-card--disabled:hover {
    transform: none;
    box-shadow: var(--shadow-sm);
    border-color: var(--ink-100);
}
.tool-card--disabled .tool-icon {
    background: var(--ink-100);
    color: var(--ink-400);
}
.tool-card--disabled .tool-name { color: var(--ink-500); }
.tool-card--disabled .tool-description { color: var(--ink-400); }

/* "Coming soon" state - editorial small-caps with a leading dash. */
.tool-card .tool-cta--soon {
    color: var(--ink-400);
    font-weight: 700;
    letter-spacing: 1.4px;
    text-transform: uppercase;
    font-size: 11px;
    display: inline-flex;
    align-items: center;
    gap: 10px;
}
.tool-card .tool-cta--soon::before {
    content: "";
    width: 12px;
    height: 1px;
    background: currentColor;
}
.tool-card .tool-cta--soon::after { content: none; }

/* Footer */
.site-footer {
    border-top: 1px solid #e5e7eb;
    padding: 24px 0;
    background: #fff;
    color: #41494f;
    font-size: 14px;
    font-weight: 300;
    text-align: center;
}

/* ============================================================================
 * TOOL-PAGE PRIMITIVES
 * Cross-tool primitives lifted out of the backlinks-checker tool when the
 * second tool was added. Section order roughly follows a tool page's DOM:
 *   - Page chrome (.tool-main; the .site-header tool-page tweaks live in
 *     each tool's own tool.css for now since not every page that uses the
 *     shared header is a "tool" page, e.g. /tools/login/)
 *   - Form card + inputs + mode toggle
 *   - Bulk controls + unique toggle
 *   - Recent searches (.history-region)
 *   - Progress region
 *   - Errors region
 *   - Results region (table + sort + pagination + empty)
 *   - Toasts
 *   - Helpers (.truncate)
 *   - Mobile tweaks
 *
 * New tools should compose these classes in their markup and only define
 * tool-specific overrides (column widths, score badges, etc.) in their own
 * code/<slug>/assets/css/tool.css.
 * ============================================================================ */

/* ---- Tool main container -------------------------------------------------- */
.tool-main {
    padding: 14px 0 64px;
}
/* The shared `.container` caps at 1140px so homepage cards align. Tool
   pages benefit from more horizontal room for wide results tables, so we
   drop the cap here. */
.tool-main > .container {
    max-width: none;
}

/* ---- Form card ----------------------------------------------------------- */
.tool-form-card {
    position: relative;
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--r-lg);
    padding: 28px 32px;
    box-shadow: var(--shadow-md);
}

/* ---- Mode toggle (sliding-pill segmented control) ----------------------- */
.mode-toggle {
    --mode-toggle-pad: 4px;
    position: relative;
    background: var(--ink-100);
    border-radius: 999px;
    padding: var(--mode-toggle-pad);
    margin-bottom: 18px;
}
/* `[role="tablist"]` is forced to display: flex by the UA stylesheet at
   the same specificity as a plain class, so we lift specificity with the
   attribute selector to keep the pill from stretching to parent width. */
.mode-toggle,
[role="tablist"].mode-toggle {
    display: inline-flex;
    width: -moz-fit-content;
    width: fit-content;
}

.mode-toggle::before {
    content: "";
    position: absolute;
    top: var(--mode-toggle-pad);
    bottom: var(--mode-toggle-pad);
    left: var(--mode-toggle-pad);
    width: calc(50% - var(--mode-toggle-pad));
    background: #fff;
    border-radius: 999px;
    box-shadow: 0 1px 3px rgba(20, 24, 29, 0.10), 0 1px 1px rgba(20, 24, 29, 0.06);
    transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
    pointer-events: none;
}

.mode-toggle[data-mode="bulk"]::before {
    transform: translateX(100%);
}

.mode-btn {
    position: relative;
    z-index: 1;
    border: 0;
    background: transparent;
    color: var(--ink-500);
    padding: 8px 22px;
    font: inherit;
    font-weight: 500;
    cursor: pointer;
    transition: color 0.2s;
    border-radius: 999px;
    min-width: 88px;
}
.mode-btn:hover { color: var(--ink-700); }
.mode-btn.is-active { color: var(--ink); }

/* ---- Input forms --------------------------------------------------------- */
.input-form { display: none; }
.input-form.is-visible { display: block; }

.input-row {
    display: flex;
    gap: 10px;
    align-items: stretch;
    flex-wrap: wrap;
}

.text-input,
.textarea-input,
.type-select,
.search-input {
    font: inherit;
    color: var(--ink-700);
    border: 1px solid var(--ink-300);
    border-radius: var(--r-sm);
    padding: 11px 14px;
    background: #fff;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.text-input:hover,
.textarea-input:hover,
.type-select:hover,
.search-input:hover {
    border-color: var(--ink-400);
}

/* Soft red glow ring instead of a harsh hard outline. */
.text-input:focus,
.textarea-input:focus,
.type-select:focus,
.search-input:focus {
    outline: none;
    border-color: var(--brand-red);
    box-shadow: var(--focus-ring);
}

.text-input {
    flex: 1 1 320px;
    min-width: 0;
    font-size: 15px;
}
.text-input::placeholder {
    color: var(--ink-400);
}

.textarea-input {
    width: 100%;
    resize: vertical;
    font-family: var(--mono);
    font-size: 14px;
    line-height: 1.6;
    letter-spacing: -0.1px;
}

.type-select {
    flex: 0 0 auto;
    min-width: 130px;
    cursor: pointer;
}

/* ---- Live-feedback row (badge + message) -------------------------------- */
.input-feedback {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 12px;
    min-height: 24px;
    font-size: 13px;
}

.type-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px 3px 8px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.2px;
}
.type-badge::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.85;
}
.type-badge--auto    { background: var(--ink-100); color: var(--ink-500); }
.type-badge--page    { background: var(--good-bg); color: var(--good-fg); }
.type-badge--url     { background: var(--good-bg); color: var(--good-fg); }
.type-badge--domain  { background: #dbeafe;        color: #1e40af; }
.type-badge--invalid { background: var(--bad-bg);  color: var(--bad-fg); }

.feedback-msg          { color: var(--ink-500); }
.feedback-msg.is-error { color: var(--bad-fg); }

/* ---- Bulk + unique controls --------------------------------------------- */
.bulk-controls {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 12px;
    flex-wrap: wrap;
}
.bulk-count {
    color: var(--ink-500);
    font-size: 13px;
    font-feature-settings: var(--tnum);
    flex: 1 1 auto;
}

.unique-toggle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-top: 18px;
    cursor: pointer;
    user-select: none;
    color: var(--ink-700);
    font-size: 14px;
}
.unique-toggle input {
    width: 16px;
    height: 16px;
    cursor: pointer;
    accent-color: var(--brand-red);
}

/* ---- Ghost button (secondary actions; cancel, dismiss, etc.) ------------ */
.ghost-btn {
    background: transparent;
    border: 1px solid var(--ink-300);
    color: var(--ink-700);
    padding: 7px 14px;
    border-radius: var(--r-sm);
    font: inherit;
    font-size: 13px;
    cursor: pointer;
    transition: background-color 0.12s, border-color 0.12s, color 0.12s;
}
.ghost-btn:hover {
    background: var(--ink-50);
    border-color: var(--ink-400);
    color: var(--ink);
}

/* ---- Recent searches ----------------------------------------------------- */
.history-region {
    margin-top: 20px;
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--r-lg);
    padding: 16px 20px;
    box-shadow: var(--shadow-sm);
}

.history-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}
.history-title {
    font-weight: 600;
    color: var(--ink);
    font-size: 11px;
    letter-spacing: 1.4px;
    text-transform: uppercase;
}
.history-clear {
    background: transparent;
    border: 0;
    color: var(--ink-500);
    font: inherit;
    font-size: 12px;
    letter-spacing: 0.2px;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: var(--r-sm);
    transition: background-color 0.15s, color 0.15s;
}
.history-clear:hover {
    color: var(--ink);
    background: var(--ink-100);
}

.history-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.history-region.is-collapsed .history-list .history-item:nth-child(n+4) {
    display: none;
}

.history-item {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 10px 12px;
    border-radius: var(--r-sm);
    cursor: pointer;
    transition: background-color 0.12s, transform 0.12s, box-shadow 0.12s;
    position: relative;
}
.history-item::before {
    /* Left-edge accent that appears on hover, hinting at the active card. */
    content: "";
    position: absolute;
    left: 0;
    top: 8px;
    bottom: 8px;
    width: 3px;
    background: var(--brand-red);
    border-radius: 0 3px 3px 0;
    opacity: 0;
    transition: opacity 0.12s;
}
.history-item:hover {
    background: var(--ink-50);
}
.history-item:hover::before { opacity: 1; }

.history-item-input {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--link);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 14px;
}
.history-item:hover .history-item-input { color: var(--link-dark); }

.history-item-meta {
    color: var(--ink-700);
    font-size: 12px;
    font-feature-settings: var(--tnum);
    white-space: nowrap;
    letter-spacing: 0.1px;
}
.history-item-when {
    color: var(--ink-400);
    font-size: 12px;
    font-feature-settings: var(--tnum);
    white-space: nowrap;
    min-width: 70px;
    text-align: right;
}

/* Per-item delete (X) button. Sits at the far right of each row.
   Visible at rest in a muted ink-300 so users can see at a glance
   that they can remove a single entry; brightens to brand-red on
   hover or focus for the destructive intent. The button stops
   propagation so clicking it doesn't trigger the row's re-open
   action. */
.history-item-delete {
    background: transparent;
    border: 0;
    padding: 4px;
    margin: 0;
    color: var(--ink-300);
    cursor: pointer;
    border-radius: var(--r-sm);
    line-height: 0;
    transition: color 0.12s, background-color 0.12s;
    flex: 0 0 auto;
}
.history-item:hover .history-item-delete {
    color: var(--ink-500);
}
.history-item-delete:hover {
    color: var(--brand-red);
    background: rgba(220, 38, 38, 0.08);
}
.history-item-delete:focus-visible {
    color: var(--brand-red);
    outline: 2px solid var(--brand-red);
    outline-offset: 2px;
}

.history-toggle {
    background: transparent;
    border: 0;
    color: var(--ink-500);
    font: inherit;
    font-size: 12px;
    letter-spacing: 0.2px;
    cursor: pointer;
    margin-top: 6px;
    padding: 6px 10px;
    border-radius: var(--r-sm);
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: background-color 0.12s, color 0.12s;
}
.history-toggle[hidden] { display: none; }
.history-toggle::after {
    content: "";
    width: 8px;
    height: 8px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg) translate(-1px, -1px);
    transition: transform 0.18s;
}
.history-region:not(.is-collapsed) .history-toggle::after {
    transform: rotate(-135deg) translate(-1px, -1px);
}
.history-toggle:hover {
    color: var(--ink);
    background: var(--ink-100);
}

/* ---- Progress region ----------------------------------------------------- */
.progress-region {
    margin-top: 24px;
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--r-lg);
    padding: 18px 22px;
    box-shadow: var(--shadow-sm);
}

.progress-bar {
    height: 10px;
    background: var(--ink-100);
    border-radius: 999px;
    overflow: hidden;
    margin-bottom: 12px;
    position: relative;
}

.progress-fill {
    height: 100%;
    /* Start at 10% so the bar is visibly "started" the moment the
       progress region appears (a 0% start renders as no fill at all
       and reads as broken / not loading). JS bumps this up over time
       as work completes. */
    width: 10%;
    border-radius: 999px;
    background:
        repeating-linear-gradient(
            -45deg,
            rgba(255, 255, 255, 0.18) 0,
            rgba(255, 255, 255, 0.18) 10px,
            transparent 10px,
            transparent 20px
        ),
        linear-gradient(90deg, var(--brand-red) 0%, var(--brand-red-light) 100%);
    background-size: 28px 28px, 100% 100%;
    transition: width 0.55s cubic-bezier(0.22, 1, 0.36, 1);
    animation: progress-stripes 1.6s linear infinite;
}

@keyframes progress-stripes {
    from { background-position: 0 0, 0 0; }
    to   { background-position: 28px 0, 0 0; }
}

.progress-row {
    display: flex;
    align-items: center;
    gap: 14px;
}
.progress-text {
    flex: 1 1 auto;
    color: var(--ink-700);
    font-size: 14px;
    font-style: italic;
    letter-spacing: 0.1px;
}

/* ---- Errors region ------------------------------------------------------- */
.errors-region {
    margin-top: 24px;
    background: #fff7f7;
    border: 1px solid #fecaca;
    border-left: 4px solid var(--bad-fg);
    border-radius: var(--r-lg);
    padding: 16px 20px;
    color: #7f1d1d;
}
.errors-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 6px;
}
.errors-header strong {
    font-size: 11px;
    letter-spacing: 1.4px;
    text-transform: uppercase;
    color: var(--bad-fg);
    font-weight: 700;
}
.errors-dismiss {
    background: transparent;
    border: 0;
    font-size: 22px;
    line-height: 1;
    color: #7f1d1d;
    cursor: pointer;
    padding: 0 6px;
    border-radius: var(--r-sm);
    transition: background-color 0.12s;
}
.errors-dismiss:hover { background: rgba(127, 29, 29, 0.08); }
.errors-list {
    margin: 0;
    padding-left: 18px;
    font-size: 13px;
    line-height: 1.55;
}
.errors-list li { padding: 2px 0; }

/* ---- Results region ------------------------------------------------------ */
.results-region {
    /* No `overflow: hidden` here - it would create a scroll container
       that breaks the sticky `.results-header` below. Inner elements
       carry their own border-radii to keep the rounded outer look. */
    margin-top: 24px;
    /* When tools auto-scroll to the results on job completion, leave
       a small gap above so the section header isn't flush to the
       viewport top. Affects every tool that scrolls into view. */
    scroll-margin-top: 16px;
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-md);
}

.results-header {
    /* Sticks to the top of the viewport when the user scrolls past the
       form card so the count badge / search box / export buttons stay
       reachable for long result sets. The table's thead is also sticky
       (see below) and stacks just under this strip. Padding deliberately
       tight (12px vertical) to keep the combined sticky chrome under
       ~110px, otherwise the data area shrinks too much on short
       viewports. */
    position: sticky;
    top: 0;
    z-index: 6;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 12px 22px;
    border-bottom: 1px solid var(--ink-200);
    /* Carry the top rounding ourselves now that .results-region no
       longer clips with overflow: hidden. */
    border-top-left-radius: var(--r-lg);
    border-top-right-radius: var(--r-lg);
    flex-wrap: wrap;
    background: linear-gradient(180deg, #fff 0%, var(--ink-25) 100%);
}

.results-title {
    font-weight: 600;
    color: var(--ink);
    font-size: 14px;
    letter-spacing: -0.1px;
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
}

/* Brand glyph in the sticky results-header strip. Mirrors the logo
 * at the page top, so when the user scrolls past the page header
 * into a long result set, the brand stays visible in the only
 * chrome left on screen. Pseudo-element keeps every tool's
 * .results-title markup untouched (no per-tool index.php edits). */
.results-title::before {
    content: '';
    display: inline-block;
    width: 18px;
    height: 18px;
    background: url('../img/keywords-everywhere-logo.png') center / contain no-repeat;
    align-self: center;
    flex-shrink: 0;
}

.results-badge {
    display: inline-block;
    background: var(--ink);
    color: #fff;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    font-feature-settings: var(--tnum);
    letter-spacing: 0.2px;
}

.results-actions {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}

.search-input {
    /* Sized smaller than the form-card inputs since this lives inside the
       results header chrome. The base padding/border come from the shared
       text-input rules above; only the size + magnifier overlay differ. */
    padding: 8px 12px 8px 34px;
    font-size: 13px;
    width: 220px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 16 16' fill='none' stroke='%239ca3af' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><circle cx='7' cy='7' r='5'/><path d='m13 13-2.5-2.5'/></svg>");
    background-repeat: no-repeat;
    background-position: 12px center;
}

.export-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #fff;
    color: var(--ink-700);
    border: 1px solid var(--ink-300);
    padding: 8px 14px;
    border-radius: var(--r-sm);
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background-color 0.12s, border-color 0.12s, color 0.12s, box-shadow 0.12s;
}
.export-btn:hover {
    background: var(--ink-50);
    border-color: var(--ink-400);
    color: var(--ink);
    box-shadow: 0 1px 2px rgba(20, 24, 29, 0.04);
}
.export-btn .icon { color: var(--ink-500); transition: color 0.12s; }
.export-btn:hover .icon { color: var(--brand-red); }

/* ---- Results table ------------------------------------------------------- */
.results-table-wrap {
    /* Deliberately NO overflow rule. Setting overflow-x: auto here used
       to give horizontal scroll on narrow viewports, but it also forces
       overflow-y to compute as auto (per CSS overflow-shorthand rules),
       which makes the wrap a scroll container - that traps the table
       thead's `position: sticky` inside the wrap instead of letting it
       stick to the viewport. We need viewport-level stick for the
       column headers, so the wrap stays overflow:visible and the page
       handles horizontal overflow on narrow viewports.
       Tools whose table needs internal horizontal scroll should add a
       per-tool override that uses `overflow-x: clip` (which doesn't
       create a scroll container) instead. */
}
.results-table {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    font-size: 14px;
}
.results-table th,
.results-table td {
    padding: 14px 18px;
    text-align: left;
    border-bottom: 1px solid var(--ink-100);
    vertical-align: middle;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.results-table thead th {
    /* Stick just below the .results-header strip (~58px tall on a wide
       viewport with the tightened padding above). On narrow viewports
       the strip wraps to two rows and gets taller; the column headers
       will then briefly sit underneath the wrapped strip while sticking
       - a small cosmetic compromise we accept rather than measuring
       height in JS. */
    position: sticky;
    top: 58px;
    z-index: 5;
    background: #fff;
    color: var(--ink-500);
    font-weight: 600;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.2px;
    user-select: none;
    border-bottom: 1px solid var(--ink-200);
    box-shadow: inset 0 -1px 0 var(--ink-200);
    /* Tighter than the body-cell padding above so the column-header band
       feels like a label strip rather than a data row, and the combined
       sticky chrome stays around 100px. */
    padding-top: 10px;
    padding-bottom: 10px;
}

.results-table tbody tr {
    transition: background-color 0.1s;
}
.results-table tbody tr:nth-child(even) { background: var(--ink-25); }
.results-table tbody tr:hover           { background: #f0f4fa; }
.results-table tr:last-child td         { border-bottom: 0; }

/* Numeric column shared treatment. Per-column widths are tool-specific and
   stay in each tool's tool.css. */
.results-table th.th-num {
    text-align: center;
    text-transform: none;
    letter-spacing: 0;
    font-size: 12px;
    line-height: 1.3;
    padding-left: 8px;
    padding-right: 8px;
}
.results-table td.td-num {
    text-align: center;
    padding-left: 8px;
    padding-right: 8px;
    font-feature-settings: var(--tnum);
}

/* ---- Sortable header ----------------------------------------------------- */
.th-sortable {
    cursor: pointer;
    transition: background-color 0.12s, color 0.12s;
}
.th-sortable:hover {
    background: var(--ink-50);
    color: var(--ink-700);
}
/* The sort-arrow span takes zero space until a column is actually sorted;
   otherwise its width visually pushes centered headers off-centre. */
.sort-arrow {
    display: inline-block;
    color: var(--ink-300);
}
.th-sortable.is-sorted-asc,
.th-sortable.is-sorted-desc { color: var(--ink); }
.th-sortable.is-sorted-asc  .sort-arrow,
.th-sortable.is-sorted-desc .sort-arrow {
    color: var(--brand-red);
    width: 8px;
    height: 8px;
    margin-left: 6px;
    vertical-align: 1px;
}
.th-sortable.is-sorted-asc  .sort-arrow::after { content: "▲"; font-size: 8px; }
.th-sortable.is-sorted-desc .sort-arrow::after { content: "▼"; font-size: 8px; }

/* ---- Cell helpers (link / muted) ---------------------------------------- */
.cell-link {
    color: var(--link);
    text-decoration: none;
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: bottom;
    font-size: 14px;
    border-bottom: 1px solid transparent;
    transition: color 0.12s, border-color 0.12s;
}
.cell-link:hover {
    color: var(--link-dark);
    border-bottom-color: currentColor;
}
.cell-muted {
    color: var(--ink-400);
    font-style: italic;
    font-size: 13px;
}

/* ---- Cross-link cells ----------------------------------------------------
 * A table cell whose text launches the matching deep-link into another
 * tool (gated by the confirm modal in crosslinks.js). Always-visible
 * dotted underline as a subtle "this is interactive" affordance; on
 * hover the underline becomes solid, the text takes brand color, and
 * the external-link icon fades in next to it.
 *
 * See CLAUDE.md, "Cross-tool linking from result cells".
 */
.cell-xlink {
    cursor: pointer;
    color: var(--ink);
    text-decoration: underline dotted var(--ink-300);
    text-underline-offset: 3px;
    transition: color 0.12s, text-decoration-color 0.12s, text-decoration-style 0.12s;
}
.cell-xlink:hover,
.cell-xlink:focus-visible {
    color: var(--brand-red);
    text-decoration-style: solid;
    text-decoration-color: var(--brand-red);
    outline: none;
}
.cell-xlink-icon {
    display: inline-block;
    margin-left: 4px;
    opacity: 0;
    transition: opacity 0.15s;
    vertical-align: -1px;
    color: var(--ink-400);
}
.cell-xlink:hover .cell-xlink-icon,
.cell-xlink:focus-visible .cell-xlink-icon {
    opacity: 1;
    color: var(--brand-red);
}
/* Same icon, but inside a .cell-link (i.e. a URL anchor that's been
 * upgraded to also show the cross-tool modal on click). Visible on
 * row hover or keyboard focus so users notice the affordance, then
 * brightens on direct hover/focus of the link itself. */
.results-table tbody tr:hover .cell-link .cell-xlink-icon {
    opacity: 0.7;
}
.cell-link:hover .cell-xlink-icon,
.cell-link:focus-visible .cell-xlink-icon {
    opacity: 1;
    color: var(--brand-red);
}

/* ---- Cross-link trigger --------------------------------------------------
 * Small standalone icon used in cells that already have a primary
 * action (e.g. an `<a>` that directly opens a URL). Appears on row
 * hover or keyboard focus and opens its own cross-link modal when
 * clicked. Built by `KeCrossLinks.makeTrigger(opener)`.
 *
 * Pattern: keep the existing `<a>` (or other primary element) as-is,
 * append this trigger AFTER it in the same cell. Clicking the URL
 * still navigates directly; clicking the trigger surfaces the
 * cross-tool chooser.
 */
.cell-xlink-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-left: 6px;
    padding: 2px 3px;
    color: var(--ink-400);
    cursor: pointer;
    border: 1px solid transparent;
    border-radius: 4px;
    vertical-align: -2px;
    opacity: 0;
    transition: opacity 0.15s, color 0.1s, background 0.1s, border-color 0.1s;
}
.results-table tbody tr:hover .cell-xlink-trigger {
    opacity: 0.85;
}
.cell-xlink-trigger:hover,
.cell-xlink-trigger:focus-visible {
    opacity: 1;
    color: var(--brand-red);
    background: var(--ink-50);
    border-color: var(--ink-200);
    outline: none;
}

/* ---- Cross-link confirm modal --------------------------------------------
 * Markup is injected by code/assets/js/crosslinks.js. The outer
 * .modal-backdrop / .modal-card primitives come from per-tool CSS
 * already; this section adds the option-chooser and skip-checkbox
 * rows that the cross-link modal uses on top of them.
 */
.ke-xlink-modal[hidden] {
    display: none;
}
.ke-xlink-modal .ke-xlink-options {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 4px 0 16px 0;
}
.ke-xlink-modal .ke-xlink-option {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--ink-100);
    border-radius: var(--r-sm);
    background: var(--ink-25);
    cursor: pointer;
    transition: border-color 0.1s, background 0.1s;
}
.ke-xlink-modal .ke-xlink-option:hover {
    background: var(--ink-50);
    border-color: var(--ink-200);
}
.ke-xlink-modal .ke-xlink-option input[type="radio"] {
    margin-top: 3px;
    accent-color: var(--brand-red);
}
.ke-xlink-modal .ke-xlink-option-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.ke-xlink-modal .ke-xlink-option-name {
    font-weight: 600;
    color: var(--ink);
    font-size: 14px;
}
.ke-xlink-modal .ke-xlink-option-desc {
    color: var(--ink-500);
    font-size: 12.5px;
    line-height: 1.4;
}
.ke-xlink-modal .ke-xlink-skip {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 6px 0 18px 0;
    color: var(--ink-700);
    font-size: 13px;
    cursor: pointer;
    user-select: none;
}
.ke-xlink-modal .ke-xlink-skip input[type="checkbox"] {
    accent-color: var(--brand-red);
}

/* ---- Empty state ---------------------------------------------------------
 * Selector is `.results-table td.results-empty` (not just `.results-empty`)
 * so we beat the default `.results-table td { text-align: left }` rule
 * above. Without that, the cell content sits left-aligned and only the
 * inner flex container's items are centered (which means the column of
 * icon + text hugs the left edge of the cell).
 */
.results-table td.results-empty {
    text-align: center;
    padding: 56px 20px;
    color: var(--ink-400);
}
.results-empty-inner {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    max-width: 360px;
}
.results-empty-icon {
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: var(--ink-100);
    color: var(--ink-400);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.results-empty-text {
    font-size: 14px;
    color: var(--ink-500);
    margin: 0;
}

/* ---- Footer (page size, info, pagination) ------------------------------- */
.results-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 22px;
    border-top: 1px solid var(--ink-200);
    /* Carry the bottom rounding ourselves now that .results-region no
       longer clips with overflow: hidden. */
    border-bottom-left-radius: var(--r-lg);
    border-bottom-right-radius: var(--r-lg);
    background: var(--ink-25);
    flex-wrap: wrap;
    font-size: 12px;
    letter-spacing: 0.1px;
}
.results-pagesize, .results-info {
    color: var(--ink-500);
    font-feature-settings: var(--tnum);
}
.results-pagesize select {
    margin: 0 6px;
    border: 1px solid var(--ink-300);
    border-radius: 4px;
    padding: 3px 6px;
    background: #fff;
    color: var(--ink-700);
    font: inherit;
    font-size: 12px;
}

.pagination {
    display: inline-flex;
    gap: 4px;
}
.page-btn {
    background: #fff;
    border: 1px solid var(--ink-300);
    border-radius: var(--r-sm);
    padding: 5px 11px;
    cursor: pointer;
    color: var(--ink-700);
    font: inherit;
    font-size: 12px;
    font-feature-settings: var(--tnum);
    transition: background-color 0.12s, border-color 0.12s, color 0.12s;
}
.page-btn:hover:not(:disabled) {
    background: var(--ink-50);
    border-color: var(--ink-400);
    color: var(--ink);
}
.page-btn.is-active {
    background: var(--brand-red);
    color: #fff;
    border-color: var(--brand-red);
    font-weight: 600;
}
.page-btn:disabled { opacity: 0.4; cursor: not-allowed; }

/* ---- Toasts -------------------------------------------------------------- */
.toasts {
    position: fixed;
    top: 20px;
    right: 20px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    z-index: 1000;
    pointer-events: none;
}
.toast {
    pointer-events: auto;
    min-width: 280px;
    max-width: 380px;
    background: #fff;
    border: 1px solid var(--ink-200);
    border-left: 4px solid var(--ink-300);
    border-radius: var(--r);
    padding: 13px 16px;
    box-shadow: var(--shadow-lg);
    font-size: 13px;
    line-height: 1.5;
    animation: toast-in 0.24s cubic-bezier(0.22, 1, 0.36, 1);
}
.toast strong {
    display: block;
    margin-bottom: 2px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
}
.toast--info     { border-left-color: #2563eb; }
.toast--success  { border-left-color: #059669; }
.toast--warning  { border-left-color: #d97706; }
.toast--danger   { border-left-color: #dc2626; }
.toast.is-leaving { animation: toast-out 0.2s ease-in forwards; }

@keyframes toast-in {
    from { opacity: 0; transform: translate3d(20px, 0, 0); }
    to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
@keyframes toast-out {
    from { opacity: 1; transform: translate3d(0, 0, 0); }
    to   { opacity: 0; transform: translate3d(20px, 0, 0); }
}

/* ---- Helpers ------------------------------------------------------------- */
.truncate {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}

/* ---- Daily-jobs quota chip ---------------------------------------------- */
/* Lightweight strip showing the current plan's daily-jobs remaining count.
   Sits above the progress region; tools.css owns the visual primitive since
   most tools surface a daily cap now. Tone via .is-warning / .is-danger
   (set by JS based on remaining vs cap). */
.quota-chip {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    background: var(--ink-50);
    border: 1px solid var(--ink-100);
    border-radius: 8px;
    color: var(--ink-700);
    font-size: 13px;
    margin-bottom: 16px;
}
/* display:flex above beats the UA [hidden] rule, so tools that toggle
   the chip visibility (e.g. Schema Markup Generator, only shows the
   chip in URL-extract mode) need this explicit override. */
.quota-chip[hidden] { display: none; }
.quota-chip-icon {
    display: inline-flex;
    align-items: center;
    color: var(--ink-500);
    flex-shrink: 0;
}
.quota-chip-icon svg {
    width: 16px;
    height: 16px;
}
.quota-chip-text {
    flex: 1;
    min-width: 0;
}
.quota-chip-upgrade {
    color: var(--brand-500, #4a59e2);
    text-decoration: none;
    font-weight: 500;
    white-space: nowrap;
    flex-shrink: 0;
}
.quota-chip-upgrade:hover {
    text-decoration: underline;
}
.quota-chip.is-warning {
    background: rgba(245, 158, 11, 0.08);
    border-color: rgba(245, 158, 11, 0.3);
    color: #92400e;
}
.quota-chip.is-warning .quota-chip-icon { color: #d97706; }
.quota-chip.is-warning .quota-chip-upgrade { color: #92400e; }
.quota-chip.is-danger {
    background: rgba(239, 68, 68, 0.08);
    border-color: rgba(239, 68, 68, 0.3);
    color: #991b1b;
}
.quota-chip.is-danger .quota-chip-icon { color: #dc2626; }
.quota-chip.is-danger .quota-chip-upgrade { color: #991b1b; font-weight: 600; }

/* ---- Upgrade banners ----------------------------------------------------- */
/* Two flavours from one set of styles:
   - default (.upgrade-banner): bottom-of-page marketing pitch. Big enough
     to be the "buy more" call to action for anonymous / free / lower-tier
     users. SVC uses it for Keyword Keg; BLC uses it to pitch the higher
     backlinks-per-URL cap.
   - .upgrade-banner--inline: tighter padding, sits inside the tool flow
     (e.g. above the results table) when the tool wants to flag that the
     user just hit a per-plan cap. Same visual language so it feels
     like the same product. */
.upgrade-banner {
    margin-top: 32px;
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 18px 22px;
    background: linear-gradient(135deg, var(--brand-red-soft) 0%, #fff 75%);
    border: 1px solid rgba(166, 53, 52, 0.22);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
}

/* `display: flex` above wins over the UA's [hidden] { display: none } at
   equal specificity, so make the hide explicit. Used by tools that
   include the banner markup permanently and reveal it from JS. */
.upgrade-banner[hidden] { display: none; }

.upgrade-banner--inline {
    margin-top: 16px;
    margin-bottom: 0;
    padding: 14px 18px;
    gap: 14px;
}

.upgrade-banner-icon {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: linear-gradient(135deg, var(--brand-red) 0%, var(--brand-red-light) 100%);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 14px rgba(166, 53, 52, 0.28);
}
.upgrade-banner-icon svg {
    width: 22px;
    height: 22px;
}
.upgrade-banner--inline .upgrade-banner-icon {
    width: 36px;
    height: 36px;
    border-radius: 10px;
}
.upgrade-banner--inline .upgrade-banner-icon svg {
    width: 18px;
    height: 18px;
}

.upgrade-banner-text {
    flex: 1 1 320px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.upgrade-banner-text strong {
    color: var(--ink);
    font-size: 14.5px;
    font-weight: 700;
    letter-spacing: -0.1px;
    line-height: 1.35;
}
.upgrade-banner-text span {
    color: var(--ink-700);
    font-size: 13px;
    line-height: 1.5;
}

.upgrade-banner-cta {
    flex: 0 0 auto;
    align-self: center;
}

@media (max-width: 720px) {
    .upgrade-banner {
        flex-wrap: wrap;
        gap: 12px;
        padding: 16px 18px;
    }
    .upgrade-banner--inline {
        padding: 12px 14px;
    }
    .upgrade-banner-text {
        flex-basis: 100%;
    }
    .upgrade-banner-cta {
        width: 100%;
        justify-content: center;
    }
}

/* ---- Mobile tweaks for tool primitives ---------------------------------- */
@media (max-width: 640px) {
    .tool-form-card {
        padding: 22px 18px;
    }
    .results-header,
    .results-footer {
        padding: 14px 16px;
    }
    .search-input { width: 100%; }
}


/* ============================================================================
   DEBUG REGION (operator troubleshooting, gated by `<tool>.logging.debug_enabled`)

   Surfaces per-call upstream API debug data: endpoint URL, masked request
   body, HTTP status code, and a 2KB preview of the raw response. Each tool
   populates the panel from its `debug` array in the job_results payload;
   the API only includes that array when the per-tool debug flag is on, so
   the panel only ever appears when an operator has explicitly enabled it.

   Markup contract (see e.g. code/organic-ranking-checker/index.php):
     <details class="debug-region" id="debug-region" hidden>
       <summary class="debug-summary">...</summary>
       <div class="debug-body" id="debug-body"></div>
     </details>
   tool.js fills .debug-body with a <div class="debug-entry"> per call.
   ============================================================================ */
.debug-region {
    margin-top: 16px;
    background: #fff7ed;            /* warm tan, distinct from results */
    border: 1px solid #fdba74;
    border-radius: var(--r-lg);
    padding: 10px 14px;
    box-shadow: var(--shadow-sm);
    font-size: 13px;
}
.debug-summary {
    cursor: pointer;
    font-weight: 600;
    color: #9a3412;
    padding: 4px 0;
    user-select: none;
}
.debug-summary:hover {
    color: #7c2d12;
}
.debug-body {
    margin-top: 12px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.debug-entry {
    background: #fff;
    border: 1px solid var(--ink-200);
    border-radius: var(--r-sm);
    padding: 10px 12px;
}
.debug-entry-input {
    font-weight: 600;
    color: var(--ink);
    margin-bottom: 6px;
    font-size: 13px;
}
.debug-entry dl {
    display: grid;
    grid-template-columns: 130px 1fr;
    gap: 4px 12px;
    margin: 0;
}
.debug-entry dt {
    color: var(--ink-500);
    font-weight: 600;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    padding-top: 2px;
}
.debug-entry dd {
    margin: 0;
    color: var(--ink);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    word-break: break-word;
    white-space: pre-wrap;
}
.debug-entry dd.debug-raw {
    background: var(--ink-50);
    padding: 6px 8px;
    border-radius: var(--r-sm);
    max-height: 240px;
    overflow: auto;
}

/* ============================================================================
 * Modal chrome (shared)
 *
 * Backdrop + card primitives used by:
 *   - Every tool's invalid-inputs modal (WTC, DAC, WAC, SSC, ...).
 *   - DAC's DA-trend zoom modal (`.modal-card--wide` variant).
 *   - Future tools' confirm dialogs.
 *
 * Previously duplicated inside each tool's per-tool CSS (WTC, DAC, WAC).
 * Lifted to shared during the SSC build per the "lift on tool 3" rule.
 *
 * Gotcha: `.modal-backdrop` sets `display: flex` to center its child,
 * which beats the UA's default `[hidden] { display: none }` rule. The
 * explicit `.modal-backdrop[hidden]` override is mandatory; without it,
 * `<div class="modal-backdrop" hidden>` would still render as a centered
 * full-viewport flex container.
 * ============================================================================ */
.modal-backdrop {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(15, 23, 42, 0.55);
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    animation: modal-backdrop-in 0.12s ease-out;
}
.modal-backdrop[hidden] {
    display: none;
}
@keyframes modal-backdrop-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
.modal-card {
    background: #fff;
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    max-width: 520px;
    width: 100%;
    padding: 24px 28px;
    animation: modal-card-in 0.18s ease-out;
}
/* Wide modifier for content that needs more horizontal room (DAC's
   DA-trend zoom uses this for a 640px chart + axis labels + stats row). */
.modal-card--wide {
    max-width: 760px;
}
@keyframes modal-card-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}
.modal-title {
    margin: 0 0 10px;
    font-size: 18px;
    font-weight: 700;
    color: var(--ink);
}
.modal-body {
    margin: 0 0 12px;
    color: var(--ink-700);
    font-size: 14px;
    line-height: 1.5;
    /* Tall modals (image lists, heading outlines, etc.) need to scroll
       inside the modal body without pushing the Close button off-screen. */
    max-height: 60vh;
    overflow-y: auto;
}

/* Body styling for the shared details modal (window.KeDetailsModal).
   Used by SEO Analyzer + SEO Optimizer for image lists, heading
   outlines, redirect chains, kv pairs, keyword tables, etc. */
.detail-note {
    font-size: 13px;
    color: var(--ink-500);
    line-height: 1.5;
    margin: 0 0 14px 0;
}
.detail-note code {
    background: var(--ink-50);
    padding: 1px 5px;
    border-radius: 3px;
    font-size: 12px;
}
.detail-list {
    list-style: none;
    margin: 0; padding: 0;
}
.detail-list li {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 4px 10px;
    padding: 8px 0;
    border-top: 1px solid var(--ink-100);
    font-size: 13px;
}
.detail-list li:first-child { border-top: 0; }
.detail-tag {
    grid-row: 1; grid-column: 1;
    align-self: center;
    font-size: 10px;
    font-weight: 700;
    padding: 2px 7px;
    border-radius: var(--r-sm);
    text-transform: uppercase;
    letter-spacing: 0.6px;
}
.detail-tag.missing { background: rgba(220, 38, 38, 0.12); color: rgb(159, 18, 18); }
.detail-tag.has    { background: rgba(22, 163, 74, 0.14); color: rgb(15, 109, 49); }
.detail-tag.lvl    { background: var(--ink-100); color: var(--ink-700); font-feature-settings: var(--tnum); }
.detail-tag.hop    { background: var(--ink-100); color: var(--ink-700); font-feature-settings: var(--tnum); }
/* Empty placeholder used by image_list rows that have alt text -
   keeps the grid's first column the same width as rows with a
   "missing" tag so the image URLs stay vertically aligned. */
.detail-tag-blank {
    display: inline-block;
    width: 64px;     /* roughly matches the "missing" tag */
    height: 1px;
}
.detail-main {
    grid-row: 1; grid-column: 2;
    word-break: break-all;
    color: var(--ink);
}
.detail-main .detail-alt {
    display: block;
    font-size: 12px;
    color: var(--ink-500);
    margin-top: 2px;
}
.detail-main mark {
    background: rgba(217, 119, 6, 0.22);
    color: rgb(120, 53, 15);
    padding: 0 2px;
    border-radius: 2px;
    font-weight: 600;
}
.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
}

/* Scrollable list of invalid input lines. Caps height so a 1000-line
   bulk submission with many bad lines doesn't blow up the modal. */
.invalid-list {
    list-style: none;
    margin: 0 0 20px;
    padding: 8px 12px;
    background: var(--ink-50);
    border: 1px solid var(--ink-100);
    border-radius: var(--r-sm);
    max-height: 220px;
    overflow-y: auto;
    font-size: 13px;
    line-height: 1.5;
}
.invalid-list li {
    color: var(--ink-700);
    padding: 4px 0;
    border-bottom: 1px solid var(--ink-100);
    display: flex;
    gap: 10px;
    align-items: baseline;
    word-break: break-all;
}
.invalid-list li:last-child {
    border-bottom: 0;
}
.invalid-list .invalid-line {
    color: var(--ink);
    font-weight: 500;
    flex: 1 1 auto;
    min-width: 0;
}
.invalid-list .invalid-reason {
    color: var(--brand-red);
    font-size: 12px;
    flex: 0 0 auto;
    white-space: nowrap;
}

/* ============================================================================
 * Tone pill picker (shared)                                                  
 * ============================================================================
 *
 * Pill-style single-choice radio group. Used by Sentence Rewriter (15 tones)
 * and AI Text Generator (15 tones). Each pill is a `<label>` wrapping a
 * hidden `<input type="radio">` plus a visible `<span class="tone-pill-label">`.
 *
 * Per-tool brand colors via CSS custom properties:
 *   --tone-brand        the selected-pill background + hover-border color
 *   --tone-brand-fade   the selected-pill hover background
 *   --tone-brand-tint   the unselected-pill hover background
 *
 * Defaults derive from the project brand-red so a tool that doesn't set its
 * own values still gets a usable picker.
 */
:root {
    --tone-brand:      var(--brand-red);
    --tone-brand-fade: var(--brand-red-dark);
    --tone-brand-tint: var(--brand-red-soft);
}
.tone-picker {
    border: none;
    padding: 0;
    margin: 0 0 12px 0;
}
.tone-picker .field-label,
.tone-picker .tone-picker-label {
    padding: 0;
    margin-bottom: 6px;
    display: block;
}
.tone-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
}
.tone-pill {
    position: relative;
    display: inline-flex;
    align-items: center;
    padding: 5px 12px;
    border: 1px solid var(--ink-200);
    border-radius: 999px;
    background: #fff;
    cursor: pointer;
    user-select: none;
    transition: all 0.12s ease;
    font-size: 0.8125rem;
    color: var(--ink-700);
}
.tone-pill input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.tone-pill:hover {
    border-color: var(--tone-brand);
    color: var(--tone-brand);
    background: var(--tone-brand-tint);
}
.tone-pill.is-selected {
    background: var(--tone-brand);
    border-color: var(--tone-brand);
    color: #fff;
    font-weight: 600;
}
.tone-pill.is-selected:hover {
    background: var(--tone-brand-fade);
    border-color: var(--tone-brand-fade);
    color: #fff;
}
.tone-pill input[type="radio"]:focus-visible + .tone-pill-label {
    outline: 2px solid var(--tone-brand-fade);
    outline-offset: 3px;
    border-radius: 4px;
}

/* Tool-info section.
   Sits inside .tool-main, after the upgrade banner and before the
   related-tools partial (which is rendered by footer.php). Holds
   per-tool methodology / glossary / FAQ content that's useful for
   first-time users AND addresses the "thin content" risk for search
   engines. Three collapsible <details> blocks: the first is open by
   default ("How it works"), the other two ("What the columns mean",
   "FAQ") are closed. FAQ items are individually collapsible via
   nested <details>; the visible HTML is paired with an inline
   application/ld+json FAQPage block that each tool's index.php emits
   for AI Overviews / voice-search eligibility (the FAQ rich result
   itself was deprecated August 2023; the markup still helps with
   non-SERP surfaces and is plain semantic anyway). */
.tool-info {
    margin: 48px 0 0;
    padding: 36px 0 8px;
    border-top: 1px solid var(--ink-100);
}
.tool-info-block {
    background: #fff;
    border: 1px solid var(--ink-100);
    border-radius: var(--r);
    box-shadow: var(--shadow-sm);
    margin-bottom: 14px;
    overflow: hidden;
}
.tool-info-block > .tool-info-summary {
    list-style: none;
    cursor: pointer;
    padding: 16px 22px;
    font-size: 16px;
    font-weight: 600;
    color: var(--ink-700);
    display: flex;
    align-items: center;
    gap: 10px;
    transition: background 0.15s ease;
}
.tool-info-block > .tool-info-summary::-webkit-details-marker { display: none; }
.tool-info-block > .tool-info-summary::before {
    content: "";
    width: 10px;
    height: 10px;
    border-right: 2px solid var(--brand-red);
    border-bottom: 2px solid var(--brand-red);
    /* Closed-state chevron points right. translateY nudge corrects
       the visual offset of the rotated diamond, which sits slightly
       below the geometric center against typographic capline. */
    transform: translateY(-2px) rotate(-45deg);
    transform-origin: 50% 50%;
    transition: transform 0.18s ease;
    flex: 0 0 auto;
    margin-right: 4px;
}
.tool-info-block[open] > .tool-info-summary::before {
    /* Open-state chevron points down. The "v" hangs lower than the
       geometric center, so a smaller upward nudge keeps it on the
       cap-line. */
    transform: translateY(-4px) rotate(45deg);
}
.tool-info-block > .tool-info-summary:hover {
    background: var(--ink-25);
}
.tool-info-block:focus-within > .tool-info-summary {
    outline: none;
}
.tool-info-block > .tool-info-summary:focus-visible {
    outline: 2px solid var(--brand-red-light);
    outline-offset: -2px;
}
.tool-info-body {
    padding: 4px 22px 22px;
    color: var(--ink-700);
    font-size: 14.5px;
    line-height: 1.65;
}
.tool-info-body p {
    margin: 0 0 12px;
}
.tool-info-body p:last-child {
    margin-bottom: 0;
}
.tool-info-body ul {
    margin: 0 0 12px;
    padding-left: 22px;
}
.tool-info-body li {
    margin: 0 0 6px;
}
.tool-info-body strong { color: #2e3439; }
.tool-info-body code {
    background: var(--ink-50);
    padding: 1px 5px;
    border-radius: 3px;
    font-size: 13px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* Glossary definition list */
.tool-info-glossary {
    margin: 0;
}
.tool-info-glossary dt {
    font-weight: 600;
    color: #2e3439;
    margin-top: 14px;
    margin-bottom: 4px;
    font-size: 14.5px;
}
.tool-info-glossary dt:first-child {
    margin-top: 4px;
}
.tool-info-glossary dd {
    margin: 0 0 4px;
    color: var(--ink-700);
}

/* FAQ items inside the FAQ block. Each is its own <details> so a user
   can scan questions and open only the answers they care about. The
   inner summary uses an h3 for semantic structure + crawlability. */
.tool-info-faq {
    padding: 4px 0 0;
}
.tool-info-faq .faq-item {
    border-top: 1px solid var(--ink-100);
}
.tool-info-faq .faq-item:first-of-type {
    border-top: 0;
}
.tool-info-faq .faq-summary {
    list-style: none;
    cursor: pointer;
    /* Left padding matches the parent .tool-info-summary's 22px so
       the FAQ chevrons sit at the same x as the "Frequently asked
       questions" chevron above. */
    padding: 14px 22px 14px 22px;
    display: flex;
    align-items: flex-start;
    gap: 12px;
    transition: color 0.15s ease;
}
.tool-info-faq .faq-summary::-webkit-details-marker { display: none; }
.tool-info-faq .faq-summary::before {
    content: "";
    width: 8px;
    height: 8px;
    /* Pin the chevron at the first-line cap-height of the h3 (15px /
       line-height 1.5 = ~22.5px line box; cap-height center sits ~5px
       below the line-box top). 4px from the summary's 14px top
       padding lines that up cleanly. */
    margin-top: 5px;
    border-right: 2px solid var(--ink-400);
    border-bottom: 2px solid var(--ink-400);
    transform: rotate(-45deg);
    transform-origin: 50% 50%;
    transition: transform 0.18s ease, border-color 0.15s ease;
    flex: 0 0 auto;
}
.tool-info-faq .faq-item[open] > .faq-summary::before {
    /* Open-state "v" sits visually lower; nudge up 1px. */
    margin-top: 4px;
    transform: rotate(45deg);
    border-color: var(--brand-red);
}
.tool-info-faq .faq-summary h3 {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: var(--ink-700);
    line-height: 1.5;
}
.tool-info-faq .faq-item[open] > .faq-summary h3 {
    color: #2e3439;
}
.tool-info-faq .faq-summary:hover h3 {
    color: var(--brand-red);
}
.tool-info-faq .faq-answer {
    /* Left padding lines the answer up under the question's first
       character. Math: faq-summary padding-left 22 + chevron 8 +
       gap 12 = 42. */
    padding: 0 22px 16px 42px;
    color: var(--ink-700);
    font-size: 14.5px;
    line-height: 1.65;
}
.tool-info-faq .faq-answer p {
    margin: 0 0 10px;
}
.tool-info-faq .faq-answer p:last-child {
    margin-bottom: 0;
}
.tool-info-faq .faq-answer a {
    color: var(--brand-red);
    text-decoration: none;
    border-bottom: 1px solid var(--brand-red-tint);
}
.tool-info-faq .faq-answer a:hover {
    border-bottom-color: var(--brand-red);
}

@media (max-width: 640px) {
    .tool-info { padding: 28px 0 4px; margin-top: 36px; }
    .tool-info-block > .tool-info-summary { padding: 14px 16px; font-size: 15px; }
    .tool-info-body { padding: 4px 16px 18px; font-size: 14px; }
    .tool-info-glossary dt { font-size: 14px; }
    .tool-info-faq .faq-summary { padding: 12px 16px 12px 16px; gap: 10px; }
    .tool-info-faq .faq-summary h3 { font-size: 14.5px; }
    /* Match the desktop alignment math at mobile padding values:
       summary padding-left 16 + chevron 8 + gap 10 = 34. */
    .tool-info-faq .faq-answer { padding: 0 16px 14px 34px; font-size: 14px; }
}

/* Related-tools section.
   Rendered at the bottom of every tool page (just above the footer) via
   code/includes/related-tools.php. The 4 cards inherit the homepage
   .tool-card visual language but in a more compact form and with a tinted
   section background so the boundary between the tool's own output and
   the "you might also like" surface is unambiguous. */
.related-tools {
    background: var(--ink-50);
    border-top: 1px solid var(--ink-100);
    padding: 48px 0 56px;
    margin-top: 48px;
}
.related-tools-heading {
    margin: 0 0 24px;
    font-size: 18px;
    font-weight: 700;
    color: var(--ink);
    letter-spacing: -0.1px;
}
.related-tools-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 16px;
}
.related-tool-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid var(--ink-100);
    border-radius: var(--r);
    padding: 18px;
    box-shadow: var(--shadow-sm);
    text-decoration: none;
    color: inherit;
    transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1),
                box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1),
                border-color 0.18s ease;
}
.related-tool-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-lg);
    border-color: var(--brand-red-tint);
    color: inherit;
    text-decoration: none;
}
.related-tool-icon {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 8px;
    background: linear-gradient(135deg, #fdecec 0%, #fbd7d6 100%);
    color: var(--brand-red);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    margin-bottom: 12px;
    transition: transform 0.18s ease;
}
.related-tool-card:hover .related-tool-icon {
    transform: scale(1.05);
}
.related-tool-name {
    margin: 0 0 6px;
    font-size: 14.5px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--ink);
    letter-spacing: -0.1px;
}
.related-tool-description {
    margin: 0 0 12px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--ink-500);
    flex-grow: 1;
}
.related-tool-cta {
    display: inline-flex;
    align-items: center;
    color: var(--brand-red);
    font-weight: 600;
    font-size: 12px;
    letter-spacing: 0.1px;
}
.related-tool-cta::after {
    content: "→";
    margin-left: 5px;
    display: inline-block;
    transition: transform 0.18s ease;
}
.related-tool-card:hover .related-tool-cta::after {
    transform: translateX(3px);
}

/* ========================================================================
   Quota banner (shared)

   Compact single-line affordance above the form-card. Shows what the
   visitor has left today for the resource(s) the current tool uses.
   Colour state is driven by the LOWEST remaining-pct across all listed
   resources:
       >= 80%  -> is-good   (green)
       50..79% -> is-fair   (blue)
       20..49% -> is-warn   (yellow)
       <  20%  -> is-danger (red)

   Markup is rendered by includes/footer.php conditional on
   $skip_quota_banner (default false on tool pages). Wired by
   code/assets/js/quota-banner.js (loaded globally from header.php).
   ======================================================================== */
.quota-banner {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 6px 14px;
    border-radius: var(--r-md);
    border-left: 3px solid currentColor;
    margin-bottom: 12px;
    font-size: 13.5px;
    line-height: 1.35;
    min-height: 32px;
}
.quota-banner[hidden] { display: none; }
.quota-banner.is-good   { background: #ecfdf5; color: #047857; }
.quota-banner.is-fair   { background: #eff6ff; color: #1d4ed8; }
.quota-banner.is-warn   { background: #fffbeb; color: #b45309; }
.quota-banner.is-danger { background: #fef2f2; color: #b91c1c; }

.quota-banner-label {
    font-weight: 700;
    color: inherit;
}
.quota-banner-resources {
    display: inline-flex;
    gap: 10px;
    flex-wrap: wrap;
    color: var(--ink-800);
}
.quota-banner-item {
    white-space: nowrap;
}
.quota-banner-item strong {
    color: inherit;
    font-weight: 700;
}
.quota-banner-sep {
    color: var(--ink-400);
    user-select: none;
}
.quota-banner-cta {
    margin-left: auto;
    color: inherit;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}
.quota-banner-cta:hover {
    text-decoration: underline;
}
.quota-banner-cta[hidden] { display: none; }

@media (max-width: 640px) {
    .quota-banner {
        font-size: 13px;
        padding: 6px 12px;
        flex-wrap: wrap;
    }
    .quota-banner-resources { gap: 6px; }
    .quota-banner-cta { margin-left: 0; }
}

/* ========================================================================
   Back-to-top button (shared)

   Markup pattern any page can drop in once:
     <button type="button" class="back-to-top" id="back-to-top"
             aria-label="Back to top" hidden>
       <svg viewBox="0 0 24 24" width="20" height="20" ...>...</svg>
     </button>

   Wiring lives in code/assets/js/back-to-top.js (loaded globally by
   the shared header).
   ======================================================================== */
.back-to-top {
    /* Fixed bottom-right, lifted clear of the reCAPTCHA badge which
       lives at ~14px from each edge. Higher z-index than page chrome
       but below the details modal backdrop. */
    position: fixed;
    bottom: 90px;
    right: 20px;
    z-index: 50;
    width: 44px; height: 44px;
    border-radius: 50%;
    background: var(--brand-red);
    color: #fff;
    border: 0;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.18s ease, transform 0.18s ease, background 0.12s;
}
.back-to-top.is-visible {
    opacity: 1;
    transform: translateY(0);
}
.back-to-top[hidden] { display: none; }
.back-to-top:hover { background: var(--brand-red-dark, #a32626); }
.back-to-top:focus-visible {
    outline: 2px solid var(--brand-red);
    outline-offset: 3px;
}
@media (max-width: 480px) {
    .back-to-top { bottom: 78px; right: 14px; width: 40px; height: 40px; }
}
