/* ============================================================
   Tracking Hippo — console theme
   ------------------------------------------------------------
   Aligns console.trackinghippo.io with the web.trackinghippo.io
   design language: Montserrat, a warm paper canvas, hairline
   slate rules, square corners and the #6840bd brand accent.

   This sheet is loaded LAST (after app.css, the pre-built
   Tailwind bundle and the Radzen base sheet) so it can re-skin
   all three without forking the pre-built stylesheet, which has
   no source in this repo.
   ============================================================ */

/* ------------------------------------------------------------
   1. Design tokens
   ------------------------------------------------------------ */
:root {
    /* Brand */
    --th-purple: #6840bd;
    --th-purple-bright: #9161f5;
    --th-purple-deep: #452880;
    --th-purple-tint: #f7f3ff;
    --th-purple-tint-2: #f1f0fa;

    /* Paper canvas */
    --th-paper: #f5f4ef; /* app canvas          */
    --th-paper-soft: #faf9f5; /* sidebar / hover     */
    --th-surface: #ffffff; /* cards               */

    /* Ink */
    --th-ink: #020617; /* slate-950           */
    --th-ink-soft: #334155; /* slate-700           */
    --th-ink-muted: #475569; /* slate-600           */
    --th-ink-faint: #64748b; /* slate-500           */

    /* Credit / balance-positive signal */
    --th-credit-tint: #f0fdf4;
    --th-credit-rule: #bbf7d0;
    --th-credit-ink: #15803d;
    --th-credit-ink-strong: #14532d;

    /* Rules */
    --th-rule: #cbd5e1; /* slate-300           */
    --th-rule-soft: #e2e8f0; /* slate-200           */
    --th-rule-strong: #94a3b8; /* slate-400           */
    --th-rule-warm: #d8d5cb; /* on paper            */

    /* shadcn token contract used across the console markup */
    --background: 50 23% 95%;
    --foreground: 222 84% 5%;
    --card: 0 0% 100%;
    --card-foreground: 222 84% 5%;
    --popover: 0 0% 100%;
    --popover-foreground: 222 84% 5%;
    --primary: 259 49% 50%;
    --primary-foreground: 0 0% 100%;
    --secondary: 48 33% 97%;
    --secondary-foreground: 215 25% 27%;
    /* `muted` backs inline code chips and meter tracks — the paper tone keeps
       them legible as inset panels on a white card. */
    --muted: 50 23% 95%;
    --muted-foreground: 215 19% 35%;
    --accent: 260 100% 98%;
    --accent-foreground: 259 49% 40%;
    --destructive: 0 72% 51%;
    --destructive-foreground: 0 0% 100%;
    --border: 213 27% 84%;
    --input: 213 27% 84%;
    --ring: 259 49% 50%;
    --radius: 0rem;

    --sidebar-background: 48 33% 97%;
    --sidebar-foreground: 215 25% 27%;
    --sidebar-primary: 259 49% 50%;
    --sidebar-primary-foreground: 0 0% 100%;
    --sidebar-accent: 260 100% 98%;
    --sidebar-accent-foreground: 259 49% 40%;
    --sidebar-border: 213 27% 84%;
    --sidebar-ring: 259 49% 50%;

    --gradient-primary: none;
    --gradient-secondary: none;
}

/* ------------------------------------------------------------
   2. Typography — Montserrat, matching the marketing site
   ------------------------------------------------------------ */
html,
body,
button,
input,
select,
textarea,
optgroup {
    font-family: "Montserrat", system-ui, -apple-system, "Segoe UI", sans-serif;
    font-feature-settings: normal;
}

body {
    background-color: var(--th-paper);
    color: var(--th-ink);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* The old display face is remapped rather than removed, so existing
   markup keeps working while picking up the new type. */
.font-space-grotesk,
.font-inter,
.font-sans {
    font-family: "Montserrat", system-ui, -apple-system, "Segoe UI", sans-serif;
}

.font-mono,
code,
kbd,
pre,
samp {
    font-family: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--th-ink);
    font-weight: 700;
    letter-spacing: -0.02em;
}

h1, .text-3xl, .text-4xl {
    letter-spacing: -0.045em;
}

.text-2xl {
    letter-spacing: -0.035em;
}

