﻿/* =============================================================================
   SocialNet - Front-End Stylesheet
   Modern, clean design for viral content/blog site
   ============================================================================= */

/* -----------------------------------------------------------------------------
   CSS Variables / Design Tokens
   ----------------------------------------------------------------------------- */
:root {
    /* Brand Colors. The primary/secondary derive from the ACTIVE THEME (--theme-*,
       set by the body's .theme-* class) so the theme picker recolors the whole layout;
       the hex fallbacks are the System-default scheme (no theme selected). The -dark
       shade tracks the primary via color-mix so link hovers stay on-palette per theme. */
    --sn-primary: var(--theme-primary, #4a6fa5);
    --sn-primary-light: var(--theme-secondary, #6b8cbe);
    --sn-primary-dark: color-mix(in srgb, var(--sn-primary) 80%, #000);

    /* System-default THEME variables (the "no theme selected" scheme). Modules like
       .sn-search consume --theme-* ; the .theme-* classes are DARK schemes that override
       these on <body>. Defined here (light, matching the --sn-* base) so modules are styled
       even when no theme is selected. */
    --theme-primary: #4a6fa5;
    --theme-primary-rgb: 74, 111, 165;
    --theme-secondary: #6b8cbe;
    --theme-secondary-rgb: 107, 140, 190;
    --theme-surface: #ffffff;
    --theme-border: #e8e4dc;        /* = --sn-gray-200 */
    --theme-text: #2e2a26;          /* = --sn-gray-800 */
    --theme-text-muted: #7d766c;    /* = --sn-gray-500 */

    /* Neutral Colors - Warm, off-white tones */
    --sn-gray-50: #faf9f7;      /* Warm off-white - main background */
    --sn-gray-100: #f5f3ef;     /* Cream */
    --sn-gray-200: #e8e4dc;     /* Light tan */
    --sn-gray-300: #d4cfc4;     /* Warm light gray */
    --sn-gray-400: #a8a198;     /* Muted gray */
    --sn-gray-500: #7d766c;     /* Medium warm gray */
    --sn-gray-600: #5c564e;     /* Darker warm gray */
    --sn-gray-700: #45403a;     /* Dark warm brown-gray */
    --sn-gray-800: #2e2a26;     /* Very dark brown */
    --sn-gray-900: #1c1917;     /* Near black, warm */

    /* Accent Colors - Muted, earthy */
    --sn-accent-red: #c45c4a;
    --sn-accent-orange: #c9834d;
    --sn-accent-green: #5a9a6e;
    --sn-accent-teal: #4a9b93;

    /* Typography */
    --sn-font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --sn-font-serif: 'Georgia', 'Times New Roman', serif;

    /* Spacing */
    --sn-spacing-xs: 0.25rem;
    --sn-spacing-sm: 0.5rem;
    --sn-spacing-md: 1rem;
    --sn-spacing-lg: 1.5rem;
    --sn-spacing-xl: 2rem;
    --sn-spacing-2xl: 3rem;

    /* Border Radius */
    --sn-radius-sm: 0.375rem;
    --sn-radius-md: 0.5rem;
    --sn-radius-lg: 0.75rem;
    --sn-radius-xl: 1rem;

    /* Shadows */
    --sn-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
    --sn-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
    --sn-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);

    /* Transitions */
    --sn-transition-fast: 150ms ease;
    --sn-transition-normal: 250ms ease;
}

/* -----------------------------------------------------------------------------
   Base Styles (Front-end pages only - not .backend-theme)
   ----------------------------------------------------------------------------- */
body:not(.backend-theme) {
    font-family: var(--sn-font-sans);
    color: var(--sn-gray-800);
    background-color: var(--sn-gray-50);
    line-height: 1.6;
}

body:not(.backend-theme) h1,
body:not(.backend-theme) h2,
body:not(.backend-theme) h3,
body:not(.backend-theme) h4,
body:not(.backend-theme) h5,
body:not(.backend-theme) h6 {
    font-weight: 700;
    line-height: 1.3;
    color: var(--sn-gray-900);
}

body:not(.backend-theme) a {
    color: var(--sn-primary);
    text-decoration: none;
    transition: color var(--sn-transition-fast);
}

body:not(.backend-theme) a:hover {
    color: var(--sn-primary-dark);
}

/* -----------------------------------------------------------------------------
   Front-End Navigation
   ----------------------------------------------------------------------------- */
.sn-navbar {
    background: var(--sn-gray-100);
    border-bottom: 1px solid var(--sn-gray-200);
    padding: var(--sn-spacing-md) 0;
    position: sticky;
    top: 0;
    z-index: 1000;
}

.sn-navbar .navbar-brand {
    font-weight: 800;
    font-size: 1.5rem;
    color: var(--sn-gray-900);
    letter-spacing: -0.025em;
}

.sn-navbar .navbar-brand:hover {
    color: var(--sn-primary);
}

.sn-navbar .nav-link {
    color: var(--sn-gray-600);
    font-weight: 500;
    padding: var(--sn-spacing-sm) var(--sn-spacing-md);
    border-radius: var(--sn-radius-md);
    transition: all var(--sn-transition-fast);
}

.sn-navbar .nav-link:hover {
    color: var(--sn-primary);
    background-color: var(--sn-gray-100);
}

.sn-navbar .btn-signin {
    background-color: var(--sn-primary);
    color: white;
    font-weight: 600;
    padding: var(--sn-spacing-sm) var(--sn-spacing-lg);
    border-radius: var(--sn-radius-md);
    border: none;
    transition: all var(--sn-transition-fast);
}

.sn-navbar .btn-signin:hover {
    background-color: var(--sn-primary-dark);
    color: white;
    transform: translateY(-1px);
}

/* -----------------------------------------------------------------------------
   Hero Section
   ----------------------------------------------------------------------------- */
.sn-hero {
    background: linear-gradient(135deg, var(--sn-gray-700) 0%, var(--sn-gray-800) 100%);
    color: var(--sn-gray-100);
    padding: var(--sn-spacing-2xl) 0;
    margin-bottom: var(--sn-spacing-2xl);
}

.sn-hero h1 {
    font-size: 2.5rem;
    font-weight: 800;
    color: var(--sn-gray-50);
    margin-bottom: var(--sn-spacing-md);
}

.sn-hero p {
    font-size: 1.125rem;
    opacity: 0.9;
    max-width: 600px;
}

.sn-hero-small {
    padding: var(--sn-spacing-xl) 0;
}

.sn-hero-small h1 {
    font-size: 1.75rem;
    margin-bottom: var(--sn-spacing-sm);
}

/* -----------------------------------------------------------------------------
   Content Cards - Blog/Viral Post Style
   ----------------------------------------------------------------------------- */
.sn-card {
    background: var(--sn-gray-100);
    border-radius: var(--sn-radius-lg);
    overflow: hidden;
    box-shadow: var(--sn-shadow-sm);
    border: 1px solid var(--sn-gray-200);
    transition: all var(--sn-transition-normal);
    height: 100%;
    display: flex;
    flex-direction: column;
}

.sn-card:hover {
    box-shadow: var(--sn-shadow-lg);
    transform: translateY(-4px);
    border-color: var(--sn-gray-300);
}

.sn-card-img {
    width: 100%;
    height: 200px;
    object-fit: cover;
    background-color: var(--sn-gray-200);
}

.sn-card-img-placeholder {
    width: 100%;
    height: 200px;
    background: linear-gradient(135deg, var(--sn-gray-300) 0%, var(--sn-gray-400) 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--sn-gray-500);
    font-size: 3rem;
}

.sn-card-body {
    padding: var(--sn-spacing-lg);
    flex: 1;
    display: flex;
    flex-direction: column;
}

.sn-card-category {
    display: inline-block;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--sn-primary);
    margin-bottom: var(--sn-spacing-sm);
}

.sn-card-title {
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--sn-gray-900);
    margin-bottom: var(--sn-spacing-sm);
    line-height: 1.4;
}

.sn-card-title a {
    color: inherit;
}

.sn-card-title a:hover {
    color: var(--sn-primary);
}

.sn-card-excerpt {
    color: var(--sn-gray-600);
    font-size: 0.9375rem;
    line-height: 1.6;
    flex: 1;
}

.sn-card-meta {
    display: flex;
    align-items: center;
    gap: var(--sn-spacing-md);
    margin-top: var(--sn-spacing-md);
    padding-top: var(--sn-spacing-md);
    border-top: 1px solid var(--sn-gray-100);
    font-size: 0.8125rem;
    color: var(--sn-gray-500);
}

.sn-card-meta i {
    margin-right: var(--sn-spacing-xs);
}

/* Featured Card - Larger variant */
.sn-card-featured {
    grid-column: span 2;
}

.sn-card-featured .sn-card-img,
.sn-card-featured .sn-card-img-placeholder {
    height: 300px;
}

.sn-card-featured .sn-card-title {
    font-size: 1.5rem;
}

@media (max-width: 767.98px) {
    .sn-card-featured {
        grid-column: span 1;
    }

    .sn-card-featured .sn-card-img,
    .sn-card-featured .sn-card-img-placeholder {
        height: 200px;
    }

    .sn-card-featured .sn-card-title {
        font-size: 1.125rem;
    }
}

/* -----------------------------------------------------------------------------
   Content Grid
   ----------------------------------------------------------------------------- */
.sn-content-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sn-spacing-xl);
}

@media (max-width: 991.98px) {
    .sn-content-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 575.98px) {
    .sn-content-grid {
        grid-template-columns: 1fr;
    }
}

/* -----------------------------------------------------------------------------
   Sidebar
   ----------------------------------------------------------------------------- */
.sn-sidebar {
    position: sticky;
    top: 100px;
}

.sn-sidebar-section {
    background: var(--sn-gray-100);
    border-radius: var(--sn-radius-lg);
    padding: var(--sn-spacing-lg);
    margin-bottom: var(--sn-spacing-lg);
    border: 1px solid var(--sn-gray-200);
}

.sn-sidebar-title {
    font-size: 0.875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--sn-gray-500);
    margin-bottom: var(--sn-spacing-md);
    padding-bottom: var(--sn-spacing-sm);
    border-bottom: 2px solid var(--sn-primary);
}

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

.sn-sidebar-list li {
    padding: var(--sn-spacing-sm) 0;
    border-bottom: 1px solid var(--sn-gray-100);
}

.sn-sidebar-list li:last-child {
    border-bottom: none;
}

.sn-sidebar-list a {
    color: var(--sn-gray-700);
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: var(--sn-spacing-sm);
}

.sn-sidebar-list a:hover {
    color: var(--sn-primary);
}

/* Search Widget */
.sn-search-form {
    display: flex;
    gap: var(--sn-spacing-sm);
}

.sn-search-form input {
    flex: 1;
    border: 1px solid var(--sn-gray-300);
    border-radius: var(--sn-radius-md);
    padding: var(--sn-spacing-sm) var(--sn-spacing-md);
    font-size: 0.9375rem;
    transition: border-color var(--sn-transition-fast);
    background-color: var(--sn-gray-50);
}

.sn-search-form input:focus {
    outline: none;
    border-color: var(--sn-primary);
    box-shadow: 0 0 0 3px rgba(74, 111, 165, 0.15);
    background-color: var(--sn-gray-50);
}

.sn-search-form button {
    background-color: var(--sn-primary);
    color: white;
    border: none;
    border-radius: var(--sn-radius-md);
    padding: var(--sn-spacing-sm) var(--sn-spacing-md);
    cursor: pointer;
    transition: background-color var(--sn-transition-fast);
}

.sn-search-form button:hover {
    background-color: var(--sn-primary-dark);
}

/* Tags/Keywords */
.sn-tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sn-spacing-sm);
}

.sn-tag {
    display: inline-block;
    background-color: var(--sn-gray-100);
    color: var(--sn-gray-700);
    padding: var(--sn-spacing-xs) var(--sn-spacing-sm);
    border-radius: var(--sn-radius-sm);
    font-size: 0.8125rem;
    font-weight: 500;
    transition: all var(--sn-transition-fast);
}

.sn-tag:hover {
    background-color: var(--sn-primary);
    color: white;
}

/* -----------------------------------------------------------------------------
   Auth Pages (Login, Register)
   ----------------------------------------------------------------------------- */
.sn-auth-container {
    min-height: calc(100vh - 200px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--sn-spacing-xl) var(--sn-spacing-md);
}

.sn-auth-card {
    background: var(--sn-gray-100);
    border-radius: var(--sn-radius-xl);
    box-shadow: var(--sn-shadow-lg);
    width: 100%;
    max-width: 420px;
    overflow: hidden;
    border: 1px solid var(--sn-gray-200);
}

.sn-auth-header {
    background: linear-gradient(135deg, var(--sn-gray-500) 0%, var(--sn-gray-600) 100%);
    color: var(--sn-gray-100);
    padding: var(--sn-spacing-xl);
    text-align: center;
}

.sn-auth-header h1 {
    color: white;
    font-size: 1.5rem;
    margin-bottom: var(--sn-spacing-xs);
}

.sn-auth-header p {
    opacity: 0.9;
    margin: 0;
    font-size: 0.9375rem;
}

.sn-auth-body {
    padding: var(--sn-spacing-xl);
}

.sn-auth-footer {
    background-color: var(--sn-gray-50);
    padding: var(--sn-spacing-lg);
    text-align: center;
    border-top: 1px solid var(--sn-gray-200);
}

.sn-auth-footer p {
    margin: 0;
    color: var(--sn-gray-600);
    font-size: 0.9375rem;
}

/* Form Elements */
.sn-form-group {
    margin-bottom: var(--sn-spacing-lg);
}

.sn-form-label {
    display: block;
    font-weight: 600;
    color: var(--sn-gray-700);
    margin-bottom: var(--sn-spacing-sm);
    font-size: 0.9375rem;
}

.sn-form-control {
    width: 100%;
    padding: 0.75rem 1rem;
    border: 1px solid var(--sn-gray-300);
    border-radius: var(--sn-radius-md);
    font-size: 1rem;
    transition: all var(--sn-transition-fast);
    background-color: var(--sn-gray-50);
}

.sn-form-control:focus {
    outline: none;
    border-color: var(--sn-primary);
    box-shadow: 0 0 0 3px rgba(74, 111, 165, 0.15);
    background-color: var(--sn-gray-50);
}

.sn-form-control::placeholder {
    color: var(--sn-gray-400);
}

.sn-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sn-spacing-sm);
    padding: 0.75rem 1.5rem;
    font-size: 1rem;
    font-weight: 600;
    border-radius: var(--sn-radius-md);
    border: none;
    cursor: pointer;
    text-decoration: none;   /* it's an anchor styled as a button — never underline */
    transition: all var(--sn-transition-fast);
}
.sn-btn:hover { text-decoration: none; }

/* A primary button's label is ALWAYS white-on-primary. !important so it beats the generic
   `body a { color: var(--sn-primary) }` rule (line ~98), which otherwise renders the label
   the same color as the button background → invisible until hovered. */
.sn-btn-primary {
    background-color: var(--sn-primary);
    color: #fff !important;
}

.sn-btn-primary:hover {
    background-color: var(--sn-primary-dark);
    color: #fff !important;
    transform: translateY(-1px);
}

.sn-btn-block {
    width: 100%;
}

/* Free-subdomain indicator chip (cyan = "info"). Clickable, opens the site in a new tab.
   Used on the My Sites list and the Site Management tab header. Doubles as the site's PRIMARY
   reachable address (.is-primary) when there's no ported domain. */
.sn-sub-chip {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 1px 8px; border-radius: 999px; font-size: .78em; line-height: 1.5;
    text-decoration: none; white-space: nowrap; vertical-align: middle;
    background: rgba(34, 211, 238, .12); color: #67e8f9; border: 1px solid rgba(34, 211, 238, .35);
}
.sn-sub-chip:hover { background: rgba(34, 211, 238, .22); color: #a5f3fc; text-decoration: none; }
.sn-sub-chip .bi { font-size: .9em; opacity: .85; }
.sn-sub-chip.is-primary { font-weight: 600; }

/* -----------------------------------------------------------------------------
   Footer
   ----------------------------------------------------------------------------- */
.sn-footer {
    background-color: var(--sn-gray-800);
    color: var(--sn-gray-400);
    padding: var(--sn-spacing-2xl) 0 var(--sn-spacing-lg);
    margin-top: var(--sn-spacing-2xl);
}

.sn-footer a {
    color: var(--sn-gray-400);
    transition: color var(--sn-transition-fast);
}

.sn-footer a:hover {
    color: var(--sn-gray-100);
}

.sn-footer-brand {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--sn-gray-100);
    margin-bottom: var(--sn-spacing-md);
}

.sn-footer-links {
    list-style: none;
    padding: 0;
    margin: 0;
}

.sn-footer-links li {
    margin-bottom: var(--sn-spacing-sm);
}

.sn-footer-title {
    color: var(--sn-gray-100);
    font-weight: 600;
    font-size: 0.875rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: var(--sn-spacing-md);
}

.sn-footer-bottom {
    border-top: 1px solid var(--sn-gray-700);
    padding-top: var(--sn-spacing-lg);
    margin-top: var(--sn-spacing-xl);
    text-align: center;
    font-size: 0.875rem;
}

/* -----------------------------------------------------------------------------
   Coming Soon / Placeholder
   ----------------------------------------------------------------------------- */
.sn-coming-soon {
    text-align: center;
    padding: var(--sn-spacing-2xl) var(--sn-spacing-md);
}

.sn-coming-soon-icon {
    font-size: 4rem;
    color: var(--sn-gray-300);
    margin-bottom: var(--sn-spacing-lg);
}

.sn-coming-soon h1 {
    font-size: 2rem;
    margin-bottom: var(--sn-spacing-md);
}

.sn-coming-soon p {
    color: var(--sn-gray-600);
    font-size: 1.125rem;
    max-width: 500px;
    margin: 0 auto;
}

/* -----------------------------------------------------------------------------
   Utilities
   ----------------------------------------------------------------------------- */
.sn-text-muted {
    color: var(--sn-gray-500);
}

.sn-text-small {
    font-size: 0.875rem;
}

.sn-mb-0 { margin-bottom: 0; }
.sn-mb-1 { margin-bottom: var(--sn-spacing-sm); }
.sn-mb-2 { margin-bottom: var(--sn-spacing-md); }
.sn-mb-3 { margin-bottom: var(--sn-spacing-lg); }
.sn-mb-4 { margin-bottom: var(--sn-spacing-xl); }

.sn-mt-0 { margin-top: 0; }
.sn-mt-1 { margin-top: var(--sn-spacing-sm); }
.sn-mt-2 { margin-top: var(--sn-spacing-md); }
.sn-mt-3 { margin-top: var(--sn-spacing-lg); }
.sn-mt-4 { margin-top: var(--sn-spacing-xl); }

/* -----------------------------------------------------------------------------
   Subtle Login Link (for unauthenticated users)
   ----------------------------------------------------------------------------- */
.sn-subtle-login {
    position: fixed;
    bottom: 20px;
    right: 20px;
    opacity: 0.4;
    z-index: 1000;
    font-size: 1rem;
    color: var(--sn-gray-500);
    transition: opacity var(--sn-transition-fast);
}

.sn-subtle-login:hover {
    opacity: 1;
    color: var(--sn-primary);
}

/* -----------------------------------------------------------------------------
   Search Results Page
   ----------------------------------------------------------------------------- */
.sn-search-results {
    min-height: 100vh;
}

.sn-search-header {
    background: linear-gradient(135deg, var(--sn-gray-200) 0%, var(--sn-gray-100) 100%);
    padding: var(--sn-spacing-xl) 0;
    margin-bottom: var(--sn-spacing-lg);
    border-bottom: 1px solid var(--sn-gray-300);
}

.sn-search-header h1 {
    font-size: 1.75rem;
    margin-bottom: var(--sn-spacing-sm);
    color: var(--sn-gray-800);
}

.sn-search-query {
    color: var(--sn-gray-600);
    margin-bottom: var(--sn-spacing-lg);
}

.sn-search-query strong {
    color: var(--sn-gray-800);
}

.sn-result-count {
    color: var(--sn-gray-500);
    font-size: 0.9rem;
}

.sn-search-form-large {
    display: flex;
    max-width: 500px;
    background: white;
    border-radius: var(--sn-radius-lg);
    overflow: hidden;
    box-shadow: var(--sn-shadow-md);
}

.sn-search-form-large input {
    flex: 1;
    border: none;
    padding: var(--sn-spacing-md) var(--sn-spacing-lg);
    font-size: 1rem;
    outline: none;
}

.sn-search-form-large button {
    background: var(--sn-primary);
    border: none;
    padding: var(--sn-spacing-md) var(--sn-spacing-lg);
    color: white;
    cursor: pointer;
    transition: background var(--sn-transition-fast);
}

.sn-search-form-large button:hover {
    background: var(--sn-primary-dark);
}

/* -----------------------------------------------------------------------------
   Product Grid - Clean, Compact Design
   ----------------------------------------------------------------------------- */
.sn-product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: var(--sn-spacing-md);
}

.sn-product-card {
    background: white;
    border-radius: var(--sn-radius-md);
    overflow: hidden;
    border: 1px solid var(--sn-gray-200);
    display: flex;
    flex-direction: column;
    transition: border-color var(--sn-transition-fast), box-shadow var(--sn-transition-fast), transform var(--sn-transition-fast);
    cursor: pointer;
}

.sn-product-card:hover {
    border-color: var(--sn-primary-light);
    box-shadow: var(--sn-shadow-md);
    transform: translateY(-2px);
}

.sn-product-card:hover .sn-product-title {
    color: var(--sn-primary);
}

.sn-product-link {
    display: flex;
    flex-direction: column;
    flex: 1;
    text-decoration: none;
    color: inherit;
}

.sn-product-link:hover {
    color: inherit;
}

.sn-product-image {
    width: 100%;
    height: 140px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: white;
    padding: var(--sn-spacing-sm);
}

.sn-product-image img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.sn-product-image-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--sn-gray-300);
    font-size: 2rem;
}

.sn-product-details {
    padding: var(--sn-spacing-sm);
    flex: 1;
    display: flex;
    flex-direction: column;
    border-top: 1px solid var(--sn-gray-100);
}

.sn-product-brand {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    color: var(--sn-gray-400);
    margin-bottom: 2px;
}

.sn-product-title {
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--sn-gray-700);
    margin-bottom: var(--sn-spacing-xs);
    line-height: 1.3;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.sn-product-features {
    display: none; /* Hide features for cleaner look */
}

.sn-product-pricing {
    margin-top: auto;
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.sn-product-price {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--sn-gray-800);
}

.sn-product-original-price {
    font-size: 0.75rem;
    color: var(--sn-gray-400);
    text-decoration: line-through;
}

.sn-product-discount {
    font-size: 0.65rem;
    font-weight: 600;
    color: var(--sn-accent-green);
    background: rgba(90, 154, 110, 0.12);
    padding: 1px 4px;
    border-radius: 3px;
}

.sn-product-prime {
    font-size: 0.7rem;
    color: var(--sn-primary);
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-top: 4px;
}

.sn-product-prime i {
    font-size: 0.6rem;
}

.sn-product-btn {
    display: none; /* Hide the button for cleaner look - card itself is clickable */
}

.sn-product-btn:hover {
    background: var(--sn-primary-dark);
    color: white;
}

.sn-product-btn i {
    font-size: 0.65rem;
    margin-left: 4px;
}

/* -----------------------------------------------------------------------------
   Sidebar Product Card (for Amazon products in sidebar)
   ----------------------------------------------------------------------------- */
.sn-sidebar-product {
    background: white;
    border-radius: var(--sn-radius-md);
    border: 1px solid var(--sn-gray-200);
    overflow: hidden;
    margin-bottom: var(--sn-spacing-md);
}

.sn-sidebar-product a {
    display: block;
    text-decoration: none;
    color: inherit;
}

.sn-sidebar-product a:hover {
    color: inherit;
}

.sn-sidebar-product-image {
    width: 100%;
    height: 160px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: white;
    padding: var(--sn-spacing-sm);
}

.sn-sidebar-product-image img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.sn-sidebar-product-details {
    padding: var(--sn-spacing-sm) var(--sn-spacing-md);
    border-top: 1px solid var(--sn-gray-100);
}

.sn-sidebar-product-title {
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--sn-primary);
    line-height: 1.4;
    margin-bottom: var(--sn-spacing-xs);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.sn-sidebar-product-title:hover {
    text-decoration: underline;
}

/* No Results State */
.sn-no-results {
    text-align: center;
    padding: var(--sn-spacing-2xl);
    background: white;
    border-radius: var(--sn-radius-lg);
    border: 1px solid var(--sn-gray-200);
}

.sn-no-results-icon {
    font-size: 4rem;
    color: var(--sn-gray-300);
    margin-bottom: var(--sn-spacing-lg);
}

.sn-no-results h2 {
    color: var(--sn-gray-700);
    margin-bottom: var(--sn-spacing-md);
}

.sn-no-results p {
    color: var(--sn-gray-600);
    margin-bottom: var(--sn-spacing-lg);
}

/* Affiliate Notice */
.sn-affiliate-notice {
    background: var(--sn-gray-100);
    border-radius: var(--sn-radius-md);
    padding: var(--sn-spacing-md) !important;
}

.sn-affiliate-notice p {
    margin: 0;
    color: var(--sn-gray-500);
}

/* -----------------------------------------------------------------------------
   Responsive Adjustments
   ----------------------------------------------------------------------------- */
@media (max-width: 991.98px) {
    .sn-product-grid {
        grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    }
}

@media (max-width: 767.98px) {
    .sn-hero h1 {
        font-size: 1.75rem;
    }

    .sn-hero p {
        font-size: 1rem;
    }

    .sn-auth-card {
        margin: var(--sn-spacing-md);
    }

    .sn-sidebar {
        position: static;
        margin-top: var(--sn-spacing-xl);
    }

    .sn-product-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--sn-spacing-sm);
    }

    .sn-search-form-large {
        max-width: 100%;
    }

    .sn-product-image {
        height: 120px;
    }

    .sn-product-title {
        font-size: 0.75rem;
    }

    .sn-product-btn {
        padding: 6px;
        font-size: 0.7rem;
    }
}

/* =============================================================================
   ADMIN PAGES - Consistent Styling
   ============================================================================= */

/* Admin Page Header - Dark gradient with accent */
.admin-page-header {
    background: linear-gradient(135deg, #1a1a2e 0%, #2d2d4a 100%);
    color: #fff;
    padding: 24px 32px;
    border-radius: 12px;
    margin-bottom: 24px;
}

.admin-page-header h1 {
    margin: 0;
    font-size: 28px;
    font-weight: 600;
    color: #fff;
}

.admin-page-header h1 i {
    color: #7c3aed;
}

.admin-page-header p {
    margin: 8px 0 0 0;
    color: rgba(255, 255, 255, 0.7);
    font-size: 14px;
}

/* Cross-tier switcher (Dashboard / Admin / SuperAdmin) — Phase 5 IA nav */
.sn-tier-nav {
    flex-wrap: wrap;
}
.sn-tier-nav .nav-link {
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 10px;
    color: #344054;
    background: #fff;
    min-width: 160px;
    line-height: 1.2;
}
.sn-tier-nav .nav-link:hover {
    border-color: #7c3aed;
    background: #faf8ff;
}
.sn-tier-nav .nav-link.active {
    background: linear-gradient(135deg, #1a1a2e 0%, #2d2d4a 100%);
    border-color: transparent;
    color: #fff;
}

/* Admin Primary Button - Gradient with visible text */
.btn-admin-primary {
    background: linear-gradient(135deg, #7c3aed 0%, #9333ea 100%) !important;
    border: none !important;
    color: #fff !important;
    padding: 10px 24px;
    font-weight: 600;
    font-size: 15px;
    border-radius: 8px;
    box-shadow: 0 4px 14px rgba(124, 58, 237, 0.4);
    transition: all 0.2s ease;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.btn-admin-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(124, 58, 237, 0.5);
    color: #fff !important;
    text-decoration: none;
}

.btn-admin-primary:focus {
    color: #fff !important;
    box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.3);
}

/* Admin Secondary Button */
.btn-admin-secondary {
    background: #374151 !important;
    border: none !important;
    color: #fff !important;
    padding: 10px 24px;
    font-weight: 600;
    font-size: 15px;
    border-radius: 8px;
    transition: all 0.2s ease;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.btn-admin-secondary:hover {
    background: #4b5563 !important;
    color: #fff !important;
    text-decoration: none;
}

/* Admin Action Buttons (for tables) */
.btn-admin-edit {
    background: #7c3aed !important;
    border: none !important;
    color: #fff !important;
    font-weight: 500;
}

.btn-admin-edit:hover {
    background: #6d28d9 !important;
    color: #fff !important;
}

.btn-admin-view {
    background: #6b7280 !important;
    border: none !important;
    color: #fff !important;
    font-weight: 500;
}

.btn-admin-view:hover {
    background: #4b5563 !important;
    color: #fff !important;
}

.btn-admin-delete {
    background: #dc2626 !important;
    border: none !important;
    color: #fff !important;
    font-weight: 500;
}

.btn-admin-delete:hover {
    background: #b91c1c !important;
    color: #fff !important;
}

/* Admin Cards */
.admin-card {
    background: #fff;
    border-radius: 12px;
    border: 1px solid #e5e7eb;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.admin-card .card-header {
    background: #f9fafb;
    border-bottom: 1px solid #e5e7eb;
    padding: 16px 20px;
    font-weight: 600;
}

/* Admin Empty State */
.admin-empty-state {
    text-align: center;
    padding: 60px 20px;
}

.admin-empty-state i {
    font-size: 4rem;
    color: #d1d5db;
    margin-bottom: 20px;
}

.admin-empty-state h4 {
    color: #374151;
    margin-bottom: 8px;
}

.admin-empty-state p {
    color: #6b7280;
    margin-bottom: 24px;
}

/* Admin Table Styles */
.admin-table {
    margin-bottom: 0;
}

.admin-table thead th {
    background: #f9fafb;
    border-bottom: 2px solid #e5e7eb;
    font-weight: 600;
    color: #374151;
    padding: 12px 16px;
}

.admin-table tbody td {
    padding: 12px 16px;
    vertical-align: middle;
}

.admin-table tbody tr:hover {
    background: #f9fafb;
}

/* Status Badges */
.badge-admin-success {
    background: #10b981 !important;
    color: #fff !important;
    font-weight: 500;
    padding: 4px 10px;
}

.badge-admin-warning {
    background: #f59e0b !important;
    color: #000 !important;
    font-weight: 500;
    padding: 4px 10px;
}

.badge-admin-danger {
    background: #ef4444 !important;
    color: #fff !important;
    font-weight: 500;
    padding: 4px 10px;
}

.badge-admin-info {
    background: #3b82f6 !important;
    color: #fff !important;
    font-weight: 500;
    padding: 4px 10px;
}

/* =============================================================================
   SUPERADMIN PAGES - Red/Dark Theme
   ============================================================================= */

/* SuperAdmin Page Header - Red gradient */
/* SuperAdmin page header — match Template Management: plain text on the page
   gradient (no boxed panel), with the small muted badge. */
.superadmin-page-header {
    background: transparent;
    color: #fff;
    padding: 4px 0 12px;
    border-radius: 0;
    margin-bottom: 16px;
    border-left: none;
}

.superadmin-page-header h1 {
    margin: 0;
    font-size: 28px;
    font-weight: 700;
    color: #fff;
    display: flex;
    align-items: center;
    gap: 12px;
}

.superadmin-page-header h1 i {
    color: #a5b4fc;
}

.superadmin-page-header p {
    margin: 8px 0 0 0;
    color: rgba(255, 255, 255, 0.6);
    font-size: 14px;
}

/* Muted maroon pill — mirrors Template Management's `badge bg-danger`. */
.superadmin-badge {
    background: #4a2c2f;
    color: #f0b8bc;
    padding: 4px 12px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    text-transform: none;
    letter-spacing: normal;
}

/* SuperAdmin Stat Cards — uniform translucent glass (Template Management look). */
.stat-card {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    padding: 20px;
    height: 100%;
}

/* Colour variants kept as class hooks but neutralised so all cards are uniform. */
.stat-card-danger,
.stat-card-warning,
.stat-card-dark,
.stat-card-success {
    border-left: 1px solid rgba(255, 255, 255, 0.1);
}

.stat-card-title {
    font-size: 14px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.6);
    margin-bottom: 8px;
}

.stat-card-danger .stat-card-title,
.stat-card-warning .stat-card-title,
.stat-card-success .stat-card-title { color: rgba(255, 255, 255, 0.6); }

.stat-card-value {
    font-size: 44px;
    font-weight: 800;
    color: #fff;
    line-height: 1;
    margin-bottom: 4px;
    letter-spacing: -0.5px;
    font-variant-numeric: tabular-nums;
}

.stat-card-label {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.4);
}

/* SuperAdmin Section Cards — glass surfaces with uniform headers. */
.section-card {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    overflow: hidden;
    height: 100%;
    display: flex;
    flex-direction: column;
}

.section-card-header {
    padding: 16px 20px;
    font-weight: 600;
    font-size: 15px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.05);
    color: #e4e6eb;
}

