/* =====================================================================
   Interview Pro — professional light SaaS design system, themed from
   ONE variable. Colors default to the main Digivo Digital site's own
   palette (assets/css/style.css), so the module reads as the same brand
   out of the box — but the shell is its own thing: a sidebar app layout
   (with a dark sidebar, like the admin panel's) instead of the main
   site's top marketing nav, different type system, different component
   language. Every color is admin-editable at any time via admin/ip_theme.php.

   ---- TO RE-THEME THE ENTIRE MODULE, CHANGE ONLY --ip-brand BELOW. ----
   Every accent, gradient, hover state, focus ring, tinted background,
   and the sidebar's active-link highlight are all mathematically
   derived from that single color via color-mix() — nothing else in
   this file (or in any Interview Pro page) hardcodes a brand color.

   Type:  display/body "Plus Jakarta Sans" · mono "IBM Plex Mono"
   ===================================================================== */

:root {
  /* ============ SINGLE SOURCE OF TRUTH ============
     --ip-brand    drives links, badges, focus rings, the sidebar's active
                   state and its background tint.
     --ip-button   drives every primary (.ip-btn-primary) button — its own
                   variable since a CTA color is often chosen separately
                   from the general brand/link color (here they match, both
                   sourced from the main Digivo Digital site's --primary).
     --ip-card-bg      drives "showcase" cards in the logged-in app (stat
                       tiles, mock interview browse cards, generic .ip-card)
                       — kept separate from --ip-surface, which still covers
                       functional/reading surfaces (the exam question card,
                       tables, toasts, modals) that need to stay neutral.
     --ip-auth-card-bg drives ONLY the login/register/forgot/reset-password
                       card — deliberately its own variable, not reusing
                       --ip-card-bg, so picking a bold color for the app's
                       showcase cards can't also (surprisingly) recolor the
                       login page, and vice versa.

     These defaults mirror assets/css/style.css (the main site's own
     design tokens) exactly, so Interview Pro reads as the same brand out
     of the box — change any of them (or use admin/ip_theme.php) to
     diverge from it. */
  --ip-brand: #6c4cf1;
  --ip-button: #6c4cf1;
  --ip-card-bg: #ffffff;
  --ip-auth-card-bg: #ffffff;
  /* ================================================== */

  /* Deliberately separate, directly-settable accents — each drives just
     ONE specific element, so picking a bold --ip-brand above (which
     still drives links/focus rings/pills) doesn't also repaint these:
       --ip-brand-name  the "Pro" in the logo text
       --ip-price-color the "₹200 / Attempt" price on test cards
       --ip-wallet       the wallet topbar chip's icon + background tint */
  --ip-brand-name: #6c4cf1;
  --ip-price-color: #6c4cf1;
  --ip-wallet: #4350a8;
  --ip-wallet-bg: color-mix(in srgb, var(--ip-wallet) 14%, white);

  /* ---- Derived brand shades — do not edit these directly ---- */
  --ip-accent: var(--ip-brand);
  --ip-accent-dark: color-mix(in srgb, var(--ip-brand) 80%, black);
  --ip-accent-soft: color-mix(in srgb, var(--ip-brand) 11%, white);
  --ip-accent-ring: color-mix(in srgb, var(--ip-brand) 30%, transparent);
  --ip-accent-glow: color-mix(in srgb, var(--ip-brand) 40%, transparent);
  --ip-gradient: var(--ip-brand); /* solid, not a gradient — kept as a "gradient" name so nothing else needs to change if you ever want one back */
  --ip-on-accent: #ffffff;

  /* ---- Derived button shades — do not edit these directly ---- */
  --ip-button-dark: color-mix(in srgb, var(--ip-button) 82%, black);
  --ip-button-glow: color-mix(in srgb, var(--ip-button) 45%, transparent);
  --ip-button-gradient: var(--ip-button); /* solid, not a gradient */
  --ip-on-button: #ffffff; /* white text — matches style.css's .btn-le-primary { color: #fff; } on the same purple */

  /* ---- Neutral surface system — same tokens as style.css's :root ---- */
  --ip-bg: #f6f5fb;
  --ip-surface: #ffffff;
  --ip-surface-alt: #efedf9;
  --ip-surface-raised: #ffffff;
  --ip-border: #e9e7f2;
  --ip-text: #14121f;
  --ip-text-soft: #625f76;
  --ip-text-faint: #8d86a6;
  --ip-heading: #14121f;

  /* App input fields (support tickets, wallet top-up, profile) — its own
     variable rather than reusing --ip-surface-alt, so picking a bold
     "Alt surfaces" color for pills/table headers doesn't also recolor
     every input box. Default matches --ip-surface-alt, so this split
     alone changes nothing. */
  --ip-input-bg: #efedf9;

  /* Login/register/forgot/reset input field background — its own variable
     rather than reusing --ip-input-bg, so it doesn't also recolor every
     input field elsewhere in the app. Default matches --ip-input-bg
     above, so this split alone changes nothing. */
  --ip-auth-input-bg: #efedf9;

  /* ---- Sidebar — deep, professional contrast against the light canvas.
     --ip-sidebar-bg is its own directly-settable root color (default
     below is what color-mix(brand 22%, #0a0e1a) used to compute, so this
     change alone doesn't move anything) — independent of --ip-brand so
     picking a sidebar color doesn't require also changing the brand
     color, and vice versa. Its border derives from ITS OWN background
     now (not brand), so it stays visually coherent with whatever the
     sidebar actually is. Active-link highlight still derives from
     --ip-brand deliberately — that's brand-accent-as-selection, not
     "sidebar chrome". Inactive-link text matches the admin panel's own dark sidebar. */
  --ip-sidebar-bg: #201c49;
  --ip-sidebar-border: color-mix(in srgb, var(--ip-sidebar-bg) 80%, white);
  --ip-sidebar-text: #b9b4cc;
  --ip-sidebar-text-hover: #ffffff;
  --ip-sidebar-active-bg: color-mix(in srgb, var(--ip-brand) 30%, transparent);
  --ip-sidebar-active-text: color-mix(in srgb, var(--ip-brand) 55%, white);

  /* ---- Status colors — same tokens as style.css (--teal, --amber) plus
     the admin panel's own danger/failed pill color ---- */
  --ip-success: #12b886;
  --ip-success-bg: color-mix(in srgb, var(--ip-success) 11%, white);
  --ip-success-border: color-mix(in srgb, var(--ip-success) 30%, transparent);
  --ip-warning: #ffb020;
  --ip-warning-bg: color-mix(in srgb, var(--ip-warning) 11%, white);
  --ip-warning-border: color-mix(in srgb, var(--ip-warning) 30%, transparent);
  --ip-danger: #c0392b;
  --ip-danger-bg: color-mix(in srgb, var(--ip-danger) 10%, white);
  --ip-danger-border: color-mix(in srgb, var(--ip-danger) 30%, transparent);
  --ip-info-bg: var(--ip-accent-soft);
  --ip-info-border: var(--ip-accent-ring);

  --ip-radius-lg: 18px;
  --ip-radius-md: 12px;
  --ip-radius-sm: 8px;

  --ip-shadow-md: 0 12px 32px -14px rgba(15,23,42,0.18);
  --ip-shadow-lg: 0 24px 60px -20px rgba(15,23,42,0.22);

  --ip-font-display: "Plus Jakarta Sans", "Inter", sans-serif;
  --ip-font-body: "Plus Jakarta Sans", -apple-system, Segoe UI, sans-serif;
  --ip-font-mono: "IBM Plex Mono", ui-monospace, monospace;
}

