/* ==========================================================================
   Brandligo — design system
   ==========================================================================

   Strict monochrome. Black, white and a grey ramp carry the entire interface.
   Colour is reserved for three jobs and nothing else:
     - star ratings (amber)
     - status states (success / warning / danger)
     - focus rings (inherits ink, so still monochrome)

   Loaded directly from public/ rather than compiled through Vite. The stylesheet
   is hand-written plain CSS with custom properties — there is nothing to
   transpile, and routing it through a build step would mean the application
   cannot render until someone runs `npm install`. One file, one source of truth.

   This replaces custom.css, which was a partial re-implementation of Tailwind
   utilities: 255 lines, duplicated across resources/ and public/ (only the
   public copy was ever loaded), and referencing `hover:` variants it never
   defined — so those hover states silently did nothing.

   Layered so Bootstrap's cascade can be overridden predictably.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
    /* Ink ramp. 0 is paper, 950 is ink. Every surface, border and text colour
       in the app resolves to one of these. */
    --ink-0: #ffffff;
    --ink-25: #fcfcfc;
    --ink-50: #f7f7f8;
    --ink-100: #ededee;
    --ink-200: #e0e0e2;
    --ink-300: #c8c8cc;
    --ink-400: #a0a0a6;
    --ink-500: #78787f;
    --ink-600: #56565c;
    --ink-700: #3d3d42;
    --ink-800: #26262a;
    --ink-900: #16161a;
    --ink-950: #0a0a0b;

    /* Semantic surfaces — the only names views should reference. Remapping
       these is what makes dark mode a single block of overrides. */
    --surface: var(--ink-0);
    --surface-sunken: var(--ink-50);
    --surface-raised: var(--ink-0);
    --surface-inverse: var(--ink-950);
    --surface-hover: var(--ink-50);
    --surface-active: var(--ink-100);

    --text: var(--ink-950);
    --text-muted: var(--ink-500);
    --text-subtle: var(--ink-400);
    --text-inverse: var(--ink-0);

    --border: var(--ink-200);
    --border-strong: var(--ink-300);
    --border-inverse: var(--ink-800);

    /* The three permitted colours. Chosen at AA contrast against --surface. */
    --rating: #b45309;
    /* Separate token for bar fills. Stars and numerals are text and need 4.5:1, but a
       meter fill is a graphical object at 3:1 — so it can be a genuinely yellow
       yellow instead of the brown-amber that text contrast forces. */
    --rating-bar: #eab308;
    --rating-bg: #fef3c7;
    --success: #15803d;
    --success-bg: #dcfce7;
    --warning: #a16207;
    --warning-bg: #fef9c3;
    --danger: #b91c1c;
    --danger-bg: #fee2e2;

    /* Type. One geometric sans; system stack so there is no webfont round trip. */
    --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
        Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
        "Liberation Mono", monospace;

    /* Fluid scale — clamp() means no breakpoint-specific font sizes. */
    --text-xs: 0.75rem;
    --text-sm: 0.8125rem;
    --text-base: 0.9375rem;
    --text-md: 1rem;
    --text-lg: 1.125rem;
    --text-xl: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
    --text-2xl: clamp(1.5rem, 1.3rem + 1vw, 2rem);
    --text-3xl: clamp(1.875rem, 1.5rem + 1.8vw, 2.75rem);
    --text-4xl: clamp(2.25rem, 1.6rem + 3vw, 3.75rem);

    --leading-tight: 1.15;
    --leading-snug: 1.35;
    --leading-normal: 1.6;

    /* Headings tighten as they grow; body stays neutral. */
    --tracking-tight: -0.025em;
    --tracking-tighter: -0.04em;
    --tracking-wide: 0.02em;
    --tracking-widest: 0.12em;

    /* 4px base. */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-8: 2rem;
    --space-10: 2.5rem;
    --space-12: 3rem;
    --space-16: 4rem;
    --space-20: 5rem;
    --space-24: 6rem;

    --radius-sm: 4px;
    --radius: 8px;
    --radius-md: 10px;
    --radius-lg: 14px;
    --radius-xl: 20px;
    --radius-full: 999px;

    /* Shadows are pure black at low alpha, so they read correctly on both
       themes rather than turning muddy the way coloured shadows do. */
    --shadow-xs: 0 1px 2px rgba(10, 10, 11, 0.05);
    --shadow-sm: 0 1px 3px rgba(10, 10, 11, 0.07), 0 1px 2px rgba(10, 10, 11, 0.04);
    --shadow: 0 4px 12px rgba(10, 10, 11, 0.07), 0 1px 3px rgba(10, 10, 11, 0.05);
    --shadow-lg: 0 12px 32px rgba(10, 10, 11, 0.1), 0 2px 6px rgba(10, 10, 11, 0.05);
    --shadow-xl: 0 24px 56px rgba(10, 10, 11, 0.14), 0 4px 10px rgba(10, 10, 11, 0.06);

    --ease: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --duration: 160ms;
    --duration-slow: 280ms;

    --header-height: 4rem;
    --container: 76rem;

    color-scheme: light;
}

/* Dark mode. Because the system is monochrome, inverting is a matter of
   remapping the semantic tokens — no component needs a dark variant. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --surface: var(--ink-950);
        --surface-sunken: #050506;
        --surface-raised: var(--ink-900);
        --surface-inverse: var(--ink-0);
        --surface-hover: var(--ink-900);
        --surface-active: var(--ink-800);

        --text: var(--ink-50);
        --text-muted: var(--ink-400);
        --text-subtle: var(--ink-500);
        --text-inverse: var(--ink-950);

        --border: var(--ink-800);
        --border-strong: var(--ink-700);
        --border-inverse: var(--ink-200);

        /* Backgrounds darken; foregrounds lighten to hold contrast on ink. */
        --rating: #fbbf24;
        --rating-bar: #facc15;
        --rating-bg: rgba(251, 191, 36, 0.12);
        --success: #4ade80;
        --success-bg: rgba(74, 222, 128, 0.12);
        --warning: #fbbf24;
        --warning-bg: rgba(251, 191, 36, 0.12);
        --danger: #f87171;
        --danger-bg: rgba(248, 113, 113, 0.12);

        --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
        --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5);
        --shadow: 0 4px 12px rgba(0, 0, 0, 0.55);
        --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.6);
        --shadow-xl: 0 24px 56px rgba(0, 0, 0, 0.7);

        color-scheme: dark;
    }
}

/* Manual toggle. Must win over the media query in both directions, which is why
   both selectors are explicit rather than relying on the cascade. */
:root[data-theme="dark"] {
    --surface: var(--ink-950);
    --surface-sunken: #050506;
    --surface-raised: var(--ink-900);
    --surface-inverse: var(--ink-0);
    --surface-hover: var(--ink-900);
    --surface-active: var(--ink-800);

    --text: var(--ink-50);
    --text-muted: var(--ink-400);
    --text-subtle: var(--ink-500);
    --text-inverse: var(--ink-950);

    --border: var(--ink-800);
    --border-strong: var(--ink-700);
    --border-inverse: var(--ink-200);

    --rating: #fbbf24;
    --rating-bar: #facc15;
    --rating-bg: rgba(251, 191, 36, 0.12);
    --success: #4ade80;
    --success-bg: rgba(74, 222, 128, 0.12);
    --warning: #fbbf24;
    --warning-bg: rgba(251, 191, 36, 0.12);
    --danger: #f87171;
    --danger-bg: rgba(248, 113, 113, 0.12);

    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5);
    --shadow: 0 4px 12px rgba(0, 0, 0, 0.55);
    --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.6);
    --shadow-xl: 0 24px 56px rgba(0, 0, 0, 0.7);

    color-scheme: dark;
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    /* Anchored sections clear the sticky header instead of hiding under it. */
    scroll-padding-top: calc(var(--header-height) + var(--space-4));
}

