/* ============================================
   Graphynia — Common Layout Classes
   ============================================ */

/* Page background follows the theme even when overscrolling */
body {
    background-color: var(--gn-body-bg);
}

/* Topbar */
.topbar {
    height: 56px;
    background-color: var(--gn-topbar-bg);
    color: var(--gn-topbar-color);
    border-bottom: 1px solid var(--gn-topbar-border);
    z-index: 1040;
}

.topbar .btn-link {
    text-decoration: none;
    color: var(--gn-topbar-color);
}

.topbar .navbar-brand {
    color: var(--gn-topbar-color);
    margin-right: 0;
}

.topbar-brand {
    font-size: 36px;
}

/* Very narrow screens: shrink the brand so the All Tools chip keeps slack */
@media (max-width: 400px) {
    .topbar-brand {
        font-size: 28px;
    }
}

/* "All Tools" button on the right side of the topbar */
.topbar-tools {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0.875rem;
    background-color: var(--gn-card-bg);
    border: 1px solid var(--gn-card-border);
    border-radius: 0.5rem;
    color: var(--gn-body-color);
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
    transition: border-color 0.15s;
}

.topbar-tools .bi {
    color: var(--gn-accent);
    line-height: 1;
}

.topbar-tools:hover {
    border-color: var(--gn-accent);
    color: var(--gn-body-color);
}

/* Category headings on the All Tools page */
.all-tools-section {
    color: var(--gn-body-color);
    text-decoration: none;
}

.all-tools-section:hover {
    color: var(--gn-accent);
}

.all-tools-section .bi,
.all-tools-section [class^="icon-"] {
    color: var(--gn-accent);
    margin-right: 0.25rem;
}

.denk-one-regular {
    font-family: "Denk One", sans-serif;
    font-weight: 400;
    font-style: normal;
}

/* Desktop sidebar (left icon rail) */
.sidebar {
    position: fixed;
    top: 56px;
    left: 0;
    bottom: 0;
    width: 75px;
    background-color: var(--gn-sidebar-bg);
    border-right: 1px solid var(--gn-topbar-border);
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    padding-top: 1rem;
    z-index: 1030;
}

.sidebar-footer {
    padding-bottom: 1rem;
}

/* The theme toggle is a <button>; strip the native chrome so it matches
   the surrounding nav links */
.theme-toggle {
    background: none;
    border: 0;
    text-align: left;
    width: 100%;
}

/* Skip link: visually hidden until keyboard-focused, then floats above
   the fixed topbar */
.skip-link {
    position: fixed;
    top: 0.5rem;
    left: 0.5rem;
    z-index: 2000;
    padding: 0.5rem 1rem;
    background-color: var(--gn-accent);
    color: #fff;
    border-radius: 0.375rem;
    text-decoration: none;
    font-weight: 600;
}

.sidebar-footer .theme-toggle {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 60px;
    padding: 0.5rem 0;
    border-radius: 0.5rem;
    color: var(--gn-sidebar-color);
    font-size: 1.2rem;
    text-decoration: none;
    transition: color 0.15s;
}

.sidebar-footer .theme-toggle:hover {
    background-color: var(--gn-sidebar-hover-bg);
}

.sidebar-footer .theme-toggle:hover span[class^="icon-"],
.sidebar-footer .theme-toggle:hover .bi {
    color: var(--gn-sidebar-hover-color);
}

.sidebar-nav .nav-link {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 60px;
    padding: 0.5rem 0;
    margin-bottom: 0.75rem;
    border-radius: 0.5rem;
    color: var(--gn-sidebar-color);
    font-size: 1.2rem;
    text-decoration: none;
    transition: color 0.15s;
}

.sidebar-label {
    font-size: 12px;
    font-weight: 600;
    margin-top: 6px;
    line-height: 1;
}

.sidebar-nav .nav-link:hover {
    background-color: var(--gn-sidebar-hover-bg);
}

.sidebar-nav .nav-link:hover span[class^="icon-"],
.sidebar-nav .nav-link:hover .bi {
    color: var(--gn-sidebar-hover-color);
}

.sidebar-nav .nav-link:hover .sidebar-label {
    color: var(--gn-sidebar-color);
}

.sidebar-nav .nav-link.active span[class^="icon-"],
.sidebar-nav .nav-link.active .bi {
    color: var(--gn-sidebar-active-color);
}

/* Main content area (flex column so the footer sticks to the bottom on short pages) */
.main-content {
    display: flex;
    flex-direction: column;
    padding-top: calc(56px + 1.5rem);
    padding-bottom: 1.5rem;
    padding-left: 1rem;
    padding-right: 1rem;
    background-color: var(--gn-body-bg);
    color: var(--gn-body-color);
    min-height: 100vh;
}

/* On desktop: make room for the left sidebar */
@media (min-width: 992px) {
    .main-content {
        margin-left: 75px;
    }
}

/* Offcanvas theming */
.offcanvas {
    background-color: var(--gn-sidebar-bg);
    color: var(--gn-sidebar-color);
}

.offcanvas .nav-link {
    color: var(--gn-sidebar-color);
    padding: 0.75rem 1rem;
    border-radius: 0.5rem;
    transition: background-color 0.15s, color 0.15s;
}

.offcanvas .nav-link:hover {
    background-color: var(--gn-sidebar-hover-bg);
    color: var(--gn-sidebar-hover-color);
}

.offcanvas .nav-link span[class^="icon-"],
.offcanvas .nav-link .bi {
    margin-right: 0.5rem;
    font-size: 1.1rem;
}

.offcanvas .nav-link.active {
    color: var(--gn-sidebar-active-color);
}

/* Bootstrap Icons inherit the body line-height on the element (unlike Icomoon,
   which sets line-height: 1 itself) - normalize so icon spacing stays tight */
.sidebar .bi,
.offcanvas .nav-link .bi,
.gn-card-icon {
    line-height: 1;
}

/* Content cards */
.gn-card {
    background-color: var(--gn-card-bg);
    border: 1px solid var(--gn-card-border);
    color: var(--gn-body-color);
    transition: border-color 0.15s, transform 0.15s;
}

