/* =============================================================================
   Xandev V3 - components
   Load after tokens.css and base.css.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
    --btn-bg: transparent;
    --btn-fg: var(--text-primary);
    --btn-border: var(--line-strong);

    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);

    padding: 0.7rem 1.25rem;
    border: 1px solid var(--btn-border);
    border-radius: var(--radius-sm);

    background: var(--btn-bg);
    color: var(--btn-fg);

    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: -0.005em;
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;

    cursor: pointer;
    transition: background-color var(--duration) var(--ease),
                border-color var(--duration) var(--ease),
                color var(--duration) var(--ease),
                transform var(--duration) var(--ease);
}

/* 1px, not the V2 lift-and-glow. At this scale the smaller movement reads as
   responsive; the larger one reads as a template. */
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn:disabled,
.btn[aria-disabled="true"] {
    opacity: 0.5;
    pointer-events: none;
}

.btn--primary {
    --btn-bg: var(--brand);
    --btn-fg: var(--text-inverse);
    --btn-border: var(--brand);
}

.btn--primary:hover {
    --btn-bg: var(--brand-strong);
    --btn-border: var(--brand-strong);
}

.btn--accent {
    --btn-bg: var(--accent);
    --btn-fg: var(--text-inverse);
    --btn-border: var(--accent);
}

.btn--accent:hover {
    --btn-bg: var(--accent-strong);
    --btn-border: var(--accent-strong);
}

.btn--ghost {
    --btn-border: transparent;
}

.btn--ghost:hover {
    --btn-bg: var(--surface-hover);
}

.btn--outline:hover {
    --btn-border: var(--brand);
    --btn-fg: var(--brand-text);
}

.btn--danger {
    --btn-bg: var(--danger);
    --btn-fg: #fff;
    --btn-border: var(--danger);
}

.btn--sm { padding: 0.45rem 0.85rem; font-size: var(--text-xs); }
.btn--lg { padding: 0.9rem 1.75rem; font-size: var(--text-base); }
.btn--block { display: flex; width: 100%; }

/* -----------------------------------------------------------------------------
   Surfaces

   Solid fills with a hairline border, not glass. V2 blurred everything, which
   costs GPU on every scroll and leaves nothing visually special. Here the blur
   is spent in exactly one place: the sticky header.
   -------------------------------------------------------------------------- */

.card {
    padding: var(--space-5);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface-raised);
    box-shadow: var(--shadow-1), var(--edge-highlight);
    transition: border-color var(--duration) var(--ease),
                box-shadow var(--duration) var(--ease),
                transform var(--duration) var(--ease);
}

.card--interactive:hover {
    border-color: var(--line-strong);
    box-shadow: var(--shadow-3), var(--edge-highlight);
    transform: translateY(-2px);
}

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

.panel {
    padding: var(--space-5);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
}

/* -----------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */

.field { display: grid; gap: var(--space-2); }

.field > label {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-secondary);
}

.field__hint {
    font-size: var(--text-xs);
    color: var(--text-muted);
}

.field__error {
    font-size: var(--text-xs);
    color: var(--danger);
}

/* Fields side by side, collapsing to a stack on narrow screens. --narrow is
   for the ones that only ever hold a date or a short enum, so a title field
   next to a date picker does not get half the row each. */
.field-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: var(--space-4);
    align-items: start;
}

.field-row .field--narrow { max-width: 12rem; }

@media (max-width: 34rem) {
    .field-row { grid-template-columns: minmax(0, 1fr); }
    .field-row .field--narrow { max-width: none; }
}

/* Checkbox and its label as one target. The input keeps its native appearance
   so the checked state does not depend on CSS we would then have to get right
   in both themes. */
.checkbox {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text-secondary);
    cursor: pointer;
}

.checkbox input {
    flex: none;
    width: 1rem;
    height: 1rem;
    margin-top: 0.15rem;
    accent-color: var(--brand);
}

.checkbox span { line-height: var(--leading-normal); }

.select--sm {
    padding: 0.35rem 2rem 0.35rem 0.6rem;
    font-size: var(--text-xs);
}

.input,
.textarea,
.select {
    width: 100%;
    padding: 0.7rem 0.9rem;

    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    color: var(--text-primary);

    font-size: var(--text-sm);
    transition: border-color var(--duration) var(--ease),
                background-color var(--duration) var(--ease);
}

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

