/* ============================================================
   main.css — Phase 3 rewrite. Down from 514 lines (premium dark-
   SaaS theming) to the small set of rules that complement Tailwind
   without re-implementing it.

   Tokens come from app/static/css/tokens.css (loaded before this
   file in base.html). Tailwind utilities cover everything else.

   What's intentionally NOT here anymore (deleted in phases 1-3):
     - Glassmorphism (.glass, backdrop-filter on aside)
     - Premium card effects (.card-hover, .rounded-xl box-shadow,
       .bg-dark-800.rounded-xl 145° gradient, text-shadow glows on
       .text-profit / .text-loss)
     - Gradient buttons (.bg-blue-600 / .bg-green-700 / .bg-red-600 /
       .bg-orange-600 linear-gradient + glow + translate hammers)
     - Purple→blue gradient text (.gradient-text, .accent-gradient)
       + the gradient-shift keyframe
     - Sidebar background gradient + active-link styles
     - Grade badge gradients (.grade-psa10 / .grade-psa9 / .grade-raw
       — dead code: pages/portfolio.js returns Tailwind utilities)
     - Animated entry cascade (animate-fade-in + 6-step fade-in-up
       cascade), .stat-number number-pop animation, .timer-urgent,
       .pulse-ring
     - Animated tbody tr:hover linear-gradient + nth-child zebra
     - .animate-spin glow filter
     - Decorative img hover scale + brightness
     - Active-page SVG drop-shadow

   The deletions enforce the design system: borders not shadows,
   flat panels not gradients, no row entry animations, no glows.
   ============================================================ */


/* ─── Base ─────────────────────────────────────────────────── */

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

/* Dark-only app — without this, native UI (select popups, autofill,
   scrollbars) renders LIGHT against the pure-black canvas. */
:root {
    color-scheme: dark;
}

/* Body face is now SANS — Inter Tight (loaded by base.html). The
   interface (titles, labels, buttons, prose) reads humanist and
   warm instead of blocky. Mono (JetBrains) is reserved for data
   and applied explicitly via the rule below + the data role
   classes, so numbers/tables/identifiers keep their terminal
   alignment. */
body {
    font-family: var(--font-sans);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    letter-spacing: -0.006em;
    background: var(--surface-bg);
    color: var(--text-secondary);
}

/* Ambient light — a single soft ember glow drifting in from the
   top, very low opacity, so the pure-black OLED canvas feels lit
   rather than dead. Fixed + pointer-events:none so it never moves
   or intercepts clicks. This is the main "lumière" cue. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: -1;
    background:
        radial-gradient(110% 75% at 50% -12%,
            oklch(0.700 0.195 52 / 0.12) 0%,
            transparent 58%),
        radial-gradient(80% 60% at 90% -5%,
            oklch(0.720 0.155 250 / 0.09) 0%,
            transparent 52%),
        radial-gradient(75% 55% at 5% 102%,
            oklch(0.800 0.185 150 / 0.05) 0%,
            transparent 55%);
}

/* Data faces stay mono + tabular: explicit numbers (.font-mono),
   table cells, and stat numbers. font-family is set here because
   the body default is now sans. */
.font-mono, td, th, .stat-number {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums lining-nums;
}


/* ─── Elevation & light ────────────────────────────────────────
   Panels are built ad-hoc across the app as `bg-surface-panel`
   (200+ refs) rather than a shared class, so we attach the depth
   treatment to the utility itself: a 1px top light-line + soft
   drop shadow lifts every panel off the pure-black canvas so it
   reads as a real, lit surface. The border utilities on each
   panel still draw the crisp edge. */
.bg-surface-panel {
    box-shadow: var(--elev-panel);
    transition: box-shadow 0.18s var(--ease);
}
/* Panels lift toward the light on hover — a faint ember edge + a
   deeper shadow makes the surface feel physical and reactive. The
   :hover only applies where a panel is genuinely interactive
   (carries a cursor-pointer / data-row-link / is an anchor); plain
   static panels keep the resting elevation. */
a.bg-surface-panel:hover,
button.bg-surface-panel:hover,
.bg-surface-panel.cursor-pointer:hover,
.bg-surface-panel[data-row-link]:hover {
    box-shadow: var(--elev-panel-hover);
}
/* Modals / floating layers go deeper. */
.bg-surface-elevated.shadow-lg,
[role="dialog"] .bg-surface-panel,
.modal-panel {
    box-shadow: var(--elev-modal);
}

