/* ================================================
   File:    style.css
   Subject: Bachelor Thesis — FX Triangular Visualization
   Author:  Felix Vadakumchery
   ================================================

   ARCHITECTURE OVERVIEW
   ---------------------
   1. CSS CUSTOM PROPERTIES (":root" block)
      All colours, spacing steps, radii, and font stacks are defined as
      CSS variables in :root.  Changing a single variable here updates
      every rule that references it — no grep-and-replace required.

   2. DARK MODE OVERRIDE  ([data-theme="dark"])
      A single attribute selector block at the bottom re-declares only the
      colour variables that differ in dark mode.  Every layout rule, spacing
      rule, and component rule written against :root variables works in both
      themes automatically without any duplication.  The data-theme attribute
      is set on <html> by the anti-flash inline script before CSS loads, so
      the correct palette is always in effect from the very first paint.

   3. RESET AND BASE  (*, html, body)
      Zeroes browser default margins and enforces border-box sizing globally.

   4. LAYOUT SKELETON
      The page uses a three-column flex row inside .app-main:
        [control-panel] [sidebar-toggle] [chart-section] [events-panel]
      .app-main has a fixed height of 100vh minus the header so the chart
      section fills the viewport without a scrollbar.

   5. COMPONENT SECTIONS (in order)
      Header → Main layout → Control panel → Sidebar toggle →
      Form elements → Date presets → Currency selectors → Date inputs →
      Generate / Reset buttons → Error message → Sanity check →
      Chart section → Loading spinner → Download bar → Animation bar →
      Notes toggle → Data notes → Utility class →
      Dark mode overrides → Theme toggle → Header navigation →
      About page layout → About sections → Table → Math blocks →
      Info button / tooltip pattern → View tabs → View panels →
      Download group → EUR note → Events panel →
      Responsive breakpoints (≤1024px, ≤768px)

   6. RESPONSIVE BREAKPOINTS
      Two @media blocks near the bottom handle tablet-landscape (≤1024px)
      and tablet-portrait (≤768px) screen widths.  The desktop layout
      (>1024px) is the default, written without any media query.
   ================================================ */

/* ------------------------------------------------
   CSS CUSTOM PROPERTIES (VARIABLES)
   Central colour and spacing definitions for the light theme (default).
   Changing a single value here updates every rule that references it.
   Dark mode counterparts live in the [data-theme="dark"] block below.
------------------------------------------------ */
:root {
    /* Color palette — UZH brand style */
    --color-bg:           #ffffff;   /* Main background — white */
    --color-surface:      #f4f6fa;   /* Panel background — light blue-grey */
    --color-border:       #dde2ea;   /* Subtle borders */
    --color-accent:       #0028a5;   /* UZH Blue — primary accent */
    --color-accent-hover: #001f8a;   /* Darker UZH Blue on hover */
    --color-text:         #1c1c1c;   /* Primary text — near black */
    --color-text-muted:   #5f6b7a;   /* Secondary text — medium grey */
    --color-success:      #057a55;   /* Green for sanity check */
    --color-error:        #c81e1e;   /* Red for error messages */

    /* Currency axis colors — kept in sync with getChartColors() in main.js */
    --color-currency-a:   #0028a5;
    --color-currency-b:   #057a55;
    --color-currency-c:   #be185d;

    /* Spacing */
    --spacing-xs:  4px;
    --spacing-sm:  8px;
    --spacing-md:  16px;
    --spacing-lg:  24px;
    --spacing-xl:  32px;

    /* Border radius */
    --radius-sm:  6px;
    --radius-md:  10px;
    --radius-lg:  16px;

    /* Typography */
    --font-main:  'Source Sans 3', 'Source Sans Pro', 'Segoe UI', system-ui, sans-serif;
    --font-mono:  'JetBrains Mono', 'Fira Code', monospace;
}

/* ------------------------------------------------
   RESET AND BASE STYLES
   Removes browser default margins and sets
   a consistent box model across all elements.
------------------------------------------------ */
*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html, body {
    height: 100%;
    font-family: var(--font-main);
    background-color: var(--color-bg);
    color: var(--color-text);
    font-size: 14px;
    line-height: 1.6;
    /* Smooth font rendering on macOS */
    -webkit-font-smoothing: antialiased;
}

/* ------------------------------------------------
   HEADER
   Top bar with application title and subtitle.
------------------------------------------------ */
.app-header {
    background-color: var(--color-surface);
    border-bottom: 3px solid var(--color-accent);
    padding: var(--spacing-lg) var(--spacing-xl);
}

.header-content {
    max-width: 1400px;
    margin: 0 auto;
}

.header-brand {
    display: flex;
    align-items: center;
    gap: var(--spacing-lg);
}

