/* ==========================================================================
   Components — nav, footer, tiles, file tree, tags, timeline, guestbook
   ========================================================================== */

/* --- terminal navigation ------------------------------------------------- */

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-48);
  padding-block: var(--space-4);
}

.nav__prompt {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: var(--text-md);
  font-weight: 500;
  white-space: nowrap;
}

.nav__path {
  color: var(--text-primary);
  text-decoration: none;
}
/* On every page but home this is a real <a href="/">; on home it's a <span>
   (see buildNav in core/site.js), so the hover/focus rule only ever matches
   where there's somewhere to go. */
a.nav__path:hover,
a.nav__path:focus-visible {
  color: var(--accent);
}

.cursor {
  color: var(--accent);
  animation: blink 1.1s step-end infinite;
}

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

.nav__links {
  display: flex;
  align-items: center;
  gap: var(--space-28, 28px);
}

.nav__link {
  color: var(--text-secondary);
  font-size: var(--text-base);
  transition: color var(--dur-fast) var(--ease);
}
.nav__link:hover {
  color: var(--text-primary);
}
.nav__link[aria-current="page"] {
  color: var(--text-primary);
}

.nav__link--external::after {
  content: " ↗";
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.nav__divider {
  width: 1px;
  height: 14px;
  background: var(--border);
}

.lang-switch {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}
.lang-switch__opt {
  color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease);
}
.lang-switch__opt[aria-pressed="true"] {
  color: var(--text-primary);
}
.lang-switch__sep {
  color: var(--text-muted);
}

.theme-toggle {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: 1;
  transition: color var(--dur-fast) var(--ease);
}
.theme-toggle:hover {
  color: var(--text-primary);
}

.nav__menu-btn {
  display: none;
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  color: var(--text-primary);
  line-height: 1;
}

@media (max-width: 860px) {
  .nav {
    gap: var(--space-16);
  }
  .nav__links {
    position: absolute;
    inset-inline: var(--page-pad);
    top: calc(var(--space-40) + 32px);
    z-index: 40;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-16);
    padding: var(--space-20);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
  }
  .nav__links[hidden] {
    display: none;
  }
  .nav__divider {
    display: none;
  }
  .nav__menu-btn {
    display: block;
  }
  .nav__controls {
    display: flex;
    align-items: center;
    gap: var(--space-16);
  }
}

@media (min-width: 861px) {
  .nav__controls {
    display: contents;
  }
}

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

.footer {
  display: flex;
  flex-direction: column;
  gap: var(--space-20);
  padding-top: var(--space-28, 28px);
  border-top: 1px solid var(--border);
}

.footer__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-40);
  flex-wrap: wrap;
}

.footer__signoff {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: var(--text-md);
  color: var(--text-secondary);
}
.footer__signoff .cmd {
  color: var(--text-muted);
}

.footer__links {
  display: flex;
  align-items: center;
  gap: var(--space-24);
  flex-wrap: wrap;
}
.footer__links a {
  font-size: var(--text-md);
  color: var(--text-secondary);
}
.footer__links a:hover {
  color: var(--text-primary);
}

.footer__colophon {
  display: flex;
  align-items: center;
  gap: var(--space-12);
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.footer__colophon a {
  color: var(--text-secondary);
}

/* --- tiles / mosaic ------------------------------------------------------ */

.mosaic {
  display: flex;
  flex-direction: column;
  gap: var(--space-24);
}

.mosaic__row {
  display: grid;
  gap: var(--space-24);
  align-items: stretch;
}
.mosaic__row--wide-square {
  grid-template-columns: minmax(0, 1fr) 420px;
}
.mosaic__row--halves {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 1024px) {
  .mosaic__row--wide-square,
  .mosaic__row--halves {
    grid-template-columns: minmax(0, 1fr);
  }
}

.tile {
  display: flex;
  flex-direction: column;
  gap: var(--space-32);
  padding: var(--space-40);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  position: relative;
}

a.tile,
.tile--link {
  transition: border-color var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
a.tile:hover,
.tile--link:hover {
  border-color: var(--text-muted);
}

.tile__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-12);
}
.tile__title {
  font-family: var(--font-mono);
  font-size: var(--text-base);
  color: var(--text-primary);
}
.tile__meta {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.tile--map {
  aspect-ratio: 1;
  padding: var(--space-28, 28px);
  overflow: hidden;
  cursor: pointer;
}

@media (max-width: 1024px) {
  .tile--map {
    aspect-ratio: auto;
  }
}

@media (max-width: 700px) {
  .tile {
    padding: var(--space-24) var(--space-20);
    gap: var(--space-20);
    border-radius: var(--radius-md);
  }
}

/* --- profile card -------------------------------------------------------- */

.profile {
  display: flex;
  gap: var(--space-40);
  align-items: flex-start;
  padding: var(--space-40);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  position: relative;
}

.profile__portrait {
  flex: 0 0 200px;
  width: 200px;
  height: 248px;
  border-radius: var(--radius-md);
  background: var(--surface-alt);
  object-fit: cover;
}

.profile__portrait--empty {
  display: grid;
  place-items: center;
}

.profile__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  min-width: 0;
}

