{"$schema":"https://ui.artbloom.tech/schema/registry-item.json","name":"daylight","type":"registry:page","title":"Daylight","description":"A calm, light one-page engineer portfolio: an airy hero, a quick-facts strip, an about section with a workspace photo, grouped skills, selected work, an experience timeline and a contact close. Every word lives in one content file, and the headshot ships background-free so it sits on any page colour.","author":"@artbloom","dependencies":[],"registryDependencies":[],"files":[{"path":"app/daylight/layout.tsx","target":"app/daylight/layout.tsx","content":"import type { Metadata } from \"next\"\n\nimport { SiteFooter } from \"./components/site-footer\"\nimport { SiteHeader } from \"./components/site-header\"\nimport { profile } from \"./data/content\"\n\nimport \"./daylight.css\"\n\nexport const metadata: Metadata = {\n  title: {\n    default: `${profile.name} ${profile.surname} — ${profile.role}`,\n    template: `%s — ${profile.name} ${profile.surname}`,\n  },\n  description: `Portfolio of ${profile.name} ${profile.surname}, a ${profile.role.toLowerCase()} based in ${profile.location}.`,\n}\n\n/**\n * The template shell.\n *\n * A nested layout, so it renders no `<html>` or `<body>` — the app's root\n * layout owns those. `.dlSite` is the single wrapper every style in\n * `daylight.css` hangs off, which is what keeps this sheet from touching\n * anything else in the app.\n *\n * The `<noscript>` block matters: scroll reveals start at `opacity: 0` in CSS\n * so they cannot flash in before hydration, which means without JavaScript they\n * would never appear at all. This turns them on for that reader instead of\n * showing them an empty page.\n */\nexport default function DaylightLayout({ children }: { children: React.ReactNode }) {\n  return (\n    <div className=\"dlSite\">\n      <noscript>\n        <style\n          dangerouslySetInnerHTML={{\n            __html: \".dlReveal{opacity:1;transform:none}\",\n          }}\n        />\n      </noscript>\n      <SiteHeader />\n      <main>{children}</main>\n      <SiteFooter />\n    </div>\n  )\n}\n","type":"registry:page"},{"path":"app/daylight/daylight.css","target":"app/daylight/daylight.css","content":"/*\n * daylight — a bright, professional developer portfolio.\n *\n * Nothing here can leak. Every class carries a `dl` prefix and every\n * bare-element rule is scoped under `.dlSite`, so the whole sheet is inert\n * outside its own wrapper. The two things most people will change live at the\n * top: the palette and the type scale. Nothing below hard-codes a value that is\n * a variable up here.\n */\n.dlSite {\n  /* Palette. One calm accent blue on a soft blue-grey ground. */\n  --bg: #eef2f7;\n  --bg-tint: #e3e9f2;\n  --card: #ffffff;\n  --ink: #1e293b;\n  --ink-soft: #475569;\n  --ink-mute: #64748b;\n  --ink-faint: #94a3b8;\n  --line: #dbe2ec;\n  --line-soft: #e8edf4;\n  --accent: #2563eb;\n  --accent-soft: #dbe6ff;\n  --accent-ink: #1d4ed8;\n\n  /* Type scale. Clamp keeps the hero confident on desktop and calm on phones. */\n  --display: clamp(2.5rem, 6vw, 4.25rem);\n  --heading: clamp(1.75rem, 3.2vw, 2.6rem);\n  --subhead: clamp(1.25rem, 2vw, 1.6rem);\n  --body: clamp(1rem, 1.05vw, 1.125rem);\n\n  /* Rhythm. */\n  --gutter: clamp(1.25rem, 5vw, 4.5rem);\n  --section: clamp(4.5rem, 9vw, 8rem);\n  --radius: 16px;\n  --radius-sm: 12px;\n  --shadow: 0 1px 2px rgba(30, 41, 59, 0.04), 0 12px 32px -12px rgba(30, 41, 59, 0.14);\n  --shadow-lift: 0 2px 4px rgba(30, 41, 59, 0.05), 0 22px 48px -16px rgba(30, 41, 59, 0.22);\n\n  --font-body: -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n\n  position: relative;\n  min-height: 100vh;\n  background: var(--bg);\n  color: var(--ink);\n  font-family: var(--font-body);\n  font-size: var(--body);\n  line-height: 1.65;\n  isolation: isolate;\n  overflow-x: hidden;\n}\n\n.dlSite *,\n.dlSite *::before,\n.dlSite *::after { box-sizing: border-box; }\n\n/* :where() adds no specificity, so any class rule below still wins. */\n.dlSite :where(a) { color: inherit; text-decoration: none; }\n.dlSite :where(button, input, textarea, select) { font: inherit; color: inherit; }\n.dlSite :where(img) { display: block; max-width: 100%; }\n.dlSite ::selection { background: var(--accent-soft); color: var(--accent-ink); }\n\n.dlSite :focus-visible {\n  outline: 2px solid var(--accent);\n  outline-offset: 3px;\n  border-radius: 4px;\n}\n\n/* ---------------------------------------------------------------- primitives */\n\n.dlWrap {\n  width: 100%;\n  max-width: 72rem;\n  margin: 0 auto;\n  padding-inline: var(--gutter);\n}\n\n.dlSection { padding-block: var(--section); }\n.dlSectionTight { padding-top: 0; }\n\n.dlLabel {\n  margin: 0 0 0.75rem;\n  font-size: 0.75rem;\n  font-weight: 600;\n  letter-spacing: 0.14em;\n  text-transform: uppercase;\n  color: var(--accent);\n}\n\n.dlHeading {\n  margin: 0;\n  font-size: var(--heading);\n  font-weight: 700;\n  line-height: 1.1;\n  letter-spacing: -0.02em;\n  text-wrap: balance;\n}\n\n.dlLede {\n  max-width: 42rem;\n  margin: 1.25rem 0 0;\n  font-size: var(--subhead);\n  line-height: 1.55;\n  color: var(--ink-soft);\n  text-wrap: pretty;\n}\n\n.dlSectionHead { margin-bottom: clamp(2rem, 4vw, 3.25rem); }\n\n/* -------------------------------------------------------------------- buttons */\n\n.dlBtn {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.5rem;\n  padding: 0.8125rem 1.5rem;\n  border: 1px solid var(--line);\n  border-radius: 999px;\n  background: var(--card);\n  color: var(--ink);\n  font-size: 0.9375rem;\n  font-weight: 600;\n  cursor: pointer;\n  box-shadow: var(--shadow);\n  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1),\n    box-shadow 0.25s ease, border-color 0.25s ease, background-color 0.25s ease, color 0.25s ease;\n}\n\n.dlBtn:hover { transform: translateY(-2px); box-shadow: var(--shadow-lift); border-color: var(--line-soft); }\n\n.dlBtnSolid {\n  background: var(--accent);\n  border-color: var(--accent);\n  color: #fff;\n  box-shadow: 0 8px 20px -8px rgba(37, 99, 235, 0.6);\n}\n\n.dlBtnSolid:hover { background: var(--accent-ink); border-color: var(--accent-ink); }\n\n.dlBtn > .dlArrow { transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1); }\n.dlBtn:hover > .dlArrow { transform: translateX(3px); }\n\n/* --------------------------------------------------------------------- header */\n\n.dlHeader {\n  position: sticky;\n  top: 0;\n  z-index: 20;\n  background: color-mix(in oklab, var(--bg) 82%, transparent);\n  backdrop-filter: blur(12px);\n  border-bottom: 1px solid var(--line-soft);\n}\n\n.dlHeaderRow {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 1.5rem;\n  height: 4.25rem;\n}\n\n.dlBrand {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.625rem;\n  font-weight: 700;\n  font-size: 1.0625rem;\n  letter-spacing: -0.01em;\n}\n\n.dlBrandMark {\n  display: grid;\n  place-items: center;\n  width: 2rem;\n  height: 2rem;\n  border-radius: 8px;\n  background: var(--accent);\n  color: #fff;\n  font-size: 0.9375rem;\n  font-weight: 700;\n}\n\n.dlBrandRole {\n  font-size: 0.75rem;\n  font-weight: 500;\n  color: var(--ink-mute);\n}\n\n.dlNav { display: none; align-items: center; gap: 1.75rem; }\n\n.dlNavLink {\n  position: relative;\n  font-size: 0.9375rem;\n  font-weight: 500;\n  color: var(--ink-soft);\n  transition: color 0.2s ease;\n}\n\n.dlNavLink:hover { color: var(--ink); }\n\n.dlNavLink::after {\n  content: \"\";\n  position: absolute;\n  left: 0;\n  bottom: -0.35rem;\n  width: 100%;\n  height: 2px;\n  border-radius: 2px;\n  background: var(--accent);\n  transform: scaleX(0);\n  transform-origin: left;\n  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n.dlNavLink:hover::after { transform: scaleX(1); }\n\n/* Mobile menu is a native <details> — no state, no focus trap to get wrong. */\n.dlMenu { position: relative; }\n\n.dlMenuSummary {\n  display: inline-flex;\n  align-items: center;\n  padding: 0.5rem 0.875rem;\n  border: 1px solid var(--line);\n  border-radius: 999px;\n  background: var(--card);\n  font-size: 0.8125rem;\n  font-weight: 600;\n  color: var(--ink-soft);\n  cursor: pointer;\n  list-style: none;\n  box-shadow: var(--shadow);\n}\n\n.dlMenuSummary::-webkit-details-marker { display: none; }\n.dlMenu[open] .dlMenuSummary { color: var(--ink); border-color: var(--accent); }\n\n.dlMenuPanel {\n  position: absolute;\n  right: 0;\n  top: calc(100% + 0.6rem);\n  z-index: 30;\n  display: grid;\n  gap: 0.125rem;\n  min-width: 11rem;\n  padding: 0.5rem;\n  border: 1px solid var(--line);\n  border-radius: var(--radius-sm);\n  background: var(--card);\n  box-shadow: var(--shadow-lift);\n}\n\n.dlMenuLink {\n  padding: 0.5rem 0.75rem;\n  border-radius: 8px;\n  font-size: 0.9375rem;\n  color: var(--ink-soft);\n}\n\n.dlMenuLink:hover { background: var(--bg-tint); color: var(--ink); }\n\n@media (min-width: 52rem) {\n  .dlNav { display: flex; }\n  .dlHeaderRow { height: 5rem; }\n  .dlMenu { display: none; }\n}\n\n/* ----------------------------------------------------------------------- hero */\n\n.dlHero { padding-top: clamp(3rem, 7vw, 5.5rem); padding-bottom: clamp(2.5rem, 5vw, 4rem); }\n\n.dlHeroGrid { display: grid; gap: clamp(2.5rem, 5vw, 4rem); align-items: center; }\n\n.dlHeroEyebrow {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.5rem;\n  padding: 0.375rem 0.875rem;\n  border-radius: 999px;\n  background: var(--accent-soft);\n  color: var(--accent-ink);\n  font-size: 0.8125rem;\n  font-weight: 600;\n}\n\n.dlHeroEyebrow::before {\n  content: \"\";\n  width: 0.5rem;\n  height: 0.5rem;\n  border-radius: 999px;\n  background: var(--accent);\n}\n\n.dlHeroGreeting {\n  margin: 1.5rem 0 0;\n  font-size: var(--subhead);\n  font-weight: 600;\n  color: var(--ink-soft);\n}\n\n.dlHeroTitle {\n  margin: 0.5rem 0 0;\n  font-size: var(--display);\n  font-weight: 800;\n  line-height: 1.05;\n  letter-spacing: -0.03em;\n  text-wrap: balance;\n}\n\n.dlHeroActions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }\n\n/* The portrait sits in a soft rounded card with a gradient halo behind it. */\n.dlHeroArt { position: relative; justify-self: center; width: 100%; max-width: 24rem; }\n\n.dlHeroArt::before {\n  content: \"\";\n  position: absolute;\n  inset: -8%;\n  border-radius: 50%;\n  background: radial-gradient(circle at 50% 40%, var(--accent-soft), transparent 70%);\n  z-index: -1;\n}\n\n.dlHeroPortrait {\n  width: 100%;\n  height: auto;\n  aspect-ratio: 1 / 1;\n  object-fit: cover;\n  border-radius: 24px;\n  border: 6px solid var(--card);\n  box-shadow: var(--shadow-lift);\n}\n\n@media (min-width: 56rem) {\n  .dlHeroGrid { grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); }\n  .dlHeroArt { justify-self: end; }\n}\n\n/* ---------------------------------------------------------------------- stats */\n\n.dlStats {\n  display: grid;\n  grid-template-columns: repeat(2, 1fr);\n  gap: 1px;\n  background: var(--line);\n  border: 1px solid var(--line);\n  border-radius: var(--radius);\n  overflow: hidden;\n  box-shadow: var(--shadow);\n}\n\n.dlStat { padding: clamp(1.25rem, 3vw, 2rem); background: var(--card); text-align: center; }\n\n.dlStatValue {\n  display: block;\n  font-size: clamp(1.75rem, 3.5vw, 2.75rem);\n  font-weight: 800;\n  letter-spacing: -0.03em;\n  color: var(--accent);\n  font-variant-numeric: tabular-nums;\n}\n\n.dlStatLabel { display: block; margin-top: 0.25rem; font-size: 0.875rem; color: var(--ink-mute); }\n\n@media (min-width: 44rem) { .dlStats { grid-template-columns: repeat(4, 1fr); } }\n\n/* ---------------------------------------------------------------------- about */\n\n.dlAbout { display: grid; gap: clamp(2rem, 5vw, 3.5rem); align-items: center; }\n\n.dlAboutBody { display: grid; gap: 1.25rem; }\n.dlAboutBody p { margin: 0; color: var(--ink-soft); text-wrap: pretty; }\n.dlAboutBody p:first-of-type { color: var(--ink); font-size: var(--subhead); line-height: 1.5; }\n\n.dlAboutFigure { position: relative; margin: 0; }\n\n.dlAboutImage {\n  width: 100%;\n  height: auto;\n  aspect-ratio: 4 / 3;\n  object-fit: cover;\n  border-radius: var(--radius);\n  box-shadow: var(--shadow-lift);\n}\n\n.dlAboutCaption {\n  margin: 0;\n  position: absolute;\n  left: 1rem;\n  bottom: 1rem;\n  padding: 0.5rem 0.875rem;\n  border-radius: 999px;\n  background: color-mix(in oklab, var(--card) 90%, transparent);\n  backdrop-filter: blur(6px);\n  font-size: 0.8125rem;\n  font-weight: 500;\n  color: var(--ink-soft);\n  box-shadow: var(--shadow);\n}\n\n@media (min-width: 56rem) { .dlAbout { grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr); } }\n\n/* --------------------------------------------------------------------- skills */\n\n.dlSkills { display: grid; gap: 1.25rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }\n\n.dlSkillGroup {\n  padding: clamp(1.25rem, 2.5vw, 1.75rem);\n  border: 1px solid var(--line);\n  border-radius: var(--radius);\n  background: var(--card);\n  box-shadow: var(--shadow);\n  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.25s ease;\n}\n\n.dlSkillGroup:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); }\n\n.dlSkillTitle {\n  margin: 0 0 1rem;\n  font-size: 0.75rem;\n  font-weight: 700;\n  letter-spacing: 0.1em;\n  text-transform: uppercase;\n  color: var(--ink-mute);\n}\n\n.dlChips { display: flex; flex-wrap: wrap; gap: 0.5rem; }\n\n.dlChip {\n  padding: 0.375rem 0.75rem;\n  border-radius: 999px;\n  background: var(--bg-tint);\n  border: 1px solid transparent;\n  font-size: 0.875rem;\n  font-weight: 500;\n  color: var(--ink-soft);\n  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;\n}\n\n.dlSkillGroup:hover .dlChip { background: var(--accent-soft); color: var(--accent-ink); }\n\n/* -------------------------------------------------------------------- projects */\n\n.dlProjects { display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); }\n\n.dlCard {\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n  border: 1px solid var(--line);\n  border-radius: var(--radius);\n  background: var(--card);\n  box-shadow: var(--shadow);\n  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.3s ease;\n}\n\n.dlCard:hover { transform: translateY(-4px); box-shadow: var(--shadow-lift); }\n\n/* The thumbnail: either the workspace photo or a soft gradient mock. */\n.dlCardThumb { position: relative; aspect-ratio: 16 / 10; overflow: hidden; }\n\n.dlCardThumb img { width: 100%; height: 100%; object-fit: cover; }\n\n.dlCardThumb::after {\n  content: \"\";\n  position: absolute;\n  inset: 0;\n  background: linear-gradient(120deg, rgba(255, 255, 255, 0.35), transparent 55%);\n  mix-blend-mode: screen;\n}\n\n.dlCardThumb[data-accent=\"aurora\"] { background: linear-gradient(135deg, #60a5fa, #a78bfa 55%, #f0abfc); }\n.dlCardThumb[data-accent=\"meadow\"] { background: linear-gradient(135deg, #34d399, #22d3ee 55%, #60a5fa); }\n.dlCardThumb[data-accent=\"dusk\"] { background: linear-gradient(135deg, #f59e0b, #fb7185 55%, #a855f7); }\n\n.dlCardMark {\n  position: absolute;\n  left: 1rem;\n  bottom: 1rem;\n  font-size: 1.5rem;\n  font-weight: 800;\n  color: #fff;\n  letter-spacing: -0.02em;\n  text-shadow: 0 2px 8px rgba(30, 41, 59, 0.35);\n}\n\n.dlCardBody { display: flex; flex-direction: column; gap: 0.875rem; padding: 1.5rem; flex: 1; }\n\n.dlCardTitle { margin: 0; font-size: 1.25rem; font-weight: 700; letter-spacing: -0.01em; }\n\n.dlCardBlurb { margin: 0; font-size: 0.9375rem; color: var(--ink-soft); text-wrap: pretty; }\n\n.dlCardTags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: auto; }\n\n.dlTag {\n  padding: 0.25rem 0.625rem;\n  border-radius: 6px;\n  background: var(--bg-tint);\n  font-size: 0.75rem;\n  font-weight: 600;\n  color: var(--ink-mute);\n}\n\n.dlCardLinks { display: flex; flex-wrap: wrap; gap: 1rem; padding-top: 0.25rem; }\n\n.dlCardLink {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.3rem;\n  font-size: 0.875rem;\n  font-weight: 600;\n  color: var(--accent);\n}\n\n.dlCardLink:hover { color: var(--accent-ink); }\n.dlCardLink > span { transition: transform 0.2s ease; }\n.dlCardLink:hover > span { transform: translateX(2px); }\n\n/* ------------------------------------------------------------------ experience */\n\n.dlTimeline { display: grid; gap: 0; }\n\n.dlBeat {\n  display: grid;\n  gap: 0.375rem;\n  padding-block: clamp(1.5rem, 3vw, 2rem);\n  border-top: 1px solid var(--line);\n}\n\n.dlBeat:first-child { border-top: 0; }\n\n.dlBeatPeriod {\n  font-size: 0.8125rem;\n  font-weight: 600;\n  letter-spacing: 0.02em;\n  color: var(--accent);\n  font-variant-numeric: tabular-nums;\n}\n\n.dlBeatTitle { margin: 0; font-size: 1.1875rem; font-weight: 700; }\n.dlBeatCompany { font-size: 0.9375rem; font-weight: 500; color: var(--ink-mute); }\n.dlBeatBody { margin: 0.25rem 0 0; max-width: 44rem; color: var(--ink-soft); text-wrap: pretty; }\n\n@media (min-width: 48rem) {\n  .dlBeat { grid-template-columns: 10rem minmax(0, 1fr); gap: 2rem; align-items: start; }\n  .dlBeatPeriod { padding-top: 0.15rem; }\n}\n\n/* -------------------------------------------------------------------- contact */\n\n.dlContact {\n  display: grid;\n  gap: 1.75rem;\n  justify-items: center;\n  text-align: center;\n  padding: clamp(2.5rem, 6vw, 4.5rem) clamp(1.5rem, 5vw, 3rem);\n  border-radius: var(--radius);\n  background: linear-gradient(160deg, var(--card), var(--bg-tint));\n  border: 1px solid var(--line);\n  box-shadow: var(--shadow);\n}\n\n.dlContact .dlLede { margin-inline: auto; text-align: center; }\n.dlContactActions { display: flex; flex-wrap: wrap; gap: 1.5rem; justify-content: center; align-items: center; }\n\n.dlContactLink { font-size: 0.9375rem; font-weight: 600; color: var(--ink-soft); transition: color 0.2s ease; }\n.dlContactLink:hover { color: var(--accent); }\n\n/* --------------------------------------------------------------------- footer */\n\n.dlFooter { border-top: 1px solid var(--line); padding-block: clamp(2.5rem, 5vw, 3.5rem); }\n\n.dlFooterRow {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 1.5rem 2rem;\n  align-items: center;\n  justify-content: space-between;\n}\n\n.dlFooterBlurb { margin: 0; max-width: 30rem; font-size: 0.9375rem; color: var(--ink-mute); text-wrap: pretty; }\n.dlFooterMeta { display: grid; gap: 0.5rem; font-size: 0.8125rem; color: var(--ink-faint); }\n.dlFooterMeta a { color: var(--ink-mute); transition: color 0.2s ease; }\n.dlFooterMeta a:hover { color: var(--accent); }\n\n/* --------------------------------------------------------------- scroll reveal */\n\n.dlReveal {\n  opacity: 0;\n  transform: translate3d(0, 1.25rem, 0);\n  transition:\n    opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),\n    transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);\n  transition-delay: var(--dl-delay, 0ms);\n}\n\n.dlReveal[data-shown=\"true\"] { opacity: 1; transform: translate3d(0, 0, 0); }\n\n@media (prefers-reduced-motion: reduce) {\n  .dlReveal,\n  .dlReveal[data-shown=\"true\"] { opacity: 1; transform: none; transition: none; }\n\n  .dlSite *,\n  .dlSite *::before,\n  .dlSite *::after {\n    transition-duration: 0.01ms !important;\n    animation-duration: 0.01ms !important;\n    scroll-behavior: auto !important;\n  }\n}\n","type":"registry:style"},{"path":"app/daylight/page.tsx","target":"app/daylight/page.tsx","content":"import { Reveal } from \"./components/reveal\"\nimport { about, contact, experience, hero, profile, projects, skills, stats } from \"./data/content\"\n\n/**\n * The daylight portfolio: one long, bright scroll.\n *\n * Hero, a quick-facts strip, about, skills, featured work, an experience\n * timeline, and a closing contact card. Every string comes from\n * `data/content.ts`; the section ids match the header anchors.\n */\nexport default function DaylightHome() {\n  return (\n    <>\n      {/* ------------------------------------------------------------- hero */}\n      <section className=\"dlWrap dlHero\">\n        <div className=\"dlHeroGrid\">\n          <div>\n            <p className=\"dlHeroGreeting\">{hero.greeting}</p>\n            <h1 className=\"dlHeroTitle\">{hero.headline}</h1>\n            <p className=\"dlLede\">{hero.lede}</p>\n            <div className=\"dlHeroActions\">\n              <a className=\"dlBtn dlBtnSolid\" href={hero.primary.href}>\n                {hero.primary.label}\n                <span className=\"dlArrow\" aria-hidden=\"true\">\n                  →\n                </span>\n              </a>\n              <a className=\"dlBtn\" href={hero.secondary.href}>\n                {hero.secondary.label}\n              </a>\n            </div>\n          </div>\n\n          <div className=\"dlHeroArt\">\n            <img\n              className=\"dlHeroPortrait\"\n              src={profile.portrait.src}\n              width={profile.portrait.width}\n              height={profile.portrait.height}\n              alt={`${profile.name} ${profile.surname}, ${profile.role}`}\n              loading=\"eager\"\n              fetchPriority=\"high\"\n              decoding=\"async\"\n            />\n          </div>\n        </div>\n      </section>\n\n      {/* ------------------------------------------------------------ stats */}\n      <section className=\"dlWrap dlSection dlSectionTight\">\n        <Reveal className=\"dlStats\">\n          {stats.map((stat) => (\n            <div className=\"dlStat\" key={stat.label}>\n              <span className=\"dlStatValue\">{stat.value}</span>\n              <span className=\"dlStatLabel\">{stat.label}</span>\n            </div>\n          ))}\n        </Reveal>\n      </section>\n\n      {/* ------------------------------------------------------------ about */}\n      <section id=\"about\" className=\"dlWrap dlSection dlSectionTight\">\n        <Reveal className=\"dlAbout\">\n          <div>\n            <p className=\"dlLabel\">{about.label}</p>\n            <h2 className=\"dlHeading\">{about.heading}</h2>\n            <div className=\"dlAboutBody\" style={{ marginTop: \"1.5rem\" }}>\n              {about.body.map((paragraph) => (\n                <p key={paragraph}>{paragraph}</p>\n              ))}\n            </div>\n          </div>\n          <figure className=\"dlAboutFigure\">\n            <img\n              className=\"dlAboutImage\"\n              src={about.image.src}\n              width={about.image.width}\n              height={about.image.height}\n              alt={about.image.alt}\n              loading=\"lazy\"\n              decoding=\"async\"\n            />\n            <figcaption className=\"dlAboutCaption\">{about.caption}</figcaption>\n          </figure>\n        </Reveal>\n      </section>\n\n      {/* ----------------------------------------------------------- skills */}\n      <section id=\"skills\" className=\"dlWrap dlSection dlSectionTight\">\n        <Reveal className=\"dlSectionHead\">\n          <p className=\"dlLabel\">{skills.label}</p>\n          <h2 className=\"dlHeading\">{skills.heading}</h2>\n          <p className=\"dlLede\">{skills.lede}</p>\n        </Reveal>\n        <div className=\"dlSkills\">\n          {skills.groups.map((group, index) => (\n            <Reveal className=\"dlSkillGroup\" key={group.title} delay={index * 70}>\n              <h3 className=\"dlSkillTitle\">{group.title}</h3>\n              <div className=\"dlChips\">\n                {group.items.map((item) => (\n                  <span className=\"dlChip\" key={item}>\n                    {item}\n                  </span>\n                ))}\n              </div>\n            </Reveal>\n          ))}\n        </div>\n      </section>\n\n      {/* --------------------------------------------------------- projects */}\n      <section id=\"work\" className=\"dlWrap dlSection dlSectionTight\">\n        <Reveal className=\"dlSectionHead\">\n          <p className=\"dlLabel\">{projects.label}</p>\n          <h2 className=\"dlHeading\">{projects.heading}</h2>\n        </Reveal>\n        <div className=\"dlProjects\">\n          {projects.items.map((project, index) => {\n            const image = \"image\" in project ? project.image : undefined\n            const accent = \"accent\" in project ? project.accent : undefined\n            return (\n              <Reveal className=\"dlCard\" as=\"article\" key={project.title} delay={index * 80}>\n                <div className=\"dlCardThumb\" data-accent={accent}>\n                  {image ? (\n                    <img src={image.src} width={image.width} height={image.height} alt=\"\" loading=\"lazy\" decoding=\"async\" />\n                  ) : (\n                    <span className=\"dlCardMark\" aria-hidden=\"true\">\n                      {project.title}\n                    </span>\n                  )}\n                </div>\n                <div className=\"dlCardBody\">\n                  <h3 className=\"dlCardTitle\">{project.title}</h3>\n                  <p className=\"dlCardBlurb\">{project.blurb}</p>\n                  <div className=\"dlCardTags\">\n                    {project.tags.map((tag) => (\n                      <span className=\"dlTag\" key={tag}>\n                        {tag}\n                      </span>\n                    ))}\n                  </div>\n                  <div className=\"dlCardLinks\">\n                    {project.links.map((link) => (\n                      <a className=\"dlCardLink\" href={link.href} key={link.href} target=\"_blank\" rel=\"noreferrer\">\n                        {link.label}\n                        <span aria-hidden=\"true\">→</span>\n                      </a>\n                    ))}\n                  </div>\n                </div>\n              </Reveal>\n            )\n          })}\n        </div>\n      </section>\n\n      {/* ------------------------------------------------------- experience */}\n      <section id=\"experience\" className=\"dlWrap dlSection dlSectionTight\">\n        <Reveal className=\"dlSectionHead\">\n          <p className=\"dlLabel\">{experience.label}</p>\n          <h2 className=\"dlHeading\">{experience.heading}</h2>\n        </Reveal>\n        <div className=\"dlTimeline\">\n          {experience.roles.map((role, index) => (\n            <Reveal className=\"dlBeat\" key={role.company} delay={index * 60}>\n              <span className=\"dlBeatPeriod\">{role.period}</span>\n              <div>\n                <h3 className=\"dlBeatTitle\">\n                  {role.title} <span className=\"dlBeatCompany\">· {role.company}</span>\n                </h3>\n                <p className=\"dlBeatBody\">{role.body}</p>\n              </div>\n            </Reveal>\n          ))}\n        </div>\n      </section>\n\n      {/* ---------------------------------------------------------- contact */}\n      <section id=\"contact\" className=\"dlWrap dlSection dlSectionTight\">\n        <Reveal className=\"dlContact\">\n          <p className=\"dlLabel\">{contact.label}</p>\n          <h2 className=\"dlHeading\">{contact.heading}</h2>\n          <p className=\"dlLede\">{contact.lede}</p>\n          <div className=\"dlContactActions\">\n            <a className=\"dlBtn dlBtnSolid\" href={contact.cta.href}>\n              {contact.cta.label}\n              <span className=\"dlArrow\" aria-hidden=\"true\">\n                →\n              </span>\n            </a>\n            <a className=\"dlContactLink\" href={profile.github.href} target=\"_blank\" rel=\"noreferrer\">\n              {profile.github.label}\n            </a>\n            <a className=\"dlContactLink\" href={profile.linkedin.href} target=\"_blank\" rel=\"noreferrer\">\n              {profile.linkedin.label}\n            </a>\n          </div>\n        </Reveal>\n      </section>\n    </>\n  )\n}\n","type":"registry:page"},{"path":"app/daylight/data/content.ts","target":"app/daylight/data/content.ts","content":"/**\n * Everything the daylight portfolio says, in one file.\n *\n * The page and its components read from here and hold no copy of their own, so\n * re-voicing the whole site for a different person is one file to edit and no\n * JSX to touch. Swap the palette in `daylight.css` and the words here and\n * nothing else needs to change.\n *\n * The persona is a fictional senior engineer. Every string is meant to sound\n * like a real portfolio, not filler — replace it with yours.\n */\n\n/**\n * Where the template is mounted. The home link uses it; the in-page nav uses\n * the `#anchor` hashes below, which do not move when `BASE` changes.\n */\nexport const BASE = \"/daylight\"\n\nexport const profile = {\n  name: \"Adrian\",\n  surname: \"Vale\",\n  /** Sits in the header beside the name and drives the page title. */\n  role: \"Senior Software Engineer\",\n  location: \"Lisbon, Portugal\",\n  email: \"hello@example.com\",\n  github: { label: \"github.com/adrianvale\", href: \"https://github.com/adrianvale\" },\n  linkedin: { label: \"in/adrianvale\", href: \"https://www.linkedin.com/in/adrianvale\" },\n  /** Friendly professional headshot, served from `public/daylight/`. */\n  portrait: { src: `${BASE}/portrait.png`, width: 1024, height: 1024 },\n  year: 2026,\n} as const\n\n/** In-page anchors. `href` is a hash so it works no matter where BASE points. */\nexport const nav = [\n  { label: \"About\", href: \"#about\" },\n  { label: \"Skills\", href: \"#skills\" },\n  { label: \"Work\", href: \"#work\" },\n  { label: \"Experience\", href: \"#experience\" },\n  { label: \"Contact\", href: \"#contact\" },\n] as const\n\n/** The opening. Kept short — the whitespace does the rest of the work. */\nexport const hero = {\n  greeting: \"Hi, I'm Adrian.\",\n  headline: \"I build calm, reliable software that people actually enjoy using.\",\n  lede:\n    \"Senior engineer with a decade of shipping web platforms end to end — from the data model to the last pixel. I care about clarity, performance, and interfaces that stay out of the way.\",\n  primary: { label: \"See my work\", href: \"#work\" },\n  secondary: { label: \"Get in touch\", href: \"#contact\" },\n} as const\n\n/** The quick-facts strip under the hero. Four numbers, no more. */\nexport const stats = [\n  { value: \"10+\", label: \"Years shipping\" },\n  { value: \"40+\", label: \"Projects delivered\" },\n  { value: \"12\", label: \"Teams mentored\" },\n  { value: \"99.9%\", label: \"Uptime maintained\" },\n] as const\n\n/** The about section: a small heading and a couple of grounded paragraphs. */\nexport const about = {\n  label: \"About\",\n  heading: \"A senior engineer who sweats the details so users never have to.\",\n  body: [\n    \"I've spent the last ten years building products across fintech, health, and developer tooling — usually as the person who owns a feature from the first sketch to the graphs the morning after launch. I like being close to the problem and close to the people it affects.\",\n    \"My happiest work sits at the seam between design and engineering: turning a fuzzy idea into something that loads fast, reads clearly, and holds up under real traffic. I write tests I'd trust at 3am, document the decisions that mattered, and leave codebases calmer than I found them.\",\n  ],\n  /** A bright, clean workspace photo, served from `public/daylight/`. */\n  image: { src: `${BASE}/workspace.png`, width: 1024, height: 1024, alt: \"A bright, tidy desk with a laptop and notebook\" },\n  /** The small caption pinned to the workspace image. */\n  caption: \"Where the work happens — Lisbon, most mornings.\",\n} as const\n\n/** Skills, grouped. Each group is a titled cluster of chips. */\nexport const skills = {\n  label: \"Skills\",\n  heading: \"The tools I reach for.\",\n  lede: \"A working set built over years, not a wishlist. These are the things I use well and often.\",\n  groups: [\n    {\n      title: \"Languages\",\n      items: [\"TypeScript\", \"JavaScript\", \"Python\", \"Go\", \"SQL\"],\n    },\n    {\n      title: \"Frontend\",\n      items: [\"React\", \"Next.js\", \"Tailwind\", \"Design systems\", \"Accessibility\"],\n    },\n    {\n      title: \"Backend\",\n      items: [\"Node.js\", \"PostgreSQL\", \"GraphQL\", \"REST APIs\", \"Redis\"],\n    },\n    {\n      title: \"Platform\",\n      items: [\"AWS\", \"Docker\", \"CI/CD\", \"Observability\", \"Terraform\"],\n    },\n  ],\n} as const\n\n/** Featured projects. Three or four, each defensible. */\nexport const projects = {\n  label: \"Selected work\",\n  heading: \"Projects I'm proud of.\",\n  items: [\n    {\n      title: \"Ledgerline\",\n      blurb:\n        \"A double-entry accounting engine for small studios. I designed the data model and the reconciliation flow, cutting month-end close from two days to twenty minutes.\",\n      tags: [\"Next.js\", \"PostgreSQL\", \"TypeScript\"],\n      /** A soft gradient stands in for a screenshot — see `daylight.css`. */\n      accent: \"aurora\",\n      links: [\n        { label: \"Live site\", href: \"https://example.com/ledgerline\" },\n        { label: \"Case study\", href: \"https://example.com/ledgerline/case-study\" },\n      ],\n    },\n    {\n      title: \"Northwind Health\",\n      blurb:\n        \"A patient-facing scheduling app used by nine clinics. Built the availability engine and the accessible booking UI; it now handles 4,000 appointments a week without a hitch.\",\n      tags: [\"React\", \"Go\", \"Accessibility\"],\n      accent: \"meadow\",\n      links: [{ label: \"Read more\", href: \"https://example.com/northwind\" }],\n    },\n    {\n      title: \"Beacon CLI\",\n      blurb:\n        \"An open-source tool that turns flaky CI logs into a single readable timeline. Started as a weekend fix for my own frustration; now 3k stars and a dozen contributors.\",\n      tags: [\"Go\", \"Open source\", \"DX\"],\n      accent: \"dusk\",\n      links: [\n        { label: \"GitHub\", href: \"https://github.com/adrianvale/beacon\" },\n        { label: \"Docs\", href: \"https://example.com/beacon\" },\n      ],\n    },\n    {\n      title: \"Studio Workspace\",\n      blurb:\n        \"A collaborative whiteboard for distributed design teams, rebuilt for speed. Rewrote the sync layer to CRDTs and brought p95 render latency under 40ms on 50-person boards.\",\n      tags: [\"TypeScript\", \"WebSockets\", \"Performance\"],\n      /** This card uses the real workspace photo instead of a gradient. */\n      image: about.image,\n      links: [{ label: \"Live site\", href: \"https://example.com/studio\" }],\n    },\n  ],\n} as const\n\n/** Experience timeline. Newest first. */\nexport const experience = {\n  label: \"Experience\",\n  heading: \"Where I've been.\",\n  roles: [\n    {\n      period: \"2022 — Now\",\n      title: \"Staff Engineer\",\n      company: \"Meridian Labs\",\n      body:\n        \"Lead the platform team behind a payments product handling millions in monthly volume. Set the technical direction, mentor five engineers, and still ship the hard bits myself.\",\n    },\n    {\n      period: \"2019 — 2022\",\n      title: \"Senior Software Engineer\",\n      company: \"Northwind Health\",\n      body:\n        \"Owned the patient scheduling platform end to end. Rebuilt it for accessibility and scale, and grew the frontend guild from a habit into a practice.\",\n    },\n    {\n      period: \"2016 — 2019\",\n      title: \"Software Engineer\",\n      company: \"Fieldnote\",\n      body:\n        \"Second engineer at an early-stage startup. Wore every hat — shipped the first web app, the mobile client, and the on-call rotation that kept them running.\",\n    },\n    {\n      period: \"2014 — 2016\",\n      title: \"Frontend Developer\",\n      company: \"Studio Cobalt\",\n      body:\n        \"Built marketing sites and product prototypes for agency clients. Learned to make things fast, make them accessible, and make them on time.\",\n    },\n  ],\n} as const\n\n/** The closing call to action. */\nexport const contact = {\n  label: \"Contact\",\n  heading: \"Let's build something worth using.\",\n  lede:\n    \"I'm open to freelance projects, fractional engineering leadership, and the occasional interesting conversation. The fastest way to reach me is email.\",\n  cta: { label: \"Say hello\", href: \"mailto:hello@example.com\" },\n} as const\n\nexport const footer = {\n  blurb:\n    \"Adrian Vale — senior software engineer in Lisbon. This is a demo of the daylight portfolio template; every word on it lives in one file.\",\n  builtWith: \"Built with Next.js. Designed to stay out of the way.\",\n} as const\n","type":"registry:lib"},{"path":"app/daylight/components/site-header.tsx","target":"app/daylight/components/site-header.tsx","content":"\"use client\"\n\nimport Link from \"next/link\"\nimport { useRef } from \"react\"\n\nimport { BASE, nav, profile } from \"../data/content\"\n\n/**\n * The header, and the only client component in the chrome.\n *\n * The nav is a set of in-page anchors, so there is no active-route state to\n * track. The mobile menu is a native `<details>` — nothing to get wrong about\n * focus or aria-expanded — and the one bit of JS closes it after a link is\n * tapped, since a hash jump does not remount the layout to close it for us.\n */\nexport function SiteHeader() {\n  const menu = useRef<HTMLDetailsElement>(null)\n  const close = () => {\n    if (menu.current) menu.current.open = false\n  }\n\n  return (\n    <header className=\"dlHeader\">\n      <div className=\"dlWrap dlHeaderRow\">\n        <Link className=\"dlBrand\" href={BASE || \"/\"}>\n          <span className=\"dlBrandMark\" aria-hidden=\"true\">\n            {profile.name[0]}\n            {profile.surname[0]}\n          </span>\n          <span>\n            {profile.name} {profile.surname}\n          </span>\n          <span className=\"dlBrandRole\">{profile.role}</span>\n        </Link>\n\n        <nav className=\"dlNav\" aria-label=\"Primary\">\n          {nav.map((link) => (\n            <a key={link.href} href={link.href} className=\"dlNavLink\">\n              {link.label}\n            </a>\n          ))}\n        </nav>\n\n        <details className=\"dlMenu\" ref={menu}>\n          <summary className=\"dlMenuSummary\">Menu</summary>\n          <nav className=\"dlMenuPanel\" aria-label=\"Primary\">\n            {nav.map((link) => (\n              <a key={link.href} href={link.href} className=\"dlMenuLink\" onClick={close}>\n                {link.label}\n              </a>\n            ))}\n          </nav>\n        </details>\n      </div>\n    </header>\n  )\n}\n","type":"registry:component"},{"path":"app/daylight/components/site-footer.tsx","target":"app/daylight/components/site-footer.tsx","content":"import { footer, profile } from \"../data/content\"\n\n/**\n * The footer. Server component — there is nothing here to hydrate. It closes\n * the page quietly with a blurb, the contact routes, and a small colophon.\n */\nexport function SiteFooter() {\n  return (\n    <footer className=\"dlFooter\">\n      <div className=\"dlWrap dlFooterRow\">\n        <p className=\"dlFooterBlurb\">{footer.blurb}</p>\n\n        <div className=\"dlFooterMeta\">\n          <a href={`mailto:${profile.email}`}>{profile.email}</a>\n          <span>\n            <a href={profile.github.href} target=\"_blank\" rel=\"noreferrer\">\n              GitHub\n            </a>{\" \"}\n            ·{\" \"}\n            <a href={profile.linkedin.href} target=\"_blank\" rel=\"noreferrer\">\n              LinkedIn\n            </a>\n          </span>\n          <span>\n            © {profile.year} {profile.name} {profile.surname} — {footer.builtWith}\n          </span>\n        </div>\n      </div>\n    </footer>\n  )\n}\n","type":"registry:component"},{"path":"app/daylight/components/reveal.tsx","target":"app/daylight/components/reveal.tsx","content":"\"use client\"\n\nimport { useEffect, useRef, useState } from \"react\"\n\ntype RevealProps = {\n  children: React.ReactNode\n  /** Merged after `dlReveal`, so this is where the layout class goes. */\n  className?: string\n  /** Stagger, in milliseconds. Feeds `--dl-delay` in the stylesheet. */\n  delay?: number\n  /** Render as something other than a `<div>` — e.g. \"section\", \"li\". */\n  as?: \"div\" | \"section\" | \"li\" | \"article\"\n}\n\n/**\n * Fades and lifts its children in when they first scroll into view.\n *\n * It merges `className` onto the element it renders, so the revealed element\n * *is* the layout element — `<Reveal className=\"dlCard\">` is a grid child, not\n * a wrapper that breaks the grid.\n *\n * Three details are deliberate:\n *\n *   - The observer disconnects on the first intersection. Re-hiding content the\n *     reader has already passed is motion for its own sake, and a long page\n *     keeps zero observers alive by the time you reach the footer.\n *   - The hidden state lives in CSS, not here, so nothing flashes in before\n *     hydration and `prefers-reduced-motion` can switch it off without this\n *     component knowing.\n *   - If `IntersectionObserver` is missing, the content shows immediately.\n *     Failing open is the only acceptable direction for a fade-in.\n */\nexport function Reveal({ children, className, delay = 0, as = \"div\" }: RevealProps) {\n  const ref = useRef<HTMLDivElement>(null)\n  const [shown, setShown] = useState(false)\n\n  useEffect(() => {\n    const node = ref.current\n    if (!node || shown) return\n\n    if (typeof IntersectionObserver === \"undefined\") {\n      setShown(true)\n      return\n    }\n\n    const observer = new IntersectionObserver(\n      (entries) => {\n        if (!entries.some((entry) => entry.isIntersecting)) return\n        setShown(true)\n        observer.disconnect()\n      },\n      /* Held back from the bottom edge so it reads as a reveal, not a pop. */\n      { rootMargin: \"0px 0px -10% 0px\", threshold: 0.05 },\n    )\n\n    observer.observe(node)\n    return () => observer.disconnect()\n  }, [shown])\n\n  const Tag = as\n  return (\n    <Tag\n      ref={ref as React.Ref<never>}\n      className={className ? `dlReveal ${className}` : \"dlReveal\"}\n      data-shown={shown ? \"true\" : \"false\"}\n      style={delay ? ({ \"--dl-delay\": `${delay}ms` } as React.CSSProperties) : undefined}\n    >\n      {children}\n    </Tag>\n  )\n}\n","type":"registry:component"}],"assets":[{"url":"https://ui.artbloom.tech/r/asset/templates/daylight/assets/portrait.png","target":"public/daylight/portrait.png","bytes":1505100},{"url":"https://ui.artbloom.tech/r/asset/templates/daylight/assets/workspace.png","target":"public/daylight/workspace.png","bytes":1779785}],"meta":{"kind":"templates","categories":["portfolio","personal","resume"],"docs":"https://ui.artbloom.tech/artbloom/templates/daylight"}}