.input:hover,
.textarea:hover,
.select:hover {
    border-color: color-mix(in oklab, var(--brand) 40%, var(--line-strong));
}

.input:focus,
.textarea:focus,
.select:focus {
    outline: none;
    border-color: var(--brand);
    background: var(--surface-raised);
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--brand) 22%, transparent);
}

.input[aria-invalid="true"],
.textarea[aria-invalid="true"] {
    border-color: var(--danger);
}

.textarea { min-height: 8rem; resize: vertical; }

/* Native select arrow varies wildly across platforms; this replaces it with
   one that matches the theme. Encoded inline so no extra request is made. */
.select {
    appearance: none;
    padding-inline-end: 2.25rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%236C7385' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.9rem center;
}

/* Honeypot: hidden from people, visible to naive bots. Not display:none,
   because some bots skip those; positioned off-canvas instead. */
.hp-field {
    position: absolute !important;
    left: -9999px !important;
    opacity: 0;
    pointer-events: none;
}

/* -----------------------------------------------------------------------------
   Badges and status
   -------------------------------------------------------------------------- */

.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);

    padding: 0.25rem 0.6rem;
    border-radius: var(--radius-full);

    font-family: var(--font-mono);
    font-size: var(--text-3xs);
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;

    background: var(--surface-overlay);
    color: var(--text-secondary);
}

.badge--success { background: var(--success-surface); color: var(--success); }
.badge--warning { background: var(--warning-surface); color: var(--warning); }
.badge--danger  { background: var(--danger-surface);  color: var(--danger); }
.badge--info    { background: var(--info-surface);    color: var(--info); }

.dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: var(--radius-full);
    background: currentColor;
    flex-shrink: 0;
}

/* -----------------------------------------------------------------------------
   Alerts / flash messages
   -------------------------------------------------------------------------- */

/* Block, not flex. As a flex container every inline child (a <code>, an <a>,
   an <strong>) became its own flex item, so any alert containing markup broke
   into a column of fragments instead of flowing as a sentence. */
.alert {
    display: block;
    padding: var(--space-4);
    line-height: var(--leading-relaxed);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    font-size: var(--text-sm);
}

.alert--success { border-color: color-mix(in oklab, var(--success) 40%, transparent); background: var(--success-surface); }
.alert--warning { border-color: color-mix(in oklab, var(--warning) 40%, transparent); background: var(--warning-surface); }
.alert--danger  { border-color: color-mix(in oklab, var(--danger)  40%, transparent); background: var(--danger-surface); }
.alert--info    { border-color: color-mix(in oklab, var(--info)    40%, transparent); background: var(--info-surface); }

/* -----------------------------------------------------------------------------
   Site header - the one glass surface
   -------------------------------------------------------------------------- */

.site-header {
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);

    border-bottom: 1px solid transparent;
    transition: border-color var(--duration) var(--ease),
                background-color var(--duration) var(--ease);
}

/* Class toggled by JS once the page scrolls, so the header is transparent over
   the hero and becomes a surface once content passes beneath it. */
.site-header.is-stuck {
    border-bottom-color: var(--line);
    background: var(--glass-bg);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
}

.site-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-5);
    min-height: 4.5rem;
}

.site-nav {
    display: flex;
    align-items: center;
    gap: var(--space-5);
}

.site-nav a {
    position: relative;
    padding-block: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--text-secondary);
    text-decoration: none;
}

.site-nav a:hover { color: var(--text-primary); }

/* The gradient's second and final appearance: marking the current page. */
.site-nav a[aria-current="page"] {
    color: var(--text-primary);
}

.site-nav a[aria-current="page"]::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    height: 2px;
    border-radius: var(--radius-full);
    background: var(--brand-gradient);
}

/* -----------------------------------------------------------------------------
   Theme toggle
   -------------------------------------------------------------------------- */

.theme-toggle {
    display: grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;

    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-secondary);

    transition: border-color var(--duration) var(--ease),
                color var(--duration) var(--ease),
                background-color var(--duration) var(--ease);
}

.theme-toggle:hover {
    border-color: var(--line-strong);
    background: var(--surface-hover);
    color: var(--text-primary);
}

.theme-toggle svg {
    width: 1.05rem;
    height: 1.05rem;
}