/* Primary ember action — give it a live glow so it reads as THE
   button on the page. Targets the accent fill; hover ignites it. */
button.bg-accent,
a.bg-accent,
.btn-accent {
    box-shadow: var(--glow-accent);
    transition: box-shadow 0.14s var(--ease), background-color 0.14s var(--ease);
}
button.bg-accent:hover,
a.bg-accent:hover,
.btn-accent:hover {
    box-shadow: var(--glow-accent-strong);
}

/* Positive / negative value chips & buttons get a faint matching
   halo when they carry a solid fill (not plain text). */
.bg-positive { box-shadow: var(--glow-positive); }
.bg-negative { box-shadow: var(--glow-negative); }


/* ─── Typographic roles ────────────────────────────────────────
   8 named roles posed directly on elements to build a real, shared
   hierarchy across all pages. Data roles stay mono (numbers /
   identifiers); prose roles opt INTO Inter Tight (--font-sans).

   IMPORTANT: these class names are referenced ~280× across the
   templates. Color is declared separately at ZERO specificity via
   :where() so any Tailwind text-* utility (e.g. text-positive on a
   P&L stat, text-faint on a muted caption) always overrides the
   role default. Never put `color` inside the role blocks below. */

.t-display {                 /* the single hero number per page */
    font-family: var(--font-mono);
    font-size: 2rem;          /* 32px */
    line-height: 1.05;
    font-weight: 600;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums lining-nums;
    /* Faint self-coloured halo — picks up text-positive/negative/
       primary so green/red/white hero values softly emit light. */
    text-shadow: 0 0 18px color-mix(in oklch, currentColor 28%, transparent);
}
.t-stat {                    /* stat-card / KPI numbers */
    font-family: var(--font-mono);
    font-size: 1.375rem;      /* 22px */
    line-height: 1.1;
    font-weight: 500;
    letter-spacing: -0.01em;
    font-variant-numeric: tabular-nums lining-nums;
}
.t-h1 {                      /* page title */
    font-family: var(--font-sans);
    font-size: 1.125rem;      /* 18px */
    line-height: 1.3;
    font-weight: 600;
    letter-spacing: -0.01em;
}
.t-h2 {                      /* section title */
    font-family: var(--font-sans);
    font-size: 0.9375rem;     /* 15px */
    line-height: 1.35;
    font-weight: 500;
}
.t-body {                    /* prose, descriptions, empty states */
    font-family: var(--font-sans);
    font-size: 0.8125rem;     /* 13px — prose floor */
    line-height: 1.5;
}
.t-label {                   /* field / column labels, normal case */
    font-family: var(--font-mono);
    font-size: 0.6875rem;     /* 11px */
    line-height: 1.3;
    letter-spacing: 0.01em;
}
.t-eyebrow {                 /* the ONE uppercase role — tiny caps */
    font-family: var(--font-mono);
    font-size: 0.625rem;      /* 10px */
    line-height: 1.2;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}
.t-micro {                   /* captions, meta, sub-stat lines */
    font-family: var(--font-mono);
    font-size: 0.625rem;      /* 10px */
    line-height: 1.3;
}

/* Default colors — zero specificity so text-* utilities win. */
:where(.t-display, .t-stat, .t-h1, .t-h2) { color: var(--text-primary); }
:where(.t-body)                           { color: var(--text-secondary); }
:where(.t-label, .t-eyebrow, .t-micro)    { color: var(--text-muted); }


/* ─── Data tables ────────��─────────────────────────────────────
   Shared treatment so every table reads the same across pages.
   Add `.t-table` to the <table>; header look, cell padding, body size
   and dividers all come from here. Per-column ALIGNMENT stays on
   the cells (text-right for numbers, text-center, etc.) because
   text-align is intentionally NOT set here, so those utilities win.
   Add `.t-table--sticky` when the header should pin while the body
   scrolls. Header color uses :where() so sortable headers can still
   lighten on hover via their own hover:text-* utility. */
.t-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.75rem;           /* 12px baseline — utilities still win */
}

/* Header identity is force-unified (this is the part that was all
   over the place): mono, 10px, uppercase, faint, hairline underline.
   Padding + color are low-specificity defaults so a table can keep
   its own edge gutters (e.g. the dashboard's pl-6/pr-6) and stay
   aligned with its body. text-align stays on the cells. */