body {
    margin: 0;
    background-color: var(--surface);
    color: var(--text);
    font-family: var(--font-sans);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-feature-settings: "cv11", "ss01";
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

h1, h2, h3, h4, h5, h6 {
    margin: 0 0 var(--space-3);
    font-weight: 650;
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tight);
    color: var(--text);
    text-wrap: balance;
}

h1 { font-size: var(--text-3xl); letter-spacing: var(--tracking-tighter); }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-xl); }
h4 { font-size: var(--text-lg); }
h5, h6 { font-size: var(--text-md); }

p { margin: 0 0 var(--space-4); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a {
    color: var(--text);
    text-decoration: none;
    text-underline-offset: 0.2em;
    transition: color var(--duration) var(--ease), opacity var(--duration) var(--ease);
}

a:hover { text-decoration: underline; }

small { font-size: var(--text-sm); }

hr {
    border: 0;
    border-top: 1px solid var(--border);
    margin: var(--space-8) 0;
    opacity: 1;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

/* Nothing may widen the page. `clip` and not `hidden` on purpose — `hidden` here
   makes the viewport a scroll container, which breaks every position:sticky
   descendant including the header. `clip` contains the overflow and leaves
   sticky working. */
html { overflow-x: clip; }

body {
    overflow-x: clip;
    /* Belt and braces: a single long unbroken string (a pasted URL in a review,
       a slug with no spaces) is the other way a page outgrows its container. */
    overflow-wrap: break-word;
}

/* Long user-supplied strings inside constrained boxes. */
td, th, dd, p, h1, h2, h3, h4, li, .bl-card, .bl-badge { min-width: 0; }

code, kbd, pre { font-family: var(--font-mono); font-size: 0.9em; }

/* Inline chrome icons. Sized in em so they track the text beside them, and given an
   explicit height because the global svg reset sets height:auto — which would otherwise
   derive height from the intrinsic aspect ratio and ignore the attribute. */
.bl-icon {
    width: 1em;
    height: 1em;
    flex: none;
}

.bl-icon--lg { width: 1.25em; height: 1.25em; }

/* One focus treatment everywhere. Monochrome, and always visible against both
   surfaces because it uses the text colour rather than a fixed hue. */
:focus-visible {
    outline: 2px solid var(--text);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

::selection {
    background: var(--surface-inverse);
    color: var(--text-inverse);
}

@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;
    }
}

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */

.bl-container {
    width: 100%;
    max-width: var(--container);
    margin-inline: auto;
    padding-inline: var(--space-5);
}

.bl-container--narrow { max-width: 46rem; }
.bl-container--wide { max-width: 90rem; }

.bl-main { flex: 1 0 auto; }

.bl-section { padding-block: var(--space-16); }
.bl-section--tight { padding-block: var(--space-10); }
.bl-section--sunken { background: var(--surface-sunken); }

.bl-stack { display: flex; flex-direction: column; gap: var(--space-4); }
.bl-stack--sm { gap: var(--space-2); }
.bl-stack--lg { gap: var(--space-8); }

.bl-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.bl-row--between { justify-content: space-between; }
.bl-row--tight { gap: var(--space-2); }

.bl-grid {
    display: grid;
    gap: var(--space-5);
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
}

.bl-grid--2 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 22rem), 1fr)); }
.bl-grid--4 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 13rem), 1fr)); }

/* Screen-reader-only, for labels that must exist but not display. */
.bl-sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Skip link — first focusable element on every page. */
.bl-skip {
    position: absolute;
    top: var(--space-2);
    left: var(--space-2);
    z-index: 200;
    padding: var(--space-2) var(--space-4);
    background: var(--surface-inverse);
    color: var(--text-inverse);
    border-radius: var(--radius);
    font-size: var(--text-sm);
    font-weight: 600;
    transform: translateY(-200%);
    transition: transform var(--duration) var(--ease);
}

.bl-skip:focus { transform: translateY(0); text-decoration: none; }

/* --------------------------------------------------------------------------
   4. Type utilities
   -------------------------------------------------------------------------- */

.bl-display {
    font-size: var(--text-4xl);
    font-weight: 700;
    letter-spacing: var(--tracking-tighter);
    line-height: 1.05;
    margin-bottom: var(--space-4);
}

.bl-lead {
    font-size: var(--text-lg);
    color: var(--text-muted);
    line-height: var(--leading-snug);
    max-width: 42rem;
}

.bl-eyebrow {
    font-size: var(--text-xs);
    font-weight: 650;
    letter-spacing: var(--tracking-widest);
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: var(--space-3);
    display: block;
}

.bl-muted { color: var(--text-muted); }
.bl-subtle { color: var(--text-subtle); }
.bl-mono { font-family: var(--font-mono); font-size: 0.9em; }
.bl-nowrap { white-space: nowrap; }
.bl-tabular { font-variant-numeric: tabular-nums; }

.bl-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Line clamping keeps card heights uniform without JS measurement. */
.bl-clamp-2,
.bl-clamp-3 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.bl-clamp-2 { -webkit-line-clamp: 2; line-clamp: 2; }
.bl-clamp-3 { -webkit-line-clamp: 3; line-clamp: 3; }

/* --------------------------------------------------------------------------
   5. Buttons
   -------------------------------------------------------------------------- */

.bl-btn {
    --btn-bg: transparent;
    --btn-fg: var(--text);
    --btn-border: var(--border-strong);

    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 0.5625rem var(--space-4);
    background: var(--btn-bg);
    color: var(--btn-fg);
    border: 1px solid var(--btn-border);
    border-radius: var(--radius);
    font: inherit;
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.005em;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
    transition: background-color var(--duration) var(--ease),
                border-color var(--duration) var(--ease),
                color var(--duration) var(--ease),
                transform var(--duration) var(--ease),
                box-shadow var(--duration) var(--ease);
}

.bl-btn:hover { text-decoration: none; }
.bl-btn:active { transform: translateY(1px); }

.bl-btn:disabled,
.bl-btn[aria-disabled="true"] {
    opacity: 0.45;
    cursor: not-allowed;
    transform: none;
}

/* Primary is solid ink — the strongest thing a monochrome palette can offer,
   which is why it is reserved for one action per view. */
.bl-btn--primary {
    --btn-bg: var(--surface-inverse);
    --btn-fg: var(--text-inverse);
    --btn-border: var(--surface-inverse);
    box-shadow: var(--shadow-xs);
}

.bl-btn--primary:hover {
    --btn-bg: var(--ink-800);
    --btn-border: var(--ink-800);
    box-shadow: var(--shadow-sm);
}