.uzh-logo-link {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

.uzh-logo {
    height: 52px;
    width: auto;
}

.app-title {
    font-size: 22px;
    font-weight: 600;
    color: var(--color-text);
    letter-spacing: -0.3px;
}

.app-subtitle {
    font-size: 13px;
    color: var(--color-text-muted);
    margin-top: var(--spacing-xs);
}

/* ------------------------------------------------
   MAIN LAYOUT
   Five-column flex row:
     [control-panel 240px] [sidebar-toggle 16px] [chart-section flex:1] [events-toggle 24px] [events-panel 260px]
   Fixed height = viewport minus header avoids a page-level scrollbar
   so the chart can fill the remaining vertical space entirely.
   The 1400px max-width centres content on very wide monitors.
------------------------------------------------ */
.app-main {
    display: flex;
    height: calc(100vh - 73px); /* Full height minus header — 73px is the measured header height */
    max-width: 1400px;
    margin: 0 auto;
    gap: 0;
}

/* ------------------------------------------------
   CONTROL PANEL
   Left sidebar containing all user inputs (currency selectors, date range,
   granularity, normalization, generate/reset buttons, sanity check).
   The sidebar-collapse mechanism works by animating width + min-width to 0
   with CSS transition (0.25s).  Setting overflow:hidden prevents content from
   bleeding outside the zero-width box during the animation.
   JavaScript adds/removes the "collapsed" class via toggleSidebar() in main.js.
------------------------------------------------ */
.control-panel {
    width: 240px;
    min-width: 240px;
    background-color: var(--color-surface);
    border-right: 1px solid var(--color-border);
    padding: var(--spacing-md);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-md);
    transition: width 0.25s ease, min-width 0.25s ease, padding 0.25s ease;
}

/* Collapsed state — all three animated properties must reach 0 simultaneously
   so content disappears cleanly without clipping artefacts. */
.control-panel.collapsed {
    width: 0;
    min-width: 0;
    padding: 0;
    overflow: hidden;
    border-right: none;
}

/* ------------------------------------------------
   SIDEBAR TOGGLE STRIP
   A 16px-wide <button> that sits between the control panel and the chart
   area in the flex row.  It shows the ‹ glyph when the panel is open and
   › when collapsed.  Keeping it as a <button> (not a <div>) makes it
   keyboard-accessible and semantically correct.  flex-shrink:0 prevents the
   flex container from squeezing it when space is tight.
------------------------------------------------ */
.sidebar-toggle {
    width: 16px;
    min-width: 16px;
    background-color: var(--color-surface);
    border: none;
    border-left: 1px solid var(--color-border);
    border-right: 1px solid var(--color-border);
    color: var(--color-text-muted);
    font-size: 13px;
    font-family: var(--font-main);
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    transition: background-color 0.2s, color 0.2s;
}

.sidebar-toggle:hover {
    background-color: var(--color-border);
    color: var(--color-text);
}

/* ------------------------------------------------
   EVENTS TOGGLE STRIP
   A 24px-wide button sitting between the chart area and the events panel.
   Wider than the left sidebar-toggle (16px) to give the badge more breathing
   room.  Shows ‹ when collapsed (panel hidden) and › when open (panel visible).
------------------------------------------------ */
.events-toggle {
    width: 24px;
    min-width: 24px;
    background-color: var(--color-surface);
    border: none;
    border-left: 1px solid var(--color-border);
    border-right: 1px solid var(--color-border);
    color: var(--color-text-muted);
    font-size: 13px;
    font-family: var(--font-main);
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    transition: background-color 0.2s, color 0.2s;
}

.events-toggle:hover {
    background-color: var(--color-border);
    color: var(--color-text);
}

/* Arrow glyph — in normal flex flow so it groups with the badge above it.
   When no badge is visible the arrow stays vertically centred on its own. */
.events-toggle-arrow {
    line-height: 1;
}

/* Event-count badge on the strip — only visible when non-empty (JS clears it when
   panel is open or no events are loaded). */
.events-toggle-badge {
    background-color: var(--color-primary, #0028a5);
    color: #fff;
    font-size: 9px;
    font-weight: 700;
    line-height: 1;
    min-width: 16px;
    height: 16px;
    border-radius: 8px;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 0 3px;
}

.events-toggle-badge:not(:empty) {
    display: flex;
}

.panel-title {
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.8px;
    color: var(--color-text-muted);
}

/* ------------------------------------------------
   FORM ELEMENTS
   Shared styles for all input groups.
------------------------------------------------ */
.form-group {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
}

.form-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* Row wrapper used by Granularity and Normalization labels —
   mirrors .sanity-header so the ? tooltip aligns consistently */
.form-label-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

/* Shared styles for all select dropdowns and date inputs.
   appearance:none removes the browser's native <select> arrow so we can
   replace it with a custom SVG arrow via background-image.  The SVG is
   inlined as a data URI to avoid an extra HTTP request.  padding-right:28px
   reserves space so the selected text never overlaps the arrow. */
.form-select,
.currency-select,
.date-input {
    background-color: var(--color-bg);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--spacing-sm) var(--spacing-md);
    font-size: 13px;
    font-family: var(--font-main);
    width: 100%;
    cursor: pointer;
    transition: border-color 0.2s ease;
    appearance: none;       /* Remove default browser arrow so we can use our own */
    /* Custom dropdown arrow using inline SVG data URI — avoids an extra file request */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%238b8fa8' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    padding-right: 28px;    /* Keeps selected text from overlapping the SVG arrow */
}