.ip-scope, .ip-scope *, .ip-scope *::before, .ip-scope *::after { box-sizing: border-box; }
.ip-scope {
  /* Tells the browser/OS this page is deliberately light-themed, so it
     won't run its own "auto dark mode" heuristics on top of it — without
     this, Chrome/Edge's forced-dark inversion can wash out light text on
     colored gradient buttons (exactly the "ghost text" bug this fixes). */
  color-scheme: light only;
  background: var(--ip-bg); color: var(--ip-text); font-family: var(--ip-font-body); min-height: 100vh;
}
.ip-scope p, .ip-scope ul, .ip-scope form { margin: 0; }
.ip-scope button { font-family: inherit; }
.ip-scope h1, .ip-scope h2, .ip-scope h3, .ip-scope h4 { font-family: var(--ip-font-display); color: var(--ip-heading); font-weight: 700; letter-spacing: -0.02em; }
.ip-scope a { color: var(--ip-accent); text-decoration: none; }
.ip-scope a:hover { color: var(--ip-accent-dark); }
.ip-scope ::selection { background: var(--ip-accent); color: var(--ip-on-accent); }
.ip-scope small, .ip-scope .ip-soft { color: var(--ip-text-soft); }
.ip-mono { font-family: var(--ip-font-mono); }