a.gn-card:hover {
    border-color: var(--gn-card-hover-border);
    color: var(--gn-body-color);
    transform: translateY(-2px);
}

.gn-card-icon {
    font-size: 2rem;
    color: var(--gn-accent);
}

.gn-muted {
    color: var(--gn-muted);
}

/* ---------------------------------------------------------------------
   Front page
   Hero, selling points, two tiers of tool cards and the category row.
   Everything here is driven by the page registry (see core/pages/home.php),
   so these classes describe shape only - never a particular tool.
   --------------------------------------------------------------------- */

.home-hero {
    display: grid;
    gap: 2rem;
    align-items: center;
    margin-bottom: 2rem;
}

@media (min-width: 992px) {
    .home-hero {
        grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
        gap: 3rem;
    }
}

.home-hero-title {
    /* Scales with the viewport so the two lines never break awkwardly */
    font-size: clamp(2.25rem, 1.2rem + 3vw, 3.5rem);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    margin-bottom: 1rem;
}

/* Kicker above the headline, inside the h1 - same typographic recipe as
   the footer's ecosystem heading, in the accent color */
.home-hero-eyebrow {
    display: block;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--gn-accent);
    margin-bottom: 0.75rem;
}

.home-hero-accent {
    color: var(--gn-accent);
}

.home-hero-lead {
    color: var(--gn-muted);
    font-size: 1.05rem;
    max-width: 34rem;
    margin-bottom: 1.5rem;
}

.home-hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

/* The framed preview beside the hero text. Below lg the text stands alone:
   a decorative frame is the first thing worth dropping on a phone. */
.home-hero-visual {
    display: none;
}

@media (min-width: 992px) {
    .home-hero-visual {
        display: block;
    }
}

.home-hero-frame {
    /* Capped so the frame stays a companion to the headline rather than
       the tallest thing on the page */
    max-width: 620px;
    margin-left: auto;
    border: 1px solid var(--gn-card-border);
    border-radius: 0.75rem;
    background-color: var(--gn-card-bg);
    overflow: hidden;
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.08);
}

[data-bs-theme="dark"] .home-hero-frame {
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.4);
}

.home-hero-bar {
    display: flex;
    gap: 0.4rem;
    padding: 0.6rem 0.8rem;
    border-bottom: 1px solid var(--gn-card-border);
}

.home-hero-bar span {
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    background-color: var(--gn-card-border);
}

.home-hero-canvas {
    display: block;
    width: 100%;
    height: auto;
}

/* Selling-point strip: one bordered band, divided into four claims */
.usp-strip {
    display: grid;
    grid-template-columns: 1fr;
    margin: 0 0 2rem;
    padding: 0;
    list-style: none;
    border: 1px solid var(--gn-card-border);
    border-radius: 0.75rem;
    background-color: var(--gn-card-bg);
    overflow: hidden;
}

@media (min-width: 576px) {
    .usp-strip {
        grid-template-columns: 1fr 1fr;
    }
}

@media (min-width: 992px) {
    .usp-strip {
        grid-template-columns: repeat(4, 1fr);
    }
}

.usp-strip li {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem 1.25rem;
    border-top: 1px solid var(--gn-card-border);
}

.usp-strip li:first-child {
    border-top: 0;
}

/* On the multi-column layouts the dividers turn vertical, so the row
   reads as one band instead of a stack of boxes */
@media (min-width: 576px) {
    .usp-strip li:nth-child(-n + 2) {
        border-top: 0;
    }

    .usp-strip li:nth-child(2n) {
        border-left: 1px solid var(--gn-card-border);
    }
}

@media (min-width: 992px) {
    .usp-strip li {
        border-top: 0;
        border-left: 1px solid var(--gn-card-border);
    }

    .usp-strip li:first-child {
        border-left: 0;
    }
}

.usp-icon {
    flex: 0 0 auto;
    font-size: 1.35rem;
    color: var(--gn-accent);
}

.usp-text {
    display: flex;
    flex-direction: column;
    font-size: 0.85rem;
    color: var(--gn-muted);
    line-height: 1.35;
}

.usp-text strong {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--gn-body-color);
}

.home-heading {
    font-size: 1.15rem;
    font-weight: 600;
    margin: 2rem 0 1rem;
}

/* Featured tools: a preview panel above the text. Stage 2 replaces the
   icon in .home-feature-preview with art the tools render themselves,
   which is why the panel has a fixed aspect ratio already. */
/* The preview panel sits flush against the card's top edge, and an image
   has square corners. Without clipping, those corners are drawn outside the
   card's rounded border and the top of every card looks both square and
   round at once. Clipping to the card beats rounding the panel to match:
   no second radius to keep in sync with Bootstrap's, and no hairline where
   the two disagree by a fraction of a pixel. */
.home-feature {
    overflow: hidden;
}

.home-feature .card-body {
    display: flex;
    flex-direction: column;
}

.home-feature-preview {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 16 / 9;
    border-bottom: 1px solid var(--gn-card-border);
}

.home-feature-preview > span {
    font-size: 3rem;
}

.home-feature-preview img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Without a preview image the panel falls back to the tool's icon on an
   accent wash - the same four-color cycle the tool page highlights use,
   so a tool waiting for its render still looks like it belongs */
.row > div:nth-child(3n + 1) .home-feature-preview:not(.has-image) {
    background-color: rgba(59, 130, 246, 0.12);
    color: #3b82f6;
}

.row > div:nth-child(3n + 2) .home-feature-preview:not(.has-image) {
    background-color: rgba(139, 92, 246, 0.12);
    color: #8b5cf6;
}

.row > div:nth-child(3n) .home-feature-preview:not(.has-image) {
    background-color: rgba(16, 185, 129, 0.12);
    color: #10a56a;
}

.home-feature-cta {
    margin-top: auto;
    padding-top: 0.5rem;
    color: var(--gn-accent);
    font-weight: 500;
    font-size: 0.9rem;
}

.home-feature-cta .bi {
    transition: transform 0.15s ease;
    display: inline-block;
}