.form-select:focus,
.currency-select:focus,
.date-input:focus {
    outline: none;
    border-color: var(--color-accent);
}

/* ------------------------------------------------
   DATE RANGE PRESETS
   Quick-select pill buttons that auto-fill the From/To date inputs.
   A 2-column grid fits pairs of buttons side by side.
   .preset-btn--wide uses grid-column:span 2 so the "Full history" button
   stretches across both columns.
   .preset-btn--active is toggled by JavaScript to show which preset is
   currently applied; it uses a faint accent background so the state is
   clear without being heavy.
------------------------------------------------ */
.preset-btns {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--spacing-xs);
}

.preset-btn {
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text-muted);
    font-size: 12px;
    font-family: var(--font-main);
    padding: var(--spacing-xs) 0;
    cursor: pointer;
    transition: border-color 0.2s, color 0.2s, background-color 0.2s;
    text-align: center;
}

.preset-btn:hover {
    border-color: var(--color-accent);
    color: var(--color-text);
}

.preset-btn--active {
    border-color: var(--color-accent);
    color: var(--color-accent);
    background-color: rgba(0, 40, 165, 0.07);
}

.preset-btn--wide {
    grid-column: span 2;
}

/* ------------------------------------------------
   CURRENCY SELECTORS
   Three dropdowns displayed in a row with labels.
------------------------------------------------ */
.currency-selectors {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
}

.selector-wrapper {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
}

.selector-label {
    /* Circle badge showing A, B or C */
    width: 24px;
    height: 24px;
    min-width: 24px;
    background-color: var(--color-accent);
    color: white;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 700;
}

/* Badge colors match the chart axis colors for A, B, C */
.currency-selectors .selector-wrapper:nth-child(1) .selector-label {
    background-color: var(--color-currency-a);
}
.currency-selectors .selector-wrapper:nth-child(2) .selector-label {
    background-color: var(--color-currency-b);
}
.currency-selectors .selector-wrapper:nth-child(3) .selector-label {
    background-color: var(--color-currency-c);
}

/* ------------------------------------------------
   DATE INPUTS
------------------------------------------------ */
.date-inputs {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
}

.date-wrapper {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
}

.date-label {
    font-size: 12px;
    color: var(--color-text-muted);
    min-width: 28px;
}

/* Override the default calendar icon color on webkit browsers */
.date-input::-webkit-calendar-picker-indicator {
    filter: invert(0.6);
    cursor: pointer;
}

/* ------------------------------------------------
   GENERATE BUTTON
------------------------------------------------ */
.generate-btn {
    background-color: var(--color-accent);
    color: white;
    border: none;
    border-radius: var(--radius-sm);
    padding: var(--spacing-md);
    font-size: 14px;
    font-weight: 600;
    font-family: var(--font-main);
    cursor: pointer;
    transition: background-color 0.2s ease, transform 0.1s ease;
    width: 100%;
    margin-top: var(--spacing-sm);
}

.generate-btn:hover {
    background-color: var(--color-accent-hover);
}

.generate-btn:active {
    /* Slight press-down effect on click */
    transform: scale(0.98);
}

.generate-btn:disabled {
    /* Greyed out while request is in progress */
    background-color: var(--color-border);
    cursor: not-allowed;
    transform: none;
}

/* ------------------------------------------------
   RESET BUTTON
   Secondary action below the generate button.
------------------------------------------------ */
.reset-btn {
    background-color: transparent;
    color: var(--color-text-muted);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--spacing-sm) var(--spacing-md);
    font-size: 13px;
    font-weight: 500;
    font-family: var(--font-main);
    cursor: pointer;
    transition: border-color 0.2s ease, color 0.2s ease;
    width: 100%;
}

.reset-btn:hover {
    border-color: var(--color-error);
    color: var(--color-error);
}

/* ------------------------------------------------
   ERROR MESSAGE
------------------------------------------------ */
.error-msg {
    background-color: rgba(200, 30, 30, 0.08);
    border: 1px solid var(--color-error);
    border-radius: var(--radius-sm);
    padding: var(--spacing-sm) var(--spacing-md);
    color: var(--color-error);
    font-size: 12px;
    line-height: 1.5;
}

/* ------------------------------------------------
   SANITY CHECK DISPLAY
------------------------------------------------ */
.sanity-check {
    background-color: rgba(5, 122, 85, 0.07);
    border: 1px solid rgba(5, 122, 85, 0.28);
    border-radius: var(--radius-sm);
    padding: var(--spacing-sm) var(--spacing-md);
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.sanity-label {
    font-size: 11px;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.sanity-value {
    font-size: 16px;
    font-weight: 600;
    font-family: var(--font-mono);
    color: var(--color-success);
}

.sanity-note {
    font-size: 11px;
    color: var(--color-text-muted);
}

/* ------------------------------------------------
   CHART SECTION
   Right side — fills all remaining space.
------------------------------------------------ */
.chart-section {
    flex: 1;                /* Takes all remaining horizontal space */
    display: flex;
    flex-direction: column;
    padding: 4px var(--spacing-sm);
    gap: 4px;
    overflow: hidden;
}

/* The div that Plotly renders the chart into */
.chart-container {
    flex: 1;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    overflow: hidden;
    background-color: var(--color-surface);
    min-height: 400px;
}

/* ------------------------------------------------
   LOADING INDICATOR
------------------------------------------------ */
.loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-md);
    padding: var(--spacing-xl);
    color: var(--color-text-muted);
}