/* ---------- Guest shell (register / login / forgot / reset) ---------- */
.ip-guest-topbar { padding: 1.25rem 1.5rem; display: flex; align-items: center; justify-content: space-between; }
.ip-scope .ip-brand { display: inline-flex; align-items: center; gap: 0.55rem; font-family: var(--ip-font-display); font-weight: 800; font-size: 1.15rem; color: var(--ip-heading); }
.ip-brand .ip-brand-mark { width: 30px; height: 30px; border-radius: 50%; object-fit: contain; flex-shrink: 0; filter: drop-shadow(0 0 10px var(--ip-accent-glow)); }
.ip-brand-accent { color: var(--ip-brand-name); }
.ip-guest-wrap { min-height: calc(100vh - 76px); display: flex; align-items: center; justify-content: center; padding: 2rem 1rem; }
.ip-auth-card { width: 100%; max-width: 440px; background: var(--ip-auth-card-bg); border: 1px solid var(--ip-border); border-radius: var(--ip-radius-lg); padding: 2.2rem; box-shadow: var(--ip-shadow-lg); }
.ip-auth-card h1 { font-size: 1.5rem; margin-bottom: 0.35rem; text-align: center; }
.ip-auth-sub { color: var(--ip-text-soft); font-size: 0.92rem; margin-bottom: 1.6rem; text-align: center; }

/* ---------- App shell (dashboard + everything logged-in) ---------- */
.ip-shell { display: flex; min-height: 100vh; }
.ip-sidebar { width: 246px; flex-shrink: 0; background: var(--ip-sidebar-bg); border-right: 1px solid var(--ip-sidebar-border); padding: 1.4rem 1rem; position: sticky; top: 0; height: 100vh; overflow-y: auto; display: flex; flex-direction: column; }
.ip-sidebar .ip-brand { margin-bottom: 2rem; padding: 0 0.4rem; color: var(--ip-sidebar-text-hover); }
.ip-side-nav { display: flex; flex-direction: column; gap: 0.15rem; flex-grow: 1; }
.ip-side-nav a { display: flex; align-items: center; gap: 0.65rem; padding: 0.62rem 0.8rem; border-radius: var(--ip-radius-sm); color: var(--ip-sidebar-text); font-weight: 600; font-size: 0.9rem; }
.ip-side-nav a:hover { background: rgba(255,255,255,0.07); color: var(--ip-sidebar-text-hover); }
.ip-side-nav a.active { background: var(--ip-sidebar-active-bg); color: var(--ip-sidebar-active-text); }
.ip-side-nav hr { border-color: var(--ip-sidebar-border); margin: 0.9rem 0; }
.ip-sidebar-foot { font-size: 0.78rem; color: color-mix(in srgb, var(--ip-sidebar-text) 65%, transparent); padding: 0 0.4rem; }
/* .ip-scope prefix here is load-bearing too (see the .ip-btn-outline
   fix further down) — without it, this tied on specificity with
   ".ip-scope .ip-btn-outline" and lost by source order, which is what
   made the sidebar's Log out button text invisible: dark app-text color
   on the dark sidebar background instead of the intended light sidebar text. */
