/* ============================================================================
   portfolio — page styles
   ----------------------------------------------------------------------------
   Base values come from the inline styles in Portfolio.dc.html. Where the page
   goes beyond that design, the block is marked BEYOND DESIGN and says why.
   ========================================================================== */

html {
  scroll-behavior: smooth;
  background: #161826;
}

body {
  margin: 0;
  text-wrap: pretty;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  min-height: 100vh;
  position: relative;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

@keyframes nocturne-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

/* Browser-default blue selection was the one place the palette broke. */
::selection {
  background: var(--color-accent);
  color: #161826;
  text-shadow: none;
}

/* ============================================================================
   link + hover system                                          BEYOND DESIGN
   ----------------------------------------------------------------------------
   The design only set `a:hover { color: accent-300 }`. Every interactive text
   surface now warms toward the accent on hover, so the whole page reacts in
   one voice instead of only prose links.
   ========================================================================== */

a {
  color: var(--color-accent);
  text-underline-offset: 3px;
  transition: color 160ms ease;
}

a:hover {
  color: var(--color-accent-200);
}

/* Prose links grow an underline rather than carrying one permanently. */
.container p a,
.contact__lede a {
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--color-accent) 40%, transparent);
  transition: color 160ms ease, text-decoration-color 160ms ease;
}

.container p a:hover {
  text-decoration-color: var(--color-accent-200);
}

/* Project repo link: a real button, so the one outbound action on a project
   card is findable at a glance. */
.gh-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 36px;
  padding: 0 14px;
  border: 1px solid color-mix(in srgb, var(--color-accent) 45%, transparent);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--color-accent) 12%, transparent);
  color: var(--color-accent-200);
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
}

.gh-btn .icon { width: 18px; height: 18px; }
.gh-btn__arrow { font-size: 13px; opacity: 0.75; }

.gh-btn:hover {
  background: color-mix(in srgb, var(--color-accent) 22%, transparent);
  border-color: var(--color-accent);
  color: var(--color-text);
}

:where(a, button):focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
  border-radius: 3px;
}

/* ---- shared ------------------------------------------------------------- */

.container {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 clamp(20px, 5vw, 56px);
}

/* Section and group titles are set as real display type. The earlier small
   mono uppercase labels with running numbers read as templated; headings at
   size carry the page's structure on their own. */
.section-title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: clamp(34px, 4.4vw, 54px);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--color-text);
  margin: 0 0 32px;
}

.group-title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: clamp(26px, 3.2vw, 38px);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--color-text);
  margin: 0 0 18px;
}

.group-title--spaced { margin-top: 80px; }
.group-title--filters { margin-bottom: 22px; }

/* The design draws row separators as an inset hairline that fades out at both
   ends, using a background-image rather than a border. */
.rule-top,
.rule-both {
  background-image:
    linear-gradient(to right, transparent, var(--color-divider) 48px, var(--color-divider) calc(100% - 48px), transparent);
  background-repeat: no-repeat;
  background-position: top;
  background-size: 100% 1px;
}

.rule-both {
  background-image:
    linear-gradient(to right, transparent, var(--color-divider) 48px, var(--color-divider) calc(100% - 48px), transparent),
    linear-gradient(to right, transparent, var(--color-divider) 48px, var(--color-divider) calc(100% - 48px), transparent);
  background-repeat: no-repeat, no-repeat;
  background-position: top, bottom;
  background-size: 100% 1px, 100% 1px;
}

/* ---- reticle (detection cursor) ----------------------------------------- */

.reticle {
  position: fixed;
  left: 0;
  top: 0;
  width: 26px;
  height: 26px;
  z-index: 60;
  pointer-events: none;
  opacity: 0;
  transition: opacity 200ms ease;
  will-change: transform, width, height;
}

.reticle__corner {
  position: absolute;
  width: 11px;
  height: 11px;
}

.reticle__corner--nw { left: 0; top: 0; border-left: 1.5px solid var(--color-accent); border-top: 1.5px solid var(--color-accent); }
.reticle__corner--ne { right: 0; top: 0; border-right: 1.5px solid var(--color-accent); border-top: 1.5px solid var(--color-accent); }
.reticle__corner--sw { left: 0; bottom: 0; border-left: 1.5px solid var(--color-accent); border-bottom: 1.5px solid var(--color-accent); }
.reticle__corner--se { right: 0; bottom: 0; border-right: 1.5px solid var(--color-accent); border-bottom: 1.5px solid var(--color-accent); }

