:root {
    /* ---------------------------------------------------------------
       Design tokens: every color and font used anywhere on the site is
       defined here, once. Nothing outside this block should hardcode a
       hex/rgb value or a font name — reference these variables instead,
       so the whole site can be re-themed by editing this one place.
       --------------------------------------------------------------- */

    /* Typography */
    --font-heading: 'Sora', 'Helvetica Neue', Arial, sans-serif;
    --font-body: 'Inter', 'Helvetica Neue', Arial, sans-serif;

    /* Neutrals — kept deliberately cool/neutral even though the brand
       palette is warm: text, borders, shadows and the dark hero/footer
       surface all read as neutral gray-black, so the green/gold brand
       colors stand out as accents instead of blending into an all-warm
       page. --color-bg-alt carries only a faint wash of the given cream
       — full-strength cream as a section background was overpowering
       large areas of the page. */
    --color-bg: #ffffff;
    --color-bg-alt: #fffcf2;
    --color-white: #ffffff;
    --color-white-rgb: 255, 255, 255;
    --color-text: #14161a;
    --color-text-muted: #5c6570;
    --color-border: #e2e5ea;
    --color-ink: #12141a;
    --color-ink-rgb: 18, 20, 26;
    --color-ink-deep: #06070a;
    --color-ink-deep-rgb: 6, 7, 10;
    /* TESTE (dev): was a hardcoded #415802 (dark olive) left over from
       the old warm palette — the dark radial glow behind "Precisa de um
       sistema específico?", the "Vamos montar juntos" CTA, and the
       footer (all --gradient-dark) kept reading as the old green even
       after the rest of the palette moved on. Tied to --color-accent
       via var() instead of a second hardcoded value, so it never
       drifts out of sync with it again. */
    --color-glow: var(--color-accent);
    /* Deliberately much lighter than --color-ink/--color-text — for
       elements that need to read as a distinct object sitting on top of
       the dark hero/CTA background (e.g. the exploded-page mockup),
       rather than blending into it. */
    --color-surface-raised: #262b35;
    --color-surface-raised-rgb: 38, 43, 53;

    /* Brand palette */
    /* TESTE (dev): trocado de #014000 (verde bem escuro) para um verde
       vívido, a pedido — para "clarificar" a página e trazer um ar de
       fluidez. --color-primary-dark fica intocado de propósito: ele é
       quem garante contraste de texto sobre fundos claros (ex.:
       .btn-outline-primary, --color-primary-tint) e não deve seguir o
       tom mais claro do novo primary. Ressalva: --gradient-brand e
       .btn-primary (texto branco) perdem contraste nesse verde mais
       claro — ok para teste visual, mas revisar antes de ir pra
       produção. */
    --color-primary: #2fcf2f;
    --color-primary-rgb: 47, 207, 47;
    /* TESTE (dev): another leftover from the old warm palette (#425b0a,
       dark olive) — only used by .blob-3, one of the hero's 3 decorative
       glow blobs. blob-1/blob-2 already moved to --color-primary/
       --color-accent, but this third one got missed, so the hero read
       as part new palette / part old depending on which blob you looked
       at. A literal midpoint between the current primary and accent
       keeps that "third distinct brand tone for variety" role intact. */
    --color-primary-mid: #2ee378;
    --color-primary-dark: #012a00;
    --color-primary-light: #51ef58;
    --color-primary-tint: #fff2cc;
    /* TESTE (dev): --color-accent e --color-highlight trocados do
       dourado/marrom original (#827514 / #d69106) pelo mesmo verde-teal,
       agora ajustado para #2df6c0, a pedido — os tons quentes que ainda
       sobravam em --gradient-brand, .text-gradient e .stat-number
       quebravam a paleta verde/fluida recém-adotada. --color-accent-light
       é um tint mais claro do mesmo tom, mantendo a mesma relação que
       --color-primary-light tem com --color-primary. */
    --color-accent: #2df6c0;
    --color-accent-rgb: 45, 246, 192;
    --color-accent-light: #8cfadc;

    /* Highlight: usado deliberadamente com moderação (glows, bordas de
       card em destaque, texto em gradiente sobre fundos escuros). NÃO
       faz parte de --gradient-brand nem de nenhum preenchimento sólido
       de botão — texto branco sobre ele tem só ~2:1 de contraste (não
       passa WCAG AA), então fica fora de superfícies grandes que levem
       texto. */
    --color-highlight: #2df6c0;
    --color-highlight-rgb: 45, 246, 192;

    /* Feedback colors */
    --color-success: #1d9a5c;
    --color-success-rgb: 46, 196, 121;
    --color-danger: #e0505f;
    --color-danger-rgb: 224, 80, 95;

    /* Decorative one-offs (not part of the themeable brand palette —
       e.g. the lightbulb icon's warm glow should stay warm regardless
       of theme) */
    --color-bulb-glow-rgb: 255, 214, 64;

    /* Gradients */
    /* TESTE (dev): 135deg (diagonal) a pedido — 40% = ~40% primária /
       60% accent (a accent já é a cor dominante no degradê). */
    --gradient-brand: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary) 40%, var(--color-accent) 100%);
    --gradient-dark: radial-gradient(circle at 20% 20%, var(--color-glow) 0%, var(--color-ink) 55%, var(--color-ink-deep) 100%);
    --gradient-ink-accent: linear-gradient(135deg, var(--color-ink), var(--color-accent));

    /* Shadows */
    --shadow-color-rgb: 18, 20, 26;
    --shadow-color-strong-rgb: 14, 16, 20;
    --shadow-color-nav-rgb: 16, 18, 24;
    --shadow-soft: 0 10px 30px rgba(var(--shadow-color-rgb), 0.08);
    --shadow-strong: 0 25px 60px rgba(var(--shadow-color-strong-rgb), 0.25);

    /* Shape & motion */
    --radius-lg: 1.5rem;
    --radius-md: 1rem;
    --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

html, body {
    font-family: var(--font-body);
    color: var(--color-text);
    background: var(--color-bg);
    scroll-behavior: smooth;
}

