/* ==========================================================================
   COMPONENTS
   ========================================================================== */

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

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}

.btn:hover {
  text-decoration: none;
  transform: translateY(-1px);
}

.btn--primary {
  background: var(--color-accent);
  color: #06170e;
}

.btn--primary:hover,
.btn--primary:focus-visible {
  box-shadow: var(--shadow-glow-accent);
}

.btn--ghost {
  background: transparent;
  border-color: var(--color-border-strong);
  color: var(--color-text);
}

.btn--ghost:hover,
.btn--ghost:focus-visible {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

/* ---------- Tags / badges ---------- */

.tag {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--color-text-muted);
  background: var(--color-bg-inset);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  transition: transform var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}

.tag--accent {
  color: var(--color-accent);
  border-color: rgba(74, 222, 128, 0.35);
  background: var(--color-accent-dim);
}

.tag--alert {
  color: var(--color-alert);
  border-color: rgba(245, 166, 35, 0.35);
  background: var(--color-alert-dim);
}

/* Skill badges grow and pick up their panel's theme color on hover —
   green for Security, orange for Dev — reinforcing the two-cluster split. */
.skills-panel--security .tag:hover {
  transform: scale(1.08);
  color: var(--color-accent);
  border-color: rgba(74, 222, 128, 0.5);
  background: var(--color-accent-dim);
}

.skills-panel--dev .tag:hover {
  transform: scale(1.08);
  color: var(--color-alert);
  border-color: rgba(245, 166, 35, 0.5);
  background: var(--color-alert-dim);
}

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

.hero {
  padding-top: var(--space-9);
}

.hero__grid {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: var(--space-8);
  align-items: center;
}

.hero__status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--color-accent);
  padding: var(--space-1) var(--space-3);
  border: 1px solid rgba(74, 222, 128, 0.35);
  border-radius: 999px;
  background: var(--color-accent-dim);
  margin-bottom: var(--space-5);
}

.hero__status .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-accent);
  box-shadow: 0 0 6px var(--color-accent);
}

@media (prefers-reduced-motion: no-preference) {
  .hero__status .dot {
    animation: pulse-dot 2s ease-in-out infinite;
  }
}

.hero__name {
  font-size: var(--fs-3xl);
  letter-spacing: -0.02em;
  margin-bottom: var(--space-4);
}

.hero__tagline {
  font-size: var(--fs-lg);
  color: var(--color-text-muted);
  max-width: 38ch;
  margin-bottom: var(--space-3);
}

.hero__subtagline {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--color-text-faint);
  margin-bottom: var(--space-6);
}

.hero__cta {
  display: flex;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-bottom: var(--space-6);
}

.hero__meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--color-text-faint);
}

.hero__meta strong {
  color: var(--color-text-muted);
  font-weight: 500;
}

/* ---------- Terminal window ---------- */

.terminal-window {
  background: var(--color-bg-inset);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}

.terminal-window__bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  background: var(--color-bg-raised);
  border-bottom: 1px solid var(--color-border);
}

.terminal-window__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
}

