/**
 * Instinctor Frontend Styles
 */

/* Single Product */
/* ── Global: suppress browser dotted/glowing focus ring everywhere ─────────── */
*:focus {
    outline: none !important;
    box-shadow: none !important;
}
*:focus-visible {
    outline: none !important;
    box-shadow: none !important;
}

.instinctor-single-product {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 40px;
    padding: 40px 0;
}

@media (max-width: 768px) {
    .instinctor-single-product {
        grid-template-columns: 1fr;
    }
}

.instinctor-product-gallery {
    background: #f5f5f5;
    border-radius: 8px;
    aspect-ratio: 1;
    overflow: hidden;
}

.instinctor-product-gallery img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.instinctor-product-details h1 {
    font-size: 28px;
    margin: 0 0 16px;
}

.instinctor-product-details .instinctor-product-price {
    font-size: 24px;
    margin-bottom: 20px;
}

.instinctor-product-description {
    color: #555;
    line-height: 1.6;
    margin-bottom: 24px;
}

/* Add to Cart Form */
.instinctor-add-to-cart-form {
    display: flex;
    gap: 12px;
    align-items: center;
    margin-bottom: 24px;
}

.instinctor-quantity-input {
    width: 80px;
    padding: 12px;
    font-size: 16px;
    border: 1px solid #ddd;
    border-radius: 4px;
    text-align: center;
}

.instinctor-add-to-cart-btn {
    flex: 1;
    padding: 14px 24px;
    font-size: 16px;
    font-weight: 600;
    color: #fff;
    background: #1d2327;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    transition: background 0.2s ease-in-out;
}

.instinctor-add-to-cart-btn:hover {
    background: #3c434a;
}

.instinctor-add-to-cart-btn:disabled {
    background: #ccc;
    cursor: not-allowed;
}

/* Cart */
.instinctor-cart {
    max-width: 800px;
    margin: 0 auto;
    padding: 40px 20px;
}

.instinctor-cart-empty {
    text-align: center;
    padding: 60px 20px;
}

.instinctor-cart-empty h2 {
    margin-bottom: 10px;
}

.instinctor-cart-empty p {
    color: #666;
    margin-bottom: 20px;
}

.instinctor-cart-table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 30px;
}

.instinctor-cart-table th,
.instinctor-cart-table td {
    padding: 16px;
    text-align: left;
    border-bottom: 1px solid #eee;
}

.instinctor-cart-table th {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: #666;
}

.instinctor-cart-item-image {
    width: 60px;
    height: 60px;
    background: #f5f5f5;
    border-radius: 4px;
    overflow: hidden;
}

.instinctor-cart-item-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.instinctor-cart-item-info {
    display: flex;
    align-items: center;
    gap: 16px;
}

.instinctor-cart-item-name {
    font-weight: 600;
}

.instinctor-cart-item-remove {
    color: #c00;
    font-size: 12px;
    cursor: pointer;
    background: none;
    border: none;
    padding: 4px 0;
}

.instinctor-cart-item-remove:hover {
    text-decoration: underline;
}

.instinctor-cart-totals {
    background: #f9f9f9;
    padding: 24px;
    border-radius: 8px;
}

.instinctor-cart-totals-row {
    display: flex;
    justify-content: space-between;
    padding: 8px 0;
}

.instinctor-cart-totals-row.total {
    font-size: 18px;
    font-weight: 700;
    border-top: 2px solid #ddd;
    margin-top: 12px;
    padding-top: 16px;
}

.instinctor-cart-actions {
    display: flex;
    justify-content: space-between;
    margin-top: 24px;
}

/* Checkout */
.instinctor-checkout {
    max-width: 1000px;
    margin: 0 auto;
    padding: 40px 20px;
}

.instinctor-checkout-grid {
    display: grid;
    grid-template-columns: 1fr 400px;
    gap: 40px;
}

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

.instinctor-checkout-section {
    background: #fff;
    border: 1px solid #e0e0e0;
    border-radius: 8px;
    padding: 24px;
    margin-bottom: 24px;
}

.instinctor-checkout-section h2 {
    font-size: 18px;
    margin: 0 0 20px;
    padding-bottom: 12px;
    border-bottom: 1px solid #eee;
}

.instinctor-form-row {
    margin-bottom: 16px;
}

.instinctor-form-row label {
    display: block;
    font-weight: 500;
    margin-bottom: 6px;
}

.instinctor-form-row input,
.instinctor-form-row select {
    width: 100%;
    padding: 12px;
    font-size: 15px;
    border: 1px solid #ddd;
    border-radius: 4px;
}

.instinctor-form-row input:focus,
.instinctor-form-row select:focus {
    border-color: #1d2327;
    outline: none;
}

.instinctor-form-row-half {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}

.instinctor-order-summary {
    background: #f9f9f9;
    border-radius: 8px;
    padding: 24px;
    position: sticky;
    top: 20px;
}

.instinctor-order-summary h2 {
    font-size: 18px;
    margin: 0 0 20px;
}

.instinctor-place-order-btn {
    width: 100%;
    padding: 16px;
    font-size: 16px;
    font-weight: 600;
    color: #fff;
    background: #1d2327;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    margin-top: 20px;
}

.instinctor-place-order-btn:hover {
    background: #3c434a;
}

/* Buttons */
.instinctor-btn {
    display: inline-block;
    padding: 12px 24px;
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
    border-radius: 4px;
    cursor: pointer;
    transition: all 0.2s ease-in-out;
}

.instinctor-btn-primary {
    color: #fff;
    background: #1d2327;
    border: none;
}

.instinctor-btn-primary:hover {
    background: #3c434a;
    color: #fff;
}

.instinctor-btn-secondary {
    color: #1d2327;
    background: #f0f0f1;
    border: 1px solid #ddd;
}

.instinctor-btn-secondary:hover {
    background: #e0e0e0;
    color: #1d2327;
}

/* Messages */
.instinctor-message {
    padding: 16px 20px;
    border-radius: 4px;
    margin-bottom: 20px;
}

.instinctor-message-success {
    background: #d4edda;
    color: #155724;
    border: 1px solid #c3e6cb;
}

.instinctor-message-error {
    background: #f8d7da;
    color: #721c24;
    border: 1px solid #f5c6cb;
}

.instinctor-message-info {
    background: #d1ecf1;
    color: #0c5460;
    border: 1px solid #bee5eb;
}

/* Loading */
.instinctor-loading {
    text-align: center;
    padding: 40px;
}

.instinctor-spinner {
    display: inline-block;
    width: 30px;
    height: 30px;
    border: 3px solid #f0f0f1;
    border-top-color: #1d2327;
    border-radius: 50%;
    animation: instinctor-spin 0.8s linear infinite;
}

@keyframes instinctor-spin {
    to { transform: rotate(360deg); }
}

/* Currency Switcher */
.instinctor-currency-selector {
    display: inline-block;
}

.instinctor-currency-selector select {
    padding: 8px 32px 8px 12px;
    border: 1px solid #ddd;
    border-radius: 4px;
    background: #fff url('data:image/svg+xml;charset=US-ASCII,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4 5"><path fill="%23666" d="M2 0L0 2h4zm0 5L0 3h4z"/></svg>') no-repeat right 10px center;
    background-size: 8px;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    cursor: pointer;
    font-size: 14px;
}

.instinctor-currency-selector select:hover {
    border-color: #999;
}

.instinctor-currency-selector select:focus {
    outline: none;
    border-color: #1d2327;
    box-shadow: 0 0 0 1px #1d2327;
}

/* ==========================================================================
   Social Proof Styles
   ========================================================================== */

/* Purchase Notification Popup */
.instinctor-purchase-notification {
    position: fixed;
    z-index: 9999;
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
    padding: 16px;
    max-width: 320px;
    opacity: 0;
    transform: translateY(20px);
    transition: all 0.3s ease-in-out;
    pointer-events: none;
}

.instinctor-purchase-notification.instinctor-visible {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.instinctor-purchase-notification.instinctor-position-bottom-left {
    bottom: 20px;
    left: 20px;
}

.instinctor-purchase-notification.instinctor-position-bottom-right {
    bottom: 20px;
    right: 20px;
}

.instinctor-purchase-notification.instinctor-position-top-left {
    top: 20px;
    left: 20px;
}

.instinctor-purchase-notification.instinctor-position-top-right {
    top: 20px;
    right: 20px;
}

.instinctor-purchase-notification-inner {
    display: flex;
    gap: 12px;
    align-items: flex-start;
}

.instinctor-purchase-notification-image {
    width: 60px;
    height: 60px;
    border-radius: 6px;
    overflow: hidden;
    flex-shrink: 0;
    background: #f5f5f5;
}

.instinctor-purchase-notification-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.instinctor-purchase-notification-content {
    flex: 1;
    min-width: 0;
}

.instinctor-purchase-notification-message {
    font-size: 14px;
    color: #333;
    margin-bottom: 4px;
    line-height: 1.4;
}

.instinctor-purchase-notification-product {
    font-weight: 600;
    color: #1d2327;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.instinctor-purchase-notification-time {
    font-size: 12px;
    color: #888;
}

.instinctor-purchase-notification-close {
    position: absolute;
    top: 8px;
    right: 8px;
    background: none;
    border: none;
    font-size: 18px;
    color: #999;
    cursor: pointer;
    padding: 0;
    line-height: 1;
}

.instinctor-purchase-notification-close:hover {
    color: #333;
}

/* Visitor Count Badge */
.instinctor-visitor-count {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: #fff;
    border-radius: 20px;
    font-size: 13px;
    font-weight: 500;
    box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
}

.instinctor-visitor-count-icon {
    display: flex;
    align-items: center;
}

.instinctor-visitor-count-icon::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    background: #22863a;
    border-radius: 50%;
    margin-right: 4px;
    animation: instinctor-pulse 2s infinite;
}

@keyframes instinctor-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.6; transform: scale(0.9); }
}

.instinctor-visitor-count-number {
    font-weight: 700;
}

/* Stock Urgency Alert */
.instinctor-stock-urgency {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    border-radius: 6px;
    font-size: 14px;
    font-weight: 500;
    margin: 12px 0;
}

.instinctor-stock-urgency-low {
    background: #fef3c7;
    color: #92400e;
    border: 1px solid #fcd34d;
}

.instinctor-stock-urgency-critical {
    background: #fee2e2;
    color: #991b1b;
    border: 1px solid #fca5a5;
    animation: instinctor-urgency-flash 2s infinite;
}

@keyframes instinctor-urgency-flash {
    0%, 100% { background: #fee2e2; }
    50% { background: #fecaca; }
}

.instinctor-stock-urgency-icon {
    font-size: 16px;
}

.instinctor-stock-urgency-icon::before {
    content: '!';
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    background: currentColor;
    color: #fff;
    border-radius: 50%;
    font-size: 12px;
    font-weight: 700;
}

.instinctor-stock-urgency-critical .instinctor-stock-urgency-icon::before {
    background: #dc2626;
}

.instinctor-stock-urgency-low .instinctor-stock-urgency-icon::before {
    background: #d97706;
}

/* Cart Activity */
.instinctor-cart-activity {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    background: #f0fdf4;
    border: 1px solid #86efac;
    border-radius: 6px;
    font-size: 14px;
    color: #166534;
    margin: 12px 0;
}

.instinctor-cart-activity-icon {
    font-size: 18px;
}

.instinctor-cart-activity-icon::before {
    content: '';
    display: inline-block;
    width: 18px;
    height: 18px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2316a34a'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z'/%3E%3C/svg%3E");
    background-size: contain;
    background-repeat: no-repeat;
}

.instinctor-cart-activity-count {
    font-weight: 700;
}

/* Recent Sales */
.instinctor-recent-sales {
    padding: 12px 16px;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    margin: 12px 0;
}

.instinctor-recent-sales-header {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 600;
    color: #374151;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 12px;
}

.instinctor-recent-sales-header::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    background: #22863a;
    border-radius: 50%;
    animation: instinctor-pulse 2s infinite;
}

.instinctor-recent-sales-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.instinctor-recent-sales-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid #f3f4f6;
    font-size: 13px;
    color: #4b5563;
}

.instinctor-recent-sales-item:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.instinctor-recent-sales-item-image {
    width: 36px;
    height: 36px;
    border-radius: 4px;
    overflow: hidden;
    background: #f5f5f5;
    flex-shrink: 0;
}

.instinctor-recent-sales-item-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.instinctor-recent-sales-item-info {
    flex: 1;
    min-width: 0;
}

.instinctor-recent-sales-item-product {
    font-weight: 500;
    color: #1f2937;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.instinctor-recent-sales-item-time {
    font-size: 11px;
    color: #9ca3af;
}

/* FOMO Countdown Timer */
.instinctor-fomo-countdown {
    padding: 16px;
    background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
    border-radius: 8px;
    color: #fff;
    text-align: center;
    margin: 16px 0;
}

.instinctor-fomo-countdown-message {
    font-size: 14px;
    margin-bottom: 12px;
    font-weight: 500;
}

.instinctor-fomo-countdown-timer {
    display: flex;
    justify-content: center;
    gap: 12px;
}

.instinctor-fomo-countdown-unit {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 50px;
}

.instinctor-fomo-countdown-value {
    font-size: 28px;
    font-weight: 700;
    line-height: 1;
    background: rgba(255, 255, 255, 0.2);
    padding: 8px 12px;
    border-radius: 6px;
}

.instinctor-fomo-countdown-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-top: 6px;
    opacity: 0.9;
}

.instinctor-fomo-countdown-separator {
    font-size: 24px;
    font-weight: 700;
    line-height: 44px;
}

/* ==========================================================================
   Vendor Store Styles
   ========================================================================== */

.instinctor-vendor-store {
    padding: 20px 0;
}

.instinctor-vendor-header {
    position: relative;
    margin-bottom: 30px;
}

.instinctor-vendor-banner {
    height: 200px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border-radius: 12px;
    overflow: hidden;
}