/* On dark, "darker ink" would mean invisible — lighten the hover instead. */
:root[data-theme="dark"] .bl-btn--primary:hover {
    --btn-bg: var(--ink-200);
    --btn-border: var(--ink-200);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .bl-btn--primary:hover {
        --btn-bg: var(--ink-200);
        --btn-border: var(--ink-200);
    }
}

.bl-btn--secondary { --btn-bg: var(--surface); }
.bl-btn--secondary:hover { --btn-bg: var(--surface-hover); --btn-border: var(--text-muted); }

.bl-btn--ghost { --btn-border: transparent; }
.bl-btn--ghost:hover { --btn-bg: var(--surface-hover); }

.bl-btn--danger { --btn-fg: var(--danger); --btn-border: var(--border-strong); }
.bl-btn--danger:hover { --btn-bg: var(--danger-bg); --btn-border: var(--danger); }

.bl-btn--sm { padding: 0.375rem var(--space-3); font-size: var(--text-xs); }
.bl-btn--lg { padding: 0.75rem var(--space-6); font-size: var(--text-md); }
.bl-btn--block { width: 100%; }

.bl-btn--icon {
    padding: 0.5rem;
    aspect-ratio: 1;
    --btn-border: transparent;
}

.bl-btn--icon:hover { --btn-bg: var(--surface-hover); }

/* --------------------------------------------------------------------------
   6. Cards
   -------------------------------------------------------------------------- */

.bl-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    transition: border-color var(--duration) var(--ease),
                box-shadow var(--duration) var(--ease),
                transform var(--duration) var(--ease);
}

.bl-card__body { padding: var(--space-5); flex: 1 1 auto; }
.bl-card__body--tight { padding: var(--space-4); }

.bl-card__header {
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

.bl-card__footer {
    padding: var(--space-4) var(--space-5);
    border-top: 1px solid var(--border);
    background: var(--surface-sunken);
}

.bl-card__media {
    aspect-ratio: 16 / 10;
    object-fit: cover;
    width: 100%;
    background: var(--surface-sunken);
    border-bottom: 1px solid var(--border);
}

/* Only cards that are genuinely a single link get the lift. */
.bl-card--interactive:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow);
    transform: translateY(-2px);
}

.bl-card--flat { border-radius: var(--radius); }

.bl-card--inverse {
    background: var(--surface-inverse);
    border-color: var(--surface-inverse);
    color: var(--text-inverse);
}

.bl-card--inverse h1, .bl-card--inverse h2, .bl-card--inverse h3,
.bl-card--inverse h4, .bl-card--inverse a { color: var(--text-inverse); }

.bl-card--inverse .bl-muted { color: var(--ink-400); }

/* Covers the whole card with one link without nesting anchors. */
.bl-card__link::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
}

/* --------------------------------------------------------------------------
   7. Badges, pills, ratings
   -------------------------------------------------------------------------- */

.bl-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.1875rem var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    color: var(--text-muted);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: var(--tracking-wide);
    white-space: nowrap;
    line-height: 1.4;
}

.bl-badge--solid {
    background: var(--surface-inverse);
    border-color: var(--surface-inverse);
    color: var(--text-inverse);
}

.bl-badge--outline { background: transparent; color: var(--text); border-color: var(--border-strong); }

.bl-badge--success { background: var(--success-bg); border-color: transparent; color: var(--success); }
.bl-badge--warning { background: var(--warning-bg); border-color: transparent; color: var(--warning); }
.bl-badge--danger { background: var(--danger-bg); border-color: transparent; color: var(--danger); }

/* A 6px dot carries status in a table row without spending horizontal space. */
.bl-dot {
    width: 0.4375rem;
    height: 0.4375rem;
    border-radius: var(--radius-full);
    background: var(--text-subtle);
    flex: none;
}

.bl-dot--success { background: var(--success); }
.bl-dot--warning { background: var(--warning); }
.bl-dot--danger { background: var(--danger); }

.bl-rating { display: inline-flex; align-items: center; gap: 0.375rem; }
.bl-rating__stars { display: inline-flex; gap: 0.0625rem; color: var(--rating); font-size: var(--text-sm); }
.bl-rating__stars .bl-star--empty { color: var(--border-strong); }
.bl-rating__value { font-weight: 650; font-variant-numeric: tabular-nums; }
.bl-rating__count { color: var(--text-muted); font-size: var(--text-sm); }

/* Rating distribution bars on a profile. */
.bl-meter {
    height: 0.375rem;
    background: var(--surface-active);
    border-radius: var(--radius-full);
    overflow: hidden;
}

.bl-meter__fill {
    /* display:block is load-bearing. This is rendered as a <span>, and an inline
       element ignores height — so height:100% produced a zero-height fill and every
       rating bar showed as an empty track. */
    display: block;
    height: 100%;
    min-width: 2px;
    background: var(--surface-inverse);
    border-radius: var(--radius-full);
    transition: width var(--duration-slow) var(--ease-out);
}

.bl-meter__fill--rating { background: var(--rating-bar); }

/* --------------------------------------------------------------------------
   8. Avatars & logos
   -------------------------------------------------------------------------- */

.bl-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: var(--radius);
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    color: var(--text-muted);
    font-size: var(--text-sm);
    font-weight: 650;
    letter-spacing: 0;
    overflow: hidden;
    flex: none;
    text-transform: uppercase;
}

/* The image is layered over the initials rather than replacing them, so a logo that fails
   to load falls back to initials with no script involved. */
.bl-avatar { position: relative; }

.bl-avatar__initials {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.bl-avatar__image,
.bl-avatar img {
    position: relative;
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: var(--surface-sunken);
}
.bl-avatar--sm { width: 2rem; height: 2rem; font-size: var(--text-xs); }
.bl-avatar--lg { width: 4rem; height: 4rem; font-size: var(--text-lg); border-radius: var(--radius-md); }
.bl-avatar--xl { width: 5.5rem; height: 5.5rem; font-size: var(--text-2xl); border-radius: var(--radius-lg); }
.bl-avatar--circle { border-radius: var(--radius-full); }

/* --------------------------------------------------------------------------
   9. Forms
   -------------------------------------------------------------------------- */

.bl-field { margin-bottom: var(--space-4); }

.bl-label {
    display: block;
    margin-bottom: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text);
}

.bl-label__required { color: var(--danger); margin-left: 0.125rem; }

.bl-input,
.bl-select,
.bl-textarea {
    display: block;
    width: 100%;
    padding: 0.5625rem var(--space-3);
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    font: inherit;
    font-size: var(--text-base);
    line-height: 1.4;
    transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
    appearance: none;
}

.bl-input::placeholder, .bl-textarea::placeholder { color: var(--text-subtle); }

.bl-input:hover, .bl-select:hover, .bl-textarea:hover { border-color: var(--text-subtle); }

.bl-input:focus, .bl-select:focus, .bl-textarea:focus {
    outline: none;
    border-color: var(--text);
    box-shadow: 0 0 0 3px var(--surface-active);
}

.bl-textarea { min-height: 7rem; resize: vertical; }

/* Chevron drawn in CSS so no icon font is needed, and it recolours with the
   theme because the stroke is encoded from currentColor's light/dark value. */
.bl-select {
    padding-right: var(--space-8);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' stroke='%2378787f' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--space-3) center;
}

.bl-input--invalid, .bl-select--invalid, .bl-textarea--invalid { border-color: var(--danger); }

