/* GENERATED FILE — DO NOT EDIT.
 *
 * Built by scripts/build-css.mjs from, in order:
 *   tokens.css
 *   fonts.css
 *   style.css
 *   ui.css
 *   components.css
 *   page.css
 *   breadcrumbs-public.css
 *   theme.css
 *   nav.css
 *   footer.css
 *
 * Edit those files and run `npm run build:css`. CI runs `--check` and fails
 * if this file is out of date.
 *
 * This is one render-blocking request that resolves the entire shared UI before
 * first paint. It replaces a serial @import chain plus four stylesheets that
 * include.js used to inject after the page had already rendered.
 */

/* ===== tokens.css ================================================== */
/* ==========================================================================
   Studiehjälpen – design tokens (single source of truth for BOTH themes)

   - Light palette lives on :root. The dark palette lives on html.dark / body.dark
     (theme-lock.js sets the class on <html> before first paint; course pages set it
     on <body>; both selectors are always kept in sync).
   - Components must use these tokens – never a literal color that only works in one
     theme. Neither theme uses pure black or pure white as a page background.
   - The dark palette is the Hittavakten slate ramp: background #0f172a, surfaces
     #1e293b, text #f1f5f9. Accents stay desaturated so nothing glows.
   ========================================================================== */
:root {
  /* ---- Brand ---- */
  --sj-brand: #2563eb;
  --sj-brand-dark: #1d4ed8;
  --sj-brand-light: #60a5fa;
  --sj-brand-gradient: linear-gradient(90deg, #2563eb 0%, #60a5fa 100%);
  --sj-brand-contrast: #ffffff;         /* text on brand backgrounds */

  /* Brand scale – hovers, tinted surfaces and borders without new hex values */
  --sj-brand-50: #eff6ff;
  --sj-brand-100: #dbeafe;
  --sj-brand-200: #bfdbfe;
  --sj-brand-600: #2563eb;
  --sj-brand-700: #1d4ed8;
  --sj-brand-800: #1e40af;

  /* ---- Neutral surfaces (never pure white) ----
     Slate ramp, same values as Hittavakten so the two products read as one
     family: page #f8fafc, cards #ffffff, subtle fills #f1f5f9, borders #e2e8f0. */
  --sj-bg: #f8fafc;                     /* default page/body background */
  --sj-bg-page: #f8fafc;                /* soft page ground so white cards get real elevation */
  --sj-bg-subtle: #f1f5f9;
  --sj-bg-muted: #f1f5f9;
  --sj-bg-accent: #eff6ff;

  --sj-surface: #ffffff;                /* cards, panels, inputs – the only pure white, always on a tinted ground */
  --sj-surface-elevated: #ffffff;
  --sj-surface-sunken: #f1f5f9;
  --sj-border: #e2e8f0;
  --sj-border-soft: #dbeafe;
  --sj-border-strong: #cbd5e1;

  --sj-input-bg: #ffffff;
  --sj-input-border: #cbd5e1;

  /* ---- Text (never pure black) ---- */
  --sj-text: #0f172a;
  /* Headings were #1e3a8a — a blue that made every h1/h2 read as a link and
     belonged to no palette. Headings now use the same ink as body text. */
  --sj-text-heading: #0f172a;
  --sj-text-secondary: #475569;
  --sj-text-muted: #64748b;
  --sj-text-inverse: #f8fafc;
  --sj-text-on-brand: #ffffff;

  /* ---- Semantic ---- */
  --sj-success: #16a34a;
  --sj-success-bg: #f0fdf4;
  --sj-success-border: #bbf7d0;
  --sj-warning: #d97706;
  --sj-warning-bg: #fffbeb;
  --sj-warning-border: #fcd34d;
  --sj-danger: #dc2626;
  --sj-danger-strong: #b91c1c;
  --sj-danger-bg: #fef2f2;
  --sj-danger-border: #fecaca;

  /* Tinted fills — Hittavakten's *-light convention, for badges and soft states */
  --sj-brand-tint: rgba(37, 99, 235, 0.07);
  --sj-success-tint: rgba(22, 163, 74, 0.08);
  --sj-warning-tint: rgba(217, 119, 6, 0.10);
  --sj-danger-tint: rgba(220, 38, 38, 0.07);
  --sj-info: #2563eb;
  --sj-info-bg: #eff6ff;
  --sj-info-border: #bfdbfe;

  /* ---- Radii ---- */
  --sj-radius-xs: 6px;
  --sj-radius-sm: 8px;
  --sj-radius: 12px;
  --sj-radius-md: 12px;
  --sj-radius-lg: 18px;
  --sj-radius-xl: 24px;
  --sj-radius-pill: 999px;

  /* ---- Spacing (4px scale) ---- */
  --sj-space-1: 0.25rem;
  --sj-space-2: 0.5rem;
  --sj-space-3: 0.75rem;
  --sj-space-4: 1rem;
  --sj-space-5: 1.25rem;
  --sj-space-6: 1.5rem;
  --sj-space-8: 2rem;
  --sj-space-10: 2.5rem;
  --sj-space-12: 3rem;
  --sj-space-16: 4rem;

  /* Shared gap rhythm for grids/lists so every surface breathes the same way */
  --sj-gap-sm: var(--sj-space-3);
  --sj-gap: var(--sj-space-4);
  --sj-gap-lg: var(--sj-space-6);
  --sj-container: 1180px;
  --sj-container-narrow: 760px;

  /* ---- Elevation (subtle by design – "very little glow") ---- */
  --sj-shadow-color: rgba(27, 33, 48, 0.08);
  --sj-shadow-xs: 0 1px 2px rgba(27, 33, 48, 0.06);
  --sj-shadow-sm: 0 2px 6px -1px rgba(27, 33, 48, 0.06);
  --sj-shadow: 0 4px 12px rgba(27, 33, 48, 0.08);
  --sj-shadow-lg: 0 10px 24px -6px rgba(27, 33, 48, 0.14);
  --sj-shadow-xl: 0 24px 48px -12px rgba(27, 33, 48, 0.18);
  --sj-shadow-hover: 0 8px 20px -6px rgba(37, 99, 235, 0.16);

  /* Focus ring – same shape everywhere so keyboard navigation is predictable */
  --sj-ring: 0 0 0 3px rgba(37, 99, 235, 0.35);
  --sj-ring-danger: 0 0 0 3px rgba(220, 38, 38, 0.28);
  --sj-focus-color: #1d4ed8;
  --sj-focus-width: 3px;
  --sj-focus-offset: 2px;

  /* ---- Typography (one family, self-hosted) ---- */
  --sj-font: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --sj-font-numeric: var(--sj-font);
  --sj-font-mono: ui-monospace, 'Cascadia Code', 'SFMono-Regular', Consolas, monospace;

  --sj-text-xs: 0.75rem;
  --sj-text-sm: 0.875rem;
  --sj-text-base: 1rem;
  --sj-text-lg: 1.125rem;
  --sj-text-xl: 1.25rem;
  --sj-text-2xl: 1.5rem;
  --sj-text-3xl: 1.875rem;
  --sj-text-4xl: 2.25rem;

  --sj-leading-tight: 1.2;
  --sj-leading-snug: 1.35;
  --sj-leading-normal: 1.6;
  --sj-leading-relaxed: 1.75;

  /* Letter-spacing is reserved for uppercase micro-labels; body text uses normal tracking */
  --sj-tracking-tight: -0.02em;
  --sj-tracking-normal: 0;
  --sj-tracking-wide: 0.04em;

  /* ---- Motion (all under the 400 ms Doherty threshold) ---- */
  --sj-ease: cubic-bezier(0.4, 0, 0.2, 1);
  --sj-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --sj-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --sj-duration-instant: 80ms;
  --sj-duration-fast: 150ms;
  --sj-duration: 220ms;
  --sj-duration-slow: 320ms;
  /* How long a theme switch takes. Every surface uses this one value so they
     all finish together. */
  --sj-theme-switch: 140ms;

  /* ---- Controls ---- */
  --sj-touch-target: 44px;              /* WCAG 2.5.5 minimum effective tap area */
  --sj-control-outer: 24px;             /* radio/checkbox visual size */
  --sj-control-inner: 16px;             /* radio dot / checkbox tick fill */
  --sj-control-border: 2px;
  --sj-input-height: 44px;
  /* The single height every interactive control shares: buttons, icon buttons,
     inputs, selects and the header controls. Before this, the header alone had
     four different heights in one row (40 / 22 / 22 / 44). */
  --sj-control-height: 44px;

  --sj-z-sticky: 100;
  --sj-z-nav: 900;
  --sj-z-overlay: 1000;
  --sj-z-modal: 1100;
  --sj-z-toast: 1200;

  /* ---- Legacy aliases (homepage / shop / forum / admin still reference these) ----
     Kept as aliases so every legacy name resolves to a token and therefore themes correctly.
     New code must use --sj-* names directly. */
  --text-dark: var(--sj-text);
  --text-muted: var(--sj-text-secondary);
  --gold-100: var(--sj-brand-50);
  --gold-200: var(--sj-brand-100);
  --gold-300: var(--sj-brand-200);
  --gold-400: var(--sj-border-strong);
  --gold-border: var(--sj-border);
  --gold-shadow: var(--sj-shadow-color);

  --shop-bg: var(--sj-bg-page);
  --shop-surface: var(--sj-surface);
  --shop-surface-hover: var(--sj-bg-muted);
  --shop-border: var(--sj-border);
  --shop-text: var(--sj-text);
  --shop-text-secondary: var(--sj-text-secondary);
  --shop-text-muted: var(--sj-text-muted);
  --shop-shadow-sm: var(--sj-shadow-sm);
  --shop-shadow: var(--sj-shadow);
  --shop-shadow-lg: var(--sj-shadow-lg);

  /* Navigation namespace (nav.css, sticky-header.css, admin-nav, sidepanel).
     These were referenced ~160 times as var(--nav-x, #1e293b) but never
     defined, so every use silently fell back to a hard-coded blue-slate —
     which is why the header stayed slate while the rest of the site turned
     neutral. Defining them here makes the fallbacks dead code. */
  --nav-bg: var(--sj-surface);
  --nav-text: var(--sj-text);
  /* The side panel used to be permanently dark chrome (#232a36) in BOTH themes,
     so opening the menu on the light site dropped a near-black slab over it —
     the one surface that ignored the theme. It is a normal themed surface now.
     The *-ink names are kept because ~40 rules reference them. */
  --nav-ink: var(--sj-surface);
  --nav-ink-2: var(--sj-bg-muted);
  --nav-on-ink: var(--sj-text);
  --nav-on-ink-muted: var(--sj-text-secondary);
  /* Light text that sits on both brand fills and ink fills, so it stays
     #f7f8fa in both themes (the dark brand gradient is darkened to match). */
  --nav-on-brand: #f7f8fa;
  --nav-btn-hover: var(--sj-bg-muted);
  --nav-radius: var(--sj-radius);
  --nav-sticky-bg: rgba(255, 255, 255, 0.98); /* sticky topbar backdrop */
  --nav-border: var(--sj-border);
  --nav-text-muted: var(--sj-text-muted);
  --nav-hover-tint: var(--sj-brand-tint);
  --nav-active-tint: rgba(37, 99, 235, 0.09);

  /* Footer namespace – previously the footer borrowed nav and surface tokens,
     so it could never be toned separately from the header. */
  --sj-footer-bg: #f8fafc;
  --sj-footer-border: #e2e8f0;
  --sj-footer-text: #475569;
  --sj-footer-heading: #1e293b;

  /* Admin namespace (admin-*.css) – mapped onto the shared tokens so admin follows the theme */
  --bg-primary: var(--sj-bg-page);
  --bg-secondary: var(--sj-surface);
  --bg-tertiary: var(--sj-bg-muted);
  --bg-card: var(--sj-surface);
  --bg-glass: var(--sj-bg-subtle);
  --bg-light: var(--sj-bg-muted);
  --bg-white: var(--sj-surface);
  --text-primary: var(--sj-text);
  --text-secondary: var(--sj-text-secondary);
  --text-heading: var(--sj-text-heading);
  --surface-muted: var(--sj-surface-sunken);
  --border-subtle: var(--sj-border);
  --border-hover: var(--sj-border-strong);
  --border-color: var(--sj-border);
  --border-strong: var(--sj-border-strong);
  --accent: var(--sj-brand);
  --accent-orange: var(--sj-brand);
  --accent-orange-light: var(--sj-brand-light);
  --accent-blue: var(--sj-brand-light);
  --accent-green: var(--sj-success);
  --accent-red: var(--sj-danger);
  --accent-purple: #7c3aed;
  --accent-yellow: var(--sj-warning);
  --card-bg: var(--sj-surface);
  --shadow-lg: var(--sj-shadow-lg);
  --shadow-glow: var(--sj-shadow-hover);
  --radius-lg: var(--sj-radius-lg);
  --radius-md: var(--sj-radius-md);
  --radius-sm: var(--sj-radius-sm);
}

/* ==========================================================================
   Dark theme – slate, matching Hittavakten: ground #0f172a, surfaces #1e293b,
   borders #334155, text #f1f5f9. Surfaces step up in lightness for elevation
   instead of relying on shadows.

   This replaces the earlier neutral #242424 / #e7e9eb pair. The two products
   are meant to read as one family, and the slate ramp carries a blue cast that
   the brand sits inside instead of fighting.
   ========================================================================== */
html.dark,
body.dark {
  --sj-brand: #3b82f6;
  --sj-brand-dark: #2563eb;
  --sj-brand-light: #60a5fa;
  /* Darker than the light-mode pair so #f8fafc text on it keeps AA contrast. */
  --sj-brand-gradient: linear-gradient(90deg, #1e3a8a 0%, #2563eb 100%);
  --sj-brand-contrast: #0f172a;

  /* The dark ramp is deliberately inverted at the low end: 50–200 are deep
     tints used as surfaces, while 600–800 stay real brand blues. Do not make
     800 the lightest step — theme.css:660 ends the hero gradient on it, and a
     pale 800 turns the top of the homepage into a light blue wash in dark mode. */
  --sj-brand-50: #172554;
  --sj-brand-100: #1e3a8a;
  --sj-brand-200: #1e40af;
  --sj-brand-600: #3b82f6;
  --sj-brand-700: #60a5fa;
  --sj-brand-800: #2563eb;

  --sj-bg: #0f172a;
  --sj-bg-page: #0f172a;
  --sj-bg-subtle: #1e293b;
  --sj-bg-muted: #1e293b;
  --sj-bg-accent: #1e293b;

  --sj-surface: #1e293b;
  --sj-surface-elevated: #334155;
  --sj-surface-sunken: #0f172a;
  --sj-border: #334155;
  --sj-border-soft: #334155;
  --sj-border-strong: #475569;

  --sj-input-bg: #1e293b;
  --sj-input-border: #475569;

  --sj-text: #f1f5f9;
  --sj-text-heading: #f1f5f9;
  --sj-text-secondary: #94a3b8;
  --sj-text-muted: #94a3b8;
  --sj-text-inverse: #0f172a;
  --sj-text-on-brand: #ffffff;

  --sj-success: #4ade80;
  --sj-success-bg: rgba(74, 222, 128, 0.12);
  --sj-success-border: rgba(74, 222, 128, 0.3);
  --sj-warning: #fbbf24;
  --sj-warning-bg: rgba(251, 191, 36, 0.16);
  --sj-warning-border: rgba(251, 191, 36, 0.35);
  --sj-danger: #f87171;
  --sj-danger-strong: #fca5a5;
  --sj-danger-bg: rgba(248, 113, 113, 0.14);
  --sj-danger-border: rgba(248, 113, 113, 0.3);
  --sj-info: #60a5fa;
  --sj-info-bg: rgba(96, 165, 250, 0.14);
  --sj-info-border: rgba(96, 165, 250, 0.3);

  --sj-brand-tint: rgba(59, 130, 246, 0.14);
  --sj-success-tint: rgba(74, 222, 128, 0.12);
  --sj-warning-tint: rgba(251, 191, 36, 0.16);
  --sj-danger-tint: rgba(248, 113, 113, 0.14);

  --sj-footer-bg: #0f172a;
  --sj-footer-border: #334155;
  --sj-footer-text: #94a3b8;
  --sj-footer-heading: #f1f5f9;

  --sj-shadow-color: rgba(0, 0, 0, 0.35);
  --sj-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --sj-shadow-sm: 0 2px 6px -1px rgba(0, 0, 0, 0.4);
  --sj-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
  --sj-shadow-lg: 0 10px 24px -6px rgba(0, 0, 0, 0.55);
  --sj-shadow-xl: 0 24px 48px -12px rgba(0, 0, 0, 0.6);
  --sj-shadow-hover: 0 8px 20px -6px rgba(0, 0, 0, 0.5);

  --sj-ring: 0 0 0 3px rgba(59, 130, 246, 0.45);
  --sj-ring-danger: 0 0 0 3px rgba(248, 113, 113, 0.4);
  --sj-focus-color: #60a5fa;

  --accent-purple: #a78bfa;

  /* Navigation sits on the same slate as the page, one step lighter, exactly
     as Hittavakten's --nav-bg/--nav-border pair. */
  --nav-bg: var(--sj-surface);
  --nav-text: var(--sj-text);
  --nav-ink: #1e293b;
  --nav-ink-2: #334155;
  --nav-on-ink: var(--sj-text);
  --nav-on-ink-muted: var(--sj-text-secondary);
  --nav-on-brand: #ffffff;
  --nav-btn-hover: #334155;
  --nav-sticky-bg: rgba(30, 41, 59, 0.98);
  --nav-border: var(--sj-border);
  --nav-text-muted: var(--sj-text-muted);
  --nav-hover-tint: var(--sj-brand-tint);
  --nav-active-tint: rgba(59, 130, 246, 0.18);
}

/* ===== fonts.css =================================================== */
/* Self-hosted Inter (latin + latin-ext). Loaded on every page via include.js so typography is
   identical everywhere and no visitor request goes to Google Fonts. font-display: swap keeps text
   visible in the system font until Inter has loaded. */

/* 400 */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/assets/fonts/inter/inter-latin-ext-400.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/assets/fonts/inter/inter-latin-400.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

/* 500 */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('/assets/fonts/inter/inter-latin-ext-500.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('/assets/fonts/inter/inter-latin-500.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

/* 600 */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('/assets/fonts/inter/inter-latin-ext-600.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url('/assets/fonts/inter/inter-latin-600.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

/* 700 */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('/assets/fonts/inter/inter-latin-ext-700.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('/assets/fonts/inter/inter-latin-700.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

/* 800 */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap;
  src: url('/assets/fonts/inter/inter-latin-ext-800.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 800; font-display: swap;
  src: url('/assets/fonts/inter/inter-latin-800.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

/* ===== style.css =================================================== */
/*
 * tokens.css is NOT @imported here any more. @import is resolved serially — the
 * browser had to download this file and parse it before it even requested the
 * tokens, so no --sj-* variable existed for two round trips. Worse, perf-boot.js
 * preloaded `tokens.css?v=…` while this @import asked for `tokens.css` with no
 * query string: different URLs, so the preload was never used and the file was
 * fetched twice. Both files are concatenated into sj-core.css by
 * scripts/build-css.mjs and linked once, first, in every page's <head>.
 *
 * The WEBCON maintenance block used to live here too, and it hid the ENTIRE
 * <body> until nav.js finished a network call:
 *
 *   html:not(.webcon-ready):not(.webcon-skip) body {
 *     visibility:hidden; opacity:0; animation:_webcon-reveal .15s .8s forwards; }
 *
 * With an 800 ms CSS fallback, the page was blank and then revealed while the
 * stylesheets were still in flight — which is precisely the "we see the whole
 * page in text format then the ui follows" report. nav.js still performs the
 * maintenance check and still redirects to /maintenance.html when the API says
 * the site is closed; it simply no longer hides the page while it waits.
 */

/* The UA stylesheet's `[hidden] { display: none }` is a plain element rule, so
   ANY author `display` on the same element beats it. Every component that sets
   its own display — .pill-badge, .messages-selection-bar, .receipts-list — was
   therefore visible while carrying the hidden attribute: the unread badge sat in
   the account nav reading "0", and the "Radera valda / Radera alla" bar showed
   on a page where nothing was selected. Components had begun papering over it
   one at a time (see components.css:801, admin.css:103, and others); this is
   that fix, once, for the whole site. */
[hidden] { display: none !important; }

/* Global base styles */
body {
  font-family: var(--sj-font);
  line-height: 1.6;
  color: var(--sj-text);
  background: var(--sj-bg);
}

a {
  text-decoration: none;
  color: inherit;
}

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

button {
  cursor: pointer;
  font-family: inherit;
}

/* ===== ui.css ====================================================== */
/* =============================================================================
   Studiehjälpen – delat UI-lager (primitiv, tillgänglighet, feedback)
   Laddas på varje sida via include.js. Innehåller inga sidspecifika regler:
   bara de byggstenar som ska se identiska ut överallt.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   1. Typografi & bas
   -------------------------------------------------------------------------- */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Ta bort grå blixt vid tryck på mobil – ersätts av riktig :active-feedback */
  -webkit-tap-highlight-color: transparent;
}

::selection {
  background: var(--sj-brand-200, #bfdbfe);
  color: var(--sj-text, #0f172a);
}

html.dark ::selection,
body.dark ::selection {
  background: rgba(96, 165, 250, 0.35);
  color: #f1f5f9;
}

/* Rubriker bryter snyggare och blir lättare att skanna */
h1, h2, h3 {
  text-wrap: balance;
}

p, li {
  text-wrap: pretty;
}

/* Siffror i tabeller/priser ska ligga i kolumn */
.sj-tabular,
.sj-price,
td.sj-num,
.sj-num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

/* -----------------------------------------------------------------------------
   2. Fokus – en enda synlig ring i hela produkten
   WCAG 2.4.7. Ersätter tidigare mönster där outline togs bort helt.
   -------------------------------------------------------------------------- */
:where(a, button, input, select, textarea, summary, [tabindex], [role='button'], [role='tab'], [role='option'], [role='menuitem'], [contenteditable='true']):focus-visible {
  outline: var(--sj-focus-width, 3px) solid var(--sj-focus-color, #1d4ed8);
  outline-offset: var(--sj-focus-offset, 2px);
  border-radius: max(var(--sj-radius-xs, 6px), 4px);
}

/* Aldrig ta bort fokus på pekskärmar – tangentbord kan alltid kopplas in */
@media (hover: none) and (pointer: coarse) {
  :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: var(--sj-focus-width, 3px) solid var(--sj-focus-color, #1d4ed8) !important;
    outline-offset: var(--sj-focus-offset, 2px) !important;
  }
}

/* Mörka ytor: ljus ring för kontrast */
html.dark :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible,
body.dark :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline-color: var(--sj-focus-color, #93c5fd);
}

/* -----------------------------------------------------------------------------
   3. Hoppa till innehåll
   Tangentbordsanvändare slipper tabba genom hela navigeringen på varje sida.
   -------------------------------------------------------------------------- */
.sj-skip-link {
  position: fixed;
  top: 0;
  left: 50%;
  transform: translate(-50%, -120%);
  z-index: calc(var(--sj-z-toast, 1200) + 10);
  display: inline-flex;
  align-items: center;
  gap: var(--sj-space-2, 0.5rem);
  padding: 0.7rem 1.15rem;
  border-radius: 0 0 var(--sj-radius, 12px) var(--sj-radius, 12px);
  background: var(--sj-brand, #2563eb);
  color: #fff;
  font: inherit;
  font-weight: 600;
  font-size: var(--sj-text-sm, 0.875rem);
  text-decoration: none;
  box-shadow: var(--sj-shadow-lg);
  transition: transform var(--sj-duration-fast, 150ms) var(--sj-ease-out);
}

.sj-skip-link:focus,
.sj-skip-link:focus-visible,
.sj-skip-link.is-visible {
  transform: translate(-50%, 0);
  outline: 3px solid #fff;
  outline-offset: -6px;
}

/* -----------------------------------------------------------------------------
   4. Skärmläsartext
   -------------------------------------------------------------------------- */
.sj-sr-only,
.sr-only:not(.sr-only-focusable) {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* -----------------------------------------------------------------------------
   5. Träffytor – Fitts lag / WCAG 2.5.5
   Ikonknappar utan text måste vara minst 44×44 px att träffa.
   -------------------------------------------------------------------------- */
.sj-touch,
button.sj-icon-btn,
a.sj-icon-btn {
  min-width: var(--sj-touch-target, 44px);
  min-height: var(--sj-touch-target, 44px);
}

@media (pointer: coarse) {
  /* Utökar träffytan utan att påverka layouten runt omkring */
  .sj-touch-expand {
    position: relative;
  }
  .sj-touch-expand::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: max(100%, var(--sj-touch-target, 44px));
    height: max(100%, var(--sj-touch-target, 44px));
    transform: translate(-50%, -50%);
  }
}

/* -----------------------------------------------------------------------------
   6. Laddningsindikatorer
   -------------------------------------------------------------------------- */
.sj-spinner,
.spinner {
  display: inline-block;
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
  border: 3px solid var(--sj-border, #e2e8f0);
  border-top-color: var(--sj-brand, #2563eb);
  border-radius: 50%;
  animation: sj-spin 0.7s linear infinite;
}

.sj-spinner--sm,
.spinner--sm {
  width: 1.05rem;
  height: 1.05rem;
  border-width: 2px;
}

.sj-spinner--inverse {
  border-color: rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
}

@keyframes sj-spin {
  to { transform: rotate(360deg); }
}

/* Knapp som arbetar: behåller bredd, byter innehåll mot spinner.
   Förhindrar layouthopp och dubbelklick. */
.sj-btn-busy {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}

.sj-btn-busy > * {
  visibility: hidden;
}

.sj-btn-busy::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1.05rem;
  height: 1.05rem;
  margin: -0.525rem 0 0 -0.525rem;
  border: 2px solid currentColor;
  border-radius: 50%;
  border-top-color: transparent;
  opacity: 0.9;
  animation: sj-spin 0.6s linear infinite;
  color: var(--sj-busy-spinner-color, #fff);
  visibility: visible;
}

/* -----------------------------------------------------------------------------
   7. Skelett – ersätter tomma ytor och snurror under hämtning
   Ger uppfattad snabbhet och behåller layouten (ingen "content shift").
   -------------------------------------------------------------------------- */
.sj-skeleton {
  position: relative;
  overflow: hidden;
  background: var(--sj-surface-sunken, #f1f5f9);
  border-radius: var(--sj-radius-sm, 8px);
  /* Skelett är dekorativt – skärmläsare får statusen via aria-live i stället */
  color: transparent !important;
  user-select: none;
}

.sj-skeleton::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.6) 50%,
    transparent 100%
  );
  animation: sj-shimmer 1.4s ease-in-out infinite;
}

html.dark .sj-skeleton::after,
body.dark .sj-skeleton::after {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.08) 50%,
    transparent 100%
  );
}

.sj-skeleton--text {
  height: 0.85em;
  margin: 0.35em 0;
  border-radius: var(--sj-radius-pill, 999px);
}

.sj-skeleton--title {
  height: 1.35em;
  width: 60%;
  border-radius: var(--sj-radius-xs, 6px);
}

.sj-skeleton--line-short { width: 45%; }
.sj-skeleton--line-mid { width: 72%; }
.sj-skeleton--block {
  height: 100%;
  min-height: 8rem;
  border-radius: var(--sj-radius, 12px);
}

@keyframes sj-shimmer {
  100% { transform: translateX(100%); }
}

/* -----------------------------------------------------------------------------
   8. Toast – ett meddelandesystem för hela produkten
   Ersätter alert() som blockerar tråden och inte kan formges.
   -------------------------------------------------------------------------- */
.sj-toast-region {
  position: fixed;
  z-index: var(--sj-z-toast, 1200);
  right: max(1rem, env(safe-area-inset-right));
  /* --sj-toast-inset sätts av ui.js till höjden på synligt botten-krom
     (sj-prefs-bar, bottennavigering) så notiser aldrig hamnar bakom dem. */
  bottom: calc(1rem + env(safe-area-inset-bottom) + var(--sj-toast-inset, 0px));
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-2, 0.5rem);
  width: min(24rem, calc(100vw - 2rem));
  pointer-events: none;
}

/* På mobil: ovanför tumzonen men under bottennavigeringen */
@media (max-width: 640px) {
  .sj-toast-region {
    left: max(0.75rem, env(safe-area-inset-left));
    right: max(0.75rem, env(safe-area-inset-right));
    bottom: calc(var(--sj-mobile-nav-height, 4.5rem) + env(safe-area-inset-bottom) + var(--sj-toast-inset, 0px));
    width: auto;
    /* Notisen får inte bli bredare än vyn när insetet växer */
    max-height: calc(100vh - 8rem);
    overflow: hidden;
  }
}

.sj-toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--sj-space-3, 0.75rem);
  padding: 0.8rem 0.9rem;
  border-radius: var(--sj-radius, 12px);
  border: 1px solid var(--sj-border, #e2e8f0);
  border-left: 4px solid var(--sj-toast-accent, var(--sj-brand, #2563eb));
  background: var(--sj-surface, #fff);
  color: var(--sj-text, #0f172a);
  box-shadow: var(--sj-shadow-xl);
  font-size: var(--sj-text-sm, 0.875rem);
  line-height: var(--sj-leading-snug, 1.35);
  animation: sj-toast-in var(--sj-duration, 220ms) var(--sj-ease-out) both;
}

html.dark .sj-toast,
body.dark .sj-toast {
  background: #1e293b;
  border-color: #334155;
  color: #f1f5f9;
}

.sj-toast--success { --sj-toast-accent: var(--sj-success, #059669); }
.sj-toast--error { --sj-toast-accent: var(--sj-danger, #dc2626); }
.sj-toast--warning { --sj-toast-accent: var(--sj-warning, #d97706); }
.sj-toast--info { --sj-toast-accent: var(--sj-brand, #2563eb); }

.sj-toast__icon {
  flex-shrink: 0;
  display: inline-flex;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 0.1rem;
  color: var(--sj-toast-accent);
}

.sj-toast__icon svg {
  width: 100%;
  height: 100%;
}

.sj-toast__body {
  flex: 1;
  min-width: 0;
}

.sj-toast__title {
  font-weight: 650;
  margin: 0;
}

.sj-toast__text {
  margin: 0.15rem 0 0;
  color: var(--sj-text-secondary, #64748b);
}

html.dark .sj-toast__text,
body.dark .sj-toast__text {
  color: #94a3b8;
}

.sj-toast__action {
  margin-top: 0.5rem;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--sj-border-strong, #cbd5e1);
  border-radius: var(--sj-radius-sm, 8px);
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: var(--sj-text-xs, 0.75rem);
  font-weight: 600;
  cursor: pointer;
  /* Åtgärden kan vara en länk – den ska ändå se ut som en knapp */
  text-decoration: none;
}

.sj-toast__action:hover {
  background: var(--sj-bg-muted, #f8fafc);
}

.sj-toast__close {
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--sj-radius-sm, 8px);
  background: transparent;
  color: var(--sj-text-muted, #94a3b8);
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
}

.sj-toast__close:hover {
  background: var(--sj-bg-muted, #f8fafc);
  color: var(--sj-text, #0f172a);
}

.sj-toast.is-leaving {
  animation: sj-toast-out var(--sj-duration-fast, 150ms) var(--sj-ease) both;
}

@keyframes sj-toast-in {
  from { opacity: 0; transform: translateY(0.75rem) scale(0.97); }
  to { opacity: 1; transform: none; }
}

@keyframes sj-toast-out {
  to { opacity: 0; transform: translateY(0.35rem) scale(0.98); }
}

/* -----------------------------------------------------------------------------
   9. Bekräftelsedialog – ersätter confirm()
   -------------------------------------------------------------------------- */
.sj-dialog-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--sj-z-modal, 1100);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(15, 23, 42, 0.55);
  backdrop-filter: blur(3px);
  animation: sj-fade-in var(--sj-duration-fast, 150ms) var(--sj-ease) both;
}

.sj-dialog {
  width: min(27rem, 100%);
  max-height: calc(100vh - 2rem);
  overflow: auto;
  padding: var(--sj-space-6, 1.5rem);
  border-radius: var(--sj-radius-lg, 18px);
  border: 1px solid var(--sj-border, #e2e8f0);
  background: var(--sj-surface, #fff);
  color: var(--sj-text, #0f172a);
  box-shadow: var(--sj-shadow-xl);
  animation: sj-dialog-in var(--sj-duration, 220ms) var(--sj-ease-out) both;
}

html.dark .sj-dialog,
body.dark .sj-dialog {
  background: #1e293b;
  border-color: #334155;
  color: #f1f5f9;
}

/* Bottensheet på mobil: närmare tummen, lättare att stänga */
@media (max-width: 560px) {
  .sj-dialog-backdrop {
    align-items: flex-end;
    padding: 0;
  }
  .sj-dialog {
    width: 100%;
    border-radius: var(--sj-radius-xl, 24px) var(--sj-radius-xl, 24px) 0 0;
    padding-bottom: calc(var(--sj-space-6, 1.5rem) + env(safe-area-inset-bottom));
    animation-name: sj-sheet-in;
  }
}

.sj-dialog__icon {
  width: 2.75rem;
  height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--sj-space-4, 1rem);
  border-radius: var(--sj-radius, 12px);
  background: var(--sj-info-bg, #eff6ff);
  color: var(--sj-brand, #2563eb);
}

.sj-dialog--danger .sj-dialog__icon {
  background: var(--sj-danger-bg, #fef2f2);
  color: var(--sj-danger, #dc2626);
}

.sj-dialog__icon svg { width: 1.4rem; height: 1.4rem; }

.sj-dialog__title {
  margin: 0 0 var(--sj-space-2, 0.5rem);
  font-size: var(--sj-text-xl, 1.25rem);
  font-weight: 700;
  letter-spacing: var(--sj-tracking-tight, -0.02em);
}

.sj-dialog__text {
  margin: 0;
  color: var(--sj-text-secondary, #64748b);
  font-size: var(--sj-text-sm, 0.875rem);
  line-height: var(--sj-leading-normal, 1.6);
}

html.dark .sj-dialog__text,
body.dark .sj-dialog__text { color: #94a3b8; }

/* Åtgärder högerställda: sekundär till vänster, primär/destruktiv längst till
   höger där ögat landar sist (samma regel som .sj-form-actions). */
.sj-dialog__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--sj-space-3, 0.75rem);
  margin-top: var(--sj-space-6, 1.5rem);
}

.sj-dialog__actions > * {
  flex: 0 1 auto;
  min-width: 7.5rem;
}

@media (max-width: 560px) {
  .sj-dialog__actions {
    flex-direction: column-reverse;
  }
  .sj-dialog__actions > * {
    width: 100%;
  }
}

@keyframes sj-fade-in {
  from { opacity: 0; }
}

@keyframes sj-dialog-in {
  from { opacity: 0; transform: translateY(0.75rem) scale(0.96); }
}

@keyframes sj-sheet-in {
  from { opacity: 0; transform: translateY(100%); }
}

/* -----------------------------------------------------------------------------
   10. Knappar – gemensam primitiv för nya ytor
   Befintliga knappklasser lämnas orörda; detta är opt-in.
   -------------------------------------------------------------------------- */
.sj-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sj-space-2, 0.5rem);
  min-height: 2.75rem;
  padding: 0.7rem 1.1rem;
  border: 1px solid transparent;
  border-radius: var(--sj-radius-sm, 8px);
  background: var(--sj-brand, #2563eb);
  color: #fff;
  font: inherit;
  font-size: var(--sj-text-sm, 0.875rem);
  font-weight: 650;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition:
    background var(--sj-duration-fast, 150ms) var(--sj-ease),
    border-color var(--sj-duration-fast, 150ms) var(--sj-ease),
    box-shadow var(--sj-duration-fast, 150ms) var(--sj-ease),
    transform var(--sj-duration-instant, 80ms) var(--sj-ease);
}

.sj-btn:hover:not(:disabled) {
  background: var(--sj-brand-dark, #1d4ed8);
  box-shadow: var(--sj-shadow);
}

/* Taktil kvittens vid tryck – bekräftar att systemet tog emot handlingen */
.sj-btn:active:not(:disabled) {
  transform: translateY(1px);
  box-shadow: none;
}

.sj-btn:disabled,
.sj-btn[aria-disabled='true'] {
  opacity: 0.55;
  cursor: not-allowed;
}

.sj-btn--secondary {
  background: var(--sj-surface, #fff);
  border-color: var(--sj-border-strong, #cbd5e1);
  color: var(--sj-text, #0f172a);
  --sj-busy-spinner-color: var(--sj-text, #0f172a);
}

.sj-btn--secondary:hover:not(:disabled) {
  background: var(--sj-bg-muted, #f8fafc);
  border-color: var(--sj-brand, #2563eb);
}

html.dark .sj-btn--secondary,
body.dark .sj-btn--secondary {
  background: #243044;
  border-color: #475569;
  color: #e2e8f0;
  --sj-busy-spinner-color: #e2e8f0;
}

.sj-btn--ghost {
  background: transparent;
  color: var(--sj-brand, #2563eb);
  --sj-busy-spinner-color: var(--sj-brand, #2563eb);
}

.sj-btn--ghost:hover:not(:disabled) {
  background: var(--sj-bg-accent, #eff6ff);
  box-shadow: none;
}

/* Riskfyllda handlingar signalerar risk med färg, inte bara ord */
.sj-btn--danger {
  background: var(--sj-danger, #dc2626);
}

.sj-btn--danger:hover:not(:disabled) {
  background: var(--sj-danger-strong, #b91c1c);
}

.sj-btn--block { width: 100%; }

.sj-btn--lg {
  min-height: 3.25rem;
  padding: 0.9rem 1.5rem;
  font-size: var(--sj-text-base, 1rem);
}

/* -----------------------------------------------------------------------------
   11. Formulär – etiketter över fältet, hjälptext under, fel i klartext
   -------------------------------------------------------------------------- */
.sj-field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-bottom: var(--sj-space-4, 1rem);
  text-align: left;
}

.sj-label {
  font-size: var(--sj-text-sm, 0.875rem);
  font-weight: 600;
  color: var(--sj-text, #0f172a);
}

html.dark .sj-label,
body.dark .sj-label { color: #e2e8f0; }

.sj-label__optional {
  margin-left: 0.35rem;
  font-weight: 500;
  color: var(--sj-text-muted, #94a3b8);
}

.sj-hint {
  font-size: var(--sj-text-xs, 0.75rem);
  line-height: var(--sj-leading-snug, 1.35);
  color: var(--sj-text-secondary, #64748b);
}

.sj-field-error {
  display: flex;
  align-items: flex-start;
  gap: 0.35rem;
  font-size: var(--sj-text-xs, 0.75rem);
  line-height: var(--sj-leading-snug, 1.35);
  font-weight: 550;
  color: var(--sj-danger, #dc2626);
}

html.dark .sj-field-error,
body.dark .sj-field-error { color: #fca5a5; }

.sj-field-error:empty { display: none; }

.sj-field-error::before {
  content: '';
  flex-shrink: 0;
  width: 0.95rem;
  height: 0.95rem;
  margin-top: 0.05rem;
  background: currentColor;
  -webkit-mask: var(--sj-icon-alert) center / contain no-repeat;
  mask: var(--sj-icon-alert) center / contain no-repeat;
}

:root {
  --sj-icon-alert: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 8v4'/%3E%3Cpath d='M12 16h.01'/%3E%3C/svg%3E");
}

/* Fältet självt markeras – användaren ser exakt var felet sitter */
.sj-input,
input.sj-input,
select.sj-input,
textarea.sj-input {
  width: 100%;
  min-height: 2.75rem;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--sj-border-strong, #cbd5e1);
  border-radius: var(--sj-radius-sm, 8px);
  background: var(--sj-surface, #fff);
  color: var(--sj-text, #0f172a);
  font: inherit;
  font-size: var(--sj-text-base, 1rem);
  transition:
    border-color var(--sj-duration-fast, 150ms) var(--sj-ease),
    box-shadow var(--sj-duration-fast, 150ms) var(--sj-ease);
}

.sj-input:focus {
  outline: none;
  border-color: var(--sj-brand, #2563eb);
  box-shadow: var(--sj-ring);
}

/* Rött fält + röd ring: felet syns även för den som inte läser texten */
[aria-invalid='true'],
.sj-input.is-invalid {
  border-color: var(--sj-danger, #dc2626) !important;
}

[aria-invalid='true']:focus,
.sj-input.is-invalid:focus {
  box-shadow: var(--sj-ring-danger) !important;
}

/* Grön bock när fältet är klart – bekräftar framsteg medan man skriver */
.sj-field.is-valid .sj-input,
.sj-input.is-valid {
  border-color: var(--sj-success-border, #a7f3d0);
}

/* -----------------------------------------------------------------------------
   12. Tomma tillstånd – aldrig en tom yta utan väg framåt
   -------------------------------------------------------------------------- */
.sj-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sj-space-3, 0.75rem);
  padding: var(--sj-space-12, 3rem) var(--sj-space-5, 1.25rem);
  max-width: 30rem;
  margin-inline: auto;
}

.sj-empty__art {
  width: 4rem;
  height: 4rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--sj-radius-lg, 18px);
  background: var(--sj-bg-accent, #eff6ff);
  color: var(--sj-brand, #2563eb);
}

html.dark .sj-empty__art,
body.dark .sj-empty__art {
  background: #1e293b;
  color: #93c5fd;
}

.sj-empty__art svg { width: 1.9rem; height: 1.9rem; }

.sj-empty__title {
  margin: 0;
  font-size: var(--sj-text-lg, 1.125rem);
  font-weight: 700;
  color: var(--sj-text, #0f172a);
}

.sj-empty__text {
  margin: 0;
  font-size: var(--sj-text-sm, 0.875rem);
  line-height: var(--sj-leading-normal, 1.6);
  color: var(--sj-text-secondary, #64748b);
}

.sj-empty__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sj-space-2, 0.5rem);
  justify-content: center;
  margin-top: var(--sj-space-2, 0.5rem);
}

/* -----------------------------------------------------------------------------
   13. Statusrad – "sparar…", "sparat", "försöker igen…"
   -------------------------------------------------------------------------- */
.sj-status {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--sj-text-xs, 0.75rem);
  font-weight: 600;
  color: var(--sj-text-secondary, #64748b);
  transition: opacity var(--sj-duration-fast, 150ms) var(--sj-ease);
}

.sj-status:empty { opacity: 0; }
.sj-status--saved { color: var(--sj-success, #059669); }
.sj-status--error { color: var(--sj-danger, #dc2626); }

.sj-status__dot {
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: currentColor;
}

.sj-status--busy .sj-status__dot {
  animation: sj-pulse 1.1s var(--sj-ease) infinite;
}

@keyframes sj-pulse {
  50% { opacity: 0.25; transform: scale(0.8); }
}

/* -----------------------------------------------------------------------------
   14. Rörelse: respektera användarens systeminställning
   -------------------------------------------------------------------------- */
@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;
  }

  /* Snurror och skelett måste fortfarande signalera "det händer något" */
  .sj-spinner,
  .spinner,
  .sj-btn-busy::after {
    animation-duration: 0.9s !important;
    animation-iteration-count: infinite !important;
  }

  .sj-skeleton::after {
    animation: none !important;
    transform: none;
    opacity: 0.5;
  }
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

/* Fokusmål efter ankarhopp hamnar inte under den fasta headern */
:target,
[id] {
  scroll-margin-top: var(--sj-scroll-offset, 5rem);
}

/* -----------------------------------------------------------------------------
   15. Kontrast i högkontrastläge
   -------------------------------------------------------------------------- */
@media (forced-colors: active) {
  .sj-btn,
  .sj-input,
  .sj-toast,
  .sj-dialog {
    border: 1px solid CanvasText;
  }
}

/* ===== components.css ============================================== */
/* =============================================================================
   Studiehjälpen – delade komponenter (components.css)
   Part of assets/css/sj-core.css, linked first in every page's <head>.
   Allt här bygger på tokens i tokens.css och fungerar i ljust + mörkt läge
   utan egna färgkoder. En definition per komponent – sidor får INTE
   skriva egna varianter av radio/checkbox, knappar, fält, kort osv.
   ============================================================================= */

/* =============================================================================
   0. FOUNDATION — one button, one card, one field, for the whole site.

   Ported from tcg_collection_manager/web/app/globals.css, which already solves
   the problem reported here: define every control once so nothing drifts into
   its own size, radius or border.

   Measured in the site header before this existed:
       nav link      77x40   radius 8px    no border
       shop icon     27x22   radius 999px  1px border
       cart icon     22x22   radius 999px  1px border
       theme toggle  44x44   radius 999px  1px border
       hamburger     44x44   radius 999px  1px border

   Four heights in one row, and the two "plain icons" were half the height of
   the controls beside them.
   ============================================================================= */

/* ---- Buttons -------------------------------------------------------------
   Every variant sets BOTH background and text colour, so a utility class can
   never leave a button with invisible text. */
.btn,
.sj-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: var(--sj-control-height, 44px);
  padding: 0.625rem 1.125rem;
  border: 1px solid transparent;
  border-radius: var(--sj-radius-sm);
  font-family: inherit;
  font-size: var(--sj-text-sm);
  font-weight: 600;
  line-height: 1.25;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--sj-duration-fast) var(--sj-ease),
              border-color var(--sj-duration-fast) var(--sj-ease),
              color var(--sj-duration-fast) var(--sj-ease),
              box-shadow var(--sj-duration-fast) var(--sj-ease);
}

.btn:focus-visible,
.sj-btn:focus-visible { outline: none; box-shadow: var(--sj-ring); }

.btn:disabled,
.sj-btn:disabled,
.btn[aria-disabled='true'] { opacity: 0.55; cursor: not-allowed; }

.btn--primary { background: var(--sj-brand); color: var(--sj-text-on-brand); border-color: var(--sj-brand); }
.btn--primary:hover:not(:disabled) { background: var(--sj-brand-dark); border-color: var(--sj-brand-dark); }

.btn--secondary { background: var(--sj-surface); color: var(--sj-text); border-color: var(--sj-border-strong); }
.btn--secondary:hover:not(:disabled) { background: var(--sj-bg-muted); }

.btn--ghost { background: transparent; color: var(--sj-text); border-color: transparent; }
.btn--ghost:hover:not(:disabled) { background: var(--sj-brand-tint); color: var(--sj-brand); }

.btn--danger { background: var(--sj-danger); color: #fff; border-color: var(--sj-danger); }
.btn--danger:hover:not(:disabled) { background: var(--sj-danger-strong); border-color: var(--sj-danger-strong); }

/* A destructive action that is not the primary one on the surface — "Ta bort
   bild" next to "Ladda upp bild", say. It has to read as removal without
   shouting louder than the action it sits beside, which a solid red does. */
.btn--danger-quiet { background: transparent; color: var(--sj-danger); border-color: var(--sj-danger-border, var(--sj-border-strong)); }
.btn--danger-quiet:hover:not(:disabled) { background: color-mix(in srgb, var(--sj-danger) 10%, transparent); border-color: var(--sj-danger); }

/* For the blue hero band, where the page tokens would be unreadable. */
.btn--on-brand { background: #fff; color: var(--sj-brand); border-color: #fff; }
.btn--on-brand:hover:not(:disabled) { background: rgba(255, 255, 255, 0.92); }

.btn--ghost-on-brand { background: rgba(255, 255, 255, 0.12); color: #fff; border-color: rgba(255, 255, 255, 0.55); }
.btn--ghost-on-brand:hover:not(:disabled) { background: rgba(255, 255, 255, 0.22); border-color: #fff; }

.btn--sm { min-height: 36px; padding: 0.375rem 0.75rem; font-size: var(--sj-text-xs); }
.btn--lg { min-height: 52px; padding: 0.875rem 1.5rem; font-size: var(--sj-text-base); }
.btn--block { width: 100%; }

/* ---- Icon button ---------------------------------------------------------
   Square, and exactly the same height as .btn, so an icon control sitting next
   to a text button or another icon control lines up. */
.btn-icon,
.sj-btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--sj-control-height, 44px);
  height: var(--sj-control-height, 44px);
  padding: 0;
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius-sm);
  background: var(--sj-surface);
  color: var(--sj-text);
  cursor: pointer;
  position: relative;
  transition: background-color var(--sj-duration-fast) var(--sj-ease),
              border-color var(--sj-duration-fast) var(--sj-ease),
              color var(--sj-duration-fast) var(--sj-ease);
}

.btn-icon:hover,
.sj-btn-icon:hover { background: var(--sj-bg-muted); border-color: var(--sj-border-strong); }

.btn-icon:focus-visible,
.sj-btn-icon:focus-visible { outline: none; box-shadow: var(--sj-ring); }

.btn-icon > svg,
.sj-btn-icon > svg { width: 20px; height: 20px; }

/* ---- Card ----------------------------------------------------------------
   One surface definition, and the brand-tinted hover glow from the TCG
   reference: a 1px accent ring plus a soft outer bloom. */
.card,
.sj-card {
  background: var(--sj-surface);
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius);
  box-shadow: var(--sj-shadow-sm);
  color: var(--sj-text);
  /* Containment. A flex/grid child defaults to min-width:auto, so a long word,
     a URL or a wide table pushes the card wider than its container instead of
     wrapping — that is content "overwriting or overflowing" the card. */
  min-width: 0;
  overflow-wrap: anywhere;
  transition: box-shadow var(--sj-duration) var(--sj-ease),
              border-color var(--sj-duration) var(--sj-ease),
              transform var(--sj-duration) var(--sj-ease-out);
}

.card > *,
.sj-card > * { min-width: 0; max-width: 100%; }

.card img, .card svg, .card video, .card canvas, .card iframe,
.sj-card img, .sj-card svg, .sj-card video, .sj-card canvas, .sj-card iframe {
  max-width: 100%;
  height: auto;
}

.card pre, .card table,
.sj-card pre, .sj-card table { max-width: 100%; overflow-x: auto; }

.card:hover,
.sj-card:hover {
  border-color: color-mix(in srgb, var(--sj-brand) 30%, var(--sj-border));
  box-shadow:
    var(--sj-shadow-lg),
    0 0 0 1px color-mix(in srgb, var(--sj-brand) 25%, transparent),
    0 0 20px -6px color-mix(in srgb, var(--sj-brand) 40%, transparent);
}

/* Only cards that actually go somewhere lift. */
a.card:hover,
a.sj-card:hover,
.card--interactive:hover,
.sj-card--interactive:hover { transform: translateY(-2px); }

/* ---- Fields --------------------------------------------------------------- */
.input,
.sj-input {
  width: 100%;
  min-height: var(--sj-control-height, 44px);
  padding: 0.625rem 0.875rem;
  background: var(--sj-input-bg);
  color: var(--sj-text);
  border: 1px solid var(--sj-input-border);
  border-radius: var(--sj-radius-sm);
  font-family: inherit;
  font-size: var(--sj-text-sm);
  transition: border-color var(--sj-duration-fast) var(--sj-ease),
              box-shadow var(--sj-duration-fast) var(--sj-ease);
}

.input::placeholder, .sj-input::placeholder { color: var(--sj-text-muted); }

.input:focus, .sj-input:focus {
  outline: none;
  border-color: var(--sj-brand);
  box-shadow: var(--sj-ring);
}

.input:disabled, .input[readonly],
.sj-input:disabled, .sj-input[readonly] {
  background: var(--sj-bg-muted);
  color: var(--sj-text-muted);
  cursor: not-allowed;
}

.label,
.sj-label {
  display: block;
  margin-bottom: 0.375rem;
  font-size: var(--sj-text-xs);
  font-weight: 600;
  color: var(--sj-text-secondary);
}

/* ---- Badge ---------------------------------------------------------------- */
.badge,
.sj-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.5rem;
  border-radius: var(--sj-radius-pill);
  border: 1px solid transparent;
  font-size: var(--sj-text-xs);
  font-weight: 700;
  line-height: 1.5;
  white-space: nowrap;
}

.badge--brand   { background: var(--sj-brand); color: var(--sj-text-on-brand); }
.badge--muted   { background: var(--sj-bg-muted); color: var(--sj-text-muted); border-color: var(--sj-border); }
.badge--success { background: var(--sj-success-tint); color: var(--sj-success); }
.badge--warning { background: var(--sj-warning-tint); color: var(--sj-warning); }
.badge--danger  { background: var(--sj-danger-tint);  color: var(--sj-danger); }

/* ---- Global containment --------------------------------------------------
   The site must hold together down to 300px. These stop long words, wide
   tables and oversized media from forcing horizontal scroll — the mechanism
   behind content escaping its box. */
/* ONE box model for the whole site.

   home.css and my-courses.css each declared `* { box-sizing: border-box }`
   globally, so the box model depended on which page-specific stylesheet
   happened to load: the homepage and My Courses were border-box, every other
   page was content-box. Padding therefore added to the width on some pages and
   not others — which is why a 300px viewport gave a 332px <main> on the 404 and
   cookie pages but not on the homepage, and part of why the same component
   looked different from page to page. */
*,
*::before,
*::after { box-sizing: border-box; }

html, body { overflow-x: clip; }

/* body is display:flex on this site, which makes <main> a flex item — and a
   flex item defaults to min-width:auto, meaning it can never shrink below its
   content's minimum width. A single wide table inside cookie-settings.html
   measured 399px min-content and dragged the whole page to 431px inside a
   300px viewport. min-width:0 lets the item shrink so the scroll container
   around the table can do its job. */
body { min-width: 0; }

/* Direct children of the flex body are constrained so a wide table cannot drag
   the page open. Fixed-position chrome is exempt: it is taken out of flow and
   sized against the viewport, and max-width:100% would cap it at the content
   box — which left the cart drawer a scrollbar's width short of the screen edge
   on mobile (375px in a 390px window). */
/* .page is exempt: it sets its own max-width from --sj-container and is
   width:100% + border-box, so it can never exceed the viewport. Without the
   exemption this rule won on specificity — four of those :not() arguments are
   IDs, which makes it (4,5,1) — and every page fell back to 100%.

   `main` is exempt for the same reason. The course pages use a bare <main> as
   their content root and size it themselves in course-bridge.css; a content
   root is not the stray wide child this rule exists to catch, and no selector
   short of !important can outrank (4,5,1). Anything that overflows as a result
   is caught by scripts/check-overflow.mjs.

   .sj-course-crumbs is exempt on exactly the same grounds. It is the container
   ProtectedController wraps the injected course breadcrumb in, and like .page
   it is width:100% + border-box with its own --sj-container cap. Capped at
   100% instead it spanned the full viewport, so the breadcrumb started at the
   left edge of a course page while every other page indented it to 90px. */
body > *:not(.page):not(main):not(.sj-course-crumbs):not(.sj-cart-drawer):not(.sj-cart-overlay):not(#sidepanel):not(.sidepanel-backdrop):not(#sj-prefs-bar):not(#sj-prefs-dialog):not(#sj-prefs-veil):not(.mobile-bottom-nav) {
  min-width: 0; max-width: 100%;
}

/* width:100% as well as min-width:0. In a column flex container a stretched
   item still cannot go below its content's minimum width; an explicit width
   makes the constraint definite so the scroll container around a wide table
   actually scrolls instead of dragging the page open. */
body > main,
body > .site-footer-chrome,
body > header,
body > section { width: 100%; }

/* Reserve the height a page's content will occupy, so the footer does not start
   halfway up an empty page and then get pushed down when the content arrives.

   Measured on /forum at 390px: .site-footer-chrome began at y=156 and jumped to
   y=575 at 1.9s, when the thread list rendered - a single shift worth 0.404 of the
   page's 0.439 CLS. Static pages never showed it because their content is in the
   HTML; only pages that fill in from an API did, and only on the narrow viewport
   where the gap is proportionally largest.

   A minimum height rather than a flex sticky-footer layout: body is not currently
   a flex container and making it one would reach into every page's stacking and
   overflow behaviour to fix one measurement. */
body > main.page {
  min-height: 60vh;
}

/* Any horizontal scroller must be allowed to be narrower than its content —
   that is the whole point of it. */
.sj-table-wrap,
.scroll-x,
[data-scroll-x] {
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

h1, h2, h3, h4, h5, h6, p, li, dd, dt, td, th, figcaption, blockquote {
  overflow-wrap: break-word;
}

img, video, canvas { max-width: 100%; }

@media (prefers-reduced-motion: reduce) {
  .card, .sj-card, .btn, .sj-btn, .btn-icon, .sj-btn-icon { transition: none; }
  a.card:hover, a.sj-card:hover,
  .card--interactive:hover, .sj-card--interactive:hover { transform: none; }
}

/* ---------------------------------------------------------------------------
   1. Radio & checkbox – 24 px yttre, 16 px inre, ≥44 px träffyta
   Gäller ALLA native radio/checkbox på sajten. Undantag via .sj-native
   (t.ex. cookie-reglaget som är en switch).
   ------------------------------------------------------------------------ */
input[type="radio"]:not(.sj-native):not(.sj-prefs-switch),
input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch) {
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  width: var(--sj-control-outer);
  height: var(--sj-control-outer);
  min-width: var(--sj-control-outer);
  margin: 0;
  padding: 0;
  flex: 0 0 auto;
  display: inline-grid;
  place-content: center;
  border: var(--sj-control-border) solid var(--sj-border-strong);
  background: var(--sj-surface);
  color: var(--sj-brand);
  cursor: pointer;
  vertical-align: middle;
  transition: border-color var(--sj-duration-fast) var(--sj-ease),
              background-color var(--sj-duration-fast) var(--sj-ease),
              box-shadow var(--sj-duration-fast) var(--sj-ease);
}

input[type="radio"]:not(.sj-native):not(.sj-prefs-switch) {
  border-radius: 50%;
}

input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch) {
  border-radius: var(--sj-radius-xs);
}

/* Inre element: 16 px prick / bock */
input[type="radio"]:not(.sj-native):not(.sj-prefs-switch)::before,
input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch)::before {
  content: "";
  width: var(--sj-control-inner);
  height: var(--sj-control-inner);
  transform: scale(0);
  transition: transform var(--sj-duration-fast) var(--sj-ease-out);
}

input[type="radio"]:not(.sj-native):not(.sj-prefs-switch)::before {
  border-radius: 50%;
  background: currentColor;
}

input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch)::before {
  border-radius: 2px;
  background: currentColor;
  /* Bock ritad som mask så att den alltid följer textfärgen */
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3 8.5l3.2 3.2L13 4.8' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3 8.5l3.2 3.2L13 4.8' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
}

input[type="radio"]:not(.sj-native):not(.sj-prefs-switch):checked,
input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch):checked {
  border-color: var(--sj-brand);
}

input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch):checked {
  background: var(--sj-brand);
  color: var(--sj-brand-contrast);
}

input[type="radio"]:not(.sj-native):not(.sj-prefs-switch):checked::before,
input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch):checked::before {
  transform: scale(1);
}

input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch):indeterminate {
  border-color: var(--sj-brand);
  background: var(--sj-brand);
}

input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch):indeterminate::before {
  transform: scale(1);
  -webkit-mask: none;
          mask: none;
  height: 3px;
  border-radius: 2px;
  background: var(--sj-brand-contrast);
}

input[type="radio"]:not(.sj-native):not(.sj-prefs-switch):hover:not(:disabled),
input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch):hover:not(:disabled) {
  border-color: var(--sj-brand);
}

input[type="radio"]:not(.sj-native):not(.sj-prefs-switch):focus-visible,
input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch):focus-visible {
  outline: none;
  box-shadow: var(--sj-ring);
}

input[type="radio"]:not(.sj-native):not(.sj-prefs-switch):disabled,
input[type="checkbox"]:not(.sj-native):not(.sj-prefs-switch):disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

input[type="radio"][aria-invalid="true"]:not(.sj-native),
input[type="checkbox"][aria-invalid="true"]:not(.sj-native) {
  border-color: var(--sj-danger);
}

/* Etikett runt kontrollen – ger 44 px träffyta utan att kontrollen växer */
.sj-choice {
  display: flex;
  align-items: flex-start;
  gap: var(--sj-space-3);
  min-height: var(--sj-touch-target);
  padding: calc((var(--sj-touch-target) - var(--sj-control-outer)) / 2) 0;
  cursor: pointer;
  color: var(--sj-text);
  font-size: var(--sj-text-base);
  line-height: var(--sj-leading-normal);
}

.sj-choice > input[type="radio"],
.sj-choice > input[type="checkbox"] {
  margin-top: calc((1em * var(--sj-leading-normal) - var(--sj-control-outer)) / 2);
}

.sj-choice__text {
  flex: 1 1 auto;
  min-width: 0;
}

.sj-choice__hint {
  display: block;
  color: var(--sj-text-secondary);
  font-size: var(--sj-text-sm);
  margin-top: 0.15rem;
}

/* Grupp: ≤5 val visas alltid som en synlig lista, aldrig en dropdown */
.sj-choice-group {
  display: flex;
  flex-direction: column;
  gap: 0;
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}

.sj-choice-group > legend,
.sj-choice-group__legend {
  font-weight: 700;
  color: var(--sj-text);
  margin-bottom: var(--sj-space-2);
  padding: 0;
}

.sj-choice-group--inline {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 0 var(--sj-space-6);
}

/* Valkort: när alternativen bär beskrivning/pris (plan, produktvariant) */
.sj-choice-card {
  display: flex;
  align-items: flex-start;
  gap: var(--sj-space-3);
  padding: var(--sj-space-4);
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius);
  background: var(--sj-surface);
  cursor: pointer;
  transition: border-color var(--sj-duration-fast) var(--sj-ease),
              box-shadow var(--sj-duration-fast) var(--sj-ease),
              background-color var(--sj-duration-fast) var(--sj-ease);
}

.sj-choice-card + .sj-choice-card {
  margin-top: var(--sj-space-3);
}

.sj-choice-card:hover {
  border-color: var(--sj-brand-light);
}

.sj-choice-card:has(input:checked) {
  border-color: var(--sj-brand);
  background: var(--sj-bg-accent);
  box-shadow: 0 0 0 1px var(--sj-brand);
}

.sj-choice-card:has(input:focus-visible) {
  box-shadow: var(--sj-ring);
}

.sj-choice-card__body {
  flex: 1 1 auto;
  min-width: 0;
}

.sj-choice-card__title {
  font-weight: 700;
  color: var(--sj-text);
  display: flex;
  justify-content: space-between;
  gap: var(--sj-space-3);
  flex-wrap: wrap;
}

.sj-choice-card__price {
  font-variant-numeric: tabular-nums;
  color: var(--sj-text-heading);
  white-space: nowrap;
}

.sj-choice-card__desc {
  color: var(--sj-text-secondary);
  font-size: var(--sj-text-sm);
  margin-top: 0.2rem;
}

/* ---------------------------------------------------------------------------
   2. Formulärlayout – vertikalt, etikett över fält, fel som text
   ------------------------------------------------------------------------ */
.sj-form {
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-5);
  min-width: 0;
}

.sj-form--tight {
  gap: var(--sj-space-4);
}

.sj-field {
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-2);
  min-width: 0;
}

.sj-field__label,
.sj-label {
  font-weight: 600;
  font-size: var(--sj-text-sm);
  color: var(--sj-text);
  line-height: 1.3;
}

.sj-field__label .sj-optional,
.sj-optional {
  font-weight: 400;
  color: var(--sj-text-muted);
  margin-left: 0.35em;
}

.sj-field__hint,
.sj-hint {
  font-size: var(--sj-text-sm);
  color: var(--sj-text-secondary);
  margin: 0;
}

/* Felmeddelande per fält – alltid text, aldrig bara färg */
.sj-field-error,
.sj-field__error {
  display: none;
  font-size: var(--sj-text-sm);
  color: var(--sj-danger);
  margin: 0;
  line-height: 1.4;
  align-items: flex-start;
  gap: 0.35rem;
}

.sj-field-error:not(:empty),
.sj-field__error:not(:empty),
.sj-field-error.is-visible,
.sj-field__error.is-visible {
  display: flex;
}

.sj-field-error::before,
.sj-field__error::before {
  content: "";
  flex: 0 0 auto;
  width: 1em;
  height: 1em;
  margin-top: 0.15em;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10' fill='none' stroke='black' stroke-width='2'/><path d='M12 8v5M12 16h.01' stroke='black' stroke-width='2.4' stroke-linecap='round'/></svg>") center / contain no-repeat;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10' fill='none' stroke='black' stroke-width='2'/><path d='M12 8v5M12 16h.01' stroke='black' stroke-width='2.4' stroke-linecap='round'/></svg>") center / contain no-repeat;
}

.sj-field.has-error .sj-input,
.sj-field.has-error .sj-select,
.sj-field.has-error .sj-textarea,
.sj-field.has-error input:not([type="radio"]):not([type="checkbox"]),
.sj-field.has-error select,
.sj-field.has-error textarea,
.sj-input[aria-invalid="true"],
input[aria-invalid="true"]:not([type="radio"]):not([type="checkbox"]),
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
  border-color: var(--sj-danger) !important;
}

.sj-field.has-error .sj-input:focus,
input[aria-invalid="true"]:not([type="radio"]):not([type="checkbox"]):focus {
  box-shadow: var(--sj-ring-danger) !important;
}

/* Bredd matchar datat: korta fält ska vara korta */
.sj-field--xs { max-width: 8rem; }
.sj-field--sm { max-width: 12rem; }
.sj-field--md { max-width: 20rem; }
.sj-field--lg { max-width: 32rem; }

.sj-form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  gap: var(--sj-space-4);
}

/* Åtgärder: primär/destruktiv till höger, sekundär till vänster */
.sj-form-actions,
.sj-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sj-space-3);
  justify-content: flex-end;
  align-items: center;
  margin-top: var(--sj-space-2);
}

.sj-form-actions > .sj-actions__start,
.sj-actions > .sj-actions__start {
  margin-right: auto;
}

@media (max-width: 480px) {
  .sj-form-actions,
  .sj-actions {
    flex-direction: column-reverse;
    align-items: stretch;
  }
  .sj-form-actions > .sj-actions__start,
  .sj-actions > .sj-actions__start {
    margin-right: 0;
  }
}

/* Sökfält med ikon + tydlig platshållare */
.sj-search {
  position: relative;
  display: flex;
  align-items: center;
  min-width: 0;
}

.sj-search > .sj-input,
.sj-search > input {
  padding-left: 2.6rem;
  width: 100%;
}

.sj-search__icon {
  position: absolute;
  left: 0.9rem;
  width: 1.1rem;
  height: 1.1rem;
  color: var(--sj-text-muted);
  pointer-events: none;
}

/* Kodfält (2FA, presentkod) – jämn teckenbredd, centrerat */
.sj-input--code {
  font-family: var(--sj-font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.2em; /* Enda tillåtna avståndet: gör siffergrupper läsbara */
  text-align: center;
  font-size: var(--sj-text-xl);
  max-width: 14rem;
}

/* Lösenordsstyrka – text-checklista, aldrig bara en färgad stapel */
.sj-strength {
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-2);
  font-size: var(--sj-text-sm);
}

.sj-strength__bar {
  height: 6px;
  border-radius: var(--sj-radius-pill);
  background: var(--sj-surface-sunken);
  overflow: hidden;
}

.sj-strength__fill {
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: var(--sj-danger);
  transition: width var(--sj-duration) var(--sj-ease), background-color var(--sj-duration) var(--sj-ease);
}

.sj-strength__fill[data-level="2"] { background: var(--sj-warning); }
.sj-strength__fill[data-level="3"] { background: var(--sj-brand); }
.sj-strength__fill[data-level="4"] { background: var(--sj-success); }

.sj-strength__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 0.25rem var(--sj-space-4);
  color: var(--sj-text-secondary);
}

.sj-strength__list li {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.sj-strength__list li::before {
  content: "";
  width: 1em;
  height: 1em;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  opacity: 0.6;
}

.sj-strength__list li.is-met {
  color: var(--sj-success);
}

.sj-strength__list li.is-met::before {
  opacity: 1;
  border: 0;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='black'/><path d='M7 12.5l3.2 3.2L17 9' fill='none' stroke='white' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='black'/><path d='M7 12.5l3.2 3.2L17 9' fill='none' stroke='white' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
}

/* ---------------------------------------------------------------------------
   3. Combobox – sök + scrolla i långa listor
   ------------------------------------------------------------------------ */
.sj-combobox {
  position: relative;
  min-width: 0;
}

.sj-combobox__input {
  width: 100%;
  padding-right: 2.5rem;
}

.sj-combobox__toggle {
  position: absolute;
  right: 0.35rem;
  top: 50%;
  transform: translateY(-50%);
  width: 2rem;
  height: 2rem;
  display: grid;
  place-content: center;
  border: 0;
  border-radius: var(--sj-radius-sm);
  background: transparent;
  color: var(--sj-text-muted);
  cursor: pointer;
}

.sj-combobox__toggle:hover {
  background: var(--sj-bg-muted);
  color: var(--sj-text);
}

.sj-combobox__list {
  position: absolute;
  z-index: var(--sj-z-overlay);
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  max-height: 16rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin: 0;
  padding: var(--sj-space-1);
  list-style: none;
  background: var(--sj-surface-elevated);
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius);
  box-shadow: var(--sj-shadow-lg);
}

.sj-combobox__list[hidden] {
  display: none;
}

.sj-combobox__option {
  padding: 0.6rem 0.75rem;
  border-radius: var(--sj-radius-sm);
  cursor: pointer;
  color: var(--sj-text);
  display: flex;
  justify-content: space-between;
  gap: var(--sj-space-3);
  min-height: 40px;
  align-items: center;
}

.sj-combobox__option[aria-selected="true"],
.sj-combobox__option.is-active {
  background: var(--sj-bg-accent);
  color: var(--sj-text-heading);
}

.sj-combobox__option:hover {
  background: var(--sj-bg-muted);
}

.sj-combobox__option mark {
  background: transparent;
  color: var(--sj-brand);
  font-weight: 700;
}

.sj-combobox__empty {
  padding: 0.75rem;
  color: var(--sj-text-muted);
  font-size: var(--sj-text-sm);
}

/* ---------------------------------------------------------------------------
   4. Reglage (range) – för sifferfilter
   ------------------------------------------------------------------------ */
.sj-range {
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-2);
}

.sj-range__values {
  display: flex;
  justify-content: space-between;
  font-size: var(--sj-text-sm);
  color: var(--sj-text-secondary);
  font-variant-numeric: tabular-nums;
}

.sj-range__values output {
  color: var(--sj-text);
  font-weight: 600;
}

.sj-range input[type="range"],
input[type="range"].sj-range__input {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: var(--sj-touch-target);
  margin: 0;
  background: transparent;
  cursor: pointer;
}

.sj-range input[type="range"]::-webkit-slider-runnable-track,
input[type="range"].sj-range__input::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: var(--sj-radius-pill);
  background: linear-gradient(to right,
    var(--sj-brand) 0%,
    var(--sj-brand) var(--sj-range-fill, 0%),
    var(--sj-border-strong) var(--sj-range-fill, 0%),
    var(--sj-border-strong) 100%);
}

.sj-range input[type="range"]::-moz-range-track,
input[type="range"].sj-range__input::-moz-range-track {
  height: 6px;
  border-radius: var(--sj-radius-pill);
  background: var(--sj-border-strong);
}

.sj-range input[type="range"]::-moz-range-progress,
input[type="range"].sj-range__input::-moz-range-progress {
  height: 6px;
  border-radius: var(--sj-radius-pill);
  background: var(--sj-brand);
}

.sj-range input[type="range"]::-webkit-slider-thumb,
input[type="range"].sj-range__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: var(--sj-control-outer);
  height: var(--sj-control-outer);
  margin-top: calc((6px - var(--sj-control-outer)) / 2);
  border-radius: 50%;
  border: var(--sj-control-border) solid var(--sj-brand);
  background: var(--sj-surface);
  box-shadow: var(--sj-shadow-sm);
  transition: transform var(--sj-duration-fast) var(--sj-ease);
}

.sj-range input[type="range"]::-moz-range-thumb,
input[type="range"].sj-range__input::-moz-range-thumb {
  width: var(--sj-control-outer);
  height: var(--sj-control-outer);
  border-radius: 50%;
  border: var(--sj-control-border) solid var(--sj-brand);
  background: var(--sj-surface);
  box-shadow: var(--sj-shadow-sm);
}

.sj-range input[type="range"]:focus-visible,
input[type="range"].sj-range__input:focus-visible {
  outline: none;
}

.sj-range input[type="range"]:focus-visible::-webkit-slider-thumb,
input[type="range"].sj-range__input:focus-visible::-webkit-slider-thumb {
  box-shadow: var(--sj-ring);
}

.sj-range input[type="range"]:focus-visible::-moz-range-thumb,
input[type="range"].sj-range__input:focus-visible::-moz-range-thumb {
  box-shadow: var(--sj-ring);
}

/* Dubbelreglage (min–max) = två inputs ovanpå varandra */
.sj-range--dual {
  position: relative;
}

.sj-range--dual .sj-range__track {
  position: relative;
  height: var(--sj-touch-target);
}

.sj-range--dual input[type="range"] {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.sj-range--dual input[type="range"]::-webkit-slider-thumb {
  pointer-events: auto;
}

.sj-range--dual input[type="range"]::-moz-range-thumb {
  pointer-events: auto;
}

.sj-range--dual input[type="range"]::-webkit-slider-runnable-track {
  background: transparent;
}

.sj-range--dual input[type="range"]::-moz-range-track {
  background: transparent;
}

.sj-range--dual input[type="range"]::-moz-range-progress {
  background: transparent;
}

.sj-range--dual .sj-range__rail {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 6px;
  transform: translateY(-50%);
  border-radius: var(--sj-radius-pill);
  background: var(--sj-border-strong);
}

.sj-range--dual .sj-range__fill {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: inherit;
  background: var(--sj-brand);
}

/* ---------------------------------------------------------------------------
   5. Kort – en hover för hela sajten (lyft + mjuk skugga, ingen glöd)
   ------------------------------------------------------------------------ */
.sj-card {
  background: var(--sj-surface);
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius-lg);
  box-shadow: var(--sj-shadow-xs);
  padding: var(--sj-space-6);
  color: var(--sj-text);
  min-width: 0;
  transition: transform var(--sj-duration) var(--sj-ease),
              box-shadow var(--sj-duration) var(--sj-ease),
              border-color var(--sj-duration) var(--sj-ease);
}

.sj-card--compact {
  padding: var(--sj-space-4);
}

.sj-card--flush {
  padding: 0;
  overflow: hidden;
}

.sj-card--interactive,
a.sj-card,
.sj-card[href] {
  display: block;
  text-decoration: none;
  cursor: pointer;
}

@media (hover: hover) and (pointer: fine) {
  .sj-card--interactive:hover,
  a.sj-card:hover,
  .sj-card[href]:hover {
    transform: translateY(-2px);
    box-shadow: var(--sj-shadow-lg);
    border-color: var(--sj-border-strong);
  }
}

.sj-card--interactive:focus-visible,
a.sj-card:focus-visible {
  outline: none;
  box-shadow: var(--sj-ring), var(--sj-shadow-lg);
}

.sj-card__media {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--sj-bg-muted);
}

.sj-card__body {
  padding: var(--sj-space-5);
}

.sj-card__title {
  font-size: var(--sj-text-lg);
  font-weight: 700;
  color: var(--sj-text-heading);
  margin: 0 0 var(--sj-space-2);
  line-height: var(--sj-leading-snug);
}

.sj-card__text {
  color: var(--sj-text-secondary);
  margin: 0;
}

.sj-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sj-space-3);
  flex-wrap: wrap;
  margin-top: var(--sj-space-4);
}

.sj-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
  gap: var(--sj-gap-lg);
}

/* ---------------------------------------------------------------------------
   6. Framsteg – linjär stapel + milstolpar
   ------------------------------------------------------------------------ */
.sj-progress {
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-2);
  min-width: 0;
}

.sj-progress__header {
  display: flex;
  justify-content: space-between;
  gap: var(--sj-space-3);
  font-size: var(--sj-text-sm);
  color: var(--sj-text-secondary);
}

.sj-progress__value {
  color: var(--sj-text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.sj-progress__track {
  position: relative;
  height: 10px;
  border-radius: var(--sj-radius-pill);
  background: var(--sj-surface-sunken);
  overflow: hidden;
}

.sj-progress--sm .sj-progress__track { height: 6px; }
.sj-progress--lg .sj-progress__track { height: 14px; }

.sj-progress__fill {
  height: 100%;
  width: var(--sj-progress, 0%);
  border-radius: inherit;
  background: var(--sj-brand);
  transition: width var(--sj-duration-slow) var(--sj-ease-out);
}

.sj-progress--success .sj-progress__fill { background: var(--sj-success); }

/* Milstolpar */
.sj-milestones {
  display: flex;
  align-items: flex-start;
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: sj-milestone;
}

.sj-milestones__item {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sj-space-2);
  font-size: var(--sj-text-sm);
  color: var(--sj-text-secondary);
  counter-increment: sj-milestone;
}

.sj-milestones__item::before {
  content: counter(sj-milestone);
  display: grid;
  place-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 2px solid var(--sj-border-strong);
  background: var(--sj-surface);
  color: var(--sj-text-secondary);
  font-weight: 700;
  z-index: 1;
}

.sj-milestones__item:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 15px;
  left: 50%;
  width: 100%;
  height: 2px;
  background: var(--sj-border);
}

.sj-milestones__item.is-done {
  color: var(--sj-text);
}

.sj-milestones__item.is-done::before {
  content: "";
  border-color: var(--sj-success);
  background: var(--sj-success);
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='12' fill='black'/><path d='M7 12.5l3.2 3.2L17 9' fill='none' stroke='white' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='12' fill='black'/><path d='M7 12.5l3.2 3.2L17 9' fill='none' stroke='white' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
}

.sj-milestones__item.is-done:not(:last-child)::after {
  background: var(--sj-success);
}

.sj-milestones__item.is-current {
  color: var(--sj-text-heading);
  font-weight: 600;
}

.sj-milestones__item.is-current::before {
  border-color: var(--sj-brand);
  color: var(--sj-brand);
  box-shadow: 0 0 0 4px var(--sj-bg-accent);
}

/* ---------------------------------------------------------------------------
   7. Stegindikator för flerstegsformulär (registrering m.fl.)
   ------------------------------------------------------------------------ */
.sj-stepper {
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-4);
}

.sj-stepper__steps {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  gap: var(--sj-space-2);
  /* The step labels have a floor below which they cannot shrink, so on a very
     narrow screen the row spilled out of the card it sits in. Scrolling the
     step list is better than breaking the card: the steps stay legible and
     side by side, which is the point of a stepper. No visual change at any
     width where the row already fits. */
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}

.sj-stepper__steps::-webkit-scrollbar { display: none; }

.sj-stepper__step {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-2);
  font-size: var(--sj-text-sm);
  color: var(--sj-text-muted);
}

.sj-stepper__step::before {
  content: "";
  display: block;
  height: 6px;
  border-radius: var(--sj-radius-pill);
  background: var(--sj-surface-sunken);
  transition: background-color var(--sj-duration) var(--sj-ease);
}

.sj-stepper__step.is-done::before {
  background: var(--sj-success);
}

.sj-stepper__step.is-current {
  color: var(--sj-text-heading);
  font-weight: 600;
}

.sj-stepper__step.is-current::before {
  background: var(--sj-brand);
}

.sj-stepper__label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sj-stepper__status {
  font-size: var(--sj-text-sm);
  color: var(--sj-text-secondary);
}

.sj-stepper__panel[hidden] {
  display: none;
}

.sj-stepper__panel:not([hidden]) {
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-5);
}

@media (max-width: 480px) {
  .sj-stepper__label {
    font-size: var(--sj-text-xs);
  }
}

/* ---------------------------------------------------------------------------
   8. Läs mer / expanderbar text
   ------------------------------------------------------------------------ */
.sj-readmore {
  position: relative;
}

.sj-readmore__content {
  position: relative;
  overflow: hidden;
  max-height: var(--sj-readmore-height, 9.5rem);
  transition: max-height var(--sj-duration-slow) var(--sj-ease);
}

.sj-readmore:not(.is-open) .sj-readmore__content::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3rem;
  background: linear-gradient(to bottom, transparent, var(--sj-readmore-fade, var(--sj-surface)));
  pointer-events: none;
}

.sj-readmore.is-open .sj-readmore__content {
  max-height: none;
}

.sj-readmore.is-short .sj-readmore__content {
  max-height: none;
}

.sj-readmore.is-short .sj-readmore__content::after,
.sj-readmore.is-short .sj-readmore__toggle {
  display: none;
}

.sj-readmore__toggle {
  margin-top: var(--sj-space-2);
  background: none;
  border: 0;
  padding: 0;
  min-height: var(--sj-touch-target);
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--sj-brand);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.sj-readmore__toggle:hover {
  text-decoration: underline;
}

.sj-readmore__toggle::after {
  content: "";
  width: 0.9em;
  height: 0.9em;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6 9l6 6 6-6' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6 9l6 6 6-6' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
  transition: transform var(--sj-duration-fast) var(--sj-ease);
}

.sj-readmore.is-open .sj-readmore__toggle::after {
  transform: rotate(180deg);
}

/* ---------------------------------------------------------------------------
   9. Tomt läge – alltid ett nästa steg
   ------------------------------------------------------------------------ */
.sj-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sj-space-3);
  padding: var(--sj-space-10) var(--sj-space-6);
  border: 1px dashed var(--sj-border-strong);
  border-radius: var(--sj-radius-lg);
  background: var(--sj-bg-subtle);
  color: var(--sj-text-secondary);
}

.sj-empty__icon {
  width: 48px;
  height: 48px;
  color: var(--sj-text-muted);
}

.sj-empty__title {
  margin: 0;
  font-size: var(--sj-text-lg);
  font-weight: 700;
  color: var(--sj-text);
}

.sj-empty__text {
  margin: 0;
  max-width: 34rem;
}

.sj-empty .sj-btn {
  margin-top: var(--sj-space-2);
}

/* ---------------------------------------------------------------------------
   10. Ikoner – en inline-SVG-uppsättning (sprite i partials/icons.svg)
   ------------------------------------------------------------------------ */
.sj-icon {
  display: inline-block;
  width: 1.25em;
  height: 1.25em;
  vertical-align: -0.3em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: 0 0 auto;
}

.sj-icon--sm { width: 1em; height: 1em; vertical-align: -0.15em; }
.sj-icon--lg { width: 1.6em; height: 1.6em; }

/* ---------------------------------------------------------------------------
   11. Tabeller – aldrig horisontell sidscroll, alltid egen scrollbehållare
   ------------------------------------------------------------------------ */
.sj-table-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius);
  background: var(--sj-surface);
}

.sj-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--sj-text-sm);
  color: var(--sj-text);
}

.sj-table th,
.sj-table td {
  padding: 0.75rem 1rem;
  text-align: left;
  border-bottom: 1px solid var(--sj-border);
  vertical-align: middle;
}

.sj-table th {
  font-weight: 700;
  color: var(--sj-text-secondary);
  background: var(--sj-bg-muted);
  white-space: nowrap;
}

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

.sj-table tbody tr:hover {
  background: var(--sj-bg-subtle);
}

.sj-table .is-numeric,
.sj-table td[data-numeric] {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.sj-table .sj-table__actions {
  text-align: right;
  white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   12. Etiketter/badges – t.ex. "Exempel" på demoinnehåll
   ------------------------------------------------------------------------ */
.sj-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.55rem;
  border-radius: var(--sj-radius-pill);
  font-size: var(--sj-text-xs);
  font-weight: 700;
  line-height: 1.4;
  background: var(--sj-bg-muted);
  color: var(--sj-text-secondary);
  border: 1px solid var(--sj-border);
  text-transform: uppercase;
  letter-spacing: var(--sj-tracking-wide); /* mikroetikett i versaler – enda tillåtna fallet */
}

.sj-badge--brand { background: var(--sj-bg-accent); color: var(--sj-brand-700); border-color: var(--sj-border-soft); }
.sj-badge--success { background: var(--sj-success-bg); color: var(--sj-success); border-color: var(--sj-success-border); }
.sj-badge--warning { background: var(--sj-warning-bg); color: var(--sj-warning); border-color: var(--sj-warning-border); }
.sj-badge--danger { background: var(--sj-danger-bg); color: var(--sj-danger); border-color: var(--sj-danger-border); }

/* ---------------------------------------------------------------------------
   13. Tillgänglighet – visuellt dold text (alltid tillgänglig på alla sidor)
   ------------------------------------------------------------------------ */
/* .visually-hidden is an alias, not a second implementation. home.css used to
   carry its own weaker copy where only `position` was !important, so the
   `width: 1px` lost to the form layer's select sizing: on the signed-in home
   page #review-rating ended up position:absolute, left:724px and 1280px WIDE,
   dragging the document 723px open at every viewport size. That was the
   "everything is going outside the width" in responsive mode. */
.sr-only,
.visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* ---------------------------------------------------------------------------
   14. Rörelse: respektera användarens inställning
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .sj-card,
  .sj-readmore__content,
  .sj-progress__fill,
  .sj-strength__fill,
  input[type="radio"]::before,
  input[type="checkbox"]::before {
    transition: none !important;
  }
  .sj-card--interactive:hover,
  a.sj-card:hover {
    transform: none;
  }
}

/* ==========================================================================
   Cookie consent — banner, settings dialog and the declaration table.

   These rules used to live in a single <style> block inside
   assets/partials/sj-prefs.html, which meant they existed in no
   stylesheet at all: hardcoded #111 banner, #fff dialog, #666 notes, #f0f0f0
   borders. The consent UI was therefore the one surface on the site that
   ignored the theme completely — a black bar and a white dialog on top of a
   slate page. Everything below is tokenised, so it follows both themes.
   ========================================================================== */

.sj-prefs-bar {
  position: fixed;
  z-index: var(--sj-z-toast);
  left: 0;
  right: 0;
  bottom: 0;
  display: none;
  padding: var(--sj-space-4);
  background: var(--sj-surface);
  color: var(--sj-text);
  border-top: 1px solid var(--sj-border);
  box-shadow: 0 -4px 24px var(--sj-shadow-color);
}

.sj-prefs-bar.show { display: block; }

/* Sit above the mobile bottom nav rather than on top of it.

   Both are position:fixed at bottom:0, and the bar wins on z-index (--sj-z-toast
   is 1200, the nav is 1000). At 390px the consent banner is 234px tall and the
   nav band is 57px, so the nav was completely swallowed: elementFromPoint at the
   nav's centre returned the banner's button. The nav was present, painted, and
   entirely un-tappable until consent was dismissed — which is exactly the
   "where is the bottom nav" report.

   The same arrangement already exists for the side panel (nav.css:656) and for
   toasts (ui.css:297); the consent bar was simply never included in it.

   :not(.offcanvas-open) because the nav hides itself while the hamburger panel
   is open — without that, the bar would be lifted over empty space. */
body.has-mobile-bottom-nav:not(.offcanvas-open):not(.ov-sidepanel-open) .sj-prefs-bar {
  bottom: var(--mobile-nav-offset, 0px);
}

/* The banner is fixed to the bottom of the viewport; the settings dialog is
   centred over it. Without this the bar sat on top of the dialog's own
   Save/Cancel row. sj-prefs.js adds the class on open and removes it on close,
   so a visitor who cancels without choosing gets the banner back. */
.sj-prefs-bar.modal-open { display: none !important; }

.sj-prefs-bar .inner {
  max-width: var(--sj-container);
  margin: 0 auto;
  display: flex;
  gap: var(--sj-space-4);
  align-items: center;
  flex-wrap: wrap;
}

.sj-prefs-bar p {
  margin: 0;
  flex: 1 1 420px;
  font-size: var(--sj-text-sm);
  line-height: var(--sj-leading-normal);
  color: var(--sj-text-secondary);
}

.sj-prefs-bar .actions {
  display: flex;
  gap: var(--sj-space-2);
  align-items: center;
  flex-wrap: wrap;
}

/* Shared button shapes for both the banner and the dialog. */
.sj-prefs-bar .btn,
.sj-prefs-dialog .btn {
  background: var(--sj-brand);
  color: var(--sj-text-on-brand);
  border: 1px solid transparent;
  padding: 0.625rem 1rem;
  border-radius: var(--sj-radius-sm);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--sj-text-sm);
  font-weight: 600;
  transition: background var(--sj-duration-fast) var(--sj-ease);
}

.sj-prefs-bar .btn:hover,
.sj-prefs-dialog .btn:hover { background: var(--sj-brand-dark); }

.sj-prefs-bar .btn.secondary,
.sj-prefs-dialog .btn.secondary {
  background: var(--sj-surface);
  color: var(--sj-text);
  border-color: var(--sj-border-strong);
}

.sj-prefs-bar .btn.secondary:hover,
.sj-prefs-dialog .btn.secondary:hover { background: var(--sj-bg-muted); }

.sj-prefs-bar .btn.link,
.sj-prefs-dialog .btn.link {
  background: transparent;
  color: var(--sj-brand);
  border-color: transparent;
  text-decoration: underline;
}

.sj-prefs-bar .btn.link:hover,
.sj-prefs-dialog .btn.link:hover {
  background: var(--sj-brand-tint);
}

.sj-prefs-bar .btn:focus-visible,
.sj-prefs-dialog .btn:focus-visible {
  outline: var(--sj-focus-width) solid var(--sj-focus-color);
  outline-offset: var(--sj-focus-offset);
}

.btn.small { padding: 0.375rem 0.625rem; font-size: var(--sj-text-xs); }

/* ---- Settings dialog ---------------------------------------------------- */

.sj-prefs-veil {
  position: fixed;
  inset: 0;
  display: none;
  z-index: var(--sj-z-overlay);
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* Laid out the way the TCG Collection Manager consent modal is: a fixed column
   whose middle section scrolls, so the header and the actions stay put however
   long the declaration gets. The dialog itself used to be the scroller, which
   pushed the Save button off the bottom of the screen as soon as a category was
   expanded. */
.sj-prefs-dialog {
  position: fixed;
  z-index: var(--sj-z-modal);
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: none;
  flex-direction: column;
  width: min(680px, 94vw);
  max-height: 92vh;
  overflow: hidden;
  background: var(--sj-surface);
  color: var(--sj-text);
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius-lg);
  box-shadow: var(--sj-shadow-xl);
}

/* openModal() sets display:block inline. Restore the column layout without
   fighting it for specificity — the inline style wins on `display`, so the
   scrolling body has to work under both values. */
.sj-prefs-dialog[style*="display: block"],
.sj-prefs-dialog[style*="display:block"] { display: flex !important; }

.sj-prefs-dialog header {
  padding: var(--sj-space-4) var(--sj-space-5);
  border-bottom: 1px solid var(--sj-border);
  display: flex;
  align-items: flex-start;
  gap: var(--sj-space-3);
  justify-content: space-between;
  flex-shrink: 0;
}

.sj-prefs-dialog__ident {
  display: flex;
  align-items: flex-start;
  gap: var(--sj-space-3);
  min-width: 0;
}

/* Tinted round badge, as in the reference. */
.sj-prefs-dialog__badge {
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: color-mix(in srgb, var(--sj-brand) 14%, transparent);
  color: var(--sj-brand);
}

.sj-prefs-dialog__badge svg { width: 20px; height: 20px; }

.sj-prefs-dialog__headings { min-width: 0; }

.sj-prefs-dialog h3 {
  margin: 0;
  font-size: var(--sj-text-lg);
  color: var(--sj-text-heading);
}

.sj-prefs-dialog__sub {
  margin: 0.15rem 0 0;
  font-size: var(--sj-text-xs);
  color: var(--sj-text-muted);
}

.sj-prefs-dialog__tools {
  display: flex;
  align-items: center;
  gap: var(--sj-space-2);
  flex-shrink: 0;
}

.sj-prefs-dialog__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: var(--sj-radius-sm);
  background: transparent;
  color: var(--sj-text-muted);
  cursor: pointer;
}

.sj-prefs-dialog__close svg { width: 18px; height: 18px; }

.sj-prefs-dialog__close:hover {
  background: var(--sj-bg-muted);
  color: var(--sj-text);
}

.sj-prefs-dialog__close:focus-visible {
  outline: var(--sj-focus-width) solid var(--sj-focus-color);
  outline-offset: var(--sj-focus-offset);
}

/* The body is the only scroller, and it sits on the page ground so the category
   cards read as raised surfaces against it. */
.sj-prefs-dialog .content {
  padding: var(--sj-space-4) var(--sj-space-5);
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
  background: var(--sj-bg);
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-3);
}

.sj-prefs-dialog footer {
  display: flex;
  gap: var(--sj-space-3);
  justify-content: flex-end;
  padding: var(--sj-space-4) var(--sj-space-5);
  border-top: 1px solid var(--sj-border);
  background: var(--sj-bg-muted);
  flex-shrink: 0;
}

.sj-prefs-dialog .lang select { font-size: var(--sj-text-sm); }

.sj-prefs-dialog .lang select {
  padding: 0.375rem 0.5rem;
  border: 1px solid var(--sj-input-border);
  border-radius: var(--sj-radius-sm);
  background: var(--sj-input-bg);
  color: var(--sj-text);
  font-family: inherit;
}

/* ---- One category row --------------------------------------------------- */

/* Each category is a card, not a table row: title, description, a "show
   details" disclosure and the switch. Same shape as the reference's
   ConsentRow. */
/* Grid, not flex-wrap: the switch must stay beside the title at every width.
   With flex it dropped onto its own line as soon as the text column got tight
   — around 400px — and sat left-aligned under the description. */
.sj-prefs-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--sj-space-3);
  padding: var(--sj-space-4);
  background: var(--sj-surface);
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius);
}

.sj-prefs-row__main { min-width: 0; }

.sj-prefs-row label {
  font-weight: 600;
  color: var(--sj-text-heading);
  display: block;
  font-size: var(--sj-text-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Disclosure that reveals exactly what the category stores. */
.sj-prefs-row__more {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: var(--sj-space-2);
  padding: 0;
  border: 0;
  background: none;
  color: var(--sj-brand);
  font: inherit;
  font-size: var(--sj-text-xs);
  font-weight: 600;
  cursor: pointer;
}

.sj-prefs-row__more svg {
  width: 13px;
  height: 13px;
  transition: transform var(--sj-duration-fast) var(--sj-ease);
}

.sj-prefs-row__more[aria-expanded="true"] svg { transform: rotate(180deg); }

.sj-prefs-row__more:hover { text-decoration: underline; }

.sj-prefs-row__more:focus-visible {
  outline: var(--sj-focus-width) solid var(--sj-focus-color);
  outline-offset: var(--sj-focus-offset);
  border-radius: var(--sj-radius-xs);
}

/* The list is a third flex item on its own line, so it spans the full card
   width under both the text and the switch. */
.sj-prefs-row__items {
  grid-column: 1 / -1;
  min-width: 0;
  list-style: none;
  margin: 0;
  padding: var(--sj-space-3) 0 0;
  border-top: 1px solid var(--sj-border);
  counter-reset: sj-prefs-item;
}

.sj-prefs-row__items[hidden] { display: none; }

/* Number in the first column, name and description stacked in the second.
   A flex row would have put the two paragraphs side by side. */
.sj-prefs-row__items > li {
  display: grid;
  grid-template-columns: 1.1rem minmax(0, 1fr);
  column-gap: 0.6rem;
  padding-top: var(--sj-space-2);
}

.sj-prefs-row__items > li::before {
  counter-increment: sj-prefs-item;
  content: counter(sj-prefs-item) ".";
  font-size: var(--sj-text-xs);
  font-weight: 600;
  color: var(--sj-brand);
}

.sj-prefs-item__name,
.sj-prefs-item__desc {
  grid-column: 2;
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

.sj-prefs-item__name {
  font-size: var(--sj-text-xs);
  font-weight: 600;
  color: var(--sj-text);
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}

.sj-prefs-item__desc {
  margin-top: 0.15rem;
  font-size: var(--sj-text-xs);
  color: var(--sj-text-muted);
  line-height: var(--sj-leading-normal);
}

.sj-prefs-row__items code {
  background: var(--sj-bg-muted);
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius-xs);
  padding: 1px 4px;
  font-family: var(--sj-font-mono);
  font-size: 0.92em;
  font-weight: 500;
  color: var(--sj-text);
}

.sj-prefs-note {
  font-size: var(--sj-text-xs);
  color: var(--sj-text-muted);
  margin-top: 0.25rem;
  line-height: var(--sj-leading-normal);
}

/* Switch. Locked categories render disabled rather than absent, so the user can
   see that "necessary" exists and why it cannot be turned off. */
.sj-prefs-switch {
  appearance: none;
  -webkit-appearance: none;
  flex-shrink: 0;
  width: 44px;
  height: 24px;
  margin: 0;
  border-radius: var(--sj-radius-pill);
  background: var(--sj-border-strong);
  border: none;
  position: relative;
  outline: none;
  cursor: pointer;
  transition: background var(--sj-duration-fast) var(--sj-ease);
}

.sj-prefs-switch:checked { background: var(--sj-brand); }

.sj-prefs-switch:disabled { cursor: not-allowed; opacity: 0.55; }

.sj-prefs-switch::before {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  transition: left var(--sj-duration-fast) var(--sj-ease);
}

.sj-prefs-switch:checked::before { left: 23px; }

.sj-prefs-switch:focus-visible {
  outline: var(--sj-focus-width) solid var(--sj-focus-color);
  outline-offset: var(--sj-focus-offset);
}

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

.sj-prefs-details { margin-top: var(--sj-space-2); padding-top: var(--sj-space-3); display: none; }
.sj-prefs-details.show { display: block; }

.sj-prefs-details .details-body {
  max-height: 42vh;
  overflow: auto;
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius);
  padding: var(--sj-space-3);
}

.cc-table { width: 100%; border-collapse: collapse; font-size: var(--sj-text-sm); }

.cc-table thead th {
  position: sticky;
  top: 0;
  text-align: left;
  background: var(--sj-bg-subtle);
  color: var(--sj-text-heading);
  border-bottom: 1px solid var(--sj-border);
  padding: 0.625rem 0.5rem;
  font-weight: 600;
}

.cc-table td {
  padding: 0.625rem 0.5rem;
  border-bottom: 1px solid var(--sj-border);
  vertical-align: top;
  color: var(--sj-text-secondary);
}

.cc-table tbody tr:hover td { background: var(--sj-bg-subtle); }

.cc-table code {
  background: var(--sj-bg-muted);
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius-xs);
  padding: 2px 4px;
  font-family: var(--sj-font-mono);
  font-size: 0.9em;
  color: var(--sj-text);
}

@media (max-width: 640px) {
  .sj-prefs-bar .actions { width: 100%; }
  .sj-prefs-bar .actions .btn { flex: 1 1 auto; }
  .cc-table { font-size: var(--sj-text-xs); }
}

/* The details/reset row is not a category, so it carries no card surface. */
.sj-prefs-row--actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  padding: 0 var(--sj-space-1);
  background: none;
  border: 0;
  border-radius: 0;
}

/* ---- Bottom sheet on small screens -------------------------------------- */

@media (max-width: 640px) {
  .sj-prefs-dialog {
    left: 0;
    top: auto;
    bottom: 0;
    transform: none;
    width: 100%;
    max-width: 100%;
    max-height: 92vh;
    border-width: 1px 0 0;
    border-radius: var(--sj-radius-lg) var(--sj-radius-lg) 0 0;
  }

  .sj-prefs-dialog header,
  .sj-prefs-dialog .content,
  .sj-prefs-dialog footer { padding-inline: var(--sj-space-4); }

  /* "Cookieinställningar" was breaking mid-word because the language select
     took most of the row. Shrink both rather than hyphenating the title. */
  .sj-prefs-dialog h3 {
    font-size: var(--sj-text-base);
    overflow-wrap: normal;
    word-break: normal;
    hyphens: none;
  }

  .sj-prefs-dialog__badge { width: 32px; height: 32px; }
  .sj-prefs-dialog__badge svg { width: 17px; height: 17px; }

  .sj-prefs-dialog .lang select {
    max-width: 6.5rem;
    padding-inline: 0.35rem;
    font-size: var(--sj-text-xs);
  }

  /* Stacked, and the primary action first so it is nearest the thumb. */
  .sj-prefs-dialog footer { flex-direction: column-reverse; }
  .sj-prefs-dialog footer .btn { width: 100%; }
}

/* At the narrowest widths the switch would squeeze the title to a couple of
   characters per line. Give it its own row instead. */
@media (max-width: 380px) {
  .sj-prefs-row { padding: var(--sj-space-3); }
  .sj-prefs-dialog__tools .lang { display: none; }
}

.sj-prefs-details h4 {
  margin: 0.875rem 0 0.5rem;
  font-size: var(--sj-text-sm);
  color: var(--sj-text-heading);
}

.sj-prefs-details h4:first-child { margin-top: 0.25rem; }

.sj-prefs-details ul {
  margin: 0.375rem 0 0 1.125rem;
  padding: 0;
  font-size: var(--sj-text-xs);
  color: var(--sj-text-muted);
  line-height: var(--sj-leading-normal);
}

.sj-prefs-details .cc-table { margin-top: 0.5rem; }

/* ---- /cookie-settings.html ---------------------------------------------- */

.sj-prefs-wrap {
  min-height: 50vh;
  padding: var(--sj-space-6) var(--sj-space-4) var(--sj-space-12);
  max-width: var(--sj-container-narrow);
  margin: 0 auto;
}

.sj-prefs-intro {
  color: var(--sj-text-secondary);
  line-height: var(--sj-leading-normal);
  max-width: 62ch;
}

.sj-prefs-card {
  padding: var(--sj-space-5);
  margin: var(--sj-space-6) 0;
}

.sj-prefs-actions {
  display: flex;
  gap: var(--sj-space-3);
  justify-content: flex-end;
  flex-wrap: wrap;
  margin-top: var(--sj-space-4);
}

.sj-prefs-actions .btn {
  background: var(--sj-brand);
  color: var(--sj-text-on-brand);
  border: 1px solid transparent;
  padding: 0.625rem 1.125rem;
  border-radius: var(--sj-radius-sm);
  font-family: inherit;
  font-size: var(--sj-text-sm);
  font-weight: 600;
  cursor: pointer;
}

.sj-prefs-actions .btn:hover { background: var(--sj-brand-dark); }

.sj-prefs-actions .btn.secondary {
  background: var(--sj-surface);
  color: var(--sj-text);
  border-color: var(--sj-border-strong);
}

.sj-prefs-actions .btn.secondary:hover { background: var(--sj-bg-muted); }

.sj-prefs-status {
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity var(--sj-duration) var(--sj-ease), transform var(--sj-duration) var(--sj-ease);
  font-size: var(--sj-text-sm);
  font-weight: 600;
  margin-bottom: var(--sj-space-3);
  min-height: 1.25rem;
  color: var(--sj-success);
}

.sj-prefs-status.is-visible { opacity: 1; transform: none; }
.sj-prefs-status[data-tone='error'] { color: var(--sj-danger); }

.sj-prefs-h2 {
  margin-top: var(--sj-space-10);
  margin-bottom: var(--sj-space-2);
  font-size: var(--sj-text-xl);
  color: var(--sj-text-heading);
}

@media (prefers-reduced-motion: reduce) {
  .sj-prefs-status { transition: none; }
}

/* The policy link used to carry style="color:#7fb7ff" inline in the partial,
   which was the only thing colouring it. Now it is a token. */
.sj-prefs-bar a,
.sj-prefs-dialog a {
  color: var(--sj-brand);
  text-decoration: underline;
}

.sj-prefs-bar a:hover,
.sj-prefs-dialog a:hover { color: var(--sj-brand-dark); }

/* ---- Card families -------------------------------------------------------
   The site grew a dozen card class names over time, each with its own hover
   (or none at all), which is why hovering felt inconsistent — some lifted, some
   glowed, most did nothing. They all share the one definition now.

   Listed explicitly rather than applied with a wildcard so that adding a class
   called "…card…" does not silently inherit a surface it was not designed for. */
.home-value-card,
.stat-card,
.shop-stat-card,
.info-card,
.ov-include-card,
.ov-fact-card,
.testimonial-card,
.shop-sidebar-card,
.subscription-card,
.auth-card,
.course-card,
.shop-card,
.forum-card {
  min-width: 0;
  overflow-wrap: anywhere;
  transition: box-shadow var(--sj-duration) var(--sj-ease),
              border-color var(--sj-duration) var(--sj-ease),
              transform var(--sj-duration) var(--sj-ease-out);
}

.home-value-card > *,
.stat-card > *,
.shop-stat-card > *,
.info-card > *,
.ov-include-card > *,
.ov-fact-card > *,
.testimonial-card > *,
.shop-sidebar-card > *,
.subscription-card > *,
.auth-card > *,
.course-card > *,
.shop-card > *,
.forum-card > * { min-width: 0; max-width: 100%; }

.home-value-card:hover,
.stat-card:hover,
.shop-stat-card:hover,
.info-card:hover,
.ov-include-card:hover,
.ov-fact-card:hover,
.testimonial-card:hover,
.shop-sidebar-card:hover,
.subscription-card:hover,
.course-card:hover,
.shop-card:hover,
.forum-card:hover {
  border-color: color-mix(in srgb, var(--sj-brand) 30%, var(--sj-border));
  box-shadow:
    var(--sj-shadow-lg),
    0 0 0 1px color-mix(in srgb, var(--sj-brand) 25%, transparent),
    0 0 20px -6px color-mix(in srgb, var(--sj-brand) 40%, transparent);
}

/* The auth card is a page-level container, not something you point at — it gets
   the containment and the surface, but no hover. */

a.course-card:hover,
a.shop-card:hover,
a.home-value-card:hover { transform: translateY(-2px); }

@media (prefers-reduced-motion: reduce) {
  a.course-card:hover,
  a.shop-card:hover,
  a.home-value-card:hover { transform: none; }
}


}

/* =============================================================================
   Cart drawer.

   Ported from nordic-storium (src/styles/Cart.css): an overlay plus a
   right-hand drawer, max 450px wide, full width below 480px, sliding in with
   transform over cubic-bezier(0.16, 1, 0.3, 1). The header cart button opens
   this instead of navigating; only "Till kassan" leaves the page.
   ========================================================================== */
.sj-cart-overlay {
  position: fixed;
  inset: 0;
  z-index: 1190;
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0;
  transition: opacity var(--sj-duration-slow) var(--sj-ease);
}

.sj-cart-overlay.is-open { opacity: 1; }

.sj-cart-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 1200;
  display: flex;
  flex-direction: column;
  /* 100vw rather than 100%: while the drawer is open the body is fixed and
     html reserves a scrollbar gutter, so a percentage width would leave the
     drawer a scrollbar's width short of the screen edge. It is position:fixed
     and right-anchored, so using the full visual viewport cannot cause overflow. */
  width: min(450px, 100vw);
  background: var(--sj-surface);
  color: var(--sj-text);
  border-left: 1px solid var(--sj-border);
  box-shadow: -4px 0 24px var(--sj-shadow-color);
  transform: translateX(100%);
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  visibility: hidden;
}

.sj-cart-drawer.is-open { transform: translateX(0); visibility: visible; }

@media (max-width: 480px) {
  .sj-cart-drawer { width: 100vw; }
}

.sj-cart-drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sj-space-3);
  padding: var(--sj-space-4) var(--sj-space-5);
  border-bottom: 1px solid var(--sj-border);
  flex-shrink: 0;
}