.instinctor-vendor-banner img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.instinctor-vendor-info {
    display: flex;
    align-items: flex-end;
    gap: 20px;
    margin-top: -40px;
    padding: 0 20px;
}

.instinctor-vendor-logo {
    width: 100px;
    height: 100px;
    border-radius: 12px;
    border: 4px solid #fff;
    background: #fff;
    overflow: hidden;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.instinctor-vendor-logo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.instinctor-vendor-logo-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f5;
    font-size: 32px;
    font-weight: 700;
    color: #999;
}

.instinctor-vendor-details {
    flex: 1;
    padding-bottom: 10px;
}

.instinctor-vendor-name {
    font-size: 24px;
    font-weight: 700;
    margin: 0 0 4px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.instinctor-vendor-verified {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    background: #1d2327;
    color: #fff;
    border-radius: 50%;
    font-size: 12px;
}

.instinctor-vendor-meta {
    display: flex;
    gap: 16px;
    font-size: 14px;
    color: #666;
}

.instinctor-vendor-rating {
    display: flex;
    align-items: center;
    gap: 4px;
}

.instinctor-vendor-stars {
    color: #f59e0b;
}

.instinctor-vendor-description {
    margin-top: 16px;
    color: #555;
    line-height: 1.6;
}

/* ==========================================================================
   Vendor Dashboard Styles
   ========================================================================== */

.instinctor-vendor-dashboard {
    padding: 20px 0;
}

.instinctor-vendor-dashboard-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 24px;
}

.instinctor-vendor-dashboard-header h1 {
    margin: 0;
    font-size: 28px;
}

.instinctor-vendor-status-badge {
    display: inline-block;
    padding: 6px 12px;
    border-radius: 20px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
}

.instinctor-vendor-status-active {
    background: #d1fae5;
    color: #065f46;
}

.instinctor-vendor-status-pending {
    background: #fef3c7;
    color: #92400e;
}

.instinctor-vendor-status-suspended {
    background: #fee2e2;
    color: #991b1b;
}

.instinctor-vendor-dashboard-nav {
    display: flex;
    gap: 8px;
    border-bottom: 1px solid #e5e7eb;
    margin-bottom: 24px;
    overflow-x: auto;
}

.instinctor-vendor-dashboard-nav a {
    display: block;
    padding: 12px 20px;
    color: #666;
    text-decoration: none;
    font-weight: 500;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    transition: all 0.2s;
}

.instinctor-vendor-dashboard-nav a:hover {
    color: #1d2327;
}

.instinctor-vendor-dashboard-nav a.active {
    color: #1d2327;
    border-bottom-color: #1d2327;
}

.instinctor-vendor-stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 20px;
    margin-bottom: 30px;
}

.instinctor-vendor-stat-card {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    padding: 20px;
}

.instinctor-vendor-stat-label {
    font-size: 13px;
    color: #666;
    margin-bottom: 8px;
}

.instinctor-vendor-stat-value {
    font-size: 28px;
    font-weight: 700;
    color: #1d2327;
}

.instinctor-vendor-stat-value.positive {
    color: #059669;
}

/* ==========================================================================
   Wholesale Application Styles
   ========================================================================== */

.instinctor-wholesale-application {
    max-width: 600px;
    margin: 0 auto;
    padding: 30px 0;
}

.instinctor-wholesale-benefits {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 16px;
    margin-bottom: 30px;
}

.instinctor-wholesale-benefit {
    background: #f0fdf4;
    border: 1px solid #86efac;
    border-radius: 12px;
    padding: 20px;
    text-align: center;
}

.instinctor-wholesale-benefit-icon {
    font-size: 32px;
    margin-bottom: 10px;
}

.instinctor-wholesale-benefit-title {
    font-weight: 600;
    margin-bottom: 4px;
}

.instinctor-wholesale-benefit-desc {
    font-size: 13px;
    color: #666;
}

/* ==========================================================================
   Bulk Order Form Styles
   ========================================================================== */

.instinctor-bulk-order-form {
    padding: 20px 0;
}

.instinctor-bulk-order-notice {
    background: #eff6ff;
    border: 1px solid #93c5fd;
    border-radius: 8px;
    padding: 16px;
    margin-bottom: 24px;
    color: #1e40af;
}

.instinctor-bulk-order-table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 24px;
}

.instinctor-bulk-order-table th {
    background: #f9fafb;
    padding: 12px;
    text-align: left;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: #6b7280;
    border-bottom: 2px solid #e5e7eb;
}

.instinctor-bulk-order-table td {
    padding: 16px 12px;
    border-bottom: 1px solid #e5e7eb;
    vertical-align: middle;
}

.instinctor-bulk-order-product {
    display: flex;
    align-items: center;
    gap: 12px;
}

.instinctor-bulk-order-product-image {
    width: 50px;
    height: 50px;
    border-radius: 6px;
    overflow: hidden;
    background: #f5f5f5;
}

.instinctor-bulk-order-product-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.instinctor-quantity-breaks {
    position: relative;
    display: inline-block;
}

.instinctor-quantity-breaks-trigger {
    background: #e0e7ff;
    color: #4338ca;
    border: none;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
    cursor: pointer;
}

.instinctor-quantity-breaks-popup {
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 12px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    white-space: nowrap;
    z-index: 100;
    display: none;
}

.instinctor-quantity-breaks-trigger:hover + .instinctor-quantity-breaks-popup,
.instinctor-quantity-breaks-popup:hover {
    display: block;
}

.instinctor-quantity-breaks-popup ul {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 13px;
}

.instinctor-quantity-breaks-popup li {
    padding: 4px 0;
}

.instinctor-bulk-order-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px;
    background: #f9fafb;
    border-radius: 8px;
}

.instinctor-bulk-order-total {
    font-size: 18px;
    font-weight: 700;
}

/* ==========================================================================
   Quote Request Styles
   ========================================================================== */

.instinctor-quote-request {
    max-width: 700px;
    margin: 0 auto;
    padding: 30px 0;
}

.instinctor-quote-items {
    margin-bottom: 24px;
}

.instinctor-quote-item {
    display: grid;
    grid-template-columns: 1fr 100px 1fr auto;
    gap: 12px;
    align-items: end;
    padding: 16px;
    background: #f9fafb;
    border-radius: 8px;
    margin-bottom: 12px;
}

.instinctor-quote-item-remove {
    background: none;
    border: none;
    color: #dc2626;
    cursor: pointer;
    padding: 8px;
}

.instinctor-quote-add-item {
    background: #f0f9ff;
    border: 2px dashed #93c5fd;
    color: #2563eb;
    padding: 12px;
    border-radius: 8px;
    cursor: pointer;
    text-align: center;
    font-weight: 500;
    transition: all 0.2s;
}

.instinctor-quote-add-item:hover {
    background: #e0f2fe;
    border-color: #60a5fa;
}

/* ==========================================================================
   Recommendations Grid Styles
   ========================================================================== */

.instinctor-recommendations {
    padding: 30px 0;
}

.instinctor-recommendations-title {
    font-size: 22px;
    font-weight: 700;
    margin: 0 0 20px;
}

.instinctor-recommendations-grid {
    display: grid;
    gap: 20px;
}

.instinctor-recommendations-grid.columns-2 {
    grid-template-columns: repeat(2, 1fr);
}

.instinctor-recommendations-grid.columns-3 {
    grid-template-columns: repeat(3, 1fr);
}

.instinctor-recommendations-grid.columns-4 {
    grid-template-columns: repeat(4, 1fr);
}

@media (max-width: 900px) {
    .instinctor-recommendations-grid.columns-4 {
        grid-template-columns: repeat(3, 1fr);
    }
}

@media (max-width: 700px) {
    .instinctor-recommendations-grid.columns-3,
    .instinctor-recommendations-grid.columns-4 {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 500px) {
    .instinctor-recommendations-grid {
        grid-template-columns: 1fr !important;
    }
}

.instinctor-recommendation-card {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    overflow: hidden;
    transition: all 0.2s;
}

.instinctor-recommendation-card:hover {
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
    transform: translateY(-2px);
}

.instinctor-recommendation-image {
    position: relative;
    aspect-ratio: 1;
    background: #f5f5f5;
    overflow: hidden;
}

.instinctor-recommendation-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.3s;
}

.instinctor-recommendation-card:hover .instinctor-recommendation-image img {
    transform: scale(1.05);
}

.instinctor-recommendation-sale-badge {
    position: absolute;
    top: 10px;
    left: 10px;
    background: #dc2626;
    color: #fff;
    padding: 4px 10px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 600;
}

.instinctor-recommendation-info {
    padding: 16px;
}

.instinctor-recommendation-title {
    font-size: 15px;
    font-weight: 600;
    margin: 0 0 8px;
    line-height: 1.4;
}

.instinctor-recommendation-title a {
    color: inherit;
    text-decoration: none;
}

.instinctor-recommendation-title a:hover {
    color: #1d2327;
}

.instinctor-recommendation-price {
    font-size: 17px;
    font-weight: 700;
    margin-bottom: 8px;
}

.instinctor-recommendation-price .sale-price {
    color: #dc2626;
}

.instinctor-recommendation-price .original-price {
    text-decoration: line-through;
    color: #9ca3af;
    font-size: 14px;
    font-weight: 400;
    margin-left: 8px;
}

.instinctor-recommendation-rating {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: #6b7280;
    margin-bottom: 12px;
}

.instinctor-recommendation-stars {
    color: #f59e0b;
}

.instinctor-recommendation-add-btn {
    width: 100%;
    padding: 10px;
    background: #1d2327;
    color: #fff;
    border: none;
    border-radius: 6px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.2s;
}

.instinctor-recommendation-add-btn:hover {
    background: #3c434a;
}

/* ==============================
   Language Switcher
   ============================== */
.instinctor-language-switcher {
    position: relative;
    display: inline-block;
    font-size: 14px;
}

/* Dropdown Style */
.instinctor-lang-dropdown .instinctor-lang-current {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    background: #fff;
    border: 1px solid #e0e0e0;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    transition: border-color 0.2s;
}

.instinctor-lang-dropdown .instinctor-lang-current:hover {
    border-color: #1d2327;
}

.instinctor-lang-dropdown .instinctor-lang-current svg {
    transition: transform 0.2s;
}

.instinctor-lang-dropdown:hover .instinctor-lang-current svg {
    transform: rotate(180deg);
}

.instinctor-lang-dropdown .instinctor-lang-list {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    min-width: 160px;
    margin: 4px 0 0;
    padding: 4px 0;
    background: #fff;
    border: 1px solid #e0e0e0;
    border-radius: 6px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    list-style: none;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition: all 0.2s;
    z-index: 1000;
}

.instinctor-lang-dropdown:hover .instinctor-lang-list {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.instinctor-lang-dropdown .instinctor-lang-list li a {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    color: #1d2327;
    text-decoration: none;
    transition: background 0.2s;
}

.instinctor-lang-dropdown .instinctor-lang-list li a:hover,
.instinctor-lang-dropdown .instinctor-lang-list li a.active {
    background: #f5f5f5;
}

.instinctor-lang-dropdown .instinctor-lang-list li a.active {
    font-weight: 600;
}

.instinctor-lang-flag {
    font-size: 18px;
    line-height: 1;
}

/* Flags Style */
.instinctor-lang-flags {
    display: flex;
    align-items: center;
    gap: 8px;
}

.instinctor-lang-flags .instinctor-lang-flag-link {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    font-size: 20px;
    text-decoration: none;
    border-radius: 4px;
    opacity: 0.6;
    transition: all 0.2s;
}

.instinctor-lang-flags .instinctor-lang-flag-link:hover,
.instinctor-lang-flags .instinctor-lang-flag-link.active {
    opacity: 1;
    background: #f5f5f5;
}

.instinctor-lang-flags .instinctor-lang-flag-link.active {
    box-shadow: 0 0 0 2px #1d2327;
}

/* RTL Support */

/* Flex Grid Responsive */
.impulse-flex-grid {
    width: 100%;
}

.impulse-flex-row {
    width: 100%;
}

.impulse-flex-cell {
    min-width: 0;
}

/* Stack on tablet (< 1024px) */
@media (max-width: 1024px) {
    .impulse-flex-row.impulse-stack-tablet {
        flex-direction: column !important;
    }
    
    .impulse-flex-row.impulse-stack-tablet > .impulse-flex-cell {
        flex: 0 0 100% !important;
        width: 100% !important;
    }
}

/* Stack on mobile (< 768px) */
@media (max-width: 768px) {
    .impulse-flex-row.impulse-stack-mobile {
        flex-direction: column !important;
    }
    
    .impulse-flex-row.impulse-stack-mobile > .impulse-flex-cell {
        flex: 0 0 100% !important;
        width: 100% !important;
    }
}

/* Hide number input spinners in cart/quantity selectors */
.impulse-cart-block input[type="number"],
.impulse-quantity-selector input[type="number"],
.instinctor-cart input[type="number"] {
    -moz-appearance: textfield;
}
.impulse-cart-block input[type="number"]::-webkit-outer-spin-button,
.impulse-cart-block input[type="number"]::-webkit-inner-spin-button,
.impulse-quantity-selector input[type="number"]::-webkit-outer-spin-button,
.impulse-quantity-selector input[type="number"]::-webkit-inner-spin-button,
.instinctor-cart input[type="number"]::-webkit-outer-spin-button,
.instinctor-cart input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* ========================================
   Product Grid + Card Base
   ======================================== */
.impulse-product-grid {
    box-sizing: border-box;
    width: 100%;
}

.impulse-product-grid > * {
    min-width: 0;
}

.impulse-pcard {
    min-width: 0;        /* grid handles sizing — never force wider than a column */
    max-width: 100%;
    width: 100%;
    box-sizing: border-box;
}

/* Pointer cursor only when card is actually clickable */
[data-qv*='"enable_modal":true'] .impulse-pcard,
.impulse-flip-card .impulse-pcard {
    cursor: pointer;
}

.impulse-pcard img {
    width: 100%;
    max-width: 100%;
    height: auto;
    display: block;
    box-sizing: border-box;
}

/* ========================================
   Product Card Image Slideshow
   ======================================== */
.impulse-pcard-image.has-slideshow {
    /* Slideshow handled by JS */
}

.impulse-pcard-slide-img {
    transition: opacity 0.5s ease-in-out;
}

.impulse-pcard-dots {
    pointer-events: auto;
}

.impulse-pcard-dot {
    transition: background 0.3s ease-in-out;
}

.impulse-pcard-dot:hover {
    transform: scale(1.2);
}

/* Legacy hover fade for 2-image cards without slideshow */
.impulse-pcard-image:not(.has-slideshow):hover .impulse-pcard-img-primary {
    opacity: 0;
}

.impulse-pcard-image:not(.has-slideshow):hover .impulse-pcard-img-secondary {
    opacity: 1;
}

/* ========================================
   Quick View Modal
   ======================================== */
.impulse-quickview-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.6);
    z-index: 99999;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
}

