/* =========================================================================
   I-Host — components & landing page
   =========================================================================
   Loads AFTER the inherited twenty-one theme.min.css, so this file is the
   last word. Everything is namespaced `ih-` and the markup uses those
   classes rather than Bootstrap's, which keeps this from turning into a
   specificity war with the parent theme.

   Bootstrap 4.5.3 is still present and still used for the grid, modals and
   collapse behaviour — no reason to reimplement those.
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. Base
   ------------------------------------------------------------------------- */

body {
    font-family: var(--ih-font-body);
    font-size: var(--ih-text-base);
    line-height: var(--ih-leading-normal);
    color: var(--ih-text);
    /* twenty-one paints the body via .primary-bg-color; the landing page
       supplies its own per-section backgrounds. */
    background: var(--ih-surface);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5, h6,
.ih-display {
    font-family: var(--ih-font-display);
    font-weight: 700;
    line-height: var(--ih-leading-tight);
    letter-spacing: var(--ih-tracking-tight);
    color: var(--ih-text);
}

a {
    color: var(--ih-blue-600);
    text-decoration: none;
    transition: color var(--ih-dur-fast) var(--ih-ease);
}

a:hover {
    color: var(--ih-blue-700);
    text-decoration: none;
}

/* A visible focus ring is not optional. twenty-one suppresses outlines in
   places, so this is restated deliberately. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--ih-blue-600);
    outline-offset: 2px;
    border-radius: var(--ih-radius-sm);
}

code, kbd, pre, samp, .ih-mono {
    font-family: var(--ih-font-mono);
    font-size: 0.9em;
}

.ih-container {
    width: 100%;
    max-width: var(--ih-container);
    margin-inline: auto;
    padding-inline: var(--ih-space-5);
}

.ih-container-narrow {
    max-width: var(--ih-container-narrow);
}

.ih-section {
    padding-block: var(--ih-section-y);
}

.ih-section--sunken { background: var(--ih-surface-sunken); }
.ih-section--dark   { background: var(--ih-surface-dark); color: var(--ih-text-on-dark); }
.ih-section--dark h2,
.ih-section--dark h3 { color: var(--ih-white); }

/* -------------------------------------------------------------------------
   2. Section headings
   ------------------------------------------------------------------------- */

.ih-section-head {
    max-width: 46rem;
    margin: 0 auto var(--ih-space-12);
    text-align: center;
}

.ih-eyebrow {
    display: inline-block;
    margin-bottom: var(--ih-space-3);
    font-size: var(--ih-text-xs);
    font-weight: 700;
    letter-spacing: var(--ih-tracking-wide);
    text-transform: uppercase;
    color: var(--ih-blue-600);
}

.ih-section--dark .ih-eyebrow { color: var(--ih-blue-200); }

.ih-section-title {
    font-size: var(--ih-text-3xl);
    margin-bottom: var(--ih-space-4);
}

.ih-section-sub {
    font-size: var(--ih-text-lg);
    line-height: var(--ih-leading-snug);
    color: var(--ih-text-muted);
    margin-bottom: 0;
}

.ih-section--dark .ih-section-sub { color: var(--ih-text-on-dark-mut); }

/* -------------------------------------------------------------------------
   3. Buttons
   ------------------------------------------------------------------------- */

.ih-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ih-space-2);
    padding: 0.7rem 1.4rem;
    border: 1px solid transparent;
    border-radius: var(--ih-radius);
    font-family: var(--ih-font-body);
    font-size: var(--ih-text-sm);
    font-weight: 600;
    line-height: 1.2;
    text-align: center;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--ih-dur-fast) var(--ih-ease),
                border-color var(--ih-dur-fast) var(--ih-ease),
                color var(--ih-dur-fast) var(--ih-ease),
                transform var(--ih-dur-fast) var(--ih-ease),
                box-shadow var(--ih-dur-fast) var(--ih-ease);
}

.ih-btn:active { transform: translateY(1px); }

/* Primary = the brand blue (was a cyan accent - removed, see tokens.css).
   White text on blue-600 clears 8.44:1, verified, so this can be plain
   white rather than needing the navy-text workaround the cyan fill
   used to need. */
.ih-btn--primary {
    background: var(--ih-blue-600);
    color: var(--ih-white);
    box-shadow: var(--ih-shadow-sm);
}

.ih-btn--primary:hover {
    background: var(--ih-blue-700);
    color: var(--ih-white);
    box-shadow: var(--ih-shadow);
}

.ih-btn--brand {
    background: var(--ih-blue-600);
    color: var(--ih-white);
    box-shadow: var(--ih-shadow-sm);
}

.ih-btn--brand:hover { background: var(--ih-blue-700); color: var(--ih-white); }

.ih-btn--outline {
    background: transparent;
    border-color: var(--ih-border-strong);
    color: var(--ih-text);
}

.ih-btn--outline:hover {
    border-color: var(--ih-blue-600);
    color: var(--ih-blue-600);
    background: var(--ih-blue-50);
}

/* For use on the navy hero / dark sections. */
/* No backdrop-filter here — see the note above .ih-header. The alpha is
   raised to 0.12 so the button reads as a distinct surface without it. */
.ih-btn--ghost-light {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.25);
    color: var(--ih-white);
}

.ih-btn--ghost-light:hover {
    background: rgba(255, 255, 255, 0.16);
    border-color: rgba(255, 255, 255, 0.45);
    color: var(--ih-white);
}

.ih-btn--lg    { padding: 0.95rem 1.9rem; font-size: var(--ih-text-base); }
.ih-btn--sm    { padding: 0.45rem 0.9rem; font-size: var(--ih-text-xs); }
.ih-btn--block { display: flex; width: 100%; }

/* -------------------------------------------------------------------------
   4. Header / navigation
   ------------------------------------------------------------------------- */

/* NO backdrop-filter anywhere in this theme. It was here originally and it
   hard-froze the page: a `position: fixed` element that blurs its backdrop
   forces the browser to re-read and re-blur everything behind it on every
   frame. Where the GPU is blocklisted or unavailable — a VM, an RDP
   session, a plain Windows Docker dev box — that work lands on the main
   thread and the tab locks up before `load` even fires.
   Opaque backgrounds cost nothing and look near-identical. Do not
   reintroduce blur here without testing on a software-rendered browser. */
.ih-header {
    position: sticky;
    top: 0;
    z-index: var(--ih-z-header);
    background: var(--ih-white);
    border-bottom: 1px solid var(--ih-border);
}

/* On the homepage the nav sits over the navy hero until the user scrolls,
   so it starts transparent and light. `.ih-scrolled` is added by JS. */
.ih-header--overlay {
    position: fixed;
    inset-inline: 0;
    background: transparent;
    border-bottom-color: transparent;
}

.ih-header--overlay .ih-nav-link { color: var(--ih-text-on-dark); }

/* Overriding colour alone wasn't enough here - .ih-nav-link:hover's own
   background: var(--ih-blue-50) (below) is a near-white tint made for a
   light header and was still winning underneath, showing as a pale
   washed-out box against the dark pre-scroll hero (reported live, with
   a screenshot). Same translucent-white treatment .ih-btn--ghost-light
   already uses for controls sitting on this exact background. */
.ih-header--overlay .ih-nav-link:hover {
    color: var(--ih-white);
    background: rgba(255, 255, 255, 0.12);
}

.ih-header--overlay.ih-scrolled {
    background: var(--ih-white);
    border-bottom-color: var(--ih-border);
    box-shadow: var(--ih-shadow-sm);
}

.ih-header--overlay.ih-scrolled .ih-nav-link { color: var(--ih-text); }

.ih-header-inner {
    display: flex;
    align-items: center;
    gap: var(--ih-space-6);
    min-height: 72px;
}

.ih-brand {
    display: inline-flex;
    align-items: center;
    gap: var(--ih-space-3);
    flex-shrink: 0;
}

.ih-brand img { height: 34px; width: auto; display: block; }

.ih-nav {
    display: flex;
    align-items: center;
    gap: var(--ih-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

.ih-nav-link {
    display: inline-block;
    padding: var(--ih-space-2) var(--ih-space-3);
    border-radius: var(--ih-radius-sm);
    font-size: var(--ih-text-sm);
    font-weight: 500;
    color: var(--ih-text-muted);
    transition: color var(--ih-dur-fast) var(--ih-ease),
                background-color var(--ih-dur-fast) var(--ih-ease);
}

.ih-nav-link:hover {
    color: var(--ih-blue-600);
    background: var(--ih-blue-50);
}

/* The empty "More" bucket (autoCollapse's overflow target, permanently
   unused - see includes/navbar.tpl) is hidden from JS, not CSS: the CSS
   Selectors spec forbids :has() nested inside :has(), which is what a
   pure-CSS "hide if child is empty" rule needs here, and browsers drop
   the whole rule silently when that happens rather than erroring. See
   hideEmptyNavOverflow() in js/ihost.js. */

.ih-header-actions {
    display: flex;
    align-items: center;
    gap: var(--ih-space-2);
    margin-left: auto;
}

.ih-cart-link { position: relative; padding: var(--ih-space-2) var(--ih-space-3); }

.ih-cart-count {
    position: absolute;
    top: 0;
    right: 0;
    min-width: 18px;
    padding: 0 5px;
    border-radius: var(--ih-radius-pill);
    background: var(--ih-blue-600);
    color: var(--ih-white);
    font-size: 10px;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
}

.ih-nav-toggle {
    display: none;
    padding: var(--ih-space-2);
    border: 0;
    background: transparent;
    color: inherit;
    font-size: 1.25rem;
}

/* Logged-in strip above the nav. */
.ih-topbar {
    background: var(--ih-blue-900);
    color: var(--ih-text-on-dark-mut);
    font-size: var(--ih-text-sm);
}

.ih-topbar a { color: var(--ih-text-on-dark); }
.ih-topbar a:hover { color: var(--ih-white); }

.ih-topbar-inner {
    display: flex;
    align-items: center;
    gap: var(--ih-space-4);
    min-height: 40px;
}

@media (max-width: 991.98px) {
    .ih-nav-toggle { display: inline-flex; }

    .ih-nav {
        display: none;
        position: absolute;
        top: 100%;
        inset-inline: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        padding: var(--ih-space-3);
        background: var(--ih-surface);
        border-bottom: 1px solid var(--ih-border);
        box-shadow: var(--ih-shadow-lg);
    }

    .ih-nav.ih-open { display: flex; }

    /* Inside the dropped panel the links sit on white regardless of the
       overlay state, so force the dark text back - and, just added,
       the hover state too: the new dark-header hover fix above
       (translucent white bg + white text) would otherwise still win in
       here on specificity, making a hovered link nearly invisible
       against this panel's own white background. */
    .ih-header--overlay .ih-nav .ih-nav-link { color: var(--ih-text); }
    .ih-header--overlay .ih-nav .ih-nav-link:hover {
        color: var(--ih-blue-600);
        background: var(--ih-blue-50);
    }

    .ih-nav-link { padding: var(--ih-space-3); font-size: var(--ih-text-base); }
}

/* -------------------------------------------------------------------------
   5. Hero
   ------------------------------------------------------------------------- */

/* The hero IS a slider now, not a static gradient with a small image
   card beside it (that first version is gone - see IHOST_THEME_PLAN.md
   1.24 for why). Layering, back to front:
     1. .ih-hero-slider-bg  - the three photos, absolutely filling the
        section, crossfading (same .ih-hero-slide rules the old card
        component used - kept, just reparented).
     2. .ih-hero-scrim      - a navy gradient over the photos so text
        stays legible regardless of which photo is showing. Real element,
        not ::before/::after: a pseudo-element generates as the first
        child, which would paint it BEHIND the real .ih-hero-slider-bg
        div rather than in front, so it has to be a normal element
        sequenced after the photos in the DOM.
     3. .ih-hero-slider-nav - the left-side dots, above the scrim.
     4. .ih-container        - the actual heading/CTA/domain-search
        content, last, on top of everything.
   The old dot-grid texture (.ih-hero::before) is gone too - a synthetic
   dot pattern layered over a real photo read as visual clutter, two
   different textures competing, once there was an actual photo doing
   that job. */
.ih-hero {
    position: relative;
    padding-top: calc(72px + var(--ih-space-20));
    padding-bottom: var(--ih-space-20);
    background: var(--ih-blue-950); /* shows only while the first photo loads */
    color: var(--ih-text-on-dark);
    overflow: hidden;
}

.ih-hero-slider-bg { position: absolute; inset: 0; z-index: 0; }

.ih-hero-scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background:
        /* Same accent glows the old flat-colour hero used - rgb(169, 200,
           238) is --ih-blue-200, rgb(46, 116, 196) is --ih-blue-400; kept
           as rgb() since a gradient can't reference a var() partway
           through an rgba() alpha channel. */
        radial-gradient(ellipse 80% 60% at 75% 0%, rgba(169, 200, 238, 0.18), transparent 60%),
        radial-gradient(ellipse 60% 50% at 10% 20%, rgba(46, 116, 196, 0.22), transparent 65%),
        linear-gradient(165deg, rgba(6, 42, 87, 0.90) 0%, rgba(4, 28, 59, 0.94) 100%);
}

/* Reserves a gutter for .ih-hero-slider-nav's dots, which are
   vertically centered on the WHOLE section (not this container), so at
   most viewport heights they'd otherwise land somewhere down the
   middle of the heading/sub/CTA column - confirmed by measuring
   getBoundingClientRect() on both, not assumed safe from a screenshot:
   overlapped at 992px width before this padding existed. 4.5rem clears
   the dots (left: --ih-space-6 = 1.5rem, 10px wide) with room to
   spare, at any width or height. */
.ih-hero > .ih-container { position: relative; z-index: 2; padding-left: 4.5rem; }

.ih-hero-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--ih-space-12);
    align-items: center;
}

@media (min-width: 992px) {
    .ih-hero-grid { grid-template-columns: 1.1fr 0.9fr; gap: var(--ih-space-16); }
}

.ih-hero-title {
    font-size: var(--ih-text-4xl);
    font-weight: 800;
    color: var(--ih-white);
    margin-bottom: var(--ih-space-5);
}

.ih-hero-title .ih-hl {
    background: linear-gradient(100deg, var(--ih-blue-100), var(--ih-blue-200));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.ih-hero-sub {
    font-size: var(--ih-text-lg);
    line-height: var(--ih-leading-snug);
    color: var(--ih-text-on-dark-mut);
    max-width: 34rem;
    margin-bottom: var(--ih-space-8);
}

.ih-hero-cta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ih-space-3);
    margin-bottom: var(--ih-space-8);
}