/* Colour variants kept as class hooks; tinted icon only, uniform glass header. */
.section-card-header-danger,
.section-card-header-primary,
.section-card-header-dark,
.section-card-header-info {
    background: rgba(255, 255, 255, 0.05);
    color: #e4e6eb;
}

.section-card-header-danger i { color: #f0b8bc; }
.section-card-header-primary i { color: #a8c4f0; }
.section-card-header-dark i { color: #cbd5e1; }
.section-card-header-info i { color: #a8f0f0; }

/* "Across your sites" cross-site/domain aggregate panel (_TrafficSiteBreakdown) — used on the dashboard
   home + the full analytics page, so the styling is global (not inline like the analytics-only bits). */
.sn-sitebd .sn-chart-body { position: relative; }
.sn-sitebd .sn-data-link { color: var(--bs-info, #6ec1e4); text-decoration: none; word-break: break-all; }
.sn-sitebd .sn-data-link:hover { text-decoration: underline; }
.sn-bd-tbl { font-size: .9rem; }
.sn-bd-tbl th { color: var(--theme-text-muted, #94a3b8); font-weight: 600; border-bottom-color: rgba(255, 255, 255, .1); white-space: nowrap; }
.sn-bd-tbl td { border-bottom-color: rgba(255, 255, 255, .06); vertical-align: middle; }
.sn-bd-name { font-weight: 600; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sn-bd-ref { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Typeahead "switch / view site" picker (per-site analytics — Dashboard + SuperAdmin). Shared partial
   _SiteSwitchTypeahead. */
.sn-siteswitch { position: relative; min-width: 240px; }
.sn-siteswitch-menu {
    position: absolute; z-index: 30; top: calc(100% + 4px); right: 0; left: 0; max-height: 340px;
    overflow-y: auto; background: #1a1d29; border: 1px solid rgba(255, 255, 255, .12); border-radius: 8px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .45); padding: 4px;
}
.sn-siteswitch-hdr { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: #94a3b8; padding: 6px 10px 2px; }
.sn-siteswitch-item {
    display: flex; justify-content: space-between; gap: 10px; align-items: center;
    padding: 7px 10px; border-radius: 6px; cursor: pointer; color: #e2e8f0; font-size: .92rem;
}
.sn-siteswitch-item:hover, .sn-siteswitch-item.active { background: rgba(var(--bs-primary-rgb, 124, 58, 237), .22); }
.sn-siteswitch-item .v { color: #94a3b8; font-size: .82rem; white-space: nowrap; }
.sn-siteswitch-item.current { opacity: .55; }
.sn-siteswitch-sys { font-size: .66rem; text-transform: uppercase; letter-spacing: .03em; color: #fcd34d;
    border: 1px solid rgba(252, 211, 77, .4); border-radius: 4px; padding: 0 5px; margin-left: 6px; }
.sn-siteswitch-empty { padding: 8px 10px; color: #94a3b8; font-size: .88rem; }

.section-card-body {
    padding: 16px;
    flex: 1;
}

.section-card-body .btn {
    margin-bottom: 8px;
    text-align: left;
    justify-content: flex-start;
}

.section-card-body .btn:last-child {
    margin-bottom: 0;
}

/* SuperAdmin Buttons */
.btn-superadmin-danger {
    background: transparent;
    border: 1px solid #dc2626;
    color: #f87171;
}

.btn-superadmin-danger:hover {
    background: rgba(220, 38, 38, 0.18);
    color: #fca5a5;
}

.btn-superadmin-primary {
    background: transparent;
    border: 1px solid #3b82f6;
    color: #60a5fa;
}

.btn-superadmin-primary:hover {
    background: rgba(59, 130, 246, 0.18);
    color: #93c5fd;
}

.btn-superadmin-dark {
    background: transparent;
    border: 1px solid #6b7280;
    color: #9ca3af;
}

.btn-superadmin-dark:hover {
    background: #4b5563;
    color: #fff;
}

.btn-superadmin-warning {
    background: transparent;
    border: 1px solid #f59e0b;
    color: #fbbf24;
}

.btn-superadmin-warning:hover {
    background: rgba(245, 158, 11, 0.18);
    color: #fcd34d;
}

.btn-superadmin-info {
    background: transparent;
    border: 1px solid #06b6d4;
    color: #22d3ee;
}

.btn-superadmin-info:hover {
    background: rgba(6, 182, 212, 0.18);
    color: #67e8f9;
}

.btn-superadmin-disabled {
    background: transparent;
    border: 1px solid #374151;
    color: #4b5563;
    cursor: not-allowed;
}

/* ============================================
   Dashboard Kit (Link-Lytics-style, SNI accent)
   Shared landing-dashboard pieces: header action
   row, stat cards, chart panels, quick-action
   icon tiles, data panels. Dark-glass on the
   backend-theme body; indigo/purple accent.
   ============================================ */

/* Header action button row (top-right of the page header). */
.sn-dash-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}
.sn-dash-actions .btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    font-size: 14px;
    border-radius: 8px;
    padding: 8px 14px;
}

/* Stat card: a small uppercase trend/sub line under the value. */
.stat-card .stat-card-sub {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.45);
    margin-top: 6px;
}
.stat-card .stat-card-sub .up { color: #34d399; }

/* Chart panel — a section-card sized for a canvas. */
.sn-chart-body {
    padding: 16px 20px 20px;
}

/* Quick-action icon tiles (replaces vertical button lists). */
.sn-tiles {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
}
@media (max-width: 992px) { .sn-tiles { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 576px) { .sn-tiles { grid-template-columns: 1fr; } }

.sn-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    text-align: center;
    min-height: 132px;
    padding: 20px 12px;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.10);
    color: #e4e6eb;
    text-decoration: none;
    transition: transform 0.12s ease, border-color 0.12s ease, background 0.12s ease;
    position: relative;
}
.sn-tile:hover {
    transform: translateY(-2px);
    border-color: rgba(124, 58, 237, 0.6);
    background: rgba(124, 58, 237, 0.10);
    color: #fff;
}
.sn-tile i { font-size: 28px; color: #a5b4fc; }
.sn-tile:hover i { color: #c4b5fd; }
.sn-tile-label { font-weight: 600; font-size: 14px; }
.sn-tile-badge {
    position: absolute;
    top: 10px;
    right: 10px;
    min-width: 22px;
    padding: 1px 7px;
    border-radius: 11px;
    font-size: 11px;
    font-weight: 700;
    background: rgba(99, 102, 241, 0.25);
    color: #c7d2fe;
}
.sn-tile-badge.warn { background: rgba(245, 158, 11, 0.22); color: #fcd34d; }
.sn-tile-badge.danger { background: rgba(220, 38, 38, 0.25); color: #fca5a5; }
.sn-tile.disabled { opacity: 0.45; pointer-events: none; }

/* Simple key/value data rows inside a section-card (top hosts, by company). */
.sn-data-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.sn-data-row:last-child { border-bottom: none; }
.sn-data-row .label { color: #d1d5db; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 70%; }
.sn-data-row .val { font-weight: 700; color: #fff; }

/* Company-context banner (SuperAdmin operating-as a company). */
.sn-context-bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    padding: 12px 18px;
    margin-bottom: 16px;
    border-radius: 12px;
    background: linear-gradient(135deg, rgba(99, 102, 241, 0.15) 0%, rgba(168, 85, 247, 0.12) 100%);
    border: 1px solid rgba(255, 255, 255, 0.12);
    color: #e4e6eb;
}
.sn-context-bar strong { color: #fff; }

/* Highlight the currently-active company card in the chooser. */
.sn-company-active {
    border-color: rgba(16, 185, 129, 0.6) !important;
    box-shadow: 0 0 0 1px rgba(16, 185, 129, 0.4);
}

/* Thin active-users progress bar on company cards. */
.sn-active-bar { height: 5px; background: rgba(255, 255, 255, 0.08); border-radius: 3px; }
.sn-active-bar .progress-bar { background: #6366f1; }

/* ============================================
   Hub Management - Glassmorphism & Pastels
   ============================================ */

/* Container with subtle gradient background */
.hub-container {
    /* Transparent so the shared body gradient (theme.css backend-theme) shows
       through — avoids a second, mismatched gradient block behind the panels. */
    background: transparent;
    padding: 24px;
}

/* Glassmorphism base card */
.hub-glass {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 16px;
}

/* Header with glass effect */
.hub-glass-header {
    background: linear-gradient(135deg, rgba(99, 102, 241, 0.15) 0%, rgba(168, 85, 247, 0.15) 100%);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 16px;
    padding: 24px 32px;
    margin-bottom: 24px;
}

.hub-glass-header h1 {
    margin: 0;
    font-size: 28px;
    font-weight: 600;
    color: #e0e7ff;
    display: flex;
    align-items: center;
    gap: 12px;
}

.hub-glass-header h1 i {
    color: #a78bfa;
}

.hub-glass-header p {
    margin: 8px 0 0 0;
    color: rgba(224, 231, 255, 0.7);
    font-size: 14px;
}

/* Hub badge - purple/violet pastel */
.hub-badge {
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.8) 0%, rgba(124, 58, 237, 0.8) 100%);
    color: #fff;
    padding: 6px 14px;
    border-radius: 8px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    backdrop-filter: blur(4px);
}

/* Primary domain badge - gold/amber glow */
.hub-badge-primary {
    background: linear-gradient(135deg, rgba(251, 191, 36, 0.9) 0%, rgba(245, 158, 11, 0.9) 100%);
    color: #1a1a2e;
    box-shadow: 0 0 20px rgba(251, 191, 36, 0.4);
    animation: primaryGlow 2s ease-in-out infinite alternate;
}

@keyframes primaryGlow {
    from { box-shadow: 0 0 15px rgba(251, 191, 36, 0.3); }
    to { box-shadow: 0 0 25px rgba(251, 191, 36, 0.5); }
}

/* Stat cards with glass effect and pastel accents */
.hub-stat-card {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    padding: 20px 24px;
    height: 100%;
    transition: all 0.3s ease;
}

.hub-stat-card:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.15);
    transform: translateY(-2px);
}

/* Pastel accent colors for stat cards */
.hub-stat-card-violet {
    border-left: 3px solid #a78bfa;
    background: linear-gradient(135deg, rgba(167, 139, 250, 0.08) 0%, rgba(255, 255, 255, 0.03) 100%);
}

.hub-stat-card-amber {
    border-left: 3px solid #fbbf24;
    background: linear-gradient(135deg, rgba(251, 191, 36, 0.08) 0%, rgba(255, 255, 255, 0.03) 100%);
}

.hub-stat-card-cyan {
    border-left: 3px solid #22d3ee;
    background: linear-gradient(135deg, rgba(34, 211, 238, 0.08) 0%, rgba(255, 255, 255, 0.03) 100%);
}

.hub-stat-card-emerald {
    border-left: 3px solid #34d399;
    background: linear-gradient(135deg, rgba(52, 211, 153, 0.08) 0%, rgba(255, 255, 255, 0.03) 100%);
}

.hub-stat-card-rose {
    border-left: 3px solid #fb7185;
    background: linear-gradient(135deg, rgba(251, 113, 133, 0.08) 0%, rgba(255, 255, 255, 0.03) 100%);
}

.hub-stat-card .stat-title {
    font-size: 13px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.6);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 8px;
}

.hub-stat-card .stat-value {
    font-size: 32px;
    font-weight: 700;
    color: #fff;
    line-height: 1;
}

.hub-stat-card .stat-label {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.5);
    margin-top: 4px;
}

.hub-stat-card-violet .stat-value { color: #c4b5fd; }
.hub-stat-card-amber .stat-value { color: #fde68a; }
.hub-stat-card-cyan .stat-value { color: #a5f3fc; }
.hub-stat-card-emerald .stat-value { color: #a7f3d0; }
.hub-stat-card-rose .stat-value { color: #fecdd3; }

/* Glass table */
.hub-glass-table {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    overflow: hidden;
}

.hub-glass-table .table {
    margin-bottom: 0;
    color: #e0e7ff;
}

.hub-glass-table .table thead th {
    background: rgba(99, 102, 241, 0.1);
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    color: #a5b4fc;
    font-weight: 600;
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 14px 16px;
}

.hub-glass-table .table tbody tr {
    transition: background 0.2s ease;
}

.hub-glass-table .table tbody tr:hover {
    background: rgba(255, 255, 255, 0.05);
}

.hub-glass-table .table tbody td {
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
    padding: 14px 16px;
    vertical-align: middle;
}

/* Primary row highlight in table */
.hub-glass-table .table tbody tr.row-primary {
    background: linear-gradient(90deg, rgba(251, 191, 36, 0.1) 0%, rgba(255, 255, 255, 0.03) 100%);
    border-left: 3px solid #fbbf24;
}

.hub-glass-table .table tbody tr.row-primary:hover {
    background: linear-gradient(90deg, rgba(251, 191, 36, 0.15) 0%, rgba(255, 255, 255, 0.05) 100%);
}

/* Glass form card */
.hub-glass-form {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 20px;
    overflow: hidden;
}

/* Primary domain editing - prominent header */
.hub-primary-edit-header {
    background: linear-gradient(135deg, rgba(251, 191, 36, 0.2) 0%, rgba(245, 158, 11, 0.15) 100%);
    border: 1px solid rgba(251, 191, 36, 0.3);
    border-radius: 16px;
    padding: 24px 32px;
    margin-bottom: 24px;
    position: relative;
    overflow: hidden;
}

.hub-primary-edit-header::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: linear-gradient(90deg, transparent 0%, rgba(251, 191, 36, 0.1) 50%, transparent 100%);
    animation: primaryShimmer 3s ease-in-out infinite;
}

@keyframes primaryShimmer {
    0%, 100% { transform: translateX(-100%); }
    50% { transform: translateX(100%); }
}

.hub-primary-edit-header h1 {
    margin: 0;
    font-size: 28px;
    font-weight: 600;
    color: #fef3c7;
    display: flex;
    align-items: center;
    gap: 12px;
    position: relative;
    z-index: 1;
}

.hub-primary-edit-header h1 i {
    color: #fbbf24;
}

.hub-primary-edit-header p {
    margin: 8px 0 0 0;
    color: rgba(254, 243, 199, 0.8);
    font-size: 14px;
    position: relative;
    z-index: 1;
}

.hub-primary-edit-header .hub-badge-primary {
    position: relative;
    z-index: 1;
}

/* Glass tabs */
.hub-glass-tabs {
    background: rgba(255, 255, 255, 0.02);
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.hub-glass-tabs .nav-tabs {
    border-bottom: none;
    padding: 0 16px;
}

.hub-glass-tabs .nav-tabs .nav-link {
    color: rgba(255, 255, 255, 0.6);
    border: none;
    border-bottom: 2px solid transparent;
    padding: 16px 20px;
    font-weight: 500;
    transition: all 0.2s ease;
    background: transparent;
    border-radius: 0;
}

.hub-glass-tabs .nav-tabs .nav-link:hover {
    color: rgba(255, 255, 255, 0.9);
    background: rgba(255, 255, 255, 0.03);
}

.hub-glass-tabs .nav-tabs .nav-link.active {
    color: #a5b4fc;
    background: rgba(99, 102, 241, 0.1);
    border-bottom-color: #818cf8;
}

.hub-glass-tabs .nav-tabs .nav-link i {
    margin-right: 8px;
}

/* Tab content area */
.hub-glass-content {
    padding: 24px;
    background: rgba(255, 255, 255, 0.02);
}

/* Form controls with glass styling */
.hub-glass-content .form-control,
.hub-glass-content .form-select {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: #e0e7ff;
    border-radius: 10px;
    transition: all 0.2s ease;
}

.hub-glass-content .form-control:focus,
.hub-glass-content .form-select:focus {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(139, 92, 246, 0.5);
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.15);
    color: #fff;
}

.hub-glass-content .form-control::placeholder {
    color: rgba(255, 255, 255, 0.35);
}

.hub-glass-content .form-label {
    color: rgba(255, 255, 255, 0.8);
    font-weight: 500;
}

.hub-glass-content .form-text {
    color: rgba(255, 255, 255, 0.5);
}

.hub-glass-content .form-check-input {
    background-color: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.2);
}

.hub-glass-content .form-check-input:checked {
    background-color: #8b5cf6;
    border-color: #8b5cf6;
}

/* Glass buttons */
.btn-hub-primary {
    background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%);
    border: none;
    color: #fff;
    border-radius: 10px;
    padding: 10px 20px;
    font-weight: 500;
    transition: all 0.2s ease;
}

.btn-hub-primary:hover {
    background: linear-gradient(135deg, #6d28d9 0%, #5b21b6 100%);
    color: #fff;
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(124, 58, 237, 0.25);
}

.btn-hub-secondary {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.15);
    color: rgba(255, 255, 255, 0.8);
    border-radius: 10px;
    padding: 10px 20px;
    font-weight: 500;
    transition: all 0.2s ease;
}

.btn-hub-secondary:hover {
    background: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.25);
    color: #fff;
}

.btn-hub-success {
    background: linear-gradient(135deg, rgba(52, 211, 153, 0.8) 0%, rgba(16, 185, 129, 0.8) 100%);
    border: 1px solid rgba(52, 211, 153, 0.5);
    color: #fff;
    border-radius: 10px;
}

.btn-hub-success:hover {
    background: linear-gradient(135deg, rgba(52, 211, 153, 0.95) 0%, rgba(16, 185, 129, 0.95) 100%);
    color: #fff;
    box-shadow: 0 4px 12px rgba(52, 211, 153, 0.3);
}

.btn-hub-warning {
    background: linear-gradient(135deg, rgba(251, 191, 36, 0.8) 0%, rgba(245, 158, 11, 0.8) 100%);
    border: 1px solid rgba(251, 191, 36, 0.5);
    color: #1a1a2e;
    border-radius: 10px;
}

.btn-hub-warning:hover {
    background: linear-gradient(135deg, rgba(251, 191, 36, 0.95) 0%, rgba(245, 158, 11, 0.95) 100%);
    color: #1a1a2e;
    box-shadow: 0 4px 12px rgba(251, 191, 36, 0.3);
}

.btn-hub-danger {
    background: linear-gradient(135deg, rgba(239, 68, 68, 0.8) 0%, rgba(220, 38, 38, 0.8) 100%);
    border: 1px solid rgba(239, 68, 68, 0.5);
    color: #fff;
    border-radius: 10px;
}

.btn-hub-danger:hover {
    background: linear-gradient(135deg, rgba(239, 68, 68, 0.95) 0%, rgba(220, 38, 38, 0.95) 100%);
    color: #fff;
    box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
}

/* Glass alerts */
.hub-glass-content .alert-info {
    background: rgba(59, 130, 246, 0.1);
    border: 1px solid rgba(59, 130, 246, 0.3);
    color: #93c5fd;
    border-radius: 12px;
}

.hub-glass-content .alert-warning {
    background: rgba(251, 191, 36, 0.1);
    border: 1px solid rgba(251, 191, 36, 0.3);
    color: #fde68a;
    border-radius: 12px;
}

.hub-glass-content .alert-danger {
    background: rgba(239, 68, 68, 0.1);
    border: 1px solid rgba(239, 68, 68, 0.3);
    color: #fecaca;
    border-radius: 12px;
}

/* Mode cards with glass effect */
.hub-mode-card {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 16px;
    padding: 20px;
    cursor: pointer;
    transition: all 0.3s ease;
    height: 100%;
}

.hub-mode-card:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.2);
    transform: translateY(-3px);
}

.hub-mode-card.selected {
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.15) 0%, rgba(99, 102, 241, 0.1) 100%);
    border-color: rgba(139, 92, 246, 0.5);
    box-shadow: 0 0 20px rgba(139, 92, 246, 0.2);
}

.hub-mode-card .mode-icon {
    font-size: 32px;
    color: rgba(255, 255, 255, 0.5);
    margin-bottom: 12px;
}

.hub-mode-card.selected .mode-icon {
    color: #a78bfa;
}

.hub-mode-card .mode-title {
    font-weight: 600;
    color: rgba(255, 255, 255, 0.9);
    margin-bottom: 4px;
}

.hub-mode-card .mode-desc {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
}

/* Theme cards */
.hub-theme-card {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    padding: 16px;
    cursor: pointer;
    transition: all 0.3s ease;
}

.hub-theme-card:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.2);
    transform: translateY(-2px);
}

.hub-theme-card.selected {
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.15) 0%, rgba(99, 102, 241, 0.1) 100%);
    border-color: rgba(139, 92, 246, 0.5);
    box-shadow: 0 0 15px rgba(139, 92, 246, 0.2);
}

/* Header style cards (Hub Site Edit) — share the theme-card look. */
.hub-header-card {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    padding: 16px;
    cursor: pointer;
    transition: all 0.3s ease;
    height: 100%;
}
.hub-header-card:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.2);
    transform: translateY(-2px);
}
.hub-header-card.selected {
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.15) 0%, rgba(99, 102, 241, 0.1) 100%);
    border-color: rgba(139, 92, 246, 0.5);
    box-shadow: 0 0 15px rgba(139, 92, 246, 0.2);
}

/* Template cards (layout selection with SVG previews) */
.hub-template-card {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    cursor: pointer;
    transition: all 0.3s ease;
    overflow: hidden;
}

.hub-template-card:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.2);
    transform: translateY(-3px);
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
}

.hub-template-card.selected {
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.15) 0%, rgba(99, 102, 241, 0.1) 100%);
    border-color: rgba(139, 92, 246, 0.5);
    box-shadow: 0 0 20px rgba(139, 92, 246, 0.25);
}

.hub-template-card.premium {
    position: relative;
}

.hub-template-card .template-preview {
    position: relative;
    padding: 12px;
    background: rgba(0, 0, 0, 0.2);
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

.hub-template-card .template-preview svg {
    width: 100%;
    height: auto;
    display: block;
    border-radius: 4px;
}

.hub-template-card .premium-badge {
    position: absolute;
    top: 8px;
    right: 8px;
    background: linear-gradient(135deg, #f59e0b, #d97706);
    color: #fff;
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 10px;
}

.hub-template-card .template-info {
    padding: 12px;
    text-align: center;
}

.hub-template-card .template-name {
    color: #e0e7ff;
    font-weight: 500;
    font-size: 14px;
    margin-bottom: 4px;
}

.hub-template-card .template-desc {
    color: rgba(255, 255, 255, 0.5);
    font-size: 11px;
    line-height: 1.3;
}

/* ============================================================================
   GRAPESJS-STYLE TEMPLATE GALLERY
   Rich visual previews showing actual mini-website layouts
   ============================================================================ */

.template-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 24px;
    margin-bottom: 24px;
}

.template-gallery-item {
    background: rgba(255, 255, 255, 0.03);
    border: 2px solid rgba(255, 255, 255, 0.1);
    border-radius: 16px;
    overflow: hidden;
    cursor: pointer;
    transition: all 0.3s ease;
    position: relative;
}

.template-gallery-item:hover {
    border-color: rgba(139, 92, 246, 0.4);
    transform: translateY(-4px);
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}

.template-gallery-item.selected {
    border-color: #8b5cf6;
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.3), 0 12px 40px rgba(139, 92, 246, 0.2);
}

.template-gallery-item.premium::before {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 60px;
    height: 60px;
    background: linear-gradient(135deg, transparent 50%, rgba(245, 158, 11, 0.9) 50%);
    z-index: 10;
}

/* Mini Website Preview Container */
.template-mini-preview {
    position: relative;
    height: 200px;
    background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
    overflow: hidden;
    padding: 8px;
}

.template-premium-badge {
    position: absolute;
    top: 8px;
    right: 8px;
    background: linear-gradient(135deg, #f59e0b, #d97706);
    color: #fff;
    padding: 4px 10px;
    border-radius: 20px;
    font-size: 10px;
    font-weight: 600;
    z-index: 20;
    box-shadow: 0 2px 8px rgba(245, 158, 11, 0.4);
}

/* Mini Site Base Styles */
.mini-site {
    width: 100%;
    height: 100%;
    background: #0f0f1a;
    border-radius: 6px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}

/* Mini Header Styles */
.mini-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 10px;
    background: rgba(255, 255, 255, 0.05);
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.mini-header.minimal {
    justify-content: center;
    background: transparent;
}

.mini-header.centered {
    justify-content: center;
}

.mini-header.ecom {
    gap: 8px;
}

.mini-logo {
    width: 40px;
    height: 10px;
    background: linear-gradient(90deg, #8b5cf6, #a78bfa);
    border-radius: 2px;
}

.mini-logo.light {
    background: rgba(255, 255, 255, 0.9);
}

.mini-logo.centered {
    width: 50px;
}

.mini-nav {
    display: flex;
    gap: 6px;
}

.mini-nav span {
    width: 20px;
    height: 4px;
    background: rgba(255, 255, 255, 0.3);
    border-radius: 2px;
}

.mini-nav.light span {
    background: rgba(255, 255, 255, 0.7);
}

.mini-search {
    flex: 1;
    height: 8px;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 4px;
    max-width: 80px;
}

.mini-cart {
    width: 12px;
    height: 12px;
    background: rgba(139, 92, 246, 0.6);
    border-radius: 2px;
}

/* Mini Hero Header */
.mini-hero-header {
    padding: 15px 10px;
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.4) 0%, rgba(59, 130, 246, 0.3) 100%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    min-height: 70px;
}

.mini-hero-header.gradient {
    background: linear-gradient(135deg, #8b5cf6 0%, #3b82f6 50%, #06b6d4 100%);
}

.mini-hero-content {
    text-align: center;
    margin-top: 4px;
}

.mini-hero-title {
    width: 80px;
    height: 8px;
    background: rgba(255, 255, 255, 0.9);
    border-radius: 2px;
    margin: 0 auto 4px;
}

.mini-hero-subtitle {
    width: 60px;
    height: 4px;
    background: rgba(255, 255, 255, 0.5);
    border-radius: 2px;
    margin: 0 auto;
}

.mini-hero-btn {
    width: 40px;
    height: 10px;
    background: rgba(255, 255, 255, 0.9);
    border-radius: 4px;
    margin: 6px auto 0;
}

/* Mini Body Styles */
.mini-body {
    flex: 1;
    padding: 8px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.mini-body.with-sidebar {
    flex-direction: row;
    gap: 8px;
}

.mini-body.with-filters {
    flex-direction: row;
    gap: 6px;
}

.mini-body.centered {
    max-width: 70%;
    margin: 0 auto;
    padding: 12px 8px;
}

.mini-body.magazine-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto auto;
    gap: 6px;
}

/* Mini Content Elements */
.mini-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.mini-title {
    width: 70%;
    height: 8px;
    background: rgba(255, 255, 255, 0.8);
    border-radius: 2px;
}

.mini-title.large {
    width: 80%;
    height: 10px;
    margin: 0 auto;
}

.mini-text {
    width: 100%;
    height: 4px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 2px;
}

.mini-text.short {
    width: 60%;
}

.mini-divider {
    width: 30px;
    height: 2px;
    background: rgba(139, 92, 246, 0.6);
    margin: 4px auto;
    border-radius: 1px;
}

/* Mini Sidebar */
.mini-sidebar {
    width: 50px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.mini-widget {
    height: 25px;
    background: rgba(139, 92, 246, 0.15);
    border-radius: 4px;
    border: 1px solid rgba(139, 92, 246, 0.2);
}

/* Mini Cards */
.mini-cards {
    display: flex;
    gap: 4px;
    margin-top: 4px;
}

.mini-card {
    flex: 1;
    height: 30px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 4px;
    border: 1px solid rgba(255, 255, 255, 0.1);
}

.mini-card-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
    padding: 8px;
}

.mini-feature-card {
    height: 35px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 6px;
    border: 1px solid rgba(255, 255, 255, 0.1);
}

/* Mini Magazine Layout */
.mini-featured {
    grid-column: 1;
    grid-row: 1;
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.3), rgba(59, 130, 246, 0.2));
    border-radius: 4px;
    min-height: 50px;
}

.mini-article-list {
    grid-column: 2;
    grid-row: 1;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.mini-article {
    height: 14px;
    background: rgba(255, 255, 255, 0.08);
    border-radius: 2px;
}

.mini-article-grid {
    grid-column: span 2;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 4px;
}

.mini-article-card {
    height: 25px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 3px;
    border: 1px solid rgba(255, 255, 255, 0.08);
}

/* Mini Landing Page Sections */
.mini-section {
    padding: 8px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.mini-section.alt {
    background: rgba(255, 255, 255, 0.03);
}

.mini-section-title {
    width: 50px;
    height: 6px;
    background: rgba(255, 255, 255, 0.7);
    border-radius: 2px;
}

.mini-feature-row {
    display: flex;
    gap: 6px;
    width: 100%;
}

.mini-feature-row > div {
    flex: 1;
    height: 20px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 4px;
    border: 1px solid rgba(255, 255, 255, 0.1);
}

.mini-testimonial {
    width: 80%;
    height: 20px;
    background: rgba(255, 255, 255, 0.08);
    border-radius: 6px;
}

.mini-cta {
    padding: 10px;
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.2), rgba(59, 130, 246, 0.15));
    display: flex;
    justify-content: center;
}

.mini-cta-btn {
    width: 50px;
    height: 12px;
    background: #8b5cf6;
    border-radius: 4px;
}

/* Mini Portfolio Grid */
.mini-portfolio-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
    padding: 4px;
}

.mini-portfolio-item {
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.2), rgba(59, 130, 246, 0.15));
    border-radius: 4px;
    min-height: 25px;
}

.mini-portfolio-item.tall {
    grid-row: span 2;
}

.mini-portfolio-item.wide {
    grid-column: span 2;
}

/* Mini Dashboard Layout */
.mini-site.dashboard {
    flex-direction: row;
}

