/*
 * The token contract: every structural scale, declared once at the root.
 *
 * Two halves, and the split is the law. The kit owns structure, the space,
 * radius, type, motion and z scales below, and a design may never redefine
 * one; `tokens/manifest.ts` is that list, and conformance reads it. A design
 * owns colour and shadow, the manifest's theme slots, and declares them
 * unlayered so they win over anything layered here without a specificity
 * trick. Structure is immutable; only the face is a design's.
 *
 * This file declares no colour. `theme-default.css` is the kit's own face, so
 * a page renders with no design at all, and a design replaces it.
 *
 * A width media query is illegal everywhere. What reflows asks a container:
 * its own, when the piece reflows on its own room, or the named `nv-page`,
 * when it reflows on the page's. :root[data-tier] stays the app shell's, set
 * by something that runs before its content. The one prefers-reduced-motion
 * block in the kit is here: --nv-motion scales every decorative duration to
 * zero under reduce.
 */

@layer nv.tokens, nv.reset, nv.base, nv.components;

@layer nv.tokens {
  :root {
    /* Spacing, raw ramp */
    --nv-space-0: 0;
    --nv-space-05: 0.125rem;
    --nv-space-1: 0.25rem;
    --nv-space-2: 0.5rem;
    --nv-space-3: 0.75rem;
    --nv-space-4: 1rem;
    --nv-space-5: 1.5rem;
    --nv-space-6: 2rem;
    --nv-space-7: 3rem;
    --nv-space-8: 4rem;
    /* The top of the ramp, for the air a marketing band wants between it and
       the next one. Nothing inside a component reaches this far. */
    --nv-space-9: 6rem;

    /* Spacing, semantic. Density and tier remap these in one place. */
    --nv-page-gutter: 1rem;
    --nv-section-gap: 2rem;
    --nv-stack-gap: 1rem;
    --nv-card-pad: 1rem;
    --nv-form-gap: 0.75rem;

    /* Radii */
    --nv-radius-sm: 4px;
    --nv-radius-md: 8px;
    --nv-radius-lg: 12px;
    --nv-radius-xl: 16px;
    --nv-radius-full: 9999px;

    /* Font slots. A design points these at its own faces and ships the
       files; the kit itself carries no webfont and falls back to the
       system stacks below. */
    --nv-font-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;
    --nv-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    --nv-font-display: var(--nv-font-sans);

    /* Type ramp, rem, with fluid display steps */
    --nv-text-2xs: 0.6875rem;
    --nv-text-xs: 0.75rem;
    --nv-text-sm: 0.875rem;
    --nv-text-base: 1rem;
    --nv-text-lg: 1.125rem;
    --nv-text-xl: 1.25rem;
    --nv-text-2xl: 1.5rem;
    --nv-text-3xl: clamp(1.75rem, 1.35rem + 1.6vw, 2rem);
    --nv-text-4xl: clamp(2rem, 1.55rem + 2vw, 2.625rem);

    /* Two steps above the document, for a line whose job is to be read from
       across a room. Neither is a heading level: `h1` stays on 4xl, and a
       piece reaches for one of these deliberately.

       They are two because a site has two kinds of loud page and one rung
       cannot serve both. 6xl opens the one page that sells the whole thing;
       5xl opens a section's own landing page, which must be quieter than
       the front door or the two shout over each other. A ramp with only the
       top rung forces the second kind either up onto the hero, flattening
       the hierarchy, or down onto 4xl, where it stops being a landing page
       at all. */
    --nv-text-5xl: clamp(2rem, 1.5rem + 2.6vw, 3.5rem);
    --nv-text-6xl: clamp(2.25rem, 1.5rem + 3.4vw, 4rem);

    /* Controls only, and never density-remapped: under 16px effective, iOS
       zooms the page when the field takes focus. */
    --nv-text-input: 1rem;

    /* Three, and the display one goes with the display step: type that
       large needs its lines closer or the words stop reading as one thing. */
    --nv-leading-display: 1.05;
    --nv-leading-tight: 1.2;
    --nv-leading-normal: 1.5;

    --nv-weight-normal: 400;
    --nv-weight-medium: 500;
    --nv-weight-semi: 600;
    --nv-weight-bold: 700;

    /* Controls, touch floor, icons. A control is sized
       max(var(--nv-control-*), var(--nv-tap-target)), never one alone. */
    --nv-control-sm: 2rem;
    --nv-control-md: 2.5rem;
    --nv-control-lg: 2.75rem;
    --nv-tap-target: 0px;
    --nv-icon-sm: 1rem;
    --nv-icon-md: 1.25rem;
    --nv-icon-lg: 1.5rem;

    /* Shell geometry */
    --nv-header-h: 3.5rem;
    --nv-tabbar-h: 3.5rem;
    --nv-sidebar-w: 17.5rem;
    --nv-rail-w: 4.5rem;
    --nv-aside-w: 20rem;

    /* The width table. No other file mints a width. */
    --nv-page-w-sm: 30rem;
    --nv-page-w-md: 36rem;
    --nv-page-w-lg: 75rem;

    /* Motion. Every decorative duration scales through --nv-motion; a
       spinner stays on --nv-duration-spin, because essential motion keeps
       its meaning under reduce. No logic keys on a decorative
       transitionend: at --nv-motion 0 a transition fires no event. */
    --nv-motion: 1;
    --nv-duration-fast: calc(150ms * var(--nv-motion));
    --nv-duration-normal: calc(250ms * var(--nv-motion));
    --nv-duration-slow: calc(400ms * var(--nv-motion));
    --nv-duration-ambient: calc(2s * var(--nv-motion));
    --nv-duration-spin: 750ms;

    --nv-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --nv-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);

    /* The z ladder. A literal z-index of 2 or more is banned everywhere. */
    --nv-z-sticky: 10;
    --nv-z-chrome: 50;
    --nv-z-overlay: 100;
    --nv-z-dialog: 200;
    --nv-z-popover: 300;
    --nv-z-toast: 400;
    --nv-z-tooltip: 500;

    /* Insets. A native wrap may override these inline, which beats every
       layer. --nv-inset-bottom is the bottom pad for every docked surface,
       a max() and never a sum: on iOS the keyboard covers the home
       indicator, so adding the two pads twice. */
    --nv-safe-top: env(safe-area-inset-top, 0px);
    --nv-safe-right: env(safe-area-inset-right, 0px);
    --nv-safe-bottom: env(safe-area-inset-bottom, 0px);
    --nv-safe-left: env(safe-area-inset-left, 0px);
    --nv-kb-inset: 0px;
    --nv-inset-bottom: max(var(--nv-safe-bottom), var(--nv-kb-inset));

    /* Optional slots, defaulted from the required ones so a design that
       says nothing about them still paints. */
    --nv-color-link: var(--nv-color-accent);
    --nv-color-link-hover: var(--nv-color-accent-hover);
    --nv-color-border-subtle: var(--nv-color-border);
    --nv-color-danger-hover: var(--nv-color-danger);
    --nv-color-fg-on-danger: var(--nv-color-fg-on-accent);
    --nv-brand-healthy: var(--nv-color-success);
    --nv-brand-reconnecting: var(--nv-color-warning);
    --nv-brand-offline: var(--nv-color-danger);
    --nv-brand-logo-size: 2rem;
  }

  /* The shell's own tier, set by an app that runs before its content does.
     A website never sets it: a page must be complete before its script, and
     a tier written by a script is a layout that arrives late. */
  :root[data-tier='tablet'],
  :root[data-tier='desktop'] {
    --nv-page-gutter: 1.5rem;
  }

  /* The same step, asked of the page's own room instead of the window, so a
     surface with no script gets it too. `.nv-viewport` in components.css is
     the container this names. */
  @container nv-page (min-width: 48rem) {
    .nv-page {
      --nv-page-gutter: 1.5rem;
    }
  }

  @media (pointer: coarse) {
    :root {
      --nv-tap-target: 44px;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    :root {
      --nv-motion: 0;
    }
  }

  /* Density: one mode, unpinned, so any subtree hosts it and a dense region
     such as a table scopes it to itself. --nv-text-input and --nv-tap-target
     stay out: a field never falls under 16px, and the coarse floor still
     wins through max(). */
  [data-density='compact'] {
    --nv-text-sm: 0.8125rem;
    --nv-text-base: 0.9375rem;
    --nv-text-lg: 1.0625rem;
    --nv-control-sm: 1.75rem;
    --nv-control-md: 2.25rem;
    --nv-card-pad: 0.75rem;
    --nv-stack-gap: 0.75rem;
    --nv-form-gap: 0.5rem;
    --nv-section-gap: 1.5rem;
  }
}