.text-xl, .text-lg {
    letter-spacing: -0.02em;
}

::selection {
    background-color: rgba(145, 97, 245, 0.22);
}

/* Editorial kicker: a hairline followed by a tracked-out micro label. */
.eyebrow {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--th-purple);
}

.eyebrow::before {
    content: "";
    display: block;
    width: 2rem;
    height: 1px;
    flex-shrink: 0;
    background-color: var(--th-purple);
}

/* ------------------------------------------------------------
   3. Geometry — square corners, hairline rules, no glass
   ------------------------------------------------------------ */
.rounded,
.rounded-sm,
.rounded-md,
.rounded-lg,
.rounded-xl,
.rounded-2xl,
.rounded-3xl,
.rounded-t,
.rounded-b,
.rounded-t-lg,
.rounded-b-lg,
.rounded-t-md,
.rounded-b-md {
    border-radius: 0;
}

/* `rounded-full` is kept for genuinely circular elements (status
   discs, dots, meters); pill-shaped labels are handled by `.tag`. */

.shadow-sm,
.shadow,
.shadow-md,
.shadow-lg,
.shadow-xl,
.shadow-medium,
.shadow-large {
    --tw-shadow: 0 0 #0000;
    --tw-shadow-colored: 0 0 #0000;
    box-shadow: none;
}

.hover\:shadow-large:hover,
.hover\:shadow-lg:hover,
.hover\:shadow-md:hover {
    box-shadow: none;
}

/* Genuine overlays keep elevation — but as a hard, offset shadow
   rather than a soft glow. */
.shadow-2xl {
    --tw-shadow: 0 0 #0000;
    box-shadow: 0 24px 48px -24px rgba(2, 6, 23, 0.35);
}