.ip-scope .ip-sidebar .ip-btn-outline { border-color: var(--ip-sidebar-border); color: var(--ip-sidebar-text); }
.ip-scope .ip-sidebar .ip-btn-outline:hover { border-color: var(--ip-brand); color: var(--ip-sidebar-text-hover); }
.ip-main { flex-grow: 1; max-width: 100%; overflow-x: hidden; min-width: 0; }
.ip-topbar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem 1.75rem; border-bottom: 1px solid var(--ip-border); flex-wrap: wrap; }
.ip-content { padding: 1.75rem; }
.ip-wallet-chip { display: inline-flex; align-items: center; gap: 0.5rem; background: var(--ip-wallet-bg); border: 1px solid var(--ip-border); border-radius: 999px; padding: 0.4rem 0.95rem; font-family: var(--ip-font-mono); font-size: 0.85rem; font-weight: 600; white-space: nowrap; }
.ip-wallet-chip i { color: var(--ip-wallet); }

/* Mobile-only sidebar toggle + off-canvas drawer. Hidden entirely on
   desktop, where the sidebar is always visible in-flow. */
.ip-menu-toggle { display: none; background: transparent; border: 1px solid var(--ip-border); color: var(--ip-heading); font-size: 1.1rem; line-height: 1; border-radius: var(--ip-radius-sm); padding: 0.45rem 0.65rem; cursor: pointer; }
.ip-topbar-brand { display: none; font-size: 1rem; }
.ip-sidebar-backdrop { display: none; position: fixed; inset: 0; background: rgba(4,6,12,0.55); z-index: 190; }

/* Desktop sidebar collapse — opt-in via .ip-collapsible on .ip-shell (the
   exam screen sets $ip_collapsible_sidebar). Distinct from the mobile
   off-canvas drawer below: this collapses the sidebar's width in place
   rather than overlaying it, since at desktop widths it's still part of
   the normal flex layout, not a fixed overlay. */
@media (min-width: 881px) {
  .ip-shell.ip-collapsible .ip-menu-toggle { display: inline-flex; }
  .ip-shell.ip-collapsible .ip-sidebar { transition: width 0.2s ease, padding 0.2s ease; }
  .ip-shell.ip-collapsible.ip-sidebar-collapsed .ip-sidebar { width: 0; padding: 0; border-right: 0; overflow: hidden; }
}

@media (max-width: 880px) {
  .ip-menu-toggle { display: inline-flex; }
  .ip-topbar-brand { display: inline-flex; }
  .ip-shell { display: block; }
  .ip-sidebar {
    position: fixed; top: 0; left: 0; height: 100vh; z-index: 200;
    transform: translateX(-100%); transition: transform 0.22s ease;
    box-shadow: var(--ip-shadow-lg);
  }
  .ip-sidebar.ip-sidebar-open { transform: translateX(0); }
  .ip-sidebar-backdrop.ip-open { display: block; }
  .ip-main { width: 100%; }
  .ip-topbar { padding: 0.85rem 1.1rem; }
  .ip-content { padding: 1.1rem; }
  .ip-test-header { padding: 0.75rem 1rem; }
  .ip-test-body { padding: 1rem; gap: 1rem; }
  .ip-question-card { padding: 1.2rem; }
}

@media (max-width: 480px) {
  .ip-content { padding: 0.85rem; }
  .ip-auth-card { padding: 1.5rem; }
  .ip-wallet-chip { font-size: 0.78rem; padding: 0.35rem 0.75rem; }
  .ip-toast-wrap { left: 0.7rem; right: 0.7rem; top: 0.7rem; }
  .ip-toast { min-width: 0; max-width: none; width: 100%; }
  .ip-palette-grid { grid-template-columns: repeat(4, 1fr); }
  .ip-test-nav { flex-direction: column-reverse; }
  .ip-test-nav .ip-btn { width: 100%; }
}

/* ---------- Buttons ---------- */
.ip-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.45rem; border: 1px solid transparent; border-radius: var(--ip-radius-sm); font-weight: 700; font-size: 0.9rem; padding: 0.62rem 1.25rem; cursor: pointer; transition: transform 0.12s ease, box-shadow 0.12s ease, opacity 0.12s ease; }
.ip-btn:active { transform: translateY(1px); }
/* .ip-scope prefix here is load-bearing, not decoration: it raises these
   rules' specificity (0,2,0) above ".ip-scope a" (0,1,1) above, which
   would otherwise win its color fight on any button rendered as an <a>
   (e.g. .ip-btn-primary on an <a> lost to var(--ip-accent), making a
   button's own white text invisible against its solid background). */