.reticle__scan {
  position: absolute;
  left: 1px;
  right: 1px;
  top: 50%;
  height: 1px;
  opacity: 0;
  background: linear-gradient(to right, transparent, color-mix(in srgb, var(--color-accent) 55%, transparent), transparent);
}

.reticle__label {
  position: absolute;
  left: 0;
  top: 100%;
  margin-top: 7px;
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--color-accent-200);
  opacity: 0;
  transition: opacity 160ms ease;
}

.reticle__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--color-accent);
  animation: nocturne-blink 1.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .reticle__dot { animation: none; }
}

/* ============================================================================
   hero
   ========================================================================== */

/* Full-bleed so the grid and bloom reach both window edges; .hero__inner keeps
   the text on the same 1120px measure as the rest of the page. */
.hero {
  position: relative;
  overflow: hidden;
  padding: 88px 0 72px;
}

.hero__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 48px clamp(32px, 5vw, 80px);
  align-items: start;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 clamp(20px, 5vw, 56px);
}

/* BEYOND DESIGN — atmosphere. The bloom is anchored off the left edge so the
   warmth enters the frame rather than sitting politely in the middle. */
.hero::before {
  content: '';
  position: absolute;
  inset: -30% 0 auto 0;
  height: 680px;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(48% 100% at 4% 44%, color-mix(in srgb, var(--color-accent) 13%, transparent) 0%, transparent 72%);
}

/* Drafting paper, not a uniform lattice: a fine 24px grid with a heavier line
   every 120px, the way a real drawing sheet is ruled. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, color-mix(in srgb, var(--color-text) 3.5%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--color-text) 3.5%, transparent) 1px, transparent 1px),
    linear-gradient(to right, color-mix(in srgb, var(--color-text) 7%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--color-text) 7%, transparent) 1px, transparent 1px);
  background-size: 24px 24px, 24px 24px, 120px 120px, 120px 120px;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.45) 52%, transparent 88%);
  mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.45) 52%, transparent 88%);
}

/* ============================================================================
   hero portrait
   ----------------------------------------------------------------------------
   Round photo beside the (shrunk) headline, sized a touch taller than the
   three-line heading next to it rather than matched to it exactly.
   ========================================================================== */

.hero__titlewrap {
  display: flex;
  align-items: center;
  gap: clamp(18px, 3vw, 28px);
  margin-bottom: 4px;
}

.hero-photo {
  display: block;
  object-fit: cover;
  object-position: 50% 15%;
  border-radius: 50%;
  flex: none;
  width: clamp(110px, 15vw, 210px);
  height: clamp(110px, 15vw, 210px);
}

.hero__titlewrap h1 { font-size: clamp(30px, 4.6vw, 56px); }

.hero h1 {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: clamp(38px, 6vw, 76px);
  line-height: 1.08;
  letter-spacing: -0.025em;
  margin: 0;
  max-width: 20ch;
  /* Safety net for the cycling phrases below — a long one on a narrow
     viewport breaks mid-word rather than overflowing the column. */
  overflow-wrap: anywhere;
}

/* ============================================================================
   hero headline cycler
   ----------------------------------------------------------------------------
   portfolio.js types/deletes between a short list of phrases, keeping any
   shared prefix on screen instead of clearing and retyping it — autoplay
   only, no click interaction.
   ========================================================================== */

.hero__caret {
  display: inline-block;
  width: 3px;
  height: 0.74em;
  margin-left: 5px;
  vertical-align: -0.06em;
  background: var(--color-accent);
  animation: nocturne-blink 1s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .hero__caret { animation: none; opacity: 0.6; }
}

.hero p {
  font-size: 17px;
  line-height: 1.7;
  color: var(--color-neutral-300);
  max-width: 54ch;
  margin: 28px 0 0;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 32px;
}

@media (max-width: 900px) {
  .hero { padding-top: 64px; }
  .hero__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: 44px;
  }
}