.terminal-window__dot--red { background: #f97066; }
.terminal-window__dot--yellow { background: #f5a623; }
.terminal-window__dot--green { background: #4ade80; }

.terminal-window__title {
  margin-inline: auto;
  transform: translateX(-16px);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--color-text-faint);
}

.terminal-window {
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}

/* Themed focus indicator for the whole widget, since the live input inside
   it (below) suppresses its own default ring for a cleaner in-terminal
   look — this keeps a clearly visible focus state, just at the container
   level instead of the input's edges. */
.terminal-window:focus-within {
  border-color: var(--color-accent);
  box-shadow: var(--shadow-glow-accent);
}

.terminal-window__body {
  padding: var(--space-5);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  min-height: 220px;
  max-height: 340px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--color-border-strong) transparent;
}

.terminal-window__body::-webkit-scrollbar {
  width: 6px;
}

.terminal-window__body::-webkit-scrollbar-thumb {
  background: var(--color-border-strong);
  border-radius: 3px;
}

.terminal-line {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.terminal-line__prompt {
  color: var(--color-accent);
  flex-shrink: 0;
}

.terminal-line__output {
  color: var(--color-text-muted);
}

/* "help" output: command name and description as two visually distinct
   columns, so the command doesn't blend into its own description. The row
   itself stays nowrap (default) — only the description column is allowed
   to wrap its own text, via flex:1/min-width:0, so a long description
   drops to a second line *under itself*, not the whole row wrapping and
   stranding the command above an orphaned description line. */
.terminal-line--ref {
  gap: var(--space-3);
  align-items: baseline;
}

.terminal-line__ref-cmd {
  color: var(--color-accent);
  font-weight: 600;
  min-width: 13ch;
  flex-shrink: 0;
}

.terminal-line__ref-desc {
  color: var(--color-text-muted);
  flex: 1;
  min-width: 0;
}

.terminal-line--input {
  align-items: center;
  margin-bottom: 0;
}

.terminal-input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  color: var(--color-text);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  caret-color: var(--color-accent);
}

.terminal-input:focus {
  outline: none; /* see .terminal-window:focus-within above */
}

.terminal-input::placeholder {
  color: var(--color-text-faint);
}

.terminal-cursor {
  display: inline-block;
  width: 0.55em;
  height: 1.1em;
  background: var(--color-accent);
  vertical-align: text-bottom;
  margin-left: 2px;
}

@media (prefers-reduced-motion: no-preference) {
  .terminal-cursor {
    animation: blink 1s steps(1) infinite;
  }
}

/* Idle cursor on the live prompt: visible only while the input is empty
   and unfocused, so the terminal still reads as "alive" before anyone
   interacts with it. Once focused, the input's own native caret takes
   over and this hides. Sits between the prompt and the input in DOM order
   (see terminal.js) so it renders right after "$" rather than after the
   input's full flex-grown width — :has() lets the visibility rule still
   key off the input's state despite the cursor coming before it. */
.terminal-cursor--idle {
  display: none;
}

@media (prefers-reduced-motion: no-preference) {
  .terminal-line--input:has(.terminal-input:placeholder-shown:not(:focus)) .terminal-cursor--idle {
    display: inline-block;
  }
}

/* ---------- About ---------- */

.about__grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-7);
  align-items: start;
}

/* The frame itself grows on hover (width/height, not an internal clip-zoom)
   — .about__grid's first column is "auto"-sized, so a bigger frame reflows
   the grid and genuinely pushes the text column over, rather than just
   zooming the image in place inside a fixed box.

   ease-in-out (not ease-out) + a slower duration so growing AND settling
   back down both feel like a deliberate animation — ease-out alone made
   the return trip read as an abrupt snap.

   Gated to devices that actually have a mouse: touch screens have no real
   "hover", so a tap would otherwise either do nothing or get stuck in the
   grown state until a later unrelated tap — this keeps phones at the base
   size with no dangling hover state.

   Note: this element also carries [data-reveal] (animations.css), which
   sets its own `transition: opacity…, transform…`. Both rules set the same
   shorthand property at equal specificity, and animations.css loads last,
   so it would otherwise silently win and eat the width/height transition
   below entirely (transition doesn't merge across separate rules — only
   one whole list applies). `#about` bumps specificity so this rule wins on
   hover-capable devices, and it re-states the opacity/transform pair too,
   so the scroll-reveal fade-in keeps working alongside the hover-grow. */
.about__photo-frame {
  position: relative;
  width: 180px;
  height: 180px;
}

@media (hover: hover) and (pointer: fine) {
  #about .about__photo-frame {
    transition: opacity var(--dur-slow) var(--ease-out),
                transform var(--dur-slow) var(--ease-out),
                width 450ms var(--ease-in-out),
                height 450ms var(--ease-in-out);
  }

  .about__photo-frame:hover {
    width: 220px;
    height: 220px;
  }
}

.about__photo-clip {
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border-strong);
}

.about__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(15%) contrast(1.05);
}

/* Retro pixel-corner accent, drawn with box-shadow "steps" — no images needed */
.about__photo-frame::before {
  content: "";
  position: absolute;
  top: -8px;
  left: -8px;
  width: 20px;
  height: 20px;
  border-top: 3px solid var(--color-accent);
  border-left: 3px solid var(--color-accent);
}

.about__photo-frame::after {
  content: "";
  position: absolute;
  bottom: -8px;
  right: -8px;
  width: 20px;
  height: 20px;
  border-bottom: 3px solid var(--color-accent);
  border-right: 3px solid var(--color-accent);
}

.about__body p {
  color: var(--color-text-muted);
  margin-bottom: var(--space-4);
  max-width: 65ch;
  transition: color var(--dur-base) var(--ease-out),
              opacity var(--dur-base) var(--ease-out);
}

.about__body p:last-child {
  margin-bottom: 0;
}

/* Same "spotlight" language as the timeline (components.css further down):
   hovering one paragraph brightens it to full text color while the other
   recedes, instead of a literal zoom/scale on running text — scaling body
   copy causes reflow and hurts readability, so this is the readable
   equivalent of the same idea. */
