/* =============================================================================
   ATRIUM · 02 · BASE
   =============================================================================
   Reset, document, typography, focus, selection, scrollbars, accessibility
   primitives, and the small layout utilities every component may assume.

   Nothing here knows about any specific component. Nothing here uses a raw
   value that exists in tokens.
   ========================================================================== */

/* --- Reset ---------------------------------------------------------------- */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    scroll-behavior: smooth;
    /* Anchors and programmatic scrolls never land under fixed chrome. */
    scroll-padding-top: calc(var(--at-topbar-h) + var(--at-s4));
}

body {
    margin: 0;
    min-height: 100vh;
    min-height: 100dvh;
    font-family: var(--at-font);
    font-size: var(--at-text-md);
    font-weight: var(--at-weight-regular);
    line-height: var(--at-leading-normal);
    letter-spacing: var(--at-tracking-body);
    color: var(--at-ink);
    background-color: var(--at-bg);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    /* The sun setting: theme change is a light change, not an inversion. */
    transition: background-color var(--at-t-slower) var(--at-ease-inout),
                color var(--at-t-slower) var(--at-ease-inout);
    /* Single-storey 'l' keeps l/I/1 apart in handles; contextual alternates. */
    font-feature-settings: "cv11" 1, "ss01" 1;
}

/* --- Viewport lock (page-aware, NOT global) --------------------------------
   Auth screens (login / sign up / create channel / link account / forgot
   password) and Direct Messages are DESTINATIONS, not documents: the page
   itself must never scroll, bounce, or fire the browser's pull-to-refresh.
   viewport-lock.js stamps .is-vlock on <html> AND <body> only while such a
   page is mounted (marker: .auth-shell / .v-dm) and strips it on leave — so
   this is never global and normal document scrolling returns everywhere else.
   Internal regions (.auth-card, the DM list + thread) keep overflow:auto and
   scroll on their own. --app-vvh mirrors the visual viewport so the on-screen
   keyboard shrinks the frame instead of hiding fields; the JS clears it on
   leave, so no permanent offset is ever left behind. */
html.is-vlock,
body.is-vlock {
    height: var(--app-vvh, 100dvh);
    min-height: 0;                 /* defeat body{min-height:100dvh} while locked */
    overflow: hidden;              /* no document scroll — vertical OR horizontal */
    overscroll-behavior: none;     /* no elastic chaining, no browser pull-to-refresh */
}

/* --- Typography ------------------------------------------------------------
   Numerals are sacred: anything that counts, prices or timestamps never
   reflows as it changes. */
time,
.v-num,
[data-v-count] {
    font-variant-numeric: tabular-nums;
}

h1, h2, h3, h4, h5, h6 {
    margin: 0 0 var(--at-s3);
    font-weight: var(--at-weight-semibold);
    line-height: var(--at-leading-tight);
    letter-spacing: var(--at-tracking-title);
    color: var(--at-ink);
    text-wrap: balance;
}

h1 { font-size: var(--at-text-2xl); }
h2 { font-size: var(--at-text-xl); }
h3 { font-size: var(--at-text-lg); }
h4, h5, h6 { font-size: var(--at-text-md); }

/* THE INSCRIPTION — the identity voice. A lapidary serif, carved once at a
   single weight, reserved for names, balances and opening lines. Meeting it
   is an occasion; it never sets body copy and is never bolded. */
.v-display {
    font-family: var(--at-font-inscription);
    font-size: var(--at-display);
    font-weight: var(--at-weight-display);
    line-height: 1.12;
    letter-spacing: var(--at-tracking-display);
    text-wrap: balance;
}

.v-display-lg {
    font-family: var(--at-font-inscription);
    font-size: var(--at-display-lg);
    font-weight: var(--at-weight-display);
    line-height: 1.08;
    letter-spacing: var(--at-tracking-display);
    text-wrap: balance;
}