.impulse-quickview-overlay.active {
    opacity: 1;
    visibility: visible;
}

.impulse-quickview-modal {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0.95);
    background: #fff;
    border-radius: 12px;
    width: 90%;
    max-width: 900px;
    max-height: 90vh;
    overflow: hidden;
    z-index: 100000;
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease-in-out;
    box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25);
}

.impulse-quickview-overlay.active .impulse-quickview-modal {
    opacity: 1;
    visibility: visible;
    transform: translate(-50%, -50%) scale(1);
}

.impulse-quickview-close {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 28px;
    height: 28px;
    background: transparent;
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
    transition: background 0.15s, border-color 0.15s;
    padding: 0;
}

.impulse-quickview-close:hover {
    background: #f5f5f5;
    border-color: #ccc;
}

.impulse-quickview-close svg {
    width: 14px;
    height: 14px;
    stroke: #666;
}

.impulse-quickview-content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    min-height: 400px;
}

/* ---- Mobile quickview ---- */
@media (max-width: 768px) {
    .impulse-quickview-content {
        grid-template-columns: 1fr;
        max-height: 90vh;
        overflow-y: auto;
    }
    .impulse-quickview-modal {
        width: 96%;
        border-radius: 8px;
        max-height: 92vh;
        overflow-y: auto;   /* modal itself scrolls on mobile; gallery+details stack vertically */
    }
    .impulse-quickview-gallery {
        height: 60vw;          /* fixed height — abs children (image, thumbs) need this */
        min-height: 200px;
        max-height: 320px;
        flex-shrink: 0;
    }
    /* Zoom preview is desktop-only — useless on touch, can shift the viewport */
    img.impulse-qv-preview {
        display: none !important;
    }
    /* Thumbs strip: solid bg so it doesn't show image content behind it */
    .impulse-quickview-thumbs {
        background: rgba(0, 0, 0, 0.45);
    }
    /* Zoom button: hide on touch */
    .impulse-quickview-zoom-btn {
        display: none !important;
    }
}

/* Gallery Side */
.impulse-quickview-gallery {
    position: relative;
    overflow: hidden;
    background: #f5f5f5;
}

.impulse-quickview-gallery-main {
    position: absolute;
    inset: 0;
    overflow: hidden;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
}

.impulse-quickview-gallery-main:active {
    cursor: pointer;
}

.impulse-quickview-gallery-main img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity 0.3s ease-in-out, transform 0.4s ease-in-out;
    pointer-events: none;
    transform: scale(1);
    transform-origin: center center;
}

.impulse-quickview-gallery-main img.active {
    opacity: 1;
}

.impulse-quickview-gallery-main .impulse-quickview-zoom-btn {
    position: absolute;
    top: 10px;
    left: 10px;
    width: 30px;
    height: 30px;
    background: rgba(0, 0, 0, 0.45);
    border: none;
    border-radius: 4px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
    opacity: 0.6 !important;
    transition: opacity 0.2s ease-in-out, background 0.2s ease-in-out;
    padding: 0;
}

.impulse-quickview-gallery-main:hover .impulse-quickview-zoom-btn,
.impulse-quickview-gallery-main .impulse-quickview-zoom-btn:hover {
    opacity: 1;
    background: rgba(0, 0, 0, 0.7);
}

.impulse-quickview-gallery-main .impulse-quickview-zoom-btn svg {
    width: 16px;
    height: 16px;
    stroke: #fff;
    flex-shrink: 0;
}


/* Hover preview — bare image, no wrapper/background/shadow */
img.impulse-qv-preview {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0.92);
    max-width: 80vw;
    max-height: 80vh;
    width: auto;
    height: auto;
    object-fit: contain;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.22s ease-in-out, transform 0.28s ease-in-out;
    z-index: 200000;
}

img.impulse-qv-preview.active {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
}

/* Thumbs strip — floats over bottom of image */
.impulse-quickview-thumbs {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex;
    gap: 6px;
    padding: 10px;
    overflow-x: auto;
    flex-shrink: 0;
    scrollbar-width: none;
    -ms-overflow-style: none;
    background: transparent;
}

.impulse-quickview-thumbs::-webkit-scrollbar {
    display: none;
}

.impulse-quickview-thumb {
    width: 52px;
    height: 52px;
    flex-shrink: 0;
    border-radius: 4px;
    overflow: hidden;
    cursor: pointer;
    border: 2px solid rgba(255,255,255,0.4);
    transition: border-color 0.15s;
    background: rgba(255,255,255,0.15);
}

.impulse-quickview-thumb.active {
    border-color: #fff;
}

.impulse-quickview-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    pointer-events: none;
}

/* Navigation dots (alternative to thumbs for many images) */
.impulse-quickview-dots {
    position: absolute;
    bottom: 16px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 8px;
}

.impulse-quickview-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.5);
    cursor: pointer;
    transition: background 0.2s;
}

.impulse-quickview-dot.active {
    background: #fff;
}

/* Details Side */
.impulse-quickview-details {
    padding: 32px;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
}

@media (max-width: 768px) {
    .impulse-quickview-details {
        padding: 24px;
    }
}

.impulse-quickview-title {
    font-size: 24px;
    font-weight: 600;
    margin: 0 0 16px;
    padding-right: 36px; /* clear close button */
    color: #1d2327;
    line-height: 1.3;
}

.impulse-quickview-desc {
    color: #666;
    font-size: 14px;
    line-height: 1.6;
    margin: 0 0 16px;
}

.impulse-quickview-sku {
    font-size: 12px;
    color: #999;
    margin: 0 0 20px;
}

/* Variants */
.impulse-quickview-variants {
    margin-bottom: 20px;
}

.impulse-quickview-variant-group {
    margin-bottom: 16px;
}

.impulse-quickview-variant-label {
    font-size: 13px;
    font-weight: 500;
    color: #333;
    margin-bottom: 8px;
}

.impulse-quickview-variant-options {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.impulse-quickview-variant-btn {
    padding: 8px 16px;
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    background: #fff;
    font-size: 13px;
    cursor: pointer;
    transition: all 0.15s;
}

.impulse-quickview-variant-btn:hover {
    border-color: #999;
}

.impulse-quickview-variant-btn.active {
    border-color: #1d2327;
    background: #1d2327;
    color: #fff;
}

/* Color swatches */
.impulse-quickview-color-swatch {
    width: 28px;
    height: 28px;
    border-radius: 4px;
    border: 2px solid #e0e0e0;
    cursor: pointer;
    transition: all 0.15s;
}

.impulse-quickview-color-swatch:hover {
    border-color: #999;
}

.impulse-quickview-color-swatch.active {
    border-color: #1d2327;
    box-shadow: 0 0 0 2px #fff, 0 0 0 4px #1d2327;
}

/* Add to Cart / Actions — always at the bottom of the details column */
.impulse-quickview-actions {
    margin-top: auto;
    padding-top: 12px;
    border-top: 1px solid #f0f0f0;
    flex-shrink: 0;
}

/* Price + Qty on same row */
.impulse-quickview-price-qty-row {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 8px;
}

.impulse-quickview-price {
    font-size: 28px;
    font-weight: 700;
    color: #1d2327;
    flex: 1;
    text-align: right;
}

.impulse-quickview-price del {
    font-size: 16px;
    color: #999;
    font-weight: 400;
    margin-left: 8px;
}

.impulse-quickview-price .sale {
    color: #dc2626;
}

.impulse-quickview-qty-control {
    display: flex;
    align-items: center;
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    overflow: hidden;
    flex-shrink: 0;
}

.impulse-quickview-qty-btn {
    width: 32px;
    height: 34px;
    border: none;
    background: #f5f5f5;
    cursor: pointer;
    font-size: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s;
    padding: 0;
}

.impulse-quickview-qty-btn:hover {
    background: #e0e0e0;
}

.impulse-quickview-qty-input {
    width: 44px;
    height: 34px;
    border: none;
    border-left: 1px solid #e0e0e0;
    border-right: 1px solid #e0e0e0;
    text-align: center;
    font-size: 13px;
    -moz-appearance: textfield;
}

.impulse-quickview-qty-input::-webkit-outer-spin-button,
.impulse-quickview-qty-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.impulse-quickview-add-btn {
    width: 100%;
    padding: 12px 24px;
    background: #1d2327;
    color: #fff;
    border: none;
    border-radius: 6px;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s;
}

.impulse-quickview-add-btn:hover {
    background: #333;
}

.impulse-quickview-add-btn:disabled {
    background: #ccc;
    cursor: not-allowed;
}

/* Placeholder image in gallery — contain so logo doesn't crop */
.impulse-qv-placeholder-img {
    object-fit: contain !important;
    padding: 20%;
}


.impulse-quickview-view-full:hover {
    color: #1d2327;
    text-decoration: underline;
}

/* Loading state */
.impulse-quickview-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 400px;
}

.impulse-quickview-spinner {
    width: 40px;
    height: 40px;
    border: 3px solid #f0f0f0;
    border-top-color: #1d2327;
    border-radius: 50%;
    animation: impulse-spin 0.8s linear infinite;
}

@keyframes impulse-spin {
    to { transform: rotate(360deg); }
}

/* ========================================
   Quick View — Add-on fields
   ======================================== */
.impulse-quickview-addons .ia-addon-check {
    opacity: 1 !important;
    visibility: visible !important;
    appearance: checkbox !important;
    -webkit-appearance: checkbox !important;
    width: 16px !important;
    height: 16px !important;
    display: inline-block !important;
    position: static !important;
    pointer-events: auto !important;
    clip: auto !important;
    clip-path: none !important;
}

/* ========================================
   Product Grid — Mobile centering
   1-col: single card centred with breathing
   room on both sides (max 480px).
   2-col: two equal columns fill the
   container naturally; justify-content:center
   keeps them centred if narrower than parent.
   ======================================== */
@media (max-width: 767px) {

    /* 1-column mode: narrow the grid track so the card doesn't
       stretch edge-to-edge and centre the whole thing */
    .impulse-product-grid[data-cols-mobile="1"] {
        grid-template-columns: minmax(0, 480px) !important;
        justify-content: center !important;
    }

    /* 2-column mode: two equal columns, centred as a unit */
    .impulse-product-grid[data-cols-mobile="2"] {
        grid-template-columns: repeat(2, 1fr) !important;
        justify-content: center !important;
    }
}

/* Product block: outer wrapper fills flex stretch, inner block centers via margin:auto */
.impulse-pblock-outer {
    width: 100%;
    align-self: stretch;
}

/* Section container children that don't have explicit widths should still stretch */
.impulse-container > *:not(.impulse-pblock-outer) {
    align-self: stretch;
}


/* ── Static blocks extracted from template renderer ─────────────────── */

@keyframes impulse-glitch{0%{transform:translate(0);clip-path:inset(0);filter:none}10%{transform:translate(-5px,3px);clip-path:inset(20% 0 40% 0);filter:hue-rotate(90deg)}20%{transform:translate(3px,-2px);clip-path:inset(60% 0 5% 0);filter:hue-rotate(180deg)}30%{transform:translate(-3px,0);clip-path:inset(5% 0 60% 0);filter:hue-rotate(270deg)}40%{transform:translate(5px,2px);clip-path:inset(40% 0 20% 0);filter:none}50%{transform:translate(-2px,-3px);clip-path:inset(0);filter:hue-rotate(120deg)}60%{transform:translate(0);clip-path:inset(0);filter:none;opacity:0}100%{transform:translate(0);clip-path:inset(0);filter:none;opacity:0}}.impulse-flip-glitching{animation:impulse-glitch 0.5s steps(1,end) forwards!important;transition:max-height 0.6s cubic-bezier(0.4, 0, 0.2, 1)!important}