.sj-cart-drawer__title {
  margin: 0;
  font-size: var(--sj-text-lg);
  font-weight: 700;
  color: var(--sj-text-heading);
}

.sj-cart-drawer__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--sj-space-4) var(--sj-space-5);
}

.sj-cart-drawer__foot {
  flex-shrink: 0;
  padding: var(--sj-space-4) var(--sj-space-5) calc(var(--sj-space-5) + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--sj-border);
  background: var(--sj-surface);
}

.sj-cart-drawer__sum {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--sj-space-3);
  font-size: var(--sj-text-sm);
  color: var(--sj-text-secondary);
}

.sj-cart-drawer__sum strong {
  font-size: var(--sj-text-xl);
  font-weight: 800;
  color: var(--sj-text-heading);
}

.sj-cart-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sj-space-4); }

.sj-cart-item {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) auto;
  gap: var(--sj-space-3);
  align-items: start;
  padding-bottom: var(--sj-space-4);
  border-bottom: 1px solid var(--sj-border);
}

.sj-cart-item:last-child { border-bottom: 0; padding-bottom: 0; }

.sj-cart-item__img {
  width: 56px;
  height: 56px;
  border-radius: var(--sj-radius-sm);
  object-fit: cover;
  background: var(--sj-bg-muted);
  border: 1px solid var(--sj-border);
}

