/*
 * ServerFellows Resellers — client area styles.
 * Built for the Serverfellow theme's sf-* utility classes; the fallback
 * block below makes things look reasonable on stock Six / Twenty-One /
 * Nexus / Lagom too. Where Serverfellow overrides ours, that wins (its
 * CSS is loaded after ours by the theme).
 */

/* ============================================================
 * Theme-agnostic fallbacks for sf-* classes.
 *
 * Wrapped in :where() so each rule has SPECIFICITY 0,0,0 — the lowest
 * possible. On the Serverfellow theme, its real .sf-btn-primary rules
 * (specificity 0,1,0) automatically win the cascade. On Six / Twenty-One
 * / Nexus / Lagom (which don't define sf-* classes at all), these
 * fallbacks render and the addon still looks like a coherent product.
 *
 * If you ever override a fallback in your own theme, you don't need to
 * fight this CSS — any normal selector wins.
 * ============================================================ */

:where(.sf-page-title) {
    font-size: 1.75rem;
    font-weight: 600;
    color: #111827;
    margin: 0 0 0.5rem;
}

:where(.sf-text-muted) { color: #6b7280; }

:where(.sf-btn-primary) {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 1rem;
    background: #b91c1c;
    color: #fff;
    border: 1px solid #b91c1c;
    border-radius: 6px;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    transition: background 0.15s;
}
:where(.sf-btn-primary):hover, :where(.sf-btn-primary):focus {
    background: #991b1b;
    border-color: #991b1b;
    color: #fff;
    text-decoration: none;
}

:where(.sf-btn-outline) {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 1rem;
    background: #fff;
    color: #b91c1c;
    border: 1px solid #b91c1c;
    border-radius: 6px;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    transition: background 0.15s;
}
:where(.sf-btn-outline):hover, :where(.sf-btn-outline):focus {
    background: #fef2f2;
    color: #b91c1c;
    text-decoration: none;
}

:where(.sf-alert) {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.7rem 1rem;
    border-radius: 6px;
    margin: 0 0 0.6rem;
    font-size: 1rem;
}
:where(.sf-alert-success) { background: #ecfdf5; color: #065f46; border: 1px solid #a7f3d0; }
:where(.sf-alert-error)   { background: #fef2f2; color: #991b1b; border: 1px solid #fecaca; }
:where(.sf-alert-info)    { background: #eff6ff; color: #1e40af; border: 1px solid #bfdbfe; }

:where(.sf-dash-stats) {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
    gap: 0.7rem;
    margin: 0 0 0.9rem;
}

:where(.sf-dash-card) {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    padding: 0.7rem 0.85rem;
    box-shadow: 0 1px 2px rgba(0,0,0,0.04);
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

:where(.sf-dash-card-top) {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

:where(.sf-dash-card-icon) {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
:where(.sf-dash-card-icon-red)    { background: #fef2f2; }
:where(.sf-dash-card-icon-blue)   { background: #eff6ff; }
:where(.sf-dash-card-icon-yellow) { background: #fef3c7; }
:where(.sf-dash-card-icon-green)  { background: #ecfdf5; }

:where(.sf-dash-card-value) {
    font-size: 1.3rem;
    font-weight: 700;
    color: #111827;
    line-height: 1.15;
}

:where(.sf-dash-card-label) {
    color: #6b7280;
    font-size: 0.82rem;
}

:where(.sf-dash-card-link) {
    color: #b91c1c;
    font-size: 0.82rem;
    text-decoration: none;
    margin-top: 0.1rem;
}
:where(.sf-dash-card-link):hover { text-decoration: underline; }

:where(.sf-dash-actions) {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 0.6rem;
    margin: 0 0 0.9rem;
}

:where(.sf-dash-action) {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    padding: 0.6rem 0.75rem;
    display: flex;
    align-items: center;
    gap: 0.65rem;
    text-decoration: none;
    color: #1f2937;
    transition: border 0.15s, transform 0.15s;
}
:where(.sf-dash-action):hover { border-color: #b91c1c; transform: translateY(-1px); text-decoration: none; }

:where(.sf-dash-action-icon) {
    width: 34px;
    height: 34px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

:where(.sf-dash-action-title) {
    font-weight: 600;
    color: #111827;
    font-size: 0.95rem;
}

:where(.sf-dash-action-desc) {
    color: #6b7280;
    font-size: 0.82rem;
}

:where(.sf-empty-state) {
    text-align: center;
    padding: 2rem 1rem;
    color: #6b7280;
}
:where(.sf-empty-state h3) { margin: 0.5rem 0 0.5rem; color: #111827; }
:where(.sf-empty-state .sf-btn-primary) { margin-top: 1rem; }

/* ============================================================
 * Module-specific styles below — sfr-* prefix
 * ============================================================ */

.sfr-client {
    color: #1f2937;
}

/* ============================================================
 * Font Awesome — self-contained, conflict-proof icon fonts.
 *
 * The page loads several Font Awesome copies (theme CDN FA5, WHMCS's own
 * auto-injected /assets/fonts FA6, ours). They all declare the SAME family
 * name ("Font Awesome 6 Pro"), so the LAST @font-face wins — and if that
 * one's webfont 404s, every .fas icon goes blank regardless of ours.
 *
 * To be immune to that, we declare UNIQUELY-named families whose webfonts are
 * served from this addon's own folder (the same path that serves this CSS, so
 * it can't 404), then force the reseller center's icons onto them. The glyph
 * codepoints (content: var(--fa) / the :before content) still come from the
 * FA stylesheets already loaded — we only override the font-family, so the
 * shared FA5/FA6 codepoints (e.g. user-cog = \f4fe) resolve correctly.
 * ============================================================ */
@font-face {
    font-family: "SFR Icons Solid";
    font-style: normal;
    font-weight: 900;
    font-display: block;
    src: url(../fa/font-awesome/fa-solid-900.woff2) format("woff2"),
         url(../fa/font-awesome/fa-solid-900.ttf) format("truetype");
}
@font-face {
    font-family: "SFR Icons Regular";
    font-style: normal;
    font-weight: 400;
    font-display: block;
    src: url(../fa/font-awesome/fa-regular-400.woff2) format("woff2"),
         url(../fa/font-awesome/fa-regular-400.ttf) format("truetype");
}
@font-face {
    font-family: "SFR Icons Brands";
    font-style: normal;
    font-weight: 400;
    font-display: block;
    src: url(../fa/font-awesome/fa-brands-400.woff2) format("woff2"),
         url(../fa/font-awesome/fa-brands-400.ttf) format("truetype");
}
.sfr-client .fa,
.sfr-client .fas,
.sfr-client .fa-solid {
    font-family: "SFR Icons Solid" !important;
    font-weight: 900 !important;
    font-style: normal !important;
}
.sfr-client .far,
.sfr-client .fa-regular {
    font-family: "SFR Icons Regular" !important;
    font-weight: 400 !important;
    font-style: normal !important;
}
.sfr-client .fab,
.sfr-client .fa-brands {
    font-family: "SFR Icons Brands" !important;
    font-weight: 400 !important;
    font-style: normal !important;
}

/* ----- sub-navigation: vertical left sidebar ----- */

/* Two-column shell: nav sidebar on the left, page content on the right. */
/* The nav is a horizontal strip above the content, not a column beside it, so
   the layout stacks. The page heading it replaced now lives in the top bar. */
.sfr-layout {
    display: block;
}

.sfr-main {
    min-width: 0;
}

/* One horizontal bar, with each item boxed inside it so the sections read as
   distinct rather than as a run of text links. */
.sfr-subnav {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 0.4rem;
    width: 100%;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    padding: 0.3rem 0.4rem;
    /* The gap under the strip, on every page in every section — the first
       card of a page always follows it, so this one value is the separation
       everywhere. Kept modest: the strip sits directly under the top bar and
       this space is spent on every screen. */
    margin-bottom: 1.25rem;
    /* Sticks directly beneath the top bar. The offset is the bar's own height,
       shared as a variable rather than repeated as a magic 60 — the two were
       drifting apart, which is what let cards ride up under the strip. */
    position: sticky;
    top: var(--sfr-topbar-h, 60px);
    z-index: 20;
    /* Cards pass underneath, so the strip needs a shadow to read as a layer
       rather than as content colliding with content. */
    box-shadow: 0 4px 10px -8px rgba(15, 23, 42, 0.35);
}

/* Duplicated by the top bar's own "Back to My Account" once the nav is
   horizontal — one of the two has to go, and the bar's is always visible. */
.sfr-subnav .sfr-subnav-back { display: none; }

.sfr-subnav-link {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.4rem 0.7rem;
    border-radius: 8px;
    color: #4b5563;
    text-decoration: none;
    font-size: 0.88rem;
    font-weight: 500;
    white-space: nowrap;
    transition: background 0.15s ease, color 0.15s ease,
                border-color 0.15s ease, box-shadow 0.15s ease;
}

/* Only the TOP-LEVEL items are boxed. The `>` matters: the same class is used
   for links inside the dropdown, and boxing those would make the panel look
   like a second menu bar. */
.sfr-subnav > .sfr-subnav-link,
.sfr-subnav > .sfr-subnav-group > .sfr-subnav-toggle {
    border: 1px solid #e5e7eb;
    background: #fcfcfd;
}

.sfr-subnav-link i,
.sfr-subnav-link svg { font-size: 1rem; opacity: 0.6; flex-shrink: 0; }

.sfr-subnav > .sfr-subnav-link:hover,
.sfr-subnav > .sfr-subnav-group > .sfr-subnav-toggle:hover {
    background: #fff;
    border-color: #b91c1c;
    color: #b91c1c;
    box-shadow: 0 2px 8px -4px rgba(185, 28, 28, 0.4);
    text-decoration: none;
}

.sfr-subnav-link:hover i,
.sfr-subnav-toggle:hover i { opacity: 1; }

/* Current page — solid, so there is never a question which section you are in. */
.sfr-subnav-link.active,
.sfr-subnav > .sfr-subnav-group > .sfr-subnav-toggle.active {
    background: #b91c1c;
    border-color: #b91c1c;
    color: #fff !important;
    box-shadow: 0 3px 10px -4px rgba(185, 28, 28, 0.55);
}

.sfr-subnav-link.active i,
.sfr-subnav-link.active svg,
.sfr-subnav-toggle.active i { opacity: 1; }

/* An open dropdown keeps its box visually joined to the panel below it. */
.sfr-subnav-group.open > .sfr-subnav-toggle {
    background: #fff;
    border-color: #b91c1c;
    color: #b91c1c;
}

/* ----- collapsible group (Settings) ----- */

/* In a horizontal strip the group cannot push the row open — its children
   drop below it as a panel instead. Same markup, same toggle script; only
   where the panel sits changes. */
.sfr-subnav-group { position: relative; }

.sfr-subnav-toggle {
    border: 0;
    background: none;
    cursor: pointer;
    text-align: left;
    font-family: inherit;
    white-space: nowrap;
}

/* margin-left:auto pushed the caret to the far edge of a full-width column
   item; in a row it just needs to sit next to its label. */
.sfr-subnav-caret {
    margin-left: 0.15rem;
    font-size: 0.75rem !important;
    transition: transform 0.15s ease;
}

/* The `>` matters: nested branches inside the panel have their own caret, and
   a descendant selector flipped those too — every branch read as expanded the
   moment the panel opened. */
.sfr-subnav-group.open > .sfr-subnav-toggle .sfr-subnav-caret { transform: rotate(180deg); }

/* Closed by default; opens when it holds the current page, or on click. */
.sfr-subnav-children { display: none; }

.sfr-subnav-group.open .sfr-subnav-children {
    display: block;
    position: absolute;
    top: calc(100% + 0.45rem);
    left: 0;
    z-index: 40;
    min-width: 215px;
    padding: 0.4rem;
    /* NOT scrollable, deliberately. Branches open as flyouts beside this panel,
       and overflow-y:auto on the parent clips any absolutely-positioned
       descendant that leaves its box — the flyout would be cut off at this
       panel's edge instead of appearing next to it.
       It does not need to scroll: nesting caps every group at five or six rows,
       and the long lists now live in the flyouts, which scroll themselves. */
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    box-shadow: 0 14px 32px -12px rgba(15, 23, 42, 0.28),
                0 2px 6px -2px rgba(15, 23, 42, 0.08);
    animation: sfr-drop 0.14s ease-out;
}

/* A panel that appears instantly reads as a glitch; a short rise reads as
   "this belongs to the button above it". */
@keyframes sfr-drop {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

.sfr-subnav-child {
    font-size: 0.94rem;
    white-space: nowrap;
}

/* ----- back to the WHMCS account -----
   The Reseller Center hides WHMCS's main menu, so this is the only way out.
   The nav scrolls (max-height + overflow-y), so it is pinned to the bottom of
   the visible area rather than appended to the end of a list the reseller would
   have to scroll to find. margin-top:auto keeps it at the bottom when the list
   is short; position:sticky keeps it in view when the list is long. */

.sfr-subnav-back {
    position: sticky;
    bottom: 0;
    margin-top: auto;
    padding-top: 0.7rem;
    border-top: 1px solid #e5e7eb;
    background: #fff;
    color: #6b7280;
    font-weight: 600;
}

.sfr-subnav-back:hover {
    background: #f3f4f6;
    color: #111827;
}

/* ============================================================
 * Standalone Reseller Center — the page is rendered without the
 * WHMCS theme, so it carries its own sticky top bar.
 * ============================================================ */

/* One source of truth for the bar's height. The nav strip sticks to it and
   anchors clear it, so all three stay in step if it ever changes. */
:root { --sfr-topbar-h: 60px; }

.sfr-topbar {
    position: sticky;
    top: 0;
    z-index: 30;
    background: #fff;
    border-bottom: 1px solid #e5e7eb;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
}

/* Anything an in-page link can land on has to clear BOTH sticky layers,
   otherwise the jump parks the target's heading behind them. */
.sfr-card,
.sfr-crumbs,
[id] {
    scroll-margin-top: calc(var(--sfr-topbar-h, 60px) + 81px);
}

/* Three tracks rather than space-between: the middle one is then centred on
   the BAR, not on whatever gap the brand and the actions happen to leave, so
   the title sits true centre however wide a reseller's brand name is. */
.sfr-topbar-inner {
    max-width: 1400px;
    margin: 0 auto;
    padding: 0 1.5rem;
    height: 60px;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 1rem;
}

.sfr-topbar-inner > .sfr-topbar-actions { justify-self: end; }

.sfr-topbar-title {
    font-weight: 600;
    font-size: 1.05rem;
    color: #0f172a;
    white-space: nowrap;
    text-align: center;
}

/* Below the tablet break the title would squeeze the brand and the actions
   into nothing, so it steps out of the bar rather than shrinking them. */
@media (max-width: 720px) {
    .sfr-topbar-inner { grid-template-columns: 1fr auto; }
    .sfr-topbar-title { display: none; }
}

.sfr-topbar-brand {
    font-weight: 700;
    font-size: 1rem;
    color: #0f172a;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* An approved reseller trades under their own identity: logo and name side by
   side, logo first. Before approval the bar shows the "Company Name" placeholder
   as plain text (the rule above). */
.sfr-topbar-brand-reseller {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.6rem;
    min-width: 0;
    line-height: 1.2;
}

.sfr-topbar-logo {
    display: block;
    flex: 0 0 auto;
    max-height: 34px;
    max-width: 150px;
    width: auto;
    object-fit: contain;
}

.sfr-topbar-name {
    font-weight: 700;
    font-size: 1rem;
    color: #0f172a;
    min-width: 0;
    max-width: 320px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A thin rule between the mark and the name so they read as one lockup rather
   than two unrelated things that happen to sit next to each other. */
.sfr-topbar-logo + .sfr-topbar-name {
    padding-left: 0.6rem;
    border-left: 1px solid #e5e7eb;
}

@media (max-width: 640px) {
    .sfr-topbar-logo { max-height: 26px; max-width: 100px; }
    .sfr-topbar-name {
        max-width: 140px;
        font-size: 0.9rem;
        padding-left: 0.45rem;
    }
    .sfr-topbar-brand-reseller { gap: 0.45rem; }
}

/* Right-hand side of the bar: the gear, then the way out. */
.sfr-topbar-actions {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex: 0 0 auto;
}

.sfr-topbar-menu { position: relative; }

.sfr-topbar-gear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    padding: 0;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    background: #fff;
    color: #374151;
    font-size: 1rem;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.sfr-topbar-gear:hover {
    background: #f9fafb;
    border-color: #d1d5db;
    color: #111827;
}

/* ----- announcements bell -----
   Same 38px box as the gear so the two sit as a matched pair in the bar. */
.sfr-topbar-bell {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    background: #fff;
    color: #374151;
    font-size: 1rem;
    text-decoration: none;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.sfr-topbar-bell:hover {
    background: #f9fafb;
    border-color: #d1d5db;
    color: #111827;
    text-decoration: none;
}

.sfr-topbar-bell.active {
    border-color: #b91c1c;
    color: #b91c1c;
}

/* Rides the icon's corner. min-width + a pill radius so "3" is a circle and
   "99+" simply grows sideways instead of being clipped. */
.sfr-bell-badge {
    position: absolute;
    top: -5px;
    right: -5px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    border-radius: 999px;
    background: #b91c1c;
    color: #fff;
    font-size: 0.65rem;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
    box-shadow: 0 0 0 2px #fff;
}

.sfr-topbar-dropdown {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 40;
    min-width: 210px;
    padding: 0.35rem;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    box-shadow: 0 12px 28px rgba(15, 23, 42, 0.12);
}

.sfr-topbar-dropdown.open { display: block; }

.sfr-topbar-menu-item {
    display: block;
    padding: 0.55rem 0.75rem;
    border-radius: 6px;
    color: #374151;
    font-size: 0.94rem;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
}

.sfr-topbar-menu-item:hover {
    background: #fef2f2;
    color: #b91c1c;
    text-decoration: none;
}

.sfr-topbar-menu-item.active {
    background: #b91c1c;
    color: #fff;
}

.sfr-topbar-back {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex: 0 0 auto;
    padding: 0.5rem 0.9rem;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    background: #fff;
    color: #374151;
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.sfr-topbar-back:hover {
    background: #f9fafb;
    border-color: #d1d5db;
    color: #111827;
    text-decoration: none;
}

/* The `top` and `max-height` override that used to live here was written for
   the VERTICAL sidebar this nav used to be. Two classes deep, it outranked
   the base rule and parked the strip at 60px + 1.5rem — a 24px band of dead
   space above the menu bar on every desktop page, which is exactly the gap
   the shell's 5px top padding was supposed to close. The nav is a horizontal
   strip now: it sticks flush to the bar via .sfr-subnav's own
   `top: var(--sfr-topbar-h)`, and a max-height on a one-row strip only risked
   clipping it. Nothing replaces it. */

@media (max-width: 640px) {
    .sfr-topbar-inner { padding: 0 1rem; }
    .sfr-topbar-back span { display: none; } /* icon-only on small screens */
}

/* ----- intro panel ----- */

.sfr-intro {
    position: relative;
    background: linear-gradient(135deg, #fef2f2 0%, #fff7ed 100%);
    border: 1px solid #fecaca;
    border-radius: 10px;
    padding: 0.9rem 1rem;
    margin-bottom: 0.7rem;
}

.sfr-intro h3 {
    margin: 0 0 0.35rem;
    color: #991b1b;
    font-size: 1.05rem;
    font-weight: 600;
}

.sfr-intro p { margin: 0 0 0.5rem; color: #4b5563; font-size: 0.9rem; }

.sfr-intro-steps {
    margin: 0;
    padding-left: 1.1rem;
    color: #4b5563;
    font-size: 0.88rem;
}

.sfr-intro-steps li { margin-bottom: 0.2rem; }

/* ----- card / panel shared ----- */

.sfr-card {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    overflow: hidden;
    margin-bottom: 0.9rem;
    box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}

/* The heading carries the page's controls now that the screens below have no
   explanatory paragraph, so it has to keep them on one line where it can and
   wrap gracefully where it can't. Title left, actions right. */
.sfr-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    flex-wrap: wrap;
    padding: 0.6rem 1rem;
    border-bottom: 1px solid #f3f4f6;
}

.sfr-card-head h3 {
    margin: 0;
    font-size: 1.02rem;
    color: #111827;
    font-weight: 600;
}

/* Title + its status badge, as one unit on the left of the heading. */
.sfr-card-title {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    min-width: 0;
}

/* ----- guide ----- */

/* Step links on the guide before the application is approved. They still
   render as text so the walkthrough reads normally, but they're greyed and
   carry a lock cursor — the pages behind them are closed until an admin
   activates the account. */
.sfr-guide-locked,
.sfr-guide-locked:hover,
.sfr-guide-locked:focus {
    color: #9ca3af;
    text-decoration: none;
    border-bottom: 1px dashed #d1d5db;
    cursor: not-allowed;
}

.sfr-guide-step-head {
    margin: 0;
    padding: 1.1rem 1.25rem 0.35rem;
    font-size: 1.15rem;
    font-weight: 600;
    color: #111827;
}

.sfr-guide-body {
    padding: 0 1.25rem 1.25rem;
    color: #374151;
    line-height: 1.6;
}

.sfr-guide-body p { margin: 0 0 0.7rem; }

.sfr-guide-body code {
    background: #f3f4f6;
    border-radius: 3px;
    padding: 0.05rem 0.3rem;
    font-size: 0.9em;
}

/* The click-by-click sub-steps inside a guide step. */
.sfr-guide-steps {
    margin: 0.5rem 0 0.8rem;
    padding-left: 1.35rem;
    color: #4b5563;
}

.sfr-guide-steps > li { margin-bottom: 0.6rem; }

.sfr-guide-steps ul {
    margin: 0.35rem 0 0;
    padding-left: 1.15rem;
    list-style: disc;
}

.sfr-guide-steps ul li { margin-bottom: 0.25rem; }

.sfr-guide-note {
    background: #f9fafb;
    border-left: 3px solid #d1d5db;
    border-radius: 4px;
    padding: 0.65rem 0.9rem;
    color: #4b5563;
    font-size: 0.94rem;
}

/* ----- table ----- */

/* ----- searchable dropdown (assets/js/select.js) -----
   Enhances <select class="sfr-select">. The native control stays in the DOM and
   still posts the form; this is only its face. */

.sfr-sel { position: relative; display: inline-block; min-width: 190px; max-width: 100%; }

.sfr-sel-native {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    width: 1px;
    height: 1px;
}

.sfr-sel-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    width: 100%;
    padding: 0.45rem 0.7rem;
    background: #fff;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    font-size: 0.95rem;
    color: #1f2937;
    text-align: left;
    cursor: pointer;
    line-height: 1.35;
}

.sfr-sel-btn:hover  { border-color: #9ca3af; }
.sfr-sel-btn:focus  { outline: none; border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37,99,235,0.15); }
.sfr-sel-open .sfr-sel-btn { border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37,99,235,0.15); }

.sfr-sel-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sfr-sel-caret { color: #6b7280; font-size: 0.8rem; flex: 0 0 auto; }

.sfr-sel-panel {
    display: none;
    position: absolute;
    z-index: 60;
    top: calc(100% + 4px);
    left: 0;
    min-width: 100%;
    width: max-content;
    max-width: 320px;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
    overflow: hidden;
}

.sfr-sel-open .sfr-sel-panel { display: block; }

.sfr-sel-search {
    width: 100%;
    padding: 0.5rem 0.7rem;
    border: 0;
    border-bottom: 1px solid #f3f4f6;
    font-size: 0.9rem;
    color: #1f2937;
}

.sfr-sel-search:focus { outline: none; background: #f9fafb; }

.sfr-sel-list { max-height: 240px; overflow-y: auto; }

.sfr-sel-opt {
    padding: 0.5rem 0.7rem;
    font-size: 0.93rem;
    color: #1f2937;
    cursor: pointer;
    white-space: nowrap;
}

.sfr-sel-opt:hover { background: #f3f4f6; }

.sfr-sel-opt.sfr-sel-active { background: #eff6ff; color: #1d4ed8; font-weight: 600; }

.sfr-sel-opt.sfr-sel-disabled { color: #9ca3af; cursor: not-allowed; }

.sfr-sel-empty {
    padding: 0.65rem 0.7rem;
    font-size: 0.9rem;
    color: #9ca3af;
    font-style: italic;
}

/* Alignment utilities.
   The Reseller Center renders as its own document — no theme, no Bootstrap — so
   the `text-right` class the templates have always used resolved to nothing and
   every "Amount" column sat left-aligned. These are the definitions it was
   missing. The table-scoped rules exist because `.sfr-table thead th` sets
   text-align:left and out-specifies a bare class. */
.text-right  { text-align: right; }
.text-center { text-align: center; }
.text-left   { text-align: left; }

.sfr-table thead th.text-right,
.sfr-table tbody td.text-right,
.sfr-table tfoot td.text-right { text-align: right; }

.sfr-table thead th.text-center,
.sfr-table tbody td.text-center,
.sfr-table tfoot td.text-center { text-align: center; }

.sfr-table-wrap { overflow-x: auto; }

.sfr-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 1rem;
}

.sfr-table thead th {
    background: #f9fafb;
    color: #6b7280;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
    text-align: left;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid #e5e7eb;
}

.sfr-table tbody td {
    padding: 0.85rem 1rem;
    border-bottom: 1px solid #f3f4f6;
    color: #1f2937;
}

.sfr-table tbody tr:last-child td { border-bottom: 0; }

.sfr-table tbody tr:hover td { background: #fafafa; }

/* An action strip must never break onto a second line — a wrapped strip
   doubles the height of every row in the table. `width: 1%` asks for the
   narrowest column the content allows, and `white-space: nowrap` makes that
   "as wide as the buttons", so the column sizes itself to however many
   actions the row actually has. The 110px it used to be pinned to was
   narrower than five 32px buttons, which is what forced the wrap on
   Customers; it survives as the min-width so tables that only carry this
   class on the <th> keep the column width they had. */
.sfr-table-actions {
    width: 1%;
    min-width: 110px;
    white-space: nowrap;
    text-align: right;
}

/* Shrink a column to its own content. On a table with a few free-text
   columns and several short ones (an id, a status pill, a date), the short
   ones otherwise take an equal share of the width and carry the surplus as
   empty space. */
.sfr-table .sfr-col-fit { width: 1%; white-space: nowrap; }

.sfr-empty {
    text-align: center;
    color: #9ca3af;
    padding: 2.5rem 1rem !important;
    font-style: italic;
}

/* ----- inline action buttons ----- */

/* 28px rather than 32: the button is the tallest thing in an action row, so
   it — not the cell padding — is what sets the row height across every table
   in the Center. The narrower gutter buys back width in the same move, which
   is what lets a five-action strip sit on one line. */
.sfr-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 6px;
    color: #6b7280;
    background: #f3f4f6;
    text-decoration: none;
    margin-left: 0.15rem;
    vertical-align: middle;
    transition: background 0.15s, color 0.15s;
}

.sfr-icon-btn:hover {
    background: #e5e7eb;
    color: #b91c1c;
    text-decoration: none;
}

.sfr-icon-btn-danger:hover {
    background: #fef2f2;
    color: #b91c1c;
}

/* ----- badges ----- */

.sfr-badge {
    display: inline-block;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.sfr-badge-success { background: #dcfce7; color: #166534; }
.sfr-badge-danger  { background: #fee2e2; color: #991b1b; }
.sfr-badge-neutral { background: #f3f4f6; color: #4b5563; }
/* "In progress" states — a locked hold or an approved-but-unpaid withdrawal is
   neither done nor failed, and rendering both as neutral grey loses the one
   distinction that matters on the Fund page. */
.sfr-badge-warning { background: #fef3c7; color: #92400e; }
.sfr-badge-info    { background: #dbeafe; color: #1e40af; }

/* A short explanatory line under a form's buttons. Full-width by the
   .sfr-form > *:not(.sfr-form-row) rule above, so it never sits in a column. */
.sfr-form-note {
    margin: 0.2rem 0 0;
    font-size: 0.78rem;
    color: #6b7280;
    line-height: 1.45;
}

/* ----- chart placeholder ----- */

.sfr-chart-placeholder {
    text-align: center;
    padding: 3rem 1rem;
    color: #9ca3af;
    background: #f9fafb;
    border-radius: 8px;
    border: 1px dashed #d1d5db;
    margin: 1rem 1.25rem 1.25rem;
}

.sfr-chart-placeholder i {
    font-size: 2.75rem;
    margin-bottom: 0.75rem;
    color: #d1d5db;
    display: block;
}

/* ----- forms (add/edit pages) ----- */

/* Forms lay out as a responsive 3-column grid so fields sit side by side
 * (horizontal) and the page stays short instead of one tall single column.
 * Each .sfr-form-row is one cell; wide controls span all columns (below). */
.sfr-form {
    padding: 0.5rem 1.25rem 1rem;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.3rem 1.25rem;
    align-items: start;
}

.sfr-form-row {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin-bottom: 0.5rem;
    min-width: 0;
    max-width: none;
}

/* Non-field children (headings, dividers, the button bar, help paragraphs)
 * always break to their own full-width row. */
.sfr-form > *:not(.sfr-form-row) {
    grid-column: 1 / -1;
}

/* Wide fields read better full-width than squeezed into one column:
 * textareas, radio groups, and composite rows that pack several inputs
 * into a nested flex wrapper (e.g. First/Last name, City/State/Postcode). */
.sfr-form-row:has(textarea),
.sfr-form-row:has(.sfr-radio),
.sfr-form-row:has(> div) {
    grid-column: 1 / -1;
}

/* ----- form controls: baseline -----
 * Standalone mode renders the Center with no theme stylesheet behind it, so
 * every control has to be styled here or it falls back to raw browser defaults.
 * The rules below therefore cover ALL control types — including file, tel, url,
 * search and .form-control — not just the handful the grid rows below style,
 * and they apply to any control in the Center, not only those inside a
 * .sfr-form-row (inline inputs in tables and toolbars were unstyled too).
 *
 * :where() holds the class part at zero specificity so that when the Center IS
 * rendered inside the client-area theme, the theme's own control styling still
 * takes precedence and nothing changes there. */

:where(.sfr-client) input[type="text"],
:where(.sfr-client) input[type="email"],
:where(.sfr-client) input[type="number"],
:where(.sfr-client) input[type="date"],
:where(.sfr-client) input[type="password"],
:where(.sfr-client) input[type="tel"],
:where(.sfr-client) input[type="url"],
:where(.sfr-client) input[type="search"],
:where(.sfr-client) input[type="file"],
:where(.sfr-client) select,
:where(.sfr-client) textarea,
:where(.sfr-client) .form-control {
    width: 100%;
    padding: 0.55rem 0.75rem;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    background: #fff;
    color: #111827;
    font-family: inherit;
    font-size: 1rem;
    line-height: 1.4;
    transition: border 0.15s, box-shadow 0.15s;
}

:where(.sfr-client) input:focus,
:where(.sfr-client) select:focus,
:where(.sfr-client) textarea:focus,
:where(.sfr-client) .form-control:focus {
    outline: none;
    border-color: #b91c1c;
    box-shadow: 0 0 0 3px rgba(185, 28, 28, 0.12);
}

/* Buttons and checkable inputs must not inherit the block above. */
:where(.sfr-client) button,
:where(.sfr-client) input[type="submit"],
:where(.sfr-client) input[type="button"] {
    font-family: inherit;
    font-size: 1rem;
}

:where(.sfr-client) input[type="checkbox"],
:where(.sfr-client) input[type="radio"] {
    width: auto;
    padding: 0;
    border: 0;
    box-shadow: none;
}

.sfr-form-row > label {
    font-weight: 500;
    color: #374151;
    font-size: 0.9rem;
}

.sfr-form-row input[type="text"],
.sfr-form-row input[type="email"],
.sfr-form-row input[type="number"],
.sfr-form-row input[type="date"],
.sfr-form-row input[type="password"],
.sfr-form-row select,
.sfr-form-row textarea {
    width: 100%;
    /* Was 0.55rem/1.05rem. Every field on every form carries this, so the
       oversized control was multiplied down the page — the single biggest
       contributor to forms running off the first screen. */
    padding: 0.45rem 0.65rem;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    font-size: 0.95rem;
    background: #fff;
    color: #111827;
    transition: border 0.15s, box-shadow 0.15s;
}

.sfr-form-row input:focus,
.sfr-form-row select:focus,
.sfr-form-row textarea:focus {
    outline: none;
    border-color: #b91c1c;
    box-shadow: 0 0 0 3px rgba(185,28,28,0.12);
}

.sfr-form-row small {
    color: #6b7280;
    font-size: 0.92rem;
}

/* ----- compact invoice view ----- */

.sfr-invoice { padding: 1.25rem; }

.sfr-invoice-head {
    display: flex;
    justify-content: space-between;
    gap: 1.5rem;
    flex-wrap: wrap;
    padding-bottom: 1.25rem;
    border-bottom: 1px solid #e5e7eb;
    margin-bottom: 1.25rem;
}

.sfr-invoice-logo {
    display: block;
    max-height: 46px;
    max-width: 200px;
    width: auto;
    margin-bottom: 0.5rem;
}

.sfr-invoice-issuer {
    font-size: 1.15rem;
    font-weight: 700;
    color: #0f172a;
}

.sfr-invoice-summary { text-align: right; }

.sfr-invoice-number {
    font-size: 1.15rem;
    font-weight: 700;
    color: #0f172a;
}

.sfr-invoice-meta {
    color: #6b7280;
    font-size: 0.9rem;
    line-height: 1.45;
}

.sfr-invoice-label {
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #94a3b8;
    margin-bottom: 0.35rem;
}

.sfr-invoice-billto { margin-bottom: 1.25rem; }

/* Invoice line items + totals share one table, so the Amount column and every
   total sit on the same right edge. One column definition, one alignment. */
.sfr-invoice-amount {
    width: 22%;
    min-width: 120px;
    white-space: nowrap;
    font-variant-numeric: tabular-nums; /* digits line up column-wise */
}

.sfr-invoice-table tfoot td {
    padding: 0.5rem 1rem;
    color: #374151;
    border: 0;
}

/* The label column of the totals: right-aligned so "Subtotal" and "Total" sit
   next to their figures rather than stranded at the far left of the row. */
.sfr-invoice-foot-label { text-align: right; }

/* Rule above the totals block — the last line item's row has no border. */
.sfr-invoice-table tfoot tr:first-child td { border-top: 1px solid #e5e7eb; padding-top: 0.85rem; }

.sfr-invoice-table tfoot tr.sfr-invoice-foot-due td {
    border-top: 1px solid #e5e7eb;
    padding-top: 0.7rem;
    font-weight: 700;
    font-size: 1.05rem;
    color: #0f172a;
}

.sfr-invoice-footer {
    margin-top: 1.5rem;
    padding-top: 1rem;
    border-top: 1px solid #e5e7eb;
    color: #6b7280;
    font-size: 0.9rem;
    white-space: pre-line;
}

@media (max-width: 640px) {
    .sfr-invoice-summary { text-align: left; }
    .sfr-invoice-amount { min-width: 90px; }
}

/* ----- wallet: top-up ----- */

.sfr-topup-form {
    padding: 0.5rem 1.25rem 1.25rem;
}

/* Amount field and the button on one line, bottom-aligned so the button sits
   level with the input rather than with the label above it. */
.sfr-topup-row {
    display: flex;
    align-items: flex-end;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.sfr-topup-field {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    flex: 0 1 260px;
    min-width: 0;
}

.sfr-topup-field > label {
    font-weight: 500;
    color: #374151;
    font-size: 1rem;
}

.sfr-topup-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    /* Match the input's height so the two read as one control pair. */
    padding: 0.55rem 1rem;
    white-space: nowrap;
}

.sfr-topup-hint {
    display: block;
    margin-top: 0.5rem;
    color: #6b7280;
    font-size: 0.92rem;
}

@media (max-width: 575px) {
    .sfr-topup-field { flex: 1 1 100%; }
    .sfr-topup-btn   { width: 100%; justify-content: center; }
}

/* ----- marketplace: buy row + status cell ----- */

/* Cycle dropdown and Buy button on one line, baselines matched. The select is
   deliberately narrow so the pair fits the (intentionally small) Buy column. */
.sfr-buy-form {
    display: flex;
    align-items: stretch;
    gap: 0.4rem;
    flex-wrap: nowrap;
    min-width: 0;
}

.sfr-buy-form .sfr-inline-select {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 150px;
    padding: 0.4rem 0.5rem;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    background: #fff;
    color: #111827;
    font-family: inherit;
    font-size: 0.85rem;
    line-height: 1.2;
    /* Long "Annually — $120.00 USD" labels would otherwise stretch the column. */
    text-overflow: ellipsis;
}

.sfr-buy-form .sfr-buy-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.4rem 0.7rem;
    font-size: 0.85rem;
    white-space: nowrap;
}

/* Status: badge, then the action that tells the reseller what to do next. */
.sfr-status-cell {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.sfr-price-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.35rem 0.65rem;
    font-size: 0.85rem;
    white-space: nowrap;
}

/* ----- Manage Products and Pricing ----- */

/* Groups landing: one card per WHMCS product group. */
.sfr-group-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 1rem;
    padding: 0 1.25rem 1.25rem;
}

.sfr-group-card {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 1rem 1.1rem;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    background: #fff;
    text-decoration: none;
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}

.sfr-group-card:hover {
    border-color: #2563eb;
    box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08);
    transform: translateY(-1px);
    text-decoration: none;
}

.sfr-group-name  { font-weight: 600; font-size: 1.02rem; color: #111827; }
.sfr-group-meta  { font-size: 0.85rem; color: #6b7280; }
.sfr-group-go    { font-size: 0.85rem; color: #2563eb; margin-top: 0.35rem; }

/* Specifications column — feature lines, kept compact inside a table cell. */
.sfr-spec-list {
    margin: 0;
    padding-left: 1.1rem;
    color: #4b5563;
    font-size: 0.86rem;
    line-height: 1.45;
}

.sfr-spec-list li { margin-bottom: 0.15rem; }

/* Selling-status cell: dropdown + Save always on ONE line. The select is
 * allowed to shrink (min-width:0 beats its intrinsic content width) so the
 * button keeps its space instead of being pushed onto a second row. */
.sfr-status-form {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: nowrap;
    margin: 0;
}

.sfr-status-select {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 150px;
    padding: 0.35rem 0.4rem;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    font-size: 0.84rem;
    background: #fff;
    color: #1f2937;
}

.sfr-status-select:focus {
    outline: none;
    border-color: #b91c1c;
    box-shadow: 0 0 0 3px rgba(185, 28, 28, 0.12);
}

.sfr-status-save {
    flex: 0 0 auto;
    padding: 0.35rem 0.6rem;
    font-size: 0.82rem;
    white-space: nowrap;
}

/* Duration picker on the Manage Price screen. */
.sfr-duration-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    padding: 0 1.25rem 1rem;
}

.sfr-duration-tab {
    padding: 0.45rem 0.85rem;
    border: 1px solid #e5e7eb;
    border-radius: 999px;
    font-size: 0.88rem;
    color: #374151;
    background: #fff;
    text-decoration: none;
    white-space: nowrap;
}

.sfr-duration-tab:hover { border-color: #9ca3af; text-decoration: none; }

.sfr-duration-tab.active {
    background: #2563eb;
    border-color: #2563eb;
    color: #fff;
    font-weight: 600;
}

.sfr-price-panel {
    margin: 0 1.25rem 1rem;
    padding: 1rem 1.1rem;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    background: #f9fafb;
}

.sfr-price-facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.85rem;
    margin-bottom: 1rem;
}

.sfr-price-fact { display: flex; flex-direction: column; gap: 0.2rem; }

.sfr-price-fact-label {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #6b7280;
}

.sfr-price-fact-value { font-size: 1.3rem; font-weight: 600; color: #111827; }
.sfr-price-fact-gain  { color: #15803d; }

.sfr-price-form {
    display: flex;
    align-items: flex-end;
    gap: 0.6rem;
    flex-wrap: wrap;
}

.sfr-price-form label {
    display: block;
    font-size: 0.85rem;
    color: #374151;
    margin-bottom: 0.25rem;
    flex-basis: 100%;
}

.sfr-price-form input[type="number"] {
    width: 160px;
    padding: 0.5rem 0.65rem;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    font-size: 1rem;
}

.sfr-price-note {
    margin: 0.75rem 0 0;
    font-size: 0.83rem;
    color: #6b7280;
}

/* ----- Domain Registration -----
 * Uses the module's own vocabulary: sfr-card shells, sf-dash-* tiles, the
 * sfr-table, and the theme's red (#b91c1c) as the single accent. Blue/green/
 * amber appear only as status tints, matching sf-dash-card-icon-*.
 */

.sfr-crumbs {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1rem;
    font-size: 0.9rem;
}

.sfr-crumbs a { color: #b91c1c; text-decoration: none; }
.sfr-crumbs a:hover { text-decoration: underline; }
.sfr-crumbs a i { font-size: 0.78rem; margin-right: 0.15rem; }
.sfr-crumb-sep  { color: #d1d5db; }
.sfr-crumb-here { color: #6b7280; }

.sfr-head-icon { color: #b91c1c; margin-right: 0.35rem; }
.sfr-head-sub  { font-weight: 400; font-size: 0.95rem; }
.sfr-currency-note { font-size: 0.85rem; }

.sfr-card-intro {
    margin: 0;
    padding: 1rem 1.25rem 0;
    color: #6b7280;
    font-size: 0.9rem;
    line-height: 1.55;
}

.sfr-card-note {
    margin: 0;
    padding: 0 1.25rem 0.25rem;
    color: #9ca3af;
    font-size: 0.84rem;
}

.sfr-card-foot {
    padding: 1rem 1.25rem;
    border-top: 1px solid #f3f4f6;
    background: #fcfcfd;
}

/* Cancel + Save, grouped together at the left — the same shape as
   .sfr-head-actions up in the card heading, so the pair reads as one control
   in both places. This replaced a space-between layout that threw Cancel to
   the far left and Save to the far right, which on a wide grid put a screen's
   width between two buttons that belong side by side. */
.sfr-card-foot-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.sfr-inset-alert {
    margin: 1rem 1.25rem 0;
    justify-content: space-between;
}

.sfr-alert-link { color: inherit; font-weight: 600; text-decoration: underline; white-space: nowrap; }

/* Stat / summary tiles inside a card. */
.sfr-domain-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 1rem;
    padding: 1.25rem;
}

.sfr-domain-actions { padding: 0 1.25rem 1.25rem; margin: 0; }

.sfr-op-card { gap: 0.35rem; }
.sfr-op-meta { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }

.sfr-fig-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #6b7280;
    font-weight: 600;
}

/* Segmented filter control. */
.sfr-toolbar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 1rem 1.25rem;
}

.sfr-segment {
    display: inline-flex;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    overflow: hidden;
    background: #f9fafb;
}

.sfr-segment-item {
    padding: 0.45rem 0.9rem;
    font-size: 0.86rem;
    color: #4b5563;
    text-decoration: none;
    border-right: 1px solid #e5e7eb;
    white-space: nowrap;
}

.sfr-segment-item:last-child { border-right: 0; }
.sfr-segment-item:hover { background: #fff; color: #b91c1c; text-decoration: none; }

.sfr-segment-item.active {
    background: #b91c1c;
    color: #fff;
    font-weight: 600;
}

.sfr-search {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 240px;
    margin: 0;
    max-width: 380px;
}

.sfr-search-icon {
    position: absolute;
    left: 0.7rem;
    color: #9ca3af;
    font-size: 0.85rem;
    pointer-events: none;
}

.sfr-search input[type="text"] {
    width: 100%;
    padding: 0.5rem 2rem 0.5rem 2.1rem;
    border: 1px solid #d1d5db;
    border-radius: 8px;
    font-size: 0.9rem;
}

.sfr-search input[type="text"]:focus {
    outline: none;
    border-color: #b91c1c;
    box-shadow: 0 0 0 3px rgba(185, 28, 28, 0.12);
}

.sfr-search-clear {
    position: absolute;
    right: 0.65rem;
    color: #9ca3af;
    font-size: 1.15rem;
    line-height: 1;
    text-decoration: none;
}
.sfr-search-clear:hover { color: #b91c1c; text-decoration: none; }

/* Price cells: selling figure, cost beneath, margin as a pill. */
.sfr-cell-sell { display: block; font-weight: 700; color: #111827; }
.sfr-cell-cost { display: block; font-size: 0.8rem; color: #9ca3af; }
.sfr-cell-na   { color: #cbd5e1; }

.sfr-pill {
    display: inline-block;
    margin-top: 0.25rem;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    font-size: 0.74rem;
    font-weight: 600;
}

.sfr-pill-up   { background: #dcfce7; color: #166534; }
.sfr-pill-down { background: #fee2e2; color: #991b1b; }
.sfr-pill-flat { background: #f3f4f6; color: #6b7280; }

/* A row priced below cost — marked, not shouted at. */
.sfr-row-loss td { background: #fffafa; box-shadow: inset 3px 0 0 #ef4444; }
.sfr-row-loss:hover td { background: #fef2f2; }

.sfr-row-actions { white-space: nowrap; }
.sfr-inline-form { display: inline; margin: 0; }

.sfr-mini-btn {
    display: inline-flex;
    padding: 0.35rem 0.65rem;
    font-size: 0.82rem;
    white-space: nowrap;
}

/* Add-on service cards. */
.sfr-addon-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 1rem;
    padding: 1.25rem;
}

/* Two stacked bands: the identity line, then the action. */
.sfr-addon-card {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.75rem 0.85rem;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    background: #fff;
}

/* icon · name · status, all on one line. */
.sfr-addon-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}

/* Takes the slack between the icon and the badge, and truncates rather than
   wrapping — a wrapped name would reintroduce the second line this layout
   exists to remove. The full label is on the tooltip either way. */
.sfr-addon-name {
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 600;
    color: #111827;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sfr-addon-head .sfr-badge { flex: 0 0 auto; }

/* Still used by the TLD and add-on detail screens. */
.sfr-fig { display: flex; flex-direction: column; gap: 0.1rem; }
.sfr-fig-value { font-weight: 700; color: #111827; font-size: 0.95rem; }
.sfr-fig-value.muted { font-weight: 500; color: #9ca3af; }

.sfr-addon-btn { width: 100%; justify-content: center; }

/* Per-term price grid. */
.sfr-term-table th.sfr-term-label {
    background: #f9fafb;
    color: #374151;
    font-weight: 600;
    white-space: nowrap;
    text-align: left;
    padding: 0.85rem 1rem;
    border-bottom: 1px solid #f3f4f6;
}

.sfr-input-money {
    display: inline-flex;
    align-items: center;
    border: 1px solid #d1d5db;
    border-radius: 8px;
    overflow: hidden;
    background: #fff;
}

.sfr-input-money:focus-within {
    border-color: #b91c1c;
    box-shadow: 0 0 0 3px rgba(185, 28, 28, 0.12);
}

.sfr-input-prefix,
.sfr-input-suffix {
    padding: 0 0.5rem;
    font-size: 0.78rem;
    color: #9ca3af;
    background: #f9fafb;
    align-self: stretch;
    display: flex;
    align-items: center;
}

.sfr-input-money input[type="number"] {
    width: 92px;
    border: 0;
    padding: 0.45rem 0.4rem;
    font-size: 0.95rem;
    text-align: center;
}

.sfr-input-money input[type="number"]:focus { outline: none; }
.sfr-input-money-lg input[type="number"] { width: 120px; font-size: 1.15rem; font-weight: 600; }

/* A box holding a price under the platform's cost — flagged as you type. */
.sfr-input-money.is-below {
    border-color: #ef4444;
    background: #fffafa;
}
.sfr-input-money.is-below .sfr-input-prefix,
.sfr-input-money.is-below .sfr-input-suffix { background: #fef2f2; color: #b91c1c; }
.sfr-input-money.is-below input[type="number"] { background: #fffafa; color: #991b1b; }

/* The cost comparison sitting directly under each input. */
.sfr-cost-compare {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-top: 0.35rem;
}

.sfr-cost-line { font-size: 0.78rem; color: #9ca3af; white-space: nowrap; }
.sfr-cost-line strong { color: #6b7280; font-weight: 600; }
.sfr-cost-compare .sfr-pill { margin-top: 0; }


/* Enable/disable services — the tile is a button, so reset button chrome. */
button.sf-dash-action {
    width: 100%;
    text-align: left;
    font: inherit;
    cursor: pointer;
    background: #fff;
}

.sfr-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 0.3rem;
    vertical-align: middle;
}

.sfr-dot-on  { background: #16a34a; }
.sfr-dot-off { background: #d1d5db; }

/* Confirm dialog. */
.sfr-modal {
    position: fixed;
    inset: 0;
    z-index: 1050;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}

.sfr-modal[hidden] { display: none; }
body.sfr-modal-open { overflow: hidden; }

.sfr-modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(17, 24, 39, 0.5);
}

.sfr-modal-box {
    position: relative;
    width: 100%;
    max-width: 440px;
    background: #fff;
    border-radius: 12px;
    padding: 1.5rem;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.18);
}

.sfr-modal-title {
    margin: 0 0 0.6rem;
    font-size: 1.15rem;
    font-weight: 600;
    color: #111827;
}

.sfr-modal-text {
    margin: 0 0 1.25rem;
    color: #6b7280;
    font-size: 0.92rem;
    line-height: 1.55;
}

.sfr-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    margin: 0;
}

.sfr-btn-danger,
.sfr-btn-danger:hover { border-color: #b91c1c; color: #b91c1c; background: #fef2f2; }

/* Bulk price grid — a whole product group edited in one pass. */
.sfr-head-actions { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }

/* One full-width toolbar: the tools sit side by side across the card and their
   controls spread into the space, rather than both bunching into a narrow
   column on the left with the rest of the row empty. */
.sfr-bulk-tools {
    display: flex;
    flex-wrap: wrap;
    /* Stretch, not flex-end. Bottom-aligning worked only while both tools were
       exactly one row tall: the markup tool now carries a mode picker as well,
       so on a narrower card its controls wrap to a second line and bottom
       alignment drops its label a line below the status tool's. Aligning from
       the top keeps the two headings on the same line whatever wraps, and gives
       the divider between them a full-height run. */
    align-items: stretch;
    gap: 1rem 1.75rem;
    padding: 1rem 1.25rem;
    margin: 1rem 1.25rem 0;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    background: #f9fafb;
}

/* Each tool claims an equal share and grows; 340px is the point below which
   its own controls would start wrapping awkwardly. */
.sfr-bulk-tool {
    flex: 1 1 340px;
    min-width: 0;
    /* Label pinned to the top, controls directly under it, so the first control
       row of each tool starts at the same height. */
    display: flex;
    flex-direction: column;
    align-items: stretch;
}

/* A hairline between the tools instead of relying on the gap alone. */
.sfr-bulk-tool + .sfr-bulk-tool {
    padding-left: 1.75rem;
    border-left: 1px solid #e5e7eb;
}

.sfr-bulk-tool > label {
    display: block;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #6b7280;
    font-weight: 600;
    margin-bottom: 0.5rem;
}

.sfr-bulk-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* Everything in the row stays its natural size — a percentage box does not
   benefit from being 300px wide, and neither does a button. */
.sfr-bulk-row .sfr-input-money { flex: 0 0 auto; }
.sfr-bulk-row .sfr-input-money input[type="number"] { width: 78px; }
.sfr-bulk-row > .sf-text-muted { flex: 0 0 auto; }
.sfr-bulk-row .sfr-status-select { flex: 0 1 170px; max-width: 190px; }

/* Percentage / Add amount. Two words wide, so it takes its own width rather
   than a status picker's 170px — that difference is most of what pushed this
   row onto a second line in the first place. */
.sfr-bulk-row .sfr-mode-select {
    flex: 0 0 auto;
    width: auto;
    max-width: 140px;
}

/* Sized to their label, not to the leftover width of the row. These used to
   stretch (flex:1 1 auto plus a 132px floor), which made "Fill all boxes",
   "Reset all to cost" and "Apply to all" read as primary actions when they
   are secondary to the grid below. Same metrics as .sfr-btn-sm. */
.sfr-bulk-row .sf-btn-outline,
.sfr-bulk-row .sf-btn-primary {
    flex: 0 0 auto;
    min-width: 0;
    padding: 0.3rem 0.6rem;
    font-size: 0.82rem;
    gap: 0.35rem;
    justify-content: center;
    white-space: nowrap;
}

/* The selection count trails the buttons rather than competing for width. */
.sfr-bulk-row .sfr-sel-count { flex: 0 0 auto; }

/* Spans the toolbar, under both tools. */
.sfr-bulk-note {
    flex: 1 1 100%;
    margin: 0.25rem 0 0;
    font-size: 0.82rem;
    color: #9ca3af;
}

.sfr-bulk-statuscol {
    min-width: 150px;
    vertical-align: middle;
}

/* Row-selection column. */
.sfr-checkcol {
    width: 38px;
    text-align: center;
    vertical-align: middle;
}

.sfr-checkcol input[type="checkbox"] {
    width: 16px;
    height: 16px;
    cursor: pointer;
    accent-color: #b91c1c;
}

.sfr-sel-count { font-size: 0.82rem; white-space: nowrap; }

/* A disabled bulk action should look unavailable, not merely inert. */
.sf-btn-outline[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

.sfr-bulk-table td.sfr-bulk-statuscol { padding: 0.85rem 1rem; }
.sfr-bulk-table td.sfr-bulk-statuscol .sfr-status-select { max-width: 100%; }

.sfr-bulk-table th.sfr-bulk-namecol {
    position: sticky;
    left: 0;
    z-index: 1;
    background: #f9fafb;
    text-align: left;
    min-width: 200px;
    box-shadow: 1px 0 0 #e5e7eb;
}

.sfr-bulk-table tbody th.sfr-bulk-namecol {
    background: #fff;
    padding: 0.85rem 1rem;
    border-bottom: 1px solid #f3f4f6;
    font-weight: 600;
    color: #111827;
    vertical-align: middle;
}

.sfr-bulk-name { display: block; }
.sfr-bulk-table td { vertical-align: top; }
.sfr-bulk-table .sfr-input-money input[type="number"] { width: 88px; }

/* The name the reseller sells a product under, edited in place beneath the
   platform's own name. Lighter than a price box: it is the row's label, not
   one of its figures, and it is empty on most rows. */
.sfr-name-input {
    display: block;
    width: 100%;
    max-width: 220px;
    margin-top: 0.3rem;
    padding: 0.3rem 0.45rem;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    background: #fff;
    font: inherit;
    font-size: 0.82rem;
    font-weight: 400;
    color: #111827;
}

.sfr-name-input:focus {
    outline: none;
    border-color: #2563eb;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}

.sfr-name-input::placeholder { color: #9ca3af; font-style: italic; }

/* The platform's own name, shown only where the reseller has replaced it. */
.sfr-name-orig {
    margin-top: 0.2rem;
    font-size: 0.78rem;
    font-weight: 400;
    color: #9ca3af;
}

/* One-line rename bar under a product's heading. */
.sfr-rename-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    padding: 0.5rem 1.25rem 0.75rem;
    font-size: 0.85rem;
}

.sfr-rename-row label { margin: 0; color: #374151; white-space: nowrap; }

.sfr-rename-row input[type="text"] {
    flex: 1 1 200px;
    max-width: 320px;
    padding: 0.4rem 0.55rem;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    font: inherit;
    font-size: 0.88rem;
}

.sfr-group-card-domains { border-color: #fecaca; background: #fffafa; }
.sfr-group-card-domains .sfr-group-name i { color: #b91c1c; margin-right: 0.35rem; }

@media (max-width: 700px) {
    .sfr-addon-card { align-items: flex-start; }
    .sfr-addon-btn  { width: 100%; justify-content: center; }
}

/* ----- validation ----- */

/* Counterpart to .sfr-req — marks a field the applicant may leave blank. */
.sfr-opt {
    color: #9ca3af;
    font-weight: 400;
    font-size: 0.85rem;
}

.sfr-req {
    color: #b91c1c;
    font-weight: 700;
    margin-left: 2px;
}

.sfr-field-error {
    color: #b91c1c;
    font-size: 0.88rem;
    margin-top: 0.3rem;
    line-height: 1.35;
}

.sfr-has-error input,
.sfr-has-error select,
.sfr-has-error textarea {
    border-color: #b91c1c !important;
    background: #fef2f2;
}

/* A submitted application is shown as values, not as disabled inputs — a
   disabled field still looks like something you might be able to type into. */
.sfr-readonly {
    padding: 0.55rem 0.75rem;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    background: #f9fafb;
    color: #111827;
    font-size: 1rem;
    min-height: 2.5rem;
    word-break: break-word;
}

.sfr-radio {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-right: 1rem;
    font-weight: 400;
    color: #374151;
    cursor: pointer;
}

.sfr-divider {
    border: 0;
    border-top: 1px solid #e5e7eb;
    margin: 0.5rem 0 1.25rem;
}

.sfr-form-actions {
    display: flex;
    gap: 0.75rem;
    align-items: center;
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid #f3f4f6;
}

.sfr-flash-stack { margin-bottom: 1rem; }

/* ----- ticket thread ----- */

.sfr-thread { display: flex; flex-direction: column; gap: 0.85rem; }

.sfr-msg {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-left-width: 4px;
    border-radius: 8px;
    padding: 1rem 1.25rem;
    box-shadow: 0 1px 2px rgba(0,0,0,0.03);
}

.sfr-msg-client   { border-left-color: #94a3b8; }
.sfr-msg-reseller { border-left-color: #b91c1c; background: #fef2f2; }
.sfr-msg-admin    { border-left-color: #1e40af; background: #eff6ff; }

.sfr-msg-meta {
    font-size: 1rem;
    color: #374151;
    margin-bottom: 0.5rem;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}

.sfr-msg-body {
    color: #1f2937;
    line-height: 1.5;
    font-size: 1.05rem;
    word-break: break-word;
}

/* ----- responsive: forms ----- */

/* Content area narrows once the sidebar stacks or on smaller laptops —
 * step the form grid down to 2 columns, then a single column. */
@media (max-width: 1100px) {
    .sfr-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

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

/* ----- mobile ----- */

@media (max-width: 900px) {
    /* Already horizontal; on a narrow screen it stops wrapping into a tall
       block and scrolls sideways instead, so the content is not pushed down
       the page by a six-row nav.
     *
     * Not sticky here: two sticky bars on a short viewport leave almost no
     * room to read anything.
     *
     * overflow-x WITHOUT overflow-y:visible — the pair is invalid, a scrollable
     * axis forces the other to auto, and that CLIPPED the Settings dropdown at
     * the strip's edge. Letting the panel escape matters more than sideways
     * scrolling, so the strip wraps on small screens instead. */
    .sfr-subnav {
        position: static;
        overflow: visible;
        flex-wrap: wrap;
        box-shadow: none;
    }
}

@media (max-width: 640px) {
    .sfr-subnav-link { padding: 0.45rem 0.7rem; font-size: 0.95rem; }
    .sfr-card-head { flex-direction: column; align-items: flex-start; gap: 0.75rem; }
    /* The 110px floor is a desktop concern; on a phone the table scrolls
       sideways inside .sfr-table-wrap, so the column may be exactly as wide
       as its buttons. nowrap still holds — the strip stays on one line. */
    .sfr-table-actions { width: auto; min-width: 0; }
}

/* ----- branding asset uploads: current, preview, crop ----- */

.sfr-current-asset {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 0.5rem;
}

.sfr-asset-logo {
    height: 42px; width: auto; max-width: 220px;
    border: 1px solid #e5e7eb; border-radius: 6px; padding: 4px; background: #fff;
}

.sfr-asset-favicon {
    width: 32px; height: 32px; object-fit: contain;
    border: 1px solid #e5e7eb; border-radius: 6px; padding: 3px; background: #fff;
}

.sfr-upload-preview {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.6rem;
    padding: 0.6rem;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    background: #f9fafb;
}

.sfr-upload-preview[hidden] { display: none; }

.sfr-upload-preview img {
    max-height: 48px; max-width: 160px; width: auto;
    background: #fff; border: 1px solid #e5e7eb; border-radius: 4px; padding: 3px;
}

.sfr-upload-meta { flex: 1 1 auto; font-size: 0.82rem; color: #6b7280; }
.sfr-upload-meta.is-bad { color: #b91c1c; font-weight: 600; }

.sfr-crop-open {
    flex: 0 0 auto;
    border: 1px solid #b91c1c; background: #fff; color: #b91c1c;
    border-radius: 6px; padding: 0.3rem 0.7rem;
    font-size: 0.82rem; font-weight: 600; cursor: pointer;
}
.sfr-crop-open:hover { background: #fef2f2; }
.sfr-crop-open[hidden] { display: none; }

/* ----- cropper ----- */

.sfr-cropper {
    position: fixed; inset: 0; z-index: 1100;
    display: flex; align-items: center; justify-content: center;
    padding: 1rem; background: rgba(17, 24, 39, 0.55);
}

.sfr-cropper-box {
    background: #fff; border-radius: 12px; padding: 1.25rem;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2); max-width: 100%;
}

.sfr-cropper-head { font-weight: 600; color: #111827; margin-bottom: 0.75rem; }

/* The stage now shows the WHOLE image with the crop box floating over it, so
   it has to be a positioning context and must not clip the handles that sit on
   its edges. The chequerboard shows through transparent logos. */
.sfr-cropper-stage {
    position: relative;
    display: inline-block;
    border: 1px solid #e5e7eb; border-radius: 8px;
    background: repeating-conic-gradient(#f3f4f6 0% 25%, #fff 0% 50%) 50% / 16px 16px;
    touch-action: none;
}

.sfr-cropper-stage canvas { display: block; max-width: 100%; }

/* ----- the four-sided crop box ----- */

/* The shadow is what dims everything outside the selection: one element, no
   overlay panels to keep in sync with it. */
.sfr-crop-rect {
    position: absolute;
    box-sizing: border-box;
    border: 1px solid #fff;
    outline: 1px solid rgba(15, 23, 42, 0.55);
    box-shadow: 0 0 0 9999px rgba(15, 23, 42, 0.45);
    cursor: move;
}

/* Rule-of-thirds guides, drawn with the element's own borders. */
.sfr-crop-rect::before,
.sfr-crop-rect::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    border-style: solid; border-color: rgba(255, 255, 255, 0.35);
}
.sfr-crop-rect::before { border-width: 0 1px; left: 33.33%; right: 33.33%; }
.sfr-crop-rect::after  { border-width: 1px 0; top: 33.33%; bottom: 33.33%; }

.sfr-crop-rect i {
    position: absolute;
    width: 12px; height: 12px;
    background: #fff;
    border: 1px solid #b91c1c;
    border-radius: 2px;
}

/* Corners */
.sfr-crop-rect i[data-h="nw"] { top: -6px;    left: -6px;   cursor: nwse-resize; }
.sfr-crop-rect i[data-h="ne"] { top: -6px;    right: -6px;  cursor: nesw-resize; }
.sfr-crop-rect i[data-h="sw"] { bottom: -6px; left: -6px;   cursor: nesw-resize; }
.sfr-crop-rect i[data-h="se"] { bottom: -6px; right: -6px;  cursor: nwse-resize; }

/* Edges — the halves that were missing before. */
.sfr-crop-rect i[data-h="n"] { top: -6px;    left: 50%; margin-left: -6px; cursor: ns-resize; }
.sfr-crop-rect i[data-h="s"] { bottom: -6px; left: 50%; margin-left: -6px; cursor: ns-resize; }
.sfr-crop-rect i[data-h="w"] { left: -6px;   top: 50%;  margin-top: -6px;  cursor: ew-resize; }
.sfr-crop-rect i[data-h="e"] { right: -6px;  top: 50%;  margin-top: -6px;  cursor: ew-resize; }

.sfr-cropper-hint {
    margin: 0.7rem 0 0.9rem;
    font-size: 0.82rem;
    color: #6b7280;
}

.sfr-cropper-reset { margin-right: auto; }

.sfr-cropper-actions { display: flex; justify-content: flex-end; gap: 0.6rem; }

.sfr-cropper-actions button {
    border-radius: 6px; padding: 0.45rem 0.9rem;
    font-size: 0.88rem; font-weight: 600; cursor: pointer;
}
.sfr-cropper-cancel { border: 1px solid #d1d5db; background: #fff; color: #4b5563; }
.sfr-cropper-apply  { border: 1px solid #b91c1c; background: #b91c1c; color: #fff; }

/* ----- replace a document after approval ----- */

.sfr-reupload {
    padding: 1rem 1.25rem 1.25rem;
    border-top: 1px solid #f3f4f6;
    background: #fcfcfd;
}

.sfr-reupload h4 { margin: 0 0 0.35rem; font-size: 0.98rem; color: #111827; }
.sfr-reupload p  { margin: 0 0 0.85rem; font-size: 0.86rem; }

.sfr-reupload-form {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin: 0;
}

.sfr-reupload-form select {
    padding: 0.45rem 0.6rem;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    font-size: 0.88rem;
    background: #fff;
}

.sfr-reupload-form input[type="file"] { font-size: 0.86rem; max-width: 100%; }

/* ----- domain pricing: terms as rows -----
 * Seven fixed columns instead of one per term, so the table never scrolls
 * sideways however many terms a TLD is sold on. Each TLD spans its terms.
 */

/* A rule where one TLD ends and the next begins — with rowspanned name and
 * status cells, the eye needs the group boundary marked. */
.sfr-price-table tr.sfr-tldstart > * { border-top: 2px solid #e5e7eb; }
.sfr-price-table tr.sfr-tldstart:first-child > * { border-top: 0; }

.sfr-price-table .sfr-tldcell {
    vertical-align: middle;
    white-space: nowrap;
}

/* The term label reads as a row header, not as data. */
.sfr-price-table th.sfr-termcol {
    background: #f9fafb;
    color: #4b5563;
    font-size: 0.82rem;
    font-weight: 600;
    text-align: left;
    white-space: nowrap;
    padding: 0.6rem 0.85rem;
    border-bottom: 1px solid #f3f4f6;
    width: 90px;
}

/* Term rows are denser than ordinary table rows — there are several per TLD. */
.sfr-price-table tr.sfr-termrow td { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.sfr-price-table .sfr-input-money input[type="number"] { width: 92px; }
.sfr-price-table .sfr-cost-line { font-size: 0.74rem; }
.sfr-price-table .sfr-pill { font-size: 0.7rem; padding: 0.05rem 0.4rem; }

/* Hovering a term row must not repaint the rowspanned cells of the whole TLD. */
.sfr-price-table tbody tr:hover td { background: #fafafa; }
.sfr-price-table tbody tr:hover .sfr-tldcell { background: transparent; }

/* ----- horizontal menu: dropdown children ----- */

/* Full-width rows inside the panel, not boxes — the panel is already the box. */
.sfr-subnav-children .sfr-subnav-child {
    display: flex;
    width: 100%;
    padding: 0.5rem 0.7rem;
    border: 0;
    background: transparent;
    border-radius: 6px;
    color: #4b5563;
}

.sfr-subnav-children .sfr-subnav-child:hover {
    background: #fef2f2;
    color: #b91c1c;
    box-shadow: none;
}

.sfr-subnav-children .sfr-subnav-child.active {
    background: #fef2f2;
    color: #b91c1c !important;
    font-weight: 600;
    box-shadow: none;
}

/* A group holding the current page stays marked even while closed — otherwise
   navigating into Settings leaves nothing in the bar showing where you are. */
.sfr-subnav-group.current > .sfr-subnav-toggle:not(.active) {
    border-color: #fecaca;
    color: #b91c1c;
}

/* ----- bulk toolbar: narrow screens ----- */

/* Below this the two tools cannot sit side by side without their buttons
   shrinking to unreadable, so they stack and the divider goes. */
@media (max-width: 860px) {
    .sfr-bulk-tool + .sfr-bulk-tool {
        padding-left: 0;
        border-left: 0;
        padding-top: 1rem;
        border-top: 1px solid #e5e7eb;
    }
    .sfr-bulk-tool { flex: 1 1 100%; }
}

/* ----- horizontal menu: icons ----- */

/* Every bar item now carries an inline SVG (single pages, group toggles and
   dropdown children alike). Fix the box so a wide glyph cannot shove the
   label around, and align it optically with the text. */
.sfr-subnav-link > svg:not(.sfr-subnav-caret) {
    width: 17px;
    height: 17px;
    flex: 0 0 17px;
    opacity: 0.55;
    transition: opacity 0.15s ease;
}

.sfr-subnav-link:hover > svg:not(.sfr-subnav-caret),
.sfr-subnav-link.active > svg:not(.sfr-subnav-caret),
.sfr-subnav-group.current > .sfr-subnav-toggle > svg:not(.sfr-subnav-caret) {
    opacity: 1;
}

/* Dropdown-panel icons read as secondary to the label, so they sit lighter
   and slightly smaller than the ones in the bar itself. */
.sfr-subnav-children .sfr-subnav-child {
    align-items: center;
    gap: 0.55rem;
}

.sfr-subnav-children .sfr-subnav-child > svg {
    width: 15px;
    height: 15px;
    flex: 0 0 15px;
    opacity: 0.45;
}

.sfr-subnav-children .sfr-subnav-child:hover > svg,
.sfr-subnav-children .sfr-subnav-child.active > svg { opacity: 1; }

/* The caret is now an SVG too, so the old font-size rule no longer sizes it. */
.sfr-subnav-caret {
    width: 11px;
    height: 11px;
    flex: 0 0 11px;
    opacity: 0.5;
}

/* ============================================================
 * Compact dashboard — everything on the first screen.
 *
 * The order the dashboard reads in: counts, then the orders chart, then a
 * 70/30 split with the working grids on the left and the account panel on
 * the right. Each piece is sized so the whole thing fits without scrolling
 * on a laptop; it may scroll later, as real data arrives, but never on a
 * quiet account.
 * ============================================================ */

/* 70 / 30. minmax(0,·) is what stops a wide table in the left column from
   forcing the grid wider than its container. */
/* .sfr-domain-split rides the same rules: Domain Registration wants the exact
   same 70/30 shape (TLD table left, add-on services right), and duplicating
   the geometry would just let the two drift apart. */
/* .sfr-split-70-30 is the canonical name — use it for new screens. The two
   page-specific aliases predate it and are kept so their templates keep
   working; all three are one rule so they cannot drift.
   (.sfr-console-split was a third alias. Its only consumer was the client
   console's details-beside-password row, which is now one pane per screen,
   so the alias went with it rather than being left to be found later.) */
.sfr-dash-split,
.sfr-domain-split,
.sfr-split-70-30 {
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 3fr);
    gap: 0.9rem;
    align-items: start;
}

.sfr-dash-split > *,
.sfr-domain-split > *,
.sfr-split-70-30 > * { min-width: 0; }

.sfr-split-70-30 { margin-bottom: 0.9rem; }

.sfr-split-70-30 > .sfr-card { margin-bottom: 0; }

@media (max-width: 980px) {
    .sfr-dash-split,
    .sfr-domain-split,
    .sfr-split-70-30 { grid-template-columns: minmax(0, 1fr); }
}

/* Track overrides for forms that sit in a column rather than across the page.
   Both are one class deep, same as .sfr-form, so they must come after it —
   they do. */
.sfr-form-1col { grid-template-columns: minmax(0, 1fr); }
.sfr-form-2col { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (max-width: 640px) {
    .sfr-form-2col { grid-template-columns: minmax(0, 1fr); }
}

/* The left column's own contents stack; the grids inside it are their own
   grids (quick actions, tables), so this only spaces them. */
.sfr-dash-col {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
}

/* Cards inside the split already have the column gap between them. */
.sfr-dash-split .sfr-card,
.sfr-domain-split > .sfr-card,
.sfr-pair > .sfr-card,
.sfr-dash-col > .sfr-card { margin-bottom: 0; }

/* ----- .sfr-pair: two short cards side by side -----
   auto-fit rather than a fixed 1fr 1fr: several of the cards that use this are
   behind {if} capability checks, and a lone survivor should take the full row
   instead of sitting in half of one with a hole beside it. */
.sfr-pair {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 0.9rem;
    align-items: start;
    margin-bottom: 0.9rem;
}

.sfr-pair > * { min-width: 0; }

/* ----- Domain Registration: add-ons in the 30% column -----
   The card is a horizontal row by default (icon | text | figures | button),
   which needs ~320px. In the narrow column it stacks instead, so the list
   reads straight down rather than wrapping into ragged rows. */
.sfr-domain-split .sfr-addon-grid {
    /* auto-fit + minmax(320px, 1fr) would hold a 320px floor and overflow the
       column, so the track is pinned to one flexible column here. */
    grid-template-columns: minmax(0, 1fr);
    gap: 0.7rem;
    padding: 0.85rem 1rem 1rem;
}

/* The card stacks and the button goes full-width in the base rules now, so
   the only thing the narrow column still has to override is the track. */

/* ----- Your Account: read vertically, one fact per row ----- */

.sfr-account-list {
    display: flex;
    flex-direction: column;
    padding: 0.25rem 0 0.35rem;
}

.sfr-account-item {
    padding: 0.5rem 1rem;
    border-bottom: 1px solid #f3f4f6;
}

.sfr-account-item:last-child { border-bottom: 0; }

.sfr-account-label {
    display: block;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #6b7280;
    font-weight: 600;
    margin-bottom: 0.1rem;
}

.sfr-account-value {
    display: block;
    font-weight: 600;
    color: #111827;
    font-size: 0.92rem;
    word-break: break-word;
}

.sfr-account-meta {
    display: block;
    color: #6b7280;
    font-size: 0.8rem;
}

.sfr-account-links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.15rem 0.75rem;
    margin-top: 0.15rem;
}

.sfr-account-links a { font-size: 0.8rem; }

/* ----- orders per day ----- */

.sfr-chart {
    display: flex;
    align-items: flex-end;
    gap: 0.3rem;
    height: 120px;
    padding: 0.9rem 1rem 0.25rem;
}

/* Each column is the full height of the plot so the bars share one baseline
   and the hit area for the tooltip covers the whole day, not just the bar. */
.sfr-chart-col {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    height: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: center;
}

.sfr-chart-bar {
    width: 100%;
    max-width: 26px;
    border-radius: 4px 4px 0 0;
    background: #b91c1c;
    transition: background 0.15s ease;
}

.sfr-chart-col:hover .sfr-chart-bar { background: #7f1d1d; }

/* A day with no orders still needs something to hover and to read as "zero",
   not as "missing". */
.sfr-chart-bar-empty {
    height: 2px;
    background: #e5e7eb;
    border-radius: 2px;
}

.sfr-chart-axis {
    display: flex;
    gap: 0.3rem;
    padding: 0 1rem 0.75rem;
    color: #9ca3af;
    font-size: 0.7rem;
}

.sfr-chart-tick {
    flex: 1 1 0;
    min-width: 0;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
}

.sfr-chart-total {
    font-size: 0.82rem;
    color: #6b7280;
    font-weight: 500;
}

/* ----- dismissable cards ----- */

/* Sits in the card's own corner rather than in the heading row, so it works
   the same on the intro panel (which has no heading row) and on a card. */
.sfr-card-dismiss {
    position: absolute;
    top: 0.4rem;
    right: 0.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: #9ca3af;
    font-size: 1.05rem;
    line-height: 1;
    cursor: pointer;
}

.sfr-card-dismiss:hover { background: rgba(15, 23, 42, 0.06); color: #4b5563; }

.sfr-card-dismissable { position: relative; }

/* Restore row: the one place hidden cards can be brought back from. Muted,
   because it is housekeeping rather than content. */
.sfr-hidden-cards {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0.25rem 0 0;
    color: #9ca3af;
    font-size: 0.8rem;
}

.sfr-hidden-cards form { display: inline; margin: 0; }

.sfr-link-btn {
    padding: 0;
    border: 0;
    background: none;
    color: #b91c1c;
    font-size: 0.8rem;
    text-decoration: underline;
    cursor: pointer;
}

/* ============================================================
 * Manage Products and Pricing — compact heading-driven screens.
 * The explanatory paragraphs are gone; the heading carries the group's
 * status on the left and the actions on the right, and the bulk tools
 * collapse so the grid itself is what the first screen shows.
 * ============================================================ */

/* Small buttons for a heading row — a full-size button makes the head taller
   than the title it sits beside. */
.sfr-btn-sm {
    padding: 0.3rem 0.6rem;
    font-size: 0.82rem;
    gap: 0.35rem;
    border-radius: 6px;
}

.sfr-head-actions .sfr-btn-sm { min-width: 0; }

/* Collapsible panel (the bulk tools / filters). Closed by default: the grid
   below it is the point of the page, and the tools are a detour. */
.sfr-collapse-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    /* Bottom margin is what separates the toggle from whatever follows it —
       the grid when collapsed, the tools panel when open. Set here so both
       states get the same gap without either one special-casing it. */
    margin: 0.6rem 1rem 0.75rem;
    padding: 0.3rem 0.6rem;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    background: #f9fafb;
    color: #4b5563;
    font-size: 0.82rem;
    font-weight: 500;
    cursor: pointer;
}

.sfr-collapse-toggle:hover { border-color: #d1d5db; color: #111827; }

.sfr-collapse-caret {
    width: 10px;
    height: 10px;
    transition: transform 0.15s ease;
}

.sfr-collapse-toggle[aria-expanded="true"] .sfr-collapse-caret { transform: rotate(180deg); }

.sfr-collapse[hidden] { display: none; }

/* The bulk toolbar is now inside a collapsible panel, so it carries less of
   its own margin. */
/* Longhand, not the `margin` shorthand: the horizontal 1rem comes from the
   compact .sfr-bulk-tools rule below and must survive. The toggle above
   already supplies the gap over the panel, so only the gap under it — the
   one before the price grid — is set here. */
.sfr-collapse > .sfr-bulk-tools,
.sfr-collapse > .sfr-toolbar { margin-top: 0; margin-bottom: 0.75rem; }

/* Group cards: same shape, less air. */
.sfr-group-grid {
    gap: 0.7rem;
    padding: 0.85rem 1rem 1rem;
}

.sfr-group-card { padding: 0.7rem 0.85rem; gap: 0.2rem; }

/* ----- pricing screens: reclaimed vertical space -----
   The explanatory paragraph that used to sit under each heading is gone, so
   the blocks that followed it now supply their own top spacing. */

.sfr-duration-tabs { padding: 0.7rem 1rem 0.6rem; }

.sfr-price-panel { margin: 0 1rem 0.75rem; padding: 0.8rem 0.9rem; }
.sfr-price-facts { gap: 0.6rem; margin-bottom: 0.7rem; }

.sfr-bulk-tools { padding: 0.75rem 0.9rem; margin: 0 1rem 0; }

.sfr-toolbar { padding: 0.6rem 1rem; }

.sfr-card-foot { padding: 0.6rem 1rem; }

.sfr-card-intro { padding: 0.7rem 1rem 0; }

.sfr-domain-stats { gap: 0.7rem; padding: 0.85rem 1rem; }

.sfr-domain-actions { padding: 0 1rem 1rem; }

/* ----- tables and empty states: compact -----
   Row height is the biggest single lever on how much of a list fits the first
   screen, so it comes down across the Center rather than page by page. */

.sfr-table { font-size: 0.9rem; }

.sfr-table thead th { padding: 0.5rem 0.8rem; font-size: 0.74rem; }

.sfr-table tbody td { padding: 0.5rem 0.8rem; }

.sfr-empty { padding: 1.25rem 1rem !important; }

:where(.sf-empty-state) { padding: 1.25rem 1rem; }

/* A dismiss button's form must not add a line of its own to the card. */
.sfr-card-dismissable > form { margin: 0; }

/* =====================================================================
   Shared table toolbar — search, rows-per-page, export (requirement.md §1)
   Built by assets/js/table-tools.js above every table marked data-tt.
   Kept deliberately low-profile: it appears on ~40 tables, so anything
   with presence here would cost a band of vertical space on every list in
   the Center. One row, small type, no card of its own.
   ===================================================================== */

.sfr-tt {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    /* Horizontal padding matches .sfr-card-head (0.6rem 1rem) so the search
       box lines up with the card title above it rather than sitting flush to
       the card edge while every other element is inset. */
    padding: 0.45rem 1rem 0.5rem;
}

.sfr-tt-left,
.sfr-tt-right { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }

.sfr-tt-search {
    width: 200px;
    max-width: 100%;
    padding: 0.32rem 0.6rem;
    border: 1px solid #e5e7eb;
    border-radius: 7px;
    font-size: 0.83rem;
    background: #fff;
    color: #111827;
}

.sfr-tt-search:focus {
    outline: none;
    border-color: #2563eb;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}

.sfr-tt-size {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.8rem;
    color: #6b7280;
    margin: 0;
}

.sfr-tt-size select {
    padding: 0.28rem 0.4rem;
    border: 1px solid #e5e7eb;
    border-radius: 7px;
    font-size: 0.82rem;
    background: #fff;
    color: #111827;
}

.sfr-tt-count { font-size: 0.78rem; color: #6b7280; white-space: nowrap; }

.sfr-tt-exports { display: inline-flex; gap: 0.25rem; }

.sfr-tt-btn {
    padding: 0.3rem 0.55rem;
    border: 1px solid #e5e7eb;
    background: #fcfcfd;
    border-radius: 7px;
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: #4b5563;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.sfr-tt-btn:hover { background: #eef2ff; border-color: #c7d2fe; color: #1e40af; }

/* Pager sits under the table, right-aligned so it reads as a footer to the
   list rather than as another control bar. */
.sfr-tt-pager {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 0.2rem;
    padding: 0.45rem 1rem 0.55rem;
    flex-wrap: wrap;
}

/* No pager (single page) must cost nothing — otherwise every short table on
   every page pays for a control that isn't there. */
.sfr-tt-pager:empty { padding: 0; }

.sfr-tt-page {
    min-width: 1.85rem;
    padding: 0.25rem 0.45rem;
    border: 1px solid #e5e7eb;
    background: #fff;
    border-radius: 6px;
    font-size: 0.78rem;
    color: #4b5563;
    cursor: pointer;
}

.sfr-tt-page:hover:not(:disabled) { background: #f3f4f6; }

.sfr-tt-page.current {
    background: #2563eb;
    border-color: #2563eb;
    color: #fff;
    font-weight: 600;
}

.sfr-tt-page:disabled { opacity: 0.4; cursor: default; }

.sfr-tt-gap { color: #9ca3af; padding: 0 0.15rem; font-size: 0.78rem; }

/* One line, always, on anything wider than a phone. The controls are short and
   the row is the table's header furniture — wrapping it into two or three
   lines is the single easiest way to push a list below the fold. nowrap keeps
   it honest; the search field is the only elastic element, so it absorbs the
   slack instead of the row breaking. */
@media (min-width: 641px) {
    .sfr-tt { flex-wrap: nowrap; }
    .sfr-tt-left { flex: 1 1 auto; min-width: 0; }
    .sfr-tt-right { flex: 0 0 auto; }
    .sfr-tt-search { flex: 0 1 260px; width: auto; }
}

@media (max-width: 640px) {
    .sfr-tt { gap: 0.4rem; }
    .sfr-tt-search { width: 100%; }
    .sfr-tt-left, .sfr-tt-right { width: 100%; justify-content: space-between; }
}

/* =====================================================================
   .sfr-filterbar — a server-side filter form as ONE aligned line.
   Used where the filtering has to happen in PHP (the transaction archive is
   not in the DOM, so the toolbar's client-side search cannot reach it).
   Deliberately NOT .sfr-form: that is a 3-column grid meant for add/edit
   pages, and four short filter fields in it come out as two ragged rows plus
   a third for the buttons.
   ===================================================================== */

.sfr-filterbar {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 0.45rem 0.6rem;
    padding: 0.55rem 1rem 0.6rem;
}

.sfr-filterbar-field {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}

/* The search field takes whatever is left; the date and type controls are
   sized to their content so they never stretch into odd wide boxes. */
.sfr-filterbar-field.grow { flex: 1 1 200px; }

.sfr-filterbar-field > label {
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: #6b7280;
    white-space: nowrap;
}

.sfr-filterbar input[type="text"],
.sfr-filterbar input[type="date"],
.sfr-filterbar select {
    padding: 0.32rem 0.55rem;
    border: 1px solid #e5e7eb;
    border-radius: 7px;
    font-size: 0.83rem;
    background: #fff;
    color: #111827;
    min-width: 0;
}

.sfr-filterbar input:focus,
.sfr-filterbar select:focus {
    outline: none;
    border-color: #2563eb;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}

/* Buttons sit on the input baseline, not the label's, so the row reads as one
   line rather than as controls at two heights. */
.sfr-filterbar-actions {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-left: auto;
}

.sfr-filterbar-actions .sf-btn-primary,
.sfr-filterbar-actions .sf-btn-outline {
    padding: 0.34rem 0.7rem;
    font-size: 0.8rem;
    line-height: 1.2;
}

@media (max-width: 640px) {
    .sfr-filterbar-field,
    .sfr-filterbar-field.grow { flex: 1 1 100%; }
    .sfr-filterbar-actions { margin-left: 0; width: 100%; }
}

/* =====================================================================
   Card tabs — .sfr-tabbed + .sfr-tabs / .sfr-tab / .sfr-tab-panel
   Driven by assets/js/tabs.js. One card, one visible list at a time, so a
   page carrying three or four tables still fits a screen.
   ===================================================================== */

.sfr-tabs {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    flex-wrap: wrap;
    min-width: 0;
}

/* A tab is a <button> when it switches a panel in place, and an <a> when it
   navigates (Transactions' Live / Archive switch reloads with a new query).
   Both are styled here so the two read identically. */
.sfr-tab {
    appearance: none;
    display: inline-block;
    border: 1px solid transparent;
    background: transparent;
    padding: 0.3rem 0.65rem;
    border-radius: 7px;
    font-size: 0.86rem;
    font-weight: 600;
    line-height: 1.35;
    color: #6b7280;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.sfr-tab:hover,
.sfr-tab:focus { background: #f3f4f6; color: #374151; text-decoration: none; }

.sfr-tab.active {
    background: #eef2ff;
    border-color: #c7d2fe;
    color: #1e40af;
}

/* A count beside a tab label — "Withdrawals 3" — without a second element. */
.sfr-tab-count {
    display: inline-block;
    margin-left: 0.3rem;
    padding: 0 0.3rem;
    border-radius: 999px;
    background: #e5e7eb;
    color: #4b5563;
    font-size: 0.68rem;
    font-weight: 700;
    vertical-align: 1px;
}

.sfr-tab.active .sfr-tab-count { background: #c7d2fe; color: #1e3a8a; }

/* Panels carry no chrome of their own — the card already provides it. */
.sfr-tab-panel { min-width: 0; }

/* =====================================================================
   Third-level menu items — a COLLAPSIBLE branch inside the dropdown panel.
   Products > Bulk Tools > Bulk Renew, Settings > Finance & Billing > …

   These used to render as titled sections, always open. That was fine for
   Settings' two short groups and wrong for Products: orders, every product
   group, six bulk tools, five domain pages and Rebrand all expanded at once
   made a panel taller than the screen — and the panel is absolutely
   positioned, so the overflow was unreachable rather than merely long.

   A flyout was the other option; it needs hover tracking, breaks on touch,
   and adds a third layer of floating chrome to a one-screen UI. An
   accordion inside the panel we already have costs one row per branch.
   ===================================================================== */

/* The flyout is positioned against this, so the branch row is the anchor. */
.sfr-subnav-section { position: relative; margin-top: 0.1rem; }

/* Reads as one of the rows around it — it is a peer of the plain links, not
   a heading over them — and gains the caret to say it opens. */
.sfr-subnav-subtoggle {
    display: flex;
    width: 100%;
    padding: 0.5rem 0.7rem;
    border: 0;
    background: transparent;
    border-radius: 6px;
    color: #4b5563;
    font-family: inherit;
    font-size: 0.94rem;
    text-align: left;
    cursor: pointer;
    white-space: nowrap;
}

/* Pushes the caret to the right edge so the carets line up down the panel
   whatever the labels are. */
.sfr-subnav-subtoggle > span { flex: 1 1 auto; }

.sfr-subnav-subtoggle:hover {
    background: #fef2f2;
    color: #b91c1c;
    box-shadow: none;
}

/* An expanded branch stays marked while its children are on screen — with
   several branches in a panel, the caret alone is easy to lose.
   .current is the branch holding the page you are ON. It is marked but NOT
   opened: the flyout is a floating panel, and one that appears the instant
   the menu is touched reads as the menu opening itself. Colour says where
   you are; opening stays the user's business. */
.sfr-subnav-section.open > .sfr-subnav-subtoggle,
.sfr-subnav-section.current > .sfr-subnav-subtoggle {
    color: #b91c1c;
    font-weight: 600;
}

/* Points RIGHT, at where the list will appear — a down-chevron on a row that
   opens sideways points at the wrong thing. It does not flip on open: the
   flyout is beside the row, not under it, so there is no direction to reverse.
   The open row is marked by colour and weight instead (above). */
.sfr-subnav-subtoggle .sfr-subnav-caret { transform: rotate(-90deg); }

/* Collapsed until its row is clicked. This is the line that keeps the
   Products panel a fixed height however many groups the reseller sells. */
.sfr-subnav-subchildren { display: none; }

/* ----- the flyout -----
   A panel of its own, beside the parent rather than inside it. Sideways is
   what buys the height back: the parent stays five rows whatever the branch
   holds, so nothing anywhere has to scroll to reach a menu item.
   Top is -0.4rem to cancel the parent's own padding, which lines the flyout's
   first row up with the branch row that opened it. */
.sfr-subnav-section.open > .sfr-subnav-subchildren {
    display: block;
    position: absolute;
    top: -0.4rem;
    left: 100%;
    margin-left: 0.35rem;
    /* Above the parent panel (z-index 40), which it overlaps by its margin. */
    z-index: 41;
    min-width: 215px;
    /* The one list that can still be genuinely long — a reseller with thirty
       product groups. It scrolls here, where it CAN: nothing clips it. */
    max-height: min(70vh, 460px);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0.4rem;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    box-shadow: 0 14px 32px -12px rgba(15, 23, 42, 0.28),
                0 2px 6px -2px rgba(15, 23, 42, 0.08);
    animation: sfr-flyout 0.14s ease-out;
}

/* Rises from the left, the way the panel below the bar rises from the top —
   the motion says which row it came out of. */
@keyframes sfr-flyout {
    from { opacity: 0; transform: translateX(-4px); }
    to   { opacity: 1; transform: translateX(0); }
}

/* Opened by the script when the flyout would run off the right of the window
   — near the end of the strip there is no room to its right, and a menu half
   off-screen is worse than one on the other side. */
.sfr-subnav-section.open.flip > .sfr-subnav-subchildren {
    left: auto;
    right: 100%;
    margin-left: 0;
    margin-right: 0.35rem;
    animation-name: sfr-flyout-flip;
}

@keyframes sfr-flyout-flip {
    from { opacity: 0; transform: translateX(4px); }
    to   { opacity: 1; transform: translateX(0); }
}

/* ----- narrow screens -----
   There is no room beside the panel on a phone, so the branch falls back to
   opening in place. Same markup, same script; only where the list sits
   changes. Everything positioning-related is reverted together. */
@media (max-width: 900px) {
    .sfr-subnav-section.open > .sfr-subnav-subchildren,
    .sfr-subnav-section.open.flip > .sfr-subnav-subchildren {
        position: static;
        margin: 0;
        min-width: 0;
        max-height: none;
        overflow: visible;
        padding: 0;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        animation: none;
    }

    /* Indented so the nesting is legible without a panel of its own. */
    .sfr-subnav-section.open > .sfr-subnav-subchildren .sfr-subnav-child {
        padding-left: 1.5rem;
    }

    /* Down again — in place, it really does open underneath. */
    .sfr-subnav-section.open > .sfr-subnav-subtoggle .sfr-subnav-caret {
        transform: rotate(0deg);
    }
}

/* =====================================================================
   .sfr-detail — a read-only record, label left / value right.
   Used by the Customer Details page. Two columns on a wide screen so a
   twenty-field record does not run off the bottom of it.
   ===================================================================== */

.sfr-detail {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
    gap: 0 1.5rem;
    margin: 0;
    padding: 0.6rem 1rem 0.75rem;
}

.sfr-detail > div {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
    padding: 0.3rem 0;
    border-bottom: 1px solid #f3f4f6;
    min-width: 0;
}

.sfr-detail dt {
    flex: 0 0 44%;
    font-size: 0.8rem;
    color: #6b7280;
    min-width: 0;
}

.sfr-detail dd {
    flex: 1 1 auto;
    margin: 0;
    font-size: 0.85rem;
    color: #111827;
    font-weight: 500;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* An empty field still occupies its row — a record with gaps in it should
   look like a record with gaps, not like a shorter record. */
.sfr-detail dd:empty::after { content: '—'; color: #9ca3af; font-weight: 400; }

/* =====================================================================
   .sfr-actionbar — the row of operations above a record.
   Modelled on the action strip in customer_details_page.png, but built from
   this Center's own button styles rather than that page's grey chiclets.
   ===================================================================== */

.sfr-actionbar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    padding: 0.55rem 1rem 0.6rem;
    border-bottom: 1px solid #f3f4f6;
}

.sfr-actionbar > form { margin: 0; display: inline; }

.sfr-actionbar .sf-btn-outline,
.sfr-actionbar .sf-btn-primary,
.sfr-actionbar button:not(.sfr-icon-btn) {
    padding: 0.3rem 0.6rem;
    font-size: 0.79rem;
    line-height: 1.25;
    white-space: nowrap;
}

/* The action you are already looking at stays visible but inert, so the bar
   reads the same on every tab instead of shuffling its contents. */
.sfr-actionbar .current {
    background: #eef2ff;
    border-color: #c7d2fe;
    color: #1e40af;
    pointer-events: none;
}

/* A value a form shows but does not let you edit — sized like the inputs
   beside it so the row does not visibly shorten where a field would be. */
.sfr-static-value {
    margin: 0;
    padding: 0.4rem 0;
    font-weight: 600;
    color: #111827;
    min-width: 0;
}


/* =====================================================================
   .sfr-filter-fold — a filter bar that stays out of the way.
   One summary line instead of a band of fields, so the table starts higher.
   ===================================================================== */
.sfr-filter-fold > summary {
    cursor: pointer;
    list-style: revert;          /* keep the native disclosure triangle */
    padding: 0.5rem 1rem;
    font-size: 0.82rem;
    font-weight: 600;
    color: #4b5563;
    border-bottom: 1px solid #f1f5f9;
    user-select: none;
}

.sfr-filter-fold > summary:hover { color: #1f2937; background: #fafafa; }

/* Open, the bar below it supplies its own padding, so the summary loses its
   rule — two lines across the card there reads as a heading it is not. */
.sfr-filter-fold[open] > summary { border-bottom: 0; }

/* Whois output. Column-aligned text from the registrar — reflowing it makes
   it harder to read than it was meant to be, so it scrolls instead. */
.sfr-whois {
    margin: 0;
    padding: 0.75rem 1rem 1rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.78rem;
    line-height: 1.5;
    color: #1f2937;
    white-space: pre;
    overflow-x: auto;
    max-height: 26rem;
    overflow-y: auto;
}

/* =====================================================================
   .sfr-inline-notice — one actionable line under a page's action strip.
   For the thing that used to justify its own tab: present only while it needs
   doing, so it cannot become another permanent item to scroll past.
   ===================================================================== */
.sfr-inline-notice {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.5rem 1rem;
    background: #fffbeb;
    border-top: 1px solid #fde68a;
    color: #92400e;
    font-size: 0.86rem;
}

.sfr-inline-notice > span { min-width: 0; }

/* =====================================================================
   .sfr-checkbox-grid — a set of short checkbox options.
   A one-per-line list of ten payment gateways is ten lines of a screen that
   is supposed to fit one; auto-fit columns turn that into three or four.
   ===================================================================== */
.sfr-checkbox-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 0.15rem 1rem;
    margin-bottom: 0.4rem;
}

.sfr-checkbox-grid > label {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 400;
    margin: 0;
    min-width: 0;
}

/* =====================================================================
   .sfr-card-narrow — a card holding one short form.
   A three-field form stretched over a 1400px screen puts its labels a hand's
   width from their inputs. Capping the card is what keeps the pair together;
   it is a max-width, so it still fills a narrow screen.
   ===================================================================== */
.sfr-card-narrow { max-width: 560px; }

/* =====================================================================
   .sfr-section-title — a bare heading above a stat row.
   Wrapping .sf-dash-stats in a .sfr-card gives every figure two borders and
   two lots of padding; this labels the row without the second box.
   ===================================================================== */
.sfr-section-title {
    margin: 0 0 0.5rem;
    font-size: 1.02rem;
    font-weight: 600;
    color: #111827;
}

/* =====================================================================
   .sfr-figures — a dense label/value grid for a handful of read-only
   numbers. The alternative is a table, which for eight figures nobody
   searches or exports costs a header row, a toolbar and cell padding
   throughout.
   ===================================================================== */
.sfr-figures {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 0.1rem 1.25rem;
    margin: 0;
    padding: 0.7rem 1rem 0.8rem;
}

.sfr-figures > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.6rem;
    padding: 0.28rem 0;
    border-bottom: 1px solid #f3f4f6;
    min-width: 0;
}

.sfr-figures dt {
    font-size: 0.82rem;
    color: #6b7280;
    min-width: 0;
}

/* Values right-aligned and tabular so the column of numbers reads straight
   down instead of jittering with digit width. */
.sfr-figures dd {
    margin: 0;
    font-size: 0.88rem;
    font-weight: 600;
    color: #111827;
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* =====================================================================
   First-run tour — a few cards pointing at the menu, once, on arrival.

   The dim is NOT a full-screen overlay with holes punched in it. It is one
   0-to-target-sized element carrying a 9999px box-shadow: the element is the
   hole, the shadow is everything else. That way nothing in the page has to be
   lifted above an overlay to be spotlit, which on a sticky nav with its own
   stacking context is a fight not worth having.
   ===================================================================== */

.sfr-tour {
    position: fixed;
    inset: 0;
    z-index: 9000;
}

.sfr-tour-spot {
    position: fixed;
    border-radius: 10px;
    box-shadow: 0 0 0 9999px rgba(15, 23, 42, 0.55);
    /* Moves between steps rather than jumping, so it is possible to follow
       where it went. Not animated on width/height alone — the shadow has to
       keep up with it. */
    transition: top 0.2s ease, left 0.2s ease, width 0.2s ease, height 0.2s ease;
    pointer-events: none;
}

.sfr-tour-card {
    position: fixed;
    width: min(340px, calc(100vw - 2rem));
    padding: 1rem 1.1rem 0.85rem;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 20px 44px -16px rgba(15, 23, 42, 0.45),
                0 3px 8px -3px rgba(15, 23, 42, 0.12);
    animation: sfr-tour-in 0.18s ease-out;
}

/* The welcome card, and any other step with nothing to point at. */
.sfr-tour-card.centred {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

@keyframes sfr-tour-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* The centred card is already transformed into place; re-running the rise
   would drag it back out of position for the length of the animation. */
.sfr-tour-card.centred { animation: none; }

.sfr-tour-title {
    margin: 0 0 0.3rem;
    font-size: 1rem;
    font-weight: 700;
    color: #111827;
}

/* The menu path, set apart from the prose. A chip rather than a sentence: it
   is an address, and an address is read, not parsed. Buried mid-paragraph it
   is the first thing skimmed past, and it is the one thing on the card the
   reseller actually has to follow. */
.sfr-tour-path {
    display: inline-block;
    margin: 0 0 0.55rem;
    padding: 0.22rem 0.5rem;
    background: #fef2f2;
    border-radius: 6px;
    color: #b91c1c;
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1.35;
}

.sfr-tour-text {
    margin: 0 0 0.55rem;
    font-size: 0.9rem;
    line-height: 1.45;
    color: #4b5563;
}

/* Why it matters, or what happens if it is left undone. Quieter than the
   instruction above it, because it is not the thing being asked for. */
.sfr-tour-note {
    margin: 0 0 0.9rem;
    padding-left: 1rem;
    list-style: disc;
    font-size: 0.82rem;
    line-height: 1.45;
    color: #6b7280;
}

.sfr-tour-note li { margin-top: 0.2rem; }

/* [hidden] loses to the block/list display these carry, so it is restated —
   a step with no path or no notes must collapse, not leave a gap. */
.sfr-tour-path[hidden],
.sfr-tour-note[hidden] { display: none; }

.sfr-tour-foot {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.sfr-tour-dots {
    display: flex;
    gap: 0.3rem;
    /* Pushes the buttons to the right edge; the dots stay left as a position
       indicator rather than as another control. */
    margin-right: auto;
}

.sfr-tour-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #e5e7eb;
    transition: background 0.15s ease;
}

.sfr-tour-dot.on { background: #b91c1c; }

.sfr-tour-acts {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.sfr-tour-btn {
    padding: 0.4rem 0.85rem;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    background: #fff;
    color: #4b5563;
    font-family: inherit;
    font-size: 0.86rem;
    font-weight: 600;
    cursor: pointer;
}

.sfr-tour-btn:hover { background: #f9fafb; color: #111827; }

/* Next is the one thing to do on this card, so it is the only filled button.
   Skip is a plain link — leaving must be possible, not inviting. */
.sfr-tour-next,
.sfr-tour-next:hover {
    border-color: #b91c1c;
    background: #b91c1c;
    color: #fff;
}

.sfr-tour-skip {
    padding: 0.4rem 0.5rem;
    border: 0;
    background: none;
    color: #9ca3af;
    font-family: inherit;
    font-size: 0.84rem;
    cursor: pointer;
}

.sfr-tour-skip:hover { color: #4b5563; text-decoration: underline; }

/* Hidden on the first card, where there is nothing to go back to. [hidden]
   loses to the display:flex these inherit, so it is restated. */
.sfr-tour-btn[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
    .sfr-tour-spot { transition: none; }
    .sfr-tour-card { animation: none; }
}

/* ---- recipient search (select.js enhanceFilter) ----
   Sits directly above a multi-select and has to read as part of it, so it
   matches the list's width and squares off the join between the two. */
.sfr-msearch {
    display: block;
    width: 100%;
    margin-bottom: -1px;
    padding: 7px 10px;
    font-size: 0.85rem;
    border: 1px solid var(--sfr-line, #e5e7eb);
    border-radius: 6px 6px 0 0;
    background: #fff;
}
.sfr-msearch:focus {
    outline: none;
    border-color: var(--sfr-accent, #b91c1c);
    position: relative;
    z-index: 1;
}
.sfr-msearch + select { border-radius: 0 0 6px 6px; }
.sfr-msearch-note {
    display: block;
    margin-top: 4px;
    font-size: 0.74rem;
    color: var(--sfr-muted, #6b7280);
}
