/* lexvd.nl — one static page.
   Palette from the TechiesReviews brand (Voldemort purple, Imperial Red, Dr. White).
   Helpers first, then one bounded @scope per component. */

@layer tokens, base, utilities, components;

@layer tokens {
  :root {
    color-scheme: light dark;

    --color-snow: #FAFAFA;
    --color-mist: #DFDFE5;
    --color-ink: #17121F;
    --color-purple: #2D135F;
    --color-purple-light: oklch(from var(--color-purple) 82% 0.06 h);
    --color-red: #EC2938;
    --color-orange: #F28C28;

    --semantic-bg: light-dark(var(--color-snow), var(--color-ink));
    --semantic-surface: light-dark(
      color-mix(in oklch, var(--color-mist) 45%, var(--color-snow)),
      color-mix(in oklch, var(--color-purple) 35%, var(--color-ink))
    );
    --semantic-text: light-dark(var(--color-ink), var(--color-snow));
    --semantic-muted: light-dark(
      color-mix(in oklch, var(--color-ink) 65%, var(--color-snow)),
      color-mix(in oklch, var(--color-snow) 70%, var(--color-ink))
    );
    --semantic-accent: light-dark(var(--color-purple), var(--color-purple-light));
    --semantic-highlight: var(--color-red);
    --semantic-shadow: light-dark(
      color-mix(in oklch, var(--color-purple) 12%, transparent),
      color-mix(in oklch, var(--color-ink) 80%, transparent)
    );
    --semantic-gradient: linear-gradient(120deg, var(--color-orange), var(--color-red) 55%, var(--color-purple-light));

    --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-mono: ui-monospace, "Roboto Mono", "SF Mono", Menlo, Consolas, monospace;

    --text-small: 0.875rem;
    --text-body: clamp(1rem, 0.95rem + 0.2vw, 1.125rem);
    --text-lead: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
    --text-h3: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem);
    --text-display: clamp(2rem, 1.6rem + 2vw, 3rem);

    --space-s: 0.75rem;
    --space-m: 1.5rem;
    --space-l: 3rem;
    --space-xl: clamp(3rem, 2.5rem + 3vw, 5rem);

    --radius-m: 1rem;
    --radius-l: 1.75rem;
    --max-width: 44rem;
  }

  body[data-theme="light"] { color-scheme: light; }
  body[data-theme="dark"] { color-scheme: dark; }
}

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

  html { scroll-behavior: smooth; scroll-padding-top: 5rem; }
  @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

  body {
    margin: 0;
    background: var(--semantic-bg);
    color: var(--semantic-text);
    font: 400 var(--text-body) / 1.6 var(--font-sans);
    -webkit-font-smoothing: antialiased;
  }

  h1, h2, h3, p, ul, figure { margin: 0; }
  ul { padding: 0; list-style: none; }
  img { display: block; max-width: 100%; }

  a { color: inherit; text-underline-offset: 0.2em; text-decoration-thickness: 1px; }
  a:hover { color: var(--semantic-highlight); }
  :focus-visible { outline: 2px solid var(--semantic-highlight); outline-offset: 3px; border-radius: 0.25rem; }

  .skip-link { position: absolute; left: var(--space-s); top: -4rem; padding: var(--space-s); background: var(--semantic-surface); }
  .skip-link:focus { top: var(--space-s); }

  body[data-theme="dark"] .theme-toggle .moon,
  body:not([data-theme="dark"]) .theme-toggle .sun { display: none; }
}