.impulse-flip-card{perspective:1000px;cursor:pointer}.impulse-flip-card .impulse-pcard{box-shadow:none!important}.impulse-flip-inner{position:relative;transform-style:preserve-3d;transition:transform 0.6s ease-in-out}.impulse-flip-front{overflow:hidden}.impulse-flip-back{position:absolute;inset:0;overflow:hidden;display:flex;flex-direction:column}.pfc-flip-h:hover .impulse-flip-inner,.pfc-flip-h.flipped .impulse-flip-inner{transform:rotateY(180deg)}.pfc-flip-h .impulse-flip-front,.pfc-flip-h .impulse-flip-back{backface-visibility:hidden;-webkit-backface-visibility:hidden}.pfc-flip-h .impulse-flip-back{transform:rotateY(180deg)}.pfc-flip-v:hover .impulse-flip-inner,.pfc-flip-v.flipped .impulse-flip-inner{transform:rotateX(180deg)}.pfc-flip-v .impulse-flip-front,.pfc-flip-v .impulse-flip-back{backface-visibility:hidden;-webkit-backface-visibility:hidden}.pfc-flip-v .impulse-flip-back{transform:rotateX(180deg)}.pfc-zoom .impulse-flip-front{transition:transform 0.4s ease-in-out,opacity 0.3s ease-in-out}.pfc-zoom .impulse-flip-back{transform:scale(0.86);opacity:0;transition:transform 0.4s ease-in-out,opacity 0.4s ease-in-out}.pfc-zoom:hover .impulse-flip-front,.pfc-zoom.flipped .impulse-flip-front{opacity:0;transform:scale(1.05)}.pfc-zoom:hover .impulse-flip-back,.pfc-zoom.flipped .impulse-flip-back{transform:scale(1);opacity:1}.pfc-push .impulse-flip-front{transition:transform 0.5s ease-in-out}.pfc-push .impulse-flip-back{transform:translateX(100%);transition:transform 0.5s ease-in-out}.pfc-push:hover .impulse-flip-front,.pfc-push.flipped .impulse-flip-front{transform:translateX(-100%)}.pfc-push:hover .impulse-flip-back,.pfc-push.flipped .impulse-flip-back{transform:translateX(0)}.pfc-swing .impulse-flip-front{transform-origin:left center;transition:transform 0.6s cubic-bezier(0.175,0.885,0.32,1.275);backface-visibility:hidden;-webkit-backface-visibility:hidden}.pfc-swing .impulse-flip-back{transform:rotateY(-90deg);transform-origin:left center;transition:transform 0.6s cubic-bezier(0.175,0.885,0.32,1.275);backface-visibility:hidden;-webkit-backface-visibility:hidden}.pfc-swing:hover .impulse-flip-front,.pfc-swing.flipped .impulse-flip-front{transform:rotateY(90deg)}.pfc-swing:hover .impulse-flip-back,.pfc-swing.flipped .impulse-flip-back{transform:rotateY(0deg)}.pfc-fade .impulse-flip-front{transition:opacity 0.7s ease-in-out}.pfc-fade .impulse-flip-back{opacity:0;transition:opacity 0.7s ease-in-out}.pfc-fade:hover .impulse-flip-front,.pfc-fade.flipped .impulse-flip-front{opacity:0}.pfc-fade:hover .impulse-flip-back,.pfc-fade.flipped .impulse-flip-back{opacity:1}

/* 2026-05-29: flip-box content must NOT be text-selectable. On mobile a tap
   on selectable text starts text selection / iOS callout, which consumes the
   touchend before the flip handler reads it as a tap — net effect: card
   never flips on mobile, plus the user sees an ugly selection highlight.
   touch-action:manipulation also kills the 300ms double-tap-zoom delay so
   the flip feels instant. cursor:pointer signals interactivity on desktop. */
.impulse-flip-box{cursor:pointer;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;touch-action:manipulation}
.impulse-flip-box .impulse-flip-title,.impulse-flip-box .impulse-flip-content{user-select:none;-webkit-user-select:none}

@keyframes impulseFlyIn{0%{transform:scale(1.0)}100%{transform:scale(1.18)}}

/* ── Utility classes replacing repeated inline styles ─────────────────── */
.imp-fill { display:block;width:100%;height:100% }
.imp-link-reset { color:inherit;text-decoration:none }


