:root {
    --color-bg: #f5f6fa;
    --color-surface: #ffffff;
    --color-border: #dfe3ea;
    --color-text: #1f2430;
    --color-muted: #6b7280;
    --color-primary: #2952cc;
    --color-primary-dark: #1e3d99;
    --color-primary-light: #eaf0ff;
    --color-accent: #f5a623;
    --color-accent-light: #fef3e0;
    --color-danger: #c0392b;
    --color-success: #1c7c3c;
    --color-warning: #8a6100;
    --radius: 8px;
    --radius-lg: 18px;
    --spacing: 1rem;
    --shadow-sm: 0 1px 2px rgba(31, 36, 48, 0.06), 0 1px 3px rgba(31, 36, 48, 0.05);
    --shadow-md: 0 8px 24px rgba(31, 36, 48, 0.09);
    --shadow-lift: 0 14px 32px rgba(41, 82, 204, 0.16);

    /* Motion system -- shared timing so every hover/press/entrance effect
       site-wide feels like one coherent system instead of each component
       picking its own random duration. --ease-out is a decelerate curve
       (fast start, gentle settle) for anything entering/growing;
       --ease-spring overshoots slightly for a livelier press/pop feel. */
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
    --duration-fast: 0.15s;
    --duration-base: 0.25s;
    --duration-slow: 0.5s;
}

* {
    box-sizing: border-box;
}

@keyframes fade-rise-in {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes fill-scale-in {
    from { transform: scaleX(0); }
    to { transform: scaleX(1); }
}

/* Global motion opt-out -- honored on top of (not instead of) any
   component-specific reduced-motion rule elsewhere in this file. Setting
   near-zero durations rather than `animation: none` keeps every JS
   listener that waits on a transitionend/animationend event (none exist
   today, but this is the standard safe pattern) from hanging forever. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}

/* .site-topbar is position:sticky, ~68px tall -- without this, jumping to
   an in-page anchor (e.g. the "Ιδρύματα" KPI tile's #chart-institutions,
   or any #chart-* target) scrolls that content flush to the very top of
   the viewport, landing it right underneath/behind the sticky header
   instead of visibly below it. scroll-padding-top reserves that space for
   every anchor jump on the site, native browser behavior, no JS needed. */
html {
    scroll-padding-top: 84px;
}

body {
    margin: 0;
    font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background: var(--color-bg);
    color: var(--color-text);
    line-height: 1.5;
}

.container {
    max-width: 1080px;
    margin: 0 auto;
    padding: 0 1.25rem;
}

h1, h2, h3 {
    line-height: 1.2;
    letter-spacing: -0.01em;
}

a {
    color: var(--color-primary);
}

.site-topbar {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    position: sticky;
    top: 0;
    z-index: 10;
}

.topbar-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.9rem 1.25rem;
    flex-wrap: wrap;
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 700;
    font-size: 1.25rem;
    text-decoration: none;
    color: var(--color-text);
}

.brand-mark {
    display: inline-flex;
    color: var(--color-primary);
    flex-shrink: 0;
}

.topbar-left {
    position: relative;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.nav-toggle {
    position: relative;
    z-index: 50;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-surface);
    color: var(--color-text);
    cursor: pointer;
}

.nav-toggle:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

.nav-toggle-icon {
    display: inline-flex;
}

.nav-toggle-icon[hidden] {
    display: none;
}

.nav-toggle-icon svg {
    width: 22px;
    height: 22px;
}

.link-button {
    text-decoration: none;
    color: var(--color-text);
    font: inherit;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
}

/* ---------------------------------------------------------------------
   Sidebar nav -- an icon rail that expands to show labels on hover/focus
   (desktop), or a full slide-in drawer toggled by the topbar hamburger
   (narrow screens). Both are the SAME element (see data-nav-panel in
   header.php); which behavior applies is purely a media-query switch.
   ------------------------------------------------------------------- */

/* Mobile-first base: a full-height drawer, closed by default. Slides in
   from the left edge instead of dropping out of the topbar -- as a
   dropdown it landed on the first content card and looked like a
   rendering fault; in normal flow it pushed the whole page down. A drawer
   over a dimmed page covers content too, but reads as an intentional
   overlay, and the page behind it never moves. */
.site-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 40;
    width: min(280px, 82vw);
    display: flex;
    flex-direction: column;
    background: var(--color-surface);
    border-right: 1px solid var(--color-border);
    box-shadow: var(--shadow-md);
    overflow-y: auto;
    overflow-x: hidden;
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform 0.22s ease, visibility 0.22s;
}

.site-sidebar.is-open {
    transform: translateX(0);
    visibility: visible;
}

/* Dimmed backdrop while the mobile drawer is open. pointer-events stay off
   so clicks still reach the page and the existing outside-click handler
   (setupNavToggle() in app.js) closes the menu. */
body:has(.site-sidebar.is-open)::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 30;
    background: rgba(16, 20, 30, 0.35);
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .site-sidebar {
        transition: none;
    }
}

.sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 4.75rem 0.6rem 1rem;
}

.sidebar-link {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 0.65rem 0.7rem;
    border-radius: 8px;
    color: var(--color-text);
    text-decoration: none;
    font: inherit;
    font-size: 0.95rem;
    white-space: nowrap;
    background: none;
    border: none;
    width: 100%;
    text-align: left;
    cursor: pointer;
}