.mini-dash-sidebar {
    width: 40px;
    background: rgba(255, 255, 255, 0.05);
    border-right: 1px solid rgba(255, 255, 255, 0.1);
    padding: 6px 4px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.mini-dash-logo {
    width: 100%;
    height: 8px;
    background: linear-gradient(90deg, #8b5cf6, #a78bfa);
    border-radius: 2px;
    margin-bottom: 6px;
}

.mini-dash-menu {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.mini-dash-menu > div {
    height: 6px;
    background: rgba(255, 255, 255, 0.15);
    border-radius: 2px;
}

.mini-dash-menu > div.active {
    background: rgba(139, 92, 246, 0.6);
}

.mini-dash-main {
    flex: 1;
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.mini-dash-header {
    height: 10px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 4px;
}

.mini-dash-widgets {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 4px;
    flex: 1;
}

.mini-dash-widget {
    background: rgba(255, 255, 255, 0.05);
    border-radius: 4px;
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.mini-dash-widget.wide {
    grid-column: span 2;
}

/* Mini E-Commerce Layout */
.mini-filters {
    width: 45px;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.mini-filter {
    height: 20px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 3px;
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.mini-products {
    flex: 1;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
}

.mini-product {
    background: rgba(255, 255, 255, 0.05);
    border-radius: 4px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    min-height: 25px;
}

/* Mini Footer Styles */
.mini-footer {
    padding: 6px 10px;
    background: rgba(255, 255, 255, 0.03);
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.mini-footer.simple {
    height: 12px;
}

.mini-footer.minimal {
    height: 8px;
    background: transparent;
    border: none;
    display: flex;
    justify-content: center;
    align-items: center;
}

.mini-footer.minimal::after {
    content: '';
    width: 30px;
    height: 3px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 2px;
}

.mini-footer.multi {
    display: flex;
    gap: 6px;
}

.mini-footer.multi > div {
    flex: 1;
    height: 15px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 2px;
}

/* Template Gallery Info */
.template-gallery-info {
    padding: 16px;
    background: rgba(0, 0, 0, 0.2);
    border-top: 1px solid rgba(255, 255, 255, 0.05);
}

.template-gallery-name {
    font-size: 16px;
    font-weight: 600;
    color: #e0e7ff;
    margin-bottom: 6px;
}

.template-gallery-desc {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.5);
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.template-selected-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 10px;
    padding: 6px 12px;
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.3), rgba(99, 102, 241, 0.2));
    border: 1px solid rgba(139, 92, 246, 0.5);
    border-radius: 20px;
    font-size: 12px;
    font-weight: 500;
    color: #a78bfa;
}

.template-selected-badge i {
    color: #8b5cf6;
}

/* ============================================================================
   PROFESSIONAL TEMPLATE GALLERY (CDN-BASED)
   GrapesJS-inspired gallery with CDN images and CSS fallbacks
   ============================================================================ */

.template-gallery-pro {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 24px;
    margin-bottom: 24px;
}

.template-card-pro {
    background: rgba(15, 15, 26, 0.95);
    border: 2px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    overflow: hidden;
    cursor: pointer;
    transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
    position: relative;
}

.template-card-pro:hover {
    border-color: rgba(139, 92, 246, 0.5);
    transform: translateY(-6px) scale(1.02);
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5), 0 0 30px rgba(139, 92, 246, 0.15);
}

.template-card-pro.selected {
    border-color: #8b5cf6;
    border-width: 4px;
    box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.45), 0 0 60px rgba(139, 92, 246, 0.35), 0 20px 50px rgba(139, 92, 246, 0.25);
    transform: translateY(-2px);
}

/* Big "SELECTED" badge in top-left corner of the thumbnail, always
   visible when the card is selected (the bottom pill is easy to miss
   inside a busy gallery). Unicode checkmark + plain text - no icon
   font dependency. */
.template-card-pro.selected .template-preview-pro::before {
    content: "\2713  SELECTED"; /* U+2713 CHECK MARK */
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    position: absolute;
    top: 12px;
    left: 12px;
    z-index: 20;
    padding: 7px 14px;
    background: linear-gradient(135deg, #10b981 0%, #059669 100%);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.08em;
    border-radius: 999px;
    box-shadow: 0 4px 16px rgba(16, 185, 129, 0.5), 0 0 0 2px rgba(255, 255, 255, 0.15);
    display: flex;
    align-items: center;
    gap: 6px;
    text-transform: uppercase;
    pointer-events: none;
}

/* Slight tint over the preview so the eye is drawn to the selected card */
.template-card-pro.selected .template-preview-pro::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.08) 0%, rgba(16, 185, 129, 0.06) 100%);
    pointer-events: none;
    z-index: 15;
}

.template-card-pro.premium {
    border-color: rgba(245, 158, 11, 0.3);
}

/* Preview Container */
.template-preview-pro {
    position: relative;
    height: 200px;
    overflow: hidden;
    background: linear-gradient(145deg, #1a1a2e 0%, #0f0f1a 100%);
}

.template-thumb-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.4s ease;
}

.template-card-pro:hover .template-thumb-img {
    transform: scale(1.08);
}

/* CSS Fallback - displayed when image fails */
.template-css-fallback {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px;
}

/* Overlay */
.template-overlay {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 12px;
    background: linear-gradient(transparent, rgba(0, 0, 0, 0.8));
    opacity: 0;
    transition: opacity 0.3s ease;
}

.template-card-pro:hover .template-overlay {
    opacity: 1;
}

.template-type-badge {
    display: inline-block;
    padding: 4px 10px;
    background: rgba(139, 92, 246, 0.9);
    border-radius: 20px;
    font-size: 10px;
    font-weight: 600;
    color: #fff;
    text-transform: capitalize;
}

/* PRO Badge */
.template-pro-badge {
    position: absolute;
    top: 10px;
    right: 10px;
    padding: 5px 12px;
    background: linear-gradient(135deg, #f59e0b, #d97706);
    border-radius: 20px;
    font-size: 11px;
    font-weight: 700;
    color: #fff;
    z-index: 10;
    box-shadow: 0 4px 15px rgba(245, 158, 11, 0.4);
    display: flex;
    align-items: center;
    gap: 4px;
}

/* Info Section */
.template-info-pro {
    padding: 16px 18px;
    background: rgba(0, 0, 0, 0.3);
    border-top: 1px solid rgba(255, 255, 255, 0.05);
}

.template-name-pro {
    font-size: 16px;
    font-weight: 600;
    color: #e0e7ff;
    margin: 0 0 6px 0;
}

.template-desc-pro {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
    line-height: 1.5;
    margin: 0;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.template-selected-indicator {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
    padding: 6px 14px;
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.3), rgba(99, 102, 241, 0.2));
    border: 1px solid rgba(139, 92, 246, 0.5);
    border-radius: 20px;
    font-size: 12px;
    font-weight: 600;
    color: #a78bfa;
}

.template-selected-indicator i {
    color: #8b5cf6;
}

/* Responsive adjustments */
@media (max-width: 768px) {
    .template-gallery-pro {
        grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
        gap: 16px;
    }

    .template-preview-pro {
        height: 160px;
    }
}

@media (min-width: 1400px) {
    .template-gallery-pro {
        grid-template-columns: repeat(4, 1fr);
    }
}

/* ============================================================================
   TEMPLATE ACTIONS OVERLAY (Preview/Select buttons on hover)
   ============================================================================ */

.template-actions-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.7);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    opacity: 0;
    transition: opacity 0.3s ease;
    z-index: 5;
}

.template-card-pro:hover .template-actions-overlay {
    opacity: 1;
}

.btn-template-action {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    transition: all 0.2s ease;
    border: 2px solid transparent;
}

.btn-template-action.btn-preview {
    background: rgba(255, 255, 255, 0.15);
    color: #fff;
    border-color: rgba(255, 255, 255, 0.3);
}

.btn-template-action.btn-preview:hover {
    background: rgba(255, 255, 255, 0.25);
    border-color: rgba(255, 255, 255, 0.5);
    transform: scale(1.1);
}

.btn-template-action.btn-select {
    background: linear-gradient(135deg, #8b5cf6, #6366f1);
    color: #fff;
    border-color: transparent;
}

.btn-template-action.btn-select:hover {
    background: linear-gradient(135deg, #a78bfa, #818cf8);
    transform: scale(1.1);
    box-shadow: 0 0 20px rgba(139, 92, 246, 0.5);
}

/* ============================================================================
   TEMPLATE SOURCES GRID (External template providers)
   ============================================================================ */

.template-load-more-section {
    padding: 20px;
    background: rgba(255, 255, 255, 0.02);
    border: 1px solid rgba(255, 255, 255, 0.05);
    border-radius: 16px;
}

.template-sources-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 12px;
}

.template-source-card {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    padding: 16px 12px;
    text-align: center;
    cursor: pointer;
    transition: all 0.25s ease;
}

.template-source-card:hover {
    background: rgba(139, 92, 246, 0.1);
    border-color: rgba(139, 92, 246, 0.3);
    transform: translateY(-2px);
}

.template-source-card .source-icon {
    font-size: 24px;
    color: #a78bfa;
    margin-bottom: 8px;
}

.template-source-card .source-name {
    font-size: 13px;
    font-weight: 600;
    color: #e0e7ff;
    margin-bottom: 4px;
}

.template-source-card .source-count {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.4);
}

/* ============================================================================
   TEMPLATE PREVIEW MODAL
   ============================================================================ */

.preview-detail-card {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    padding: 16px;
    text-align: center;
}

.preview-detail-card i {
    font-size: 24px;
    color: #8b5cf6;
    margin-bottom: 8px;
    display: block;
}

.preview-detail-card .detail-label {
    display: block;
    font-size: 11px;
    color: rgba(255, 255, 255, 0.4);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 4px;
}

.preview-detail-card .detail-value {
    display: block;
    font-size: 14px;
    font-weight: 600;
    color: #e0e7ff;
}

/* ============================================================================
   IMPORT TEMPLATES MODAL
   ============================================================================ */

.import-source-tab {
    background: rgba(255, 255, 255, 0.05) !important;
    border: 1px solid rgba(255, 255, 255, 0.1) !important;
    color: rgba(255, 255, 255, 0.7) !important;
    border-radius: 8px !important;
    padding: 8px 16px !important;
    font-size: 13px !important;
}

.import-source-tab:hover {
    background: rgba(255, 255, 255, 0.1) !important;
    color: #fff !important;
}

.import-source-tab.active {
    background: linear-gradient(135deg, rgba(139, 92, 246, 0.3), rgba(99, 102, 241, 0.2)) !important;
    border-color: rgba(139, 92, 246, 0.5) !important;
    color: #fff !important;
}

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

.import-template-card {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 14px;
    overflow: hidden;
    transition: all 0.3s ease;
}

.import-template-card:hover {
    border-color: rgba(139, 92, 246, 0.4);
    transform: translateY(-4px);
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.3);
}

.import-template-img {
    position: relative;
    height: 180px;
    overflow: hidden;
}

.import-template-img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.3s ease;
}

.import-template-card:hover .import-template-img img {
    transform: scale(1.05);
}

.import-template-actions {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.75);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.import-template-card:hover .import-template-actions {
    opacity: 1;
}

.import-template-info {
    padding: 16px;
}

.import-template-info h6 {
    font-size: 15px;
    font-weight: 600;
    color: #e0e7ff;
    margin: 0 0 6px 0;
}

.import-template-info p {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.5);
    margin: 0 0 10px 0;
}

.import-template-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.import-template-tags .tag {
    padding: 3px 8px;
    background: rgba(139, 92, 246, 0.15);
    border-radius: 4px;
    font-size: 11px;
    color: #a78bfa;
}

/* Page cards */
.hub-page-card {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    padding: 16px;
    cursor: pointer;
    transition: all 0.2s ease;
}

.hub-page-card:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.2);
}

.hub-page-card.selected {
    background: linear-gradient(135deg, rgba(52, 211, 153, 0.1) 0%, rgba(16, 185, 129, 0.08) 100%);
    border-color: rgba(52, 211, 153, 0.5);
}

/* Glass footer */
.hub-glass-footer {
    background: rgba(255, 255, 255, 0.02);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    padding: 16px 24px;
}

/* Accordion with glass styling */
.hub-glass-content .accordion-item {
    background: rgba(255, 255, 255, 0.02);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px !important;
    margin-bottom: 8px;
}

.hub-glass-content .accordion-button {
    background: rgba(255, 255, 255, 0.03);
    color: rgba(255, 255, 255, 0.8);
    border-radius: 12px !important;
}

.hub-glass-content .accordion-button:not(.collapsed) {
    background: rgba(99, 102, 241, 0.1);
    color: #a5b4fc;
}

.hub-glass-content .accordion-button::after {
    filter: invert(1) opacity(0.5);
}

.hub-glass-content .accordion-body {
    background: transparent;
}

/* Section dividers */
.hub-section-title {
    color: rgba(255, 255, 255, 0.9);
    font-size: 18px;
    font-weight: 600;
    margin-bottom: 16px;
    display: flex;
    align-items: center;
    gap: 10px;
}

.hub-section-title i {
    color: #a78bfa;
}

/* Character counter styling */
.hub-char-counter {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.5);
}

.hub-char-counter.warning {
    color: #fbbf24;
}

.hub-char-counter.danger {
    color: #f87171;
}

/* ============================================================================
   HUB SITE THEMES (Color Schemes)
   Applied to <body> via ViewBag.Request.Site.ThemeCssClass
   ============================================================================ */

/* Base theme variables - These are overridden by specific themes */
body[class*="theme-"] {
    --theme-primary: #8b5cf6;
    --theme-primary-rgb: 139, 92, 246;
    --theme-secondary: #a78bfa;
    --theme-secondary-rgb: 167, 139, 250;
    --theme-bg: #0f0f1a;
    --theme-surface: rgba(255, 255, 255, 0.03);
    --theme-border: rgba(255, 255, 255, 0.1);
    --theme-text: #e0e7ff;
    --theme-text-muted: rgba(255, 255, 255, 0.72);
}

/* Theme 1: Default Dark (Violet) */
/* NOTE: these specific themes are prefixed `body` so their specificity (0,1,1)
   ties the base `body[class*="theme-"]` var block (0,1,1) and wins by source
   order (defined later) — otherwise a bare `.theme-ocean-blue` (0,1,0) loses to
   the base block and every theme renders with the base violet primary. */
body.theme-default-dark {
    --theme-primary: #8b5cf6;
    --theme-primary-rgb: 139, 92, 246;
    --theme-secondary: #a78bfa;
    --theme-secondary-rgb: 167, 139, 250;
    background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #16213e 100%);
    min-height: 100vh;
}

/* Theme 2: Ocean Blue */
body.theme-ocean-blue {
    --theme-primary: #0ea5e9;
    --theme-primary-rgb: 14, 165, 233;
    --theme-secondary: #38bdf8;
    --theme-secondary-rgb: 56, 189, 248;
    background: linear-gradient(135deg, #0c1929 0%, #0f2744 50%, #0d3b66 100%);
    min-height: 100vh;
}

/* Theme 3: Forest Green */
body.theme-forest-green {
    --theme-primary: #10b981;
    --theme-primary-rgb: 16, 185, 129;
    --theme-secondary: #34d399;
    --theme-secondary-rgb: 52, 211, 153;
    background: linear-gradient(135deg, #0d1f17 0%, #132f20 50%, #1a4731 100%);
    min-height: 100vh;
}

/* Theme 4: Sunset Orange */
body.theme-sunset-orange {
    --theme-primary: #f59e0b;
    --theme-primary-rgb: 245, 158, 11;
    --theme-secondary: #fbbf24;
    --theme-secondary-rgb: 251, 191, 36;
    background: linear-gradient(135deg, #1a1207 0%, #2d1f0a 50%, #44290e 100%);
    min-height: 100vh;
}

/* Theme 5: Rose Pink */
body.theme-rose-pink {
    --theme-primary: #ec4899;
    --theme-primary-rgb: 236, 72, 153;
    --theme-secondary: #f472b6;
    --theme-secondary-rgb: 244, 114, 182;
    background: linear-gradient(135deg, #1a0d14 0%, #2d1423 50%, #441d32 100%);
    min-height: 100vh;
}

/* Theme 6: Crimson Red */
body.theme-crimson-red {
    --theme-primary: #b91c1c;
    --theme-primary-rgb: 185, 28, 28;
    --theme-secondary: #dc2626;
    --theme-secondary-rgb: 220, 38, 38;
    background: linear-gradient(135deg, #1a0a0a 0%, #2d1010 50%, #441515 100%);
    min-height: 100vh;
}

/* Theme 7: Midnight (Dark Slate) */
body.theme-midnight {
    --theme-primary: #475569;
    --theme-primary-rgb: 71, 85, 105;
    --theme-secondary: #64748b;
    --theme-secondary-rgb: 100, 116, 139;
    background: linear-gradient(135deg, #0f1115 0%, #1a1d24 50%, #252a33 100%);
    min-height: 100vh;
}

/* Theme 8: Light Glass */
body.theme-light-glass {
    --theme-primary: #6366f1;
    --theme-primary-rgb: 99, 102, 241;
    --theme-secondary: #818cf8;
    --theme-secondary-rgb: 129, 140, 248;
    --theme-bg: #f8fafc;
    --theme-surface: rgba(255, 255, 255, 0.8);
    --theme-border: rgba(0, 0, 0, 0.1);
    --theme-text: #1e293b;
    --theme-text-muted: rgba(0, 0, 0, 0.6);
    background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 50%, #cbd5e1 100%);
    min-height: 100vh;
    color: var(--theme-text);
}

/* ---------------------------------------------------------------------------
   Glass themes (frosted) — deep gradient + translucent white surfaces, mirroring
   the .hub-glass admin look. Seeded IsFrosted=1 (HubThemes), so the body gets
   `sn-frosted` and the frosted card rules below add backdrop-blur. Surfaces use
   the same rgba(255,255,255,.05/.1) as .hub-glass.
   --------------------------------------------------------------------------- */
body.theme-amethyst-glass {
    --theme-primary: #a78bfa;
    --theme-primary-rgb: 167, 139, 250;
    --theme-secondary: #c4b5fd;
    --theme-secondary-rgb: 196, 181, 253;
    --theme-surface: rgba(255, 255, 255, 0.05);
    --theme-border: rgba(255, 255, 255, 0.1);
    --theme-text: #ece9ff;
    --theme-text-muted: rgba(255, 255, 255, 0.72);
    background: linear-gradient(135deg, #150f29 0%, #221a40 50%, #2d1f55 100%);
    min-height: 100vh;
    color: var(--theme-text);
}
body.theme-aurora-glass {
    --theme-primary: #2dd4bf;
    --theme-primary-rgb: 45, 212, 191;
    --theme-secondary: #5eead4;
    --theme-secondary-rgb: 94, 234, 212;
    --theme-surface: rgba(255, 255, 255, 0.05);
    --theme-border: rgba(255, 255, 255, 0.1);
    --theme-text: #e0fbf4;
    --theme-text-muted: rgba(255, 255, 255, 0.72);
    background: linear-gradient(135deg, #07201f 0%, #0a2e33 50%, #0d3f4a 100%);
    min-height: 100vh;
    color: var(--theme-text);
}
body.theme-rose-quartz-glass {
    --theme-primary: #fb7185;
    --theme-primary-rgb: 251, 113, 133;
    --theme-secondary: #fda4af;
    --theme-secondary-rgb: 253, 164, 175;
    --theme-surface: rgba(255, 255, 255, 0.05);
    --theme-border: rgba(255, 255, 255, 0.1);
    --theme-text: #ffeaf0;
    --theme-text-muted: rgba(255, 255, 255, 0.72);
    background: linear-gradient(135deg, #261019 0%, #3a1827 50%, #4d2236 100%);
    min-height: 100vh;
    color: var(--theme-text);
}
body.theme-smoke-glass {
    --theme-primary: #cbd5e1;
    --theme-primary-rgb: 203, 213, 225;
    --theme-secondary: #e2e8f0;
    --theme-secondary-rgb: 226, 232, 240;
    --theme-surface: rgba(255, 255, 255, 0.05);
    --theme-border: rgba(255, 255, 255, 0.1);
    --theme-text: #eef1f5;
    --theme-text-muted: rgba(255, 255, 255, 0.7);
    background: linear-gradient(135deg, #131519 0%, #1c1f26 50%, #272b34 100%);
    min-height: 100vh;
    color: var(--theme-text);
}

/* Frosted effect: when the selected theme is frosted (HubThemes.IsFrosted →
   body.sn-frosted from BaseController), give translucent surfaces a real
   backdrop-blur so the gradient shows through like frosted glass. Only on
   Full-mode themed pages (Accent/None keep the template's own surfaces). */
body.sn-frosted[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .card,
body.sn-frosted[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .card-body,
body.sn-frosted[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .hub-glass,
body.sn-frosted[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .sn-search,
body.sn-frosted[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .sn-product-card,
body.sn-frosted[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .sn-no-results {
    -webkit-backdrop-filter: blur(12px) saturate(140%);
    backdrop-filter: blur(12px) saturate(140%);
    background-color: rgba(255, 255, 255, 0.07);
}

/* Apply theme colors to common elements when a theme is active.
   How far the theme reaches is gated by the template's Theme Mode, emitted as a
   body class by BaseController.InjectThemeClass from HubTemplates.ThemeModeId
   (see SocialNet.Core.Common.TemplateThemeModeIds):
     - Full   (sn-theme-full)   : recolor text + surfaces/cards AND accents
     - Accent (sn-theme-accent) : only tint links/buttons; keep own text & cards
     - None   (sn-theme-none)   : theme ignored
   The :not() form preserves the original full-recolor behaviour for any page
   WITHOUT a mode class (non-skin front-end pages, older callers) — only explicit
   Accent/None templates opt out. So self-styled templates (SB Admin 2) keep their
   own text/cards while still letting the theme tint their accents. */

/* Text + surfaces: every themed page EXCEPT Accent / None modes. */
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) main {
    color: var(--theme-text);
}
/* Headings too: the front-end rule `body:not(.backend-theme) h1..h6` pins headings to
   --sn-gray-900 (a fixed dark), which is dark-on-dark under a dark theme (e.g. search
   results "No products found"). Re-point them at the theme text color. Universal across
   templates; higher specificity than the front-end heading rule so it wins. */
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) h1,
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) h2,
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) h3,
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) h4,
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) h5,
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) h6 {
    color: var(--theme-text);
}
/* Muted/secondary text that modules hard-code to a fixed gray (e.g. search
   "We couldn't find…", .text-muted) reads too dark on a dark theme — re-point it
   at the theme's muted color. Universal across Full-mode themed templates. */
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .sn-no-results p,
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .text-muted,
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .sn-product-features {
    color: var(--theme-text-muted) !important;
}
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .card,
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .hub-glass {
    background: var(--theme-surface);
    border-color: var(--theme-border);
}
/* UNIVERSAL (any Full-mode template, not just Legacy): a theme's background is dark,
   so any template's Bootstrap light-surface bands (bg-light header/nav/footer, bg-white)
   would stay white with light --theme-text on top = unreadable. Neutralize them so the
   theme background shows through. Accent/None modes keep the template's own surfaces. */
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .bg-light,
body[class*="theme-"]:not(.sn-mode-accent):not(.sn-mode-none) .bg-white {
    background-color: transparent !important;
    background-image: none !important;
}

/* Accent tinting (links + buttons): every themed page EXCEPT None mode. */
/* Recolor links to the theme accent — but NOT anchors styled as buttons (.sn-btn). Those carry
   their own bg + text color (e.g. .sn-btn-primary is white-on-primary); letting this rule win made
   the "Back to Home" button on the search empty-state render its label in the same blue as its
   background → invisible. */
body[class*="theme-"]:not(.sn-mode-none) a:not(.sn-btn) {
    color: var(--theme-primary);
}
body[class*="theme-"]:not(.sn-mode-none) a:not(.sn-btn):hover {
    color: var(--theme-secondary);
}
body[class*="theme-"]:not(.sn-mode-none) .btn-primary,
body[class*="theme-"]:not(.sn-mode-none) .btn-hub-primary {
    background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-secondary) 100%);
    border-color: var(--theme-primary);
}

/* Accent / None: the template owns its own background — don't take the theme
   class's dark body gradient or forced full-height (those are for Full-mode
   layouts built to be themed). Without this a self-styled template (SB Admin 2)
   gets a dark bg bleeding behind it and a stray vertical scrollbar from
   min-height:100vh stacking with the fixed admin-chrome spacer. Specificity
   (0,2,1) beats the body.theme-* rule (0,1,1) so no !important needed. */
body.sn-mode-accent[class*="theme-"],
body.sn-mode-none[class*="theme-"] {
    background: none;
    min-height: 0;
}



/* ============================================================================
   HUB SITE TEMPLATES (Layout Structures)
   Applied to <body> via ViewBag.Request.Site.TemplateCssClass
   ============================================================================ */

/* Base template styles */
body[class*="template-"] main {
    max-width: 1400px;
    margin: 0 auto;
    padding: 0 20px;
}

/* (Removed: stale `.template-classic main { display: grid; … }` historical block.
   That ruleset never matched any active template — the SNI: Classic body class was
   `template-legacy` until 2026-05-30 — and now that the rename makes it actually
   `template-classic`, the old grid rule would conflict with the modern skin's
   container/row/col Bootstrap layout below. Modern skin styles for SNI: Classic
   live under the `body.sn-skin-page:is(.template-classic, .template-legacy,
   .template-glassed)` block farther down.) */

/* Template 2: Modern Hero - Full-width hero with card content */
.template-modern-hero main {
    display: flex;
    flex-direction: column;
    gap: 40px;
}

.template-modern-hero .hero-section {
    width: 100vw;
    margin-left: calc(-50vw + 50%);
    min-height: 60vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, rgba(var(--theme-primary-rgb), 0.2) 0%, rgba(var(--theme-secondary-rgb), 0.1) 100%);
    text-align: center;
    padding: 60px 20px;
}

.template-modern-hero .content-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 24px;
}

/* Template 3: Minimal - Clean, typography-focused */
.template-minimal main {
    max-width: 800px;
    margin: 60px auto;
    padding: 0 24px;
}

.template-minimal main h1,
.template-minimal main h2,
.template-minimal main h3 {
    font-weight: 300;
    letter-spacing: -0.02em;
}

.template-minimal main p {
    font-size: 1.125rem;
    line-height: 1.75;
    color: var(--theme-text-muted);
}

/* Template 4: Magazine - Multi-column grid */
.template-magazine main {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 24px;
    padding-top: 30px;
}

.template-magazine .featured-article {
    grid-column: span 8;
}

.template-magazine .sidebar-articles {
    grid-column: span 4;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.template-magazine .article-grid {
    grid-column: span 12;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 24px;
}

@media (max-width: 992px) {
    .template-magazine .featured-article,
    .template-magazine .sidebar-articles {
        grid-column: span 12;
    }
}

/* Template 5: Landing Page - Conversion-focused sections */
.template-landing main {
    display: flex;
    flex-direction: column;
}

.template-landing .section {
    padding: 80px 20px;
    width: 100vw;
    margin-left: calc(-50vw + 50%);
}

.template-landing .section:nth-child(even) {
    background: var(--theme-surface);
}

.template-landing .section-content {
    max-width: 1200px;
    margin: 0 auto;
}

.template-landing .cta-section {
    background: linear-gradient(135deg, rgba(var(--theme-primary-rgb), 0.15) 0%, rgba(var(--theme-secondary-rgb), 0.1) 100%);
    text-align: center;
}

/* Template 6: Portfolio - Visual masonry grid */
.template-portfolio main {
    padding-top: 40px;
}

.template-portfolio .portfolio-header {
    text-align: center;
    margin-bottom: 40px;
}

.template-portfolio .portfolio-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 16px;
}

.template-portfolio .portfolio-item {
    position: relative;
    overflow: hidden;
    border-radius: 12px;
    aspect-ratio: 4/3;
}

.template-portfolio .portfolio-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.3s ease;
}

.template-portfolio .portfolio-item:hover img {
    transform: scale(1.05);
}

/* Template 7: Dashboard - Sidebar navigation layout */
.template-dashboard {
    display: flex;
    min-height: 100vh;
}

.template-dashboard .sidebar-nav {
    width: 260px;
    background: var(--theme-surface);
    border-right: 1px solid var(--theme-border);
    padding: 20px;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
}

.template-dashboard main {
    flex: 1;
    padding: 30px;
}

.template-dashboard .dashboard-widgets {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 24px;
}

@media (max-width: 992px) {
    .template-dashboard {
        flex-direction: column;
    }
    .template-dashboard .sidebar-nav {
        width: 100%;
        height: auto;
        position: static;
        border-right: none;
        border-bottom: 1px solid var(--theme-border);
    }
}

/* Template 8: E-Commerce - Shop layout with filters */
.template-ecommerce main {
    display: grid;
    grid-template-columns: 260px 1fr;
    gap: 30px;
    padding-top: 30px;
}

.template-ecommerce .filter-sidebar {
    background: var(--theme-surface);
    border-radius: 12px;
    padding: 20px;
    height: fit-content;
    position: sticky;
    top: 20px;
}

.template-ecommerce .product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 24px;
}

.template-ecommerce .product-card {
    background: var(--theme-surface);
    border: 1px solid var(--theme-border);
    border-radius: 12px;
    overflow: hidden;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.template-ecommerce .product-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
}

@media (max-width: 992px) {
    .template-ecommerce main {
        grid-template-columns: 1fr;
    }
    .template-ecommerce .filter-sidebar {
        position: static;
    }
}

/* ============================================================================
   SN Frontend Module Styles (Phase 1A ViewComponents)
   These rules style the new ViewComponents (SiteHeader, SiteNav, MainContent,
   AltContent, Search, AmazonProducts, PopularSites, AdBlock, Keywords, Footer)
   using the theme tokens defined above (--theme-surface, --theme-text, etc.)
   so they inherit colors from whichever theme class is on <body>.
   ============================================================================ */

/* Generic shell wrapper - reserves the spot where the template class lives.
   Inherits text color so nested modules don't need to redeclare. */
.sn-template-frame {
    color: var(--theme-text);
}

/* Site header --------------------------------------------------------------- */
/* Fallback background — when no canned header-style class (sn-header-*) is
   applied AND no background-image is set, the header would otherwise render
   transparent and the page-body color shows through (looks like a flat dark
   void on dark themes). The fallback paints a subtle theme-aware accent so
   the header reads as a header even unstyled. Canned styles' more-specific
   selectors (.sn-header-glass-bar, .sn-header-hero, etc.) still win on top. */
.sn-site-header {
    background: var(--theme-surface, rgba(255, 255, 255, 0.06));
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}
.sn-site-header-inner {
    padding: 40px 24px;
}
/* DEFAULT banner header ONLY: flex column so the primary image can be positioned
   (horizontal via align-self / cross axis, vertical via auto margins / main axis), with
   vertical room when an image is present. The canned header styles (glass-bar / hero /
   centered / minimal) define their own layout and must NOT inherit this — otherwise the
   slim styles blow up to a tall band. Scoped via the sn-header-default marker class. */
.sn-site-header.sn-header-default .sn-site-header-inner {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}
.sn-site-header.sn-header-default.has-primary-image .sn-site-header-inner {
    min-height: 260px;
}
/* Default-banner 3x3 GRID layout (title + logo placement, HUB_DOMAIN_SITE_DESIGN 14b). The inner becomes a
   3-col x 3-row grid; each item is placed into its cell via grid-row/column + align-self/justify-self.
   Inline min-height (the site setting) governs height (grid still grows to fit a tall logo), overriding the
   fixed 260px above for grid-mode headers. */
.sn-site-header.sn-header-default .sn-site-header-inner.sn-hdr-grid {
    display: grid;
    /* Side columns size to their content, the middle absorbs the slack: a left/right item (e.g. the logo)
       shrinks to its own width instead of reserving a full third, so a left-justified title butts right up
       against it rather than starting at the 1/3 line. A spanning item that includes the middle column gets
       the remaining width and justifies within it. */
    grid-template-columns: auto 1fr auto;
    /* Three rows: top + flexible filler + bottom. Rows size to their content (no equal-row "tripling"),
       so a tall logo in the bottom row sets the header height; the 1fr middle row absorbs slack so
       top/middle/bottom map to the real top/centre/bottom. Items are placed by grid-row/column (the view),
       so a title and logo in the SAME column but different rows sit apart (no overlap) and the header grows
       to fit both; same exact cell → they stack (handled in the view). align-items:stretch resets the
       parent's flex-only 'flex-start' (invalid in grid). */
    grid-template-rows: auto 1fr auto;
    align-items: stretch;
    gap: 8px 16px;
}
/* Mobile: the auto/1fr/auto grid keeps logo + title side-by-side, which crushes a long title into a
   sliver on a phone. Below 600px, STACK the cells (logo on top, then title), each full-width + centered,
   so the header wraps cleanly. Applies to every skin (SNI: Classic, SNI: Glassed Over, …) since they all
   render the shared SiteHeader. !important overrides the per-item inline grid-column/align-self the view emits. */
@media (max-width: 600px) {
    .sn-site-header.sn-header-default .sn-site-header-inner.sn-hdr-grid {
        display: flex;
        flex-direction: column;
        align-items: center;
        text-align: center;
        gap: 12px;
    }
    .sn-site-header.sn-header-default .sn-hdr-grid > * {
        grid-column: auto !important;
        grid-row: auto !important;
        width: 100% !important;
        align-self: auto !important;
        justify-self: auto !important;
        text-align: center !important;
    }
    .sn-site-header.sn-header-default .sn-hdr-grid .sn-site-logo-link { order: -1; }   /* logo above the title */
    .sn-site-header.sn-header-default .sn-hdr-grid .sn-site-header-image { max-width: 80%; height: auto; }
}
/* Draw the eye to "Save changes" after a Header-layout Apply (changes aren't live until saved). */
.sn-save-attn { animation: snSaveAttn 1.1s ease-in-out 3; }
@keyframes snSaveAttn {
    0%, 100% { box-shadow: 0 0 0 0 rgba(255, 193, 7, 0); }
    50% { box-shadow: 0 0 0 4px rgba(255, 193, 7, 0.55); }
}
.sn-site-title {
    margin: 0;
    color: var(--theme-text);
}
/* When a header background image is set, give the title a readable scrim
   instead of relying on the image to have the right contrast. Author controls
   image; we control legibility. (.has-bg-image is set when the bg renders in its
   own layer — the older [style*=background-image] match no longer applies then.) */
.sn-site-header[style*="background-image"] .sn-site-title,
.sn-site-header.has-bg-image .sn-site-title {
    color: #fff;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.6);
}

/* ===========================================================================
   CANNED HEADER STYLES  (Sites.HeaderStyleId -> .sn-site-header.<CssClass>)
   The class is added to the rendered .sn-site-header. NULL style = legacy banner
   (these rules just don't apply). Each arranges the existing title + logo (Image1)
   + optional bg image into a defined layout.
   =========================================================================== */

/* 1. Glass Bar — slim frosted band, logo + title left. The frosted overlay (::before) sits OVER the
   header background image when one is set ("real glass over the photo"); with no image it IS the
   theme-surface bar (the original look). The bg image itself lives on the .sn-site-header element
   (inline, from the image editor: position/size/crop). */
.sn-site-header.sn-header-glass-bar {
    position: relative;
    overflow: hidden;
    background-size: cover;
    background-position: center;
    border-bottom: 1px solid var(--theme-border, rgba(255, 255, 255, 0.1));
}
.sn-site-header.sn-header-glass-bar::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    background: var(--theme-surface, rgba(255, 255, 255, 0.06));
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
}
.sn-site-header.sn-header-glass-bar .sn-site-header-inner {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 14px 28px;
}
.sn-site-header.sn-header-glass-bar .sn-site-title {
    font-size: 1.55rem;
    margin: 0;
    line-height: 1.1;
}
.sn-site-header.sn-header-glass-bar .sn-site-header-image {
    order: -1;            /* logo before the title */
    max-width: 100%;
    object-fit: contain;  /* honour the image editor (size/shape); no forced circle */
    flex-shrink: 0;
}

/* 2. Hero Banner — tall bg image + dark scrim, title (and logo) at the bottom. */
.sn-site-header.sn-header-hero {
    position: relative;
    min-height: 280px;
    display: flex;
    align-items: flex-end;
    background-size: cover;
    background-position: center;
}
/* WITH image: dark scrim so the title remains legible regardless of the photo. */
.sn-site-header.sn-header-hero[style*="background-image"]::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(0, 0, 0, 0.15) 0%, rgba(0, 0, 0, 0.7) 100%);
}
/* WITHOUT image: themed gradient + soft radial accents so the hero doesn't
   render as a flat void (the historical default when no DefaultHeaderBkgImage
   was set). User can still override by setting a bg image URL later. */