.home-feature:hover .home-feature-cta .bi {
    transform: translateX(3px);
}

/* The remaining tools: a compact row, icon left and chevron right */
.home-row-text {
    display: block;
    min-width: 0;
}

.home-row-text .card-text {
    display: block;
}

.home-row-chevron {
    flex: 0 0 auto;
    margin-left: auto;
    color: var(--gn-muted);
    transition: transform 0.15s ease;
}

.home-row:hover .home-row-chevron {
    transform: translateX(3px);
    color: var(--gn-accent);
}

/* Category row: one chip per category, wrapping as the width allows */
.home-categories {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.home-category {
    flex: 1 1 9rem;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 1rem 0.75rem;
    border: 1px solid var(--gn-card-border);
    border-radius: 0.75rem;
    background-color: var(--gn-card-bg);
    color: var(--gn-body-color);
    text-decoration: none;
    transition: border-color 0.15s ease, transform 0.15s ease;
}

.home-category:hover {
    border-color: var(--gn-card-hover-border);
    color: var(--gn-body-color);
    transform: translateY(-2px);
}

.home-category-icon {
    font-size: 1.2rem;
    color: var(--gn-accent);
}

.home-category-label {
    font-weight: 500;
}

/* Badge on category cards that have no tools yet */
.coming-soon-badge {
    display: inline-block;
    margin-left: 0.4rem;
    padding: 0.1rem 0.5rem;
    background-color: var(--gn-sidebar-hover-bg);
    color: var(--gn-muted);
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    border-radius: 999px;
    vertical-align: middle;
}

/* Page headings */
.page-title {
    font-size: 1.75rem;
    margin-bottom: 0.25rem;
}

.page-intro {
    color: var(--gn-muted);
    margin-bottom: 1.5rem;
}

/* Breadcrumb on tool pages */
.gn-breadcrumb {
    font-size: 0.875rem;
    color: var(--gn-muted);
    margin-bottom: 0.75rem;
}

.gn-breadcrumb a {
    color: var(--gn-accent);
    text-decoration: none;
}

.gn-breadcrumb a:hover {
    text-decoration: underline;
}

/* Centered content on wide screens (browse mode) */
.page-container {
    max-width: 1320px;
}

/* Site footer (inside <main>, pushed to the bottom by margin-top: auto) */
.site-footer {
    margin-top: auto;
    padding-top: 2.5rem;
}

/* Ecosystem strip: the Injosoft sister sites, shown above the footer line */
.ecosystem {
    margin-bottom: 1.5rem;
}

.ecosystem-heading {
    display: flex;
    align-items: center;
    gap: 1rem;
    color: var(--gn-muted);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.25em;
    text-transform: uppercase;
    white-space: nowrap;
}

.ecosystem-heading::before,
.ecosystem-heading::after {
    content: '';
    flex: 1;
    border-top: 1px solid var(--gn-card-border);
}

.ecosystem-sites {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    padding: 1.25rem 0 0.9rem;
}

.ecosystem-card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.2rem;
    width: 215px;
    padding: 1rem 0.75rem;
    background-color: var(--gn-card-bg);
    border: 1px solid transparent;
    border-radius: 0.75rem;
    text-decoration: none;
    transition: transform 0.15s, border-color 0.15s;
}

/* The generic footer link hover underlines; the cards must stay clean */
.site-footer a.ecosystem-card,
.site-footer a.ecosystem-card:hover {
    text-decoration: none;
}

a.ecosystem-card:hover {
    transform: translateY(-2px);
}

.ecosystem-name {
    font-weight: 700;
    font-size: 1.125rem;
    color: var(--gn-body-color);
}