.sidebar-link:hover {
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.sidebar-link.is-active {
    background: var(--color-primary-light);
    color: var(--color-primary);
    font-weight: 600;
}

.sidebar-icon {
    position: relative;
    display: inline-flex;
    flex: 0 0 24px;
    color: inherit;
}

.sidebar-icon svg {
    width: 24px;
    height: 24px;
}

.sidebar-icon-badge {
    position: absolute;
    top: -6px;
    right: -8px;
    min-width: 15px;
    height: 15px;
    padding: 0 3px;
    line-height: 15px;
    font-size: 0.62rem;
}

/* Desktop: an always-visible collapsed rail (icons only) that widens on
   hover/keyboard-focus to reveal labels, OVERLAYING the page instead of
   pushing it -- main.container keeps a constant left margin matching the
   COLLAPSED width only, so nothing shifts when the rail expands. */
@media (min-width: 900px) {
    .nav-toggle {
        display: none;
    }

    .site-sidebar {
        top: 0;
        width: 64px;
        transform: none;
        visibility: visible;
        transition: width 0.18s ease;
    }

    .site-sidebar:hover,
    .site-sidebar:focus-within {
        width: 240px;
        box-shadow: var(--shadow-lift);
    }

    body:has(.site-sidebar.is-open)::after {
        content: none;
    }

    .sidebar-nav {
        padding: 1.25rem 0.6rem 1rem;
    }

    .sidebar-label {
        opacity: 0;
        transition: opacity 0.12s ease;
    }

    .site-sidebar:hover .sidebar-label,
    .site-sidebar:focus-within .sidebar-label {
        opacity: 1;
    }

    /* main.container deliberately gets NO left margin -- it stays centered
       in the full viewport exactly like it was under the old hamburger
       drawer (which was a zero-layout-impact overlay too). Only the topbar
       needs its own accommodation, so the brand mark doesn't sit directly
       under the collapsed rail. */
    .topbar-inner {
        padding-left: 64px;
    }
}

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

.lang-switch {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.lang-switch-icon {
    display: inline-flex;
    color: var(--color-primary);
}

.lang-switch select {
    width: auto;
    padding: 0.3rem 0.7rem;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 0.85rem;
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.lang-switch select:hover,
.lang-switch select:focus {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-primary-light);
}

main.container {
    padding-top: 1.5rem;
    padding-bottom: 3rem;
}

/* Just the arrow glyph, no button chrome and no label -- this sits above the
   page title on every page (search results, a profile, requests...), so it
   has to read as a quiet corner mark, not a UI element competing with the
   actual content. The accessible name lives in the visually-hidden span and
   the title="" tooltip instead of visible text. */
.back-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 1rem;
    padding: 0.2rem;
    border: none;
    background: none;
    color: var(--color-muted);
    cursor: pointer;
}

/* On narrow centered-card pages (login/register/contact/account_delete),
   the back button otherwise sits pinned to the far-left edge of the full-
   width container while the card it belongs to is centered below it --
   reads as a stray, disconnected icon. Track the card's own width/centering
   instead so the arrow lines up with the card's left edge. */
main.container:has(> .form-card) > .back-button {
    display: flex;
    justify-content: flex-start;
    /* A <button> shrink-wraps to its content's width even as a block-level
       flex container (unlike a plain <div>, which fills the available
       width by default) -- max-width alone left it sized to just the icon,
       so margin:auto centered that tiny box instead of the icon sitting at
       the real card's left edge. width:100% (capped by max-width) forces it
       to actually occupy the same 480px the card below does. */
    width: 100%;
    max-width: 480px;
    margin-left: auto;
    margin-right: auto;
}

.back-button:hover,
.back-button:focus-visible {
    color: var(--color-primary);
}

.back-button svg {
    width: 22px;
    height: 22px;
    flex-shrink: 0;
}

.card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 1.25rem;
    margin-bottom: 1.25rem;
    box-shadow: var(--shadow-sm);
    /* Rises + fades in once on page load. animation-delay below is keyed
       off :nth-child, which CSS always resolves per-parent -- so every
       .grid of cards (profile_edit.php's sections, admin.php's KPI row,
       cv template picker...) gets its own independent cascade rather than
       one global counter, with zero page-specific CSS needed. */
    animation: fade-rise-in var(--duration-slow) var(--ease-out) both;
}

.card:nth-child(1) { animation-delay: 0s; }
.card:nth-child(2) { animation-delay: 0.04s; }
.card:nth-child(3) { animation-delay: 0.08s; }
.card:nth-child(4) { animation-delay: 0.12s; }
.card:nth-child(5) { animation-delay: 0.16s; }
.card:nth-child(6) { animation-delay: 0.2s; }
.card:nth-child(7) { animation-delay: 0.24s; }
.card:nth-child(n+8) { animation-delay: 0.28s; }

.form-card {
    max-width: 480px;
    margin-left: auto;
    margin-right: auto;
}

/* two_factor_setup.php's plain-text secret / otpauth:// URI -- shown as a
   selectable code block since there's no QR image renderer available. */
.totp-secret-display {
    font-size: 1.1rem;
    letter-spacing: 0.05em;
    padding: 0.75rem;
    background: var(--color-primary-light);
    border-radius: var(--radius);
    word-break: break-all;
}

.totp-uri-display {
    display: block;
    font-size: 0.78rem;
    word-break: break-all;
    color: var(--color-muted);
}

/* events.php's inline day/month/year/hour picker row */
.date-select-row {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.date-select-row select {
    width: auto;
    flex: 1;
    min-width: 90px;
}

.grid {
    display: grid;
    gap: 1.25rem;
}

/* Grid items default to a min-width based on their content's intrinsic size
   (min-content), not the track's own width -- a <select> with a long option
   (e.g. a profession name) or an unbreakable value can silently force its
   whole column, and every grid nested inside it, wider than the page,
   producing a horizontal scrollbar on the entire site. Resetting min-width
   lets items shrink to fit their track instead; width:100% on inputs/
   selects/textareas (see below) already makes them fill that track. */
.grid > * {
    min-width: 0;
}

.two-col {
    grid-template-columns: 1fr 1fr;
}

/* profile_edit.php: every section sits in the same multi-column grid so
   collapsed cards line up side by side instead of stacking one under the
   other. Opening a card (native <details open>) grows it to the full row
   width -- otherwise its form fields would be squeezed into one narrow
   column -- via grid-column, no JS needed. */
.profile-sections-grid {
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    align-items: start;
}

.profile-sections-grid > .profile-section[open] {
    grid-column: 1 / -1;
}

.form-grid {
    grid-template-columns: 1fr 1fr;
}

.form-grid .full-width {
    grid-column: 1 / -1;
}

@media (max-width: 720px) {
    .two-col,
    .form-grid {
        grid-template-columns: 1fr;
    }
}

label {
    display: block;
    font-weight: 600;
    margin: 0.75rem 0 0.25rem;
    font-size: 0.9rem;
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="tel"],
input[type="number"],
input[type="date"],
input[type="file"],
select,
textarea {
    width: 100%;
    padding: 0.55rem 0.65rem;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    font: inherit;
    background: #fff;
    color: inherit;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="tel"]:focus,
input[type="number"]:focus,
input[type="date"]:focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-primary-light);
}

.checkbox-label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 400;
    margin-top: 0.75rem;
}

.checkbox-label input {
    width: auto;
}

.checkbox-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0 1.5rem;
}

.btn {
    display: inline-block;
    padding: 0.65rem 1.25rem;
    border-radius: 8px;
    border: none;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    margin-top: 1rem;
    transition: transform var(--duration-fast) var(--ease-spring), box-shadow var(--duration-fast) ease, background var(--duration-fast) ease;
}

/* Tactile press feedback -- a quick scale-down on the way in (:active) so
   clicking a button reads as physically pressing it, not just a color
   swap. Pairs with each variant's own :hover lift below. */
.btn:active {
    transform: scale(0.97);
}

.btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--color-primary-light);
}

.btn-primary {
    background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
    color: #fff;
    box-shadow: 0 6px 16px rgba(41, 82, 204, 0.28);
}

.btn-primary:hover {
    background: linear-gradient(135deg, var(--color-primary-dark), var(--color-primary-dark));
    transform: translateY(-2px);
    box-shadow: 0 10px 20px rgba(41, 82, 204, 0.32);
}

.btn-secondary {
    background: #eceff5;
    color: var(--color-text);
}

.btn-secondary:hover {
    background: #e1e5f0;
    transform: translateY(-2px);
}

.btn-danger {
    background: var(--color-danger);
    color: #fff;
    box-shadow: 0 6px 16px rgba(192, 57, 43, 0.22);
}

.btn-danger:hover {
    background: #a8321f;
    transform: translateY(-2px);
    box-shadow: 0 10px 20px rgba(192, 57, 43, 0.28);
}

.link-danger {
    color: var(--color-danger);
}

.inline-form {
    display: inline;
}

.alert {
    padding: 0.75rem 1rem;
    border-radius: 6px;
    margin-bottom: 1rem;
    font-size: 0.9rem;
    animation: fade-rise-in var(--duration-base) var(--ease-out) both;
}

.alert-error {
    background: #fdecea;
    color: var(--color-danger);
    border: 1px solid #f5c6c1;
}

.alert-success {
    background: #e9f7ef;
    color: var(--color-success);
    border: 1px solid #bfe6cc;
}