.sj-cart-item__img--empty {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--sj-text-muted);
}

.sj-cart-item__main { min-width: 0; }

.sj-cart-item__name {
  margin: 0 0 0.15rem;
  font-size: var(--sj-text-sm);
  font-weight: 600;
  color: var(--sj-text);
  overflow-wrap: anywhere;
}

.sj-cart-item__price,
.sj-cart-item__note {
  margin: 0;
  font-size: var(--sj-text-xs);
  color: var(--sj-text-muted);
}

.sj-cart-item__qty {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.4rem;
  font-size: var(--sj-text-sm);
  font-weight: 600;
}

.btn-icon--sm { width: 28px; height: 28px; font-size: 1rem; line-height: 1; }

.sj-cart-item__end {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.4rem;
}

.sj-cart-item__line {
  font-size: var(--sj-text-sm);
  font-weight: 700;
  color: var(--sj-text);
  white-space: nowrap;
}

.sj-cart-item__remove {
  display: inline-flex;
  padding: 0.25rem;
  border: 0;
  border-radius: var(--sj-radius-xs);
  background: transparent;
  color: var(--sj-text-muted);
  cursor: pointer;
}

.sj-cart-item__remove:hover { color: var(--sj-danger); background: var(--sj-danger-tint); }
.sj-cart-item__remove .sj-icon { width: 16px; height: 16px; }