/* Animated spinning circle */
.loading-spinner {
    width: 36px;
    height: 36px;
    border: 3px solid var(--color-border);
    border-top-color: var(--color-accent);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

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

.loading-text {
    font-size: 13px;
    color: var(--color-text-muted);
}

/* ------------------------------------------------
   DOWNLOAD BAR
   Shown below the chart after successful generation.
------------------------------------------------ */
.download-bar {
    display: flex;
    justify-content: flex-end;
    gap: var(--spacing-xl);
    flex-wrap: wrap;
}

/* Direction key — small labeled row showing which chart direction = which currency */
.direction-key {
    display: flex;
    justify-content: center;
    gap: var(--spacing-xl);
    padding: 4px 0;
    font-size: 12px;
    font-family: var(--font-main);
    color: var(--color-text-muted);
}

.dir-item {
    font-weight: 600;
    letter-spacing: 0.01em;
}

.download-btn {
    background-color: transparent;
    color: var(--color-accent);
    border: 1px solid var(--color-accent);
    border-radius: var(--radius-sm);
    padding: var(--spacing-sm) var(--spacing-lg);
    font-size: 13px;
    font-family: var(--font-main);
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.download-btn:hover {
    background-color: var(--color-accent);
    color: white;
}

/* ------------------------------------------------
   ANIMATION BAR + TOGGLE BUTTON
   Shown below the chart after rendering.
------------------------------------------------ */
.anim-bar {
    display: flex;
    align-items: center;
    padding: 3px 8px;
    border-top: 1px solid var(--color-border);
}

.anim-toggle-btn {
    padding: 3px 14px;
    font-size: 13px;
    font-family: var(--font-main);
    background-color: transparent;
    color: var(--color-accent);
    border: 1px solid var(--color-accent);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.anim-toggle-btn:hover {
    background-color: var(--color-accent);
    color: white;
}

.anim-toggle-btn:disabled {
    opacity: 0.55;
    cursor: wait;
}

/* Tooltip on the arrow-toggle button.
   The data-tooltip attribute is only set by JavaScript when arrows are
   unavailable (>1500 data points) and the button is therefore disabled.
   The ::after pseudo-element reads the attribute value at render time so
   no JS is needed to update the tooltip text.  pointer-events:none prevents
   the tooltip itself from capturing mouse events that should pass through to
   the button.  z-index:100 keeps it above the chart container. */
#arrow-toggle-btn {
    position: relative;
}

#arrow-toggle-btn[data-tooltip]::after {
    content: attr(data-tooltip);
    position: absolute;
    bottom: calc(100% + 6px);
    left: 0;
    background: var(--color-surface-2);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 4px 10px;
    font-size: 11px;
    white-space: nowrap;
    pointer-events: none;    /* Let mouse events pass through to the button */
    opacity: 0;
    transition: opacity 0.15s ease;
    z-index: 100;            /* Above the chart container */
}

#arrow-toggle-btn[data-tooltip]:hover::after {
    opacity: 1;
}

/* ------------------------------------------------
   DATA NOTES TOGGLE
   Small pill that reveals/hides the notes section.
   Collapsed by default to maximise chart height.
------------------------------------------------ */
.notes-toggle {
    align-self: flex-start;
    background: transparent;
    border: none;
    color: var(--color-text-muted);
    font-size: 11px;
    font-family: var(--font-main);
    padding: 2px 0 2px 14px;
    cursor: pointer;
    transition: color 0.15s ease;
}

.notes-toggle:hover {
    color: var(--color-text);
}

/* ------------------------------------------------
   DATA AVAILABILITY NOTES
   Shown below the chart when ECB data coverage is
   limited for the selected currencies or date range,
   and when aggregated granularities are in use.
------------------------------------------------ */
.data-notes {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px 14px;
    background-color: var(--color-surface);
    border-top: 1px solid var(--color-border);
}

.data-note {
    font-size: 12px;
    font-family: var(--font-main);
    color: var(--color-text-muted);
    line-height: 1.6;
}

/* ------------------------------------------------
   UTILITY CLASS
   Elements with this class are not visible.
   JavaScript adds and removes this class dynamically.
------------------------------------------------ */
.hidden {
    display: none !important;
}