.alert-warning {
    background: #fff6e0;
    color: var(--color-warning);
    border: 1px solid #f0dca0;
}

.entry-list {
    list-style: none;
    padding: 0;
    margin: 0 0 1rem;
}

.entry-list li {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--color-border);
}

.entry-list.read-only li {
    display: block;
}

.leaderboard-list li {
    padding: 0;
    border-bottom: none;
}

.leaderboard-list a {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--color-border);
    color: inherit;
    text-decoration: none;
}

.leaderboard-list a:hover {
    color: var(--color-primary);
}

.proficiency-dots {
    display: inline-flex;
    gap: 3px;
    vertical-align: middle;
    margin-left: 0.3rem;
}

.proficiency-dots .dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-border);
}

.proficiency-dots .dot-filled {
    background: var(--color-primary);
}

.star-rating {
    display: inline-flex;
    gap: 1px;
    vertical-align: middle;
    margin-left: 0.3rem;
    font-size: 0.85rem;
    line-height: 1;
}

.star-rating .star {
    color: var(--color-border);
}

.star-rating .star-filled {
    color: var(--color-primary);
}

.entry-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-shrink: 0;
}

.date-select-group {
    display: flex;
    gap: 0.5rem;
}

.date-select-group select {
    width: auto;
    flex: 1;
    min-width: 0;
}

.muted {
    color: var(--color-muted);
    font-size: 0.85rem;
}

.profile-photo-preview {
    max-width: 160px;
    max-height: 160px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
    margin-bottom: 0.75rem;
    border: 3px solid var(--color-primary-light);
    box-shadow: var(--shadow-sm);
}

.photo-preview-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}

.photo-delete-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.82rem;
}

.photo-delete-btn svg {
    width: 13px;
    height: 13px;
}

.photo-actions {
    margin-bottom: 1rem;
}

.photo-actions-buttons {
    display: flex;
    gap: 0.6rem;
    align-items: center;
    margin-bottom: 0.4rem;
}

/* Visually hidden (not display:none) so Tab/Enter and screen readers still
   reach the real input -- the <label class="file-trigger"> is what's shown
   and clicking it opens the native file dialog same as clicking the input
   itself would. */
