<!doctype html>
<html lang="en">
<head>
  <script>document.documentElement.classList.add('js');</script>
  <script async src="https://www.googletagmanager.com/gtag/js?id=G-1C95T94M8D"></script>
  <script>
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());
    gtag('config', 'G-1C95T94M8D');
  </script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
  <meta name="color-scheme" content="light">
  <title>Tomás Müller | Software, Systems, Writing</title>
  <meta name="description" content="Tomás Müller's site. Background, writing, code, and a few places to keep reading.">
  <meta name="robots" content="index, follow">
  <meta name="theme-color" content="#f1e7d8">
  <link rel="canonical" href="https://tomasmuller.dev/">
  <link rel="me" href="https://www.linkedin.com/in/t0masmuller/">
  <link rel="me" href="https://github.com/tomasmuller">
  <link rel="me" href="https://x.com/tomasmuller">
  <meta property="og:site_name" content="Tomás Müller">
  <meta property="og:locale" content="en_US">
  <meta property="og:title" content="Tomás Müller | Software, Systems, Writing">
  <meta property="og:description" content="Background, writing, code, and notes from Tomás Müller.">
  <meta property="og:type" content="website">
  <meta property="og:url" content="https://tomasmuller.dev/">
  <meta name="twitter:card" content="summary">
  <meta name="twitter:title" content="Tomás Müller | Software, Systems, Writing">
  <meta name="twitter:description" content="Background, writing, code, and notes from Tomás Müller.">
  <meta name="twitter:creator" content="@tomasmuller">
  <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' rx='22' fill='%23cf6a39'/%3E%3Ctext x='50' y='62' text-anchor='middle' font-size='46' fill='%23f7f0e4'%3ET%3C/text%3E%3C/svg%3E">
  <style>
    :root {
      --paper: oklch(96.2% 0.018 80);
      --paper-deep: oklch(92.8% 0.028 80);
      --panel: oklch(98.1% 0.01 80);
      --panel-strong: oklch(95.8% 0.016 80);
      --ink: oklch(24% 0.03 250);
      --ink-soft: oklch(33% 0.028 244);
      --muted: oklch(49% 0.025 244);
      --line: oklch(84% 0.016 80);
      --line-strong: oklch(74% 0.03 80);
      --accent: oklch(63% 0.17 42);
      --accent-strong: oklch(53% 0.16 41);
      --accent-soft: oklch(88% 0.07 44);
      --secondary: oklch(56% 0.085 212);
      --secondary-soft: oklch(92% 0.028 212);
      --shadow: oklch(23% 0.025 250 / 0.12);
      --focus: oklch(69% 0.13 212 / 0.32);
      --font-serif: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", "URW Palladio L", Georgia, serif;
      --font-sans: "Avenir Next", "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif;
      --space-xs: 0.25rem;
      --space-sm: 0.5rem;
      --space-md: 0.75rem;
      --space-lg: 1rem;
      --space-xl: 1.5rem;
      --space-2xl: 2rem;
      --space-3xl: 3rem;
      --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
      --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
    }

    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    html {
      background: #f1e7d8;
      background: var(--paper);
      color: #1f2937;
      color: var(--ink);
      font-family: var(--font-sans);
      font-kerning: normal;
      line-height: 1.5;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-rendering: optimizeLegibility;
    }

    body {
      min-height: 100svh;
      display: grid;
      place-items: center;
      padding-top: max(1rem, env(safe-area-inset-top));
      padding-right: max(1rem, env(safe-area-inset-right));
      padding-bottom: max(1rem, env(safe-area-inset-bottom));
      padding-left: max(1rem, env(safe-area-inset-left));
      background:
        radial-gradient(circle at 12% 10%, oklch(88.5% 0.08 44 / 0.55) 0, transparent 20rem),
        radial-gradient(circle at 88% 18%, oklch(93% 0.05 212 / 0.7) 0, transparent 16rem),
        linear-gradient(180deg, var(--paper) 0%, oklch(95% 0.015 80) 100%);
      color: var(--ink);
      overflow-x: hidden;
      position: relative;
    }

    body::before {
      content: "";
      position: fixed;
      inset: 0;
      pointer-events: none;
      background:
        linear-gradient(to right, oklch(84% 0.014 80 / 0.55) 1px, transparent 1px),
        linear-gradient(to bottom, oklch(84% 0.014 80 / 0.4) 1px, transparent 1px);
      background-size: 4.75rem 4.75rem;
      mask-image: linear-gradient(180deg, transparent 0, black 14%, black 86%, transparent 100%);
      opacity: 0.42;
      z-index: 0;
    }

    main {
      position: relative;
      z-index: 1;
      width: min(100%, 72rem);
      margin: 0;
      padding: clamp(1.4rem, 4vw, 2.4rem);
      background:
        linear-gradient(180deg, var(--panel) 0%, oklch(97.4% 0.012 80) 100%);
      border: 1px solid var(--line-strong);
      border-radius: 2rem 1rem 2.6rem 1.3rem;
      box-shadow:
        0 1.6rem 4rem var(--shadow),
        inset 0 0 0 1px oklch(99% 0.004 80 / 0.7);
      overflow: hidden;
      isolation: isolate;
      container-type: inline-size;
    }

    main::before {
      content: "";
      position: absolute;
      top: 1rem;
      right: 1.2rem;
      width: clamp(4.5rem, 16vw, 7rem);
      aspect-ratio: 1.15;
      background:
        linear-gradient(135deg, oklch(89% 0.07 44) 0%, oklch(81% 0.13 42) 100%);
      border-radius: 1rem 0.65rem 1.35rem 0.75rem;
      border: 1px solid oklch(72% 0.08 42 / 0.4);
      transform: rotate(-11deg);
      opacity: 0.92;
      z-index: -1;
      animation: drift 8s var(--ease-out-quart) infinite alternate;
    }

    main::after {
      content: "";
      position: absolute;
      left: -1.1rem;
      bottom: 5.5rem;
      width: 4.25rem;
      height: 4.25rem;
      border-radius: 999px;
      background: oklch(92% 0.028 212);
      border: 1px solid oklch(77% 0.04 212 / 0.45);
      z-index: -1;
    }

    .shell {
      display: grid;
      gap: clamp(2rem, 6vw, 4.5rem);
    }

    .intro,
    .links-panel {
      display: grid;
      align-content: start;
    }

    .intro {
      gap: var(--space-xl);
      padding-top: 0.35rem;
    }

    .section-label {
      width: fit-content;
      font-size: 0.78rem;
      font-weight: 700;
      letter-spacing: 0.16em;
      line-height: 1;
      text-transform: uppercase;
    }

    .system-banner {
      position: relative;
      width: fit-content;
      max-width: min(100%, 27rem);
      display: grid;
      grid-template-columns: auto minmax(0, 1fr) auto;
      align-items: center;
      gap: 0.78rem;
      padding: 0.58rem 0.72rem 0.58rem 0.62rem;
      border: 1px solid color-mix(in oklch, var(--line-strong) 72%, var(--secondary) 28%);
      border-radius: 1rem 1.25rem 1rem 0.75rem;
      background: linear-gradient(140deg, oklch(97.8% 0.01 80) 0%, oklch(95.9% 0.02 212) 100%);
      box-shadow: 0 0.9rem 2rem oklch(23% 0.025 250 / 0.06);
      overflow: hidden;
      isolation: isolate;
    }

    .system-banner::after {
      content: "";
      position: absolute;
      inset: 0;
      background: linear-gradient(120deg, transparent 0%, oklch(100% 0 0 / 0.34) 44%, transparent 72%);
      transform: translate3d(-115%, 0, 0);
      animation: sweep 5.8s var(--ease-out-quart) infinite;
      pointer-events: none;
      z-index: -1;
    }

    .system-leds {
      display: inline-flex;
      align-items: center;
      gap: 0.35rem;
    }

    .system-leds span {
      width: 0.58rem;
      height: 0.58rem;
      border-radius: 999px;
      opacity: 0.88;
      animation: ledPulse 2.2s var(--ease-out-quart) infinite alternate;
    }

    .system-leds span:nth-child(1) {
      background: oklch(74% 0.15 36);
      box-shadow: 0 0 0 0.24rem oklch(74% 0.15 36 / 0.14);
    }

    .system-leds span:nth-child(2) {
      background: oklch(79% 0.12 92);
      box-shadow: 0 0 0 0.24rem oklch(79% 0.12 92 / 0.14);
      animation-delay: 140ms;
    }

    .system-leds span:nth-child(3) {
      background: oklch(69% 0.1 212);
      box-shadow: 0 0 0 0.24rem oklch(69% 0.1 212 / 0.14);
      animation-delay: 280ms;
    }

    .system-copy {
      min-width: 0;
      display: grid;
      gap: 0.12rem;
    }

    .system-copy strong {
      color: var(--ink);
      font-size: 0.88rem;
      font-weight: 700;
      letter-spacing: -0.02em;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .system-copy span {
      color: var(--muted);
      font-size: 0.72rem;
      font-weight: 700;
      letter-spacing: 0.12em;
      line-height: 1.2;
      text-transform: uppercase;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .system-glyph {
      position: relative;
      width: 2.05rem;
      height: 2.05rem;
      border: 1px solid var(--line);
      border-radius: 0.8rem;
      background: color-mix(in oklch, var(--panel) 68%, var(--secondary-soft) 32%);
      color: var(--secondary);
      flex-shrink: 0;
    }

    .system-glyph::before,
    .system-glyph::after {
      content: "";
      position: absolute;
      border: 1.5px solid currentColor;
      border-radius: 0.28rem;
    }

    .system-glyph::before {
      inset: 0.45rem 0.56rem 0.66rem 0.42rem;
      transform: translate3d(0.18rem, -0.18rem, 0);
      opacity: 0.75;
    }

    .system-glyph::after {
      inset: 0.64rem 0.42rem 0.44rem 0.56rem;
      background: oklch(92% 0.03 212 / 0.5);
    }

    .display {
      max-width: 8ch;
      font-family: var(--font-serif);
      font-size: clamp(3.35rem, 14.5vw, 6.9rem);
      font-weight: 700;
      letter-spacing: -0.065em;
      line-height: 0.88;
      text-wrap: balance;
    }

    .display span {
      display: block;
      position: relative;
      width: fit-content;
      padding-right: 0.2em;
      margin-left: -0.04em;
    }

    .display span::after {
      content: "";
      position: absolute;
      left: -0.04em;
      right: 0;
      bottom: 0.08em;
      height: 0.2em;
      background: linear-gradient(90deg, oklch(89% 0.07 44) 0%, oklch(86% 0.06 50) 100%);
      border-radius: 999px;
      transform: rotate(-1.4deg);
      z-index: -1;
    }

    .summary {
      max-width: 36ch;
      color: var(--ink-soft);
      font-size: 1.0625rem;
      line-height: 1.55;
      text-wrap: pretty;
    }

    .signals {
      list-style: none;
      display: flex;
      flex-wrap: wrap;
      gap: 0.55rem;
      max-width: 34rem;
    }

    .signals li {
      min-height: 2.75rem;
      display: inline-flex;
      align-items: center;
      padding: 0.55rem 0.9rem;
      border: 1px solid var(--line);
      border-radius: 999px;
      background: var(--panel);
      color: var(--ink-soft);
      font-size: 0.9rem;
    }

    .links-panel {
      gap: var(--space-lg);
    }

    .section-label {
      color: var(--secondary);
    }

    .link-list {
      list-style: none;
      display: grid;
      gap: 0.8rem;
    }

    .link-tile {
      min-height: 5.25rem;
      display: grid;
      grid-template-columns: auto 1fr auto;
      gap: 0.9rem;
      align-items: start;
      padding: 1rem 0.95rem;
      color: inherit;
      text-decoration: none;
      background: linear-gradient(145deg, var(--panel) 0%, var(--panel-strong) 100%);
      border: 1px solid var(--line);
      border-radius: 1.35rem 0.8rem 1.35rem 0.8rem;
      box-shadow: 0 0.6rem 1.4rem oklch(23% 0.025 250 / 0.05);
      transition:
        transform 220ms var(--ease-out-quart),
        border-color 220ms var(--ease-out-quart),
        box-shadow 220ms var(--ease-out-quart),
        background 220ms var(--ease-out-quart);
    }

    .link-index {
      min-width: 2ch;
      padding-top: 0.1rem;
      font-family: var(--font-serif);
      font-size: 1.1rem;
      color: var(--secondary);
      line-height: 1;
      transition: transform 220ms var(--ease-out-quart);
    }

    .link-copy {
      display: grid;
      gap: 0.25rem;
    }

    .link-copy strong {
      display: block;
      color: var(--ink);
      font-size: 1.04rem;
      font-weight: 700;
      letter-spacing: -0.02em;
    }

    .link-copy span {
      color: var(--muted);
      font-size: 0.95rem;
      line-height: 1.45;
      text-wrap: pretty;
    }

    .link-arrow {
      width: 2.75rem;
      height: 2.75rem;
      display: grid;
      place-items: center;
      align-self: center;
      border: 1px solid var(--line);
      border-radius: 999px;
      background: var(--panel);
      color: var(--accent-strong);
      font-size: 1.1rem;
      transition:
        transform 220ms var(--ease-out-quart),
        background 220ms var(--ease-out-quart),
        border-color 220ms var(--ease-out-quart);
    }

    .link-list li:nth-child(odd) .link-index {
      color: var(--accent-strong);
    }

    .link-list li:nth-child(2) .link-tile,
    .link-list li:nth-child(5) .link-tile {
      background: linear-gradient(145deg, oklch(97.5% 0.014 80) 0%, oklch(95.8% 0.018 212) 100%);
    }

    .link-tile:focus-visible {
      outline: none;
      border-color: var(--secondary);
      box-shadow:
        0 0 0 0.25rem var(--focus),
        0 0.8rem 2rem oklch(23% 0.025 250 / 0.08);
    }

    .link-tile:active {
      transform: scale(0.992);
    }

    .site-footer {
      position: relative;
      display: flex;
      flex-wrap: wrap;
      gap: 0.45rem;
      align-items: center;
      margin-top: clamp(1.2rem, 3vw, 1.8rem);
      color: var(--muted);
      font-size: 0.875rem;
    }

    .site-footer::before {
      content: "";
      position: absolute;
      top: -0.72rem;
      left: 0;
      width: min(100%, 9rem);
      height: 0.65rem;
      background:
        radial-gradient(circle at 0.3rem 0.32rem, var(--accent) 0 0.13rem, transparent 0.17rem),
        radial-gradient(circle at 1.25rem 0.32rem, oklch(56% 0.085 212 / 0.26) 0 0.08rem, transparent 0.11rem),
        linear-gradient(90deg, oklch(84% 0.014 80 / 0) 0%, oklch(80% 0.03 80 / 0.34) 22%, oklch(78% 0.03 212 / 0.2) 58%, oklch(84% 0.014 80 / 0) 100%);
      background-repeat: no-repeat;
      background-size: 0.62rem 0.62rem, 0.3rem 0.3rem, 100% 1px;
      background-position: 0 0, 1.14rem 0.18rem, 0 0.31rem;
      opacity: 0.72;
      pointer-events: none;
    }

    .site-footer::after {
      content: "";
      position: absolute;
      top: -0.65rem;
      left: 0.6rem;
      width: 0.34rem;
      height: 0.34rem;
      border: 1px solid color-mix(in oklch, var(--line-strong) 58%, var(--secondary) 42%);
      border-radius: 0.1rem;
      background: linear-gradient(135deg, var(--panel) 0%, oklch(95.4% 0.016 212) 100%);
      box-shadow: 0 0 0 0.14rem oklch(92% 0.028 212 / 0.1);
      transform: rotate(45deg);
      pointer-events: none;
    }

    .js body [data-reveal] {
      opacity: 0;
      transform: translateY(1rem);
    }

    .js body.page-ready [data-reveal] {
      opacity: 1;
      transform: translateY(0);
      transition:
        opacity 620ms var(--ease-out-expo),
        transform 620ms var(--ease-out-expo);
      transition-delay: calc(var(--i, 0) * 70ms);
    }

    @media (hover: hover) and (pointer: fine) {
      .link-tile:hover {
        transform: translate3d(0.28rem, -0.18rem, 0);
        border-color: var(--line-strong);
        box-shadow: 0 1rem 2.4rem oklch(23% 0.025 250 / 0.09);
      }

      .link-tile:hover .link-arrow {
        transform: translate3d(0.18rem, -0.18rem, 0);
        background: var(--accent-soft);
        border-color: oklch(76% 0.06 44);
      }

      .link-tile:hover .link-index {
        transform: translate3d(0.08rem, -0.06rem, 0);
      }
    }

    @container (min-width: 52rem) {
      .shell {
        grid-template-columns: minmax(0, 0.95fr) minmax(20rem, 1.05fr);
        align-items: start;
      }

      .links-panel {
        padding-top: 1.15rem;
      }

      .site-footer {
        justify-content: flex-end;
      }
    }

    @container (max-width: 34rem) {
      .system-banner {
        grid-template-columns: auto minmax(0, 1fr);
        padding-right: 0.9rem;
      }

      .system-glyph {
        display: none;
      }
    }

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

      .js body [data-reveal] {
        opacity: 1;
        transform: none;
      }
    }

    @keyframes drift {
      from {
        transform: rotate(-11deg) translate3d(0, 0, 0);
      }

      to {
        transform: rotate(-8deg) translate3d(0.35rem, -0.3rem, 0);
      }
    }

    @keyframes ledPulse {
      from {
        opacity: 0.72;
        transform: scale(0.96);
      }

      to {
        opacity: 1;
        transform: scale(1);
      }
    }

    @keyframes sweep {
      from {
        transform: translate3d(-115%, 0, 0);
      }

      to {
        transform: translate3d(140%, 0, 0);
      }
    }
  </style>
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Person",
    "name": "Tomás Augusto Müller",
    "url": "https://tomasmuller.dev/",
    "jobTitle": "Senior Full-Stack Software Engineer",
    "sameAs": [
      "https://logs.tomasmuller.dev/about",
      "https://logs.tomasmuller.dev",
      "https://github.com/tomasmuller",
      "https://www.linkedin.com/in/t0masmuller/",
      "https://x.com/tomasmuller"
    ],
    "knowsAbout": [
      "Ruby on Rails",
      "React",
      "TypeScript",
      "Product Engineering",
      "User Experience"
    ]
  }
  </script>
