/* Dagda — dagda.dev
 * Hand-written CSS. No framework, no build step, no preprocessor.
 * Edit this file directly.
 *
 * Layer order fixes the cascade once and for all, so nothing below ever needs
 * !important or selector-weight games to win:
 *   reset < base < layout < components < utilities
 */
@layer reset, base, layout, components, utilities;

/* ─── Fonts ───────────────────────────────────────────────────────────── */

@font-face {
  font-family: 'Alan Sans';
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url('/assets/fonts/AlanSans-Variable.woff2') format('woff2-variations');
}

@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url('/assets/fonts/JetBrainsMono-Variable.woff2')
    format('woff2-variations');
}

/* ─── Tokens ──────────────────────────────────────────────────────────── */

:root {
  /* Brand green — the only custom palette. Anchored on --green-700. */
  --green-100: #d9ecd2;
  --green-200: #c3e6b5;
  --green-300: #9ede84;
  --green-400: #71cb46;
  --green-500: #58b721;
  --green-600: #469713;
  --green-700: #397618;
  --green-800: #305d1b;
  --green-900: #2a4c1b;

  /* Surfaces and ink */
  --white: #fff;
  --ink: oklch(14.5% 0 none); /* body text, dark surfaces  */
  --rule: oklch(20.5% 0 none); /* 1.5px structural borders  */
  --muted: oklch(43.9% 0 none); /* secondary copy            */
  --hairline: oklch(86.9% 0.005 56.366); /* soft dividers, ink on dark */

  --font-sans:
    'Alan Sans', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* The single allowed border width, and the single allowed shadow. */
  --rule-w: 1.5px;
  --press: 6px 6px 0 var(--rule);

  --gutter: 1.5rem; /* page side padding, widened at --bp    */
  --container: 1440px;
  --content: 80rem; /* 1280px — the default reading column   */

  --ease: cubic-bezier(0.4, 0, 0.2, 1);

  /* Body-copy leading. Deliberately airy: these are long French paragraphs. */
  --lh-prose: 1.75;
}

@media (width >= 48rem) {
  :root {
    --gutter: 4rem;
  }
}

/* ─── Reset ───────────────────────────────────────────────────────────── */

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

  * {
    margin: 0;
  }

  img,
  svg {
    display: block;
    max-width: 100%;
  }

  ul,
  ol {
    list-style: none;
    padding: 0;
  }

  a {
    color: inherit;
    text-decoration: none;
  }

  button,
  input,
  label {
    font: inherit;
  }
}

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

@layer base {
  html {
    background: var(--white);
    color: var(--ink);
    font-family: var(--font-sans);
    font-feature-settings:
      'kern' 1,
      'liga' 1;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    scroll-behavior: smooth;
    scroll-padding-top: 6rem;
  }

  body {
    font-size: 1.125rem;
    line-height: 1.5;
    letter-spacing: -0.01em;
    overflow-x: hidden;
  }

  ::selection {
    background: var(--green-700);
    color: var(--white);
  }

  :focus-visible {
    outline: 2px solid var(--green-700);
    outline-offset: 2px;
  }

  /* Headings are sized by their component, never by their tag. */
  h1,
  h2,
  h3,
  h4 {
    font-size: inherit;
    font-weight: 700;
    text-wrap: pretty;
  }

  /* The green emphasis inside a heading. Inverts on dark surfaces below. */
  em {
    font-style: normal;
    color: var(--green-700);
  }

  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: 1ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 1ms !important;
    }
  }
}

/* ─── Layout ──────────────────────────────────────────────────────────── */

@layer layout {
  .page {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
  }

  main {
    flex: 1;
  }

  .section {
    padding: 2.5rem var(--gutter);
    position: relative;
  }

  .section__inner {
    max-width: var(--content);
    margin-inline: auto;
    position: relative;
  }

  .section__inner--wide {
    max-width: var(--container);
  }

  /* Section rhythm variants. */
  .section--hero {
    padding-block-start: 0;
  }
  .section--tight {
    padding-block: 1.5rem;
  }
  .section--dark {
    padding-block: 4rem;
    background: var(--green-900);
    color: var(--white);
  }

  @media (width >= 48rem) {
    .section {
      padding-block: 4rem;
    }
    .section--hero {
      padding-block-start: 0;
    }
    .section--tight {
      padding-block: 2rem;
    }
    .section--dark {
      padding-block: 6rem;
    }
  }

  /* An anchored section must clear the sticky masthead. */
  [id] {
    scroll-margin-top: 6rem;
  }
}