.bl-input--invalid:focus, .bl-select--invalid:focus, .bl-textarea--invalid:focus {
    border-color: var(--danger);
    box-shadow: 0 0 0 3px var(--danger-bg);
}

.bl-hint { margin-top: var(--space-2); font-size: var(--text-sm); color: var(--text-muted); }
.bl-error { margin-top: var(--space-2); font-size: var(--text-sm); color: var(--danger); font-weight: 500; }

.bl-check { display: flex; align-items: flex-start; gap: var(--space-3); margin-bottom: var(--space-3); }

.bl-check input[type="checkbox"],
.bl-check input[type="radio"] {
    width: 1.0625rem;
    height: 1.0625rem;
    margin: 0.1875rem 0 0;
    accent-color: var(--text);
    flex: none;
    cursor: pointer;
}

.bl-check label { font-size: var(--text-base); cursor: pointer; }

.bl-fieldset {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--space-4);
    margin-bottom: var(--space-5);
}

.bl-fieldset > legend {
    padding-inline: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 650;
    color: var(--text-muted);
    width: auto;
    float: none;
}

/* Search field with a leading icon slot. */
.bl-search { position: relative; }
.bl-search .bl-input { padding-left: var(--space-10); }
.bl-search__icon {
    position: absolute;
    left: var(--space-3);
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-subtle);
    pointer-events: none;
    font-size: var(--text-sm);
}

/* --------------------------------------------------------------------------
   10. Tables
   -------------------------------------------------------------------------- */

.bl-table-wrap {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow-x: auto;
    background: var(--surface-raised);
}

.bl-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }

.bl-table th {
    padding: var(--space-3) var(--space-4);
    text-align: left;
    font-size: var(--text-xs);
    font-weight: 650;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--text-muted);
    background: var(--surface-sunken);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}

.bl-table td {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}

.bl-table tbody tr:last-child td { border-bottom: 0; }
.bl-table tbody tr { transition: background-color var(--duration) var(--ease); }
.bl-table tbody tr:hover { background: var(--surface-hover); }

.bl-table__num { text-align: right; font-variant-numeric: tabular-nums; }
.bl-table__actions { text-align: right; white-space: nowrap; }

/* --------------------------------------------------------------------------
   11. Header & navigation
   -------------------------------------------------------------------------- */

.bl-header {
    position: sticky;
    top: 0;
    z-index: 100;
    background: color-mix(in srgb, var(--surface) 88%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--border);
}

/* backdrop-filter is not universal; fall back to an opaque bar. */
@supports not (backdrop-filter: blur(1px)) {
    .bl-header { background: var(--surface); }
}

.bl-header__inner {
    height: var(--header-height);
    display: flex;
    align-items: center;
    gap: var(--space-6);
}

.bl-nav { display: flex; align-items: center; gap: var(--space-1); }

.bl-nav__link {
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius);
    font-size: var(--text-sm);
    font-weight: 550;
    color: var(--text-muted);
    transition: color var(--duration) var(--ease), background-color var(--duration) var(--ease);
}

.bl-nav__link:hover { color: var(--text); background: var(--surface-hover); text-decoration: none; }

.bl-nav__link[aria-current="page"] { color: var(--text); font-weight: 650; }

.bl-header__spacer { flex: 1 1 auto; }

/* Mobile drawer, toggled by a checkbox so it works without JavaScript. */
/* Grouped nav menu. The header's five directory indexes collapse into one
   dropdown so the top bar stops mirroring the footer's Browse column. */
.bl-nav__group { position: relative; }

.bl-nav__link--button {
    background: none;
    border: 0;
    font: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.bl-nav__caret {
    font-size: 0.6em;
    transition: transform var(--duration-fast) var(--ease-out);
}

.bl-nav__group .dropdown-toggle::after { display: none; }
.bl-nav__link--button[aria-expanded="true"] .bl-nav__caret { transform: rotate(180deg); }

.bl-menu {
    min-width: 19rem;
    padding: var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--shadow-lg);
}

.bl-menu__item {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3);
    border-radius: var(--radius-md);
    color: var(--text);
    text-decoration: none;
}

.bl-menu__item:hover,
.bl-menu__item:focus-visible {
    background: var(--surface-sunken);
    color: var(--text);
}

.bl-menu__icon {
    flex: 0 0 auto;
    width: 1.25rem;
    margin-top: 0.15rem;
    color: var(--text-muted);
    text-align: center;
}

.bl-menu__text { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.bl-menu__label { font-weight: var(--weight-medium); }
.bl-menu__blurb { font-size: var(--text-xs); color: var(--text-muted); }

.bl-nav-toggle { display: none; }

/* The drawer is hidden at every width unless it is toggled open. This rule used to
   live inside the max-width:900px block, which meant nothing hid it on desktop at
   all — it rendered as a permanent second navigation strip under the header, a
   near-duplicate of the primary nav. */
.bl-drawer {
    display: none;
    border-top: 1px solid var(--border);
    background: var(--surface);
    padding: var(--space-4) 0;
}

.bl-drawer .bl-nav { flex-direction: column; align-items: stretch; }
.bl-drawer .bl-nav__link { padding: var(--space-3); }

@media (max-width: 900px) {
    .bl-nav--primary,
    .bl-header__search { display: none; }
    .bl-nav-toggle { display: inline-flex; }

    /* Only openable where the toggle that opens it is actually reachable. */
    .bl-drawer[data-open="true"] { display: block; }
}

/* --------------------------------------------------------------------------
   12. Footer
   -------------------------------------------------------------------------- */

.bl-footer {
    margin-top: auto;
    border-top: 1px solid var(--border);
    background: var(--surface-sunken);
    padding-block: var(--space-12) var(--space-8);
    font-size: var(--text-sm);
}

.bl-footer__grid {
    display: grid;
    gap: var(--space-8);
    grid-template-columns: minmax(14rem, 1.4fr) repeat(auto-fit, minmax(9rem, 1fr));
    margin-bottom: var(--space-10);
}

.bl-footer h2, .bl-footer h3 {
    font-size: var(--text-xs);
    font-weight: 650;
    letter-spacing: var(--tracking-widest);
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: var(--space-4);
}

.bl-footer ul { list-style: none; padding: 0; margin: 0; }
.bl-footer li { margin-bottom: var(--space-2); }
.bl-footer a { color: var(--text-muted); }
.bl-footer a:hover { color: var(--text); }

.bl-footer__bottom {
    border-top: 1px solid var(--border);
    padding-top: var(--space-6);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-4);
    flex-wrap: wrap;
    color: var(--text-muted);
    font-size: var(--text-xs);
}

/* --------------------------------------------------------------------------
   13. Empty states, alerts, breadcrumbs, pagination
   -------------------------------------------------------------------------- */

.bl-empty {
    text-align: center;
    padding: var(--space-16) var(--space-5);
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius-lg);
    background: var(--surface-sunken);
}

.bl-empty__icon { font-size: 1.75rem; color: var(--text-subtle); margin-bottom: var(--space-4); }
.bl-empty__title { font-size: var(--text-lg); margin-bottom: var(--space-2); }
.bl-empty p { color: var(--text-muted); max-width: 28rem; margin-inline: auto; }