/* ============================================================================
   credentials panel                                            BEYOND DESIGN
   ----------------------------------------------------------------------------
   The Aimtec win is the strongest single signal on this site and the reason it
   exists, so it sits above the fold instead of inside a table three screens
   down. It also fills the hero's empty right-hand column.
   ========================================================================== */

/* No card: a ruled column. The hairline that fades at both ends is the page's
   own separator, used here at a tighter inset to suit the narrower measure. */
.creds { padding-top: 6px; }

.creds__label {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-neutral-400);
  margin: 0 0 18px;
}

.creds__lead,
.creds__list li {
  background-image:
    linear-gradient(to right, transparent, var(--color-divider) 14px, var(--color-divider) calc(100% - 14px), transparent);
  background-repeat: no-repeat;
  background-position: bottom;
  background-size: 100% 1px;
}

.creds__lead {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding: 0 0 18px;
  text-decoration: none;
  color: inherit;
}

/* The place is set as a display numeral — the emphasis comes from scale and
   colour, not from a pill or a badge. */
.creds__lead-place {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 34px;
  line-height: 0.9;
  letter-spacing: -0.03em;
  color: var(--color-accent);
  font-feature-settings: 'tnum' 1;
  flex: none;
  min-width: 44px;
  transition: color 180ms ease;
}

.creds__lead:hover .creds__lead-place { color: var(--color-accent-200); }

.creds__lead-text { min-width: 0; }

.creds__event {
  display: block;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 19px;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--color-text);
  transition: color 180ms ease;
}

.creds__lead:hover .creds__event { color: var(--color-accent-200); }

.creds__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin-top: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--color-neutral-400);
  font-feature-settings: 'tnum' 1;
}

.creds__go {
  color: var(--color-accent-300);
  transition: color 160ms ease;
}

.creds__lead:hover .creds__go { color: var(--color-accent-200); }

.creds__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.creds__list li {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--color-neutral-300);
}

.creds__place {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 15px;
  color: var(--color-accent-300);
  font-feature-settings: 'tnum' 1;
  min-width: 44px;
  flex: none;
}

/* Accent-coloured and weighted like a call to action: it is the exit from the
   hero panel toward the full results, not a quiet footnote link. */
.creds__all {
  display: inline-block;
  margin-top: 18px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--color-accent-300);
  transition: color 160ms ease, transform 160ms ease;
}

.creds__all::after { content: ' →'; display: inline-block; transition: transform 160ms ease; }
.creds__all:hover { color: var(--color-accent-200); }
.creds__all:hover::after { transform: translateX(3px); }

/* ============================================================================
   projects
   ========================================================================== */

#projekty {
  padding: 48px 0 0;
}

.entry {
  display: flex;
  flex-wrap: wrap;
  gap: 14px clamp(24px, 4vw, 48px);
  padding: 26px 16px;
  margin-inline: -16px;
  transition: background-color 220ms ease;
}

/* BEYOND DESIGN — the list was static. A tint on hover plus a warming title
   makes seven rows feel browsable instead of printed. */
.entry:hover {
  background-color: color-mix(in srgb, var(--color-text) 3.5%, transparent);
}

.entry__head { flex: 1 1 290px; min-width: 0; }
.entry__body { flex: 1 1 330px; min-width: 0; }

.entry__head h4 {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: clamp(20px, 2.1vw, 25px);
  line-height: 1.2;
  letter-spacing: -0.015em;
  margin: 0;
  transition: color 220ms ease;
}

.entry:hover .entry__head h4 { color: var(--color-accent-200); }

.entry__meta {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-neutral-400);
  margin: 10px 0 0;
}

.entry__body p {
  font-size: 15px;
  line-height: 1.7;
  margin: 0;
  color: var(--color-neutral-300);
  max-width: 52ch;
}

.stack {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 14px 0 0;
}

/* A stack row that also carries a repo link. */
.entry__aside {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin: 14px 0 0;
}

.entry__aside .stack { margin: 0; }

/* Phones: projects were a quarter of the page. The description and tags fold
   away behind each title; the GitHub button stays visible. The toggle only
   exists at phone width, so desktop always shows everything. */
.entry__toggle { display: none; }