.backdrop-blur-sm,
.backdrop-blur,
.backdrop-blur-md {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

.bg-white\/80,
.bg-white\/90,
.bg-white\/95 {
    background-color: var(--th-surface);
}

.bg-background {
    background-color: var(--th-paper);
}

/* `bg-background` doubles as the app canvas *and* as the fill for outline
   buttons and fields. The canvas wants paper; controls want to disappear
   into whatever surface they sit on, exactly as on the marketing site. */
:where(button, a, input, select, textarea, [role="tablist"]).bg-background {
    background-color: #ffffff;
}

.bg-card {
    background-color: var(--th-surface);
}

/* Gradients flatten to a single tone — the marketing site is flat. */
.bg-gradient-to-r,
.bg-gradient-to-l,
.bg-gradient-to-t,
.bg-gradient-to-b,
.bg-gradient-to-br,
.bg-gradient-to-bl,
.bg-gradient-to-tr,
.bg-gradient-to-tl {
    background-image: none;
}

.bg-gradient-to-br.from-purple-100,
.bg-gradient-to-r.from-purple-100 {
    background-color: var(--th-purple-tint);
}

/* Default rule colour for anything relying on the preflight border. */
.border,
.border-t,
.border-b,
.border-l,
.border-r,
.border-x,
.border-y {
    border-color: var(--th-rule);
}

.border-border\/50,
.bg-border\/50 {
    border-color: var(--th-rule);
}

.bg-border\/50 {
    background-color: var(--th-rule);
}

.border-gray-200,
.border-gray-300 {
    border-color: var(--th-rule);
}

.divide-y > * + *,
.divide-border\/50 > * + * {
    border-color: var(--th-rule-soft);
}

/* ------------------------------------------------------------
   4. Brand purple scale
   The console markup uses Tailwind's stock purple ramp; it is
   remapped onto the Tracking Hippo violet so both properties
   read as one brand.
   ------------------------------------------------------------ */
.text-purple-400 {
    color: var(--th-purple-bright);
}

.text-purple-500 {
    color: #7c52d8;
}

.text-purple-600,
.text-purple-700 {
    color: var(--th-purple);
}

.text-purple-800,
.text-purple-900 {
    color: var(--th-purple-deep);
}

.hover\:text-purple-700:hover,
.group:hover .group-hover\:text-purple-700 {
    color: var(--th-purple);
}

.bg-purple-50 {
    background-color: var(--th-purple-tint);
}

.bg-purple-100 {
    background-color: #ece4fb;
}

.bg-purple-200 {
    background-color: #dbcdf7;
}

.bg-purple-600,
.bg-purple-700 {
    background-color: var(--th-purple);
}

.hover\:bg-purple-50:hover {
    background-color: var(--th-purple-tint);
}

.hover\:bg-purple-700:hover {
    background-color: var(--th-purple-deep);
}

.border-purple-200 {
    border-color: #dbcdf7;
}

.border-purple-600 {
    border-color: var(--th-purple);
}

.hover\:border-purple-300:hover {
    border-color: var(--th-purple);
}

.focus\:border-purple-400:focus,
.focus\:border-purple-500:focus {
    border-color: var(--th-purple);
}

.focus\:ring-purple-400\/20:focus,
.focus\:ring-purple-500:focus {
    --tw-ring-color: rgba(104, 64, 189, 0.18);
    box-shadow: 0 0 0 3px rgba(104, 64, 189, 0.18);
}

/* Gradient stops used by the old CTA buttons. */
.from-purple-600,
.hover\:from-purple-700:hover {
    --tw-gradient-from: var(--th-ink);
}

.to-purple-700,
.hover\:to-purple-800:hover {
    --tw-gradient-to: var(--th-ink);
}

/* ------------------------------------------------------------
   5. Controls — buttons
   Primary reads as the site's near-black CTA that turns violet
   on hover; secondary is a hairline box that adopts the accent.
   ------------------------------------------------------------ */
.bg-primary {
    background-color: var(--th-ink);
}

.bg-primary.text-primary-foreground,
.bg-primary .text-primary-foreground {
    color: #ffffff;
}

.hover\:bg-primary\/90:hover {
    background-color: var(--th-purple);
}

/* The legacy "gradient" save button collapses onto the same CTA. */
.bg-gradient-to-r.from-purple-600 {
    background-color: var(--th-ink);
    color: #ffffff;
}

.bg-gradient-to-r.from-purple-600:hover {
    background-color: var(--th-purple);
}

button,
.inline-flex[class*="border-input"],
a[class*="border-input"] {
    transition: background-color 0.15s ease, border-color 0.15s ease,
    color 0.15s ease;
}

.border-input {
    border-color: var(--th-rule);
}

.border.border-input:hover,
.border-input:hover {
    border-color: var(--th-purple);
    color: var(--th-purple);
}

.hover\:bg-accent:hover {
    background-color: var(--th-purple-tint);
}

.hover\:text-accent-foreground:hover {
    color: var(--th-purple);
}

.hover\:bg-gray-100:hover,
.hover\:bg-gray-50:hover,
.hover\:bg-gray-200:hover {
    background-color: var(--th-paper-soft);
}

.hover\:text-gray-900:hover {
    color: var(--th-ink);
}

.hover\:border-gray-400:hover {
    border-color: var(--th-purple);
}

/* Focus ring: a square violet outline instead of a soft halo. */
.focus-visible\:ring-2:focus-visible,
.focus\:ring-2:focus {
    --tw-ring-color: rgba(104, 64, 189, 0.35);
    box-shadow: 0 0 0 3px rgba(104, 64, 189, 0.18);
}

.focus-visible\:ring-ring:focus-visible {
    --tw-ring-color: rgba(104, 64, 189, 0.35);
}

/* ------------------------------------------------------------
   6. Controls — fields
   ------------------------------------------------------------ */
input[type="text"],
input[type="email"],
input[type="number"],
input[type="search"],
input[type="password"],
input[type="tel"],
input[type="url"],
select,
textarea {
    border-radius: 0;
    background-color: #ffffff;
    border: 1px solid var(--th-rule);
    color: var(--th-ink);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

input::placeholder,
textarea::placeholder {
    color: var(--th-rule-strong);
}

input[type="text"]:focus,
input[type="email"]:focus,
input[type="number"]:focus,
input[type="search"]:focus,
input[type="password"]:focus,
input[type="tel"]:focus,
input[type="url"]:focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--th-purple);
    box-shadow: 0 0 0 3px rgba(104, 64, 189, 0.15);
}

input[type="checkbox"],
input[type="radio"] {
    accent-color: var(--th-purple);
}