.bl-alert {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--border);
    border-left-width: 3px;
    border-radius: var(--radius);
    background: var(--surface-sunken);
    font-size: var(--text-base);
    margin-bottom: var(--space-4);
}

.bl-alert__icon { flex: none; margin-top: 0.125rem; }
.bl-alert__body { flex: 1 1 auto; min-width: 0; }
.bl-alert__body > :last-child { margin-bottom: 0; }

.bl-alert--success { border-left-color: var(--success); background: var(--success-bg); color: var(--success); }
.bl-alert--warning { border-left-color: var(--warning); background: var(--warning-bg); color: var(--warning); }
.bl-alert--danger { border-left-color: var(--danger); background: var(--danger-bg); color: var(--danger); }
.bl-alert--info { border-left-color: var(--text); }

.bl-alert--success .bl-alert__body,
.bl-alert--warning .bl-alert__body,
.bl-alert--danger .bl-alert__body { color: inherit; }

.bl-alert ul { margin: var(--space-2) 0 0; padding-left: var(--space-5); }

.bl-breadcrumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    list-style: none;
    padding: 0;
    margin: 0 0 var(--space-5);
    font-size: var(--text-sm);
    color: var(--text-muted);
}

.bl-breadcrumbs li { display: flex; align-items: center; gap: var(--space-2); }
.bl-breadcrumbs li:not(:last-child)::after { content: "/"; color: var(--text-subtle); }
.bl-breadcrumbs a { color: var(--text-muted); }
.bl-breadcrumbs a:hover { color: var(--text); }
.bl-breadcrumbs [aria-current="page"] { color: var(--text); font-weight: 550; }

/* Spacing only. The paginator's nav lays its own contents out — results text on one
   side, controls on the other — so centering the wrapper would collapse it. */
.bl-pagination { margin-top: var(--space-10); }
.bl-pagination > nav { flex: 1 1 auto; }

/* Bootstrap renders pagination markup; these rules restyle it in place. */
.bl-pagination .pagination { display: flex; gap: var(--space-1); list-style: none; padding: 0; margin: 0; }

.bl-pagination .page-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.25rem;
    height: 2.25rem;
    padding: 0 var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text-muted);
    font-size: var(--text-sm);
    font-weight: 550;
    text-decoration: none;
    transition: all var(--duration) var(--ease);
}

.bl-pagination .page-link:hover { background: var(--surface-hover); color: var(--text); border-color: var(--border-strong); }

.bl-pagination .active .page-link,
.bl-pagination .page-item.active .page-link {
    background: var(--surface-inverse);
    border-color: var(--surface-inverse);
    color: var(--text-inverse);
}

.bl-pagination .disabled .page-link { opacity: 0.4; pointer-events: none; }

/* --------------------------------------------------------------------------
   14. Stat tiles
   -------------------------------------------------------------------------- */

.bl-stat {
    padding: var(--space-5);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface-raised);
}

.bl-stat__value {
    display: block;
    font-size: var(--text-2xl);
    font-weight: 700;
    letter-spacing: var(--tracking-tighter);
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.bl-stat__label {
    display: block;
    margin-top: var(--space-1);
    font-size: var(--text-sm);
    color: var(--text-muted);
}

.bl-stat--compact { padding: var(--space-4); }
.bl-stat--compact .bl-stat__value { font-size: var(--text-xl); }

/* --------------------------------------------------------------------------
   15. Command palette
   -------------------------------------------------------------------------- */

.bl-palette {
    position: fixed;
    inset: 0;
    z-index: 300;
    display: none;
    padding: max(8vh, var(--space-8)) var(--space-4) var(--space-4);
    background: rgba(10, 10, 11, 0.45);
    backdrop-filter: blur(2px);
}

.bl-palette[data-open="true"] { display: block; }

.bl-palette__panel {
    max-width: 36rem;
    margin-inline: auto;
    background: var(--surface-raised);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xl);
    overflow: hidden;
    animation: bl-palette-in var(--duration-slow) var(--ease-out);
}

@keyframes bl-palette-in {
    from { opacity: 0; transform: translateY(-8px) scale(0.99); }
    to { opacity: 1; transform: none; }
}

.bl-palette__input {
    width: 100%;
    padding: var(--space-4) var(--space-5);
    border: 0;
    border-bottom: 1px solid var(--border);
    background: transparent;
    color: var(--text);
    font: inherit;
    font-size: var(--text-md);
}

.bl-palette__input:focus { outline: none; }
.bl-palette__results { max-height: 24rem; overflow-y: auto; padding: var(--space-2); }

.bl-palette__item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-3);
    border: 0;
    border-radius: var(--radius);
    background: transparent;
    color: var(--text);
    font: inherit;
    font-size: var(--text-base);
    text-align: left;
    cursor: pointer;
    text-decoration: none;
}

.bl-palette__item:hover,
.bl-palette__item[data-active="true"] { background: var(--surface-active); text-decoration: none; }

.bl-palette__item small { color: var(--text-muted); }

.bl-palette__footer {
    padding: var(--space-2) var(--space-4);
    border-top: 1px solid var(--border);
    background: var(--surface-sunken);
    font-size: var(--text-xs);
    color: var(--text-muted);
    display: flex;
    gap: var(--space-4);
}

.bl-kbd {
    display: inline-flex;
    align-items: center;
    padding: 0.0625rem 0.3125rem;
    border: 1px solid var(--border-strong);
    border-bottom-width: 2px;
    border-radius: var(--radius-sm);
    background: var(--surface);
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   16. Compare tray
   -------------------------------------------------------------------------- */

.bl-tray {
    position: fixed;
    bottom: var(--space-4);
    left: 50%;
    transform: translateX(-50%);
    z-index: 90;
    display: flex;
    align-items: center;
    gap: var(--space-4);
    /* 100vw counts the vertical scrollbar; 100% of the containing block does not. */
    max-width: min(calc(100% - var(--space-8)), 44rem);
    padding: var(--space-3) var(--space-4);
    background: var(--surface-inverse);
    color: var(--text-inverse);
    border-radius: var(--radius-full);
    box-shadow: var(--shadow-xl);
    font-size: var(--text-sm);
    animation: bl-tray-in var(--duration-slow) var(--ease-out);
}

@keyframes bl-tray-in {
    from { opacity: 0; transform: translate(-50%, 1rem); }
    to { opacity: 1; transform: translateX(-50%); }
}

/* Plain links inside the tray only. Setting color on .bl-tray .bl-btn (specificity
   0,2,0) beat .bl-btn's own `color: var(--btn-fg)` (0,1,0), so the primary button
   rendered white text on its white background and looked like an empty box. */
.bl-tray a:not(.bl-btn) { color: var(--text-inverse); }

.bl-tray .bl-btn {
    --btn-fg: var(--text-inverse);
    --btn-border: var(--ink-700);
}

.bl-tray .bl-btn--ghost { --btn-border: transparent; }
.bl-tray .bl-btn--ghost:hover { --btn-bg: var(--ink-800); }

/* Inverted: light button on the dark tray. */
.bl-tray .bl-btn--primary {
    --btn-bg: var(--surface);
    --btn-fg: var(--text);
    --btn-border: var(--surface);
}

.bl-tray .bl-btn--primary:hover {
    --btn-bg: var(--ink-100);
    --btn-border: var(--ink-100);
}

@media (max-width: 600px) {
    .bl-tray { border-radius: var(--radius-lg); left: var(--space-4); right: var(--space-4); transform: none; max-width: none; }
    @keyframes bl-tray-in { from { opacity: 0; } to { opacity: 1; } }
}

/* Comparison matrix — first column pinned while the rest scrolls. */
.bl-compare { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.bl-compare th, .bl-compare td {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border);
    text-align: left;
    vertical-align: top;
}

.bl-compare tbody th {
    position: sticky;
    left: 0;
    background: var(--surface-sunken);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--text-muted);
    white-space: nowrap;
    min-width: 9rem;
}