.ih-hero-points {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ih-space-2) var(--ih-space-6);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--ih-text-sm);
    color: var(--ih-text-on-dark-mut);
}

.ih-hero-points li { display: flex; align-items: center; gap: var(--ih-space-2); }
.ih-hero-points i { color: var(--ih-blue-200); }

/* ---- Domain search, sitting in the hero ---- */

.ih-domain-card {
    padding: var(--ih-space-6);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: var(--ih-radius-xl);
    background: rgba(255, 255, 255, 0.10);
    box-shadow: var(--ih-shadow-xl);
}

.ih-domain-card h2 {
    font-size: var(--ih-text-xl);
    color: var(--ih-white);
    margin-bottom: var(--ih-space-2);
}

.ih-domain-card p {
    font-size: var(--ih-text-sm);
    color: var(--ih-text-on-dark-mut);
    margin-bottom: var(--ih-space-5);
}

.ih-domain-form { display: flex; gap: var(--ih-space-2); flex-wrap: wrap; }

.ih-domain-input {
    flex: 1 1 12rem;
    min-width: 0;
    padding: 0.85rem 1rem;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: var(--ih-radius);
    background: rgba(255, 255, 255, 0.95);
    color: var(--ih-text);
    font-size: var(--ih-text-base);
}

.ih-domain-input::placeholder { color: var(--ih-gray-400); }

.ih-domain-input:focus {
    outline: none;
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

.ih-tld-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ih-space-2);
    margin-top: var(--ih-space-5);
    padding-top: var(--ih-space-5);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    font-size: var(--ih-text-sm);
    color: var(--ih-text-on-dark-mut);
}

.ih-tld-chip {
    padding: 0.2rem 0.6rem;
    border-radius: var(--ih-radius-pill);
    background: rgba(255, 255, 255, 0.08);
    font-family: var(--ih-font-mono);
    font-size: var(--ih-text-xs);
    color: var(--ih-white);
}

/* ---- Hero image slider ----------------------------------------------
   The photos and dots for the WHOLE hero (see the layering note above
   .ih-hero) - not a card, so no wrapper of its own; .ih-hero-slider-bg
   and .ih-hero-scrim already size themselves to inset:0 of .ih-hero.
   js/ihost.js's initHeroSlider() drives rotation and the dots, but
   is-active on the first <figure> is written directly in homepage.tpl,
   not added by JS - so with JS disabled or failed, the crossfade rule
   below still shows exactly the first slide (opacity 1) with the rest
   hidden (opacity 0), a normal static hero photo, not a broken stack. */
/* Two independent motions layered together, not one - a plain opacity
   crossfade read as flat once there were real photos to show:
     - the FIGURE (this rule) handles the transition BETWEEN slides -
       fades and, before it's a fully static crossfade, settles in from
       a slight zoom-out (1.06 -> 1) so the incoming photo feels like
       it's arriving, not just appearing.
     - the IMG inside it (below) runs its own slow, continuous "Ken
       Burns" zoom for the whole time a slide is active, independent of
       the figure's transition - nested transforms compose visually, so
       the two combine into one smooth motion rather than fighting.
   .ih-hero's own overflow: hidden clips both to the section, so the
   zoomed image never visibly spills past the hero's edges. */
.ih-hero-slide {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    z-index: 1;
    transform: scale(1.06);
    transition: opacity 1200ms var(--ih-ease),
                transform 1200ms var(--ih-ease);
}

.ih-hero-slide.is-active { opacity: 1; z-index: 2; transform: scale(1); }

.ih-hero-slide img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Runs only while a slide is the active one, and restarts from `from`
   every time - the animation-name only matches .is-active, so it's
   removed when a slide cycles out and reapplied fresh when it cycles
   back in, rather than resuming mid-zoom. 7s is deliberately longer
   than the 5s auto-advance interval in js/ihost.js: most slides get
   cut off mid-zoom by the next crossfade rather than visibly finishing
   and holding, which reads as more continuous, less like a loop
   resetting. Neutralised automatically under prefers-reduced-motion by
   tokens.css's existing global animation-duration override - no
   separate opt-out needed here. */
.ih-hero-slide.is-active img { animation: ihHeroKenBurns 7s var(--ih-ease-out) forwards; }

@keyframes ihHeroKenBurns {
    from { transform: scale(1); }
    to   { transform: scale(1.12); }
}

.ih-hero-slider-nav {
    position: absolute;
    top: 50%;
    left: var(--ih-space-6);
    z-index: 3;
    display: flex;
    flex-direction: column;
    gap: var(--ih-space-3);
    transform: translateY(-50%);
}

.ih-hero-dot {
    width: 10px;
    height: 10px;
    padding: 0;
    border: 2px solid rgba(255, 255, 255, 0.7);
    border-radius: 50%;
    background: transparent;
    cursor: pointer;
    transition: background-color var(--ih-dur-fast) var(--ih-ease),
                border-color var(--ih-dur-fast) var(--ih-ease),
                transform var(--ih-dur-fast) var(--ih-ease);
}

.ih-hero-dot:hover { border-color: var(--ih-white); }

.ih-hero-dot.is-active {
    background: var(--ih-white);
    border-color: var(--ih-white);
    transform: scale(1.2);
}

/* -------------------------------------------------------------------------
   6. Trust bar
   ------------------------------------------------------------------------- */

.ih-trust {
    border-bottom: 1px solid var(--ih-border);
    background: var(--ih-surface);
}

.ih-trust-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--ih-space-6);
    padding-block: var(--ih-space-10);
}

@media (min-width: 768px) {
    .ih-trust-grid { grid-template-columns: repeat(4, 1fr); }
}

.ih-trust-item { text-align: center; }

.ih-trust-value {
    display: block;
    font-family: var(--ih-font-display);
    font-size: var(--ih-text-2xl);
    font-weight: 800;
    letter-spacing: var(--ih-tracking-tight);
    color: var(--ih-blue-600);
}

.ih-trust-label {
    font-size: var(--ih-text-sm);
    color: var(--ih-text-muted);
}

/* -------------------------------------------------------------------------
   7. Plan cards
   ------------------------------------------------------------------------- */

.ih-plan-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--ih-space-6);
    align-items: start;
}

@media (min-width: 640px) { .ih-plan-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 992px) { .ih-plan-grid { grid-template-columns: repeat(3, 1fr); } }

.ih-plan {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: var(--ih-space-8) var(--ih-space-6);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
    transition: transform var(--ih-dur) var(--ih-ease-out),
                box-shadow var(--ih-dur) var(--ih-ease-out),
                border-color var(--ih-dur) var(--ih-ease-out);
}

.ih-plan:hover {
    transform: translateY(-4px);
    border-color: var(--ih-blue-200);
    box-shadow: var(--ih-shadow-lg);
}

.ih-plan--featured {
    border-color: var(--ih-blue-600);
    border-width: 2px;
    box-shadow: var(--ih-shadow-lg);
}

.ih-plan-badge {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 0.3rem 0.9rem;
    border-radius: var(--ih-radius-pill);
    background: var(--ih-blue-600);
    color: var(--ih-white);
    font-size: var(--ih-text-xs);
    font-weight: 700;
    letter-spacing: var(--ih-tracking-wide);
    text-transform: uppercase;
    white-space: nowrap;
}

.ih-plan-name {
    font-size: var(--ih-text-xl);
    margin-bottom: var(--ih-space-1);
}

.ih-plan-tag {
    font-size: var(--ih-text-sm);
    color: var(--ih-text-muted);
    margin-bottom: var(--ih-space-5);
}

.ih-plan-price {
    display: flex;
    align-items: baseline;
    gap: 0.3rem;
    margin-bottom: var(--ih-space-1);
}

.ih-plan-amount {
    font-family: var(--ih-font-display);
    font-size: var(--ih-text-3xl);
    font-weight: 800;
    letter-spacing: var(--ih-tracking-tight);
    color: var(--ih-text);
    line-height: 1;
}

.ih-plan-per { font-size: var(--ih-text-sm); color: var(--ih-text-muted); }

.ih-plan-note {
    min-height: 1.35rem;
    margin-bottom: var(--ih-space-6);
    font-size: var(--ih-text-xs);
    color: var(--ih-text-subtle);
}

.ih-plan-save { color: var(--ih-success-text); font-weight: 600; }

.ih-plan-features {
    flex: 1 1 auto;
    margin: 0 0 var(--ih-space-6);
    padding: var(--ih-space-5) 0 0;
    border-top: 1px solid var(--ih-border);
    list-style: none;
    font-size: var(--ih-text-sm);
}

.ih-plan-features li {
    display: flex;
    align-items: flex-start;
    gap: var(--ih-space-2);
    padding-block: 0.35rem;
    color: var(--ih-text-muted);
}

.ih-plan-features i {
    flex-shrink: 0;
    margin-top: 0.28em;
    font-size: 0.8em;
    color: var(--ih-success);
}

/* -------------------------------------------------------------------------
   7b. Store product list (products.tpl)

   Deliberately NOT another .ih-plan grid - a live product group can be
   3 SKUs or 12 (the VPS group is), and a wall of tall pricing tiles is
   the wrong shape for scanning a dozen options. This is a row-based
   catalogue instead: icon medallion + name + inline spec pills on the
   left, price and CTA on the right - closer in spirit to the spec
   comparison table (§8) than to the homepage's 3-tier pricing cards,
   which is why it reuses .ih-cell-price for the amount rather than
   inventing a third price treatment.
   ------------------------------------------------------------------------- */

.ih-store-list {
    display: flex;
    flex-direction: column;
    gap: var(--ih-space-4);
}

.ih-store-item {
    display: flex;
    align-items: flex-start;
    gap: var(--ih-space-5);
    padding: var(--ih-space-6);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
    transition: transform var(--ih-dur) var(--ih-ease-out),
                box-shadow var(--ih-dur) var(--ih-ease-out),
                border-color var(--ih-dur) var(--ih-ease-out);
}

.ih-store-item:hover {
    transform: translateY(-2px);
    border-color: var(--ih-blue-200);
    box-shadow: var(--ih-shadow-lg);
}

.ih-store-item-icon {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    border-radius: var(--ih-radius);
    background: var(--ih-blue-50);
    color: var(--ih-blue-600);
    font-size: var(--ih-text-lg);
}

.ih-store-item-body { flex: 1 1 auto; min-width: 0; }

.ih-store-item-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--ih-space-3);
    margin-bottom: var(--ih-space-1);
}

.ih-store-item-name { font-size: var(--ih-text-lg); font-weight: 700; color: var(--ih-text); }

.ih-store-item-desc {
    margin: 0 0 var(--ih-space-3);
    font-size: var(--ih-text-sm);
    color: var(--ih-text-muted);
}

.ih-store-item-features {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ih-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.ih-store-feature-pill {
    display: inline-flex;
    align-items: center;
    padding: 0.3em 0.75em;
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-pill);
    background: var(--ih-surface-sunken);
    font-size: var(--ih-text-xs);
    color: var(--ih-text-muted);
}

.ih-store-feature-pill strong { margin-right: 0.35em; color: var(--ih-text); font-weight: 700; }

.ih-store-item-price {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--ih-space-3);
    min-width: 9.5rem;
    text-align: right;
}

.ih-store-item-note { font-size: var(--ih-text-xs); color: var(--ih-text-subtle); }

/* addons.tpl's per-item "attach to which product" picker - the one
   piece of interactive input .ih-store-item never needed before. */
.ih-store-item-select {
    width: 100%;
    margin-top: var(--ih-space-2);
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--ih-border-strong);
    border-radius: var(--ih-radius);
    background: var(--ih-surface);
    font-size: var(--ih-text-sm);
    color: var(--ih-text);
}

@media (max-width: 767.98px) {
    .ih-store-item { flex-direction: column; }

    .ih-store-item-price {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        width: 100%;
        text-align: left;
    }
}

/* -------------------------------------------------------------------------
   7c. Order confirmation (complete.tpl)
   ------------------------------------------------------------------------- */

.ih-order-confirm {
    max-width: 34rem;
    margin: 0 auto var(--ih-space-8);
    padding-top: var(--ih-space-6);
    text-align: center;
}

.ih-order-confirm-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3.5rem;
    height: 3.5rem;
    margin-bottom: var(--ih-space-5);
    border-radius: var(--ih-radius-pill);
    background: var(--ih-success-bg);
    color: var(--ih-success);
    font-size: var(--ih-text-xl);
}

.ih-order-confirm .ih-page-title,
.ih-order-confirm .ih-page-sub { text-align: center; }

.ih-order-confirm-number {
    display: inline-block;
    margin: var(--ih-space-5) 0;
    padding: var(--ih-space-3) var(--ih-space-6);
    border-radius: var(--ih-radius-pill);
    background: var(--ih-blue-50);
    color: var(--ih-blue-700);
    font-size: var(--ih-text-sm);
}

.ih-order-confirm-number strong { font-weight: 700; }

.ih-order-confirm-note {
    margin-top: var(--ih-space-4);
    color: var(--ih-text-muted);
    font-size: var(--ih-text-sm);
}

/* -------------------------------------------------------------------------
   7d. Checkout & cart review (checkout.tpl, viewcart.tpl) - CSS-only reskin

   Unlike products.tpl/complete.tpl, these two are NOT restructured -
   see IHOST_THEME_PLAN.md 1.34. checkout.tpl alone has dozens of ids
   WHMCS's own JS binds to (payment gateway switching, password
   strength, credit-card validation, existing/new customer toggling)
   and viewcart.tpl has a promo-code/tax tab switcher and remove-item
   modals - restructuring either is a real risk to the one page in the
   whole site that touches money and cardholder data. So: every
   original class name, id, and DOM shape stays exactly as shipped;
   this section only themes colors/type/spacing on the classes already
   there. Every rule is scoped under #order-standard_cart (present on
   both pages' root wrapper) specifically so it outranks the order
   form's own bundled all.css on specificity alone, regardless of which
   stylesheet's <link> happens to load second in the DOM - the same
   cascade lesson learned the hard way on the sidebar bug (§1.29/1.33).
   Native form widgets (radio/checkbox appearance, Bootstrap modals,
   the promo/tax tab switcher) are left as Bootstrap defaults for this
   pass - color/spacing only, not a full component rebuild.
   ------------------------------------------------------------------------- */

#order-standard_cart .header-lined {
    padding: 0;
    border: 0;
    margin-bottom: var(--ih-space-8);
}