.file-input-visually-hidden {
    position: absolute;
    /* !important on the two dimensions only -- input[type="file"] (in the
       shared form-control block above) has equal-or-higher specificity via
       its type attribute selector and was winning with width:100%, so this
       "hidden" input was actually rendering at full container width (real
       layout box, not just visible content) and pushing the whole page's
       scrollWidth out far past the viewport -- clip:rect() hides the paint,
       not the box. Confirmed via a scratch script measuring every element's
       getBoundingClientRect(): this input alone accounted for the entire
       ~800px of horizontal overflow on profile_edit.php. */
    width: 1px !important;
    height: 1px !important;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.file-trigger {
    cursor: pointer;
}

.file-name {
    display: block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.85rem;
    color: var(--color-text-muted, #6b7280);
}

.avatar-placeholder-lg {
    width: 160px;
    height: 160px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-primary-light);
    color: var(--color-primary);
    margin-bottom: 0.75rem;
    border: 3px solid var(--color-primary-light);
}

.avatar-placeholder-lg svg {
    width: 45%;
    height: 45%;
}

.hero {
    display: flex;
    align-items: center;
    gap: 2.5rem;
    padding: 3.5rem 2.5rem;
    margin-bottom: 2rem;
    border-radius: var(--radius-lg);
    background:
        radial-gradient(circle at 90% 10%, rgba(245, 166, 35, 0.16), transparent 45%),
        radial-gradient(circle at 10% 90%, rgba(41, 82, 204, 0.14), transparent 50%),
        linear-gradient(135deg, var(--color-primary-light), #ffffff 65%);
    border: 1px solid var(--color-border);
    overflow: hidden;
}

.hero-copy {
    flex: 1 1 320px;
    min-width: 0;
}

.hero-art {
    flex: 0 0 auto;
    width: min(320px, 40%);
}

.hero-art svg {
    width: 100%;
    height: auto;
    display: block;
}

.hero h1 {
    font-size: 2.3rem;
    line-height: 1.15;
    margin: 0 0 0.75rem;
}

.hero p {
    color: var(--color-muted);
    font-size: 1.05rem;
    max-width: 46ch;
}

.hero-actions {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 1.5rem;
}

@media (max-width: 780px) {
    .hero {
        flex-direction: column;
        text-align: center;
        padding: 2.5rem 1.5rem;
    }

    .hero p {
        max-width: none;
    }

    .hero-actions {
        justify-content: center;
    }

    .hero-art {
        width: min(260px, 70%);
        order: -1;
    }
}

.features-grid {
    grid-template-columns: repeat(3, 1fr);
}

@media (max-width: 720px) {
    .features-grid {
        grid-template-columns: 1fr;
    }
}

.feature-card {
    text-align: left;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.feature-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
}

.feature-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: 14px;
    background: var(--color-primary-light);
    color: var(--color-primary);
    margin-bottom: 0.85rem;
}

.feature-card:nth-child(2) .feature-icon {
    background: var(--color-accent-light);
    color: var(--color-accent);
}

.feature-card:nth-child(3) .feature-icon {
    background: #e9f7ef;
    color: var(--color-success);
}

.feature-icon svg {
    width: 26px;
    height: 26px;
}

.feature-card h2 {
    margin: 0 0 0.4rem;
    font-size: 1.1rem;
}

.feature-card p {
    margin: 0;
    color: var(--color-muted);
}

.section-heading {
    text-align: center;
    margin: 0 0 1.5rem;
}

.search-form {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    max-width: 620px;
    margin-bottom: 1.5rem;
}

.search-form input {
    flex: 1;
    min-width: 200px;
}

.search-year-filter {
    max-width: 160px;
}

.results-grid {
    grid-template-columns: repeat(3, 1fr);
}

@media (max-width: 900px) {
    .results-grid {
        grid-template-columns: 1fr 1fr;
    }
}

@media (max-width: 560px) {
    .results-grid {
        grid-template-columns: 1fr;
    }
}

.result-card {
    display: flex;
    gap: 0.75rem;
    align-items: center;
    text-decoration: none;
    color: inherit;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.result-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
}

.result-photo,
.avatar-placeholder {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

.avatar-placeholder {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.avatar-placeholder svg {
    width: 55%;
    height: 55%;
}

/* avatar-{male,female}.png already include their own circular badge
   background, unlike the generic SVG above -- so these fill the whole
   circle instead of being centered/shrunk inside the blue one. */
.avatar-placeholder img,
.avatar-placeholder-lg img {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
}

.result-info {
    min-width: 0;
    flex: 1;
}

.result-school {
    font-size: 0.82rem;
}

/* Masked cards get a dashed border rather than the solid one revealed cards
   use -- a visual cue (readable even without color) that this row is not
   yet a full profile, matching the masked name/generic-avatar treatment. */
.result-card-masked {
    border-style: dashed;
}

/* Wraps a .result-card <a> plus a sibling dismiss <form> (index.php's
   suggestions widget) -- a <form> can't nest inside the <a> itself, so this
   is the grid cell instead of the card being the cell directly. */
.result-card-wrap {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.result-card-dismiss {
    text-align: right;
}

.result-reveal {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.result-reveal svg {
    width: 17px;
    height: 17px;
}

.result-reveal-pending {
    background: var(--color-surface-muted, #eef0f4);
    color: var(--color-text-muted, #6b7280);
}

.plans-grid {
    grid-template-columns: repeat(2, 1fr);
}

.plan-card {
    text-align: center;
}

.plan-price {
    font-size: 1.8rem;
    font-weight: 700;
    margin: 0.5rem 0;
}

.table-scroll {
    overflow-x: auto;
    overflow-y: auto;
    max-height: 70vh;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

.table-scroll .admin-table thead th {
    position: sticky;
    top: 0;
    background: var(--color-surface);
    z-index: 1;
}

.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.admin-table th,
.admin-table td {
    text-align: left;
    padding: 0.6rem 0.9rem;
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
}

.admin-table tbody tr:last-child td {
    border-bottom: none;
}

.admin-grant-form {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0.75rem 0;
}

.admin-grant-form select {
    font-size: 0.85rem;
    padding: 0.2rem 0.4rem;
}

.admin-table tbody tr {
    position: relative;
}

/* Stretches the click target to the whole row via ::after, not just the
   visible name text -- a member with no first/last name set used to leave
   nothing visible to click, making that row's modal unreachable. */
.admin-member-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dashed var(--color-border);
}

.admin-member-link::after {
    content: "";
    position: absolute;
    inset: 0;
}

.admin-table tbody tr:has(.admin-member-link) {
    cursor: pointer;
}

.admin-member-link:hover {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

.admin-report-flag {
    display: inline-flex;
    color: var(--color-danger);
}

.admin-report-flag svg {
    width: 16px;
    height: 16px;
}

/* Pure-CSS modal via :target -- no JS needed under script-src 'self'. Each
   member row links to #member-<id>; the matching .admin-modal becomes
   visible only while that fragment is the active one. Server-side
   redirects append the same fragment back on (e.g. after submitting a
   membership action inside the modal) so the modal doesn't appear to
   silently close after every click -- see admin.php's redirect() call. */
.admin-modal {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(20, 23, 30, 0.55);
    z-index: 100;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}

.admin-modal:target {
    display: flex;
}

.admin-modal-content {
    position: relative;
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lift);
    padding: 1.75rem;
    max-width: 520px;
    width: 100%;
    max-height: 85vh;
    overflow-y: auto;
    /* Replays every time :target toggles .admin-modal to display:flex --
       a CSS animation always (re)starts when its element goes from not
       rendered to rendered, so this needs no JS trigger. */
    animation: pop-in var(--duration-base) var(--ease-spring) both;
}

@keyframes pop-in {
    from { opacity: 0; transform: scale(0.96) translateY(6px); }
    to { opacity: 1; transform: scale(1) translateY(0); }
}

/* Matches the plain-link look of the "My Profile · Subscription ·
   Messages" row above it, rather than the bold heading .expand-panel
   summary reads as everywhere else -- this is the odd one out in the
   account modal (a form trigger, not a section title). */
.admin-modal-content .expand-panel summary {
    color: var(--color-primary);
    font-weight: 400;
}

/* Sits in the same line as "My Profile · Subscription · Messages" instead
   of dropping to its own row -- <details> is block-level by default, which
   pushed it below that paragraph even though it reads as one of that same
   row's links. Its own <form> content is still block once expanded (a form
   can't stay inline), so opening it naturally continues below this line. */
.account-modal-inline-toggle {
    display: inline;
}

.account-modal-inline-toggle summary {
    display: inline;
}

.account-modal-inline-toggle[open] summary {
    display: block;
}

.account-modal-inline-toggle form {
    margin-top: 0.5rem;
}

.admin-modal-close {
    position: absolute;
    top: 0.75rem;
    right: 1rem;
    font-size: 1.75rem;
    line-height: 1;
    text-decoration: none;
    color: var(--color-muted);
}

.admin-modal-close:hover {
    color: var(--color-text);
}

.account-modal-footer-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 1rem;
}

.admin-modal-actions {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin: 1rem 0;
}

/* Admin-granted verified mark -- next to a name wherever it's shown
   (profile_view.php, cv.php, admin.php's table/modal). currentColor lets
   it pick up --color-primary in most contexts and the CV's own accent
   color inside a CV template, rather than a hardcoded blue everywhere. */
.verified-badge {
    display: inline-flex;
    width: 18px;
    height: 18px;
    color: var(--color-primary);
    vertical-align: middle;
}

.verified-badge svg {
    width: 100%;
    height: 100%;
}

.calendar-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.75rem;
}

.calendar-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 0.25rem;
}

.calendar-cell {
    min-height: 72px;
    border: 1px solid var(--color-border);
    border-radius: 4px;
    padding: 0.25rem;
    font-size: 0.8rem;
    overflow: hidden;
}

.calendar-cell-empty {
    border: none;
}

.calendar-day-num {
    display: block;
    font-weight: 600;
    color: var(--color-muted);
}

.calendar-event {
    display: block;
    font-size: 0.72rem;
    background: var(--color-primary-light);
    color: var(--color-primary-dark);
    border-radius: 3px;
    padding: 0 0.25rem;
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.status-badge {
    display: inline-block;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
}

.status-active {
    background: #e9f7ef;
    color: var(--color-success);
}

.status-inactive {
    background: #fdecea;
    color: var(--color-danger);
}

.status-seeking {
    background: var(--color-accent-light);
    color: #8a5a00;
    margin-top: 0.35rem;
}

.status-mentor {
    background: #f1edff;
    color: #6a45e0;
    margin-top: 0.35rem;
    margin-left: 0.35rem;
}

.profile-safety-links {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    margin-top: 0.75rem;
    font-size: 0.85rem;
}

.profile-safety-links .expand-panel {
    margin: 0;
}

.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 1.5rem;
}

.pagination-link,
.pagination-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.4rem;
    height: 2.4rem;
    padding: 0 0.7rem;
    border-radius: 999px;
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text);
    background: #eceff5;
    transition: background 0.15s ease, color 0.15s ease;
}

.pagination-link:hover,
.pagination-number:hover {
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.pagination-link.is-disabled {
    color: var(--color-muted);
    background: transparent;
    cursor: default;
}

.pagination-number.is-current {
    background: var(--color-primary);
    color: #fff;
}

.pagination-ellipsis {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    color: var(--color-muted);
}

/* Owner-only insight badge (profile_view.php / cv.php): "N more graduates
   from your institution/department", linking into search.php. Styled as a
   pill like .status-badge but it's an <a>, so it needs its own hover state
   to read as clickable -- same rationale as .kpi-tile-link above. */
.schoolmates-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.7rem;
    margin-top: 0.5rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--color-primary) 12%, white);
    color: var(--color-primary);
    font-size: 0.82rem;
    font-weight: 600;
    text-decoration: none;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.schoolmates-badge:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
}

.schoolmates-badge svg {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
}

/* Profile completion bar (profile_edit.php). Fill width is a fixed set of
   classes keyed on the raw filled-check count (0-12), not an inline
   `style="width: X%"` -- style-src 'self' has no unsafe-inline, same
   constraint the CV accent-color picker works around with .color-swatch-*. */
.completion-card {
    margin-top: 1.5rem;
    padding: 0.85rem 1.1rem;
}

.completion-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
}

.completion-header h2 {
    margin: 0;
    font-size: 0.95rem;
}

.completion-percentage {
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-primary);
}

.completion-card .muted {
    font-size: 0.8rem;
}