/* ─── Components ──────────────────────────────────────────────────────── */

@layer components {
  /* Skip link ------------------------------------------------------- */

  .skip-link:not(:focus) {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .skip-link:focus {
    position: absolute;
    z-index: 1000;
    margin: 0.75rem;
    padding: 0.75rem;
    background: var(--white);
    border: var(--rule-w) solid var(--rule);
  }

  /* Status bar ------------------------------------------------------ */

  .statusbar {
    background: var(--green-700);
    color: var(--white);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    line-height: 1.5;
    letter-spacing: 0.04em;
  }

  .statusbar[data-state='busy'] {
    background: var(--green-900);
  }

  .statusbar__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    max-width: var(--container);
    margin-inline: auto;
    padding: 0.5rem var(--gutter);
  }

  .statusbar__state {
    display: flex;
    align-items: center;
    gap: 0.625rem;
  }

  .statusbar__stack {
    display: none;
    opacity: 0.9;
  }

  @media (width >= 48rem) {
    .statusbar__stack {
      display: block;
    }
  }

  /* The availability dot. Pulses when free, static when busy. */
  .dot {
    inline-size: 0.5rem;
    block-size: 0.5rem;
    border-radius: 50%;
    background: var(--green-500);
    animation: pulse 2.2s ease-in-out infinite;
  }

  [data-state='busy'] .dot {
    background: var(--white);
    opacity: 0.6;
    animation: none;
  }

  @keyframes pulse {
    0%,
    100% {
      opacity: 1;
      transform: scale(1);
    }
    50% {
      opacity: 0.4;
      transform: scale(0.85);
    }
  }

  /* Mastheads ------------------------------------------------------- */

  .masthead,
  .mobilebar {
    position: sticky;
    top: 0;
    background: var(--white);
    border-block-end: var(--rule-w) solid var(--rule);
  }

  .masthead {
    display: none;
    z-index: 50;
  }
  .mobilebar {
    z-index: 40;
  }

  @media (width >= 48rem) {
    .masthead {
      display: block;
    }
    .mobilebar {
      display: none;
    }
  }

  .masthead__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    max-width: var(--container);
    margin-inline: auto;
    padding: 2rem var(--gutter);
  }

  .masthead__actions {
    display: flex;
    align-items: center;
    gap: 2rem;
  }

  .brand {
    display: flex;
    align-items: center;
  }

  .brand img {
    block-size: 3.25rem;
    inline-size: auto;
  }

  /* Main nav — the underline sweeps in from the right. */
  .mainnav {
    display: flex;
    align-items: center;
    gap: 2rem;
  }

  .mainnav a {
    position: relative;
    display: block;
    padding-block: 0.5rem;
    font-size: 0.9375rem;
    font-weight: 500;
    line-height: 1.4;
    letter-spacing: -0.01em;
  }

  .mainnav a::after {
    content: '';
    position: absolute;
    inset-inline: 0 100%;
    inset-block-end: -4px;
    block-size: 2px;
    background: var(--green-700);
    transition: inset-inline-end 250ms ease-out;
  }

  .mainnav a:hover::after,
  .mainnav a:focus-visible::after {
    inset-inline-end: 0;
  }

  /* Mobile bar — the menu is a checkbox toggle, no JavaScript. */
  .mobilebar__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    block-size: 4rem;
    padding-inline: 1rem;
  }

  .mobilebar .brand {
    position: relative;
    z-index: 50;
  }
  .mobilebar .brand img {
    block-size: 2.25rem;
  }

  .burger {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    inline-size: 2.5rem;
    block-size: 2.5rem;
    position: relative;
    z-index: 50;
    cursor: pointer;
  }

  /* Umami resolves a click to closest("a,button"); a <label> matches neither,
   * so it falls back to the raw event target. Without this, clicks landing on
   * a bar report the <span> and the menu-toggle event is silently dropped. */
  .burger span {
    pointer-events: none;
    inline-size: 1.25rem;
    block-size: 2px;
    background: var(--ink);
    transition:
      rotate 150ms var(--ease),
      translate 150ms var(--ease),
      opacity 150ms var(--ease);
  }

  .mobilemenu {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 40;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2rem;
    padding-inline: 3rem;
    background: var(--white);
  }

  /* The overlay is a sibling of the checkbox, so a plain ~ reaches it. The
   * burger bars are not — they are nested in the label — so they need :has()
   * instead. Getting this wrong is why the bars never animated on dagda.dev. */
  #mobile-menu-toggle:checked ~ .mobilemenu {
    display: flex;
  }

  .mobilebar:has(#mobile-menu-toggle:checked) .burger span:nth-child(1) {
    rotate: 45deg;
    translate: 0 8px;
  }
  .mobilebar:has(#mobile-menu-toggle:checked) .burger span:nth-child(2) {
    opacity: 0;
  }
  .mobilebar:has(#mobile-menu-toggle:checked) .burger span:nth-child(3) {
    rotate: -45deg;
    translate: 0 -8px;
  }

  /* Lock the page behind the open overlay. */
  html:has(#mobile-menu-toggle:checked) {
    overflow: hidden;
  }

  .mobilemenu__list {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2rem;
  }

  .mobilemenu__list a {
    font-size: 1.5rem;
    font-weight: 500;
    transition: color 300ms var(--ease);
  }

  .mobilemenu__list a:hover {
    color: var(--green-700);
  }

  /* Buttons --------------------------------------------------------- */

  .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.875rem 1.75rem;
    background: var(--ink);
    color: var(--white);
    border: var(--rule-w) solid transparent;
    font-size: 1rem;
    font-weight: 500;
    line-height: 1.2;
    letter-spacing: -0.01em;
    transition:
      background-color 150ms ease-out,
      translate 150ms ease-out,
      box-shadow 150ms ease-out;
  }

  .btn:hover {
    background: var(--green-700);
    translate: -2px -2px;
    box-shadow: var(--press);
  }

  .btn--lg {
    padding: 1.125rem 2.25rem;
    font-size: 1.375rem;
    line-height: 1.2;
  }

  .btn__arrow {
    transition: translate 150ms ease-out;
  }

  .btn:hover .btn__arrow {
    translate: 4px 0;
  }

  /* On a dark surface the button inverts so it stays the brightest thing. */
  .section--dark .btn {
    background: var(--white);
    color: var(--ink);
  }

  .section--dark .btn:hover {
    background: var(--green-500);
    color: var(--ink);
    box-shadow: 6px 6px 0 var(--green-700);
  }

  /* Prose ----------------------------------------------------------- */

  .prose p {
    margin-block-end: 1.5rem;
    font-size: 1.0625rem;
    line-height: var(--lh-prose);
  }

  .lead {
    max-width: 60rem;
    color: var(--muted);
    font-size: 1.75rem;
    line-height: var(--lh-prose);
    letter-spacing: -0.015em;
    text-wrap: pretty;
  }

  .note {
    max-width: 60rem;
    margin-block: 2rem 0;
    color: var(--muted);
    line-height: var(--lh-prose);
    text-wrap: pretty;
  }

  /* Hero ------------------------------------------------------------ */

  .hero {
    display: flow-root;
    max-width: calc((100% - 4rem) * 0.75);
  }

  @media (width < 48rem) {
    .hero {
      max-width: none;
    }
  }

  .hero h1 {
    margin-block: 2rem;
    font-size: clamp(3.5rem, 14vw, 10.5rem);
    line-height: 0.86;
    letter-spacing: -0.045em;
    overflow-wrap: break-word;
    hyphens: auto;
  }

  .hero .lead {
    margin-block-start: 1.5rem;
  }
  .hero .btn {
    margin-block: 1rem;
  }

  /* Section headings ------------------------------------------------ */

  .section__title,
  .section__subtitle {
    text-wrap: pretty;
    overflow-wrap: break-word;
    hyphens: auto;
  }

  .section__title {
    margin-block: 1.5rem;
    font-size: clamp(2.25rem, 7vw, 4.5rem);
    line-height: 0.95;
    letter-spacing: -0.035em;
    text-align: center;
  }

  .section__subtitle {
    margin-block: 1rem 2rem;
    font-size: clamp(2rem, 5.5vw, 3.25rem);
    line-height: 0.95;
    letter-spacing: -0.035em;
  }

  /* The subtitle that opens a block sits tighter than one that follows a
   * card grid, which needs air above it to separate the two groups. */
  .cards + .section__subtitle {
    margin-block: 3rem 1rem;
  }

  .section__intro {
    max-width: 60rem;
    margin: 1rem auto 2.5rem;
    color: var(--muted);
    line-height: var(--lh-prose);
    text-align: center;
    text-wrap: pretty;
  }

  /* Card grid ------------------------------------------------------- */

  /* The 1.5px gaps show the grid's own background through, which collapses
   * adjacent card borders into single hairlines instead of doubling them. */
  .cards {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--rule-w);
    background: var(--rule);
    border: var(--rule-w) solid var(--rule);
  }

  @media (width >= 48rem) {
    .cards {
      grid-template-columns: 1fr 1fr;
    }
  }

  .card {
    padding: 2rem;
    background: var(--white);
    text-align: center;
  }

  .card h3,
  .card h4 {
    font-size: 1.375rem;
    line-height: 1.05;
    letter-spacing: -0.02em;
    margin-block-end: 1.5rem;
  }

  .card p {
    color: var(--muted);
    line-height: var(--lh-prose);
    text-wrap: pretty;
  }

  /* A card that spans the full grid keeps the same measure as its siblings,
   * so a wide card reads as one of the set rather than a banner. */
  .card--wide {
    grid-column: 1 / -1;
  }

  .card--wide > * {
    max-width: 36rem;
    margin-inline: auto;
  }

  /* Stats ----------------------------------------------------------- */

  .stats {
    display: grid;
    grid-template-columns: 1fr;
    align-items: center;
    border-block: var(--rule-w) solid var(--hairline);
  }

  @media (width >= 48rem) {
    .stats {
      grid-template-columns: repeat(5, 1fr);
    }
  }

  .stats li {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    padding: 2rem;
    text-align: center;
  }

  .stats b {
    font-size: clamp(2rem, 5.5vw, 3.25rem);
    font-weight: 700;
    line-height: 0.95;
    letter-spacing: -0.035em;
  }

  .stats span {
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.45;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  /* About ----------------------------------------------------------- */

  .about {
    display: grid;
    gap: 4rem;
    align-items: start;
  }

  @media (width >= 48rem) {
    .about {
      grid-template-columns: 42fr 58fr;
    }
  }

  .about h2 {
    margin-block: 1.5rem;
    font-size: clamp(2.25rem, 7vw, 4.5rem);
    line-height: 0.95;
    letter-spacing: -0.035em;
    overflow-wrap: break-word;
    hyphens: auto;
  }

  .rule {
    border: 0;
    border-block-start: var(--rule-w) solid var(--hairline);
    margin-block: 3rem;
  }

  /* Tech stack ------------------------------------------------------ */

  .stack {
    border-block-end: var(--rule-w) solid var(--hairline);
  }

  .stack__row {
    display: grid;
    gap: 0.75rem;
    padding-block: 1.25rem;
    border-block-start: var(--rule-w) solid var(--hairline);
  }

  @media (width >= 48rem) {
    .stack__row {
      grid-template-columns: 12rem 1fr;
      gap: 2rem;
    }
  }

  .stack dt {
    color: var(--green-700);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    line-height: 1.5;
    letter-spacing: 0.04em;
  }

  .stack dt::before {
    content: '/ ';
  }

  .tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .tags li {
    padding: 0.25rem 0.5rem;
    border: var(--rule-w) solid var(--rule);
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    font-weight: 500;
    line-height: 1.5;
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }

  /* Contact CTA ----------------------------------------------------- */

  .cta {
    display: grid;
    gap: 3rem;
    align-items: end;
  }

  @media (width >= 48rem) {
    .cta {
      grid-template-columns: 58fr 42fr;
    }
  }

  .cta h2 {
    margin-block: 2rem;
    font-size: clamp(3rem, 11vw, 7.5rem);
    line-height: 0.9;
    letter-spacing: -0.04em;
    overflow-wrap: break-word;
    hyphens: auto;
  }

  .cta__body p {
    color: rgb(255 255 255 / 0.85);
    line-height: var(--lh-prose);
    text-wrap: pretty;
  }

  .cta__body .btn {
    margin-block-start: 1rem;
  }

  .infocards {
    display: grid;
    gap: 2rem;
    margin-block-start: 3rem;
  }

  @media (width >= 48rem) {
    .infocards {
      grid-template-columns: 1fr 1fr;
    }
  }

  .infocard {
    display: flex;
    align-items: start;
    gap: 1rem;
    padding: 1.5rem;
    border: var(--rule-w) solid var(--green-700);
  }

  .infocard svg {
    flex-shrink: 0;
    inline-size: 1.25rem;
    block-size: 1.25rem;
    margin-block-start: 0.25rem;
    color: var(--green-500);
  }

  .infocard p:last-child {
    color: rgb(255 255 255 / 0.8);
    font-size: 1rem;
    line-height: 1.45;
  }

  .infocard__label {
    margin-block-end: 0.5rem;
    color: var(--green-200);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.45;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  /* Dark-surface inversion ------------------------------------------ */

  .section--dark h1,
  .section--dark h2,
  .section--dark h3,
  .section--dark h4 {
    color: var(--white);
  }

  .section--dark em {
    color: var(--green-500);
  }

  /* 404 -------------------------------------------------------------- */

  .eyebrow {
    display: inline-block;
    padding: 0.25rem 0.5rem;
    background: var(--green-700);
    color: var(--white);
    border: var(--rule-w) solid var(--green-700);
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    font-weight: 500;
    line-height: 1.5;
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }

  .page-title {
    margin-block: 2rem;
    font-size: clamp(3rem, 11vw, 7.5rem);
    line-height: 0.9;
    letter-spacing: -0.04em;
    overflow-wrap: break-word;
    hyphens: auto;
  }

  /* Footer ---------------------------------------------------------- */

  .sitefooter {
    background: var(--ink);
    color: var(--hairline);
    border-block-start: 6px solid var(--green-500);
  }

  .sitefooter__inner {
    display: grid;
    grid-template-columns: 1fr;
    gap: 3rem;
    max-width: var(--container);
    margin-inline: auto;
    padding: 4rem var(--gutter);
  }

  @media (width >= 48rem) {
    .sitefooter__inner {
      grid-template-columns: repeat(4, 1fr);
    }
    .sitefooter__brand {
      grid-column: span 1;
    }
    .sitefooter__nav {
      grid-column: span 3;
    }
  }

  .sitefooter__brand a {
    display: inline-block;
    margin-block-end: 1rem;
  }

  .sitefooter__brand img {
    block-size: 2.25rem;
    inline-size: auto;
  }

  .sitefooter__tagline {
    max-width: 20rem;
    margin-block-end: 1.5rem;
    opacity: 0.8;
    font-size: 1rem;
    line-height: 1.45;
  }

  .sitefooter__colophon {
    opacity: 0.7;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    font-weight: 500;
    line-height: 1.625;
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }

  .sitefooter__nav {
    display: grid;
    grid-template-columns: 1fr;
    gap: 3rem;
  }

  @media (width >= 40rem) {
    .sitefooter__nav {
      grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    }
  }

  .sitefooter__heading {
    margin-block-end: 1.5rem;
    color: var(--green-200);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.45;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .sitefooter__nav ul {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
  }

  .sitefooter__nav a {
    font-size: 1rem;
    line-height: 1.45;
    transition: color 150ms var(--ease);
  }

  .sitefooter__nav a:hover {
    color: var(--green-200);
  }
}

/* ─── Utilities ───────────────────────────────────────────────────────── */

/* One utility, and only because the element it lands on (the mobile menu
 * checkbox) already belongs to a component and still has to be hidden. */
@layer utilities {
  /* Visually hidden but still announced. */
  .visually-hidden {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