#order-standard_cart .header-lined h1 {
    font-family: var(--ih-font-display);
    font-size: var(--ih-text-3xl);
    font-weight: 800;
    letter-spacing: var(--ih-tracking-tight);
    color: var(--ih-text);
}

#order-standard_cart .sub-heading {
    margin: var(--ih-space-8) 0 var(--ih-space-4);
    padding-bottom: var(--ih-space-2);
    border-bottom: 1px solid var(--ih-border);
}

#order-standard_cart .sub-heading .primary-bg-color {
    background: transparent;
    padding: 0;
    color: var(--ih-blue-700);
    font-size: var(--ih-text-sm);
    font-weight: 700;
    letter-spacing: var(--ih-tracking-wide);
    text-transform: uppercase;
}

#order-standard_cart .form-control,
#order-standard_cart .field,
#order-standard_cart select.field,
#order-standard_cart textarea.field {
    border: 1px solid var(--ih-border-strong);
    border-radius: var(--ih-radius);
    background: var(--ih-surface);
    color: var(--ih-text);
}

#order-standard_cart .form-control:focus,
#order-standard_cart .field:focus {
    outline: none;
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

#order-standard_cart .alert-danger { background: var(--ih-danger-bg); color: var(--ih-danger-text); border-color: var(--ih-danger); }
#order-standard_cart .alert-warning { background: var(--ih-warning-bg); color: var(--ih-warning-text); border-color: var(--ih-warning); }
#order-standard_cart .alert-success { background: var(--ih-success-bg); color: var(--ih-success-text); border-color: var(--ih-success); }
#order-standard_cart .alert-info { background: var(--ih-blue-50); color: var(--ih-blue-700); border-color: var(--ih-blue-200); }

/* #btnCompleteOrder itself is already covered by §17's pre-existing,
   more-specific id rule (from an earlier "Phase 3" pass this task's
   author wasn't aware of until reading that section directly) - this
   only needs to cover .btn-primary generally. */
#order-standard_cart .btn-primary {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
    color: var(--ih-white);
}

#order-standard_cart .btn-primary:hover {
    background: var(--ih-blue-700);
    border-color: var(--ih-blue-700);
}

#order-standard_cart .btn-default,
#order-standard_cart .btn-checkout,
#order-standard_cart .btn-continue-shopping {
    border-color: var(--ih-border-strong);
    color: var(--ih-text);
}

#order-standard_cart .btn-checkout {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
    color: var(--ih-white);
}

#order-standard_cart .btn-checkout:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

/* Existing-account picker (checkout.tpl) */
#order-standard_cart .account {
    padding: var(--ih-space-4);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius);
    background: var(--ih-surface);
}

#order-standard_cart .account.active { border-color: var(--ih-blue-600); background: var(--ih-blue-50); }

/* Cart line items (viewcart.tpl) */
#order-standard_cart .view-cart-items-header {
    padding: var(--ih-space-3) var(--ih-space-4);
    color: var(--ih-text-subtle);
    font-size: var(--ih-text-xs);
    font-weight: 700;
    letter-spacing: var(--ih-tracking-wide);
    text-transform: uppercase;
}

#order-standard_cart .view-cart-items .item {
    padding: var(--ih-space-4);
    margin-bottom: var(--ih-space-3);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
}

#order-standard_cart .item-title { font-weight: 700; color: var(--ih-text); }
#order-standard_cart .item-group,
#order-standard_cart .item-domain { color: var(--ih-text-muted); font-size: var(--ih-text-sm); }
#order-standard_cart .item-price { color: var(--ih-text); font-weight: 700; }
#order-standard_cart .item-price .cycle { display: block; color: var(--ih-text-muted); font-weight: 400; font-size: var(--ih-text-xs); }

#order-standard_cart .view-cart-empty {
    padding: var(--ih-space-8);
    text-align: center;
    color: var(--ih-text-muted);
    border: 1px dashed var(--ih-border);
    border-radius: var(--ih-radius-lg);
}

/* Order summary sidebar (viewcart.tpl) */
#order-standard_cart .order-summary {
    padding: var(--ih-space-6);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
}

#order-standard_cart .order-summary h2 {
    font-family: var(--ih-font-display);
    font-size: var(--ih-text-xl);
    font-weight: 800;
    margin-bottom: var(--ih-space-4);
}

#order-standard_cart .summary-container > div { padding-block: var(--ih-space-2); }
#order-standard_cart .bordered-totals { border-top: 1px solid var(--ih-border); border-bottom: 1px solid var(--ih-border); margin: var(--ih-space-2) 0; }

#order-standard_cart .total-due-today {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    padding-top: var(--ih-space-4);
    margin-top: var(--ih-space-2);
    border-top: 1px solid var(--ih-border);
}

#order-standard_cart .total-due-today .amt {
    font-family: var(--ih-font-display);
    font-size: var(--ih-text-2xl);
    font-weight: 800;
    color: var(--ih-text);
}

/* Payment total callout on checkout.tpl (#totalDueToday.alert-success) */
#order-standard_cart .alert.large-text#totalDueToday strong {
    font-family: var(--ih-font-display);
    font-size: var(--ih-text-xl);
}

#order-standard_cart .apply-credit-container {
    padding: var(--ih-space-4);
    margin: var(--ih-space-4) 0;
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius);
    background: var(--ih-surface-sunken);
}

#order-standard_cart .marketing-email-optin {
    padding: var(--ih-space-4);
    margin: var(--ih-space-4) 0;
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius);
}

/* configureproduct.tpl (product config step) - same CSS-only-reskin
   discipline as checkout.tpl/viewcart.tpl above: ion.rangeSlider,
   recalctotals(), and the AJAX-refreshed order summary all key off
   ids/classes that stay exactly as shipped. */
#order-standard_cart .product-info .product-title {
    font-family: var(--ih-font-display);
    font-size: var(--ih-text-xl);
    font-weight: 800;
    color: var(--ih-text);
}

#order-standard_cart .field-container { margin-bottom: var(--ih-space-4); }

/* Addon selection cards, inline on configureproduct.tpl */
#order-standard_cart .panel-addon {
    padding: var(--ih-space-4);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
    transition: border-color var(--ih-dur-fast) var(--ih-ease);
}

#order-standard_cart .panel-addon-selected { border-color: var(--ih-blue-600); background: var(--ih-blue-50); }
#order-standard_cart .panel-addon .panel-price { margin-top: var(--ih-space-2); font-weight: 700; color: var(--ih-text); }
#order-standard_cart .panel-addon .panel-add { margin-top: var(--ih-space-2); color: var(--ih-blue-600); font-size: var(--ih-text-sm); font-weight: 600; }

/* ordersummary.tpl - the AJAX-refreshed fragment rendered into
   #producttotal on configureproduct.tpl (and equivalent containers
   elsewhere). .total-due-today/.amt are already covered by the
   viewcart.tpl rules above - this only adds what's unique here. */
#order-standard_cart .product-name { display: block; font-weight: 700; color: var(--ih-text); }
#order-standard_cart .product-group { display: block; margin-bottom: var(--ih-space-2); font-size: var(--ih-text-sm); color: var(--ih-text-muted); }
#order-standard_cart .summary-totals { padding-top: var(--ih-space-2); margin-top: var(--ih-space-2); border-top: 1px solid var(--ih-border); }

/* Domain registration/transfer flow (domainregister.tpl,
   domaintransfer.tpl, domainoptions.tpl, configuredomains.tpl,
   configureproductdomain.tpl) - task #42/§1.36. The most heavily
   AJAX-driven pages in the whole order-form: live availability
   checking, TLD spotlight cards, suggestion lists, an iCheck-powered
   checkbox plugin, dropdown pricing menus. Same CSS-only discipline as
   checkout.tpl - every id/class stays exactly as shipped, this only
   themes color/type/spacing on what's already there. Several classes
   here (.panel-addon, .sub-heading/.primary-bg-color, .form-control,
   .btn-primary) are already covered by the checkout/configure rules
   above and apply for free. */

#order-standard_cart .domain-checker-bg {
    padding: var(--ih-space-8) var(--ih-space-6);
    margin-bottom: var(--ih-space-6);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface-sunken);
}

#order-standard_cart .domain-checker-bg .form-control {
    border-radius: var(--ih-radius) 0 0 var(--ih-radius);
}

#order-standard_cart .domain-checker-bg .btn-primary {
    border-radius: 0 var(--ih-radius) var(--ih-radius) 0;
}

#order-standard_cart .domain-checker-result-headline {
    padding: var(--ih-space-3) 0;
    font-size: var(--ih-text-lg);
    font-weight: 700;
}

#order-standard_cart .domain-checker-available { color: var(--ih-success-text); }
#order-standard_cart .domain-checker-unavailable,
#order-standard_cart .domain-checker-invalid { color: var(--ih-danger-text); }

#order-standard_cart .btn-add-to-cart,
#order-standard_cart .domain-suggestion .btn-default,
#order-standard_cart .spotlight-tld .btn-default {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
    color: var(--ih-white);
}

#order-standard_cart .btn-add-to-cart:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

#order-standard_cart .spotlight-tld {
    padding: var(--ih-space-4);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
    text-align: center;
}

#order-standard_cart .suggested-domains,
#order-standard_cart .domain-pricing .bg-white {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    overflow: hidden;
}

#order-standard_cart .tld-pricing-header {
    padding: var(--ih-space-3) 0;
    color: var(--ih-text-subtle);
    font-size: var(--ih-text-xs);
    font-weight: 700;
    letter-spacing: var(--ih-tracking-wide);
    text-transform: uppercase;
    background: var(--ih-surface-sunken);
}

#order-standard_cart .tld-row {
    padding: var(--ih-space-3) 0;
    border-bottom: 1px solid var(--ih-border);
}

#order-standard_cart .tld-row:last-child { border-bottom: 0; }

#order-standard_cart .tld-filters .badge {
    display: inline-block;
    margin: 0 var(--ih-space-2) var(--ih-space-2) 0;
    padding: 0.4em 0.9em;
    border-radius: var(--ih-radius-pill);
    background: var(--ih-blue-50);
    color: var(--ih-blue-700);
    font-size: var(--ih-text-xs);
    font-weight: 600;
}

#order-standard_cart .domain-promo-box {
    padding: var(--ih-space-6);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
    text-align: center;
}

#order-standard_cart .domain-promo-box i { color: var(--ih-blue-600); margin-bottom: var(--ih-space-3); }

/* configureproductdomain.tpl's radio-choice rows (register/transfer/
   own domain/subdomain) and the .panel.card wrapper domaintransfer.tpl
   already dual-classes with card-header/card-title/card-body/
   card-footer (twenty-one's own Bootstrap .card CSS covers those
   generically; this just adds the same border/radius language as
   every other card in the theme). */
#order-standard_cart .domain-selection-options .option {
    padding: var(--ih-space-4) 0;
    border-bottom: 1px solid var(--ih-border);
}

#order-standard_cart .domain-selection-options .option:last-child { border-bottom: 0; }

#order-standard_cart .panel.card {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    overflow: hidden;
}

/* Renewals (service-renewals.tpl/service-renewal-item.tpl,
   domain-renewals.tpl) - task #43/§1.37. Both share the same shape
   (a filterable list of renewal cards + the same .order-summary
   sidebar already styled above) and the same two class families:
   Bootstrap 3-era .label.label-* status badges (twenty-one is BS4,
   so these ship with no real styling of their own) and
   .btn-add-renewal-to-cart, which isn't .btn-primary so needed its
   own color rule. CSS-only, same reasoning as every AJAX-heavy page
   in this phase - recalculateRenewalTotals() and the add-to-cart AJAX
   flow key off ids/classes staying exactly as shipped. */

#order-standard_cart .service-renewal,
#order-standard_cart .domain-renewal {
    padding: var(--ih-space-5);
    margin-bottom: var(--ih-space-3);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
}

#order-standard_cart .service-renewal h3,
#order-standard_cart .domain-renewal h3 {
    font-family: var(--ih-font-display);
    font-size: var(--ih-text-lg);
    font-weight: 800;
    color: var(--ih-text);
}

#order-standard_cart .label {
    display: inline-block;
    padding: 0.3em 0.8em;
    border-radius: var(--ih-radius-pill);
    font-size: var(--ih-text-xs);
    font-weight: 600;
}

#order-standard_cart .label-warning { background: var(--ih-warning-bg); color: var(--ih-warning-text); }
#order-standard_cart .label-success { background: var(--ih-success-bg); color: var(--ih-success-text); }
#order-standard_cart .label-danger  { background: var(--ih-danger-bg); color: var(--ih-danger-text); }
#order-standard_cart .label-info    { background: var(--ih-blue-50); color: var(--ih-blue-700); }
#order-standard_cart .label-grey    { background: var(--ih-surface-sunken); color: var(--ih-text-subtle); }

#order-standard_cart .btn-add-renewal-to-cart {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
    color: var(--ih-white);
}

#order-standard_cart .btn-add-renewal-to-cart:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }
#order-standard_cart .div-renewal-period-label { color: var(--ih-text-subtle); font-size: var(--ih-text-xs); text-transform: uppercase; letter-spacing: var(--ih-tracking-wide); }
#order-standard_cart .div-renewal-ineligible,
#order-standard_cart .domain-renewal-desc { color: var(--ih-text-muted); font-size: var(--ih-text-sm); }

/* Checkout edge cases (task #44/§1.38): error.tpl, fraudcheck.tpl,
   linkedaccounts.tpl, marketconnect-promo.tpl. The first two are
   almost entirely covered for free already - .alert-danger,
   .header-lined h1, .sub-heading/.primary-bg-color and .btn-default
   are all styled by the rules above from earlier in Phase A, so these
   only need the one piece those pages add that nothing else uses:
   .error-heading (icon spacing on the alert). linkedaccounts.tpl
   (embedded in checkout.tpl - already reachable there) needed one
   variant class its "or" divider uses that plain .sub-heading
   doesn't. marketconnect-promo.tpl is a genuinely new component (a
   compact cross-sell card), so it gets a real small rule set. */

#order-standard_cart .error-heading i { margin-right: var(--ih-space-2); }

#order-standard_cart .sub-heading-borderless {
    margin: var(--ih-space-6) 0 var(--ih-space-2);
}

#order-standard_cart .sub-heading-borderless .primary-bg-color {
    background: transparent;
    padding: 0;
    color: var(--ih-blue-700);
    font-size: var(--ih-text-sm);
    font-weight: 700;
    letter-spacing: var(--ih-tracking-wide);
    text-transform: uppercase;
}

