/**
 * Tunnyl Dashboard Common Styles
 * Shared styles for dashboard, profile, community, and settings pages
 *
 * Palette and card system come from the Claude Design "Tunnyl Feed" pass,
 * with two deliberate departures from what it drew:
 *
 * 1. NO BLUE. The design used the Tailwind blue-500 accent for links, focus,
 *    unread counts and tints. That colour was removed on purpose in 0366a63
 *    and a test fails the build if its hex returns anywhere under public/ —
 *    including in a comment like this one, which is why it is described
 *    rather than quoted. Removing it is also what fixed the
 *    contrast failures on six pages. Every accent maps to the neutral ramp,
 *    and links keep their underline so colour is never the only signal
 *    (WCAG 1.4.1).
 *
 * 2. TWO OF ITS GREYS FAIL AA on its own var(--hover-bg) page background, measured:
 *      Gray 400  2.33:1   (its helper text)
 *      Gray 500  4.43:1   (its secondary text)
 *      var(--text-muted)  6.93:1   <- used instead
 *    4.43:1 is the exact figure the palette rule in CLAUDE.md already warns
 *    about. --text-muted is Gray 600 for anything sitting on a tinted
 *    surface; var(--text-secondary) stays legal on white and is kept for text inside cards.
 */

@import url('tokens.css');


/* ===== Base Reset ===== */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    /* The design specifies Roboto from Google Fonts. Not adopted: the CSP is
       `font-src 'self'` with no Google origin in style-src, so both the
       stylesheet and the font files are refused and it silently falls back to
       Helvetica anyway. Self-hosting Roboto is the fix if the typeface
       matters; until then the system stack renders identically on the Apple
       and Windows devices this audience uses. */
    font-family: var(--font-sans);
    /* Flat, per the design — the dot grid competed with the new bordered
       cards, which already carry the page's structure. */
    background-color: var(--page-bg);
    color: var(--text-primary);
    line-height: 1.6;
    min-height: 100vh;
}

/* ===== Authentication Loading Screen ===== */
/* Retired as a screen. Nine pages hid everything behind a full-page spinner
   until the profile call answered; the header, nav and sidebar chrome need no
   data and now paint immediately, with skeletons where the data goes. The
   element stays in the markup because page scripts still add .hidden to it. */
.auth-loading {
    display: none;
}
/* Except when a page has written an error into it (community.js does): then
   it is the page's error state and shows inline, above the shell. */
.auth-loading:has([role="alert"]) {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    padding: 3rem 1rem;
}

.auth-loading.hidden {
    display: none;
}

.loading-spinner {
    width: 40px;
    height: 40px;
    border: 3px solid rgba(0, 0, 0, 0.1);
    border-left: 3px solid var(--accent);
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin-bottom: 1rem;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

.loading-text {
    font-size: 1rem;
    color: rgba(0, 0, 0, 0.7);
}

/* ===== Header ===== */
.header {
    background: var(--card-bg);
    border-bottom: 1px solid var(--card-border);
    padding: 1rem 0;
    position: sticky;
    top: 0;
    z-index: 100;
}

.header-content {
    max-width: var(--shell-max);
    margin: 0 auto;
    padding: 0 var(--shell-pad);
    display: flex;
    align-items: center;
    /* flex-start, not space-between. With space-between the nav's position
       depended on how many siblings a page happened to have: pages with a
       search box (dashboard, news, profile) grouped it left, and pages without
       one (settings, connections, messages) pushed it to the centre. Same
       component, two positions, decided by an unrelated element.

       The account menu is pinned right by its own auto margin instead, which
       holds however many elements sit between. */
    justify-content: flex-start;
    gap: 2rem;
    min-height: var(--header-h);
}

.logo {
    /* The thin, large wordmark is the Tunnyl look. A 20/600 version was
       tried in Sep 2026 and reverted at Carter's request. */
    font-size: 2rem;
    font-weight: 300;
    color: var(--text-primary);
    letter-spacing: -0.02em;
    text-decoration: none;
}

.search-box {
    flex: 1;
    padding: 0.625rem 1rem;
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    font-size: 0.875rem;
}

.search-box:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--ring);
}

/* ===== Search Container & Autocomplete ===== */
.search-container {
    /* min-width: 0 so the search box absorbs the squeeze between ~768px and
       ~1000px rather than pushing the nav or the avatar out of the header. */
    min-width: 0;
    position: relative;
    flex: 1;
}

.search-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: 8px;
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
    margin-top: 0.25rem;
    z-index: 1000;
    display: none;
    max-height: 400px;
    overflow-y: auto;
}

.search-dropdown.show {
    display: block;
}

.search-dropdown-section {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--surface-3);
}

.search-dropdown-section:last-child {
    border-bottom: none;
}

.search-dropdown-title {
    font-size: 0.6875rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.375rem 1rem;
}

.search-suggestion {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.625rem 1rem;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease);
}

.search-suggestion:hover,
.search-suggestion.selected {
    background: var(--surface-3);
}

.search-suggestion-icon {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--surface-3);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.875rem;
    flex-shrink: 0;
}

.search-suggestion-icon.community {
    border-radius: 6px;
}

.search-suggestion-text {
    flex: 1;
    min-width: 0;
}