</head>
<body>
  <main aria-labelledby="name">
    <div class="shell">
      <section class="intro" aria-label="Introduction">
        <div class="system-banner" data-reveal style="--i: 0;" aria-label="Site identity">
          <span class="system-leds" aria-hidden="true">
            <span></span>
            <span></span>
            <span></span>
          </span>
          <span class="system-copy">
            <strong>tomasmuller.dev</strong>
            <span>Software / writing / notes</span>
          </span>
          <span class="system-glyph" aria-hidden="true"></span>
        </div>
        <h1 id="name" class="display" data-reveal style="--i: 1;">
          Tomás
          <span>Augusto Müller</span>
        </h1>
        <p class="summary" data-reveal style="--i: 2;">Senior full-stack engineer. 20+ years on the web, 12+ with Rails, and React + TypeScript in production.</p>
        <ul class="signals" aria-label="Core focus areas" data-reveal style="--i: 3;">
          <li>Ruby on Rails</li>
          <li>React + TypeScript</li>
          <li>Product engineering</li>
          <li>Interface craft</li>
        </ul>
      </section>

      <section class="links-panel" aria-labelledby="links-heading">
        <p id="links-heading" class="section-label" data-reveal style="--i: 4;">Start here</p>
        <nav aria-label="Primary links">
          <ul class="link-list">
            <li data-reveal style="--i: 5;">
              <a class="link-tile" href="https://logs.tomasmuller.dev/about?utm_source=tomasmuller.dev" aria-label="Open the About page">
                <span class="link-index" aria-hidden="true">01</span>
                <span class="link-copy">
                  <strong>About</strong>
                  <span>Background, what I'm working on, and how I think about building software.</span>
                </span>
                <span class="link-arrow" aria-hidden="true">↗</span>
              </a>
            </li>
            <li data-reveal style="--i: 6;">
              <a class="link-tile" href="https://www.linkedin.com/in/t0masmuller?utm_source=tomasmuller.dev" aria-label="Open the LinkedIn profile">
                <span class="link-index" aria-hidden="true">02</span>
                <span class="link-copy">
                  <strong>LinkedIn</strong>
                  <span>Work history, dates, and the more buttoned-up version.</span>
                </span>
                <span class="link-arrow" aria-hidden="true">↗</span>
              </a>
            </li>
            <li data-reveal style="--i: 7;">
              <a class="link-tile" href="https://github.com/tomasmuller?utm_source=tomasmuller.dev" aria-label="Open the GitHub profile">
                <span class="link-index" aria-hidden="true">03</span>
                <span class="link-copy">
                  <strong>GitHub</strong>
                  <span>Repositories, experiments, and the code behind what I make.</span>
                </span>
                <span class="link-arrow" aria-hidden="true">↗</span>
              </a>
            </li>
            <li data-reveal style="--i: 8;">
              <a class="link-tile" href="https://logs.tomasmuller.dev?utm_source=tomasmuller.dev" aria-label="Open the writing and logs site">
                <span class="link-index" aria-hidden="true">04</span>
                <span class="link-copy">
                  <strong>Logs</strong>
                  <span>Writing and notes when I need more room than a short post gives me.</span>
                </span>
                <span class="link-arrow" aria-hidden="true">↗</span>
              </a>
            </li>
            <li data-reveal style="--i: 9;">
              <a class="link-tile" href="https://x.com/tomasmuller?utm_source=tomasmuller.dev" aria-label="Open the X profile">
                <span class="link-index" aria-hidden="true">05</span>
                <span class="link-copy">
                  <strong>X</strong>
                  <span>Short posts, links, and thoughts that are still taking shape.</span>
                </span>
                <span class="link-arrow" aria-hidden="true">↗</span>
              </a>
            </li>
          </ul>
        </nav>
      </section>
    </div>

    <footer class="site-footer" data-reveal style="--i: 10;">
      <span>tomasmuller.dev</span>
      <span aria-hidden="true">•</span>
      <span>© 2026 Tomás Müller</span>
    </footer>
  </main>

  <script>
    window.addEventListener('load', function () {
      requestAnimationFrame(function () {
        document.body.classList.add('page-ready');
      });
    });
  </script>
</body>
</html>