#order-standard_cart .social-signin-btns { display: flex; flex-wrap: wrap; gap: var(--ih-space-3); justify-content: center; margin-bottom: var(--ih-space-3); }

#order-standard_cart .mc-promo {
    padding: var(--ih-space-4);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
}

#order-standard_cart .mc-promo .header { display: flex; align-items: center; gap: var(--ih-space-3); }
#order-standard_cart .mc-promo .icon img { width: 2.5rem; height: 2.5rem; }
#order-standard_cart .mc-promo .headline { font-weight: 700; color: var(--ih-text); }
#order-standard_cart .mc-promo .tagline { font-size: var(--ih-text-sm); color: var(--ih-text-muted); }
#order-standard_cart .mc-promo .price { font-family: var(--ih-font-display); font-weight: 800; color: var(--ih-text); }

#order-standard_cart .mc-promo .btn-add {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
    color: var(--ih-white);
}

#order-standard_cart .mc-promo .btn-add:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

#order-standard_cart .mc-promo .body ul { margin: var(--ih-space-3) 0 0; padding: 0; list-style: none; font-size: var(--ih-text-sm); color: var(--ih-text-muted); }
#order-standard_cart .mc-promo .body li { padding-block: 0.2rem; }
#order-standard_cart .mc-promo .body i { color: var(--ih-success); margin-right: var(--ih-space-2); }

/* -------------------------------------------------------------------------
   8. Comparison table (VPS)
   ------------------------------------------------------------------------- */

.ih-tabs {
    display: inline-flex;
    gap: var(--ih-space-1);
    padding: var(--ih-space-1);
    margin-bottom: var(--ih-space-8);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-pill);
    background: var(--ih-surface-sunken);
}

.ih-tab {
    padding: 0.5rem 1.25rem;
    border: 0;
    border-radius: var(--ih-radius-pill);
    background: transparent;
    color: var(--ih-text-muted);
    font-size: var(--ih-text-sm);
    font-weight: 600;
    cursor: pointer;
    transition: background-color var(--ih-dur-fast) var(--ih-ease),
                color var(--ih-dur-fast) var(--ih-ease);
}

.ih-tab[aria-selected="true"] {
    background: var(--ih-surface);
    color: var(--ih-blue-600);
    box-shadow: var(--ih-shadow-sm);
}

/* The table must scroll inside its own box. A 12-row spec table that
   forces the whole page sideways on a phone is a bug, not a layout. */
.ih-table-scroll {
    overflow-x: auto;
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
    -webkit-overflow-scrolling: touch;
}

.ih-table {
    width: 100%;
    min-width: 720px;
    margin: 0;
    border-collapse: collapse;
    font-size: var(--ih-text-sm);
}

.ih-table th,
.ih-table td {
    padding: var(--ih-space-4) var(--ih-space-5);
    text-align: left;
    vertical-align: middle;
    border-bottom: 1px solid var(--ih-border);
}

.ih-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--ih-surface-sunken);
    font-size: var(--ih-text-xs);
    font-weight: 700;
    letter-spacing: var(--ih-tracking-wide);
    text-transform: uppercase;
    color: var(--ih-text-muted);
    white-space: nowrap;
}

.ih-table tbody tr:last-child td { border-bottom: 0; }
.ih-table tbody tr { transition: background-color var(--ih-dur-fast) var(--ih-ease); }
.ih-table tbody tr:hover { background: var(--ih-blue-50); }

.ih-table .ih-cell-name { font-weight: 600; color: var(--ih-text); white-space: nowrap; }
.ih-table .ih-cell-spec { font-family: var(--ih-font-mono); color: var(--ih-text-muted); white-space: nowrap; }

.ih-cell-price {
    font-family: var(--ih-font-display);
    font-size: var(--ih-text-lg);
    font-weight: 800;
    color: var(--ih-text);
    white-space: nowrap;
}

.ih-cell-price small {
    font-family: var(--ih-font-body);
    font-size: var(--ih-text-xs);
    font-weight: 400;
    color: var(--ih-text-subtle);
}

.ih-cell-action { text-align: right; white-space: nowrap; }

.ih-scroll-hint {
    display: none;
    margin-top: var(--ih-space-3);
    font-size: var(--ih-text-xs);
    color: var(--ih-text-subtle);
    text-align: center;
}

@media (max-width: 767.98px) { .ih-scroll-hint { display: block; } }

/* -------------------------------------------------------------------------
   9. Feature tiles
   ------------------------------------------------------------------------- */

.ih-tile-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--ih-space-6);
}

@media (min-width: 640px) { .ih-tile-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 992px) { .ih-tile-grid { grid-template-columns: repeat(3, 1fr); } }

.ih-tile {
    padding: var(--ih-space-6);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
    transition: transform var(--ih-dur) var(--ih-ease-out),
                border-color var(--ih-dur) var(--ih-ease),
                box-shadow var(--ih-dur) var(--ih-ease);
}

/* Matches .ih-plan's hover lift (§7) - same card affordance language
   sitewide rather than two different hover styles for the same idea. */
.ih-tile:hover {
    transform: translateY(-4px);
    border-color: var(--ih-blue-200);
    box-shadow: var(--ih-shadow);
}

.ih-tile-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin-bottom: var(--ih-space-4);
    border-radius: var(--ih-radius);
    background: var(--ih-blue-50);
    color: var(--ih-blue-600);
    font-size: 1.15rem;
}

.ih-tile h3 { font-size: var(--ih-text-lg); margin-bottom: var(--ih-space-2); }
.ih-tile p { margin: 0; font-size: var(--ih-text-sm); color: var(--ih-text-muted); }

/* -------------------------------------------------------------------------
   10. FAQ
   ------------------------------------------------------------------------- */

.ih-faq { max-width: 46rem; margin-inline: auto; }

.ih-faq-item {
    border-bottom: 1px solid var(--ih-border);
}

.ih-faq-q {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ih-space-4);
    width: 100%;
    padding: var(--ih-space-5) 0;
    border: 0;
    background: transparent;
    font-family: var(--ih-font-display);
    font-size: var(--ih-text-lg);
    font-weight: 600;
    letter-spacing: var(--ih-tracking-tight);
    text-align: left;
    color: var(--ih-text);
    cursor: pointer;
}

.ih-faq-q:hover { color: var(--ih-blue-600); }

.ih-faq-q i {
    flex-shrink: 0;
    font-size: 0.85em;
    color: var(--ih-text-subtle);
    transition: transform var(--ih-dur) var(--ih-ease);
}

.ih-faq-q[aria-expanded="true"] i { transform: rotate(180deg); }

.ih-faq-a {
    padding: 0 0 var(--ih-space-5);
    font-size: var(--ih-text-base);
    color: var(--ih-text-muted);
}

.ih-faq-a p:last-child { margin-bottom: 0; }

/* -------------------------------------------------------------------------
   11. Final CTA
   ------------------------------------------------------------------------- */

.ih-cta {
    position: relative;
    padding-block: var(--ih-section-y);
    background:
        /* was a cyan glow (rgba(0, 184, 212, ...)); rgb(169, 200, 238) is
           --ih-blue-200, see the same note on .ih-hero. */
        radial-gradient(ellipse 70% 100% at 50% 0%, rgba(169, 200, 238, 0.2), transparent 65%),
        /* Same photo as the hero's first slide, reused rather than
           sourcing a fourth image - keeps the two dark sections feeling
           like one visual system instead of two unrelated ones. The
           gradient stops are ~90-96% opaque, not solid, specifically so
           this stays a background TEXTURE: text contrast was verified
           against the solid navy this replaces (§1.23) and a barely-
           visible photo underneath a near-opaque gradient can't move
           that meaningfully - a bold, clearly-visible photo here could,
           and wasn't checked, so wasn't risked. */
        linear-gradient(160deg, rgba(8, 61, 128, 0.92), rgba(4, 28, 59, 0.96)),
        url('../img/hero/slide-1-server-rack.jpg');
    background-size: cover;
    background-position: center;
    color: var(--ih-text-on-dark);
    text-align: center;
    overflow: hidden;
}

.ih-cta h2 { font-size: var(--ih-text-3xl); color: var(--ih-white); margin-bottom: var(--ih-space-4); }

.ih-cta p {
    max-width: 38rem;
    margin: 0 auto var(--ih-space-8);
    font-size: var(--ih-text-lg);
    color: var(--ih-text-on-dark-mut);
}

/* -------------------------------------------------------------------------
   12. Footer
   ------------------------------------------------------------------------- */

.ih-footer {
    padding-top: var(--ih-space-16);
    background: var(--ih-blue-950);
    color: var(--ih-text-on-dark-mut);
    font-size: var(--ih-text-sm);
}

.ih-footer-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--ih-space-10);
    padding-bottom: var(--ih-space-12);
}

@media (min-width: 640px) { .ih-footer-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 992px) { .ih-footer-grid { grid-template-columns: 1.6fr repeat(3, 1fr); } }

.ih-footer h4 {
    margin-bottom: var(--ih-space-4);
    font-size: var(--ih-text-xs);
    font-weight: 700;
    letter-spacing: var(--ih-tracking-wide);
    text-transform: uppercase;
    color: var(--ih-white);
}

.ih-footer ul { margin: 0; padding: 0; list-style: none; }
.ih-footer li { margin-bottom: var(--ih-space-2); }
.ih-footer a { color: var(--ih-text-on-dark-mut); }
.ih-footer a:hover { color: var(--ih-blue-200); }

.ih-footer-brand { display: flex; align-items: center; gap: var(--ih-space-3); margin-bottom: var(--ih-space-4); }
.ih-footer-brand img { height: 32px; width: auto; }

.ih-footer-blurb { max-width: 26rem; margin-bottom: var(--ih-space-5); }

.ih-footer-bottom {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ih-space-4);
    padding-block: var(--ih-space-6);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    font-size: var(--ih-text-xs);
}

.ih-footer-bottom p { margin: 0; }

.ih-social { display: flex; gap: var(--ih-space-2); }

.ih-social a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--ih-radius-sm);
    background: rgba(255, 255, 255, 0.07);
    color: var(--ih-text-on-dark);
}

.ih-social a:hover { background: var(--ih-blue-200); color: var(--ih-blue-950); }

/* -------------------------------------------------------------------------
   12b. Return-to-admin ribbon
   -------------------------------------------------------------------------
   footer.tpl (and header.tpl's topbar) render WHMCS's own
   {if !$loggedin && $adminLoggedIn} link unchanged from twenty-one - it
   only appears to an admin browsing the storefront without an active
   client session, never to a real visitor, but it was still rendering in
   twenty-one's stock, un-rebranded style: flat grey (rgb(215,215,215)),
   #777 text, no shadow - the one element in the theme nobody had restyled.
   twenty-one also pins it with `top: 425px !important`, a fixed pixel
   offset from the viewport top - on any window shorter than ~460px
   (confirmed live: this in-app browser's own default viewport is one)
   that pivot point sits below the visible area and the whole tab is
   clipped off-screen. `top` here is the pivot the 90deg rotation swings
   around - the rotated tab's bottom edge lands exactly at this y, then
   extends upward - so `calc(100vh - 24px)` keeps a consistent 24px gap
   above the viewport bottom at any window height instead of a value
   tuned for one specific screen. Left transform/transform-origin
   untouched (top right, as twenty-one set it) since changing the pivot
   corner without redoing the rotation direction pushes the tab
   off-screen sideways instead - tried that first, caught it by checking
   getBoundingClientRect() live rather than trusting the math by eye.
   Selector matches twenty-one/six's own (theme.css ~L9767) so this wins
   on both specificity and source order (loads after). */
.btn-return-to-admin,
.btn-return-to-admin .floating {
    top: calc(100vh - 24px) !important;
    right: 0 !important;
    padding: var(--ih-space-2) var(--ih-space-4) !important;
    background-color: var(--ih-blue-900) !important;
    color: var(--ih-white) !important;
    font-size: var(--ih-text-sm) !important;
    font-weight: 600;
    border-radius: var(--ih-radius-sm) var(--ih-radius-sm) 0 0 !important;
    box-shadow: var(--ih-shadow-sm);
}

.btn-return-to-admin:hover,
.btn-return-to-admin .floating:hover {
    background-color: var(--ih-blue-950) !important;
    color: var(--ih-white) !important;
}

/* -------------------------------------------------------------------------
   13. Inner pages
   -------------------------------------------------------------------------
   Most of what is not the landing page still renders through the
   inherited twenty-one templates, restyled without restructuring - see
   IHOST_THEME_PLAN.md 1.25 for which few (Contact, Announcements,
   Network Status, so far) got a real template rewrite instead, and why
   the rest (Store browsing, Knowledgebase, Submit Ticket, Client Area's
   transactional pages) deliberately did not in this pass. */

/* header.tpl gives both branches id="main-body" - the inner-page
   <section> (styled here) and the landing page's own <main class="ih-main">
   (which supplies its own full-bleed sections and must NOT get this
   padding/background). A bare #main-body selector caught both, pushing
   the landing page's hero down by --ih-space-10 and leaving this sunken
   grey visible above it, behind the fixed transparent header, until the
   page was scrolled - confirmed live via getBoundingClientRect() showing
   .ih-hero starting 40px below the viewport top instead of at 0. Scoped
   to section#main-body, matching how twenty-one's own core CSS scopes
   the same ID (theme.css), so it can no longer match the <main>. */
section#main-body { padding-block: var(--ih-space-10); background: var(--ih-surface-sunken); }

/* Bootstrap's own .breadcrumb (via .master-breadcrumb's wrapper) still
   had default Bootstrap grey text, default "/" separators and cramped
   padding - never actually restyled before, just given a background.
   Quiet wayfinding, not a heavy component: small, brand blue links,
   a chevron separator instead of the default slash. */
.master-breadcrumb {
    background: var(--ih-surface);
    border-bottom: 1px solid var(--ih-border);
    padding-block: var(--ih-space-4);
}

.master-breadcrumb .breadcrumb {
    margin: 0;
    padding: 0;
    background: transparent;
    font-size: var(--ih-text-sm);
}

.master-breadcrumb .breadcrumb-item a {
    color: var(--ih-text-muted);
    transition: color var(--ih-dur-fast) var(--ih-ease);
}

.master-breadcrumb .breadcrumb-item a:hover { color: var(--ih-blue-600); }
.master-breadcrumb .breadcrumb-item.active { color: var(--ih-text); font-weight: 600; }