/* Injected by site.js's initPageLoadingIndicator on every page (loaded
   globally, not just on the marketing site) — a thin bar that creeps
   toward (never quite reaching) 90% the instant an outbound link is
   clicked, so a real full-page navigation — e.g. #solicitar's "Continuar"
   into an [Authorize]-gated route while signed out, which redirects
   through /login and can take the better part of a second — reads as
   "loading" instead of "frozen". No JS-driven completion state: the whole
   point is that the browser replaces this page (bar included) once the
   next one is ready, so the animation never has to know when that happens. */
[data-page-loading-bar] {
    position: fixed;
    top: 0;
    left: 0;
    height: 3px;
    width: 0;
    background: var(--gradient-brand);
    z-index: 9999;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
}

[data-page-loading-bar].is-active {
    opacity: 1;
    animation: page-loading-progress 4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes page-loading-progress {
    0% { width: 0%; }
    15% { width: 35%; }
    40% { width: 60%; }
    100% { width: 88%; }
}

@media (prefers-reduced-motion: reduce) {
    [data-page-loading-bar].is-active {
        animation: none;
        width: 60%;
    }
}

/* Paired with the inline head script in App.razor: keeps the page blank for
   the brief instant between "hash says #solicitar/#sobre-nos" and "the
   overlay script has actually opened it", instead of flashing the normal
   homepage first. */
html.pending-hash-overlay body {
    visibility: hidden;
}

h1, h2, h3, h4, h5, .display-font {
    font-family: var(--font-heading);
}

/* ---------- Shared building blocks (used across every page) ---------- */
.section-head {
    text-align: center;
    max-width: 640px;
    margin: 0 auto 3rem;
}

.eyebrow {
    display: inline-block;
    color: var(--color-primary);
    font-weight: 700;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-bottom: 0.6rem;
}

.section-subtitle {
    color: var(--color-text-muted);
    margin: 0;
}

.hero-actions {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
}

.page-shell {
    display: flex;
    flex-direction: column;
}

/* The [data-tilt] hover effect (initTilt in site.js) sets a fresh
   perspective()+rotateX/rotateY transform on every mousemove frame —
   without these hints, Chromium/WebKit re-rasterize the card's text at
   an angle each frame instead of compositing a single GPU layer, which
   reads as the text going blurry while the card tilts. */
[data-tilt] {
    will-change: transform;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

/* ---------- Shared "request flow" page shell (Solicitar*.razor) ---------- */
.request-shell {
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: calc(100vh - 4rem);
}

/* Decorative shapes filling the empty side gutters beside a centered
   form/panel on wide screens. Purely cosmetic (aria-hidden), and hidden
   below 1100px where the gutters disappear and shapes would overlap
   the content. */
.request-decor {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
}

.decor-shape {
    position: absolute;
    top: var(--decor-top, 50%);
    left: var(--decor-left, auto);
    right: var(--decor-right, auto);
    width: var(--decor-size, 80px);
    height: var(--decor-size, 80px);
    background: rgba(var(--decor-color, var(--color-primary-rgb)), var(--decor-alpha, 0.1));
    will-change: transform;
}

.decor-circle {
    border-radius: 50%;
}

.decor-hexagon {
    clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
}

.decor-triangle {
    clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
}

.decor-pentagon {
    clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%);
}

@media (max-width: 1100px) {
    .request-decor {
        display: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .decor-shape {
        display: none;
    }
}

/* ---------- Shared form primitives (Solicitar*.razor) ---------- */
.request-form {
    background: var(--color-white);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: clamp(1.5rem, 4vw, 2.5rem);
    box-shadow: var(--shadow-soft);
}

.request-form .btn {
    width: 100%;
    margin-top: 0.5rem;
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin-bottom: 1.5rem;
}

.form-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
}

.form-row-pair {
    grid-template-columns: repeat(2, 1fr);
    margin-top: 0.6rem;
}

.form-group label {
    font-weight: 600;
    font-size: 0.92rem;
    color: var(--color-text);
}

.field-hint {
    color: var(--color-text-muted);
    font-size: 0.85rem;
    margin: 0;
    line-height: 1.5;
}

@media (max-width: 640px) {
    .form-row {
        grid-template-columns: 1fr;
    }
}

/* Blazor's built-in <InputText>/<InputSelect>/<InputTextArea>/
   <ValidationMessage> components — used by any form on the site, for
   the automatic valid/invalid CSS classes and aria-invalid they add —
   don't forward a page's CSS-isolation scope attribute onto the
   element they render (same gap as <NavLink> not forwarding it onto
   its <a>). Scoped rules targeting them silently never match, so this
   styling has to live here instead of in a per-page .razor.css file. */
.form-control,
.form-select {
    font-family: inherit;
    font-size: 0.95rem;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--color-border);
    border-radius: 0.65rem;
    background: var(--color-white);
    color: var(--color-text);
    transition: border-color 0.25s ease, box-shadow 0.25s ease;
}

.form-control:focus,
.form-select:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.15);
}

/* Applied automatically once EditContext has a validation message for
   the field — covers a submit with untouched required fields, not
   just ones the user typed into and left invalid. */
.form-control.invalid,
.form-select.invalid {
    border-color: var(--color-danger);
    background: rgba(var(--color-danger-rgb), 0.04);
}

.form-control.invalid:focus,
.form-select.invalid:focus {
    border-color: var(--color-danger);
    box-shadow: 0 0 0 3px rgba(var(--color-danger-rgb), 0.18);
}

/* Positive counterpart to .invalid above — once a touched field passes
   validation, confirm it with green instead of just going quiet/neutral. */
.form-control.valid.modified,
.form-select.valid.modified {
    border-color: var(--color-success);
    background: rgba(var(--color-success-rgb), 0.06);
}

.form-control.valid.modified:focus,
.form-select.valid.modified:focus {
    border-color: var(--color-success);
    box-shadow: 0 0 0 3px rgba(var(--color-success-rgb), 0.18);
}

textarea.form-control {
    resize: vertical;
    min-height: 8rem;
    line-height: 1.5;
}