/* ------------------------------------------------
   DARK MODE OVERRIDES
   Applied when JavaScript sets data-theme="dark" on the <html> element.
   This happens in two places:
     a) The anti-flash inline <script> in the <head> (runs before CSS loads)
        reads localStorage or the system preference and sets the attribute
        immediately so the page never flashes the wrong theme.
     b) toggleTheme() in theme.js switches the attribute on user demand and
        persists the choice to localStorage.

   DESIGN PATTERN
   All component rules are written against CSS variables (var(--color-*)).
   This block only needs to redefine the variables themselves — every
   component rule automatically adopts the dark values without any
   selector-level duplication.  Only components with hardcoded rgba() colours
   (which cannot be expressed as a single variable) need explicit overrides.
------------------------------------------------ */
[data-theme="dark"] {
    --color-bg:           #0f1117;
    --color-surface:      #1a1d27;
    --color-border:       #2a2d3e;
    --color-accent:       #4f8ef7;
    --color-accent-hover: #3a7ae0;
    --color-text:         #e8eaf0;
    --color-text-muted:   #8b8fa8;
    --color-success:      #43c59e;
    --color-error:        #e05c5c;

    /* Currency axis colors — dark mode equivalents */
    --color-currency-a:   #4f8ef7;
    --color-currency-b:   #43c59e;
    --color-currency-c:   #f472b6;
}

[data-theme="dark"] .error-msg {
    background-color: rgba(224, 92, 92, 0.12);
}

[data-theme="dark"] .sanity-check {
    background-color: rgba(67, 197, 158, 0.08);
    border-color:     rgba(67, 197, 158, 0.3);
}

[data-theme="dark"] .preset-btn--active {
    background-color: rgba(79, 142, 247, 0.08);
}

[data-theme="dark"] .eur-note {
    background-color: rgba(79, 142, 247, 0.08);
    border-color:     rgba(79, 142, 247, 0.25);
}

[data-theme="dark"] .info-tooltip {
    background-color: #252836;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}

[data-theme="dark"] .uzh-logo {
    /* The UZH logo SVG is black on transparent.  In dark mode the background
       is near-black so the logo would be invisible.  brightness(0) turns it
       fully black, then invert(1) flips it to fully white. */
    filter: brightness(0) invert(1);
}

/* ------------------------------------------------
   THEME TOGGLE BUTTON
------------------------------------------------ */
.theme-toggle {
    background: none;
    color: var(--color-text-muted);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: var(--spacing-xs) var(--spacing-sm);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    font-family: var(--font-main);
    transition: border-color 0.2s, color 0.2s;
    position: relative;
}

.theme-toggle:hover {
    color: var(--color-text);
    border-color: var(--color-accent);
}

/* CSS-only tooltip pattern used by the theme toggle button.
   The data-tooltip attribute holds the tooltip text.  A ::after pseudo-element
   reads that value with content:attr(data-tooltip) and renders it as a floating
   box above the button.  This avoids the native browser title="" tooltip which
   cannot be styled and appears with an annoying delay.
   opacity transitions from 0 to 1 on :hover for a smooth fade-in.
   right:0 aligns the tooltip to the right edge of the button so it never
   overflows the viewport on narrow screens.
   z-index:200 ensures it sits above the chart area (z-index ~100). */
.theme-toggle::after {
    content: attr(data-tooltip);
    position: absolute;
    bottom: calc(100% + 6px);
    right: 0;
    background-color: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 4px 8px;
    font-size: 11px;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s ease;
    z-index: 200;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.10);
}

.theme-toggle:hover::after {
    opacity: 1;
}

/* ------------------------------------------------
   HEADER NAVIGATION
   Links displayed on the right side of the header.
------------------------------------------------ */
.header-content {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.header-left {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xs);
    border-left: 2px solid var(--color-border);
    padding-left: var(--spacing-lg);
}

.header-nav {
    display: flex;
    gap: var(--spacing-sm);
}

.nav-link {
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: 13px;
    font-weight: 500;
    padding: var(--spacing-xs) var(--spacing-md);
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    transition: color 0.2s ease, border-color 0.2s ease;
}

.nav-link:hover {
    color: var(--color-text);
}

.nav-link--active {
    color: var(--color-accent);
    border-color: var(--color-accent);
}

/* ------------------------------------------------
   ABOUT PAGE LAYOUT
------------------------------------------------ */
.about-main {
    max-width: 820px;
    margin: 0 auto;
    padding: var(--spacing-xl) var(--spacing-lg);
}

.about-article {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xl);
}

.about-title {
    font-size: 28px;
    font-weight: 700;
    color: var(--color-text);
    letter-spacing: -0.4px;
    text-align: left;   /* titles stay left-aligned, only body text is justified */
}

.about-lead {
    font-size: 15px;
    color: var(--color-text-muted);
    line-height: 1.8;
    margin-top: calc(-1 * var(--spacing-md));
    text-align: justify;
}

.about-dl-inline {
    color: var(--color-accent);
    text-decoration: none;
    white-space: nowrap;
}

.about-dl-inline:hover {
    text-decoration: underline;
}

/* ------------------------------------------------
   ABOUT PAGE SECTIONS
------------------------------------------------ */
.about-section {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-md);
    padding-top: var(--spacing-lg);
    border-top: 1px solid var(--color-border);
}

.about-h2 {
    font-size: 18px;
    font-weight: 600;
    color: var(--color-text);
}

.about-h3 {
    font-size: 14px;
    font-weight: 600;
    color: var(--color-text);
    margin-top: 16px;
    margin-bottom: 4px;
}

.about-section p {
    font-size: 14px;
    color: var(--color-text-muted);
    line-height: 1.85;
    text-align: justify;
}

.about-list {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
    padding-left: var(--spacing-md);
}