.completion-bar {
    height: 6px;
    border-radius: 999px;
    background: #eef0f4;
    overflow: hidden;
    margin: 0.4rem 0 0.5rem;
}

.completion-bar-fill {
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--color-primary), var(--color-accent));
    transition: width 0.3s ease;
    transform-origin: left;
    /* scaleX(0 -> 1) always lands at exactly whatever width the
       [data-completion-level] rules below set, regardless of which
       discrete level that is -- so the bar visibly fills up on every page
       load instead of just appearing already-full. */
    animation: fill-scale-in 0.9s var(--ease-out) 0.15s both;
}

.completion-bar-fill[data-completion-level="0"] { width: 0%; }
.completion-bar-fill[data-completion-level="1"] { width: 8.33%; }
.completion-bar-fill[data-completion-level="2"] { width: 16.67%; }
.completion-bar-fill[data-completion-level="3"] { width: 25%; }
.completion-bar-fill[data-completion-level="4"] { width: 33.33%; }
.completion-bar-fill[data-completion-level="5"] { width: 41.67%; }
.completion-bar-fill[data-completion-level="6"] { width: 50%; }
.completion-bar-fill[data-completion-level="7"] { width: 58.33%; }
.completion-bar-fill[data-completion-level="8"] { width: 66.67%; }
.completion-bar-fill[data-completion-level="9"] { width: 75%; }
.completion-bar-fill[data-completion-level="10"] { width: 83.33%; }
.completion-bar-fill[data-completion-level="11"] { width: 91.67%; }
.completion-bar-fill[data-completion-level="12"] { width: 100%; }

.completion-missing-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.completion-missing-list li {
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    background: #fdecea;
    color: var(--color-danger);
    font-size: 0.78rem;
    font-weight: 600;
}

.stats-section {
    margin-top: 3rem;
}

.section-subheading {
    text-align: center;
    margin: -1rem 0 1.75rem;
}

.kpi-row {
    grid-template-columns: repeat(4, 1fr);
}

@media (max-width: 860px) {
    .kpi-row {
        grid-template-columns: repeat(2, 1fr);
    }
}

.kpi-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.2rem;
    text-align: center;
    padding: 1.4rem 1rem;
}

.kpi-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border-radius: 12px;
    margin-bottom: 0.4rem;
}

.kpi-icon svg {
    width: 22px;
    height: 22px;
}

.kpi-icon-a {
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.kpi-icon-b {
    background: var(--color-accent-light);
    color: var(--color-accent);
}

.kpi-icon-c {
    background: #e9f7ef;
    color: var(--color-success);
}

.kpi-icon-d {
    background: #f1edff;
    color: #7c5cff;
}

.kpi-icon-e {
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.kpi-value {
    font-size: 2.1rem;
    font-weight: 700;
    line-height: 1.1;
    color: var(--color-primary);
}

.kpi-label {
    font-size: 0.85rem;
    color: var(--color-muted);
}

/* .kpi-tile is a plain <div> everywhere else -- this variant is an <a>, so
   it needs the link underline/color reset plus its own hover state to read
   as clickable without looking like a stray blue link dropped into an
   otherwise static row of stat cards. */
.kpi-tile-link {
    text-decoration: none;
    color: inherit;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.kpi-tile-link:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
}

.kpi-tile-link .kpi-value {
    text-decoration: none;
}

.chart-card {
    padding: 1.4rem 1.5rem;
}

.chart-card-compact {
    max-width: 480px;
    margin-left: auto;
    margin-right: auto;
}

.chart-title {
    margin: 0 0 1rem;
    font-size: 1rem;
}

/* Every homepage chart's title opens its full list on its own page (see
   get_homepage_chart_registry() / chart_detail.php) -- inherit the
   heading's own color instead of the default link blue so it still reads
   as a title first, link second; underline only on hover as the
   interactivity cue. */
.chart-title a {
    color: inherit;
    text-decoration: none;
}

.chart-title a:hover {
    text-decoration: underline;
}

.chart-svg {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
}

/* chart_detail.php's full-list pages pull up to 1000 rows (see
   get_homepage_chart_registry()) -- .chart-svg scales its height to the
   row count, so without a cap the page itself stretches to match a
   thousand 44px rows. Capping and scrolling this wrapper instead keeps
   the page height sane while the full list stays reachable. */
.chart-detail-scroll {
    max-height: 65vh;
    overflow-y: auto;
}

.chart-svg-bar {
    height: 26px;
}

.chart-row-link {
    cursor: pointer;
}

.chart-line-point {
    cursor: pointer;
}

.chart-line-point circle:last-child {
    transition: r 0.15s ease;
}

.chart-line-point:hover circle:last-child {
    r: 6;
}

.chart-row-link .chart-row-hit {
    transition: fill 0.15s ease;
}

.chart-row-link:hover .chart-row-hit {
    fill: var(--color-bg);
}

.donut-chart-row {
    display: flex;
    align-items: center;
    gap: 2rem;
    flex-wrap: wrap;
}

.donut-chart-figure {
    flex: 0 0 auto;
    width: 160px;
}

.chart-svg-donut {
    width: 100%;
    height: auto;
}

.chart-legend-stacked {
    flex: 1 1 220px;
    flex-direction: column;
    gap: 0.6rem;
}

.chart-legend {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
    padding: 0;
    margin: 0.9rem 0 0;
    font-size: 0.88rem;
    color: var(--color-muted);
}

.chart-legend li {
    display: flex;
    align-items: center;
    gap: 0.45rem;
}

.chart-legend a {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: inherit;
    text-decoration: none;
    border-radius: 6px;
    padding: 0.15rem 0.4rem;
    margin: -0.15rem -0.4rem;
    transition: background 0.15s ease;
}

.chart-legend a:hover {
    background: var(--color-primary-light);
}

.directory-tabs {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
}

.directory-tab {
    padding: 0.5rem 1rem;
    border-radius: 999px;
    background: #eceff5;
    color: var(--color-text);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.9rem;
}

.directory-tab.is-active {
    background: var(--color-primary);
    color: #fff;
}

.directory-year-filter {
    display: flex;
    gap: 0.5rem;
    max-width: 280px;
    margin-bottom: 1.5rem;
}

.directory-year-filter select {
    flex: 1;
}

.admin-days-input {
    width: 60px;
    font-size: 0.85rem;
    padding: 0.2rem 0.4rem;
}

.admin-links {
    display: flex;
    gap: 1.25rem;
    margin-bottom: 0.75rem;
}

.expand-panel {
    margin: 1rem 0;
}

.expand-panel summary {
    cursor: pointer;
    list-style: none;
}

.expand-panel summary::-webkit-details-marker {
    display: none;
}

.expand-panel[open] summary {
    margin-bottom: 0.75rem;
}

/* profile_edit.php sections -- collapsible <details> so the page doesn't
   force one long scroll through every section at once (see faq-item above
   for the same summary::after +/- toggle convention). Fragment links that
   point INTO a closed section (e.g. profile_edit.php?edit_education=5#education-form,
   or the post-save redirect's own #anchor) still work with zero JS: modern
   browsers auto-open a closed <details> when navigation targets its id or
   something inside it. */
.profile-section summary {
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
    list-style: none;
}

.profile-section summary::-webkit-details-marker {
    display: none;
}

.profile-section summary h2 {
    margin: 0;
}

.profile-section summary::after {
    content: '+';
    flex-shrink: 0;
    margin-left: 1rem;
    font-weight: 400;
    font-size: 1.4rem;
    line-height: 1;
    color: var(--color-primary);
    display: inline-block;
    /* Rotating the same "+" glyph 45° reads as "×" (close) -- a smoother,
       more modern affordance than the old instant +/− content swap, and
       one that's actually animatable since it's the same character. */
    transition: transform var(--duration-base) var(--ease-spring);
}

.profile-section[open] summary::after {
    transform: rotate(45deg);
}

.profile-section[open] summary {
    margin-bottom: 1rem;
}

/* Content inside an opened section eases in rather than snapping into
   view. @starting-style is what makes a transition possible at all on an
   element going from not-rendered (closed <details>) to rendered -- on a
   browser that doesn't support it yet, this block is simply ignored and
   the content appears exactly as it always did, so there's no fallback
   branch to maintain. */
.profile-section > *:not(summary),
.expand-panel > *:not(summary) {
    transition: opacity var(--duration-slow) var(--ease-out), transform var(--duration-slow) var(--ease-out);
}

@starting-style {
    .profile-section[open] > *:not(summary),
    .expand-panel[open] > *:not(summary) {
        opacity: 0;
        transform: translateY(-8px);
    }
}

.faq-list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin: 1.5rem 0;
}

.faq-item {
    margin: 0;
    padding: 1rem 1.25rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

.faq-item summary {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    font-weight: 600;
}

.faq-item summary::after {
    content: '+';
    flex-shrink: 0;
    font-weight: 400;
    color: var(--color-primary);
    font-size: 1.2rem;
}

.faq-item[open] summary::after {
    content: '\2212';
}

.faq-item p {
    margin: 0.75rem 0 0;
    color: var(--color-muted);
}

.job-post-fields,
.job-apply-form {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    max-width: 480px;
    padding: 1rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
}

.job-posting-card .status-badge {
    margin-top: 0.5rem;
}

.achievement-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0.75rem 0;
}

.achievement-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.25rem 0.65rem;
    border-radius: 999px;
    background: var(--color-accent-light);
    color: var(--color-warning);
    font-size: 0.78rem;
    font-weight: 600;
}