.search-suggestion-primary {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.search-suggestion-secondary {
    font-size: 0.75rem;
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.search-view-all {
    display: block;
    text-align: center;
    padding: 0.75rem;
    font-size: 0.875rem;
    color: var(--text-secondary);
    font-weight: 500;
    cursor: pointer;
    border-top: 1px solid var(--surface-3);
}

.search-view-all:hover {
    background: var(--surface-2);
}

/* ===== Header Right Section (Notifications + User) ===== */
.header-right {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    /* Pins the account menu to the right edge regardless of what precedes it. */
    margin-left: auto;
}

/* ===== Primary Navigation =====
 *
 * From the design's header bar. Its version was Feed / Communities /
 * Research / Jobs; the last two have no backend, so the slots go to Messages
 * and Connections, which were reachable only from inside the avatar dropdown
 * — and Communities had no top-level entry point at all.
 *
 * Real anchors, not click handlers: keyboard and middle-click work for free,
 * and there is no inline JavaScript for the strict script-src to refuse.
 */
.primary-nav {
    display: flex;
    align-items: center;
    gap: 4px;
}

.primary-nav-link {
    padding: 8px 14px;
    border-radius: 6px;
    font-size: 14px;
    font-weight: 400;
    color: var(--text-body);
    /* Not underlined, deliberately. The palette rule underlines text links
       because colour alone cannot distinguish them from prose; a nav item is
       distinguished by shape and position, so 1.4.1 is already satisfied and
       an underline here would just be noise. */
    text-decoration: none;
    white-space: nowrap;
}

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

/* The current page carries weight AND a background, never colour alone —
   the same reason the links above keep their underline. */
.primary-nav-link[aria-current="page"] {
    font-weight: 500;
    color: var(--text-primary);
    background: var(--hover-bg);
}

.primary-nav-link:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* ===== User Section (Header) ===== */
/* Positioning context for the dropdown, and nothing else. The interactive
   styling moved to .user-section-trigger below, because this element is now a
   plain wrapper that also contains the menu — it is not the control. */
.user-section {
    display: flex;
    align-items: center;
    position: relative;
}

/* The real control. Was a <div onclick>, which is not focusable and ignores
   Enter and Space, so the account menu was unreachable by keyboard. As a
   <button> it needs the browser's default button styling stripped back to what
   the div looked like — font and color do not inherit into a button. */
.user-section-trigger {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    cursor: pointer;
    padding: 0.5rem 0.75rem;
    border-radius: 8px;
    background: none;
    border: none;
    font: inherit;
    color: inherit;
    text-align: left;
}

.user-section-trigger:hover {
    background: var(--surface-2);
}

.user-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--avatar-bg);
    color: var(--accent-fg);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.875rem;
    font-weight: 500;
}

/* ===== Verification Badge ===== */
.verified-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    background: var(--accent);
    color: var(--accent-fg);
    border-radius: 50%;
    font-size: 10px;
    font-weight: 700;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    line-height: 1;
    flex-shrink: 0;
    margin-left: 4px;
    vertical-align: middle;
}

.verified-badge::after {
    content: 'T';
}

/* Larger badge variant for profile pages */
.verified-badge.verified-badge-lg {
    width: 20px;
    height: 20px;
    font-size: 12px;
    margin-left: 6px;
}

/* Extra large for profile header */
.verified-badge.verified-badge-xl {
    width: 24px;
    height: 24px;
    font-size: 14px;
    margin-left: 8px;
}

/* Badge with tooltip */
.verified-badge-wrapper {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.verified-badge-wrapper .verified-tooltip {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    background: var(--accent);
    color: var(--accent-fg);
    padding: 6px 10px;
    border-radius: 4px;
    font-size: 11px;
    font-weight: 500;
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--dur-base) var(--ease), visibility var(--dur-base) var(--ease);
    z-index: 100;
}

.verified-badge-wrapper .verified-tooltip::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: var(--accent);
}

.verified-badge-wrapper:hover .verified-tooltip {
    opacity: 1;
    visibility: visible;
}

/* Username with badge inline */
.username-verified {
    display: inline-flex;
    align-items: center;
    gap: 0;
}

.user-name {
    font-size: 0.875rem;
    font-weight: 500;
}

.user-dropdown {
    position: absolute;
    top: 100%;
    right: 0;
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: 6px;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
    padding: 0.5rem 0;
    min-width: 180px;
    z-index: 1000;
    display: none;
    margin-top: 0.5rem;
}

.user-dropdown.show {
    display: block;
}

.dropdown-item {
    display: block;
    padding: 0.625rem 1rem;
    color: rgba(0, 0, 0, 0.8);
    text-decoration: none;
    font-size: 0.875rem;
    cursor: pointer;
    border: none;
    background: none;
    width: 100%;
    text-align: left;
}

.dropdown-item:hover {
    background: var(--surface-2);
}

.logout-btn {
    /* var(--danger) is 3.76:1 on the dropdown's white background — under AA for
       text. var(--danger) is 4.83:1 and is what the other 29 files use. */
    color: var(--danger) !important;
    border-top: 1px solid var(--card-border);
    margin-top: 0.5rem;
    padding-top: 1rem !important;
}

/* ===== Main Layout ===== */
.dashboard-content {
    display: block;
}

.dashboard-content.show {
    display: block;
}

.main-container {
    max-width: var(--shell-max);
    margin: 0 auto;
    padding: 20px var(--shell-pad) 80px;
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr) 300px;
    gap: var(--col-gap);
    /* minmax(0, 1fr) and align-items: start both come from the design. The
       first stops a long post title from widening the centre column past its
       share; the second is the correct way to keep a grid item at its natural
       height, which the sticky columns rely on. */
    align-items: start;
}

