/*
Theme Name: QueStudy
Theme URI: https://www.questudy.com
Author: QueStudy Team
Author URI: https://www.questudy.com
Description: Premium EdTech SaaS WordPress theme for the QueStudy educational examination platform. Designed for students, teachers, schools, and researchers. Fully integrated with the QueStudy Exam System UI plugin for online CBT examinations, practice tests, AI learning tools, and academic management.
Version: 7.2.0
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 8.0
License: GPL v3 or later
License URI: https://www.gnu.org/licenses/gpl-3.0.html
Text Domain: questudy
Domain Path: /languages
Tags: education, lms, learning-management-system, e-learning, examination, cbt, modern, saas, dashboard, two-columns, right-sidebar, custom-header, custom-menu, custom-logo, featured-images, theme-options, translation-ready, blog, portfolio, accessibility-ready

QueStudy Theme, (C) 2026 QueStudy.com
QueStudy is distributed under the terms of the GNU GPL v3 or later.
*/

/* ==========================================================================
   QueStudy Design System — canonical tokens (single source of truth)

   Every colour, radius, shadow and type value in the theme resolves through
   this block. It is the ONLY place these are defined.

   Do not redeclare any of these in another stylesheet. Two `:root` blocks used
   to exist (here and in assets/css/main.css) with 18 tokens disagreeing on
   value, so the rendered result depended on which file happened to load last.
   assets/css/main.css is enqueued with no dependency on the theme stylesheet,
   so that was genuinely arbitrary. The duplicate block is now gone.

   Semantic model, so the layers stop fighting:
     primary   blue    brand, CTAs, links
     accent    amber   the .qs-*-amber icon/pill family (baked amber rgba)
     success   green   positive states
     warning   amber   caution states (shares the accent hue on purpose:
                        both mean "pay attention", not "success")
     info      sky    deliberately NOT the brand blue, so informational
                        states stay distinguishable from a primary CTA
     secondary slate   headings and the footer (near-black, not green)
   ========================================================================== */