/* Hairline micro-label — the only sanctioned uppercase. */
.v-eyebrow {
    font-size: var(--at-text-xs);
    font-weight: var(--at-weight-semibold);
    letter-spacing: var(--at-tracking-caps);
    text-transform: uppercase;
    color: var(--at-ink-muted);
}

p {
    margin: 0 0 var(--at-s4);
    line-height: var(--at-leading-relaxed);
}

small,
.v-meta {
    font-size: var(--at-text-xs);
    letter-spacing: var(--at-tracking-meta);
    color: var(--at-ink-muted);
}

a {
    color: var(--at-accent-ink);
    text-decoration: none;
    transition: color var(--at-t-fast) var(--at-ease-out);
}

a:hover {
    color: var(--at-accent-hover);
}

/* Prose links (documents) underline; UI links do not. */
.v-prose a {
    text-decoration: underline;
    text-underline-offset: 2px;
    text-decoration-color: var(--at-hairline-strong);
}

img, svg, video, canvas {
    max-width: 100%;
    height: auto;
    vertical-align: middle;
}

hr {
    height: 1px;
    margin: var(--at-s6) 0;
    border: 0;
    background-color: var(--at-hairline);
}

code, pre, kbd, samp {
    font-family: var(--at-font-mono);
    font-size: 0.9em;
}

/* Selected text carries the brand, not the browser's default blue.
   -----------------------------------------------------------------------------
   Three things are needed for this to actually take on iOS Safari, which is why
   the earlier one-liner didn't:
     1. `background-color`, not the `background` shorthand — iOS drops the
        shorthand inside ::selection.
     2. a literal colour fallback — older iOS won't resolve var() here.
     3. an ELEMENT-SCOPED copy of the rule. The body sets
        `-webkit-user-select: none` and re-enables selection on readable elements
        (posts, comments, messages, bios, inputs); on those re-enabled regions
        iOS ignores a purely global ::selection and paints its default blue. The
        scoped rule below is what colours them.
   Dark ink on the accent stays readable against the fill in both themes. This is
   the text-SELECTION colour only — the iOS tap highlight is a separate property
   (see `-webkit-tap-highlight-color` below) and is intentionally not touched here. */
