/* ---------- Grid-sparks background (source: ~/development/web/animation/grid-sparks.html) ---------- */
.bg-sparks {
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;

  --cell: clamp(16px, 2.2vmin, 32px);
  --sec-per-cell: 1.4s;
  --line: color-mix(in srgb,
            color-mix(in srgb, #003566 62%, #9fc4e8) 42%, transparent);
  --spark: #ffd60a;
  --spark-glow: #ffc300;

  background-image:
    linear-gradient(to right,  var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px),
    radial-gradient(ellipse 90% 80% at 50% 45%,
      #001d3d 0%, #000814 70%);
  background-size:
    var(--cell) var(--cell),
    var(--cell) var(--cell),
    100% 100%;
  background-position: 0 0;
  background-repeat: repeat, repeat, no-repeat;
}

/* ---------- Static grid background (blog pages, no animation) ---------- */
.bg-grid {
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;

  --cell: clamp(16px, 2.2vmin, 32px);
  --line: color-mix(in srgb,
            color-mix(in srgb, #003566 62%, #9fc4e8) 42%, transparent);

  background-image:
    linear-gradient(to right,  var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px),
    radial-gradient(ellipse 90% 80% at 50% 45%,
      #001d3d 0%, #000814 70%);
  background-size:
    var(--cell) var(--cell),
    var(--cell) var(--cell),
    100% 100%;
  background-position: 0 0;
  background-repeat: repeat, repeat, no-repeat;
}

/* Edge fade: cheap full-viewport overlay in the base color instead of
   mask-image, which would force offscreen buffers for grid + sparks. */
.bg-sparks-fade {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 72% 72% at 50% 50%,
    rgba(0, 8, 20, 0) 30%,
    rgba(0, 8, 20, .55) 62%,
    rgba(0, 8, 20, 1) 100%);
}

/* One spark travelling along exactly one grid edge.
   --fx/--fy = viewport-relative position; round() snaps it to a
   multiple of --cell, i.e. exactly onto a grid node.
   --rot sets the travel direction (0/90/180/270). */
.bg-sparks .edge {
  position: absolute;
  left: calc(var(--fx) * 100vw);
  top:  calc(var(--fy) * 100dvh);
  left: round(down, calc(var(--fx) * 100vw), var(--cell));
  top:  round(down, calc(var(--fy) * 100dvh), var(--cell));
  width: calc(var(--len, 1) * var(--cell));
  height: 2px;
  margin-top: -1px;
  transform: rotate(var(--rot, 0deg));
  transform-origin: 0 50%;
}

.bg-sparks .comet {
  position: absolute;
  left: -1.5px;
  top: 50%;
  margin-top: -1.5px;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--spark);
  box-shadow: 0 0 6px 1px color-mix(in srgb, var(--spark-glow) 70%, transparent);
  opacity: 0;
  animation: spark-travel calc(var(--len, 1) * var(--sec-per-cell) / var(--active, .22))
             linear var(--delay, 0s) infinite;
}

/* Run over one edge, then a long pause -> occasional sparks */
@keyframes spark-travel {
  0%   { transform: translateX(0); opacity: 0; }
  1%   { opacity: 1; }
  19%  { opacity: 1; }
  22%  { transform: translateX(calc(var(--len, 1) * var(--cell))); opacity: 0; }
  100% { transform: translateX(calc(var(--len, 1) * var(--cell))); opacity: 0; }
}

/* Long runs: active share 50% instead of 22%, otherwise the pause is too long */
.bg-sparks .edge.long .comet {
  animation-name: spark-travel-long;
  animation-duration: calc(var(--len, 1) * var(--sec-per-cell) / .5);
}

@keyframes spark-travel-long {
  0%   { transform: translateX(0); opacity: 0; }
  2%   { opacity: 1; }
  45%  { opacity: 1; }
  50%  { transform: translateX(calc(var(--len, 1) * var(--cell))); opacity: 0; }
  100% { transform: translateX(calc(var(--len, 1) * var(--cell))); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .bg-sparks .comet { animation: none; opacity: 0; }
}

/* ---------- Custom UI Styles ---------- */
.glass-card {
  background: rgba(0, 29, 61, 0.6);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 1rem;
}

/* Skill badges */
.skill-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.375rem 0.875rem;
  background: rgba(255, 195, 0, 0.08);
  color: #cbd5e1;
  border: 1px solid rgba(255, 195, 0, 0.2);
  border-radius: 9999px;
  font-size: 0.875rem;
  font-weight: 500;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}

.skill-badge:hover {
  background: rgba(255, 195, 0, 0.18);
  border-color: rgba(255, 195, 0, 0.5);
  color: #fff4cc;
}

.text-gradient {
  background: linear-gradient(to right, #ffd60a, #ffc300, #ffef9f);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* Legal pages (impressum, datenschutz) */
.legal-prose p { margin-bottom: 0.75rem; }
.legal-prose .field { margin-bottom: 1.25rem; }

/* ---------- Blog article body (rendered from Markdown) ---------- */
.prose-blog {
  font-size: 1rem;
  line-height: 1.75;
  color: #94a3b8;
}

@media (min-width: 768px) {
  .prose-blog { font-size: 1.0625rem; }
}

.prose-blog > * + * { margin-top: 1.25em; }

.prose-blog h2 {
  color: #fff;
  font-size: 1.375rem;
  font-weight: 700;
  line-height: 1.3;
  margin-top: 2em;
  margin-bottom: 0.75em;
}

.prose-blog h3 {
  color: #fff;
  font-size: 1.125rem;
  font-weight: 700;
  margin-top: 1.75em;
  margin-bottom: 0.5em;
}

.prose-blog strong { color: #e2e8f0; font-weight: 600; }

.prose-blog a {
  color: #ffc300;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.prose-blog a:hover { color: #ffd60a; }

.prose-blog ul,
.prose-blog ol {
  padding-left: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.prose-blog ul { list-style: disc; }
.prose-blog ol { list-style: decimal; }
.prose-blog li::marker { color: #ffc300; }

.prose-blog blockquote {
  border-left: 3px solid #ffc300;
  padding-left: 1.25rem;
  color: #cbd5e1;
  font-style: italic;
}

.prose-blog code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.875em;
  background: rgba(255, 195, 0, 0.08);
  border: 1px solid rgba(255, 195, 0, 0.2);
  border-radius: 0.375rem;
  padding: 0.1em 0.35em;
  color: #ffd60a;
}

.prose-blog pre {
  background: rgba(0, 8, 20, 0.85);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 0.75rem;
  padding: 1rem 1.25rem;
  overflow-x: auto;
}

.prose-blog pre code {
  background: none;
  border: none;
  padding: 0;
  color: #cbd5e1;
  font-size: 0.875rem;
  line-height: 1.6;
}

.prose-blog img {
  border-radius: 0.75rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.prose-blog hr {
  border: none;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  margin-top: 2em;
}

.prose-blog table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

.prose-blog th {
  color: #ffc300;
  text-align: left;
  font-weight: 600;
  border-bottom: 1px solid rgba(255, 195, 0, 0.3);
  padding: 0.5rem 0.75rem;
}

.prose-blog td {
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  padding: 0.5rem 0.75rem;
}

/* Smooth expansion for detail accordions (offerings + career stations).
   Progressive enhancement: browsers without ::details-content / interpolate-size
   support simply toggle instantly. */
@supports (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }

  details[data-detail]::details-content {
    block-size: 0;
    overflow-y: clip;
    transition: content-visibility 400ms allow-discrete, block-size 400ms ease;
  }

  details[data-detail][open]::details-content {
    block-size: auto;
  }
}