.ecosystem-tag {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.ecosystem-binaryia { border-color: rgba(124, 58, 237, 0.45); }
.ecosystem-binaryia .ecosystem-tag { color: #7c3aed; }
a.ecosystem-binaryia:hover { border-color: #7c3aed; }

.ecosystem-graphynia {
    border: 2px solid #3d8bfd;
    box-shadow: 0 0 12px rgba(61, 139, 253, 0.35);
}
.ecosystem-graphynia .ecosystem-tag { color: #3d8bfd; }

.ecosystem-textynia { border-color: rgba(139, 92, 246, 0.45); }
.ecosystem-textynia .ecosystem-tag { color: #8b5cf6; }
a.ecosystem-textynia:hover { border-color: #8b5cf6; }

.ecosystem-arcynia { border-color: rgba(225, 29, 112, 0.45); }
.ecosystem-arcynia .ecosystem-tag { color: #e11d70; }
a.ecosystem-arcynia:hover { border-color: #e11d70; }

.ecosystem-badge {
    position: absolute;
    bottom: -0.7rem;
    left: 50%;
    transform: translateX(-50%);
    padding: 0.15rem 0.6rem;
    background-color: #3d8bfd;
    color: #fff;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    border-radius: 999px;
    white-space: nowrap;
}

.site-footer-inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem 1.5rem;
    border-top: 1px solid var(--gn-card-border);
    padding-top: 1rem;
    font-size: 0.875rem;
    color: var(--gn-muted);
}

.site-footer a {
    color: var(--gn-muted);
    text-decoration: none;
}

.site-footer a:hover {
    color: var(--gn-accent);
    text-decoration: underline;
}

.site-footer-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1.5rem;
}

/* WCAG 2.2 wants a 24px minimum target. Links inside a sentence are exempt,
   but these are a navigation list rather than prose, so the exemption does
   not obviously cover them - and two pixels of padding is cheaper than the
   argument. Text position is unchanged; only the hit area grows. */
.site-footer-nav a {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
}

/* The running app covers the workspace; the footer would only add scroll */
body.app-active .site-footer {
    display: none;
}

/* Static content pages (about, policies) and the front page's prose.
   Centered in the workspace rather than hugging the left edge - which is
   why the heading and intro live inside this wrapper on those pages, not
   above it: a full-width h1 over a centered column reads as a mistake. */
.page-content {
    max-width: 800px;
    margin-left: auto;
    margin-right: auto;
}

.page-content h2 {
    font-size: 1.25rem;
    margin-top: 2rem;
    margin-bottom: 0.5rem;
}

.page-content h3 {
    font-size: 1.05rem;
    margin-top: 1.5rem;
    margin-bottom: 0.5rem;
}

/* Both wrappers, as with the code blocks and FAQ blocks. Without the second
   selector the prose links on tool pages fall back to Bootstrap's own link
   blue, which is the one shade that does not clear 4.5:1 on the page
   background - so the pages with the most prose were the ones missing it. */
.page-content a,
.tool-content a {
    color: var(--gn-accent);
}

/* Multi-line list items need air between them, or a list of explanations
   reads as one paragraph that happens to have bullets in it. Both wrappers,
   as with the code blocks below. The step cards opt out further down: they
   are a grid and space themselves with gap. */
.page-content li,
.tool-content li {
    margin-bottom: 0.5rem;
}

/* Code blocks in page content. Used by the CSS Shape Generator's shape
   pages, where the rule being explained is the whole point of the page,
   so it gets to look like something you would copy. Both wrappers, because
   plain pages use .page-content and tool pages use .tool-content. */
.page-content pre,
.tool-content pre:not(.csg-code) {
    padding: 0.85rem 1rem;
    margin: 1rem 0;
    overflow-x: auto;
    border: 1px solid var(--gn-card-border);
    border-radius: 0.5rem;
    background-color: var(--gn-card-bg);
    font-size: 0.82rem;
    line-height: 1.55;
}

/* Bootstrap tints inline <code>; inside a block it would fight the rule */
.page-content pre code,
.tool-content pre code {
    padding: 0;
    background: none;
    color: inherit;
}

.content-updated {
    color: var(--gn-muted);
    font-style: italic;
}

/* Highlighted note box (policy cross-references, key summaries) */
.content-note {
    background-color: var(--gn-card-bg);
    border: 1px solid var(--gn-card-border);
    border-radius: 0.5rem;
    padding: 1rem 1.25rem;
    margin: 1.25rem 0;
}

.content-note > :last-child {
    margin-bottom: 0;
}

/* The start card of a fullscreen tool. A tool that takes a file can declare
   'start' in the page registry and make this card the input step itself:
   its own heading, and a drop target that opens the app with the file
   (see tool.php and script/app-loader.js). */
.app-start-droppable {
    border-style: dashed;
    transition: border-color 0.15s, background-color 0.15s;
}

.app-start-dropping {
    border-color: var(--gn-accent);
    background-color: var(--gn-sidebar-hover-bg);
}

/* The app panel (window chrome around fullscreen apps) is hidden until started */
.app-panel {
    display: none;
}

/* App mode: the workspace takes the full area below the topbar.
   The topbar and the sidebar rail stay visible; the app sits in a framed panel. */
body.app-active .main-content {
    padding: 56px 0 0 0;
    height: 100vh;
    overflow: hidden;
}

body.app-active .main-content > .page-container {
    max-width: none;
    padding: 1rem;
    height: calc(100vh - 56px);
}

body.app-active .app-intro {
    display: none;
}

body.app-active .app-panel {
    display: flex;
    flex-direction: column;
    height: 100%;
    background-color: var(--gn-card-bg);
    border: 1px solid var(--gn-card-border);
    border-radius: 0.5rem;
    overflow: hidden;
}

@media (max-width: 575px) {
    body.app-active .main-content > .page-container {
        padding: 0.5rem;
    }
}

/* App panel header: app name left, fullscreen + close right */
.app-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.5rem 1rem;
    border-bottom: 1px solid var(--gn-card-border);
    -webkit-user-select: none;
    user-select: none;
}

.app-panel-title {
    font-weight: 600;
}

.app-panel-actions {
    display: flex;
    gap: 0.25rem;
}

.app-panel .btn-app {
    background: none;
    border: 0;
    color: var(--gn-muted);
    padding: 0.25rem 0.5rem;
    border-radius: 0.375rem;
    line-height: 1;
    font-size: 1rem;
}

.app-panel .btn-app:hover {
    color: var(--gn-body-color);
    background-color: var(--gn-sidebar-hover-bg);
}

/* Brand button opens the menu; only shown when topbar + rail are covered
   (maximized or browser fullscreen). Styled like the favicon: fixed brand
   colors so it looks the same in both themes. */
.app-panel .app-panel-brand {
    display: none;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    background-color: #16213e;
    color: #6ea8fe;
    border-radius: 0.375rem;
    font-size: 1.125rem;
}

body.app-maximized .app-panel-brand,
body.app-active .app-panel:fullscreen .app-panel-brand {
    display: inline-flex;
}

.app-panel .app-panel-brand:hover {
    background-color: #223462;
    color: #8bb9fe;
}

/* The offcanvas menu must layer above the maximized panel (z-index 1050) */
body.app-maximized .offcanvas {
    z-index: 1060;
}

body.app-maximized .offcanvas-backdrop {
    z-index: 1055;
}

.app-panel #app-root {
    flex: 1 1 auto;
    min-height: 0;
}

/* Maximized covers the whole browser viewport (above topbar + rail);
   browser fullscreen shares the same frameless look */
body.app-maximized .app-panel,
body.app-active .app-panel:fullscreen {
    position: fixed;
    inset: 0;
    z-index: 1050;
    height: auto;
    border: 0;
    border-radius: 0;
}

/* Toolbar inside fullscreen apps */
.app-toolbar {
    background-color: var(--gn-card-bg);
    border-bottom: 1px solid var(--gn-card-border);
}

/* Range sliders (site-wide): vertical swipes over a slider scroll the page
   instead of changing the value - only horizontal drags adjust it. Without
   this, scrolling a controls panel on touch screens constantly nudges
   whatever slider the thumb lands on. */
.form-range {
    touch-action: pan-y;
}

/* Selects: no focus ring at all, site-wide (per design preference; the
   dropdown itself makes focus obvious). Keyboard focus on range sliders
   keeps a clear accent outline (WCAG 2.4.7). */
.form-select:focus,
.form-select:focus-visible {
    border-color: var(--bs-border-color);
    box-shadow: none;
    outline: none;
}

.form-range:focus-visible {
    outline: 2px solid var(--gn-accent);
    outline-offset: 2px;
}

/* Range sliders: no focus ring around the thumb (site-wide) - the live
   value next to the label is feedback enough. Separate rules per engine:
   an unknown pseudo-element would invalidate a combined selector. */
.form-range:focus::-webkit-slider-thumb {
    box-shadow: none;
}

.form-range:focus::-moz-range-thumb {
    box-shadow: none;
}

/* Reusable side-panel layout for app control panels: a fixed header and
   footer with a scrollable body between them. An app adds these classes to
   its own panel element (plus its own class for width/placement):
       <aside class="my-panel app-side-panel">
           <div class="app-side-header">always visible (e.g. main pickers)</div>
           <div class="app-side-body">scrolling controls</div>
           <div class="app-side-footer">always visible (e.g. action buttons)</div>
       </aside> */
.app-side-panel {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.app-side-header {
    flex: 0 0 auto;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--gn-card-border);
}

.app-side-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 1rem;
}

.app-side-footer {
    flex: 0 0 auto;
    padding: 0.75rem 1rem;
    border-top: 1px solid var(--gn-card-border);
}

/* ---------------------------------------------------------------------
   Studio chrome (apps/_lib/studio.js): the furniture every generator app
   shares - a preview stage with a letterboxing aspect menu, round fab
   buttons, and a save dialog that never changes height. Wave, Pattern,
   Mandala, Blob and Swirl Maker still carry their own copies of this and
   can migrate one at a time.
   --------------------------------------------------------------------- */

/* Workspace: stage left, control panel right */
.gn-studio {
    position: relative;
    display: flex;
    height: 100%;
    overflow: hidden;
}

.gn-studio-stage {
    position: relative;
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    background-color: var(--gn-card-bg);
}

.gn-studio-frame {
    position: relative;
    width: 100%;
    height: 100%;
}

/* Drag-to-rotate is on (see the `rotate` option of createStudioStage) */
.gn-studio-turnable {
    cursor: grab;
}

.gn-studio-turnable.gn-studio-turning {
    cursor: grabbing;
}

/* Letterboxed to an aspect ratio: lift it off the stage so the shape of
   the target surface is obvious */
.gn-studio-frame-boxed {
    border: 1px solid var(--gn-card-border);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
}

/* Pixel-size chip, shown only in exact-size preview */
.gn-studio-size {
    position: absolute;
    left: 50%;
    bottom: 0.5rem;
    transform: translateX(-50%);
    padding: 0.125rem 0.5rem;
    border-radius: 1rem;
    background-color: rgba(0, 0, 0, 0.65);
    color: #fff;
    font-size: 0.7rem;
    white-space: nowrap;
    pointer-events: none;
}

/* Transparent mode: the classic checkerboard */
.gn-studio-transparent {
    background-color: #fff;
    background-image: repeating-conic-gradient(#dfdfdf 0% 25%, #ffffff 0% 50%);
    background-size: 20px 20px;
}

.gn-studio-panel {
    flex: 0 0 300px;
    border-left: 1px solid var(--gn-card-border);
}

.gn-studio-label {
    display: block;
    font-size: 0.8rem;
    color: var(--gn-muted);
    margin-top: 0.5rem;
    margin-bottom: 0;
}

/* Live value beside a slider label */
.gn-studio-val {
    float: right;
    color: var(--gn-accent);
    font-size: 0.75rem;
}

.gn-studio-sep {
    margin: 0.75rem 0;
    border-color: var(--gn-card-border);
    opacity: 1;
}

/* Tuck a slider up against its label + value row */
.gn-studio .form-range {
    margin-top: -2px;
}

/* Floating round buttons on the stage */
.gn-studio-fabs {
    position: absolute;
    right: 1rem;
    bottom: 1rem;
    z-index: 5;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.5rem;
}

/* The aspect fab sits top-right; capping the wrap to the stage means its
   menu can never overflow - the list scrolls and the toggle stays put */
.gn-studio-fabs-top {
    top: 1rem;
    bottom: auto;
    max-height: calc(100% - 2rem);
}

.gn-studio-fab {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.2);
    background-color: #fff;
    color: #2b2d42;
    font-size: 1.125rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
    transition: transform 0.1s, border-color 0.15s, color 0.15s;
}

.gn-studio-fab:hover {
    border-color: var(--gn-accent);
    color: var(--gn-accent);
}

.gn-studio-fab:active {
    transform: scale(0.95);
}

.gn-studio-menu {
    display: flex;
    flex-direction: column;
    min-width: 170px;
    min-height: 0;
    padding: 0.25rem;
    background-color: var(--gn-card-bg);
    border: 1px solid var(--gn-card-border);
    border-radius: 0.5rem;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}

.gn-studio-menu.d-none {
    display: none;
}

.gn-studio-menu-scroll {
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow-y: auto;
}

.gn-studio-menu button {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 0.75rem;
    background: none;
    border: 0;
    border-radius: 0.375rem;
    color: var(--gn-body-color);
    font-size: 0.875rem;
    text-align: left;
    white-space: nowrap;
}

.gn-studio-menu button:hover {
    background-color: var(--gn-sidebar-hover-bg);
}

/* The check mark marks the selected entry only */
.gn-studio-menu button .bi {
    color: var(--gn-accent);
    visibility: hidden;
}

.gn-studio-menu button.active .bi {
    visibility: visible;
}

.gn-studio-menu button:disabled {
    color: var(--gn-muted);
    opacity: 0.55;
}

.gn-studio-menu-sep {
    margin: 0.25rem 0.5rem;
    border-color: var(--gn-card-border);
    opacity: 1;
}

/* Save dialog: a card over a dimmed backdrop, inside the app area so it
   still works when the app is in browser fullscreen */
.gn-modal {
    position: absolute;
    inset: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background-color: rgba(0, 0, 0, 0.45);
}

.gn-modal.d-none {
    display: none;
}

.gn-modal-card {
    display: flex;
    flex-direction: column;
    width: min(440px, 100%);
    max-height: 100%;
    background-color: var(--gn-card-bg);
    border: 1px solid var(--gn-card-border);
    border-radius: 0.75rem;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
}

.gn-modal-header {
    display: flex;
    align-items: center;
    padding: 0.625rem 1rem;
    border-bottom: 1px solid var(--gn-card-border);
}

.gn-modal-title {
    font-weight: 600;
}

/* On a short screen the body scrolls; header and footer stay in view */
.gn-modal-body {
    padding: 0.5rem 1rem 0.75rem;
    min-height: 0;
    overflow-y: auto;
}

.gn-modal-footer {
    display: flex;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
    border-top: 1px solid var(--gn-card-border);
}

/* A row that does not apply to the current format keeps its space, so the
   dialog never jumps; visibility also drops it from the tab order */
.gn-invisible {
    visibility: hidden;
}

/* Every note variant is stacked in one grid cell, so the container is as
   tall as the longest and the dialog holds its height */
.gn-modal-note-stack {
    display: grid;
}

.gn-modal-note-stack > .gn-modal-note {
    grid-area: 1 / 1;
}

.gn-note-sizer {
    visibility: hidden;
}

.gn-modal-note {
    font-size: 0.75rem;
    color: var(--gn-muted);
    margin: 0.625rem 0 0;
}

.gn-size-input {
    max-width: 110px;
}

.gn-size-x {
    color: var(--gn-muted);
}

/* Small screens: stack, with the preview pinned at the top so it stays
   visible while the controls below are scrolled */
@media (max-width: 767px) {
    .gn-studio {
        flex-direction: column;
        overflow-y: auto;
    }

    .gn-studio-stage {
        position: sticky;
        top: 0;
        z-index: 4;
        flex: 0 0 auto;
        height: 40vh;
    }

    .gn-studio-panel {
        flex: 0 0 auto;
        border-left: 0;
        border-top: 1px solid var(--gn-card-border);
    }

    /* The whole app scrolls instead of the panel body; the panel's header
       and footer stick to the preview and the bottom edge */
    .gn-studio-panel .app-side-body {
        overflow-y: visible;
    }

    .gn-studio-panel .app-side-header {
        position: sticky;
        top: 40vh;
        z-index: 3;
        background-color: var(--gn-card-bg);
    }

    .gn-studio-panel .app-side-footer {
        position: sticky;
        bottom: 0;
        z-index: 3;
        background-color: var(--gn-card-bg);
    }
}

/* Palette picker component (apps/_lib/components.js): the current
   palette strip and a random-palette pick joined as one group - both
   share the select's border color - plus a dropdown grid of curated
   palettes. Used by Wave Maker and Blob Maker. */
.gn-palette-group {
    display: flex;
    align-items: stretch;
}

.gn-palette-btn {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
    padding: 4px 8px;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.375rem 0 0 0.375rem;
    background: none;
    color: var(--gn-muted);
}

.gn-palette-random {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border: 1px solid var(--bs-border-color);
    border-left: 0;
    border-radius: 0 0.375rem 0.375rem 0;
    background: none;
    color: var(--gn-muted);
}

.gn-palette-btn:hover,
.gn-palette-random:hover {
    background-color: var(--gn-sidebar-hover-bg);
    color: var(--gn-accent);
}

.gn-palette-strip {
    flex: 1 1 auto;
    display: flex;
    height: 18px;
    border-radius: 9px;
    overflow: hidden;
    border: 1px solid rgba(0, 0, 0, 0.15);
}

.gn-palette-strip span {
    flex: 1 1 auto;
}

/* Popover (used with apps/_lib/components.js wirePopover): the panel
   floats over the content below its anchor instead of pushing it down;
   long lists scroll inside it. A slightly darkened border marks the edge
   - no glow/shadow. */
.gn-popover-anchor {
    position: relative;
}

.gn-popover {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 30;
    padding: 6px;
    margin-top: 4px;
    max-height: 264px;
    overflow-y: auto;
    border: 1px solid color-mix(in srgb, var(--gn-card-border) 60%, var(--gn-muted));
    border-radius: 0.5rem;
    background-color: var(--gn-card-bg);
}

/* Palette popover: the count row (2-5 colors per palette) stays pinned
   on top while the palette grid scrolls under it */
.gn-palette-pop {
    padding: 0;
}

.gn-palette-count {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 6px;
    background-color: var(--gn-card-bg);
    border-bottom: 1px solid var(--gn-card-border);
}

.gn-palette-count button {
    flex: 1 1 auto;
    padding: 2px 0;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.35rem;
    background: none;
    color: var(--gn-muted);
    font-size: 0.75rem;
    line-height: 1.4;
}

.gn-palette-count button:hover {
    background-color: var(--gn-sidebar-hover-bg);
    color: var(--gn-accent);
}

.gn-palette-count button.active {
    border-color: var(--gn-accent);
    color: var(--gn-accent);
}

.gn-palette-list {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    padding: 6px;
}

.gn-palette-list.d-none {
    display: none;
}

.gn-palette-list button {
    padding: 3px;
    border: 2px solid transparent;
    border-radius: 0.4rem;
    background: none;
}

.gn-palette-list button:hover,
.gn-palette-list button.active {
    border-color: var(--gn-accent);
}

/* Round color swatch: a 30px circular <input type="color"> (used by the
   color stops row and background picker components) */
.gn-color-swatch {
    position: relative;
    width: 30px;
    height: 30px;
    display: inline-block;
}

.gn-color-swatch input[type="color"] {
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid rgba(0, 0, 0, 0.2);
    border-radius: 50%;
    background: none;
    cursor: pointer;
    overflow: hidden;
}

.gn-color-swatch input[type="color"]::-webkit-color-swatch-wrapper {
    padding: 0;
}

.gn-color-swatch input[type="color"]::-webkit-color-swatch {
    border: none;
    border-radius: 50%;
}

.gn-color-swatch input[type="color"]::-moz-color-swatch {
    border: none;
    border-radius: 50%;
}

/* Color stops row component (apps/_lib/components.js): a row of round
   editable swatches with a remove badge each and an add button */
.gn-colors-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 0.25rem 0;
}

/* Remove badge: on hover where hover exists, always on touch screens */
.gn-swatch-del {
    position: absolute;
    top: -5px;
    right: -5px;
    width: 15px;
    height: 15px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--gn-card-border);
    background-color: var(--gn-card-bg);
    color: var(--gn-muted);
    font-size: 11px;
    line-height: 1;
    display: none;
    align-items: center;
    justify-content: center;
}

.gn-color-swatch:hover .gn-swatch-del {
    display: inline-flex;
}

@media (hover: none) {
    .gn-swatch-del {
        display: inline-flex;
    }
}

.gn-color-add {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    border: 1px dashed var(--gn-muted);
    background: none;
    color: var(--gn-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.gn-color-add:hover {
    border-color: var(--gn-accent);
    color: var(--gn-accent);
}

/* Background picker component (apps/_lib/components.js): a round color
   swatch and a round transparent (checkerboard) swatch as a two-way
   radio below the app's label; the active choice gets an accent border */
.gn-bg-options {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0.25rem 0;
}

.gn-bg-check {
    width: 30px;
    height: 30px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.2);
    background-color: #fff;
    background-image: repeating-conic-gradient(#dfdfdf 0% 25%, #ffffff 0% 50%);
    background-size: 10px 10px;
}

.gn-bg-options .gn-bg-active input[type="color"],
.gn-bg-check.gn-bg-active {
    border: 2px solid var(--gn-accent);
}

/* Some apps have content that cannot lose its background color; there the
   transparent choice is disabled and reads as unavailable */
.gn-bg-check:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* Tool pages: one focused, centered column - hero, start card,
   highlights and SEO content all share the same measure, so the page
   keeps a single width rhythm (category pages keep their wide grids) */
/* Tool pages share one centered column inside the wider page container:
   the intro, an inline app and the content below it all line up. Fullscreen
   apps are exempt - they take over the whole workspace. */
.app-intro,
#app-root[data-app-mode="inline"] {
    max-width: 980px;
    margin-left: auto;
    margin-right: auto;
}

/* Tool hero extras (registry: tagline, chips, highlights): feature pills
   under the intro and a highlights strip under the start card */
.tool-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: -0.25rem 0 1.25rem;
}

.tool-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.75rem;
    border: 1px solid var(--gn-card-border);
    border-radius: 2rem;
    background-color: var(--gn-card-bg);
    font-size: 0.85rem;
    color: var(--gn-body-color);
    white-space: nowrap;
}

