/**
 * Shared design system — the single source of truth for color,
 * typography, spacing, shadow, and radius tokens used across the
 * landing page, the app (frontend/app/), and the admin waitlist view.
 *
 * Loaded directly by the landing page and admin view; the app's own
 * styles.css @imports this file rather than duplicating tokens, so
 * there is exactly one palette to change if it ever needs to shift.
 */

/* Inter is self-hosted (fonts/inter-latin-var.woff2 — one 48 KB
   variable file, Latin subset, covers weights 100–900) rather than
   linked from fonts.googleapis.com. The Google Fonts <link> cost two
   render-blocking cross-origin round trips per page: the CSS request,
   then the woff2 request on a second domain (fonts.gstatic.com). Now
   there's one same-origin request, declared here.

   Because this stylesheet reaches the app pages through an @import in
   app/styles.css, the font request would otherwise sit at the end of a
   styles.css → design-system.css → woff2 chain. Every HTML entry point
   carries a <link rel="preload" as="font" crossorigin> for the woff2
   so it downloads in parallel from the first byte instead — that's the
   piece that keeps the fallback-to-Inter swap from flashing on large
   text (the landing hero h1). font-display: swap keeps text visible
   the whole time regardless. */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url(fonts/inter-latin-var.woff2) format('woff2');
}