/* --------------------------------------------------------------------------
   17. Misc
   -------------------------------------------------------------------------- */

.bl-divider { border-top: 1px solid var(--border); margin-block: var(--space-6); }

.bl-tabs {
    display: flex;
    gap: var(--space-1);
    border-bottom: 1px solid var(--border);
    margin-bottom: var(--space-6);
    overflow-x: auto;
    /* Setting only overflow-x:auto makes CSS compute overflow-y as auto too, which
       produced a stray vertical scrollbar beside the tab strip. */
    overflow-y: hidden;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

/* The strip scrolls horizontally on narrow screens; the bar itself is noise. */
.bl-tabs::-webkit-scrollbar { display: none; }

.bl-tabs__link {
    padding: var(--space-3) var(--space-4);
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-muted);
    white-space: nowrap;
}

.bl-tabs__link:hover { color: var(--text); text-decoration: none; }
.bl-tabs__link[aria-current="page"] { color: var(--text); border-bottom-color: var(--text); }

/* Hairline grid backdrop for hero sections — pure monochrome texture. */
.bl-hero {
    position: relative;
    padding-block: var(--space-24) var(--space-16);
    overflow: hidden;
}

.bl-hero::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(var(--border) 1px, transparent 1px),
        linear-gradient(90deg, var(--border) 1px, transparent 1px);
    background-size: 4rem 4rem;
    mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, black 20%, transparent 75%);
    -webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, black 20%, transparent 75%);
    opacity: 0.55;
    pointer-events: none;
}

.bl-hero > * { position: relative; }

/* Completeness ring, drawn with conic-gradient — no SVG, no JS. */
.bl-ring {
    --pct: 0;
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background:
        conic-gradient(var(--text) calc(var(--pct) * 1%), var(--surface-active) 0);
    flex: none;
}

.bl-ring__inner {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background: var(--surface-raised);
    display: grid;
    place-items: center;
    font-size: var(--text-xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.bl-print-only { display: none; }

@media print {
    .bl-header, .bl-footer, .bl-tray, .bl-palette, .bl-skip { display: none !important; }
    .bl-print-only { display: block; }
    body { background: #fff; color: #000; }
    .bl-card { break-inside: avoid; border-color: #ccc; }
}

/* --------------------------------------------------------------------------
   18. Brand lockup
   -------------------------------------------------------------------------- */

.bl-logo {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--text);
    text-decoration: none;
    flex: none;
}

.bl-logo:hover { text-decoration: none; opacity: 0.75; }

.bl-logo__mark { flex: none; }

.bl-logo__text { display: flex; flex-direction: column; line-height: 1.1; }

.bl-logo__word {
    font-size: 1.1875rem;
    font-weight: 700;
    /* Tight tracking is what stops the wordmark reading as body copy. */
    letter-spacing: -0.035em;
}

.bl-logo__tagline {
    font-size: 0.625rem;
    font-weight: 600;
    letter-spacing: var(--tracking-widest);
    text-transform: uppercase;
    color: var(--text-muted);
    margin-top: 0.125rem;
}

.bl-logo--lg .bl-logo__word { font-size: 1.5rem; }

/* --------------------------------------------------------------------------
   19. Company card tools
   -------------------------------------------------------------------------- */

/* Compare/shortlist controls must sit above .bl-card__link's ::after overlay,
   or the whole-card anchor swallows their clicks. */
.bl-card-tools {
    position: relative;
    z-index: 2;
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border);
}

.bl-company-card { height: 100%; }

/* --------------------------------------------------------------------------
   20. Reviews
   -------------------------------------------------------------------------- */

.bl-review { margin-bottom: var(--space-4); }

.bl-review__components {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5);
    margin: var(--space-4) 0 0;
    padding: var(--space-3) 0 0;
    border-top: 1px solid var(--border);
    font-size: var(--text-sm);
}

.bl-review__components dt {
    color: var(--text-muted);
    font-size: var(--text-xs);
    margin-bottom: var(--space-1);
}

.bl-review__components dd {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    font-weight: 600;
}

.bl-review__recommendation {
    margin: var(--space-4) 0 0;
    padding: var(--space-3) var(--space-4);
    border-left: 2px solid var(--border-strong);
    background: var(--surface-sunken);
    border-radius: 0 var(--radius) var(--radius) 0;
    font-size: var(--text-sm);
}

.bl-review__footer {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border);
}

/* The owner response is visually subordinate to the review it answers —
   indented and sunken, so the reader's eye keeps the order of the exchange. */
.bl-review__reply {
    margin: 0 var(--space-5) var(--space-5);
    padding: var(--space-4);
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    border-left: 3px solid var(--text);
    font-size: var(--text-sm);
}

/* Inline forms that hold a single button must not introduce block layout. */
.bl-inline-form { display: inline-flex; margin: 0; }

/* --------------------------------------------------------------------------
   21. Checklists & misc content
   -------------------------------------------------------------------------- */

.bl-checklist {
    list-style: none;
    padding: 0;
    margin: var(--space-4) 0 0;
    border-top: 1px solid var(--border);
    padding-top: var(--space-3);
    font-size: var(--text-sm);
}

.bl-checklist li {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) 0;
    color: var(--text-muted);
}

.bl-checklist li i { color: var(--text-subtle); font-size: 0.75em; }

/* Numbered rank column on leaderboards. */
.bl-rank {
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    flex: none;
    border-radius: var(--radius);
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    font-size: var(--text-sm);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* Top three carry weight; the rest are just ordered. */
.bl-rank--medal {
    background: var(--surface-inverse);
    border-color: var(--surface-inverse);
    color: var(--text-inverse);
}

.bl-theme-toggle .bl-theme-toggle__dark { display: none; }
:root[data-theme="dark"] .bl-theme-toggle .bl-theme-toggle__light { display: none; }
:root[data-theme="dark"] .bl-theme-toggle .bl-theme-toggle__dark { display: inline; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .bl-theme-toggle .bl-theme-toggle__light { display: none; }
    :root:not([data-theme="light"]) .bl-theme-toggle .bl-theme-toggle__dark { display: inline; }
}

/* --------------------------------------------------------------------------
   22. Admin shell
   -------------------------------------------------------------------------- */

.bl-admin { background: var(--surface-sunken); }

.bl-admin__shell {
    display: grid;
    grid-template-columns: 15rem 1fr;
    min-height: 100vh;
}

.bl-admin__sidebar {
    display: flex;
    flex-direction: column;
    background: var(--surface-inverse);
    color: var(--text-inverse);
    border-right: 1px solid var(--border-inverse);
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
}

/* The sidebar is permanently inverse — it is the one place a monochrome system
   can signal "you are in a different mode" without introducing colour. */
.bl-admin__sidebar .bl-logo,
.bl-admin__sidebar .bl-logo__word { color: var(--text-inverse); }
.bl-admin__sidebar .bl-logo__tagline { color: var(--ink-500); }

.bl-admin__brand { padding: var(--space-5); border-bottom: 1px solid var(--border-inverse); }

.bl-admin__nav { padding: var(--space-4) var(--space-3); flex: 1 1 auto; }

.bl-admin__group {
    padding: var(--space-4) var(--space-3) var(--space-2);
    margin: 0;
    font-size: var(--text-xs);
    font-weight: 650;
    letter-spacing: var(--tracking-widest);
    text-transform: uppercase;
    color: var(--ink-500);
}

.bl-admin__link {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius);
    color: var(--ink-300);
    font-size: var(--text-sm);
    font-weight: 550;
    text-decoration: none;
    transition: background-color var(--duration) var(--ease), color var(--duration) var(--ease);
}