.about-list li {
    font-size: 14px;
    color: var(--color-text-muted);
    line-height: 1.7;
    position: relative;
}

.about-list li::before {
    content: "—";
    position: absolute;
    left: calc(-1 * var(--spacing-md));
    color: var(--color-border);
}

/* ------------------------------------------------
   ABOUT PAGE TABLE
------------------------------------------------ */
.about-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    margin: var(--spacing-md) 0;
}
.about-table th,
.about-table td {
    padding: 7px 12px;
    text-align: left;
    border-bottom: 1px solid var(--color-border);
}
.about-table thead th {
    color: var(--color-text-muted);
    font-weight: 600;
    border-bottom: 2px solid var(--color-border);
}
.about-table tbody tr:last-child td { border-bottom: none; }
.about-table tbody tr:hover { background: var(--color-surface); }

/* ------------------------------------------------
   MATH FORMULA BLOCKS
   MathJax renders LaTeX formulas inside these divs.
------------------------------------------------ */
.math-block {
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--spacing-lg);
    text-align: center;
    font-size: 15px;
    overflow-x: auto;     /* Allows horizontal scrolling on narrow screens */
}

/* ------------------------------------------------
   ABOUT PAGE LINK
------------------------------------------------ */
.about-link {
    color: var(--color-accent);
    text-decoration: none;
}

.about-link:hover {
    text-decoration: underline;
}

/* ------------------------------------------------
   INFO BUTTON AND TOOLTIP PATTERN
   Used next to the Sanity Check indicator, the Granularity label, and the
   Normalization label.  The pattern has four parts:

   1. .info-btn-wrapper  — position:relative container that holds both the
      button and the tooltip so the tooltip can be positioned relative to it.

   2. .info-btn  — the circular ? button.  Clicking it is intentionally
      not wired to JS; the tooltip appears on CSS :hover of the wrapper,
      so it works without any event listener.

   3. .info-btn-wrapper::after  — an invisible "hover bridge" that fills the
      gap between the button and the tooltip panel.  Without it, moving the
      mouse upward from the button to read the tooltip exits the wrapper for
      a moment and the tooltip disappears before the user reaches it.

   4. .info-tooltip  — the floating tooltip panel.  display:none by default;
      shown as display:block by the .info-btn-wrapper:hover selector when the
      cursor is anywhere inside the wrapper (button + bridge + tooltip).

   DEFAULT DIRECTION: tooltip opens UPWARD (bottom:calc(100% + 8px)) and is
   right-aligned to the button (right:0).  This suits the sanity check widget
   at the bottom of the panel where there is plenty of space above.

   DOWNWARD VARIANT: .info-btn-wrapper--down flips both the bridge and the
   tooltip so they open DOWNWARD.  Used for the Granularity and Normalization
   labels near the top of the panel where the tooltip would clip against the
   panel's top edge if it opened upward.

   Width is capped at 200px to stay within the panel's inner width
   (240px panel − 2×16px padding = 208px usable), preventing horizontal
   overflow that would be clipped by the panel's overflow-y:auto scrollbar.
   z-index:100 keeps the tooltip above the chart container.
------------------------------------------------ */
.sanity-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-sm);
}

.info-btn-wrapper {
    position: relative;
    display: inline-flex;
}

/* Invisible bridge that fills the gap between the ? button and the tooltip.
   Without this the mouse exits the wrapper while crossing the 8px gap and the
   tooltip disappears before the user can read it. */
.info-btn-wrapper::after {
    content: '';
    position: absolute;
    left: -4px;
    right: -4px;
    bottom: 100%;   /* bridge sits above the button */
    height: 8px;
}

/* Downward variant — used when the button is high enough that opening upward
   would clip against the panel top (e.g. Granularity, Normalization labels). */
.info-btn-wrapper--down::after {
    bottom: auto;
    top: 100%;      /* bridge sits below the button */
}

.info-btn-wrapper--down .info-tooltip {
    bottom: auto;
    top: calc(100% + 8px);  /* tooltip opens below the button */
}

.info-btn {
    /* Small circular button displaying a question mark */
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 1px solid var(--color-text-muted);
    background: transparent;
    color: var(--color-text-muted);
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    transition: border-color 0.2s, color 0.2s;
    padding: 0;
}

.info-btn:hover {
    border-color: var(--color-accent);
    color: var(--color-accent);
}

.info-tooltip {
    /* Opens upward, right-aligned to the ? button.
       Width is capped at 200 px so it stays within the 208 px panel inner width
       (240 px panel − 16 px padding × 2) and is never clipped by the panel's
       overflow-x (which is forced to auto by overflow-y: auto). */
    display: none;
    position: absolute;
    bottom: calc(100% + 8px);
    right: 0;
    width: 200px;
    background-color: #ffffff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--spacing-md);
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    z-index: 100;
}

.info-btn-wrapper:hover .info-tooltip {
    /* The tooltip appears when the wrapper (button + tooltip) is hovered */
    display: block;
}

.info-tooltip strong {
    display: block;
    font-size: 12px;
    color: var(--color-text);
    margin-bottom: var(--spacing-sm);
}