::selection      { background-color: var(--at-accent, #F07629); color: #160f08; text-shadow: none; }
::-moz-selection { background-color: var(--at-accent, #F07629); color: #160f08; text-shadow: none; }

input::selection, textarea::selection, [contenteditable]::selection,
.v-input::selection, .v-textarea::selection, .comment-input::selection,
.v-post__text::selection, .v-comment__text::selection, .chat-message::selection,
.v-dm-msg__text::selection, .v-profile__biotext::selection, .v-prose::selection,
.v-selectable::selection {
    background-color: var(--at-accent, #F07629); color: #160f08; text-shadow: none;
}
input::-moz-selection, textarea::-moz-selection, [contenteditable]::-moz-selection,
.v-input::-moz-selection, .v-textarea::-moz-selection, .comment-input::-moz-selection,
.v-post__text::-moz-selection, .v-comment__text::-moz-selection, .chat-message::-moz-selection,
.v-dm-msg__text::-moz-selection, .v-profile__biotext::-moz-selection, .v-prose::-moz-selection,
.v-selectable::-moz-selection {
    background-color: var(--at-accent, #F07629); color: #160f08; text-shadow: none;
}

/* Tap feedback is a subtle brand tint, never the iOS default grey/blue box.
   Interactive chrome (buttons, nav, cards) overrides this to transparent where
   a flash would read as un-app-like; here it is the global default for links and
   body text a finger lands on. */
html {
    -webkit-tap-highlight-color: color-mix(in srgb, var(--at-accent) 20%, transparent);
}

/* --- Focus -----------------------------------------------------------------
   Visible for the keyboard, silent for the pointer. Never removed without
   replacement — anywhere. */
:focus:not(:focus-visible) {
    outline: none;
}

:focus-visible {
    outline: 2px solid var(--at-accent);
    outline-offset: 2px;
    border-radius: var(--at-r-xs);
}

/* --- Scrollbars ------------------------------------------------------------
   A scrollbar is a hint, not a fixture: a hairline thumb on no track at all,
   which firms up under the pointer. Panels that scroll reserve their gutter
   so content never shifts sideways when the bar appears. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--at-hairline-strong) transparent;
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-corner { background: transparent; }

::-webkit-scrollbar-thumb {
    background-color: var(--at-hairline-strong);
    border: 3px solid transparent;
    border-radius: var(--at-r-pill);
    background-clip: content-box;
    transition: background-color var(--at-t-fast) var(--at-ease-out);
}

::-webkit-scrollbar-thumb:hover { background-color: var(--at-ink-faint); }
::-webkit-scrollbar-thumb:active { background-color: var(--at-ink-muted); }

/* Scroll containers hold their gutter open — an arriving scrollbar must not
   reflow the content beside it. */
.v-rail,
.offcanvas-body,
.modal-body,
.v-table-wrap,
.v-search__panel { scrollbar-gutter: stable; }

/* --- Accessibility primitives ---------------------------------------------- */
.v-visually-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

.v-skip-link {
    position: absolute;
    top: var(--at-s2);
    left: var(--at-s2);
    z-index: calc(var(--at-z-toast) + 1);
    padding: var(--at-s2) var(--at-s4);
    border-radius: var(--at-r-sm);
    background: var(--at-accent);
    color: var(--at-accent-contrast);
    font-weight: var(--at-weight-semibold);
    transform: translateY(-200%);
    transition: transform var(--at-t-base) var(--at-ease-out);
}

.v-skip-link:focus {
    transform: translateY(0);
    color: var(--at-accent-contrast);
}

/* RTL: the whole layout mirrors, not just text. Components use logical
   properties; this class marks explicit RTL scopes (Hebrew). */
[dir="rtl"] {
    text-align: start;
}

/* Directional GLYPHS in the icon font do not follow logical properties, so the
   navigational chevrons — every "back" affordance points the same way — must be
   mirrored by hand under RTL. Layout already flips; only the arrow inside does
   not. Scoped to back buttons and jump/directional controls so content icons
   (a play arrow, a send arrow) keep their meaning. */
[dir="rtl"] .v-back > i,
[dir="rtl"] .v-dm-back > i,
[dir="rtl"] .v-dm-thread__actions .fi-rr-angle-left,
[dir="rtl"] .v-btn .fi-rr-angle-left {
    transform: scaleX(-1);
}

/* Script-aware typography. Thai stacks tone marks and vowels above and below
   the baseline; a tight line-height clips them, so give inherited-leading text
   more room. Chinese has no inter-word spaces — long Latin/URL runs are the
   only overflow risk, so allow them to break rather than push a row wide. The
   rules target the html[lang] the server sets in header.php. */
html[lang="th"] body {
    line-height: var(--at-leading-relaxed, 1.7);
}

html[lang="th"] .v-btn,
html[lang="th"] .dropdown-item,
html[lang="th"] .v-menu__item {
    line-height: 1.4;
}

html[lang="zh"] .v-post__text,
html[lang="zh"] .v-comment__text,
html[lang="zh"] .v-prose,
html[lang="th"] .v-post__text,
html[lang="th"] .v-comment__text,
html[lang="th"] .v-prose {
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* --- Reduced motion: a designed state, not a fallback ----------------------
   State changes crossfade ink; nothing is hostage to an animation. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* --- Elevated contrast -----------------------------------------------------
   When the viewer asks for more contrast, the mortar firms up: the faint
   hairlines step to their strong form, muted ink rises to secondary, and the
   focus ring goes solid. No new values — the stronger member of each pair
   already exists in every theme, so this resolves correctly in Day and
   Lamplight alike. */
@media (prefers-contrast: more) {
    :root {
        --at-hairline:   var(--at-hairline-strong);
        --at-ink-muted:  var(--at-ink-secondary);
        --at-ink-faint:  var(--at-ink-muted);
        --at-focus-ring: var(--at-accent);
    }
}

/* --- Forced colors (Windows High Contrast) ---------------------------------
   ATRIUM builds hierarchy from luminance and soft shadow, never strokes. A
   forced-colors palette strips both, so without help every surface would
   flatten onto one plane. Restore a hairline on the containers and controls
   that were defined by their elevation; the system supplies the color. The
   focus ring drops the accent hue the palette would override for Highlight. */
@media (forced-colors: active) {
    .v-card, .v-post, .modal-content, .dropdown-menu, .v-menu,
    .offcanvas, .v-toast, .v-sheet {
        border: 1px solid;
    }
    .v-btn, .btn, .v-input, .form-control,
    input, textarea, select {
        border: 1px solid;
    }
    :focus-visible { outline-color: Highlight; }
}

/* =============================================================================
   LAYOUT UTILITIES
   -----------------------------------------------------------------------------
   The only utilities in the system. Everything else is a component.
   ========================================================================== */
.v-stack   { display: flex; flex-direction: column; gap: var(--at-s4); }
.v-stack-2 { display: flex; flex-direction: column; gap: var(--at-s2); }
.v-stack-6 { display: flex; flex-direction: column; gap: var(--at-s6); }
.v-row     { display: flex; align-items: center; gap: var(--at-s3); }
.v-row-2   { display: flex; align-items: center; gap: var(--at-s2); }
.v-spacer  { flex: 1 1 auto; }
.v-center  { display: flex; align-items: center; justify-content: center; }

.v-truncate {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.v-clamp-2 {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.v-ink           { color: var(--at-ink); }
.v-ink-secondary { color: var(--at-ink-secondary); }
.v-ink-muted     { color: var(--at-ink-muted); }
.v-text-xs { font-size: var(--at-text-xs); }
.v-text-sm { font-size: var(--at-text-sm); }
.v-text-lg { font-size: var(--at-text-lg); }

/* =============================================================================
   ICONS
   -----------------------------------------------------------------------------
   One stroke family, drawn ink. Works with any glyph-font or inline SVG set:
   the wrapper controls size and optical alignment; color is currentColor,
   always.
   ========================================================================== */
.v-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1em;
    height: 1em;
    font-size: var(--at-icon-md);
    line-height: 1;
    vertical-align: -0.125em;
    flex: 0 0 auto;
    color: currentColor;
}

.v-icon > svg { width: 100%; height: 100%; stroke: currentColor; fill: none; }
.v-icon::before { line-height: 1; display: block; } /* glyph-font hosts */

.v-icon--xs { font-size: var(--at-icon-xs); }
.v-icon--sm { font-size: var(--at-icon-sm); }
.v-icon--lg { font-size: var(--at-icon-lg); }

/* Icon directly preceding a label: fixed relationship, never eyeballed. */
.v-icon--lead { margin-inline-end: var(--at-s2); font-size: var(--at-icon-sm); }

/* =============================================================================
   HAIRLINES & DIVIDERS
   ========================================================================== */
.v-hairline-t { border-top: 1px solid var(--at-hairline); }
.v-hairline-b { border-bottom: 1px solid var(--at-hairline); }

.v-divider {
    display: flex;
    align-items: center;
    gap: var(--at-s3);
    margin: var(--at-s6) 0;
    color: var(--at-ink-muted);
    font-size: var(--at-text-xs);
    letter-spacing: var(--at-tracking-caps);
    text-transform: uppercase;
}

.v-divider::before,
.v-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background-color: var(--at-hairline);
}

/* =============================================================================
   KEYBOARD KEY
   ========================================================================== */
.v-kbd {
    display: inline-block;
    padding: 0.1em 0.45em;
    border-radius: var(--at-r-xs);
    background: var(--at-surface-sunken);
    box-shadow: var(--at-edge), var(--at-shadow-xs);
    color: var(--at-ink-secondary);
    font-family: var(--at-font-mono);
    font-size: var(--at-text-xs);
    line-height: 1.6;
}