.sj-cart-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sj-space-3);
  padding: var(--sj-space-12) var(--sj-space-4);
  text-align: center;
  color: var(--sj-text-muted);
}

.sj-cart-empty__icon { color: var(--sj-border-strong); }
.sj-cart-empty__icon .sj-icon { width: 48px; height: 48px; }
.sj-cart-loading { color: var(--sj-text-muted); font-size: var(--sj-text-sm); }

@media (prefers-reduced-motion: reduce) {
  .sj-cart-drawer, .sj-cart-overlay { transition: none; }
}

/* ===== page.css ==================================================== */
/* ==========================================================================
   The page shell — one layout for every public page.
   ==========================================================================

   Before this file the site had seven container widths and six wrapper class
   names for the same job: 1400px (.shop-container), 1200px (.center-wrap,
   .info-grid), 1180px (the breadcrumb, alone), 1120px (footer inner), 1100px
   (cart, in an inline <style>), 1080px (.ov-section), 900px (.info-content),
   760px (.sj-prefs-wrap, .not-found-main) and 680px (order confirmation, also
   inline). <main> was used four incompatible ways, including not at all on two
   pages.

   Every public page now uses `<main class="page">`, and the width comes from
   --sj-container, the token that already existed in tokens.css and that almost
   nothing used.

   Variants:
     .page--narrow   prose-only pages that want the 760px measure
     .page__prose    a readable column inside the full-width frame
     .page__grid     sticky table of contents + article (the legal pages)
   ========================================================================== */