.bl-admin__link i { width: 1rem; text-align: center; font-size: 0.9em; flex: none; }
.bl-admin__link span:not(.bl-admin__count) { flex: 1 1 auto; min-width: 0; }

.bl-admin__link:hover { background: var(--ink-800); color: var(--ink-0); text-decoration: none; }

.bl-admin__link[aria-current="page"] { background: var(--ink-800); color: var(--ink-0); }

/* Queue depth. Deliberately not red — a moderation backlog is normal work, not
   an error, and colouring it as one trains admins to ignore real alerts. */
.bl-admin__count {
    flex: none;
    min-width: 1.375rem;
    padding: 0 0.3125rem;
    border-radius: var(--radius-full);
    background: var(--ink-0);
    color: var(--ink-950);
    font-size: 0.6875rem;
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.bl-admin__footer {
    padding: var(--space-3);
    border-top: 1px solid var(--border-inverse);
}

.bl-admin__content { display: flex; flex-direction: column; min-width: 0; }

.bl-admin__topbar {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    height: 3.5rem;
    padding-inline: var(--space-5);
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}

.bl-admin__main { flex: 1 1 auto; padding-block: var(--space-8); }
.bl-admin__menu { display: none; }

@media (max-width: 1000px) {
    .bl-admin__shell { grid-template-columns: 1fr; }

    .bl-admin__sidebar {
        position: fixed;
        inset: 0 auto 0 0;
        width: 15rem;
        z-index: 120;
        transform: translateX(-100%);
        transition: transform var(--duration-slow) var(--ease-out);
    }

    .bl-admin__shell[data-sidebar="open"] .bl-admin__sidebar { transform: none; }
    .bl-admin__menu { display: inline-flex; }
}

/* --------------------------------------------------------------------------
   23. Filter bars
   -------------------------------------------------------------------------- */

.bl-filters {
    padding: var(--space-5);
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
}

.bl-filters__grid {
    display: grid;
    gap: var(--space-4);
    /* auto-fit rather than a fixed column count: the same bar serves the company
       listing (6 controls) and the product listing (5) without a variant. */
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
    align-items: end;
}

.bl-filters .bl-label { font-size: var(--text-xs); margin-bottom: var(--space-1); }
.bl-filters .bl-field { margin-bottom: 0; }

.bl-filters__submit { display: flex; flex-direction: column; gap: var(--space-2); }

/* --------------------------------------------------------------------------
   24. Homepage
   -------------------------------------------------------------------------- */

.bl-hero__search {
    display: flex;
    gap: var(--space-2);
    max-width: 34rem;
    margin-inline: auto;
}

.bl-input--lg { padding: 0.8125rem var(--space-4); font-size: var(--text-md); }
.bl-search .bl-input--lg { padding-left: var(--space-10); }

@media (max-width: 520px) {
    .bl-hero__search { flex-direction: column; }
}

/* Ranked list. The number is the point, so it gets a fixed gutter and the row
   stays a single line at every width. */
.bl-ranked {
    list-style: none;
    counter-reset: rank;
    padding: 0;
    margin: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface-raised);
    overflow: hidden;
}

.bl-ranked > li {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--border);
    transition: background-color var(--duration) var(--ease);
}

.bl-ranked > li:last-child { border-bottom: 0; }
.bl-ranked > li:hover { background: var(--surface-hover); }

.bl-list-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-raised);
    color: var(--text);
    text-decoration: none;
    transition: border-color var(--duration) var(--ease), background-color var(--duration) var(--ease);
}

.bl-list-row:hover { text-decoration: none; border-color: var(--border-strong); background: var(--surface-hover); }

.bl-category-tile {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-raised);
    color: var(--text);
    text-decoration: none;
    transition: border-color var(--duration) var(--ease), transform var(--duration) var(--ease);
}

.bl-category-tile:hover {
    text-decoration: none;
    border-color: var(--text);
    transform: translateY(-2px);
}

.bl-category-tile__name { font-weight: 600; }

/* Step numeral on the "how it works" cards. */
.bl-step {
    display: grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: var(--radius);
    background: var(--surface-inverse);
    color: var(--text-inverse);
    font-weight: 700;
    font-size: var(--text-sm);
}

/* Three-up on wide screens for the how-it-works row specifically. */
@media (min-width: 900px) {
    .bl-grid[style*="--bl-cols: 3"] { grid-template-columns: repeat(3, 1fr); }
}

/* Winner cell in a comparison row. Weight and a glyph rather than a colour fill,
   so the emphasis survives the strict-monochrome rule. */
.bl-compare__best { font-weight: 700; background: var(--surface-active); }
.bl-compare__best i { color: var(--success); margin-left: var(--space-1); font-size: 0.85em; }

/* Leaderboard row meta collapses under the name on narrow screens rather than
   squeezing the company name to nothing. */
.bl-leaderboard__meta { flex: none; }

@media (max-width: 760px) {
    .bl-ranked > li { flex-wrap: wrap; }
    .bl-leaderboard__meta { width: 100%; padding-left: 3rem; }
}

/* Quoted context inside a moderation card — sunken and indented so the moderator
   can tell at a glance which text is the submission and which is the original. */
.bl-moderation__context {
    padding: var(--space-4);
    background: var(--surface-sunken);
    border-left: 3px solid var(--border-strong);
    border-radius: 0 var(--radius) var(--radius) 0;
}

/* --------------------------------------------------------------------------
   25. Detail lists
   -------------------------------------------------------------------------- */

.bl-detail-list { margin: var(--space-4) 0 0; font-size: var(--text-sm); }

.bl-detail-list > div {
    display: grid;
    grid-template-columns: minmax(6rem, 8rem) 1fr;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--border);
}

.bl-detail-list > div:last-child { border-bottom: 0; }
.bl-detail-list dt { color: var(--text-muted); }
.bl-detail-list dd { margin: 0; }

@media (max-width: 520px) {
    .bl-detail-list > div { grid-template-columns: 1fr; gap: var(--space-1); }
}

/* --------------------------------------------------------------------------
   26. Profile pages
   -------------------------------------------------------------------------- */

.bl-profile {
    display: flex;
    align-items: flex-start;
    gap: var(--space-5);
    padding-bottom: var(--space-6);
    margin-bottom: var(--space-2);
}

.bl-profile__actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    flex: none;
    align-items: stretch;
}

