/**
 * Yorsh — shared stylesheet.
 *
 * Single stylesheet for every page. Inline styles are deliberately avoided so
 * the site can be served under a `style-src 'self'` Content Security Policy
 * (see `_headers`).
 *
 * Each colour token pairs its light and dark value in a single `light-dark()`
 * declaration, so no colour is written twice and the two palettes cannot drift
 * apart. Which half applies is decided entirely by the used `color-scheme`,
 * which makes a theme switch a one-property change on `:root`.
 *
 * This is the portfolio.yorsh.co copy. Everything above the "Portfolio" section
 * is kept identical to the yorsh.co stylesheet so the sites stay visually in
 * step; the section below it is portfolio-only. Brand changes belong in
 * yorsh.co's copy first (alongside `docs/branding.md`), then get propagated
 * here.
 */

:root {
  color-scheme: light dark;

  --brand: light-dark(#276182, #7ab0d0);
  --accent: light-dark(#823437, #d99a9c);
  --accent-strong: light-dark(#6a2a2d, #e8b3b5);

  --bg: light-dark(#f8fafb, #0f1720);
  --surface: light-dark(#ffffff, #16202b);
  --text: light-dark(#1c2429, #e6edf3);
  --muted: light-dark(#5a6670, #9aa9b5);
  --border: light-dark(#e2e8ec, #26323f);
  --on-solid: light-dark(#ffffff, #0f1720);

  --page-width: 62rem;
  --measure: 68ch;
  --radius: 0.5rem;

  --font-sans:
    system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

/* A stored preference pins `color-scheme`, which re-resolves every
   `light-dark()` above and switches native scrollbars and form controls to
   match. No attribute means no preference, and `light dark` follows the OS. */
:root[data-theme="light"] {
  color-scheme: light;
}

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-text-size-adjust: 100%;
}

a {
  color: var(--brand);
  text-decoration-color: color-mix(in srgb, var(--brand) 40%, transparent);
  text-underline-offset: 0.15em;
}

a:hover {
  color: var(--accent);
  text-decoration-color: currentColor;
}

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 2px;
}

img {
  max-width: 100%;
  height: auto;
}

/* Layout ------------------------------------------------------------------ */

.container {
  max-width: var(--page-width);
  margin: 0 auto;
  padding: 2rem 1.25rem 3rem;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  z-index: 10;
}

.skip-link:focus {
  left: 1rem;
  top: 1rem;
}

/* Text carried for screen readers only, where the visual design already conveys
   the same thing by other means. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

section {
  margin-top: 3rem;
}

/* Header ------------------------------------------------------------------ */

.site-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--border);
}

.site-header__mark {
  display: block;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius);
}

.site-header__name {
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text);
  text-decoration: none;
}

.site-header__name:hover {
  color: var(--brand);
}

/* `margin-left: auto` pushes the control to the far end of the header flex row.
   The square matches the height of `.site-header__mark`, and every glyph is the
   same size, so the header never shifts as the theme cycles. */
.theme-toggle {
  display: grid;
  place-items: center;
  margin-left: auto;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
}

/* `display` above outranks the user agent's `[hidden] { display: none }`, which
   would otherwise leave a dead control on the page for readers without
   JavaScript — `theme.js` is what clears the attribute. */
.theme-toggle[hidden] {
  display: none;
}

.theme-toggle:hover {
  color: var(--brand);
  border-color: var(--brand);
}

/* Stroke and size live here rather than on the elements, so the three glyphs
   cannot drift apart across the seven pages that repeat this markup.
   `currentColor` is what lets them inherit the hover colour above. */
.theme-toggle__icon {
  display: none;
  width: 1.125rem;
  height: 1.125rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Which glyph shows is a function of `data-theme` alone — absent means System —
   so the icon follows the palette without the script touching it. */
.theme-toggle__icon--system,
:root[data-theme="light"] .theme-toggle__icon--light,
:root[data-theme="dark"] .theme-toggle__icon--dark {
  display: block;
}

:root[data-theme] .theme-toggle__icon--system {
  display: none;
}

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

.hero {
  margin-top: 3.5rem;
  text-align: center;
}

.hero__logo {
  width: 5.5rem;
  height: 5.5rem;
  border-radius: 1rem;
  margin-bottom: 1.5rem;
}

.hero h1 {
  font-size: clamp(2.25rem, 6vw, 3.25rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 0.75rem;
}

.hero__tagline {
  max-width: 34ch;
  margin: 0 auto 2rem;
  font-size: clamp(1.05rem, 2.5vw, 1.3rem);
  color: var(--muted);
  text-wrap: balance;
}

/* Headings ---------------------------------------------------------------- */

h2 {
  position: relative;
  font-size: 1.375rem;
  letter-spacing: -0.01em;
  margin: 0 0 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}

/* Accent segment overlaying the left end of the heading rule. */
h2::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 2.5rem;
  height: 2px;
  background: var(--accent);
}

/* Clause headings nested under a part heading. No rule or accent, so the
   two levels stay visually distinct. */
h3 {
  font-size: 1.0625rem;
  letter-spacing: -0.005em;
  margin: 2rem 0 0.5rem;
}

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

.btn {
  display: inline-block;
  padding: 0.7rem 1.5rem;
  border-radius: var(--radius);
  font-weight: 600;
  text-decoration: none;
}

/* The accent carries the primary call to action, against the brand-teal page. */
.btn--primary {
  background: var(--accent);
  color: var(--on-solid);
}

.btn--primary:hover {
  background: var(--accent-strong);
  color: var(--on-solid);
}

/* Services ---------------------------------------------------------------- */

.services {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.services li {
  padding: 0.875rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
}

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

.profiles {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin: 1.5rem 0 0;
  padding: 0;
}

/* Legal pages ------------------------------------------------------------- */

.page-title {
  margin: 2.5rem 0 0.25rem;
  font-size: clamp(1.75rem, 5vw, 2.25rem);
  letter-spacing: -0.02em;
}

.updated {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
}

.legal ul {
  max-width: var(--measure);
  padding-left: 1.25rem;
}

.legal li {
  margin-bottom: 0.375rem;
}

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

.site-footer {
  margin-top: 4rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
  font-size: 0.875rem;
  color: var(--muted);
  text-align: center;
}

.site-footer p {
  max-width: none;
  margin: 0.5rem 0;
}

.site-footer nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 1.25rem;
  margin-bottom: 1rem;
}

/* Error page -------------------------------------------------------------- */

.error {
  margin-top: 5rem;
  text-align: center;
}

.error p {
  margin: 0 auto 2rem;
  color: var(--muted);
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}
/* Portfolio --------------------------------------------------------------- */

/* Case studies ------------------------------------------------------------ */

/* One centred column for reading. `--case-width` is set as a page-level layout
   width rather than a `p` measure, so the shared stylesheet's unconstrained
   paragraphs stay untouched and figures can still run to the full page. */
.case {
  --case-width: 45rem;
  max-width: var(--case-width);
  margin: 0 auto;
}

.case section {
  margin-top: 3.5rem;
}

.case ul:not([class]) {
  padding-left: 1.25rem;
}

.case ul:not([class]) li {
  margin-bottom: 0.375rem;
}

.case__back {
  display: inline-block;
  margin-top: 2rem;
  font-size: 0.9375rem;
}

.case__outcome {
  margin: 0.5rem 0 1.25rem;
  font-size: clamp(1.05rem, 2.5vw, 1.25rem);
  color: var(--muted);
  text-wrap: pretty;
}

.case__status {
  margin: 1rem 0 0;
  font-size: 0.9rem;
  color: var(--muted);
}

/* Stack chips --------------------------------------------------------------- */

.chips {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
}

.chips li {
  padding: 0.125rem 0.625rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--brand);
  background: color-mix(in srgb, var(--brand) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand) 30%, transparent);
  border-radius: 999px;
}

/* In short ---------------------------------------------------------------- */

/* The few-second summary at the top of every case study. The heading keeps the
   shared h2 treatment so the block reads as part of the page, while the panel
   and accent rule set it apart from the sections below. */
.case .tldr {
  margin-top: 2rem;
  padding: 1rem 1.25rem 1.125rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

.tldr h2 {
  font-size: 1rem;
  margin-bottom: 0.75rem;
}

.tldr dl {
  display: grid;
  gap: 0.625rem;
  margin: 0;
}

.tldr dl div {
  display: grid;
  gap: 0.125rem 1rem;
}

@media (min-width: 36rem) {
  .tldr dl div {
    grid-template-columns: 6rem 1fr;
  }
}

.tldr dt {
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1.9;
}

.tldr dd {
  margin: 0;
}

/* At a glance ------------------------------------------------------------- */

/* `<dl>` keeps each figure paired with its label for assistive technology;
   the value is visually first through `order`, not by reversing the markup. */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: 0.75rem;
  margin: 0;
}

.stats div {
  display: flex;
  flex-direction: column;
  padding: 1rem 1.125rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 3px solid var(--brand);
  border-radius: var(--radius);
}

.stats dt {
  order: 1;
  font-size: 0.875rem;
  color: var(--muted);
  line-height: 1.4;
}

.stats dd {
  margin: 0 0 0.25rem;
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

/* Key features ------------------------------------------------------------ */

.features {
  list-style: none;
  display: grid;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
}

.features li {
  padding: 1rem 1.125rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
}

.features h3 {
  margin: 0 0 0.25rem;
}

.features p {
  margin: 0.25rem 0 0;
}

/* The "why it matters" line, set apart so a skim reads only these. */
.features .why {
  color: var(--muted);
  font-size: 0.9375rem;
}

/* Under the hood ---------------------------------------------------------- */

.hood {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.hood summary {
  padding: 0.875rem 1.125rem;
  font-weight: 600;
  cursor: pointer;
}

.hood summary:hover {
  color: var(--brand);
}

.hood[open] summary {
  border-bottom: 1px solid var(--border);
}

.hood__body {
  padding: 0 1.125rem 1rem;
}

.hood__body code {
  font-size: 0.875em;
}

/* Tables ------------------------------------------------------------------ */

.table-scroll {
  overflow-x: auto;
  margin: 1.25rem 0;
}

.case-table {
  border-collapse: collapse;
  width: 100%;
  min-width: 28rem;
  font-size: 0.9375rem;
}

.case-table th,
.case-table td {
  padding: 0.5rem 0.75rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--border);
}

.case-table thead th {
  border-bottom: 2px solid var(--border);
  font-weight: 600;
}

/* Landing ----------------------------------------------------------------- */

.intro {
  max-width: var(--measure);
}

.intro p {
  color: var(--muted);
  font-size: clamp(1.05rem, 2.5vw, 1.2rem);
  text-wrap: pretty;
}

/* Project cards. Two columns from 40rem; a lone card keeps its column width
   rather than stretching across the page. The card has no media yet; a media
   slot above the title arrives with the recorded posters. */
.cards {
  list-style: none;
  display: grid;
  gap: 1rem;
  margin: 0;
  padding: 0;
}

@media (min-width: 40rem) {
  .cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1.25rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 3px solid var(--brand);
  border-radius: var(--radius);
}

.card:hover,
.card:focus-within {
  border-color: var(--brand);
}

.card__title {
  margin: 0;
  font-size: 1.25rem;
}

/* Stretches the title link over the whole card; the text stays selectable. */
.card__title a {
  text-decoration: none;
}

.card__title a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.card__outcome {
  margin: 0;
  color: var(--muted);
}

.card .chips {
  margin-top: auto;
}

/* Code -------------------------------------------------------------------- */

/* Scrolls inside the block so a long line never widens the page. */
.hood__body pre {
  overflow-x: auto;
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.875rem;
  line-height: 1.5;
}

.hood__body pre code {
  font-size: inherit;
}