.info-tooltip p {
    font-size: 11px;
    color: var(--color-text-muted);
    line-height: 1.6;
    margin-bottom: var(--spacing-sm);
}

.info-tooltip p:last-child {
    margin-bottom: 0;
}

/* ------------------------------------------------
   VIEW TABS
   Tab buttons for switching between Triangular Chart
   and Time Series views.
------------------------------------------------ */
.view-tabs {
    display: flex;
    gap: var(--spacing-xs);
    border-bottom: 1px solid var(--color-border);
    padding-bottom: 3px;
    margin-bottom: 3px;
}

.view-tab {
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--color-text-muted);
    font-size: 13px;
    font-weight: 500;
    font-family: var(--font-main);
    padding: var(--spacing-xs) var(--spacing-md);
    cursor: pointer;
    transition: color 0.2s, border-color 0.2s;
}

.view-tab:hover {
    color: var(--color-text);
}

.view-tab--active {
    color: var(--color-accent);
    border-color: var(--color-accent);
}

/* ------------------------------------------------
   VIEW PANELS
   Each panel corresponds to one tab.
   Only the active panel is visible.
------------------------------------------------ */
.view-panel {
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: 4px;
    min-height: 0;
}

/* ------------------------------------------------
   DOWNLOAD GROUP
   Wraps the download label and format buttons side by side.
------------------------------------------------ */
.download-group {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
}

.download-label {
    font-size: 12px;
    color: var(--color-text-muted);
}

.download-btn {
    background-color: transparent;
    color: var(--color-accent);
    border: 1px solid var(--color-accent);
    border-radius: var(--radius-sm);
    padding: var(--spacing-xs) var(--spacing-md);
    font-size: 13px;
    font-family: var(--font-main);
    cursor: pointer;
    transition: background-color 0.2s, color 0.2s;
}

.download-btn:hover {
    background-color: var(--color-accent);
    color: white;
}

/* ------------------------------------------------
   EUR INFO NOTE
   Shown in the time series view when EUR is selected,
   explaining why it has no data line.
------------------------------------------------ */
.eur-note {
    background-color: rgba(0, 40, 165, 0.07);
    border: 1px solid rgba(0, 40, 165, 0.22);
    border-radius: var(--radius-sm);
    padding: var(--spacing-sm) var(--spacing-md);
    color: var(--color-text-muted);
    font-size: 12px;
    line-height: 1.6;
}

/* ------------------------------------------------
   EVENTS PANEL
   Right sidebar that lists macroeconomic events within the selected date
   range.  It mirrors the left control panel's collapse behaviour:
   JavaScript adds/removes "collapsed" to animate width to 0.
   The panel uses display:flex + flex-direction:column so the events-list
   can grow to fill remaining vertical space while the header, tier bar,
   and pin bar remain at fixed heights.
------------------------------------------------ */


.events-panel {
    width: 260px;
    min-width: 260px;
    background-color: var(--color-surface);
    border-left: 1px solid var(--color-border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transition: width 0.25s ease, min-width 0.25s ease;
}
.events-panel.collapsed {
    width: 0;
    min-width: 0;
    border-left: none;
}

.events-panel-header {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 10px 12px 8px;
    border-bottom: 1px solid var(--color-border);
    flex-shrink: 0;
}
.events-panel-title {
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.8px;
    color: var(--color-text-muted);
}
.events-count {
    font-size: 11px;
    color: var(--color-text-muted);
    background: var(--color-border);
    border-radius: 10px;
    padding: 1px 7px;
    flex-shrink: 0;
}
.events-chart-btn {
    margin-left: auto;
    background: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text-muted);
    font-size: 11px;
    font-family: var(--font-main);
    padding: 3px 8px;
    cursor: pointer;
    transition: border-color 0.2s, color 0.2s;
    flex-shrink: 0;
}
.events-chart-btn:hover { border-color: var(--color-accent); color: var(--color-text); }
.events-chart-btn.active {
    background: var(--color-accent);
    color: #fff;
    border-color: var(--color-accent);
}

/* Tier filter bar */
.events-tier-bar {
    display: flex;
    gap: 4px;
    padding: 6px 10px;
    border-bottom: 1px solid var(--color-border);
    flex-shrink: 0;
    flex-wrap: wrap;
}
.tier-btn {
    background: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text-muted);
    font-size: 11px;
    font-family: var(--font-main);
    padding: 2px 8px;
    cursor: pointer;
    transition: all 0.15s;
}
.tier-btn:hover { border-color: var(--color-accent); color: var(--color-text); }
.tier-btn--active {
    background: var(--color-accent);
    color: #fff;
    border-color: var(--color-accent);
}

/* Pin all / unpin all bar */
.events-pin-bar {
    display: flex;
    gap: 4px;
    padding: 6px 10px;
    border-bottom: 1px solid var(--color-border);
    flex-shrink: 0;
}

/* Events list */
.events-list {
    flex: 1;
    overflow-y: auto;
    padding: 8px 0;
}
.events-placeholder {
    color: var(--color-text-muted);
    font-size: 12px;
    text-align: center;
    padding: 20px 12px;
}