:root {
    /* ---- Brand: primary blue ---- */
    --qs-primary: #2563eb;
    --qs-primary-light: #3b82f6;
    --qs-primary-dark: #1d4ed8;
    --qs-primary-darker: #1e40af;
    --qs-primary-50: #eff6ff;
    --qs-primary-100: #dbeafe;
    --qs-primary-200: #bfdbfe;
    --qs-primary-300: #93c5fd;
    --qs-primary-400: #60a5fa;
    --qs-primary-500: #3b82f6;

    /* ---- Accent: amber (attention, not success) ---- */
    --qs-accent: #f59e0b;
    --qs-accent-light: #fbbf24;
    --qs-accent-dark: #d97706;
    --qs-accent-50: #fffbeb;

    /* ---- Secondary: slate (headings, footer) ---- */
    --qs-secondary: #0f172a;
    --qs-secondary-dark: #020617;
    --qs-secondary-50: #f8fafc;

    /* ---- Status ---- */
    --qs-success: #10b981;
    --qs-success-light: #a7f3d0;
    --qs-success-dark: #059669;
    --qs-success-bg: #ecfdf5;
    --qs-warning: #f59e0b;
    --qs-warning-light: #fde68a;
    --qs-warning-bg: #fffbeb;
    --qs-error: #ef4444;
    --qs-error-light: #fecaca;
    --qs-error-bg: #fef2f2;
    --qs-info: #0ea5e9;
    --qs-info-light: #bae6fd;
    --qs-info-bg: #f0f9ff;

    /* ---- Surfaces & text ---- */
    --qs-white: #ffffff;
    /* Text/icon colour that sits ON --qs-primary. --qs-primary is pale blue
       (#60a5fa) in dark mode, so hardcoding #fff here would give only 2.5:1.
       Dark mode needs near-black text on that pale blue (7.0:1). */
    --qs-on-primary: #ffffff;
    --qs-dark: #0f172a;
    --qs-dark-light: #1e293b;
    --qs-bg: #f8fafc;
    --qs-bg-card: #ffffff;
    --qs-bg-white: #ffffff;
    --qs-text: #1e293b;
    --qs-text-light: #64748b;
    --qs-text-lighter: #94a3b8;
    --qs-text-inverse: #ffffff;
    --qs-border: #e2e8f0;
    --qs-border-light: #f1f5f9;

    /* ---- Neutral ramp ---- */
    --qs-gray-50: #f8fafc;
    --qs-gray-100: #f1f5f9;
    --qs-gray-200: #e2e8f0;
    --qs-gray-300: #cbd5e1;
    --qs-gray-400: #94a3b8;
    --qs-gray-500: #64748b;
    --qs-gray-600: #475569;
    --qs-gray-700: #334155;
    --qs-gray-800: #1e293b;
    --qs-gray-900: #0f172a;

    /* ---- Radius ---- */
    --qs-radius-sm: 6px;
    --qs-radius: 8px;
    --qs-radius-md: 12px;
    --qs-radius-lg: 16px;
    --qs-radius-xl: 24px;
    --qs-radius-2xl: 32px;
    --qs-radius-full: 999px;

    /* ---- Elevation ---- */
    --qs-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
    --qs-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
    --qs-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.07), 0 2px 4px -1px rgba(0, 0, 0, 0.04);
    --qs-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -2px rgba(0, 0, 0, 0.04);
    --qs-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
    --qs-shadow-glow: 0 0 20px rgba(37, 99, 235, 0.15);

    /* ---- Type ---- */
    --qs-font: 'Inter', 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --qs-font-heading: 'Inter', 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    --qs-font-mono: 'JetBrains Mono', 'Fira Code', ui-monospace, SFMono-Regular, Menlo, monospace;
    --qs-body-font-size: 1rem;
    --qs-line-height: 1.6;
    --qs-heading-weight: 700;

    /* ---- Motion ---- */
    --qs-transition: 200ms cubic-bezier(0.4, 0, 0.2, 1);
    --qs-transition-slow: 350ms cubic-bezier(0.4, 0, 0.2, 1);
    --qs-transition-bounce: 500ms cubic-bezier(0.34, 1.56, 0.64, 1);

    /* ---- Layout ----
       --qs-container* and --qs-max-width* are two names for the same two
       concepts, used by different stylesheets. They are aliased rather than
       given independent values, because they previously disagreed
       (narrow was 800px in one place and 900px in another). */
    --qs-container: 1280px;
    --qs-container-narrow: 900px;
    --qs-max-width: var(--qs-container);
    --qs-max-width-narrow: var(--qs-container-narrow);
    --qs-header-height: 72px;
    --qs-sidebar-width: 280px;
    --qs-header-bg: #ffffff;
    --qs-header-text: #0f172a;
    --qs-footer-bg: #0f172a;
    --qs-footer-text: #cbd5e1;
    --qs-footer-link: #94a3b8;
}

/* ==========================================================================
   Dark mode — canonical dark values

   This block was previously absent, which is why dark mode only ever worked on
   the app shell. assets/css/home.css carried a `html[data-theme="dark"]` block
   remapping the --qs-app-* layer, so only the ~350 rules consuming those tokens
   followed the theme. assets/css/main.css consumes the canonical --qs-* layer
   instead and has no dark mapping of its own, so its 100+ rules stayed light
   no matter what the toggle did.

   All dark remapping now lives here, in the same file as the light values, so
   there is one place to change a dark value. home.css's duplicate block was
   removed; its --qs-app-* overrides are folded in below.

   The app tokens are remapped here too. That block used to sit in home.css,
   whose :root declarations are *lighter* in the cascade than this selector
   (0,1,0 for :root versus 0,1,1 for html[data-theme="dark"]), so the move is
   safe regardless of stylesheet order.

   `color-scheme` makes the UA render native widgets, scrollbars and the
   canvas background in dark rather than flashing light.
   ========================================================================== */