.field-error {
    color: var(--color-danger);
    font-size: 0.82rem;
}

a, .btn-link {
    color: var(--color-primary);
}

.btn-primary {
    color: var(--color-white);
    background: var(--gradient-brand);
    border: none;
    box-shadow: 0 8px 20px rgba(var(--color-primary-rgb), 0.35);
    transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

.btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 14px 30px rgba(var(--color-primary-rgb), 0.45);
}

/* Bootstrap's own .btn-outline-primary reads --bs-primary, which is never
   remapped to this site's palette anywhere — left alone, every outline
   button (every "Voltar", "Falar com a gente"...) rendered in Bootstrap's
   default blue (#0d6efd) instead of the brand green, clashing with
   .btn-primary right next to it. */
.btn-outline-primary {
    color: var(--color-primary-dark);
    border-color: var(--color-primary);
    background: transparent;
    transition: background 0.2s var(--ease), color 0.2s var(--ease), border-color 0.2s var(--ease);
}

.btn-outline-primary:hover,
.btn-outline-primary:focus {
    color: var(--color-white);
    background: var(--color-primary);
    border-color: var(--color-primary);
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 0;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* ---------- Scroll-reveal engine (used across pages) ---------- */
[data-reveal] {
    opacity: 0;
    transform: translateY(28px);
    transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
    will-change: opacity, transform;
}

[data-reveal].is-visible {
    opacity: 1;
    transform: translateY(0);
}

[data-reveal-delay="1"] { transition-delay: 0.08s; }
[data-reveal-delay="2"] { transition-delay: 0.16s; }
[data-reveal-delay="3"] { transition-delay: 0.24s; }
[data-reveal-delay="4"] { transition-delay: 0.32s; }
[data-reveal-delay="5"] { transition-delay: 0.4s; }

/* Opacity-only variant of the reveal engine, for elements (like the
   semicircle icons) whose `transform` is already busy positioning them
   and can't also carry the reveal's slide-in offset. */
[data-reveal-fade] {
    opacity: 0;
    transition: opacity 0.6s var(--ease);
    will-change: opacity;
}

[data-reveal-fade].is-visible {
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    [data-reveal] {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }

    [data-reveal-fade] {
        opacity: 1 !important;
        transition: none !important;
    }
}

/* ---------- Site builder (etapa "Criando" do /solicitar/site) ----------
   Shared across every Components/SiteBuilder/*.razor component — kept here
   instead of per-component .razor.css because they're all one cohesive UI
   and several classes (.item-grid, .add-item-btn) are reused identically
   across module editors. */
.module-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-bottom: 2rem;
}

.module-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 1rem;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    background: var(--color-white);
    color: var(--color-text-muted);
    font-size: 0.88rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.25s var(--ease), border-color 0.25s var(--ease), color 0.25s var(--ease);
}

.module-chip-dot {
    width: 0.55rem;
    height: 0.55rem;
    border-radius: 50%;
    background: var(--color-border);
    transition: background 0.25s var(--ease);
}

.module-chip.is-enabled {
    background: rgba(var(--color-primary-rgb), 0.08);
    border-color: rgba(var(--color-primary-rgb), 0.35);
    color: var(--color-primary-dark);
}

.module-chip.is-enabled .module-chip-dot {
    background: var(--gradient-brand);
}

.module-section {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    margin-bottom: 1.25rem;
    background: var(--color-white);
}

.module-section > summary {
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.1rem 1.4rem;
    cursor: pointer;
    font-family: var(--font-heading);
    font-weight: 700;
}

.module-section > summary::-webkit-details-marker {
    display: none;
}

.module-section-chevron {
    color: var(--color-text-muted);
    transition: transform 0.25s var(--ease);
    flex-shrink: 0;
}

.module-section[open] .module-section-chevron {
    transform: rotate(180deg);
}

.module-section-title-row {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.module-settings-gear {
    border: 1px solid var(--color-border);
    background: var(--color-white);
    font-size: 0.85rem;
    line-height: 1;
    cursor: pointer;
    padding: 0.35rem 0.6rem;
    border-radius: var(--radius-md);
    opacity: 0.85;
    box-shadow: var(--shadow-soft);
    transition: opacity 0.2s var(--ease), background 0.2s var(--ease), border-color 0.2s var(--ease);
}

.module-settings-gear:hover {
    opacity: 1;
    background: rgba(var(--color-primary-rgb), 0.08);
    border-color: var(--color-primary);
}

.module-settings-gear.is-active {
    background: var(--gradient-brand);
    border-color: transparent;
    color: var(--color-white);
    opacity: 1;
}

.module-settings-popover {
    padding: 1.1rem 1.4rem;
    border-top: 1px solid var(--color-border);
    background: var(--color-bg-alt);
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
}

.module-section-body {
    padding: 0 1.4rem 1.5rem;
    border-top: 1px solid var(--color-border);
    padding-top: 1.4rem;
}

/* ---------- Builder layout: editor list + one compiled, tabbed preview ----------
   Every enabled module's editor stacks in the left column; a single global
   preview panel on the right compiles ALL of them behind a top nav ("guias")
   instead of each module carrying its own separate preview. */
.builder-layout {
    display: grid;
    grid-template-columns: 1.2fr 0.8fr;
    gap: 1.75rem;
    align-items: start;
}

.builder-editor-col {
    min-width: 0;
}

.builder-preview-col {
    position: sticky;
    /* Clears the sticky site nav (~3rem once scrolled) with some breathing room. */
    top: 4.5rem;
    /* Without this, a CSS grid track won't shrink below its content's
       intrinsic width — and .site-preview-body's fixed 1200px width in
       "computador" mode (seção 5.2) makes that intrinsic width 1200px, so
       the 0.8fr track was growing to fit it instead of honoring its share
       and letting .site-preview-viewport's own overflow-x:auto handle the
       overflow. That's what broke the two-column layout the moment
       "computador" mode rendered anything. */
    min-width: 0;
}

.site-preview-panel {
    border-radius: var(--radius-md);
    /* No background fill here on purpose — a predefined color behind the
       layout would compete with (and make it hard to judge) the real site
       background configured below. The shadow alone is what sets this
       panel apart as a "device frame" around the actual site preview. */
    box-shadow: var(--shadow-soft);
    overflow: hidden;
}

.site-preview-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-bg-alt);
}

