/* tokens.css — design token substrate (no Tailwind build)
 *
 * Same shape as apps/team-central/public/tokens.css, deliberately not the same file:
 *
 *  1. NUMERIC scales (spacing, radii, weight) mirror Tailwind v4's own variable names and values, so
 *     `css()` output references them directly and the numbers live in one place. That is the half
 *     worth keeping identical between the two apps.
 *  2. COLOUR is where they diverge, and should. team-central resolves light/dark through
 *     `light-dark()` because it is an internal portal that follows the OS. This is a brand site with
 *     one fixed look — dark, warm, fixed. There is no theme toggle and no `light-dark()`; adding one
 *     would be a design decision, not a port.
 *
 * The brand palette and the type stack are carried over verbatim from the SvelteKit app's `@theme`
 * block, so the colours on screen do not move.
 */

/* ── Lora (display) and DM Sans (body), self-hosted. The fallback faces carry metric overrides so the
 *    swap does not shift layout — measured against Georgia and the system sans respectively, and
 *    copied across unchanged. No external font CDN. ── */
@font-face {
  font-family: 'Lora';
  src: url('/fonts/Lora-VariableFont_wght.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Lora';
  src: url('/fonts/Lora-Italic-VariableFont_wght.woff2') format('woff2');
  font-weight: 400 700;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Lora Fallback';
  src: local('Georgia');
  size-adjust: 97.4%;
  ascent-override: 99%;
  descent-override: 27%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'DM Sans';
  src: url('/fonts/DMSans-VariableFont_opsz,wght.woff2') format('woff2');
  font-weight: 100 1000;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'DM Sans Fallback';
  src: local('sans-serif');
  size-adjust: 94.4%;
  ascent-override: 101%;
  descent-override: 28%;
  line-gap-override: 0%;
}

:root {
  color-scheme: dark;

  /* ── Brand palette. Verbatim from the SvelteKit @theme block. ─────────────── */
  --color-green: #a8ce72;
  --color-ember: #c4622d;
  --color-charcoal: #1a1814;
  --color-charcoal-mid: #242018;
  --color-charcoal-light: #2e2a24;
  --color-charcoal-border: #3a342c;
  --color-ash: #857f78;
  --color-ash-light: #8a837c;
  --color-cream: #f0ebe1;
  --color-cream-dim: #c9c2b5;

  /* ── Type stack ───────────────────────────────────────────────────────────── */
  --font-display: 'Lora', 'Lora Fallback', Georgia, serif;
  --font-body: 'DM Sans', 'DM Sans Fallback', sans-serif;

  /* ── Spacing — Tailwind's single-base model: step N = calc(var(--spacing) * N). ── */
  --spacing: 0.25rem;

  --font-weight-light: 300;
  --font-weight-normal: 400;
  --font-weight-medium: 500;

  /* Height of the fixed header. Sticky elements on the menu pages offset by it, so it has to be a
   * variable rather than a magic number. The SvelteKit nav overwrote it from `clientHeight` on mount;
   * this default is the measured height and is correct without JavaScript, which is the point. */
  --header-offset: 64px;
}

@layer base {
  /* The box model, reset once. Tailwind's preflight supplied this on the SvelteKit site
   * (`*,:after,:before,::backdrop{box-sizing:border-box;…}`) and removing Tailwind removed it with
   * nothing in its place, so every `width: 100%` element carrying padding overflowed its container.
   * Measured on /jobs before this landed: text inputs and textareas 834px inside an 800px parent —
   * 800 + 32px padding + 2px border — while selects sat correctly at 800px, because the UA
   * stylesheet already gives `<select>` border-box. Two controls on one form, different widths (#161).
   *
   * Margins and padding are zeroed too. An earlier version of this reset did the box model only, on
   * the reasoning that the rest of preflight would change more than it fixed. That was wrong: the
   * components were written against a site that had the full reset, and they had been compensating
   * by setting `marginTop: 0` by hand all over the place. What that missed showed up as a section
   * label carrying the UA's default 10.88px `<p>` margin-top where production has none (#164).
   *
   * Borders are not reset. Preflight sets `border: 0 solid` so its utilities can add one back; we
   * have no such utilities, and every component that wants a border already declares it in full.
   *
   * In `base` so anything the css() mixins emit into `rmx` still wins. */
  *,
  *::before,
  *::after,
  ::backdrop {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
  }

  /* Form controls do not inherit typography by default — the UA gives them its own font, and they
   * ignore the document's line-height. Tailwind's preflight covered this with
   * `button,input,select,optgroup,textarea{font:inherit;letter-spacing:inherit;color:inherit}` and
   * removing Tailwind removed it, the same gap as the box-sizing reset in #161.
   *
   * Measured before this landed: every input, select and textarea had `line-height: normal` where
   * production computes 23.04px, and radio inputs rendered in Arial 13.3333px at weight 400 in white
   * rather than inheriting DM Sans — so control heights and the vertical rhythm around them were
   * wrong throughout (#164).
   *
   * `line-height: 1.6` on body is unitless, so it inherits as a ratio and each control recomputes it
   * against its own font-size, which is what makes a 14.4px input 23.04px and a 12.8px button
   * 20.48px, exactly as production does. */
  button,
  input,
  select,
  optgroup,
  textarea {
    font: inherit;
    letter-spacing: inherit;
    color: inherit;
  }

  /* Replaced media elements are block-level, as they are in Tailwind's preflight
   * (`img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}`). Without
   * it an iframe is inline and sits on the text baseline, leaving a descender gap under it. */
  img,
  svg,
  video,
  canvas,
  audio,
  iframe,
  embed,
  object {
    display: block;
    vertical-align: middle;
  }

  /* `color-scheme: dark` on :root gives us dark scrollbars and dark native pickers, which the site
   * wants. It also inherits into iframes, and it is the property a browser uses to decide what to
   * paint behind an embedded document that does not paint its own background. The live site sets no
   * color-scheme at all — computed `normal` on root, body and the OpenTable iframe — and its widget
   * blends with the page where ours rendered on a light panel (#152).
   *
   * Scoped back to `normal` on iframes only, so the widget matches production while the rest of the
   * site keeps its dark chrome. Cause of the light panel: unverified — the widget's document is
   * cross-origin and cannot be inspected from here — but this was the only paint-related property on
   * the element that differed from production, and Steven confirmed the fix visually. */
  iframe {
    color-scheme: normal;
  }

  /* The remaining preflight rules that touch elements this site actually renders (#168). Audited
   * against the deployed stylesheet's `@layer base` rather than copied wholesale: of its 53 rules,
   * most govern elements we have none of — `hr`, `abbr`, `code`, `pre`, `table`, `sub`, `sup`, `ol`,
   * `video`, `progress`. Those are deliberately not restored; adding rules for markup that does not
   * exist is how a reset becomes noise nobody reads.
   *
   * Each rule below was kept because a probe measured our rendering differing from production's. */

  /* Unstyled links render browser-blue and underlined. Measured on /faq, which has one today —
   * `rgb(158, 158, 255)` against production's inherited cream. */
  a {
    color: inherit;
    text-decoration: inherit;
  }

  /* Headings otherwise take UA sizes — a bare `<h2>` measured 24px/700 against production's
   * 16px/400. Every heading the site renders sets its own size, so this changes nothing today and
   * stops the next one inheriting a size nobody chose. */
  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    font-size: inherit;
    font-weight: inherit;
  }

  /* Bullets. Measured `disc` against production's `none`. Every list we render sets this itself; the
   * reset means the next one does not have to. */
  ol,
  ul,
  menu {
    list-style: none;
  }

  /* Measured `max-width: none` against production's `100%`, so an image without explicit sizing
   * overflows its container rather than fitting it. */
  img,
  video {
    max-width: 100%;
    height: auto;
  }

  /* `[hidden]` is only a UA default and loses to any author `display`. Measured: a `<span hidden>`
   * carrying `display: flex` rendered visible here and stayed hidden on production. The client
   * entries render `<span hidden />`, so this is load-bearing rather than theoretical. */
  [hidden]:where(:not([hidden='until-found'])) {
    display: none !important;
  }

  button,
  input:where([type='button'], [type='reset'], [type='submit']) {
    appearance: button;
  }

  /* Firefox dims placeholders by default; production normalises it and we did not. */
  ::placeholder {
    opacity: 1;
  }

  html {
    /* Stops iOS inflating text in landscape. Not observable on a desktop browser, so this one is
       carried over on production's authority rather than on a measurement of ours. */
    -webkit-text-size-adjust: 100%;
    tab-size: 4;
    scroll-behavior: auto;
  }

  body {
    background-color: var(--color-charcoal);
    color: var(--color-cream);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    margin: 0;
    /* Clears the fixed mobile bottom nav; removed once that nav is not rendered. */
    padding-bottom: 4.5rem;
  }

  @media (min-width: 768px) {
    body {
      padding-bottom: 0;
    }
  }

  /* Grain overlay. A full-viewport fractal-noise filter at 3.5% opacity — the texture the whole
   * design sits on. Flagged in the spec as worth profiling: if it costs anything measurable, a small
   * pre-rendered tiled WebP is the same effect for none of the compositing cost. Not changed here,
   * because #99 is a port and that would be a change. */
  body::before {
    content: '';
    position: fixed;
    inset: 0;
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='1'/%3E%3C/svg%3E");
    opacity: 0.035;
    pointer-events: none;
    z-index: 1000;
  }
}