@media (max-width: 680px) {
  .entry { row-gap: 10px; padding-block: 20px; }
  .entry__head { position: relative; }

  .entry__toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 10px;
    padding: 0;
    background: none;
    border: 0;
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-accent-300);
    cursor: pointer;
  }

  /* the whole title block is the tap target, not just the small label */
  .entry__toggle::before {
    content: '';
    position: absolute;
    inset: -10px 0;
  }

  .entry__toggle svg {
    width: 12px;
    height: 12px;
    transition: transform 200ms ease;
  }

  .entry.is-open .entry__toggle svg { transform: rotate(180deg); }

  .entry:not(.is-open) .entry__body > p,
  .entry:not(.is-open) .entry__body .stack { display: none; }
  .entry:not(.is-open) .entry__aside { margin-top: 0; }
  /* nothing left to show without a repo button: drop the empty column */
  .entry:not(.is-open) .entry__body:not(:has(.gh-btn)) { display: none; }
}

@media (max-width: 680px) and (prefers-reduced-motion: reduce) {
  .entry__toggle svg { transition: none; }
}

/* ============================================================================
   about
   ========================================================================== */

#o-mne {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: 32px clamp(24px, 5vw, 72px);
  align-items: start;
  padding: 72px 0;
}

#o-mne .section-title { margin-bottom: 28px; }

#o-mne p.statement {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: clamp(25px, 3vw, 34px);
  line-height: 1.15;
  letter-spacing: -0.02em;
  margin: 0;
  max-width: 24ch;
}

#o-mne p {
  font-size: 15px;
  line-height: 1.75;
  color: var(--color-neutral-300);
  max-width: 50ch;
  margin: 22px 0 0;
}

.about__figure { margin: 0; }

/* Shows the whole photo, uncropped — the panel gives a transparent-background
   portrait an edge to sit against instead of floating on the page. */
.portrait {
  border-radius: var(--radius-md);
  width: 100%;
  aspect-ratio: 1 / 1;
  padding: clamp(16px, 3vw, 32px);
  box-sizing: border-box;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.portrait img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* ============================================================================
   experience
   ========================================================================== */

#cv { padding: 72px 0 40px; }

#uspechy { padding: 72px 0 80px; }

.row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px clamp(24px, 4vw, 48px);
  padding: 20px 0;
}

.row--baseline { align-items: baseline; }

.row__head { flex: 1 1 270px; min-width: 0; }
.row__body { flex: 1 1 320px; min-width: 0; }

.row__title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 18px;
  line-height: 1.3;
  margin: 0;
}

.row__date {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-neutral-400);
  font-feature-settings: 'tnum' 1;
  margin: 8px 0 0;
}

.row__body p {
  font-size: 15px;
  line-height: 1.7;
  margin: 0;
  color: var(--color-neutral-300);
}

.row__body--inline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
}

/* ============================================================================
   award block                                                  BEYOND DESIGN
   ----------------------------------------------------------------------------
   The design filed the Aimtec win as an ordinary row with a small tag. It is
   the headline credential, so it gets its own surface.
   ========================================================================== */

.award {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 16px clamp(24px, 4vw, 48px);
  padding: 34px 0 36px;
}

.award__place {
  flex: none;
  display: flex;
  align-items: baseline;
  gap: 9px;
  margin: 0;
  min-width: 110px;
}

/* The whole emphasis rests on one numeral at display scale. */
.award__num {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(44px, 5.2vw, 62px);
  line-height: 0.82;
  letter-spacing: -0.04em;
  color: var(--color-accent);
  font-feature-settings: 'tnum' 1;
}

.award__place-label {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-accent-300);
}

.award__head { flex: 1 1 240px; min-width: 0; }
.award__body { flex: 1 1 320px; min-width: 0; }

.award__title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: clamp(20px, 2.1vw, 24px);
  line-height: 1.25;
  letter-spacing: -0.015em;
  margin: 0;
}

.award__date {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-neutral-400);
  font-feature-settings: 'tnum' 1;
  margin: 8px 0 0;
}

.award__body p {
  font-size: 15px;
  line-height: 1.7;
  color: var(--color-neutral-300);
  margin: 0;
  max-width: 52ch;
}

.award__link {
  display: inline-block;
  margin-top: 14px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--color-accent-300);
}

.award__link:hover { color: var(--color-accent-200); }