.site-preview-fullscreen-btn {
    border: none;
    background: var(--color-white);
    border-radius: var(--radius-md);
    padding: 0.4rem 0.75rem;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--color-text-muted);
    cursor: pointer;
    box-shadow: var(--shadow-soft);
    transition: transform 0.15s var(--ease), color 0.15s var(--ease);
}

.site-preview-fullscreen-btn:hover {
    transform: scale(1.03);
    color: var(--color-text);
}

.site-preview-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    padding: 0.6rem;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-white);
}

.site-preview-nav-link {
    border: none;
    background: transparent;
    padding: 0.45rem 0.85rem;
    border-radius: var(--radius-md);
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: background 0.2s var(--ease), color 0.2s var(--ease);
}

.site-preview-nav-link.is-active {
    background: var(--gradient-brand);
    color: var(--color-white);
}

.site-preview-device-toggle {
    display: inline-flex;
    gap: 0.15rem;
    padding: 0.2rem;
    background: var(--color-bg-alt);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.device-toggle-btn {
    border: none;
    background: transparent;
    padding: 0.35rem 0.55rem;
    border-radius: calc(var(--radius-md) - 0.2rem);
    font-size: 0.95rem;
    line-height: 1;
    cursor: pointer;
    opacity: 0.55;
    transition: background 0.2s var(--ease), opacity 0.2s var(--ease);
}

.device-toggle-btn.is-active {
    background: var(--color-white);
    box-shadow: var(--shadow-soft);
    opacity: 1;
}

.site-preview-body {
    --preview-accent: var(--color-primary);
    padding: 1.25rem;
    font-family: var(--font-body);
    max-height: min(70vh, 640px);
    overflow-y: auto;
}

/* "Computador" only forces a real desktop content width (1200px) in tela
   cheia (.is-fullscreen further below) — forcing it here too, in the
   embedded sidebar preview, used to make ordinary content (the map embed,
   item-grids) bleed past the panel's own edge into a horizontal scrollbar,
   which read as broken rather than as "see the real width" — especially
   since the sidebar is almost always much narrower than 1200px to begin
   with, so nearly everything triggered it. The embedded view now just
   reflows to whatever width the column actually is (like every other
   block type already does); tela cheia is where the real, no-compromise
   desktop width — and the multi-column item-grids it enables — actually
   lives, where there's genuine room for it. */
.site-preview-viewport.is-desktop.is-fullscreen {
    overflow-x: auto;
}

.site-preview-viewport.is-mobile {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 1.5rem 1rem;
    background: var(--color-bg-alt);
}

.site-preview-viewport.is-mobile .site-preview-body {
    width: 375px;
    max-width: 100%;
    max-height: min(70vh, 700px);
    border-radius: 1.75rem;
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-soft);
}

/* Fullscreen has real room, so "computador" no longer needs the horizontal
   scroll above — it just fits (or scales down gracefully on a narrow
   window) — and "celular" gets more headroom to show a taller slice of the
   page before it has to scroll internally. */
.site-preview-viewport.is-fullscreen {
    flex: 1;
    min-height: 0;
}

.site-preview-viewport.is-desktop.is-fullscreen .site-preview-body {
    width: min(1200px, 100%);
    max-width: 1200px;
    margin: 0 auto;
    /* The inline embedded panel's 70vh/640px cap makes sense for a sidebar
       preview, but tela cheia has an entire screen to work with — now that
       it stacks every section into one page (seção 5.3) instead of showing
       one tab at a time, keeping that same small cap would defeat the point
       of "tela cheia" by cramming the whole page back into a tiny scrollbox. */
    max-height: min(85vh, 900px);
}

.site-preview-viewport.is-mobile.is-fullscreen {
    padding: 2.5rem 1rem;
}

.site-preview-viewport.is-mobile.is-fullscreen .site-preview-body {
    max-height: min(85vh, 812px);
}

.site-preview-fullscreen-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 16, 20, 0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    z-index: 1000;
}

.site-preview-fullscreen-panel {
    background: var(--color-white);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-strong);
    width: 100%;
    height: 100%;
    max-width: 1400px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.site-preview-fullscreen-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-bg-alt);
}

.site-preview-fullscreen-close {
    border: none;
    background: var(--color-white);
    border-radius: var(--radius-md);
    padding: 0.45rem 0.85rem;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--color-text-muted);
    cursor: pointer;
    box-shadow: var(--shadow-soft);
}

/* Mockup of the real site's own header — brand left, links right — painted
   with the business's actual primary color (set inline via style, since it
   comes from SiteDraft, not a fixed value) instead of the builder's own UI
   chrome, so "computador"/"celular" in tela cheia reads as a preview of the
   real site rather than a generic modal. See SitePreviewPanel.razor's
   FullscreenNavbar/NavTextColor for how the text color always stays legible
   against whatever that primary color turns out to be. */
.site-preview-fullscreen-navbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.85rem 1.5rem;
    transition: background-color 0.2s var(--ease);
}

/* Tamanho (NavSettings.Size, seção 2.2) — just the navbar's own padding, so
   "Compacto" reads as a tighter bar and "Amplo" as a roomier one without
   touching anything else in the layout. */
.site-preview-fullscreen-navbar.nav-size-compacto {
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
}

.site-preview-fullscreen-navbar.nav-size-amplo {
    padding-top: 1.35rem;
    padding-bottom: 1.35rem;
}

.site-preview-fullscreen-brand {
    display: flex;
    align-items: center;
    min-width: 0;
}

.site-preview-fullscreen-logo {
    max-height: 2.25rem;
    max-width: 9rem;
    object-fit: contain;
}

.site-preview-fullscreen-logo-placeholder {
    font-size: 0.8rem;
    font-weight: 600;
    font-style: italic;
    opacity: 0.65;
}