label {
    color: var(--th-ink-soft);
}

/* Switches: square track and knob, so they sit with the rest of the UI. */
[role="switch"] {
    border-radius: 0;
    border-color: transparent;
}

[role="switch"] > span {
    border-radius: 0;
    background-color: #ffffff;
    box-shadow: inset 0 0 0 1px rgba(2, 6, 23, 0.14);
}

/* ------------------------------------------------------------
   7. Surfaces — cards read as white sheets on paper
   ------------------------------------------------------------ */
.rounded-lg.border,
.rounded-md.border,
.rounded-lg.border-border\/50,
.form-card,
.pricing-card,
.container-card {
    border-radius: 0;
}

.sticky-page-header {
    background: var(--th-paper);
    border-bottom: 1px solid var(--th-rule);
}

/* ------------------------------------------------------------
   8. Status tags — square, hairline, quiet
   ------------------------------------------------------------ */
.tag {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.1875rem 0.5rem;
    border: 1px solid var(--th-rule);
    background-color: var(--th-paper-soft);
    color: var(--th-ink-soft);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    line-height: 1.25rem;
    white-space: nowrap;
}

.tag svg {
    width: 0.75rem;
    height: 0.75rem;
    flex-shrink: 0;
}

.tag--purple {
    border-color: #dbcdf7;
    background-color: var(--th-purple-tint);
    color: var(--th-purple-deep);
}

.tag--green {
    border-color: #bbf7d0;
    background-color: #f0fdf4;
    color: #15803d;
}

.tag--blue {
    border-color: #bfdbfe;
    background-color: #eff6ff;
    color: #1d4ed8;
}

.tag--amber {
    border-color: #fde68a;
    background-color: #fffbeb;
    color: #b45309;
}

.tag--red {
    border-color: #fecaca;
    background-color: #fef2f2;
    color: #b91c1c;
}

.tag--gray {
    border-color: var(--th-rule);
    background-color: var(--th-paper-soft);
    color: var(--th-ink-muted);
}

/* Counter chip beside a button label. */
.count-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.25rem;
    height: 1.25rem;
    padding: 0 0.25rem;
    background-color: var(--th-purple);
    color: #ffffff;
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 1;
}

/* ------------------------------------------------------------
   9. Tables — hairline rows, tracked-out headers
   ------------------------------------------------------------ */
table thead th {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--th-ink-faint);
}

/* The workspace users table is six columns wide and only fits the content
   column from ~1100px. Between the point where it replaces the card list and
   there, trim the cell padding instead of letting it scroll sideways. */
@media (min-width: 1024px) and (max-width: 1149px) {
    .workspace-users-table th,
    .workspace-users-table td {
        padding-left: 0.5rem;
        padding-right: 0.5rem;
    }
}

table thead tr {
    border-color: var(--th-rule);
}

table tbody tr {
    border-color: var(--th-rule-soft);
}

table tbody tr:hover {
    background-color: var(--th-paper-soft);
}

/* ------------------------------------------------------------
   10. Left menu
   ------------------------------------------------------------ */
.left-menu {
    background-color: var(--th-paper-soft);
    border-right: 1px solid var(--th-rule);
}

.left-menu .menu-header {
    border-bottom: 1px solid var(--th-rule);
}

.left-menu .menu-section-title {
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--th-ink-faint);
}

.left-menu .menu-item {
    border-radius: 0;
    border-left: 2px solid transparent;
    color: var(--th-ink-soft);
    font-weight: 600;
    transition: background-color 0.15s ease, color 0.15s ease,
    border-color 0.15s ease;
}

.left-menu .menu-item:hover {
    background-color: #ffffff;
    color: var(--th-ink);
}

.left-menu .menu-item.active {
    background-color: #ffffff;
    border-left-color: var(--th-purple);
    color: var(--th-purple);
}