/* Two-column layout variant (for profile, settings) */
.main-container.two-column {
    grid-template-columns: 1fr 320px;
}

/* Single column layout variant */
.main-container.single-column {
    grid-template-columns: 1fr;
    max-width: 800px;
}

/* ===== Sidebar ===== */
.sidebar {
    position: sticky;
    top: var(--sticky-top);
    /* align-items: start on the grid now handles this; kept because
       .trending-section is also used outside that grid. */
    height: fit-content;

    /* With a realistic number of communities this column is taller than the
       viewport — measured at 1134px against an 800px screen — and a sticky
       element pins the moment you scroll, so everything past the fold could
       never be reached at any scroll position. The bottom of the list was not
       hard to find; it was unreachable.

       Its own scrollbar keeps the column pinned alongside the feed while
       making the whole list available. Note this is overflow on the sticky
       element ITSELF, which is fine — it is overflow on an ANCESTOR that
       silently disables position: sticky. */
    max-height: calc(100vh - var(--sticky-top) - var(--col-gap));
    overflow-y: auto;
    /* Without this, reaching the end of the community list hands the scroll to
       the page and the feed lurches, which reads as the column "jumping". */
    overscroll-behavior: contain;
}

.sidebar-section {
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--card-radius);
    box-shadow: none;
    padding: 14px 16px;
    margin-bottom: var(--stack-gap);
    overflow: hidden;
}

.sidebar-title {
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    /* On white inside the card, so --text-secondary is legal here (4.83:1).
       The rule that was here drew a divider under every heading; the card
       border now does that job and the divider read as a double line. */
    color: var(--text-secondary);
    margin-bottom: 0.5rem;
}

/* ===== Community Item ===== */
.community-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 9px 8px;
    border-radius: 6px;
    border-left: 2px solid transparent;
    cursor: pointer;
    margin-bottom: 2px;
}

.community-item:hover {
    background: var(--hover-bg);
    /* The design marks the hovered row with a 2px left edge in its blue.
       Monochrome here; the transparent border in the base rule reserves the
       space so the row does not shift by 2px on hover. */
    border-left-color: var(--accent);
}

.community-icon {
    width: 36px;
    height: 36px;
    border-radius: 6px;
    background: var(--avatar-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.125rem;
}

.community-info {
    flex: 1;
}

.community-name {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--text-primary);
}

.community-members {
    font-size: 0.75rem;
    color: var(--text-secondary);
}

/* ===== Feed ===== */
.feed {
    max-width: 680px;
}

/* ===== Card Component ===== */
.card {
    background: var(--card-bg);
    border: none;
    border-radius: 0;
    padding: 1.5rem;
    margin-bottom: 1.5rem;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}

/* ===== Post Creation ===== */
.post-creation {
    background: var(--card-bg);
    border: none;
    border-radius: 0;
    padding: 1.5rem;
    margin-bottom: 0;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}

.post-textarea {
    width: 100%;
    min-height: 100px;
    padding: 1rem;
    border: 1px solid var(--card-border);
    border-radius: 6px;
    font-family: inherit;
    font-size: 0.9375rem;
    resize: vertical;
    margin-bottom: 1rem;
}

.post-textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--ring);
}

.post-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.visibility-select {
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--card-border);
    border-radius: 6px;
    font-size: 0.875rem;
}

/* ===== Buttons ===== */
.btn-primary,
.post-button {
    padding: 0.625rem 1.5rem;
    background: var(--accent);
    color: var(--accent-fg);
    border: none;
    border-radius: 6px;
    font-weight: 500;
    cursor: pointer;
    font-size: 0.875rem;
}

.btn-primary:hover,
.post-button:hover {
    background: var(--accent-hover);
}

.btn-primary:disabled,
.post-button:disabled {
    background: var(--border-strong);
    cursor: not-allowed;
}

.btn-secondary {
    padding: 0.625rem 1.5rem;
    background: var(--card-bg);
    color: var(--text-primary);
    border: 1px solid var(--accent);
    border-radius: 6px;
    font-weight: 500;
    cursor: pointer;
    font-size: 0.875rem;
}

.btn-secondary:hover {
    background: var(--surface-2);
}

/* ===== Post Card ===== */
.post-card {
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--card-radius);
    box-shadow: none;
    padding: 20px;
    margin-bottom: var(--stack-gap);
}

.post-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1rem;
}

.post-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--avatar-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--accent-fg);
    font-weight: 500;
}

.post-author-info {
    flex: 1;
}

.post-author-name {
    font-weight: 600;
    font-size: 0.9375rem;
}

.post-metadata {
    font-size: 0.8125rem;
    color: var(--text-secondary);
}

.post-content {
    font-size: 1.0625rem;
    line-height: 1.75;
    margin-bottom: 1rem;
    white-space: pre-wrap;
}

.post-community-tag {
    display: inline-block;
    padding: 0.25rem 0.75rem;
    background: var(--surface-3);
    color: var(--text-secondary);
    border-radius: 4px;
    font-size: 0.8125rem;
    font-weight: 500;
    margin-bottom: 1rem;
    letter-spacing: 0.02em;
}