.about__body:has(p:hover) p {
  opacity: 0.6;
}

.about__body:has(p:hover) p:hover {
  opacity: 1;
  color: var(--color-text);
}

/* ---------- Skills ---------- */

.skills-panel {
  background: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}

.skills-panel__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  margin-bottom: var(--space-5);
}

.skills-panel--security .skills-panel__title { color: var(--color-accent); }
.skills-panel--dev .skills-panel__title { color: var(--color-alert); }

.skills-group {
  margin-bottom: var(--space-5);
}

.skills-group:last-child {
  margin-bottom: 0;
}

.skills-group__label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-faint);
  margin-bottom: var(--space-3);
}

.skills-group__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* ---------- Project cards ---------- */

.project-card {
  position: relative;
  background: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  transition: border-color var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out);
}

.project-card:hover {
  border-color: var(--color-border-strong);
  transform: translateY(-2px);
}

.project-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 14px;
  height: 14px;
  border-top: 2px solid var(--color-accent);
  border-left: 2px solid var(--color-accent);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out);
}

.project-card:hover::before {
  opacity: 1;
}

.project-card__kicker {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--color-text-faint);
  margin-bottom: var(--space-2);
}

.project-card__title {
  font-size: var(--fs-md);
  margin-bottom: var(--space-3);
}

.project-card__tech {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.project-card__desc {
  color: var(--color-text-muted);
  font-size: var(--fs-sm);
  margin-bottom: var(--space-5);
}

.project-card__desc li {
  position: relative;
  padding-left: var(--space-4);
  margin-bottom: var(--space-2);
}

.project-card__desc li::before {
  content: ">";
  position: absolute;
  left: 0;
  color: var(--color-accent);
}

.project-card__footer {
  margin-top: auto;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.project-card__link {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.project-card__link--pending {
  color: var(--color-text-faint);
  font-style: normal;
  cursor: default;
}

.project-card__link--pending:hover {
  text-decoration: none;
}

/* ---------- Timeline (Experience & Education) ---------- */

.timeline {
  position: relative;
  padding-left: var(--space-6);
  border-left: 1px solid var(--color-border-strong);
}

.timeline__item {
  position: relative;
  padding-bottom: var(--space-7);
  transform-origin: left center;
  transition: transform var(--dur-base) var(--ease-out),
              opacity var(--dur-base) var(--ease-out);
}

/* Spotlight behavior: hovering one entry grows it (anchored on the
   timeline rail via transform-origin, so the dot stays roughly in place)
   while every *other* entry shrinks and dims slightly. Plain per-item
   hover-grow alone felt repetitive with five near-identical entries —
   this makes the hovered one clearly the focus instead of just "twitching". */
.timeline:has(.timeline__item:hover) .timeline__item {
  transform: scale(0.965);
  opacity: 0.55;
}

/* Higher specificity than the rule above (same prefix + :hover again) so
   the actively-hovered item — which also matches that rule, since it's a
   .timeline__item inside a .timeline that :has() a hovered item — wins
   the cascade instead of getting dimmed by its own hover. */
.timeline:has(.timeline__item:hover) .timeline__item:hover {
  transform: scale(1.035);
  opacity: 1;
}

.timeline__item--education:hover .timeline__title {
  color: var(--color-accent);
}

.timeline__item--experience:hover .timeline__title {
  color: var(--color-alert);
}

.timeline__item:last-child {
  padding-bottom: 0;
}

.timeline__item::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--space-6) - 5px);
  top: 4px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--color-bg);
  border: 2px solid var(--color-accent); /* default: education */
}

.timeline__item--experience::before {
  border-color: var(--color-alert);
}

/* Upcoming (currently just the incoming Master's) stays its own type's
   color — green, since it's education — but pulses gently to flag it as
   "planned, not done yet" without hijacking orange, which now consistently
   means "experience" everywhere else on the timeline. */
@media (prefers-reduced-motion: no-preference) {
  .timeline__item--upcoming::before {
    animation: pulse-dot 2s ease-in-out infinite;
  }
}

.timeline__date {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--color-text-faint);
  margin-bottom: var(--space-2);
}

.timeline__title {
  font-size: var(--fs-md);
  margin-bottom: var(--space-1);
}

.timeline__org {
  color: var(--color-text-muted);
  font-size: var(--fs-sm);
  margin-bottom: var(--space-3);
  transition: color var(--dur-base) var(--ease-out);
}

.timeline__desc li {
  position: relative;
  padding-left: var(--space-4);
  color: var(--color-text-muted);
  font-size: var(--fs-sm);
  margin-bottom: var(--space-1);
  transition: color var(--dur-base) var(--ease-out);
}