.t-table thead th {
    font-family: var(--font-mono);
    font-size: 0.625rem;          /* 10px */
    font-weight: 400;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
    border-bottom: 1px solid var(--border-subtle);
}
:where(.t-table thead th) {
    color: var(--text-faint);
    padding: 0.5rem 0.75rem;
}

/* Body cell padding is a low-specificity default so tables that
   already tuned their density (inventory, analytics) keep it, while
   tables with no padding pick up a sane default. */
:where(.t-table tbody td) {
    padding: 0.5rem 0.75rem;
    vertical-align: middle;
}

/* Row dividers + hover, unified. tr+tr avoids a top border on the
   first row. color-mix gives the subtle hairline the ad-hoc /30
   opacities were reaching for, but consistently. */
.t-table tbody tr + tr {
    border-top: 1px solid color-mix(in oklch, var(--border-subtle) 45%, transparent);
}
.t-table tbody tr:hover {
    background: color-mix(in oklch, var(--surface-elevated) 55%, transparent);
}

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


/* ─── Card thumbnails ──────────────────────────────────────────
   ONE treatment for every card image so they read the same across
   pages (the borders/radii/bg were all over the place: ring-1 vs
   border vs border-b vs border-2 vs none; rounded vs -md vs -lg vs
   none). The ring is an inset box-shadow so it adds NO layout box —
   safe to drop onto any existing sized <img> after stripping its old
   border/ring/rounded/bg utilities. Keep w-/h-/aspect + object-fit
   inline: sizes are contextual and cover-vs-contain is semantic
   (photos = cover, logos/sealed = contain). */
.t-card-img {
    background-color: var(--surface-elevated);
    border-radius: 3px;
    box-shadow: inset 0 0 0 1px var(--border-subtle);
}
/* Empty placeholder cells (no <img>) reuse the same frame. */
.t-card-frame {
    background-color: var(--surface-elevated);
    border-radius: 3px;
    box-shadow: inset 0 0 0 1px var(--border-subtle);
}


/* ─── Scrollbars ───────────────────────────────────────────── */

::-webkit-scrollbar       { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-subtle); }
::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }

/* Opt-in `.scrollbar-thin` for inner scroll panels (search set
   suggestions, card detail sales history). Same rule, just scoped
   so it doesn't reset other browsers' defaults globally. */
.scrollbar-thin::-webkit-scrollbar       { width: 6px; height: 6px; }
.scrollbar-thin::-webkit-scrollbar-track { background: var(--surface-elevated); }
.scrollbar-thin::-webkit-scrollbar-thumb { background: var(--border-subtle); }


/* ─── Profit / loss colour aliases ─────────────────────────── */

/* Tailwind's `text-profit` / `text-loss` utilities are aliased to
   the new positive / negative tokens via tailwind.config.js. These
   rules cover the few places the classes are referenced from raw
   CSS (notifications, etc.) and stay in sync. */
.text-profit { color: var(--positive); }
.text-loss   { color: var(--negative); }
.bg-profit   { background-color: var(--positive); }
.bg-loss     { background-color: var(--negative); }


/* ─── Form fields ──────────────────────────────────────────── */

/* Focus state is a single border colour shift — no shadow ring.
   Phase 3 keeps this as a safety net; per-field utility classes
   from Tailwind already cover most of it. */
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--border-strong);
    box-shadow: var(--glow-focus);
}
input::placeholder, textarea::placeholder {
    color: var(--text-faint);
}

/* Keyboard focus — this keyboard-first app (j/k row nav, Cmd+K
   palette) had ZERO visible focus outside form fields. :focus-visible
   keeps mouse clicks ring-free; input/textarea stay on the :focus rule
   above so the glow isn't double-applied. Kept BEFORE the
   [data-row-link]:focus rule below so the vim-nav bar wins on rows. */
a:focus-visible, button:focus-visible, select:focus-visible,
[tabindex]:focus-visible {
    outline: none;
    box-shadow: var(--glow-focus);
    border-radius: var(--radius-1);
}

/* Custom <select> caret — neutral chevron matching --text-muted.
   Hex is locked instead of a var() because data: URLs can't read
   CSS custom properties. Hue chosen to approximate the token. */
select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%237c7e84' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    padding-right: 2rem;
}