.site-preview-fullscreen-navbar-links {
    display: flex;
    align-items: center;
    gap: 1.75rem;
}

.site-preview-fullscreen-navlink {
    border: none;
    background: transparent;
    color: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    padding: 0.3rem 0;
    opacity: 0.8;
    border-bottom: 2px solid transparent;
    transition: opacity 0.2s var(--ease), border-color 0.2s var(--ease);
}

.site-preview-fullscreen-navlink:hover {
    opacity: 1;
}

.site-preview-fullscreen-navlink.is-active {
    opacity: 1;
    border-bottom-color: currentColor;
}

/* "Celular" collapses to a hamburger instead of shrinking the same
   horizontal link row — mirrors the real site's own mobile nav collapse
   (NavMenu.razor/home.css) rather than being a purely cosmetic size change. */
.site-preview-fullscreen-navbar-toggle {
    border: none;
    background: color-mix(in srgb, currentColor 15%, transparent);
    color: inherit;
    border-radius: var(--radius-md);
    width: 2.25rem;
    height: 2.25rem;
    font-size: 1.05rem;
    line-height: 1;
    cursor: pointer;
    flex-shrink: 0;
}

.site-preview-fullscreen-navbar-dropdown {
    display: flex;
    flex-direction: column;
    padding: 0.25rem 1.5rem 1rem;
    gap: 0.15rem;
}

.site-preview-fullscreen-navbar-dropdown .site-preview-fullscreen-navlink {
    text-align: left;
    padding: 0.6rem 0;
    border-bottom: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}

.site-preview-fullscreen-navbar-dropdown .site-preview-fullscreen-navlink:last-child {
    border-bottom: none;
}

/* A NavGroup (Menu superior do site → "Grupos de menu") bundles several
   layouts under one dropdown item instead of each getting its own flat
   link — SitePreviewPanel.NavEntries decides what's grouped, these just
   draw whichever shape it hands back. */
.site-preview-navlink-group {
    position: relative;
}

.site-preview-navlink-group-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: 0.5rem;
    display: flex;
    flex-direction: column;
    min-width: 10rem;
    padding: 0.4rem 0.9rem;
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-strong);
    z-index: 10;
    animation: previewNavDropdownIn 0.18s var(--ease);
}

.site-preview-navlink-group-dropdown .site-preview-fullscreen-navlink {
    text-align: left;
    padding: 0.5rem 0;
    border-bottom: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}

.site-preview-navlink-group-dropdown .site-preview-fullscreen-navlink:last-child {
    border-bottom: none;
}

/* Mobile hamburger dropdown: no open/close state of its own (the hamburger
   itself is already that toggle) — a group just shows as a small label with
   its members indented right under it. */
.site-preview-navlink-group-label {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.6;
    padding: 0.6rem 0 0.1rem;
}

.site-preview-fullscreen-navbar-dropdown .site-preview-navlink-group-member {
    padding-left: 0.9rem;
}

/* ---------- Tela cheia: entrance/transition polish ---------- */

@keyframes previewFullscreenFadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes previewFullscreenPanelIn {
    from { opacity: 0; transform: scale(0.97); }
    to { opacity: 1; transform: scale(1); }
}

.site-preview-fullscreen-backdrop {
    animation: previewFullscreenFadeIn 0.2s var(--ease);
}

.site-preview-fullscreen-panel {
    animation: previewFullscreenPanelIn 0.25s var(--ease);
}

@keyframes previewNavDropdownIn {
    from { opacity: 0; transform: translateY(-8px); }
    to { opacity: 1; transform: translateY(0); }
}

.site-preview-fullscreen-navbar-dropdown {
    transform-origin: top;
    animation: previewNavDropdownIn 0.22s var(--ease);
}

.site-preview-fullscreen-navbar-toggle {
    transition: background 0.2s var(--ease), transform 0.15s var(--ease);
}

.site-preview-fullscreen-navbar-toggle:active {
    transform: scale(0.92);
}

@keyframes previewOverlaySectionIn {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
}

.site-preview-overlay-section {
    animation: previewOverlaySectionIn 0.3s var(--ease);
}

.site-preview-overlay-close {
    border: none;
    background: var(--color-bg-alt);
    border-radius: var(--radius-md);
    padding: 0.5rem 0.9rem;
    margin-bottom: 1.25rem;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: background 0.2s var(--ease), transform 0.15s var(--ease);
}

.site-preview-overlay-close:hover {
    background: var(--color-border);
}

.site-preview-overlay-close:active {
    transform: scale(0.97);
}

/* Every stacked section fades/slides in on its own — independent of
   whatever RevealAnimation (seção 6) that specific layout has configured —
   so tela cheia always feels alive the moment it opens, not just the
   sections someone happened to pick an animation for. The stagger
   (animation-delay, set inline per section index) is what turns a page's
   worth of sections appearing at once into something that reads as a
   sequence instead of a flash. */
@keyframes previewStackedSectionIn {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: translateY(0); }
}

.site-preview-stacked-section {
    animation: previewStackedSectionIn 0.45s var(--ease) both;
}

.site-preview-stacked-section + .site-preview-stacked-section {
    margin-top: 2.5rem;
    padding-top: 2.5rem;
    border-top: 1px solid var(--color-border);
}

/* Switching "computador"/"celular" morphs the frame instead of snapping —
   both the surrounding padding (viewport) and the frame itself (width,
   corners, border, shadow) animate together. */
.site-preview-viewport {
    transition: padding 0.3s var(--ease);
}

.site-preview-body {
    transition: width 0.3s var(--ease), max-width 0.3s var(--ease),
        border-radius 0.3s var(--ease), box-shadow 0.3s var(--ease),
        border-color 0.3s var(--ease);
}

.preview-title {
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 1.15rem;
    color: var(--preview-accent);
    margin-bottom: 0.5rem;
}

.preview-text {
    color: var(--color-text);
    line-height: 1.5;
    margin-bottom: 0.5rem;
    font-size: 0.92rem;
}

.preview-muted {
    color: var(--color-text-muted);
    font-size: 0.85rem;
}