/* Each icon is present in the DOM; the theme decides which one is shown, so
   there is no icon swap flicker and no JS needed to change the markup. */
.theme-toggle__moon { display: none; }
.theme-toggle__sun  { display: block; }

[data-theme="light"] .theme-toggle__moon { display: block; }
[data-theme="light"] .theme-toggle__sun  { display: none; }

/* -----------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

/* No large top margin: the preceding section already contributes
   --section-y of padding, and stacking both left a void above the footer. */
.site-footer {
    margin-block-start: var(--space-6);
    border-top: 1px solid var(--line);
    padding-block: var(--space-8) var(--space-6);
    font-size: var(--text-sm);
    color: var(--text-muted);
}

.site-footer a {
    color: var(--text-secondary);
    text-decoration: none;
}

.site-footer a:hover { color: var(--text-primary); }

/* -----------------------------------------------------------------------------
   Tables - invoices, time logs, anything with numbers
   -------------------------------------------------------------------------- */

.table-wrap {
    overflow-x: auto;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
}

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

.table th,
.table td {
    padding: var(--space-3) var(--space-4);
    text-align: left;
    border-bottom: 1px solid var(--line-faint);
}

/* Column headers only. Scoped to thead because a <th scope="row"> is a row
   label carrying real content - a person's name, a client - and uppercasing
   it in a mono face made every row read like a column heading. */
.table thead th {
    font-family: var(--font-mono);
    font-size: var(--text-3xs);
    font-weight: 500;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--text-muted);
    background: var(--surface-sunken);
    white-space: nowrap;
}

/* Row headers read as content, not as chrome. */
.table tbody th {
    font-weight: 600;
    color: var(--text-primary);
    text-align: left;
}

.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr:hover { background: var(--surface-hover); }

.table td.numeric,
.table th.numeric {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* -----------------------------------------------------------------------------
   Empty states - an empty screen should tell you what to do next
   -------------------------------------------------------------------------- */

.empty-state {
    display: grid;
    justify-items: center;
    gap: var(--space-3);
    padding: var(--space-9) var(--space-5);
    text-align: center;
    color: var(--text-muted);
}

.empty-state h3 {
    font-size: var(--text-lg);
    color: var(--text-secondary);
}

/* =============================================================================
   Page compositions

   Everything below exists because the Content Security Policy forbids inline
   style attributes. A CSP nonce authorises <style> elements and <link> tags,
   it does NOT authorise style="..." on an element; that needs 'unsafe-inline',
   which would also authorise any style an attacker manages to inject.

   So layout lives in classes. That constraint is worth keeping: it is the
   difference between a policy that genuinely stops injected CSS and one that
   only looks like it does.
   ========================================================================== */

.brand-mark {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

/*
   The logo is inlined SVG, so its two parts theme independently: the brackets
   take the brand colour, and the word inherits currentColor and therefore
   flips with the light/dark theme without a second asset.
*/
.site-logo {
    height: 1.75rem;
    width: auto;
    overflow: visible;
}

.site-logo__bracket { stroke: var(--brand); fill: none; }
.site-logo__word    { fill: currentColor; }

.brand-mark { color: var(--text-primary); }
.brand-mark--sm .site-logo { height: 1.5rem; }

.header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

/* --- Generic arrangement helpers ------------------------------------------ */

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

.between--top { align-items: flex-start; }

.grid-auto {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.center-text { text-align: center; }
.center-items { justify-content: center; }

.lead {
    font-size: var(--text-lg);
    color: var(--text-secondary);
}

/* --- Status page (Phase 1 only; removed once the real home page lands) ----- */

.status-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
}

.status-card__value {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    color: var(--text-primary);
    word-break: break-word;
}

.specimen__display {
    font-family: var(--font-display);
    font-stretch: var(--width-display);
    font-weight: 800;
    font-size: var(--text-4xl);
    letter-spacing: var(--tracking-display);
    line-height: 1;
}

.specimen__mono {
    font-family: var(--font-mono);
    font-size: var(--text-3xs);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--text-muted);
}

/* --- Footer --------------------------------------------------------------- */

.footer-top {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-8);
}

.footer-blurb {
    max-width: 22rem;
    font-size: var(--text-sm);
}

.footer-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--space-8);
}

.footer-col {
    display: grid;
    gap: var(--space-2);
    align-content: start;
}