.left-menu .menu-version {
    color: var(--th-rule-strong);
    font-size: 0.625rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* Collapsed rail keeps the active marker legible. */
.left-menu.collapsed .menu-item {
    border-left-width: 2px;
}

/* Mobile header strip */
.mobile-header {
    background-color: var(--th-paper-soft);
    border-color: var(--th-rule);
}

/* Mobile drawer: a full-screen menu that covers the whole app, so it sits at
   the top of the stacking order (see the layer table at the end of this file). */
.mobile-drawer {
    z-index: 20000;
    overscroll-behavior: contain;
}

.mobile-drawer-panel {
    width: 100%;
    background: var(--th-paper-soft);
}

/* Full-bleed: no right-hand rule, since there is nothing beside it. */
.mobile-drawer .left-menu {
    border-right: 0;
}

/* The panel covers the scrim completely, so the close button is the only way
   out other than navigating. It is not optional. */

.mobile-drawer-close {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    color: var(--th-ink-muted);
    background: transparent;
    border: 1px solid transparent;
}

.mobile-drawer-close:hover,
.mobile-drawer-close:focus-visible {
    color: var(--th-purple);
    border-color: var(--th-rule);
    outline: none;
}

/* ------------------------------------------------------------
   11. Tabs
   ------------------------------------------------------------ */
[role="tablist"] {
    border-color: var(--th-rule) !important;
}

[role="tab"] {
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--th-ink-muted);
}

[role="tab"]:hover {
    color: var(--th-ink);
}

[role="tab"][data-state="active"] {
    color: var(--th-purple);
    border-bottom-color: var(--th-purple);
}

/* ------------------------------------------------------------
   12. Application components declared in app.css
   ------------------------------------------------------------ */
.form-card,
.pricing-card {
    background: var(--th-surface);
    border: 1px solid var(--th-rule);
    box-shadow: none;
}

.form-card-body {
    padding: 1.75rem;
}

.form-label {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--th-ink-muted);
}

.form-input {
    border-radius: 0;
    background: #ffffff;
    border: 1px solid var(--th-rule);
    height: 2.875rem;
}

.form-input:hover {
    border-color: var(--th-rule-strong);
}

.form-input:focus {
    border-color: var(--th-purple);
    box-shadow: 0 0 0 3px rgba(104, 64, 189, 0.15);
}

.form-hint {
    color: var(--th-ink-faint);
}

.form-actions {
    border-top: 1px solid var(--th-rule);
}

.form-submit {
    border-radius: 0;
    background: var(--th-ink);
    box-shadow: none;
    letter-spacing: 0.01em;
}

.form-submit:hover {
    background: var(--th-purple);
    box-shadow: none;
    filter: none;
    transform: none;
}

.form-submit:active {
    transform: none;
}

.pricing-card-header {
    background: var(--th-paper-soft);
    border-bottom: 1px solid var(--th-rule);
}

/* Between the phone layout and the two-column desktop one, the pricing card
   spans the whole content column and is mostly empty. Split it the way the
   marketing site's pricing panel is split — price on the left, what's
   included on the right, divided by a hairline. */
@media (min-width: 768px) and (max-width: 1023px) {
    .create-layout-aside .pricing-card {
        display: grid;
        grid-template-columns: 0.9fr 1.1fr;
    }

    .create-layout-aside .pricing-card-header {
        border-bottom: 0;
        border-right: 1px solid var(--th-rule);
    }

    /* The credit banner is a full-width lead-in above both columns, not a
       third cell — without this it takes the price column and displaces the
       header and feature list into the wrong cells. */
    .create-layout-aside .credit-banner {
        grid-column: 1 / -1;
    }
}

/* Credit banner — same hairline/square treatment as the rest of the console,
   keeping the green reserved for the "you already have money here" signal. */
.credit-banner {
    background: var(--th-credit-tint);
    border-bottom: 1px solid var(--th-credit-rule);
}

.credit-banner-row {
    color: var(--th-credit-ink);
}

.credit-banner-label {
    letter-spacing: 0.18em;
    font-weight: 700;
    font-size: 0.6875rem;
}

.credit-banner-amount {
    font-family: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas,
    monospace;
    letter-spacing: -0.03em;
    color: var(--th-credit-ink-strong);
}

.credit-banner-note {
    color: var(--th-credit-ink);
}

.pricing-eyebrow {
    letter-spacing: 0.18em;
    color: var(--th-purple);
    font-weight: 700;
    font-size: 0.6875rem;
}

.price-toggle {
    border-radius: 0;
    background: transparent;
    border: 1px solid var(--th-rule);
    padding: 0;
    gap: 0;
}