.master-breadcrumb .breadcrumb-item + .breadcrumb-item::before {
    /* This install ships Font Awesome 5 PRO, not the "Free" package -
       confirmed by grepping the actual @font-face rules in
       assets/css/fontawesome-all.min.css, which only define "Font
       Awesome 5 Pro" (plus Brands/Duotone). "Font Awesome 5 Free" isn't
       a loaded font here at all, so the glyph fell back to .notdef (a
       hollow square) instead of erroring - caught live, not assumed
       from writing the rule. */
    font-family: "Font Awesome 5 Pro";
    font-weight: 900;
    content: "\f105"; /* fa-chevron-right */
    font-size: 0.7em;
    color: var(--ih-border-strong);
}

/* ---- Page head - includes/page-banner.tpl ------------------------------
   Reuses the landing page's own section-header language (.ih-eyebrow +
   a section-title-scale heading), not an invented component - see the
   include's own header comment for why the first version (a navy
   gradient card borrowed from .ih-cta) was wrong: that gradient means
   "promotional moment" everywhere else it's used, and a plain page
   title isn't one. */
.ih-page-head {
    max-width: 46rem;
    margin-bottom: var(--ih-space-10);
}

.ih-page-head .ih-eyebrow { display: flex; align-items: center; gap: var(--ih-space-2); }

.ih-page-title {
    font-size: var(--ih-text-3xl);
    margin: 0 0 var(--ih-space-2);
    color: var(--ih-text);
}

.ih-page-sub {
    font-size: var(--ih-text-lg);
    line-height: var(--ih-leading-snug);
    color: var(--ih-text-muted);
    margin: 0;
}

/* ---- Sidebar (includes/sidebar.tpl, twenty-one's own generic,
   data-driven menu - Knowledgebase categories, Announcements' by-month
   list, ticket departments, and more all render through this one
   template with different content, so this has to work generically,
   not per-page). Never restyled before now - was plain unstyled
   Bootstrap cards sitting next to fully redesigned content. Card
   language matches .ih-panel (§14) so the two component systems read
   as one, not two. --------------------------------------------------- */
.card-sidebar {
    background: var(--ih-surface);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    box-shadow: var(--ih-shadow-sm);
    overflow: hidden;
}

.card-sidebar .card-header {
    display: flex;
    align-items: center;
    padding: var(--ih-space-4) var(--ih-space-5);
    background: var(--ih-surface-sunken);
    border-bottom: 1px solid var(--ih-border);
}

.card-sidebar .card-title {
    display: flex;
    align-items: center;
    gap: var(--ih-space-2);
    flex: 1;
    font-size: var(--ih-text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--ih-tracking-wide);
    color: var(--ih-text);
}

.card-sidebar .card-title i:first-child { color: var(--ih-blue-600); }
.card-sidebar .card-title .badge { background: var(--ih-blue-100); color: var(--ih-blue-700); font-weight: 700; }
.card-sidebar .card-minimise { color: var(--ih-text-subtle); }

.card-sidebar .list-group-item {
    display: flex;
    align-items: center;
    padding: var(--ih-space-3) var(--ih-space-5);
    border: 0;
    border-bottom: 1px solid var(--ih-border);
    color: var(--ih-text-muted);
    font-size: var(--ih-text-sm);
    transition: background-color var(--ih-dur-fast) var(--ih-ease), color var(--ih-dur-fast) var(--ih-ease);
}

.card-sidebar .list-group-item:last-child { border-bottom: 0; }

/* The actual culprit behind the "grey background, blue text" report,
   found by checking the live computed style rather than the source:
   twenty-one's own theme.css has .sidebar .list-group-item.active {
   background-color: #666 } (theme.css ~L10439) - a literal hardcoded
   grey, not a token, not something this theme ever set. That selector
   and this one below were TIED on specificity (three classes each),
   and twenty-one's kept winning despite ihost.css loading later in
   the document - confirmed via document.styleSheets which rule
   actually wins is not something worth re-deriving by hand next time,
   check it live. Fixed by prefixing `.sidebar` here too, so this
   selector is unambiguously MORE specific instead of hoping source
   order breaks the tie the way it's supposed to - that's the entire
   fix. §1.26 also swapped --ih-blue-50 for --ih-blue-100 here, on a
   mistaken read of what was wrong before the real #666 cause was
   found - reverted back to --ih-blue-50 on request, which also
   restores consistency with .ih-nav-link:hover and every other hover
   state elsewhere in the theme that was never touched. Active still
   gets bold weight, so it reads as distinct from a transient :hover
   on the same item without needing a different background to do it. */
.sidebar .card-sidebar .list-group-item:hover {
    background: var(--ih-blue-50);
    color: var(--ih-blue-600);
}

.sidebar .card-sidebar .list-group-item.active {
    background: var(--ih-blue-50);
    color: var(--ih-blue-700);
    font-weight: 600;
}

.card-sidebar .sidebar-menu-item-wrapper { display: flex; align-items: center; gap: var(--ih-space-3); width: 100%; }
.card-sidebar .sidebar-menu-item-icon { color: var(--ih-text-subtle); width: 1.1em; }
.card-sidebar .list-group-item:hover .sidebar-menu-item-icon,
.card-sidebar .list-group-item.active .sidebar-menu-item-icon { color: var(--ih-blue-600); }
.card-sidebar .sidebar-menu-item-label { flex: 1; }
.card-sidebar .sidebar-menu-item-badge .badge { background: var(--ih-blue-100); color: var(--ih-blue-700); }

.card-sidebar .card-body { padding: var(--ih-space-5); font-size: var(--ih-text-sm); }
.card-sidebar .card-footer {
    padding: var(--ih-space-3) var(--ih-space-5);
    background: var(--ih-surface-sunken);
    border-top: 1px solid var(--ih-border);
    font-size: var(--ih-text-sm);
}

/* ---- Contact page ------------------------------------------------------ */
.ih-contact-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--ih-space-6);
    align-items: start;
}

@media (min-width: 992px) { .ih-contact-grid { grid-template-columns: 1.4fr 1fr; } }

.ih-contact-form-card,
.ih-contact-aside {
    background: var(--ih-surface);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    box-shadow: var(--ih-shadow-sm);
}

.ih-contact-form-card { padding: var(--ih-space-6); }

.ih-contact-form-card .form-group label {
    font-weight: 600;
    font-size: var(--ih-text-sm);
    color: var(--ih-text);
}

.ih-contact-aside-item {
    display: flex;
    align-items: flex-start;
    gap: var(--ih-space-4);
    padding: var(--ih-space-5);
    border-bottom: 1px solid var(--ih-border);
    color: inherit;
    transition: background-color var(--ih-dur-fast) var(--ih-ease);
}

.ih-contact-aside-item:last-child { border-bottom: none; }
a.ih-contact-aside-item:hover { background: var(--ih-surface-sunken); color: inherit; }

.ih-contact-aside-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: var(--ih-radius);
    background: var(--ih-blue-50);
    color: var(--ih-blue-600);
}

.ih-contact-aside-title { font-weight: 600; font-size: var(--ih-text-sm); margin-bottom: 2px; }
.ih-contact-aside-sub { font-size: var(--ih-text-xs); color: var(--ih-text-muted); }

/* ---- Announcements ------------------------------------------------------ */
.ih-announcement-card {
    padding: var(--ih-space-6);
    background: var(--ih-surface);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    margin-bottom: var(--ih-space-5);
    transition: box-shadow var(--ih-dur) var(--ih-ease), border-color var(--ih-dur) var(--ih-ease);
}

.ih-announcement-card:hover { box-shadow: var(--ih-shadow); border-color: var(--ih-blue-200); }

.ih-announcement-title { font-size: var(--ih-text-xl); margin-bottom: var(--ih-space-2); }
.ih-announcement-title a { color: var(--ih-text); }
.ih-announcement-title a:hover { color: var(--ih-blue-600); }

.ih-announcement-meta {
    display: flex;
    align-items: center;
    gap: var(--ih-space-2);
    font-size: var(--ih-text-sm);
    color: var(--ih-text-muted);
    margin-bottom: var(--ih-space-3);
}

.ih-announcement-body { color: var(--ih-text-muted); margin-bottom: var(--ih-space-4); }

/* ---- Announcement detail (viewannouncement.tpl) - shares
   .ih-announcement-card/.ih-announcement-meta with the list page
   (announcements.tpl) so a preview and its full article read as one
   system; only the title needs to be bigger here; it's the page's
   main content, not a card heading in a list. */
.ih-announcement-detail-title {
    font-size: var(--ih-text-3xl);
    margin-bottom: var(--ih-space-3);
}

.ih-announcement-detail-body {
    color: var(--ih-text);
    line-height: var(--ih-leading-normal);
    padding-block: var(--ih-space-5);
}

/* ---- Network status ------------------------------------------------------ */
.ih-status-table-card {
    padding: var(--ih-space-6);
    background: var(--ih-surface);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    box-shadow: var(--ih-shadow-sm);
    margin-bottom: var(--ih-space-6);
}

.ih-issue-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ih-space-4);
    font-size: var(--ih-text-sm);
    color: var(--ih-text-muted);
    margin-bottom: var(--ih-space-3);
}

/* Priority badges reuse .ih-badge's shape, adding the semantic colours
   .ih-badge itself never needed (it only ever had one, brand-blue,
   use before this) - status meaning has to read at a glance here, so
   colour is doing real work, not decoration. */
.ih-badge--danger  { background: var(--ih-danger-bg);  color: var(--ih-danger-text); }
.ih-badge--warning { background: var(--ih-warning-bg); color: var(--ih-warning-text); }
.ih-badge--success { background: var(--ih-success-bg); color: var(--ih-success-text); }
.ih-badge--info    { background: var(--ih-blue-50);    color: var(--ih-blue-700); }

/* -------------------------------------------------------------------------
   14. Client dashboard
   -------------------------------------------------------------------------
   clientareahome.tpl. The panel markup below (.ih-panel, .ih-panel-list)
   is a re-skin of WHMCS's own ClientAreaHomepagePanels contract - the
   Gift Cards addon renders a real panel through it. See the note at the
   top of clientareahome.tpl before changing this template's logic. */

.ih-stat-tiles {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--ih-space-4);
    margin-bottom: var(--ih-space-8);
}

@media (min-width: 1200px) {
    .ih-stat-tiles { grid-template-columns: repeat(4, 1fr); }
}

.ih-stat-tile {
    display: flex;
    flex-direction: column;
    gap: var(--ih-space-1);
    padding: var(--ih-space-5);
    background: var(--ih-surface);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    border-top: 3px solid transparent;
    transition: box-shadow var(--ih-dur-fast) var(--ih-ease),
                border-color var(--ih-dur-fast) var(--ih-ease);
}

.ih-stat-tile:hover {
    box-shadow: var(--ih-shadow);
    color: inherit;
}

.ih-stat-tile i { font-size: var(--ih-text-lg); color: var(--ih-text-subtle); }
.ih-stat-tile-value { font-size: var(--ih-text-2xl); font-weight: 700; color: var(--ih-text); line-height: 1; }
.ih-stat-tile-label { font-size: var(--ih-text-sm); color: var(--ih-text-muted); }

.ih-stat-tile--info    { border-top-color: var(--ih-info); }
.ih-stat-tile--success { border-top-color: var(--ih-success); }
.ih-stat-tile--warning { border-top-color: var(--ih-warning); }
.ih-stat-tile--danger  { border-top-color: var(--ih-danger); }

.ih-alert {
    padding: var(--ih-space-4) var(--ih-space-5);
    border-radius: var(--ih-radius);
    font-size: var(--ih-text-sm);
    margin-bottom: var(--ih-space-6);
}

.ih-alert--danger {
    background: var(--ih-danger-bg);
    color: var(--ih-danger-text);
    border: 1px solid var(--ih-danger);
}

.ih-alert--warning {
    background: var(--ih-warning-bg);
    color: var(--ih-warning-text);
    border: 1px solid var(--ih-warning);
}

.ih-alert--success {
    background: var(--ih-success-bg);
    color: var(--ih-success-text);
    border: 1px solid var(--ih-success);
}

.ih-alert--info {
    background: var(--ih-blue-50);
    color: var(--ih-blue-700);
    border: 1px solid var(--ih-blue-200);
}

.ih-badge {
    display: inline-block;
    padding: 0.15em 0.55em;
    border-radius: var(--ih-radius-pill);
    font-size: var(--ih-text-xs);
    font-weight: 600;
    background: var(--ih-blue-100);
    color: var(--ih-blue-700);
}

.ih-panel-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--ih-space-6);
}

@media (min-width: 992px) {
    .ih-panel-grid { grid-template-columns: 1fr 1fr; }
    .ih-panel-grid-full { grid-column: 1 / -1; }
}

.ih-panel-grid-full,
.ih-panel-grid-col {
    display: flex;
    flex-direction: column;
    gap: var(--ih-space-6);
}

.ih-panel {
    background: var(--ih-surface);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    border-top: 3px solid var(--ih-border-strong);
    overflow: hidden;
}

.ih-panel--accent-blue   { border-top-color: var(--ih-info); }
.ih-panel--accent-green  { border-top-color: var(--ih-success); }
.ih-panel--accent-red    { border-top-color: var(--ih-danger); }
.ih-panel--accent-gold   { border-top-color: var(--ih-warning); }

.ih-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ih-space-3);
    padding: var(--ih-space-4) var(--ih-space-5);
    border-bottom: 1px solid var(--ih-border);
}

.ih-panel-title {
    display: flex;
    align-items: center;
    gap: var(--ih-space-2);
    margin: 0;
    font-size: var(--ih-text-base);
    font-weight: 600;
}

.ih-panel-title i { color: var(--ih-text-subtle); }

.ih-panel-body { padding: var(--ih-space-5); }

/* Panel bodies are set via setBodyHtml() by modules (e.g. Gift Cards),
   authored against Bootstrap's own .form-control / .btn classes - those
   still render via the inherited BS4 CSS, so this only needs spacing. */
.ih-panel-body .form-group:last-child { margin-bottom: 0; }

.ih-panel-list { border-top: 1px solid var(--ih-border); }

.ih-panel-list-item {
    display: flex;
    align-items: center;
    gap: var(--ih-space-2);
    padding: var(--ih-space-3) var(--ih-space-5);
    color: var(--ih-text);
    border-bottom: 1px solid var(--ih-border);
    transition: background-color var(--ih-dur-fast) var(--ih-ease);
}