.page {
  width: 100%;
  max-width: var(--sj-container);
  margin-inline: auto;
  /* The gutter grows with the viewport instead of stopping at a fixed 2rem,
     which is what made the shop look edge-to-edge on a laptop. */
  padding-inline: clamp(1rem, 4vw, 2.5rem);
  padding-block: clamp(1.25rem, 3vw, 2.5rem) clamp(2rem, 5vw, 4rem);
  box-sizing: border-box;
}

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

/* Flush variant for pages that paint their own full-bleed sections (the
   homepage, the quiz landing pages). They keep the shared <main class="page">
   so the shell is uniform, but opt out of the column. */
.page--bleed {
  max-width: none;
  padding-inline: 0;
  padding-block: 0;
}

/* ---- Page head ----------------------------------------------------------
   Breadcrumb, title, optional meta row, optional lead. Modelled on the TCG
   legal-page header: a tinted icon chip beside the title, a muted metadata
   line, then a lead capped at a readable measure. */

.page__head {
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
  padding-bottom: var(--sj-space-6);
  border-bottom: 1px solid var(--sj-border);
}

.page__head--plain {
  padding-bottom: 0;
  border-bottom: 0;
}

.page__title-row {
  display: flex;
  align-items: center;
  gap: var(--sj-space-3);
  min-width: 0;
}

.page__icon {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--sj-radius);
  background: color-mix(in srgb, var(--sj-brand) 12%, transparent);
  color: var(--sj-brand);
}

.page__icon svg { width: 22px; height: 22px; }

.page__title {
  margin: 0;
  min-width: 0;
  font-size: clamp(1.5rem, 3.4vw, 2rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: var(--sj-leading-tight, 1.2);
  color: var(--sj-text-heading);
}

.page__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sj-space-2) var(--sj-space-5);
  margin-top: var(--sj-space-3);
  font-size: var(--sj-text-sm);
  color: var(--sj-text-muted);
}

.page__meta strong {
  font-weight: 600;
  color: var(--sj-text-secondary);
}

.page__lead {
  max-width: 68ch;
  margin: var(--sj-space-3) 0 0;
  font-size: var(--sj-text-base);
  line-height: var(--sj-leading-relaxed, 1.7);
  color: var(--sj-text-secondary);
}

/* ---- Body ---------------------------------------------------------------- */

.page__prose { max-width: 72ch; }

.page__prose > * + * { margin-top: var(--sj-space-4); }

.page__prose h2 {
  margin-top: var(--sj-space-10);
  margin-bottom: var(--sj-space-3);
  font-size: var(--sj-text-lg);
  font-weight: 700;
  color: var(--sj-text-heading);
  padding-bottom: var(--sj-space-2);
  border-bottom: 1px solid var(--sj-border);
}

.page__prose h3 {
  margin-top: var(--sj-space-6);
  margin-bottom: var(--sj-space-2);
  font-size: var(--sj-text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--sj-text-muted);
}

.page__prose p,
.page__prose li {
  line-height: var(--sj-leading-relaxed, 1.7);
  color: var(--sj-text-secondary);
}

.page__prose ul,
.page__prose ol {
  padding-left: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-2);
}

/* Anchors that are not buttons. `.page__prose a` used to match .btn too, and
   page.css is bundled after components.css, so a link-styled colour landed on
   top of the button's own — .btn--primary ended up with color identical to its
   background and the label was invisible in both themes. */
.page__prose a:not([class]),
.page__prose a.info-btn-quiet { color: var(--sj-brand); }

.page__prose strong { color: var(--sj-text); }

/* ---- Two-column: sticky contents + article ------------------------------- */

.page__grid {
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  gap: var(--sj-space-8);
  align-items: start;
}

@media (max-width: 900px) {
  .page__grid { grid-template-columns: minmax(0, 1fr); }
  .page__aside { display: none; }
}

.page__aside { min-width: 0; }

.page__toc {
  position: sticky;
  /* Clear the sticky header, or anchor targets land underneath it. */
  top: calc(var(--sj-header-height, 64px) + var(--sj-space-4));
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sj-space-4);
  background: var(--sj-surface);
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius);
}

.page__toc-title {
  margin: 0 0 var(--sj-space-2);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--sj-text-muted);
}

.page__toc a {
  display: block;
  padding: 0.3rem 0.5rem;
  border-radius: var(--sj-radius-xs);
  font-size: var(--sj-text-sm);
  color: var(--sj-text-secondary);
  text-decoration: none;
  transition: background-color var(--sj-duration-fast) var(--sj-ease),
              color var(--sj-duration-fast) var(--sj-ease);
}

.page__toc a:hover {
  background: var(--sj-bg-muted);
  color: var(--sj-text);
}

.page__article > section + section { margin-top: var(--sj-space-10); }

.page__article section {
  /* Anchor links from the contents list must not hide under the header. */
  scroll-margin-top: calc(var(--sj-header-height, 64px) + var(--sj-space-4));
}

/* ---- Callout ------------------------------------------------------------
   The three tints from the TCG legal pages, for the disclaimers that are
   currently buried mid-paragraph. */

.notice {
  margin-top: var(--sj-space-4);
  padding: var(--sj-space-4);
  border-radius: var(--sj-radius);
  border: 1px solid;
  font-size: var(--sj-text-sm);
  line-height: var(--sj-leading-relaxed, 1.7);
}

.notice--info {
  background: color-mix(in srgb, var(--sj-brand) 8%, transparent);
  border-color: color-mix(in srgb, var(--sj-brand) 30%, transparent);
}

.notice--warning {
  background: color-mix(in srgb, #f59e0b 10%, transparent);
  border-color: color-mix(in srgb, #f59e0b 35%, transparent);
}

.notice--positive {
  background: color-mix(in srgb, #22c55e 10%, transparent);
  border-color: color-mix(in srgb, #22c55e 30%, transparent);
}


/* ---- FAQ accordion ------------------------------------------------------
   These rules lived in footer.css, because the questions used to be a shared
   partial that the footer area owned. They are page content, so they live with
   the page shell now. Native <details>/<summary> — no JS.

   `.site-faq-more` went with them: it was the "Se kurser i butiken →" link
   sitting directly above the back link, two plain links in a row saying
   different things. */

/* Centred column: the FAQ is a list people scan, so it reads better centred in
   the page frame than pinned to the left margin. */
.page__prose--center { margin-inline: auto; }

/* Each category is itself a disclosure, so a whole group can be folded away. */
.faq-group { margin: 0; }
.faq-group + .faq-group { margin-top: var(--sj-space-6); }

.faq-group__title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 var(--sj-space-3);
  padding: 0;
  font-size: var(--sj-text-sm);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--sj-text-muted);
  cursor: pointer;
  list-style: none;
}

.faq-group__title::-webkit-details-marker { display: none; }
.faq-group__title::marker { content: ""; }

/* Chevron, rotated when the group is open. */
.faq-group__title::after {
  content: "";
  width: 8px;
  height: 8px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transform-origin: center;
  margin-top: -4px;
  transition: transform var(--sj-duration-fast) var(--sj-ease);
}

.faq-group[open] > .faq-group__title::after { transform: rotate(-135deg); margin-top: 2px; }

.faq-group__title:hover { color: var(--sj-text); }

.faq-group__title:focus-visible {
  outline: var(--sj-focus-width) solid var(--sj-focus-color);
  outline-offset: 3px;
  border-radius: var(--sj-radius-xs);
}

/* ===== Site footer chrome (FAQ + expanded footer) ===== */

.site-footer-chrome {
  margin-top: auto;
  width: 100%;
  align-self: stretch;
}

/* ---------- FAQ ---------- */
.faq {
  background: var(--sj-surface);
  border-top: 1px solid var(--sj-border);
  padding: clamp(1.75rem, 4vw, 2.75rem) 1.25rem;
}

.faq-inner {
  max-width: 760px;
  margin: 0 auto;
  text-align: center;
}

.faq-eyebrow {
  margin: 0 0 .5rem;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--sj-brand);
}

.faq-title {
  margin: 0 0 1.25rem;
  font-size: clamp(1.35rem, 3vw, 1.65rem);
  font-weight: 800;
  color: var(--sj-text);
  line-height: 1.2;
}

.faq-list {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  text-align: left;
}

.faq-item {
  border: 1px solid var(--sj-border);
  border-radius: .85rem;
  background: var(--sj-surface);
  overflow: hidden;
  transition: border-color .15s ease, box-shadow .15s ease;
}

.faq-item[open] {
  border-color: var(--sj-brand-200);
  box-shadow: var(--sj-shadow-hover);
}

.faq-item summary {
  list-style: none;
  list-style-type: none;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.8rem 1rem;
  font-weight: 700;
  color: var(--sj-text);
  font-size: 0.9rem;
  line-height: 1.35;
}

.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::marker { content: ""; display: none; }

.faq-item summary::after {
  content: "→";
  flex-shrink: 0;
  color: var(--sj-text-muted);
  font-size: 1.1rem;
  transition: transform .2s ease, color .2s ease;
}

.faq-item[open] summary::after {
  transform: rotate(90deg);
  color: var(--sj-brand);
}

.faq-item summary:hover {
  color: var(--sj-brand-dark);
}

/* Färgbyte räcker inte som fokusmarkör (WCAG 1.4.1) – behåll ramen */
.faq-item summary:focus-visible {
  color: var(--sj-brand-dark);
  outline: var(--sj-focus-width, 3px) solid var(--sj-focus-color, var(--sj-brand-dark));
  outline-offset: var(--sj-focus-offset, 2px);
  border-radius: var(--sj-radius-sm, 8px);
}

.faq-answer {
  padding: 0 1rem 0.9rem;
  color: var(--sj-text-secondary);
  font-size: 0.875rem;
  line-height: 1.55;
}

.faq-answer p {
  margin: 0;
}

.faq-answer a {
  color: var(--sj-brand);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ---- Dark theme: no blue body text --------------------------------------
   Headings, labels and links all read as near-white or grey; only the
   underline marks a link. Brand blue stays where it is a surface (buttons,
   the active nav pill), never as running text. */

html.dark .page__prose a:not([class]),
body.dark .page__prose a:not([class]),
html.dark .page__prose a.info-btn-quiet,
body.dark .page__prose a.info-btn-quiet,
html.dark .sj-breadcrumb a,
body.dark .sj-breadcrumb a,
html.dark .page__toc a,
body.dark .page__toc a {
  color: var(--sj-text);
  text-decoration-color: var(--sj-border-strong);
}

html.dark .page__prose a:not([class]),
body.dark .page__prose a:not([class]) {
  text-decoration: underline;
  text-underline-offset: 3px;
}

html.dark .page__prose strong,
body.dark .page__prose strong,
html.dark .contact-facts dt,
body.dark .contact-facts dt {
  color: var(--sj-text);
}

/* The contents list marks the current section with weight, not colour. */
html.dark .page__toc a:hover,
body.dark .page__toc a:hover { color: var(--sj-text-heading); }

/* ---- Dark: disclosure labels read as text, not as muted chrome -----------
   Every collapsible summary is a target you click, so it gets full text ink in
   dark. The "INNEHÅLL" heading above the contents list stays muted — it is a
   label, not a target. */

html.dark .faq-group__title,
body.dark .faq-group__title,
html.dark .faq-item summary,
body.dark .faq-item summary,
html.dark .sj-prefs-row__more,
body.dark .sj-prefs-row__more {
  color: var(--sj-text);
}

html.dark .faq-group__title:hover,
body.dark .faq-group__title:hover,
html.dark .sj-prefs-row__more:hover,
body.dark .sj-prefs-row__more:hover {
  color: var(--sj-text-heading);
}

/* ---- "Populärt just nu" card grid ---------------------------------------
   Was a stacked column of link-buttons capped at 28rem with no media query, so
   it stayed a narrow list even on a 1440px page. */

.home-key-pages-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: var(--sj-space-5);
  margin-top: var(--sj-space-6);
  text-align: left;
}

.home-key-card {
  display: flex;
  flex-direction: column;
  gap: var(--sj-space-2);
  padding: var(--sj-space-6);
  text-decoration: none;
  color: inherit;
}

.home-key-card__title {
  margin: 0;
  font-size: var(--sj-text-lg);
  font-weight: 700;
  color: var(--sj-text-heading);
}

.home-key-card__desc {
  margin: 0;
  color: var(--sj-text-secondary);
  line-height: var(--sj-leading-relaxed, 1.7);
}

.home-key-card__price {
  margin-top: auto;
  padding-top: var(--sj-space-3);
  font-weight: 700;
  color: var(--sj-text);
}

.home-key-card__price--link { color: var(--sj-brand); }

/* ===== breadcrumbs-public.css ====================================== */
/* Public site breadcrumbs – visible trail + page title on current crumb.
 *
 * The band is gone. These used to paint their own
 * linear-gradient(--sj-bg-page -> --sj-bg-muted) with a bottom border, which put
 * a second grey strip directly under the navbar on every sub-page. They sit on
 * the page ground now.
 *
 * Sizes come from the shared type scale instead of the one-off 0.9rem /
 * clamp(1.05rem, 2.4vw, 1.4rem) ladder they had, which matched nothing else.
 */
.sj-breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.5rem;
  margin: 0 auto;
  max-width: var(--sj-container);
  padding: var(--sj-space-4) var(--sj-space-4) var(--sj-space-2);
  font-family: var(--sj-font);
  font-size: var(--sj-text-sm);
  line-height: var(--sj-leading-snug);
  color: var(--sj-text-muted);
  background: transparent;
  border-bottom: 0;
  position: relative;
  z-index: 5;
}

.sj-breadcrumb--visible {
  width: 100%;
  box-sizing: border-box;
}

.sj-breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
  width: 100%;
}

.sj-breadcrumb li {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  min-width: 0;
}

/* Rows align on the baseline so crumb text lines up with the separators. An icon
   has no baseline worth aligning to, so the home crumb centres itself rather
   than dragging every other row off its baseline to suit it. */
.sj-breadcrumb__home {
  display: inline-flex;
  align-items: center;
  align-self: center;
  color: var(--sj-text-muted);
}

.sj-breadcrumb__home .sj-icon {
  width: 1.05em;
  height: 1.05em;
}

.sj-breadcrumb__home:hover { color: var(--sj-brand); }

.sj-breadcrumb li + li::before {
  content: "›";
  color: var(--sj-text-muted);
  font-weight: 600;
  speak-as: none;
}

[dir="rtl"] .sj-breadcrumb li + li::before {
  content: "‹";
}

/* Brödsmulorna var 20 px höga – under de 24 px som krävs för en träffyta
   (WCAG 2.5.8). På telefon blev de lätta att missa och lätta att träffa fel.
   Vertikal padding höjer ytan utan att texten flyttar sig: raden är redan
   center-justerad och padding ligger utanför textens radhöjd. */
.sj-breadcrumb a {
  color: var(--sj-brand);
  text-decoration: none;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding-block: 2px;
}

.sj-breadcrumb a:hover {
  text-decoration: underline;
  color: var(--sj-brand-dark);
}

.sj-breadcrumb a:focus-visible {
  outline: 2px solid var(--sj-brand);
  outline-offset: 2px;
  border-radius: 4px;
}

/* The current crumb used to be set at clamp(1.05rem, 2.4vw, 1.4rem) / 800 —
   larger and heavier than the page's own <h1> in some places, so the trail read
   as a second title. It is a breadcrumb: same size as the rest of the trail,
   just not muted. */
.sj-breadcrumb__current,
.sj-breadcrumb [aria-current="page"] {
  color: var(--sj-text);
  font-weight: 600;
  font-size: var(--sj-text-sm);
  line-height: var(--sj-leading-snug);
  letter-spacing: normal;
}

.shop-container > .sj-breadcrumb,
.info-content > .sj-breadcrumb,
.cart-wrapper > .sj-breadcrumb {
  max-width: none;
  margin-bottom: 0.75rem;
  border-radius: 0;
  border-left: none;
  border-right: none;
}

body > .sj-breadcrumb,
main > .sj-breadcrumb {
  margin-top: 0;
}

/* Shop product/cart legacy class names share the same look */
.shop-breadcrumb.sj-breadcrumb ol,
.cart-breadcrumb.sj-breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (max-width: 600px) {
  .sj-breadcrumb {
    font-size: 0.84rem;
    padding: 0.65rem 0.85rem 0.75rem;
  }

  .sj-breadcrumb__current,
  .sj-breadcrumb [aria-current="page"] {
    font-size: 1.05rem;
  }
}

/* Dark mode */
html.dark .sj-breadcrumb,
body.dark .sj-breadcrumb {
  color: var(--sj-text-secondary);
  background: var(--sj-bg);
  background-image: none;
  border-bottom-color: var(--sj-border);
}


html.dark .sj-breadcrumb a,
body.dark .sj-breadcrumb a {
  color: var(--sj-brand-light);
}

html.dark .sj-breadcrumb a:hover,
body.dark .sj-breadcrumb a:hover {
  color: var(--sj-brand-light);
}

/* ===== theme.css =================================================== */
/* Shared light/dark theme – public site (uses same html.dark / body.dark as courses) */

html {
  color-scheme: only light !important;
  forced-color-adjust: none;
  -webkit-forced-color-adjust: none;
}

:root {
  color-scheme: only light;
}

html.dark,
body.dark {
  color-scheme: only dark !important;
  forced-color-adjust: none;
  -webkit-forced-color-adjust: none;
}

/* Design tokens for both themes live in tokens.css (single source of truth).
   This file only carries component styles that differ between themes. */

/* Header theme toggle.
   The markup is `.sj-theme-toggle.btn-icon`, so size, surface, border, radius,
   hover and focus ring all come from .btn-icon — the same ones the cart button
   and the hamburger use. This block used to redeclare them, with
   `border-radius: var(--sj-radius-pill)` and `background: var(--sj-bg-page)`,
   which is why the toggle was a slightly-grey pill between two white squares. */
.sj-theme-toggle {
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
}

.sj-theme-toggle__icon {
  display: inline-flex;
  width: 22px;
  height: 22px;
}

.sj-theme-toggle__icon svg {
  width: 100%;
  height: 100%;
  display: block;
}

.sj-theme-toggle__icon--dark {
  display: none;
}

.sj-theme-toggle.is-dark .sj-theme-toggle__icon--light {
  display: none;
}

.sj-theme-toggle.is-dark .sj-theme-toggle__icon--dark {
  display: inline-flex;
}


.hero--public .hero-topbar .sj-theme-toggle,
.hero--landing .hero-topbar .sj-theme-toggle {
  pointer-events: auto;
}

/* Sidepanel theme control */
.sidepanel-theme {
  margin-top: auto;
  padding-top: 0.75rem;
  border-top: 1px solid rgba(255, 255, 255, 0.18);
}