.post-stats {
    display: flex;
    gap: 1.5rem;
    padding: 0.75rem 0;
    border-top: 1px solid var(--surface-3);
    border-bottom: 1px solid var(--surface-3);
    margin-bottom: 0.5rem;
    font-size: 0.8125rem;
    color: var(--text-secondary);
}

.post-actions-bar {
    display: flex;
    gap: 0.5rem;
}

.action-button {
    flex: 1;
    padding: 0.625rem;
    background: none;
    border: none;
    border-radius: 6px;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--text-secondary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
}

.action-button:hover {
    background: var(--surface-2);
}

.action-button.liked {
    color: var(--text-primary);
}

/* ===== Right Sidebar - Trending ===== */
.trending-section {
    position: sticky;
    top: var(--sticky-top);
    /* align-items: start on the grid now handles this; kept because
       .trending-section is also used outside that grid. */
    height: fit-content;

    /* Same problem as .sidebar, slightly worse: 1168px against an 800px
       viewport. See the comment there for why overflow here does not break
       the stickiness. */
    max-height: calc(100vh - var(--sticky-top) - var(--col-gap));
    overflow-y: auto;
    overscroll-behavior: contain;
}

.trending-card {
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--card-radius);
    box-shadow: none;
    padding: 14px 16px;
    margin-bottom: var(--stack-gap);
}

.trending-title {
    font-size: 0.75rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
    margin-bottom: 0.75rem;
    padding-bottom: 0.75rem;
    border-bottom: 1px solid var(--card-border);
}

.trending-item {
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--surface-3);
}

.trending-item:last-child {
    border-bottom: none;
}

.trending-tag {
    font-size: 1rem;
    font-weight: 500;
    color: var(--text-primary);
}

.trending-count {
    font-size: 0.8125rem;
    color: var(--text-secondary);
}

/* ===== Empty State ===== */
.empty-state {
    text-align: center;
    padding: 3rem 2rem;
    color: var(--text-secondary);
}

.empty-state-icon {
    font-size: 3rem;
    margin-bottom: 1rem;
}

/* ===== Form Inputs ===== */
.form-group {
    margin-bottom: 1.5rem;
}

.form-label {
    display: block;
    font-size: 0.875rem;
    font-weight: 500;
    margin-bottom: 0.5rem;
    color: var(--text-primary);
}

.form-input {
    width: 100%;
    padding: 0.75rem 1rem;
    border: 1px solid var(--card-border);
    border-radius: 6px;
    font-size: 0.9375rem;
    font-family: inherit;
}

.form-input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--ring);
}

.form-textarea {
    width: 100%;
    min-height: 120px;
    padding: 0.75rem 1rem;
    border: 1px solid var(--card-border);
    border-radius: 6px;
    font-size: 0.9375rem;
    font-family: inherit;
    resize: vertical;
}

.form-textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--ring);
}

/* ===== Tabs ===== */
.tabs {
    display: flex;
    border-bottom: 1px solid var(--card-border);
    margin-bottom: 1.5rem;
}

.tab {
    padding: 0.75rem 1.5rem;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--text-secondary);
    border: none;
    background: none;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

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

.tab.active {
    color: var(--text-primary);
    border-bottom-color: var(--accent);
}

/* ===== Connection Button ===== */
.connect-btn {
    padding: 0.5rem 1rem;
    background: var(--accent);
    color: var(--accent-fg);
    border: none;
    border-radius: 6px;
    font-weight: 500;
    cursor: pointer;
    font-size: 0.8125rem;
}

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

.connect-btn.connected {
    background: var(--card-bg);
    color: var(--text-primary);
    border: 1px solid var(--card-border);
}

.connect-btn.pending {
    background: var(--surface-3);
    color: var(--text-secondary);
    cursor: default;
}

/* ===== Toast Notifications ===== */
@keyframes slideIn {
    from {
        transform: translateX(100%);
        opacity: 0;
    }
    to {
        transform: translateX(0);
        opacity: 1;
    }
}

@keyframes slideOut {
    from {
        transform: translateX(0);
        opacity: 1;
    }
    to {
        transform: translateX(100%);
        opacity: 0;
    }
}

/* ===== Loading Skeletons ===== */
.skeleton {
    background: linear-gradient(90deg, var(--skeleton-1) 25%, var(--skeleton-2) 50%, var(--skeleton-1) 75%);
    background-size: 200% 100%;
    animation: shimmer 1.5s infinite;
    border-radius: 4px;
}

@keyframes shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

.skeleton-text {
    height: 1rem;
    margin-bottom: 0.5rem;
}

.skeleton-text.short {
    width: 60%;
}

.skeleton-text.medium {
    width: 80%;
}

.skeleton-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
}

.skeleton-card {
    padding: 1.5rem;
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: 8px;
    margin-bottom: 1rem;
}

/* ===== Error States ===== */
.error-state {
    text-align: center;
    padding: 2rem;
    background: var(--danger-tint);
    border: 1px solid var(--danger-border);
    border-radius: 8px;
    margin-bottom: 1rem;
}

/*
 * Gray 600 for text on a tinted surface.
 *
 * Gray 500 (var(--text-secondary)) measures 4.83:1 on white and passes AA there, but only
 * 4.41:1 on this error tint and 4.43:1 on Gray 100 — both below the 4.5:1 AA
 * needs. The palette note in CLAUDE.md already says never to put text on the
 * decorative greys at those values; this is the same hazard one step along,
 * where the text colour is fine and the surface underneath is what moved.
 */