.price-toggle-btn {
    border-radius: 0;
    color: var(--th-ink-muted);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-size: 0.6875rem;
}

.price-toggle-btn + .price-toggle-btn {
    border-left: 1px solid var(--th-rule);
}

.price-toggle-btn.active {
    background: var(--th-ink);
    color: #ffffff;
    box-shadow: none;
}

.price-amount {
    font-family: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas,
    monospace;
    letter-spacing: -0.03em;
    color: var(--th-ink);
}

.price-period,
.price-approx,
.pricing-note {
    color: var(--th-ink-faint);
}

.pricing-feature svg {
    color: var(--th-purple);
}

.steps-box {
    border-radius: 0;
    background: var(--th-purple-tint);
    border: 1px solid #dbcdf7;
}

.steps-box-title {
    color: var(--th-purple-deep);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    font-size: 0.6875rem;
}

.step-num {
    border-radius: 0;
    background: var(--th-purple);
}

/* Container cards on the overview */
.container-card {
    border: 1px solid var(--th-rule);
    background: var(--th-surface);
    box-shadow: none;
    transition: border-color 0.2s ease, background-color 0.2s ease;
}

.container-card:hover {
    border-color: var(--th-purple);
    background: var(--th-paper-soft);
}

/* Workspace switcher */
.workspace-dropdown {
    border-radius: 0 !important;
    border: 1px solid var(--th-rule) !important;
    box-shadow: 0 18px 36px -20px rgba(2, 6, 23, 0.4) !important;
}

/* Info popovers */
.info-popover-card {
    border-radius: 0;
    border: 1px solid var(--th-rule);
    box-shadow: 0 18px 36px -20px rgba(2, 6, 23, 0.4);
    color: var(--th-ink-soft);
}

.info-popover-arrow {
    border-color: var(--th-rule);
}

.info-popover-link {
    border-radius: 0;
    background: var(--th-ink);
    color: #ffffff;
}

.info-popover-link:hover {
    background: var(--th-purple);
}

/* API connectivity banner */
.api-status-banner {
    background: var(--th-ink);
    border-bottom: 1px solid var(--th-purple);
    box-shadow: none;
}

.api-status-banner--success {
    background: #15803d;
    border-bottom-color: #15803d;
}

.api-status-banner__retry {
    border-radius: 0;
    color: var(--th-ink);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.api-status-banner__retry:hover {
    background: var(--th-purple);
    color: #ffffff;
    transform: none;
}

/* Toasts */
.toast {
    border-radius: 0;
    border-left: 3px solid rgba(255, 255, 255, 0.55);
    opacity: 1;
}

.toast-info {
    background-color: var(--th-purple);
}

.toast-success {
    background-color: #15803d;
}

.toast-warning {
    background-color: #b45309;
}

.toast-error {
    background-color: #b91c1c;
}

/* Blazor error strip */
#blazor-error-ui {
    background: var(--th-ink);
    color: #ffffff;
    box-shadow: none;
    border-top: 1px solid var(--th-purple);
}

#blazor-error-ui .reload,
#blazor-error-ui .dismiss {
    color: var(--th-purple-bright);
}

.blazor-error-boundary {
    background-color: var(--th-purple);
}

/* Loader — squares hopping on paper, in place of the circles */
.loader-overlay {
    background: rgba(245, 244, 239, 0.92);
}

.loaderdiv {
    width: 72px;
}

.circle {
    width: 14px;
    height: 14px;
    border-radius: 0;
    background-color: var(--th-purple);
}

/* Log console keeps a terminal feel but on the brand's near-black */
.log-content,
.log-container {
    border-radius: 0;
}

/* ------------------------------------------------------------
   13. Grey-scale utilities used by the log view / empty states
   ------------------------------------------------------------ */
.bg-gray-900 {
    background-color: #14161a;
}

.bg-gray-800,
.hover\:bg-gray-800\/50:hover {
    background-color: #1b1e23;
}

.border-gray-700 {
    border-color: #2b2f36;
}

.bg-gray-50 {
    background-color: var(--th-paper-soft);
}

.bg-gray-100 {
    background-color: var(--th-paper-soft);
}

.text-gray-600 {
    color: var(--th-ink-muted);
}