.sidepanel-theme-btn {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  width: 100%;
  border: none;
  border-radius: var(--nav-radius, 10px);
  background: rgba(255, 255, 255, 0.14);
  color: var(--nav-text, var(--nav-on-brand, #f7f8fa));
  font: inherit;
  font-weight: 700;
  font-size: 1rem;
  padding: 0.65rem 0.75rem;
  cursor: pointer;
  text-align: left;
  transition: background 0.2s ease, transform 0.1s ease;
}

.sidepanel-theme-btn:hover {
  background: var(--nav-btn-hover, rgba(255, 255, 255, 0.25));
  transform: translateX(2px);
}

.sidepanel-theme-btn:focus-visible {
  outline: 2px solid var(--nav-on-brand, #f7f8fa);
  outline-offset: 2px;
}

.sidepanel-theme-btn__icon {
  display: inline-flex;
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
}

.sidepanel-theme-btn__icon svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* Public topbar (undersidor + startsida) */
html.dark .hero--landing,
html.dark .hero--public,
body.dark .hero--landing,
body.dark .hero--public {
  background: var(--sj-bg) !important;
  background-image: none !important;
  --hero-bg-band: var(--sj-bg);
  --hero-bg-body: var(--sj-bg);
}

/* --sj-surface, matching light. This forced the header back onto --sj-bg,
   which IS the page ground in dark, so the navbar had no edge at all. */
html.dark .hero--public .hero-topbar,
body.dark .hero--public .hero-topbar,
html.dark .hero--landing .hero-topbar,
body.dark .hero--landing .hero-topbar {
  background: var(--sj-surface) !important;
  border-bottom-color: var(--sj-border) !important;
}


html.dark .hero--public .hero-topbar .hero-brand-name,
body.dark .hero--public .hero-topbar .hero-brand-name,
html.dark .hero--landing .hero-topbar .hero-brand-name,
body.dark .hero--landing .hero-topbar .hero-brand-name {
  color: var(--sj-text);
}

html.dark .hero--public .hero-topbar .hero-brand-sub,
body.dark .hero--public .hero-topbar .hero-brand-sub,
html.dark .hero--landing .hero-topbar .hero-brand-sub,
body.dark .hero--landing .hero-topbar .hero-brand-sub {
  color: var(--sj-text-secondary);
}



/* Prevent Samsung/Chrome forced dark mode from inverting UI when site is in light mode */
html:not(.dark),
html:not(.dark) body {
  forced-color-adjust: none !important;
  -webkit-forced-color-adjust: none !important;
}

html:not(.dark) .hero--public .hero-topbar .hamburger,
html:not(.dark) .hero--landing .hero-topbar .hamburger,
html:not(.dark) .hero--public .hero-topbar .sj-theme-toggle,
html:not(.dark) .hero--landing .hero-topbar .sj-theme-toggle {
  forced-color-adjust: none;
}

/* forced-color-adjust only. The colour used to be set here as
   `background-color: var(--nav-ink)` — and --nav-ink is `var(--sj-surface)`
   (tokens.css:209), i.e. WHITE in light mode, so this rule painted white lines
   onto a white button. The one rule in nav.css uses var(--sj-text), which flips
   with the theme on its own. */
html:not(.dark) .hero--public .hero-topbar .hamburger .burger-lines,
html:not(.dark) .hero--public .hero-topbar .hamburger .burger-lines::before,
html:not(.dark) .hero--public .hero-topbar .hamburger .burger-lines::after,
html:not(.dark) .hero--landing .hero-topbar .hamburger .burger-lines,
html:not(.dark) .hero--landing .hero-topbar .hamburger .burger-lines::before,
html:not(.dark) .hero--landing .hero-topbar .hamburger .burger-lines::after {
  forced-color-adjust: none;
}

html.dark .hero--public .hero-cart-link,
body.dark .hero--public .hero-cart-link,
html.dark .hero--public .hero-topbar .hero-cart-link,
body.dark .hero--public .hero-topbar .hero-cart-link,
html.dark .hero--public .hero-topbar-end .hero-cart-link,
body.dark .hero--public .hero-topbar-end .hero-cart-link {
  background: var(--sj-surface) !important;
  border-color: var(--sj-border) !important;
  color: var(--sj-text) !important;
  box-shadow: none !important;
}

html.dark .hero--public .hero-cart-link:hover,
body.dark .hero--public .hero-cart-link:hover,
html.dark .hero--public .hero-topbar .hero-cart-link:hover,
body.dark .hero--public .hero-topbar .hero-cart-link:hover {
  background: var(--sj-surface-elevated) !important;
}

/* Landing page body */
html.dark.page-home,
html.dark .page-home,
body.dark.page-home {
  background: var(--sj-bg-page);
  color: var(--sj-text);
}

html.dark .page-home main,
body.dark .page-home main {
  background: var(--sj-bg-page);
}

html.dark .hero--landing .hero-marketing,
body.dark .hero--landing .hero-marketing {
  background: linear-gradient(180deg, var(--sj-bg) 0%, var(--sj-bg-muted) 100%);
  color: var(--sj-text);
}

/* The hero band is BLUE in dark mode too — the gradient further down this file
   (html.dark .hero--landing .hero-marketing, with !important) wins over the flat
   slate fill declared above. These text colours used to be picked for that
   losing flat fill: --sj-text-secondary (#94a3b8) sat on a blue gradient at
   roughly 2:1 contrast, which is why the hero copy looked washed out. Text on
   the blue band uses the on-brand ink instead, exactly as in light mode. */
html.dark .hero--landing .hero-eyebrow,
body.dark .hero--landing .hero-eyebrow {
  color: #bfdbfe;
}

html.dark .hero--landing .hero-tagline,
html.dark .hero--landing .hero-trust,
body.dark .hero--landing .hero-tagline,
body.dark .hero--landing .hero-trust {
  color: rgba(255, 255, 255, 0.86);
}

/* Home page sections */
html.dark .home-courses-showcase,
html.dark .home-key-pages,
html.dark .home-value,
html.dark .how-it-works,
html.dark .testimonials,
body.dark .home-courses-showcase,
body.dark .home-key-pages,
body.dark .home-value,
body.dark .how-it-works,
body.dark .testimonials {
  background: var(--sj-bg);
  color: var(--sj-text-heading);
}

html.dark .section-title,
html.dark .section-sub,
body.dark .section-title,
body.dark .section-sub {
  color: var(--sj-text);
}

html.dark .section-sub,
body.dark .section-sub {
  color: var(--sj-text-secondary);
}

html.dark .home-course-card,
html.dark .home-key-page-card,
html.dark .home-value-card,
html.dark .how-step,
html.dark .value-card,
html.dark .step-card,
html.dark .testimonial,
html.dark .testimonial-card,
body.dark .home-course-card,
body.dark .home-key-page-card,
body.dark .home-value-card,
body.dark .how-step,
body.dark .value-card,
body.dark .step-card,
body.dark .testimonial,
body.dark .testimonial-card {
  background: var(--sj-surface);
  border-color: var(--sj-border);
  color: var(--sj-text-heading);
}

html.dark .home-courses-carousel-shell,
html.dark .home-courses-viewport,
body.dark .home-courses-carousel-shell,
body.dark .home-courses-viewport {
  background: transparent;
}

html.dark .hero-btn-secondary,
html.dark .hero-btn-ghost,
body.dark .hero-btn-secondary,
body.dark .hero-btn-ghost {
  border-color: rgba(148, 163, 184, 0.45);
  color: var(--sj-text-heading);
}

html.dark .hero-btn-secondary:hover,
html.dark .hero-btn-ghost:hover,
body.dark .hero-btn-secondary:hover,
body.dark .hero-btn-ghost:hover {
  background: rgba(148, 163, 184, 0.12);
}

/* Forum */
html.dark,
body.dark {
  --text-primary: var(--sj-text);
  --text-secondary: var(--sj-text-secondary);
  --text-heading: var(--sj-text-heading);
  --bg-light: var(--sj-bg-muted);
  --bg-white: var(--sj-surface);
  --bg-dark: var(--sj-bg);
  --bg-darker: var(--sj-surface);
  --surface-muted: var(--sj-surface);
  --border-color: var(--sj-border);
  --border-strong: var(--sj-border-strong);
}

html.dark .forum-card,
html.dark .forum-post,
html.dark .forum-sidebar-card,
html.dark .forum-filter-bar,
body.dark .forum-card,
body.dark .forum-post,
body.dark .forum-sidebar-card,
body.dark .forum-filter-bar {
  background: var(--sj-surface);
  border-color: var(--sj-border);
}

/* Public inner pages */

html.dark .center-wrap,
html.dark main.center-wrap,
body.dark .center-wrap,
body.dark main.center-wrap {
  color: var(--sj-text-heading);
}

html.dark .info-content,
html.dark .sj-prefs-wrap,
body.dark .info-content,
body.dark .sj-prefs-wrap {
  color: var(--sj-text-secondary);
}

/* Shop */
html.dark .product-card,
html.dark .cart-item,
html.dark .cart-summary,
body.dark .product-card,
body.dark .cart-item,
body.dark .cart-summary {
  background: var(--sj-surface);
  border-color: var(--sj-border);
  color: var(--sj-text);
}

/* Auth */
html.dark .auth-card,
body.dark .auth-card {
  background: var(--sj-surface);
  border-color: var(--sj-border);
  color: var(--sj-text);
}


html.dark .auth-form input,
html.dark .auth-form select,
html.dark .auth-form textarea,
body.dark .auth-form input,
body.dark .auth-form select,
body.dark .auth-form textarea {
  background: var(--sj-bg);
  border-color: var(--sj-border);
  color: var(--sj-text);
}

html.dark .auth-form input::placeholder,
body.dark .auth-form input::placeholder {
  color: var(--sj-text-muted);
}

/* Footer */
html.dark .site-footer,
body.dark .site-footer {
  background: var(--sj-surface);
  border-color: var(--sj-border);
  color: var(--sj-text-secondary);
}


/* The FAQ accordion is page content now, not footer chrome; .faq-item takes its
   surface and border straight from the tokens, which already flip per theme. */

html.dark .site-footer a,
body.dark .site-footer a {
  color: var(--sj-text);
}

/* Breadcrumbs */
html.dark .public-breadcrumbs,
html.dark .sj-breadcrumb,
html.dark .shop-breadcrumb,
html.dark .cart-breadcrumb,
body.dark .public-breadcrumbs,
body.dark .sj-breadcrumb,
body.dark .shop-breadcrumb,
body.dark .cart-breadcrumb {
  color: var(--sj-text-secondary) !important;
  background: var(--sj-bg) !important;
  background-image: none !important;
  border-bottom-color: var(--sj-border) !important;
}

html.dark .public-breadcrumbs a,
html.dark .sj-breadcrumb a,
html.dark .shop-breadcrumb a,
html.dark .cart-breadcrumb a,
body.dark .public-breadcrumbs a,
body.dark .sj-breadcrumb a,
body.dark .shop-breadcrumb a,
body.dark .cart-breadcrumb a {
  color: var(--sj-text) !important;
}

html.dark .sj-breadcrumb__current,
html.dark .sj-breadcrumb [aria-current="page"],
html.dark .shop-breadcrumb [aria-current="page"],
html.dark .cart-breadcrumb [aria-current="page"],
body.dark .sj-breadcrumb__current,
body.dark .sj-breadcrumb [aria-current="page"],
body.dark .shop-breadcrumb [aria-current="page"],
body.dark .cart-breadcrumb [aria-current="page"] {
  color: var(--sj-text) !important;
}

.hero:not(.hero--landing):not(.hero--public) > .sj-theme-toggle {
  grid-column: 3;
  grid-row: 1;
  justify-self: end;
  align-self: center;
  z-index: 2;
  background: rgba(255, 255, 255, 0.15);
  border-color: rgba(255, 255, 255, 0.25);
  color: var(--nav-on-brand, #f7f8fa);
}

.hero:not(.hero--landing):not(.hero--public) > .sj-theme-toggle:hover {
  background: rgba(255, 255, 255, 0.25);
  box-shadow: var(--sj-shadow);
}

/* Generic cards & surfaces */
html.dark .card,
html.dark .modal-content,
body.dark .card,
body.dark .modal-content {
  background: var(--sj-surface);
  border-color: var(--sj-border);
  color: var(--sj-text);
}

/* Protected auth pages */
html.dark .profile-container,
html.dark .page-container,
html.dark .messages-container,
html.dark .settings-page,
body.dark .profile-container,
body.dark .page-container,
body.dark .messages-container,
body.dark .settings-page {
  background: var(--sj-bg);
  color: var(--sj-text-heading);
}

html.dark .sidebar,
html.dark .settings-card,
html.dark .profile-card,
body.dark .sidebar,
body.dark .settings-card,
body.dark .profile-card {
  background: var(--sj-surface);
  border-color: var(--sj-border);
  color: var(--sj-text-heading);
}

/* =============================================================================
   Dark theme – comprehensive public site (hittavakten-style slate surfaces)
   ============================================================================= */

/* Adminpanelen har en egen, medvetet ljus yta (admin-dark.css). Den ärvde
   tidigare den här !important-satta ljusa textfärgen medan korten låg kvar
   på vitt – rubriker och etiketter hamnade då runt 1,1:1 i kontrast och var
   i praktiken osynliga. Adminskalet undantas därför här. */
html.dark,
html.dark body:not(.admin-dark),
body.dark:not(.admin-dark) {
  background: var(--sj-bg) !important;
  color: var(--sj-text) !important;
}

/* Section backgrounds */
html.dark .home-value,
html.dark .home-courses-showcase,
html.dark .home-key-pages,
html.dark .how-it-works,
html.dark .testimonials,
html.dark .shop-page,
html.dark .center-wrap,
body.dark .home-value,
body.dark .home-courses-showcase,
body.dark .home-key-pages,
body.dark .how-it-works,
body.dark .testimonials,
body.dark .shop-page,
body.dark .center-wrap {
  background: var(--sj-bg) !important;
  color: var(--sj-text);
  border-color: var(--sj-border);
}

html.dark .how-it-works,
body.dark .how-it-works {
  background: linear-gradient(180deg, var(--sj-bg-muted) 0%, var(--sj-bg) 55%, var(--sj-bg) 100%) !important;
  border-bottom-color: var(--sj-border) !important;
}

html.dark .home-courses-showcase,
html.dark .home-key-pages,
body.dark .home-courses-showcase,
body.dark .home-key-pages {
  background: var(--sj-bg-muted) !important;
}

/* Section headings */
html.dark .home-value .section-title,
html.dark .how-it-works .section-title,
html.dark .how-it-works-lead,
html.dark .home-courses-showcase-header .section-title,
html.dark .testimonials-title,
html.dark .testimonials-eyebrow,
html.dark .public-page-title,
body.dark .home-value .section-title,
body.dark .how-it-works .section-title,
body.dark .how-it-works-lead,
body.dark .home-courses-showcase-header .section-title,
body.dark .testimonials-title,
body.dark .testimonials-eyebrow,
body.dark .public-page-title {
  color: var(--sj-text);
}

html.dark .home-value .section-sub,
html.dark .how-it-works .section-sub,
html.dark .home-courses-showcase-header .section-sub,
html.dark .home-courses-nav-hint,
html.dark .testimonials-lede,
html.dark .testimonials-score-meta,
body.dark .home-value .section-sub,
body.dark .how-it-works .section-sub,
body.dark .home-courses-showcase-header .section-sub,
body.dark .home-courses-nav-hint,
body.dark .testimonials-lede,
body.dark .testimonials-score-meta {
  color: var(--sj-text-secondary);
}

html.dark .home-value-card h3,
html.dark .how-step h3,
html.dark .how-step p,
html.dark .home-value-card p,
body.dark .home-value-card h3,
body.dark .how-step h3,
body.dark .how-step p,
body.dark .home-value-card p {
  color: inherit;
}

html.dark .home-value-card,
body.dark .home-value-card {
  background: linear-gradient(180deg, var(--sj-surface) 0%, var(--sj-surface) 100%) !important;
  box-shadow: var(--sj-shadow);
}

html.dark .home-value-card:hover,
html.dark .how-step:hover,
body.dark .home-value-card:hover,
body.dark .how-step:hover {
  border-color: var(--sj-border-strong) !important;
  box-shadow: var(--sj-shadow-lg);
}

html.dark .how-step,
body.dark .how-step {
  background: var(--sj-surface) !important;
  border-color: var(--sj-border) !important;
}

html.dark .how-steps::before,
body.dark .how-steps::before {
  background: linear-gradient(90deg, transparent, var(--sj-border-strong), var(--sj-border-strong), transparent) !important;
}

/* Hero marketing – mörkare blå gradient.
   This is the rule that actually paints the dark hero; the flat slate fill
   earlier in this file loses to the !important here. Keep the two in mind
   together — the hero text colours are chosen for THIS background. */
html.dark .hero--landing .hero-marketing,
body.dark .hero--landing .hero-marketing {
  background: linear-gradient(180deg, var(--sj-brand-50) 0%, var(--sj-brand-50) 48%, var(--sj-brand-800) 100%) !important;
  color: #ffffff;
}

html.dark .hero-btn-primary,
body.dark .hero-btn-primary {
  background: var(--sj-text-heading) !important;
  /* Dark label on a near-white button. This is a SURFACE, not running text,
     so it keeps the brand colour. */
  color: var(--sj-brand-800) !important;
  box-shadow: var(--sj-shadow);
}

html.dark .hero-btn-secondary,
html.dark .hero-btn-ghost,
body.dark .hero-btn-secondary,
body.dark .hero-btn-ghost {
  border-color: rgba(248, 250, 252, 0.45) !important;
  color: var(--sj-text) !important;
}

html.dark .hero-btn-secondary:hover,
html.dark .hero-btn-ghost:hover,
body.dark .hero-btn-secondary:hover,
body.dark .hero-btn-ghost:hover {
  background: rgba(248, 250, 252, 0.12) !important;
}

/* Course carousel controls */
html.dark .home-courses-segments,
body.dark .home-courses-segments {
  background: var(--sj-surface);
  border: 1px solid var(--sj-border);
}

html.dark .home-courses-segment,
html.dark .home-courses-nav-arrow,
body.dark .home-courses-segment,
body.dark .home-courses-nav-arrow {
  background: var(--sj-surface-elevated) !important;
  border-color: var(--sj-border) !important;
  color: var(--sj-text-heading) !important;
}

html.dark .home-courses-segment.is-active,
body.dark .home-courses-segment.is-active {
  background: var(--sj-surface-elevated) !important;
  color: var(--sj-text) !important;
}

html.dark .home-courses-segment:hover,
html.dark .home-courses-nav-arrow:hover:not(:disabled),
body.dark .home-courses-segment:hover,
body.dark .home-courses-nav-arrow:hover:not(:disabled) {
  background: var(--sj-surface-elevated) !important;
}

html.dark .home-courses-viewport,
body.dark .home-courses-viewport {
  background: transparent;
}

html.dark .home-course-spotlight .ov-cta-primary,
body.dark .home-course-spotlight .ov-cta-primary {
  background: var(--sj-text-heading) !important;
  /* Dark label on a near-white button. This is a SURFACE, not running text,
     so it keeps the brand colour. */
  color: var(--sj-brand-800) !important;
}

html.dark .home-course-spotlight .ov-cta-ghost,
body.dark .home-course-spotlight .ov-cta-ghost {
  border-color: rgba(248, 250, 252, 0.45) !important;
  color: var(--sj-text) !important;
}

html.dark .home-course-spotlight .ov-cta-ghost:hover,
body.dark .home-course-spotlight .ov-cta-ghost:hover {
  background: rgba(248, 250, 252, 0.1) !important;
}

/* Key pages links */
html.dark .home-key-pages-link,
body.dark .home-key-pages-link {
  background: var(--sj-surface) !important;
  border-color: var(--sj-border) !important;
  color: var(--sj-text) !important;
}

html.dark .home-key-pages-link:hover,
html.dark .home-key-pages-link:focus-visible,
body.dark .home-key-pages-link:hover,
body.dark .home-key-pages-link:focus-visible {
  background: var(--sj-surface-elevated) !important;
  border-color: var(--sj-border-strong) !important;
}

/* Testimonials */
html.dark .testimonials-score,
html.dark .testimonial-cta-card,
body.dark .testimonials-score,
body.dark .testimonial-cta-card {
  background: var(--sj-surface) !important;
  border-color: var(--sj-border) !important;
  color: var(--sj-text-heading);
}

html.dark .testimonial-card,
body.dark .testimonial-card {
  background: var(--sj-surface) !important;
  border-color: var(--sj-border) !important;
}

html.dark .testimonial-card:hover,
body.dark .testimonial-card:hover {
  border-color: var(--sj-border-strong) !important;
}


html.dark .testimonial-role,
html.dark .testimonial-quote p,
html.dark .testimonial-cta-text,
html.dark .testimonials-empty-text,
body.dark .testimonial-role,
body.dark .testimonial-quote p,
body.dark .testimonial-cta-text,
body.dark .testimonials-empty-text {
  color: var(--sj-text-secondary);
}

html.dark .testimonials-carousel-arrow,
html.dark .testimonial-cta .btn-secondary,
body.dark .testimonials-carousel-arrow,
body.dark .testimonial-cta .btn-secondary {
  background: var(--sj-surface-elevated) !important;
  border-color: var(--sj-border) !important;
  color: var(--sj-text-heading) !important;
}


html.dark .testimonials-carousel-dot.is-active,
body.dark .testimonials-carousel-dot.is-active {
  background: var(--sj-brand-light);
}

/* Ordningsvakt sales blocks */
html.dark .ov-sales-hero,
html.dark .ov-section,
html.dark .ov-fact-card,
html.dark .ov-include-card,
html.dark .ov-steps li,
html.dark .ov-trust,
body.dark .ov-sales-hero,
body.dark .ov-section,
body.dark .ov-fact-card,
body.dark .ov-include-card,
body.dark .ov-steps li,
body.dark .ov-trust {
  background: var(--sj-surface) !important;
  border-color: var(--sj-border) !important;
  color: var(--sj-text-heading);
}

html.dark .ov-sales-hero,
body.dark .ov-sales-hero {
  background: linear-gradient(135deg, var(--sj-bg-muted) 0%, var(--sj-bg) 60%, var(--sj-bg) 100%) !important;
}

html.dark .ov-eyebrow,
body.dark .ov-eyebrow {
  background: var(--sj-brand-50) !important;
  color: var(--sj-text) !important;
}

html.dark .ov-sales-hero h1,
html.dark .ov-sales-hero h2,
html.dark .ov-section h2,
html.dark .ov-include-body h3,
html.dark .ov-steps h3,
html.dark .ov-fact-card .ov-fact-value,
html.dark .ov-price-row,
body.dark .ov-sales-hero h1,
body.dark .ov-sales-hero h2,
body.dark .ov-section h2,
body.dark .ov-include-body h3,
body.dark .ov-steps h3,
body.dark .ov-fact-card .ov-fact-value,
body.dark .ov-price-row {
  color: var(--sj-text);
}


html.dark .ov-cta-ghost,
body.dark .ov-cta-ghost {
  background: transparent !important;
  border-color: var(--sj-border-strong) !important;
  color: var(--sj-text-heading) !important;
}

html.dark .ov-cta-ghost:hover,
body.dark .ov-cta-ghost:hover {
  background: var(--sj-surface-elevated) !important;
}


html.dark .ov-trust p a,
body.dark .ov-trust p a {
  color: var(--sj-text);
}

/* Shop / cart */
/* .product-detail is NOT in this list.

   It is the product page's own <main> (handla/product.html), not a card, and
   painting it --shop-surface made the whole page container read as one big card
   in dark theme - measured rgb(30,41,59) on a rgb(15,23,42) page. Worse, the
   real cards inside it (.product-info-price-block, .product-section) resolve to
   that same colour, so they vanished against the container that should never
   have been painted. Removing it here restores them. */
html.dark .product-card,
html.dark .cart-item,
html.dark .cart-summary,
html.dark .filter-bar,
html.dark .checkout-card,
body.dark .product-card,
body.dark .cart-item,
body.dark .cart-summary,
body.dark .filter-bar,
body.dark .checkout-card {
  background: var(--shop-surface) !important;
  border-color: var(--shop-border) !important;
  color: var(--shop-text) !important;
}

html.dark .btn-secondary,
html.dark .btn-shop.btn-secondary,
html.dark .btn-outline,
body.dark .btn-secondary,
body.dark .btn-shop.btn-secondary,
body.dark .btn-outline {
  background: var(--sj-surface-elevated) !important;
  border-color: var(--sj-border-strong) !important;
  color: var(--sj-text-heading) !important;
}

html.dark .btn-secondary:hover,
html.dark .btn-shop.btn-secondary:hover,
body.dark .btn-secondary:hover,
body.dark .btn-shop.btn-secondary:hover {
  background: var(--sj-surface-elevated) !important;
}

/* Info / legal pages */
html.dark .info-content,
html.dark .info-page,
html.dark .sj-prefs-wrap,
html.dark .legal-content,
body.dark .info-content,
body.dark .info-page,
body.dark .sj-prefs-wrap,
body.dark .legal-content {
  background: transparent;
  color: var(--sj-text-secondary);
}

/* Infonavet hade tre band med hårdkodad "background: white" som mörkt läge
   aldrig täckte: .info-intro, .info-grid och .back-section. Rubriken i
   .info-intro ärvde den ljusa texten från mörkt läge men behöll den vita
   bakgrunden och landade på 1.10:1 – i praktiken osynlig. Banden följer nu
   sidans mörka yta. */
html.dark .info-intro,
html.dark .info-grid,
html.dark .back-section,
body.dark .info-intro,
body.dark .info-grid,
body.dark .back-section {
  background: transparent;
}



html.dark .info-card,
html.dark .info-panel,
body.dark .info-card,
body.dark .info-panel {
  background: var(--sj-surface) !important;
  border-color: var(--sj-border) !important;
  color: var(--sj-text-heading);
}

/* Korttexterna hade egna färger i info.css som vann över .info-card:
   rubriken låg på 2.83:1 och brödtexten på 2.55:1 mot den mörka ytan. */
html.dark .info-card h2,
html.dark .info-card h3,
body.dark .info-card h2,
body.dark .info-card h3 {
  color: var(--sj-text-heading);
}


/* Brödtexten på varje villkors- och policysida låg på 1.41:1 i mörkt läge:
   info-pages.css sätter color:#333 på p, vilket vann över den ljusa färgen
   som .info-content ärver. Sidorna gick i praktiken inte att läsa mörkt.
   Rubriker och fet text låg på 3.45:1, under gränsen för brödtextstorlek. */
html.dark .info-content p,
html.dark .info-content li,
html.dark .info-content dd,
body.dark .info-content p,
body.dark .info-content li,
body.dark .info-content dd {
  color: var(--sj-text-secondary);
}

html.dark .info-content h2,
body.dark .info-content h2 {
  color: var(--sj-text-heading);
}

html.dark .info-content h3,
body.dark .info-content h3 {
  color: var(--sj-text-heading);
}

html.dark .info-content strong,
html.dark .contact-facts dt,
body.dark .info-content strong,
body.dark .contact-facts dt {
  color: var(--sj-text);
}

/* Bara textlänkar – knapparna (.info-btn-back m.fl.) har vit text på
   blå gradient och ska inte få länkfärg. */
html.dark .info-content a:not([class]),
html.dark .contact-email a:not([class]),
body.dark .info-content a:not([class]),
body.dark .contact-email a:not([class]) {
  color: var(--sj-text);
}

html.dark .info-back-section,
body.dark .info-back-section {
  background: transparent;
}

html.dark .info-btn-quiet,
body.dark .info-btn-quiet {
  color: var(--sj-text);
}

html.dark .info-btn-quiet:hover,
body.dark .info-btn-quiet:hover {
  color: var(--sj-text);
}

/* Tabellen i cookiepolicyn har en ljus yta som inte följde med till mörkt
   läge – texten ärvde den ljusa färgen och hamnade på 1.48:1 mot vitt. */
html.dark .info-table-scroll,
body.dark .info-table-scroll {
  background: var(--sj-surface);
  border-color: var(--sj-border);
}

html.dark .info-table caption,
body.dark .info-table caption {
  color: var(--sj-text-secondary);
  border-bottom-color: var(--sj-border);
}

html.dark .info-table thead th,
body.dark .info-table thead th {
  background: var(--sj-surface-elevated);
  color: var(--sj-text);
}


html.dark .info-table td,
body.dark .info-table td {
  color: var(--sj-text-secondary);
}

html.dark .info-table th,
html.dark .info-table td,
body.dark .info-table th,
body.dark .info-table td {
  border-bottom-color: var(--sj-border);
}

html.dark .info-table a,
body.dark .info-table a {
  color: var(--sj-text);
}

/* Footer chrome */

html.dark .faq-item[open],
body.dark .faq-item[open] {
  border-color: var(--sj-border-strong) !important;
  box-shadow: var(--sj-shadow);
}

html.dark .faq-item summary,
html.dark .site-footer,
html.dark .site-footer--expanded,
body.dark .faq-item summary,
body.dark .site-footer,
body.dark .site-footer--expanded {
  color: var(--sj-text-heading);
}

html.dark .site-footer a,
body.dark .site-footer a {
  color: var(--sj-text);
}

/* Mobile UI */
html.dark .mobile-bottom-nav,
html.dark .mobile-bottom-nav__bar,
body.dark .mobile-bottom-nav,
body.dark .mobile-bottom-nav__bar {
  background: var(--sj-bg) !important;
  border-color: var(--sj-border) !important;
}

html.dark .mobile-bottom-nav__item,
body.dark .mobile-bottom-nav__item {
  color: var(--sj-text-secondary);
}

html.dark .mobile-bottom-nav__item.is-active,
body.dark .mobile-bottom-nav__item.is-active {
  color: var(--sj-text);
}

html.dark .mobile-bottom-nav__sheet,
html.dark .mobile-bottom-nav__sheet-panel,
body.dark .mobile-bottom-nav__sheet,
body.dark .mobile-bottom-nav__sheet-panel {
  background: var(--sj-surface) !important;
  color: var(--sj-text-heading);
}

html.dark .preview-cart-fab,
html.dark .preview-cart-fab__panel,
body.dark .preview-cart-fab,
body.dark .preview-cart-fab__panel {
  background: var(--sj-surface) !important;
  border-color: var(--sj-border) !important;
  color: var(--sj-text-heading);
}

/* Modals & forms */
html.dark .modal .modal-content,
body.dark .modal .modal-content {
  background: var(--sj-surface) !important;
  border: 1px solid var(--sj-border);
  color: var(--sj-text);
}

html.dark input,
html.dark select,
html.dark textarea,
body.dark input,
body.dark select,
body.dark textarea {
  background-color: var(--sj-bg);
  border-color: var(--sj-border);
  color: var(--sj-text);
}

html.dark input::placeholder,
html.dark textarea::placeholder,
body.dark input::placeholder,
body.dark textarea::placeholder {
  color: var(--sj-text-muted);
}

html.dark label,
html.dark .form-hint,
body.dark label,
body.dark .form-hint {
  color: var(--sj-text-secondary);
}

/* Image lightbox */
html.dark .image-lightbox__dialog,
body.dark .image-lightbox__dialog {
  background: var(--sj-surface) !important;
}

/* Ordningsvakt carousel / preview on homepage */
html.dark .ov-carousel-section--home,
html.dark .ov-preview-card,
html.dark .ov-preview-option,
html.dark .ov-product-trust,
body.dark .ov-carousel-section--home,
body.dark .ov-preview-card,
body.dark .ov-preview-option,
body.dark .ov-product-trust {
  background: var(--sj-surface) !important;
  border-color: var(--sj-border) !important;
  color: var(--sj-text-heading);
}

html.dark .ov-preview-intro,
html.dark .ov-preview-progress,
html.dark .ov-preview-question,
body.dark .ov-preview-intro,
body.dark .ov-preview-progress,
body.dark .ov-preview-question {
  color: var(--sj-text-secondary);
}

html.dark .ov-preview-option:hover:not(:disabled),
body.dark .ov-preview-option:hover:not(:disabled) {
  background: var(--sj-surface-elevated) !important;
  border-color: var(--sj-border-strong) !important;
}

html.dark .ov-preview-option .letter,
body.dark .ov-preview-option .letter {
  background: var(--sj-surface-elevated);
  color: var(--sj-text);
}


html.dark .ov-product-trust p a,
html.dark .ov-product-trust .links a,
body.dark .ov-product-trust p a,
body.dark .ov-product-trust .links a {
  color: var(--sj-text);
}

html.dark .ov-carousel-nav button,
html.dark .ov-carousel-dot,
body.dark .ov-carousel-nav button,
body.dark .ov-carousel-dot {
  background: var(--sj-surface-elevated) !important;
  border-color: var(--sj-border) !important;
  color: var(--sj-text-heading) !important;
}

/* Eyebrow labels are running text, not accents — ink in dark, like every other
   label. (Buttons, pills and badges keep brand colour: those are surfaces.) */
html.dark .hero-eyebrow,
body.dark .hero-eyebrow,
html.dark .product-card-category,
body.dark .product-card-category,
html.dark .home-course-spotlight-badge,
body.dark .home-course-spotlight-badge {
  color: var(--sj-text-secondary);
}

/* ===== nav.css ===================================================== */
/* inlined by build-css: footer.css */

/* --nav-text used to be redefined here as var(--nav-on-brand) — near-white.
   It is tokens.css's property, and this file is concatenated AFTER tokens.css
   into sj-core.css, so with identical (0,1,0) specificity this copy won in
   LIGHT theme. Dark was fine only by accident: tokens.css declares it again
   under `html.dark, body.dark`, which is (0,2,0) and outranks both.

   That asymmetry is why this class of bug is invisible to anyone testing in
   dark mode, and why it kept coming back — the side panel's user name was
   #f7f8fa on #f1f5f9, a contrast ratio of 1.03:1. Seven separate hand-patches
   elsewhere in this file exist purely to work around it. Measured after
   removing this line: 16.30:1 in light, dark unchanged at 13.35:1.

   --nav-text now falls through to tokens.css (var(--sj-text)), which flips.
   --nav-btn-bg is gone too: nothing consumed it.

   --nav-bg and --nav-btn-hover are duplicated here the same way, but they have
   live consumers and dropping them would change real backgrounds — a design
   decision, not a bugfix. scripts/check-tokens.mjs keeps that debt visible. */
:root {
  --nav-bg: var(--sj-brand-gradient, linear-gradient(180deg, var(--sj-brand) 0%, var(--sj-brand-light) 100%));
  --nav-btn-hover: rgba(255,255,255,0.25);
  --nav-radius: 10px;
  --hamburger-size: 44px;
  --hamburger-gap: 14px;
  --hero-logo-max-width: min(240px, 56vw);
  --hero-logo-max-height: clamp(40px, 10vw, 50px);
  --hero-bg-band: var(--sj-brand-gradient, linear-gradient(90deg, var(--sj-brand) 0%, var(--sj-brand-light) 100%));
  --hero-bg-body: linear-gradient(180deg, var(--sj-brand-light) 0%, var(--sj-brand-light) 52%, var(--sj-brand-200) 100%);
  --hero-bg-band-extra: clamp(0.55rem, 1.6vw, 0.85rem);
  --hero-band-height: calc(clamp(0.85rem, 2.5vw, 1.35rem) + var(--hero-logo-max-height) + var(--hero-bg-band-extra));
  --hero-body-min-height: clamp(6.25rem, 17vw, 8.5rem);
  --hero-sheen-line: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.7) 25%, rgba(255,255,255,1) 50%, rgba(255,255,255,.7) 75%, rgba(255,255,255,0) 100%);
}

html.dark, body.dark {
  --nav-ink: var(--sj-surface-sunken);
  --nav-ink-2: var(--sj-surface-elevated);
  --nav-on-ink: var(--sj-text);
  --nav-on-ink-muted: var(--sj-text-secondary);
}

/* ---------- Hero (shared across all pages) ---------- */
.hero {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: var(--hero-band-height) minmax(var(--hero-body-min-height), 1fr);
  align-items: center;
  column-gap: 0;
  row-gap: 0;
  text-align: center;
  min-height: calc(var(--hero-band-height) + var(--hero-body-min-height));
  padding-top: 0;
  padding-bottom: 0;
  padding-left: max(0.5rem, env(safe-area-inset-left));
  padding-right: max(0.5rem, env(safe-area-inset-right));
  background:
    var(--hero-bg-band),
    var(--hero-bg-body);
  background-size: 100% var(--hero-band-height), 100% 100%;
  background-position: top center, top center;
  background-repeat: no-repeat;
  color: var(--nav-on-brand, #f7f8fa);
  box-shadow: var(--sj-shadow);
  position: relative;
  z-index: 1;
  isolation: isolate;
}

/* Övre hjärtpuls-linjen under logotypbandet (samma stil som nedersta strecket) */
.hero::before {
  content: "";
  position: absolute;
  left: 50%;
  top: calc(var(--hero-band-height) - 1px);
  transform: translateX(-50%);
  width: min(1200px, 95vw);
  height: 2px;
  border-radius: var(--sj-radius-pill);
  background: var(--hero-sheen-line);
  animation: heartbeat-sheen 1.6s infinite;
  z-index: 2;
  pointer-events: none;
}

.hero .hamburger,
.hero .hero-logo-link,
.hero > .hero-logo,
.hero .hero-cart-link,
.hero .hero-topbar {
  position: relative;
  z-index: 1;
}

/* Rad 1: undersidor – meny vänster, logotyp centrerad, varukorg höger */
.hero:not(.hero--landing) {
  grid-template-columns: var(--hamburger-size) minmax(0, 1fr) var(--hamburger-size);
}

.hero:not(.hero--landing) .hamburger {
  grid-column: 1;
  grid-row: 1;
  justify-self: start;
  align-self: center;
  min-height: var(--hamburger-size);
}

.hero:not(.hero--landing) .hero-logo-link,
.hero:not(.hero--landing) > .hero-logo {
  grid-column: 2;
  grid-row: 1;
  justify-self: center;
  align-self: center;
  margin: 0;
}

.hero:not(.hero--landing) .hero-cart-link {
  grid-column: 3;
  grid-row: 1;
  justify-self: end;
  align-self: center;
  z-index: 2;
}

.hero-logo-link {
  display: block;
  line-height: 0;
}

/* Startsida: vit header (logga vänster, meny höger) + blå marknadsföringsyta */
.hero--landing {
  position: relative;
  --hero-bg-band: var(--sj-surface);
  --hero-bg-body: linear-gradient(180deg, var(--sj-brand) 0%, var(--sj-brand-light) 48%, var(--sj-brand-light) 100%);
  box-shadow: none;
}

.hero--landing::before {
  display: none;
}

.hero--landing .hero-topbar {
  grid-column: 1 / -1;
  grid-row: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  align-self: stretch;
  position: relative;
  z-index: 10;
  width: 100%;
  max-width: 100%;
  min-height: 0;
  height: 100%;
  margin: 0;
  padding: 0 0.15rem;
  background: var(--sj-surface);
  border-bottom: 1px solid var(--sj-border);
  box-sizing: border-box;
  overflow: hidden;
}

.hero--landing .hero-topbar .hamburger,
.hero--landing .hero-topbar .hero-brand,
.hero--landing .hero-topbar .hero-logo-link,
.hero--landing .hero-topbar .hero-topbar-end,
.hero--landing .hero-topbar .sj-theme-toggle {
  pointer-events: auto;
}

.hero--landing .hero-topbar .hero-brand,
.hero--landing .hero-topbar .hero-logo-link {
  grid-column: 1;
  grid-row: 1;
  justify-self: start;
  align-self: center;
  position: static;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  margin: 0;
  padding-left: 0.15rem;
  text-decoration: none;
  color: var(--sj-text);
}

.hero--landing .hero-topbar-end {
  grid-column: 2;
  grid-row: 1;
  justify-self: end;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}

.hero--landing .hero-topbar .hero-brand-text {
  min-width: 0;
  overflow: hidden;
}

.hero--landing .hero-topbar .hero-brand-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.hero-brand-icon {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 0.55rem;
  box-shadow: var(--sj-shadow-sm);
  object-fit: cover;
}

.hero-brand-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.1;
  min-width: 0;
}

.hero-brand-name {
  font-size: 1rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--sj-text);
}

.hero-brand-sub {
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--sj-text-secondary);
  margin-top: 0.12rem;
}