.tool-chip > span {
    color: var(--gn-accent);
}

.tool-highlights {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
    margin-top: 1.5rem;
}

@media (max-width: 575px) {
    .tool-highlights {
        grid-template-columns: 1fr;
    }
}

.tool-highlight {
    display: flex;
    gap: 0.75rem;
    padding: 1rem;
    border: 1px solid var(--gn-card-border);
    border-radius: 0.75rem;
    background-color: var(--gn-card-bg);
}

.tool-highlight-icon {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    border-radius: 0.6rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.15rem;
}

/* Soft pastel icon bubbles, cycling four accents like the tool cards */
.tool-highlight:nth-child(4n + 1) .tool-highlight-icon {
    background-color: rgba(59, 130, 246, 0.15);
    color: #3b82f6;
}

.tool-highlight:nth-child(4n + 2) .tool-highlight-icon {
    background-color: rgba(139, 92, 246, 0.15);
    color: #8b5cf6;
}

.tool-highlight:nth-child(4n + 3) .tool-highlight-icon {
    background-color: rgba(16, 185, 129, 0.15);
    color: #10a56a;
}

.tool-highlight:nth-child(4n) .tool-highlight-icon {
    background-color: rgba(245, 158, 11, 0.18);
    color: #d98a00;
}

.tool-highlight-title {
    font-size: 0.95rem;
    font-weight: 600;
    margin: 0 0 0.25rem;
}