.ip-scope .ip-btn-primary { background: var(--ip-button-gradient); color: var(--ip-on-button); box-shadow: 0 8px 24px -8px var(--ip-button-glow); }
.ip-scope .ip-btn-primary:hover { color: var(--ip-on-button); opacity: 0.92; }
.ip-scope .ip-btn-outline { background: transparent; border-color: var(--ip-border); color: var(--ip-text); }
.ip-scope .ip-btn-outline:hover { border-color: var(--ip-accent); color: var(--ip-accent); }
.ip-scope .ip-btn-ghost { background: transparent; color: var(--ip-text-soft); }
.ip-scope .ip-btn-ghost:hover { color: var(--ip-heading); }
.ip-scope .ip-btn-danger { background: var(--ip-danger-bg); color: var(--ip-danger); }
.ip-scope .ip-btn-danger:hover { color: var(--ip-on-accent); background: var(--ip-danger); }
.ip-btn-sm { padding: 0.42rem 0.85rem; font-size: 0.8rem; }
.ip-btn-block { width: 100%; }
/* Explicit colors here, not opacity-faded whatever-the-variant-had: fading
   dark text (e.g. .ip-btn-outline's near-black) via opacity alone washes
   it out to near-invisible pale gray on a light card. Also pinned against
   :hover — disabled buttons still visually match :hover in most browsers
   (disabled only blocks clicks, not CSS hover matching), which was why
   this text was only readable on hover: the hover color (vivid purple)
   stays visibly colored even faded, unlike the near-black default. */
.ip-scope .ip-btn:disabled,
.ip-scope .ip-btn:disabled:hover {
  opacity: 1;
  cursor: not-allowed;
  background: var(--ip-surface-alt);
  border-color: var(--ip-border);
  color: var(--ip-text-faint);
  box-shadow: none;
  transform: none;
}

/* ---------- Forms ---------- */
.ip-scope label { font-size: 0.83rem; font-weight: 600; color: var(--ip-text-soft); margin-bottom: 0.35rem; display: block; }
.ip-input, .ip-scope select.ip-input, .ip-scope textarea.ip-input {
  width: 100%; background: var(--ip-input-bg); border: 1px solid var(--ip-border); color: var(--ip-text);
  border-radius: var(--ip-radius-sm); padding: 0.68rem 0.9rem; font-size: 0.92rem; font-family: var(--ip-font-body);
}
.ip-input:focus { outline: none; border-color: var(--ip-accent); box-shadow: 0 0 0 3px var(--ip-accent-ring); }
/* Overrides the background above specifically inside the login/register/
   forgot/reset card — 2 classes beats .ip-input's 1, no .ip-scope prefix needed. */
.ip-auth-card .ip-input { background: var(--ip-auth-input-bg); }
.ip-field { margin-bottom: 1.05rem; }
.ip-field-hint { font-size: 0.78rem; color: var(--ip-text-faint); margin-top: 0.3rem; }

/* Icon-in-input fields (login/register auth cards) — icon sits absolutely
   over the input's left padding, input text is inset to clear it. Wraps
   just the input (not the label/hint), so the icon centers on the input
   itself regardless of what else is in the .ip-field. */
.ip-input-wrap { position: relative; }
.ip-input-wrap > i { position: absolute; left: 0.9rem; top: 50%; transform: translateY(-50%); color: var(--ip-text-soft); font-size: 0.9rem; pointer-events: none; }
.ip-input-wrap > .ip-input { padding-left: 2.4rem; }