/* Geometry only. Surface, border and hover come from .btn-icon, so the
   hamburger stays identical to the cart and the theme toggle beside it — these
   rules used to set --sj-bg-page, one shade off the cart's --sj-surface. */
.hero--landing .hero-topbar .hamburger {
  position: static;
  margin: 0;
}

.hero--landing .hero-topbar .hamburger:focus-visible {
  outline: 3px solid var(--sj-brand);
  outline-offset: 2px;
}


/* Vit header-rad; blå yta sätts explicit på .hero-marketing i home.css */
.hero--landing {
  background: var(--sj-surface);
  background-image: none;
  padding-left: 0;
  padding-right: 0;
}

.hero--landing .hero-topbar {
  padding-left: max(1rem, env(safe-area-inset-left));
  padding-right: max(1rem, env(safe-area-inset-right));
}

/* Offentliga undersidor: vit topbar utan blå titelband */
.hero--public {
  position: relative;
  display: block;
  background: var(--sj-surface);
  background-image: none;
  box-shadow: none;
  padding: 0;
  min-height: 0;
  max-width: 100%;
  overflow-x: clip;
  --hero-bg-band: var(--sj-surface);
  --hero-bg-body: var(--sj-surface);
}

.hero--public::before,
.hero--public::after {
  display: none;
}

.hero--public .hero-topbar {
  grid-column: 1 / -1;
  grid-row: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  align-self: stretch;
  position: relative;
  z-index: 10;
  width: 100%;
  max-width: 100%;
  min-height: var(--hero-band-height);
  margin: 0;
  padding: 0 max(1rem, env(safe-area-inset-right)) 0 max(1rem, env(safe-area-inset-left));
  /* NO pointer-events:none. It dates from when the topbar was overlaid on the
     hero and clicks had to pass through to the content beneath, and it came with
     an allowlist of children switched back to auto. The nav links were added
     later and were never in that list, so every top-level link in the header was
     simply not clickable — elementFromPoint returned the <section>, not the <a>.
     The header is an ordinary sticky bar now; nothing sits under it. */
  background: var(--sj-surface);
  border-bottom: 1px solid var(--sj-border);
  box-sizing: border-box;
  overflow: visible;
}

/* The matching allowlist is gone with it — everything in the header is
   clickable, which is the only sane default for a navigation bar. */
.hero--public .hero-topbar,
.hero--public .hero-topbar * {
  pointer-events: auto;
}

.hero--public .hero-topbar .hero-brand {
  grid-column: 1;
  grid-row: 1;
  justify-self: start;
  align-self: center;
  position: static;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  margin: 0;
  padding-left: 0.15rem;
  padding-right: 0.35rem;
  text-decoration: none;
  color: var(--sj-text);
}

.hero--public .hero-topbar .hero-brand-text {
  min-width: 0;
  overflow: hidden;
}

.hero--public .hero-topbar .hero-brand-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.hero--public .hero-topbar-end {
  grid-column: 2;
  grid-row: 1;
  justify-self: end;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
  position: relative;
  z-index: 2;
}

/* Geometry only. Surface, border and hover come from .btn-icon, so the
   hamburger stays identical to the cart and the theme toggle beside it — these
   rules used to set --sj-bg-page, one shade off the cart's --sj-surface. */
.hero--public .hero-topbar .hamburger {
  position: static;
  margin: 0;
}

.hero--public .hero-topbar .hamburger:focus-visible {
  outline: 3px solid var(--sj-brand);
  outline-offset: 2px;
}


.hero--public .hero-cart-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--hamburger-size);
  height: var(--hamburger-size);
  border-radius: var(--sj-radius-pill);
  background: var(--sj-bg-page);
  border: 1px solid var(--sj-border);
  color: var(--sj-text);
  text-decoration: none;
  flex-shrink: 0;
  box-shadow: none;
}

.hero--public .hero-cart-link:hover {
  background: var(--sj-bg-muted);
  transform: none;
  box-shadow: var(--sj-shadow-sm);
}

.hero--public .hero-cart-link:active {
  transform: none;
}

.hero--public .hero-cart-badge {
  border-color: var(--sj-bg-page);
}

@media (max-width: 640px) {
  .hero--public .hero-topbar .hero-brand-icon {
    width: 32px;
    height: 32px;
  }

  .hero--public .hero-topbar .hero-brand-name {
    font-size: 0.92rem;
  }

  .hero--public .hero-topbar .hero-brand-sub {
    font-size: 0.55rem;
    letter-spacing: 0.2em;
  }

  .hero--public .hero-topbar,
  .hero--landing .hero-topbar {
    padding-left: max(0.65rem, env(safe-area-inset-left));
    padding-right: max(0.65rem, env(safe-area-inset-right));
  }

  .hero--public .hero-topbar-end,
  .hero--landing .hero-topbar-end {
    gap: 0.25rem;
  }
}

/* Fallback om topbar saknas (äldre markup) */
.hero--landing > .hamburger {
  position: absolute;
  left: max(0.5rem, env(safe-area-inset-left));
  top: clamp(0.5rem, 2.5vw, 0.85rem);
  z-index: 10;
  grid-column: unset;
  grid-row: unset;
}

.hero--landing > .hero-logo-link {
  position: absolute;
  left: 50%;
  top: clamp(0.5rem, 2.5vw, 0.85rem);
  transform: translateX(-50%);
  z-index: 10;
  height: var(--hamburger-size);
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: calc(100% - (var(--hamburger-size) * 2) - 1rem);
  grid-column: unset;
  grid-row: unset;
}

.hero-logo {
  display: block;
  width: auto;
  max-width: var(--hero-logo-max-width);
  height: auto;
  margin: 0;
}

.hero--landing .hero-logo {
  flex-shrink: 0;
  width: auto;
  height: var(--hero-logo-max-height);
  max-width: var(--hero-logo-max-width);
  max-height: var(--hero-logo-max-height);
  object-fit: contain;
  object-position: center center;
}

/* Rad 2: sidtitel / marknadsföring – centrerad vertikalt mellan strecken */
.hero > h1,
.hero > p,
.hero > .hero-cta,
.hero > .hero-marketing {
  grid-column: 1 / -1;
  grid-row: 2;
  align-self: center;
  justify-self: center;
  position: relative;
  z-index: 1;
  width: 100%;
}

/* The landing banner no longer contains the topbar.
   .hero is a two-row grid: row 1 is the white topbar band, row 2 the body. That
   was right when one .hero--landing section held both. The topbar has since been
   extracted into its own baked .hero--public section above, but .hero--landing
   kept reserving row 1 for it, so an empty 85px band of surface rendered between
   the navbar and the blue banner - which is exactly the gap it looked like.

   Collapsing the band row on this variant only. .hero--public keeps the grid,
   because the band row is the row its topbar actually sits in. The min-height
   drops the band term for the same reason: reserving height for a row that is
   not there would put the gap back on a short banner. */
.hero--landing {
  grid-template-rows: minmax(var(--hero-body-min-height), 1fr);
  min-height: var(--hero-body-min-height);
}

.hero--landing > .hero-marketing {
  grid-row: 1;
}

.hero h1 {
  font-size: clamp(1.15rem, 2.8vw, 1.5rem);
  font-weight: 700;
  margin: 0;
  letter-spacing: -0.02em;
  line-height: 1.25;
  opacity: 1;
}

.hero > h1 {
  padding-top: 0;
  border-top: none;
  max-width: 40rem;
  margin-left: auto;
  margin-right: auto;
}

.hero p {
  font-size: clamp(0.95rem, 2.2vw, 1.15rem);
  opacity: 0.92;
  font-weight: 500;
  margin: 0;
  line-height: 1.5;
}

/* Hjärtpuls-linjen under hero */
.hero::after {
  content:"";
  position:absolute;
  left:50%;
  transform:translateX(-50%);
  bottom:-1px;
  width:min(1200px,95vw);
  height:2px;
  border-radius:var(--sj-radius-pill);
  background: var(--hero-sheen-line);
  animation: heartbeat-sheen 1.6s infinite;
  z-index: 2;
}
@keyframes heartbeat-sheen {
  0%,100% {opacity:1;}
  10% {opacity:.4;}
  20% {opacity:1;}
}

/* ------- Hamburgerknapp -------
   The markup is `.hamburger.btn-icon`, and everything visual now comes from
   .btn-icon: the same surface, the same 1px border and the same radius as the
   cart and the theme toggle beside it.

   It used to set `background: var(--nav-bg)` — and nav.css redefines --nav-bg to
   the brand GRADIENT — plus `border: none` and a box-shadow. That is why it read
   as a different, blue control next to two white ones. Only geometry and the
   press feedback are declared here now. */
.hamburger {
  position: relative;
  top: auto;
  left: auto;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background-color var(--sj-duration-fast) var(--sj-ease),
              border-color var(--sj-duration-fast) var(--sj-ease),
              transform .15s ease;
}
.hamburger:active { transform: scale(.95); }

/* Ikonlinjer */
.hamburger .burger-lines,
.hamburger .burger-lines::before,
.hamburger .burger-lines::after {
  content: "";
  display: block;
  width: 20px;
  height: 2px;
  border-radius: 2px;
  /* Ink, not --nav-on-brand. White lines only made sense while the button
     itself was the blue gradient; on the shared white surface they vanished. */
  background: var(--sj-text);
  position: relative;
}
.hamburger .burger-lines::before,
.hamburger .burger-lines::after {
  position: absolute;
  left: 0;
}
.hamburger .burger-lines::before { top: -6px; }
.hamburger .burger-lines::after  { top: 6px; }

/* ------- Hero Cart Link (shop pages) ------- */
.hero-cart-link {
  position: relative;
  top: auto;
  right: auto;
  width: var(--hamburger-size);
  height: var(--hamburger-size);
  border-radius: var(--sj-radius);
  border: none;
  cursor: pointer;
  background: var(--nav-bg);
  box-shadow: var(--sj-shadow-sm);
  display: grid;
  place-items: center;
  transition: transform .15s ease, box-shadow .15s ease;
  text-decoration: none;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--nav-on-brand, #f7f8fa);
  z-index: 2;
}
.hero-cart-link:hover { transform: scale(1.05); box-shadow: var(--sj-shadow); }
.hero-cart-link:active { transform: scale(.95); }
.hero-cart-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  background: var(--sj-danger);
  color: var(--sj-text-on-brand);
  font-size: 0.65rem;
  min-width: 18px;
  height: 18px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  border: 2px solid var(--sj-brand);
}

/* ------- Sidopanel (endast sajtens hamburgermeny – inte kursmenyer) ------- */
/* The panel opens on the SAME SIDE as the button that opens it. The hamburger
   sits at the right end of the header, but this used to be left:0 with
   translateX(-100%), so the panel flew in from the opposite corner to the one
   you had just tapped. */
#sidepanel.sidepanel:not(.kursbok-menu) {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: clamp(260px, 80vw, 300px);
  /* Height comes from top+bottom now. A fixed 100dvh here would override the
     bottom inset above and put the panel back over the bar. */
  max-height: none;
  /* Sidopanelen är mörkt krom i båda teman och har ljus text. Tidigare stod
     här var(--nav-bg) utan reservvärde – och eftersom --nav-bg aldrig var
     definierad blev hela regeln ogiltig, så panelen saknade bakgrund helt
     medan texten var nästan vit. Nu är färgparet ett token-par. */
  background: var(--nav-ink);
  color: var(--nav-on-ink);
  transform: translateX(100%);
  transition: transform .28s ease;
  z-index: 1200;
  box-shadow: var(--sj-shadow-lg);
  padding: 16px 14px;
  /* --sj-bottom-chrome sätts av ui.js till sj-prefs-barns höjd. Utan den
     hamnade panelens nedersta knapp bakom bannern och gick inte att trycka på. */
  padding-bottom: calc(16px + var(--sj-bottom-chrome, 0px) + env(safe-area-inset-bottom, 0px));
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
#sidepanel.sidepanel:not(.kursbok-menu).open { transform: translateX(0); }

/* The panel stops above the mobile bottom bar rather than covering it — the bar
   no longer hides itself when the panel opens, and the panel is z-index 1200.
   Scoped to the widths where the bar actually exists: --mobile-nav-offset is
   published by mobile-bottom-nav.js and KEEPS its last measured value when the
   bar is hidden, so applying it unconditionally left a 56px dead strip under
   the panel on desktop. 899px matches the bar's own breakpoint. */
@media (max-width: 899px) {
  #sidepanel.sidepanel:not(.kursbok-menu) {
    bottom: var(--mobile-nav-offset, 0px);
  }
}

/* Stängknapp */
#sidepanel:not(.kursbok-menu) .sidepanel-close {
  align-self: flex-end;
  border: none;
  background: transparent;
  color: var(--nav-on-brand, #f7f8fa);
  font-size: 28px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 6px;
  border-radius: var(--sj-radius-sm);
  transition: transform .15s ease;
}
#sidepanel:not(.kursbok-menu) .sidepanel-close:hover { transform: scale(1.1); }

/* ------- Navigationslänkar ------- */
#sidepanel:not(.kursbok-menu) .sidepanel-nav {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  padding-bottom: 1rem;
}
#sidepanel:not(.kursbok-menu) .sidepanel-nav a {
  /* flex, not block: every entry now carries an SVG icon from icons.js and the
     label has to sit beside it on one baseline. */
  display: flex;
  align-items: center;
  gap: 0.625rem;
  text-decoration: none;
  font-weight: 700;
  font-size: 1rem;
  color: var(--nav-text);
  background: rgba(255, 255, 255, 0.22);
  padding: 8px 10px;
  border-radius: var(--nav-radius);
  transition: background .2s ease, transform .1s ease;
}

#sidepanel:not(.kursbok-menu) .sidepanel-nav a .sj-icon {
  flex-shrink: 0;
  width: 1.15em;
  height: 1.15em;
  opacity: 0.85;
}

/* Signed-in identity. The panel gave no sign of who was logged in — logged out
   and logged in looked identical, which is what the user reported. */
.sidepanel-user {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 10px;
  margin-bottom: 6px;
  border-radius: var(--nav-radius);
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid var(--nav-border, rgba(255, 255, 255, 0.2));
}

.sidepanel-user__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--sj-brand);
  color: var(--sj-text-on-brand);
}

.sidepanel-user__avatar .sj-icon { width: 18px; height: 18px; opacity: 1; }

.sidepanel-user__text { display: flex; flex-direction: column; min-width: 0; }

.sidepanel-user__name {
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--nav-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidepanel-user__email {
  font-size: 0.75rem;
  color: var(--nav-text-muted, var(--sj-text-muted));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Replaces the inline style="color:#dc2626;font-weight:700" that bypassed every
   token and stayed the same red in dark mode. */
#sidepanel:not(.kursbok-menu) .sidepanel-nav a.sidepanel-link--admin {
  color: var(--sj-danger);
}
#sidepanel:not(.kursbok-menu) .sidepanel-nav a:hover {
  background: var(--nav-btn-hover);
  transform: translateX(2px);
}
#sidepanel:not(.kursbok-menu) .sidepanel-nav a:focus-visible {
  outline: 2px solid var(--nav-on-brand, #f7f8fa);
  outline-offset: 2px;
}

/* ------- Bakgrundsdimma ------- */
.sidepanel-backdrop {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  height: 100dvh;
  min-height: -webkit-fill-available;
  background: rgba(0,0,0,.45);
  z-index: 1190;
  opacity: 0;
  visibility: hidden;
  transition: opacity .2s ease, visibility .2s ease;
  overscroll-behavior: none;
}
.sidepanel-backdrop.show {
  opacity: 1;
  visibility: visible;
}

/* Lås scroll när panelen är öppen.
 *
 * Two attempts failed before this one, both visible as the page jumping when
 * the menu opened:
 *
 *   1. body { position:fixed; top:-scrollY; width:100%; HEIGHT:100% } — the
 *      height:100% is the problem. body is a flex column, so pinning it to the
 *      viewport height re-flowed the whole column and the content visibly moved.
 *   2. html { overflow:hidden } on its own — html is the scrolling element, so
 *      removing its overflow collapses scrollY to 0. Opening the menu threw the
 *      reader back to the top of the page.
 *
 * So: fix the body at a negative offset (which is what actually holds the
 * viewport still) but leave its height alone. nav.js restores the offset and
 * the scroll position on close. */
/* No scrollbar-gutter here. Reserving the gutter keeps the layout viewport
   narrower than the window, so a right-anchored fixed element — the side panel,
   the cart drawer — stops a scrollbar's width short of the screen edge. The lock
   instead freezes the body's width in JS before hiding the overflow, which keeps
   the content from reflowing and lets fixed chrome reach the true edge. */
html.offcanvas-open {
  overflow: hidden;
  overscroll-behavior: none;
}

body.offcanvas-open {
  position: fixed;
  width: 100%;
  left: 0;
  right: 0;
  overscroll-behavior: none;
}
body.offcanvas-open .profile-container,
body.offcanvas-open .page-container {
  pointer-events: none;
}

/* ===== Responsivitet ===== */
@media (max-width: 640px) {
  :root {
    --hero-body-min-height: clamp(6.5rem, 20vw, 8rem);
  }

  .hero {
    grid-template-rows: var(--hero-band-height) auto;
    min-height: 0;
  }

  /* Same reason as the base rule above: this variant has no topbar of its own,
     so it must not reserve the band row. Restated inside the query because the
     .hero rule here has equal specificity and comes later in the file. */
  .hero--landing {
    grid-template-rows: auto;
    min-height: 0;
  }

  .hero > h1,
  .hero > p,
  .hero > .hero-cta {
    align-self: start;
    padding-top: clamp(1.35rem, 5.5vw, 1.85rem);
    padding-bottom: clamp(1rem, 3.5vw, 1.35rem);
  }

  .hero--landing > .hero-marketing {
    align-self: start;
  }

  .hero > .hero-logo,
  .hero-logo-link .hero-logo {
    max-width: min(210px, 52vw);
  }
}
@media (max-width: 360px) { .hamburger { transform: scale(.9); } }

/* ===== Aktiv länkmarkering (med ikon) ===== */
#sidepanel:not(.kursbok-menu) .sidepanel-nav a.active {
  position: relative;
  background:
    radial-gradient(120% 60% at 50% -30%, rgba(255,255,255,.75) 0%, rgba(255,255,255,0) 60%),
    rgba(255,255,255,.4);
  color: var(--nav-on-brand, #f7f8fa);
  font-weight: 900;
  box-shadow: inset 0 0 0 2px rgba(255,255,255,.85);
  transform: translateX(3px);
}
#sidepanel:not(.kursbok-menu) .sidepanel-nav a.active::before {
  content: "🔸";
  position: absolute;
  left: -1.3rem;
  top: 50%;
  transform: translateY(-50%) scale(1);
  font-size: 1.1rem;
  opacity: 0.9;
  animation: pulse-icon 1.4s infinite ease-in-out;
}
@keyframes pulse-icon {
  0%, 100% { transform: translateY(-50%) scale(1); opacity: 0.9; }
  50% { transform: translateY(-50%) scale(1.2); opacity: 1; }
}

/* ===== Top admin navigation bar (shared across admin pages) ===== */
.admin-nav {
  background: var(--sj-surface);
  border-radius: var(--sj-radius-lg);
  padding: 1rem;
  margin-bottom: 2rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  box-shadow: var(--sj-shadow);
}

.admin-nav a {
  padding: 0.75rem 1.5rem;
  border-radius: var(--sj-radius-sm);
  text-decoration: none;
  color: var(--sj-text-secondary);
  font-weight: 600;
  transition: all 0.2s;
}