/* The hero nav's scroll state. `app/home/nav-scroll.tsx` sets `data-scrolled` on <html> past 80px;
 * this turns the transparent hero nav solid. It lives in the `overrides` layer because the nav's own
 * transparent background is generated by `css()` into the `rmx` layer, and later layers win
 * regardless of specificity — a rule here in `base` would simply never apply.
 *
 * Only the hero nav carries `data-hero`; every other page's nav is solid from the start. */
@layer overrides {
  /* Controls that exist only for the unenhanced path. `data-rmx-enhanced` is set on <html> by
   * entry.client.tsx after every navigation; see there for why this is CSS and not `.remove()`.
   *
   * Flat, and in this layer, for the same reason as the rules below: `css()` cannot express an
   * ancestor selector, and CSS nesting is the lowest-support feature the site ships. */
  [data-rmx-enhanced] [data-unenhanced] {
    display: none;
  }

  /* ── Control states, written flat so they survive without CSS nesting ─────────
   *
   * `css()` emits every pseudo-class as a nested rule — `&:checked`, `&:focus` inside the class
   * block. Native CSS nesting is the lowest-support feature this site ships: 93.07% of UK traffic,
   * 89.58% on desktop, measured with scripts/tools/browser-support.js. Below `color-mix()` at
   * 95.43%, which .claude/rules/browser-support.md currently names as the binding constraint (#173).
   *
   * For most of what nesting carries here — hover, ::before, ::after, placeholder colour — losing it
   * costs decoration. These two are different, because in each case the neutralising declaration
   * sits at the TOP level of the same rule and therefore always applies:
   *
   *   radio        `appearance: none` removes the native dot; `&:checked` draws the replacement.
   *                Without nesting the dot goes and nothing replaces it, so a selected radio is
   *                indistinguishable from an unselected one. The jobs form has three required radio
   *                groups.
   *   text inputs  `outline: none` suppresses the UA focus ring; `&:focus` tints the border instead.
   *                Without nesting there is no focus indicator at all.
   *
   * Restated flat here, in `overrides` so they beat the generated class in `rmx`. Selectors match
   * the live site's own, which styles these by element rather than by class. The mixins keep their
   * nested versions — this is a floor, not a replacement, and the two agree. */
  input[type='radio']:checked {
    border-color: var(--color-green);
    background: var(--color-green);
    box-shadow: inset 0 0 0 3px var(--color-charcoal-mid);
  }

  input[type='radio']:focus-visible {
    outline: 2px solid var(--color-green);
    outline-offset: 2px;
  }

  input:not([type='checkbox']):not([type='radio']):focus,
  select:focus,
  textarea:focus {
    border-color: var(--color-green);
  }

  :root[data-scrolled] nav[data-hero] {
    background: rgba(26, 24, 20, 0.98);
    background-image: none;
    border-bottom: 1px solid var(--color-charcoal-light);
  }
}