:root {
    /* ---- Brand / accent: the same deep-charcoal-and-brass palette the
       landing page introduced, now promoted to the shared default so
       every screen (app, admin, landing) renders one cohesive palette
       instead of the landing page being the only one that opted out of
       a default indigo/violet SaaS look. One accent color, used flat
       (never as a gradient) — a flat warm metal reads as considered and
       editorial; a diagonal two-stop gradient is the templated-SaaS
       tell this palette exists to avoid. ---- */
    --lux-black: #0a0a0b;
    --lux-charcoal: #17171a;
    --lux-charcoal-2: #202024;
    --lux-ivory: #f6f3ec;
    --lux-accent: #b68a4e;
    --lux-accent-hover: #a37a41;
    --lux-accent-tint: #f2e9d8;

    --primary-color: var(--lux-accent);
    --primary-hover: var(--lux-accent-hover);
    --primary-light: var(--lux-accent-tint);
    --primary-dark: #8f6c3a;
    --accent-color: var(--lux-accent);
    --gradient-brand: var(--lux-accent);
    /* --lux-accent itself is 3.1:1 against white -- fine for a button
       background or an icon (non-text UI only needs 3:1), but fails
       WCAG AA (4.5:1) for actual text: links, "Go to Alerts ->",
       accent-colored labels, etc. This is the same brass, one step
       darker (reuses --primary-dark's value), for every place the
       accent color renders AS text rather than as a fill. See Phase 5
       (WORK_LOG.md) for the audit and the buttons this doesn't cover. */
    --lux-accent-text: var(--primary-dark);
    /* A hand-picked darker step of --lux-accent-tint, for hovering an
       element whose resting state IS the tint (e.g. a filled chip) --
       named here instead of being a bare hex the one place it was
       used, since "hover = one step darker than the tint" is a real,
       reusable pattern in this palette. */
    --lux-accent-tint-hover: #e8dcc3;

    /* ---- Semantic colors: kept clearly red/amber/green (that mapping
       is load-bearing for scanning risk flags and confidence at a
       glance — this redesign doesn't get to break it), but deepened
       toward a jewel-tone register rather than flat/bright SaaS
       success-green and error-red, and warmed to sit comfortably next
       to the ivory background instead of the cooler blue-grays this
       app used before. ---- */
    --success-color: #2f6b4f;
    --success-light: #e3ede6;
    --error-color: #9a3b3b;
    --error-light: #f3e3e1;
    --warning-color: #a6741f;
    --warning-light: #f3e7d2;
    /* --error-color is tuned for a white/ivory background and reads as
       muddy on the dark hero (contrast, not just taste) -- this is
       that same "something is wrong" signal, tuned to stay legible on
       --lux-charcoal instead. Landing page only, for now. */
    --lux-error-on-dark: #e5a5a0;

    /* ---- Neutral scale: warm charcoal/ivory, replacing the cool slate
       scale this app used before the landing redesign. Kept as a named
       scale (not just single tokens) since a couple of components still
       need in-between steps (borders, hover states). ---- */
    --slate-950: #0a0a0b;
    --slate-900: #17171a;
    --slate-800: #202024;
    --slate-700: #3a3833;
    --slate-600: #58554d;
    --slate-500: #6f6c62;
    --slate-400: #8b8779;
    --slate-300: #b3ada0;
    --slate-200: #e6e0d2;
    --slate-100: #efeade;
    --slate-50: #f6f3ec;

    --text-dark: #161512;
    --text-medium: var(--slate-600);
    --text-light: var(--slate-400);
    --border-color: var(--slate-200);
    --background: var(--lux-ivory);
    --white: #ffffff;

    --sidebar-bg: var(--lux-charcoal);
    --sidebar-text: var(--slate-300);
    --sidebar-text-active: var(--lux-ivory);

    /* ---- Confidence colors (extraction certainty) — same values as
       the semantic success/warning/error colors above; kept as their
       own tokens (not aliased) since confidence and severity describe
       different things and have needed to diverge before. ---- */
    --confidence-high: #2f6b4f;
    --confidence-high-bg: #e3ede6;
    --confidence-medium: #a6741f;
    --confidence-medium-bg: #f3e7d2;
    --confidence-low: #9a3b3b;
    --confidence-low-bg: #f3e3e1;
    --confidence-none-bg: #eae6db;

    /* ---- Severity colors (lease risk) — kept distinct from confidence
       even though the high/medium/low mapping is similar, since they
       describe different things ---- */
    --severity-high: #9a3b3b;
    --severity-high-bg: #f3e3e1;
    --severity-medium: #a6741f;
    --severity-medium-bg: #f3e7d2;
    --severity-low: #6f6c62;
    --severity-low-bg: #efeade;

    /* ---- Elevation: soft, layered shadows instead of harsh drop-shadows ---- */
    --shadow-sm: 0 1px 2px rgba(10, 10, 11, 0.05), 0 1px 1px rgba(10, 10, 11, 0.03);
    --shadow-md: 0 4px 8px -2px rgba(10, 10, 11, 0.08), 0 2px 4px -2px rgba(10, 10, 11, 0.05);
    --shadow-lg: 0 12px 24px -6px rgba(10, 10, 11, 0.12), 0 4px 8px -4px rgba(10, 10, 11, 0.06);
    --shadow-xl: 0 24px 48px -12px rgba(10, 10, 11, 0.20), 0 8px 16px -8px rgba(10, 10, 11, 0.08);

    /* ---- Radius scale: left unchanged — this pass is a color
       redesign, and every app component's padding/sizing was tuned
       against these existing radii, so changing them risks visual
       regressions this project has no way to screenshot-verify. ---- */
    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-lg: 14px;
    --radius-xl: 20px;
    --radius-full: 9999px;

    /* ---- Typography ---- */
    --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
        'Helvetica Neue', sans-serif;

    /* ---- Type scale: named, not new. This is the exact scale already
       in disciplined use across every screen (audited via grep across
       all three stylesheets before adding this) -- a fine 0.0625rem
       (1px @ 16px root) step grid, chosen for a data-dense app where a
       badge, a table cell, and a card heading all need their own
       adjacent step. Existing declarations were NOT mass-converted to
       these tokens (they already match the scale; converting ~600
       correct declarations would be pure churn with real regression
       risk in a file this size) -- use these for new or touched CSS
       going forward. ---- */
    --text-xs: 0.6875rem;    /* meta text, tiny badges */
    --text-sm: 0.75rem;      /* captions, table meta */
    --text-base-sm: 0.8125rem; /* the single most common size in this app: secondary body text */
    --text-base: 0.875rem;   /* default body / button text */
    --text-md: 0.9375rem;    /* subtitles, .view-subtitle */
    --text-lg: 1rem;
    --text-xl: 1.0625rem;    /* card values, emphasized numbers */
    --text-2xl: 1.125rem;
    --text-3xl: 1.25rem;     /* dialog/card h1 */
    --text-4xl: 1.5rem;      /* section headings */
    --text-5xl: 1.75rem;     /* page h1 */

    /* ---- Spacing scale: same story as the type scale above -- names
       an already-consistent 0.0625rem-grid system, doesn't force a
       rewrite of what already matches it. ---- */
    --space-1: 0.125rem;
    --space-2: 0.25rem;
    --space-3: 0.375rem;
    --space-4: 0.5rem;
    --space-5: 0.625rem;
    --space-6: 0.75rem;
    --space-7: 0.875rem;
    --space-8: 1rem;
    --space-10: 1.25rem;
    --space-12: 1.5rem;
    --space-16: 2rem;
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/* Belt-and-suspenders against horizontal overflow on mobile: a single
   un-wrapped flex/grid row anywhere on the page (a button toolbar, a
   data table) will otherwise widen the whole layout viewport on a real
   phone well past the device width, shrinking everything else down
   with it rather than just scrolling the one offending element -- found
   auditing the dashboard/rent-roll/owner-console screens at 375px,
   where this silently turned the entire page into a zoomed-out desktop
   layout. Individual overflowing elements should still be fixed to
   wrap/scroll on their own (see .today-briefing-grid, .table-controls,
   .owner-header); this only stops any we missed from taking the whole
   page down with them. */
html {
    overflow-x: hidden;
}

body {
    font-family: var(--font-sans);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    background-color: var(--background);
    color: var(--text-dark);
    line-height: 1.5;
    overflow-x: hidden;
}

button, input {
    font-family: inherit;
}

a {
    color: inherit;
}

/* ===================== Shared buttons (landing + admin) ===================== */

.btn-primary, .btn-secondary, .btn-danger {
    padding: 0.625rem 1.25rem;
    border-radius: var(--radius-md);
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.15s, border-color 0.15s, transform 0.15s, box-shadow 0.15s;
    white-space: nowrap;
}

.btn-primary {
    /* --lux-accent (#b68a4e) behind white text is only 3.1:1 — fails
       WCAG AA (4.5) for the button label. --lux-accent-text (the
       one-step-darker brass, #8f6c3a) clears it at 4.8:1 and is already
       the palette's "brass as text" value. The accent stays #b68a4e
       everywhere it's a fill/border/icon, where 3:1 is enough. */
    background: var(--lux-accent-text);
    color: var(--white);
    border: 1px solid transparent;
    box-shadow: var(--shadow-sm);
}

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

.btn-primary:active {
    transform: translateY(0);
}

.btn-secondary {
    background-color: var(--white);
    color: var(--text-dark);
    border: 1px solid var(--border-color);
}

.btn-secondary:hover {
    background-color: var(--background);
    border-color: var(--slate-300);
}

.btn-danger {
    background-color: var(--white);
    color: var(--error-color);
    border: 1px solid var(--error-light);
}

.btn-danger:hover {
    background-color: var(--error-light);
}

.btn-block {
    width: 100%;
    margin-top: 0.75rem;
}

/* ===================== Shared loading affordances ===================== */

.loading-inline {
    color: var(--text-medium);
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 1rem 0;
}

.spinner-small {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    border: 2px solid var(--border-color);
    border-top-color: var(--primary-color);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

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

/* ===================== Accessibility utilities ===================== */

/* Visible only to screen readers — used to give icon-only / spinner-only
   UI a spoken label without changing the visual. */
.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;
}

/* Keyboard skip link — off-screen until focused, then pinned top-left
   so a keyboard user can jump past the sidebar nav to the main content. */
.skip-link {
    position: fixed;
    top: 0.5rem;
    left: 0.5rem;
    z-index: 2000;
    padding: 0.5rem 0.875rem;
    background-color: var(--white);
    color: var(--text-dark);
    font-size: 0.875rem;
    font-weight: 600;
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lg);
    transform: translateY(-150%);
    transition: transform 0.15s ease;
}