.timeline__desc li::before {
  content: "-";
  position: absolute;
  left: 0;
  color: var(--color-text-faint);
}

/* Brighten the secondary text (institution, bullet points) along with the
   title on hover, instead of leaving it muted while only the heading lights
   up — the whole entry should read as "in focus", not just its title. */
.timeline__item:hover .timeline__org,
.timeline__item:hover .timeline__desc li {
  color: var(--color-text);
}

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

.contact-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-4);
}

.contact-card {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5);
  background: var(--color-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  color: var(--color-text);
  transition: border-color var(--dur-base) var(--ease-out);
}

.contact-card:hover,
.contact-card:focus-visible {
  border-color: var(--color-accent);
  text-decoration: none;
}

.contact-card__icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  color: var(--color-accent);
}

.contact-card__label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--color-text-faint);
  margin-bottom: 2px;
}

.contact-card__value {
  font-size: var(--fs-sm);
  word-break: break-word;
}

/* ---------- Language toggle ---------- */

.lang-toggle {
  display: flex;
  align-items: center;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  overflow: hidden;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
}

.lang-toggle button {
  padding: var(--space-1) var(--space-3);
  color: var(--color-text-faint);
}

.lang-toggle button[aria-pressed="true"] {
  background: var(--color-accent-dim);
  color: var(--color-accent);
}

.lang-toggle button:hover {
  color: var(--color-text);
}

/* ---------- Mobile nav toggle icon ---------- */

.nav-toggle {
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  color: var(--color-text);
}

.nav-toggle__bars {
  position: relative;
  width: 16px;
  height: 2px;
  background: currentColor;
}

.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: "";
  position: absolute;
  left: 0;
  width: 16px;
  height: 2px;
  background: currentColor;
}

.nav-toggle__bars::before { top: -5px; }
.nav-toggle__bars::after { top: 5px; }

/* ---------- Easter-egg toast ---------- */

.easter-egg-toast {
  position: fixed;
  bottom: var(--space-6);
  left: 50%;
  transform: translateX(-50%) translateY(12px);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  background: var(--color-bg-raised);
  border: 1px solid var(--color-accent);
  box-shadow: var(--shadow-glow-accent);
  border-radius: var(--radius-md);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  z-index: 100;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out);
}

.easter-egg-toast[data-visible="true"] {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.easter-egg-toast__sprite {
  font-size: 1.25rem;
  line-height: 1;
}

/* ---------- Responsive ---------- */

@media (max-width: 860px) {
  .hero__grid {
    grid-template-columns: 1fr;
  }

  .about__grid {
    grid-template-columns: 1fr;
  }

  .about__photo-frame {
    width: 120px;
    height: 120px;
  }

  .project-grid {
    grid-template-columns: 1fr;
  }
}

/* ---------- Phone-width centering ----------
   Below 560px, headings, badges, buttons, tags and photos center — but
   running prose (About's paragraphs, project bullet points, timeline
   bullet points) stays left-aligned within its own centered block. Fully
   centering multi-line text gives ragged edges on both sides and is
   genuinely harder to read; centering the block it sits in gets the
   "centered" look without that readability cost. */
@media (max-width: 560px) {
  .hero__name {
    font-size: var(--fs-2xl);
  }

  .hero__content {
    text-align: center;
  }

  .hero__status {
    margin-inline: auto;
  }

  .hero__tagline,
  .hero__subtagline {
    margin-inline: auto;
  }

  .hero__cta {
    flex-direction: column;
    align-items: center;
  }

  .hero__cta .btn {
    justify-content: center;
  }

  .hero__meta {
    align-items: center;
  }

  .about__photo-frame {
    margin-inline: auto;
  }

  .skills-panel__title {
    justify-content: center;
  }

  .skills-group__label {
    text-align: center;
  }

  .skills-group__tags {
    justify-content: center;
  }

  .project-card__kicker,
  .project-card__title {
    text-align: center;
  }

  .project-card__tech,
  .project-card__footer {
    justify-content: center;
  }

  /* The rail-and-dot layout only makes sense left-aligned — rather than
     center a design built around a left rail, drop the rail on phones and
     let each entry read as its own centered block instead. */
  .timeline {
    padding-left: 0;
    border-left: none;
  }

  .timeline__item::before {
    display: none;
  }

  .timeline__item {
    text-align: center;
  }

  .timeline__desc {
    text-align: left;
    max-width: 34ch;
    margin-inline: auto;
  }
}