.ih-panel-list-item:last-child { border-bottom: none; }

a.ih-panel-list-item:hover,
a.ih-panel-list-item.active {
    background: var(--ih-surface-sunken);
    color: var(--ih-blue-600);
}

.ih-panel-list-item i { color: var(--ih-text-subtle); width: 1.1em; }

.ih-panel-footer {
    padding: var(--ih-space-4) var(--ih-space-5);
    border-top: 1px solid var(--ih-border);
    background: var(--ih-surface-sunken);
}

/* -------------------------------------------------------------------------
   14b. Knowledgebase
   -------------------------------------------------------------------------
   knowledgebase.tpl (index), knowledgebasecat.tpl (a category's
   articles), knowledgebasearticle.tpl (one article) - three real
   template rewrites sharing one component set, since twenty-one's
   originals already share the same search bar / category-card /
   article-list markup across all three. Article lists reuse
   .ih-panel/.ih-panel-list (§14, already built for the client
   dashboard) rather than a new component - only .ih-panel-list-item
   needed a variant, since a KB article needs a title *and* an excerpt
   line, not just a single-line label. */

.ih-kb-search { margin-bottom: var(--ih-space-8); }

.ih-kb-search-group { display: flex; gap: var(--ih-space-2); }

.ih-kb-search-input {
    flex: 1;
    padding: 0.85rem 1.1rem;
    border: 1px solid var(--ih-border-strong);
    border-radius: var(--ih-radius);
    font-size: var(--ih-text-base);
    background: var(--ih-surface);
}

.ih-kb-search-input:focus {
    outline: none;
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

.ih-kb-cat-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--ih-space-4);
    margin-bottom: var(--ih-space-6);
}

@media (min-width: 768px) { .ih-kb-cat-grid { grid-template-columns: repeat(2, 1fr); } }

.ih-kb-cat-card {
    display: flex;
    align-items: flex-start;
    gap: var(--ih-space-4);
    padding: var(--ih-space-5);
    background: var(--ih-surface);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    color: inherit;
    transition: transform var(--ih-dur) var(--ih-ease-out),
                border-color var(--ih-dur) var(--ih-ease),
                box-shadow var(--ih-dur) var(--ih-ease);
}

.ih-kb-cat-card:hover {
    transform: translateY(-2px);
    border-color: var(--ih-blue-200);
    box-shadow: var(--ih-shadow);
    color: inherit;
}

.ih-kb-cat-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: var(--ih-radius);
    background: var(--ih-blue-50);
    color: var(--ih-blue-600);
    font-size: 1.1rem;
}

.ih-kb-cat-name {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ih-space-2);
    font-weight: 700;
    color: var(--ih-text);
    margin-bottom: var(--ih-space-1);
}

.ih-kb-cat-desc { font-size: var(--ih-text-sm); color: var(--ih-text-muted); margin: 0; }

/* Title + excerpt stacked, instead of .ih-panel-list-item's default
   single-line icon+label row - everything else (hover, border,
   spacing) is inherited unchanged. */
.ih-panel-list-item--kb { align-items: flex-start; gap: var(--ih-space-3); }
.ih-panel-list-item--kb i { margin-top: 0.2em; }
.ih-panel-list-item--kb-title { display: block; font-weight: 600; color: var(--ih-text); margin-bottom: 2px; }
a.ih-panel-list-item--kb:hover .ih-panel-list-item--kb-title { color: var(--ih-blue-600); }
.ih-panel-list-item--kb-excerpt { display: block; font-size: var(--ih-text-sm); color: var(--ih-text-muted); }

.ih-kb-article-meta {
    display: flex;
    align-items: center;
    gap: var(--ih-space-4);
    padding-bottom: var(--ih-space-5);
    margin-bottom: var(--ih-space-5);
    border-bottom: 1px solid var(--ih-border);
    font-size: var(--ih-text-sm);
    color: var(--ih-text-muted);
}

.ih-kb-article-body { color: var(--ih-text); line-height: var(--ih-leading-normal); margin-bottom: var(--ih-space-6); }

.ih-kb-vote { padding-top: var(--ih-space-5); border-top: 1px solid var(--ih-border); }
.ih-kb-vote h4 { font-size: var(--ih-text-base); margin-bottom: var(--ih-space-3); }

/* Same visual treatment as .ih-announcement-card/-detail-title (§13,
   viewannouncement.tpl) - a card wrapping one long-form piece of
   content with a big title - but kept as separate rules rather than
   sharing the class, since .ih-announcement-card is also used for
   announcements.tpl's list-preview cards and the FB-comments wrapper;
   reusing it here risked an edit meant for KB quietly touching an
   already-shipped, unrelated page. */
.ih-kb-article-card {
    padding: var(--ih-space-6);
    background: var(--ih-surface);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    margin-bottom: var(--ih-space-5);
}

.ih-kb-article-title {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--ih-space-4);
    font-size: var(--ih-text-3xl);
    margin-bottom: var(--ih-space-3);
}

/* -------------------------------------------------------------------------
   15. Bootstrap 3 compatibility
   -------------------------------------------------------------------------
   The Contabo VPS control panel and the gift-card templates were authored
   in BS3 idiom (.panel, .btn-default, .label-*, .help-block). twenty-one
   ships shims that keep them rendering; those shims are inherited, but
   they are styled for the OLD look. These rules re-skin the BS3 classes to
   the new design language WITHOUT touching the module templates, so the
   modules stay exactly as tested.

   Class inventory taken from the module templates themselves, not guessed
   (re-counted, not assumed - grep against clientarea.tpl):
     btn-default 11, panel-title 6, panel-heading 6, panel-default 5,
     panel-body 5, panel-danger 1, help-block 3, label 1, input-sm 1.
   Every one of those is covered below.

   See IHOST_THEME_PLAN.md section 6 — restyle only, never restructure. */

.panel {
    margin-bottom: var(--ih-space-6);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
    box-shadow: var(--ih-shadow-sm);
}

.panel-heading {
    padding: var(--ih-space-4) var(--ih-space-5);
    border-bottom: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg) var(--ih-radius-lg) 0 0;
    background: var(--ih-surface-sunken);
    font-family: var(--ih-font-display);
    font-weight: 700;
    letter-spacing: var(--ih-tracking-tight);
    color: var(--ih-text);
}

.panel-title { margin: 0; font-size: var(--ih-text-lg); }
.panel-body  { padding: var(--ih-space-5); }
.panel-footer {
    padding: var(--ih-space-4) var(--ih-space-5);
    border-top: 1px solid var(--ih-border);
    border-radius: 0 0 var(--ih-radius-lg) var(--ih-radius-lg);
    background: var(--ih-surface-sunken);
}

/* Verified in-browser: without this, the Contabo panel's irreversible
   "Reinstall operating system" action (wipes all data - clientarea.tpl
   marks it panel-danger for exactly this reason) rendered pixel-identical
   to "Add-ons". The plan calls for "clearer destructive-action framing"
   and this closes that gap without touching the module template. */
.panel-danger {
    border-color: var(--ih-danger);
}

.panel-danger > .panel-heading {
    background: var(--ih-danger-bg);
    color: var(--ih-danger-text);
    border-bottom-color: var(--ih-danger);
}

.btn-default {
    border-color: var(--ih-border-strong);
    background: var(--ih-surface);
    color: var(--ih-text);
}

.btn-default:hover {
    border-color: var(--ih-blue-600);
    background: var(--ih-blue-50);
    color: var(--ih-blue-600);
}

.label {
    display: inline-block;
    padding: 0.25em 0.6em;
    border-radius: var(--ih-radius-pill);
    font-size: 0.78em;
    font-weight: 600;
}

.label-success { background: var(--ih-success-bg); color: var(--ih-success-text); }
.label-warning { background: var(--ih-warning-bg); color: var(--ih-warning-text); }
.label-danger  { background: var(--ih-danger-bg);  color: var(--ih-danger-text); }
.label-default { background: var(--ih-gray-100);   color: var(--ih-gray-600); }
.label-info    { background: var(--ih-info-bg);    color: var(--ih-info); }

.help-block { font-size: var(--ih-text-sm); color: var(--ih-text-subtle); }

/* BS3 sized the small input with .input-sm; BS4 renamed it
   .form-control-sm and never shipped the old name. The Contabo panel
   still uses .input-sm, so it needs a real rule or that field renders at
   full size next to the small buttons beside it. */
.input-sm {
    height: calc(1.5em + 0.5rem + 2px);
    padding: 0.25rem 0.5rem;
    font-size: var(--ih-text-sm);
    line-height: 1.5;
    border-radius: var(--ih-radius-sm);
}

/* -------------------------------------------------------------------------
   16. Service detail
   -------------------------------------------------------------------------
   clientareaproductdetails.tpl. Unlike the Contabo panel or the client
   dashboard, nothing on this page is a module hook contract - so instead
   of re-skinning Bootstrap's .card / .nav-tabs globally (which would also
   hit invoices, tickets, and every other inherited page reusing those
   same classes), the template wraps everything in .ih-service-detail and
   every rule below is scoped under it. Nothing here leaks to other pages.

   .ih-panel / .ih-panel-body / .ih-panel-header / .ih-panel-title /
   .ih-panel-footer / .ih-panel--accent-* / .ih-badge are reused as-is from
   "14. Client dashboard" above - those are already this theme's own
   component classes, not a framework's shared ones, so reusing them here
   is safe by the same logic that makes re-skinning .panel (Contabo, BS3-
   only, module-scoped) safe: nothing else on the site uses them yet. */

.ih-product-status {
    text-align: center;
    padding: var(--ih-space-5);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface-sunken);
}

.ih-product-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    margin-bottom: var(--ih-space-2);
    border-radius: 50%;
    background: var(--ih-blue-100);
    color: var(--ih-blue-600);
    font-size: var(--ih-text-xl);
}

.ih-product-status h3 { margin: 0; font-size: var(--ih-text-lg); }
.ih-product-status h4 { margin: 0 0 var(--ih-space-3); font-size: var(--ih-text-sm); font-weight: 400; color: var(--ih-text-muted); }

.ih-product-status-badge {
    display: inline-block;
    padding: 0.3em 0.9em;
    border-radius: var(--ih-radius-pill);
    font-size: var(--ih-text-sm);
    font-weight: 600;
    background: var(--ih-gray-100);
    color: var(--ih-gray-600);
}

.ih-product-status--active .ih-product-icon,
.ih-product-status--completed .ih-product-icon {
    background: var(--ih-success-bg);
    color: var(--ih-success);
}
.ih-product-status--active .ih-product-status-badge,
.ih-product-status--completed .ih-product-status-badge {
    background: var(--ih-success-bg);
    color: var(--ih-success-text);
}

.ih-product-status--pending .ih-product-icon { background: var(--ih-info-bg); color: var(--ih-info); }
.ih-product-status--pending .ih-product-status-badge { background: var(--ih-info-bg); color: var(--ih-info); }

.ih-product-status--suspended .ih-product-icon { background: var(--ih-warning-bg); color: var(--ih-warning); }
.ih-product-status--suspended .ih-product-status-badge { background: var(--ih-warning-bg); color: var(--ih-warning-text); }

.ih-product-status--terminated .ih-product-icon,
.ih-product-status--cancelled .ih-product-icon,
.ih-product-status--fraud .ih-product-icon {
    background: var(--ih-danger-bg);
    color: var(--ih-danger);
}
.ih-product-status--terminated .ih-product-status-badge,
.ih-product-status--cancelled .ih-product-status-badge,
.ih-product-status--fraud .ih-product-status-badge {
    background: var(--ih-danger-bg);
    color: var(--ih-danger-text);
}

.ih-service-detail .ih-service-nav-tabs {
    border-bottom: 2px solid var(--ih-border);
    margin-bottom: 0;
}

.ih-service-detail .ih-service-nav-tabs .nav-link {
    border: none;
    color: var(--ih-text-muted);
    font-weight: 600;
    font-size: var(--ih-text-sm);
    padding: var(--ih-space-3) var(--ih-space-4);
}

.ih-service-detail .ih-service-nav-tabs .nav-link:hover {
    border: none;
    color: var(--ih-blue-600);
}

.ih-service-detail .ih-service-nav-tabs .nav-link.active {
    border: none;
    border-bottom: 2px solid var(--ih-blue-600);
    margin-bottom: -2px;
    color: var(--ih-blue-600);
    background: transparent;
}

.ih-service-detail .ih-service-tab-container {
    padding: var(--ih-space-5);
    background: var(--ih-surface);
    border: 1px solid var(--ih-border);
    border-top: none;
    border-radius: 0 0 var(--ih-radius-lg) var(--ih-radius-lg);
}

/* -------------------------------------------------------------------------
   17. Checkout
   -------------------------------------------------------------------------
   templates/orderforms/standard_cart/checkout.tpl - NOT overridden.

   A real child order-form theme (templates/orderforms/ihost_cart/) was
   built and activated first, the same way the rest of Phase 3 restyled
   pages by wrapping/extending the parent's markup. It never rendered:
   confirmed live that {include file="orderforms/$carttpl/checkout.tpl"}
   in the parent's own viewcart.tpl resolves via a Smarty variable that
   stays fixed to "standard_cart" regardless of the OrderFormTemplate
   config - verified by switching that setting to the stock premium_
   comparison theme and watching its products.tpl pick it up correctly
   (its own style.css loaded) while checkout.tpl still compiled from
   standard_cart every time (checked the compiled templates_c output
   directly, which names its literal source path). Products.tpl-style
   order-form theming and checkout.tpl are two different resolution
   paths on this WHMCS version; only the first honours OrderFormTemplate.
   ihost_cart added nothing checkout.tpl could use and was removed rather
   than left as dead code someone might later think is live.

   So checkout is restyled the same way clientareaproductdetails.tpl
   handles pages built from Bootstrap's own shared classes: scope
   everything under the one stable, always-present container ID
   (#order-standard_cart - confirmed present regardless of which
   order-form theme is configured, since it's hardcoded in checkout.tpl
   itself) rather than touching a template file that cannot actually be
   overridden here. The progress indicator and trust-signal line the plan
   calls for are added by JS instead of Smarty, since that's the only
   layer that reliably runs on whatever checkout.tpl actually ships -
   see initCheckoutEnhancements() in js/ihost.js. Nothing here or there
   touches the payment form's own fields, ids, or submit handling. */

#order-standard_cart .order-summary {
    border-radius: var(--ih-radius-lg);
    box-shadow: var(--ih-shadow);
}