/* "How it works" step cards: an <ol class="tool-steps"> keeps the
   semantic numbered list while CSS renders it as cards - number badges
   from the list counter, dashed connectors between the steps */
.tool-steps {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
    padding: 0;
    margin: 1.25rem 0 0;
    counter-reset: tool-step;
}

.tool-steps li {
    /* Grid items: the gap already spaces them, so no list margin */
    margin-bottom: 0;
    position: relative;
    counter-increment: tool-step;
    border: 1px solid var(--gn-card-border);
    border-radius: 0.75rem;
    background-color: var(--gn-card-bg);
    padding: 1.25rem 1rem 1rem;
    text-align: center;
}

.tool-steps li::before {
    content: counter(tool-step);
    position: absolute;
    top: 10px;
    left: 10px;
    width: 27px;
    height: 27px;
    border-radius: 50%;
    background-color: var(--gn-accent);
    color: #fff;
    font-size: 0.85rem;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Dashed connector bridging the gap to the next card */
.tool-steps li:not(:last-child)::after {
    content: "";
    position: absolute;
    top: 50%;
    right: -1.5rem;
    width: 1.5rem;
    border-top: 2px dashed var(--gn-card-border);
}

.tool-step-icon {
    font-size: 1.5rem;
    color: var(--gn-accent);
}

/* Both wrappers: the front page uses .page-content, whose generic h3 rule
   would otherwise size and space these like a section heading */
.page-content .tool-steps h3,
.tool-content .tool-steps h3 {
    font-size: 0.95rem;
    font-weight: 600;
    margin: 0.5rem 0 0.35rem;
}

.tool-steps p {
    font-size: 0.875rem;
    color: var(--gn-muted);
    margin: 0;
}

@media (max-width: 767px) {
    .tool-steps {
        grid-template-columns: 1fr;
    }

    .tool-steps li:not(:last-child)::after {
        display: none;
    }
}

/* Tool page SEO content (below the intro, hidden while the app runs).
   The column is wider than classic body-text measure, so slightly more
   line height keeps the longer lines comfortable. */
.tool-content {
    margin-top: 2.5rem;
}

.tool-content p,
.tool-content li {
    line-height: 1.65;
}

.tool-content h2 {
    font-size: 1.25rem;
    margin-top: 1.75rem;
    margin-bottom: 0.5rem;
}

/* FAQ blocks, in both wrappers - the front page carries an FAQ too */
.page-content details,
.tool-content details {
    border: 1px solid var(--gn-card-border);
    border-radius: 0.5rem;
    padding: 0.625rem 0.875rem;
    margin-bottom: 0.5rem;
    background-color: var(--gn-card-bg);
}

.page-content summary,
.tool-content summary {
    cursor: pointer;
    font-weight: 600;
}

.page-content details p,
.tool-content details p {
    margin: 0.625rem 0 0;
    color: var(--gn-muted);
}

/* Prose that sits below a full-width grid - the front page and the category
   pages - needs the gap the tool pages get from .tool-content. Centering
   comes from .page-content. The text itself stays left-aligned everywhere:
   centered paragraphs give every line a different starting point, which is
   what makes them tiring to read. */
.home-content,
.section-content {
    margin-top: 2.5rem;
}

/* Pointer to tools on one of our other sites. Deliberately not shaped like
   our own tool cards: these lead somewhere else, and the reader should be
   able to tell that before clicking rather than after. The site name sits
   in the panel header doing that job, so no individual link has to. */
.gn-sister {
    margin: 1.25rem 0;
    padding: 1.25rem;
    border: 1px solid var(--gn-card-border);
    border-radius: 0.75rem;
    background-color: var(--gn-card-bg);
}

.gn-sister-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem;
    margin-bottom: 0.9rem;
}