/* ---------- Cards / stat tiles ---------- */
.ip-card { background: var(--ip-card-bg); border: 1px solid var(--ip-border); border-radius: var(--ip-radius-lg); padding: 1.4rem; }
.ip-stat { background: var(--ip-card-bg); border: 1px solid var(--ip-border); border-radius: var(--ip-radius-lg); padding: 1.3rem 1.4rem; position: relative; overflow: hidden; }
.ip-stat .ip-stat-label { font-family: var(--ip-font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ip-text-soft); }
.ip-stat .ip-stat-value { font-family: var(--ip-font-display); font-size: 1.9rem; font-weight: 800; color: var(--ip-heading); margin-top: 0.3rem; }
.ip-stat .ip-stat-sub { font-size: 0.8rem; color: var(--ip-text-faint); margin-top: 0.2rem; }
.ip-stat.ip-stat-accent::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--ip-gradient); }

.ip-test-card { background: var(--ip-card-bg); border: 1px solid var(--ip-border); border-radius: var(--ip-radius-lg); padding: 1.5rem; display: flex; flex-direction: column; gap: 0.9rem; transition: border-color 0.15s, transform 0.15s; }
.ip-test-card:hover { border-color: var(--ip-accent); transform: translateY(-2px); }
.ip-test-card h3 { font-size: 1.15rem; margin: 0; }
.ip-test-meta { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.ip-test-meta span { font-size: 0.78rem; color: var(--ip-text-soft); background: var(--ip-surface-alt); border-radius: 999px; padding: 0.28rem 0.7rem; }
.ip-test-price { font-family: var(--ip-font-mono); font-size: 1.05rem; font-weight: 700; color: var(--ip-price-color); }

/* ---------- Badges / pills ---------- */
.ip-pill { display: inline-flex; align-items: center; gap: 0.35rem; font-family: var(--ip-font-mono); font-size: 0.72rem; font-weight: 600; padding: 0.24rem 0.65rem; border-radius: 999px; }
.ip-pill-success { background: var(--ip-success-bg); color: var(--ip-success); }
.ip-pill-warning { background: var(--ip-warning-bg); color: var(--ip-warning); }
.ip-pill-danger { background: var(--ip-danger-bg); color: var(--ip-danger); }
.ip-pill-info { background: var(--ip-info-bg); color: var(--ip-accent); }
.ip-pill-neutral { background: var(--ip-surface-alt); color: var(--ip-text-soft); }

/* ---------- Alerts / toasts ---------- */
.ip-alert { border-radius: var(--ip-radius-md); padding: 0.85rem 1.05rem; font-size: 0.88rem; border: 1px solid transparent; }
.ip-alert-success { background: var(--ip-success-bg); color: var(--ip-success); border-color: var(--ip-success-border); }
.ip-alert-danger { background: var(--ip-danger-bg); color: var(--ip-danger); border-color: var(--ip-danger-border); }
.ip-alert-info { background: var(--ip-info-bg); color: var(--ip-accent); border-color: var(--ip-info-border); }
.ip-alert-warning { background: var(--ip-warning-bg); color: var(--ip-warning); border-color: var(--ip-warning-border); }

.ip-toast-wrap { position: fixed; top: 1.1rem; right: 1.1rem; z-index: 2000; display: flex; flex-direction: column; gap: 0.6rem; }
.ip-toast { min-width: 260px; max-width: 340px; background: var(--ip-surface-raised); border: 1px solid var(--ip-border); border-radius: var(--ip-radius-md); padding: 0.8rem 1rem; box-shadow: var(--ip-shadow-md); font-size: 0.85rem; animation: ip-toast-in 0.18s ease-out; }
.ip-toast.ip-toast-success { border-left: 3px solid var(--ip-success); }
.ip-toast.ip-toast-danger { border-left: 3px solid var(--ip-danger); }
@keyframes ip-toast-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } }

/* ---------- Tables ---------- */
.ip-table-wrap { overflow-x: auto; border: 1px solid var(--ip-border); border-radius: var(--ip-radius-lg); }
.ip-table { width: 100%; border-collapse: collapse; font-size: 0.87rem; background: var(--ip-surface); }
.ip-table th { text-align: left; padding: 0.75rem 1rem; background: var(--ip-surface-alt); font-family: var(--ip-font-mono); font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.07em; color: var(--ip-text-soft); white-space: nowrap; border-bottom: 1px solid var(--ip-border); }
.ip-table td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--ip-border); vertical-align: middle; }
.ip-table tr:last-child td { border-bottom: none; }
.ip-table tr:hover td { background: var(--ip-surface-alt); }