@layer utilities {
  .section { padding-block: var(--space-xl); }

  .container {
    display: flex;
    flex-direction: column;
    gap: var(--space-l);
    width: 100%;
    max-width: var(--max-width);
    margin-inline: auto;
    padding-inline: var(--space-m);
  }

  .layout-flex { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-m); }

  .layout-grid {
    --_columns: 1;
    display: grid;
    grid-template-columns: repeat(var(--_columns), minmax(0, 1fr));
    gap: var(--space-m);
  }

  .eyebrow {
    font: 500 var(--text-small) / 1.4 var(--font-mono);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--semantic-muted);
  }

  .heading-style-display {
    font-size: var(--text-display);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -0.025em;
    text-wrap: balance;
  }

  .heading-style-h3 { font-size: var(--text-h3); font-weight: 600; line-height: 1.25; letter-spacing: -0.01em; }

  .lead { font-size: var(--text-lead); line-height: 1.5; text-wrap: pretty; }

  .image { width: 100%; height: auto; object-fit: cover; aspect-ratio: 1 / 1; }

  .button { font-weight: 500; transition: color 160ms ease-out; }

  /* Outgoing-link arrow: nudges in on hover; on press it shoots out top-right
     while a fresh arrow slides in from the bottom-left. The two arrows are two
     layers of one mask, so the box clips them and the colour follows the link. */
  .external-arrow::after {
    --_arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 17 17 7M8 7h9v9'/%3E%3C/svg%3E");
    content: "";
    display: inline-block;
    width: 0.8em;
    height: 0.8em;
    margin-inline-start: 0.3em;
    vertical-align: -0.05em;
    background-color: var(--semantic-muted);
    mask: var(--_arrow) 0 0 / 100% 100% no-repeat, var(--_arrow) -0.8em 0.8em / 100% 100% no-repeat;
    transition: mask-position 280ms cubic-bezier(0.34, 1.56, 0.64, 1), background-color 160ms ease-out;
  }
  @media (hover: hover) {
    .external-arrow:hover::after {
      background-color: currentColor;
      mask-position: -0.14em 0.14em, -0.8em 0.8em;
    }
  }
  .external-arrow:active::after,
  .external-arrow:focus:not(:focus-visible)::after {
    background-color: currentColor;
    animation: external-arrow-shoot 520ms both;
  }
  @keyframes external-arrow-shoot {
    0% { mask-position: -0.14em 0.14em, -0.8em 0.8em; animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); }
    40% { mask-position: 0.8em -0.8em, -0.8em 0.8em; animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
    100% { mask-position: 0.8em -0.8em, 0 0; }
  }
  @media (prefers-reduced-motion: reduce) {
    .external-arrow::after { transition: background-color 160ms ease-out; }
    .external-arrow:hover::after { mask-position: 0 0, -0.8em 0.8em; }
    .external-arrow:active::after,
    .external-arrow:focus:not(:focus-visible)::after { animation: none; }
  }
}