.admin-nav a:hover,
.admin-nav a.active,
.admin-nav .admin-nav-link:hover,
.admin-nav .admin-nav-link.active {
  background: var(--sj-brand-gradient);
  color: var(--nav-on-brand, #f7f8fa);
  transform: translateY(-1px);
}

.admin-nav a.swagger-link {
  background: var(--nav-ink, #10151f);
  color: var(--nav-on-brand, #f7f8fa);
}
.admin-nav a.swagger-link:hover { background: var(--nav-ink-2, #1e293b); color: var(--nav-on-brand, #f7f8fa); }

.logout-btn {
  background: var(--sj-danger);
  color: var(--sj-text-on-brand);
  border: none;
  padding: 0.75rem 1.5rem;
  border-radius: var(--sj-radius-sm);
  cursor: pointer;
  font-weight: 600;
  margin-left: auto;
  transition: background 0.2s;
}
.logout-btn:hover { background: var(--sj-danger-strong); }

@media (max-width: 768px) {
  .admin-nav { flex-direction: column; }
  .admin-nav a { text-align: center; }
  .logout-btn { margin-left: 0; width: 100%; }
}

.site-footer:not(.site-footer--expanded) {
  text-align: center;
  background: var(--sj-brand-gradient);
  color: var(--nav-on-brand, #f7f8fa);
  padding: 2rem 1rem 1.5rem;
  font-weight: 600;
  box-shadow: var(--sj-shadow);
  width: 100%;
  box-sizing: border-box;
}
.site-footer:not(.site-footer--expanded) p { margin: 0; font-size: .95rem; }
.site-footer:not(.site-footer--expanded) a { color: var(--sj-text-on-brand); text-decoration: underline; }
.site-footer-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .65rem 1.25rem;
  margin-bottom: 1rem;
  font-size: .9rem;
}
.site-footer-nav a {
  color: var(--nav-on-brand, #f7f8fa);
  text-decoration: none;
  font-weight: 600;
}
.site-footer-nav a:hover,
.site-footer-nav a:focus-visible {
  text-decoration: underline;
}

/* ===== Sticky footer on short pages ===== */
html, body { 
  margin: 0; 
  padding: 0;
}
body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
/* Place the footer at the bottom when content is short */
.site-footer-chrome,
.site-footer { margin-top: auto; }

/* ===== Session-expired modal ===== */
#sessionExpiredModal {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: none;               /* toggled via JS */
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, .55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  padding: 1rem;
}
#sessionExpiredModal .modal-content {
  background: var(--nav-ink, #10151f);
  color: var(--nav-on-brand, #f7f8fa);
  border-radius: var(--sj-radius-lg);
  max-width: 420px;
  width: 100%;
  padding: clamp(1.5rem, 5vw, 2.5rem);
  text-align: center;
  box-shadow: var(--sj-shadow-xl);
  animation: sessionFadeIn .3s ease;
  position: relative;
}
.session-modal-close {
  position: absolute;
  top: 12px;
  right: 14px;
  background: none;
  border: none;
  color: rgba(255, 255, 255, .5);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: var(--sj-radius-xs);
  transition: color .2s, background .2s;
}
.session-modal-close:hover {
  color: var(--nav-on-brand, #f7f8fa);
  background: rgba(255, 255, 255, .12);
}
#sessionExpiredModal .modal-title {
  font-size: 1.35rem;
  font-weight: 700;
  margin: 0 0 .5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
}
#sessionExpiredModal .modal-title::before {
  content: "⏱️";
  font-size: 1.6rem;
}
#sessionExpiredModal .modal-content > p {
  color: rgba(255, 255, 255, .72);
  font-size: .95rem;
  line-height: 1.5;
  margin: 0 0 1.5rem;
}
#sessionExpiredModal .modal-actions {
  display: flex;
  gap: .75rem;
  justify-content: center;
  flex-wrap: wrap;
}
#sessionExpiredModal .btn {
  padding: .65rem 1.5rem;
  border-radius: var(--sj-radius-sm);
  font-weight: 600;
  font-size: .95rem;
  cursor: pointer;
  border: none;
  transition: background .2s, transform .15s, box-shadow .2s;
  min-width: 120px;
}
#sessionExpiredModal .btn:active {
  transform: scale(.96);
}
#sessionExpiredModal .btn-primary {
  background: var(--sj-brand-gradient);
  color: var(--nav-on-brand, #f7f8fa);
  box-shadow: var(--sj-shadow-hover);
}
#sessionExpiredModal .btn-primary:hover {
  background: linear-gradient(135deg, var(--sj-brand-dark), var(--sj-brand));
  box-shadow: var(--sj-shadow-hover);
}
#sessionExpiredModal .btn:not(.btn-primary) {
  background: rgba(255, 255, 255, .1);
  color: var(--nav-on-brand, #f7f8fa);
  border: 1px solid rgba(255, 255, 255, .2);
}
#sessionExpiredModal .btn:not(.btn-primary):hover {
  background: rgba(255, 255, 255, .18);
}
@keyframes sessionFadeIn {
  from { opacity: 0; transform: scale(.92); }
  to   { opacity: 1; transform: scale(1); }
}


/* ===== Sidopanel Logga Ut Knapp ===== */
#sidepanel:not(.kursbok-menu) .sidepanel-nav .btn-logout {
  background: var(--sj-surface) !important;
  color: var(--sj-brand) !important;
  border: 1px solid transparent;
  padding: 0.6rem 1.1rem;
  font-weight: bold;
  border-radius: 10px;
  cursor: pointer;
  transition: background .2s, transform .15s, box-shadow .15s, border-color .15s;
  margin-top: 0.5rem;
  text-align: center;
}
#sidepanel:not(.kursbok-menu) .sidepanel-nav .btn-logout:hover {
  background: var(--sj-brand-100) !important;
  transform: translateY(-1px);
}
#sidepanel:not(.kursbok-menu) .sidepanel-nav .btn-logout:active {
  transform: translateY(0);
}

/* ===== Topbar controls =====
   Nothing here. The cart, the theme toggle and the hamburger are all
   `.btn-icon`, and .btn-icon in components.css already gives them one surface,
   one 1px border, one radius and one hover.

   Two blocks used to live at this spot — "Modern topbar controls (light)" and
   its dark twin — forcing `background`, `border` and `border-radius: pill` with
   !important on `.hamburger`, `.sj-theme-toggle` and `.hero-cart-link`. They
   were written to beat the blue hero buttons that no longer exist, and they
   listed `.hero-cart-link`, which is the OLD cart markup. The current cart is
   `.hero-cart-btn`, so it was never matched — it fell through to .btn-icon while
   the other two got a different background and a pill radius. That is precisely
   why the three controls did not look alike. Deleted rather than extended. */

html:not(.dark) .hero--public .hero-topbar .hero-cart-badge,
html:not(.dark) .hero--public .hero-topbar-end .hero-cart-badge {
  border-color: var(--sj-bg-page) !important;
}

/* ===== Dark mode header (canonical – lives in nav.css for load-order safety) ===== */
/* --sj-surface, matching the light theme. These said --sj-bg, which IS the page
   ground in dark, so the header had no edge against the content at all — the
   same reason the footer dissolved. Chrome sits one step above the page in both
   themes now. */
html.dark .hero--landing,
html.dark .hero--public {
  background: var(--sj-surface) !important;
  background-image: none !important;
  --hero-bg-band: var(--sj-surface);
  --hero-bg-body: var(--sj-surface);
}

html.dark .hero--landing .hero-topbar,
html.dark .hero--public .hero-topbar {
  background: var(--sj-surface) !important;
  border-bottom-color: var(--sj-border) !important;
}

html.dark .hero--landing .hero-topbar .hero-brand,
html.dark .hero--public .hero-topbar .hero-brand,
html.dark .hero--landing .hero-topbar .hero-brand-name,
html.dark .hero--public .hero-topbar .hero-brand-name {
  color: var(--sj-text) !important;
}

html.dark .hero--landing .hero-topbar .hero-brand-sub,
html.dark .hero--public .hero-topbar .hero-brand-sub {
  color: var(--sj-text-secondary) !important;
}


html.dark .hero--public .hero-topbar .hero-cart-badge {
  border-color: var(--sj-border) !important;
}

/* ==========================================================================
   Top-level navigation in the header.

   The header used to contain no links whatsoever: brand, a shop icon, a cart
   icon, the theme toggle and a hamburger. Every destination — Kurser, Forum,
   FAQ, Om oss — was reachable only by opening the side panel, on desktop too.
   Hittavakten shows its four main routes inline, and so do we now.

   Styling follows Hittavakten's .nav-link: a tinted pill on hover, a stronger
   tint for the current page.
   ========================================================================== */
.hero-nav {
  display: none;
  align-items: center;
  gap: 0.125rem;
  /* No margin: justify-self:center centres the MARGIN box, so a margin on one
     side shifts the visible links off centre by half of it. */
}

@media (min-width: 900px) {
  .hero-nav { display: flex; }
}

.hero-nav__link {
  padding: 0.5rem 0.875rem;
  border-radius: var(--sj-radius-sm);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  /* NOT --nav-text: that resolves to --nav-on-brand (near white) because it
     dates from when the whole hero was a blue band. The topbar is a white
     surface now, so these links use the normal page ink. */
  color: var(--sj-text);
  text-decoration: none;
  white-space: nowrap;
  background: transparent;
  transition: background var(--sj-duration-fast) var(--sj-ease),
              color var(--sj-duration-fast) var(--sj-ease);
}

.hero-nav__link:hover {
  color: var(--sj-brand);
  background: var(--nav-hover-tint, rgba(37, 99, 235, 0.07));
}

.hero-nav__link[data-active='true'] {
  color: var(--sj-brand);
  background: var(--nav-active-tint, rgba(37, 99, 235, 0.09));
}

.hero-nav__link:focus-visible {
  outline: var(--sj-focus-width) solid var(--sj-focus-color);
  outline-offset: 2px;
}

/* Once sticky-header.js reparents the topbar into #sj-top-chrome the links come
   along with it, and the chrome uses the same surface, so no override is needed
   there. */

/* The header nav links share the control height so the whole row sits on one
   baseline with the four icon buttons beside them (all 44px). */
.hero-nav__link {
  min-height: var(--sj-control-height, 44px);
  display: inline-flex;
  align-items: center;
}

/* ---------------------------------------------------------------------------
   Auth in the header.

   The header showed no sign of whether you were signed in — the same brand,
   icons and hamburger either way. Now the guest pair (Logga in / Registrera)
   and the signed-in account button live here at desktop widths, and move into
   the hamburger panel below 900px, which is the breakpoint the top-level nav
   links already use.
   ------------------------------------------------------------------------ */
.hero-auth {
  display: none;
  align-items: center;
  gap: 0.375rem;
  margin-left: 0.25rem;
}

@media (min-width: 900px) {
  /* The block is width-RESERVED, not merely shown.
     nav.js renders the signed-out pair ("Logga in" + "Registrera", 188px) into
     the HTML and swaps it for the account button ("Demo", 85px) once the shared
     auth promise resolves. Right-aligned, that 103px difference dragged the
     whole header sideways a beat after every page load — the visible half of
     "the page moves diagonally up-left on refresh".
     Reserving the wider of the two states means the swap changes what is in the
     box, never the box. min-width, not width, so an unusually long name still
     gets the room it needs. */
  .hero-auth {
    display: inline-flex;
    justify-content: flex-end;
    min-width: 11.75rem;
  }
}

.hero-auth .btn {
  min-height: var(--sj-control-height, 44px);
  padding: 0.5rem 0.9rem;
  font-size: 0.9375rem;
}

/* Signed-in: avatar + name, opening the account menu. */
.hero-account {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: var(--sj-control-height, 44px);
  padding: 0.3rem 0.65rem 0.3rem 0.35rem;
  border: 1px solid var(--sj-border);
  border-radius: var(--sj-radius-sm);
  background: var(--sj-surface);
  color: var(--sj-text);
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}

.hero-account:hover { background: var(--sj-bg-muted); border-color: var(--sj-border-strong); }

.hero-account:focus-visible { outline: none; box-shadow: var(--sj-ring); }

.hero-account__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--sj-brand);
  color: var(--sj-text-on-brand);
}

.hero-account__avatar .sj-icon { width: 16px; height: 16px; }

.hero-account__name {
  max-width: 10ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* =============================================================================
   Sticky header — CSS only.

   This used to be assets/js/sticky-header.js: 202 lines that waited for load,
   created a fixed #sj-top-chrome container, MOVED the topbar into it, then set
   --header-offset as body padding to compensate for the hole it had just made.

   That sequence is a layout-shift machine. Measured on /handla/, the reparent
   showed up as the breadcrumb jumping top:85 -> 0 -> 86 within 45ms, and it ran
   ~1.9s into the load, long after the page looked settled.

   The header is baked into the HTML now, so it is present at first paint and
   position:sticky does the whole job with no JavaScript, no DOM moves and no
   shift.
   ========================================================================== */
.hero--public,
.hero--landing > .hero-topbar,
.hero--public > .hero-topbar {
  position: sticky;
  top: 0;
  z-index: var(--sj-z-nav, 900);
}

/* The header is its own painted surface, so content scrolling under it does not
   show through. */
.hero--public {
  background: var(--sj-surface);
  border-bottom: 1px solid var(--sj-border);
}

@supports (backdrop-filter: blur(1px)) {
  .hero--public {
    background: var(--nav-sticky-bg, var(--sj-surface));
    backdrop-filter: blur(12px) saturate(160%);
    -webkit-backdrop-filter: blur(12px) saturate(160%);
  }
}

/* The side panel must sit above the sticky header — and the backdrop BELOW the
   panel. Giving both the same z-index made the backdrop, which comes later in
   the DOM, paint on top of the panel it is meant to sit behind, so every
   control inside the panel became unclickable. Playwright caught it exactly:
   "<div class=\"sidepanel-backdrop show\"> intercepts pointer events". */
#sidepanel.sidepanel:not(.kursbok-menu) { z-index: 1200; }
.sidepanel-backdrop { z-index: 1150; }

/* =============================================================================
   Header layout — one row, three columns.

   Was 85px tall with the nav crammed into the right-hand cluster next to the
   icons. Now: brand left, navigation centred, controls right, on a 64px row
   (56px below 900px), which is the same pair Hittavakten uses.

   Header icon buttons are 38px rather than the 44px used elsewhere. 44 is the
   right touch target in a form or a menu, but four of them in a row made the
   header read as heavy; 38 with a 34px tap area still clears the guidance for
   a pointer-driven header, and the hamburger keeps 44 on touch widths below.
   ========================================================================== */
:root {
  --sj-header-height: 64px;
  --sj-header-control: 38px;
}

@media (max-width: 899px) {
  :root { --sj-header-height: 56px; }
}

.hero--public > .hero-topbar,
.hero-topbar {
  display: grid;
  /* 1fr auto 1fr, not auto 1fr auto. With both outer tracks content-sized the
     middle one is only centred when they happen to be equal — and they are not:
     the brand is ~149px while the controls (Logga in + Registrera + three icon
     buttons) are ~323px, so the nav sat ~91px left of true centre at every
     width. Equal outer shares put it dead centre. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 0.5rem;
  min-height: var(--sj-header-height);
  height: var(--sj-header-height);
  padding-inline: max(1rem, env(safe-area-inset-left)) max(1rem, env(safe-area-inset-right));
}

.hero-topbar > .hero-brand { grid-column: 1; justify-self: start; }
.hero-topbar > .hero-nav { grid-column: 2; justify-self: center; }
.hero-topbar > .hero-topbar-end { grid-column: 3; justify-self: end; }

.hero-topbar-end {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}

/* Brand shrinks with the row. */
.hero-brand-icon { width: 32px; height: 32px; }
.hero-brand-name { font-size: 0.95rem; }
.hero-brand-sub { font-size: 0.58rem; letter-spacing: 0.26em; }

/* Smaller icon buttons in the header only. */
.hero-topbar .btn-icon,
.hero-topbar-end .btn-icon {
  width: var(--sj-header-control);
  height: var(--sj-header-control);
}

.hero-topbar .btn-icon > svg,
.hero-topbar-end .btn-icon > svg,
.hero-topbar-end .sj-theme-toggle svg { width: 18px; height: 18px; }

/* Auth buttons match the icon height so the row is one band. */
.hero-auth .btn {
  min-height: var(--sj-header-control);
  padding: 0.35rem 0.8rem;
  font-size: 0.875rem;
}

/* The account button was noticeably taller than the icons beside it. */
.hero-account {
  min-height: var(--sj-header-control);
  padding: 0.2rem 0.6rem 0.2rem 0.25rem;
  font-size: 0.8125rem;
}

.hero-account__avatar { width: 26px; height: 26px; }
.hero-account__avatar .sj-icon { width: 14px; height: 14px; }

.hero-nav__link {
  min-height: var(--sj-header-control);
  padding: 0.4rem 0.75rem;
  font-size: 0.9rem;
}

/* Below 900px the nav and auth move into the hamburger, so the row is just
   brand + controls and the middle column collapses. */
@media (max-width: 899px) {
  .hero-topbar { grid-template-columns: auto minmax(0, 1fr) auto; }
  .hero-topbar > .hero-nav { display: none; }
  .hero-topbar .btn-icon,
  .hero-topbar-end .btn-icon { width: 40px; height: 40px; }
}

/* .hero:not(.hero--landing) .hamburger sets min-height:var(--hamburger-size)
   (44px), which kept the burger taller than the icons beside it. */
.hero-topbar .hamburger.btn-icon {
  min-height: var(--sj-header-control);
  height: var(--sj-header-control);
}

@media (max-width: 899px) {
  .hero-topbar .hamburger.btn-icon { min-height: 40px; height: 40px; }
}

/* The panel is a themed surface, so its links need themed fills rather than the
   translucent white they used when the panel was always dark chrome. */
#sidepanel:not(.kursbok-menu) .sidepanel-nav a {
  background: var(--sj-bg-muted);
  color: var(--sj-text);
  border: 1px solid var(--sj-border);
}

#sidepanel:not(.kursbok-menu) .sidepanel-nav a:hover {
  background: var(--sj-brand-tint);
  border-color: color-mix(in srgb, var(--sj-brand) 35%, var(--sj-border));
  color: var(--sj-brand);
}

#sidepanel:not(.kursbok-menu) {
  border-left: 1px solid var(--sj-border);
}

.sidepanel-user {
  background: var(--sj-bg-muted);
  border-color: var(--sj-border);
}

#sidepanel:not(.kursbok-menu) .sidepanel-close {
  color: var(--sj-text);
}

.sidepanel-theme-btn {
  background: var(--sj-surface);
  color: var(--sj-text);
  border: 1px solid var(--sj-border-strong);
}

.sidepanel-theme-btn:hover { background: var(--sj-bg-muted); }

/* The header cart badge. The cart button itself is a plain .btn-icon in the
   header row now — it is no longer inside .hero-mobile-actions, which is
   display:none by design and whose stylesheet only loads below 640px. */
.hero-cart-btn { position: relative; }

.hero-cart-btn__badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: var(--sj-radius-pill);
  border: 1.5px solid var(--sj-surface);
  background: var(--sj-danger);
  color: #fff;
  font-size: 0.6rem;
  font-weight: 800;
  line-height: 13px;
  text-align: center;
}

.hero-cart-btn__badge[hidden] { display: none; }

/* =============================================================================
   Header icon glyphs.

   The burger lines used var(--nav-ink-2), which I repointed to --sj-bg-muted
   when the side panel stopped being permanently dark chrome. In light mode that
   is #f1f5f9 — near-white lines on a white header, i.e. an invisible hamburger.
   The header is a normal surface, so its glyphs use the page ink.
   ========================================================================== */

/* The two toggle icons swap with display:none, so exactly one is ever laid out.
   Setting `display` on BOTH of them here (as an earlier version of this block
   did) overrode that hide rule, so both were laid out side by side inside the
   38px button and the visible one sat 9px left of centre. Size them, centre
   them, and leave the showing and hiding to the state rules below. */
.hero-topbar .sj-theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 0;
}

.hero-topbar .sj-theme-toggle .sj-theme-toggle__icon {
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin: 0;
  padding: 0;
}

.hero-topbar .sj-theme-toggle .sj-theme-toggle__icon svg {
  width: 18px;
  height: 18px;
  display: block;
}

/* State: light shows the sun, dark shows the moon. */
.hero-topbar .sj-theme-toggle .sj-theme-toggle__icon--light { display: inline-flex; }
.hero-topbar .sj-theme-toggle .sj-theme-toggle__icon--dark { display: none; }
.hero-topbar .sj-theme-toggle.is-dark .sj-theme-toggle__icon--light { display: none; }
.hero-topbar .sj-theme-toggle.is-dark .sj-theme-toggle__icon--dark { display: inline-flex; }

/* The current page in the side panel. It used to be near-white text on a
   translucent white fill — fine over the old dark-chrome panel, invisible once
   the panel became a normal light surface. It now uses the same tinted-pill
   treatment as the active route in the header. */
#sidepanel:not(.kursbok-menu) .sidepanel-nav a.active,
#sidepanel:not(.kursbok-menu) .sidepanel-nav a[aria-current="page"] {
  background: var(--nav-active-tint, rgba(37, 99, 235, 0.09));
  border-color: color-mix(in srgb, var(--sj-brand) 45%, var(--sj-border));
  color: var(--sj-brand);
  font-weight: 800;
}

#sidepanel:not(.kursbok-menu) .sidepanel-nav a.active .sj-icon,
#sidepanel:not(.kursbok-menu) .sidepanel-nav a[aria-current="page"] .sj-icon {
  opacity: 1;
}

/* ===== footer.css ================================================== */

/* ---------- Expanded footer ---------- */
.site-footer.site-footer--expanded {
  text-align: left;
  /* --sj-surface, not --sj-bg-page: the latter is byte-identical to the
     page ground in both themes, so the footer dissolved into the page. */
  background: var(--sj-surface);
  color: var(--sj-text-secondary);
  padding: 0;
  font-weight: 400;
  box-shadow: none;
  border-top: 1px solid var(--sj-border);
  width: 100%;
  box-sizing: border-box;
}

.site-footer-main {
  /* Same column as every page. This was a private 1120px — a seventh width,
     matching nothing else on the site. */
  max-width: var(--sj-container);
  width: 100%;
  margin: 0 auto;
  padding: clamp(1.5rem, 3.5vw, 2.25rem) 1.25rem 1.5rem;
  box-sizing: border-box;
}

.site-footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(4, minmax(0, 1fr));
  gap: 1.5rem 2rem;
  width: 100%;
}

.site-footer-logo {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  text-decoration: none;
  color: var(--sj-text);
  font-weight: 800;
  font-size: 1rem;
  margin-bottom: 0.65rem;
}

.site-footer-logo img {
  width: 32px;
  height: 32px;
  border-radius: 0.45rem;
  box-shadow: var(--sj-shadow-sm);
}

.site-footer-tagline {
  margin: 0;
  max-width: 34rem;
  color: var(--sj-text-secondary);
  font-size: 0.85rem;
  line-height: 1.55;
}

.site-footer-heading {
  margin: 0 0 0.65rem;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--sj-text-secondary);
}

.site-footer-chrome ul,
.site-footer-chrome ol {
  list-style: none;
  margin: 0;
  padding: 0;
}

.site-footer-chrome li {
  list-style: none;
  list-style-type: none;
}

.site-footer-chrome li::marker {
  content: none;
}

.site-footer-links {
  list-style: none;
  list-style-type: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.site-footer-links li {
  list-style: none;
  list-style-type: none;
  padding-left: 0;
}

.site-footer-links a {
  color: var(--sj-text-secondary);
  text-decoration: none;
  font-size: 0.85rem;
  font-weight: 500;
  line-height: 1.4;
}

.site-footer-links a:hover,
.site-footer-links a:focus-visible {
  color: var(--sj-brand);
  text-decoration: underline;
}

.site-footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1.25rem;
  max-width: var(--sj-container);
  width: 100%;
  margin: 0 auto;
  padding: 0.75rem 1.25rem 1rem;
  border-top: 1px solid var(--sj-border);
  font-size: 0.8rem;
  color: var(--sj-text-secondary);
  box-sizing: border-box;
}

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

.site-footer-bottom a {
  color: var(--sj-text-secondary);
  text-decoration: none;
  font-weight: 500;
}

.site-footer-bottom a:hover,
.site-footer-bottom a:focus-visible {
  color: var(--sj-brand);
  text-decoration: underline;
}

/* Företagsuppgifter (e-handelslagen): namn, företagsform, ort, e-post */
@media (max-width: 600px) {
    }

/* Admin: keep footer readable on dark shell.
   Ytan tvingas ljus här nedan, men theme.css färgar samtidigt sidfotens
   länkar för mörkt underlag (#93c5fd). På adminsidor hamnade de därför på
   ljusblått mot nästan vitt – runt 1,7:1, långt under WCAG 1.4.3. Länkarna
   får tillbaka sina ljusa-ytan-färger. */
body.admin-dark.dark .site-footer a,
body.admin-dark.dark .site-footer--expanded a {
  color: var(--sj-text-secondary);
}

body.admin-dark.dark .site-footer .site-footer-logo {
  color: var(--sj-text);
}

body.admin-dark.dark .site-footer .site-footer-bottom a {
  color: var(--sj-text-secondary);
}

body.admin-dark.dark .site-footer a:hover,
body.admin-dark.dark .site-footer a:focus-visible {
  color: var(--sj-brand-dark);
}

body.admin-dark .site-footer.site-footer--expanded {
  /* --sj-surface, not --sj-bg-page: the latter is byte-identical to the
     page ground in both themes, so the footer dissolved into the page. */
  background: var(--sj-surface);
  color: var(--sj-text-secondary);
}

/* Responsive */

/* There was a .page-home special case here: at >=901px the home page got THREE
   footer columns (and its own side padding) instead of the five every other
   page uses. It dates from when the home footer carried fewer sections. It has
   the same five now, so the override wrapped them onto a second row — the home
   footer measured 445px tall against 260px everywhere else, which is the
   "footer is different in other pages, pushing the other parts down".
   One footer, one layout, every page. */

@media (max-width: 860px) {
  .site-footer-grid {
    grid-template-columns: 1fr 1fr;
  }

  .site-footer-brand {
    grid-column: 1 / -1;
  }
}

@media (max-width: 560px) {
  .site-footer-grid {
    grid-template-columns: 1fr;
    gap: 1.15rem;
  }

  .site-footer-bottom {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* Mobile bottom nav: keep FAQ + footer together above fixed nav */
body.has-mobile-bottom-nav .site-footer-chrome {
  margin-top: auto;
}

body.has-mobile-bottom-nav .site-footer-bottom {
  padding-bottom: calc(1rem + var(--mobile-nav-safe, env(safe-area-inset-bottom, 0px)));
}

/* The company identity line in the bottom bar. Required by e-handelslagen
   (2002:562) 8 § so the trader is identifiable; the fuller details live on
   /info/support.html. */
.site-footer-address {
  font-style: normal;
  font-size: var(--sj-text-xs);
  color: var(--sj-text-muted);
}

.site-footer-bottom { justify-content: space-between; }

@media (max-width: 900px) {
  .site-footer-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .site-footer-brand { grid-column: 1 / -1; }
}

@media (max-width: 560px) {
  .site-footer-grid { grid-template-columns: minmax(0, 1fr); }
}
