/* File: /assets/css/portal.css
   Module: CartHacker Dashboard - Secure Access deck, Learning Center & account hub
   Light theme first, dark overrides at the bottom (html[data-theme="dark"]).
   Surfaces mirror the site system: page var(--ch-bg-main), cards #FFFFFF.
   Emphasis panels (onboarding, the QR slots upsell) are light cards in light
   mode and the #0F172A / #1E293B DevSecOps panel in dark only. Since
   2026-10-04 no panel is dark in light mode (Adrian): a light page carries
   emphasis with colour, wash and shadow. Devices (the QR editor's handset)
   and code stay dark in both themes because that is what they are. */

/* ==========================================================================
   1. LAYOUT SHELL
   ========================================================================== */
.ch-portal {
    max-width: 1200px;
    margin: 0 auto;
    padding: 2.5rem 1.5rem 4rem;
}

.ch-portal-kicker {
    display: inline-block;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--ch-cta);
    margin-bottom: 0.6rem;
}

/* Global page alert (OAuth errors, welcome) */
.ch-portal-alert {
    max-width: 960px;
    margin: 0 auto 1.5rem;
    padding: 0.85rem 1.1rem;
    border-radius: 10px;
    font-size: 0.9rem;
    font-weight: 600;
    color: #B91C1C;
    background-color: rgba(239, 68, 68, 0.08);
    border: 1px solid rgba(239, 68, 68, 0.35);
    animation: ch-fade-up 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.ch-portal-alert.is-success {
    color: #047857;
    background-color: rgba(16, 185, 129, 0.08);
    border-color: rgba(16, 185, 129, 0.35);
}

/* ==========================================================================
   2. AUTH SCREEN (split deck)
   ========================================================================== */
.ch-auth-shell {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    max-width: 960px;
    margin: 0 auto;
    border: 1px solid var(--ch-border);
    border-radius: 16px;
    overflow: hidden;
    background-color: #FFFFFF;
    box-shadow: 0 20px 50px -20px rgba(15, 23, 42, 0.18);
    animation: ch-fade-up 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* --- 2.1 Dark briefing panel --- */
.ch-auth-side {
    position: relative;
    overflow: hidden;
    background-color: #0F172A;
    padding: 2.75rem 2.25rem;
    display: flex;
}

.ch-auth-side::before {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse 75% 55% at 15% -10%, rgba(16, 185, 129, 0.18), transparent 70%);
    pointer-events: none;
}

/* Slow ambient sweep - the panel feels alive without being loud */
.ch-auth-side::after {
    content: '';
    position: absolute;
    left: -60%;
    top: 0;
    width: 55%;
    height: 100%;
    background: linear-gradient(105deg, transparent 0%, rgba(148, 163, 184, 0.05) 45%, rgba(16, 185, 129, 0.07) 50%, transparent 100%);
    animation: ch-sweep 7s ease-in-out infinite;
    pointer-events: none;
}

.ch-auth-side-inner {
    position: relative;
    display: flex;
    flex-direction: column;
}

.ch-auth-side-title {
    font-size: clamp(1.8rem, 3vw, 2.3rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1.08;
    color: #F8FAFC;
    margin: 0 0 0.9rem;
}

.ch-auth-side-sub {
    color: #94A3B8;
    font-size: 0.95rem;
    line-height: 1.6;
    margin: 0 0 1.75rem;
}

.ch-auth-benefits {
    list-style: none;
    padding: 0;
    margin: 0 0 auto;
}

.ch-auth-benefits li {
    position: relative;
    padding-left: 1.35rem;
    margin-bottom: 0.85rem;
    color: #CBD5E1;
    font-size: 0.85rem;
    line-height: 1.55;
}

.ch-auth-benefits li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.5em;
    width: 7px;
    height: 7px;
    border-radius: 2px;
    background-color: var(--ch-cta);
}

.ch-auth-side-meta {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 2rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: #64748B;
}

.ch-auth-side-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: var(--ch-cta);
    box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.5);
    animation: ch-pulse 2.4s ease-out infinite;
}

/* --- 2.1b Light-mode briefing panel ---
   Same living glow + ambient sweep + pulse as the dark deck, recoloured to a
   vivid emerald -> teal -> cyan gradient. Reads bright against the light page
   while white copy still pops. Dark mode keeps the hardcoded slate panel. */
html[data-theme="light"] .ch-auth-side {
    background: linear-gradient(150deg, #064E3B 0%, #0F766E 52%, #0E7490 100%);
}

html[data-theme="light"] .ch-auth-side::before {
    background:
        radial-gradient(ellipse 75% 55% at 12% -10%, rgba(110, 231, 183, 0.45), transparent 68%),
        radial-gradient(ellipse 60% 50% at 100% 112%, rgba(45, 212, 191, 0.28), transparent 72%);
}

html[data-theme="light"] .ch-auth-side::after {
    background: linear-gradient(105deg, transparent 0%, rgba(255, 255, 255, 0.10) 45%, rgba(167, 243, 208, 0.16) 50%, transparent 100%);
}

html[data-theme="light"] .ch-auth-side-sub {
    color: #D1FAE5;
}

html[data-theme="light"] .ch-auth-benefits li {
    color: #ECFDF5;
}

html[data-theme="light"] .ch-auth-benefits li::before {
    background-color: #6EE7B7;
}

html[data-theme="light"] .ch-auth-side-meta {
    color: rgba(236, 253, 245, 0.68);
}

html[data-theme="light"] .ch-auth-side-dot {
    background-color: #ECFDF5;
    box-shadow: 0 0 0 0 rgba(236, 253, 245, 0.7);
    animation: ch-pulse-light 2.4s ease-out infinite;
}

/* --- 2.2 Forms column --- */
.ch-auth-main {
    padding: 2.5rem 2.5rem 2.25rem;
}

/* Tabs with animated glider */
.ch-auth-tabs {
    position: relative;
    display: grid;
    grid-template-columns: 1fr 1fr;
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    border-radius: 10px;
    padding: 4px;
    margin-bottom: 1.75rem;
}

.ch-auth-tab {
    position: relative;
    z-index: 1;
    appearance: none;
    background: transparent;
    border: 0;
    padding: 0.6rem 0.5rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--ch-text-muted);
    cursor: pointer;
    transition: color 0.25s;
}

/* HARD OVERRIDE: GeneratePress paints generic button:hover with its own
   background + white text, which wrecked the tab pills. Transparent always. */
.ch-auth-tab,
.ch-auth-tab:hover,
.ch-auth-tab:focus,
.ch-auth-tab:active {
    background: transparent !important;
    box-shadow: none;
}

.ch-auth-tab:hover {
    color: var(--ch-cta) !important;
}

.ch-auth-tab:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px rgba(16, 185, 129, 0.45);
    border-radius: 7px;
}

.ch-auth-tab.is-active,
.ch-auth-tab.is-active:hover,
.ch-auth-tab.is-active:focus {
    color: var(--ch-text-main) !important;
}

.ch-auth-tab-glider {
    position: absolute;
    top: 4px;
    left: 4px;
    width: calc(50% - 4px);
    height: calc(100% - 8px);
    background-color: #FFFFFF;
    border: 1px solid var(--ch-border);
    border-radius: 7px;
    box-shadow: 0 2px 6px rgba(15, 23, 42, 0.08);
    transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}

.ch-auth-tabs[data-active="register"] .ch-auth-tab-glider {
    transform: translateX(100%);
}

/* Panels */
.ch-auth-panel {
    animation: ch-fade-up 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.ch-auth-panel[hidden] {
    display: none;
}

/* Fields */
.ch-field {
    margin-bottom: 1.1rem;
}

.ch-field-label {
    display: block;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--ch-text-muted);
    margin-bottom: 0.45rem;
}

.ch-input {
    width: 100%;
    font-family: 'Inter', sans-serif;
    font-size: 0.95rem;
    color: var(--ch-text-main);
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    border-radius: 8px;
    padding: 0.7rem 0.9rem;
    transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s;
}

.ch-input:focus {
    outline: none;
    border-color: var(--ch-cta);
    background-color: #FFFFFF;
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.18);
}

/* HARD OVERRIDE: GeneratePress ships high-specificity input[type="email"] /
   input[type="password"] rules that repainted typed text invisible. Element +
   class + !important beats the parent theme in every state, in both modes. */
.ch-portal input.ch-input,
.ch-portal input.ch-input:hover,
.ch-portal input.ch-input:focus,
.ch-portal input.ch-input:active {
    color: var(--ch-text-main) !important;
    -webkit-text-fill-color: var(--ch-text-main) !important;
    caret-color: var(--ch-text-main) !important;
}

.ch-portal input.ch-input::placeholder {
    color: var(--ch-text-muted);
    opacity: 0.75;
}

/* Fix for browser autofill overriding input colors */
.ch-input:-webkit-autofill,
.ch-input:-webkit-autofill:hover, 
.ch-input:-webkit-autofill:focus, 
.ch-input:-webkit-autofill:active {
    -webkit-text-fill-color: var(--ch-text-main) !important;
    -webkit-box-shadow: 0 0 0 999px var(--ch-bg-main) inset !important;
    transition: background-color 5000s ease-in-out 0s;
    caret-color: var(--ch-text-main);
}

.ch-input.is-invalid {
    border-color: #EF4444;
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.14);
}

.ch-input-group {
    position: relative;
}

.ch-input-group .ch-input {
    padding-right: 2.9rem;
}

.ch-eye {
    position: absolute;
    top: 50%;
    right: 0.55rem;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    appearance: none;
    background: transparent;
    border: 0;
    border-radius: 6px;
    color: var(--ch-text-muted);
    cursor: pointer;
    transition: color 0.2s, background-color 0.2s;
}

.ch-eye:hover {
    color: var(--ch-cta);
    background-color: rgba(16, 185, 129, 0.08);
}

.ch-field-hint {
    display: block;
    margin-top: 0.4rem;
    font-size: 0.75rem;
    color: var(--ch-text-muted);
    line-height: 1.45;
}

.ch-field-error {
    display: block;
    margin-top: 0.4rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: #DC2626;
    min-height: 0;
}

.ch-field-error:empty {
    display: none;
}

/* Password strength meter */
.ch-pw-meter {
    height: 4px;
    margin-top: 0.5rem;
    border-radius: 2px;
    background-color: var(--ch-border);
    overflow: hidden;
}

.ch-pw-meter-bar {
    display: block;
    height: 100%;
    width: 0;
    border-radius: 2px;
    background-color: #EF4444;
    transition: width 0.4s cubic-bezier(0.22, 1, 0.36, 1), background-color 0.4s;
}

/* Form-level alert */
.ch-form-alert {
    margin: 0 0 1rem;
    padding: 0.7rem 0.9rem;
    border-radius: 8px;
    font-size: 0.85rem;
    font-weight: 600;
    color: #B91C1C;
    background-color: rgba(239, 68, 68, 0.08);
    border: 1px solid rgba(239, 68, 68, 0.35);
    animation: ch-shake 0.4s cubic-bezier(0.36, 0.07, 0.19, 0.97);
}

.ch-form-alert.is-success {
    color: #047857;
    background-color: rgba(16, 185, 129, 0.08);
    border-color: rgba(16, 185, 129, 0.35);
    animation: ch-fade-up 0.35s ease both;
}

/* Primary action buttons with spinner state */
.ch-btn-auth,
.ch-btn-logout {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    cursor: pointer;
}

.ch-btn-auth {
    width: 100%;
    appearance: none;
    border: 0;
    background-color: var(--ch-cta);
    color: #FFFFFF;
    font-family: 'Inter', sans-serif;
    font-size: 0.95rem;
    font-weight: 800;
    padding: 0.8rem 1.5rem;
    border-radius: 8px;
    box-shadow: 0 4px 15px rgba(16, 185, 129, 0.3);
    transition: background-color 0.2s, transform 0.2s, box-shadow 0.2s;
}

.ch-btn-auth:hover {
    background-color: #059669;
    transform: translateY(-2px);
    box-shadow: 0 8px 20px rgba(16, 185, 129, 0.35);
}

.ch-btn-auth:active {
    transform: translateY(0);
}

.ch-btn-spinner {
    display: none;
    width: 17px;
    height: 17px;
    border: 2px solid rgba(255, 255, 255, 0.35);
    border-top-color: #FFFFFF;
    border-radius: 50%;
    animation: ch-spin 0.7s linear infinite;
}

.is-loading .ch-btn-spinner {
    display: inline-block;
}

.is-loading .ch-btn-label {
    opacity: 0.75;
}

.is-loading {
    pointer-events: none;
}

.ch-auth-legal {
    margin: 0.9rem 0 0;
    font-size: 0.75rem;
    color: var(--ch-text-muted);
    line-height: 1.5;
}

/* Plain-text trigger, not a real button visually - sits under the login
   password field. !important neutralizes GeneratePress's generic button
   background/border the same way .ch-eye and other unstyled controls do. */
.ch-auth-forgot {
    display: block;
    width: auto;
    margin: 0.5rem 0 1rem;
    padding: 0;
    background: none !important;
    border: none !important;
    font-size: 0.78rem;
    color: var(--ch-text-muted);
    cursor: pointer;
    text-align: right;
    text-decoration: underline;
    text-underline-offset: 2px;
    transition: color 0.2s;
}

.ch-auth-forgot:hover,
.ch-auth-forgot:focus-visible {
    color: var(--ch-cta);
}

/* Divider */
.ch-auth-divider {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin: 1.6rem 0 1.1rem;
    color: var(--ch-text-muted);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
}

.ch-auth-divider::before,
.ch-auth-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background-color: var(--ch-border);
}

/* OAuth buttons */
.ch-oauth-row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.75rem;
}

.ch-oauth-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.7rem 0.5rem;
    background-color: #FFFFFF;
    border: 1px solid var(--ch-border);
    border-radius: 8px;
    font-size: 0.88rem;
    font-weight: 700;
    color: var(--ch-text-main) !important;
    text-decoration: none !important;
    transition: transform 0.2s, border-color 0.2s, box-shadow 0.2s;
}

.ch-oauth-btn:hover {
    transform: translateY(-2px);
    border-color: var(--ch-cta);
    box-shadow: 0 8px 18px -8px rgba(15, 23, 42, 0.2);
}

.ch-oauth-btn svg {
    flex-shrink: 0;
}

.ch-oauth-gh {
    display: inline-flex;
    color: #0F172A;
}

/* ==========================================================================
   3. DASHBOARD (CartHacker Dashboard hub)
   ========================================================================== */
.ch-dash-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1.25rem;
    border-bottom: 1px solid var(--ch-border);
    padding-bottom: 1.5rem;
    margin-bottom: 2rem;
    animation: ch-fade-up 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.ch-dash-title {
    font-size: clamp(1.8rem, 3.5vw, 2.4rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1.1;
    margin: 0 0 0.35rem;
    color: var(--ch-text-main);
}

.ch-dash-sub {
    margin: 0;
    color: var(--ch-text-muted);
    font-size: 0.95rem;
}

/* Ghost button, destructive red on hover. The !important flags neutralize
   GeneratePress generic button backgrounds that left this control unstyled. */
.ch-btn-logout,
.ch-btn-logout:focus {
    appearance: none;
    background: transparent !important;
    border: 1px solid var(--ch-border) !important;
    border-radius: 8px;
    padding: 0.6rem 1.1rem;
    font-family: 'Inter', sans-serif;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--ch-text-main) !important;
    transition: color 0.2s, border-color 0.2s, background-color 0.2s, transform 0.2s;
}

.ch-btn-logout:hover {
    background: rgba(220, 38, 38, 0.07) !important;
    color: #DC2626 !important;
    border-color: #DC2626 !important;
    transform: translateY(-2px);
}

.ch-btn-logout:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.25);
}

.ch-btn-logout .ch-btn-spinner {
    border-color: rgba(220, 38, 38, 0.3);
    border-top-color: #DC2626;
}

/* Cards grid with staggered entrance */
.ch-dash-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1.5rem;
    align-items: start;
}

.ch-dash-card {
    background-color: #FFFFFF;
    border: 1px solid var(--ch-border);
    border-radius: 14px;
    padding: 1.6rem;
    box-shadow: 0 2px 4px rgba(15, 23, 42, 0.03);
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s, border-color 0.3s;
    animation: ch-fade-up 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.ch-dash-card:nth-child(2) { animation-delay: 0.07s; }
.ch-dash-card:nth-child(3) { animation-delay: 0.14s; }

.ch-dash-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 12px 24px -12px rgba(15, 23, 42, 0.15);
}

.ch-dash-card-label {
    display: inline-block;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.68rem;
    font-weight: 800;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--ch-text-muted);
    margin-bottom: 1.1rem;
}

/* --- 3.1 Identity + avatar uploader --- */
.ch-identity-row {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
}

.ch-avatar-uploader {
    position: relative;
    width: 96px;
    height: 96px;
    flex-shrink: 0;
}

.ch-avatar-img,
.ch-avatar-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 96px;
    height: 96px;
    border-radius: 50%;
    object-fit: cover;
}

/* Keep the placeholder <img> (empty src) fully out of the layout so its
   alt text can never leak into the card when no avatar is set. */
.ch-avatar-img[hidden] {
    display: none;
}

.ch-avatar-fallback {
    background: linear-gradient(135deg, #0F172A, #334155);
    color: #F8FAFC;
    font-size: 2rem;
    font-weight: 800;
}

.ch-avatar-ring {
    position: absolute;
    inset: -4px;
    border-radius: 50%;
    border: 2px solid var(--ch-cta);
    opacity: 0.55;
    transition: opacity 0.25s, transform 0.25s;
    pointer-events: none;
}

.ch-avatar-uploader:hover .ch-avatar-ring {
    opacity: 1;
    transform: scale(1.04);
}

.ch-avatar-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.15rem;
    appearance: none;
    border: 0;
    border-radius: 50%;
    /* Lighter scrim so the avatar underneath stays partly visible on hover,
       while the label keeps its contrast via the text-shadow below. */
    background-color: rgba(15, 23, 42, 0.38);
    color: #F8FAFC;
    text-shadow: 0 1px 3px rgba(15, 23, 42, 0.9);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    opacity: 0;
    cursor: pointer;
    backdrop-filter: blur(1px);
    transition: opacity 0.25s;
}

.ch-avatar-overlay svg {
    filter: drop-shadow(0 1px 2px rgba(15, 23, 42, 0.9));
}

.ch-avatar-uploader:hover .ch-avatar-overlay,
.ch-avatar-overlay:focus-visible {
    opacity: 1;
}

.ch-avatar-spinner {
    position: absolute;
    inset: -4px;
    display: none;
    border-radius: 50%;
    border: 3px solid rgba(16, 185, 129, 0.2);
    border-top-color: var(--ch-cta);
    animation: ch-spin 0.8s linear infinite;
    pointer-events: none;
}

.ch-avatar-uploader.is-uploading .ch-avatar-spinner {
    display: block;
}

.ch-avatar-uploader.is-uploading .ch-avatar-overlay {
    opacity: 0;
    pointer-events: none;
}

.ch-identity-meta {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    min-width: 0;
}

.ch-identity-name-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}

.ch-identity-name {
    font-size: 1.25rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    margin: 0;
    color: var(--ch-text-main);
    overflow-wrap: anywhere;
    min-width: 0;
}

.ch-name-edit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 26px;
    height: 26px;
    padding: 0;
    appearance: none;
    border: 1px solid transparent;
    border-radius: 7px;
    background: transparent;
    color: var(--ch-text-muted);
    cursor: pointer;
    transition: color 0.18s, background-color 0.18s, border-color 0.18s;
}

.ch-name-edit:hover,
.ch-name-edit:focus-visible {
    outline: none;
    color: var(--ch-cta);
    border-color: var(--ch-border);
    background-color: var(--ch-bg-main);
}

/* --- inline name editor --- */
.ch-name-form {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin: 0.1rem 0 0.15rem;
}

.ch-name-form[hidden] {
    display: none;
}

.ch-name-input {
    max-width: 320px;
    padding: 0.5rem 0.7rem;
    font-size: 0.95rem;
    font-weight: 700;
}

.ch-name-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.ch-name-save,
.ch-name-cancel {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    appearance: none;
    border-radius: 8px;
    padding: 0.4rem 0.9rem;
    font-family: 'Inter', sans-serif;
    font-size: 0.8rem;
    font-weight: 700;
    cursor: pointer;
    transition: background-color 0.18s, border-color 0.18s, color 0.18s, opacity 0.18s;
}

.ch-name-save {
    border: 1px solid var(--ch-cta);
    background-color: var(--ch-cta);
    color: #FFFFFF;
}

.ch-name-save:hover:not(:disabled) {
    filter: brightness(1.06);
}

.ch-name-save:disabled {
    opacity: 0.65;
    cursor: default;
}

.ch-name-cancel {
    border: 1px solid var(--ch-border);
    background-color: transparent;
    color: var(--ch-text-muted);
}

.ch-name-cancel:hover {
    color: var(--ch-text-main);
    border-color: var(--ch-text-muted);
}

/* spinner reuses the shared btn spinner pattern */
.ch-name-save .ch-btn-spinner {
    width: 14px;
    height: 14px;
    border: 2px solid rgba(255, 255, 255, 0.4);
    border-top-color: #FFFFFF;
    border-radius: 50%;
    display: none;
    animation: ch-spin 0.7s linear infinite;
}

.ch-name-save.is-loading .ch-btn-label {
    visibility: hidden;
}

.ch-name-save.is-loading .ch-btn-spinner {
    display: block;
    position: absolute;
}

.ch-name-error {
    font-size: 0.78rem;
    font-weight: 600;
    color: #DC2626;
    line-height: 1.4;
}

.ch-name-error:empty {
    display: none;
}

html[data-theme="dark"] .ch-name-error {
    color: #F87171;
}

.ch-identity-email {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.78rem;
    color: var(--ch-text-muted);
    overflow-wrap: anywhere;
}

.ch-identity-provider {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    margin-top: 0.35rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--ch-text-muted);
}

.ch-provider-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: var(--ch-cta);
}

.ch-provider-google   { background-color: #4285F4; }
.ch-provider-facebook { background-color: #1877F2; }
.ch-provider-github   { background-color: #0F172A; }

.ch-avatar-hint {
    margin: 1.1rem 0 0;
    font-size: 0.75rem;
    color: var(--ch-text-muted);
    line-height: 1.5;
}

/* --- 3.2 Subscription --- */
.ch-plan-row {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-bottom: 1.1rem;
}

.ch-plan-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    align-self: flex-start;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.8rem;
    font-weight: 800;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--ch-text-main);
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    border-radius: 6px;
    padding: 0.35rem 0.7rem;
}

/* THE PREMIUM MARK. Premium is blue, everywhere.
   Adrian, 2026-10-03, after an inventory of every Premium mark on the site:
   /premium/, the Store Speed Test plan cards, the Trust Badges builder, the
   newsletter landing and the global Pro badge in the header and footer were
   already royal blue, and only this dashboard and the account dropdown were
   emerald. Emerald is the action color (every CTA, every Free flag), so a
   green Premium mark read as one more button. The fill is the exact gradient
   /premium/ uses (--p-pro-fill), so the badge a member sees here is the badge
   they bought.

   One object, not three: a blue pill with a white Pro chip inside it and a
   soft blue shadow, which is what stops it detaching from the card. White on
   the lightest stop (#2563EB) is 5.2:1; the chip's #1E40AF on white is 8.7:1. */
.ch-plan-badge.is-premium {
    color: #FFFFFF;
    background: linear-gradient(180deg, #2563EB 0%, #1D4ED8 55%, #1E40AF 100%);
    border-color: #1E40AF;
    box-shadow: 0 1px 2px rgba(30, 64, 175, 0.22), 0 6px 14px -8px rgba(37, 99, 235, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}

.ch-plan-badge.is-premium .ch-badge,
.ch-hero-chip.is-premium .ch-badge {
    background: #FFFFFF;
    color: #1E40AF;
    line-height: 1.25;
}

.ch-plan-status {
    font-size: 0.82rem;
    color: var(--ch-text-muted);
}

.ch-plan-benefits {
    list-style: none;
    padding: 0;
    margin: 0 0 1.2rem;
}

.ch-plan-benefits li {
    position: relative;
    padding-left: 1.3rem;
    margin-bottom: 0.5rem;
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--ch-text-main);
}

.ch-plan-benefits li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.48em;
    width: 7px;
    height: 7px;
    border-radius: 2px;
    background-color: var(--ch-cta);
}

/* Filled emerald buttons follow the brand contrast rule: Emerald 700 with
   white in light (5.5:1, #065F46 on hover 7.7:1), brand #10B981 with #04241C
   in dark. White on #10B981 was 2.5:1 on Continue Learning, View plan &
   billing and See Premium in full. Every state declares color and background
   at 0,2,0 or above (the GeneratePress hover trap). */
.ch-btn-upgrade {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    background-color: #047857;
    color: #FFFFFF !important;
    font-size: 0.88rem;
    font-weight: 800;
    padding: 0.65rem 1.3rem;
    border-radius: 8px;
    text-decoration: none !important;
    box-shadow: 0 4px 15px rgba(4, 120, 87, 0.28);
    transition: background-color 0.2s, transform 0.2s, gap 0.25s;
}

.ch-btn-upgrade:hover,
.ch-btn-upgrade:focus-visible,
.ch-btn-upgrade:active {
    background-color: #065F46;
    color: #FFFFFF !important;
    transform: translateY(-2px);
    gap: 0.75rem;
}

html[data-theme="dark"] .ch-btn-upgrade {
    background-color: #10B981;
    color: #04241C !important;
    box-shadow: 0 4px 15px rgba(16, 185, 129, 0.25);
}

html[data-theme="dark"] .ch-btn-upgrade:hover,
html[data-theme="dark"] .ch-btn-upgrade:focus-visible,
html[data-theme="dark"] .ch-btn-upgrade:active {
    background-color: #34D399;
    color: #04241C !important;
}

/* A button that sells Premium ("Get CartHacker Premium", "See Premium in
   full") is the sitewide Premium button, not an emerald action: same fill,
   glow and light sweep as the header (style.css :root --ch-pro-*). Managing
   an existing plan stays emerald. */
.ch-btn-upgrade.is-premium {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    border: 1px solid var(--ch-pro-line);
    background-color: #2563EB;
    background-image: var(--ch-pro-fill);
    color: #FFFFFF !important;
    box-shadow: var(--ch-pro-glow);
}

.ch-btn-upgrade.is-premium::after {
    content: "";
    position: absolute;
    z-index: -1;
    top: 0;
    left: -80%;
    width: 50%;
    height: 100%;
    background: var(--ch-pro-sweep);
    transform: skewX(-18deg);
    transition: left 0.65s cubic-bezier(0.22, 1, 0.36, 1);
    pointer-events: none;
}

.ch-btn-upgrade.is-premium:hover,
.ch-btn-upgrade.is-premium:focus-visible,
.ch-btn-upgrade.is-premium:active,
html[data-theme="dark"] .ch-btn-upgrade.is-premium:hover,
html[data-theme="dark"] .ch-btn-upgrade.is-premium:focus-visible,
html[data-theme="dark"] .ch-btn-upgrade.is-premium:active {
    background-color: #1D4ED8;
    background-image: var(--ch-pro-fill-hi);
    color: #FFFFFF !important;
    box-shadow: var(--ch-pro-glow-hi);
}

.ch-btn-upgrade.is-premium:hover::after,
.ch-btn-upgrade.is-premium:focus-visible::after {
    left: 130%;
}

.ch-btn-upgrade.is-premium:focus-visible {
    outline: 3px solid var(--ch-pro-ring);
    outline-offset: 2px;
}

html[data-theme="dark"] .ch-btn-upgrade.is-premium {
    background-color: #2563EB;
    background-image: var(--ch-pro-fill);
    color: #FFFFFF !important;
    box-shadow: var(--ch-pro-glow);
}

@media (prefers-reduced-motion: reduce) {
    .ch-btn-upgrade.is-premium::after {
        transition: none;
    }

    .ch-btn-upgrade.is-premium:hover::after,
    .ch-btn-upgrade.is-premium:focus-visible::after {
        left: -80%;
    }
}

.ch-plan-since {
    display: block;
    margin-top: 1.1rem;
    padding-top: 1rem;
    border-top: 1px dashed var(--ch-border);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--ch-text-muted);
}