html[data-theme="dark"] {
    color-scheme: dark;

    /* ---- Surfaces & text ---- */
    --qs-bg: #0b1220;
    --qs-bg-card: #101a2e;
    --qs-bg-white: #101a2e;
    --qs-text: #e6edf7;
    --qs-text-light: #c3cede;
    --qs-text-lighter: #94a3b8;

    /* Headings were the light theme's near-black. In dark they must invert or
       they read as holes punched in the page. */
    --qs-secondary: #e6edf7;
    --qs-secondary-dark: #f8fafc;

    /* ---- Borders ---- */
    --qs-border: #1e2a41;
    --qs-border-light: #172238;

    /* ---- Status surfaces: light tints become low-alpha so the foreground
           colour keeps its contrast against the dark card ---- */
    --qs-success-bg: rgba(16, 185, 129, 0.14);
    --qs-warning-bg: rgba(245, 158, 11, 0.14);
    --qs-error-bg: rgba(239, 68, 68, 0.14);
    --qs-info-bg: rgba(14, 165, 233, 0.14);
    --qs-accent-50: rgba(245, 158, 11, 0.14);
    --qs-secondary-50: #0d1626;
    --qs-primary-50: rgba(59, 130, 246, 0.14);

    /* ---- Primary: the 500/600 ramp reads brighter on dark, and the pale
           steps used for tinted fills would otherwise be too light to sit
           behind dark text ---- */
    --qs-primary: #60a5fa;
    --qs-primary-light: #93c5fd;
    --qs-primary-dark: #3b82f6;
    --qs-on-primary: #0b1220;
    --qs-primary-100: rgba(59, 130, 246, 0.22);
    --qs-primary-200: rgba(96, 165, 250, 0.32);
    --qs-primary-300: #93c5fd;

    /* ---- Elevation: shadows do not read on a dark ground, so depth comes
           from the border plus a slightly lifted surface ---- */
    --qs-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --qs-shadow: 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.3);
    --qs-shadow-md: 0 4px 8px -2px rgba(0, 0, 0, 0.5);
    --qs-shadow-lg: 0 12px 20px -6px rgba(0, 0, 0, 0.55);
    --qs-shadow-xl: 0 20px 28px -8px rgba(0, 0, 0, 0.6);
    --qs-shadow-glow: 0 0 20px rgba(96, 165, 250, 0.2);

    /* ---- Chrome ---- */
    --qs-header-bg: #101a2e;
    --qs-header-text: #e6edf7;
    --qs-footer-bg: #080f1c;
    --qs-footer-text: #c3cede;
    --qs-footer-link: #94a3b8;

    /* ---- App shell layer (previously home.css:39-56) ---- */
    --qs-app-bg: #0b1220;
    --qs-app-card: #101a2e;
    --qs-app-card-soft: #0d1626;
    --qs-app-border: #1e2a41;
    --qs-app-border-strong: #27344f;
    --qs-app-text: #e6edf7;
    --qs-app-text-soft: #c3cede;
    --qs-app-muted: #94a3b8;
    --qs-app-faint: #64748b;
    --qs-app-primary: #3b82f6;
    --qs-app-primary-dark: #2563eb;
    --qs-app-primary-soft: rgba(59, 130, 246, 0.14);
    --qs-app-primary-border: rgba(59, 130, 246, 0.35);
    --qs-app-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
    --qs-app-shadow-md: 0 6px 16px -6px rgba(0, 0, 0, 0.5);
    --qs-app-shadow-lg: 0 18px 40px -12px rgba(0, 0, 0, 0.6);
}

/* No stored preference and no JS: follow the OS directly. The theme's own
   script always writes an explicit data-theme, so a user's light/dark choice
   still wins here. */