@layer components {
  /* Sticky header with a progressive blur, as on techies.review (after Jhey
     Tompkins's jhey.dev/demos/2024/progressive-blurs): five backdrop layers
     that blur less the lower they start, so the blur fades out under the bar.
     Browsers without mask or sin() get one even blur; without
     backdrop-filter, a nearly solid bar. */
  @scope (.header_component) to ([class*="_component"]) {
    :scope {
      --fade: 2rem;
      position: sticky;
      top: 0;
      z-index: 10;
      padding-block: var(--space-m);
      background: color-mix(in oklch, var(--semantic-bg) 96%, transparent);
    }
    .container { position: relative; }
    .backdrop { display: none; }

    @supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
      :scope {
        background: color-mix(in oklch, var(--semantic-bg) 80%, transparent);
        -webkit-backdrop-filter: saturate(1.6) blur(12px);
        backdrop-filter: saturate(1.6) blur(12px);
      }
    }

    @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) and ((mask-image: linear-gradient(#000, #000)) or (-webkit-mask-image: linear-gradient(#000, #000))) and (width: calc(1px * sin(90deg))) {
      /* The header must not blur itself here: it would become the backdrop
         root of the layers, and they would blur nothing. */
      :scope { background: none; -webkit-backdrop-filter: none; backdrop-filter: none; }

      .backdrop {
        --layers: 5;
        --blur-max: 16;
        position: absolute;
        inset: 0 0 auto;
        display: block;
        height: calc(100% + var(--fade));
        pointer-events: none;
      }
      .backdrop > i, .backdrop::after { position: absolute; inset: 0; }
      .backdrop > i:nth-child(1) { --i: 1; }
      .backdrop > i:nth-child(2) { --i: 2; }
      .backdrop > i:nth-child(3) { --i: 3; }
      .backdrop > i:nth-child(4) { --i: 4; }
      .backdrop > i:nth-child(5) { --i: 5; }
      .backdrop > i {
        --blur: calc(sin((var(--layers) - var(--i)) / var(--layers) * 90deg) * var(--blur-max) * 1px);
        --stop: calc(sin(var(--i) / var(--layers) * 90deg) * 100);
        --mask: linear-gradient(to top, #0000 0 calc((100 - var(--stop)) * 1%), #000 100%);
        -webkit-backdrop-filter: blur(var(--blur));
        backdrop-filter: blur(var(--blur));
        -webkit-mask-image: var(--mask);
        mask-image: var(--mask);
      }
      /* A tint that fades out by the bar's edge keeps the links readable. */
      .backdrop::after {
        content: "";
        background: linear-gradient(to bottom, color-mix(in oklch, var(--semantic-bg) 72%, transparent) 0%, transparent calc(100% - var(--fade)));
      }
    }

    @media (prefers-reduced-transparency: reduce) {
      :scope { background: var(--semantic-bg); -webkit-backdrop-filter: none; backdrop-filter: none; }
      .backdrop { display: none; }
    }
    .container { flex-direction: row; justify-content: space-between; }
    .wordmark { margin-inline-end: auto; font: 600 1.125rem / 1 var(--font-mono); text-decoration: none; }
    .wordmark::after { content: "."; color: var(--semantic-highlight); }
    nav a { font-size: var(--text-small); text-decoration: none; color: var(--semantic-muted); }
    nav a:hover { color: var(--semantic-text); }
    .theme-toggle { display: inline-flex; padding: 0.25rem; border: 0; background: none; color: var(--semantic-muted); cursor: pointer; }
    .theme-toggle:hover { color: var(--semantic-text); }
  }

  @scope (.hero_component) to ([class*="_component"]) {
    :scope { padding-block-start: var(--space-l); }
    .heading-style-display { max-width: 20ch; }
    .layout-grid { gap: var(--space-l); align-items: start; }
    .content { display: flex; flex-direction: column; gap: var(--space-m); color: var(--semantic-muted); }
    .lead { color: var(--semantic-text); }
    .portrait { width: 6rem; grid-row: 1; }
  }

  @scope (.now_component) to ([class*="_component"]) {
    .layout-grid { gap: var(--space-l); }
  }

  @scope (.card_component) to ([class*="_component"]) {
    :scope {
      display: flex;
      flex-direction: column;
      gap: var(--space-s);
    }
    .heading-style-h3 a { text-decoration: none; }
    p { color: var(--semantic-muted); }
    .meta { font: 400 var(--text-small) / 1.4 var(--font-mono); color: var(--semantic-accent); }
  }

  @scope (.made_component) to ([class*="_component"]) {
    .container { gap: var(--space-m); }
    .intro { color: var(--semantic-muted); }

    .row {
      display: grid;
      grid-template-columns: 1fr;
      grid-template-areas: "name status" "description description";
      grid-template-columns: 1fr auto;
      gap: 0.25rem var(--space-m);
      align-items: baseline;
      padding-block: var(--space-s);
    }

    .name { grid-area: name; font-size: var(--text-body); font-weight: 600; }
    .name a { text-decoration: none; }
    .source { display: inline-flex; margin-inline-start: 0.5em; vertical-align: -0.1em; color: var(--semantic-muted); }
    .source:hover { color: var(--semantic-text); }
    .description { grid-area: description; color: var(--semantic-muted); }
    .status { grid-area: status; font: 400 var(--text-small) / 1.4 var(--font-mono); color: var(--semantic-muted); }
  }

  @scope (.contact_component) to ([class*="_component"]) {
    :scope { padding-block-end: var(--space-l); }
    .container { gap: var(--space-m); }
    .lead { color: var(--semantic-muted); }
    .layout-flex { gap: var(--space-s) var(--space-m); }
  }

  @scope (.footer_component) to ([class*="_component"]) {
    :scope { padding-block: var(--space-l); font-size: var(--text-small); color: var(--semantic-muted); }
    .container { flex-direction: row; justify-content: space-between; }
  }
}