.achievement-badge-icon {
    display: inline-flex;
    width: 14px;
    height: 14px;
}

.achievement-badge-icon svg {
    width: 100%;
    height: 100%;
}

.messages-layout {
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: 1rem;
    align-items: start;
}

@media (max-width: 760px) {
    .messages-layout {
        grid-template-columns: 1fr;
    }
}

.conversation-list {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.5rem;
}

.conversation-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem;
    border-radius: 8px;
    text-decoration: none;
    color: var(--color-text);
}

.conversation-item:hover,
.conversation-item.is-active {
    background: var(--color-primary-light);
}

.conversation-item-info {
    min-width: 0;
    flex: 1;
}

.conversation-preview {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.conversation-thread {
    min-height: 300px;
    display: flex;
    flex-direction: column;
}

.thread-messages {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    margin: 1rem 0;
    flex: 1;
}

.thread-message {
    max-width: 70%;
    padding: 0.6rem 0.9rem;
    border-radius: 12px;
    background: #eef0f4;
}

.thread-message p {
    margin: 0;
}

.thread-message-time {
    font-size: 0.72rem;
}

.thread-message-mine {
    align-self: flex-end;
    background: var(--color-primary-light);
}

.thread-reply-form {
    display: flex;
    gap: 0.5rem;
    align-items: flex-end;
}

.thread-reply-form textarea {
    flex: 1;
}

.announcements-widget {
    margin-top: 2rem;
}

.announcements-widget-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
}

.announcements-widget-head h2 {
    margin: 0;
}

.notification-list li {
    border-radius: 8px;
}

.notification-list a {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 0.75rem 1rem;
    text-decoration: none;
    color: var(--color-text);
}

.notification-unread {
    background: color-mix(in srgb, var(--color-primary) 6%, white);
    font-weight: 600;
}

.notification-time {
    white-space: nowrap;
    font-weight: 400;
}

.mutual-connections-badge {
    display: inline-flex;
    align-items: center;
    padding: 0.3rem 0.7rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--color-success) 14%, white);
    color: var(--color-success);
    font-size: 0.82rem;
    font-weight: 600;
    margin-top: 0.5rem;
}

.chart-legend strong {
    color: var(--color-text);
}

.legend-percent {
    color: var(--color-muted);
    font-size: 0.85em;
}

/* Chart section under a chart-card, giving each new stat block (employment
   rate by school, most-employed professions...) the same title/spacing
   rhythm as the existing chart-card blocks without duplicating that whole
   card. */
.chart-subtitle {
    margin: 1.5rem 0 0.5rem;
    font-size: 0.95rem;
    font-weight: 700;
}

.legend-swatch {
    width: 12px;
    height: 12px;
    border-radius: 3px;
    flex-shrink: 0;
}

.legend-employed {
    background: #2952cc;
}

.legend-seeking {
    background: #eb6834;
}

.legend-not-employed {
    background: #9aa0ab;
}

/* Matches CHART_ACCENTS (includes/stats.php), cycled by index -- for
   dynamic-length legends like admin.php's membership composition donut,
   where the segment count/order isn't fixed the way employment status is. */
.legend-swatch-accent-0 {
    background: #2952cc;
}

.legend-swatch-accent-1 {
    background: #f5a623;
}

.legend-swatch-accent-2 {
    background: #1c7c3c;
}

.legend-swatch-accent-3 {
    background: #7c5cff;
}

.legend-business-owner {
    background: #7c5cff;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.account-menu-trigger {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text);
    text-decoration: none;
    border-bottom: 1px dashed var(--color-border);
    white-space: nowrap;
}

.account-menu-trigger:hover {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

.nav-bell {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text);
    padding: 0.3rem;
}

.nav-bell svg {
    width: 20px;
    height: 20px;
}

.nav-bell .nav-badge {
    position: absolute;
    top: -2px;
    right: -2px;
}

.nav-badge {
    display: inline-block;
    min-width: 18px;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--color-danger);
    color: #fff;
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
    vertical-align: middle;
}

.nav-badge-blink {
    animation: nav-badge-blink 1.1s ease-in-out infinite;
}

@keyframes nav-badge-blink {
    0%, 100% {
        opacity: 1;
    }
    50% {
        opacity: 0.35;
    }
}

/* Cake + firework bursts, shown once on the homepage when the logged-in
   viewer's own profiles.birth_date matches today (see is_birthday_today()
   and index.php) -- pure CSS animation, no JS/canvas, so it still respects
   the site's strict script-src 'self' CSP. Each .birthday-firework-N is a
   fixed position/color/delay combo (can't use inline style="" here) that
   radiates colored dots outward via a shared keyframe, box-shadow standing
   in for a burst of sparks without needing N separate elements per firework. */
.birthday-banner {
    position: relative;
    overflow: hidden;
    margin-top: 2rem;
    text-align: center;
    padding: 2.5rem 1.5rem;
    background: linear-gradient(135deg, var(--color-accent-light), #ffffff 70%);
    border-color: var(--color-accent);
}

.birthday-banner h2 {
    margin: 0.75rem 0 0.35rem;
}

.birthday-cake-icon {
    display: inline-flex;
    width: 48px;
    height: 48px;
    color: var(--color-accent);
    animation: birthday-cake-bounce 1.6s ease-in-out infinite;
}

.birthday-cake-icon svg {
    width: 100%;
    height: 100%;
}

@keyframes birthday-cake-bounce {
    0%, 100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-6px);
    }
}