.preview-testimonial {
    font-style: italic;
    line-height: 1.6;
    border-left: 3px solid currentColor;
    padding-left: 1rem;
    margin: 0 0 0.5rem;
}

.preview-testimonial-author {
    display: block;
    margin-top: 0.5rem;
    font-style: normal;
    font-weight: 600;
    font-size: 0.85em;
    opacity: 0.85;
}

.preview-cta-button {
    display: inline-block;
    padding: 0.75rem 1.75rem;
    border-radius: 999px;
    font-weight: 700;
    text-decoration: none;
    cursor: pointer;
    box-shadow: var(--shadow-soft);
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.preview-cta-button:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-strong);
}

.preview-cta-button.is-placeholder {
    opacity: 0.6;
    font-style: normal;
}

.avaliacao-author-input,
.botao-link-input {
    margin-top: 0.5rem;
}

.is-placeholder {
    color: var(--color-text-muted);
    font-style: italic;
}

.preview-meta-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    font-size: 0.9rem;
}

.preview-map-placeholder {
    margin-top: 0.85rem;
    padding: 1.5rem 1rem;
    text-align: center;
    border: 1px dashed var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    font-size: 0.85rem;
}

.preview-map-embed {
    display: block;
    width: 100%;
    height: 220px;
    margin-top: 0.85rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.preview-menu-categoria {
    margin-bottom: 1.1rem;
}

.preview-menu-categoria h4 {
    font-family: var(--font-heading);
    font-weight: 700;
    color: var(--preview-accent);
    margin-bottom: 0.5rem;
    padding-bottom: 0.35rem;
    border-bottom: 1px solid var(--color-border);
}

.preview-menu-item {
    margin-bottom: 0.75rem;
}

.preview-menu-item-row {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    font-weight: 600;
    font-size: 0.92rem;
}

.preview-menu-item-photo {
    width: 100%;
    max-width: 220px;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: var(--radius-md);
    display: block;
    margin-bottom: 0.5rem;
    cursor: zoom-in;
}

/* Clicking a Menu de itens photo (.preview-menu-item-photo above) opens this —
   same fixed-backdrop-plus-panel shape as .site-preview-fullscreen-backdrop,
   reparented onto <body> for the same reason (see FlexibleLayoutPreview's
   OnAfterRenderAsync): escapes .builder-preview-col's position:sticky
   stacking context so it isn't clipped/out-z-indexed by anything outside it.
   Higher z-index than the fullscreen preview's own (1000) since this can be
   triggered from inside that fullscreen preview too. */
.menu-item-lightbox-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 16, 20, 0.75);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    z-index: 1100;
}

.menu-item-lightbox-panel {
    position: relative;
    background: var(--color-white);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-strong);
    width: 100%;
    max-width: 420px;
    max-height: 90vh;
    overflow-y: auto;
}

.menu-item-lightbox-panel img {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    display: block;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.menu-item-lightbox-close {
    position: absolute;
    top: 0.6rem;
    right: 0.6rem;
    border: none;
    background: var(--color-white);
    border-radius: 50%;
    width: 2rem;
    height: 2rem;
    box-shadow: var(--shadow-soft);
    cursor: pointer;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.menu-item-lightbox-info {
    padding: 1rem 1.25rem 1.25rem;
}

.menu-item-lightbox-info h4 {
    margin: 0 0 0.5rem;
    font-family: var(--font-heading);
    font-size: 1.15rem;
}

.menu-item-lightbox-price {
    display: inline-block;
    margin-top: 0.4rem;
    font-weight: 700;
    color: var(--preview-accent);
}

/* Carrossel block (BlockType.Carrossel). Bootstrap's own CSS (bootstrap.min.css,
   linked globally in App.razor) already draws the control-arrow icons,
   indicator dot sizing, dark-variant colors and caption box for free — only
   the actual slide transition needs supplementing here, since this app
   doesn't vendor Bootstrap's JS bundle (see Docs/SiteBuilder.md and
   siteBuilder.bindCarousel, wwwroot/js/sitebuilder.js, for why and how). */
.carousel-inner {
    position: relative;
    overflow: hidden;
}

/* aspect-ratio, not a fixed height — a fixed height doesn't scale down with
   a narrower container (the embedded sidebar preview is nowhere near as
   wide as tela cheia's real desktop width), so the same "22rem" that looks
   right at 1200px wide turned into a tall, narrow strip at ~200-300px wide.
   16:9 scales correctly at any container width. */
.carousel-item img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    display: block;
}

/* Slide (default): every item sits side by side in a flex row; advancing
   shifts the whole row via transform, driven by --gd-carousel-index (set by
   bindCarousel). */
.carousel:not(.carousel-fade) .carousel-inner {
    display: flex;
    transition: transform 0.6s var(--ease);
    transform: translateX(calc(-100% * var(--gd-carousel-index, 0)));
}

.carousel:not(.carousel-fade) .carousel-item {
    flex: 0 0 100%;
    display: block !important;
}

/* Fade: items stack on top of each other, so the container needs its own
   size source (absolutely positioned children don't contribute to it) —
   same 16:9 as the images themselves, so it also scales with width instead
   of being a fixed height. Advancing just crossfades opacity. */
.carousel-fade .carousel-inner {
    aspect-ratio: 16 / 9;
}

.carousel-fade .carousel-item {
    display: block !important;
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 0.6s var(--ease);
}

.carousel-fade .carousel-item.active {
    opacity: 1;
}

.carousel-caption p {
    margin-bottom: 0;
}

.carousel-options-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 0.4rem 1rem;
    margin-top: 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--color-border);
}

.carousel-options-grid .field-group-inline {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.carousel-options-grid input[type="number"] {
    width: 4.5rem;
    display: inline-block;
}

/* Card de imagem block (BlockType.CardImagem) — Bootstrap's .card/.card-img-top/
   .card-body/.card-title/.card-text are already styled by bootstrap.min.css;
   only the placeholder state needs a rule of our own. */
.preview-card-image.is-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 12rem;
    background: var(--color-bg-alt);
    color: var(--color-text-muted);
    font-size: 0.8rem;
}