.sn-site-header.sn-header-hero:not([style*="background-image"]) {
    background: linear-gradient(135deg,
        var(--theme-primary, #6366f1) 0%,
        var(--theme-accent,  #8b5cf6) 100%);
}
.sn-site-header.sn-header-hero:not([style*="background-image"])::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        radial-gradient(circle at 20% 30%, rgba(255, 255, 255, 0.10) 0%, transparent 50%),
        radial-gradient(circle at 80% 70%, rgba(255, 255, 255, 0.06) 0%, transparent 50%);
    pointer-events: none;
}
.sn-site-header.sn-header-hero .sn-site-header-inner {
    position: relative;
    z-index: 1;
    padding: 34px 30px;
}
.sn-site-header.sn-header-hero .sn-site-title {
    font-size: clamp(2rem, 4vw, 3rem);
    margin: 0;
    color: #fff;
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.6);
}
.sn-site-header.sn-header-hero .sn-site-header-image {
    max-width: 100%;
    object-fit: contain;  /* honour the image editor (size/shape); no forced circle */
    margin-bottom: 12px;
    display: block;
}

/* 3. Centered Hero — logo centered above a centered title (over bg image if set). */
.sn-site-header.sn-header-centered {
    position: relative;
    background-size: cover;
    background-position: center;
    text-align: center;
}
/* WITH image: dark overlay for title legibility. */
.sn-site-header.sn-header-centered[style*="background-image"]::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
}
/* WITHOUT image: themed radial gradient so the centered style reads as
   intentional even before a bg image is uploaded. */