/* Year group — events are grouped by year in the list.
   The year label is position:sticky so it remains visible at the top of
   the scrollable events list while the user scrolls through that year's
   events.  z-index:1 ensures it sits above the event items below it.
   background:var(--color-surface) gives it an opaque background so events
   do not show through the label while it is pinned. */
.event-year-group { margin-bottom: 4px; }
.event-year-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text-muted);
    padding: 4px 12px 2px;
    letter-spacing: 0.5px;
    position: sticky;
    top: 0;
    background: var(--color-surface);
    z-index: 1;    /* Above scrolling event items, below tooltips */
}

/* Individual event item */
.event-item {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    padding: 5px 12px;
    cursor: pointer;
    transition: background 0.15s;
    border-left: 2px solid transparent;
    user-select: none;
}
.event-item:hover { background: var(--color-bg); }
.event-item.pinned {
    background: var(--color-bg);
    border-left-color: #f59e0b;
}

/* Importance dot */
.event-imp {
    font-size: 9px;
    margin-top: 3px;
    flex-shrink: 0;
    width: 16px;
    text-align: center;
}
.event-imp--3 { color: #dc2626; }
.event-imp--2 { color: #d97706; }
.event-imp--1 { color: var(--color-text-muted); }

/* Event text */
.event-content { flex: 1; min-width: 0; }
.event-date {
    font-size: 10px;
    color: var(--color-text-muted);
    margin-bottom: 1px;
    font-variant-numeric: tabular-nums;
}
.event-label {
    font-size: 11px;
    line-height: 1.35;
    color: var(--color-text);
    word-break: break-word;
}


/* Events buttons — pushed to the right edge in both chart views */
#events-anim-btn,
#events-ts-btn { margin-left: auto; }

/* Dark mode overrides for events panel */
[data-theme="dark"] .event-year-label { background: var(--color-surface); }

/* ================================================
   RESPONSIVE LAYOUT
   The app is primarily designed for desktop (> 1024px) where the full
   three-column layout fits comfortably.  Two breakpoints progressively
   shrink sidebars and text to keep the chart usable on smaller screens.
   No mobile-portrait breakpoint exists — the chart needs a minimum of
   ~500px to be readable and collapsing to a single column would require
   a fundamentally different layout.
================================================ */

/* ------------------------------------------------
   TABLET LANDSCAPE  ≤ 1024 px
   Tighten header padding and reduce both sidebar widths so the chart
   area keeps at least ~550px of horizontal space.
   The header height also shrinks (from ~73px to ~62px) so .app-main's
   calc(100vh - Xpx) is updated to match.
------------------------------------------------ */
@media (max-width: 1024px) {

    /* Header */
    .app-header {
        padding: var(--spacing-md) var(--spacing-lg);   /* 16px 24px */
    }
    .uzh-logo      { height: 42px; }
    .app-title     { font-size: 18px; }
    .app-subtitle  { font-size: 12px; }
    .header-left   { padding-left: var(--spacing-md); }

    /* Main layout */
    .app-main {
        height: calc(100vh - 62px);
    }

    /* Left sidebar */
    .control-panel {
        width: 210px;
        min-width: 210px;
    }

    /* Right sidebar */
    .events-panel {
        width: 220px;
        min-width: 220px;
    }

    /* Control panel internals */
    .panel-title { font-size: 12px; }

    .form-label  { font-size: 11px; }

    .form-select,
    .currency-select,
    .date-input {
        font-size: 12px;
        padding: 6px 10px;
        padding-right: 26px;
    }

    .preset-btn   { font-size: 11px; }
    .generate-btn { font-size: 13px; padding: var(--spacing-sm) var(--spacing-md); }

    /* About page */
    .about-main { padding: var(--spacing-lg) var(--spacing-md); }
}

/* ------------------------------------------------
   TABLET PORTRAIT  ≤ 768 px
   Hide the subtitle line entirely to reclaim vertical space.
   Shrink sidebars further.  Switch preset buttons to a single column
   because the narrower panel can't fit two buttons side by side without
   text truncation.  Left-align the download bar to prevent overflow.
   Header height drops to ~54px so .app-main height is updated again.
------------------------------------------------ */
@media (max-width: 768px) {

    /* Header */
    .app-subtitle { display: none; }
    .uzh-logo     { height: 34px; }
    .app-title    { font-size: 16px; }

    /* Main layout */
    .app-main {
        height: calc(100vh - 54px);
    }

    /* Left sidebar */
    .control-panel {
        width: 185px;
        min-width: 185px;
    }

    /* Right sidebar */
    .events-panel {
        width: 190px;
        min-width: 190px;
    }

    /* Preset buttons: single column so text doesn't truncate */
    .preset-btns {
        grid-template-columns: 1fr;
    }
    .preset-btn--wide {
        grid-column: span 1;
    }

    /* Download bar: left-align so buttons don't overflow on narrow screens */
    .download-bar {
        justify-content: flex-start;
        gap: var(--spacing-md);
    }

    /* About page */
    .about-main  { padding: var(--spacing-md); }
    .about-title { font-size: 22px; }

    .about-table          { font-size: 12px; }
    .about-table th,
    .about-table td       { padding: 5px 8px; }
}