@media (max-width: 860px) {
    .builder-layout {
        grid-template-columns: 1fr;
    }

    .builder-preview-col {
        position: static;
    }

    .site-preview-body {
        max-height: none;
    }
}

.item-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 1rem;
    margin-bottom: 1rem;
}

.item-card {
    position: relative;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    background: var(--color-bg-alt);
}

.item-card-remove {
    position: absolute;
    top: 0.6rem;
    right: 0.6rem;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    border: none;
    background: rgba(var(--color-danger-rgb), 0.1);
    color: var(--color-danger);
    font-size: 0.9rem;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.add-item-btn {
    align-self: flex-start;
    border: 1px dashed rgba(var(--color-primary-rgb), 0.4);
    background: transparent;
    color: var(--color-primary-dark);
    font-weight: 600;
    padding: 0.6rem 1.1rem;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background 0.25s var(--ease), border-color 0.25s var(--ease);
}

.add-item-btn:hover {
    background: rgba(var(--color-primary-rgb), 0.06);
    border-color: rgba(var(--color-primary-rgb), 0.6);
}

.logo-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    align-items: flex-start;
    margin-bottom: 2rem;
}

.logo-preview {
    width: 6rem;
    height: 6rem;
    border-radius: var(--radius-md);
    border: 1px dashed var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    flex-shrink: 0;
    background: var(--color-bg-alt);
    color: var(--color-text-muted);
}

.logo-preview img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* Reading and resizing an image (LogoColorPicker/GaleriaModuleEditor —
   sitebuilder.js's readAndResizeImage(s)) takes a visible moment on a big
   photo — this is the "something is happening" signal for that stretch,
   shown in place of the preview/grid slot the finished image will occupy. */
.upload-spinner {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    color: var(--color-text-muted);
    font-size: 0.75rem;
    text-align: center;
}

.spinner {
    width: 1.4rem;
    height: 1.4rem;
    border: 2px solid var(--color-border);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

.item-card-loading {
    align-items: center;
    justify-content: center;
    min-height: 8rem;
}

label.btn.is-disabled {
    opacity: 0.6;
    cursor: not-allowed;
    pointer-events: none;
}

.palette-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-top: 0.75rem;
}

.palette-swatch {
    position: relative;
    width: 3.75rem;
    height: 3.75rem;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    box-shadow: var(--shadow-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.62rem;
    font-weight: 700;
    font-family: var(--font-body);
    line-height: 1.1;
    padding: 0;
}

.palette-swatch.is-selected {
    border-color: var(--color-text);
    box-shadow: 0 0 0 3px rgba(var(--color-white-rgb), 0.9), 0 0 0 5px var(--color-text);
}

.palette-swatch.is-primary {
    box-shadow: 0 0 0 3px rgba(var(--color-white-rgb), 0.9), 0 0 0 5px var(--color-primary);
}

.palette-swatch.is-secondary {
    box-shadow: 0 0 0 3px rgba(var(--color-white-rgb), 0.9), 0 0 0 5px var(--color-accent);
}

.palette-swatch-badge {
    position: absolute;
    top: -0.3rem;
    right: -0.3rem;
    width: 1.3rem;
    height: 1.3rem;
    border-radius: 50%;
    background: var(--color-text);
    color: var(--color-white);
    font-size: 0.65rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--shadow-soft);
}

.add-palette-color-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-top: 1rem;
}

@media (max-width: 640px) {
    .logo-picker {
        flex-direction: column;
        align-items: center;
        text-align: center;
    }
}

/* ---------- Flexible layout editor (Sobre / Contato block system) ---------- */
.layout-preset-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 1.25rem;
    margin-bottom: 1.5rem;
}

.layout-preset-bar {
    padding: 1rem 1.15rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-alt);
}

.layout-preset-bar label {
    font-weight: 600;
    display: block;
    margin-bottom: 0.4rem;
}

/* Menu superior do site: a sibling of .layout-preset-grid instead of a grid
   item inside it — its visibility/grouping UI (seção 3.4) needs the whole
   row's width to lay out its columns reasonably, which it never had while
   squeezed into the same 240px-ish grid track as Estilo de layout/Animação
   padrão. */
.layout-preset-bar-full {
    margin-bottom: 1.5rem;
}

.layout-preset-bar .field-hint {
    margin-top: 0.5rem;
    margin-bottom: 0;
}

.layout-preset-bar-label-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.4rem;
}

.layout-preset-bar-label-row label {
    margin-bottom: 0;
}

.layout-block-card {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 1rem;
    margin-bottom: 1rem;
    background: var(--color-bg-alt);
}

.layout-block-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

.layout-block-title-group {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.layout-block-drag-handle {
    cursor: grab;
    color: var(--color-text-muted);
    font-size: 1.1rem;
    padding: 0.2rem 0.3rem;
    user-select: none;
    line-height: 1;
}

.layout-block-drag-handle:active {
    cursor: grabbing;
}

.layout-block-card.is-dragging {
    opacity: 0.5;
}

.layout-block-title {
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 0.95rem;
}

.layout-block-actions {
    display: flex;
    gap: 0.4rem;
}

.layout-block-actions button {
    width: 1.8rem;
    height: 1.8rem;
    border-radius: 50%;
    border: 1px solid var(--color-border);
    background: var(--color-white);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.85rem;
    line-height: 1;
}

.layout-block-actions button:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

.layout-block-actions button.item-card-remove {
    position: static;
}

.block-inline-checkbox {
    display: block;
    margin-top: 0.6rem;
    font-size: 0.88rem;
    color: var(--color-text-muted);
}

.block-style-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
    margin-top: 1rem;
    padding-top: 1rem;
    border-top: 1px dashed var(--color-border);
}