/* --- 3.3 Security --- */
.ch-security-title {
    font-size: 1.1rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    margin: 0 0 0.75rem;
    color: var(--ch-text-main);
}

.ch-security-note {
    font-size: 0.82rem;
    color: var(--ch-text-muted);
    line-height: 1.55;
    margin: 0 0 1rem;
}

/* ==========================================================================
   4. FAULT STATE + TOASTS
   ========================================================================== */
.ch-portal-fault {
    display: flex;
    justify-content: center;
}

.ch-portal-fault-card {
    max-width: 460px;
    text-align: center;
    background-color: #FFFFFF;
    border: 1px solid var(--ch-border);
    border-radius: 16px;
    padding: 2.5rem 2rem;
    animation: ch-fade-up 0.5s ease both;
}

.ch-portal-fault-card h1 {
    font-size: 1.4rem;
    font-weight: 800;
    margin: 0 0 0.6rem;
    color: var(--ch-text-main);
}

.ch-portal-fault-card p {
    color: var(--ch-text-muted);
    font-size: 0.92rem;
    line-height: 1.6;
    margin: 0 0 1.5rem;
}

.ch-toast-stack {
    position: fixed;
    right: 1.25rem;
    bottom: 1.25rem;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    pointer-events: none;
}

.ch-toast {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    max-width: 340px;
    background-color: #0F172A;
    color: #F1F5F9;
    border: 1px solid #334155;
    border-left: 3px solid var(--ch-cta);
    border-radius: 10px;
    padding: 0.75rem 1rem;
    font-size: 0.85rem;
    font-weight: 600;
    box-shadow: 0 12px 30px -10px rgba(2, 6, 23, 0.6);
    animation: ch-toast-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.ch-toast.is-error {
    border-left-color: #EF4444;
}

.ch-toast.is-leaving {
    animation: ch-toast-out 0.3s ease both;
}

/* ==========================================================================
   5. KEYFRAMES + MOTION SAFETY
   ========================================================================== */
@keyframes ch-spin {
    to { transform: rotate(360deg); }
}

@keyframes ch-fade-up {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
}

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

@keyframes ch-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.5); }
    70%  { box-shadow: 0 0 0 9px rgba(16, 185, 129, 0); }
    100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}

@keyframes ch-pulse-light {
    0%   { box-shadow: 0 0 0 0 rgba(236, 253, 245, 0.7); }
    70%  { box-shadow: 0 0 0 9px rgba(236, 253, 245, 0); }
    100% { box-shadow: 0 0 0 0 rgba(236, 253, 245, 0); }
}

@keyframes ch-shake {
    10%, 90%      { transform: translateX(-1px); }
    20%, 80%      { transform: translateX(2px); }
    30%, 50%, 70% { transform: translateX(-3px); }
    40%, 60%      { transform: translateX(3px); }
}

@keyframes ch-toast-in {
    from { opacity: 0; transform: translateX(24px); }
    to   { opacity: 1; transform: translateX(0); }
}

@keyframes ch-toast-out {
    to { opacity: 0; transform: translateX(24px); }
}

@media (prefers-reduced-motion: reduce) {
    .ch-portal *,
    .ch-portal *::before,
    .ch-portal *::after,
    .ch-toast {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ==========================================================================
   6. RESPONSIVE
   ========================================================================== */
@media (max-width: 1024px) {
    .ch-dash-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .ch-card-security {
        grid-column: 1 / -1;
    }
}

@media (max-width: 860px) {
    .ch-auth-shell {
        grid-template-columns: 1fr;
    }

    .ch-auth-side {
        padding: 2rem 1.75rem;
    }

    .ch-auth-side-title br {
        display: none;
    }

    .ch-auth-main {
        padding: 1.9rem 1.5rem;
    }
}

@media (max-width: 640px) {
    .ch-portal {
        padding: 1.5rem 1rem 3rem;
    }

    .ch-dash-grid {
        grid-template-columns: 1fr;
    }

    .ch-oauth-row {
        grid-template-columns: 1fr;
    }

    .ch-dash-head {
        align-items: flex-start;
        flex-direction: column;
    }
}

/* ==========================================================================
   7. DARK MODE OVERRIDES
   (dark DevSecOps side panel + toasts are hardcoded slate and stay identical)
   ========================================================================== */
html[data-theme="dark"] .ch-auth-shell {
    background-color: #1E293B;
    box-shadow: 0 20px 50px -20px rgba(0, 0, 0, 0.6);
}

html[data-theme="dark"] .ch-auth-tab-glider {
    background-color: #1E293B;
    border-color: #475569;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
}

html[data-theme="dark"] .ch-input {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-input:focus {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-oauth-btn {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-oauth-btn:hover {
    box-shadow: 0 8px 18px -8px rgba(0, 0, 0, 0.6);
}

html[data-theme="dark"] .ch-oauth-gh {
    color: #F1F5F9;
}

html[data-theme="dark"] .ch-dash-card,
html[data-theme="dark"] .ch-portal-fault-card {
    background-color: #1E293B;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
}

html[data-theme="dark"] .ch-dash-card:hover {
    box-shadow: 0 12px 24px -12px rgba(0, 0, 0, 0.55);
}

html[data-theme="dark"] .ch-plan-badge {
    background-color: #0F172A;
}

/* Dark mode used to erase this badge outright: the rule above carries an
   attribute selector plus a class and therefore outranks .ch-plan-badge
   .is-premium, so the gradient was overwritten with flat #0F172A - a
   near-black pill on a #1E293B card. The premium mark has to be LIGHTER than
   its surface here, not darker: the same blue fill, a pale blue hairline and
   a blue glow under it, with the Pro chip softened to #DBEAFE so it does not
   glare on a dark page. */
html[data-theme="dark"] .ch-plan-badge.is-premium {
    color: #FFFFFF;
    background: linear-gradient(180deg, #2563EB 0%, #1D4ED8 55%, #1E40AF 100%);
    border-color: rgba(147, 197, 253, 0.4);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35), 0 6px 16px -8px rgba(59, 130, 246, 0.55);
}

html[data-theme="dark"] .ch-plan-badge.is-premium .ch-badge,
html[data-theme="dark"] .ch-hero-chip.is-premium .ch-badge {
    background: #DBEAFE;
    color: #1E3A8A;
}

html[data-theme="dark"] .ch-provider-github {
    background-color: #F1F5F9;
}

html[data-theme="dark"] .ch-portal-alert {
    color: #FCA5A5;
    background-color: rgba(239, 68, 68, 0.12);
    border-color: rgba(239, 68, 68, 0.4);
}

html[data-theme="dark"] .ch-portal-alert.is-success {
    color: #6EE7B7;
    background-color: rgba(16, 185, 129, 0.12);
    border-color: rgba(16, 185, 129, 0.4);
}

html[data-theme="dark"] .ch-form-alert {
    color: #FCA5A5;
    background-color: rgba(239, 68, 68, 0.12);
    border-color: rgba(239, 68, 68, 0.4);
}

html[data-theme="dark"] .ch-form-alert.is-success {
    color: #6EE7B7;
    background-color: rgba(16, 185, 129, 0.12);
    border-color: rgba(16, 185, 129, 0.4);
}

html[data-theme="dark"] .ch-field-error {
    color: #F87171;
}

html[data-theme="dark"] .ch-avatar-fallback {
    background: linear-gradient(135deg, #334155, #0F172A);
}

html[data-theme="dark"] .ch-input:-webkit-autofill,
html[data-theme="dark"] .ch-input:-webkit-autofill:hover, 
html[data-theme="dark"] .ch-input:-webkit-autofill:focus, 
html[data-theme="dark"] .ch-input:-webkit-autofill:active {
    -webkit-text-fill-color: #F1F5F9 !important;
    -webkit-box-shadow: 0 0 0 999px #0F172A inset !important;
    caret-color: #F1F5F9;
}
/* ==========================================================================
   8. LEARNING CENTER: ONBOARDING (platform selection)
   A light card in light mode, the deep DevSecOps panel in dark only (the
   html[data-theme="dark"] rules at the end of section 14). It was #0F172A in
   both themes until 2026-10-04, when Adrian ruled it out: light mode carries
   a block with colour, wash and shadow, never a black slab on a light page.
   ========================================================================== */
.ch-onboard {
    position: relative;
    overflow: hidden;
    text-align: center;
    background-color: #FFFFFF;
    background-image: linear-gradient(180deg, #ECFDF5 0%, rgba(236, 253, 245, 0) 46%);
    border: 1px solid rgba(16, 185, 129, 0.3);
    border-radius: 16px;
    padding: clamp(2rem, 5vw, 3.25rem);
    margin-bottom: 2rem;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 28px 56px -36px rgba(4, 120, 87, 0.45);
    animation: ch-fade-up 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.ch-onboard::before {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse 70% 60% at 50% -15%, rgba(16, 185, 129, 0.12), transparent 70%);
    pointer-events: none;
}

.ch-onboard::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background-image: linear-gradient(90deg, #10B981 0%, #047857 100%);
    pointer-events: none;
}

.ch-onboard > * {
    position: relative;
}

/* Emerald 700: the global kicker colour (#10B981) is 2.5:1 on this card. */
.ch-onboard .ch-portal-kicker {
    color: #047857;
}

.ch-onboard-title {
    font-size: clamp(1.5rem, 3vw, 2.1rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1.15;
    text-wrap: balance;
    color: #0F172A;
    margin: 0 0 0.7rem;
}

.ch-onboard-sub {
    max-width: 580px;
    margin: 0 auto 2rem;
    color: #334155;
    font-size: 0.98rem;
    line-height: 1.6;
}

.ch-onboard-sub strong {
    color: #0F172A;
    font-weight: 700;
}

.ch-onboard-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem;
    max-width: 720px;
    margin: 0 auto;
}

.ch-onboard-card,
.ch-onboard-card:hover,
.ch-onboard-card:focus {
    /* GP generic button styles neutralized */
    appearance: none;
    background-color: #FFFFFF !important;
    color: #334155 !important;
    text-align: left;
}

.ch-onboard-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    border: 1px solid #E2E8F0;
    border-radius: 14px;
    padding: 1.75rem 1.6rem;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.3s, box-shadow 0.3s;
}

.ch-onboard-card:hover {
    transform: translateY(-4px);
}

.ch-onboard-card:focus-visible {
    outline: 3px solid rgba(4, 120, 87, 0.55);
    outline-offset: 2px;
}

.ch-onboard-card.is-shopify:hover,
.ch-onboard-card.is-shopify:focus-visible {
    border-color: #96BF48;
    box-shadow: 0 14px 30px -14px rgba(150, 191, 72, 0.45);
}

.ch-onboard-card.is-woo:hover,
.ch-onboard-card.is-woo:focus-visible {
    border-color: #7F54B3;
    box-shadow: 0 14px 30px -14px rgba(127, 84, 179, 0.4);
}

.ch-onboard-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 54px;
    height: 54px;
    border-radius: 12px;
    margin-bottom: 0.4rem;
}

.is-shopify .ch-onboard-icon {
    background-color: rgba(150, 191, 72, 0.14);
    border: 1px solid rgba(150, 191, 72, 0.4);
    color: #4D7C0F;
}

.is-woo .ch-onboard-icon {
    background-color: rgba(127, 84, 179, 0.1);
    border: 1px solid rgba(127, 84, 179, 0.3);
    color: #6D28D9;
}

.ch-onboard-name {
    font-size: 1.2rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: #0F172A;
}

.ch-onboard-desc {
    font-size: 0.88rem;
    line-height: 1.55;
    color: #475569;
}

.ch-onboard-desc strong {
    color: #1E293B;
    font-weight: 650;
}

.ch-onboard-cta {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: auto;
    padding-top: 0.8rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: #047857;
    transition: gap 0.25s;
}

.ch-onboard-card:hover .ch-onboard-cta {
    gap: 0.65rem;
}

.ch-onboard-card .ch-btn-spinner {
    position: absolute;
    top: 1.1rem;
    right: 1.1rem;
    border-color: rgba(16, 185, 129, 0.25);
    border-top-color: var(--ch-cta);
}

.ch-onboard-undecided {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    margin-top: 1.75rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: #475569 !important;
    text-decoration: none !important;
    transition: color 0.2s, gap 0.25s;
}

.ch-onboard-undecided:hover,
.ch-onboard-undecided:focus-visible {
    color: #047857 !important;
    gap: 0.7rem;
}

.ch-onboard-undecided:focus-visible {
    outline: 2px solid rgba(4, 120, 87, 0.55);
    outline-offset: 3px;
    border-radius: 4px;
}

/* ==========================================================================
   9. LEARNING PROGRESS CARD
   ========================================================================== */
.ch-card-progress,
.ch-card-plugins {
    grid-column: 1 / -1;
}

.ch-dash-card:nth-child(4) { animation-delay: 0.21s; }
.ch-dash-card:nth-child(5) { animation-delay: 0.28s; }

.ch-progress-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.ch-stack-switch {
    display: inline-flex;
    gap: 2px;
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    border-radius: 8px;
    padding: 3px;
    margin-bottom: 1.1rem;
}

.ch-stack-btn,
.ch-stack-btn:hover,
.ch-stack-btn:focus {
    appearance: none;
    border: 0;
    background: transparent !important;
    color: var(--ch-text-muted) !important;
}

.ch-stack-btn {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    padding: 0.35rem 0.7rem;
    border-radius: 6px;
    cursor: pointer;
    transition: color 0.2s, background-color 0.2s;
}

.ch-stack-btn:not(.is-active):hover {
    color: var(--ch-cta) !important;
}

.ch-stack-btn.is-active,
.ch-stack-btn.is-active:hover,
.ch-stack-btn.is-active:focus {
    background-color: #FFFFFF !important;
    color: var(--ch-text-main) !important;
    box-shadow: 0 1px 4px rgba(15, 23, 42, 0.12);
    cursor: default;
}

.ch-progress-stats {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.6rem;
}

.ch-progress-count {
    font-size: 0.95rem;
    color: var(--ch-text-main);
}

.ch-progress-count strong {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-weight: 800;
}

.ch-progress-pct {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 1.5rem;
    font-weight: 800;
    color: var(--ch-cta);
}

.ch-progress-track {
    position: relative;
    height: 10px;
    border-radius: 5px;
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    overflow: hidden;
    margin-bottom: 1.4rem;
}

.ch-progress-fill {
    position: relative;
    display: block;
    height: 100%;
    border-radius: 5px;
    background: linear-gradient(90deg, #059669, #10B981 60%, #34D399);
    transition: width 0.9s cubic-bezier(0.22, 1, 0.36, 1);
    overflow: hidden;
}

/* Subtle moving sheen keeps the bar alive without being loud */
.ch-progress-fill::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.28) 50%, transparent 70%);
    transform: translateX(-100%);
    animation: ch-progress-sheen 2.8s ease-in-out infinite;
}

@keyframes ch-progress-sheen {
    0%       { transform: translateX(-100%); }
    55%, 100% { transform: translateX(100%); }
}

.ch-progress-next-label {
    display: inline-block;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--ch-text-muted);
    margin-bottom: 0.35rem;
}

.ch-progress-list {
    list-style: none;
    padding: 0;
    margin: 0 0 1.25rem;
}

.ch-progress-list li {
    position: relative;
    padding: 0.5rem 0 0.5rem 1.3rem;
    border-bottom: 1px dashed var(--ch-border);
}

.ch-progress-list li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 1em;
    width: 7px;
    height: 7px;
    border-radius: 2px;
    background-color: var(--ch-cta);
}

.ch-progress-list a {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--ch-text-main);
    text-decoration: none;
    transition: color 0.2s;
}

.ch-progress-list a:hover {
    color: var(--ch-cta);
}

.ch-btn-continue {
    align-self: flex-start;
}

.ch-progress-done {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--ch-cta);
    font-size: 0.9rem;
    font-weight: 700;
    margin: 0;
}

.ch-progress-empty {
    color: var(--ch-text-muted);
    font-size: 0.9rem;
    line-height: 1.6;
    margin: 0;
}

/* ==========================================================================
   10. PLUGINS & TOOLS GRID
   ========================================================================== */
.ch-plugins-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
}

.ch-plugin-card {
    display: flex;
    flex-direction: column;
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    border-radius: 12px;
    padding: 1.2rem;
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.3s, box-shadow 0.3s;
}

.ch-plugin-card:hover {
    transform: translateY(-3px);
    border-color: var(--ch-cta);
    box-shadow: 0 10px 20px -10px rgba(15, 23, 42, 0.15);
}

.ch-plugin-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.8rem;
}

.ch-plugin-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 9px;
    background-color: #FFFFFF;
    border: 1px solid var(--ch-border);
    color: var(--ch-text-main);
    transition: color 0.2s, border-color 0.2s;
}

.ch-plugin-card:hover .ch-plugin-icon {
    color: var(--ch-cta);
    border-color: var(--ch-cta);
}

/* The Pro flag is the plan badge at flag scale: the same blue fill, so a card
   flag and an account badge read as the same product. Free stays an emerald
   wash, In development a dashed slate outline with an amber build dot, so the
   three states never share a color. */
.ch-plugin-flag {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.6rem;
    font-weight: 800;
    letter-spacing: 1px;
    text-transform: uppercase;
    white-space: nowrap;
    padding: 0.22rem 0.5rem;
    border-radius: 5px;
    color: #FFFFFF;
    background: linear-gradient(180deg, #2563EB 0%, #1D4ED8 55%, #1E40AF 100%);
    border: 1px solid #1E40AF;
    box-shadow: 0 1px 2px rgba(30, 64, 175, 0.22);
}

.ch-plugin-flag.is-free {
    color: #047857;
    background: rgba(16, 185, 129, 0.1);
    border-color: rgba(16, 185, 129, 0.35);
    box-shadow: none;
}

.ch-plugin-flag.is-dev {
    color: #475569;
    background: transparent;
    border: 1px dashed #CBD5E1;
    box-shadow: none;
}

.ch-plugin-flag.is-dev::before {
    content: "";
    flex-shrink: 0;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background-color: #F59E0B;
    animation: ch-dev-pulse 2.4s ease-in-out infinite;
}

@keyframes ch-dev-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
    .ch-plugin-flag.is-dev::before {
        animation: none;
    }
}

/* In development: nothing on the card is a link, so it must not answer the
   pointer the way a live card does (lift, emerald border, emerald icon). */
.ch-plugin-card.is-dev:hover {
    transform: none;
    border-color: var(--ch-border);
    box-shadow: none;
}

.ch-plugin-card.is-dev .ch-plugin-icon,
.ch-plugin-card.is-dev:hover .ch-plugin-icon {
    color: var(--ch-text-muted);
    border-color: var(--ch-border);
}

.ch-plugin-eta {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.8rem;
    font-weight: 700;
    color: #475569;
    white-space: nowrap;
}

.ch-plugin-eta svg {
    flex-shrink: 0;
    color: #B45309;
}

.ch-plugin-name {
    font-size: 0.95rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--ch-text-main);
    margin: 0 0 0.35rem;
}

.ch-plugin-desc {
    flex-grow: 1;
    font-size: 0.8rem;
    line-height: 1.55;
    color: var(--ch-text-muted);
    margin: 0;
}

/* The one bolded takeaway phrase per card needs to actually read as the
   payoff, not just heavier gray-on-gray text */
.ch-plugin-desc strong {
    color: var(--ch-text-main);
    font-weight: 700;
}

.ch-plugin-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 0.9rem;
    padding-top: 0.8rem;
    border-top: 1px dashed var(--ch-border);
}

.ch-plugin-platform {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--ch-text-muted);
}

/* Emerald 700, not the brand #10B981: emerald 500 text on the #F8FAFC card is
   2.4:1. #047857 is 5.3:1 at rest and #065F46 7.3:1 on hover; dark mode keeps
   the brand emerald, which reads at 6.9:1 on #0F172A (section 11). */
.ch-plugin-action {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.8rem;
    font-weight: 800;
    color: #047857 !important;
    text-decoration: none !important;
    transition: gap 0.25s, color 0.2s;
}

.ch-plugin-action:hover,
.ch-plugin-action:focus-visible {
    gap: 0.55rem;
    color: #065F46 !important;
}

.ch-plugin-action.is-locked {
    color: #B45309 !important;
}

.ch-plugin-action.is-locked:hover {
    color: #92400E !important;
}

/* ==========================================================================
   11. NEW SECTIONS: RESPONSIVE + DARK OVERRIDES
   ========================================================================== */
@media (max-width: 1024px) {
    .ch-plugins-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 640px) {
    .ch-onboard-grid {
        grid-template-columns: 1fr;
    }

    .ch-plugins-grid {
        grid-template-columns: 1fr;
    }

    .ch-progress-head {
        flex-direction: column;
        align-items: flex-start;
    }
}

html[data-theme="dark"] .ch-portal input.ch-input,
html[data-theme="dark"] .ch-portal input.ch-input:hover,
html[data-theme="dark"] .ch-portal input.ch-input:focus,
html[data-theme="dark"] .ch-portal input.ch-input:active {
    color: #F1F5F9 !important;
    -webkit-text-fill-color: #F1F5F9 !important;
    caret-color: #F1F5F9 !important;
}

html[data-theme="dark"] .ch-btn-logout,
html[data-theme="dark"] .ch-btn-logout:focus {
    color: #F1F5F9 !important;
}

html[data-theme="dark"] .ch-btn-logout:hover {
    background: rgba(239, 68, 68, 0.12) !important;
    color: #F87171 !important;
    border-color: #F87171 !important;
}