/* Content plus a sidebar that becomes a stacked block on narrow screens. */
.bl-profile__body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 19rem;
    gap: var(--space-8);
    align-items: start;
}

@media (max-width: 900px) {
    .bl-profile { flex-wrap: wrap; }
    .bl-profile__actions { width: 100%; flex-direction: row; flex-wrap: wrap; }
    .bl-profile__body { grid-template-columns: 1fr; }
}

/* Rating distribution row: label, bar, count — the bar takes the slack. */
.bl-distribution__row {
    display: grid;
    grid-template-columns: 2.5rem 1fr 2rem;
    align-items: center;
    gap: var(--space-3);
    padding: 0.1875rem 0;
}

.bl-distribution__row .bl-muted { text-align: right; }

/* --------------------------------------------------------------------------
   27. Prose & two-column content
   -------------------------------------------------------------------------- */

/* Long-form copy. Measure is capped in ch so the line length stays readable
   regardless of the root font size the reader has chosen. */
.bl-prose { max-width: 68ch; }
.bl-prose h2 { font-size: var(--text-xl); margin-top: var(--space-10); }
.bl-prose h2:first-child { margin-top: 0; }
.bl-prose h3 { font-size: var(--text-md); margin-top: var(--space-6); }
.bl-prose p, .bl-prose ul, .bl-prose ol { margin-bottom: var(--space-4); }
.bl-prose ul, .bl-prose ol { padding-left: var(--space-5); }
.bl-prose li { margin-bottom: var(--space-2); }
.bl-prose a { text-decoration: underline; }

.bl-contact {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 19rem;
    gap: var(--space-8);
    align-items: start;
}

@media (max-width: 900px) {
    .bl-contact { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   28. Auth shell
   -------------------------------------------------------------------------- */

.bl-auth {
    display: grid;
    grid-template-columns: 1fr 1fr;
    min-height: 100vh;
    background: var(--surface);
}

.bl-auth__panel {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: var(--space-8) var(--space-6);
}

.bl-auth__card { width: 100%; max-width: 24rem; margin-inline: auto; }
.bl-auth__foot { text-align: center; margin: var(--space-8) 0 0; font-size: var(--text-sm); }
.bl-auth__foot a { color: var(--text-muted); }

/* The inverse panel is the strongest emphasis available without colour, and it
   marks the auth screens as a distinct context. */
.bl-auth__aside {
    display: flex;
    align-items: center;
    padding: var(--space-12);
    background: var(--surface-inverse);
    color: var(--text-inverse);
    position: relative;
    overflow: hidden;
}

.bl-auth__aside::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.06) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.06) 1px, transparent 1px);
    background-size: 3rem 3rem;
    pointer-events: none;
}

.bl-auth__aside > * { position: relative; max-width: 28rem; }

.bl-auth__headline {
    font-size: var(--text-3xl);
    letter-spacing: var(--tracking-tighter);
    color: var(--text-inverse);
    margin-bottom: var(--space-4);
}

.bl-auth__copy { color: var(--ink-400); margin-bottom: var(--space-8); }

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

.bl-auth__list li {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    color: var(--ink-300);
    font-size: var(--text-sm);
}

.bl-auth__list i { color: var(--ink-0); font-size: 0.75em; }

/* Below 900px the editorial panel is dead weight above the form. */
@media (max-width: 900px) {
    .bl-auth { grid-template-columns: 1fr; }
    .bl-auth__aside { display: none; }
}

/* Two fields side by side, stacking below 620px. Used by every multi-field form. */
.bl-form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-4);
}

@media (max-width: 620px) {
    .bl-form-row { grid-template-columns: 1fr; gap: 0; }
}

/* --------------------------------------------------------------------------
   29. Dashboard
   -------------------------------------------------------------------------- */

.bl-dashboard {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 19rem;
    gap: var(--space-8);
    align-items: start;
}

@media (max-width: 1000px) {
    .bl-dashboard { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   30. Rating picker
   -------------------------------------------------------------------------- */

/* Radio group styled as selectable rows. Real radios, visually hidden but
   focusable — the keyboard and screen-reader behaviour is the native one. */
.bl-rating-picker { display: flex; flex-direction: column; gap: var(--space-1); }

.bl-rating-picker__option {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: 1px solid transparent;
    border-radius: var(--radius);
    cursor: pointer;
    transition: background-color var(--duration) var(--ease), border-color var(--duration) var(--ease);
}

.bl-rating-picker__option:hover { background: var(--surface-hover); }

.bl-rating-picker__option input {
    position: absolute;
    width: 1px; height: 1px;
    opacity: 0;
    pointer-events: none;
}

.bl-rating-picker__option:has(input:checked) {
    background: var(--surface-active);
    border-color: var(--text);
}

/* :has() is widely supported but not universal; without it the focus ring below
   still shows which option is active during keyboard use. */
.bl-rating-picker__option:has(input:focus-visible) {
    outline: 2px solid var(--text);
    outline-offset: 2px;
}

.bl-rating-picker__stars { color: var(--rating); font-size: var(--text-sm); flex: none; letter-spacing: 0.05em; }
.bl-rating-picker__label { font-size: var(--text-sm); font-weight: 550; }

/* --------------------------------------------------------------------------
   31. Wizard progress
   -------------------------------------------------------------------------- */

.bl-wizard { margin-bottom: var(--space-8); }

.bl-wizard__list {
    display: flex;
    list-style: none;
    padding: 0;
    margin: 0;
    gap: var(--space-2);
    counter-reset: step;
}

.bl-wizard__step {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: 1 1 0;
    min-width: 0;
    padding-bottom: var(--space-3);
    /* The bar under each step is the progress track — no separate element needed. */
    border-bottom: 2px solid var(--border);
    font-size: var(--text-sm);
}

.bl-wizard__step[data-state="done"],
.bl-wizard__step[data-state="current"] { border-bottom-color: var(--text); }

.bl-wizard__marker {
    display: grid;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    flex: none;
    border-radius: var(--radius-full);
    border: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--text-muted);
    font-size: var(--text-xs);
    font-weight: 700;
}

.bl-wizard__step[data-state="done"] .bl-wizard__marker,
.bl-wizard__step[data-state="current"] .bl-wizard__marker {
    background: var(--surface-inverse);
    border-color: var(--surface-inverse);
    color: var(--text-inverse);
}

.bl-wizard__label { color: var(--text-muted); font-weight: 550; }
.bl-wizard__step[data-state="current"] .bl-wizard__label { color: var(--text); font-weight: 650; }

/* Below 700px only the current step's label is worth the space. */
@media (max-width: 700px) {
    .bl-wizard__step { flex: none; }
    .bl-wizard__step .bl-wizard__label { display: none; }
    .bl-wizard__step[data-state="current"] { flex: 1 1 auto; }
    .bl-wizard__step[data-state="current"] .bl-wizard__label { display: inline; }
}

/* Livewire loading state. */
.bl-loading { opacity: 0.5; pointer-events: none; transition: opacity var(--duration) var(--ease); }

/* Category checkbox grid — multi-column so a long list does not become a scroll. */
.bl-checkbox-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 13rem), 1fr));
    gap: 0 var(--space-4);
}

.bl-checkbox-grid .bl-check { margin-bottom: var(--space-2); }