.text-gray-700 {
    color: var(--th-ink-soft);
}

.text-gray-900 {
    color: var(--th-ink);
}

.text-muted-foreground {
    color: var(--th-ink-muted);
}

/* ------------------------------------------------------------
   14. Radzen — chart + dropdown, aligned to the palette
   ------------------------------------------------------------ */
.rz-dropdown,
.rz-multiselect,
.rz-textbox,
.rz-numeric,
.rz-dropdown-panel,
.rz-dialog {
    border-radius: 0 !important;
    font-family: "Montserrat", system-ui, sans-serif !important;
}

.rz-dropdown,
.rz-textbox {
    border: 1px solid var(--th-rule) !important;
    background-color: #ffffff !important;
}

.rz-dropdown:not(.rz-state-disabled).rz-state-focused,
.rz-textbox:focus {
    border-color: var(--th-purple) !important;
    box-shadow: 0 0 0 3px rgba(104, 64, 189, 0.15) !important;
}

.rz-dropdown-panel {
    border: 1px solid var(--th-rule) !important;
    box-shadow: 0 18px 36px -20px rgba(2, 6, 23, 0.4) !important;
}

.rz-dropdown-panel .rz-dropdown-item.rz-state-highlight,
.rz-dropdown-panel .rz-dropdown-item:hover {
    background-color: var(--th-purple-tint) !important;
    color: var(--th-purple-deep) !important;
}

.rz-chart text {
    font-family: "Montserrat", system-ui, sans-serif !important;
    fill: var(--th-ink-muted);
}

/* ------------------------------------------------------------
   15. Mobile
   The console is a workspace tool, so phones get the same
   information — reflowed, not hidden.
   ------------------------------------------------------------ */

/* Page headers only became sticky (with padding) at >=768px, so on a phone
   the theme's hairline sat flush against the last line of text. */
@media (max-width: 767px) {
    .sticky-page-header {
        margin: -1.5rem -1.5rem 0 -1.5rem;
        padding: 1.5rem 1.5rem 1.25rem 1.5rem;
    }

    /* Page titles: let long container names wrap instead of collapsing to
       an ellipsis while a badge keeps its full width beside them. */
    .page-title-row {
        flex-wrap: wrap;
        font-size: 1.5rem;
        line-height: 1.2;
    }

    .page-title-name {
        min-width: 0;
        overflow-wrap: anywhere;
    }

    /* Header action clusters stack and fill the width. */
    .header-actions {
        width: 100%;
        flex-direction: column;
        align-items: stretch;
    }

    .header-actions > button,
    .header-actions > a {
        width: 100%;
    }

    /* Titles step down a size so they stop crowding the viewport. */
    .text-3xl {
        font-size: 1.5rem;
        line-height: 1.2;
    }

    .text-2xl {
        font-size: 1.3125rem;
        line-height: 1.25;
    }

    /* Dialog bodies use p-8 / px-8, which is a lot of a phone's width.
       Card padding (p-6) is deliberately left alone: the page wrapper uses
       the same value and `.sticky-page-header` cancels it with a negative
       margin, so changing it here would misalign the header rules. */
    .shadow-2xl .p-8 {
        padding: 1.5rem;
    }

    .shadow-2xl .px-8 {
        padding-left: 1.5rem;
        padding-right: 1.5rem;
    }

    /* The workspace switcher was a fixed 20rem inside a padded card.
       (Its dropdown panel is sized in ContainersPage.razor — that page's
       inline <style> renders after this sheet, so it has to own those
       rules.) */
    .w-80 {
        width: 100%;
    }

    /* Custom-amount + Pay + Cancel, promo code + Apply, and similar
       input-plus-button rows wrap rather than overflow. */
    .flex.items-end.gap-2 {
        flex-wrap: wrap;
    }

    .w-44,
    .w-36 {
        width: 100%;
    }

    /* Horizontally scrolling regions (the tab strip) scroll natively; the
       partially-visible next tab is the affordance. No edge fade — it would
       also paint over regions whose content happens to fit. */
    .overflow-x-auto,
    [role="tablist"] {
        -webkit-overflow-scrolling: touch;
    }

    /* Card header rows that pair a title with a button cluster: wrap rather
       than squeeze the title into two words per line. */
    .card-header-row {
        flex-wrap: wrap;
        gap: 0.75rem;
    }

    /* Terminal panel: `100vh - 400px` leaves almost nothing on a short
       phone, so clamp it to something readable. */
    .log-content {
        height: 60vh !important;
        min-height: 260px;
    }



    /* Dialogs get to use the full width and stay scrollable. */
    .shadow-2xl {
        max-height: calc(100vh - 2rem);
        overflow-y: auto;
    }
}