html[data-theme="dark"] .ch-stack-btn.is-active,
html[data-theme="dark"] .ch-stack-btn.is-active:hover,
html[data-theme="dark"] .ch-stack-btn.is-active:focus {
    background-color: #1E293B !important;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

html[data-theme="dark"] .ch-progress-track {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-plugin-card {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-plugin-card:hover {
    box-shadow: 0 10px 20px -10px rgba(0, 0, 0, 0.55);
}

html[data-theme="dark"] .ch-plugin-icon {
    background-color: #1E293B;
}

/* The blue fill is already lighter than the #0F172A card, so dark mode keeps
   it and only trades the navy hairline for a pale blue one that reads on
   slate. */
html[data-theme="dark"] .ch-plugin-flag {
    color: #FFFFFF;
    background: linear-gradient(180deg, #2563EB 0%, #1D4ED8 55%, #1E40AF 100%);
    border-color: rgba(147, 197, 253, 0.4);
    box-shadow: none;
}

html[data-theme="dark"] .ch-plugin-flag.is-free {
    color: #6EE7B7;
    background: rgba(16, 185, 129, 0.12);
    border-color: rgba(52, 211, 153, 0.35);
}

html[data-theme="dark"] .ch-plugin-flag.is-dev {
    color: #CBD5E1;
    background: transparent;
    border-color: #475569;
}

html[data-theme="dark"] .ch-plugin-flag.is-dev::before {
    background-color: #FBBF24;
}

html[data-theme="dark"] .ch-plugin-card.is-dev:hover {
    box-shadow: none;
}

html[data-theme="dark"] .ch-plugin-eta {
    color: #CBD5E1;
}

html[data-theme="dark"] .ch-plugin-eta svg {
    color: #FBBF24;
}

html[data-theme="dark"] .ch-plugin-action {
    color: #10B981 !important;
}

html[data-theme="dark"] .ch-plugin-action:hover,
html[data-theme="dark"] .ch-plugin-action:focus-visible {
    color: #34D399 !important;
}

html[data-theme="dark"] .ch-plugin-action.is-locked {
    color: #F59E0B !important;
}

html[data-theme="dark"] .ch-plugin-action.is-locked:hover {
    color: #FBBF24 !important;
}

/* ==========================================================================
   12. DASH HEAD ACTIONS + HERO STRIP (identity + progress ring)
   ========================================================================== */
.ch-dash-head-actions {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}

/* Ghost button, emerald on hover - the constructive sibling of .ch-btn-logout */
.ch-btn-settings,
.ch-btn-settings:focus {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    appearance: none;
    background: transparent !important;
    border: 1px solid var(--ch-border) !important;
    border-radius: 8px;
    padding: 0.6rem 1.1rem;
    font-family: 'Inter', sans-serif;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--ch-text-main) !important;
    text-decoration: none !important;
    transition: color 0.2s, border-color 0.2s, background-color 0.2s, transform 0.2s;
}

.ch-btn-settings:hover {
    background: rgba(16, 185, 129, 0.08) !important;
    color: var(--ch-cta) !important;
    border-color: var(--ch-cta) !important;
    transform: translateY(-2px);
}

.ch-btn-settings:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.25);
}

/* --- Hero strip --- */
.ch-card-hero,
.ch-card-learning {
    grid-column: 1 / -1;
}

/* ==========================================================================
   SET-A-PASSWORD NOTICE
   Emerald, not amber. Amber and red are spent on things that are already
   broken - a spent allowance, a failed scan - and this is neither: the
   account works, it is simply missing its second key. Painting a healthy
   account in warning colours every single visit trains the member to ignore
   the colour, which costs us the next real warning.

   Full width above the hero because it is about the account, not about any
   one card, and a notice that shares a row with two other cards reads as a
   third card rather than as a message.
   ========================================================================== */
.ch-pwnag {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.15rem;
    border: 1px solid rgba(16, 185, 129, 0.38);
    border-radius: 14px;
    background: linear-gradient(120deg, rgba(16, 185, 129, 0.09), rgba(16, 185, 129, 0.03));
    animation: chPwNagIn 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
}

@keyframes chPwNagIn {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .ch-pwnag { animation: none; }
}

/* Dismissal is a fade the script waits on, so the row does not vanish under
   the cursor mid-click. */
.ch-pwnag.is-dismissed {
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity 0.22s, transform 0.22s;
}

.ch-pwnag-ico {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 10px;
    background-color: rgba(16, 185, 129, 0.14);
    color: #047857;
}

.ch-pwnag-ico svg {
    display: block;
    width: 20px;
    height: 20px;
}

.ch-pwnag-body {
    min-width: 0;
    flex: 1 1 auto;
}

.ch-pwnag-title {
    display: block;
    font-size: 0.95rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--ch-text-main);
}

.ch-pwnag-text {
    margin: 0.2rem 0 0;
    font-size: 0.85rem;
    line-height: 1.6;
    color: var(--ch-text-muted);
}

.ch-pwnag-cta {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.4rem;
    padding: 0.6rem 1.05rem;
    border-radius: 8px;
    background-color: #047857;
    color: #FFFFFF !important;
    font-size: 0.85rem;
    font-weight: 700;
    text-decoration: none !important;
    white-space: nowrap;
    transition: background-color 0.2s, transform 0.2s;
}

/* Same contrast pair as .ch-btn-upgrade. */
.ch-pwnag-cta:hover,
.ch-pwnag-cta:focus-visible,
.ch-pwnag-cta:active {
    background-color: #065F46;
    color: #FFFFFF !important;
    transform: translateY(-1px);
}

html[data-theme="dark"] .ch-pwnag-cta {
    background-color: #10B981;
    color: #04241C !important;
}

html[data-theme="dark"] .ch-pwnag-cta:hover,
html[data-theme="dark"] .ch-pwnag-cta:focus-visible,
html[data-theme="dark"] .ch-pwnag-cta:active {
    background-color: #34D399;
    color: #04241C !important;
}

.ch-pwnag-cta svg {
    display: block;
    width: 14px;
    height: 14px;
}

/* 40px hit area on a 16px glyph: this is the one control on the row somebody
   taps on a phone with a thumb, and the row is dense. */
.ch-pwnag-x {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--ch-text-muted);
    cursor: pointer;
    transition: background-color 0.2s, color 0.2s;
}

.ch-pwnag-x:hover {
    background-color: rgba(15, 23, 42, 0.06);
    color: var(--ch-text-main);
}

.ch-pwnag-x svg {
    display: block;
    width: 16px;
    height: 16px;
}

/* Below 720 the row stacks and the close button leaves the flow entirely,
   pinning to the corner: keeping it inline would push the CTA onto a fourth
   line for one 16px glyph. */
@media (max-width: 720px) {
    .ch-pwnag {
        position: relative;
        flex-wrap: wrap;
        padding-right: 3rem;
    }

    .ch-pwnag-body {
        flex: 1 1 100%;
        order: 2;
    }

    .ch-pwnag-ico {
        order: 1;
    }

    .ch-pwnag-cta {
        order: 3;
        width: 100%;
        justify-content: center;
    }

    .ch-pwnag-x {
        position: absolute;
        top: 0.55rem;
        right: 0.55rem;
    }
}

html[data-theme="dark"] .ch-pwnag {
    border-color: rgba(52, 211, 153, 0.34);
    background: linear-gradient(120deg, rgba(16, 185, 129, 0.13), rgba(16, 185, 129, 0.05));
}

html[data-theme="dark"] .ch-pwnag-ico {
    background-color: rgba(16, 185, 129, 0.18);
    color: #34D399;
}

html[data-theme="dark"] .ch-pwnag-x:hover {
    background-color: rgba(248, 250, 252, 0.08);
}

.ch-card-hero {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 2rem;
    flex-wrap: wrap;
}

.ch-hero-identity {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    flex-wrap: wrap;
    min-width: 0;
}

.ch-hero-avatar {
    position: relative;
    width: 112px;
    height: 112px;
    flex-shrink: 0;
}

.ch-hero-ring {
    position: absolute;
    inset: 0;
    transform: rotate(-90deg);
}

.ch-hero-ring-track {
    fill: none;
    stroke: var(--ch-border);
    stroke-width: 5;
}

.ch-hero-ring-fill {
    fill: none;
    stroke: var(--ch-cta);
    stroke-width: 5;
    stroke-linecap: round;
    transition: stroke-dashoffset 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}

.ch-hero-avatar-img,
.ch-hero-avatar-fallback {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 88px;
    height: 88px;
    border-radius: 50%;
    object-fit: cover;
}

.ch-hero-avatar-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #0F172A, #334155);
    color: #F8FAFC;
    font-size: 1.9rem;
    font-weight: 800;
}

.ch-hero-meta {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    min-width: 0;
}

.ch-hero-name {
    font-size: 1.35rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    margin: 0;
    color: var(--ch-text-main);
    overflow-wrap: anywhere;
}

.ch-hero-email {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.78rem;
    color: var(--ch-text-muted);
    overflow-wrap: anywhere;
}

.ch-hero-chips {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.4rem;
}

.ch-hero-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.64rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    padding: 0.3rem 0.65rem;
    border-radius: 6px;
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    color: var(--ch-text-muted);
    text-decoration: none !important;
    transition: color 0.2s, border-color 0.2s;
}

.ch-hero-chip.is-platform.is-shopify     { color: #5C8A22; border-color: rgba(150, 191, 72, 0.5); }
.ch-hero-chip.is-platform.is-woocommerce { color: #7F54B3; border-color: rgba(127, 84, 179, 0.5); }
.ch-hero-chip.is-platform.is-other       { color: #0E7490; border-color: rgba(14, 116, 144, 0.45); }
.ch-hero-chip.is-platform.is-undecided   { color: #B45309; border-color: rgba(180, 83, 9, 0.4); }

/* Emerald 700 in light: brand #10B981 text on the #F8FAFC chip is 2.4:1. */
.ch-hero-chip.is-store:hover,
.ch-hero-chip.is-store:focus-visible {
    color: #047857;
    border-color: #047857;
}

html[data-theme="dark"] .ch-hero-chip.is-store:hover,
html[data-theme="dark"] .ch-hero-chip.is-store:focus-visible {
    color: #34D399;
    border-color: #34D399;
}

/* Same object at chip scale. It sits in a row of outlined chips, so it keeps
   their exact metrics and earns its prominence from fill alone - a badge that
   is also taller than its neighbours reads as a misalignment, not emphasis. */
.ch-hero-chip.is-premium {
    color: #FFFFFF;
    background: linear-gradient(180deg, #2563EB 0%, #1D4ED8 55%, #1E40AF 100%);
    border-color: #1E40AF;
    box-shadow: 0 1px 2px rgba(30, 64, 175, 0.22), 0 4px 10px -6px rgba(37, 99, 235, 0.55);
}

.ch-hero-chip.is-premium .ch-badge {
    font-size: 0.58rem;
    padding: 0.1rem 0.3rem;
}

/* Same pair as .ch-plugin-action: #047857 / #065F46 in light (the brand
   emerald was 2.5:1 on the white card), #10B981 / #34D399 in dark. */
.ch-hero-manage {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.55rem;
    font-size: 0.8rem;
    font-weight: 700;
    color: #047857 !important;
    text-decoration: none !important;
    transition: gap 0.25s, color 0.2s;
}

.ch-hero-manage:hover,
.ch-hero-manage:focus-visible {
    gap: 0.65rem;
    color: #065F46 !important;
}

html[data-theme="dark"] .ch-hero-manage {
    color: #10B981 !important;
}

html[data-theme="dark"] .ch-hero-manage:hover,
html[data-theme="dark"] .ch-hero-manage:focus-visible {
    color: #34D399 !important;
}

.ch-hero-progress {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.35rem;
    text-align: right;
}

.ch-hero-pct {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 2.4rem;
    font-weight: 800;
    line-height: 1;
    color: var(--ch-cta);
}

.ch-hero-count {
    font-size: 0.85rem;
    color: var(--ch-text-muted);
}

.ch-hero-count strong {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-weight: 800;
    color: var(--ch-text-main);
}

.ch-hero-progress .ch-btn-continue {
    margin-top: 0.5rem;
}

.ch-hero-complete {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    margin-top: 0.5rem;
    color: var(--ch-cta);
    font-size: 0.88rem;
    font-weight: 700;
}

/* ==========================================================================
   13. LEARNING CENTER CURRICULUM (grouped list + per-guide toggles)
   ========================================================================== */
.ch-lc-curriculum {
    margin-top: 0.4rem;
}

.ch-lc-group {
    margin-bottom: 1.4rem;
}

.ch-lc-group:last-child {
    margin-bottom: 0;
}

.ch-lc-group-head {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    margin: 0 0 0.4rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--ch-text-muted);
}

.ch-lc-group-icon {
    display: inline-flex;
    color: var(--ch-cta);
}

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

.ch-lc-item {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    padding: 0.55rem 0.6rem;
    border-radius: 9px;
    border-bottom: 1px dashed var(--ch-border);
    transition: background-color 0.2s;
}

.ch-lc-item:last-child {
    border-bottom: 0;
}

.ch-lc-item:hover {
    background-color: var(--ch-bg-main);
}

/* Circle toggle. GP generic button styles neutralized with hard overrides. */
.ch-lc-item-toggle,
.ch-lc-item-toggle:hover,
.ch-lc-item-toggle:focus {
    appearance: none;
    background: transparent !important;
    padding: 0;
}

.ch-lc-item-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    border: 2px solid var(--ch-border);
    border-radius: 50%;
    color: transparent;
    cursor: pointer;
    transition: border-color 0.2s, background-color 0.2s, color 0.2s, transform 0.15s;
}

.ch-lc-item-toggle:hover {
    border-color: var(--ch-cta);
    transform: scale(1.08);
}

.ch-lc-item-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.3);
}

.ch-lc-item.is-read .ch-lc-item-toggle,
.ch-lc-item.is-read .ch-lc-item-toggle:hover,
.ch-lc-item.is-read .ch-lc-item-toggle:focus {
    background-color: var(--ch-cta) !important;
    border-color: var(--ch-cta);
    color: #FFFFFF;
}

.ch-lc-item-toggle.is-loading {
    opacity: 0.45;
    pointer-events: none;
}

.ch-lc-item-title {
    flex: 1;
    min-width: 0;
    font-size: 0.92rem;
    font-weight: 600;
    color: var(--ch-text-main) !important;
    text-decoration: none !important;
    transition: color 0.2s;
    overflow-wrap: anywhere;
}

.ch-lc-item-title:hover {
    color: var(--ch-cta) !important;
}

.ch-lc-item.is-read .ch-lc-item-title {
    color: var(--ch-text-muted) !important;
}

.ch-lc-item-tag {
    flex-shrink: 0;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.58rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    padding: 0.22rem 0.5rem;
    border-radius: 5px;
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    color: var(--ch-text-muted);
}

.ch-lc-item-open {
    display: inline-flex;
    flex-shrink: 0;
    color: var(--ch-text-muted) !important;
    transition: color 0.2s, transform 0.2s;
}

.ch-lc-item-open:hover {
    color: var(--ch-cta) !important;
    transform: translateX(2px);
}

/* Plugins card sits beside Subscription on wide screens */
.ch-card-plugins {
    grid-column: 2 / -1;
}

.ch-card-plugins .ch-plugins-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* ==========================================================================
   14. ONBOARDING V2 (two steps: store status -> autodetect / manual pick)
   ========================================================================== */
.ch-ob-step[hidden] {
    display: none;
}

.ch-ob-choice-grid {
    max-width: 720px;
}

.ch-ob-pick-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    max-width: 900px;
}

.ch-onboard-card.is-yes:hover,
.ch-onboard-card.is-yes:focus-visible {
    border-color: var(--ch-cta);
    box-shadow: 0 14px 30px -14px rgba(16, 185, 129, 0.45);
}

.ch-onboard-card.is-prelaunch:hover,
.ch-onboard-card.is-prelaunch:focus-visible {
    border-color: #F59E0B;
    box-shadow: 0 14px 30px -14px rgba(245, 158, 11, 0.4);
}

.ch-onboard-card.is-other:hover,
.ch-onboard-card.is-other:focus-visible {
    border-color: #06B6D4;
    box-shadow: 0 14px 30px -14px rgba(6, 182, 212, 0.35);
}

/* Icon colours at the 700 step in light, so each glyph holds 3:1 or better
   on its own tint; dark takes the 300-400 steps below. */
.is-yes .ch-onboard-icon {
    background-color: rgba(16, 185, 129, 0.12);
    border: 1px solid rgba(16, 185, 129, 0.35);
    color: #047857;
}

.is-prelaunch .ch-onboard-icon {
    background-color: rgba(245, 158, 11, 0.12);
    border: 1px solid rgba(245, 158, 11, 0.35);
    color: #B45309;
}

.is-other .ch-onboard-icon {
    background-color: rgba(6, 182, 212, 0.1);
    border: 1px solid rgba(6, 182, 212, 0.3);
    color: #0E7490;
}

/* Detect form: a normal light field in light mode, a slate one in dark. */
.ch-detect-form {
    max-width: 620px;
    margin: 0 auto;
}

.ch-detect-row {
    display: flex;
    gap: 0.75rem;
    align-items: stretch;
}

.ch-detect-row .ch-input {
    flex: 1;
    min-width: 0;
}

.ch-detect-btn {
    width: auto;
    flex-shrink: 0;
    white-space: nowrap;
}

.ch-onboard input.ch-detect-input,
.ch-onboard input.ch-detect-input:hover,
.ch-onboard input.ch-detect-input:focus,
.ch-onboard input.ch-detect-input:active {
    background-color: #FFFFFF !important;
    border-color: #CBD5E1;
    color: #0F172A !important;
    -webkit-text-fill-color: #0F172A !important;
    caret-color: #0F172A !important;
}

.ch-onboard input.ch-detect-input:focus {
    border-color: var(--ch-cta);
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.22);
}

.ch-onboard input.ch-detect-input::placeholder {
    color: #64748B;
    opacity: 1;
}

.ch-onboard .ch-form-alert {
    max-width: 620px;
    margin: 1rem auto 0;
    text-align: left;
}

.ch-ob-divider {
    max-width: 620px;
    margin: 1.75rem auto 1.5rem;
    color: #475569;
}

.ch-ob-divider::before,
.ch-ob-divider::after {
    background-color: #E2E8F0;
}

/* Back control - looks like the undecided link, behaves like a button */
.ch-ob-back,
.ch-ob-back:hover,
.ch-ob-back:focus {
    appearance: none;
    background: transparent !important;
    border: 0;
    cursor: pointer;
}

.ch-ob-back:hover {
    color: #047857 !important;
}

/* --- Onboarding in dark: the deep DevSecOps panel ------------------------- */

html[data-theme="dark"] .ch-onboard {
    background-color: #0F172A;
    background-image: none;
    border-color: #1E293B;
    box-shadow: none;
}

html[data-theme="dark"] .ch-onboard::before {
    background: radial-gradient(ellipse 70% 60% at 50% -15%, rgba(16, 185, 129, 0.16), transparent 70%);
}