@media (prefers-color-scheme: dark) {
    html:not([data-theme="light"]) {
        color-scheme: dark;

        --qs-bg: #0b1220;
        --qs-bg-card: #101a2e;
        --qs-bg-white: #101a2e;
        --qs-text: #e6edf7;
        --qs-text-light: #c3cede;
        --qs-text-lighter: #94a3b8;
        --qs-secondary: #e6edf7;
        --qs-secondary-dark: #f8fafc;
        --qs-border: #1e2a41;
        --qs-border-light: #172238;
        --qs-success-bg: rgba(16, 185, 129, 0.14);
        --qs-warning-bg: rgba(245, 158, 11, 0.14);
        --qs-error-bg: rgba(239, 68, 68, 0.14);
        --qs-info-bg: rgba(14, 165, 233, 0.14);
        --qs-accent-50: rgba(245, 158, 11, 0.14);
        --qs-secondary-50: #0d1626;
        --qs-primary-50: rgba(59, 130, 246, 0.14);
        --qs-primary: #60a5fa;
        --qs-primary-light: #93c5fd;
        --qs-primary-dark: #3b82f6;
        --qs-on-primary: #0b1220;
        --qs-primary-100: rgba(59, 130, 246, 0.22);
        --qs-primary-200: rgba(96, 165, 250, 0.32);
        --qs-primary-300: #93c5fd;
        --qs-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
        --qs-shadow: 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.3);
        --qs-shadow-md: 0 4px 8px -2px rgba(0, 0, 0, 0.5);
        --qs-shadow-lg: 0 12px 20px -6px rgba(0, 0, 0, 0.55);
        --qs-shadow-xl: 0 20px 28px -8px rgba(0, 0, 0, 0.6);
        --qs-shadow-glow: 0 0 20px rgba(96, 165, 250, 0.2);
        --qs-header-bg: #101a2e;
        --qs-header-text: #e6edf7;
        --qs-footer-bg: #080f1c;
        --qs-footer-text: #c3cede;
        --qs-footer-link: #94a3b8;

        --qs-app-bg: #0b1220;
        --qs-app-card: #101a2e;
        --qs-app-card-soft: #0d1626;
        --qs-app-border: #1e2a41;
        --qs-app-border-strong: #27344f;
        --qs-app-text: #e6edf7;
        --qs-app-text-soft: #c3cede;
        --qs-app-muted: #94a3b8;
        --qs-app-faint: #64748b;
        --qs-app-primary: #3b82f6;
        --qs-app-primary-dark: #2563eb;
        --qs-app-primary-soft: rgba(59, 130, 246, 0.14);
        --qs-app-primary-border: rgba(59, 130, 246, 0.35);
        --qs-app-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
        --qs-app-shadow-md: 0 6px 16px -6px rgba(0, 0, 0, 0.5);
        --qs-app-shadow-lg: 0 18px 40px -12px rgba(0, 0, 0, 0.6);
    }
}

/* --------------------------------------------------------------------------
   Dark-mode repair for pages that style themselves with inline styles.

   ~31 templates (446 inline style="..." attributes, 192 hardcoded hex values)
   set colours directly on the element, so no token mapping can reach them:
   --qs-text and friends never apply. The worst case is `color:#1e40af` used as
   TEXT on 61 headings (h2/h3/h4) plus 19 <p> and 6 <td> across page-terms,
   page-about, page-privacy, page-disclaimer, page-contact, page-cbt-exam,
   page-faq and page-dashboard. That navy is #1e40af on a #0b1220 canvas, i.e.
   effectively invisible, and it is also an accessibility failure rather than
   just a cosmetic one.

   These rules need !important because the declarations they override are
   inline, and inline beats every selector short of !important. They are scoped
   to the containers those templates actually use.

   .qs-page-title / .qs-page-subtitle are explicitly excluded: they are white
   text on an intentional brand gradient (linear-gradient(135deg,#1e40af,#3b82f6))
   inside .qs-page-header, and they are already correct in both themes. An audit
   of the inline styles confirmed no dark-text element sits on a brand
   background, so nothing here has to fight those two rules.

   The real fix is to delete the inline styles and use the token layer; this is
   the safety net that makes dark mode usable until that happens.
   -------------------------------------------------------------------------- */
html[data-theme="dark"] .qs-page-wrapper h2,
html[data-theme="dark"] .qs-page-wrapper h3,
html[data-theme="dark"] .qs-page-wrapper h4,
html[data-theme="dark"] .qs-page-wrapper li,
html[data-theme="dark"] .qs-page-wrapper td,
html[data-theme="dark"] .qs-page-wrapper th,
html[data-theme="dark"] .qs-page-wrapper ul,
html[data-theme="dark"] .qs-page-wrapper summary,
html[data-theme="dark"] .qs-page-wrapper p:not(.qs-page-subtitle),
html[data-theme="dark"] .qs-legal-text,
html[data-theme="dark"] .qs-terms-text,
html[data-theme="dark"] .qs-quick-link {
    color: var(--qs-app-text) !important;
}
/* Amber reward avatar: keep the tinted chip, but lift the glyph off the dark
   canvas (#b45309 on #0b1220 is close to unreadable). */
html[data-theme="dark"] .qsp-avatar {
    color: #fbbf24 !important;
}
html[data-theme="dark"] .qs-page-wrapper p:not(.qs-page-subtitle),
html[data-theme="dark"] .qs-quick-link {
    color: var(--qs-app-text-soft) !important;
}
/* Body copy was #64748b / #334155; map to the muted token rather than full
   text so the paragraph/body hierarchy survives. */