#order-standard_cart .order-summary .total-due-today .amt {
    color: var(--ih-blue-600);
}

#order-standard_cart #btnCompleteOrder {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
    color: var(--ih-white);
}

#order-standard_cart #btnCompleteOrder:hover,
#order-standard_cart #btnCompleteOrder:focus {
    background: var(--ih-blue-700);
    border-color: var(--ih-blue-700);
    color: var(--ih-white);
}

/* Keeps the total-due banner in view while the (long) form scrolls,
   without needing new server data - it already has the real total.
   `top` is set from JS (initCheckoutEnhancements in js/ihost.js), not a
   fixed value here: .ih-header's real height varies (a masquerading-
   admin bar alone adds ~40px on top of the normal nav), and a hardcoded
   guess would either leave a gap or - confirmed live, this genuinely
   happened during testing - sit hidden behind the header entirely,
   since both are position: sticky at the top of the same scroll
   context. Falls back to 8px if JS never runs (progressive
   enhancement - the total is still visible in normal document flow,
   just not sticky). */
#order-standard_cart #totalDueToday {
    position: sticky;
    top: 8px;
    z-index: 5;
}

.ih-checkout-steps {
    display: flex;
    align-items: center;
    gap: var(--ih-space-2);
    margin-bottom: var(--ih-space-6);
    font-size: var(--ih-text-sm);
    font-weight: 600;
    color: var(--ih-text-subtle);
}

.ih-checkout-step-sep {
    flex: 0 0 32px;
    height: 1px;
    background: var(--ih-border);
}

.ih-checkout-step--done { color: var(--ih-success-text); }
.ih-checkout-step--done i { margin-right: 4px; }
.ih-checkout-step--current { color: var(--ih-blue-600); }

.ih-checkout-trust {
    margin: 0 0 var(--ih-space-3);
    font-size: var(--ih-text-sm);
    color: var(--ih-text-subtle);
}

.ih-checkout-trust i {
    color: var(--ih-success);
    margin-right: 4px;
}

/* -------------------------------------------------------------------------
   18. Utilities
   ------------------------------------------------------------------------- */

.ih-center { text-align: center; }
.ih-mt-8   { margin-top: var(--ih-space-8); }
.ih-mb-6   { margin-bottom: var(--ih-space-6); }
.ih-stack  { display: flex; flex-direction: column; gap: var(--ih-space-4); }

.ih-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* -------------------------------------------------------------------------
   19. Scroll reveal
   -------------------------------------------------------------------------
   js/ihost.js's initScrollReveal() adds .ih-reveal to landing-page cards
   and section headings on page load, then swaps in .ih-revealed via
   IntersectionObserver as each one enters the viewport - progressive
   enhancement, same rule this file already holds itself to (see its own
   header comment): a class JS ADDS, never one baked into the template,
   so with JS disabled or failed nothing is ever hidden in the first
   place. Respects prefers-reduced-motion automatically - it's the same
   `transition` property tokens.css's global media query already zeroes
   out, no separate opt-out needed here. */
.ih-reveal {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity var(--ih-dur-slow) var(--ih-ease-out),
                transform var(--ih-dur-slow) var(--ih-ease-out);
}

.ih-reveal.ih-revealed { opacity: 1; transform: translateY(0); }

/* -------------------------------------------------------------------------
   20. Auth & account pages (task #45/§1.39)
   -------------------------------------------------------------------------
   login.tpl, password-reset-container.tpl (+ its four -*-prompt.tpl
   partials), two-factor-challenge.tpl, two-factor-new-backup-code.tpl,
   user-verify-email.tpl, clientregister.tpl - all in templates/twenty-one/,
   none overridden here. CSS-only, no new template files needed at all:
   unlike the orderforms/ work, these pages DO fall through the normal
   child-theme chain, so ihost.css (loaded on every page regardless of
   which template rendered the body) reaches their classes directly.

   Two scopes. `.card.mw-540` is twenty-one's own "single centered card"
   component - used by every page above except clientregister.tpl, and
   also by a few pages outside this task (store/not-found.tpl,
   subscription-manage.tpl, user-switch-account*.tpl), which get this
   styling for free since the treatment is generic to the component, not
   specific to auth. `#registration` scopes clientregister.tpl's own
   multi-card form, which is a near-exact structural twin of
   checkout.tpl's account-creation section (.prepend-icon/.field-icon/
   .field, the password-strength meter's own ids) - same reasoning as
   every CSS-only page in Phase A: preserve every id, restyle only.
   The .pw-input/.btn-reveal-pw password-reveal toggle on login.tpl
   (bound in twenty-one/js/scripts.js) is untouched either way.

   Also added: real theming for includes/alert.tpl's `.alert-{type}`
   output, UNSCOPED (not just for these pages) - that partial is shared
   across most of templates/twenty-one/, so this is a real, deliberate
   head start on every page still to come in Phases B-D, not scope
   creep. Compound-class selectors (`.alert.alert-danger`, not just
   `.alert-danger`) deliberately, for the same specificity-safety reason
   as every #order-standard_cart rule in this file - includes/alert.tpl
   always emits both classes together, so this costs nothing and avoids
   relying on stylesheet load order to win the cascade. */

.alert.alert-danger { background: var(--ih-danger-bg); color: var(--ih-danger-text); border-color: var(--ih-danger); }
.alert.alert-warning { background: var(--ih-warning-bg); color: var(--ih-warning-text); border-color: var(--ih-warning); }
.alert.alert-success { background: var(--ih-success-bg); color: var(--ih-success-text); border-color: var(--ih-success); }
.alert.alert-info { background: var(--ih-blue-50); color: var(--ih-blue-700); border-color: var(--ih-blue-200); }

.card.mw-540 {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    box-shadow: var(--ih-shadow);
}

.card.mw-540 .card-title,
.card.mw-540 h6.h3 {
    font-family: var(--ih-font-display);
    font-weight: 800;
    color: var(--ih-text);
}

.card.mw-540 .card-footer {
    background: var(--ih-surface-sunken);
    border-top: 1px solid var(--ih-border);
}

.card.mw-540 .input-group-text {
    background: var(--ih-surface-sunken);
    border-color: var(--ih-border-strong);
    color: var(--ih-text-subtle);
}

.card.mw-540 .form-control { border-color: var(--ih-border-strong); }

.card.mw-540 .form-control:focus {
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

.card.mw-540 .btn-primary {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
}

.card.mw-540 .btn-primary:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

/* clientregister.tpl */
#registration .card {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
}

#registration .card-title {
    font-family: var(--ih-font-display);
    font-weight: 800;
    margin-bottom: var(--ih-space-4);
}

#registration .field,
#registration .form-control {
    border-color: var(--ih-border-strong);
}

#registration .field:focus,
#registration .form-control:focus {
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

#registration .btn-primary {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
}

#registration .btn-primary:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

/* -------------------------------------------------------------------------
   21. Billing: invoices, quotes, add funds (task #46/§1.40)
   -------------------------------------------------------------------------
   Three sub-groups, three different reasons for the technique used:

   1. viewinvoice.tpl/viewquote.tpl render as standalone HTML documents
      (their own <head>, no header.tpl/footer.tpl) by design - meant to
      be printable/downloadable, not carry site nav. ihost.css was
      never loaded on them at all until this task's two purely-additive
      overrides (two new <link> tags, nothing else changed) gave them
      the same tokens.css/ihost.css include includes/head.tpl uses
      everywhere else. Scoped under .invoice-container, the wrapper
      already present in the original markup on both pages.

   2. clientareaaddfunds.tpl/invoice-payment.tpl render with normal site
      chrome and use plain, generic .card/.form-control/.btn-primary -
      wrapped in one new .ih-billing-page div (the same scoping
      precedent as .ih-service-detail on clientareaproductdetails.tpl,
      §1.12) so this doesn't reach every other .card on the site
      (KB/announcement sidebars, order-form cards, etc.). CSS-only for
      invoice-payment.tpl specifically - it's the closest thing in this
      task to checkout.tpl's risk profile (WHMCS.payment.event.* gateway
      JS), so no structural changes there at all.

   3. Global, unscoped: includes/tablelist.tpl's DataTables instance
      (clientareainvoices.tpl, clientareaquotes.tpl today; every future
      list page in Phases B-D reuses the exact same partial - tickets,
      domains, downloads), includes/panel.tpl's `.card-title.bg-{type}`
      output (also shared broadly), and .total-row (used by both the
      standalone invoice/quote documents AND payment/invoice-summary.tpl
      inside .ih-billing-page - narrow and stable enough to theme once
      rather than duplicate per scope). All narrow, compound, or
      component-specific enough selectors that global reach is safe -
      none of them are bare Bootstrap utility classes.
   ------------------------------------------------------------------------- */

/* --- 1. Standalone invoice/quote documents --- */

.invoice-container .card {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
}

.invoice-container .card-header {
    background: var(--ih-surface-sunken);
    border-bottom: 1px solid var(--ih-border);
}

.invoice-container .card-title {
    font-family: var(--ih-font-display);
    font-weight: 800;
}

.invoice-container .btn-default {
    border-color: var(--ih-border-strong);
    color: var(--ih-text);
}

.invoice-container .btn-primary,
.invoice-container .btn-success {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
}