.profile__aside {
  display: flex;
  gap: var(--space-8);
  color: var(--text-muted);
  font-size: var(--text-base);
}
.profile__aside .glyph {
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  padding-top: 3px;
}

@media (max-width: 700px) {
  .profile {
    flex-direction: column;
    padding: var(--space-24) var(--space-20);
    gap: var(--space-20);
    border-radius: var(--radius-md);
  }
  .profile__portrait {
    flex: none;
    width: 100%;
    height: 200px;
  }
}

/* --- guestbook launcher (the notebook) ----------------------------------- */

/**
 * The notebook and its handwritten invitation, riding the card's top edge.
 *
 * One flex row rather than two absolutely positioned pieces, so the note
 * always sits beside the notebook whatever its width — and it does change,
 * since the Portuguese line is noticeably longer than the English one.
 */
.guestbook-cue {
  position: absolute;
  top: -20px;
  right: 36px;
  display: flex;
  align-items: center;
  gap: var(--space-12);
}

.guestbook-cue__note {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-hand);
  font-size: 1.25rem;
  line-height: 1.1;
  color: var(--text-secondary);
  white-space: nowrap;
  /* Scribbled in the margin, not a label. */
  transform: rotate(-1.5deg);
  transition: color var(--dur-fast) var(--ease);
}
.guestbook-cue__arrow {
  color: var(--accent);
}
.guestbook-cue:hover .guestbook-cue__note {
  color: var(--accent);
}

.notebook-btn {
  position: relative;
  flex: none;
  width: 52px;
  height: 64px;
  border-radius: 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  transition: transform var(--dur) var(--ease);
}
.notebook-btn:hover {
  transform: translateY(-3px) rotate(-2deg);
}
.notebook-btn__spine {
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 6px;
  background: var(--accent);
}
.notebook-btn__line {
  position: absolute;
  left: 16px;
  width: 24px;
  height: 1px;
  background: var(--border);
}

@media (max-width: 700px) {
  .guestbook-cue {
    right: 20px;
    gap: var(--space-8);
  }
  .notebook-btn {
    width: 48px;
    height: 58px;
  }
  .guestbook-cue__note {
    font-size: 1.05rem;
  }
}

/* Below this the note cannot stay on one line without running off the card,
   and a wrapped handwritten scrawl above the corner reads as a mistake. The
   notebook keeps its accessible name, so nothing is lost but the flourish. */
@media (max-width: 460px) {
  .guestbook-cue__note {
    display: none;
  }
}

/* --- file tree ----------------------------------------------------------- */

.tree {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  min-width: 0;
}

.tree__row {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  padding: 6px 8px;
  margin-inline: -8px;
  border-radius: var(--radius-xs);
  min-width: 0;
}
.tree__row--interactive {
  transition: background-color var(--dur-fast) var(--ease);
}
.tree__row--interactive:hover,
.tree__row[aria-current="true"] {
  background: var(--surface-alt);
}

.tree__prefix {
  flex: none;
  color: var(--text-muted);
  white-space: pre;
}

.tree__label {
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tree__row--nested .tree__label {
  color: var(--text-secondary);
}

/* 8-bit icons: keep the pixel grid crisp at any zoom */
.pixel-icon {
  flex: none;
  width: 16px;
  height: 16px;
  shape-rendering: crispEdges;
}
.pixel-icon--folder {
  color: var(--accent);
}
.pixel-icon--file {
  color: var(--text-muted);
}

/* --- slideshow ----------------------------------------------------------- */

.slideshow {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  flex: none;
  width: 380px;
}

.slideshow__frame {
  position: relative;
  aspect-ratio: 38 / 25;
  border-radius: var(--radius-md);
  background: var(--surface-alt);
  overflow: hidden;
}
.slideshow__slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease);
}
.slideshow__slide[data-active] {
  opacity: 1;
}
.slideshow__caption {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  padding: var(--space-12);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
  text-align: center;
}