.footer-rule {
    margin-block: var(--space-6) var(--space-4);
    opacity: 0.35;
}

.footer-bottom {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    font-size: var(--text-xs);
}

/* --- Error page ----------------------------------------------------------- */

.error-title { font-size: var(--text-3xl); }

.error-detail {
    text-align: left;
    font-size: var(--text-2xs);
    max-height: 22rem;
}

/* --- Flash region --------------------------------------------------------- */

.flash-region {
    padding-block-start: var(--space-5);
    display: grid;
    gap: var(--space-3);
}

/* Footer social row. Icon-only links, so each carries an aria-label - and a
   40px hit area, because a 16px icon is not a tappable target on a phone. */
.social-links {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    list-style: none;
}

.social-links a {
    display: grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    transition: color var(--duration) var(--ease),
                background-color var(--duration) var(--ease);
}

.social-links a:hover {
    color: var(--text-primary);
    background: var(--surface-hover);
}

.social-links svg { width: 1.15rem; height: 1.15rem; }

/* -----------------------------------------------------------------------------
   Analytics: the engagement popup and the chat widget

   Both are injected by tracker.js, so they are the only elements on the site
   whose markup lives in a script rather than a template. Their classes are
   prefixed xdv- for exactly that reason: a rename here breaks something that
   grep over templates/ will not find.
   -------------------------------------------------------------------------- */

.xdv-pop,
.xdv-chat {
    position: fixed;
    right: var(--space-5);
    bottom: var(--space-5);
    z-index: 60;
    width: min(22rem, calc(100vw - var(--space-6)));
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    background: var(--surface-overlay);
    box-shadow: 0 18px 48px rgb(0 0 0 / 0.34);
}

.xdv-pop { padding: var(--space-5); }

.xdv-pop__close,
.xdv-chat__close {
    position: absolute;
    top: var(--space-2);
    right: var(--space-3);
    padding: var(--space-1) var(--space-2);
    border: 0;
    background: none;
    color: var(--text-muted);
    font-size: var(--text-lg);
    line-height: 1;
    cursor: pointer;
}

.xdv-pop__close:where(:hover),
.xdv-chat__close:where(:hover) { color: var(--text-primary); }

.xdv-pop__title {
    margin: 0 0 var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--text-primary);
}

.xdv-pop__body {
    margin: 0 0 var(--space-4);
    color: var(--text-secondary);
    font-size: var(--text-sm);
    line-height: var(--leading-relaxed);
}

.xdv-pop__form { display: flex; flex-direction: column; gap: var(--space-2); }

.xdv-pop__label {
    font-family: var(--font-mono);
    font-size: var(--text-3xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
}

.xdv-pop__input,
.xdv-chat__input {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    color: var(--text-primary);
    font: inherit;
    font-size: var(--text-sm);
}

.xdv-pop__input:focus-visible,
.xdv-chat__input:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

.xdv-pop__send,
.xdv-chat__send {
    align-self: flex-start;
    margin-top: var(--space-2);
    padding: var(--space-2) var(--space-4);
    border: 0;
    border-radius: var(--radius-sm);
    background: var(--brand);
    color: var(--on-brand);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
}

/* --- Chat ----------------------------------------------------------------- */

.xdv-chat { display: flex; flex-direction: column; max-height: min(28rem, 70vh); }

.xdv-chat__head {
    position: relative;
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--line);
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--text-primary);
}

.xdv-chat__log {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-3) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.xdv-chat__line {
    max-width: 85%;
    margin: 0;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    line-height: var(--leading-relaxed);
    overflow-wrap: anywhere;
}

.xdv-chat__line--alex {
    align-self: flex-start;
    background: var(--surface-sunken);
    color: var(--text-primary);
}

.xdv-chat__line--you {
    align-self: flex-end;
    background: color-mix(in oklab, var(--brand) 22%, transparent);
    color: var(--text-primary);
}

.xdv-chat__form {
    display: flex;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-top: 1px solid var(--line);
}

.xdv-chat__send { align-self: auto; margin-top: 0; }

@media (prefers-reduced-motion: no-preference) {
    .xdv-pop, .xdv-chat { animation: xdv-rise 220ms var(--ease) both; }
}

@keyframes xdv-rise {
    from { opacity: 0; transform: translateY(0.75rem); }
    to   { opacity: 1; transform: none; }
}