html[data-theme="dark"] .ch-onboard .ch-portal-kicker { color: #34D399; }
html[data-theme="dark"] .ch-onboard-title { color: #F8FAFC; }
html[data-theme="dark"] .ch-onboard-sub { color: #CBD5E1; }
html[data-theme="dark"] .ch-onboard-sub strong { color: #F8FAFC; }

html[data-theme="dark"] .ch-onboard-card,
html[data-theme="dark"] .ch-onboard-card:hover,
html[data-theme="dark"] .ch-onboard-card:focus {
    background-color: #1E293B !important;
    color: #CBD5E1 !important;
}

html[data-theme="dark"] .ch-onboard-card {
    border-color: #334155;
    box-shadow: none;
}

html[data-theme="dark"] .ch-onboard-card:focus-visible { outline-color: rgba(52, 211, 153, 0.6); }

html[data-theme="dark"] .ch-onboard-name { color: #F8FAFC; }
html[data-theme="dark"] .ch-onboard-desc { color: #94A3B8; }
html[data-theme="dark"] .ch-onboard-desc strong { color: #E2E8F0; }
html[data-theme="dark"] .ch-onboard-cta { color: #34D399; }

html[data-theme="dark"] .is-yes .ch-onboard-icon { color: #34D399; }
html[data-theme="dark"] .is-prelaunch .ch-onboard-icon { color: #FBBF24; }
html[data-theme="dark"] .is-other .ch-onboard-icon { color: #22D3EE; }
html[data-theme="dark"] .is-shopify .ch-onboard-icon { color: #96BF48; }
html[data-theme="dark"] .is-woo .ch-onboard-icon { color: #B794E4; }

html[data-theme="dark"] .ch-onboard-undecided { color: #94A3B8 !important; }
html[data-theme="dark"] .ch-onboard-undecided:hover,
html[data-theme="dark"] .ch-onboard-undecided:focus-visible,
html[data-theme="dark"] .ch-ob-back:hover { color: #34D399 !important; }

html[data-theme="dark"] .ch-onboard input.ch-detect-input,
html[data-theme="dark"] .ch-onboard input.ch-detect-input:hover,
html[data-theme="dark"] .ch-onboard input.ch-detect-input:focus,
html[data-theme="dark"] .ch-onboard input.ch-detect-input:active {
    background-color: #1E293B !important;
    border-color: #334155;
    color: #F1F5F9 !important;
    -webkit-text-fill-color: #F1F5F9 !important;
    caret-color: #F1F5F9 !important;
}

html[data-theme="dark"] .ch-onboard input.ch-detect-input::placeholder { color: #94A3B8; }

html[data-theme="dark"] .ch-ob-divider { color: #94A3B8; }
html[data-theme="dark"] .ch-ob-divider::before,
html[data-theme="dark"] .ch-ob-divider::after { background-color: #334155; }

/* ==========================================================================
   15. SETTINGS PAGE (tabs, panels, store form, newsletter)
   ========================================================================== */
.ch-settings-tabs {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 1.75rem;
    animation: ch-fade-up 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.ch-settings-tab,
.ch-settings-tab:hover,
.ch-settings-tab:focus {
    appearance: none;
    background: transparent !important;
}

.ch-settings-tab {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 1.1rem;
    border: 1px solid var(--ch-border);
    border-radius: 999px;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--ch-text-muted) !important;
    cursor: pointer;
    transition: color 0.2s, border-color 0.2s, background-color 0.2s;
}

.ch-settings-tab:hover {
    color: var(--ch-cta) !important;
    border-color: var(--ch-cta);
}

.ch-settings-tab:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.25);
}

.ch-settings-tab.is-active,
.ch-settings-tab.is-active:hover {
    background-color: #FFFFFF !important;
    border-color: var(--ch-cta);
    color: var(--ch-text-main) !important;
    box-shadow: 0 2px 8px -2px rgba(16, 185, 129, 0.25);
}

.ch-settings-panel {
    max-width: 760px;
    animation: ch-fade-up 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.ch-settings-panel[hidden] {
    display: none;
}

/* Every settings panel held exactly one card until the Security panel gained
   the danger zone underneath the password form, and two cards with no rule
   between them sat edge to edge with their borders touching. Matches the
   1.5rem rhythm .ch-dash-grid uses everywhere else. Written as a sibling
   margin rather than a flex gap on the panel so the [hidden] display toggle
   above keeps working untouched. */
.ch-settings-panel .ch-dash-card + .ch-dash-card {
    margin-top: 1.5rem;
}

/* --- Store panel: platform radio cards --- */
.ch-platform-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
    margin-top: 0.2rem;
}

.ch-platform-option {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.85rem 1rem;
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    border-radius: 10px;
    cursor: pointer;
    transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s;
}

.ch-platform-option:hover {
    border-color: var(--ch-cta);
}

.ch-platform-option input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.ch-platform-option.is-active {
    border-color: var(--ch-cta);
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.16);
}

.ch-platform-option.is-active::after {
    content: '';
    position: absolute;
    top: 0.8rem;
    right: 0.8rem;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background-color: var(--ch-cta);
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.25);
}

.ch-platform-option-name {
    font-size: 0.9rem;
    font-weight: 800;
    color: var(--ch-text-main);
}

.ch-platform-option-desc {
    font-size: 0.75rem;
    color: var(--ch-text-muted);
}

/* --- Newsletter panel --- */
.ch-nl-status {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    flex-wrap: wrap;
    margin-bottom: 1.4rem;
}

.ch-nl-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 1px;
    text-transform: uppercase;
    padding: 0.4rem 0.8rem;
    border-radius: 999px;
    color: var(--ch-text-muted);
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
}

.ch-nl-badge .ch-nl-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: #94A3B8;
}

.ch-nl-badge.is-on {
    color: #047857;
    border-color: rgba(16, 185, 129, 0.4);
    background-color: rgba(16, 185, 129, 0.07);
}

.ch-nl-badge.is-on .ch-nl-dot {
    background-color: var(--ch-cta);
    animation: ch-pulse 2.4s ease-out infinite;
}

.ch-nl-status-note {
    flex: 1;
    min-width: 220px;
    font-size: 0.78rem;
    color: var(--ch-text-muted);
    line-height: 1.5;
}

/* Master switch */
.ch-nl-master {
    display: flex;
    align-items: flex-start;
    gap: 0.9rem;
    padding: 1rem 1.1rem;
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    border-radius: 12px;
    cursor: pointer;
    margin-bottom: 1.1rem;
    transition: border-color 0.2s;
}

.ch-nl-master:hover {
    border-color: var(--ch-cta);
}

.ch-nl-master input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.ch-nl-switch {
    position: relative;
    flex-shrink: 0;
    width: 42px;
    height: 24px;
    margin-top: 0.1rem;
    border-radius: 999px;
    background-color: var(--ch-border);
    transition: background-color 0.25s;
}

.ch-nl-switch::after {
    content: '';
    position: absolute;
    top: 3px;
    left: 3px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background-color: #FFFFFF;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.3);
    transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.ch-nl-master input:checked ~ .ch-nl-switch {
    background-color: var(--ch-cta);
}

.ch-nl-master input:checked ~ .ch-nl-switch::after {
    transform: translateX(18px);
}

.ch-nl-master input:focus-visible ~ .ch-nl-switch {
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.3);
}

.ch-nl-master-text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.ch-nl-master-text strong {
    font-size: 0.92rem;
    font-weight: 800;
    color: var(--ch-text-main);
}

.ch-nl-master-text span {
    font-size: 0.78rem;
    color: var(--ch-text-muted);
    line-height: 1.5;
}

/* Topic checkboxes */
.ch-nl-topics {
    border: 0;
    padding: 0;
    margin: 0 0 1.2rem;
    transition: opacity 0.25s;
}

.ch-nl-topics[disabled] {
    opacity: 0.45;
    pointer-events: none;
}

.ch-nl-topics legend {
    margin-bottom: 0.6rem;
}

.ch-nl-topic {
    display: flex;
    align-items: flex-start;
    gap: 0.8rem;
    padding: 0.75rem 0.9rem;
    border-radius: 10px;
    cursor: pointer;
    transition: background-color 0.2s;
}

.ch-nl-topic:hover {
    background-color: var(--ch-bg-main);
}

.ch-nl-topic input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.ch-nl-check {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 21px;
    height: 21px;
    margin-top: 0.1rem;
    border: 2px solid var(--ch-border);
    border-radius: 6px;
    color: transparent;
    transition: border-color 0.2s, background-color 0.2s, color 0.2s;
}

.ch-nl-topic input:checked ~ .ch-nl-check {
    background-color: var(--ch-cta);
    border-color: var(--ch-cta);
    color: #FFFFFF;
}

.ch-nl-topic input:focus-visible ~ .ch-nl-check {
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.3);
}

.ch-nl-topic-text {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.ch-nl-topic-text strong {
    font-size: 0.88rem;
    font-weight: 700;
    color: var(--ch-text-main);
}

.ch-nl-topic-text span {
    font-size: 0.76rem;
    color: var(--ch-text-muted);
    line-height: 1.5;
}

/* Settings forms submit: natural width, not full-bleed */
.ch-store-form .ch-btn-auth,
.ch-nl-form .ch-btn-auth {
    width: auto;
    padding-left: 1.75rem;
    padding-right: 1.75rem;
}

/* ==========================================================================
   16. NEW SURFACES: RESPONSIVE + DARK OVERRIDES
   ========================================================================== */
@media (max-width: 1024px) {
    .ch-card-plugins {
        grid-column: 1 / -1;
    }

    .ch-ob-pick-grid {
        grid-template-columns: 1fr;
        max-width: 460px;
    }
}

@media (max-width: 780px) {
    .ch-card-hero {
        flex-direction: column;
        align-items: flex-start;
    }

    .ch-hero-progress {
        align-items: flex-start;
        text-align: left;
        width: 100%;
        padding-top: 1.1rem;
        border-top: 1px dashed var(--ch-border);
    }
}

@media (max-width: 640px) {
    .ch-detect-row {
        flex-direction: column;
    }

    .ch-platform-grid {
        grid-template-columns: 1fr;
    }

    .ch-card-plugins .ch-plugins-grid {
        grid-template-columns: 1fr;
    }

    .ch-lc-item {
        flex-wrap: wrap;
    }

    .ch-lc-item-title {
        flex-basis: calc(100% - 4.5rem);
    }

    .ch-lc-item-tag {
        margin-left: 2.3rem;
    }

    .ch-dash-head-actions {
        width: 100%;
    }
}

html[data-theme="dark"] .ch-btn-settings,
html[data-theme="dark"] .ch-btn-settings:focus {
    color: #F1F5F9 !important;
}

html[data-theme="dark"] .ch-btn-settings:hover {
    color: #34D399 !important;
    border-color: #34D399 !important;
    background: rgba(16, 185, 129, 0.12) !important;
}

html[data-theme="dark"] .ch-hero-avatar-fallback {
    background: linear-gradient(135deg, #334155, #0F172A);
}

html[data-theme="dark"] .ch-hero-ring-track {
    stroke: #334155;
}

html[data-theme="dark"] .ch-hero-chip {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-hero-chip.is-premium {
    color: #FFFFFF;
    background: linear-gradient(180deg, #2563EB 0%, #1D4ED8 55%, #1E40AF 100%);
    border-color: rgba(147, 197, 253, 0.4);
    box-shadow: 0 4px 12px -6px rgba(59, 130, 246, 0.5);
}

html[data-theme="dark"] .ch-hero-chip.is-platform.is-shopify     { color: #A7D45C; }
html[data-theme="dark"] .ch-hero-chip.is-platform.is-woocommerce { color: #B794E4; }
html[data-theme="dark"] .ch-hero-chip.is-platform.is-other       { color: #67E8F9; }
html[data-theme="dark"] .ch-hero-chip.is-platform.is-undecided   { color: #FBBF24; }

html[data-theme="dark"] .ch-lc-item:hover {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-lc-item-tag {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-settings-tab.is-active,
html[data-theme="dark"] .ch-settings-tab.is-active:hover {
    background-color: #1E293B !important;
    box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.5);
}

html[data-theme="dark"] .ch-platform-option {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-nl-badge {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-nl-badge.is-on {
    color: #6EE7B7;
    background-color: rgba(16, 185, 129, 0.1);
}

html[data-theme="dark"] .ch-nl-master {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-nl-switch {
    background-color: #334155;
}

html[data-theme="dark"] .ch-nl-master input:checked ~ .ch-nl-switch {
    background-color: var(--ch-cta);
}

html[data-theme="dark"] .ch-nl-topic:hover {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-nl-check {
    border-color: #475569;
}

html[data-theme="dark"] .ch-nl-topic input:checked ~ .ch-nl-check {
    border-color: var(--ch-cta);
}

/* ==========================================================================
   17. POST-OAUTH PROVISIONING SCREEN ("Setting up your account")
   Dark DevSecOps panel in dark mode, vivid emerald deck in light mode -
   mirrors the auth briefing panel treatment so the flow feels continuous.
   ========================================================================== */
.ch-portal-setup {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    min-height: 60vh;
}

.ch-setup {
    position: relative;
    overflow: hidden;
    width: 100%;
    max-width: 620px;
    background-color: #0F172A;
    border: 1px solid #1E293B;
    border-radius: 16px;
    padding: clamp(2rem, 5vw, 3rem);
    box-shadow: 0 24px 60px -24px rgba(2, 6, 23, 0.55);
    animation: ch-fade-up 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.ch-setup::before {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse 75% 55% at 20% -10%, rgba(16, 185, 129, 0.18), transparent 70%);
    pointer-events: none;
}

/* Ambient sweep - the provisioning deck feels alive while it works */
.ch-setup::after {
    content: '';
    position: absolute;
    left: -60%;
    top: 0;
    width: 55%;
    height: 100%;
    background: linear-gradient(105deg, transparent 0%, rgba(148, 163, 184, 0.05) 45%, rgba(16, 185, 129, 0.07) 50%, transparent 100%);
    animation: ch-sweep 6s ease-in-out infinite;
    pointer-events: none;
}

.ch-setup > * {
    position: relative;
}

.ch-setup-title {
    font-size: clamp(1.5rem, 3vw, 2rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1.12;
    color: #F8FAFC;
    margin: 0 0 0.55rem;
}

.ch-setup-sub {
    color: #94A3B8;
    font-size: 0.92rem;
    line-height: 1.6;
    margin: 0 0 1.8rem;
}

.ch-setup-sub strong {
    color: #F8FAFC;
}

/* --- Step list --- */
.ch-setup-steps {
    list-style: none;
    padding: 0;
    margin: 0 0 1.6rem;
    counter-reset: none;
}

.ch-setup-step {
    display: flex;
    align-items: flex-start;
    gap: 0.9rem;
    padding: 0.7rem 0.75rem;
    border-radius: 10px;
    opacity: 0.42;
    transition: opacity 0.35s, background-color 0.35s;
}

.ch-setup-step.is-active {
    opacity: 1;
    background-color: rgba(30, 41, 59, 0.75);
}

.ch-setup-step.is-done,
.ch-setup-step.is-skip {
    opacity: 0.88;
}

/* State bubble: outline -> spinner -> emerald check */
.ch-setup-state {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 26px;
    height: 26px;
    margin-top: 0.05rem;
    border: 2px solid #334155;
    border-radius: 50%;
    color: transparent;
    transition: border-color 0.3s, background-color 0.3s, color 0.3s;
}

.ch-setup-spin {
    position: absolute;
    inset: -2px;
    display: none;
    border: 2px solid rgba(16, 185, 129, 0.2);
    border-top-color: var(--ch-cta);
    border-radius: 50%;
    animation: ch-spin 0.7s linear infinite;
}

.ch-setup-step.is-active .ch-setup-spin {
    display: block;
}

.ch-setup-check {
    opacity: 0;
    transform: scale(0.4);
}

.ch-setup-step.is-done .ch-setup-state {
    background-color: var(--ch-cta);
    border-color: var(--ch-cta);
    color: #FFFFFF;
}

.ch-setup-step.is-done .ch-setup-check {
    opacity: 1;
    animation: ch-check-pop 0.45s cubic-bezier(0.22, 1.6, 0.36, 1) both;
}

/* Skip = non-blocking miss (e.g. provider returned no avatar) */
.ch-setup-step.is-skip .ch-setup-state {
    background-color: rgba(245, 158, 11, 0.15);
    border-color: #F59E0B;
    color: #FBBF24;
}

.ch-setup-step.is-skip .ch-setup-check {
    opacity: 1;
    animation: ch-check-pop 0.45s cubic-bezier(0.22, 1.6, 0.36, 1) both;
}

.ch-setup-step-text {
    display: flex;
    flex-direction: column;
    gap: 0.12rem;
    min-width: 0;
}

.ch-setup-step-text strong {
    font-size: 0.92rem;
    font-weight: 700;
    color: #F1F5F9;
}

.ch-setup-step-text span {
    font-size: 0.76rem;
    color: #64748B;
    line-height: 1.5;
}

.ch-setup-step.is-skip .ch-setup-step-text span {
    color: #FBBF24;
}

/* --- Progress bar + status line --- */
.ch-setup-bar {
    height: 8px;
    border-radius: 4px;
    background-color: #1E293B;
    border: 1px solid #334155;
    overflow: hidden;
    margin-bottom: 0.8rem;
}

.ch-setup-bar-fill {
    position: relative;
    display: block;
    width: 0;
    height: 100%;
    border-radius: 4px;
    background: linear-gradient(90deg, #059669, #10B981 60%, #34D399);
    transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1);
    overflow: hidden;
}

.ch-setup-bar-fill::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.3) 50%, transparent 70%);
    transform: translateX(-100%);
    animation: ch-progress-sheen 2.2s ease-in-out infinite;
}

.ch-setup-status {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: #64748B;
}

/* Blinking terminal caret after the status line */
.ch-setup-status::after {
    content: '';
    width: 7px;
    height: 12px;
    background-color: var(--ch-cta);
    animation: ch-caret-blink 1s steps(2, start) infinite;
}

@keyframes ch-check-pop {
    0%   { transform: scale(0.4); }
    60%  { transform: scale(1.2); }
    100% { transform: scale(1); }
}

@keyframes ch-caret-blink {
    0%, 49%  { opacity: 1; }
    50%, 100% { opacity: 0; }
}

/* Light mode: the vivid emerald deck (same recipe as the auth briefing panel).
   Copy stays white-on-dark-green, so step states need no palette forks. */
html[data-theme="light"] .ch-setup {
    background: linear-gradient(150deg, #064E3B 0%, #0F766E 52%, #0E7490 100%);
    border-color: rgba(6, 78, 59, 0.4);
    box-shadow: 0 24px 60px -24px rgba(6, 78, 59, 0.5);
}

html[data-theme="light"] .ch-setup::before {
    background:
        radial-gradient(ellipse 75% 55% at 12% -10%, rgba(110, 231, 183, 0.45), transparent 68%),
        radial-gradient(ellipse 60% 50% at 100% 112%, rgba(45, 212, 191, 0.28), transparent 72%);
}

html[data-theme="light"] .ch-setup::after {
    background: linear-gradient(105deg, transparent 0%, rgba(255, 255, 255, 0.10) 45%, rgba(167, 243, 208, 0.16) 50%, transparent 100%);
}

html[data-theme="light"] .ch-setup-sub {
    color: #D1FAE5;
}

html[data-theme="light"] .ch-setup-step.is-active {
    background-color: rgba(6, 78, 59, 0.45);
}

html[data-theme="light"] .ch-setup-state {
    border-color: rgba(236, 253, 245, 0.35);
}

html[data-theme="light"] .ch-setup-step-text span {
    color: rgba(209, 250, 229, 0.75);
}

html[data-theme="light"] .ch-setup-bar {
    background-color: rgba(6, 78, 59, 0.55);
    border-color: rgba(236, 253, 245, 0.25);
}

html[data-theme="light"] .ch-setup-bar-fill {
    background: linear-gradient(90deg, #6EE7B7, #A7F3D0);
}

html[data-theme="light"] .ch-setup-status {
    color: rgba(236, 253, 245, 0.7);
}

html[data-theme="light"] .ch-setup-status::after {
    background-color: #ECFDF5;
}

/* ==========================================================================
   17. QR CODE LIBRARY (dashboard panel for tracking links)
   Head: title + intro on the left, quota meter + New code CTA on the right.
   Rows: thumbnail well (portal.js paints the real pattern) > identity block
   > scan stats > action rail. Retire keeps the record, Delete erases it.
   ========================================================================== */
.ch-card-qr {
    grid-column: 1 / -1;
    /* Opening and closing the editor scrolls this card into view; the sticky
       site header would otherwise cover its first 100px. */
    scroll-margin-top: 100px;
}

.ch-qrlib-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1.25rem 2rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.ch-qrlib-heading {
    min-width: 0;
    flex: 1 1 380px;
}

.ch-qrlib-title {
    margin: 0 0 0.35rem;
    font-size: 1.15rem;
    font-weight: 800;
    letter-spacing: -0.015em;
    color: var(--ch-text-main);
}

.ch-qrlib-intro {
    margin: 0;
    color: var(--ch-text-muted);
    font-size: 0.9rem;
    line-height: 1.6;
    max-width: 64ch;
}

.ch-qrlib-side {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.7rem;
    flex-shrink: 0;
}

.ch-qrlib-meter {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.4rem;
    min-width: 190px;
}

.ch-qrlib-quota {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ch-text-muted);
}

.ch-qrlib-quota strong {
    color: var(--ch-cta);
}

.ch-qrlib-meter-track {
    width: 100%;
    height: 6px;
    border-radius: 999px;
    background-color: var(--ch-border);
    overflow: hidden;
}

.ch-qrlib-meter-fill {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, #34D399, var(--ch-cta));
    transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.ch-qrlib-new {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.5rem 0.9rem;
    border: 1px solid var(--ch-border);
    border-radius: 8px;
    background-color: #FFFFFF;
    color: var(--ch-text-main);
    font-size: 0.8rem;
    font-weight: 700;
    text-decoration: none;
    transition: color 0.2s, border-color 0.2s, transform 0.2s, box-shadow 0.2s;
}

.ch-qrlib-new svg {
    color: var(--ch-cta);
}

/* Emerald 700 for the text, not the brand #10B981: that one is 2.5:1 on
   white and the label went faint exactly when the pointer landed on it. */
.ch-qrlib-new:hover {
    color: #047857;
    border-color: var(--ch-cta);
    transform: translateY(-2px);
    box-shadow: 0 8px 16px -10px rgba(16, 185, 129, 0.45);
}

/* --- Empty state ---
   Always in the DOM so deleting the last row can reveal it without a reload;
   the explicit [hidden] rule is required because display:flex would otherwise
   override the UA's hidden handling. */
.ch-qrlib-empty[hidden] {
    display: none;
}

.ch-qrlib-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.7rem;
    padding: 2.2rem 1rem;
    border: 1px dashed var(--ch-border);
    border-radius: 12px;
    text-align: center;
}

.ch-qrlib-empty svg {
    color: var(--ch-text-muted);
    opacity: 0.6;
}

.ch-qrlib-empty p {
    margin: 0;
    color: var(--ch-text-muted);
    font-size: 0.9rem;
    max-width: 48ch;
}

/* --- Rows --- */
.ch-qrlib-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 0.6rem;
}

.ch-qrlib-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 0.6rem 1.1rem;
    padding: 0.85rem 1.1rem;
    background-color: var(--ch-bg-main);
    border: 1px solid var(--ch-border);
    border-radius: 12px;
    transition: border-color 0.25s, box-shadow 0.25s, opacity 0.3s,
                height 0.3s cubic-bezier(0.4, 0, 0.2, 1),
                padding 0.3s, margin 0.3s;
}

.ch-qrlib-row:hover {
    border-color: #CBD5E1;
    box-shadow: 0 10px 22px -16px rgba(15, 23, 42, 0.28);
}

/* Paused, not retired. The row stays legible because the state is reversible
   and the owner still has to be able to read it to decide. */
.ch-qrlib-row.is-paused {
    opacity: 0.66;
}

/* Delete exit: the row collapses instead of vanishing between frames */
.ch-qrlib-row.is-leaving {
    opacity: 0;
    height: 0 !important;
    padding-top: 0;
    padding-bottom: 0;
    margin: 0;
    border-width: 0;
    overflow: hidden;
}

/* --- Thumbnail well: the stored snapshot, or a repaint when there is none --- */
.ch-qrlib-thumb {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 46px;
    height: 46px;
    border-radius: 9px;
    background-color: #FFFFFF;
    border: 1px solid var(--ch-border);
    overflow: hidden;
    /* Placeholder checker until (or unless) the encoder paints the code */
    background-image:
        linear-gradient(45deg, rgba(148, 163, 184, 0.18) 25%, transparent 25%),
        linear-gradient(-45deg, rgba(148, 163, 184, 0.18) 25%, transparent 25%);
    background-size: 8px 8px;
}

.ch-qrlib-thumb.has-code {
    background-image: none;
}

.ch-qrlib-thumb canvas,
.ch-qrlib-thumb img {
    display: block;
    width: 40px;
    height: 40px;
    /* The stored snapshot is a styled render with curves and a logo, so it has
       to be resampled smoothly. Only the plain repaint fallback, which is a
       hard-edged module grid, wants nearest neighbour. */
    object-fit: contain;
}

.ch-qrlib-thumb canvas {
    image-rendering: pixelated;
}

.ch-qrlib-row.is-paused .ch-qrlib-thumb {
    filter: grayscale(1);
    opacity: 0.7;
}

/* --- Payload type badge --- */
.ch-qrlib-type {
    display: inline-flex;
    align-items: center;
    padding: 0.12rem 0.5rem;
    border-radius: 999px;
    border: 1px solid var(--ch-border);
    background-color: var(--ch-bg-card);
    color: var(--ch-text-muted);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
}

/* One accent per payload kind. The tint is the only thing that differs, so a
   library of twenty rows scans by colour before it scans by word. */
.ch-qrlib-type.is-website {
    border-color: rgba(59, 130, 246, 0.32);
    background-color: rgba(59, 130, 246, 0.1);
    color: #1D4ED8;
}

.ch-qrlib-type.is-vcard {
    border-color: rgba(139, 92, 246, 0.32);
    background-color: rgba(139, 92, 246, 0.1);
    color: #6D28D9;
}

.ch-qrlib-type.is-wifi {
    border-color: rgba(14, 165, 233, 0.32);
    background-color: rgba(14, 165, 233, 0.1);
    color: #0369A1;
}

.ch-qrlib-type.is-text {
    border-color: rgba(100, 116, 139, 0.32);
    background-color: rgba(100, 116, 139, 0.1);
    color: #475569;
}

/* --- Identity block --- */
.ch-qrlib-main {
    min-width: 0;
}

.ch-qrlib-line {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    flex-wrap: wrap;
}

.ch-qrlib-short {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.84rem;
    font-weight: 700;
    color: var(--ch-text-main);
}

.ch-qrlib-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.12rem 0.5rem;
    border-radius: 999px;
    background-color: rgba(16, 185, 129, 0.1);
    color: #047857;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* Live pulse dot */
.ch-qrlib-badge::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background-color: var(--ch-cta);
}

.ch-qrlib-badge.is-off {
    background-color: rgba(100, 116, 139, 0.12);
    color: var(--ch-text-muted);
}

.ch-qrlib-badge.is-off::before {
    background-color: #94A3B8;
}

.ch-qrlib-target {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.8rem;
    color: var(--ch-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: color 0.2s;
}

.ch-qrlib-target:hover {
    color: var(--ch-accent);
}

/* Non-website rows carry a summary, not a link. Killing the hover colour stops
   it pretending to be clickable. */
.ch-qrlib-target.is-plain,
.ch-qrlib-target.is-plain:hover {
    color: var(--ch-text-muted);
    cursor: default;
}

.ch-qrlib-meta {
    display: block;
    margin-top: 0.2rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.64rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: #94A3B8;
}

/* --- Scan stats --- */
.ch-qrlib-stats {
    display: flex;
    gap: 1.1rem;
    flex-shrink: 0;
    font-size: 0.78rem;
    color: var(--ch-text-muted);
}

.ch-qrlib-stat strong {
    display: block;
    color: var(--ch-text-main);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 1.05rem;
    font-weight: 800;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

/* --- Action rail --- */
.ch-qrlib-actions {
    display: flex;
    gap: 0.4rem;
    flex-shrink: 0;
    flex-wrap: wrap;
}

/* EVERY STATE IS STATED, ON PURPOSE.
   GeneratePress ships `button:hover, button:focus { background-color: #3f4047;
   color: #fff }` at specificity (0,1,1). The old rule set a hover colour but
   no hover background, so in light mode the parent theme's charcoal won and a
   hovered or clicked chip turned into a dark block with dark text on it. Dark
   mode only escaped by accident, through the html[data-theme] override below.
   The fix is not !important: it is a background and a colour on :hover, :focus
   and :active at (0,2,0), which outranks the parent theme in both modes and
   still leaves room for the tone modifiers (is-warn, is-danger, is-accent) to
   win at (0,3,0). */
.ch-qrlib-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.42rem 0.7rem;
    border: 1px solid var(--ch-border);
    border-radius: 8px;
    background-color: #FFFFFF;
    color: var(--ch-text-muted);
    font-family: inherit;
    font-size: 0.76rem;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    transition: color 0.2s, border-color 0.2s, background-color 0.2s, transform 0.2s;
}

.ch-qrlib-btn:focus,
.ch-qrlib-btn:active {
    background-color: #FFFFFF;
    color: var(--ch-text-muted);
}

.ch-qrlib-btn svg {
    flex-shrink: 0;
    opacity: 0.75;
}

.ch-qrlib-btn:hover {
    background-color: #F8FAFC;
    color: var(--ch-text-main);
    border-color: #94A3B8;
    transform: translateY(-1px);
}

.ch-qrlib-btn:focus-visible {
    outline: 2px solid var(--ch-cta);
    outline-offset: 2px;
}

.ch-qrlib-btn.is-primary,
.ch-qrlib-btn.is-primary:focus,
.ch-qrlib-btn.is-primary:active {
    background-color: var(--ch-cta);
    border-color: var(--ch-cta);
    color: #FFFFFF;
}

.ch-qrlib-btn.is-primary:hover {
    background-color: #059669;
    border-color: #059669;
    color: #FFFFFF;
}

/* Edit is the action this row exists for, so it carries the emerald tint the
   Core Web Vitals panel uses for its primary chip, not a solid fill: five solid
   buttons in a row would read as five equal commands. */
.ch-qrlib-btn.is-accent,
.ch-qrlib-btn.is-accent:focus,
.ch-qrlib-btn.is-accent:active {
    background-color: #ECFDF5;
    border-color: #A7F3D0;
    color: #047857;
}

.ch-qrlib-btn.is-accent svg {
    opacity: 1;
}

/* White on brand #10B981 is 2.5:1. The filled hover uses Emerald 700, which
   carries white at 5.5:1 and still reads as the same green. */
.ch-qrlib-btn.is-accent:hover {
    background-color: #047857;
    border-color: #047857;
    color: #FFFFFF;
}

.ch-qrlib-btn.is-warn:hover {
    color: #B45309;
    border-color: #FCD34D;
    background-color: #FFFBEB;
}

.ch-qrlib-btn.is-danger:hover {
    color: #B91C1C;
    border-color: #FCA5A5;
    background-color: #FEF2F2;
}

.ch-qrlib-btn.is-loading {
    opacity: 0.6;
    cursor: wait;
}

.ch-qrlib-btn[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
    transform: none;
}

/* --- Account level strips ---
   Sit above the list rather than inside a row, because the constraint belongs
   to the account and not to any one code. The base is the neutral informational
   panel; .is-slots opts into the Premium panel below. */
.ch-qrlib-upsell {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    margin: 0 0 1rem;
    padding: 0.95rem 1.1rem;
    border: 1px solid var(--ch-border);
    border-radius: 12px;
    background-color: var(--ch-bg-main);
}

.ch-qrlib-upsell[hidden] {
    display: none;
}

.ch-qrlib-upsell-ico {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background-color: rgba(16, 185, 129, 0.12);
    color: var(--ch-cta);
}

.ch-qrlib-upsell-copy {
    display: grid;
    gap: 0.22rem;
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.87rem;
    line-height: 1.6;
    color: var(--ch-text-muted);
}

.ch-qrlib-upsell-copy strong {
    color: var(--ch-text-main);
    font-size: 0.94rem;
    font-weight: 700;
}

/* Both strips send the owner to /premium/, so the button is the Premium
   button (style.css 7.0b tokens). It was white on Emerald 500 until
   2026-10-04: 2.5:1, and the wrong colour for a Premium sale. White on the
   Blue 600-800 fill is 5.17:1 or better in both themes. */
.ch-qrlib-upsell-cta,
.ch-qrlib-upsell-cta:visited {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.6rem 1rem;
    border: 1px solid var(--ch-pro-line);
    border-radius: 9px;
    background-color: #2563EB;
    background-image: var(--ch-pro-fill);
    box-shadow: var(--ch-pro-glow);
    color: #FFFFFF;
    font-size: 0.86rem;
    font-weight: 700;
    text-decoration: none;
    transition: transform 0.16s ease, box-shadow 0.16s ease;
}

.ch-qrlib-upsell-cta:hover,
.ch-qrlib-upsell-cta:focus-visible,
.ch-qrlib-upsell-cta:active {
    color: #FFFFFF;
    background-color: #1D4ED8;
    background-image: var(--ch-pro-fill-hi);
    box-shadow: var(--ch-pro-glow-hi);
    transform: translateY(-1px);
}

.ch-qrlib-upsell-cta:focus-visible {
    outline: 3px solid var(--ch-pro-ring);
    outline-offset: 2px;
}

/* --- Slots-full strip ---
   Amber was wrong here twice over: nothing is broken, and a brown warning band
   is the one colour the rest of this product never uses. A full library is a
   commercial ceiling, not a fault, so it reads as a Premium offer: in light
   mode a white strip with a blue wash, a blue hairline and a blue-tinted
   shadow; in dark the deep panel (end of this file). It was #0F172A in both
   themes until 2026-10-04, when Adrian ruled out dark panels on a light page.
   The lapsed-stats strip above it stays neutral, so the two never read as
   the same message. */
.ch-qrlib-upsell.is-slots {
    border-color: rgba(37, 99, 235, 0.3);
    background-color: #FFFFFF;
    background-image: linear-gradient(90deg, #EFF6FF 0%, rgba(239, 246, 255, 0) 72%);
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 14px 30px -24px rgba(30, 64, 175, 0.55);
}

.ch-qrlib-upsell.is-slots .ch-qrlib-upsell-ico {
    background-color: #DBEAFE;
    color: #1D4ED8;
}

.ch-qrlib-upsell.is-slots .ch-qrlib-upsell-copy {
    color: #475569;
}

.ch-qrlib-upsell.is-slots .ch-qrlib-upsell-copy strong {
    color: #0F172A;
}

/* The inner strong is the Premium offer, so it reads in Premium blue. */
.ch-qrlib-upsell.is-slots .ch-qrlib-upsell-copy span strong {
    color: #1E40AF;
}

/* The meter goes neutral rather than amber the moment the last slot goes: a
   full bar already says full, and colouring it like a warning contradicts the
   panel below it. */
.ch-qrlib-meter.is-full .ch-qrlib-meter-fill {
    background-color: #64748B;
}

.ch-qrlib-meter.is-full .ch-qrlib-quota strong {
    color: var(--ch-text-main);
}

/* --- Deactivate vs Delete footnote --- */
.ch-qrlib-foot {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 1.1rem 0 0;
    color: var(--ch-text-muted);
    font-size: 0.78rem;
    line-height: 1.55;
}

.ch-qrlib-foot svg {
    flex-shrink: 0;
    margin-top: 0.15rem;
    color: var(--ch-cta);
}

.ch-qrlib-foot strong {
    color: var(--ch-text-main);
}

@media (max-width: 900px) {
    .ch-qrlib-row {
        grid-template-columns: auto minmax(0, 1fr);
    }

    .ch-qrlib-stats {
        grid-column: 2;
        justify-content: flex-start;
    }

    .ch-qrlib-actions {
        grid-column: 1 / -1;
        justify-content: flex-start;
    }

    .ch-qrlib-side {
        align-items: flex-start;
        width: 100%;
    }

    .ch-qrlib-meter {
        align-items: flex-start;
        width: 100%;
    }
}

/* --- dark --- */
html[data-theme="dark"] .ch-qrlib-row {
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-qrlib-row:hover {
    border-color: #475569;
    box-shadow: 0 10px 22px -16px rgba(0, 0, 0, 0.6);
}

html[data-theme="dark"] .ch-qrlib-meter-track {
    background-color: #334155;
}

html[data-theme="dark"] .ch-qrlib-new,
html[data-theme="dark"] .ch-qrlib-btn,
html[data-theme="dark"] .ch-qrlib-btn:focus,
html[data-theme="dark"] .ch-qrlib-btn:active {
    background-color: #1E293B;
    color: #CBD5E1;
}

html[data-theme="dark"] .ch-qrlib-new {
    color: var(--ch-text-main);
}

html[data-theme="dark"] .ch-qrlib-btn:hover {
    background-color: #273449;
    border-color: #64748B;
    color: #F8FAFC;
}

html[data-theme="dark"] .ch-qrlib-btn.is-accent,
html[data-theme="dark"] .ch-qrlib-btn.is-accent:focus,
html[data-theme="dark"] .ch-qrlib-btn.is-accent:active {
    background-color: rgba(16, 185, 129, 0.12);
    border-color: rgba(52, 211, 153, 0.4);
    color: #6EE7B7;
}

html[data-theme="dark"] .ch-qrlib-btn.is-accent:hover {
    background-color: var(--ch-cta);
    border-color: var(--ch-cta);
    color: #04241C;
}

/* The thumbnail stays a white well in both themes: a QR code needs a light
   ground to read as a QR code, and the row surface provides the contrast. */
html[data-theme="dark"] .ch-qrlib-thumb {
    background-color: #FFFFFF;
    border-color: #475569;
}

html[data-theme="dark"] .ch-qrlib-badge {
    background-color: rgba(16, 185, 129, 0.16);
    color: #6EE7B7;
}

html[data-theme="dark"] .ch-qrlib-badge.is-off {
    background-color: rgba(148, 163, 184, 0.14);
    color: #94A3B8;
}

html[data-theme="dark"] .ch-qrlib-btn.is-primary,
html[data-theme="dark"] .ch-qrlib-btn.is-primary:focus,
html[data-theme="dark"] .ch-qrlib-btn.is-primary:active {
    background-color: var(--ch-cta);
    color: #04241C;
}

html[data-theme="dark"] .ch-qrlib-btn.is-primary:hover {
    background-color: #34D399;
    border-color: #34D399;
    color: #04241C;
}

html[data-theme="dark"] .ch-qrlib-btn.is-warn:hover {
    color: #FCD34D;
    border-color: #92400E;
    background-color: rgba(245, 158, 11, 0.1);
}

html[data-theme="dark"] .ch-qrlib-btn.is-danger:hover {
    color: #FCA5A5;
    border-color: #7F1D1D;
    background-color: rgba(239, 68, 68, 0.1);
}

/* ==========================================================================
   18. QR CODE EDITOR
   A view inside the QR library card, swapped in for the list by portal.js.
   It replaced a modal dialog when a saved code learned to change its type:
   switching a printed code from a website to a business card rewrites every
   field on screen, and the owner has to see what the next scan will open
   while they decide. That needs a page, not an overlay.

   Two columns on desktop. The form on the left, and on the right, sticky, the
   two things the form is about: the printed code (which never changes) and a
   phone showing the page the next scan opens (which is what they are
   changing). Below 1024px the aside dissolves into the flow with
   display: contents, so a phone reads: the printed code, the form, then the
   preview, without a second copy of either block in the markup.

   Every button here states its :hover, :focus and :active background. The
   parent theme paints button:hover and button:focus charcoal at (0,1,1), and
   a control that only sets a hover colour inherits that charcoal. That is the
   exact bug the library chips shipped with.

   Layer discipline. The whole theme's fixed furniture sits on one ladder and
   every overlay reads from it rather than inventing a number:
     header 100 / mobile nav 300-320 / quick login 9000 /
     portal overlays 9500-9600 / toasts 9999.
   The confirm dialog (18b) takes the top overlay step. The editor's save bar
   is sticky inside the page, so it only needs to clear its own siblings.
   ========================================================================== */

:root {
    --ch-layer-overlay: 9500;
    --ch-layer-overlay-top: 9600;

    --ch-qre-well: #F8FAFC;
    --ch-qre-well-border: #E2E8F0;
    --ch-qre-ink-soft: #475569;
    --ch-qre-sel-bg: #F0FDF8;
    --ch-qre-sel-ring: rgba(16, 185, 129, 0.18);
    --ch-qre-bar-bg: rgba(255, 255, 255, 0.9);
    --ch-qre-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 12px 28px -20px rgba(15, 23, 42, 0.32);
    /* Clearance for the sticky site header, the same figure the tool pages
       use for scroll-margin-top. */
    --ch-qre-top: 104px;
}

html[data-theme="dark"] {
    --ch-qre-well: #0F172A;
    --ch-qre-well-border: #334155;
    --ch-qre-ink-soft: #CBD5E1;
    --ch-qre-sel-bg: rgba(16, 185, 129, 0.08);
    --ch-qre-sel-ring: rgba(52, 211, 153, 0.22);
    --ch-qre-bar-bg: rgba(30, 41, 59, 0.9);
    --ch-qre-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 16px 32px -22px rgba(0, 0, 0, 0.75);
}

html.ch-cd-open {
    overflow: hidden;
}

/* Every dashboard card lifts on hover. With an editor inside, that is a whole
   page shifting under the cursor on every mouse move, so the lift is off for
   as long as the editor is open. */
.ch-card-qr.is-editing,
.ch-card-qr.is-editing:hover {
    transform: none;
}

.ch-qrlib-view[hidden],
.ch-qre[hidden] {
    display: none;
}

.ch-qre {
    animation: ch-qre-in 0.32s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* --- Breadcrumb --- */
.ch-qre-crumbs {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.55rem;
    margin: 0 0 1.35rem;
}

.ch-qre-back,
.ch-qre-back:focus,
.ch-qre-back:active {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.42rem 0.8rem 0.42rem 0.62rem;
    border: 1px solid var(--ch-border);
    border-radius: 999px;
    background-color: var(--ch-bg-card);
    color: var(--ch-text-main);
    font-family: inherit;
    font-size: 0.82rem;
    font-weight: 700;
    line-height: 1.2;
    cursor: pointer;
    transition: color 0.18s, border-color 0.18s, background-color 0.18s;
}

.ch-qre-back svg {
    transition: transform 0.18s;
}

.ch-qre-back:hover {
    border-color: var(--ch-cta);
    background-color: #ECFDF5;
    color: #047857;
}

.ch-qre-back:hover svg {
    transform: translateX(-2px);
}

.ch-qre-back:focus-visible {
    outline: 2px solid var(--ch-cta);
    outline-offset: 2px;
}

.ch-qre-crumb-sep {
    color: #CBD5E1;
    font-weight: 700;
}

.ch-qre-crumb {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--ch-text-muted);
    overflow-wrap: anywhere;
}

/* --- Heading --- */
.ch-qre-head {
    max-width: 74ch;
    margin-bottom: 1.5rem;
}

.ch-qre-eyebrow {
    display: inline-block;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.7rem;
    font-weight: 800;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #059669;
}

.ch-qre-title {
    margin: 0.45rem 0 0.55rem;
    font-size: clamp(1.3rem, 2.3vw, 1.62rem);
    font-weight: 800;
    line-height: 1.2;
    letter-spacing: -0.022em;
    color: var(--ch-text-main);
}

.ch-qre-title:focus {
    outline: none;
}

.ch-qre-lead {
    margin: 0;
    color: var(--ch-qre-ink-soft);
    font-size: 0.95rem;
    line-height: 1.65;
}

.ch-qre-lead strong {
    color: var(--ch-text-main);
}

.ch-qre-lead-code {
    padding: 0.08rem 0.42rem;
    border: 1px solid var(--ch-qre-well-border);
    border-radius: 6px;
    background-color: var(--ch-qre-well);
    color: var(--ch-text-main);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.84em;
    font-weight: 700;
    white-space: nowrap;
}

/* --- Paused strip --- */
.ch-qre-paused[hidden] {
    display: none;
}

.ch-qre-paused {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    margin: 0 0 1.25rem;
    padding: 0.8rem 1rem;
    border: 1px solid #FCD34D;
    border-radius: 12px;
    background-color: #FFFBEB;
    color: #78350F;
    font-size: 0.88rem;
    line-height: 1.55;
}

.ch-qre-paused-ico {
    flex-shrink: 0;
    display: inline-flex;
    color: #B45309;
}

.ch-qre-paused-copy {
    flex: 1 1 auto;
    min-width: 0;
}

.ch-qre-paused-copy strong {
    color: #78350F;
}

/* --- Layout --- */
.ch-qre-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 372px;
    gap: 1.75rem;
    align-items: start;
}

.ch-qre-form {
    display: grid;
    gap: 1.2rem;
    min-width: 0;
}

/* Stretched to the height of the row, so the sticky block inside it has room
   to travel. A sticky child can only stick inside a parent taller than
   itself, and align-items: start above would otherwise shrink this to fit. */
.ch-qre-side {
    align-self: stretch;
    min-width: 0;
}

.ch-qre-side-inner {
    position: sticky;
    top: var(--ch-qre-top);
    display: grid;
    gap: 1rem;
}

.ch-qre-loading {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.2rem 0;
    color: var(--ch-text-muted);
    font-size: 0.9rem;
}

.ch-qre-loading[hidden] {
    display: none;
}

.ch-qre-spin {
    flex-shrink: 0;
    width: 16px;
    height: 16px;
    border: 2px solid rgba(16, 185, 129, 0.25);
    border-top-color: var(--ch-cta);
    border-radius: 50%;
    animation: ch-spin 0.7s linear infinite;
}

/* --- Form blocks ---
   Fieldsets, so one `disabled` attribute locks every control inside until
   the stored content has arrived. The legend is floated to escape the border
   notch browsers draw for it, and every sibling clears it. */
.ch-qre-block {
    min-inline-size: 0;
    margin: 0;
    padding: 1.2rem 1.3rem 1.35rem;
    border: 1px solid var(--ch-border);
    border-radius: 14px;
    background-color: var(--ch-bg-card);
    box-shadow: var(--ch-qre-shadow);
    transition: opacity 0.2s;
}

.ch-qre-block[disabled] {
    opacity: 0.55;
}

.ch-qre-block > :not(legend) {
    clear: both;
}

.ch-qre-block-title {
    float: left;
    width: 100%;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0 0 0.35rem;
    padding: 0;
    color: var(--ch-text-main);
    font-size: 1rem;
    font-weight: 800;
    letter-spacing: -0.01em;
}

.ch-qre-step {
    display: inline-grid;
    place-items: center;
    width: 22px;
    height: 22px;
    border: 1px solid #A7F3D0;
    border-radius: 7px;
    background-color: #ECFDF5;
    color: #047857;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.72rem;
    font-weight: 800;
}

.ch-qre-block-hint {
    margin: 0 0 1rem;
    color: var(--ch-text-muted);
    font-size: 0.88rem;
    line-height: 1.55;
}

/* --- Type picker ---
   Real radio inputs, visually hidden but focusable, so arrow keys move the
   selection the way a radio group should. portal.js mirrors the checked state
   onto the label as .is-selected. */
.ch-qre-types {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.65rem;
}

.ch-qre-type {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.85rem 0.9rem;
    border: 1px solid var(--ch-border);
    border-radius: 12px;
    background-color: var(--ch-bg-card);
    cursor: pointer;
    transition: border-color 0.18s, box-shadow 0.18s, background-color 0.18s, transform 0.18s;
}

.ch-qre-type:hover {
    border-color: #94A3B8;
    transform: translateY(-1px);
}

.ch-qre-block[disabled] .ch-qre-type {
    cursor: default;
    transform: none;
}

.ch-qre-type-input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    opacity: 0;
    pointer-events: none;
}

.ch-qre-type:has(.ch-qre-type-input:focus-visible) {
    outline: 2px solid var(--ch-cta);
    outline-offset: 2px;
}

.ch-qre-type.is-selected {
    border-color: var(--ch-cta);
    background-color: var(--ch-qre-sel-bg);
    box-shadow: 0 0 0 3px var(--ch-qre-sel-ring);
    transform: none;
}

.ch-qre-type-ico {
    flex-shrink: 0;
    display: inline-grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border: 1px solid transparent;
    border-radius: 10px;
}

/* The same four tints as the type badges in the list, so a row and its
   editor agree on what colour a business card is. */
.ch-qre-type.is-website .ch-qre-type-ico {
    border-color: rgba(59, 130, 246, 0.28);
    background-color: rgba(59, 130, 246, 0.1);
    color: #1D4ED8;
}

.ch-qre-type.is-vcard .ch-qre-type-ico {
    border-color: rgba(139, 92, 246, 0.28);
    background-color: rgba(139, 92, 246, 0.1);
    color: #6D28D9;
}

.ch-qre-type.is-wifi .ch-qre-type-ico {
    border-color: rgba(14, 165, 233, 0.28);
    background-color: rgba(14, 165, 233, 0.1);
    color: #0369A1;
}

.ch-qre-type.is-text .ch-qre-type-ico {
    border-color: rgba(100, 116, 139, 0.28);
    background-color: rgba(100, 116, 139, 0.1);
    color: #475569;
}

.ch-qre-type-text {
    display: grid;
    gap: 0.18rem;
    min-width: 0;
    padding-right: 3.6rem;
}

.ch-qre-type-name {
    color: var(--ch-text-main);
    font-size: 0.93rem;
    font-weight: 800;
    line-height: 1.3;
}

.ch-qre-type-desc {
    color: var(--ch-text-muted);
    font-size: 0.8rem;
    line-height: 1.45;
}

.ch-qre-type-now[hidden] {
    display: none;
}

.ch-qre-type-now {
    position: absolute;
    top: 0.6rem;
    right: 0.6rem;
    padding: 0.22rem 0.42rem;
    border: 1px solid var(--ch-qre-well-border);
    border-radius: 999px;
    background-color: var(--ch-qre-well);
    color: var(--ch-text-muted);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.56rem;
    font-weight: 800;
    letter-spacing: 0.08em;
    line-height: 1;
    text-transform: uppercase;
}

.ch-qre-type-tick {
    position: absolute;
    right: 0.65rem;
    bottom: 0.65rem;
    display: inline-flex;
    color: var(--ch-cta);
    opacity: 0;
    transform: scale(0.6);
    transition: opacity 0.18s, transform 0.18s;
}

.ch-qre-type.is-selected .ch-qre-type-tick {
    opacity: 1;
    transform: none;
}

/* --- Type-switch notice --- */
.ch-qre-switch[hidden] {
    display: none;
}

.ch-qre-switch {
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    margin-top: 0.95rem;
    padding: 0.8rem 0.95rem;
    border: 1px solid rgba(59, 130, 246, 0.3);
    border-radius: 11px;
    background-color: rgba(59, 130, 246, 0.06);
    color: #1E3A8A;
    font-size: 0.88rem;
    line-height: 1.55;
    animation: ch-qre-in 0.24s ease both;
}

.ch-qre-switch-ico {
    flex-shrink: 0;
    display: inline-flex;
    margin-top: 0.12rem;
    color: #2563EB;
}

.ch-qre-switch-copy {
    margin: 0;
}

.ch-qre-switch-copy strong {
    color: #1E3A8A;
}

/* --- Fields ---
   The shared field primitives are tuned for a 380px auth column; here they
   sit in a wide panel and step up one size, exactly as the old dialog did. */
.ch-qre-group {
    margin-top: 0.85rem;
}

.ch-qre-group[hidden] {
    display: none;
}

.ch-qre .ch-field {
    margin-bottom: 0;
}

.ch-qre .ch-field-label {
    margin-bottom: 0.4rem;
    color: var(--ch-qre-ink-soft);
    font-size: 0.72rem;
    letter-spacing: 0.08em;
}

.ch-qre .ch-input {
    padding: 0.72rem 0.9rem;
    border-radius: 9px;
    font-size: 0.98rem;
}

.ch-qre .ch-input:hover {
    border-color: #CBD5E1;
}

.ch-qre .ch-input:focus {
    border-color: var(--ch-cta);
}

.ch-qre textarea.ch-input {
    min-height: 9rem;
    line-height: 1.6;
    resize: vertical;
}

.ch-qre .ch-field-hint {
    margin-top: 0.4rem;
    font-size: 0.82rem;
    line-height: 1.5;
}

.ch-qre-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.9rem 0.85rem;
}

.ch-qre-grid .col-2 {
    grid-column: span 2;
}

.ch-qre-grid .ch-field[hidden] {
    display: none;
}

.ch-qre-note {
    margin: 1rem 0 0;
    padding: 0.7rem 0.85rem;
    border-left: 3px solid rgba(16, 185, 129, 0.55);
    border-radius: 9px;
    background-color: var(--ch-qre-well);
    color: var(--ch-qre-ink-soft);
    font-size: 0.86rem;
    line-height: 1.55;
}

/* Custom checkbox: the native input stays in the DOM for the keyboard and
   the form, the box beside it carries the look in both themes. */
.ch-qre-check {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-top: 0.95rem;
    color: var(--ch-qre-ink-soft);
    font-size: 0.9rem;
    line-height: 1.45;
    cursor: pointer;
}

.ch-qre-check input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    opacity: 0;
}

.ch-qre-check-box {
    flex-shrink: 0;
    position: relative;
    width: 20px;
    height: 20px;
    border: 1.5px solid #CBD5E1;
    border-radius: 6px;
    background-color: var(--ch-bg-card);
    transition: background-color 0.15s, border-color 0.15s;
}

.ch-qre-check-box::after {
    content: '';
    position: absolute;
    left: 6px;
    top: 2px;
    width: 5px;
    height: 10px;
    border: solid #FFFFFF;
    border-width: 0 2px 2px 0;
    opacity: 0;
    transform: rotate(45deg);
}

.ch-qre-check input:checked + .ch-qre-check-box {
    border-color: var(--ch-cta);
    background-color: var(--ch-cta);
}

.ch-qre-check input:checked + .ch-qre-check-box::after {
    opacity: 1;
}

.ch-qre-check input:focus-visible + .ch-qre-check-box {
    outline: 2px solid var(--ch-cta);
    outline-offset: 2px;
}

.ch-qre .ch-form-alert {
    margin: 0;
    font-size: 0.9rem;
    line-height: 1.5;
}

/* --- Save bar ---
   Sticky to the bottom of the viewport while the form is on screen, so the
   Save button is never a scroll away from the field just edited, and it comes
   to rest at the end of the form. */
.ch-qre-bar {
    position: sticky;
    bottom: 0.75rem;
    z-index: 6;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.75rem 1rem;
    padding: 0.75rem 0.85rem 0.75rem 1.05rem;
    border: 1px solid var(--ch-border);
    border-radius: 14px;
    background-color: var(--ch-qre-bar-bg);
    -webkit-backdrop-filter: blur(10px) saturate(1.2);
    backdrop-filter: blur(10px) saturate(1.2);
    box-shadow: 0 -10px 30px -24px rgba(15, 23, 42, 0.4), var(--ch-qre-shadow);
}

.ch-qre-state {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--ch-text-muted);
    font-size: 0.86rem;
    font-weight: 600;
}

.ch-qre-state-dot {
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: #CBD5E1;
}

.ch-qre-state[data-kind="dirty"] {
    color: #B45309;
}

.ch-qre-state[data-kind="dirty"] .ch-qre-state-dot {
    background-color: #F59E0B;
    box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);
}

.ch-qre-state[data-kind="saving"] .ch-qre-state-dot {
    background-color: var(--ch-cta);
    animation: ch-pulse 1.2s ease-out infinite;
}

.ch-qre-state[data-kind="saved"] {
    color: #047857;
}

.ch-qre-state[data-kind="saved"] .ch-qre-state-dot {
    background-color: var(--ch-cta);
}

.ch-qre-state[data-kind="error"] {
    color: #B91C1C;
}

.ch-qre-state[data-kind="error"] .ch-qre-state-dot {
    background-color: #EF4444;
}

.ch-qre-bar-actions {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-left: auto;
}

/* --- Buttons --- */
.ch-qre-btn,
.ch-qre-btn:focus,
.ch-qre-btn:active {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    padding: 0.62rem 1rem;
    border: 1px solid var(--ch-border);
    border-radius: 9px;
    background-color: var(--ch-bg-card);
    color: var(--ch-text-main);
    font-family: inherit;
    font-size: 0.88rem;
    font-weight: 700;
    line-height: 1.2;
    cursor: pointer;
    transition: color 0.18s, border-color 0.18s, background-color 0.18s;
}

.ch-qre-btn:hover {
    border-color: #94A3B8;
    background-color: var(--ch-qre-well);
    color: var(--ch-text-main);
}

.ch-qre-btn:focus-visible {
    outline: 2px solid var(--ch-cta);
    outline-offset: 2px;
}

.ch-qre-btn[disabled],
.ch-qre-btn[disabled]:hover {
    border-color: var(--ch-border);
    background-color: var(--ch-bg-card);
    color: var(--ch-text-muted);
    opacity: 0.55;
    cursor: not-allowed;
}

.ch-qre-btn.is-small {
    flex-shrink: 0;
    padding: 0.45rem 0.85rem;
    font-size: 0.8rem;
}

.ch-qre-btn .ch-btn-spinner {
    border-color: rgba(100, 116, 139, 0.3);
    border-top-color: var(--ch-text-main);
}

/* Emerald 700 in light, not the brand #10B981: white text on #10B981 is
   2.5:1, which is below any readable threshold for a 14px label. Dark mode
   keeps the brand green and flips the text to near-black instead (below). */
.ch-qre-save,
.ch-qre-save:focus,
.ch-qre-save:active {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-width: 176px;
    padding: 0.66rem 1.25rem;
    border: 1px solid #047857;
    border-radius: 9px;
    background-color: #047857;
    color: #FFFFFF;
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 800;
    line-height: 1.2;
    cursor: pointer;
    box-shadow: 0 8px 18px -10px rgba(16, 185, 129, 0.75);
    transition: background-color 0.18s, border-color 0.18s, transform 0.18s, box-shadow 0.18s;
}

.ch-qre-save:hover {
    border-color: #065F46;
    background-color: #065F46;
    color: #FFFFFF;
    transform: translateY(-1px);
}

.ch-qre-save:focus-visible {
    outline: 2px solid var(--ch-cta);
    outline-offset: 3px;
}

.ch-qre-save[disabled],
.ch-qre-save[disabled]:hover {
    border-color: var(--ch-border);
    background-color: var(--ch-qre-well);
    color: var(--ch-text-muted);
    box-shadow: none;
    transform: none;
    cursor: not-allowed;
}

.ch-qre-save.is-loading {
    cursor: wait;
}

/* --- Aside cards --- */
.ch-qre-printed,
.ch-qre-preview {
    padding: 1.05rem 1.1rem 1.1rem;
    border: 1px solid var(--ch-border);
    border-radius: 14px;
    background-color: var(--ch-bg-card);
    box-shadow: var(--ch-qre-shadow);
}

.ch-qre-side-label {
    display: block;
    color: var(--ch-text-muted);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.66rem;
    font-weight: 800;
    letter-spacing: 0.12em;
    line-height: 1.2;
    text-transform: uppercase;
}

.ch-qre-printed-body {
    display: flex;
    align-items: center;
    gap: 0.95rem;
    margin-top: 0.8rem;
}

/* The well stays white in both themes: a stored snapshot can be a dark code
   on a transparent ground, and on a slate tile that is an invisible code. */
/* Flex, not grid, and max-* rather than width/height: 100%. A stored snapshot
   is only square when it has no frame; with a label frame ("SCAN ME") it is
   taller than wide. Inside a grid cell the percentage height did not resolve
   against the well, so the image laid out at full width, grew taller than the
   well and lost its label to overflow: hidden. Max sizes against a flex box
   of fixed height scale any aspect ratio to fit, whole. */
.ch-qre-thumb {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 116px;
    height: 116px;
    padding: 7px;
    border: 1px solid var(--ch-border);
    border-radius: 12px;
    background-color: #FFFFFF;
    overflow: hidden;
}

.ch-qre-thumb img,
.ch-qre-thumb canvas {
    display: block;
    flex: 0 1 auto;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    min-width: 0;
    min-height: 0;
    object-fit: contain;
}

/* The fallback canvas is always a square plain code and carries its pixel
   size as attributes, so it gets an explicit box to shrink into. */
.ch-qre-thumb canvas {
    width: 100%;
    height: 100%;
    image-rendering: pixelated;
}

.ch-qre.is-paused .ch-qre-thumb img,
.ch-qre.is-paused .ch-qre-thumb canvas {
    filter: grayscale(1);
    opacity: 0.7;
}

.ch-qre-printed-meta {
    display: grid;
    gap: 0.5rem;
    min-width: 0;
}

.ch-qre-short-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    min-width: 0;
    margin-top: 0.75rem;
    padding: 0.4rem 0.4rem 0.4rem 0.7rem;
    border: 1px solid var(--ch-qre-well-border);
    border-radius: 10px;
    background-color: var(--ch-qre-well);
}

.ch-qre-short {
    min-width: 0;
    color: var(--ch-text-main);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1.35;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ch-qre-icon-btn,
.ch-qre-icon-btn:focus,
.ch-qre-icon-btn:active {
    flex-shrink: 0;
    display: inline-grid;
    place-items: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid var(--ch-border);
    border-radius: 7px;
    background-color: var(--ch-bg-card);
    color: var(--ch-text-muted);
    cursor: pointer;
    transition: color 0.18s, border-color 0.18s, background-color 0.18s;
}

.ch-qre-icon-btn:hover {
    border-color: var(--ch-cta);
    background-color: #ECFDF5;
    color: #047857;
}

.ch-qre-icon-btn:focus-visible {
    outline: 2px solid var(--ch-cta);
    outline-offset: 2px;
}

.ch-qre-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.ch-qre-badges .ch-qrlib-type:empty,
.ch-qre-badges .ch-qrlib-badge:empty {
    display: none;
}

.ch-qre-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    margin: 0;
}

.ch-qre-stats dt {
    color: var(--ch-text-muted);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.58rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.ch-qre-stats dd {
    margin: 0.25rem 0 0;
    color: var(--ch-text-main);
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.95rem;
    font-weight: 800;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.ch-qre-stats div:last-child dd {
    padding-top: 0.12rem;
    font-size: 0.76rem;
}

.ch-qre-side-note {
    display: flex;
    align-items: flex-start;
    gap: 0.45rem;
    margin: 0.85rem 0 0;
    padding-top: 0.75rem;
    border-top: 1px dashed var(--ch-border);
    color: var(--ch-qre-ink-soft);
    font-size: 0.8rem;
    line-height: 1.5;
}

.ch-qre-side-note svg {
    flex-shrink: 0;
    margin-top: 0.15rem;
    color: var(--ch-cta);
}

/* --- Live preview --- */
.ch-qre-preview-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.85rem;
}

.ch-qre-scheme {
    display: inline-flex;
    padding: 3px;
    border: 1px solid var(--ch-qre-well-border);
    border-radius: 9px;
    background-color: var(--ch-qre-well);
}

.ch-qre-scheme-btn,
.ch-qre-scheme-btn:focus,
.ch-qre-scheme-btn:active {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.55rem;
    border: 0;
    border-radius: 6px;
    background-color: transparent;
    color: var(--ch-text-muted);
    font-family: inherit;
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1.2;
    cursor: pointer;
    transition: color 0.18s, background-color 0.18s, box-shadow 0.18s;
}

.ch-qre-scheme-btn:hover {
    background-color: transparent;
    color: var(--ch-text-main);
}

.ch-qre-scheme-btn[aria-pressed="true"] {
    background-color: var(--ch-bg-card);
    color: var(--ch-text-main);
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.14);
}

.ch-qre-scheme-btn:focus-visible {
    outline: 2px solid var(--ch-cta);
    outline-offset: 1px;
}

/* The handset is hardcoded slate in both themes, like every other dark
   DevSecOps panel on the site: it is a device, not a surface of the page. */
.ch-qre-phone {
    position: relative;
    width: min(100%, 312px);
    margin: 0 auto;
    padding: 10px;
    border-radius: 40px;
    background-color: #0F172A;
    box-shadow: inset 0 0 0 1.5px #334155,
                0 0 0 1px rgba(15, 23, 42, 0.08),
                0 26px 50px -26px rgba(15, 23, 42, 0.6);
}

.ch-qre-phone-bar {
    position: absolute;
    top: 17px;
    left: 50%;
    z-index: 2;
    width: 74px;
    height: 20px;
    margin-left: -37px;
    border-radius: 999px;
    background-color: #020617;
}

.ch-qre-screen {
    position: relative;
    height: clamp(380px, calc(100vh - 480px), 560px);
    border-radius: 31px;
    background-color: #F8FAFC;
    overflow: hidden;
}

.ch-qre-phone[data-scheme="dark"] .ch-qre-screen {
    background-color: #0B1220;
}

/* A thin sweep along the top edge while a fresh preview is on its way. The
   previous render stays visible underneath, so typing never blanks the phone. */
.ch-qre-phone.is-updating .ch-qre-screen::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    z-index: 3;
    width: 38%;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--ch-cta), transparent);
    animation: ch-qre-sweep 0.9s linear infinite;
}

/* Stacked, because for a moment there are two: the visible render and the
   next one loading on top of it. The pending frame is invisible rather than
   display: none, so it has a layout for portal.js to restore the scroll
   position into before it is revealed.

   Rendered at a real phone's width, then shrunk. The frame is laid out at
   375 CSS pixels, an iPhone's logical width, and scaled by --ch-qre-scale
   (screen width / 375, kept current by a ResizeObserver in portal.js). Laid
   out at the mockup's own 270 to 296px instead, the hosted card wrapped its
   button label and every long line like no phone ever would, which is not a
   preview of anything. The height is divided by the same factor so the
   scaled frame still fills the screen exactly.

   max-width: none is load-bearing. GeneratePress ships
   `embed, iframe, object { max-width: 100% }`, which clamped the 375px frame
   to the ~270px screen; the scale then shrank it a second time and the card
   sat in the left two thirds of the phone with an empty strip on the right. */
.ch-qre-frame {
    position: absolute;
    top: 0;
    left: 0;
    display: block;
    width: 375px;
    max-width: none;
    max-height: none;
    height: calc(100% / var(--ch-qre-scale, 1));
    border: 0;
    background-color: transparent;
    transform: scale(var(--ch-qre-scale, 1));
    transform-origin: 0 0;
}

.ch-qre-frame.is-pending {
    visibility: hidden;
}

.ch-qre-redirect[hidden],
.ch-qre-screen-wait[hidden] {
    display: none;
}

.ch-qre-screen-wait {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
}

/* Website codes have no hosted page to render: the scan is a bare redirect.
   The phone says so instead of showing a page that does not exist. */
.ch-qre-redirect {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    background-color: #F8FAFC;
    color: #0F172A;
}

.ch-qre-phone[data-scheme="dark"] .ch-qre-redirect {
    background-color: #0B1220;
    color: #F1F5F9;
}

.ch-qre-urlbar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    margin: 44px 14px 0;
    padding: 0.45rem 0.75rem;
    border-radius: 999px;
    background-color: rgba(15, 23, 42, 0.06);
    color: #334155;
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
}

.ch-qre-urlbar svg {
    flex-shrink: 0;
    color: #059669;
}

.ch-qre-urlbar span {
    overflow: hidden;
    text-overflow: ellipsis;
}

.ch-qre-phone[data-scheme="dark"] .ch-qre-urlbar {
    background-color: rgba(148, 163, 184, 0.12);
    color: #CBD5E1;
}

.ch-qre-redirect-body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.55rem;
    padding: 1rem 1.3rem 2rem;
    text-align: center;
}

.ch-qre-redirect-ico {
    display: grid;
    place-items: center;
    width: 54px;
    height: 54px;
    margin-bottom: 0.2rem;
    border-radius: 16px;
    background-color: rgba(59, 130, 246, 0.1);
    color: #2563EB;
}

.ch-qre-redirect-body strong {
    font-size: 1rem;
    font-weight: 800;
    letter-spacing: -0.01em;
}

.ch-qre-redirect-body p {
    margin: 0;
    color: #64748B;
    font-size: 0.8rem;
    line-height: 1.5;
}

.ch-qre-redirect-body code {
    max-width: 100%;
    padding: 0.5rem 0.65rem;
    border: 1px solid rgba(15, 23, 42, 0.08);
    border-radius: 9px;
    background-color: rgba(15, 23, 42, 0.04);
    color: inherit;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.45;
    overflow-wrap: anywhere;
}

.ch-qre-phone[data-scheme="dark"] .ch-qre-redirect-ico {
    background-color: rgba(96, 165, 250, 0.14);
    color: #93C5FD;
}

.ch-qre-phone[data-scheme="dark"] .ch-qre-redirect-body p {
    color: #94A3B8;
}

.ch-qre-phone[data-scheme="dark"] .ch-qre-redirect-body code {
    border-color: rgba(148, 163, 184, 0.18);
    background-color: rgba(148, 163, 184, 0.08);
}

.ch-qre-issue[hidden] {
    display: none;
}

.ch-qre-issue {
    margin: 0.85rem 0 0;
    padding: 0.55rem 0.75rem;
    border: 1px solid #FDE68A;
    border-radius: 9px;
    background-color: #FFFBEB;
    color: #92400E;
    font-size: 0.8rem;
    line-height: 1.45;
}

.ch-qre-preview-note {
    margin: 0.75rem 0 0;
    color: var(--ch-text-muted);
    font-size: 0.78rem;
    line-height: 1.5;
    text-align: center;
}

.ch-qre-live {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    margin-top: 0.5rem;
    color: var(--ch-text-main);
    font-size: 0.8rem;
    font-weight: 700;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.ch-qre-live:hover {
    color: #047857;
}

@keyframes ch-qre-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

@keyframes ch-qre-sweep {
    from { transform: translateX(-100%); }
    to   { transform: translateX(270%); }
}

/* --- Tablet and phone ---
   The aside and its sticky wrapper dissolve with display: contents, so their
   three children join the layout grid and take an order of their own: the
   printed code first (what am I editing), the form, then the preview. */
@media (max-width: 1024px) {
    .ch-qre-layout {
        grid-template-columns: minmax(0, 1fr);
        gap: 1.1rem;
    }

    .ch-qre-side,
    .ch-qre-side-inner {
        display: contents;
    }

    .ch-qre-printed {
        order: -1;
    }

    .ch-qre-preview {
        order: 1;
    }

    .ch-qre-screen {
        height: 520px;
    }
}

@media (max-width: 640px) {
    .ch-qre-crumbs {
        margin-bottom: 1.1rem;
    }

    .ch-qre-crumb-sep,
    .ch-qre-crumb {
        display: none;
    }

    .ch-qre-lead-code {
        white-space: normal;
        overflow-wrap: anywhere;
    }

    .ch-qre-paused {
        flex-wrap: wrap;
    }

    .ch-qre-block {
        padding: 1rem 1rem 1.15rem;
        border-radius: 12px;
    }

    .ch-qre-types,
    .ch-qre-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .ch-qre-grid .col-2 {
        grid-column: span 1;
    }

    .ch-qre-type {
        padding: 0.75rem 0.8rem;
    }

    .ch-qre-thumb {
        width: 84px;
        height: 84px;
    }

    .ch-qre-bar {
        bottom: 0;
        padding: 0.7rem 0.75rem calc(0.7rem + env(safe-area-inset-bottom));
        border-radius: 12px;
    }

    .ch-qre-bar-actions {
        width: 100%;
        margin-left: 0;
    }

    .ch-qre-bar-actions .ch-qre-btn {
        flex: 0 0 auto;
    }

    .ch-qre-save {
        flex: 1 1 auto;
        min-width: 0;
    }

    .ch-qre-screen {
        height: 500px;
    }
}

/* --- dark --- */
html[data-theme="dark"] .ch-qre-back,
html[data-theme="dark"] .ch-qre-back:focus,
html[data-theme="dark"] .ch-qre-back:active {
    background-color: #1E293B;
}

html[data-theme="dark"] .ch-qre-back:hover {
    border-color: rgba(52, 211, 153, 0.55);
    background-color: rgba(16, 185, 129, 0.12);
    color: #6EE7B7;
}

html[data-theme="dark"] .ch-qre-crumb-sep {
    color: #475569;
}

html[data-theme="dark"] .ch-qre-eyebrow {
    color: #34D399;
}

html[data-theme="dark"] .ch-qre-paused {
    border-color: rgba(245, 158, 11, 0.38);
    background-color: rgba(245, 158, 11, 0.08);
    color: #FDE68A;
}

html[data-theme="dark"] .ch-qre-paused-copy strong {
    color: #FEF3C7;
}

html[data-theme="dark"] .ch-qre-paused-ico {
    color: #FCD34D;
}

html[data-theme="dark"] .ch-qre-step {
    border-color: rgba(52, 211, 153, 0.35);
    background-color: rgba(16, 185, 129, 0.12);
    color: #6EE7B7;
}

html[data-theme="dark"] .ch-qre-type:hover {
    border-color: #64748B;
}

html[data-theme="dark"] .ch-qre-type.is-selected {
    border-color: var(--ch-cta);
}

html[data-theme="dark"] .ch-qre-type.is-website .ch-qre-type-ico {
    border-color: rgba(96, 165, 250, 0.34);
    background-color: rgba(96, 165, 250, 0.14);
    color: #93C5FD;
}

html[data-theme="dark"] .ch-qre-type.is-vcard .ch-qre-type-ico {
    border-color: rgba(167, 139, 250, 0.34);
    background-color: rgba(167, 139, 250, 0.14);
    color: #C4B5FD;
}

html[data-theme="dark"] .ch-qre-type.is-wifi .ch-qre-type-ico {
    border-color: rgba(56, 189, 248, 0.34);
    background-color: rgba(56, 189, 248, 0.14);
    color: #7DD3FC;
}

html[data-theme="dark"] .ch-qre-type.is-text .ch-qre-type-ico {
    border-color: rgba(148, 163, 184, 0.34);
    background-color: rgba(148, 163, 184, 0.14);
    color: #CBD5E1;
}

html[data-theme="dark"] .ch-qre-type-tick {
    color: #34D399;
}

html[data-theme="dark"] .ch-qre-switch {
    border-color: rgba(96, 165, 250, 0.32);
    background-color: rgba(96, 165, 250, 0.08);
    color: #BFDBFE;
}

html[data-theme="dark"] .ch-qre-switch-copy strong {
    color: #DBEAFE;
}

html[data-theme="dark"] .ch-qre-switch-ico {
    color: #93C5FD;
}

html[data-theme="dark"] .ch-qre .ch-input:hover {
    border-color: #475569;
}

html[data-theme="dark"] .ch-qre .ch-input:focus {
    border-color: var(--ch-cta);
}

html[data-theme="dark"] .ch-qre-check-box {
    border-color: #475569;
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-qre-bar {
    box-shadow: 0 -10px 30px -24px rgba(0, 0, 0, 0.8), var(--ch-qre-shadow);
}

html[data-theme="dark"] .ch-qre-state[data-kind="dirty"] {
    color: #FCD34D;
}

html[data-theme="dark"] .ch-qre-state[data-kind="saved"] {
    color: #6EE7B7;
}

html[data-theme="dark"] .ch-qre-state[data-kind="error"] {
    color: #FCA5A5;
}

html[data-theme="dark"] .ch-qre-state-dot {
    background-color: #475569;
}

html[data-theme="dark"] .ch-qre-btn,
html[data-theme="dark"] .ch-qre-btn:focus,
html[data-theme="dark"] .ch-qre-btn:active,
html[data-theme="dark"] .ch-qre-icon-btn,
html[data-theme="dark"] .ch-qre-icon-btn:focus,
html[data-theme="dark"] .ch-qre-icon-btn:active {
    background-color: #1E293B;
}

html[data-theme="dark"] .ch-qre-btn:hover {
    border-color: #64748B;
    background-color: #273449;
    color: #F8FAFC;
}

html[data-theme="dark"] .ch-qre-btn[disabled],
html[data-theme="dark"] .ch-qre-btn[disabled]:hover {
    border-color: #334155;
    background-color: #1E293B;
    color: #94A3B8;
}

html[data-theme="dark"] .ch-qre-icon-btn:hover {
    border-color: rgba(52, 211, 153, 0.55);
    background-color: rgba(16, 185, 129, 0.12);
    color: #6EE7B7;
}

html[data-theme="dark"] .ch-qre-save,
html[data-theme="dark"] .ch-qre-save:focus,
html[data-theme="dark"] .ch-qre-save:active {
    border-color: var(--ch-cta);
    background-color: var(--ch-cta);
    color: #04241C;
}

html[data-theme="dark"] .ch-qre-save:hover {
    border-color: #34D399;
    background-color: #34D399;
    color: #04241C;
}

html[data-theme="dark"] .ch-qre-save .ch-btn-spinner {
    border-color: rgba(4, 36, 28, 0.3);
    border-top-color: #04241C;
}

html[data-theme="dark"] .ch-qre-save[disabled],
html[data-theme="dark"] .ch-qre-save[disabled]:hover {
    border-color: #334155;
    background-color: #0F172A;
    color: #64748B;
}

html[data-theme="dark"] .ch-qre-thumb {
    border-color: #475569;
}

html[data-theme="dark"] .ch-qre-scheme-btn[aria-pressed="true"] {
    background-color: #334155;
    color: #F8FAFC;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

html[data-theme="dark"] .ch-qre-phone {
    background-color: #020617;
    box-shadow: inset 0 0 0 1.5px #334155,
                0 0 0 1px rgba(148, 163, 184, 0.1),
                0 26px 50px -26px rgba(0, 0, 0, 0.9);
}

html[data-theme="dark"] .ch-qre-phone-bar {
    background-color: #000000;
}

html[data-theme="dark"] .ch-qre-issue {
    border-color: rgba(245, 158, 11, 0.32);
    background-color: rgba(245, 158, 11, 0.08);
    color: #FCD34D;
}

html[data-theme="dark"] .ch-qre-live:hover {
    color: #6EE7B7;
}

/* The neutral base surface moves like every other well in the dashboard, and
   the slots strip becomes the deep Premium panel, dark mode only. */
html[data-theme="dark"] .ch-qrlib-upsell {
    border-color: #334155;
    background-color: #0F172A;
}

html[data-theme="dark"] .ch-qrlib-upsell.is-slots {
    border-color: rgba(147, 197, 253, 0.3);
    background-color: #020617;
    background-image: radial-gradient(120% 140% at 100% 0%, rgba(59, 130, 246, 0.16) 0%, rgba(2, 6, 23, 0) 58%);
    box-shadow: 0 14px 30px -22px rgba(0, 0, 0, 0.9);
}

html[data-theme="dark"] .ch-qrlib-upsell.is-slots .ch-qrlib-upsell-ico {
    background-color: rgba(59, 130, 246, 0.16);
    color: #93C5FD;
}

html[data-theme="dark"] .ch-qrlib-upsell.is-slots .ch-qrlib-upsell-copy { color: #94A3B8; }
html[data-theme="dark"] .ch-qrlib-upsell.is-slots .ch-qrlib-upsell-copy strong { color: #F8FAFC; }
html[data-theme="dark"] .ch-qrlib-upsell.is-slots .ch-qrlib-upsell-copy span strong { color: #93C5FD; }

html[data-theme="dark"] .ch-qrlib-upsell-ico {
    background-color: rgba(52, 211, 153, 0.14);
    color: #34D399;
}

html[data-theme="dark"] .ch-qrlib-meter.is-full .ch-qrlib-meter-fill {
    background-color: #94A3B8;
}

html[data-theme="dark"] .ch-qrlib-type {
    background-color: rgba(148, 163, 184, 0.12);
    border-color: #334155;
}

html[data-theme="dark"] .ch-qrlib-type.is-website {
    border-color: rgba(96, 165, 250, 0.38);
    background-color: rgba(96, 165, 250, 0.14);
    color: #93C5FD;
}

html[data-theme="dark"] .ch-qrlib-type.is-vcard {
    border-color: rgba(167, 139, 250, 0.38);
    background-color: rgba(167, 139, 250, 0.14);
    color: #C4B5FD;
}

html[data-theme="dark"] .ch-qrlib-type.is-wifi {
    border-color: rgba(56, 189, 248, 0.38);
    background-color: rgba(56, 189, 248, 0.14);
    color: #7DD3FC;
}

html[data-theme="dark"] .ch-qrlib-type.is-text {
    border-color: rgba(148, 163, 184, 0.34);
    background-color: rgba(148, 163, 184, 0.14);
    color: #CBD5E1;
}

/* ==========================================================================
   18b. CONFIRM DIALOG
   Replaces window.confirm() for the two destructive QR library actions. A native
   confirm is not a styling problem, it is a product problem: it renders in the
   OS chrome, prints the bare origin as its title, cannot show which QR code is
   about to be destroyed, ignores the theme entirely, and on mobile it is a
   system sheet the user has been trained to dismiss without reading.

   Built by chConfirm() in portal.js and appended to <body>, not to the card it
   was fired from, so no ancestor transform or overflow can trap it. It sits one
   step above the edit dialog on the layer ladder because a confirm can be raised
   from inside another overlay and must never open behind its own trigger.
   ========================================================================== */

.ch-cd {
    position: fixed;
    inset: 0;
    z-index: var(--ch-layer-overlay-top, 9600);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.25rem;
    opacity: 0;
    transition: opacity 0.18s ease;
}

.ch-cd.is-active {
    opacity: 1;
}

.ch-cd-veil {
    position: absolute;
    inset: 0;
    background-color: rgba(15, 23, 42, 0.66);
    backdrop-filter: blur(6px) saturate(0.9);
    -webkit-backdrop-filter: blur(6px) saturate(0.9);
}

.ch-cd-card {
    position: relative;
    width: 100%;
    max-width: 540px;
    max-height: calc(100dvh - 2.5rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    display: grid;
    grid-template-columns: 46px minmax(0, 1fr);
    gap: 0.35rem 1rem;
    padding: 1.75rem 1.75rem 1.5rem;
    background-color: #FFFFFF;
    background-color: var(--ch-bg-card, #FFFFFF);
    color: var(--ch-text-main);
    border: 1px solid var(--ch-border);
    border-radius: 18px;
    box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.06),
                0 40px 80px -28px rgba(15, 23, 42, 0.55),
                0 12px 28px -18px rgba(15, 23, 42, 0.35);
    transform: translateY(10px) scale(0.985);
    transition: transform 0.2s cubic-bezier(0.2, 0.8, 0.3, 1);
}

.ch-cd.is-active .ch-cd-card {
    transform: none;
}

.ch-cd-card:focus {
    outline: none;
}

.ch-cd-x,
.ch-cd-x:focus,
.ch-cd-x:active {
    position: absolute;
    top: 0.9rem;
    right: 0.9rem;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: 9px;
    background-color: transparent;
    color: var(--ch-text-muted);
    cursor: pointer;
    transition: background-color 0.18s, color 0.18s;
}

.ch-cd-x:hover {
    background-color: var(--ch-bg-main);
    color: var(--ch-text-main);
}

/* The glyph is the only thing that changes between tones. Everything else stays
   identical so the two dialogs are read as the same object at two severities,
   not as two different components. */
.ch-cd-ico {
    grid-row: 1 / span 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 46px;
    border-radius: 13px;
    background-color: rgba(245, 158, 11, 0.13);
    color: #B45309;
}

.ch-cd.is-danger .ch-cd-ico {
    background-color: rgba(239, 68, 68, 0.12);
    color: #DC2626;
}

.ch-cd-main {
    min-width: 0;
    padding-right: 1.5rem;
}

.ch-cd-kicker {
    display: block;
    font-family: "JetBrains Mono", "Roboto Mono", monospace;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: #B45309;
}

.ch-cd.is-danger .ch-cd-kicker {
    color: #DC2626;
}

.ch-cd-title {
    margin: 0.4rem 0 0.55rem;
    font-size: 1.4rem;
    font-weight: 800;
    line-height: 1.24;
    letter-spacing: -0.02em;
    color: var(--ch-text-main);
}

.ch-cd-body {
    margin: 0;
    font-size: 0.97rem;
    line-height: 1.62;
    color: #475569;
}

.ch-cd-body strong {
    color: var(--ch-text-main);
    font-weight: 700;
}

/* The short code, spelled out. A native confirm could never show this, and it is
   the single most useful thing on the dialog: it is what proves the user is
   about to act on the row they think they clicked. */
.ch-cd-subject {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    margin-top: 0.9rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--ch-border);
    border-radius: 10px;
    background-color: var(--ch-bg-main);
    font-family: "JetBrains Mono", "Roboto Mono", monospace;
    font-size: 0.86rem;
    font-weight: 700;
    color: var(--ch-text-main);
    overflow-wrap: anywhere;
}

.ch-cd-subject svg {
    flex: 0 0 auto;
    color: var(--ch-text-muted);
}

.ch-cd-points {
    margin: 0.9rem 0 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 0.42rem;
}

.ch-cd-points li {
    display: flex;
    align-items: flex-start;
    gap: 0.55rem;
    font-size: 0.9rem;
    line-height: 1.5;
    color: #475569;
}

.ch-cd-points svg {
    flex: 0 0 auto;
    margin-top: 0.18rem;
    color: #94A3B8;
}

.ch-cd-points li.is-loss svg {
    color: #DC2626;
}

.ch-cd-points li.is-keep svg {
    color: #059669;
}

.ch-cd-actions {
    grid-column: 2;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-top: 1.35rem;
}

.ch-cd-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.68rem 1.15rem;
    border: 1px solid var(--ch-border);
    border-radius: 10px;
    background-color: var(--ch-bg-card, #FFFFFF);
    color: var(--ch-text-main);
    font-family: inherit;
    font-size: 0.94rem;
    font-weight: 700;
    line-height: 1.2;
    cursor: pointer;
    transition: background-color 0.16s, border-color 0.16s, color 0.16s, transform 0.16s, box-shadow 0.16s;
}

/* EVERY STATE STATES ITS TEXT COLOUR, NOT ONLY ITS BACKGROUND.
   GeneratePress ships `button:hover, button:focus { color: #fff;
   background-color: #3f4047 }` at (0,1,1). The old :hover here changed the
   background to the light page tint and left the colour alone, so the parent
   theme's white won and "Keep it live" turned into white text on near-white.
   Colour and background are now declared together on :hover, :focus and
   :active for every variant, at (0,2,0) and up. */
.ch-cd-btn:focus,
.ch-cd-btn:active {
    background-color: var(--ch-bg-card, #FFFFFF);
    color: var(--ch-text-main);
}

.ch-cd-btn:hover {
    background-color: var(--ch-bg-main);
    border-color: #94A3B8;
    color: var(--ch-text-main);
}

.ch-cd-btn:focus-visible {
    outline: 2px solid var(--ch-cta);
    outline-offset: 2px;
}

.ch-cd-btn.is-go,
.ch-cd-btn.is-go:focus,
.ch-cd-btn.is-go:active {
    border-color: transparent;
    background-color: #B45309;
    color: #FFFFFF;
}

.ch-cd-btn.is-go:hover {
    background-color: #92400E;
    border-color: transparent;
    color: #FFFFFF;
    transform: translateY(-1px);
    box-shadow: 0 10px 22px -12px rgba(180, 83, 9, 0.85);
}

.ch-cd.is-danger .ch-cd-btn.is-go,
.ch-cd.is-danger .ch-cd-btn.is-go:focus,
.ch-cd.is-danger .ch-cd-btn.is-go:active {
    background-color: #DC2626;
    color: #FFFFFF;
}

.ch-cd.is-danger .ch-cd-btn.is-go:hover {
    background-color: #B91C1C;
    color: #FFFFFF;
    box-shadow: 0 10px 22px -12px rgba(220, 38, 38, 0.85);
}

.ch-cd-btn[disabled] {
    opacity: 0.6;
    cursor: wait;
}

/* Phone: the icon rail collapses, the buttons go full width, and the primary
   action sits on top so the thumb reaches it first. Column-reverse keeps Cancel
   first in the DOM, which is what a keyboard and a screen reader should meet. */
@media (max-width: 560px) {
    .ch-cd {
        padding: 0.75rem;
    }

    .ch-cd-card {
        grid-template-columns: minmax(0, 1fr);
        gap: 0;
        padding: 1.5rem 1.2rem 1.3rem;
        border-radius: 16px;
    }

    .ch-cd-ico {
        grid-row: auto;
        margin-bottom: 0.9rem;
    }

    .ch-cd-main {
        padding-right: 0;
    }

    .ch-cd-title {
        font-size: 1.28rem;
    }

    .ch-cd-actions {
        grid-column: 1;
        flex-direction: column-reverse;
        align-items: stretch;
    }

    .ch-cd-btn {
        width: 100%;
        padding: 0.8rem 1rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ch-cd,
    .ch-cd-card,
    .ch-cd-btn {
        transition: none;
    }
}

/* --- dark --- */
html[data-theme="dark"] .ch-cd-veil {
    background-color: rgba(2, 6, 23, 0.78);
}

html[data-theme="dark"] .ch-cd-card {
    border-color: #334155;
    box-shadow: 0 0 0 1px rgba(148, 163, 184, 0.08),
                0 40px 80px -28px rgba(0, 0, 0, 0.9),
                0 12px 28px -18px rgba(0, 0, 0, 0.7);
}

html[data-theme="dark"] .ch-cd-x:hover {
    background-color: #0F172A;
}

/* Amber 700 and Red 600 both fail contrast on slate, so both tones step up a
   rung exactly the way the library row buttons already do. */
html[data-theme="dark"] .ch-cd-ico,
html[data-theme="dark"] .ch-cd-kicker {
    color: #FBBF24;
}

html[data-theme="dark"] .ch-cd-ico {
    background-color: rgba(245, 158, 11, 0.16);
}

html[data-theme="dark"] .ch-cd.is-danger .ch-cd-ico,
html[data-theme="dark"] .ch-cd.is-danger .ch-cd-kicker {
    color: #FCA5A5;
}

html[data-theme="dark"] .ch-cd.is-danger .ch-cd-ico {
    background-color: rgba(239, 68, 68, 0.15);
}

html[data-theme="dark"] .ch-cd-body,
html[data-theme="dark"] .ch-cd-points li {
    color: #CBD5E1;
}

html[data-theme="dark"] .ch-cd-points li.is-loss svg {
    color: #FCA5A5;
}

html[data-theme="dark"] .ch-cd-points li.is-keep svg {
    color: #34D399;
}

html[data-theme="dark"] .ch-cd-subject {
    background-color: #0F172A;
    border-color: #334155;
}

html[data-theme="dark"] .ch-cd-btn,
html[data-theme="dark"] .ch-cd-btn:focus,
html[data-theme="dark"] .ch-cd-btn:active {
    background-color: #0F172A;
    border-color: #334155;
    color: #F1F5F9;
}

html[data-theme="dark"] .ch-cd-btn:hover {
    background-color: #273449;
    border-color: #64748B;
    color: #F8FAFC;
}

html[data-theme="dark"] .ch-cd-btn.is-go,
html[data-theme="dark"] .ch-cd-btn.is-go:focus,
html[data-theme="dark"] .ch-cd-btn.is-go:active {
    background-color: #D97706;
    border-color: transparent;
    color: #0F172A;
}

html[data-theme="dark"] .ch-cd-btn.is-go:hover {
    background-color: #F59E0B;
    color: #0F172A;
}

html[data-theme="dark"] .ch-cd.is-danger .ch-cd-btn.is-go,
html[data-theme="dark"] .ch-cd.is-danger .ch-cd-btn.is-go:focus,
html[data-theme="dark"] .ch-cd.is-danger .ch-cd-btn.is-go:active {
    background-color: #DC2626;
    color: #FFFFFF;
}

/* Darker on hover, not lighter: white on Red 500 is 3.8:1, on Red 700 6.5:1. */
html[data-theme="dark"] .ch-cd.is-danger .ch-cd-btn.is-go:hover {
    background-color: #B91C1C;
    color: #FFFFFF;
}

/* ==========================================================================
   19. LAPSED SUBSCRIPTION STATES
   What a QR code library looks like after a subscription stops paying. The
   codes keep resolving - they are printed on physical objects and breaking
   them would punish the customer's customers for a billing event - but the
   ones beyond the free allowance stop recording scans. The UI has to say that
   plainly, in the row and above the list, without implying anything is broken.
   ========================================================================== */

/* The strip is informational first and an upsell second, so it keeps the light
   neutral surface while the slots strip takes the dark premium panel. Stacked,
   the two must not read as the same message: one says "you cannot add another",
   the other says "these stopped measuring". */
.ch-qrlib-upsell.is-muted {
    border-color: var(--ch-border);
    background-color: var(--ch-bg-main);
    box-shadow: inset 3px 0 0 var(--ch-accent);
}

.ch-qrlib-upsell.is-muted .ch-qrlib-upsell-ico {
    background-color: rgba(37, 99, 235, 0.1);
    color: var(--ch-accent);
}

/* Row level. Deliberately subtle: the QR code still works, so greying the whole
   row the way a paused code is greyed would be a lie. Only the numbers dim. */
.ch-qrlib-row.is-muted .ch-qrlib-stats {
    opacity: 0.5;
}

.ch-qrlib-badge.is-muted {
    background-color: rgba(100, 116, 139, 0.12);
    color: var(--ch-text-muted);
    cursor: help;
}

.ch-qrlib-badge.is-muted::before {
    background-color: #94A3B8;
    /* A hollow dot: the live badge's filled dot means "recording", so the same
       filled dot next to "Stats off" would contradict the word beside it. */
    box-shadow: inset 0 0 0 1.5px var(--ch-bg-card);
}

html[data-theme="dark"] .ch-qrlib-upsell.is-muted {
    border-color: #334155;
    background-color: #0F172A;
    box-shadow: inset 3px 0 0 var(--ch-accent);
}

html[data-theme="dark"] .ch-qrlib-upsell.is-muted .ch-qrlib-upsell-ico {
    background-color: rgba(96, 165, 250, 0.14);
    color: var(--ch-accent);
}

html[data-theme="dark"] .ch-qrlib-badge.is-muted {
    background-color: rgba(148, 163, 184, 0.14);
}

/* ==========================================================================
   19. PDF TOOLS CARD
   The suite stores nothing per user, so this card is not a library: it is the
   allowance made visible plus a door into the two shipped tools. Full width,
   like the QR library, because a three-column cell cannot hold a pip meter and
   two tool rows without either wrapping badly or shrinking the type below the
   dashboard's floor.
   ========================================================================== */
.ch-card-pdf {
    grid-column: 1 / -1;
}

.ch-pdfdash-head {
    display: grid;
    grid-template-columns: minmax(0, 280px) minmax(0, 1fr);
    gap: 1.25rem 2rem;
    align-items: start;
    margin-bottom: 1.35rem;
}

.ch-pdfdash-meter {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 1.1rem 1.15rem;
    border: 1px solid var(--ch-border);
    border-radius: 12px;
    background-color: #F8FAFC;
}

.ch-pdfdash-plan {
    align-self: flex-start;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.63rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    padding: 0.24rem 0.55rem;
    border-radius: 5px;
    color: var(--ch-text-muted);
    background-color: rgba(15, 23, 42, 0.06);
}

/* "Premium plan" is a Premium mark like the plan badge, so it is blue too. */
.ch-pdfdash-meter.is-premium .ch-pdfdash-plan {
    color: #1E40AF;
    background-color: rgba(37, 99, 235, 0.12);
}

.ch-pdfdash-meter.is-empty .ch-pdfdash-plan {
    color: #B45309;
    background-color: rgba(245, 158, 11, 0.18);
}

/* Named limits, not prose. A member about to drop 60 files on a tool needs
   the ceiling as a number they can compare against, and a sentence about
   batches is a number they have to go looking for. */
.ch-pdfdash-facts {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin: 0.25rem 0 0;
    padding: 0.7rem 0 0;
    border-top: 1px dashed var(--ch-border);
    list-style: none;
}

.ch-pdfdash-facts li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    font-size: 0.79rem;
}

.ch-pdfdash-facts li > span {
    color: var(--ch-text-muted);
}

.ch-pdfdash-facts li > strong {
    font-weight: 600;
    text-align: right;
    color: var(--ch-text-main);
}

.ch-pdfdash-meter.is-empty {
    border-color: rgba(245, 158, 11, 0.38);
    background-color: rgba(245, 158, 11, 0.09);
}

.ch-pdfdash-meter.is-premium {
    border-color: rgba(37, 99, 235, 0.3);
    background-color: rgba(37, 99, 235, 0.06);
}

.ch-pdfdash-pips {
    display: inline-flex;
    gap: 4px;
}

.ch-pdfdash-pip {
    width: 26px;
    height: 6px;
    border-radius: 3px;
    background-color: var(--ch-cta);
}

.ch-pdfdash-pip.is-spent {
    background-color: #CBD5E1;
}

.ch-pdfdash-figure {
    font-size: 1.02rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--ch-text-main);
}

.ch-pdfdash-sub {
    font-size: 0.8rem;
    line-height: 1.55;
    color: var(--ch-text-muted);
}

.ch-pdfdash-intro p {
    margin: 0 0 0.7rem;
    font-size: 0.92rem;
    line-height: 1.7;
    color: var(--ch-text-muted);
}

.ch-pdfdash-intro p:last-child {
    margin-bottom: 0;
}

.ch-pdfdash-intro strong {
    color: var(--ch-text-main);
}

/* --- Group headings -----------------------------------------------------
   39 tiles in one undifferentiated grid is a wall, and the member arrives
   knowing the VERB they want (convert, sign) long before the tool name.
   These are the public hub groups, in the hub order, so the two surfaces
   can be learned once. */
.ch-pdfdash-group {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 1.5rem 0 0.75rem;
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ch-text-muted);
}

.ch-pdfdash-group:first-of-type {
    margin-top: 0;
}

.ch-pdfdash-group-ico {
    display: inline-flex;
    align-items: center;
    line-height: 0;
    color: var(--ch-text-muted);
}

.ch-pdfdash-group-ico svg {
    display: block;
    width: 14px;
    height: 14px;
}

.ch-pdfdash-group-n {
    font-size: 0.65rem;
    font-weight: 700;
    padding: 0.1rem 0.4rem;
    border-radius: 20px;
    color: var(--ch-text-muted);
    background-color: rgba(15, 23, 42, 0.06);
}

.ch-pdfdash-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(272px, 1fr));
    gap: 0.7rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.ch-pdfdash-item {
    display: flex;
    align-items: flex-start;
    gap: 0.8rem;
    height: 100%;
    padding: 0.85rem 0.95rem;
    border: 1px solid var(--ch-border);
    border-radius: 10px;
    background-color: #F8FAFC;
    text-decoration: none !important;
    transition: border-color 0.2s, background-color 0.2s, transform 0.2s, box-shadow 0.2s;
}

.ch-pdfdash-item:hover {
    transform: translateY(-2px);
    border-color: var(--ch-tint-line, rgba(16, 185, 129, 0.42));
    background-color: #FFFFFF;
    box-shadow: 0 8px 18px -12px rgba(15, 23, 42, 0.3);
}

/* The glyph well reads the tile own tint, exactly as it does on the public
   hub. With no tint class it falls back to emerald, so a tool shipped
   without a tint key degrades to the old look instead of to a hole. */
.ch-pdfdash-item-ico {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 9px;
    background-color: var(--ch-tint-bg, rgba(16, 185, 129, 0.1));
    color: var(--ch-tint, #059669);
    transition: background-color 0.2s;
}

.ch-pdfdash-item:hover .ch-pdfdash-item-ico {
    background-color: var(--ch-tint-bg-hi, rgba(16, 185, 129, 0.18));
}

.ch-pdfdash-item-ico svg {
    display: block;
    width: 20px;
    height: 20px;
}

/* ---- TOOL TILE TINTS ----------------------------------------------------
   Copied from pdf-tools.css rather than shared, because that stylesheet is
   6,000 lines of tool-page machinery and loading it on the dashboard to
   borrow fourteen custom properties would cost more than the duplication.
   The values are identical on purpose: the same tool must be the same colour
   on both surfaces or the tint stops being a wayfinding signal. Scoped to the
   panel so they cannot collide with the hub own copy. */
.ch-pdfdash-list .ch-tint-emerald { --ch-tint: #047857; --ch-tint-bg: rgba(16, 185, 129, 0.10); --ch-tint-bg-hi: rgba(16, 185, 129, 0.18); --ch-tint-line: rgba(16, 185, 129, 0.45); }
.ch-pdfdash-list .ch-tint-teal    { --ch-tint: #0F766E; --ch-tint-bg: rgba(20, 184, 166, 0.11); --ch-tint-bg-hi: rgba(20, 184, 166, 0.19); --ch-tint-line: rgba(20, 184, 166, 0.45); }
.ch-pdfdash-list .ch-tint-cyan    { --ch-tint: #0E7490; --ch-tint-bg: rgba(6, 182, 212, 0.12);  --ch-tint-bg-hi: rgba(6, 182, 212, 0.20);  --ch-tint-line: rgba(6, 182, 212, 0.45); }
.ch-pdfdash-list .ch-tint-sky     { --ch-tint: #0369A1; --ch-tint-bg: rgba(14, 165, 233, 0.11); --ch-tint-bg-hi: rgba(14, 165, 233, 0.19); --ch-tint-line: rgba(14, 165, 233, 0.45); }
.ch-pdfdash-list .ch-tint-blue    { --ch-tint: #1D4ED8; --ch-tint-bg: rgba(59, 130, 246, 0.11); --ch-tint-bg-hi: rgba(59, 130, 246, 0.19); --ch-tint-line: rgba(59, 130, 246, 0.45); }
.ch-pdfdash-list .ch-tint-indigo  { --ch-tint: #4338CA; --ch-tint-bg: rgba(99, 102, 241, 0.11); --ch-tint-bg-hi: rgba(99, 102, 241, 0.19); --ch-tint-line: rgba(99, 102, 241, 0.45); }
.ch-pdfdash-list .ch-tint-violet  { --ch-tint: #6D28D9; --ch-tint-bg: rgba(139, 92, 246, 0.11); --ch-tint-bg-hi: rgba(139, 92, 246, 0.19); --ch-tint-line: rgba(139, 92, 246, 0.45); }
.ch-pdfdash-list .ch-tint-fuchsia { --ch-tint: #A21CAF; --ch-tint-bg: rgba(217, 70, 239, 0.10); --ch-tint-bg-hi: rgba(217, 70, 239, 0.18); --ch-tint-line: rgba(217, 70, 239, 0.42); }
.ch-pdfdash-list .ch-tint-rose    { --ch-tint: #BE123C; --ch-tint-bg: rgba(244, 63, 94, 0.10);  --ch-tint-bg-hi: rgba(244, 63, 94, 0.18);  --ch-tint-line: rgba(244, 63, 94, 0.42); }
.ch-pdfdash-list .ch-tint-red     { --ch-tint: #B91C1C; --ch-tint-bg: rgba(239, 68, 68, 0.10);  --ch-tint-bg-hi: rgba(239, 68, 68, 0.18);  --ch-tint-line: rgba(239, 68, 68, 0.42); }
.ch-pdfdash-list .ch-tint-orange  { --ch-tint: #C2410C; --ch-tint-bg: rgba(249, 115, 22, 0.11); --ch-tint-bg-hi: rgba(249, 115, 22, 0.19); --ch-tint-line: rgba(249, 115, 22, 0.45); }
.ch-pdfdash-list .ch-tint-amber   { --ch-tint: #B45309; --ch-tint-bg: rgba(245, 158, 11, 0.13); --ch-tint-bg-hi: rgba(245, 158, 11, 0.22); --ch-tint-line: rgba(245, 158, 11, 0.48); }
.ch-pdfdash-list .ch-tint-green   { --ch-tint: #15803D; --ch-tint-bg: rgba(34, 197, 94, 0.11);  --ch-tint-bg-hi: rgba(34, 197, 94, 0.19);  --ch-tint-line: rgba(34, 197, 94, 0.45); }
.ch-pdfdash-list .ch-tint-slate   { --ch-tint: #475569; --ch-tint-bg: rgba(100, 116, 139, 0.13); --ch-tint-bg-hi: rgba(100, 116, 139, 0.21); --ch-tint-line: rgba(100, 116, 139, 0.45); }

.ch-pdfdash-item-body {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}

.ch-pdfdash-item-body strong {
    font-size: 0.92rem;
    font-weight: 600;
    color: var(--ch-text-main);
}

/* Two lines, then stop. The full sentence lives on the tool page; here its
   job is to separate this tile from the one beside it, and a five-line
   caption on one tile forces every tile in the row to that height. */
.ch-pdfdash-item-body span {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 0.78rem;
    line-height: 1.45;
    color: var(--ch-text-muted);
}

.ch-pdfdash-item-arrow {
    display: inline-flex;
    flex: 0 0 auto;
    align-self: center;
    margin-left: auto;
    color: var(--ch-text-muted);
    transition: transform 0.2s, color 0.2s;
}

.ch-pdfdash-item:hover .ch-pdfdash-item-arrow {
    transform: translateX(3px);
    color: var(--ch-tint, #059669);
}

.ch-pdfdash-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 1.6rem;
    padding-top: 1rem;
    border-top: 1px solid var(--ch-border);
}

.ch-pdfdash-upgrade {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--ch-text-muted) !important;
    text-decoration: underline !important;
    text-underline-offset: 3px;
}

.ch-pdfdash-upgrade:hover {
    color: var(--ch-text-main) !important;
}

@media (max-width: 860px) {
    .ch-pdfdash-head {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* --- dark --- */
html[data-theme="dark"] .ch-pdfdash-meter,
html[data-theme="dark"] .ch-pdfdash-item {
    background-color: #0F172A;
    border-color: #334155;
}

html[data-theme="dark"] .ch-pdfdash-item:hover {
    background-color: #273449;
    border-color: rgba(52, 211, 153, 0.42);
}

html[data-theme="dark"] .ch-pdfdash-meter.is-empty {
    background-color: rgba(245, 158, 11, 0.14);
    border-color: rgba(245, 158, 11, 0.4);
}

html[data-theme="dark"] .ch-pdfdash-meter.is-premium {
    background-color: rgba(59, 130, 246, 0.1);
    border-color: rgba(147, 197, 253, 0.35);
}

html[data-theme="dark"] .ch-pdfdash-pip.is-spent {
    background-color: #475569;
}

html[data-theme="dark"] .ch-pdfdash-plan {
    background-color: rgba(148, 163, 184, 0.16);
}

html[data-theme="dark"] .ch-pdfdash-meter.is-premium .ch-pdfdash-plan {
    color: #93C5FD;
    background-color: rgba(96, 165, 250, 0.16);
}

html[data-theme="dark"] .ch-pdfdash-meter.is-empty .ch-pdfdash-plan {
    color: #FCD34D;
    background-color: rgba(245, 158, 11, 0.2);
}

html[data-theme="dark"] .ch-pdfdash-facts {
    border-top-color: #334155;
}

html[data-theme="dark"] .ch-pdfdash-group-n {
    background-color: rgba(148, 163, 184, 0.16);
}

/* The text-grade tints are set for white. On slate every one of them drops
   below 3:1 and the glyph becomes a smudge, so the whole palette steps up to
   the 300-400 band - the same flip the tool pages make in pdf-tools.css. */
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-emerald { --ch-tint: #34D399; --ch-tint-bg: rgba(16, 185, 129, 0.16); --ch-tint-bg-hi: rgba(16, 185, 129, 0.26); --ch-tint-line: rgba(52, 211, 153, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-teal    { --ch-tint: #2DD4BF; --ch-tint-bg: rgba(45, 212, 191, 0.15); --ch-tint-bg-hi: rgba(45, 212, 191, 0.25); --ch-tint-line: rgba(45, 212, 191, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-cyan    { --ch-tint: #22D3EE; --ch-tint-bg: rgba(34, 211, 238, 0.15); --ch-tint-bg-hi: rgba(34, 211, 238, 0.25); --ch-tint-line: rgba(34, 211, 238, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-sky     { --ch-tint: #38BDF8; --ch-tint-bg: rgba(56, 189, 248, 0.15); --ch-tint-bg-hi: rgba(56, 189, 248, 0.25); --ch-tint-line: rgba(56, 189, 248, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-blue    { --ch-tint: #60A5FA; --ch-tint-bg: rgba(96, 165, 250, 0.16); --ch-tint-bg-hi: rgba(96, 165, 250, 0.26); --ch-tint-line: rgba(96, 165, 250, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-indigo  { --ch-tint: #A5B4FC; --ch-tint-bg: rgba(129, 140, 248, 0.18); --ch-tint-bg-hi: rgba(129, 140, 248, 0.28); --ch-tint-line: rgba(129, 140, 248, 0.45); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-violet  { --ch-tint: #C4B5FD; --ch-tint-bg: rgba(167, 139, 250, 0.18); --ch-tint-bg-hi: rgba(167, 139, 250, 0.28); --ch-tint-line: rgba(167, 139, 250, 0.45); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-fuchsia { --ch-tint: #E879F9; --ch-tint-bg: rgba(232, 121, 249, 0.15); --ch-tint-bg-hi: rgba(232, 121, 249, 0.25); --ch-tint-line: rgba(232, 121, 249, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-rose    { --ch-tint: #FDA4AF; --ch-tint-bg: rgba(251, 113, 133, 0.16); --ch-tint-bg-hi: rgba(251, 113, 133, 0.26); --ch-tint-line: rgba(251, 113, 133, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-red     { --ch-tint: #FCA5A5; --ch-tint-bg: rgba(248, 113, 113, 0.16); --ch-tint-bg-hi: rgba(248, 113, 113, 0.26); --ch-tint-line: rgba(248, 113, 113, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-orange  { --ch-tint: #FDBA74; --ch-tint-bg: rgba(251, 146, 60, 0.16);  --ch-tint-bg-hi: rgba(251, 146, 60, 0.26);  --ch-tint-line: rgba(251, 146, 60, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-amber   { --ch-tint: #FCD34D; --ch-tint-bg: rgba(251, 191, 36, 0.16);  --ch-tint-bg-hi: rgba(251, 191, 36, 0.26);  --ch-tint-line: rgba(251, 191, 36, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-green   { --ch-tint: #86EFAC; --ch-tint-bg: rgba(74, 222, 128, 0.15);  --ch-tint-bg-hi: rgba(74, 222, 128, 0.25);  --ch-tint-line: rgba(74, 222, 128, 0.42); }
html[data-theme="dark"] .ch-pdfdash-list .ch-tint-slate   { --ch-tint: #CBD5E1; --ch-tint-bg: rgba(148, 163, 184, 0.16); --ch-tint-bg-hi: rgba(148, 163, 184, 0.26); --ch-tint-line: rgba(148, 163, 184, 0.42); }

/* ==========================================================================
   12. DANGER ZONE - account deletion (settings > security)
   ==========================================================================
   The only irreversible control in the product, so it is styled to look
   unlike every other card on the page. Red is reserved for this and for
   nothing else: a destructive action that shares a colour with a routine one
   is a destructive action somebody performs by muscle memory. The form itself
   ships hidden and the submit stays disabled until DELETE is typed, so the
   collapsed state below is the default, not a decoration. */

.ch-danger-card {
    border-color: rgba(220, 38, 38, 0.28);
    background-image: linear-gradient(180deg, rgba(220, 38, 38, 0.035), rgba(220, 38, 38, 0) 120px);
}

.ch-dash-card-label.is-danger {
    color: #B91C1C;
}

.ch-danger-card .ch-security-note a {
    color: var(--ch-cta);
    font-weight: 700;
}

/* GeneratePress ships its own button colours and wins on specificity, which is
   why every button in this file states background, border and colour with
   !important and repeats itself for :focus. Written without that, the label on
   this one turned white-on-pink the moment it was hovered. Same house pattern
   as .ch-btn-logout and .ch-btn-settings above. */
.ch-btn-danger-ghost,
.ch-btn-danger-ghost:focus {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    appearance: none;
    cursor: pointer;
    margin-top: 0.4rem;
    background: transparent !important;
    border: 1px solid rgba(220, 38, 38, 0.45) !important;
    color: #B91C1C !important;
    font-family: 'Inter', sans-serif;
    font-size: 0.85rem;
    font-weight: 800;
    padding: 0.6rem 1.1rem;
    border-radius: 8px;
    text-decoration: none !important;
    transition: background-color 0.2s, border-color 0.2s, color 0.2s, transform 0.2s;
}

.ch-btn-danger-ghost:hover {
    background: rgba(220, 38, 38, 0.07) !important;
    border-color: #DC2626 !important;
    color: #DC2626 !important;
    transform: translateY(-2px);
}

.ch-btn-danger-ghost:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.25);
}

.ch-danger-form {
    margin-top: 1.25rem;
    padding-top: 1.25rem;
    border-top: 1px dashed var(--ch-border);
}

/* The consequences, spelled out. Not a tooltip, not a placeholder: the one
   surface where a reader has to be able to find out what breaks before it
   breaks. */
.ch-danger-warning {
    border: 1px solid rgba(220, 38, 38, 0.3);
    background-color: rgba(220, 38, 38, 0.05);
    border-radius: 10px;
    padding: 1rem 1.15rem;
    margin-bottom: 1.25rem;
    font-size: 0.86rem;
    line-height: 1.6;
    color: var(--ch-text-main);
}

.ch-danger-warning strong {
    color: #B91C1C;
}

.ch-danger-warning ul {
    margin: 0.65rem 0 0;
    padding-left: 1.1rem;
}

.ch-danger-warning li {
    margin-bottom: 0.45rem;
}

.ch-danger-warning li:last-child {
    margin-bottom: 0;
}

.ch-danger-warning li strong {
    color: inherit;
    font-weight: 800;
}

/* Deliberately monospace and letter-spaced: typing DELETE should feel like
   typing a command, not filling in a field. */
.ch-danger-form input[name="confirm"] {
    font-family: 'JetBrains Mono', 'Roboto Mono', monospace;
    letter-spacing: 2px;
    font-weight: 700;
    text-transform: uppercase;
}

.ch-danger-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.ch-btn-danger,
.ch-btn-danger:focus {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    appearance: none;
    cursor: pointer;
    background: #DC2626 !important;
    border: 1px solid #DC2626 !important;
    color: #FFFFFF !important;
    font-family: 'Inter', sans-serif;
    font-size: 0.9rem;
    font-weight: 800;
    padding: 0.75rem 1.4rem;
    border-radius: 8px;
    text-decoration: none !important;
    transition: background-color 0.2s, border-color 0.2s, opacity 0.2s, transform 0.2s;
}

.ch-btn-danger:hover:not(:disabled) {
    background: #B91C1C !important;
    border-color: #B91C1C !important;
    transform: translateY(-2px);
}

.ch-btn-danger:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.3);
}

.ch-btn-danger:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    transform: none;
}

/* Cancel. The safe way out of a destructive form, so it has to read as a real
   button sitting next to the red one rather than as a stray link - same
   height and radius, no fill, no underline. The first version inherited
   GeneratePress's dark button background and came out as a grey slab with
   underlined text. */
.ch-btn-quiet,
.ch-btn-quiet:focus {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    appearance: none;
    cursor: pointer;
    background: transparent !important;
    border: 1px solid var(--ch-border) !important;
    color: var(--ch-text-muted) !important;
    font-family: 'Inter', sans-serif;
    font-size: 0.9rem;
    font-weight: 700;
    padding: 0.75rem 1.4rem;
    border-radius: 8px;
    text-decoration: none !important;
    transition: background-color 0.2s, border-color 0.2s, color 0.2s;
}

.ch-btn-quiet:hover {
    background: var(--ch-bg-main) !important;
    border-color: var(--ch-text-muted) !important;
    color: var(--ch-text-main) !important;
}

.ch-btn-quiet:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(100, 116, 139, 0.25);
}

html[data-theme="dark"] .ch-danger-card {
    border-color: rgba(248, 113, 113, 0.3);
    background-image: linear-gradient(180deg, rgba(248, 113, 113, 0.05), rgba(248, 113, 113, 0) 120px);
}

html[data-theme="dark"] .ch-dash-card-label.is-danger,
html[data-theme="dark"] .ch-danger-warning strong {
    color: #FCA5A5;
}

html[data-theme="dark"] .ch-btn-danger-ghost,
html[data-theme="dark"] .ch-btn-danger-ghost:focus {
    color: #FCA5A5 !important;
    border-color: rgba(248, 113, 113, 0.4) !important;
}

html[data-theme="dark"] .ch-btn-danger-ghost:hover {
    background: rgba(248, 113, 113, 0.12) !important;
    border-color: #FCA5A5 !important;
    color: #FCA5A5 !important;
}

html[data-theme="dark"] .ch-btn-danger,
html[data-theme="dark"] .ch-btn-danger:focus {
    background: #DC2626 !important;
    border-color: #DC2626 !important;
    color: #FFFFFF !important;
}

html[data-theme="dark"] .ch-btn-danger:hover:not(:disabled) {
    background: #EF4444 !important;
    border-color: #EF4444 !important;
}

html[data-theme="dark"] .ch-btn-quiet,
html[data-theme="dark"] .ch-btn-quiet:focus {
    border-color: #334155 !important;
    color: #94A3B8 !important;
}

html[data-theme="dark"] .ch-btn-quiet:hover {
    background: rgba(148, 163, 184, 0.1) !important;
    border-color: #94A3B8 !important;
    color: #F1F5F9 !important;
}

html[data-theme="dark"] .ch-danger-warning {
    border-color: rgba(248, 113, 113, 0.28);
    background-color: rgba(248, 113, 113, 0.07);
}

/* ==========================================================================
   20. NEWSLETTER PROMO (Settings > Newsletter, ?from=newsletter|email)
   The box above the switch for a visit that came for the newsletter: the
   benefits, the platform the issues are matched to, and a one-click
   subscribe. Three views (off, pending, on); portal.js shows one.
   Filled button: Emerald 700 #047857 with white text in light (5.5:1), never
   white on #10B981 (2.5:1); #10B981 with #04241C text in dark. Every state
   declares colour AND background at 0,3,0, above the GeneratePress
   button:hover rule (0,1,1).
   ========================================================================== */
.ch-nlp {
    position: relative;
    overflow: hidden;
    border-color: rgba(16, 185, 129, 0.4);
    background-image: linear-gradient(180deg, rgba(16, 185, 129, 0.07) 0%, rgba(16, 185, 129, 0) 140px);
}

.ch-nlp::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: linear-gradient(90deg, #1D4ED8 0%, #2563EB 35%, #10B981 100%);
}

.ch-nlp-label {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: #047857;
}

.ch-nlp-view[hidden] {
    display: none;
}

.ch-nlp-title {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    margin: 0 0 0.9rem;
    font-size: 1.25rem;
    font-weight: 800;
    line-height: 1.3;
    letter-spacing: -0.01em;
    color: var(--ch-text-main);
    outline: none;
}

.ch-nlp-list {
    display: grid;
    gap: 0.55rem;
    margin: 0 0 1.25rem;
    padding: 0;
    list-style: none;
}

.ch-nlp-list li {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    margin: 0;
    font-size: 0.92rem;
    line-height: 1.45;
    color: var(--ch-text-main);
}

.ch-nlp-check {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    margin-top: 0.05rem;
    border-radius: 50%;
    background-color: rgba(16, 185, 129, 0.12);
    color: #047857;
}

.ch-nlp-check.is-on {
    width: 26px;
    height: 26px;
    margin-top: 0;
    background-color: #047857;
    color: #FFFFFF;
}

.ch-nlp-text,
.ch-nlp-extra {
    margin: 0 0 1rem;
    font-size: 0.92rem;
    line-height: 1.6;
    color: #334155;
}

.ch-nlp-text strong {
    color: var(--ch-text-main);
}

.ch-nlp-extra {
    padding: 0.75rem 0.9rem;
    border: 1px solid rgba(37, 99, 235, 0.3);
    border-radius: 10px;
    background-color: rgba(37, 99, 235, 0.06);
    color: #1E40AF;
}

.ch-nlp-fine {
    margin: 0.85rem 0 0;
    font-size: 0.8rem;
    line-height: 1.5;
    color: var(--ch-text-muted);
}

.ch-nlp .ch-nlp-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 46px;
    padding: 0.75rem 1.5rem;
    border: 1px solid #047857;
    border-radius: 9px;
    background-color: #047857;
    color: #FFFFFF;
    font-family: 'Inter', sans-serif;
    font-size: 0.95rem;
    font-weight: 800;
    line-height: 1.2;
    cursor: pointer;
    box-shadow: 0 8px 18px -10px rgba(4, 120, 87, 0.7);
    transition: background-color 0.2s, border-color 0.2s, color 0.2s, transform 0.2s;
}

.ch-nlp .ch-nlp-btn:hover,
.ch-nlp .ch-nlp-btn:focus,
.ch-nlp .ch-nlp-btn:focus-visible,
.ch-nlp .ch-nlp-btn:active {
    border-color: #065F46;
    background-color: #065F46;
    color: #FFFFFF;
}

.ch-nlp .ch-nlp-btn:hover {
    transform: translateY(-1px);
}

.ch-nlp .ch-nlp-btn:focus-visible {
    outline: 3px solid rgba(16, 185, 129, 0.45);
    outline-offset: 3px;
}

.ch-nlp .ch-nlp-btn.is-ghost {
    border-color: #CBD5E1;
    background-color: #FFFFFF;
    color: #0F172A;
    box-shadow: none;
}

.ch-nlp .ch-nlp-btn.is-ghost:hover,
.ch-nlp .ch-nlp-btn.is-ghost:focus,
.ch-nlp .ch-nlp-btn.is-ghost:focus-visible,
.ch-nlp .ch-nlp-btn.is-ghost:active {
    border-color: #334155;
    background-color: #F1F5F9;
    color: #0F172A;
}

.ch-nlp .ch-nlp-btn.is-ghost .ch-btn-spinner {
    border-color: rgba(15, 23, 42, 0.2);
    border-top-color: #0F172A;
}

.ch-nlp .ch-nlp-btn:disabled,
.ch-nlp .ch-nlp-btn:disabled:hover {
    cursor: progress;
    transform: none;
}

.ch-nlp-match {
    display: flex;
    align-items: flex-start;
    gap: 0.55rem;
    margin: 1.2rem 0 0;
    padding-top: 1rem;
    border-top: 1px dashed var(--ch-border);
    font-size: 0.84rem;
    line-height: 1.55;
    color: #334155;
}

.ch-nlp-match svg {
    flex-shrink: 0;
    margin-top: 0.15rem;
    color: #047857;
}

.ch-nlp .ch-nlp-match a,
.ch-nlp .ch-nlp-match a:visited,
.ch-nlp .ch-nlp-extra a,
.ch-nlp .ch-nlp-extra a:visited {
    color: #1D4ED8;
    background-color: transparent;
    font-weight: 700;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.ch-nlp .ch-nlp-match a:hover,
.ch-nlp .ch-nlp-match a:focus,
.ch-nlp .ch-nlp-match a:active,
.ch-nlp .ch-nlp-extra a:hover,
.ch-nlp .ch-nlp-extra a:focus,
.ch-nlp .ch-nlp-extra a:active {
    color: #1E3A8A;
    background-color: transparent;
    text-decoration-thickness: 2px;
}

.ch-nlp [data-nlp-alert] {
    margin-top: 1rem;
}

/* The status note in the Newsletter card is toggled by portal.js now. */
.ch-nl-status-note[hidden] {
    display: none;
}

/* Sign-in deck opened from the newsletter: the opt-in line is the point of
   the visit, so it is framed and tinted. Never pre-ticked (GDPR consent). */
.ch-nl-topic.is-featured {
    border: 1px solid rgba(16, 185, 129, 0.45);
    background-color: rgba(16, 185, 129, 0.07);
}

.ch-nl-topic.is-featured:hover {
    border-color: #047857;
    background-color: rgba(16, 185, 129, 0.1);
}

.ch-nl-topic.is-featured .ch-nl-check {
    border-color: #047857;
}

.ch-nl-topic.is-featured input:checked ~ .ch-nl-check {
    background-color: #047857;
    border-color: #047857;
}

@media (max-width: 640px) {
    .ch-nlp .ch-nlp-btn {
        width: 100%;
    }
}

html[data-theme="dark"] .ch-nlp {
    border-color: rgba(52, 211, 153, 0.4);
    background-image: linear-gradient(180deg, rgba(16, 185, 129, 0.1) 0%, rgba(16, 185, 129, 0) 140px);
}

html[data-theme="dark"] .ch-nlp-label,
html[data-theme="dark"] .ch-nlp-match svg {
    color: #6EE7B7;
}

html[data-theme="dark"] .ch-nlp-check {
    background-color: rgba(16, 185, 129, 0.16);
    color: #6EE7B7;
}

html[data-theme="dark"] .ch-nlp-check.is-on {
    background-color: #10B981;
    color: #04241C;
}

html[data-theme="dark"] .ch-nlp-text,
html[data-theme="dark"] .ch-nlp-match {
    color: #CBD5E1;
}

html[data-theme="dark"] .ch-nlp-extra {
    border-color: rgba(147, 197, 253, 0.35);
    background-color: rgba(96, 165, 250, 0.1);
    color: #BFDBFE;
}

html[data-theme="dark"] .ch-nlp .ch-nlp-btn {
    border-color: #10B981;
    background-color: #10B981;
    color: #04241C;
    box-shadow: 0 8px 18px -10px rgba(16, 185, 129, 0.6);
}

html[data-theme="dark"] .ch-nlp .ch-nlp-btn:hover,
html[data-theme="dark"] .ch-nlp .ch-nlp-btn:focus,
html[data-theme="dark"] .ch-nlp .ch-nlp-btn:focus-visible,
html[data-theme="dark"] .ch-nlp .ch-nlp-btn:active {
    border-color: #34D399;
    background-color: #34D399;
    color: #04241C;
}

html[data-theme="dark"] .ch-nlp .ch-nlp-btn .ch-btn-spinner {
    border-color: rgba(4, 36, 28, 0.3);
    border-top-color: #04241C;
}

html[data-theme="dark"] .ch-nlp .ch-nlp-btn.is-ghost {
    border-color: #475569;
    background-color: #0F172A;
    color: #F1F5F9;
    box-shadow: none;
}

html[data-theme="dark"] .ch-nlp .ch-nlp-btn.is-ghost:hover,
html[data-theme="dark"] .ch-nlp .ch-nlp-btn.is-ghost:focus,
html[data-theme="dark"] .ch-nlp .ch-nlp-btn.is-ghost:focus-visible,
html[data-theme="dark"] .ch-nlp .ch-nlp-btn.is-ghost:active {
    border-color: #94A3B8;
    background-color: #334155;
    color: #FFFFFF;
}

html[data-theme="dark"] .ch-nlp .ch-nlp-btn.is-ghost .ch-btn-spinner {
    border-color: rgba(241, 245, 249, 0.25);
    border-top-color: #F1F5F9;
}

html[data-theme="dark"] .ch-nlp .ch-nlp-match a,
html[data-theme="dark"] .ch-nlp .ch-nlp-match a:visited,
html[data-theme="dark"] .ch-nlp .ch-nlp-extra a,
html[data-theme="dark"] .ch-nlp .ch-nlp-extra a:visited {
    color: #93C5FD;
}

html[data-theme="dark"] .ch-nlp .ch-nlp-match a:hover,
html[data-theme="dark"] .ch-nlp .ch-nlp-match a:focus,
html[data-theme="dark"] .ch-nlp .ch-nlp-match a:active,
html[data-theme="dark"] .ch-nlp .ch-nlp-extra a:hover,
html[data-theme="dark"] .ch-nlp .ch-nlp-extra a:focus,
html[data-theme="dark"] .ch-nlp .ch-nlp-extra a:active {
    color: #DBEAFE;
}

html[data-theme="dark"] .ch-nl-topic.is-featured {
    border-color: rgba(52, 211, 153, 0.45);
    background-color: rgba(16, 185, 129, 0.1);
}

html[data-theme="dark"] .ch-nl-topic.is-featured:hover {
    border-color: #34D399;
    background-color: rgba(16, 185, 129, 0.14);
}

html[data-theme="dark"] .ch-nl-topic.is-featured .ch-nl-check {
    border-color: #34D399;
}

html[data-theme="dark"] .ch-nl-topic.is-featured input:checked ~ .ch-nl-check {
    background-color: #10B981;
    border-color: #10B981;
    color: #04241C;
}

/* ==========================================================================
   21. CONTRAST PASS: SIGN-IN DECK AND ACCOUNT BUTTONS (2026-10-03)
   Found by the hover/focus audit when /newsletter/ started sending guests to
   the deck:
   - .ch-btn-auth was white on Emerald 500 #10B981 (2.5:1, 3.8:1 on hover).
     Light is now Emerald 700 #047857 with white text (5.5:1), dark is
     #10B981 with #04241C text, the pairs the brand standard prescribes.
   - An inactive .ch-auth-tab took GeneratePress's white button:focus text
     on its transparent background (1:1, invisible), and its hover was
     #10B981 on the light well (2.4:1).
   - .ch-eye hover was #10B981 on white (2.4:1).
   Colour AND background on every state, above button:hover (0,1,1).
   ========================================================================== */
.ch-btn-auth {
    background-color: #047857;
    box-shadow: 0 4px 15px rgba(4, 120, 87, 0.28);
}

.ch-btn-auth:hover,
.ch-btn-auth:focus,
.ch-btn-auth:focus-visible,
.ch-btn-auth:active {
    background-color: #065F46;
    color: #FFFFFF;
}

.ch-btn-auth:focus-visible {
    outline: 3px solid rgba(16, 185, 129, 0.45);
    outline-offset: 3px;
}

html[data-theme="dark"] .ch-btn-auth {
    background-color: #10B981;
    color: #04241C;
    box-shadow: 0 4px 15px rgba(16, 185, 129, 0.25);
}

html[data-theme="dark"] .ch-btn-auth:hover,
html[data-theme="dark"] .ch-btn-auth:focus,
html[data-theme="dark"] .ch-btn-auth:focus-visible,
html[data-theme="dark"] .ch-btn-auth:active {
    background-color: #34D399;
    color: #04241C;
}

html[data-theme="dark"] .ch-btn-auth .ch-btn-spinner {
    border-color: rgba(4, 36, 28, 0.3);
    border-top-color: #04241C;
}

/* Focus first, hover second: a focused tab under the pointer shows hover. */
.ch-auth-tab:focus {
    color: var(--ch-text-muted) !important;
}

.ch-auth-tab:hover {
    color: #047857 !important;
}

html[data-theme="dark"] .ch-auth-tab:hover {
    color: #34D399 !important;
}

.ch-eye:hover,
.ch-eye:focus,
.ch-eye:active {
    background-color: rgba(16, 185, 129, 0.08);
    color: #047857;
}

html[data-theme="dark"] .ch-eye:hover,
html[data-theme="dark"] .ch-eye:focus,
html[data-theme="dark"] .ch-eye:active {
    background-color: rgba(16, 185, 129, 0.12);
    color: #34D399;
}

/* The contact form's .ch-field label rule in style.css (0,1,1: block, mono,
   uppercase, muted) also matched the consent rows of the registration form,
   which are labels inside .ch-field too, and stacked the tick box above
   uppercase text. 0,2,0 puts the checkbox row back in its own layout. */
.ch-field .ch-nl-topic {
    display: flex;
    margin-bottom: 0;
    font-family: inherit;
    font-size: inherit;
    font-weight: inherit;
    letter-spacing: normal;
    text-transform: none;
    color: inherit;
}