/* Wide data tables stack up to 1023px, not just on phones: the 16rem left
   menu appears at 768px, so tablet portrait leaves only ~464px of content —
   the payment history still overflowed it by 136px as a real table. */
@media (max-width: 1023px) {
    /* Wide data tables (payment history, transactions) reflow into
       label/value blocks instead of scrolling eight columns sideways.
       Each `td` carries a `data-label` matching its column header. */
    .table-stack thead {
        display: none;
    }

    .table-stack,
    .table-stack tbody,
    .table-stack tr,
    .table-stack td {
        display: block;
        width: auto;
    }

    .table-stack tr {
        border-bottom: 1px solid var(--th-rule);
        padding: 0.5rem 0;
    }

    .table-stack tr:last-child {
        border-bottom: 0;
    }

    .table-stack td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 1rem;
        padding: 0.3125rem 0 !important;
        text-align: right !important;
    }

    .table-stack td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        font-size: 0.625rem;
        font-weight: 700;
        letter-spacing: 0.1em;
        text-transform: uppercase;
        color: var(--th-ink-faint);
        text-align: left;
    }

    /* Cells with no label (or nothing to show) collapse away. */
    .table-stack td:not([data-label]) {
        display: none;
    }

    .table-stack td:empty {
        display: none;
    }

    /* The wrapper no longer needs to scroll once the table stacks. */
    .table-stack-wrap {
        overflow-x: visible;
        -webkit-mask-image: none;
        mask-image: none;
    }
}

/* Touch targets: much of the markup leans on h-8 / py-1.5 controls that come
   out at 29–34px. On a touch pointer they get a comfortable floor. */
@media (pointer: coarse) {
    button,
    a[class*="inline-flex"],
    [role="tab"],
    [role="switch"] {
        touch-action: manipulation;
    }

    button,
    a[class*="inline-flex"],
    .price-toggle-btn {
        min-height: 2.25rem;
    }

    /* Icon-only square buttons — copy, delete, download invoice — are the
       only route to those actions, so they get the full target. */
    .h-8:where(button, a),
    .w-8.h-8:where(button, a),
    .w-9.h-9:where(button, a) {
        min-height: 2.5rem;
        min-width: 2.5rem;
    }

    [role="tab"] {
        min-height: 2.75rem;
    }
}

/* ------------------------------------------------------------
   16. Scrollbars
   ------------------------------------------------------------ */
* {
    scrollbar-color: var(--th-rule) transparent;
}

::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: var(--th-rule);
    border: 3px solid transparent;
    background-clip: content-box;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--th-rule-strong);
    background-clip: content-box;
}

/* ============================================================
   17. Stacking order
   ------------------------------------------------------------
   The app had no layer scheme, just escalating magic numbers —
   which is how the workspace switcher (999999 / 9999999) ended
   up painting over the loader on mobile. Anything that needs to
   sit above the page belongs on this ladder; do not invent a
   bigger number.

       20      sticky page header        app.css
       30/40   popovers & dropdowns      workspace switcher,
                                         info popover
       1000    Blazor error strip        app.css
       1050    blocking loader overlay   app.css
       9999    toasts                    ToastComponent
       10000   API connectivity banner   app.css
       20000   mobile menu               .mobile-drawer

   Dialogs (ConfirmationComponent, AddonsModalComponent) still
   carry inline z-indexes of 9999/10000 from before this scale
   existed. They land between the toasts and the banner, which
   is where they belong, so they are left as-is — but they are
   the one group not expressed here.

   Note that `position: sticky` + `z-index` on `.sticky-page-header`
   creates a stacking context at >=768px and none below it, so a
   z-index that looks contained on desktop can escape on mobile.
   ============================================================ */