.block-style-group {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.block-style-label {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.block-style-options {
    display: flex;
    gap: 0.4rem;
}

.block-style-options button {
    padding: 0.4rem 0.75rem;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-white);
    font-size: 0.82rem;
    cursor: pointer;
}

.block-style-options button.is-active {
    background: var(--gradient-brand);
    border-color: transparent;
    color: var(--color-white);
}

.block-color-options {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.block-color-option {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.65rem;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-white);
    font-size: 0.8rem;
    cursor: pointer;
}

.block-color-option.is-active {
    border-color: var(--color-primary);
    background: rgba(var(--color-primary-rgb), 0.08);
    font-weight: 600;
}

.block-color-swatch {
    width: 1.1rem;
    height: 1.1rem;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.15);
    flex-shrink: 0;
}

.block-color-variants {
    display: flex;
    gap: 0.3rem;
    margin-left: 0.25rem;
}

.block-color-variant {
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.15);
    cursor: pointer;
    padding: 0;
}

.block-color-variant.is-active {
    box-shadow: 0 0 0 2px var(--color-white), 0 0 0 4px var(--color-primary);
}

.richtext-toolbar {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-bottom: 0.4rem;
    flex-wrap: wrap;
}

.richtext-toolbar button {
    width: 2rem;
    height: 2rem;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-white);
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1;
}

.richtext-toolbar button:hover {
    background: rgba(var(--color-primary-rgb), 0.08);
}

.richtext-toolbar select {
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-white);
    font-size: 0.8rem;
    padding: 0.3rem 0.4rem;
}

.richtext-editable {
    min-height: 2.6rem;
    cursor: text;
}

.layout-bg-picker {
    padding: 0.9rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-white);
}

.nav-settings-editor {
    margin-top: 0.75rem;
    padding: 0.9rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-white);
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
}

.nav-settings-preview {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.6rem 0.9rem;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    font-size: 0.8rem;
    font-weight: 600;
    transition: background-color 0.2s var(--ease), color 0.2s var(--ease);
}

.nav-settings-preview-brand {
    opacity: 0.7;
    font-style: italic;
}

.nav-group-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.nav-group-row .form-control {
    flex: 1;
}

.nav-layout-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(9rem, auto) minmax(9rem, auto);
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--color-border);
}

.nav-layout-row:last-child {
    border-bottom: none;
}

.nav-layout-row-label {
    font-weight: 600;
    font-size: 0.88rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.layout-bg-type-options {
    display: flex;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
}

.layout-bg-type-options button {
    padding: 0.4rem 0.75rem;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-white);
    font-size: 0.82rem;
    cursor: pointer;
}

.layout-bg-type-options button.is-active {
    background: var(--gradient-brand);
    border-color: transparent;
    color: var(--color-white);
}

.layout-bg-fields {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    margin-bottom: 0.75rem;
}

.layout-bg-field {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.82rem;
    color: var(--color-text-muted);
}

.layout-bg-angle-field {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.3rem;
}

.layout-bg-angle-field input[type="range"] {
    width: 10rem;
}

.layout-bg-preview {
    height: 3.5rem;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
}

/* Typed as a percentage so the two custom properties the interactive
   background's glow position rides on (site.js sets them on mousemove) can
   actually be transitioned — animating a raw, untyped custom property is a
   no-op in CSS. Without this, the glow snaps straight to the cursor on every
   pixel of movement, which is exactly what read as "raw" (see the buttons
   below picking it up via the shared .layout-bg-preview/.layout-preview-surface
   transition instead). */
@property --mx {
    syntax: '<percentage>';
    inherits: true;
    initial-value: 50%;
}

@property --my {
    syntax: '<percentage>';
    inherits: true;
    initial-value: 50%;
}

.layout-bg-preview,
.layout-preview-surface {
    transition: background-color 0.3s var(--ease), --mx 0.5s var(--ease), --my 0.5s var(--ease);
}

.layout-bg-quick-picks {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

.layout-bg-quick-pick {
    width: 1.15rem;
    height: 1.15rem;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.15);
    cursor: pointer;
    padding: 0;
}

.block-contrast-warning {
    margin-top: 0.75rem;
    padding: 0.6rem 0.85rem;
    border-radius: var(--radius-md);
    background: rgba(var(--color-danger-rgb), 0.1);
    color: var(--color-danger);
    font-size: 0.82rem;
    font-weight: 600;
}

.add-block-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
    margin-top: 1.5rem;
}

.add-block-row .form-select {
    max-width: 260px;
}

.layout-preview-surface {
    padding: 1rem;
    border-radius: var(--radius-md);
}

/* ---------- Animation demo replays ----------
   These play once whenever the element they're on is (re)created — the
   Blazor components pair each of these classes with an @key tied to the
   chosen RevealAnimation, so picking a different animation forces Blazor to
   recreate the node and the browser to replay the @keyframes from scratch.
   On the real published site these would instead be scroll-triggered (like
   the marketing site's own [data-reveal] in site.js); here, since the
   preview box is too small to scroll within, playing once on selection is
   what actually lets the user see what they picked. */
@keyframes reveal-demo-fade-up {
    from { opacity: 0; transform: translateY(24px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes reveal-demo-fade-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes reveal-demo-slide-left {
    from { opacity: 0; transform: translateX(40px); }
    to { opacity: 1; transform: translateX(0); }
}

@keyframes reveal-demo-slide-right {
    from { opacity: 0; transform: translateX(-40px); }
    to { opacity: 1; transform: translateX(0); }
}

@keyframes reveal-demo-zoom-in {
    from { opacity: 0; transform: scale(0.85); }
    to { opacity: 1; transform: scale(1); }
}

.reveal-demo-fade-up { animation: reveal-demo-fade-up 0.6s var(--ease); }
.reveal-demo-fade-in { animation: reveal-demo-fade-in 0.6s var(--ease); }
.reveal-demo-slide-left { animation: reveal-demo-slide-left 0.6s var(--ease); }
.reveal-demo-slide-right { animation: reveal-demo-slide-right 0.6s var(--ease); }
.reveal-demo-zoom-in { animation: reveal-demo-zoom-in 0.6s var(--ease); }

@media (prefers-reduced-motion: reduce) {
    .reveal-demo-fade-up,
    .reveal-demo-fade-in,
    .reveal-demo-slide-left,
    .reveal-demo-slide-right,
    .reveal-demo-zoom-in {
        animation: none;
    }
}