/* ---------- Ticket thread ---------- */
.ip-msg { border: 1px solid var(--ip-border); border-radius: var(--ip-radius-md); padding: 0.9rem 1.1rem; margin-bottom: 0.8rem; }
.ip-msg-candidate { background: var(--ip-surface); }
.ip-msg-admin { background: var(--ip-info-bg); }
.ip-msg-system { background: var(--ip-surface-alt); font-size: 0.83rem; color: var(--ip-text-soft); font-style: italic; padding: 0.6rem 1.1rem; }
.ip-msg-head { display: flex; justify-content: space-between; gap: 1rem; font-size: 0.78rem; color: var(--ip-text-soft); margin-bottom: 0.4rem; }
.ip-msg-author { font-weight: 700; color: var(--ip-heading); }
.ip-msg-body { white-space: pre-wrap; word-break: break-word; }

/* ---------- Empty / skeleton states ---------- */
.ip-empty { text-align: center; padding: 3rem 1.5rem; color: var(--ip-text-soft); }
.ip-empty .ip-empty-icon { font-size: 2.2rem; margin-bottom: 0.6rem; opacity: 0.6; }
.ip-skel { background: linear-gradient(90deg, var(--ip-surface-alt) 25%, var(--ip-surface-raised) 37%, var(--ip-surface-alt) 63%); background-size: 400% 100%; animation: ip-skel 1.4s ease infinite; border-radius: var(--ip-radius-sm); }
@keyframes ip-skel { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ---------- Progress bar ---------- */
.ip-progress { height: 8px; background: var(--ip-surface-alt); border-radius: 999px; overflow: hidden; }
.ip-progress-fill { height: 100%; background: var(--ip-gradient); border-radius: 999px; transition: width 0.25s ease; }

/* ---------- Test-taking screen ---------- */
.ip-test-header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 0.8rem; padding: 0.9rem 1.5rem; background: var(--ip-surface); border-bottom: 1px solid var(--ip-border); position: sticky; top: 0; z-index: 50; }
.ip-timer { font-family: var(--ip-font-mono); font-size: 1.15rem; font-weight: 700; background: var(--ip-surface-alt); border: 1px solid var(--ip-border); border-radius: var(--ip-radius-sm); padding: 0.4rem 0.9rem; }
.ip-timer.ip-timer-low { color: var(--ip-danger); border-color: var(--ip-danger-border); animation: ip-pulse 1s ease infinite; }
@keyframes ip-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }

.ip-test-body { display: grid; grid-template-columns: 1fr 300px; gap: 1.5rem; padding: 1.5rem; align-items: start; }
@media (max-width: 900px) { .ip-test-body { grid-template-columns: 1fr; } }

.ip-question-card { background: var(--ip-surface); border: 1px solid var(--ip-border); border-radius: var(--ip-radius-lg); padding: 1.8rem; }
.ip-question-text { font-size: 1.08rem; line-height: 1.6; color: var(--ip-heading); margin-bottom: 1.4rem; }
.ip-option { display: flex; align-items: flex-start; gap: 0.75rem; padding: 0.85rem 1rem; border: 1px solid var(--ip-border); border-radius: var(--ip-radius-md); margin-bottom: 0.65rem; cursor: pointer; transition: border-color 0.12s, background 0.12s; }
.ip-option:hover { border-color: var(--ip-accent); }
.ip-option.ip-selected { border-color: var(--ip-accent); background: var(--ip-info-bg); }
.ip-option input { margin-top: 0.2rem; accent-color: var(--ip-accent); }
.ip-option-letter { font-family: var(--ip-font-mono); font-weight: 700; color: var(--ip-text-soft); }
.ip-option.ip-selected .ip-option-letter { color: var(--ip-accent); }

.ip-test-nav { display: flex; justify-content: space-between; gap: 0.6rem; margin-top: 1.6rem; flex-wrap: wrap; }