.error-state p,
.error-state a,
.error-state li,
.error-state .muted {
    color: var(--text-muted);
}

.error-state-icon {
    font-size: 2rem;
    margin-bottom: 0.5rem;
}

.error-state-message {
    color: var(--danger-strong);
    font-size: 0.9375rem;
    margin-bottom: 1rem;
}

.retry-btn {
    padding: 0.5rem 1.25rem;
    /* Was var(--danger), which is 3.76:1 against the white label — under AA. It
       survived the contrast audit because this button only exists inside an
       error state, and nothing in the suite made an API fail, so axe never
       saw it rendered. var(--danger) measures 4.83:1 and was already the hover
       colour, so nothing about the design moves. */
    background: var(--danger);
    color: var(--accent-fg);
    border: none;
    border-radius: 6px;
    font-weight: 500;
    cursor: pointer;
    font-size: 0.875rem;
}

.retry-btn:hover {
    /* 6.47:1, and still visibly a step darker now that the base moved. */
    background: var(--danger-strong);
}

/* ===== Mobile Navigation ===== */
.hamburger-btn {
    display: none;
    width: 40px;
    height: 40px;
    padding: 8px;
    background: none;
    border: none;
    cursor: pointer;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
}

.hamburger-btn span {
    display: block;
    width: 24px;
    height: 2px;
    background: var(--accent);
    transition: background-color var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease), color var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease), opacity var(--dur-base) var(--ease);
}

.hamburger-btn.active span:nth-child(1) {
    transform: rotate(45deg) translate(5px, 5px);
}

.hamburger-btn.active span:nth-child(2) {
    opacity: 0;
}

.hamburger-btn.active span:nth-child(3) {
    transform: rotate(-45deg) translate(5px, -5px);
}

/* Mobile Menu Overlay */
.mobile-menu-overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 998;
    opacity: 0;
    transition: opacity var(--dur-base) var(--ease);
}

.mobile-menu-overlay.show {
    display: block;
    opacity: 1;
}

/* Mobile Sidebar */
.mobile-sidebar {
    position: fixed;
    top: 0;
    left: -300px;
    width: 280px;
    height: 100%;
    background: var(--card-bg);
    z-index: 999;
    overflow-y: auto;
    transition: left var(--dur-base) var(--ease);
    box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
}

.mobile-sidebar.show {
    left: 0;
}

.mobile-sidebar-header {
    padding: 1.5rem;
    border-bottom: 1px solid var(--card-border);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.mobile-sidebar-content {
    padding: 1rem;
}

.mobile-nav-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.875rem 1rem;
    color: var(--text-primary);
    text-decoration: none;
    border-radius: 8px;
    margin-bottom: 0.25rem;
    font-size: 0.9375rem;
}

.mobile-nav-item:hover {
    background: var(--hover-bg);
}

.mobile-nav-item.active {
    background: var(--hover-bg);
    font-weight: 500;
}

.mobile-nav-divider {
    height: 1px;
    background: var(--card-border);
    margin: 1rem 0;
}

.close-sidebar-btn {
    width: 32px;
    height: 32px;
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
    color: var(--text-secondary);
}

/* ===== Responsive ===== */
/* Below 1200px the shell has to give up a column, and below 900px a second
   one. Both used to do that with `display: none`, which did not move the
   content anywhere — Communities was unreachable from 769px to 1200px (a
   laptop that is not maximised) and Trending and Security News were
   unreachable below 900px on every device. Nothing covered the gap: the
   hamburger menu that carries Communities only appears at 768px, and it has
   never carried Trending or News at all.

   So the columns re-flow instead. Communities becomes a horizontal strip
   ABOVE the feed — above, not below, because the feed is unbounded and
   anything placed after it is unreachable for a different reason. Trending
   is reference material rather than navigation, so it is the one column that
   can afford to sit after the feed, and only at 900px where there is
   genuinely no room beside it. */
@media (max-width: 1200px) {
    .main-container {
        grid-template-columns: minmax(0, 1fr) 300px;
    }

    .main-container.two-column {
        grid-template-columns: 1fr;
    }

    /* `order` applies because every child of .main-container is a grid item.
       The create-community modal is one too, but it is display: none until
       opened and position: fixed once it is, so it never joins this flow. */
    .sidebar {
        grid-column: 1 / -1;
        order: -1;
    }

    /* The sticky pin and the column's own scrollbar exist to make a tall
       vertical list reachable. Laid out horizontally it is neither tall nor
       pinned, and a max-height would clip the strip instead. */
    .sidebar {
        position: static;
        max-height: none;
        overflow: visible;
    }

    .sidebar .sidebar-section {
        margin-bottom: 0;
    }

    .community-list {
        display: flex;
        gap: 0.5rem;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        /* Room for the horizontal scrollbar on platforms that reserve space,
           so it does not sit on top of the last row of text. */
        padding-bottom: 4px;
    }

    .community-list > .community-item {
        flex: 0 0 auto;
        min-width: 180px;
        margin-bottom: 0;
        /* The hover marker is a 2px left edge in the vertical list; between
           chips that reads as a stray tick, so the whole chip carries the
           border and the hover moves its colour. Same reserved space either
           way, so nothing shifts on hover. */
        border: 1px solid var(--card-border);
    }

    .community-list > .community-item:hover {
        border-color: var(--accent);
    }

    /* The skeleton, empty and error states are not .community-item, so the
       strip has to be told what to do with them: skeleton and empty rows take
       a chip's width, the error state takes the whole strip because it owns a
       retry button. */
    .community-list > :not(.community-item) {
        flex: 0 0 auto;
        min-width: 180px;
    }

    .community-list > .error-state {
        flex: 1 1 100%;
    }
}