.gn-sister-label {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--gn-muted);
}

.gn-sister-site {
    font-weight: 600;
}

.gn-sister-list {
    list-style: none;
    padding-left: 0;
    margin-bottom: 0;
}

.gn-sister-list li:last-child {
    margin-bottom: 0;
}

.gn-sister-list a {
    font-weight: 500;
}

/* The arrow marks an outbound link without needing the word "external" */
.gn-sister .bi {
    font-size: 0.75em;
    margin-left: 0.15rem;
    opacity: 0.75;
}

/* Comparison table, for choosing between sibling tools. Deliberately not
   card-shaped: next to a grid of tool cards, a third set of icon-and-text
   boxes reads as the same thing said twice, however different the words. */
.gn-compare-wrap {
    margin: 1.25rem 0;
    border: 1px solid var(--gn-card-border);
    border-radius: 0.5rem;
    background-color: var(--gn-card-bg);
    overflow: hidden;
}

.gn-compare {
    width: 100%;
    border-collapse: collapse;
}

.gn-compare th,
.gn-compare td {
    padding: 0.7rem 0.875rem;
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid var(--gn-card-border);
}

.gn-compare thead th {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--gn-muted);
}

.gn-compare tbody td:nth-child(2) {
    white-space: nowrap;
    font-weight: 500;
}