.ip-palette-card { background: var(--ip-surface); border: 1px solid var(--ip-border); border-radius: var(--ip-radius-lg); padding: 1.2rem; position: sticky; top: 90px; }
.ip-palette-legend { display: flex; flex-direction: column; gap: 0.4rem; font-size: 0.76rem; color: var(--ip-text-soft); margin-bottom: 1rem; }
.ip-palette-legend span { display: inline-flex; align-items: center; gap: 0.4rem; }
.ip-legend-dot { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.ip-palette-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 0.4rem; }
.ip-palette-btn { aspect-ratio: 1; border-radius: 8px; border: 1px solid var(--ip-border); background: var(--ip-surface-alt); color: var(--ip-text-soft); font-family: var(--ip-font-mono); font-size: 0.78rem; font-weight: 700; cursor: pointer; display: flex; align-items: center; justify-content: center; }
.ip-palette-btn.ip-p-answered { background: var(--ip-success-bg); color: var(--ip-success); border-color: var(--ip-success-border); }
.ip-palette-btn.ip-p-marked { background: var(--ip-warning-bg); color: var(--ip-warning); border-color: var(--ip-warning-border); }
.ip-palette-btn.ip-p-unanswered { background: var(--ip-surface-alt); color: var(--ip-text-soft); }
.ip-palette-btn.ip-p-current { outline: 2px solid var(--ip-accent); outline-offset: 1px; }
.ip-palette-btn.ip-p-locked { background: var(--ip-surface-alt); color: var(--ip-text-faint); border-style: dashed; cursor: not-allowed; opacity: 0.7; font-size: 0.72rem; }

/* ---------- Result page ---------- */
.ip-score-ring { width: 150px; height: 150px; border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-direction: column; background: conic-gradient(var(--ip-accent) calc(var(--pct,0) * 1%), var(--ip-surface-alt) 0); margin: 0 auto; }
.ip-score-ring-inner { width: 118px; height: 118px; border-radius: 50%; background: var(--ip-surface); display: flex; flex-direction: column; align-items: center; justify-content: center; }
.ip-score-ring-inner .num { font-family: var(--ip-font-display); font-size: 1.6rem; font-weight: 800; color: var(--ip-heading); }
.ip-score-ring-inner .lbl { font-size: 0.7rem; color: var(--ip-text-soft); }

.ip-review-item { border: 1px solid var(--ip-border); border-radius: var(--ip-radius-md); padding: 1.1rem 1.3rem; margin-bottom: 0.8rem; }
.ip-review-item.ip-correct { border-left: 3px solid var(--ip-success); }
.ip-review-item.ip-incorrect { border-left: 3px solid var(--ip-danger); }
.ip-review-item.ip-skipped { border-left: 3px solid var(--ip-text-faint); }

/* ---------- Modal ---------- */
.ip-modal-backdrop { position: fixed; inset: 0; background: rgba(4,6,12,0.72); display: none; align-items: center; justify-content: center; z-index: 1000; padding: 1rem; }
.ip-modal-backdrop.ip-open { display: flex; }
.ip-modal { width: 100%; max-width: 420px; background: var(--ip-surface-raised); border: 1px solid var(--ip-border); border-radius: var(--ip-radius-lg); padding: 1.6rem; box-shadow: var(--ip-shadow-lg); }

/* ---------- Misc ---------- */
.ip-divider { border: none; border-top: 1px solid var(--ip-border); margin: 1.2rem 0; }
.ip-page-title { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 0.8rem; margin-bottom: 1.5rem; }
.ip-page-title h1 { font-size: 1.55rem; margin: 0; }

.ip-spinner { width: 34px; height: 34px; border-radius: 50%; border: 3px solid var(--ip-border); border-top-color: var(--ip-accent); animation: ip-spin 0.7s linear infinite; }
@keyframes ip-spin { to { transform: rotate(360deg); } }

.ip-amount-chip { border: 1px solid var(--ip-border); background: var(--ip-surface-alt); color: var(--ip-text); border-radius: var(--ip-radius-sm); padding: 0.55rem 0.9rem; font-weight: 700; font-family: var(--ip-font-mono); cursor: pointer; }
.ip-amount-chip.ip-selected { border-color: var(--ip-accent); background: var(--ip-info-bg); color: var(--ip-accent); }