.invoice-status span {
    display: inline-block;
    padding: 0.4em 1em;
    border-radius: var(--ih-radius-pill);
    font-size: var(--ih-text-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: var(--ih-tracking-wide);
}

.invoice-status .paid { background: var(--ih-success-bg); color: var(--ih-success-text); }
.invoice-status .unpaid { background: var(--ih-warning-bg); color: var(--ih-warning-text); }
.invoice-status .draft { background: var(--ih-surface-sunken); color: var(--ih-text-subtle); }
.invoice-status .refunded { background: var(--ih-blue-50); color: var(--ih-blue-700); }
.invoice-status .cancelled,
.invoice-status .collections { background: var(--ih-danger-bg); color: var(--ih-danger-text); }

/* --- 2. Add funds / invoice payment --- */

.ih-billing-page .card {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
}

.ih-billing-page .card-title {
    font-family: var(--ih-font-display);
    font-weight: 800;
}

.ih-billing-page .form-control {
    border-color: var(--ih-border-strong);
}

.ih-billing-page .form-control:focus {
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

.ih-billing-page .btn-primary {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
}

.ih-billing-page .btn-primary:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

/* --- 3. Global: DataTables list, shared panel, invoice line totals --- */

.total-row { border-top: 1px solid var(--ih-border); font-weight: 700; }

.card-title.bg-danger  { background: var(--ih-danger) !important; }
.card-title.bg-success { background: var(--ih-success) !important; }
.card-title.bg-warning { background: var(--ih-warning) !important; }
.card-title.bg-info    { background: var(--ih-blue-600) !important; }

.label.status {
    display: inline-block;
    padding: 0.35em 0.9em;
    border-radius: var(--ih-radius-pill);
    font-size: var(--ih-text-xs);
    font-weight: 700;
}

/* $invoice.statusClass/$quote.stageClass render the literal status
   name as the class suffix (confirmed live: an "Unpaid" invoice
   renders class="label status status-unpaid", not a generic
   Bootstrap severity name like "status-warning" as first guessed -
   fixed after live verification caught the mismatch, see
   IHOST_THEME_PLAN.md 1.40). Covers both invoice statuses (Paid/
   Unpaid/Overdue/Cancelled/Refunded/Collections/Draft/Payment Pending)
   and quote stages (Draft/Delivered/Accepted/Declined/Expired/Lost/
   Dead/On Hold) sharing this one component. */
.label.status.status-paid,
.label.status.status-active,
.label.status.status-accepted { background: var(--ih-success-bg); color: var(--ih-success-text); }

.label.status.status-unpaid,
.label.status.status-paymentpending,
.label.status.status-onhold { background: var(--ih-warning-bg); color: var(--ih-warning-text); }

.label.status.status-overdue,
.label.status.status-collections,
.label.status.status-lost,
.label.status.status-declined { background: var(--ih-danger-bg); color: var(--ih-danger-text); }

.label.status.status-refunded,
.label.status.status-delivered { background: var(--ih-blue-50); color: var(--ih-blue-700); }

.label.status.status-draft,
.label.status.status-cancelled,
.label.status.status-expired,
.label.status.status-dead { background: var(--ih-surface-sunken); color: var(--ih-text-subtle); }

.table-container .table-list thead th {
    border-bottom: 2px solid var(--ih-border);
    color: var(--ih-text-subtle);
    font-size: var(--ih-text-xs);
    font-weight: 700;
    letter-spacing: var(--ih-tracking-wide);
    text-transform: uppercase;
}

.table-container .table-list tbody tr { cursor: pointer; transition: background-color var(--ih-dur-fast) var(--ih-ease); }
.table-container .table-list tbody tr:hover { background: var(--ih-blue-50); }
.table-container .table-list tbody td { border-color: var(--ih-border); }

.dataTables_filter input {
    border: 1px solid var(--ih-border-strong);
    border-radius: var(--ih-radius);
    padding: 0.4rem 0.75rem;
}

.dataTables_filter input:focus {
    outline: none;
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

.dataTables_length select {
    border: 1px solid var(--ih-border-strong);
    border-radius: var(--ih-radius);
}

.dataTables_paginate .paginate_button {
    border-radius: var(--ih-radius);
    color: var(--ih-text) !important;
}

.dataTables_paginate .paginate_button.current {
    background: var(--ih-blue-600) !important;
    border-color: var(--ih-blue-600) !important;
    color: var(--ih-white) !important;
}

.dataTables_paginate .paginate_button:hover:not(.current) {
    background: var(--ih-blue-50) !important;
    border-color: var(--ih-blue-200) !important;
    color: var(--ih-blue-700) !important;
}

/* -------------------------------------------------------------------------
   22. Support tickets (task #47/§1.41)
   -------------------------------------------------------------------------
   viewticket.tpl, supportticketsubmit-stepone/-steptwo/-confirm.tpl,
   ticketfeedback.tpl - all wrapped in one new .ih-tickets-page div
   (same precedent as .ih-billing-page/.ih-service-detail), CSS-only.
   supportticketslist.tpl reuses includes/tablelist.tpl - already
   themed globally in §1.40 - so needed no override, just two new
   global rules for what's unique to it (.ticket-number/.ticket-subject,
   plus new .label.status.status-* entries for ticket-specific
   statuses). viewemail.tpl needed nothing at all: it already includes
   includes/head.tpl directly, so it's had ihost.css since day one.

   The star rating widget (.rating/.star) is left completely alone -
   it's a specific shape/sprite/interaction twenty-one's own CSS and JS
   already implement correctly, and this task has no reason to touch
   working, unrelated visual mechanics just because it's on the same
   page as things that do need theming. */

.ih-tickets-page .card {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
}

.ih-tickets-page .card-title {
    font-family: var(--ih-font-display);
    font-weight: 800;
}

.ih-tickets-page .form-control {
    border-color: var(--ih-border-strong);
}

.ih-tickets-page .form-control:focus {
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

.ih-tickets-page .btn-primary {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
}

.ih-tickets-page .btn-primary:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

.ih-tickets-page .btn-default {
    border-color: var(--ih-border-strong);
    color: var(--ih-text);
}

.ih-tickets-page .ticket-reply {
    padding-bottom: var(--ih-space-4);
    border-bottom: 1px solid var(--ih-border);
}

.ih-tickets-page .ticket-reply.staff { background: var(--ih-blue-50); border-radius: var(--ih-radius); }

.ih-tickets-page .posted-by { padding: var(--ih-space-3); font-size: var(--ih-text-sm); border-bottom: 1px solid var(--ih-border); }
.ih-tickets-page .posted-by-name { font-weight: 700; color: var(--ih-text); }
.ih-tickets-page .posted-on { color: var(--ih-text-subtle); }

/* .requestor-badge/.requestor-type-* deliberately NOT touched: twenty-one's
   own theme.css (~L10297) already has a complete, sensible color for
   every real requestor type (operator/owner/authorizeduser/
   registereduser/subaccount/guest) - confirmed live (a real posted
   reply renders class="requestor-type-owner", not the guessed
   "requestor-type-staff" this task first tried, which doesn't match
   any real value at all). Same call as leaving the star-rating widget
   alone: don't restyle an already-complete, working component just
   because it's on a page that needs other things themed. */

.ih-tickets-page .attachment-list { list-style: none; margin: var(--ih-space-2) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--ih-space-2); }

.ih-tickets-page .attachment-list li a,
.ih-tickets-page .attachment-list li span {
    display: flex;
    align-items: center;
    gap: var(--ih-space-2);
    padding: var(--ih-space-2) var(--ih-space-3);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius);
    font-size: var(--ih-text-sm);
    color: var(--ih-text-muted);
}

.ih-tickets-page .attachment-list li a:hover { border-color: var(--ih-blue-600); color: var(--ih-blue-600); }

.ih-tickets-page .custom-file-label {
    border: 1px solid var(--ih-border-strong);
    border-radius: var(--ih-radius) 0 0 var(--ih-radius);
}

.ih-tickets-page .kbarticles .kb-article-item {
    border-color: var(--ih-border);
    transition: background-color var(--ih-dur-fast) var(--ih-ease);
}

.ih-tickets-page .kbarticles .kb-article-item:hover { background: var(--ih-blue-50); }

/* Global: ticket list (supportticketslist.tpl uses includes/tablelist.tpl,
   already themed in §1.40) */
.ticket-number { font-weight: 700; color: var(--ih-text); margin-right: var(--ih-space-2); }
.ticket-subject.unread { font-weight: 700; }
.ticket-subject.unread::after { content: "\2022"; margin-left: var(--ih-space-2); color: var(--ih-blue-600); }

/* Ticket statuses, added to §1.40's .label.status.status-* set (same
   component, same "verify the real class before guessing" discipline -
   see IHOST_THEME_PLAN.md 1.41 for what got corrected here live). */
.label.status.status-open,
.label.status.status-inprogress { background: var(--ih-blue-50); color: var(--ih-blue-700); }
.label.status.status-answered { background: var(--ih-success-bg); color: var(--ih-success-text); }
.label.status.status-customerreply { background: var(--ih-warning-bg); color: var(--ih-warning-text); }
.label.status.status-onhold { background: var(--ih-warning-bg); color: var(--ih-warning-text); }
.label.status.status-closed { background: var(--ih-surface-sunken); color: var(--ih-text-subtle); }

/* -------------------------------------------------------------------------
   23. Products dashboard & upgrade flow (task #48/§1.42) - Phase B complete
   -------------------------------------------------------------------------
   upgrade.tpl, upgrade-configure.tpl, upgradesummary.tpl wrapped in one
   new .ih-products-page div (same precedent as every other page in
   Phase B), CSS-only. subscription-manage.tpl needed nothing at all -
   it's plain .card.mw-540, already themed in §1.39.
   clientareaproducts.tpl also needed no override: it reuses
   includes/tablelist.tpl (themed in §1.40), so only new global
   .label.status.status-* entries for product statuses were needed -
   verified live rather than assumed, same discipline as invoice/quote/
   ticket statuses before it. */

.ih-products-page .card {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
}

.ih-products-page .table {
    margin-bottom: 0;
}

.ih-products-page .table th,
.ih-products-page .table td {
    border-color: var(--ih-border);
}

/* Widened to global (task #51, IHOST_THEME_PLAN.md 1.45): masspay.tpl
   uses this same class outside .ih-products-page's scope. */
.masspay-total td {
    font-weight: 700;
    border-top: 2px solid var(--ih-border);
}

.ih-products-page .form-control {
    border-color: var(--ih-border-strong);
}

.ih-products-page .form-control:focus {
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

.ih-products-page .btn-primary {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
}

.ih-products-page .btn-primary:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

.ih-products-page .btn-default {
    border-color: var(--ih-border-strong);
    color: var(--ih-text);
}

/* Upgrade product-choice cards (upgrade-configure.tpl) */
.ih-products-page .upgrade .product {
    position: relative;
    height: 100%;
    padding: var(--ih-space-5);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
    display: flex;
    flex-direction: column;
}

.ih-products-page .upgrade .product .header h4 {
    font-family: var(--ih-font-display);
    font-weight: 800;
}

.ih-products-page .upgrade .product .current,
.ih-products-page .upgrade .product .recommended {
    display: inline-block;
    align-self: flex-start;
    margin-bottom: var(--ih-space-2);
    padding: 0.25em 0.8em;
    border-radius: var(--ih-radius-pill);
    font-size: var(--ih-text-xs);
    font-weight: 700;
}

.ih-products-page .upgrade .product .current { background: var(--ih-surface-sunken); color: var(--ih-text-subtle); }
.ih-products-page .upgrade .product .recommended { background: var(--ih-blue-100); color: var(--ih-blue-700); }

.ih-products-page .upgrade .product ul {
    flex: 1 1 auto;
    margin: 0 0 var(--ih-space-4);
    padding: var(--ih-space-4) 0 0;
    border-top: 1px solid var(--ih-border);
    list-style: none;
    font-size: var(--ih-text-sm);
}

.ih-products-page .upgrade .product ul li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-block: 0.35rem;
    color: var(--ih-text-muted);
}

.ih-products-page .upgrade .product .footer .btn-block {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
    color: var(--ih-white);
}

.ih-products-page .upgrade .product .footer .btn-block:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

/* Global: product statuses (clientareaproducts.tpl uses
   includes/tablelist.tpl, already themed in §1.40) */
.label.status.status-active { background: var(--ih-success-bg); color: var(--ih-success-text); }
.label.status.status-pending { background: var(--ih-warning-bg); color: var(--ih-warning-text); }
.label.status.status-suspended,
.label.status.status-fraud { background: var(--ih-danger-bg); color: var(--ih-danger-text); }
.label.status.status-terminated,
.label.status.status-cancelled { background: var(--ih-surface-sunken); color: var(--ih-text-subtle); }
.label.status.status-completed { background: var(--ih-blue-50); color: var(--ih-blue-700); }

/* -------------------------------------------------------------------------
   24. Domain management (task #49/§1.43)
   -------------------------------------------------------------------------
   clientareadomaindetails.tpl (+ its 5 embedded tabs), the 6 standalone
   action pages (addons/contactinfo/dns/emailforwarding/getepp/
   registerns), and bulkdomainmanagement.tpl - all wrapped in one new
   .ih-domains-page div, CSS-only. Every one of these is plain .card/
   .form-control/.table/.nav-tabs, the same shape as every other Phase
   B/C page, so the same wrapper-scope approach applies directly.
   clientareadomains.tpl (list) and domain-pricing.tpl needed no
   override - both reuse already-globally-themed patterns
   (includes/tablelist.tpl from §1.40; .domain-pricing/.featured-tld/
   .tld-filters from §1.36, previously scoped under #order-standard_cart
   only - widened here to also cover this plain client-area page, since
   the class names are specific enough that global reach is safe). */

.ih-domains-page .card {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
}

.ih-domains-page .card-title {
    font-family: var(--ih-font-display);
    font-weight: 800;
}

.ih-domains-page .form-control {
    border-color: var(--ih-border-strong);
}

.ih-domains-page .form-control:focus {
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

.ih-domains-page .btn-primary {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
}

.ih-domains-page .btn-primary:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

.ih-domains-page .btn-default {
    border-color: var(--ih-border-strong);
    color: var(--ih-text);
}

.ih-domains-page .list-group-item { border-color: var(--ih-border); }

.ih-domains-page .nav-tabs .nav-link.active {
    color: var(--ih-blue-600);
    border-color: var(--ih-border) var(--ih-border) var(--ih-surface);
}

.ih-domains-page .label-success { background: var(--ih-success); }
.ih-domains-page .label-danger { background: var(--ih-danger); }

/* domain-pricing.tpl - same visual language as domainregister.tpl's
   TLD browser (§1.36), widened from #order-standard_cart-only to
   global since both pages share these exact classes. */
.domain-pricing .featured-tld {
    padding: var(--ih-space-4);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
    background: var(--ih-surface);
    text-align: center;
}

.tld-filters .badge {
    display: inline-block;
    margin: 0 var(--ih-space-2) var(--ih-space-2) 0;
    padding: 0.4em 0.9em;
    border-radius: var(--ih-radius-pill);
    background: var(--ih-blue-50);
    color: var(--ih-blue-700);
    font-size: var(--ih-text-xs);
    font-weight: 600;
}

.tld-filters .badge.badge-success { background: var(--ih-blue-600); color: var(--ih-white); }

/* Global: domain statuses (clientareadomains.tpl uses
   includes/tablelist.tpl, already themed in §1.40). Taken straight from
   tbldomains.status's enum definition, same as §1.42's product
   statuses - active/cancelled/fraud already have rules from that
   section and apply here for free, since it's the same shared
   .label.status component across every list in the site. */
.label.status.status-expired,
.label.status.status-redemption { background: var(--ih-danger-bg); color: var(--ih-danger-text); }
.label.status.status-pending,
.label.status.status-pendingregistration,
.label.status.status-pendingtransfer,
.label.status.status-grace,
.label.status.status-transferredaway { background: var(--ih-warning-bg); color: var(--ih-warning-text); }

/* §25 Account settings (task #50): clientareadetails, user-profile,
   user-password, user-security, clientareasecurity, account-user-*,
   account-contacts-*, account-paymentmethods-* - all CSS-only reskins
   under the new .ih-account-page wrapper scope (IHOST_THEME_PLAN.md
   1.44), matching every other Phase B/C page. Status/severity badges
   (label-success/-default/-info etc, used for "verified"/"owner"
   badges here) already have global rules from §21 - nothing new needed
   for those. */
.ih-account-page .card {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
}

.ih-account-page .card-title {
    font-family: var(--ih-font-display);
    font-weight: 800;
}

.ih-account-page .form-control {
    border-color: var(--ih-border-strong);
}

.ih-account-page .form-control:focus {
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

.ih-account-page .btn-primary {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
}

.ih-account-page .btn-primary:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

.ih-account-page .btn-default {
    border-color: var(--ih-border-strong);
    color: var(--ih-text);
}

.ih-account-page .btn-danger {
    background: var(--ih-danger);
    border-color: var(--ih-danger);
}

.ih-account-page .btn-success {
    background: var(--ih-success);
    border-color: var(--ih-success);
}

/* These tables (user-management, payment-methods) mark up their header
   row as a plain first <tr><th> with no <thead> - the browser folds it
   into the implicit tbody, so a `thead th` selector never matches.
   Row striping is already handled by twenty-one's own .table-striped
   rule (theme.css ~1514); only the header row needs the extra weight. */
.ih-account-page .table.table-striped tr:first-child th {
    border-bottom: 2px solid var(--ih-border);
    color: var(--ih-text-subtle);
    font-weight: 700;
}

.ih-account-page .alert.alert-block.alert-info {
    border-radius: var(--ih-radius-lg);
}

.ih-account-page .well {
    background: var(--ih-surface-sunken);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius);
    padding: var(--ih-space-4);
}

/* §26 Low-traffic pages (task #51, Phase D - CSS-only pass, not a full
   rewrite per that task's own scope): SSL config wizard, SSL list,
   downloads, affiliates, masspay, 3D Secure, cancellation request,
   email history, markdown guide - one shared .ih-misc-page wrapper
   scope, reusing every pattern already established rather than
   inventing new ones. .kb-category/.kb-article-item (downloads),
   .affiliate-stat (affiliates), and .table-container .table-list
   (managessl/clientareaemails/affiliates, via includes/tablelist.tpl,
   themed in 1.40) already have real styling from twenty-one's own
   theme.css or from earlier sections - nothing new needed for those. */
.ih-misc-page .card {
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius-lg);
}

.ih-misc-page .card-title {
    font-family: var(--ih-font-display);
    font-weight: 800;
}

.ih-misc-page .form-control {
    border-color: var(--ih-border-strong);
}

.ih-misc-page .form-control:focus {
    border-color: var(--ih-blue-600);
    box-shadow: var(--ih-ring);
}

.ih-misc-page .btn-primary {
    background: var(--ih-blue-600);
    border-color: var(--ih-blue-600);
}

.ih-misc-page .btn-primary:hover { background: var(--ih-blue-700); border-color: var(--ih-blue-700); }

.ih-misc-page .btn-default {
    border-color: var(--ih-border-strong);
    color: var(--ih-text);
}

.ih-misc-page .btn-danger {
    background: var(--ih-danger);
    border-color: var(--ih-danger);
}

.ih-misc-page .list-group-item { border-color: var(--ih-border); }

/* markdown-guide.tpl's <pre> blocks render inside a modal with no
   other styling of their own - light touch only, matching this
   task's CSS-only-pass scope. */
.ih-misc-page pre {
    background: var(--ih-surface-sunken);
    border: 1px solid var(--ih-border);
    border-radius: var(--ih-radius);
    padding: var(--ih-space-3);
}