.gn-compare td:last-child {
    color: var(--gn-muted);
    font-size: 0.9rem;
}

.gn-compare tbody tr:last-child td {
    border-bottom: 0;
}

/* Below the sm breakpoint three text columns leave about 100px each, which
   is unreadable, and a horizontal scrollbar hides the third column behind a
   gesture. Each row becomes its own stack instead, with the column heading
   repeated from data-label. */
@media (max-width: 575px) {
    .gn-compare thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }

    .gn-compare tr {
        display: block;
        padding: 0.875rem;
        border-bottom: 1px solid var(--gn-card-border);
    }

    .gn-compare tbody tr:last-child {
        border-bottom: 0;
    }

    .gn-compare td,
    .gn-compare tbody tr:last-child td {
        display: block;
        padding: 0;
        border-bottom: 0;
    }

    .gn-compare td::before {
        content: attr(data-label);
        display: block;
        margin-top: 0.6rem;
        font-size: 0.7rem;
        font-weight: 600;
        letter-spacing: 0.05em;
        text-transform: uppercase;
        color: var(--gn-muted);
    }

    .gn-compare td:first-child::before {
        margin-top: 0;
    }

    .gn-compare tbody td:nth-child(2) {
        white-space: normal;
    }
}

/* Loading / error state shown by the app loader */
.app-status {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    height: 100%;
    padding: 3rem 1rem;
    color: var(--gn-muted);
    text-align: center;
}

/* --- Segmented control ---------------------------------------------------
   A row of mutually exclusive options with a thumb that slides to the
   checked one. Set --seg-count to the number of options; the JS side sets
   --seg-index on the container when the choice changes. Real radios stay in
   the markup, hidden, so keyboard and screen readers get a proper group.
   Wave Maker has its own .wm-seg copy of this; it can move over to these
   classes whenever that app is next touched. */
.gn-seg {
    position: relative;
    display: grid;
    grid-template-columns: repeat(var(--seg-count, 4), 1fr);
    padding: 3px;
    margin-top: 0.25rem;
    background-color: var(--gn-sidebar-hover-bg);
    border: 1px solid var(--gn-card-border);
    border-radius: 0.5rem;
}

.gn-seg-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.gn-seg > label {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: 0.35rem 0.25rem;
    border-radius: 0.4rem;
    cursor: pointer;
    color: var(--gn-muted);
    font-size: 0.65rem;
    line-height: 1;
    text-align: center;
}

.gn-seg > label .bi {
    font-size: 1rem;
    line-height: 1;
}

.gn-seg-input:checked + label {
    color: var(--gn-accent);
}

.gn-seg-input:focus-visible + label {
    outline: 2px solid var(--gn-accent);
    outline-offset: -2px;
}

.gn-seg-thumb {
    position: absolute;
    top: 3px;
    bottom: 3px;
    left: 3px;
    width: calc((100% - 6px) / var(--seg-count, 4));
    transform: translateX(calc(var(--seg-index, 0) * 100%));
    background-color: var(--gn-card-bg);
    border: 1px solid var(--gn-card-border);
    border-radius: 0.4rem;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
    transition: transform 0.18s ease;
}

@media (prefers-reduced-motion: reduce) {
    .gn-seg-thumb {
        transition: none;
    }
}