/* ── Moved from inline impulse_output_frontend_styles ─────────────────── */
/* Impulse Frontend Styles */
    /* Default page font: Helvetica/Arial system stack. The previous stack
       (-apple-system,BlinkMacSystemFont,...) tripped Chrome's canvas font
       parser with the leading hyphen-prefixed identifier — the 3D heading
       canvas would silently fall back to whatever Chrome's "default sans"
       was on the OS (often a font with malformed glyph paths that produced
       self-intersecting strokes when traced by strokeText). Helvetica Neue
       on Mac, Arial on Windows — both clean glyphs, both already in OS RAM,
       no font download. */
    .impulse-page{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;line-height:1.6;color:#1a1a1a;display:flex;flex-direction:column;min-height:calc(100vh - var(--impulse-screen-bottom-inset, 0px));animation:impulse-fade-in 0.4s ease-in-out both}
    .impulse-page input:-webkit-autofill,.impulse-page input:-webkit-autofill:hover,.impulse-page input:-webkit-autofill:focus,.impulse-page textarea:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #fff inset!important;-webkit-text-fill-color:#1d2327!important;transition:background-color 5000s ease-in-out 0s}
    @keyframes impulse-fade-in{from{opacity:0}to{opacity:1}}
    /* Scene-mode pages skip the page-level fade-in. The fade kicks in
       from `opacity:0` and depends on the browser advancing the CSS
       animation, but scene-mode init mutates the body's `cssText`
       (`position:fixed`, `overflow:hidden`, etc.) right after page
       load — those reflows leave the animation registered with
       `currentTime: 0` indefinitely (verified via getAnimations()).
       Result: the page stayed at opacity:0 until something forced a
       repaint, which is why a single scroll suddenly brought the
       first screen on. Scene mode has its own screen-transition
       reveal pipeline (applyFocusState + decomposeEnter); the page-
       level fade isn't doing anything useful there anyway. */
    body.impulse-screen-mode-active .impulse-page,
    body[data-screen-mode="1"] .impulse-page{animation:none;opacity:1}
    .impulse-page > *{flex-shrink:0}
    .impulse-page *{box-sizing:border-box}
    
    /* Container - centered with margin auto */
    /* 2026-05-23: cap content width at 1280px — Instinctor's "premium by
       default" principle. Any user, regardless of design skill, should
       get layouts that look intentional and framed rather than sprawled
       across an ultra-wide monitor. 1280px is the classic premium
       content width: wide enough for 3- and 4-column grids, narrow
       enough that nothing feels lost in space. Also gives editor⇄
       frontend WYSIWYG parity: the editor preview iframe and the live
       page now compute the same content width regardless of monitor
       size. Section background (smoke, video, gradient) still fills
       the FULL viewport via .impulse-section; only the inner content
       container is capped + centred. */
    .impulse-container{max-width:1280px;margin:0 auto;padding:0;display:flex;flex-direction:column;gap:var(--impulse-item-space, 0px)}
    @media(max-width:767px){.impulse-container,.impulse-content-wrapper{flex-direction:column!important}}
    /* Match editor .impulse-el — all children stretch to full width by default.
       Blocks with explicit width (unfold etc.) override with inline align-self:center */
    .impulse-container > *{align-self:stretch}
    .impulse-content-wrapper > *{align-self:stretch}
    /* Per-block "Push to bottom": margin-top:auto in the section's flex column
       drops this block + those after it to the bottom edge (earlier blocks stay
       pinned top). Emitted as data-push-bottom on the block root. v2.1.2164. */
    .impulse-container > [data-push-bottom="1"]{margin-top:auto!important}
    .impulse-container > [data-push-top="1"]{margin-bottom:auto!important}
    /* Counterweight for CENTRED sections: without it a pushed child's auto
       margin absorbs ALL free space and slams the remaining content to the
       opposite edge. The zero-size spacer splits the space so the rest stays
       centred. Top/bottom valign keeps the old edge-pinned behaviour. */
    /* One-sided pushes only: a section pinned at BOTH edges is already
       balanced by its own two auto margins; counterweights there split the
       space four ways and pull everything toward the middle. */
    .impulse-container.impulse-valign-center:has(> [data-push-bottom="1"]):not(:has(> [data-push-top="1"]))::before{content:'';margin-bottom:auto}
    .impulse-container.impulse-valign-center:has(> [data-push-top="1"]):not(:has(> [data-push-bottom="1"]))::after{content:'';margin-top:auto}

    /* ── ONE bottom anchor per container ────────────────────────────────────
       Every auto margin in a flex column takes an EQUAL share of the free
       space, so two blocks asking for the bottom do not both go to the bottom:
       the space splits between them and the column spreads out. That is the
       "title pushed to the bottom too / evenly distributed" bug (Sergei
       2026-07-29/30, generic-site then installer-site rendered eyebrow / title
       / button in exact thirds).
       The FIRST block to ask wins, which is what "this block and everything
       after it drop to the bottom" means; later claims are neutralised here.
       Done in CSS on purpose: sibling selectors are order-based and survive the
       editor re-rendering ONE block in isolation, which no server-side
       bookkeeping can see. Author !important beats the inline margin.
       Two spellings exist - push_bottom (data attr) and the Button block's
       legacy btn_pin_bottom (inline margin, tagged .impulse-btn-pin-bottom).
       The legacy key is honoured, not dropped: client installs carry their own
       databases we cannot migrate, and on some of them that pin is a hero's
       only bottom anchor. */
    .impulse-container > [data-push-bottom="1"] ~ [data-push-bottom="1"]{margin-top:0 !important}
    /* Mirror of the multi-push-bottom rule above, and the same flexbox trap: EVERY
       auto margin takes an EQUAL share of the free space, so two blocks pushed to
       the top plus one pushed to the bottom produced three competing autos and an
       evenly distributed column, with the second block stranded mid-section
       (Sergei 2026-08-03, academy hero). Only the LAST push-top keeps its auto
       margin; earlier ones sit tight against it, so the pushed blocks read as one
       group at the top. Also fixes top-only sections, where the ::after
       counterweight was the third competing auto. */
    .impulse-container > [data-push-top="1"]:has(~ [data-push-top="1"]){margin-bottom:0 !important}
    .impulse-container > [data-push-bottom="1"] ~ * .impulse-btn-pin-bottom,
    .impulse-container > [data-push-bottom="1"] ~ .impulse-btn-pin-bottom{margin-top:0 !important}
    .impulse-grid-cell > *,
    .impulse-rows-cell > *,
    .impulse-cell-content > *{width:100%}
    /* When a cell has explicit left/right halign, children become
       content-sized AND defer their cross-axis position to the cell's
       align-items (flex-start / flex-end). Default halign=center keeps
       the 100%-width rule, so text-based blocks span the cell and
       text-align on the cell positions their inner text. Blocks that
       have their own width (single-mode products card, fixed-width
       buttons, etc.) sit at the requested edge.
       align-self:auto is critical: any block-level `.impulse-el {
       align-self: stretch }` would otherwise force the child to fill the
       cross-axis regardless of width:auto. */
    .impulse-grid-cell[data-halign="left"] > *,
    .impulse-grid-cell[data-halign="right"] > *{width:auto;max-width:100%;align-self:auto}
    /* Explicit cell halign WINS over a block's own align-self. Image/text
       blocks emit inline `align-self:var(--impulse-ca,center)`, and an inline
       declaration beats a plain stylesheet rule - so a right-aligned cell
       still centred its image (Sergei 2026-07-25, salon 526 section 8).
       Width is deliberately NOT forced here: the block keeps its own width. */
    .impulse-grid-cell[data-halign="left"] > *{align-self:flex-start!important}
    .impulse-grid-cell[data-halign="right"] > *{align-self:flex-end!important}
    /* Row-flow cells: content-size children for any halign (see editor CSS). 2026-07-19. */
    .impulse-grid-cell[data-flow="row"] > *{width:auto;max-width:100%;align-self:auto}
    .impulse-container-full{width:100%;max-width:none;padding:0}
    
    /* Section */
    .impulse-section{position:relative;overflow-x:clip;overflow-y:visible}
    /* A background-mode Kinetic block sits at z-index:-1 so it paints under
       the section's in-flow content. position:relative alone does NOT make
       the section a stacking context, so without this the -1 would escape
       past the section and hide behind its own background. */
    .impulse-section:has(> .impulse-container .impulse-kinetic-bg){isolation:isolate}
    /* Nested sections (inside grid cells) don't guard the viewport against
       horizontal scrollbars - the clip only amputated hover effects that
       animate outside the cell (icon parallax, cinematica360 2026-07-24). */
    .impulse-grid-cell .impulse-section{overflow-x:visible}
    /* Spread / space-* alignments fall back to flex-start on narrow
       viewports so content doesn't push past the visible area when it
       can't fit a single screen height. The renderer routes
       space-between/around/evenly through the --impulse-justify custom
       property; overriding the prop here cascades into the inline
       `justify-content:var(--impulse-justify) !important` rule. */
    @media (max-width: 768px) {
        .impulse-section > .impulse-container,
        .impulse-section{
            --impulse-justify: flex-start;
        }
        /* Flipboxes inside any grid: fall back to full-cell-width on
           mobile when the designer didn't set `section_max_width_mobile`
           (the per-instance value emits its own !important @media rule
           via flip_box.php and wins this; no !important here, so the
           designer's slider drives). Height intentionally NOT overridden
           — the per-device Height slider now controls mobile sizing
           directly. The earlier !important clamp to height:auto +
           min-height:170px blocked any "shorter on mobile" attempt
           regardless of what the designer set in the panel. */
        .impulse-grid .impulse-flip-box,
        .impulse-rows .impulse-flip-box,
        .impulse-columns .impulse-flip-box{
            max-width: 100%;
        }
    }
    /* Section with ambient/tilt motion: overflow visible so content isn't clipped during scale/translate. */
    .impulse-section[data-section-ambient],
    .impulse-section[data-section-tilt]{overflow:visible}
    /* Tilt 3D rotation: the wrapper (.impulse-el) must also allow overflow so perspective-transformed edges don't clip. */
    .impulse-el:has(> section[data-section-tilt]){overflow:visible}
    .impulse-el:has(.impulse-divider) .impulse-section{overflow:visible}
    .impulse-el:has(.impulse-logo-animator) .impulse-section{overflow:visible}
    .impulse-el:has(.impulse-logo-animator) .impulse-section > .impulse-container{overflow:visible}
    .impulse-el:has(.impulse-logo-animator){overflow:visible}
    /* 2026-05-24: breathing-room padding inside the animator container so
       canvas-backed presets (breathing, tilt, scale, push) have pixels
       to grow into. Without this, text fills 96% of the canvas width and
       any growth gets rasterised to nothing — ancestor overflow:visible
       can't restore pixels that were never drawn. em-based so the room
       scales with the heading's font-size. */
    .impulse-logo-animator{padding:0.3em 0.5em;box-sizing:content-box}
    .impulse-el:has(.impulse-divider) .impulse-section > .impulse-container{overflow:visible}
    .impulse-el:has(.impulse-display-text) .impulse-section{overflow:visible}
    .impulse-el:has(.impulse-display-text) .impulse-section > .impulse-container{overflow:visible}
    .impulse-el:has(.impulse-display-text){overflow:visible}
    .impulse-content-wrapper:has(.impulse-display-text){overflow:visible}
    .impulse-content-wrapper{position:relative;overflow-x:clip;overflow-y:visible}
    .impulse-bg-shape-layer{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:3;overflow:hidden}
    /* 2026-05-23: z-index:0 (was 1!important). Overlay sits in the same
       layer as bg-video, painted above it via DOM order, but always below
       section content (.impulse-container at z-index:4). Fixes overlay
       painting over heading/text in some stacking contexts. */
    .impulse-section-overlay{z-index:0}
    .impulse-section-bg-video{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:cover;z-index:0;pointer-events:none}
    .impulse-section-bg-video-fallback{position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center;z-index:0;pointer-events:none;display:none}
    @media(hover:none),(pointer:coarse){.impulse-section-bg-video{display:none!important}.impulse-section-bg-video-fallback{display:block!important}}
    .impulse-section-animation{z-index:2}
    /* 2026-05-29: container must escape every positioned bg sibling, not just
       .impulse-bg-shape-layer. Sections with an animation_layer (z-index:2)
       but no bg-shape used to leave .impulse-container unpositioned, so the
       lava/rings/etc canvas painted ON TOP of the heading + grid, read as
       "the moving gradient erases content on hover". */
    .impulse-bg-shape-layer ~ .impulse-container,
    .impulse-section-animation ~ .impulse-container,
    .impulse-section-bg-video ~ .impulse-container,
    .impulse-section-bg-video-fallback ~ .impulse-container,
    .impulse-section-overlay ~ .impulse-container{position:relative;z-index:4}
    /* A background-mode Kinetic block must fill the SECTION. The overlay rule
       above makes the container position:relative, which turns it into the
       containing block and caps the block at the container's max-width (1440
       inside a 1920 section), so Background stopped short of full width.
       Drop the positioning only when a background block is present: the
       content keeps its own stacking from the sibling rule, which already
       sits above the overlay. Must come AFTER the overlay rule - equal
       specificity, so source order decides. */
    .impulse-container:has(.impulse-kinetic-bg){position:static !important}
    /* A background block sits at z-index:-1, which puts it behind the
       container itself - so a tap anywhere the container covers never reaches
       a linked disc. Lift it to 0 and raise the in-flow content to 1: same
       paint order, but the block is now hit-testable. Mirrors the editor. */
    .impulse-container:has(.impulse-kinetic-bg) > .impulse-kinetic-bg{z-index:0 !important}
    .impulse-container:has(.impulse-kinetic-bg) > *:not(.impulse-kinetic-bg){position:relative;z-index:1}
    /* !important because the container carries position:relative;z-index:4 as an
       INLINE style from the renderer, which no stylesheet rule can outrank. The
       z-index goes inert with it, so the content relies on the sibling rule above
       (z-index:1) to stay above a section overlay, which sits at 0. */
    .impulse-bg-shape-el{pointer-events:none}
    .impulse-bg-shape-el svg{display:block;width:100%;height:100%}
    .impulse-stretch{width:100vw;position:relative;left:50%;right:50%;margin-left:-50vw;margin-right:-50vw}
    /* impulse-stretch is for top-level sections that need to bleed to viewport edges.
       When the section is nested inside a grid/cell-grid/layout cell, the bleed
       breaks out of the cell with margin:-50vw and content lays out at the viewport's
       left edge — cancel the bleed so the section stays bounded by its cell. */
    .impulse-grid-cell .impulse-section.impulse-stretch,
    .impulse-rows-cell .impulse-section.impulse-stretch,
    .impulse-layout-cell .impulse-section.impulse-stretch{width:auto;position:static;left:auto;right:auto;margin-left:0;margin-right:0}
    /* Cancelling the bleed above leaves width:auto, and a cell is a flex column
       with align-items:center — so a nested card section shrink-wrapped to its
       own copy instead of filling its track. In a 2x2 of cards that reads as
       mismatched boxes: the one with the shortest line came out narrower and
       shorter than its siblings (Sergei 2026-07-30, cinematica 466 "How it
       works"). Only halign=center (the default) is touched — left/right cells
       deliberately content-size their children, and the height fill is limited
       to a sole-child section, i.e. an actual card filling its cell. */
    .impulse-grid-cell[data-halign="center"] > .impulse-section.impulse-stretch{width:100%}
    .impulse-grid-cell[data-halign="center"] > .impulse-section.impulse-stretch:only-child{height:100%}
    /* Compact section (v2.1.1326): bg hugs wrapped content for card-shape
       Wrap-in-Section output. align-self reads parent's content_align via
       --impulse-ca; inner .impulse-container drops its content_width %
       since percentages are meaningless on a shrink-to-fit parent. */
    /* Compact mode (v2.1.1327): shrink inner section to content + cancel
       the .impulse-stretch full-bleed transform. Renderer emits inline
       margin-left/right:auto from the section's own content_align so it
       positions left / center / right within its block parent. */
    .impulse-section.is-compact{width:max-content !important;max-width:100% !important;left:auto !important;right:auto !important;position:relative !important}
    /* v2.1.1357: the inner container fills the section's content box
       (was `width:auto` — the legacy Wrap-in-Section shape from v2.1.1327
       where the section hugged its children and the container shrank
       alongside). Now that compact mode has an explicit Width slider
       (`compact_max_width`), the section is the one with a fixed width
       (`width: <N>px !important` inline) and the container needs to fill
       it. Without this change, content collapses to its intrinsic
       (max-content) width and leaves big gaps on either side inside the
       card. The outer rule above still lets the section shrink to
       max-content if no Width slider is set — the inline `width: <N>px`
       beats `width: max-content` per specificity. */
    .impulse-section.is-compact > .impulse-container{width:100% !important;max-width:100% !important}
    
    /* Layout elements — always full-width, always responsive */
    /* Slider: full bleed like section */
    .impulse-new-slider{width:100%}
    /* Grid: collapse to 1 col on mobile (per-element 2col inline CSS overrides with higher ID specificity) */
    @media(max-width:767px){
        .impulse-grid{grid-template-columns:1fr!important;width:100%}
        .impulse-rows-row{flex-direction:column!important;height:auto!important}
        .impulse-rows-cell{flex:none!important;width:100%!important;height:auto!important;min-height:60px}
    }
    /* Grid: max 2 cols on tablet */
    @media(max-width:1024px){
        .impulse-grid{width:100%}
    }
    
    /* Site Header & Footer - outside content wrapper, always full width */
    .impulse-header,.impulse-footer{
        width:100%;
        box-sizing:border-box
    }
    
    /* Row */
    .impulse-row{display:flex;flex-wrap:wrap}
    .impulse-col{flex:1;min-width:0}
    
    /* Heading */
    
    /* Display Text */
    .impulse-display-text{position:relative;width:100%;min-width:0;max-width:100%;box-sizing:border-box}
    .impulse-display-text h1,.impulse-display-text h2,.impulse-display-text h3,.impulse-display-text h4,.impulse-display-text h5,.impulse-display-text h6,.impulse-display-text p{white-space:pre-line}
    /* Selection background — peach at full opacity, dark text. Low-opacity
       blue used to read as "no selection" against either dark or light page
       bgs. Animator's source text is opacity:0 (canvas overlay covers it),
       so show selection as a semi-transparent strip the canvas can't hide. */
    /* Selection colour: neutral grey to match the strict-greyscale rule. Was
       peach (#dd886b) — chosen because animator/3D-text source text is
       opacity:0 and covered by canvas, so the selection strip needed to read
       through the overlay. Grey at high alpha still does that without the
       brand-orange surprise. */
    .impulse-display-text ::selection{background:rgba(85,85,85,0.6);color:#fff}
    .impulse-display-text ::-moz-selection{background:rgba(85,85,85,0.6);color:#fff}
    .impulse-logo-animator ::selection{background:rgba(85,85,85,0.85);color:#fff}
    .impulse-logo-animator ::-moz-selection{background:rgba(85,85,85,0.85);color:#fff}
    .impulse-dt-line{transform-origin:center center}
    
    /* Text */
    .impulse-text{word-break:break-word;overflow-wrap:break-word}
    /* Line balancing. `text-wrap: balance` evens out line lengths, which is what
       a statement wants: a full first line with a short remainder underneath
       reads as broken (Sergei 2026-07-25/07-28). Inside a GRID CELL the copy has
       a narrow measure and has to fill it instead: balance shortened every line
       to match, so a paragraph stopped at ~80% of its cell and left a right gap
       no width setting could close (Sergei 2026-07-31, home screen 4:
       353/383/360px lines in a 430px box). Centred copy in a cell still balances,
       it reads as a block rather than as body text. Kept here rather than inline
       so the frontend, the editor canvas and the editor's single-element
       re-render cannot drift. */
    .impulse-text{text-wrap:balance}
    .impulse-grid-cell .impulse-text:not(.impulse-text-center){text-wrap:pretty}
    .impulse-text a,.impulse-text a:visited,.impulse-text a:hover,.impulse-text a:active{color:inherit;text-decoration:underline}
    .impulse-text p{margin:0}
    /* Forms */
    .impulse-contact-form,.impulse-login-form,.impulse-register-form{box-sizing:border-box}
    .impulse-contact-form input,.impulse-contact-form textarea,.impulse-login-form input,.impulse-register-form input{font-family:inherit}
    .impulse-contact-form input::placeholder,.impulse-login-form input::placeholder,.impulse-register-form input::placeholder,.impulse-contact-form textarea::placeholder{color:inherit;opacity:0.45}
    .impulse-contact-form input:focus,.impulse-login-form input:focus,.impulse-register-form input:focus,.impulse-contact-form textarea:focus{border-color:#888!important;outline:none!important}
    /* Accordion */
    .impulse-unfold{box-sizing:border-box}

    /* Image */
    .impulse-image img{max-width:100%;height:auto;display:block;transition:all 0.5s ease-in-out}
    .impulse-image a{display:inline-block;text-decoration:none;border:none;outline:none}
    .impulse-image a:focus,.impulse-image a:active{outline:none;border:none}
    .impulse-image a img{border:none}
    /* Image hover effects */
    .impulse-img-hover{position:relative;display:block}
    .impulse-img-hover[data-hover="shine"],.impulse-img-hover[data-hover="zoom"],.impulse-img-hover[data-hover="tilt"],.impulse-img-hover[data-hover="blur"],.impulse-img-hover[data-hover="portal"],.impulse-img-hover[data-hover="slices"],.impulse-img-hover[data-hover=],.impulse-img-hover[data-hover="thermal"],.impulse-img-hover[data-hover="burn"],.impulse-img-hover[data-hover="glitch"],.impulse-img-hover[data-hover="hologram"],.impulse-img-hover[data-hover="pixelate"]{overflow:hidden !important}
    /* Shine rides inside the image only — border-radius + isolation make it
       respect rounded corners and never leak past the image bounds. */
    .impulse-img-hover[data-hover="shine"]{isolation:isolate;border-radius:inherit}
    .impulse-img-hover[data-hover="shine"]::before{content:'';position:absolute;top:0;left:-75%;width:50%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.3),transparent);transform:skewX(-25deg);transition:max-height 0.6s cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none;z-index:2;border-radius:inherit}
    .impulse-img-hover[data-hover="shine"]:hover::before{animation:impulse-img-shine 1s ease-in-out forwards}
    @keyframes impulse-img-shine{0%{left:-75%}100%{left:125%}}
    .impulse-img-hover[data-hover="zoom"] img{transition:transform 0.8s ease-in-out}
    .impulse-img-hover[data-hover="zoom"]:hover img{transform:scale(1.08)}
    .impulse-img-hover[data-hover="tilt"]{perspective:600px}
    .impulse-img-hover[data-hover="tilt"] img{transition:transform 0.7s ease-in-out}
    .impulse-img-hover[data-hover="tilt"]:hover img{transform:rotateY(4deg) rotateX(2deg) scale(1.03)}
    .impulse-img-hover[data-hover="blur"] img{transition:filter 0.7s ease-in-out,transform 0.7s ease-in-out}
    .impulse-img-hover[data-hover="blur"]:hover img{filter:blur(3px) brightness(1.1);transform:scale(1.02)}
    .impulse-image-wrapper{position:relative;perspective:900px;overflow:hidden;--cyl-px:50%;--cyl-py:50%;--cyl-ea:0;--cyl-sx:50%;--cyl-sy:50%;--cyl-ha:0;touch-action:pan-y}
    /* edge shadow removed */
    .impulse-image-wrapper::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:3;background:radial-gradient(circle at var(--cyl-sx) var(--cyl-sy),rgba(255,255,255,var(--cyl-ha)) 0%,transparent 75%)}
    .impulse-image-wrapper img{will-change:transform}

    /* Grid — masonry mode: children break at column boundaries, gap between rows via margin-bottom */
    .impulse-grid-masonry > *{break-inside:avoid;-webkit-column-break-inside:avoid;page-break-inside:avoid;display:block;margin-bottom:var(--impulse-masonry-gap,16px);width:100%}
    .impulse-grid-masonry > *:last-child{margin-bottom:0}

    /* Button — single render path; all styling on the inline `style` attr.
       The .impulse-button a-descendant selectors below were left over from
       a long-dead structure where .impulse-button wrapped an <a>; today
       .impulse-button IS the <a>, so the descendant rules matched nothing.
       Deleted in 2.1.646. */
    .impulse-button-wrap{max-width:100%;overflow:hidden}
    /* Buttons never wrap their label across multiple lines on
       desktop / tablet. When a width is set (btn_min_width slider,
       or 100% / full-align), text that exceeds it stays single-line
       so the button keeps the dimensions the renderer intended. The
       wrap symptom — "Order" on one line, "Starter" on the next —
       happened when the width pin shrank the box below intrinsic
       text size. Single-line + ellipsis is the consistent visual
       contract; users widen the button if they want more text to
       fit. */
    .impulse-button{max-width:100%;box-sizing:border-box;white-space:nowrap}
    /* Mobile auto-correction: when the layout collapses to a single
       column (CSS Grid 1fr fallback, etc.) and a button's label is
       too long for the column, single-line + overflow:hidden
       produced a button that looked off-centre against shorter
       siblings (the long button was clipped to 100% width while
       the short ones stayed intrinsic and centred). Below 768px,
       let the label wrap to a second line and stretch the button +
       wrap to the cell width so every button in a column shares
       the same horizontal span. Sergei rule: cover this kind of
       layout edge case at the plugin level so designers don't have
       to. 2026-06-04. */
    @media (max-width: 767px) {
        .impulse-button-wrap { overflow: visible; width: 100%; }
        .impulse-grid-cell > .impulse-button-wrap .impulse-button,
        .impulse-layout-cell > .impulse-button-wrap .impulse-button,
        .impulse-button-wrap > .impulse-button {
            white-space: normal;
            word-break: break-word;
            line-height: 1.25;
        }
    }
    /* Block any inherited :active/:focus scaling — there are no UI rules
       that scale .impulse-button down on press, but browsers / editor
       contexts / parent transforms can re-trigger the entrance animation
       which starts at scale(0.9). Locking transform:none on press kills
       the visible "shrink" without disabling the initial entrance — the
       :active state is only briefly applied after the entrance completes.
       Also kill the browser focus outline + tap highlight + any width/
       padding shift coming from user-agent stylesheets — the cluster of
       defaults that combine to read as "dimensions change on click". */
    .impulse-button{outline:none;-webkit-tap-highlight-color:transparent}
    .impulse-button:active,
    .impulse-button:focus,
    .impulse-button:focus-visible{
        transform:none!important;
        animation:none!important;
        outline:none!important;
        box-shadow:none!important;
    }
    /* 2026-05-24: extend the press-shrink guard up to the wrap and the
       wrapping .impulse-el. Clicking anywhere in the parent container
       was visibly shrinking the button — the entrance keyframe
       `impulse-emerge` (scale 0.9 → 1) was re-triggering on parent
       state changes (selection, focus-within, container :active) that
       bubbled down through transform inheritance. Killing transform +
       animation on each level of the press cascade stops the chain
       cold without disabling the initial entrance (it's a transition,
       not a hover state). */
    .impulse-button-wrap:active,
    .impulse-button-wrap:focus-within,
    .impulse-el:has(> .impulse-button-wrap):active,
    .impulse-el:has(> .impulse-button-wrap):focus-within,
    .impulse-el[data-type="button"]:active,
    .impulse-el[data-type="button"]:focus-within,
    .impulse-el[data-type="button"].selected,
    .impulse-el[data-type="button"].selected .impulse-button-wrap,
    .impulse-el[data-type="button"].selected .impulse-button {
        transform:none!important;
        animation:none!important;
    }

    /* Frosted-glass variant — paired with the inline backdrop-filter the
       renderer emits when the Frosted Glass checkbox is on. Three
       components combine to give the visual character of glass on any
       background:
         1. The renderer rewrites bg to a low-alpha rgba tint so the
            backdrop-filter has something translucent to filter through
            (an opaque fill hides the blur entirely).
         2. backdrop-filter:blur+saturate distorts what's behind — only
            visible when there IS content behind. On a plain section
            with nothing varied to blur, this contributes nothing.
         3. (THIS RULE) inner highlight + shadow + outer glow give the
            button its own glassy character regardless of what's behind,
            so the effect reads as "frosted" even on solid colour
            sections. The top inner highlight reads as a glass edge
            catching light; the bottom inset shadow as a thin lower
            lip; the outer drop is a soft glow that lifts the button
            visually off the surface. */
    .impulse-frosted{
        box-shadow:
            inset 0 1px 0 rgba(255,255,255,0.45),
            inset 0 -1px 0 rgba(0,0,0,0.08),
            0 4px 14px rgba(0,0,0,0.08);
    }
    /* Stroke saturation lift — when the gradient ring is also present,
       boost it so the ring reads as crisp as the backdrop's saturate(160%)
       lift. */
    .impulse-frosted.impulse-grad-border::before{
        filter:saturate(160%);
    }
    /* Frosted glass needs to blur whatever sits behind the button. CSS
       spec: `backdrop-filter` only blurs content inside its containing
       stacking context. The renderer inserts `isolation:isolate` on
       every grid cell (defensive for the grad-border z-index:-1 trick)
       and JS injects `will-change:transform,filter` on the wrap (perf
       hint for hover halo) — both promote to new stacking contexts and
       trap backdrop-filter inside an empty bubble, so the 3D background
       behind never gets blurred.

       Scoped override: only on cells/wraps that actually contain a
       frosted button. Every other use of isolation/will-change (grad
       ring without frosted, 3D text canvas, etc.) stays put. !important
       beats the inline styles. */
    .impulse-grid-cell:has(.impulse-frosted){isolation:auto !important}
    .impulse-button-wrap:has(.impulse-frosted){
        will-change:auto !important;
        overflow:visible !important;
    }
    /* Same trap, one layer up — for the SECTION compact frosted glass
       (v2.1.1351). The screen-mode runtime sets `will-change: transform,
       opacity` on every `.impulse-screen` for transition perf, which makes
       the screen a backdrop root. The bg img / depth canvas / env canvas
       live at body level (z-index -1, OUTSIDE the screen), so a frosted
       section nested inside the screen has nothing to blur — the blur
       computes but samples an empty backdrop. Visually you see the
       translucent tint and the inner-highlight box-shadow but no actual
       blur, so the "glass" effect collapses into a flat panel.
       Override `will-change: auto` on any screen that contains a frosted
       descendant. Cheap: gives up the GPU-promotion hint for screens with
       frosted content (transitions still work, just without the pre-promote
       optimization). Every other screen keeps the hint. */
    .impulse-screen:has(.impulse-frosted){will-change:auto !important}
    /* Two more backdrop-root creators in the ancestor chain that needed the
       same `:has(.impulse-frosted)` treatment (v2.1.1358 — diagnosed after
       v1351's will-change override fixed the initial paint but the effect
       still went unstable mid-session):
         - `.impulse-screen-wrapper { perspective: 1200px }` — perspective
           creates a backdrop root. Chrome is lenient about it while no 3D
           content is animating, but the moment a screen transition fires
           a translateZ / scale-perspective combo, the compositor locks
           the perspective layer in as a backdrop root and never releases
           it for the rest of the session. From that point on, every
           descendant `backdrop-filter` samples an empty backdrop because
           the body-level depth canvas (the only thing actually painting
           interesting content) sits OUTSIDE the wrapper.
         - `.impulse-screen { backface-visibility: hidden }` — similar
           stacking-context promotion that can become a backdrop root
           under compositor pressure.
       Disabling both on pages that contain a frosted descendant trades
       3D depth in screen transitions for stable glass on those pages.
       Pages with no frosted sections keep their full 3D treatment. */
    /* 2026-07-18: frosted flattening yields during screen transitions (body
       class set by impulse-screens.js goTo/cleanup) - unconditional, these
       rules killed every depth-family reveal on screens hosting a frosted
       section (transform:none/perspective:none leave only an opacity fade). */
    body:not(.impulse-screens-transitioning) .impulse-screen-wrapper:has(.impulse-frosted){perspective:none !important}
    .impulse-screen:has(.impulse-frosted){
        backface-visibility:visible !important;
        -webkit-backface-visibility:visible !important;
        /* v2.1.1364: `contain: paint` on `.impulse-screen-wrapper > .impulse-screen`
           (line ~2846, added to clip Z-translated buttons during transitions) is
           a backdrop-root creator per the CSS spec, so descendant
           `backdrop-filter` only sees what's inside the screen and never the
           body-level env canvas. Override to `none` on screens that contain a
           frosted section. Trade-off: Z-translated buttons in transition presets
           may briefly project beyond screen bounds on frosted screens. */
        contain:none !important;
    }
    /* v2.1.1365: belt-and-braces — same defensive overrides applied at the
       section's local box and its immediate `.impulse-el` wrapper. Mirrors
       the working pattern used for frosted BUTTONS at line ~2531
       (`.impulse-grid-cell:has(.impulse-frosted){isolation:auto}` +
       `.impulse-button-wrap:has(.impulse-frosted){will-change:auto;
       overflow:visible}`). Sergei's diagnostic: buttons with frosted glass
       survive scroll-back without issue; only sections collapse. Whatever
       trap the section's local context creates that the button's doesn't,
       we kill every candidate here. */
    body:not(.impulse-screens-transitioning) .impulse-el:has(> section.impulse-frosted){
        isolation:auto !important;
        contain:none !important;
        will-change:auto !important;
        transform:none !important;
        filter:none !important;
        overflow:visible !important;
    }
    section.impulse-frosted{
        isolation:auto !important;
        contain:none !important;
        will-change:auto !important;
        filter:none !important;
    }

    /* Gradient ring on buttons — ::before pseudo masked with composite=exclude
       so the gradient shows ONLY in the border zone. Same rule as the editor's
       impulse-preview.php inline copy; both must stay in sync. Conic gradient
       (not linear): linear paints perpendicular stripes that read as "one side
       at a time" snapping when the angle spins; conic radiates from the centre
       so the highlight orbits the perimeter smoothly. First and last stops
       repeat the same colour to close the loop without a seam at 0°/360°. */
    .impulse-grad-border::before{
        content:'';position:absolute;inset:0;z-index:-1;box-sizing:border-box;
        padding:var(--impulse-border-width,2px);border-radius:inherit;
        background:conic-gradient(
            from var(--impulse-border-gradient-angle,135deg),
            var(--impulse-border-color,#1d2327),
            var(--impulse-border-gradient-to,transparent),
            var(--impulse-border-color,#1d2327)
        );
        -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
        -webkit-mask-composite:xor;
        mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
        mask-composite:exclude;pointer-events:none;
    }
    
    /* Video */
    .impulse-video iframe,.impulse-video video{max-width:100%}
    
    /* Divider */
    .impulse-divider hr{border:none;margin:0}
            @keyframes impulseDivAurora{0%{background-position:0% 50%}100%{background-position:-200% 50%}}
                
    /* Spacer */
    
    /* Icon */
    .impulse-icon{display:flex;align-items:center;justify-content:center}
    .impulse-icon-wrap{display:inline-flex;align-items:center;justify-content:center}
    
    /* Container element */
    
    /* Entrance Animations */
    .impulse-animated{opacity:0;animation-fill-mode:forwards}
    /* PHP renders animation-play-state:paused inline on each .impulse-animated
       element; without !important the CSS rule can't override the inline value
       and the animation never runs (heading stays at opacity:0 indefinitely). */
    .impulse-animated.impulse-visible{animation-play-state:running !important}
    
    /* Icon hover animations */
    .impulse-icon-hover-grow:hover{transform:scale(1.15)!important}
    .impulse-icon-hover-shrink:hover{transform:scale(0.85)!important}
    .impulse-icon-hover-pulse:hover{animation:impulse-pulse 0.6s ease-in-out infinite}
    .impulse-icon-hover-rotate:hover{transform:rotate(15deg)!important}
    
    @keyframes impulse-fade-in{from{opacity:0}to{opacity:1}}
    @keyframes impulse-emerge{from{opacity:0;transform:scale(var(--ea-scale,0.9));filter:blur(var(--ea-blur,4px))}to{opacity:1;transform:scale(1);filter:blur(0)}}
    @keyframes impulse-surface{from{opacity:0;transform:perspective(800px) translateZ(var(--ea-depth,-60px))}to{opacity:1;transform:perspective(800px) translateZ(0)}}
    /* Unveil keyframes: the inactive edge of each direction uses a negative
     * inset so the final state never clips a glyph's natural overflow
     * (descenders on "g/y/p/q" for unveil-up; ascenders + diacritics for
     * unveil-down; italic side-bearing for unveil-left/right). Without this,
     * inset(0 0 0 0) clipped to the heading's exact bounding box and lopped
     * off the bottom of letters like "g" in headings using line-height:1.1. */
    @keyframes impulse-unveil-up{from{opacity:1;clip-path:inset(100% 0 -30% 0)}to{opacity:1;clip-path:inset(0 0 -30% 0)}}
    @keyframes impulse-unveil-down{from{opacity:1;clip-path:inset(-30% 0 100% 0)}to{opacity:1;clip-path:inset(-30% 0 0 0)}}
    @keyframes impulse-unveil-left{from{opacity:1;clip-path:inset(-30% 100% -30% -10%)}to{opacity:1;clip-path:inset(-30% -10% -30% 0)}}
    @keyframes impulse-unveil-right{from{opacity:1;clip-path:inset(-30% -10% -30% 100%)}to{opacity:1;clip-path:inset(-30% 0 -30% -10%)}}
    @keyframes impulse-resolve{from{opacity:1;filter:blur(var(--ea-blur,12px))}to{opacity:1;filter:blur(0)}}
    @keyframes impulse-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.1)}}

    /* Responsive */
    @media (max-width: 768px) {
        .impulse-row{flex-direction:column}
        .impulse-col{width:100%!important}
        /* Forms: each field honours its per-field mobile width (--imp-fw-m, set
           by the contact renderer; defaults to 100% = single column, the
           historical behaviour). Base flex-wrap:row stays, so fields set to 50%
           pair 2-up while 100% fields wrap to their own row. Sergei 2026-06-25. */
        .impulse-contact-form > div{width:var(--imp-fw-m,100%)!important}
        .impulse-register-form > div[style*="display:flex"]{flex-direction:column!important}
        /* Login/Register: force full width on narrow screens */
        .impulse-login-wrapper,.impulse-register-form{min-width:0!important}
        /* Flip box: reduce height on mobile */
        .impulse-flip-box{max-height:80vh}
        /* Icon box horizontal: stack on mobile */
        .impulse-icon[style*="flex-direction:row"]{flex-direction:column!important;text-align:center!important}
        /* Pricing cards: single column below 768 */
        .impulse-pricing-grid{grid-template-columns:1fr!important}
        /* Accordion: full width */
        .impulse-unfold{width:100%!important}
        /* Slider mobile stack: slides shown vertically, no carousel */
        .impulse-carousel-slides{touch-action:pan-y}
    .impulse-new-slider[data-mobile-stack="1"] .impulse-carousel-track{height:auto!important;min-height:auto!important;overflow:visible!important}
        .impulse-new-slider[data-mobile-stack="1"] .impulse-carousel-slides{display:flex!important;flex-direction:column!important;height:auto!important;min-height:auto!important;transform:none!important;transition:none!important}
        .impulse-new-slider[data-mobile-stack="1"] .impulse-carousel-slide{position:relative!important;width:100%!important;flex-shrink:0!important;opacity:1!important;transform:none!important}
        .impulse-new-slider[data-mobile-stack="1"] .impulse-carousel-nav,.impulse-new-slider[data-mobile-stack="1"] .impulse-carousel-dots,.impulse-new-slider[data-mobile-stack="1"] .impulse-slide-nav{display:none!important}
    }
    
    /* Device Visibility */
    @media (min-width: 1025px) {
        .impulse-hide-desktop{display:none!important}
    }
    @media (min-width: 768px) and (max-width: 1024px) {
        .impulse-hide-tablet{display:none!important}
    }
    @media (max-width: 767px) {
        .impulse-hide-mobile{display:none!important}
    }
    @media (max-width: 480px) {
        /* Very narrow: forms go full width */
        .impulse-login-wrapper,.impulse-register-form > *{width:100%!important}
        /* Icon list: rearrange ABC → A / BC */
        .impulse-table-headers{display:none!important}
        .impulse-table li,.impulse-table li > a{flex-wrap:wrap!important}
        /* Force text span to fill first line (icon + text), pushing col2+col3 to wrap */
        .impulse-table li > span:nth-child(2),.impulse-table li > a > span:nth-child(2){flex:1 0 calc(100% - 40px)!important}
        /* Col2+Col3 wrap to second line, sit side by side */
        .impulse-il-col2,.impulse-il-col3{flex:1 1 auto!important;text-align:left!important;font-size:0.9em!important;opacity:0.75}
        /* Price list: smaller text */
        .impulse-price-list{font-size:14px}
    }
    
    /* Icon Box */
    .impulse-icon{overflow:visible}
    .impulse-icon-wrap{transition:transform 0.7s ease-in-out,filter 0.7s ease-in-out}
    @keyframes impulse-icon-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.15)}}
    .impulse-effect-pulse .impulse-icon-wrap{animation:impulse-icon-pulse 2s ease-in-out infinite}
    @keyframes impulse-icon-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
    .impulse-effect-float .impulse-icon-wrap{animation:impulse-icon-float 3s ease-in-out infinite}
    @keyframes impulse-icon-wobble{0%{transform:rotate(0)}15%{transform:rotate(6deg)}30%{transform:rotate(-5deg)}45%{transform:rotate(4deg)}60%{transform:rotate(-2deg)}75%{transform:rotate(1deg)}100%{transform:rotate(0)}}
    .impulse-effect-wobble .impulse-icon-wrap{animation:impulse-icon-wobble 2s ease-in-out infinite}
    .impulse-icon-image{width:var(--impulse-size,48px);height:auto;object-fit:contain;display:block}

    /* Icon hover effects — parallax + lift. Previously these rules were
       emitted PER-ELEMENT via wp_add_inline_style with #impulse-icon-N-card
       selectors (so a page with 12 icon cards shipped 12 duplicated copies
       of the same ~14 lines). Now consolidated as ONE class+data-attr
       ruleset — same behaviour, ~1/12 the CSS payload on icon-heavy pages.
       The icon renderer emits `data-hover-effect="$value"` on the card div. */
    .impulse-icon[data-hover-effect="parallax"]{perspective:900px;transform-style:preserve-3d}
    .impulse-icon[data-hover-effect="parallax"] .impulse-icon-wrap,
    .impulse-icon[data-hover-effect="parallax"] .impulse-icon-title,
    .impulse-icon[data-hover-effect="parallax"] .impulse-icon-text{transform-style:preserve-3d;will-change:transform;transition:transform 0.35s cubic-bezier(0.4, 0, 0.2, 1)}
    /* Two triggers — :hover (desktop pointer) and .impulse-icon-on (mobile,
       added by impulse-feature-card-parallax.js when card scrolls into view).
       Six SVG shapes covered: path, line, circle, rect, polyline, polygon. */
    .impulse-icon[data-hover-effect="parallax"]:hover .impulse-icon-wrap svg path,
    .impulse-icon[data-hover-effect="parallax"]:hover .impulse-icon-wrap svg line,
    .impulse-icon[data-hover-effect="parallax"]:hover .impulse-icon-wrap svg circle,
    .impulse-icon[data-hover-effect="parallax"]:hover .impulse-icon-wrap svg rect,
    .impulse-icon[data-hover-effect="parallax"]:hover .impulse-icon-wrap svg polyline,
    .impulse-icon[data-hover-effect="parallax"]:hover .impulse-icon-wrap svg polygon,
    .impulse-icon[data-hover-effect="parallax"].impulse-icon-on .impulse-icon-wrap svg path,
    .impulse-icon[data-hover-effect="parallax"].impulse-icon-on .impulse-icon-wrap svg line,
    .impulse-icon[data-hover-effect="parallax"].impulse-icon-on .impulse-icon-wrap svg circle,
    .impulse-icon[data-hover-effect="parallax"].impulse-icon-on .impulse-icon-wrap svg rect,
    .impulse-icon[data-hover-effect="parallax"].impulse-icon-on .impulse-icon-wrap svg polyline,
    .impulse-icon[data-hover-effect="parallax"].impulse-icon-on .impulse-icon-wrap svg polygon{animation:impulseIconStroke 0.9s cubic-bezier(0.4, 0, 0.2, 1) both}

    .impulse-icon[data-hover-effect="lift"]{transition:transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),box-shadow 0.3s ease-in-out}
    .impulse-icon[data-hover-effect="lift"]:hover{transform:translateY(-4px);box-shadow:0 12px 28px rgba(0,0,0,0.10)}

    /* SVG-URL icon paths — currentColor inheritance. Was emitted per-element
       inline via wp_add_inline_style; now matches any SVG inside an icon-wrap
       that was rendered with `data-svg="1"` (set by the renderer when the
       source was a URL/path rather than a Lucide name). */
    .impulse-icon-wrap[data-svg="1"] svg{fill:currentColor}

    .impulse-social-hover-shine a{position:relative;overflow:hidden}
    .impulse-social-hover-shine a::before{content:'';position:absolute;top:0;left:-75%;width:50%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.4),transparent);transform:skewX(-25deg);transition:max-height 0.6s cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none;z-index:2}
    .impulse-social-hover-shine a:hover::before{animation:impulse-img-shine 1s ease-in-out forwards}
    .impulse-social-hover-spin a{transition:transform 0.7s}.impulse-social-hover-spin a:hover{transform:rotate(360deg)}
    .impulse-social-hover-grow a{transition:transform 0.3s}.impulse-social-hover-grow a:hover{transform:scale(1.2)}
    /* Icon-list hover effects — 3D motion only. Parallax and Tilt are JS-driven (impulse-table-hover.js). */
    .impulse-table-hover{perspective:900px}
    .impulse-table-hover li{transition:transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);transform-style:preserve-3d;will-change:transform}
    .impulse-table-hover li > span:first-child,
    .impulse-table-hover li > a > span:first-child{transition:transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);transform-style:preserve-3d}
    /* Pop — whole row pushes forward on hover with a soft shadow */
    .impulse-hh-pop li:hover{transform:translate3d(0,0,24px);box-shadow:0 10px 28px rgba(0,0,0,0.14)}
    /* Burst — icon punches forward with a soft energy ring expanding behind it */
    .impulse-hh-burst li > span:first-child,
    .impulse-hh-burst li > a > span:first-child{position:relative;transition:transform 0.28s cubic-bezier(0.34,1.56,0.64,1)}
    .impulse-hh-burst li:hover > span:first-child,
    .impulse-hh-burst li:hover > a > span:first-child{transform:translate3d(0,0,30px) scale(1.18)}
    .impulse-hh-burst li > span:first-child::before,
    .impulse-hh-burst li > a > span:first-child::before{content:'';position:absolute;inset:-10%;border-radius:50%;background:radial-gradient(circle,currentColor 0%,currentColor 30%,transparent 70%);opacity:0;transform:scale(0.2);pointer-events:none;z-index:-1}
    .impulse-hh-burst li:hover > span:first-child::before,
    .impulse-hh-burst li:hover > a > span:first-child::before{animation:impulseIconBurst 0.7s cubic-bezier(0.4, 0, 0.2, 1) both}
    @keyframes impulseIconBurst{0%{opacity:0.45;transform:scale(0.2)}60%{opacity:0.12;transform:scale(2.0)}100%{opacity:0;transform:scale(2.5)}}
    /* Shared keyframe for Feature Card stroke-draw (dasharray + --sl set per-path by impulse-feature-card-parallax.js) */
    @keyframes impulseIconStroke{0%{stroke-dashoffset:var(--sl,200)}100%{stroke-dashoffset:0}}
    .impulse-table-stagger li{opacity:0;transform:translateY(12px)}
    .impulse-table-stagger.impulse-in-view li{animation:impulse-stagger-in 0.5s ease-in-out forwards}
    @keyframes impulse-stagger-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
    
    /* Product grid inside slider - natural height, centered */
    .impulse-grid-in-slider{width:100%}
    
    /* Section inside slider - fill available height */
    .impulse-slide-content-wrapper > .impulse-section.impulse-fill-slide{flex:1;height:100%;display:flex;flex-direction:column}
    .impulse-slide-content-wrapper .impulse-section.impulse-fill-slide > .impulse-container{flex:1;display:flex;flex-direction:column}
    
    /* FRONTEND: Hide editor elements, reset all hover borders/outlines from themes and WP core */
    /* Scoped to .impulse-frontend-page body class so this stylesheet is safe to load in the
       editor iframe too — the editor iframe does not have that body class, so toolbars stay visible. */
    .impulse-frontend-page .impulse-el-toolbar,.impulse-frontend-page .impulse-dropzone,.impulse-frontend-page .impulse-cell-empty-indicator,.impulse-frontend-page .impulse-empty-placeholder,.impulse-frontend-page .impulse-element-label,.impulse-frontend-page .impulse-add-element,.impulse-frontend-page .impulse-add-section,.impulse-frontend-page .impulse-empty-section{display:none!important}
    .impulse-frontend-page section:hover,
    .impulse-frontend-page section:focus,
    .impulse-frontend-page div:not(input):not(select):not(textarea):not(button):hover,
    .impulse-frontend-page div:not(input):not(select):not(textarea):not(button):focus{outline:none!important;-webkit-tap-highlight-color:transparent}
    .impulse-frontend-page *:focus-visible:not(input):not(select):not(textarea):not(button):not(a){outline:none!important}
    .impulse-frontend-page .impulse-el,.impulse-frontend-page .impulse-el *{outline:none!important;-webkit-tap-highlight-color:transparent}
    .impulse-el{width:100%;box-sizing:border-box;align-self:stretch}
    .impulse-el[data-type="grid"] .impulse-grid-wrapper,.impulse-el[data-type="grid"] .impulse-grid{margin-left:auto!important;margin-right:auto!important}
    .impulse-el[data-type="rows"] > *,.impulse-el[data-type="columns"] > *{margin-left:auto!important;margin-right:auto!important}
    @media(min-width:769px){.impulse-el[data-type="checkout"],.impulse-el[data-type="contact"],.impulse-el[data-type="login"],.impulse-el[data-type="register"],.impulse-el[data-type="shipping"],.impulse-el[data-type="table"]{max-width:50%;margin-left:auto;margin-right:auto}}.impulse-el[data-type="checkout"],.impulse-el[data-type="contact"],.impulse-el[data-type="login"],.impulse-el[data-type="register"]{margin-left:auto!important;margin-right:auto!important}
    .impulse-el[data-type="cart"]{max-width:800px;margin-left:auto;margin-right:auto;width:100%;box-sizing:border-box}.impulse-el[data-type="map"],.impulse-el[data-type="booking"],.impulse-el[data-type="unfold"],.impulse-el[data-type="modal"]{max-width:var(--impulse-content-max-width,1440px);margin-left:auto;margin-right:auto;width:100%;box-sizing:border-box}
    .impulse-el[data-type="video"]{margin-left:auto;margin-right:auto;width:100%;box-sizing:border-box}
    .impulse-product-bundle{display:block!important;width:100%!important;box-sizing:border-box!important}
    .impulse-frontend-page .impulse-el::before,.impulse-frontend-page .impulse-el::after{display:none!important}
    .impulse-frontend-page .impulse-el:hover,.impulse-frontend-page .impulse-el:focus,.impulse-frontend-page .impulse-el:focus-within,.impulse-frontend-page .impulse-el:focus-visible{outline:none!important;box-shadow:none!important}
    .impulse-frontend-page [contenteditable]{outline:none!important;cursor:default!important;-webkit-user-modify:read-only!important}
    .impulse-frontend-page .impulse-rows-cell,.impulse-frontend-page .impulse-grid-cell,.impulse-frontend-page .impulse-layout-cell{outline:none!important;cursor:default!important}
    .impulse-layout-grid{display:grid}
    .impulse-layout-col{display:flex;flex-direction:column}
    .impulse-layout-cell{position:relative;flex:1;display:flex;flex-direction:column}
    @media(max-width:767px){.impulse-layout-grid{grid-template-columns:1fr!important}.impulse-layout-col{min-height:0}}
    @media(min-width:1025px){.impulse-hide-desktop{display:none!important}}
    @media(min-width:768px) and (max-width:1024px){.impulse-hide-tablet{display:none!important}}
    @media(max-width:767px){.impulse-hide-mobile{display:none!important}}
    /* Cell content must be constrained to cell height */
    .impulse-cell-content{min-height:0!important}
    /* Images inside cell grid should respect row height */
    .impulse-cell-content > img,.impulse-cell-content > a{flex:1;min-height:0;max-height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden}
    .impulse-cell-content > img,.impulse-cell-content > a > img{max-height:100%;max-width:100%;width:auto;height:auto;object-fit:contain;margin:0 auto}