.skip-link:focus {
    transform: translateY(0);
    outline: 2px solid var(--lux-accent-text);
    outline-offset: 2px;
}

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

/* ===================== Shared confirm dialog =====================
   One styled replacement for window.confirm() across the app, admin,
   and owner surfaces (each has a thin JS wrapper — confirmDialog() —
   that builds this markup and returns a Promise<boolean>). Backdrop
   fades, card scales in; both respect prefers-reduced-motion. */

.confirm-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background-color: rgba(10, 10, 11, 0.45);
    opacity: 0;
    transition: opacity 0.16s ease;
}

.confirm-backdrop.show {
    opacity: 1;
}

.confirm-dialog {
    width: 100%;
    max-width: 26rem;
    background-color: var(--white);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xl);
    padding: 1.5rem;
    transform: scale(0.96);
    transition: transform 0.16s ease;
}

.confirm-backdrop.show .confirm-dialog {
    transform: scale(1);
}

.confirm-dialog h2 {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--text-dark);
    margin-bottom: 0.5rem;
}

.confirm-dialog p {
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--text-medium);
    margin-bottom: 1.25rem;
}

.confirm-dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.625rem;
}

@media (prefers-reduced-motion: reduce) {
    .confirm-backdrop,
    .confirm-dialog {
        transition: none;
    }
}