.sn-site-header.sn-header-centered:not([style*="background-image"]) {
    background:
        radial-gradient(ellipse at center, var(--theme-primary, #6366f1) 0%, var(--theme-surface, #1e1b4b) 100%);
}
.sn-site-header.sn-header-centered .sn-site-header-inner {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 44px 24px;
}
.sn-site-header.sn-header-centered .sn-site-header-image {
    order: -1;            /* logo above the title */
    max-width: 100%;
    object-fit: contain;  /* honour the image editor (size/shape); no forced circle */
}
.sn-site-header.sn-header-centered .sn-site-title {
    margin: 0;
    font-size: clamp(1.9rem, 3.5vw, 2.6rem);
}

/* 4. Minimal Band — thin, compact band that SHOWS the header background image when one is set (with a
   light scrim for title legibility). With no image it's a clean thin band on the theme. The bg image
   lives on .sn-site-header (inline, from the image editor). For a deliberate no-image header use the
   "No Image" style below. */
.sn-site-header.sn-header-minimal {
    position: relative;
    overflow: hidden;
    background-size: cover;
    background-position: center;
    border-bottom: 1px solid var(--theme-border, var(--sn-gray-200, #e8e4dc));
}
/* Scrim only when an image is set, so the title stays readable over the photo. */
.sn-site-header.sn-header-minimal[style*="background-image"]::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(0, 0, 0, 0.20) 0%, rgba(0, 0, 0, 0.48) 100%);
}
.sn-site-header.sn-header-minimal .sn-site-header-inner {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 22px;
}
.sn-site-header.sn-header-minimal .sn-site-title {
    font-size: 1.7rem;
    margin: 0;
}
/* Title over the scrim → force light text for legibility when an image is set. */
.sn-site-header.sn-header-minimal[style*="background-image"] .sn-site-title {
    color: #fff;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.55);
}
.sn-site-header.sn-header-minimal .sn-site-header-image {
    order: -1;            /* small logo before the title (like Glass Bar) */
    max-width: 100%;
    object-fit: contain;  /* honour the image editor (size/shape); no forced circle */
    flex-shrink: 0;
}

/* 5. No Image — title only, NEVER shows a header image (content-first). The deliberate "no banner"
   option; even if the site/page has a header image set, this style suppresses it. */
.sn-site-header.sn-header-noimage {
    background-image: none !important;
    background: transparent;
    border-bottom: 1px solid var(--theme-border, var(--sn-gray-200, #e8e4dc));
}
.sn-site-header.sn-header-noimage .sn-site-header-image { display: none; }
.sn-site-header.sn-header-noimage .sn-site-header-inner { padding: 18px 4px; }
.sn-site-header.sn-header-noimage .sn-site-title {
    font-size: 1.7rem;
    margin: 0;
}

/* Site nav (mix of local + global links — viral linking) ------------------- */
/* Inherit-friendly styling: no background, no forced colours, no Bootstrap
   `.nav-link` collision. Color comes from the template's slot context via
   `currentColor` inheritance. The accent dots use `currentColor` too so they
   pick up whatever the surrounding text colour is. */
.sn-site-nav,
.sn-site-pages {
    padding: 8px 0;
    background: transparent;
    color: inherit;
}
/* Hamburger for the site-page links. Hidden on desktop (links always shown); on phones the list
   collapses behind this toggle. Skin-neutral: inherits the nav's colour, no icon-font dependency. */
.sn-nav-toggle { display: none; }
@media (max-width: 600px) {
    .sn-site-nav .sn-nav-toggle {
        display: inline-flex;
        align-items: center;
        gap: 0.5rem;
        cursor: pointer;
        font: inherit;
        color: inherit;
        background: transparent;
        border: 1px solid currentColor;
        border-radius: 0.375rem;
        padding: 0.45rem 0.8rem;
        opacity: 0.9;
    }
    .sn-site-nav .sn-nav-toggle-bars { font-size: 1.15rem; line-height: 1; }
    /* Collapsed by default; !important beats any inline ListFlowStyle (e.g. display:flex) the slot emits. */
    .sn-site-nav .sn-site-nav-list { display: none !important; }
    .sn-site-nav.sn-nav-open .sn-site-nav-list { display: block !important; margin-top: 8px; }
}
.sn-site-nav-heading,
.sn-site-pages-heading {
    margin: 0 0 6px;
    font-size: 0.85rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    opacity: 0.7;
    color: inherit;
}
/* Suppress bullets. !important because host themes scope `<ul>` rules deeply
   (e.g. `.sidebar .nav-item ul` etc.) and would otherwise re-introduce
   markers. Showing markers is opt-in via the `.sn-list-bulleted` class
   below (which also uses !important to win back). */
ul.sn-site-nav-list,
ul.sn-site-pages-list {
    list-style: none !important;
    margin: 0;
    padding: 0;
}
ul.sn-site-nav-list > li,
ul.sn-site-pages-list > li {
    padding: 3px 0;
    list-style: none !important;
}
ul.sn-site-nav-list > li::marker,
ul.sn-site-pages-list > li::marker {
    content: "" !important;
}
/* showBullets option opts back in to bullet markers. We use a ::before pseudo
   on the link (further below) rather than list-style markers, because host
   templates often wrap our slot in flex/grid containers where list-style
   markers fail to render or land in the wrong place. The padding here just
   gives the marker a bit of breathing room from the container edge. */
ul.sn-list-bulleted {
    padding-left: 4px;
}
ul.sn-list-bulleted > li {
    padding: 3px 0 3px 4px;
}
.sn-nav-link,
.sn-site-pages-link {
    color: inherit;
    text-decoration: none;
    opacity: 0.85;
    transition: opacity 0.12s ease;
    display: inline-block;
    max-width: 100%;
}
.sn-nav-link:hover,
.sn-site-pages-link:hover {
    opacity: 1;
    text-decoration: underline;
}
/* Defensive wrapping. !important is used here intentionally because host
   templates often scope their nav-link rules deeply (e.g. SB Admin 2 uses
   `.sidebar .collapse-inner .collapse-item` — specificity (0,3,0)), which
   beats any reasonable class-only selector we could write. These three
   properties are non-negotiable defaults: host CSS shouldn't decide whether
   our module overflows its container. The truncate/clamp variants below use
   !important too so they can still override each other via source order. */
.sn-site-pages-list > li > a,
.sn-site-nav-list > li > a {
    white-space: normal !important;
    overflow-wrap: anywhere !important;
    word-break: break-word !important;
}

/* Truncate variant (single-line ellipsis) — set on the <ul> via the
   sn-list-truncate class when options.truncate=true. */
.sn-list-truncate > li {
    overflow: hidden;
}
.sn-list-truncate > li > a {
    display: block;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Multi-line clamp variant — set when options.maxLines is provided.
   Uses CSS custom property `--sn-clamp-lines` so the partial can wire any
   integer line count without per-N classes. */
.sn-list-clamp > li > a {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: var(--sn-clamp-lines, 2);
    line-clamp: var(--sn-clamp-lines, 2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: normal !important;
}

/* Defensive ::before/::after reset. Two reasons to nuke pseudo-element content
   on every link/item in our nav lists: (1) host themes sometimes inject markers
   via `.collapse-item::before { content: "•" }` etc., which `list-style: none`
   can't touch; (2) we want `showBullets` to be the single source of truth. */
ul.sn-site-pages-list > li::before,
ul.sn-site-pages-list > li::after,
ul.sn-site-pages-list > li > a::before,
ul.sn-site-pages-list > li > a::after,
ul.sn-site-nav-list > li::before,
ul.sn-site-nav-list > li::after,
ul.sn-site-nav-list > li > a::before,
ul.sn-site-nav-list > li > a::after {
    content: none !important;
    display: none !important;
}
/* When `showBullets: true`, re-introduce a marker via ::before on the link so
   it appears regardless of whether the host suppressed list-style markers.
   Uses Unicode bullet glyph so it's not dependent on `list-style: disc`
   actually rendering inside flex/grid contexts the host may have set.
   Needs higher specificity than the reset above to win — adds the
   `.sn-list-bulleted` class to the selector for that. */
ul.sn-list-bulleted.sn-site-pages-list > li > a::before,
ul.sn-list-bulleted.sn-site-nav-list > li > a::before {
    content: "\2022" !important;
    display: inline !important;
    margin-right: 6px;
    opacity: 0.7;
}
.sn-site-nav-empty,
.sn-site-pages-empty {
    margin: 0;
    font-size: 0.85rem;
    font-style: italic;
    opacity: 0.6;
    color: inherit;
}

/* Main content -------------------------------------------------------------- */
/* `.sn-editor-article` is the WYSIWYG editor's content <body> (TinyMCE iframe). It is grouped with
   `.sn-main-content` everywhere the article body is styled so the editor and the live page-view share ONE
   ruleset — true editor/preview parity, no hand-mirrored CSS in JS. The class only ever exists inside the
   editor iframe, so adding it here is inert for the live site. See CONTENT_EDITORS.md. */
.sn-main-content,
.sn-editor-article {
    color: var(--theme-text);
}

/* AltContent teasers (recent pages / promoted local content) --------------- */
.sn-alt-content {
    padding: 16px 0;
    border-bottom: 1px solid var(--theme-border);
}
.sn-alt-content:last-child { border-bottom: 0; }
.sn-alt-content-title { margin: 0 0 8px; font-size: 1.05rem; }
.sn-alt-content-title a { color: var(--theme-text); text-decoration: none; }
.sn-alt-content-title a:hover { color: var(--theme-primary); }
.sn-alt-content-excerpt { color: var(--theme-text-muted); margin: 0 0 8px; }
.sn-alt-content-more a { color: var(--theme-primary); font-size: 0.9rem; }

/* Search box --------------------------------------------------------------- */
.sn-search {
    padding: 14px;
    background: var(--theme-surface);
    border: 1px solid var(--theme-border);
    border-radius: 10px;
    margin-bottom: 16px;
}
.sn-search-heading {
    color: var(--theme-text);
    margin: 0 0 10px;
    font-size: 0.95rem;
    font-weight: 600;
}
/* Scope Bootstrap form-control restyling to inside an sn-search so we don't
   touch admin / backend form inputs that legitimately want a white background. */
.sn-search .form-control {
    background: rgba(0, 0, 0, 0.15);
    color: var(--theme-text);
    border: 1px solid var(--theme-border);
}
.sn-search .form-control::placeholder { color: var(--theme-text-muted); }
.sn-search .form-control:focus {
    background: rgba(0, 0, 0, 0.2);
    color: var(--theme-text);
    border-color: var(--theme-primary);
    box-shadow: 0 0 0 0.2rem rgba(var(--theme-primary-rgb), 0.25);
}
.sn-search .btn-primary {
    background: var(--theme-primary);
    border-color: var(--theme-primary);
}
.sn-search-recent-label { color: var(--theme-text-muted); margin-right: 6px; }
.sn-search-recent-badge {
    display: inline-block;
    padding: 3px 10px;
    background: rgba(var(--theme-primary-rgb), 0.15);
    color: var(--theme-text);
    border: 1px solid var(--theme-border);
    border-radius: 999px;
    font-size: 0.8rem;
    margin: 4px 4px 0 0;
}
.sn-search-recent-badge:hover {
    background: rgba(var(--theme-primary-rgb), 0.3);
    color: var(--theme-text);
}

/* Amazon Products sidebar cards (also used for any future affiliate source) - */
.sn-amazon-products { display: grid; gap: 10px; margin-bottom: 16px; }
.sn-sidebar-product {
    background: var(--theme-surface);
    border: 1px solid var(--theme-border);
    border-radius: 8px;
    overflow: hidden;
    transition: transform 0.15s ease, border-color 0.15s ease;
}
.sn-sidebar-product:hover {
    transform: translateY(-2px);
    border-color: var(--theme-primary);
}
.sn-sidebar-product a { color: var(--theme-text); text-decoration: none; display: block; }
.sn-sidebar-product-image img { width: 100%; height: auto; display: block; }
.sn-sidebar-product-details { padding: 8px 10px; }
.sn-sidebar-product-title {
    font-size: 0.85rem;
    line-height: 1.3;
    color: var(--theme-text);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Popular / Featured Sites (cross-site referral) --------------------------- */
.sn-popular-sites {
    padding: 14px;
    background: var(--theme-surface);
    border: 1px solid var(--theme-border);
    border-radius: 10px;
    margin-bottom: 16px;
}
.sn-popular-sites-heading {
    color: var(--theme-text);
    margin: 0 0 10px;
    font-size: 0.95rem;
    font-weight: 600;
}
.sn-popular-sites-list { margin: 0; padding: 0; }
.sn-popular-sites-list li { padding: 4px 0; }
.sn-popular-sites-list a { color: var(--theme-primary); text-decoration: none; }
.sn-popular-sites-list a:hover { text-decoration: underline; }
.sn-popular-sites-list li.truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Keywords ----------------------------------------------------------------- */
.sn-keywords {
    padding: 14px;
    background: var(--theme-surface);
    border: 1px solid var(--theme-border);
    border-radius: 10px;
    margin-bottom: 16px;
}
.sn-keywords-heading {
    color: var(--theme-text);
    margin: 0 0 10px;
    font-size: 0.95rem;
    font-weight: 600;
}
.sn-keywords-list { margin: 0; }
.sn-keyword {
    display: inline-block;
    margin: 0 6px 4px 0;
    padding: 2px 8px;
    background: rgba(var(--theme-primary-rgb), 0.15);
    color: var(--theme-text);
    border-radius: 4px;
    font-size: 0.8rem;
}

/* Ad block wrapper - the wrapper itself is transparent; embedded HTML or
   the AmazonProducts module brings its own styling. */
.sn-adblock { margin-bottom: 16px; }

/* Footer ------------------------------------------------------------------- */
.sn-site-footer {
    margin-top: 24px;
    padding: 16px 0;
    color: var(--theme-text-muted);
    border-top: 1px solid var(--theme-border);
    text-align: center;
}

/* =============================================================================
   MODERN SNI SKIN  —  "Soft modern cards"
   Shared by SNI: Classic (template-classic) + Legacy Default (template-legacy) +
   SNI: Glassed Over (template-glassed). Same modern look across all three; the
   glassed variant gets additional frosted treatment in the block right after this one.
   -----------------------------------------------------------------------------
   Scoped to body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed)
   — `sn-skin-page` and the template's LayoutCssClass are injected by
   BaseController.InjectThemeClass. So none of this leaks into the admin/dashboard
   screens that share this stylesheet, nor onto OTHER skin templates (SB Admin 2
   etc.), which carry their own design.

   Note: until 2026-05-30 the SNI: Classic template had LayoutCssClass='template-legacy'
   in the DB; PostScript 1.0103 renamed it to 'template-classic' so the body element
   reads `template-classic` and matches the display name. Both classes remain in the
   selector so the rename is forward-and-backward compatible (Legacy Default still
   uses 'template-legacy').

   The look is driven by --sk-* tokens defined below. System default (no theme
   class) gets a light page + white cards + soft shadows. When a dark .theme-*
   class is present we re-point the tokens at the theme surfaces so the dark
   schemes keep working instead of being forced light.
   ========================================================================== */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) {
    --sk-page-bg: #eef1f6;
    --sk-card-bg: #ffffff;
    --sk-card-radius: 16px;
    --sk-card-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 10px 28px rgba(16, 24, 40, .07);
    --sk-card-border: 1px solid rgba(16, 24, 40, .06);
    --sk-divider: #e9edf3;
    --sk-input-bg: #f1f3f7;
    --sk-nav-hover: rgba(var(--theme-primary-rgb), .10);

    color: var(--theme-text);
    /* Use the app's font (--sn-font-sans = Inter, then Segoe UI) for the whole skin so
       the title, headings and body content all match — rather than a separate stack. */
    font-family: var(--sn-font-sans);
    -webkit-font-smoothing: antialiased;
}

/* Secondary sub-nav (e.g. the Blog tab's Posts | Settings) — understated underline tabs that
   sit under the main site-management tabs without the jarring solid-blue nav-pill fill. */
.sn-subnav { display: inline-flex; gap: .25rem; margin: 1rem 0 .25rem; border-bottom: 1px solid rgba(255, 255, 255, .12); }
.sn-subnav a {
    padding: .45rem .95rem; font-size: .92rem; font-weight: 600; color: #9aa0aa;
    text-decoration: none; border-bottom: 2px solid transparent; margin-bottom: -1px;
    transition: color .12s ease, border-color .12s ease;
}
.sn-subnav a:hover { color: #e9ecf1; }
.sn-subnav a.active { color: #fff; border-bottom-color: #8b5cf6; }

/* ============================================================================
   Blog (Phase 2) — article + index styling. Rendered into the Page view's
   MainContent slot by PageController; themed via --theme-* so it adapts to the
   site's theme (light + dark). See BLOG_ENGINE_PLAN.md.
   ========================================================================== */
.sn-blog { max-width: 100%; }
/* Constrain to a comfortable reading measure and center, so the article doesn't span the full content
   column on wide templates/screens (a single post reads best ~70-80 chars wide). */
.sn-blog-single { max-width: 820px; margin-left: auto; margin-right: auto; }
.sn-blog-index { max-width: 1140px; margin-left: auto; margin-right: auto; }

/* ---- Single post ---- */
.sn-blog-header {
    margin-bottom: 1.5rem; padding-bottom: 1.25rem;
    border-bottom: 1px solid var(--theme-border, rgba(128, 128, 128, .25));
}
.sn-blog-title { font-size: clamp(1.9rem, 4vw, 2.6rem); line-height: 1.15; font-weight: 800; margin: 0 0 .4rem; }
.sn-blog-subtitle { font-size: 1.2rem; color: var(--theme-text-muted, #8a8a8a); margin: 0 0 .8rem; font-weight: 400; }
.sn-blog-byline { display: flex; flex-wrap: wrap; gap: .35rem 1rem; font-size: .9rem; color: var(--theme-text-muted, #8a8a8a); }
.sn-blog-byline > span + span::before { content: "·"; margin-right: 1rem; opacity: .55; }
.sn-blog-featured { margin: 0 0 1.5rem; }

/* Scale with the VIEWPORT, not just the column width. A portrait reel still (1080x1920) at width:100% is
   nearly twice the column's height — it filled the screen and pushed the article itself below the fold
   (owner, 2026-08-05). Capping the HEIGHT and letting the width follow keeps any aspect ratio readable
   without cropping anything away: landscape images are unchanged (they hit max-width first), tall ones stop
   at 70vh and centre. */
.sn-blog-featured img {
    display: block;
    width: auto; max-width: 100%;
    height: auto; max-height: 70vh;
    margin-inline: auto;
    border-radius: 14px;
}

/* Imported post: the featured image links to the ORIGINAL (BLOG_ENGINE_PLAN.md §10.7). It needs a visible
   affordance — an image that silently happens to be a link is one nobody clicks — hence the caption below
   it and a lift on hover/focus. :focus-visible is styled too, so it is reachable by keyboard. */
/* fit-content + auto margins so the link box HUGS the image. It anchors the play badge, and a full-width
   link would park that badge in the COLUMN's corner rather than the picture's — obvious the moment a
   portrait image is narrower than the column. */
.sn-blog-featured-link {
    position: relative;
    display: block; width: fit-content; max-width: 100%;
    margin-inline: auto;
    border-radius: 14px;
    transition: opacity .15s ease, transform .15s ease;
}

/* Video (reel) marker on an imported post's featured image — same glyph and same top-right corner as the
   import picker's tiles, so it reads as the same thing in both places. Larger here because this is a hero,
   not a 150px tile. pointer-events:none keeps the link underneath as the click target. */
.sn-blog-featured-play {
    position: absolute; top: .6rem; right: .6rem;
    display: flex; align-items: center; justify-content: center;
    width: 2rem; height: 2rem;
    border-radius: 999px;
    background: rgba(0, 0, 0, .55);
    color: #fff;
    pointer-events: none;
}
.sn-blog-featured-play .bi { font-size: 1.35rem; line-height: 1; margin-left: .08rem; /* optical centring */ }
.sn-blog-featured-link:hover img,
.sn-blog-featured-link:focus-visible img { opacity: .9; }
.sn-blog-featured-link:focus-visible { outline: 2px solid var(--theme-primary, #4a6fa5); outline-offset: 3px; }
.sn-blog-featured-src {
    margin-top: .5rem; font-size: .82rem; opacity: .72;
    color: var(--theme-body-color, inherit);
}
.sn-blog-body { font-size: 1.06rem; line-height: 1.8; }
.sn-blog-body > :first-child { margin-top: 0; }
.sn-blog-body img { max-width: 100%; height: auto; border-radius: 12px; margin: 1.25rem auto; display: block; }
.sn-blog-body h2 { margin-top: 1.9rem; }
.sn-blog-body h3 { margin-top: 1.4rem; }
.sn-blog-footer {
    margin-top: 2.5rem; padding-top: 1.25rem;
    border-top: 1px solid var(--theme-border, rgba(128, 128, 128, .25));
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem;
}
.sn-blog-back { font-weight: 600; text-decoration: none; color: var(--theme-primary, #4a6fa5); }
.sn-blog-back:hover { text-decoration: underline; }
.sn-blog-author { font-weight: 600; }

/* Social share row */
.sn-blog-share { display: inline-flex; align-items: center; gap: .55rem; }
.sn-blog-share-label { font-size: .9rem; color: var(--theme-text-muted, #8a8a8a); margin-right: .15rem; }
.sn-blog-share-link {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.1rem; height: 2.1rem; border-radius: 50%;
    color: var(--theme-text, inherit); text-decoration: none; font-size: 1.05rem;
    border: 1px solid var(--theme-border, rgba(128, 128, 128, .3));
    transition: background-color .15s ease, color .15s ease, border-color .15s ease, transform .12s ease;
}
.sn-blog-share-link:hover {
    background: var(--theme-primary, #4a6fa5); color: #fff;
    border-color: var(--theme-primary, #4a6fa5); transform: translateY(-2px);
}
.sn-blog-author a { color: inherit; text-decoration: none; }
.sn-blog-author a:hover { text-decoration: underline; }

/* ---- Category + tag chips (single post) + taxonomy/author headers ---- */
.sn-blog-taxonomy { margin-top: 2rem; display: flex; flex-direction: column; gap: .6rem; }
/* ── Embedded video card (editor toolbar → Insert video) ─────────────────────────────────────────
   Theme variables with fallbacks, no fixed colours: the same ruleset styles the block inside the
   TinyMCE iframe (which loads this file via themeEditorConfig) and on the published page, so what an
   author sees while writing is what readers get. CONTENT_EDITORS.md - one shared ruleset, no mirroring. */
.sn-video-card {
    margin: 1.5rem 0; padding: 0; border-radius: 12px; overflow: hidden;
    border: 1px solid var(--theme-border, rgba(128,128,128,.3));
    background: var(--theme-surface, var(--theme-bg, transparent));
}
/* aspect-ratio keeps the player 16:9 at every width without the old padding-top hack, so the card
   never reserves the wrong height on a phone. */
.sn-video-frame { position: relative; width: 100%; aspect-ratio: 16 / 9; background: #000; }
.sn-video-frame iframe {
    position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block;
}
.sn-video-meta { padding: .85rem 1rem; display: flex; flex-direction: column; gap: .25rem; }
.sn-video-title { font-weight: 600; line-height: 1.3; color: var(--theme-text, inherit); }
.sn-video-teaser { font-size: .92rem; color: var(--theme-text-muted, rgba(128,128,128,.9)); }
/* Unrecognised host: a labelled link rather than an iframe we cannot vouch for. */
.sn-video-link { padding: 1rem; margin: 0; }
.sn-video-link a { font-weight: 600; text-decoration: none; }
.sn-video-link a:hover { text-decoration: underline; }




/* ── Featured image dialog: preview left, options right ─────────────────────────────────────────
   Judging a picture needs room, so the preview gets the larger column and the fields sit beside it
   rather than under it. One column below 640px, where two would leave both too narrow. */
/* Near-fullscreen dialog: 80% of the viewport, so the picture is judged at something like the size it
   will be seen. Bootstrap's own max-width has to be overridden, and the height is set on the CONTENT so
   the preview can be told to fill what's left. */
.modal-dialog.sn-fi-dialog { max-width: 80vw; }
.sn-fi-dialog .modal-content { height: 80vh; }
.sn-fi-dialog .modal-body { overflow: auto; }
@media (max-width: 768px) {
    .modal-dialog.sn-fi-dialog { max-width: 96vw; }
    .sn-fi-dialog .modal-content { height: 90vh; }
}

/* Fill the body: the grid is the full height, and the preview takes whatever the fields don't. */
.sn-fi-dialog .sn-fi-grid { height: 100%; }
.sn-fi-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 1.25rem; }
@media (max-width: 640px) { .sn-fi-grid { grid-template-columns: 1fr; } }
.sn-fi-preview {
    position: relative; display: flex; align-items: center; justify-content: center;
    min-height: 200px; height: 100%; padding: .5rem; border-radius: 12px;
    background: rgba(0,0,0,.25);
    border: 1px solid var(--bs-border-color, rgba(128,128,128,.3));
}
/* contain, not cover: a portrait photo must be judged whole, not cropped to the box. */
.sn-fi-preview img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 8px; display: block; }
.sn-fi-none { display: flex; flex-direction: column; align-items: center; gap: .4rem; opacity: .55; font-size: .85rem; }
.sn-fi-none i { font-size: 2rem; }
.sn-fi-note {
    position: absolute; left: .6rem; bottom: .6rem;
    background: rgba(0,0,0,.72); color: #fff; border-radius: 999px;
    padding: .15rem .6rem; font-size: .72rem;
}
.sn-fi-fields { display: flex; flex-direction: column; min-width: 0; }

/* ── Featured image on the post editor ───────────────────────────────────────────────────────────
   The editor shows BodyHtml only, so without this a post with a picture looks like one without. Big
   enough to judge the image, small enough not to push the editor off screen. */
/* It is a BUTTON now (click to edit), so the browser's button chrome has to go. */
/* The thumbnail, as a button. It used to wrap the text too — see .sn-featured-block for why that had to
   change — so it is now sized to the picture and nothing else. */
.sn-editor-featured {
    display: block; flex: 0 0 auto;
    padding: .25rem; border-radius: 12px; text-align: left;
    background: transparent; border: 1px solid transparent; color: inherit; cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}
.sn-editor-featured:hover, .sn-editor-featured:focus-visible {
    border-color: var(--bs-border-color, rgba(128,128,128,.35));
    background: rgba(128,128,128,.08); outline: none;
}
/* No image yet: show the slot rather than hiding the control, so it can still be set. */
.sn-editor-featured-empty {
    width: 132px; height: 88px; flex: 0 0 auto; border-radius: 10px;
    border: 1px dashed var(--bs-border-color, rgba(128,128,128,.45));
    display: flex; align-items: center; justify-content: center;
    font-size: 1.6rem; opacity: .5;
}
.sn-editor-featured img {
    width: 132px; height: 88px; object-fit: cover; border-radius: 10px; flex: 0 0 auto;
    border: 1px solid var(--bs-border-color, rgba(128,128,128,.3));
}
/* "Show above the post", inline under the featured-image control.
   ⚠️ Sits OUTSIDE .sn-editor-featured (a <button>) — a checkbox inside a button is invalid HTML and its
   clicks would open the image modal instead of toggling. Indented to line up with the text beside the
   thumbnail, so it reads as part of that block rather than a stray control under the heading. */
/* Featured-image block: [thumbnail button] [heading · description · switch].
   ⚠️ The thumbnail is its own <button> and the text column is a SIBLING. It was all one button before,
   which is what made the switch impossible to place: a checkbox can't live inside a button, and anything
   after the button sits below it — and the button is as tall as the 88px thumbnail, so the switch always
   hung off the bottom. Two rounds of indenting and re-rowing were spent on that before the structure was
   the thing at fault. */
.sn-featured-block { display: flex; align-items: center; gap: 1rem; max-width: 46rem; }
.sn-featured-meta { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.sn-featured-meta > span { font-size: .82rem; opacity: .75; line-height: 1.4; }

/* The heading opens the same modal as the thumbnail, so the text stays clickable now that it is no longer
   inside the button. Styled as text, not as a control — it is a title that happens to be actionable. */
.sn-featured-heading {
    background: none; border: 0; padding: 0; text-align: left; color: inherit; cursor: pointer;
    font-size: .9rem; line-height: 1.3;
}
.sn-featured-heading:hover, .sn-featured-heading:focus-visible { text-decoration: underline; outline: none; }

.sn-featured-toggle {
    margin: .25rem 0 0; font-size: .85rem;
    display: flex; align-items: center; gap: .5rem; min-height: 1.5rem;
    /* Bootstrap's .form-check lays the input out with a negative margin against a matching left padding.
       Flex ignores the float that trick relies on, so both are zeroed and the gap does the spacing. */
    padding-left: 0;
}
.sn-featured-toggle .form-check-input { margin: 0; flex: 0 0 auto; cursor: pointer; }
.sn-featured-toggle .form-check-label { cursor: pointer; opacity: .9; }
.sn-featured-toggle-msg { font-size: .78rem; opacity: .75; }

/* ── Social-post import picker (BLOG_ENGINE_PLAN.md §10) ─────────────────────────────────────────
   A visual feed is chosen from visually: a tile grid to scan, then the selected post large with the
   rest as a filmstrip underneath, so moving along the feed doesn't mean going back to the grid. */
/* A native <optgroup> label is painted by the OS, not by our theme: on Windows it comes out as a white
   bar with near-invisible text in dark mode. Setting both colours on the element is what the browser
   actually honours here — inheriting from the <select> is not enough. Scoped to this picker rather than
   applied to every select in the app, so nothing else shifts. */
#npSource optgroup,
#npSource option {
    background-color: var(--bs-body-bg);
    color: var(--bs-body-color);
}
#npSource optgroup {
    font-style: normal;
    font-weight: 600;
    color: var(--bs-secondary-color, rgba(160,160,160,.9));
}

.sn-imp-grid {
    display: grid; gap: .75rem;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
/* The picker goes from one row of controls to a twelve-tile grid. Without a floor the dialog snaps
   between two wildly different heights every time you read a profile, which reads as a glitch. Holding
   the space means the skeletons below appear IN it rather than resizing the modal around them. */
.sn-imp-stage { min-height: 46vh; position: relative; }
/* The detail view renders OUTSIDE the stage, so the grid's reserved height has to be given back —
   otherwise opening a post leaves 46vh of nothing above it. */
.sn-imp-stage.is-collapsed { min-height: 0; }
/* Before anything has been read the stage is a large empty rectangle, which looks broken rather than
   ready. This fills it with the SHAPE of what is coming — an outlined grid — behind a plain instruction,
   so the space reads as "waiting for you" instead of "failed to load". */
.sn-imp-empty {
    position: absolute; inset: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: .5rem; text-align: center; padding: 1rem; pointer-events: none;
}
.sn-imp-empty-grid {
    position: absolute; inset: 0; z-index: 0;
    display: grid; gap: .75rem; opacity: .35;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    grid-auto-rows: minmax(0, 1fr);
    overflow: hidden;
}
.sn-imp-empty-grid > i {
    border: 1px dashed var(--bs-border-color, rgba(128,128,128,.35));
    border-radius: 10px;
}
.sn-imp-empty-msg { position: relative; z-index: 1; }
.sn-imp-empty-msg .bi { font-size: 1.75rem; display: block; margin-bottom: .35rem; }
/* Crawl feedback: tiles in the shape of the result, not a spinner. It says what is coming, fills the
   space the results will occupy, and a slow crawl looks like progress instead of a hang. */
.sn-imp-skel {
    border-radius: 10px; overflow: hidden;
    border: 1px solid var(--bs-border-color, rgba(128,128,128,.3));
    background: linear-gradient(100deg,
        rgba(128,128,128,.10) 30%, rgba(128,128,128,.22) 50%, rgba(128,128,128,.10) 70%);
    background-size: 300% 100%;
    animation: snImpShimmer 1.4s ease-in-out infinite;
    aspect-ratio: 3 / 4;
}
.sn-imp-skel:nth-child(2n) { animation-delay: .12s; }
.sn-imp-skel:nth-child(3n) { animation-delay: .24s; }
@keyframes snImpShimmer {
    0%   { background-position: 130% 0; }
    100% { background-position: -30% 0; }
}
/* Someone who has asked not to see motion still gets the placeholder, just still. */
@media (prefers-reduced-motion: reduce) {
    .sn-imp-skel { animation: none; }
}
.sn-imp-tile {
    position: relative; display: flex; flex-direction: column; gap: .4rem;
    padding: 0; border: 1px solid var(--bs-border-color, rgba(128,128,128,.3));
    border-radius: 10px; overflow: hidden; background: transparent;
    text-align: left; color: inherit; cursor: pointer;
    transition: border-color .15s ease, transform .12s ease;
}
.sn-imp-tile:hover, .sn-imp-tile:focus-visible {
    border-color: var(--bs-primary, #6f42c1); transform: translateY(-2px); outline: none;
}
.sn-imp-tile > img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block; }
.sn-imp-tile-cap {
    /* Bottom PADDING would sit inside the clipped box and let a sliver of the third line show through
       under the clamp — which is exactly how these tiles looked. Margin is outside the clip, so two
       lines means two lines. */
    padding: 0 .55rem; margin-bottom: .55rem;
    font-size: .8rem; line-height: 1.35; opacity: .85;
    /* Two lines, then ellipsis — tiles must stay the same height or the grid stops being scannable. */
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* A tile with NO picture is an EXPECTED state, not an error: social CDN thumbs are signed and expire, and
   the grid deliberately drops one that fails to load rather than showing a broken box. Without a stand-in
   the tile collapsed to a stray caption and the row lost its alignment — so keep the 1:1 block and put a
   glyph in it, which also keeps every tile the same height. */
.sn-imp-tile-noimg {
    width: 100%; aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--bs-body-color, #888) 8%, transparent);
    color: var(--bs-body-color, #888); opacity: .45; font-size: 1.6rem;
}
/* Already-imported tiles: dimmed only slightly now that an overlay carries the meaning — the picture is
   still what you scan by, so washing it out made the grid harder to read, not easier. */
.sn-imp-tile.is-imported { opacity: .82; }
/* Overlay sized to the image, which is a 1:1 square — a tick centred over the picture reads at a glance,
   where a small word in the corner had to be hunted for. */
.sn-imp-imported {
    position: absolute; top: 0; left: 0; width: 100%; aspect-ratio: 1 / 1; z-index: 1;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .35rem;
    background: rgba(0,0,0,.55);
    color: #fff; font-size: .72rem; letter-spacing: .02em;
    pointer-events: none;   /* the tile underneath is still the click target */
}
.sn-imp-imported .bi {
    font-size: 1.9rem; line-height: 1;
    color: #2ecc71;
    background: rgba(0,0,0,.35); border-radius: 999px;
}

/* Reel / video marker — TOP RIGHT, mirroring where Instagram's own grid puts it, so a familiar glyph
   lands in a familiar place. Shared by all three thumbnail renderers (tiles, preview, filmstrip).
   z-index 2 keeps it above the "Imported" scrim (z-index 1): a tile can be both, and the fact that it is a
   video shouldn't disappear the moment it has been imported. */
.sn-imp-reel {
    position: absolute; top: .35rem; right: .35rem; z-index: 2;
    display: flex; align-items: center; justify-content: center;
    width: 1.35rem; height: 1.35rem;
    border-radius: 999px;
    background: rgba(0, 0, 0, .55);
    color: #fff;
    pointer-events: none;   /* the tile underneath is still the click target */
}
.sn-imp-reel .bi { font-size: .95rem; line-height: 1; margin-left: .05rem; /* optical centring of a triangle */ }

/* The filmstrip cell is 74px, so the same badge at full size would swamp it. */
.sn-imp-frame .sn-imp-reel { top: .15rem; right: .15rem; width: 1.05rem; height: 1.05rem; }
.sn-imp-frame .sn-imp-reel .bi { font-size: .75rem; }

.sn-imp-preview { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 1.25rem; }
@media (max-width: 820px) { .sn-imp-preview { grid-template-columns: 1fr; } }
.sn-imp-preview-media {
    position: relative;   /* anchors the reel badge */
    border-radius: 12px; overflow: hidden;
    border: 1px solid var(--bs-border-color, rgba(128,128,128,.3));
    background: rgba(0,0,0,.25);
    display: flex; align-items: center; justify-content: center;
    max-height: 46vh;   /* the modal still has to fit a laptop screen */
}
.sn-imp-preview-media img { width: 100%; max-height: 46vh; object-fit: contain; display: block; }
.sn-imp-preview-body { display: flex; flex-direction: column; min-width: 0; }
.sn-imp-date { font-size: .82rem; opacity: .7; margin-bottom: .35rem; }
.sn-imp-caption { white-space: pre-wrap; line-height: 1.55; margin: 0 0 .75rem; max-height: 30vh; overflow: auto; }
.sn-imp-tags { display: flex; flex-wrap: wrap; gap: .3rem; margin-bottom: 1rem; }
.sn-imp-tag {
    font-size: .74rem; padding: .18rem .5rem; border-radius: 999px;
    border: 1px solid var(--bs-border-color, rgba(128,128,128,.35)); opacity: .85;
}
/* "AI crawler ready" pill on a social account row — a feed-less profile that IS importable because the
   account has an AI profile. Info-coloured rather than success-green: it states a capability, it is not a
   thing the user just did successfully. */
.sn-ai-ready {
    font-size: .7rem; font-weight: 600; letter-spacing: .01em;
    color: var(--bs-info, #0dcaf0);
    background: color-mix(in srgb, var(--bs-info, #0dcaf0) 15%, transparent);
    border: 1px solid color-mix(in srgb, var(--bs-info, #0dcaf0) 40%, transparent);
    padding: .15rem .5rem;
}
.sn-ai-ready .bi { font-size: .8em; }

/* ── Copy button on code blocks (sn-copy.js) ─────────────────────────────────────────────────────
   Injected, not written into each view. Sits over the top-right of the block, quiet until the block is
   hovered — but ALWAYS visible on keyboard focus, since a control that only appears on hover is a control
   a keyboard user cannot find. */
.sn-copy-wrap { position: relative; }
.sn-copy-btn {
    position: absolute; top: .4rem; right: .4rem; z-index: 2;
    display: inline-flex; align-items: center; justify-content: center;
    width: 2rem; height: 2rem; padding: 0;
    border: 1px solid rgba(255, 255, 255, .18); border-radius: 6px;
    background: rgba(255, 255, 255, .08); color: #e9ecef;
    opacity: 0; transition: opacity .12s ease, background-color .12s ease, color .12s ease;
    cursor: pointer;
}
.sn-copy-wrap:hover .sn-copy-btn,
.sn-copy-btn:focus-visible { opacity: 1; }
.sn-copy-btn:hover { background: rgba(255, 255, 255, .18); }
.sn-copy-btn:focus-visible { outline: 2px solid var(--bs-primary, #6f42c1); outline-offset: 2px; }
.sn-copy-btn.is-copied { color: #2ecc71; border-color: rgba(46, 204, 113, .5); opacity: 1; }
/* Touch has no hover: leave it showing rather than unreachable. */
@media (hover: none) { .sn-copy-btn { opacity: .85; } }
/* The button overlays the block's top-right — keep the first line clear of it. */
.sn-copy-wrap > pre { padding-right: 3rem; }

.sn-imp-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: auto; }

/* ── Importing: the post goes quiet, the button does not ──────────────────────────────────────────
   An import is a server round trip that ends in a full page navigation, so the seconds in between need
   to look deliberate. A scrim over the POST says "this is being taken", while the actions row is lifted
   ABOVE it so the control you just pressed stays crisp and legible — dimming the button along with
   everything else would hide the very thing reporting progress. */
.sn-imp-preview { position: relative; }
#npDetail.is-importing .sn-imp-preview::after {
    content: ""; position: absolute; inset: -.35rem; z-index: 1; border-radius: 12px;
    background: rgba(0, 0, 0, .38);
    backdrop-filter: blur(1.5px);
    pointer-events: none;   /* the scrim is a signal, not a click trap */
}
#npDetail.is-importing .sn-imp-actions { position: relative; z-index: 2; }
/* The filmstrip and the back link lead AWAY from an import that is already running. */
#npDetail.is-importing .sn-imp-film,
#npDetail.is-importing #npBackToGrid { opacity: .45; pointer-events: none; }

.sn-imp-film {
    display: flex; gap: .5rem; overflow-x: auto; padding: .85rem .1rem .25rem;
    margin-top: 1rem; border-top: 1px solid var(--bs-border-color, rgba(128,128,128,.25));
    scrollbar-width: thin;
}
.sn-imp-frame {
    position: relative;   /* anchors the reel badge */
    flex: 0 0 auto; width: 74px; height: 74px; padding: 0; overflow: hidden;
    border: 2px solid transparent; border-radius: 8px; background: rgba(0,0,0,.25); cursor: pointer;
    transition: border-color .15s ease, opacity .15s ease;
}
.sn-imp-frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Same placeholder element as the tiles, scaled for a 74px frame — the strip must keep its cell count and
   spacing whether or not a thumbnail loaded, or stepping through posts jumps around. */
.sn-imp-frame .sn-imp-tile-noimg { height: 100%; aspect-ratio: auto; font-size: 1.1rem; }
.sn-imp-frame:hover { border-color: var(--bs-border-color, rgba(128,128,128,.6)); }
.sn-imp-frame.is-current { border-color: var(--bs-primary, #6f42c1); }
.sn-imp-frame.is-imported { opacity: .55; }

/* ── Post-footer author box (BLOG_ENGINE_PLAN.md) ────────────────────────────────────────────────
   Profile left, "most read in the last N days" right. Colours come from theme variables only, so the
   box follows whatever skin the site wears.

   THIS BOX RENDERS INSIDE ARBITRARY USER-CHOSEN SKINS, so its internal layout is defended with
   !important on the few properties a theme can wreck. That is not belt-and-braces: a template rule
   centring images (`margin: … auto`) turned the avatar into a centred blob with the author's name shoved
   against the far edge, because auto margins on a flex item eat all the free space. Only layout
   primitives are pinned — colour, type and spacing stay themeable. */
.sn-author-box {
    margin: 2.5rem 0 0 !important;
    padding: 1.5rem;
    border-radius: 14px;
    border: 1px solid var(--theme-border, rgba(128,128,128,.3));
    background: var(--theme-surface, var(--theme-bg, transparent));
    display: grid !important;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.75rem 2.5rem;
    align-items: start;
    float: none !important;
}
/* Two columns only when there is a second column to fill. A lone profile stretched across the full
   width left the name marooned a screen-width from its own avatar. */
.sn-author-box.has-mostread { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); }
@media (max-width: 760px) {
    .sn-author-box, .sn-author-box.has-mostread { grid-template-columns: minmax(0, 1fr); padding: 1.15rem; }
}
.sn-author-profile, .sn-author-mostread { min-width: 0; }
/* Without a most-read column the profile shouldn't run the full content width — long bios read badly at
   900px and a short one looks stranded. */
.sn-author-box:not(.has-mostread) .sn-author-profile { max-width: 44rem; }

.sn-author-heading {
    text-transform: uppercase; letter-spacing: .09em; font-size: .74rem; font-weight: 700;
    color: var(--theme-text-muted, #8a8a8a);
    margin: 0 0 1rem !important; padding: 0;
}

.sn-author-identity {
    display: flex !important; align-items: center; gap: 1rem;
    justify-content: flex-start !important;
}
/* The avatar is a fixed square whatever the theme says about images. */
.sn-author-avatarwrap {
    position: relative; flex: 0 0 auto;
    width: 72px !important; height: 72px !important;
    margin: 0 !important; border-radius: 50%; overflow: hidden;
    border: 1px solid var(--theme-border, rgba(128,128,128,.3));
    display: block;
}
/* Initials sit UNDER the photo. When the src is wrong — a profile-page URL instead of an image file is
   the easy mistake — the img removes itself and this shows through, so a typo costs the photo rather
   than leaving a broken-image glyph in the middle of the page. */
.sn-author-initials {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 1.5rem; letter-spacing: .02em;
    color: var(--theme-primary, #4a6fa5);
    background: color-mix(in srgb, var(--theme-primary, #4a6fa5) 16%, transparent);
}
.sn-author-avatar {
    position: absolute; inset: 0;
    width: 100% !important; height: 100% !important;
    max-width: none !important; min-width: 0 !important;
    object-fit: cover; border-radius: 0 !important;
    margin: 0 !important; padding: 0; float: none !important; display: block !important;
}

.sn-author-namewrap { min-width: 0; }
.sn-author-name {
    display: block; font-size: 1.2rem; font-weight: 700; line-height: 1.25;
    color: var(--theme-text, inherit); text-decoration: none;
}
a.sn-author-name:hover { color: var(--theme-primary, #4a6fa5); text-decoration: underline; }

.sn-author-socials { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .55rem; }
.sn-author-social {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; border-radius: 50%; text-decoration: none; font-size: 1rem; line-height: 1;
    border: 1px solid var(--theme-border, rgba(128,128,128,.3));
    color: var(--theme-text, inherit);
    transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.sn-author-social:hover {
    background: var(--theme-primary, #4a6fa5); color: #fff; border-color: var(--theme-primary, #4a6fa5);
}

.sn-author-bio { margin: 1rem 0 0 !important; line-height: 1.6; color: var(--theme-text, inherit); }
.sn-author-site { margin: .65rem 0 0 !important; font-size: .9rem; }
.sn-author-site a {
    color: var(--theme-primary, #4a6fa5); text-decoration: none;
    display: inline-flex; align-items: center; gap: .3rem;
}
.sn-author-site a:hover { text-decoration: underline; }

.sn-author-toplist {
    margin: 0 !important; padding: 0 !important; list-style: none !important;
    counter-reset: sn-author-top;
}
.sn-author-topitem {
    counter-increment: sn-author-top; position: relative;
    margin: 0 !important; padding: .55rem 0 .55rem 1.9rem !important;
    border-bottom: 1px solid var(--theme-border, rgba(128,128,128,.2));
    list-style: none !important;
}
.sn-author-topitem:last-child { border-bottom: 0; }
.sn-author-topitem::before {
    content: counter(sn-author-top); position: absolute; left: 0; top: .55rem;
    font-weight: 700; font-size: .85rem; line-height: 1.5;
    color: var(--theme-primary, #4a6fa5);
}
.sn-author-topitem a { color: var(--theme-text, inherit); text-decoration: none; line-height: 1.4; }
.sn-author-topitem a:hover { color: var(--theme-primary, #4a6fa5); text-decoration: underline; }


.sn-blog-cats, .sn-blog-tags { display: flex; flex-wrap: wrap; gap: .4rem; }
.sn-blog-cat, .sn-blog-tag {
    display: inline-flex; align-items: center; text-decoration: none; line-height: 1;
    font-size: .82rem; padding: .35rem .6rem; border-radius: 999px;
    border: 1px solid var(--theme-border, rgba(128,128,128,.3)); color: var(--theme-text, inherit);
    transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.sn-blog-cat { font-weight: 600; }
.sn-blog-cat:hover, .sn-blog-tag:hover {
    background: var(--theme-primary, #4a6fa5); color: #fff; border-color: var(--theme-primary, #4a6fa5);
}
.sn-blog-tag { color: var(--theme-text-muted, #8a8a8a); }

.sn-blog-tax-header .sn-blog-tax-kind {
    text-transform: uppercase; letter-spacing: .08em; font-size: .78rem; font-weight: 700;
    color: var(--theme-primary, #4a6fa5); margin-bottom: .25rem;
}
.sn-blog-author-card { display: flex; align-items: center; gap: 1.1rem; }
.sn-blog-author-avatar { width: 84px; height: 84px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.sn-blog-author-meta { min-width: 0; }
.sn-blog-author-link { display: inline-block; margin-top: .35rem; font-weight: 600; text-decoration: none; color: var(--theme-primary, #4a6fa5); }
.sn-blog-author-link:hover { text-decoration: underline; }
.sn-blog-tax-back { margin-top: 1.5rem; }

/* ---- Comments ---- */
.sn-blog-comments { margin-top: 2.75rem; padding-top: 1.5rem; border-top: 1px solid var(--theme-border, rgba(128,128,128,.25)); }
.sn-comments-title { font-size: 1.4rem; font-weight: 800; margin: 0 0 1rem; }
.sn-comment-note { padding: .6rem .8rem; border-radius: .4rem; margin-bottom: 1rem; font-size: .95rem; }
.sn-comment-err { background: rgba(220,53,69,.12); border: 1px solid rgba(220,53,69,.4); }
/* Success note auto-dismisses: hold ~4s, then fade + slide up + collapse. Errors persist (read them). */
.sn-comment-ok {
    background: rgba(25,135,84,.15); border: 1px solid rgba(25,135,84,.4);
    overflow: hidden; animation: snCommentNoteHide .6s ease 4s forwards;
}
@keyframes snCommentNoteHide {
    0%   { opacity: 1; max-height: 8rem; }
    60%  { opacity: 0; max-height: 8rem; }
    100% { opacity: 0; max-height: 0; margin: 0; padding-top: 0; padding-bottom: 0; border-width: 0; }
}
@media (prefers-reduced-motion: reduce) { .sn-comment-ok { animation: none; } }
.sn-comment-list { list-style: none; padding: 0; margin: 0 0 2rem; display: flex; flex-direction: column; gap: 1rem; }
.sn-comment { padding: .9rem 1rem; border: 1px solid var(--theme-border, rgba(128,128,128,.2)); border-radius: .5rem; }
.sn-comment-head { display: flex; flex-wrap: wrap; gap: .35rem 1rem; align-items: baseline; margin-bottom: .35rem; }
.sn-comment-author { font-weight: 700; }
.sn-comment-author a { color: var(--theme-primary, #4a6fa5); text-decoration: none; }
.sn-comment-author a:hover { text-decoration: underline; }
.sn-comment-date { font-size: .82rem; color: var(--theme-text-muted, #8a8a8a); }
/* Per-comment Share / permalink action */
.sn-comment-share {
    font-size: .8rem; text-decoration: none; color: var(--theme-text-muted, #8a8a8a);
    display: inline-flex; align-items: center; gap: .15rem; margin-left: auto;
}
.sn-comment-head { align-items: center; }
.sn-comment-share:hover { color: var(--theme-primary, #4a6fa5); }
.sn-comment-share-done { color: var(--theme-success, #2e9e5b) !important; }
/* Highlight a comment when navigated to via its permalink (#comment-N). */
.sn-comment:target {
    outline: 2px solid var(--theme-primary, #4a6fa5);
    outline-offset: 2px;
    animation: snCommentTargetGlow 2.5s ease;
}
@keyframes snCommentTargetGlow {
    0% { background: color-mix(in srgb, var(--theme-primary, #4a6fa5) 22%, transparent); }
    100% { background: transparent; }
}
/* Comments badge in the post byline — jumps to the thread. */
.sn-blog-comments-link {
    display: inline-flex; align-items: center; gap: .3rem; text-decoration: none; font-weight: 600;
    color: var(--theme-primary, #4a6fa5);
}
.sn-blog-comments-link:hover { text-decoration: underline; }
.sn-comment-body { line-height: 1.6; overflow-wrap: break-word; }
.sn-comment-closed { color: var(--theme-text-muted, #8a8a8a); font-style: italic; }

/* Threaded replies (one level deep) */
.sn-comment-replies { list-style: none; margin: 1rem 0 0; padding: 0 0 0 1.25rem; border-left: 2px solid var(--theme-border, rgba(128,128,128,.25)); display: flex; flex-direction: column; gap: 1rem; }
.sn-comment-reply { background: color-mix(in srgb, var(--theme-text, #888) 5%, transparent); }
.sn-comment-reply-toggle { margin-top: .65rem; }
.sn-comment-reply-toggle > summary { cursor: pointer; display: inline-block; font-size: .85rem; font-weight: 600; color: var(--theme-primary, #4a6fa5); list-style: none; }
.sn-comment-reply-toggle > summary::-webkit-details-marker { display: none; }
.sn-comment-reply-toggle > summary::before { content: "↳ "; }
.sn-comment-reply-toggle[open] > summary { margin-bottom: .5rem; }
.sn-comment-reply-form { max-width: 560px; }

.sn-comment-form { max-width: 640px; }
.sn-comment-form-title { font-size: 1.15rem; font-weight: 700; margin: 0 0 .75rem; }
.sn-comment-row { display: grid; grid-template-columns: 1fr; gap: .75rem; }
@media (min-width: 600px) { .sn-comment-row { grid-template-columns: 1fr 1fr; } }
.sn-comment-field { display: flex; flex-direction: column; gap: .25rem; margin-bottom: .75rem; }
.sn-comment-field > span { font-size: .88rem; font-weight: 600; }
.sn-comment-field > span small { font-weight: 400; color: var(--theme-text-muted, #8a8a8a); }
.sn-comment-field input, .sn-comment-field textarea {
    padding: .55rem .7rem; border-radius: .4rem;
    border: 1px solid var(--theme-border, rgba(128,128,128,.35));
    background: var(--theme-surface, rgba(128,128,128,.08)); color: inherit; font: inherit;
}
.sn-comment-field input:focus, .sn-comment-field textarea:focus {
    outline: none; border-color: var(--theme-primary, #4a6fa5);
    box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--theme-primary, #4a6fa5) 25%, transparent);
}
.sn-comment-submit {
    margin-top: .25rem; padding: .6rem 1.4rem; border: none; border-radius: .4rem; cursor: pointer;
    font-weight: 600; color: #fff; background: var(--theme-primary, #4a6fa5);
    transition: filter .15s ease, transform .12s ease;
}
.sn-comment-submit:hover { filter: brightness(1.08); transform: translateY(-1px); }
/* Honeypot — visually hidden but present for bots. */
.sn-comment-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Comment Markdown rendering — code blocks + inline code (StackOverflow-style, non-runnable) */
.sn-comment-body pre.sn-code {
    background: var(--theme-code-bg, rgba(128,128,128,.14)); border: 1px solid var(--theme-border, rgba(128,128,128,.25));
    border-radius: .4rem; padding: .75rem .9rem; margin: .6rem 0; overflow-x: auto;
}
.sn-comment-body pre.sn-code code {
    font-family: SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; font-size: .88rem;
    white-space: pre; background: none; padding: 0; border: 0; color: inherit;
}
.sn-comment-body code.sn-inlinecode, .sn-comment-hint code {
    font-family: SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; font-size: .86em;
    background: var(--theme-code-bg, rgba(128,128,128,.16)); border-radius: .25rem; padding: .1rem .35rem;
}
.sn-comment-hint { font-size: .8rem; color: var(--theme-text-muted, #8a8a8a); margin: -.25rem 0 .75rem; }
.sn-comment-hint code { font-size: .78rem; }

/* ===== Hub homepage blog sections (Hub 2026 shell) ===== */
/* Latest from the network — trending post rows */
.sn-h-netposts { padding: 6px; display: flex; flex-direction: column; }
.sn-h-netpost { display: block; text-decoration: none; color: inherit; padding: 12px 14px 8px; border-radius: 10px; transition: background-color .14s ease; }
/* The row separator moved to the WRAPPER: tag chips are links, so they live OUTSIDE the card's anchor
   (nested anchors are invalid), which means the cards are no longer siblings of each other. */
.sn-h-netpost-wrap + .sn-h-netpost-wrap { border-top: 1px solid var(--h26-border, rgba(255,255,255,.07)); }
.sn-h-netpost:hover { background: var(--h26-surface-2, rgba(255,255,255,.04)); }
.sn-h-netpost-title { font-family: var(--h26-font-display, inherit); font-weight: 600; font-size: 15px; line-height: 1.35; margin-bottom: 5px; }
/* Teaser clamped to 2 lines — matches the "most-read" roll-up so the two sections read as one system. */
.sn-h-netpost-teaser { font-size: 13.5px; line-height: 1.55; margin: 0 0 7px; color: var(--h26-text-3, #8a8a8a);
                       display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* Chips align with the card's text, and sit under it rather than inside the link. */
/* ── Featured image on a "Latest from the network" row (2026-08-07) ──────────────────────────────────
   Owner: "if featured image is available for blog post, let's add it, but I don't think I want the box to
   grow, and I think I want it left justified."

   ⚠️ The thumbnail is STRETCHED to the row's existing height, not given one. The row is already as tall as
   its title + 2-line teaser + meta, so an image that takes that height can never make it taller — which is
   the "don't grow" requirement expressed in layout rather than in a magic pixel value that would stop being
   true the first time the text changed. Fixed WIDTH is what keeps the text column aligned down the list. */
.sn-h-netpost { display: flex; align-items: stretch; gap: 12px; }
.sn-h-netpost-text { flex: 1 1 auto; min-width: 0; }   /* min-width:0 or a long title stops the teaser ellipsis */
.sn-h-netpost-thumb {
    flex: 0 0 84px; overflow: hidden; border-radius: 8px;
    background: color-mix(in srgb, var(--h26-accent, #4a6fa5) 6%, rgba(0, 0, 0, .18));
}
/* `contain`: these are other people's featured images, logos included, and cropping one to fill an 84px
   box is the same mistake the post cards just had. The backdrop above is what the letterboxing sits on. */
.sn-h-netpost-thumb img { width: 100%; height: 100%; object-fit: contain; display: block; }

.sn-h-netpost-tags { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 14px 12px; }
/* Line the tags up with the TEXT column rather than the card edge, so a row with an image doesn't look
   like two separate things stacked. 14px anchor padding + 84px thumb + 12px gap. */
.sn-h-netpost--img .sn-h-netpost-tags { padding-left: 110px; }
.sn-h-netpost-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: 12.5px; color: var(--h26-text-3, #8a8a8a); }
.sn-h-netpost-fav { width: 15px; height: 15px; border-radius: 3px; flex: 0 0 auto; }

/* From the SocialNet blog — featured + teasers */
.sn-h-blogfeed { display: grid; grid-template-columns: 1.4fr 1fr; gap: 16px; align-items: start; }
@media (max-width: 820px) { .sn-h-blogfeed { grid-template-columns: 1fr; } }
.sn-h-blogfeat { display: block; text-decoration: none; color: inherit; overflow: hidden; padding: 0; }
.sn-h-blogfeat-thumb { aspect-ratio: 16/9; overflow: hidden; }
.sn-h-blogfeat-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sn-h-blogfeat-body { padding: 18px 20px; }
.sn-h-blogfeat-eyebrow { text-transform: uppercase; letter-spacing: .08em; font-size: 11px; font-weight: 700; color: var(--h26-accent, #8b5cf6); margin-bottom: 8px; }
.sn-h-blogfeat-title { font-family: var(--h26-font-display, inherit); font-weight: 700; font-size: 20px; line-height: 1.25; margin-bottom: 8px; }
.sn-h-blogfeat-excerpt { color: var(--h26-text-2, #aaa); font-size: 14px; line-height: 1.55; margin-bottom: 10px; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.sn-h-blogfeat-date, .sn-h-blogteaser-date { font-size: 12.5px; color: var(--h26-text-3, #8a8a8a); }
.sn-h-blogteasers { display: flex; flex-direction: column; gap: 10px; }
.sn-h-blogteaser { display: block; text-decoration: none; color: inherit; padding: 14px 16px; transition: background-color .14s ease; }
.sn-h-blogteaser:hover { background: var(--h26-surface-2, rgba(255,255,255,.04)); }
.sn-h-blogteaser-title { font-weight: 600; font-size: 14.5px; line-height: 1.35; margin-bottom: 5px; }
.sn-h-viewall { display: inline-flex; align-items: center; gap: 6px; text-decoration: none; font-weight: 600; font-size: 14px; color: var(--h26-accent, #8b5cf6); }
.sn-h-viewall:hover { text-decoration: underline; }

/* Comment editor toolbar (injected by sn-comments.js) */
.sn-comment-toolbar { display: flex; flex-wrap: wrap; gap: .25rem; margin-bottom: .4rem; }
.sn-ct-btn {
    min-width: 2rem; padding: .25rem .5rem; line-height: 1; cursor: pointer;
    border: 1px solid var(--theme-border, rgba(128,128,128,.35)); border-radius: .3rem;
    background: var(--theme-surface, rgba(128,128,128,.08)); color: inherit; font-size: .85rem;
    transition: background-color .12s ease, border-color .12s ease;
}
.sn-ct-btn:hover { background: var(--theme-primary, #4a6fa5); color: #fff; border-color: var(--theme-primary, #4a6fa5); }
.sn-ct-btn.sn-ct-code { font-family: SFMono-Regular, Menlo, Consolas, monospace; }

/* ---- Index / listing ---- */
.sn-blog-index-header { margin-bottom: 1.75rem; }
.sn-blog-index-title { font-size: clamp(1.8rem, 4vw, 2.4rem); font-weight: 800; margin: 0 0 .35rem; }
.sn-blog-index-desc { color: var(--theme-text-muted, #8a8a8a); font-size: 1.1rem; margin: 0; }
.sn-blog-cards { display: grid; grid-template-columns: 1fr; gap: 1.25rem; }
@media (min-width: 768px) { .sn-blog-cards { grid-template-columns: repeat(2, 1fr); } }

/* Latest-post HERO on the blog index: full-width feature above the grid of older posts. */
.sn-blog-featured-wrap { margin-bottom: 1.75rem; }
.sn-blog-eyebrow {
    display: inline-block; align-self: flex-start;
    font-size: .72rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
    color: var(--theme-primary, #4a6fa5);
    background: color-mix(in srgb, var(--theme-primary, #4a6fa5) 14%, transparent);
    padding: .18rem .6rem; border-radius: 999px; margin-bottom: .1rem;
}
.sn-blog-card--hero { background: color-mix(in srgb, var(--theme-primary, #4a6fa5) 8%, transparent); }
.sn-blog-card--hero .sn-blog-card-title { font-size: clamp(1.5rem, 3.2vw, 2.15rem); line-height: 1.2; }
.sn-blog-card--hero .sn-blog-card-excerpt { font-size: 1.05rem; }
.sn-blog-card--hero .sn-blog-card-body { padding: 1.5rem 1.6rem 1.7rem; gap: .6rem; }
/* Hero rendered as the WHOLE post inline (landing "show full post"). */
/* ── Hero rendered as the FULL post ──────────────────────────────────────────────────────────────────
   A teaser card is two columns (thumbnail beside an excerpt). A whole post in that right-hand column
   reads as a narrow ribbon of text with a tall empty gap where the thumbnail was — which is what
   "it's not filling" meant. Full mode is one column, the same shape the post's own page uses.

   The side-by-side rule below keys off `:has(.sn-blog-card-thumb)`, and in full mode the image is
   rendered as `.sn-blog-card-hero-img` INSIDE the body instead — so that rule already stops matching.
   These are the deliberate belt: the layout must not depend on a `:has()` near-miss. */
.sn-blog-card--full { display: block; }
.sn-blog-card--full .sn-blog-card-body { flex: 1 1 auto; width: 100%; justify-content: flex-start; }
/* Full width, natural aspect — NOT the card thumbnail's 16/9 crop, which would slice a portrait image. */
.sn-blog-card-hero-img { display: block; margin: .4rem 0 1rem; }
.sn-blog-card-hero-img img { display: block; width: 100%; height: auto; border-radius: 10px; }

.sn-blog-card-fullbody { margin: .3rem 0 .6rem; line-height: 1.7; }
.sn-blog-card-fullbody > :first-child { margin-top: 0; }
.sn-blog-card-fullbody img { max-width: 100%; height: auto; border-radius: 8px; }
.sn-blog-card-fullbody h2, .sn-blog-card-fullbody h3, .sn-blog-card-fullbody h4 { margin-top: 1.25rem; }
.sn-blog-card-fullbody pre { overflow-x: auto; }

/* ── Online-presence dot (SuperAdmin Users) ── */
.sn-presence-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 6px; vertical-align: middle; background: #6b7280; }
.sn-presence-dot.on { background: #22c55e; box-shadow: 0 0 0 3px rgba(34, 197, 94, .22); }
.sn-presence-dot.idle { background: #f59e0b; box-shadow: 0 0 0 3px rgba(245, 158, 11, .20); }
.sn-presence-dot.off { background: #9ca3af; opacity: .5; }

/* ── Header "online now" widget (SuperAdmin) — count + hover roster ── */
.sn-online-widget { position: relative; display: inline-block; }
/* A <button> since 2026-07-28 (was a hover-only span, unreachable by keyboard or touch) — hence the
   UA reset. Hover still opens the roster on desktop; click/Enter opens it everywhere. */
.sn-online-trigger { border: 0; background: transparent; font-family: inherit; cursor: pointer;
                     color: #cfd5e3; font-size: .85rem; white-space: nowrap; padding: .3rem .55rem; border-radius: 8px; }
.sn-online-widget:hover .sn-online-trigger { background: rgba(255, 255, 255, .07); }
.sn-online-trigger .bi-broadcast { color: #22c55e; }
.sn-online-trigger #snOnlineCount { font-weight: 700; color: #f1f3f9; }
.sn-online-pop { display: none; position: absolute; right: 0; top: 100%; z-index: 1050; min-width: 15rem; max-width: 22rem;
    background: #161a26; border: 1px solid rgba(255, 255, 255, .12); border-radius: 12px; padding: .5rem;
    box-shadow: 0 16px 40px -14px rgba(0, 0, 0, .75); }
.sn-online-widget:hover .sn-online-pop { display: block; }
/* …but not while the messaging panel is open — the two overlap, and the panel is the active surface. */
body.sn-msg-open .sn-online-widget:hover .sn-online-pop { display: none; }
.sn-online-pop-title { font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #8a93a9; padding: .15rem .5rem .4rem; }
.sn-online-list { list-style: none; margin: 0; padding: 0; max-height: 340px; overflow-y: auto; }
.sn-online-list li { display: flex; align-items: center; gap: .5rem; padding: .35rem .5rem; border-radius: 8px; color: #d7dbe6; font-size: .88rem; }
.sn-online-list li:hover { background: rgba(255, 255, 255, .05); }
.sn-online-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sn-online-ago { flex: 0 0 auto; color: #8a93a9; font-size: .78rem; white-space: nowrap; }
/* SuperAdmin marker in the presence roster — company users see WHO is platform staff. */
.sn-online-sa { display: inline-block; margin-left: .35rem; padding: 0 .3rem; border-radius: 4px;
                font-size: .62rem; font-weight: 700; letter-spacing: .04em; vertical-align: middle;
                color: #fee2e2; background: rgba(248, 113, 113, .18); border: 1px solid rgba(248, 113, 113, .45); }
/* Second line under the name (company) — SuperAdmin roster only. */
.sn-online-sub { display: block; font-size: .72rem; line-height: 1.2; color: #8a93a9;
                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Fixed width so "active" and "idle 1h 5m" occupy the same column — statuses line up down the roster. */
.sn-online-status { flex: 0 0 4.75rem; font-size: .78rem; white-space: nowrap; text-align: right; }
.sn-online-status.active { color: #22c55e; }
.sn-online-status.idle { color: #f59e0b; }
.sn-online-empty, .sn-online-more { color: #8a93a9; font-size: .82rem; padding: .35rem .5rem; }
/* "Message this person" on a roster row — revealed on hover/focus so the roster stays calm at rest.
   Your OWN row has no button, so an equally sized spacer holds the slot open; without it every other row's
   status text sits one button-width to the left of yours. */
.sn-online-msg, .sn-online-msg-spacer { flex: 0 0 1.6rem; height: 1.15rem; }
.sn-online-msg { border: 0; background: transparent; color: #8a93a9; padding: 0;
                 border-radius: 6px; line-height: 1; opacity: 0; transition: opacity .12s ease, color .12s ease; }
.sn-online-list li:hover .sn-online-msg, .sn-online-msg:focus-visible { opacity: 1; }
.sn-online-msg:hover { color: #f1f3f9; background: rgba(255, 255, 255, .10); }

/* ── Loading banner (REUSABLE) ──────────────────────────────────────────────────────────────────────
   A purple, animated "work in progress" bar that stands in for content still being fetched. Designed as
   a PLACEHOLDER, not a notice: put it in the slot the real content will occupy, so the content fills in
   exactly where it sat instead of appearing elsewhere while a banner disappears.

   Use it where a panel is slow enough that its absence reads as "there's nothing here" rather than
   "not loaded yet" — the case it was built for (owner liked the effect; reuse it on similar surfaces).

     <div class="sn-loading-banner" aria-live="polite">
       <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
       <span>Loading X<span class="sn-loading-banner-dots" aria-hidden="true"></span></span>
     </div>

   One per view is plenty — quieter inline spinners for everything else, or it stops meaning anything. */
.sn-loading-banner, .sn-ai-loading {
    display: flex; align-items: center; gap: .6rem;
    padding: .7rem 1rem; border-radius: 12px; text-decoration: none;
    color: #efe7ff; font-weight: 600;
    background: linear-gradient(100deg, rgba(139, 92, 246, .30), rgba(109, 40, 217, .18), rgba(139, 92, 246, .30));
    background-size: 200% 100%;
    border: 1px solid rgba(167, 139, 250, .55);
    animation: snLoadingSheen 2.4s linear infinite, snLoadingGlow 2.4s ease-in-out infinite;
}
.sn-loading-banner .spinner-border, .sn-ai-loading .spinner-border { color: #c4b5fd; }
/* Trailing "…" animating independently of the sheen, so it reads as active even mid-fade. */
.sn-loading-banner-dots::after, .sn-ai-loading-dots::after { content: ''; animation: snLoadingDots 1.4s steps(4, end) infinite; }
@keyframes snLoadingSheen { to { background-position: -200% 0; } }
@keyframes snLoadingGlow {
    0%, 100% { box-shadow: 0 0 0 0 rgba(139, 92, 246, .35); }
    50%      { box-shadow: 0 0 18px 2px rgba(139, 92, 246, .30); }
}
@keyframes snLoadingDots { 0% { content: ''; } 25% { content: '.'; } 50% { content: '..'; } 75% { content: '...'; } }
/* Reduced motion: keep the colour and the meaning, drop the movement. */
@media (prefers-reduced-motion: reduce) {
    .sn-loading-banner, .sn-ai-loading { animation: none; }
    .sn-loading-banner-dots::after, .sn-ai-loading-dots::after { animation: none; content: '…'; }
}

/* ── Header messaging widget (BACKEND_MESSAGING_PLAN.md M3) ── */
.sn-msg-widget { position: relative; display: inline-block; }
.sn-msg-btn { position: relative; border: 0; background: transparent; color: #cfd5e3; font-size: 1rem;
              padding: .3rem .55rem; border-radius: 8px; line-height: 1; }
.sn-msg-btn:hover, .sn-msg-btn[aria-expanded="true"] { background: rgba(255, 255, 255, .07); color: #f1f3f9; }
.sn-msg-badge { position: absolute; top: -2px; right: -2px; min-width: 1.05rem; padding: 0 .25rem;
                border-radius: 999px; background: #dc2626; color: #fff; font-size: .62rem; font-weight: 700;
                line-height: 1.05rem; text-align: center; }
/* Click-toggled (unlike the hover roster) — you need to be able to type in it. */
/* 21rem was a phone width shown on a desktop: bubbles wrapped every four or five words and the thread read
   as a column of fragments (owner: "on desktop it's kinda squished"). The drawer below overrides this
   entirely at ≤991.98px, so widening here is desktop-only. */
.sn-msg-panel { display: none; position: absolute; right: 0; top: 100%; z-index: 1050; width: 27rem; max-width: 92vw;
                background: #161a26; border: 1px solid rgba(255, 255, 255, .12); border-radius: 12px; padding: .65rem;
                box-shadow: 0 16px 40px -14px rgba(0, 0, 0, .75); }
.sn-msg-panel.show { display: block; }
.sn-msg-head { display: flex; align-items: center; gap: .4rem; padding: .15rem .35rem .45rem; }
.sn-msg-back { border: 0; background: transparent; color: #8a93a9; padding: 0 .25rem; border-radius: 6px; line-height: 1; }
.sn-msg-back:hover { color: #f1f3f9; background: rgba(255, 255, 255, .08); }
.sn-msg-title { font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #8a93a9;
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Image-launcher summary (sn-image-editor.js). A stored image's value is a guid filename with no spaces,
   which has no break opportunity — without this it runs straight out of its column and across the field
   beside it. `anywhere`, not `break-word`: break-word won't split a single unbroken token. */
.sn-img-launcher-summary { overflow-wrap: anywhere; word-break: break-word; min-width: 0; }

/* ── Media field button (sn-media-field.js) ──────────────────────────────────────────────────────────
   The Choose/Upload button appended to any input marked data-sn-media. Styled to sit flush against a
   .form-control on the dark admin screens rather than inheriting Bootstrap's light outline button, which
   reads as a hole punched in the field. */
.sn-media-field-btn {
    background: rgba(255, 255, 255, .05);
    border: 1px solid rgba(255, 255, 255, .14);
    border-left: 0;
    color: #a78bfa;
}
.sn-media-field-btn:hover, .sn-media-field-btn:focus-visible {
    background: rgba(255, 255, 255, .12);
    border-color: rgba(255, 255, 255, .22);
    color: #c4b5fd;
}

/* Title flexes so the New/Close controls are pushed to the right edge of the bar. */
.sn-msg-title { flex: 1 1 auto; }
.sn-msg-new { flex: 0 0 auto; margin-left: auto; border: 0; background: transparent; color: #8a93a9;
              padding: 0 .25rem; border-radius: 6px; line-height: 1; }
.sn-msg-new:hover { color: #f1f3f9; background: rgba(255, 255, 255, .08); }
.sn-msg-error { font-size: .8rem; padding: .4rem .6rem; margin: 0 .25rem .35rem; }

/* ── Compose a new conversation (M17) ────────────────────────────────────────────────────────────────
   One flow for both kinds: one person picked opens the direct thread, several create a group. */
.sn-msg-compose { padding: .35rem .25rem .5rem; border-bottom: 1px solid rgba(255, 255, 255, .10); margin-bottom: .35rem; }
.sn-msg-chips { display: flex; flex-wrap: wrap; gap: .3rem; }
.sn-msg-chips:not(:empty) { margin-bottom: .35rem; }
.sn-msg-chip-person {
    display: inline-flex; align-items: center; gap: .25rem;
    background: color-mix(in srgb, var(--theme-primary, #4a6fa5) 34%, #1b2233);
    border: 1px solid rgba(255, 255, 255, .16); border-radius: 999px;
    color: #e6e9f2; font-size: .78rem; padding: .12rem .2rem .12rem .5rem;
}
.sn-msg-chip-person-x { border: 0; background: transparent; color: #cfd5e3; line-height: 1;
                        padding: 0 .15rem; border-radius: 50%; font-size: .8rem; }
.sn-msg-chip-person-x:hover { background: rgba(220, 38, 38, .6); color: #fff; }
.sn-msg-tosearch, .sn-msg-subject {
    width: 100%; background: #0f1320; color: #e6e9f2; font-size: .85rem;
    border: 1px solid rgba(255, 255, 255, .14); border-radius: 8px; padding: .35rem .5rem;
}
.sn-msg-tosearch:focus, .sn-msg-subject:focus { outline: 0; border-color: var(--theme-primary, #4a6fa5); }
.sn-msg-toresults { list-style: none; margin: .3rem 0 0; padding: 0; max-height: 13rem; overflow-y: auto; }
.sn-msg-toresults:empty { display: none; }
.sn-msg-toresult { display: flex; align-items: center; gap: .35rem; padding: .35rem .5rem;
                   border-radius: 8px; cursor: pointer; }
.sn-msg-toresult:hover, .sn-msg-toresult.sel { background: rgba(255, 255, 255, .08); }
.sn-msg-toname { color: #e6e9f2; font-size: .85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Pushed to the far end and dimmed: it's the tie-breaker between two identical names, not a headline. */
.sn-msg-tocompany { margin-left: auto; flex: 0 1 auto; color: #8a93a9; font-size: .72rem;
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sn-msg-composebar { display: flex; align-items: center; gap: .35rem; margin-top: .4rem; }
.sn-msg-subject { flex: 1 1 auto; width: auto; }
.sn-msg-composego, .sn-msg-composecancel {
    flex: 0 0 auto; border: 0; border-radius: 999px; font-size: .74rem; font-weight: 600;
    padding: .28rem .85rem; line-height: 1.4;
}
.sn-msg-composego { background: var(--theme-primary, #4a6fa5); color: #fff; margin-left: auto; }
.sn-msg-composego:disabled { opacity: .5; }
.sn-msg-composecancel { background: rgba(255, 255, 255, .12); color: #cfd5e3; }
.sn-msg-composecancel:hover { background: rgba(255, 255, 255, .2); color: #fff; }
/* Group markers on an inbox row. */
.sn-msg-rowgroup { flex: 0 0 auto; color: #8a93a9; font-size: .8rem; }
.sn-msg-rowcount { flex: 0 0 auto; color: #8a93a9; font-size: .68rem; font-weight: 700;
                   background: rgba(255, 255, 255, .08); border-radius: 999px; padding: 0 .35rem; }
/* vh-relative so a tall desktop window actually gets used, capped so it never runs off a short one. */
.sn-msg-list { list-style: none; margin: 0; padding: 0; max-height: min(62vh, 30rem); overflow-y: auto; }
.sn-msg-empty { color: #8a93a9; font-size: .82rem; padding: .5rem; }
.sn-msg-rowbtn { display: block; width: 100%; text-align: left; border: 0; background: transparent;
                 color: #d7dbe6; padding: .4rem .5rem; border-radius: 8px; position: relative; }
.sn-msg-rowbtn:hover { background: rgba(255, 255, 255, .05); }
.sn-msg-rowtop { display: flex; align-items: center; gap: .35rem; }
.sn-msg-rowname { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .88rem; }
.sn-msg-row.unread .sn-msg-rowname { font-weight: 700; color: #f1f3f9; }
.sn-msg-rowtime { flex: 0 0 auto; color: #8a93a9; font-size: .72rem; }
.sn-msg-rowprev { display: block; color: #8a93a9; font-size: .78rem; line-height: 1.3; margin-top: .1rem;
                  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sn-msg-rowunread { position: absolute; right: .5rem; bottom: .4rem; min-width: 1.05rem; padding: 0 .25rem;
                    border-radius: 999px; background: #dc2626; color: #fff; font-size: .62rem; font-weight: 700;
                    line-height: 1.05rem; text-align: center; }
/* min-height so an empty/one-line thread still reads as a conversation area, not a broken strip. */
.sn-msg-thread { list-style: none; margin: 0; padding: .35rem .3rem; min-height: 7rem; max-height: min(58vh, 30rem);
                 overflow-y: auto; display: flex; flex-direction: column; gap: .55rem; }
.sn-msg-thread .sn-msg-empty { margin: auto; text-align: center; }
.sn-msg-bubble { max-width: 85%; align-self: flex-start; background: rgba(255, 255, 255, .06);
                 border-radius: 12px 12px 12px 4px; padding: .5rem .7rem; }
.sn-msg-bubble.mine { align-self: flex-end; background: color-mix(in srgb, var(--theme-primary, #4a6fa5) 40%, #1b2233);
                      border-radius: 12px 12px 4px 12px; }
/* .sn-msg-bubble is the positioning context for the tapback palette. */
.sn-msg-bubble { position: relative; }
/* Bubble controls (react + unsend) — inline on the meta line, revealed on hover/focus so the thread
   stays calm at rest. They RESERVE their space rather than appearing from nothing, so the bubble
   doesn't jump width as the pointer crosses it. */
.sn-msg-react, .sn-msg-unsend, .sn-msg-edit {
    flex: 0 0 auto; border: 0; background: transparent; color: #b9c0d0;
    padding: .05rem .25rem; border-radius: 6px; line-height: 1; font-size: .72rem;
    opacity: 0; transition: opacity .12s ease;
}
.sn-msg-react { margin-left: auto; }   /* pushes both controls to the far end of the meta row */
.sn-msg-bubble:hover .sn-msg-react, .sn-msg-react:focus-visible,
.sn-msg-bubble:hover .sn-msg-unsend, .sn-msg-unsend:focus-visible,
.sn-msg-bubble:hover .sn-msg-edit, .sn-msg-edit:focus-visible { opacity: 1; }
.sn-msg-react:hover, .sn-msg-edit:hover { color: #fff; background: rgba(255, 255, 255, .18); }
.sn-msg-unsend:hover { color: #fff; background: rgba(220, 38, 38, .55); }
/* Touch has no hover, so the controls would be permanently invisible — show them, dimmed. */
body.sn-docked .sn-msg-react, body.sn-docked .sn-msg-unsend, body.sn-docked .sn-msg-edit { opacity: .6; }

/* ── Reactions / tapbacks (M11) ─────────────────────────────────────────────────────────────────── */
/* The trigger itself is styled with the other bubble controls, above. This is the palette it opens —
   anchored to the BUBBLE, which is why .sn-msg-bubble is position:relative. */
.sn-msg-tapback {
    /* Just above the meta row — i.e. right where the trigger is, rather than above the whole bubble,
       which on a tall message put the palette a long way from the thing you clicked. Opening UPWARD
       (not below) keeps it clear of the composer for the last message in a thread. */
    position: absolute; bottom: 1.3rem; right: 0; z-index: 12;
    display: flex; gap: .1rem; padding: .2rem .25rem;
    background: #10141f; border: 1px solid rgba(255, 255, 255, .16); border-radius: 999px;
    box-shadow: 0 10px 26px -12px rgba(0, 0, 0, .85);
}
.sn-msg-tapback-btn { border: 0; background: transparent; font-size: 1.05rem; line-height: 1;
                      padding: .2rem .28rem; border-radius: 999px; }
.sn-msg-tapback-btn:hover { background: rgba(255, 255, 255, .16); transform: scale(1.15); }

/* Chips under the message. Yours is outlined — that's the cue that tapping it takes it back. */
.sn-msg-reactions { display: flex; flex-wrap: wrap; gap: .2rem; margin: .3rem 0 .1rem; }
.sn-msg-reaction {
    display: inline-flex; align-items: center; gap: .15rem;
    border: 1px solid rgba(255, 255, 255, .14); background: rgba(0, 0, 0, .28);
    color: #e6e9f2; font-size: .72rem; line-height: 1;
    padding: .12rem .35rem; border-radius: 999px;
}
.sn-msg-reaction:hover { background: rgba(255, 255, 255, .16); }
.sn-msg-reaction.mine { border-color: var(--theme-primary, #4a6fa5); background: color-mix(in srgb, var(--theme-primary, #4a6fa5) 32%, #10141f); }
.sn-msg-reaction-glyph { font-size: .85rem; line-height: 1; }
.sn-msg-reaction-n { font-weight: 700; font-size: .68rem; color: #cfd5e3; }
.sn-msg-body { color: #e6e9f2; font-size: .875rem; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; }
.sn-msg-body.deleted { color: #8a93a9; font-style: italic; }

/* ── Links inside a message (M18) ────────────────────────────────────────────────────────────────────
   ⚠️ The leading `body` and the element qualifier are deliberate. site.css carries
   `body[class*="theme-"]:not(.sn-mode-none) a:not(.sn-btn) { color: var(--theme-primary) }` at (0,3,1),
   which would paint these in the theme accent — unreadable on a "mine" bubble, whose background IS that
   accent. This is (0,3,2) so it wins outright rather than by source order. Same trap that made the blog
   card thumbnails a three-round fix; checked this time before shipping. */
body .sn-msg-bubble .sn-msg-body a.sn-msg-link {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
    overflow-wrap: anywhere;    /* a pasted URL has no spaces and would otherwise widen the bubble */
}
body .sn-msg-bubble .sn-msg-body a.sn-msg-link:hover { color: #fff; }

/* Copy control, styled like the bubble's other controls: reserved space, revealed on hover, so a thread
   full of links isn't a thread full of buttons. */
.sn-msg-linkcopy {
    border: 0; background: transparent; color: inherit;
    opacity: 0; transition: opacity .12s ease;
    padding: 0 .2rem; margin-left: .1rem; border-radius: 4px;
    font-size: .72rem; line-height: 1;
}
.sn-msg-bubble:hover .sn-msg-linkcopy, .sn-msg-linkcopy:focus-visible { opacity: .8; }
.sn-msg-linkcopy:hover { opacity: 1; background: rgba(255, 255, 255, .18); }
/* Touch has no hover — same rule the react/unsend controls need. */
body.sn-docked .sn-msg-linkcopy { opacity: .6; }
/* Doubles as the bubble's toolbar — the react/unsend controls sit here rather than floating over the
   message, where they used to overlap the text of anything short. */
.sn-msg-meta { color: #8a93a9; font-size: .68rem; margin-top: .15rem;
               display: flex; align-items: center; gap: .25rem; }
.sn-msg-metatext { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Attached image — capped so a big screenshot can't blow the panel out; click opens it full size. */
.sn-msg-img { display: block; max-width: 100%; max-height: 12rem; width: auto; height: auto;
              border-radius: 8px; margin-top: .25rem; object-fit: cover; }
.sn-msg-file { display: inline-block; margin-top: .25rem; font-size: .8rem; word-break: break-all; }
/* Drop target feedback while dragging an image over the panel. */
.sn-msg-panel.drag { outline: 2px dashed var(--theme-primary, #4a6fa5); outline-offset: -4px; }
.sn-msg-typing { padding: .1rem .5rem .25rem; font-size: .74rem; font-style: italic; color: #8a93a9; }
.sn-msg-composer { display: flex; align-items: flex-end; gap: .4rem; padding: .5rem .25rem .15rem;
                   border-top: 1px solid rgba(255, 255, 255, .10); margin-top: .45rem; }
/* Starts one line and grows with what you type (sn-autogrow). resize:none is deliberate — the height is
   the engine's, and a manual drag would be silently undone on the next keystroke. */
.sn-msg-input { flex: 1 1 auto; resize: none; background: #0f1320; color: #e6e9f2; font-size: .875rem;
                line-height: 1.45; border: 1px solid rgba(255, 255, 255, .14); border-radius: 8px;
                padding: .45rem .55rem; }
.sn-msg-input:focus { outline: 0; border-color: rgba(255, 255, 255, .3); }

/* ── Comment moderation table ───────────────────────────────────────────────────────────────────────
   Spam arrives with 130-character unbroken URLs and no-space payloads. A cell containing one has a
   minimum width equal to that string, so the table grew past the viewport and pushed the Approve/Spam/
   Trash buttons out of reach inside .table-responsive — the moderation screen defeated by the very spam
   it exists to clear (owner, 2026-07-28). `anywhere` is required, not `break-word`: break-word won't
   split a single unbroken token that is itself wider than the column. */
.sn-cmt-author, .sn-cmt-body { overflow-wrap: anywhere; word-break: break-word; }
.sn-cmt-author { max-width: 260px; min-width: 160px; }
.sn-cmt-body { max-width: 340px; min-width: 200px; }
/* The href stays full-length; only the visible label is shortened, so the link still works and the
   tooltip shows where it goes before you click something a spammer wrote. */
.sn-cmt-author a { display: inline-block; max-width: 100%; overflow-wrap: anywhere; }

/* ── Staged attachments (M13) ───────────────────────────────────────────────────────────────────────
   Pasted/dropped images wait here until you send, so a screenshot can be captioned and several can go
   in one message. Sits ABOVE the input row inside the composer (which is column-flex for this reason). */
.sn-msg-composer { flex-wrap: wrap; }
.sn-msg-tray { display: none; flex-basis: 100%; width: 100%; flex-wrap: wrap; gap: .35rem; padding: 0 .25rem .4rem; }
.sn-msg-tray.show { display: flex; }
.sn-msg-chip { position: relative; width: 3.25rem; height: 3.25rem; border-radius: 8px; overflow: hidden;
               border: 1px solid rgba(255, 255, 255, .18); background: #0f1320; flex: 0 0 auto; }
.sn-msg-chip img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sn-msg-chip-x { position: absolute; top: 1px; right: 1px; width: 1.15rem; height: 1.15rem; padding: 0;
                 display: flex; align-items: center; justify-content: center; border: 0; border-radius: 50%;
                 background: rgba(0, 0, 0, .68); color: #fff; font-size: .68rem; line-height: 1; }
.sn-msg-chip-x:hover { background: rgba(220, 38, 38, .9); }

/* ── Inline message editing (M12) ───────────────────────────────────────────────────────────────────
   Replaces the bubble's body in place, so the message keeps its position, reactions and pictures. */
/* A message being edited takes the FULL width of the thread. At 85% the editor re-wrapped the text at a
   different place than the message itself reads at, and a long message showed three lines of itself through
   a scrollbar nested inside the thread's scrollbar — the "squished" complaint at its worst. `width` as well
   as `max-width` so a short message doesn't give you a two-inch box to edit in. */
.sn-msg-bubble.sn-editing { max-width: 100%; width: 100%; }

.sn-msg-editbox { margin: .15rem 0 .3rem; }
/* Height is owned by sn-autogrow (data-sn-autogrow-max on the element); resize stays for manual override. */
.sn-msg-editinput { display: block; width: 100%; resize: vertical; background: #0f1320; color: #e6e9f2;
                    font-size: .875rem; line-height: 1.45; border: 1px solid rgba(255, 255, 255, .22);
                    border-radius: 8px; padding: .45rem .55rem; }
.sn-msg-editinput:focus { outline: 0; border-color: var(--theme-primary, #4a6fa5);
                          box-shadow: 0 0 0 2px color-mix(in srgb, var(--theme-primary, #4a6fa5) 35%, transparent); }
/* wrap: the hint is pushed to the far end by margin-left:auto and would otherwise squeeze the buttons
   rather than dropping below them on a narrow panel. */
.sn-msg-editbar { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem; margin-top: .4rem; }
.sn-msg-editsave, .sn-msg-editcancel { border: 0; border-radius: 999px; font-size: .74rem; font-weight: 600;
                                       padding: .28rem .85rem; line-height: 1.4; }
.sn-msg-editsave { background: var(--theme-primary, #4a6fa5); color: #fff; }
.sn-msg-editsave:hover { filter: brightness(1.12); }
.sn-msg-editcancel { background: rgba(255, 255, 255, .12); color: #cfd5e3; }
.sn-msg-editcancel:hover { background: rgba(255, 255, 255, .2); color: #fff; }
.sn-msg-edithint { font-size: .64rem; color: #8a93a9; margin-left: auto; white-space: nowrap; }
/* iOS zooms any focused input under 16px — same guard the composer needs in the drawer. */
body.sn-docked .sn-msg-editinput { font-size: 1rem; }

/* ── Emoji: picker + suggestion bar (sn-emoji.js) ───────────────────────────────────────────────────
   Both popups anchor to the composer, so it has to be a positioned ancestor. */
.sn-msg-composer { position: relative; }
.sn-msg-emoji { border: 0; background: transparent; color: #8a93a9; font-size: 1rem; line-height: 1;
                padding: .35rem .3rem; border-radius: 8px; flex: 0 0 auto; }
.sn-msg-emoji:hover, .sn-msg-emoji[aria-expanded="true"] { color: #f1f3f9; background: rgba(255, 255, 255, .08); }

/* Suggestion strip — sits directly above the composer while an emoticon/shortcode is in progress. */
.sn-emoji-bar { display: none; position: absolute; left: .25rem; right: .25rem; bottom: calc(100% + .25rem);
                z-index: 10; align-items: center; gap: .15rem; padding: .2rem .3rem;
                background: #10141f; border: 1px solid rgba(255, 255, 255, .14); border-radius: 10px;
                box-shadow: 0 10px 26px -12px rgba(0, 0, 0, .8); overflow-x: auto; }
.sn-emoji-bar.show { display: flex; }
.sn-emoji-sug { border: 0; background: transparent; font-size: 1.15rem; line-height: 1;
                padding: .2rem .3rem; border-radius: 8px; flex: 0 0 auto; }
.sn-emoji-sug:hover, .sn-emoji-sug.sel { background: rgba(255, 255, 255, .14); }
.sn-emoji-hint { margin-left: auto; padding-left: .4rem; font-size: .62rem; letter-spacing: .04em;
                 text-transform: uppercase; color: #6b7385; flex: 0 0 auto; }

/* Full picker. */
.sn-emoji-panel { display: none; position: absolute; left: .25rem; right: .25rem; bottom: calc(100% + .25rem);
                  z-index: 11; flex-direction: column; max-height: 17rem;
                  background: #10141f; border: 1px solid rgba(255, 255, 255, .14); border-radius: 12px;
                  box-shadow: 0 16px 40px -14px rgba(0, 0, 0, .8); overflow: hidden; }
.sn-emoji-panel.show { display: flex; }
.sn-emoji-search { padding: .4rem .4rem .3rem; }
.sn-emoji-q { width: 100%; background: #0f1320; color: #e6e9f2; font-size: .82rem;
              border: 1px solid rgba(255, 255, 255, .14); border-radius: 8px; padding: .3rem .5rem; }
.sn-emoji-q:focus { outline: 0; border-color: rgba(255, 255, 255, .3); }
.sn-emoji-tabs { display: flex; gap: .1rem; padding: 0 .35rem .25rem; overflow-x: auto; flex: 0 0 auto; }
.sn-emoji-tab { border: 0; background: transparent; font-size: .95rem; line-height: 1;
                padding: .25rem .35rem; border-radius: 8px; flex: 0 0 auto; opacity: .65; }
.sn-emoji-tab:hover { opacity: 1; background: rgba(255, 255, 255, .08); }
.sn-emoji-tab.on { opacity: 1; background: rgba(255, 255, 255, .14); }
.sn-emoji-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(2.1rem, 1fr));
                 gap: .1rem; padding: .25rem .35rem .45rem; overflow-y: auto; overscroll-behavior: contain; }
.sn-emoji-cell { border: 0; background: transparent; font-size: 1.25rem; line-height: 1;
                 aspect-ratio: 1; border-radius: 8px; display: flex; align-items: center; justify-content: center; }
.sn-emoji-cell:hover { background: rgba(255, 255, 255, .14); }
.sn-emoji-empty { grid-column: 1 / -1; padding: .9rem .4rem; text-align: center; font-size: .78rem; color: #8a93a9; }
/* Docked, the drawer is tall — let the picker use more of it, and keep taps comfortable. */
body.sn-docked .sn-emoji-panel { max-height: 45vh; }
body.sn-docked .sn-emoji-grid { grid-template-columns: repeat(auto-fill, minmax(2.5rem, 1fr)); }
body.sn-docked .sn-emoji-q { font-size: 1rem; }   /* iOS zoom-on-focus guard, as with the composer */
/* ── Image lightbox (message attachments) ───────────────────────────────────────────────────────────
   Above the messaging panel (1050) and Bootstrap modals (1055), because it opens FROM the panel. */
.sn-lightbox {
    display: none; position: fixed; inset: 0; z-index: 2000;
    background: rgba(0, 0, 0, .85);
    align-items: center; justify-content: center; padding: 2.5rem;
}
.sn-lightbox.show { display: flex; }
.sn-lightbox-img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 6px; }
.sn-lightbox-close {
    position: absolute; top: 1rem; right: 1rem; z-index: 1;
    width: 2.5rem; height: 2.5rem; border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, .25); background: rgba(0, 0, 0, .55);
    color: #fff; font-size: 1rem; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.sn-lightbox-close:hover { background: rgba(255, 255, 255, .18); border-color: rgba(255, 255, 255, .5); }
/* Freeze the page behind it so a scroll gesture doesn't move the thread underneath. */
body.sn-lightbox-open { overflow: hidden; }

/* ── Back-end navbar brand logo ─────────────────────────────────────────────────────────────────────
   The hub's primary image standing in for the "SocialNet" wordmark (owner, 2026-08-09).

   ⚠️ Sized HERE and nowhere else, for the same reason the Hub header logo is: `Sites.DefaultImage1Style`
   belongs to the LEGACY content rendering of that column (`float-right rounded-circle mx-3`,
   `max-height: 150px`) and applying it inline once dropped a 150px logo over the navigation.

   ⚠️ And deliberately NOT `Sites.BrandLogoHeight` either, which is a different question with the same
   units. That field is tuned against the Hub's public header, which GROWS to fit it (--h26-header-h
   derives from it). This is a fixed ~56px utility strip, so one number driving both would mean tuning the
   shop window quietly resizes the admin chrome — and clamping it here to something the bar can take would
   make the field mean two different things depending on where you looked.

   38px matches the Hub's default so the two agree at rest, and still clears the ~56px bar without
   changing its height (owner chose this over 30px, 2026-08-09). Height is not the real limit on a logo
   like ours anyway: a tagline set in small type inside the image needs ~60-70px to resolve — taller than
   the whole bar — so no value that fits here will render it. That wants a compact logo variant, not more
   pixels. `width: auto` keeps the logo's own proportions; `max-width` stops a very wide banner crowding
   out the links beside it. */
.navbar-brand .sn-nav-brand-img {
    display: block;
    max-height: 38px;
    width: auto;
    max-width: 260px;
    object-fit: contain;
}
/* The brand is a flex row only when it holds an image — as text it must stay a plain inline baseline box,
   or it stops aligning with the nav links next to it. A server-set class rather than `:has()`: the markup
   already knows which case it is, so there is nothing for the selector to work out. */
.navbar-brand.sn-nav-brand-has-img { display: flex; align-items: center; padding-top: 0; padding-bottom: 0; }

/* ── Legacy admin banner, switched off on the Hub's front end ───────────────────────────────────────
   The Hub 2026 header carries the owner's destinations now — Dashboard, My Sites, Inbox, My Account,
   and (P7) Admin / SuperAdmin / the active-company switcher — so the black bar above it is duplicate
   navigation on the one surface meant to look like a public site.

   ⚠️ NOT `display: none` on the <nav>. The presence and messaging widgets are rendered INSIDE it and
   hub-2026-shell.js moves those same nodes into the Hub header; `display:none` on an ancestor hides a
   descendant no matter where it is positioned, so until the move ran the Hub's own message button would
   have nothing visible behind it — and if the script ever failed, messaging would be gone rather than
   merely unstyled. Stripping the bar to nothing leaves the widgets renderable and the layout unaffected.

   `!important` on the background because .bg-dark is itself !important in Bootstrap. */
.navbar.sn-legacy-nav-off {
    background: none !important;
    padding: 0;
    min-height: 0;
    border: 0;
}
.navbar.sn-legacy-nav-off > .container { padding: 0; }

/* ── Mobile dock (notification-center rail) ─────────────────────────────────────────────────────────
   Below Bootstrap's lg breakpoint the presence + messaging widgets are MOVED out of .navbar-collapse
   (which is display:none while the hamburger is shut, so they were unreachable) into #snDock — a fixed
   rail of tabs on the right edge. The move is done in _Layout.cshtml; everything here is presentation.

   NOTE: no `transform` on .sn-dock, deliberately. A transformed element becomes the containing block
   for its position:fixed descendants, which would re-anchor the drawer and the roster popover to this
   ~46px box instead of the viewport. Hence `top: 38vh` rather than top:50% + translateY(-50%). */
.sn-dock { position: fixed; right: 0; top: 38vh; z-index: 1045; display: flex; flex-direction: column; gap: .4rem; }
.sn-dock:empty { display: none; }                          /* desktop: the widgets live in the navbar */
.sn-dock .sn-msg-widget, .sn-dock .sn-online-widget { display: block; margin: 0 !important; }
.sn-dock .sn-msg-widget { order: -1; }                     /* messages on top — it's the actionable one */
/* Both tabs share one silhouette: a pill flush to the right edge. ~53px — sized up from 46px on
   owner feedback after testing on a real phone; 44px is the bare minimum, not a comfortable one. */
.sn-dock .sn-msg-btn, .sn-dock .sn-online-trigger {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .05rem;
    width: 3.3rem; height: 3.3rem; padding: 0;
    background: #161a26; color: #e7ebf5;
    border: 1px solid rgba(255, 255, 255, .14); border-right: 0; border-radius: 12px 0 0 12px;
    box-shadow: -8px 0 22px -10px rgba(0, 0, 0, .85);
}
.sn-dock .sn-msg-btn { font-size: 1.3rem; }
.sn-dock .sn-online-trigger { font-size: 1.05rem; }
.sn-dock .sn-msg-btn:hover, .sn-dock .sn-msg-btn[aria-expanded="true"],
.sn-dock .sn-online-trigger:hover, .sn-dock .sn-online-trigger[aria-expanded="true"] {
    background: #1e2434; color: #fff;
}
.sn-dock .sn-online-word { display: none; }                /* rail shows the icon + the number only */
.sn-dock #snOnlineCount { font-size: .72rem; font-weight: 700; line-height: 1; }
/* Badge moves INBOARD: the rail is flush right, so an outboard badge would be off-screen. */
.sn-dock .sn-msg-badge { top: -4px; right: auto; left: -6px; }

/* Docked, the messaging panel becomes a full-height drawer rather than a 21rem popover. */
body.sn-docked .sn-msg-panel {
    position: fixed; inset: 0 0 0 auto; width: min(94vw, 25rem); max-width: none;
    border-radius: 0; border-top: 0; border-right: 0; border-bottom: 0;
    padding: .5rem .5rem calc(.5rem + env(safe-area-inset-bottom, 0px));
    box-shadow: -14px 0 40px -12px rgba(0, 0, 0, .8);
}
body.sn-docked .sn-msg-panel.show { display: flex; flex-direction: column; }
/* The list/thread stop being fixed-height boxes and just take the space that's left. */
body.sn-docked .sn-msg-list, body.sn-docked .sn-msg-thread { max-height: none; flex: 1 1 auto; overscroll-behavior: contain; }
/* iOS zooms the whole page when a focused input is under 16px. Only in the drawer — the desktop
   popover is fine at .85rem and shouldn't grow. */
body.sn-docked .sn-msg-input { font-size: 1rem; }
/* Close control: needed in the drawer (little left to tap "outside"), noise on desktop. */
.sn-msg-close { display: none; border: 0; background: transparent; color: #8a93a9; margin-left: auto;
                padding: 0 .25rem; border-radius: 6px; line-height: 1; }
.sn-msg-close:hover { color: #f1f3f9; background: rgba(255, 255, 255, .08); }
body.sn-docked .sn-msg-close { display: block; }

/* Roster popover, docked: opens inboard of the rail instead of below the navbar. */
body.sn-docked .sn-online-pop {
    position: fixed; right: 3.2rem; top: 50%; transform: translateY(-50%);
    min-width: 14rem; max-width: min(20rem, 84vw); max-height: 70vh; overflow-y: auto;
}
/* Click-to-open, for touch and keyboard. Desktop hover is unaffected (same declaration).
   ORDER AND SPECIFICITY BELOW ARE LOAD-BEARING — a touch device keeps :hover after a tap, so the
   docked "ignore hover" rule and the docked "is open" rule are deliberately the same weight (0,4,0)
   and resolved by source order. Making the open rule shorter lets hover:none win and the roster
   silently never opens on a phone. */
.sn-online-widget.sn-online-open .sn-online-pop { display: block; }
body.sn-docked .sn-online-widget:hover .sn-online-pop { display: none; }
body.sn-docked .sn-online-widget.sn-online-open .sn-online-pop { display: block; }
/* Last word: the messaging drawer is the active surface and the two would overlap. */
body.sn-msg-open .sn-online-widget.sn-online-open .sn-online-pop { display: none; }
.sn-msg-imglink { display: inline-block; cursor: zoom-in; }

/* Attach (paperclip) — the discoverable route to sending an image; paste/drop are shortcuts on top. */
.sn-msg-attach { flex: 0 0 auto; border: 0; background: transparent; color: #8a93a9;
                 padding: .35rem .4rem; border-radius: 8px; line-height: 1; }
.sn-msg-attach:hover { color: #f1f3f9; background: rgba(255, 255, 255, .10); }
.sn-msg-send { flex: 0 0 auto; border: 0; border-radius: 8px; padding: .35rem .55rem; line-height: 1;
               background: var(--theme-primary, #4a6fa5); color: #fff; }
.sn-msg-send:disabled { opacity: .55; }

/* ── Account dropdown in the top nav — dark theme (Bootstrap's default is white-on-light + clashes) ── */
.sn-user-menu {
    background: #161a26;
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 12px;
    padding: .35rem;
    box-shadow: 0 16px 40px -14px rgba(0, 0, 0, .75);
    min-width: 12rem;
}
.sn-user-menu .dropdown-header { color: #8a93a9; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; font-size: .72rem; }
.sn-user-menu .dropdown-item { color: #d7dbe6; border-radius: 8px; padding: .5rem .75rem; }
.sn-user-menu .dropdown-item:hover,
.sn-user-menu .dropdown-item:focus {
    background: color-mix(in srgb, var(--sn-primary, #7c3aed) 26%, transparent);
    color: #fff;
}
.sn-user-menu .dropdown-item:active { background: var(--sn-primary, #7c3aed); color: #fff; }
.sn-user-menu .dropdown-divider { border-top-color: rgba(255, 255, 255, .1); }
.sn-user-menu form { margin: 0; }
.sn-user-menu form .dropdown-item { width: 100%; text-align: left; background: transparent; border: 0; }

/* ── Glass auth pages (ForgotPassword / ResetPassword / confirmations) — matches the hub login modal ── */
.sn-gauth {
    /* Same accent tokens the Login page (.sn-auth-container) uses, so buttons/fields read app-purple. */
    --a-accent: #7c3aed;
    --a-accent-rgb: 124, 58, 237;
    --a-accent-2: #22d3ee;
    display: flex; align-items: center; justify-content: center; padding: 3rem 1rem;
}
.sn-gauth-card {
    width: 100%; max-width: 440px;
    background: rgba(18, 22, 34, .72);
    border: 1px solid rgba(255, 255, 255, .10);
    border-radius: 20px;
    padding: 1.75rem 1.75rem 1.5rem;
    -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
    box-shadow: 0 30px 70px -24px rgba(0, 0, 0, .8);
    color: #f1f3f9;
}
.sn-gauth-head { display: flex; align-items: center; gap: .9rem; margin-bottom: 1.35rem; }
.sn-gauth-icon {
    width: 52px; height: 52px; flex: 0 0 auto; border-radius: 14px;
    display: flex; align-items: center; justify-content: center; font-size: 1.5rem; color: #fff;
    background: linear-gradient(135deg, var(--a-accent), var(--a-accent-2));
    box-shadow: 0 8px 20px -8px rgba(var(--a-accent-rgb), .7);
}
.sn-gauth-ttl { font-size: 1.4rem; font-weight: 700; line-height: 1.15; }
.sn-gauth-sub { font-size: .9rem; color: #aab2c5; margin-top: .15rem; }
.sn-gauth-row { display: block; margin-bottom: 1rem; }
.sn-gauth-lbl { display: block; font-size: .85rem; font-weight: 600; color: #cfd5e3; margin-bottom: .35rem; }
.sn-gauth-field {
    display: flex; align-items: center; gap: .5rem;
    background: rgba(10, 12, 19, .7);
    border: 1px solid rgba(255, 255, 255, .12); border-radius: 12px; padding: 0 .75rem;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.sn-gauth-field:focus-within { border-color: var(--a-accent); box-shadow: 0 0 0 3px rgba(var(--a-accent-rgb), .25); }
.sn-gauth-field > i { color: #6f7891; font-size: 1rem; }
.sn-gauth-field input { flex: 1; min-width: 0; background: transparent; border: 0; outline: 0; color: #f1f3f9; padding: .72rem 0; font-size: .98rem; }
.sn-gauth-field input::placeholder { color: #6f7891; }
/* Kill the browser autofill's white/yellow background — paint the dark field color over it. */
.sn-gauth-field input:-webkit-autofill,
.sn-gauth-field input:-webkit-autofill:hover,
.sn-gauth-field input:-webkit-autofill:focus,
.sn-gauth-field input:-webkit-autofill:active {
    -webkit-text-fill-color: #f1f3f9;
    caret-color: #f1f3f9;
    -webkit-box-shadow: 0 0 0 1000px rgba(10, 12, 19, .96) inset;
    box-shadow: 0 0 0 1000px rgba(10, 12, 19, .96) inset;
    transition: background-color 6000s ease-out 0s;
}
.sn-gauth-eye { background: transparent; border: 0; color: #8a93a9; cursor: pointer; padding: .2rem; }
.sn-gauth-eye:hover { color: #cfd5e3; }
.sn-gauth-btn {
    width: 100%; display: flex; align-items: center; justify-content: center; gap: .5rem;
    border: 0; border-radius: 12px; padding: .82rem 1rem; margin-top: .3rem;
    font-size: 1rem; font-weight: 700; color: #fff; cursor: pointer;
    background: linear-gradient(180deg, rgba(255, 255, 255, .14), transparent), var(--a-accent);
    transition: filter .15s ease, transform .05s ease;
}
.sn-gauth-btn:hover { filter: brightness(1.08); color: #fff; text-decoration: none; }
.sn-gauth-btn:active { transform: translateY(1px); }
.sn-gauth-alt { text-align: center; margin-top: 1.15rem; font-size: .9rem; color: #aab2c5; }
.sn-gauth-alt a, .sn-gauth a.sn-gauth-link { color: #a78bfa; font-weight: 600; text-decoration: none; }
.sn-gauth-alt a:hover, .sn-gauth a.sn-gauth-link:hover { color: #c4b5fd; text-decoration: underline; }
.sn-gauth-alt a:hover { text-decoration: underline; }
.sn-gauth-msg { font-size: .95rem; color: #c2c9d8; line-height: 1.6; }
.sn-gauth-note { font-size: .85rem; color: #8a93a9; margin-top: .9rem; }
.sn-gauth .text-danger { color: #ff8a8a !important; }
.sn-gauth-success-icon { color: #22c55e; font-size: 2.4rem; }
@media (min-width: 768px) {
    /* With a featured image, lay the hero out side-by-side (image left, text right); text-only stays stacked. */
    .sn-blog-card--hero:has(.sn-blog-card-thumb) { flex-direction: row; align-items: stretch; }
    .sn-blog-card--hero .sn-blog-card-thumb { flex: 0 0 48%; aspect-ratio: auto; }
    .sn-blog-card--hero .sn-blog-card-thumb img { height: 100%; }
    .sn-blog-card--hero:has(.sn-blog-card-thumb) .sn-blog-card-body { flex: 1 1 52%; justify-content: center; padding: 1.9rem 2rem; }
}

/* "Popular across the network" roll-up on the hub blog index */
.sn-blog-network { margin-top: 2.75rem; padding-top: 1.75rem; border-top: 1px solid var(--theme-border, rgba(128, 128, 128, .25)); }
.sn-blog-network .sn-blog-index-header { margin-bottom: 1.1rem; }
.sn-blog-network .sn-blog-index-title { font-size: clamp(1.3rem, 3vw, 1.6rem); }
.sn-blog-source { align-items: center; }
.sn-blog-source-fav { width: 16px; height: 16px; border-radius: 3px; object-fit: contain; vertical-align: -3px; margin-right: .3rem; }
.sn-blog-source > span + span::before { content: "·"; margin-right: .5rem; opacity: .55; }
.sn-blog-card {
    display: flex; flex-direction: column; overflow: hidden;
    border: 1px solid var(--theme-border, rgba(128, 128, 128, .25));
    border-radius: 14px;
    background: color-mix(in srgb, var(--theme-primary, #4a6fa5) 5%, transparent);
    transition: transform .15s ease, box-shadow .15s ease;
}
.sn-blog-card:hover { transform: translateY(-3px); box-shadow: 0 .6rem 1.4rem rgba(0, 0, 0, .18); }
/* The BOX keeps a fixed 16/9 so a row of cards lines up; the IMAGE fits inside it whole.
   ⚠️ `contain`, not `cover`. Cover fills the box by cropping whatever doesn't fit, which is fine for a
   wide photo and destroys anything else — a logo used as a featured image had its bottom half sliced off
   (owner, 2026-08-07: "the featured image is not scaling/fitting in the box"). We can't tell a logo from a
   photo, and cutting the subject out of the picture is the worse failure of the two. The trade is bars
   beside a portrait image; the tinted backdrop is what stops those reading as a broken image.

   ⚠️ REVISED 2026-08-07 — back to `cover`, with an exception. Owner: "it's ok to fill the box if the image
   is bigger than the box, but don't scale it up if smaller, do center it like that for smaller images."
   `.is-natural` is added by sn-blog-cards.js AFTER measuring the image, because CSS cannot branch on an
   image's intrinsic size (`cover` upscales, `contain` never fills, `scale-down` fits rather than fills —
   there is no "cover but never enlarge"). `cover` stays the DEFAULT so the no-JS result is the filled look
   rather than a broken one; the class only ever relaxes the fill. */
.sn-blog-card-thumb { display: block; aspect-ratio: 16 / 9; overflow: hidden;
                      background: color-mix(in srgb, var(--theme-primary, #4a6fa5) 6%, rgba(0, 0, 0, .18)); }
.sn-blog-card-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* `none` = intrinsic size, centred by object-position's 50% default, clipped by the box's overflow. */
.sn-blog-card-thumb.is-natural img { object-fit: none; }
.sn-blog-card-body { padding: 1.1rem 1.2rem 1.25rem; display: flex; flex-direction: column; gap: .5rem; }
.sn-blog-card-title { font-size: 1.25rem; font-weight: 700; margin: 0; line-height: 1.25; }
.sn-blog-card-title a { color: inherit; text-decoration: none; }
.sn-blog-card-title a:hover { color: var(--theme-primary, #4a6fa5); }
.sn-blog-card-excerpt { margin: 0; color: var(--theme-text-muted, #8a8a8a); font-size: .97rem; line-height: 1.55; }
.sn-blog-readmore { margin-top: auto; font-weight: 600; text-decoration: none; color: var(--theme-primary, #4a6fa5); font-size: .92rem; }
.sn-blog-readmore:hover { text-decoration: underline; }
.sn-blog-empty { padding: 2rem 0; color: var(--theme-text-muted, #8a8a8a); }
.sn-blog-pager {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    margin-top: 2rem; padding-top: 1.25rem;
    border-top: 1px solid var(--theme-border, rgba(128, 128, 128, .25));
}
.sn-blog-pager a { font-weight: 600; text-decoration: none; color: var(--theme-primary, #4a6fa5); }
.sn-blog-pager a:hover { text-decoration: underline; }
.sn-blog-pager-info { color: var(--theme-text-muted, #8a8a8a); font-size: .9rem; }
/* Be explicit so MainContent body HTML / teaser headings can't fall back to a UA font. */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed),
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) h1, body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) h2, body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) h3,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) h4, body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) h5, body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) h6,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) p, body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) a, body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) li,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-site-title, body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content {
    font-family: var(--sn-font-sans);
}
/* Dark themes: re-point tokens at the theme's own surfaces (don't force light). */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed)[class*="theme-"] {
    --sk-card-bg: var(--theme-surface);
    --sk-card-shadow: 0 8px 28px rgba(0, 0, 0, .35);
    --sk-card-border: 1px solid var(--theme-border);
    --sk-divider: var(--theme-border);
    --sk-input-bg: rgba(0, 0, 0, .22);
}
/* Light page background only for System default; dark themes keep their gradient. */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed):not([class*="theme-"]) {
    background: var(--sk-page-bg);
}

/* Container rhythm — fill more of common modern viewports (1080p/1440p/4K) while
   still capping reasonably so article line-lengths don't blow past a readable measure
   on ultrawide displays. 1180px (the previous value) wasted ~720px on each side at 4K. */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) > .container {
    max-width: min(1600px, 95vw);
    padding-bottom: 40px;
}

/* --- Header band: drop bg-light, clean prominent title --------------------- */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) #sn-header {
    background: transparent !important;   /* override Bootstrap .bg-light !important */
    padding: 0 !important;                /* override .py-5 */
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-site-header-inner {
    padding: 36px 4px 8px;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-site-title {
    font-size: clamp(2rem, 3.2vw, 2.75rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--theme-text);
    margin: 0;
}

/* --- Sidebar cards: soft, rounded, shadowed (override Bootstrap .card) ----- */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .card,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .card-body {
    background: var(--sk-card-bg);
    border: var(--sk-card-border);
    border-radius: var(--sk-card-radius);
    box-shadow: var(--sk-card-shadow);
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .card.card-body {
    padding: 20px;
}

/* --- Search product cards: adopt the same theme-aware surface + text as .card, so they
   aren't blinding white (with invisible dark text) on dark themes. The product photo keeps a
   white plate — Amazon images are cut out on white — while the card body + text follow the
   theme. On Glassed Over the frosted block above gives the card the translucent blur. --- */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-product-card {
    background: var(--sk-card-bg);
    border: var(--sk-card-border);
    box-shadow: var(--sk-card-shadow);
    border-radius: var(--sk-card-radius);
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-product-details {
    border-top: 1px solid var(--sk-divider);
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-product-title,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-product-price {
    color: var(--theme-text);
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-product-brand,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-product-original-price {
    color: var(--theme-text-muted);
}
/* Product photos still want a white plate even on dark themes (keep image area opaque). */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-product-image {
    background: #fff;
}

/* Section headings (search / popular / keywords / nav) */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-search-heading,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-popular-sites-heading,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-keywords-heading,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-site-nav-heading {
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--theme-text-muted);
    margin: 0 0 12px;
    opacity: 1;
}

/* --- Network nav: pill hover ---------------------------------------------- */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-site-nav {
    padding: 4px 0;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-nav-link {
    display: block;
    padding: 7px 12px;
    border-radius: 9px;
    color: var(--theme-text);
    text-decoration: none;
    line-height: 1.35;
    transition: background .12s ease, color .12s ease;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-nav-link:hover {
    background: var(--sk-nav-hover);
    color: var(--theme-primary);
}

/* --- Main content + alt-content teasers -----------------------------------
   NOTE: every rule below is grouped with `.sn-editor-article` (the WYSIWYG editor body) so the editor
   renders the article IDENTICALLY to the live page-view from ONE source — no mirrored CSS in JS, no drift.
   `.sn-editor-article` never exists on the live site, so those selectors are inert there. */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content,
.sn-editor-article {
    font-size: 1.02rem;
    line-height: 1.7;
    /* Long words / inline base64 URLs / pasted URLs in AI-generated articles must wrap
       rather than overflow the column and break the Bootstrap grid. */
    overflow-wrap: break-word;
    word-wrap: break-word;
    max-width: 100%;
}

/* Responsive media inside user content — without `img { max-width: 100% }` a large
   AI-generated image (e.g. inline base64 from gpt-image-2 at 1200x675 px) will blow
   out the `<main class="col">` column and force the layout to stack or scroll. */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content img,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content video,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content iframe,
.sn-editor-article img,
.sn-editor-article video,
.sn-editor-article iframe {
    max-width: 100%;
    height: auto;
    display: block;
    margin: 1rem auto;
    border-radius: 12px;
}

/* ⚠️ …but a card THUMBNAIL is chrome, not user content, and the rule above was silently breaking it.
   `.sn-main-content` wraps the whole blog index, so every card image inherited `height: auto` — which
   defeats the fixed 16/9 frame entirely: the image renders at its natural size (a square logo becomes as
   tall as the card is wide) and `overflow: hidden` slices off whatever doesn't fit. `object-fit` never
   even came into it, because object-fit only does anything when the element's box differs from the
   image's intrinsic ratio, and `height: auto` makes them the same. That is why switching cover→contain
   changed nothing (owner, 2026-08-07: "I have rebuilt it twice and deployed to prod twice, still same
   thing" — the DevTools Styles pane is what found it).

   Specificity is deliberate: 4 classes beats the 3 above, so this cannot be resolved by source order and
   won't silently flip if the blocks are ever reordered. Margin and radius are reset too — those belong to
   an image sitting IN an article, not to one filling a frame that has its own corners. */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content .sn-blog-card-thumb img,
.sn-editor-article .sn-blog-card-thumb img {
    height: 100%;
    width: 100%;
    object-fit: cover;
    margin: 0;
    border-radius: 0;
}
/* The small-image exception has to be restated at THIS specificity too — the block above outranks the base
   rules, so `.is-natural` alone would lose to it and every thumbnail would stay on cover. */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content .sn-blog-card-thumb.is-natural img,
.sn-editor-article .sn-blog-card-thumb.is-natural img {
    object-fit: none;
}
/* Same trap, same fix: a fixed-size avatar must keep its height or the circle collapses to whatever
   aspect the uploaded file happens to have. It survives today only because the avatars are square. */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content .sn-blog-author-avatar,
.sn-editor-article .sn-blog-author-avatar {
    height: 84px;
    margin: 0;
    border-radius: 50%;
}

/* Typography inside the article body — without these, the browser-default h1/h2/h3
   sizes (especially the 2em default H1) compete with the page H1 and look oversized. */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content h1,
.sn-editor-article h1 {
    font-size: 1.875rem;
    line-height: 1.25;
    font-weight: 700;
    margin: 0.75em 0 0.5em;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content h2,
.sn-editor-article h2 {
    font-size: 1.5rem;
    line-height: 1.3;
    font-weight: 700;
    margin: 1.25em 0 0.5em;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content h3,
.sn-editor-article h3 {
    font-size: 1.25rem;
    line-height: 1.35;
    font-weight: 600;
    margin: 1em 0 0.4em;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content p,
.sn-editor-article p {
    margin: 0 0 1em;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content a,
.sn-editor-article a {
    color: var(--theme-primary);
    text-decoration: none;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-main-content a:hover,
.sn-editor-article a:hover {
    text-decoration: underline;
}

/* Sidebar nav link wrapping — long site-page titles in the narrow col-md-2
   sidebar must wrap fully rather than clip mid-line. We previously clamped to
   2 lines with ellipsis to keep the nav compact, but that hid the rest of
   long titles (e.g. "Capturing the Pulse: Trending Social Media Topics in
   2023" lost half its words). Owner pref: show the full title; readers click
   what they can read. Tight line-height keeps the nav from getting tall. */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) #sn-nav .sn-nav-link {
    display: block;
    line-height: 1.3;
    overflow-wrap: anywhere;
    word-break: break-word;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-alt-content {
    padding: 18px 0;
    border-bottom: 1px solid var(--sk-divider);
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-alt-content:last-child { border-bottom: 0; }
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-alt-content-title {
    margin: 0 0 6px;
    font-size: 1.15rem;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-alt-content-title a {
    color: var(--theme-text);
    font-weight: 700;
    text-decoration: none;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-alt-content-title a:hover { color: var(--theme-primary); }
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-alt-content-excerpt {
    color: var(--theme-text-muted);
    margin: 0 0 6px;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-alt-content-more a {
    color: var(--theme-primary);
    font-weight: 600;
    font-size: .9rem;
    text-decoration: none;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-alt-content-more a:hover { text-decoration: underline; }

/* --- Search box ----------------------------------------------------------- */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-search .form-control {
    background: var(--sk-input-bg);
    border: 1px solid transparent;
    border-radius: 10px 0 0 10px;
    color: var(--theme-text);
    padding: .6rem .9rem;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-search .form-control::placeholder { color: var(--theme-text-muted); }
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-search .form-control:focus {
    background: var(--sk-card-bg);
    border-color: var(--theme-primary);
    box-shadow: 0 0 0 .2rem rgba(var(--theme-primary-rgb), .2);
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-search .input-group .btn-primary {
    background: var(--theme-primary);
    border-color: var(--theme-primary);
    border-radius: 0 10px 10px 0;
    padding-inline: 1rem;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-search-recent-badge {
    background: rgba(var(--theme-primary-rgb), .10);
    border: 1px solid transparent;
    color: var(--theme-primary);
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-search-recent-badge:hover {
    background: rgba(var(--theme-primary-rgb), .18);
    color: var(--theme-primary);
}

/* --- Popular / featured sites --------------------------------------------- */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-popular-sites-list a {
    color: var(--theme-primary);
    text-decoration: none;
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-popular-sites-list a:hover { text-decoration: underline; }

/* --- Buttons (search "Back to Home", CTAs) -------------------------------- */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-btn-primary {
    background: var(--theme-primary);
    border: 1px solid var(--theme-primary);
    border-radius: 10px;
    color: #fff;   /* solid, flat — matches the search button (.sn-search .btn-primary) */
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-btn-primary:hover {
    background: color-mix(in srgb, var(--theme-primary) 88%, #000);
    border-color: color-mix(in srgb, var(--theme-primary) 88%, #000);
    color: #fff;
}

/* No-results panel as a soft card */
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-no-results {
    background: var(--sk-card-bg);
    border: var(--sk-card-border);
    border-radius: var(--sk-card-radius);
    box-shadow: var(--sk-card-shadow);
}

/* --- Footer band: drop bg-light --------------------------------------------*/
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) #sn-footer {
    background: transparent !important;   /* override .bg-light */
}
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed) .sn-site-footer {
    border-top: 1px solid var(--sk-divider);
    color: var(--theme-text-muted);
}

/* =============================================================================
   SNI: GLASSED OVER  —  glass treatment on top of the shared modern skin above.
   Same layout/skeleton/slots as SNI: Classic, but a frosted dark-glass look out of
   the box: dark gradient base + translucent cards with backdrop-blur, even on the
   System default (no theme). A selected theme still recolors it (Full mode); a glass
   theme just deepens the effect.
   ========================================================================== */
/* Base (System default, no theme): dark gradient + glass tokens so it reads as glass
   without a theme. A .theme-* class out-specifies this (more classes) and recolors. */
body.sn-skin-page.template-glassed:not([class*="theme-"]) {
    /* --sk-* (the modern skin's card tokens) */
    --sk-card-bg: rgba(255, 255, 255, 0.05);
    --sk-card-border: 1px solid rgba(255, 255, 255, 0.10);
    --sk-card-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
    --sk-divider: rgba(255, 255, 255, 0.10);
    --sk-input-bg: rgba(0, 0, 0, 0.22);
    --sk-nav-hover: rgba(255, 255, 255, 0.08);
    /* --theme-* (consumed DIRECTLY by modules: .sn-search, .sn-sidebar-product, etc.).
       Without these the modules fall back to the light :root values (white surfaces). */
    --theme-surface: rgba(255, 255, 255, 0.05);
    --theme-border: rgba(255, 255, 255, 0.10);
    --theme-text: #e8eaf2;
    --theme-text-muted: rgba(255, 255, 255, 0.72);
    --theme-primary: #a78bfa;
    --theme-primary-rgb: 167, 139, 250;
    --theme-secondary: #c4b5fd;
    --theme-secondary-rgb: 196, 181, 253;
    /* EXACT admin/HubSiteEdit backdrop (theme.css .backend-theme body). The #0f3460 endpoint
       is what makes the gradient visibly blue instead of flat near-black. */
    background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
    color: var(--theme-text);
    min-height: 100vh;
}

/* CRITICAL for the glass look on TALL pages: pin the gradient to the viewport (like the
   admin's .backend-theme body) so the full dark→blue range is always visible behind the
   content. Without this, a long article stretches the gradient over the whole document and
   the visible top shows only the dark start, so translucent panels read as dark/opaque.
   Applies to Glassed Over and any themed skin page (all carry a gradient). */
body.sn-skin-page.template-glassed,
body.sn-skin-page:is(.template-classic, .template-legacy, .template-glassed)[class*="theme-"],
body.sn-skin-page[class*="theme-"] {
    background-attachment: fixed;
}
/* Headings readable on the dark glass base regardless of theme presence (the front-end
   rule pins them to --sn-gray-900 dark otherwise). --theme-text adapts per theme. */
body.sn-skin-page.template-glassed h1,
body.sn-skin-page.template-glassed h2,
body.sn-skin-page.template-glassed h3,
body.sn-skin-page.template-glassed h4,
body.sn-skin-page.template-glassed h5,
body.sn-skin-page.template-glassed h6 {
    color: var(--theme-text);
}
/* Drop the skeleton's bg-light bands so the gradient shows through (theme path
   already handles this; this covers Glassed Over on the System default too). */
body.sn-skin-page.template-glassed .bg-light {
    background: transparent !important;
}
/* Always-frosted cards on Glassed Over (independent of the per-theme IsFrosted flag). */
body.sn-skin-page.template-glassed .card,
body.sn-skin-page.template-glassed .card-body,
body.sn-skin-page.template-glassed .sn-search,
body.sn-skin-page.template-glassed .sn-no-results {
    -webkit-backdrop-filter: blur(12px) saturate(140%);
    backdrop-filter: blur(12px) saturate(140%);
}

/* Glassed Over: dialed-down boxiness — only the left NAV becomes a frosted glass panel.
   The main article stays open over the gradient (no big central box) and the sidebar
   teasers keep the shared skin's hairline dividers (not individual cards). The search /
   ad slots are still .card (glass). Keeps the glass feel without boxing everything. */
body.sn-skin-page.template-glassed .sn-site-nav {
    background: var(--theme-surface);
    border: 1px solid var(--theme-border);
    border-radius: 16px;
    padding: 20px;
    -webkit-backdrop-filter: blur(12px) saturate(140%);
    backdrop-filter: blur(12px) saturate(140%);
}

/* Header: dim a site's own header background image with a dark scrim so the band reads
   as part of the dark glass instead of a clashing bright photo. Title stays readable
   (it already has a white color + shadow when a bg image is present). */
body.sn-skin-page.template-glassed .sn-site-header { position: relative; }
body.sn-skin-page.template-glassed .sn-site-header[style*="background-image"]::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(15, 15, 26, 0.55) 0%, rgba(15, 15, 26, 0.78) 100%);
    pointer-events: none;
}
body.sn-skin-page.template-glassed .sn-site-header-inner { position: relative; z-index: 1; }

/* ===========================================================================
   TEMPLATE-AWARE HEADER HARMONIZATION
   ---------------------------------------------------------------------------
   The canned .sn-header-* classes (Glass Bar / Hero / Centered / Minimal)
   still control header layout + content placement. These per-template rules
   layer the template's edge / glass / shadow language on top so a header
   doesn't look like a foreign component bolted onto the skin — the operator
   can pick any header style within any template and the visual treatment
   reads as one design system.
   =========================================================================== */

/* Glassed Over — frosted aesthetic carried into the header. Soft rounded
   bottom (mirrors the template's card chrome elsewhere), a low-opacity
   border to suggest a panel rather than a slab, and a gentle drop shadow to
   lift it above the gradient page background. overflow:hidden keeps the
   existing background-image scrim and the canned-style backdrop-filter
   honored inside the rounded clip. */
body.sn-skin-page.template-glassed .sn-site-header {
    border-radius: 0 0 18px 18px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-top: none;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28);
    overflow: hidden;
}
/* Glass Bar specifically WITHIN the Glassed template — stronger blur + a
   touch more saturation to give the bar that "real frosted glass" depth.
   Non-glassed templates keep the base Glass Bar treatment (less aggressive). */
body.sn-skin-page.template-glassed .sn-site-header.sn-header-glass-bar::before {
    -webkit-backdrop-filter: blur(16px) saturate(160%);
    backdrop-filter: blur(16px) saturate(160%);
}

/* Classic — clean editorial banner; just a hair of bottom-edge shadow so the
   header reads as separated from the content column without losing the flat
   newsprint feel the template is going for. */
body.sn-skin-page.template-classic .sn-site-header {
    box-shadow: 0 2px 0 rgba(0, 0, 0, 0.08);
}

/* Legacy stays bare on purpose — its design language is unadorned. No
   override here; the canned style's own rules are the whole treatment. */


/* ===========================================================================
   TEMPLATE THUMBNAIL FALLBACK
   ---------------------------------------------------------------------------
   Rendered on the Site Appearance template picker when a HubTemplate has no
   cached preview thumbnail yet (e.g. freshly-seeded templates on a new
   deploy). Reads as "intentional placeholder, preview coming" instead of
   "broken / black void". Themed gradient + subtle grid overlay matches the
   rest of the dark UI; bootstrap-icons layout-text-window suggests "this is
   a layout preview slot".
   =========================================================================== */
.sn-tpl-fallback {
    aspect-ratio: 16 / 10;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    position: relative;
    overflow: hidden;
    border-radius: 0.375rem 0.375rem 0 0;
    background: linear-gradient(135deg,
        var(--theme-surface,  rgba(99, 102, 241, 0.18)) 0%,
        var(--theme-primary,  rgba(168, 85, 247, 0.22)) 100%);
    color: rgba(255, 255, 255, 0.92);
}
/* Subtle grid pattern overlay — reads as "design canvas" without screaming.
   Pure CSS so it works regardless of image-asset deployment quirks. */
.sn-tpl-fallback::before {
    content: '';
    position: absolute; inset: 0;
    background-image:
        linear-gradient(to right,  rgba(255, 255, 255, 0.05) 1px, transparent 1px),
        linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
    background-size: 16px 16px;
    pointer-events: none;
}
.sn-tpl-fallback-icon {
    font-size: 1.75rem;
    color: rgba(255, 255, 255, 0.55);
    z-index: 1;
}
.sn-tpl-fallback-name {
    font-weight: 600;
    font-size: 0.85rem;
    text-align: center;
    padding: 0 8px;
    z-index: 1;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}
.sn-tpl-fallback-hint {
    font-size: 0.7rem;
    color: rgba(255, 255, 255, 0.55);
    z-index: 1;
}

/* =============================================================================
   Auth pages (Login / Register) — Hub 2026 dark glass skin.
   The standalone /Account pages shipped in a warm-gray light theme that jarred
   against the dark app shell + the Hub 2026 auth modal. This block reskins them
   dark. EVERYTHING is scoped under .sn-auth-container / .sn-auth-card, and
   .sn-form-control is used ONLY on these two pages, so nothing here leaks into
   the dashboard / admin forms.
   ============================================================================= */
.sn-auth-container {
    --a-accent: #7c3aed;
    --a-accent-2: #22d3ee;
    --a-surface: #10131c;
    --a-surface-2: #161a26;
    --a-field: rgba(0, 0, 0, .3);
    --a-line: rgba(255, 255, 255, .10);
    --a-line-2: rgba(255, 255, 255, .14);
    --a-text: #f1f3f9;
    --a-text-2: #aab2c5;
    --a-text-3: #6f7891;
}
.sn-auth-container .sn-auth-card {
    background: var(--a-surface);
    border: 1px solid var(--a-line-2);
    box-shadow: 0 30px 70px -24px rgba(0, 0, 0, .8);
}
.sn-auth-container .sn-auth-header {
    background: linear-gradient(135deg, rgba(124, 58, 237, .22) 0%, rgba(34, 211, 238, .12) 100%), var(--a-surface-2);
    border-bottom: 1px solid var(--a-line);
    color: var(--a-text);
}
.sn-auth-container .sn-auth-header h1 { color: #fff; }
.sn-auth-container .sn-auth-header h1 i { color: var(--a-accent-2); }
.sn-auth-container .sn-auth-header p { color: var(--a-text-2); opacity: 1; }
.sn-auth-container .sn-auth-body { background: var(--a-surface); }
.sn-auth-container .sn-auth-footer {
    background: var(--a-surface-2);
    border-top: 1px solid var(--a-line);
}
.sn-auth-container .sn-auth-footer p { color: var(--a-text-2); }
.sn-auth-container .sn-auth-footer a,
.sn-auth-container .sn-auth-body a:not(.sn-btn) { color: var(--a-accent-2); }
.sn-auth-container .sn-form-label { color: var(--a-text-2); }
.sn-auth-container .sn-form-label .text-muted,
.sn-auth-container .text-muted { color: var(--a-text-3) !important; }

/* Fields — both the custom .sn-form-control and the Bootstrap .form-control the
   password input-groups use. */
.sn-auth-container .sn-form-control,
.sn-auth-container .form-control {
    background-color: var(--a-field);
    border: 1px solid var(--a-line-2);
    color: var(--a-text);
}
.sn-auth-container .sn-form-control::placeholder,
.sn-auth-container .form-control::placeholder { color: var(--a-text-3); }
.sn-auth-container .sn-form-control:focus,
.sn-auth-container .form-control:focus {
    background-color: var(--a-field);
    border-color: var(--a-accent);
    box-shadow: 0 0 0 3px rgba(124, 58, 237, .25);
    color: var(--a-text);
}
.sn-auth-container input[readonly] { background-color: var(--a-surface-2) !important; color: var(--a-text-2); }
/* Chrome autofill repaint (same fix as the modal). */
.sn-auth-container .sn-form-control:-webkit-autofill,
.sn-auth-container .form-control:-webkit-autofill,
.sn-auth-container .sn-form-control:-webkit-autofill:focus,
.sn-auth-container .form-control:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--a-text);
    -webkit-box-shadow: 0 0 0 1000px #0d0f17 inset;
    box-shadow: 0 0 0 1000px #0d0f17 inset;
    caret-color: var(--a-text);
    transition: background-color 9999s ease-in-out 0s;
}

/* Primary button — Hub accent gradient. */
.sn-auth-container .sn-btn-primary {
    background: linear-gradient(180deg, rgba(255, 255, 255, .12) 0%, transparent 100%), var(--a-accent);
    color: #fff;
}
.sn-auth-container .sn-btn-primary:hover {
    background: linear-gradient(180deg, rgba(255, 255, 255, .18) 0%, transparent 100%), var(--a-accent);
}

/* Password-toggle + Generate/Copy buttons (Bootstrap outline/link variants). */
.sn-auth-container .input-group .btn-outline-secondary {
    background: rgba(255, 255, 255, .04);
    border: 1px solid var(--a-line-2);
    color: var(--a-text-2);
    border-radius: 0 .5rem .5rem 0;
}
.sn-auth-container .input-group .btn-outline-secondary:hover {
    background: rgba(255, 255, 255, .08);
    color: var(--a-text);
}
.sn-auth-container .btn-link { color: var(--a-accent-2); text-decoration: none; }
.sn-auth-container .btn-outline-primary { color: var(--a-accent-2); border-color: var(--a-line-2); }

/* Remember-me checkbox. */
.sn-auth-container .form-check-input { background-color: var(--a-field); border-color: var(--a-line-2); }
.sn-auth-container .form-check-input:checked { background-color: var(--a-accent); border-color: var(--a-accent); }
.sn-auth-container .form-check-label { color: var(--a-text-2); }

/* Bootstrap alerts -> dark tinted. */
.sn-auth-container .alert-info {
    background: rgba(34, 211, 238, .10); border: 1px solid rgba(34, 211, 238, .35); color: var(--a-accent-2);
}
.sn-auth-container .alert-success {
    background: rgba(34, 197, 94, .10); border: 1px solid rgba(34, 197, 94, .35); color: #4ade80;
}
.sn-auth-container .alert-danger {
    background: rgba(239, 68, 68, .10); border: 1px solid rgba(239, 68, 68, .38); color: #f87171;
}
.sn-auth-container hr { border-color: var(--a-line); opacity: 1; }
.sn-auth-container code { background: rgba(255, 255, 255, .06); color: var(--a-accent-2); padding: 2px 6px; border-radius: 6px; }

/* ============================================================================
   Blog link (Site Appearance → Sites.BlogLinkStyleId). Base = solid accent
   (SNI: Classic); the .template-glassed override turns it into frosted glass
   (SNI: Glassed Over). Five treatments: pill / floating orb / header ribbon (top
   bar) / icon-nav / bottom bar.
   ============================================================================ */
/* Skin templates (SNI: Classic / Glassed Over) render via the skin pipeline and
   give us no nav anchor, so the link is a FIXED overlay injected at <body> top.
   Corner treatments sit bottom-right; the bar treatments span full width (ribbon
   pinned to the top — the controller pushes page content down & stacks it below
   any admin chrome; bottom bar pinned to the bottom). */
.sn-bloglink { text-decoration: none; }
.sn-bloglink .sn-bloglink-ico { line-height: 1; }

/* 1) Accent nav pill — fixed bottom-right badge (default): bordered pill + the icon in a medallion,
   matching the "Visit the blog" badge in the bar treatments. */
.sn-bloglink-pill {
    position: fixed; right: 20px; bottom: 20px; z-index: 1030;
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .4rem .9rem .4rem .45rem; border-radius: 999px;
    background: var(--theme-primary, #6d5efc); color: #fff; font-weight: 700; font-size: .95rem;
    border: 1px solid rgba(255,255,255,.45);
    box-shadow: 0 4px 16px rgba(0,0,0,.28);
}
.sn-bloglink-pill .sn-bloglink-ico {
    display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px; border-radius: 50%;
    background: rgba(255,255,255,.22); font-size: .95rem;
}
.sn-bloglink-pill .sn-bloglink-label { padding-right: .25rem; }
.sn-bloglink-pill:hover { filter: brightness(1.08); color: #fff; transform: translateY(-1px); }

/* 2) Floating button — fixed bottom-right CIRCULAR icon orb (icon only) */
.sn-bloglink-fab {
    position: fixed; right: 22px; bottom: 22px; z-index: 1030;
    display: inline-flex; align-items: center; justify-content: center;
    width: 58px; height: 58px; border-radius: 50%;
    background: var(--theme-primary, #6d5efc); color: #fff; font-size: 1.5rem;
    box-shadow: 0 6px 22px rgba(0,0,0,.32);
}
.sn-bloglink-fab .sn-bloglink-label { display: none; }   /* orb is icon-only (title attr carries the label) */
.sn-bloglink-fab:hover { filter: brightness(1.08); transform: translateY(-2px) scale(1.04); color: #fff; }

/* 3) Header ribbon (top) + 5) Bottom bar — full-width bars teasing the latest post */
.sn-bloglink-ribbon, .sn-bloglink-bottombar {
    position: fixed; left: 0; right: 0; z-index: 1029;
    display: flex; align-items: center; gap: .5rem; flex-wrap: nowrap; overflow: hidden;
    padding: .3rem .9rem; background: var(--theme-primary, #6d5efc); color: #fff; font-size: .82rem;
}
.sn-bloglink-ribbon { top: 0; box-shadow: 0 2px 14px rgba(0,0,0,.2); }       /* controller offsets `top` below admin chrome */
.sn-bloglink-bottombar { bottom: 0; box-shadow: 0 -2px 14px rgba(0,0,0,.2); }
/* The bar is a container of links: a "Visit the blog" BADGE + arrow → blog index, and a "Latest: …"
   teaser → the post. Force colours with !important so the host template's own <a> styles (link colour /
   underline) don't leak into the injected bar. */
.sn-bloglink-ribbon a, .sn-bloglink-bottombar a { text-decoration: none !important; }

/* "Visit the blog" — a solid pill badge so it reads as a button, not body text */
.sn-bloglink-bar-main {
    display: inline-flex; align-items: center; gap: .35rem; flex: 0 0 auto;
    padding: .18rem .7rem; border-radius: 999px;
    background: rgba(255,255,255,.20); border: 1px solid rgba(255,255,255,.4);
    color: #fff !important; font-weight: 700; font-size: .8rem; white-space: nowrap;
}
.sn-bloglink-bar-main:hover { background: rgba(255,255,255,.32); }
.sn-bloglink-bar-main .sn-bloglink-ico { font-size: 1rem; }

/* "Latest: <headline>" teaser — legible, single line with ellipsis on overflow */
.sn-bloglink-rib-title {
    display: inline-flex; align-items: baseline; gap: .45rem; min-width: 0;
    color: #fff !important; font-size: .92rem;
}
.sn-bloglink-rib-kicker {
    flex: 0 0 auto; font-size: .66rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
    padding: .08rem .4rem; border-radius: 4px; background: rgba(0,0,0,.28); color: #fff;
}
.sn-bloglink-rib-headline { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sn-bloglink-rib-title:hover .sn-bloglink-rib-headline { text-decoration: underline; }

.sn-bloglink-bar-go { margin-left: auto; flex: 0 0 auto; color: #fff !important; font-size: 1.15rem; line-height: 1; }
.sn-bloglink-bar-go:hover { transform: translateX(2px); }

/* Slots epic S2 — PromoTeasers logo tiles: a compact FIXED height so a wide logo (contain-fit) stays a
   short banner instead of scaling tall with the column width. Lives here (a live static file), not the
   component's inline <style>, so it applies without recompiling the Razor view; targets the tile by its
   contain image via :has, so it works regardless of the tile's class. */
.sn-pt-thumb:has(> .sn-pt-img.contain) { aspect-ratio: auto !important; height: 118px !important; }
.sn-bloglink-arrow { font-weight: 700; }
.sn-bloglink-rib-label { font-weight: 700; }

/* 4) Icon nav link — fixed bottom-right, low-key dark chip with a "new" dot */
.sn-bloglink-iconnav {
    position: fixed; right: 20px; bottom: 20px; z-index: 1030;
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .45rem .75rem; border-radius: 10px;
    background: rgba(0,0,0,.4); color: #fff; font-weight: 600;
}
.sn-bloglink-iconnav:hover { color: #fff; background: rgba(0,0,0,.55); }
.sn-bloglink-iconnav .sn-bloglink-dot { width: 7px; height: 7px; border-radius: 50%; background: #ef4444; }

/* ---- Glassed Over override: frosted glass for all treatments ---- */
.template-glassed .sn-bloglink-pill,
.template-glassed .sn-bloglink-fab,
.template-glassed .sn-bloglink-iconnav,
.template-glassed .sn-bloglink-ribbon,
.template-glassed .sn-bloglink-bottombar {
    background: rgba(255,255,255,.12);
    -webkit-backdrop-filter: blur(12px) saturate(140%);
    backdrop-filter: blur(12px) saturate(140%);
    border: 1px solid rgba(255,255,255,.28);
    color: var(--theme-text, #fff);
    box-shadow: 0 8px 30px rgba(0,0,0,.25), inset 0 1px 0 rgba(255,255,255,.25);
}
.template-glassed .sn-bloglink-pill:hover,
.template-glassed .sn-bloglink-fab:hover,
.template-glassed .sn-bloglink-iconnav:hover,
.template-glassed .sn-bloglink-ribbon:hover,
.template-glassed .sn-bloglink-bottombar:hover {
    background: rgba(255,255,255,.18); filter: none; color: var(--theme-text, #fff);
    box-shadow: 0 10px 36px rgba(0,0,0,.32), inset 0 1px 0 rgba(255,255,255,.35), 0 0 18px var(--theme-primary, rgba(109,94,252,.5));
}
.template-glassed .sn-bloglink-iconnav .sn-bloglink-dot { box-shadow: 0 0 8px #ef4444; }

/* The full-width bars read too dark as plain frosted glass — brighten the frost and add an accent edge
   (bottom for the top ribbon, top for the bottom bar) so they feel intentional, not murky. */
.template-glassed .sn-bloglink-ribbon,
.template-glassed .sn-bloglink-bottombar { background: rgba(255,255,255,.17); }
.template-glassed .sn-bloglink-ribbon { border-bottom: 2px solid var(--theme-primary, #6d5efc); }
.template-glassed .sn-bloglink-bottombar { border-top: 2px solid var(--theme-primary, #6d5efc); }

/* ============================================================================
   AI-generated "buttons" — render/behave as BUTTONS, not links, in EVERY theme.
   The AI emits <a> styled with an inline background (the yellow CTA, etc.); as
   anchors they inherit link styling (blue text, underline + colour change on
   hover). Kill that link look everywhere site.css loads — all themes/templates,
   editor + live. Real Bootstrap `.btn` anchors use CLASSES (not inline
   backgrounds) so they're untouched. The per-button TEXT colour (dark-on-light /
   light-on-dark contrast) is set inline by the editor (sn-content-ai.js).
   ============================================================================ */
a[style*="background"] {
    text-decoration: none !important;
    cursor: pointer;
}
a[style*="background"]:hover,
a[style*="background"]:focus {
    text-decoration: none !important;     /* never underline a button */
    filter: brightness(0.94);             /* button-style feedback, NOT a link colour change */
}

/* Every link / button-styled element shows the pointer cursor on hover. */
a, [role="button"], button { cursor: pointer; }

/* ── Shared media picker (_MediaPickerModal.cshtml / sn-media-picker.js) ─────────────────────────
   A grid of square thumbnails. auto-fill + minmax means it reflows from a phone to a wide desktop
   without breakpoints, and the square aspect keeps the grid tidy whatever shape the pictures are. */
.sn-mp-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: .75rem;
}

.sn-mp-item {
    position: relative;
    display: block;
    padding: 0;
    width: 100%;
    aspect-ratio: 1 / 1;
    overflow: hidden;
    border: 2px solid var(--bs-border-color, rgba(255, 255, 255, .125));
    border-radius: .5rem;
    background: var(--bs-tertiary-bg, rgba(255, 255, 255, .04));
    cursor: pointer;
}

/* object-fit: contain, NOT cover — this is a chooser. Cropping a picture to fill a square is how you
   pick the wrong one: a portrait shot shows only its middle and looks like a different image. The
   letterboxing is the honest view of what you are selecting. */
/* The tile a just-uploaded file landed on, so a drop or an upload ends in something the author can SEE
   rather than a dialog that closed. Uses the theme's accent + a token-based glow, never a hardcoded colour,
   so it reads correctly on light and dark skins. Animates once and settles - a permanent pulse in a grid
   you are trying to read is noise. */
.sn-mp-item-new {
    border-color: var(--bs-primary, #6f42c1);
    box-shadow: 0 0 0 .25rem rgba(var(--bs-primary-rgb, 111, 66, 193), .35);
    animation: snMpNew .9s ease-out 1;
}

@keyframes snMpNew {
    0%   { box-shadow: 0 0 0 0 rgba(var(--bs-primary-rgb, 111, 66, 193), .55); }
    100% { box-shadow: 0 0 0 .25rem rgba(var(--bs-primary-rgb, 111, 66, 193), .35); }
}

/* Respect a reduced-motion preference - the border and glow still mark the tile without the animation. */
@media (prefers-reduced-motion: reduce) {
    .sn-mp-item-new { animation: none; }
}

.sn-mp-item img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

.sn-mp-item:hover { border-color: var(--bs-primary, #0d6efd); }

/* Focus must be at least as visible as hover — this grid is fully keyboard-navigable. */
.sn-mp-item:focus-visible {
    outline: 2px solid var(--bs-primary, #0d6efd);
    outline-offset: 2px;
    border-color: var(--bs-primary, #0d6efd);
}

.sn-mp-badge {
    position: absolute;
    left: .35rem;
    bottom: .35rem;
    padding: .1rem .4rem;
    font-size: .7rem;
    line-height: 1.4;
    border-radius: .25rem;
    background: rgba(0, 0, 0, .65);
    color: #fff;
}

/* ── Avatar picker control (blog authors) ────────────────────────────────────────────────────────
   The picture IS the control, and it is always present — an empty circle when there is no avatar, so a
   NEW author still has something to aim at. Circular because that is how the author box renders it: a
   cropping surprise belongs here, not on the published page. */
.sn-avatar-pick {
    position: relative;
    flex: 0 0 auto;
    width: 96px; height: 96px;
    padding: 0;
    border: 2px dashed var(--bs-border-color, rgba(128, 128, 128, .45));
    border-radius: 50%;
    overflow: hidden;
    background: var(--bs-tertiary-bg, rgba(255, 255, 255, .04));
    cursor: pointer;
    transition: border-color .15s ease;
}
.sn-avatar-pick:hover { border-color: var(--bs-primary, #6f42c1); }
.sn-avatar-pick:focus-visible {
    outline: 2px solid var(--bs-primary, #6f42c1);
    outline-offset: 2px;
    border-color: var(--bs-primary, #6f42c1);
}

/* ⚠️ :not([hidden]) on BOTH children, deliberately. A bare `display:` rule here is an AUTHOR rule and
   would beat the user-agent's `[hidden] { display: none }`, so toggling the hidden attribute in JS would
   silently stop working — the same class of trap as combining `hidden` with a Bootstrap d-* utility. */
.sn-avatar-pick img:not([hidden]) {
    display: block;
    width: 100%; height: 100%;
    object-fit: cover;       /* an avatar is a crop by definition — the circle is the frame */
}
/* Solid ring once it holds a real picture: dashed reads as "empty slot". */
.sn-avatar-pick:has(img:not([hidden])) { border-style: solid; }

.sn-avatar-pick-empty:not([hidden]) {
    display: flex; align-items: center; justify-content: center;
    width: 100%; height: 100%;
    color: var(--bs-secondary-color, rgba(255, 255, 255, .45));
}
.sn-avatar-pick-empty .bi { font-size: 2.4rem; line-height: 1; }

/* ── "Default author" callout (_BlogDefaultAuthorSummary) ────────────────────────────────────────
   Shipped as .form-text and the owner had to hunt for it: under a field's own help line, a third grey
   sentence reads as more help rather than as a statement about what will be PUBLISHED. Given a label,
   an icon and a left border so it registers as an answer, not a footnote. */
.sn-default-author {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    margin-top: .6rem;
    padding: .6rem .8rem;
    border-radius: .5rem;
    border: 1px solid var(--bs-border-color, rgba(128, 128, 128, .3));
    border-left: 3px solid var(--bs-primary, #6f42c1);
    background: var(--bs-tertiary-bg, rgba(255, 255, 255, .04));
    font-size: .95rem;
    line-height: 1.45;
}

.sn-default-author-icon { font-size: 1.05rem; line-height: 1.35; color: var(--bs-primary, #6f42c1); }

/* Not a heading element: it labels the statement beside it, and a real <h*> here would land in the middle
   of a form's heading outline for no navigational benefit. */
.sn-default-author-label {
    display: block;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    opacity: .7;
}

/* The chosen author has been deleted — publishing is blocked, so it reads as a problem, not a note. */
.sn-default-author.is-warning {
    border-left-color: var(--bs-warning, #ffc107);
    background: color-mix(in srgb, var(--bs-warning, #ffc107) 10%, transparent);
}
.sn-default-author.is-warning .sn-default-author-icon { color: var(--bs-warning, #ffc107); }

/* ── Drop zones (sn-dropzone.js) ────────────────────────────────────────────────────────────────────
   Anywhere you can drop a picture instead of hunting for it in a file dialog.

   The resting state is deliberately INVISIBLE: these sit on top of controls that already look like
   themselves (a thumbnail, a preview pane), and outlining them permanently would clutter the screen to
   advertise a shortcut. The affordance appears at the only moment it is useful — while a file is over
   the page. */
.sn-dropzone { position: relative; }
.sn-dropzone-over {
    outline: 2px dashed var(--bs-primary, #6f42c1);
    outline-offset: -4px;
    background: color-mix(in srgb, var(--bs-primary, #6f42c1) 10%, transparent);
    border-radius: .5rem;
}
/* The hint names what will happen, so a drop is never a guess. `pointer-events: none` matters: an overlay
   that swallowed the pointer would sit between the cursor and the drop target and cancel the drag. */
.sn-dropzone-over::after {
    content: attr(data-sn-drop-hint);
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    text-align: center; padding: .5rem;
    font-size: .85rem; font-weight: 600;
    color: var(--bs-body-color);
    background: color-mix(in srgb, var(--bs-body-bg, #111) 78%, transparent);
    border-radius: .5rem;
    pointer-events: none;
}
/* A non-image was dropped. Brief and red — silence would read as "the feature is broken" when the real
   answer is "that was a PDF". */
.sn-dropzone-reject {
    outline: 2px dashed var(--bs-danger, #dc3545);
    outline-offset: -4px;
    background: color-mix(in srgb, var(--bs-danger, #dc3545) 12%, transparent);
    border-radius: .5rem;
}
@media (prefers-reduced-motion: reduce) { .sn-dropzone, .sn-dropzone-over { transition: none; } }

/* ============================================================================================
   Insert/Edit Image dialog - our additions (sn-content-ai.js)
   ============================================================================================
   TinyMCE's image dialog is narrow and has no preview pane. We inject a thumbnail, a
   "Choose from library" button and a staged-file chip, which needs both more WIDTH (the default
   is cramped once a preview is in there) and a body that still SCROLLS so Alternative
   description / Width / Height stay reachable below the picture.

   Scoped to [data-sn-img-dialog] - set by wireImageDialogDrop() on the image dialog only - so no
   other TinyMCE dialog is resized. */

.tox .tox-dialog[data-sn-img-dialog="1"] {
    width: min(920px, 94vw);
    max-width: 94vw;
    max-height: 92vh;
}

/* The picture is the point of this dialog, so give it real room - but cap it against the viewport
   so a tall image cannot push the buttons off a short screen. */
.sn-img-dialog-preview {
    margin-top: 10px;
    border-radius: 6px;
    padding: 6px;
    text-align: center;
    background: rgba(0, 0, 0, .18);
}

.sn-img-dialog-preview img {
    display: inline-block;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 340px;   /* scale down to fit - never crop */
}

/* The friendly face of a staged file. Laid OVER the Source input (whose value stays the real blob
   URI, because that is what Save reads) - so the author sees "baobabs.jpg - not uploaded yet"
   instead of blob:https://localhost:62732/758c5558-… */
/* ⚠️ Geometry is set in JS from the input's own offset box, NOT `inset: 0` on the parent. The Source
   row is a horizontal stack holding the input AND the browse button, so stretching to the parent would
   cover browse and leave no way to choose a different file. */
.sn-img-staged {
    position: absolute;
    border: 0;
    border-radius: 3px;
    padding: 0 10px;
    text-align: left;
    font: inherit;
    cursor: text;
    background: var(--bs-tertiary-bg, #2b3a4a);
    color: var(--bs-body-color, #e9ecef);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sn-img-staged:hover,
.sn-img-staged:focus-visible {
    outline: 2px solid var(--bs-primary, #6f42c1);
    outline-offset: -2px;
}

/* Sits just under Source as a quiet secondary action, not a row-hogging button. */
.sn-img-lib-btn {
    margin-top: 4px;
    padding: 2px 0;
    font-size: .8125rem;
    text-decoration: underline;
}

.sn-img-staged-warn {
    margin-top: 8px;
    padding: 10px 12px;
    border-radius: 6px;
    border: 1px solid var(--bs-warning, #ffc107);
    background: rgba(var(--bs-warning-rgb, 255, 193, 7), .12);
    font-size: .875rem;
}

.sn-img-staged-warn-actions {
    display: flex;
    gap: 8px;
    margin-top: 8px;
    flex-wrap: wrap;
}