.birthday-firework {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: transparent;
    animation: birthday-firework-burst 1.8s ease-out infinite;
}

.birthday-firework-1 {
    top: 20%;
    left: 15%;
    color: var(--color-primary);
    animation-delay: 0s;
}

.birthday-firework-2 {
    top: 25%;
    left: 80%;
    color: var(--color-danger);
    animation-delay: 0.45s;
}

.birthday-firework-3 {
    top: 70%;
    left: 25%;
    color: var(--color-success);
    animation-delay: 0.9s;
}

.birthday-firework-4 {
    top: 65%;
    left: 85%;
    color: var(--color-accent);
    animation-delay: 1.35s;
}

@keyframes birthday-firework-burst {
    0%, 15% {
        box-shadow: 0 0 currentColor;
        opacity: 1;
    }
    100% {
        box-shadow:
            0 -26px currentColor, 18px -18px currentColor, 26px 0 currentColor,
            18px 18px currentColor, 0 26px currentColor, -18px 18px currentColor,
            -26px 0 currentColor, -18px -18px currentColor;
        opacity: 0;
    }
}

.request-list li {
    align-items: center;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.request-person {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
}

a.request-person {
    text-decoration: none;
    color: inherit;
}

.request-reason-badge {
    display: inline-block;
    margin-top: 0.35rem;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    background: var(--color-primary-light);
    color: var(--color-primary);
    font-size: 0.78rem;
    font-weight: 600;
}

.request-message {
    margin: 0.35rem 0 0;
    font-size: 0.88rem;
    color: var(--color-muted);
    font-style: italic;
}

.request-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.request-actions .btn {
    margin-top: 0;
}

.request-form {
    max-width: 420px;
    margin: 1rem auto 0;
    text-align: left;
}

.status-approved {
    background: #e9f7ef;
    color: var(--color-success);
}

.status-pending {
    background: #fff6e0;
    color: var(--color-warning);
}

.status-rejected {
    background: #fdecea;
    color: var(--color-danger);
}

.members-locked {
    text-align: center;
    padding: 2.5rem 1.5rem;
}

.members-locked-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--color-primary-light);
    color: var(--color-primary);
    margin-bottom: 0.9rem;
}

.members-locked-icon svg {
    width: 26px;
    height: 26px;
}

.members-locked h2 {
    margin: 0 0 0.4rem;
    font-size: 1.15rem;
}

.members-locked p {
    color: var(--color-muted);
    max-width: 46ch;
    margin: 0 auto;
}

.password-field {
    position: relative;
    display: block;
}

.password-field input {
    padding-right: 2.9rem;
}

.password-toggle {
    position: absolute;
    top: 50%;
    right: 0.5rem;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: none;
    color: var(--color-muted);
    cursor: pointer;
}

.password-toggle:hover {
    color: var(--color-primary);
    background: var(--color-primary-light);
}

.password-toggle:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

.password-toggle svg {
    width: 18px;
    height: 18px;
}

/* ---------------------------------------------------------------------
   CV template picker.
   The swatches are intentionally MONOCHROME. Color is a separate axis --
   every template accepts all 12 accents from the color picker below it --
   so a colored swatch would only tell the user which default accent the
   template ships with, not what the template actually is. Instead each
   swatch is a grey mock-up of the real page: which side the sidebar is on,
   whether there's a header band, how section headings are ruled, and how
   entries are marked. The classes come from CV_TEMPLATE_SHAPES in
   includes/profile.php.
   --------------------------------------------------------------------- */
.template-picker {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 0.5rem;
}

.template-select {
    flex: 0 1 260px;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: #fff;
    font: inherit;
    font-weight: 600;
    color: var(--color-text);
    cursor: pointer;
}

.template-select:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

.template-swatch {
    position: relative;
    display: flex;
    flex: none;
    width: 132px;
    height: 92px;
    background: #fff;
    border-radius: 7px;
    overflow: hidden;
    border: 2px solid var(--color-border);
    box-shadow: var(--shadow-sm);
    transition: border-color 0.15s ease, transform 0.15s ease;
}

/* --- columns --- */
.tsw-side {
    width: 36%;
    flex: none;
    padding: 6px 5px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    background: #5b6472;
}

.tsw-body {
    flex: 1;
    min-width: 0;
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.tsw-right {
    flex-direction: row-reverse;
}

.tsw-none .tsw-side {
    display: none;
}

/* --- sidebar tone --- */
.tsw-dark .tsw-side {
    background: #23262e;
}

.tsw-soft .tsw-side {
    background: #dfe3ea;
}

.tsw-plain .tsw-side {
    background: #fff;
    box-shadow: inset -1px 0 0 #cfd4dc;
}

.tsw-night {
    background: #23262b;
}

.tsw-night .tsw-side {
    background: #16181d;
}

.tsw-panel .tsw-side {
    background: #23262e;
    border-radius: 6px;
    margin: 5px 0 5px 5px;
}

/* --- photo --- */
.tsw-avatar {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.5);
    margin: 0 auto 2px;
    flex: none;
}

.tsw-soft .tsw-avatar,
.tsw-plain .tsw-avatar {
    background: rgba(31, 36, 48, 0.22);
}

.tsw-photo-sq .tsw-avatar {
    border-radius: 4px;
}

.tsw-ring .tsw-avatar {
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.35);
}

.tsw-photo-wide .tsw-avatar {
    width: calc(100% + 10px);
    height: 20px;
    border-radius: 0;
    margin: -6px -5px 4px;
}

/* --- sidebar text lines --- */
.tsw-srow {
    height: 3px;
    border-radius: 2px;
    background: rgba(255, 255, 255, 0.42);
}

.tsw-soft .tsw-srow,
.tsw-plain .tsw-srow {
    background: rgba(31, 36, 48, 0.2);
}

.tsw-srow.tsw-short {
    width: 62%;
}

/* --- main column body lines --- */
.tsw-row {
    height: 3px;
    border-radius: 2px;
    background: #e3e6ec;
}

.tsw-row.tsw-short {
    width: 62%;
}

.tsw-night .tsw-row {
    background: #3a3f48;
}

/* --- heading rule: this is what makes each template legible at a glance --- */
.tsw-h {
    height: 6px;
    width: 58%;
    border-radius: 2px;
    background: #aab1bd;
    flex: none;
}