/* ─── Skeleton loading shimmer ─────────────────────────────── */

/* Used by the {% macro skeleton() %} atom in _macros.html. Tailwind
   ships .animate-pulse out of the box; this rule is the legacy hook
   for templates that still write `class="skeleton"` directly. */
.skeleton {
    background: linear-gradient(90deg,
        var(--surface-elevated) 0%,
        var(--border-subtle) 50%,
        var(--surface-elevated) 100%);
    background-size: 200% 100%;
    animation: skeleton-loading 1.5s var(--ease) infinite;
}
@keyframes skeleton-loading {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}


/* ─── Notifications ────────────────────────────────────────── */

.notification-enter { animation: notification-in 200ms var(--ease); }
.notification-leave { animation: notification-out 150ms var(--ease); }
@keyframes notification-in {
    from { opacity: 0; transform: translateY(0.5rem); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes notification-out {
    from { opacity: 1; transform: translateY(0); }
    to   { opacity: 0; transform: translateY(0.25rem); }
}


/* ─── Dashboard top-deal row ─────────────────────────────────
   The best net € on the board wears the ember rail + a faint lift
   so the eye lands on it without reading a single number. The rail
   sits on the first cell, not the row — border-collapse swallows
   box-shadows painted on <tr> in Chromium. */
.row-top-deal td {
    background-color: color-mix(in oklch, var(--surface-elevated) 45%, transparent);
}
.row-top-deal td:first-child {
    box-shadow: inset 2px 0 0 0 var(--accent);
}


/* ─── Vim-style row navigation focus ───────────────────────
   Pages opt rows into j/k navigation by adding `data-row-link`
   to the row's primary anchor. The global handler in palette.js
   focuses the next/previous matching element on j/k. This rule
   gives the focused row a 2px accent left bar so the selection
   reads consistently regardless of the row's own background. */
[data-row-link]:focus {
    outline: none;
    box-shadow: inset 2px 0 0 0 var(--accent),
                inset 0 0 24px -8px oklch(0.700 0.195 52 / 0.35);
    background-color: var(--surface-elevated);
}


/* ─── Unified data table (.t-table) ────────────────────────
   One table grammar for the whole app. Before this, every table
   hand-rolled its own header (9 different <thead> treatments: some
   bg-surface-elevated/50, some sticky, some uppercase+tracking, some
   bare), 3 font sizes (sm/xs/[11px]), ~20 padding combos on <th>, and
   border-t vs border-b row dividers — so no two tables matched.

   These descendant rules carry normal specificity (0,1,1) so they
   WIN over inline utility classes (0,1,0) and force uniformity for
   appearance/padding without editing every <th>. The ONE thing left
   to per-column utilities is alignment: text-align is set at zero
   specificity via :where(), so `text-right` on numeric columns and
   `text-center` still override the left default. Add `t-table` to a
   <table> and it inherits the house style; keep your text-right/
   @click sort utilities on the cells. */

.t-table { width: 100%; border-collapse: collapse; }

/* Alignment default at zero specificity → text-right/center win. */
:where(.t-table th), :where(.t-table td) { text-align: left; }

.t-table thead th {
    font-family: var(--font-mono);
    font-size: 0.625rem;                 /* 10px */
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--text-muted);
    padding: 0.5rem 0.75rem;             /* py-2 px-3 — uniform */
    background: var(--surface-panel);    /* keeps sticky headers opaque */
    border-bottom: 1px solid var(--border-subtle);
    white-space: nowrap;
    vertical-align: middle;
}
.t-table tbody td {
    font-size: 0.75rem;                  /* 12px — uniform body cell */
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
}
/* Fade the interior dividers; the header keeps the full-strength line. */
.t-table tbody tr:not(:last-child) td { border-bottom-color: color-mix(in oklch, var(--border-subtle) 45%, transparent); }
.t-table tbody tr { transition: background-color 0.12s var(--ease), box-shadow 0.12s var(--ease); }
.t-table tbody tr:hover {
    background-color: var(--surface-elevated);
    box-shadow: inset 2px 0 0 0 oklch(0.700 0.195 52 / 0.55);
}


/* ─── Text utilities ───────────────────────────────────────── */

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


/* ─── Print ────────────────────────────────────────────────── */

@media print {
    .no-print { display: none !important; }
    body { background: white; color: black; }
}