/* ---- filters + table ---------------------------------------------------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 18px 36px;
  margin: 0 0 22px;
}

.filters__label {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-400);
  margin: 0 0 8px;
}

.filters__options {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.table-wrap { overflow-x: auto; }

.table-wrap .table {
  min-width: 620px;
  font-feature-settings: 'tnum' 1;
}

/* BEYOND DESIGN — the table is scannable data; a row tint helps track across
   five columns. */
.table tbody tr {
  transition: background-color 160ms ease;
}

.table tbody tr:hover {
  background-color: color-mix(in srgb, var(--color-text) 3.5%, transparent);
}

.table tbody tr:hover td:first-child { color: var(--color-accent-200); }

.table-empty {
  font-size: 15px;
  line-height: 1.7;
  color: var(--color-neutral-300);
  margin: 18px 0 0;
}

.table-count {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--color-neutral-400);
  margin: 14px 0 0;
}

/* ============================================================================
   contact
   ========================================================================== */

#kontakt {
  background: radial-gradient(120% 160% at 12% 0%, var(--color-section-glow) 0%, var(--color-section) 55%, var(--color-section) 100%);
  color: var(--color-text);
}

.contact__inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 80px clamp(20px, 5vw, 56px);
}

#kontakt p.statement {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: clamp(24px, 2.8vw, 32px);
  line-height: 1.1;
  letter-spacing: -0.025em;
  margin: 0;
}

.contact__lede {
  font-size: 16px;
  line-height: 1.7;
  color: var(--color-neutral-300);
  max-width: 46ch;
  margin: 18px 0 0;
}

/* Flex, not equal grid columns: each channel takes the width its value needs,
   so the e-mail address is not squeezed into a quarter and split mid-word. */
.contact__grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 26px clamp(24px, 4vw, 48px);
  margin-top: 48px;
}

.contact__label {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-300);
  margin: 0 0 6px;
}

.contact__value {
  display: inline-block;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 16px;
  color: var(--color-accent-200);
  margin: 0;
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--color-accent) 35%, transparent);
  padding-bottom: 2px;
  transition: color 160ms ease, border-color 160ms ease;
}

.contact__value:hover {
  color: var(--color-text);
  border-bottom-color: var(--color-accent-200);
}

/* Break only when the address genuinely cannot fit (narrow phones). */
.contact__value--email { overflow-wrap: anywhere; }

.contact__value--static {
  border-bottom-color: transparent;
  cursor: default;
}

/* ============================================================================
   tech stack                                                   BEYOND DESIGN
   ----------------------------------------------------------------------------
   Grouped by area. Deliberately no proficiency bars, star ratings or percentages
   — those are invented numbers, and a committee reads them as such. Every item
   carries a monochrome brand mark; depth stands on the projects above.
   ========================================================================== */

.stackgroups {
  grid-column: 1 / -1;
  padding-top: 8px;
}

/* 250px min lands on three columns at full width, so five groups break 3 + 2
   instead of stranding one on a row of its own — and the wider column stops the
   longer tag rows from wrapping. */
.stackgroups__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 28px clamp(24px, 4vw, 48px);
}

.stackgroup__label {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-400);
  margin: 0 0 12px;
  padding-bottom: 10px;
  background-image:
    linear-gradient(to right, var(--color-divider), var(--color-divider) calc(100% - 14px), transparent);
  background-repeat: no-repeat;
  background-position: bottom;
  background-size: 100% 1px;
}

/* Each item is a line: a large brand mark in its own colour, then the name.
   Brand hexes are lifted to at least 4.5:1 against --color-bg where the
   official colour would disappear (GitHub, ROS, .NET, C++…). */
.stacklist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 4px;
}

.stackitem {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 6px 0;
  font-size: 16px;
  color: var(--color-text);
}

.stackitem__icon {
  width: 30px;
  height: 30px;
  transition: transform 180ms cubic-bezier(.2, .7, .2, 1);
}

.stackitem:hover .stackitem__icon { transform: scale(1.12); }

/* Phones: one column of 28 lines was 18% of the whole page. Two-up with
   smaller marks roughly halves it and keeps every item visible. */
@media (max-width: 680px) {
  .stackgroups__grid { gap: 24px; }
  .stacklist { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 12px; row-gap: 2px; }
  .stackitem { gap: 10px; padding: 5px 0; font-size: 14px; }
  .stackitem__icon { width: 24px; height: 24px; }
}