/* ── Moved from inline <head> style block ─────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
        body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #1d2327; }
        /* Aggressive theme layout overrides — Impulse owns the entire viewport.
           Body bg must stay transparent so the html element's paint (engine boot
           cover + per-screen runtime paint, see screens.js) shows through. A
           literal color here would mask the engine's html paint and cause
           catastrophic invisibility for any screen with content that matches
           that color (e.g. white kinetic text on a transparent screen). */
        body.impulse-frontend-page { background: transparent; width: 100%; max-width: none !important; overflow-x: hidden; }
        /* Screen mode: lock viewport, hide scrollbars, no horizontal overflow */
        body.impulse-screen-mode-active {
            overflow: hidden !important;
            max-width: 100vw !important;
            overscroll-behavior: none;
        }
        body.impulse-screen-mode-active .impulse-screen {
            overflow-x: hidden !important;
            max-width: 100vw !important;
            box-sizing: border-box;
        }
        body.impulse-screen-mode-active .impulse-screen::-webkit-scrollbar { display: none; }
        /* Pre-size screens before JS: prevents height flash on load/reload.
           `contain:paint` enforces the screen clips all its descendants to its
           own box — regardless of preserve-3d children inside (e.g. Tiers/arc
           pricing cards that use translateZ on the CTA button wrapper). Without
           this, Z-translated buttons can briefly project beyond the outgoing
           screen's bounds during transitions and flash onto the next screen. */
        .impulse-screen-wrapper > .impulse-screen { height:100dvh; min-height:100dvh; max-height:100dvh; overflow:hidden; contain:paint; }
        body.impulse-screen-mode-active .impulse-content-wrapper {
            box-sizing: border-box;
            max-width: 100vw;
            overflow-x: hidden;
        }
        /* ── Native (classic) vertical scroll ────────────────────────────────
           body.impulse-scroll-classic: the page scrolls normally and screens are
           full-height sections in document flow. The screen engine bails on this
           class (no snap, no reveals, no env) in BOTH the live site
           (assets/js/impulse-screens.js) and the editor preview
           (admin/views/impulse-preview.php), so these rules undo the screen-mode
           sizing/lock and let tall content grow past one viewport. The two
           engines use different screen selectors, so both are covered. */
        /* body must NOT be a scroll container, or it traps the mouse wheel: when
           the screen-mode critical CSS pins html to 100dvh (the real scroll
           root) while body also has overflow-y:auto, body is exactly as tall as
           its content so it can't scroll, yet it swallows wheel events before
           they reach html — the page then only scrolls via the scrollbar, not
           the wheel. overflow:visible takes body out of the scroll chain so the
           wheel reaches the html scroll root. html clips horizontal + scrolls. */
        body.impulse-scroll-classic { overflow: visible !important; height: auto !important; max-height: none !important; position: static !important; }
        html:has(> body.impulse-scroll-classic) { overflow-x: hidden !important; overflow-y: auto !important; height: auto !important; max-height: none !important; scroll-behavior: smooth; }
        body.impulse-scroll-classic .impulse-screen-wrapper,
        body.impulse-scroll-classic .impulse-content-wrapper { position: relative !important; height: auto !important; min-height: 0 !important; overflow: visible !important; perspective: none !important; transform: none !important; }
        /* Resolve the per-device screen minimum at PAINT time. The values ride
           each screen's --imp-nvh/-t/-m inline vars (emitted next to the
           data-native-min-vh attrs); the classic-bail JS later writes the same
           numbers inline, so its pass moves nothing. Before this, min-height sat
           at 0/desktop until the JS arrived - a whole-document reflow at script
           time that re-rated LCP to 21-27s on throttled mobile (2026-08-02). */
        body.impulse-scroll-classic .impulse-screen-wrapper > .impulse-screen { --imp-nvh-r: var(--imp-nvh, 0px); }
        @media (max-width: 1024px) {
            body.impulse-scroll-classic .impulse-screen-wrapper > .impulse-screen { --imp-nvh-r: var(--imp-nvh-t, var(--imp-nvh, 0px)); }
        }
        @media (max-width: 767px) {
            body.impulse-scroll-classic .impulse-screen-wrapper > .impulse-screen { --imp-nvh-r: var(--imp-nvh-m, var(--imp-nvh-t, var(--imp-nvh, 0px))); }
        }
        body.impulse-scroll-classic .impulse-screen-wrapper > .impulse-screen,
        body.impulse-scroll-classic .impulse-content-wrapper > .impulse-el[data-type="section"] {
            position: relative !important;
            height: auto !important; min-height: var(--imp-nvh-r, 0); max-height: none !important; /* native scroll: sections size to content; the resolved per-device var above IS the data-native-min-vh minimum, applied from first paint */
            overflow: visible !important; contain: none !important;
            opacity: 1 !important; visibility: visible !important;
            transform: none !important; filter: none !important; clip-path: none !important;
            pointer-events: auto !important;
        }
        /* .impulse-page (the per-screen inner wrapper) carries min-height:100vh
           from its base rule. In classic scroll that forced EVERY body screen
           to a full viewport, leaving big empty gaps under short sections and
           pushing the footer up the page. Release it on classic screens that
           have no explicit per-screen min height; the hero keeps its 100vh
           because it carries data-native-min-vh. 2026-07-03. */
        body.impulse-scroll-classic .impulse-screen .impulse-page { min-height: var(--imp-nvh-r, 0) !important; }
        /* Same paint-time floor for the content wrapper: the classic-bail JS caps
           it to the per-device vh, and until this rule that cap arrived only with
           the JS - another late reflow feeding the 21s lab LCP (2026-08-02). */
        body.impulse-scroll-classic .impulse-screen .impulse-content-wrapper { min-height: var(--imp-nvh-r, 0) !important; } /* released on ALL classic screens 2026-07-22: the :not([data-native-min-vh]) carve-out predated the 40vh default - every new section carried the attr and kept the 100vh floor, swallowing the per-section vh. The per-screen minimum is enforced by the data-native-min-vh applier + the classic-vh floors in section.php / impulse-page.php. */
        /* Footer is ALWAYS pinned to the very bottom of the page. The page
           wrapper is a flex column at min-height:100vh, so margin-top:auto on
           the footer pushes it to the bottom even when the content is shorter
           than the viewport (short pages like the Solutions hub). 2026-07-03. */
        body.impulse-scroll-classic .impulse-footer { margin-top: auto !important; }
        /* Native scroll: top-level section CONTENT caps at the page Max content
           width (centered column) while the band stays full-bleed. Gated on
           .impulse-scroll-classic so cinematic/snap screens are unaffected;
           scoped to .impulse-stretch = top-level sections only (nested-in-cell
           sections cancel their stretch, keeping cell width). Max content
           width=0 emits --impulse-content-max-width:none = no cap. Per-device
           caps come from the media-query block in impulse-page.php. v2.1.1768. */
        body.impulse-scroll-classic .impulse-section.impulse-stretch > .impulse-container-full {
            max-width: var(--impulse-content-max-width, 1440px);
            margin-left: auto;
            margin-right: auto;
        }
        body.impulse-scroll-classic #impulse-fx-canvas,
        body.impulse-scroll-classic #impulse-3d-canvas,
        body.impulse-scroll-classic #impulse-tunnel-canvas,
        body.impulse-scroll-classic #impulse-motion-lava-canvas,
        body.impulse-scroll-classic #impulse-wave-canvas,
        body.impulse-scroll-classic #impulse-depth-canvas { display: none !important; }
        body.impulse-frontend-page #page,
        body.impulse-frontend-page #content,
        body.impulse-frontend-page .site,
        body.impulse-frontend-page .site-content,
        body.impulse-frontend-page .content-area,
        body.impulse-frontend-page .entry-content,
        body.impulse-frontend-page .main-content,
        body.impulse-frontend-page main,
        body.impulse-frontend-page .container,
        body.impulse-frontend-page .wrapper { width: 100% !important; max-width: none !important; margin: 0 !important; padding: 0 !important; float: none !important; display: block !important; }
        body.impulse-frontend-page .sidebar,
        body.impulse-frontend-page .widget-area,
        body.impulse-frontend-page #secondary,
        body.impulse-frontend-page aside.sidebar { display: none !important; }
        /* Hide any theme-injected header/footer content */
        body > header:not(.impulse-global-header),
        body > .site-header,
        body > .header,
        body > #header,
        body > footer:not(.impulse-global-footer),
        body > .site-footer,
        body > #footer,
        body > .footer,
        body > #page > header,
        body > #page > footer,
        .site-title:not(.impulse-site-title),
        .site-description:not(.impulse-description) { display: none !important; }
        a { color: inherit; }
        img { max-width: 100%; height: auto; }
        .impulse-page-wrapper { display: flex; flex-direction: column; min-height: calc(100vh - var(--impulse-screen-bottom-inset, 0px)); width: 100%; overflow-x: hidden; animation: impulse-fade-in 0.4s ease-in-out both; }
        @keyframes impulse-fade-in { from { opacity: 0; } to { opacity: 1; } }
        .impulse-page { flex: 1; width: 100%; }
        /* Badge button rules deleted 2.1.646 — badge mode retired. */
        /* Map pulse */
        /* Map circle hover — expand to rectangle */
        .impulse-map-circle{transition:border-radius 0.5s cubic-bezier(0.4,0,0.2,1)}
        .impulse-map-circle:hover{border-radius:0!important}
        /* Map shine on hover */
        .impulse-map-shine::before{content:'';position:absolute;top:0;left:-100%;width:60%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.15),transparent);transition:max-height 0.6s cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none}
        .impulse-google-map:hover .impulse-map-shine::before{left:150%;transition:left 0.8s ease-in-out}
        /* Map scroll reveal */
        .impulse-map-reveal{opacity:0;transform:scale(0.85);transition:opacity 0.8s cubic-bezier(0.4, 0, 0.2, 1),transform 0.8s cubic-bezier(0.4, 0, 0.2, 1)}
        .impulse-map-reveal.revealed{opacity:1;transform:scale(1)}
        /* Icon list linked items */
        a.impulse-il-item{transition:opacity 0.15s}
        a.impulse-il-item:hover{opacity:0.7}
        /* Reviews (Google-style testimonials) */
        /* Per-card scroll decompose reuses the shared entrance engine: each card
           is wrapped in .impulse-animated with a chosen 3D-reveal keyframe
           (impulse-surface/emerge/unveil/resolve) + staggered delay, gated on the
           block's entrance_animation via impulse_decompose_attrs(). No custom
           keyframe needed here. */
        .impulse-reviews-card{transition:box-shadow 0.2s ease-in-out,transform 0.2s ease-in-out}
        .impulse-reviews-card:hover{box-shadow:0 6px 20px rgba(0,0,0,0.08);transform:translateY(-2px)}
        .impulse-reviews .impulse-reviews-header a[target="_blank"]:hover{opacity:0.85}
        /* Per-device columns + alignment are emitted as id-scoped @media by the
           renderer (reviews.php). Here we only stop the header action group from
           hugging the right edge once it wraps on a narrow screen. */
        @media (max-width:767px){.impulse-reviews-header > div:last-child{margin-left:0 !important}}