html[data-theme="dark"] .qs-page-wrapper a[style*="color"],
html[data-theme="dark"] .qs-legal-text a {
    color: var(--qs-app-primary) !important;
}
/* Light panels (callouts, stat bars) stay light in dark mode because their
   background is inline. Repaint them onto the card surface.

   Pages converted to tokens are deliberately NOT in this list any more:
     - .qs-story (About) now uses --qs-secondary-50, so it follows dark mode.
     - .qs-tab (FAQ) styles its own tabs in main.css; an !important rule here
       would override it.
     - .qs-exam-notice / .qs-tip-callout (CBT) use the semantic
       --qs-warning-bg / --qs-info-bg tokens, which already have dark values.
     - .qs-stats-bar--gradient keeps the brand gradient + white text in both
       themes, so the plain .qs-stats-bar is excluded with :not(). */
html[data-theme="dark"] .qs-section.qs-tips,
html[data-theme="dark"] .qs-section.qs-performance-tips,
html[data-theme="dark"] .qs-section.qs-faq,
html[data-theme="dark"] .qs-section.qs-stats-bar:not(.qs-stats-bar--gradient) {
    background: var(--qs-app-card) !important;
    color: var(--qs-app-text) !important;
    border-color: var(--qs-app-border) !important;
}

/* Deliberately box-sizing only. This sheet is now actually loaded (it never
   was before), and a margin/padding reset here would newly collapse the UA
   padding of every bare <button>, <input>, <select>, <th> and <td> in the
   theme, because only the .qs-btn-* modifier classes set their own padding.
   Element margins that the theme actually wants are set explicitly below. */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
    font-family: var(--qs-font);
    font-size: var(--qs-body-font-size);
    line-height: var(--qs-line-height);
    color: var(--qs-text);
    background: var(--qs-bg);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}

a { color: var(--qs-primary); text-decoration: none; transition: color var(--qs-transition); }
a:hover { color: var(--qs-primary-dark); }

/* One focus ring for every interactive element. Previously only `a` had one in
   this file while assets/css/main.css had a global :focus-visible rule, so
   buttons and inputs focused differently depending on load order. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--qs-primary);
    outline-offset: 2px;
    border-radius: var(--qs-radius-sm);
}

img { max-width: 100%; height: auto; display: block; }
svg { display: block; }

h1, h2, h3, h4, h5, h6 {
    font-family: var(--qs-font-heading);
    font-weight: var(--qs-heading-weight);
    line-height: 1.25;
    color: var(--qs-secondary);
    margin-bottom: 0.5em;
}
h1 { font-size: clamp(2rem, 5vw, 3.5rem); }
h2 { font-size: clamp(1.5rem, 3vw, 2.5rem); }
h3 { font-size: clamp(1.25rem, 2vw, 1.75rem); }
h4 { font-size: 1.25rem; }
h5 { font-size: 1.125rem; }
h6 { font-size: 1rem; }

p { margin-bottom: 1rem; color: var(--qs-text); }
p:last-child { margin-bottom: 0; }

ul, ol { margin: 0 0 1rem 1.5rem; }
li { margin-bottom: 0.25rem; }

button, input, select, textarea { font-family: inherit; font-size: inherit; line-height: inherit; }

::selection { background: var(--qs-primary-200); color: var(--qs-primary-darker); }

.visually-hidden,
.screen-reader-text {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.qs-container { width: 100%; max-width: var(--qs-max-width); margin: 0 auto; padding: 0 24px; }
.qs-container-narrow { max-width: var(--qs-max-width-narrow); }

@media (max-width: 768px) {
    .qs-container { padding: 0 16px; }
}

/* Respect the OS motion preference across the whole theme. home.css and
   main.css already guard their own animations; this covers everything else,
   which otherwise kept animating through --qs-transition. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

.skip-link {
    position: absolute;
    top: -100%;
    left: 50%;
    transform: translateX(-50%);
    background: var(--qs-primary);
    color: var(--qs-white);
    padding: 8px 24px;
    z-index: 100000;
    border-radius: 0 0 var(--qs-radius-sm) var(--qs-radius-sm);
    font-weight: 600;
    transition: top 0.2s;
}
.skip-link:focus { top: 0; color: var(--qs-white); }