@media (max-width: 900px) {
    .main-container {
        grid-template-columns: minmax(0, 1fr);
    }

    .trending-section {
        order: 1;
        position: static;
        max-height: none;
        overflow: visible;
        /* Trending and Security News sit side by side while there is room, so
           News is not a second screen further down. */
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
        gap: var(--stack-gap);
        align-items: start;
    }

    .trending-section > .trending-card {
        margin-bottom: 0;
    }

    /* The 680px cap keeps the feed readable beside two other columns. Alone in
       a single column on a narrow viewport it would just leave dead space. */
    .feed {
        max-width: none;
    }
}

@media (max-width: 768px) {
    /* Hidden at precisely the width the hamburger appears, so there is never a
       viewport with neither the bar nor the menu. The mobile sidebar carries
       the same destinations. */
    .primary-nav {
        display: none;
    }

    .hamburger-btn {
        display: flex;
    }

    .header-content {
        padding: 0 1rem;
        flex-wrap: wrap;
        gap: 0.5rem;
    }

    .main-container {
        padding: 1rem;
    }

    /* Search container mobile - full width below header */
    .search-container {
        flex: 1 1 100%;
        max-width: none;
        order: 10;
        margin-top: 0.5rem;
    }

    .search-box {
        width: 100%;
        max-width: none;
    }

    /* Search dropdown mobile improvements */
    .search-dropdown {
        max-height: 60vh;
        border-radius: 0 0 8px 8px;
    }

    .search-suggestion {
        padding: 0.875rem 1rem;
    }

    .search-suggestion-icon {
        width: 40px;
        height: 40px;
        font-size: 1rem;
    }

    .user-name {
        display: none;
    }

    .logo {
        font-size: 1.5rem;
    }

    /* Header right - compact on mobile */
    .header-right {
        gap: 0.25rem;
    }

    /* Notification bell touch target */
    .notification-bell {
        min-width: 44px;
        min-height: 44px;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    /* Post card mobile adjustments */
    .post-card {
        padding: 1rem;
        margin-bottom: 0.5rem;
        border-radius: 0;
        border-left: none;
        border-right: none;
    }

    .post-avatar {
        width: 40px;
        height: 40px;
    }

    .post-author-name {
        font-size: 0.875rem;
    }

    .post-content {
        font-size: 0.9375rem;
        line-height: 1.5;
    }

    .post-stats {
        gap: 1rem;
        flex-wrap: wrap;
    }

    /* Touch-friendly action buttons */
    .action-button {
        padding: 0.75rem 0.5rem;
        font-size: 0.875rem;
        min-height: 44px;
    }

    .post-actions-bar {
        gap: 0.25rem;
    }

    /* Feed container */
    .feed {
        max-width: 100%;
    }

    /* Post creation mobile */
    .post-creation {
        border-radius: 0;
        border-left: none;
        border-right: none;
        margin: 0 -1rem 1rem;
        padding: 1rem;
    }

    .post-textarea {
        min-height: 80px;
        font-size: 1rem;
    }

    .post-actions {
        flex-direction: column;
        gap: 0.75rem;
    }

    .post-actions .visibility-select {
        width: 100%;
        min-height: 44px;
    }

    .post-actions .post-button {
        width: 100%;
        min-height: 44px;
    }

    /* User dropdown mobile */
    .user-dropdown {
        right: -0.5rem;
        min-width: 180px;
    }

    .dropdown-item {
        padding: 0.875rem 1rem;
        font-size: 0.9375rem;
    }

    /* Cards and sections */
    .card,
    .sidebar-section {
        border-radius: 0;
        border-left: none;
        border-right: none;
    }

    /* Trending section on mobile - show as horizontal scroll */
    .trending-section.mobile-visible {
        display: block;
        margin: 0 -1rem 1rem;
        padding: 1rem;
        overflow-x: auto;
        white-space: nowrap;
        -webkit-overflow-scrolling: touch;
    }

    .trending-section.mobile-visible .trending-item {
        display: inline-block;
        margin-right: 0.75rem;
        white-space: normal;
        width: 200px;
        vertical-align: top;
    }
}

@media (max-width: 480px) {
    .header-content {
        gap: 0.5rem;
        padding: 0 0.75rem;
    }

    .logo {
        font-size: 1.25rem;
    }

    .user-section {
        padding: 0.25rem 0.5rem;
    }

    .user-avatar {
        width: 36px;
        height: 36px;
        font-size: 0.8125rem;
    }

    .post-header {
        gap: 0.5rem;
    }

    .post-avatar {
        width: 36px;
        height: 36px;
    }

    /* Hide action button text on small screens */
    .action-button span:not(:first-child) {
        display: none;
    }

    .action-button {
        font-size: 1rem;
    }

    /* Search styles */
    .search-container {
        margin-top: 0.375rem;
    }

    .search-box {
        padding: 0.75rem 1rem;
        font-size: 1rem;
    }

    .search-suggestion {
        padding: 1rem;
    }

    /* Post content */
    .post-content {
        font-size: 0.9375rem;
    }

    .post-card {
        padding: 0.875rem;
    }

    /* Mobile sidebar adjustments */
    .mobile-sidebar {
        width: 85vw;
        max-width: 300px;
    }

    .mobile-nav-item {
        padding: 1rem;
        font-size: 1rem;
    }

    /* Profile page mobile */
    .profile-container {
        padding: 0;
    }

    .profile-header {
        border-radius: 0;
        border-left: none;
        border-right: none;
        padding: 1rem;
    }

    .profile-banner {
        height: 120px;
        margin-bottom: -40px;
    }

    .profile-avatar-large {
        width: 80px;
        height: 80px;
        font-size: 1.75rem;
    }

    .profile-name {
        font-size: 1.5rem;
    }

    .profile-stats {
        gap: 1.5rem;
    }

    .stat-value {
        font-size: 1.25rem;
    }

    /* Community page mobile */
    .community-container {
        padding: 0;
    }

    .community-header {
        border-radius: 0;
        border-left: none;
        border-right: none;
        padding: 1rem;
    }

    .community-banner {
        height: 120px;
        font-size: 3rem;
    }

    .community-name {
        font-size: 1.5rem;
    }

    .community-info {
        flex-direction: column;
        gap: 1rem;
    }

    .community-actions {
        width: 100%;
    }

    .community-actions .action-btn {
        flex: 1;
    }

    /* Tabs mobile */
    .tab-nav {
        gap: 0;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    .tab-item {
        flex-shrink: 0;
        padding: 0.75rem 1rem;
        font-size: 0.875rem;
    }
}

/* ===== Extra Small Devices (360px and below) ===== */
@media (max-width: 360px) {
    .header-content {
        padding: 0 0.5rem;
    }

    .logo {
        font-size: 1.125rem;
    }

    .hamburger-btn {
        width: 36px;
        height: 36px;
        padding: 6px;
    }

    .hamburger-btn span {
        width: 20px;
    }

    .user-avatar {
        width: 32px;
        height: 32px;
    }

    .search-box {
        padding: 0.625rem 0.75rem;
        font-size: 0.9375rem;
    }

    .post-card {
        padding: 0.75rem;
    }

    .post-avatar {
        width: 32px;
        height: 32px;
    }

    .profile-avatar-large {
        width: 64px;
        height: 64px;
        font-size: 1.5rem;
    }

    .profile-name {
        font-size: 1.25rem;
    }

    .community-banner {
        height: 100px;
        font-size: 2.5rem;
    }
}

/* ===== Safe Area Support (Notched Phones) ===== */
@supports (padding: env(safe-area-inset-top)) {
    .header {
        padding-top: env(safe-area-inset-top);
    }

    .mobile-sidebar {
        padding-top: env(safe-area-inset-top);
        padding-bottom: env(safe-area-inset-bottom);
        padding-left: env(safe-area-inset-left);
    }

    .main-container {
        padding-left: calc(1rem + env(safe-area-inset-left));
        padding-right: calc(1rem + env(safe-area-inset-right));
    }

    @media (max-width: 768px) {
        .main-container {
            padding-left: env(safe-area-inset-left);
            padding-right: env(safe-area-inset-right);
        }
    }
}

/* ===== Touch Device Optimizations ===== */
@media (hover: none) and (pointer: coarse) {
    /* Larger touch targets */
    .action-button,
    .dropdown-item,
    .mobile-nav-item,
    .tab-item {
        min-height: 44px;
    }

    /* Remove hover effects on touch devices */
    .post-card:hover,
    .member-item:hover,
    .connection-item:hover {
        background: inherit;
    }

    /* Active state instead of hover */
    .action-button:active {
        background: var(--card-border);
    }

    .post-card:active {
        background: var(--surface-2);
    }

    /* Smooth scrolling for touch */
    .search-dropdown,
    .tab-nav,
    .trending-section {
        -webkit-overflow-scrolling: touch;
        scroll-behavior: smooth;
    }

    /* Prevent text selection on interactive elements */
    .action-button,
    .mobile-nav-item,
    .tab-item {
        -webkit-user-select: none;
        user-select: none;
    }
}

/* ===== Landscape Mode Adjustments ===== */
@media (max-height: 500px) and (orientation: landscape) {
    .header {
        padding: 0.5rem 0;
    }

    .header-content {
        min-height: 48px;
    }

    .search-container {
        margin-top: 0;
        order: 0;
        flex: 0 1 300px;
    }

    .mobile-sidebar {
        width: 50vw;
    }

    .search-dropdown {
        max-height: 50vh;
    }
}

/* ===== Infinite Scroll Loading ===== */
.load-more-indicator {
    text-align: center;
    padding: 1.5rem;
    color: var(--text-secondary);
}

.load-more-indicator .loading-spinner {
    margin: 0 auto;
}

/* ── Accessibility ───────────────────────────────────────────────────────── */

/* Keyboard skip link. Off-screen until focused, so it costs sighted users
   nothing while giving keyboard users a way past the header on every page. */
.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 10000;
    padding: 0.75rem 1rem;
    background: var(--accent);
    color: var(--accent-fg);
    text-decoration: none;
    border-radius: 0 0 6px 0;
}

.skip-link:focus {
    left: 0;
}

/* Every interactive control here is custom-styled, and several reset `outline`
   or `border` away. Without an explicit rule, keyboard focus is invisible —
   the page is operable but you cannot see where you are. */
:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Photos in every avatar circle. The containers were text-only initials;
   TunnylAvatar.markup() drops an <img> into the same box. */
.post-avatar, .comment-avatar, .connection-avatar, .member-avatar, .conversation-avatar,
.chat-avatar, .user-avatar-large, .mention-avatar, .notification-avatar, .notification-row-avatar,
.activity-avatar, .chat-conversation-avatar, .chat-message-avatar {
    overflow: hidden;
}
.post-avatar img.avatar-img, .comment-avatar img.avatar-img, .connection-avatar img.avatar-img,
.member-avatar img.avatar-img, .conversation-avatar img.avatar-img, .chat-avatar img.avatar-img,
.user-avatar-large img.avatar-img, .mention-avatar img.avatar-img,
.activity-avatar img.avatar-img, .chat-conversation-avatar img.avatar-img, .chat-message-avatar img.avatar-img {
    width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block;
}

/* Report dialog (js/utils/report-dialog.js). */
.tn-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 1200; display: flex; align-items: center; justify-content: center; padding: 1rem; }
.tn-modal-overlay[hidden] { display: none; }
.tn-modal { background: var(--card-bg); color: var(--text-primary); border-radius: 12px; width: 100%; max-width: 32rem; max-height: 90vh; overflow: auto; padding: 1.25rem 1.25rem 1rem; box-shadow: 0 20px 50px rgba(0,0,0,0.25); }
.tn-modal-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.tn-modal-head h2 { margin: 0; font-size: 1.15rem; }
.tn-modal-close { background: none; border: 0; font-size: 1.5rem; line-height: 1; cursor: pointer; color: var(--text-muted); padding: 0.25rem 0.5rem; border-radius: 6px; }
.tn-modal-close:focus-visible { outline: 2px solid var(--accent); }
.tn-modal-intro { color: var(--text-muted); font-size: 0.9rem; margin: 0.5rem 0 1rem; }
.tn-report-reasons { border: 0; padding: 0; margin: 0 0 1rem; display: grid; gap: 0.35rem; }
.tn-report-reason { display: flex; gap: 0.6rem; align-items: flex-start; padding: 0.5rem 0.6rem; border: 1px solid var(--card-border); border-radius: 8px; cursor: pointer; }
.tn-report-reason:has(input:checked) { border-color: var(--accent); background: var(--hover-bg); }
.tn-report-reason input { margin-top: 0.3rem; }
.tn-report-reason strong { display: block; font-size: 0.92rem; }
.tn-report-reason small { display: block; color: var(--text-muted); font-size: 0.8rem; }
.tn-report-note { display: block; margin-bottom: 0.75rem; font-size: 0.9rem; }
.tn-report-note span { display: block; margin-bottom: 0.35rem; }
.tn-report-note em { color: var(--text-secondary); font-style: normal; }
.tn-report-note textarea { width: 100%; border: 1px solid var(--border-strong); border-radius: 8px; padding: 0.5rem 0.6rem; font: inherit; resize: vertical; }
.tn-report-error { color: var(--danger-strong); min-height: 1.2rem; margin: 0 0 0.5rem; font-size: 0.875rem; }
.tn-modal-actions { display: flex; justify-content: flex-end; gap: 0.5rem; }
.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; }
.post-report-btn, .comment-action.report { background: none; border: 0; color: var(--text-secondary); cursor: pointer; font: inherit; font-size: 0.8rem; padding: 0.35rem 0.5rem; border-radius: 6px; }
.post-report-btn:hover, .post-report-btn:focus-visible, .comment-action.report:hover { color: var(--text-primary); background: var(--hover-bg); outline: none; }