.slideshow__dots {
  display: flex;
  gap: 6px;
}
.slideshow__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--border);
}
.slideshow__dot[data-active] {
  background: var(--accent);
}

.tile__split {
  display: flex;
  gap: var(--space-40);
  align-items: flex-start;
}

@media (max-width: 900px) {
  .tile__split {
    flex-direction: column;
    gap: var(--space-24);
  }
  .slideshow {
    width: 100%;
  }
}

/* --- tags ---------------------------------------------------------------- */

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding-top: var(--space-4);
}

.tag {
  padding: 3px 8px;
  border-radius: var(--radius-xs);
  background: var(--surface-alt);
  border: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  border: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  transition: background-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease);
}
.chip[aria-pressed="true"],
.chip--active {
  background: var(--text-primary);
  border-color: var(--text-primary);
  color: var(--bg);
}

/* Colour key: matches that mode's route colour on the globe. */
.chip__swatch {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
}

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

/* --- timeline (experience / education) ----------------------------------- */

.timeline {
  display: flex;
  flex-direction: column;
  gap: var(--space-28, 28px);
}

.timeline__entry {
  display: flex;
  gap: var(--space-40);
  align-items: flex-start;
}

.timeline__date {
  flex: none;
  width: 150px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
  white-space: pre-line;
}

.timeline__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  min-width: 0;
}

.timeline__meta {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  flex-wrap: wrap;
  color: var(--text-secondary);
  font-size: var(--text-base);
}
.timeline__meta .sep {
  color: var(--text-muted);
}
.timeline__meta .place {
  color: var(--text-muted);
  font-size: var(--text-md);
}

@media (max-width: 700px) {
  .timeline__entry {
    flex-direction: column;
    gap: var(--space-8);
  }
  .timeline__date {
    width: auto;
    white-space: normal;
  }
}

/* Education stacks its degrees and separates them with a hairline */
.degrees {
  display: flex;
  flex-direction: column;
  gap: var(--space-24);
}
.degrees__entry {
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.degrees__entry + .degrees__entry {
  padding-top: var(--space-24);
  border-top: 1px solid var(--border);
}

/* --- contact ------------------------------------------------------------- */

.contact-links {
  display: flex;
  flex-direction: column;
  gap: var(--space-16);
}
.contact-links a {
  display: flex;
  align-items: center;
  gap: var(--space-12);
  color: var(--text-primary);
}
.contact-links a:hover .label {
  color: var(--accent);
}
.contact-links .glyph {
  flex: none;
  width: 24px;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--accent);
}
.contact-links .label {
  transition: color var(--dur-fast) var(--ease);
}

/* --- globe (home tile preview) ------------------------------------------- */

/* <model-viewer> is a custom element; it renders its own canvas and does not
   take fill/stroke styling, so this is sizing and background only. */
.globe-preview {
  flex: 1;
  display: block;
  width: 100%;
  /* Unlike the SVG it replaces, model-viewer has no intrinsic size — the tile
     is square at desktop (.tile--map, aspect-ratio: 1) so flex: 1 is enough
     there, but at <=1024px .tile--map drops to aspect-ratio: auto and a
     column-flex child with no basis can collapse to zero height. */
  min-height: 220px;
  background: transparent;
  --poster-color: transparent;
}

/* Credit for the 3D model — see assets/low_poly_planet_earth/license.txt.
   An info button rather than always-visible text, since the model tile is
   otherwise unlabelled by anything but its own shape. */
.tile__info-wrap {
  position: absolute;
  right: var(--space-16);
  bottom: var(--space-16);
  z-index: 1;
}
.tile__info {
  all: unset;
  box-sizing: border-box;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-style: italic;
  cursor: help;
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.tile__info:hover,
.tile__info:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
}
.tile__info-panel {
  position: absolute;
  right: 0;
  bottom: calc(100% + var(--space-12));
  width: 200px;
  padding: var(--space-12);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--text-secondary);
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.tile__info-panel strong {
  color: var(--text-primary);
}
.tile__info-wrap:hover .tile__info-panel,
.tile__info-wrap:focus-within .tile__info-panel,
.tile__info-wrap.is-open .tile__info-panel {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

/* --- loading / empty states ---------------------------------------------- */

.skeleton {
  background: linear-gradient(
    90deg,
    var(--surface-alt) 25%,
    var(--border) 50%,
    var(--surface-alt) 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.4s linear infinite;
  border-radius: var(--radius-xs);
  color: transparent;
}
@keyframes shimmer {
  to {
    background-position: -200% 0;
  }
}

.notice {
  padding: var(--space-12) var(--space-16);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