.tsw-under .tsw-h {
    width: 78%;
    height: 6px;
    border-radius: 0;
    background: linear-gradient(#6b7280 0 3px, transparent 3px 4px, #dfe3e9 4px 6px);
}

.tsw-double .tsw-h {
    width: 74%;
    height: 7px;
    border-radius: 0;
    background: linear-gradient(#6b7280 0 3px, transparent 3px 4px, #6b7280 4px 5px, transparent 5px 6px, #6b7280 6px 7px);
}

.tsw-bar .tsw-h {
    width: 100%;
    height: 8px;
    background: #d7dbe2;
}

.tsw-fill .tsw-h {
    width: 100%;
    height: 8px;
    background: #4a5261;
}

.tsw-pill .tsw-h {
    width: 50%;
    height: 8px;
    border-radius: 999px;
    background: #c3c9d3;
}

.tsw-tab .tsw-h {
    width: 100%;
    height: 7px;
    border-radius: 0;
    background: linear-gradient(to right, #3a4150 0 4px, #e3e6ec 4px);
}

.tsw-caps .tsw-h {
    width: 66%;
    height: 4px;
    border-radius: 0;
    background: repeating-linear-gradient(to right, #4a5261 0 5px, transparent 5px 8px);
}

.tsw-hair .tsw-h {
    width: 86%;
    height: 6px;
    border-radius: 0;
    background: linear-gradient(#6b7280 0 2px, transparent 2px 5px, #dfe3e9 5px 6px);
}

.tsw-box .tsw-h {
    width: 100%;
    height: 9px;
    box-sizing: border-box;
    border: 1px solid #b9c0ca;
    background: #f0f2f5;
}

.tsw-serif .tsw-h {
    border-radius: 0;
}

.tsw-night .tsw-h {
    background: #565d69;
}

.tsw-night.tsw-fill .tsw-h {
    background: #7d8794;
}

/* --- entry marker --- */
.tsw-cards .tsw-row {
    height: 9px;
    border-radius: 2px;
    background: linear-gradient(to right, #c3c9d3 0 2px, #f0f2f5 2px);
}

.tsw-rail .tsw-row {
    background: linear-gradient(to right, #8b93a1 0 3px, #e3e6ec 3px);
}

/* --- sheet-level shapes: bands, curves, corners, angles --- */
.tsw-top {
    display: none;
}

.tsw-band .tsw-top {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 15px;
    background: #4a5261;
    z-index: 2;
}

.tsw-band .tsw-side,
.tsw-band .tsw-body {
    padding-top: 19px;
}

.tsw-halfband .tsw-top {
    display: block;
    position: absolute;
    top: 0;
    right: 0;
    width: 64%;
    height: 13px;
    background: #4a5261;
    z-index: 2;
}

.tsw-halfband .tsw-body {
    padding-top: 17px;
}

.tsw-curve .tsw-top {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 36%;
    height: 20px;
    background: #4a5261;
    border-radius: 0 0 55% 55%;
    z-index: 2;
}

.tsw-curve .tsw-side {
    padding-top: 16px;
}

.tsw-corner .tsw-top {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 36%;
    height: 16px;
    background: #b9c0ca;
    clip-path: polygon(0 0, 100% 0, 100% 45%, 0 100%);
    z-index: 2;
}

.tsw-corner .tsw-side {
    padding-top: 14px;
}

.tsw-angle .tsw-side {
    clip-path: polygon(0 0, 100% 0, 84% 100%, 0 100%);
}

.tsw-notch .tsw-side {
    clip-path: polygon(0 0, 100% 0, 100% 76%, 76% 100%, 0 100%);
}

/* Multi-value picker rendered as togglable chips (driving licence
   categories) -- a holder usually has several, so this is checkboxes rather
   than a single-value <select>. */
.checkbox-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.checkbox-chip {
    display: inline-flex;
    align-items: center;
    cursor: pointer;
    margin: 0;
}

.checkbox-chip input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.checkbox-chip span {
    display: inline-block;
    min-width: 3rem;
    padding: 0.4rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    background: #fff;
    font-size: 0.9rem;
    font-weight: 600;
    text-align: center;
    color: var(--color-text-muted, #6b7280);
}

.checkbox-chip input:checked + span {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: #fff;
}

.checkbox-chip input:focus-visible + span {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

/* Driving-licence category picker: one card per category, laid out to
   mirror the category table printed on the back of the Greek licence
   (code, vehicle pictogram, plain-language description). */
.license-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(108px, 1fr));
    gap: 0.6rem;
    margin-bottom: 1rem;
}

.license-option {
    cursor: pointer;
    margin: 0;
}

.license-option input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.license-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.3rem;
    height: 100%;
    padding: 0.6rem 0.4rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: #fff;
    text-align: center;
}

.license-option input:checked + .license-card {
    border-color: var(--color-primary);
    background: var(--color-primary-light);
}

.license-option input:focus-visible + .license-card {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.license-code {
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--color-text);
}

/* Kept deliberately small -- this is a supporting glyph next to the code,
   not the primary identifier, so it can't outweigh the code/description
   text or the cards get noisy at 15-wide. */
.license-pictogram {
    display: inline-flex;
    color: var(--color-text-muted, #6b7280);
}

.license-option input:checked + .license-card .license-pictogram {
    color: var(--color-primary);
}

.license-pictogram svg {
    width: 34px;
    height: 15px;
}

.license-desc {
    font-size: 0.72rem;
    line-height: 1.25;
    color: var(--color-text-muted, #6b7280);
}

.gender-grid {
    display: flex;
    gap: 0.6rem;
    margin-bottom: 1rem;
}

.gender-option {
    cursor: pointer;
    margin: 0;
}

.gender-option input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.gender-card {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    background: #fff;
    font-size: 0.9rem;
    color: var(--color-text);
}

.gender-card svg {
    width: 20px;
    height: 20px;
    color: var(--color-muted);
}

.gender-card img {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    object-fit: cover;
}

.gender-option input:checked + .gender-card {
    border-color: var(--color-primary);
    background: var(--color-primary-light);
}

.gender-option input:checked + .gender-card svg {
    color: var(--color-primary);
}

.gender-option input:focus-visible + .gender-card {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.color-picker {
    display: flex;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin: 0;
}

.color-swatch {
    position: relative;
    cursor: pointer;
    line-height: 0;
}

.color-swatch input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.color-swatch-circle {
    display: block;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 2px solid #fff;
    box-shadow: 0 0 0 1px var(--color-border);
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.color-swatch:hover .color-swatch-circle {
    transform: scale(1.08);
}

.color-swatch input:checked + .color-swatch-circle {
    box-shadow: 0 0 0 2px var(--color-primary);
}

.color-swatch input:focus-visible + .color-swatch-circle {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.color-swatch-blue { background: #2952cc; }
.color-swatch-navy { background: #16375f; }
.color-swatch-teal { background: #157d7d; }
.color-swatch-green { background: #1c7c3c; }
.color-swatch-olive { background: #767b1a; }
.color-swatch-gold { background: #a67c00; }
.color-swatch-orange { background: #c56a1f; }
.color-swatch-red { background: #a52f22; }
.color-swatch-pink { background: #a53d70; }
.color-swatch-purple { background: #6b3fa0; }
.color-swatch-brown { background: #6b4630; }
.color-swatch-gray { background: #4b5563; }

.cv-accent-bar-label {
    margin-top: 1.1rem;
}

.site-footer {
    border-top: 1px solid var(--color-border);
    background: linear-gradient(180deg, transparent, var(--color-primary-light) 400%);
    padding: 1.75rem 0 2rem;
    color: var(--color-muted);
    font-size: 0.85rem;
    margin-top: 2rem;
}

.footer-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.85rem;
    text-align: center;
}

.footer-inner::before {
    content: "";
    width: 40px;
    height: 3px;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--color-primary), var(--color-accent));
}

.footer-copyright {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
}

.footer-copyright .brand-mark {
    color: var(--color-primary);
}

.footer-copyright .brand-mark svg {
    width: 16px;
    height: 16px;
}

.footer-link {
    color: var(--color-muted);
    text-decoration: underline;
}

.small-print {
    font-size: 0.8rem;
    margin-top: -0.5rem;
}