/* Header offset belongs to the FIRST screen only: it is the one the fixed header
   overlaps. Sections emit padding-top:calc(<pad> + var(--impulse-header-height))
   inline, so zero the variable everywhere except the first screen and the calc
   resolves to the author's own padding.
   Each section sits in its OWN .impulse-screen > .impulse-page >
   .impulse-content-wrapper, so every section is :first-child of its wrapper and
   the screen index is the only discriminator. Descendant selector, not child:
   there are two wrappers in between. Sergei 2026-08-07, a section set to 7px was
   rendering 76px. */
/* "any screen preceded by another screen", not ":not(:first-child)": the screen
   wrapper holds non-screen elements too (canvases), so the first SCREEN is not
   the first CHILD and the hero was losing its offset. */
.impulse-screen ~ .impulse-screen .impulse-section,
.impulse-el[data-type="section"] ~ .impulse-el[data-type="section"] .impulse-section {
    --impulse-header-height: 0px;
}

/* PER-DEVICE push. Desktop rules above are the baseline; these override inside a
   breakpoint. Three states: no attribute = inherit desktop, "1" = pin, "0" =
   explicitly do not pin (needed when desktop pushes and the narrower device must
   not, which is the whole reason this exists). !important matches the desktop
   rules it has to beat. Sergei 2026-08-07. */
@media (max-width: 1024px) {
    .impulse-container > [data-push-bottom-tablet="1"]{margin-top:auto!important}
    .impulse-container > [data-push-bottom-tablet="0"]{margin-top:0!important}
    .impulse-container > [data-push-top-tablet="1"]{margin-bottom:auto!important}
    .impulse-container > [data-push-top-tablet="0"]{margin-bottom:0!important}
}
@media (max-width: 767px) {
    .impulse-container > [data-push-bottom-mobile="1"]{margin-top:auto!important}
    .impulse-container > [data-push-bottom-mobile="0"]{margin-top:0!important}
    .impulse-container > [data-push-top-mobile="1"]{margin-bottom:auto!important}
    .impulse-container > [data-push-top-mobile="0"]{margin-bottom:0!important}
}