/* ===== Search shortcut hint ===== */
/* ⌘K / Ctrl K sits inside the search box; shell.js sets the label for the
   platform and handles the key. Hidden on touch widths, where there is no
   keyboard to hint at. */
.search-kbd {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    height: 20px;
    padding: 0 6px;
    border: 1px solid var(--card-border);
    border-radius: 4px;
    background: var(--surface-3);
    /* Gray 600 not 500: 500 is 4.43:1 on this tint, below AA. */
    color: var(--text-muted);
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 500;
    line-height: 18px;
    letter-spacing: 0.02em;
    pointer-events: none;
}
.search-container .search-box { padding-right: 56px; width: 100%; }
@media (max-width: 768px) { .search-kbd { display: none; } }

/* ===== Mobile drawer: one nav, every page ===== */
.mobile-sidebar-header .logo { font-size: 1.5rem; }
.mobile-nav-item svg { flex-shrink: 0; }
.mobile-nav-item[aria-current="page"] { background: var(--hover-bg); font-weight: 500; }
.mobile-nav-footer {
    margin-top: auto;
    border-top: 1px solid var(--card-border);
    padding: 1rem;
}
.mobile-sidebar { display: flex; flex-direction: column; }
.mobile-sidebar-content { flex: 1; }

/* ===== Skeleton rows for sidebars ===== */
.skeleton-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 9px 8px;
}
.skeleton-row .skeleton-lines { flex: 1; display: flex; flex-direction: column; gap: 6px; }
.skeleton-row .skeleton-text { margin: 0; height: 12px; }
.skeleton-square { width: 36px; height: 36px; border-radius: 6px; flex-shrink: 0; }

/* A dot on the Messages nav item when a message arrives while elsewhere. */
.primary-nav-link { position: relative; }
.nav-dot { position: absolute; top: 6px; right: 6px; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