@media (prefers-reduced-motion: reduce) {
  .stackitem__icon { transition: none; }
}

/* ============================================================================
   competition logos                                            BEYOND DESIGN
   ----------------------------------------------------------------------------
   Organisers' own marks, stored locally in assets/competitions. Where no usable
   mark exists (Matematická and Technická olympiáda) a drawn glyph stands in.
   ========================================================================== */

.complogo {
  width: 22px;
  height: 22px;
  object-fit: contain;
  flex: none;
  border-radius: 4px;
}

.complogo--glyph {
  box-sizing: border-box;
  padding: 3px;
  color: var(--color-accent-300);
  border: 1px solid var(--color-divider);
}

/* Physics Olympiad: the galaxy from its badge, round, ringed in the accent,
   and set turning while its row is hovered. */
.complogo--fo {
  border-radius: 50%;
  box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--color-accent) 70%, transparent),
              0 0 10px color-mix(in srgb, var(--color-accent) 35%, transparent);
}

@keyframes fo-orbit { to { transform: rotate(-360deg); } }

.table tbody tr:hover .complogo--fo { animation: fo-orbit 6s linear infinite; }

@media (prefers-reduced-motion: reduce) {
  .table tbody tr:hover .complogo--fo { animation: none; }
}

.complogo--lead { width: 38px; height: 38px; border-radius: 7px; align-self: center; }
.complogo--award { width: 40px; height: 40px; border-radius: 8px; }
.complogo--row { width: 28px; height: 28px; border-radius: 6px; }

.award__title,
.row__title--logo {
  display: flex;
  align-items: center;
  gap: 14px;
}

.compcell {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

/* ============================================================================
   contact additions                                            BEYOND DESIGN
   ========================================================================== */

/* One block per channel: the mark sits beside label and value together. */
.contact__item {
  display: flex;
  align-items: center;
  gap: 16px;
  min-width: 0;
}

.contact__icon {
  width: 40px;
  height: 40px;
  color: var(--color-accent-300);   /* mail; brand marks set their own colour inline */
}

.contact__text { min-width: 0; }

/* A Discord username cannot be linked, so it is copied instead. */
.contact__copy {
  position: relative;
  font-family: var(--font-heading);
  background: none;
  /* The UA button border survives .contact__value's border-bottom, which left
     a full box around it. */
  border: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--color-accent) 35%, transparent);
  padding: 0 0 2px;
  cursor: pointer;
  text-align: left;
}

/* Absolute, and below rather than beside: in flow the hidden hint padded the
   button out to the full column width, and placing it to the right would run
   off-screen in a narrow column. */
.contact__copy::after {
  content: attr(data-hint);
  position: absolute;
  left: 0;
  top: calc(100% + 6px);
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-accent-300);
  opacity: 0;
  transition: opacity 160ms ease;
}

.contact__copy:hover::after,
.contact__copy:focus-visible::after,
.contact__copy.is-copied::after { opacity: 1; }

/* An unmistakable hole, not a broken link. */
.contact__value--todo {
  color: var(--color-neutral-400);
  border-bottom: 1px dashed color-mix(in srgb, var(--color-neutral-400) 60%, transparent);
  font-family: var(--font-mono);
  font-size: 14px;
}

/* ---- footer ------------------------------------------------------------- */

.footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  padding: 36px 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--color-neutral-400);
}

/* ============================================================================
   scroll reveal
   ----------------------------------------------------------------------------
   Reversible: an element that leaves through the BOTTOM of the viewport (you
   scrolled back up) returns to its hidden state, so scrolling down plays the
   entrance again. Leaving through the top does nothing — content you already
   read must not animate behind you.
   ========================================================================== */

.reveal {
  transition: opacity 420ms ease;
}

.reveal.is-hidden {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .reveal,
  .reveal.is-hidden { opacity: 1; transition: none; }
}

/* ---- print -------------------------------------------------------------- */

@media print {
  .reveal, .reveal.is-hidden { opacity: 1 !important; transition: none !important; }
  .nav, .reticle { display: none !important; }
  body { background: #fff; color: #000; }
  .hero::before, .hero::after { display: none !important; }
}
