/* ============================================================================
   Patrick Hartanto — portfolio
   One typeface, hairline rules, and a terminal's ANSI palette (after Monokai
   Pro) where every hue has exactly one job:
     yellow  — measured impact (**highlights** in data.js)
     green   — live / available
     cyan    — things you can click
     accents — each project's own identity color; tags colored by category
   Chrome is uppercase and dim; content is sentence case and bright.
   ========================================================================== */

:root {
  /* Ground */
  --void:     #000000;
  --panel:    #070707;
  --panel-up: #0d0d0d;

  /* Rules */
  --rule:     #1c1c1c;
  --rule-mid: #2a2a2a;
  --rule-hi:  #f0f0f0;

  /* Ink */
  --dim:      #565656;
  --mid:      #8e8e8e;
  --hi:       #f0f0f0;

  /* ANSI palette */
  --c-green:  #a9dc76;
  --c-yellow: #ffd866;
  --c-orange: #fc9867;
  --c-red:    #ff6188;
  --c-purple: #ab9df2;
  --c-cyan:   #78dce8;
  --c-blue:   #82aaff;

  /* Type */
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo,
          Consolas, "Liberation Mono", monospace;

  --fs-micro: 10px;
  --fs-xs:    11px;
  --fs-sm:    12px;
  --fs-md:    13px;
  --fs-lg:    15px;

  --track-wide: 0.14em;
  --track:      0.06em;

  --pad: 26px;
  --rail-w: 372px;
}

/* -- Reset ----------------------------------------------------------------- */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--void);
  color: var(--mid);
  font-family: var(--mono);
  font-size: var(--fs-md);
  font-weight: 400;
  line-height: 1.65;
  font-variant-ligatures: none;
  -webkit-font-smoothing: antialiased;

  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

h1, h2, h3, p, dl, dd, dt, ul, figure { margin: 0; }
ul { padding: 0; list-style: none; }

a { color: inherit; }

::selection { background: var(--hi); color: var(--void); }

:focus-visible {
  outline: 1px solid var(--hi);
  outline-offset: 2px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 8px;
  z-index: 10;
  padding: 8px 14px;
  background: var(--hi);
  color: var(--void);
  text-decoration: none;
  font-size: var(--fs-xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}
.skip:focus { left: 8px; }

/* -- Scrollbars ------------------------------------------------------------ */

.rail, .main { scrollbar-width: thin; scrollbar-color: var(--rule-mid) transparent; }
.rail::-webkit-scrollbar, .main::-webkit-scrollbar { width: 9px; }
.rail::-webkit-scrollbar-track, .main::-webkit-scrollbar-track { background: transparent; }
.rail::-webkit-scrollbar-thumb, .main::-webkit-scrollbar-thumb {
  background: var(--rule-mid);
  border: 3px solid var(--void);
}
.rail::-webkit-scrollbar-thumb:hover, .main::-webkit-scrollbar-thumb:hover { background: #444; }

/* -- Frame ----------------------------------------------------------------- */

.shell {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
}

.rail {
  min-height: 0;
  overflow-y: auto;
  border-right: 1px solid var(--rule);
  background: var(--panel);
}

.main {
  min-height: 0;
  overflow-y: auto;
}

/* -- Rail blocks ----------------------------------------------------------- */

.block {
  padding: var(--pad);
  border-bottom: 1px solid var(--rule);
}
.block--last { border-bottom: 0; padding-bottom: 40px; }

.block-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--hi);
  padding-bottom: 10px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--rule);
}

/* -- Identity -------------------------------------------------------------- */

.monogram {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.15;
  color: var(--hi);
  margin: 0 0 22px;
  white-space: pre;
  overflow: hidden;
  width: max-content;
  max-width: 100%;
}

/* MONOGRAM as one block: gradient through the palette */
.monogram--gradient {
  background: linear-gradient(100deg, var(--c-green) 0%, var(--c-cyan) 45%, var(--c-purple) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* MONOGRAM as one block per letter: solid face, darkened shadow.
   41 columns at 12px is ~295px, inside the 320px rail content box. */
.monogram--letters {
  /* Google's IBM Plex Mono files carry no block characters (U+2580-259F),
     so █ and ░ would fall back to another font while the spaces between
     them stayed Plex. Different advance widths shear the art apart (badly
     on Windows). Every font here has the full block set, so whichever one
     the visitor gets draws spaces and blocks alike. */
  font-family: Menlo, Consolas, "DejaVu Sans Mono", "Liberation Mono",
               "Courier New", monospace;
  font-size: 12px;
  line-height: 1.05;
}
.mono-face { color: var(--c); }
.mono-edge { color: color-mix(in srgb, var(--c) 38%, #000); }

/* MONOGRAM_MOTION = "wave": one 6s color cycle through the letter colors
   (--w1 → --w2 → --w3 → --w2), shadows following in their darkened tone.
   Each character starts the cycle at a point set by its position (--o, ms;
   112.5ms per column, 90ms per row), so the colors travel diagonally left to
   right. Offsets stay under 6000, so every delay is negative: the art is
   mid-wave the moment it appears, never frozen first. */
.monogram--wave .mono-face,
.monogram--wave .mono-edge {
  animation-duration: 6s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-delay: calc((var(--o) - 6000) * 1ms);
}
.monogram--wave .mono-face { animation-name: mono-wave; }
.monogram--wave .mono-edge { animation-name: mono-wave-edge; }
@keyframes mono-wave {
  0%, 100% { color: var(--w1); }
  25%      { color: var(--w2); }
  50%      { color: var(--w3); }
  75%      { color: var(--w2); }
}
@keyframes mono-wave-edge {
  0%, 100% { color: color-mix(in srgb, var(--w1) 38%, #000); }
  25%      { color: color-mix(in srgb, var(--w2) 38%, #000); }
  50%      { color: color-mix(in srgb, var(--w3) 38%, #000); }
  75%      { color: color-mix(in srgb, var(--w2) 38%, #000); }
}

.name {
  font-size: var(--fs-lg);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--hi);
  line-height: 1.35;
}

.rule-label {
  font-size: var(--fs-xs);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--dim);
  margin-top: 4px;
}

.kv {
  margin-top: 20px;
  display: grid;
  grid-template-columns: 62px minmax(0, 1fr);
  gap: 5px 12px;
  font-size: var(--fs-sm);
}
.kv dt {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--dim);
  padding-top: 2px;
}
.kv dd { color: var(--mid); word-break: break-word; }
.kv a { text-decoration: none; border-bottom: 1px solid var(--rule-mid); }
.kv a:hover { color: var(--hi); border-bottom-color: var(--hi); }

/* -- Education ------------------------------------------------------------- */

.edu-school {
  font-size: var(--fs-md);
  color: var(--hi);
  font-weight: 500;
}
.edu-line { font-size: var(--fs-sm); color: var(--mid); }
.edu-meta {
  font-size: var(--fs-xs);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--dim);
  margin-top: 3px;
}

.sublist { margin-top: 18px; }
.sublist-title {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 7px;
}
.sublist li {
  font-size: var(--fs-sm);
  color: var(--mid);
  padding-left: 16px;
  position: relative;
  line-height: 1.55;
  margin-bottom: 3px;
}
.sublist li::before {
  content: "+";
  position: absolute;
  left: 0;
  color: var(--dim);
}

/* -- Highlights (**phrase** in data.js) ------------------------------------ */

mark.hl {
  color: var(--c-yellow);
  background: color-mix(in srgb, var(--c-yellow) 11%, transparent);
  padding: 0 3px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

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

.skillrow { margin-bottom: 15px; }
.skillrow:last-child { margin-bottom: 0; }
.skillrow-title {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 5px;
}
.skillrow-items {
  font-size: var(--fs-sm);
  color: var(--mid);
  line-height: 1.6;
}

/* -- Main pane ------------------------------------------------------------- */

.main-head {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: var(--pad) var(--pad) 16px;
  background: var(--void);
  border-bottom: 1px solid var(--rule);
}

.prompt {
  font-size: var(--fs-lg);
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--hi);
}
.p-user { color: var(--c-green); }
.p-path { color: var(--c-blue); }
.p-dim  { color: var(--dim); }
.p-cmd  { color: var(--hi); }
/* "$ ls -lt" and the cursor travel together; a wrap can only happen before "$". */
.p-tail { white-space: nowrap; }

/* Section switcher: bash brace expansion, ~/{projects,experience}. Braces
   and commas are dim text; each name is a button. Current section bright
   blue like the rest of the path; the others dim until hovered. */
.sec-opt {
  font: inherit;
  letter-spacing: inherit;
  padding: 0;
  color: var(--dim);
  background: none;
  border: 0;
  cursor: pointer;
  transition: color .12s linear;
}
.sec-opt[aria-pressed="true"] { color: var(--c-blue); cursor: default; }
.sec-opt[aria-pressed="false"]:hover {
  color: var(--c-blue);
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}

/* First-load cue: the dim names brighten twice, like phosphor. */
.sec-opt.is-pulsing { animation: sec-glow 1.1s ease-in-out 2; }
@keyframes sec-glow {
  0%, 100% { text-shadow: none; }
  50%      { color: var(--c-blue); text-shadow: 0 0 12px var(--c-blue); }
}

/* Block cursor at the end of the prompt. Sized in em so it tracks the
   prompt's font size; solid while a command is typing, blinking after. */
.caret {
  display: inline-block;
  width: 0.6em;
  height: 1.1em;
  margin-left: 0.35em;
  vertical-align: -0.2em;
  background: var(--c-green);
  box-shadow: 0 0 10px color-mix(in srgb, var(--c-green) 45%, transparent);
  animation: blink 1.1s steps(1) infinite;
}
.prompt[data-typing] .caret { animation: none; opacity: 1; }
@keyframes blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

.cards {
  padding: var(--pad);
  display: flex;
  flex-direction: column;
  gap: 18px;
}

/* Masonry: main.js deals cards into .card-col columns (CARD_LAYOUT). */
.cards--columns {
  flex-direction: row;
  align-items: flex-start;
}
.card-col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

/* Breathing room under the last row of cards. */
.panel { padding-bottom: 18px; }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* -- Cards (projects and experience) ---------------------------------------------------------- */

.card {
  --accent: var(--c-cyan);
  border: 1px solid var(--rule-mid);
  box-shadow: inset 2px 0 0 var(--accent);
  background: var(--panel);
  transition: border-color .14s linear, background-color .14s linear;
}
.card:hover,
.card:focus-within {
  border-color: var(--accent);
  background: var(--panel-up);
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--rule-mid);
  transition: background-color .14s linear, border-color .14s linear;
}
.card:hover > .card-head,
.card:focus-within > .card-head {
  background: var(--accent);
  border-bottom-color: var(--accent);
}

.card-mark {
  color: var(--accent);
  font-size: 0.6em;
  margin-right: 12px;
  vertical-align: 0.2em;
  transition: color .14s linear;
}
.card:hover .card-mark,
.card:focus-within .card-mark { color: var(--void); }

/* Same size as the prompt line, so the page has one heading size. */
.card-name {
  font-size: var(--fs-lg);
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--hi);
  transition: color .14s linear;
}
.card-badge {
  --badge: var(--dim);
  font-size: var(--fs-micro);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--badge);
  border: 1px solid color-mix(in srgb, var(--badge) 45%, transparent);
  padding: 2px 8px;
  white-space: nowrap;
  transition: color .14s linear, border-color .14s linear;
}
.card-badge[data-tone="green"] { --badge: var(--c-green); }
.card-badge[data-tone="cyan"]  { --badge: var(--c-cyan); }
.card-badge[data-state="active"]::before { content: "\25CF\00a0"; font-size: 8px; vertical-align: 1px; }
.card:hover > .card-head .card-name,
.card:focus-within > .card-head .card-name { color: var(--void); }
.card:hover > .card-head .card-badge,
.card:focus-within > .card-head .card-badge {
  color: rgba(0, 0, 0, .7);
  border-color: rgba(0, 0, 0, .35);
}

/* Monospace sets letters wide apart; a little negative tracking and a
   slightly tighter line height make the bullets read as words, not cells. */
.card-body { padding: 18px 20px; letter-spacing: -0.015em; }

.card-tagline {
  font-size: var(--fs-sm);
  color: var(--dim);
  margin-bottom: 15px;
}

/* Card image. A chosen image (data.js `image`) fills a 16:9 frame; a
   README image is shown whole, in a frame that follows its proportions
   (set inline by main.js). Cards without an image have no frame at all. */
.card-media {
  margin: 0 0 16px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--void);
  border: 1px solid var(--rule-mid);
}
.card-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.card-media--readme { background: var(--panel-up); }
.card-media--readme img { object-fit: contain; }
.card-media--enter { animation: media-in .45s ease-out both; }
@keyframes media-in { from { opacity: 0; } }

/* Experience: organization and place on the left, dates on the right. */
.card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 16px;
  margin-bottom: 15px;
}
.card-where { font-size: var(--fs-sm); }
.card-org   { color: var(--hi); font-weight: 500; }
.card-loc   { color: var(--dim); white-space: pre; }
.card-dates {
  font-size: var(--fs-xs);
  letter-spacing: var(--track);
  color: var(--mid);
  white-space: nowrap;
}

.card-notes li {
  font-size: var(--fs-md);
  line-height: 1.6;
  color: var(--mid);
  padding-left: 26px;
  position: relative;
  margin-bottom: 11px;
}
.card-notes li:last-child { margin-bottom: 0; }
.card-notes li::before {
  content: "[+]";
  position: absolute;
  left: 0;
  color: var(--dim);
  font-size: var(--fs-sm);
}

.card-stack {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px dashed var(--rule-mid);
}
.tag {
  --tag: #6e6e6e;
  font-size: var(--fs-micro);
  letter-spacing: var(--track);
  color: var(--tag);
  background: color-mix(in srgb, var(--tag) 7%, transparent);
  border: 1px solid color-mix(in srgb, var(--tag) 38%, transparent);
  padding: 3px 8px;
  white-space: nowrap;
}
.card:hover .tag,
.card:focus-within .tag { border-color: color-mix(in srgb, var(--tag) 65%, transparent); }

.card-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

.btn {
  flex: 1 1 auto;
  min-width: 168px;
  display: block;
  padding: 10px 14px;
  border: 1px solid var(--rule-mid);
  color: var(--mid);
  background: none;
  font-family: var(--mono);
  font-size: var(--fs-xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  transition: border-color .12s linear, color .12s linear, background-color .12s linear;
}
.btn:hover {
  border-color: var(--accent, var(--hi));
  background: var(--accent, var(--hi));
  color: var(--void);
}
.btn[aria-disabled="true"] {
  color: #3d3d3d;
  border-style: dashed;
  border-color: var(--rule);
  cursor: default;
  pointer-events: none;
}

/* -- Status bar ------------------------------------------------------------ */

.statusbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 0 var(--pad);
  min-height: 46px;
  border-top: 1px solid var(--rule);
  background: var(--panel);
}

.statusbar-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 22px;
}
.statusbar-links a {
  font-size: var(--fs-xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--dim);
  text-decoration: none;
  transition: color .12s linear;
}
.statusbar-links a::before { content: "\2197\00a0"; }
.statusbar-links a:hover { color: var(--c-cyan); }
.statusbar-links a.is-primary {
  color: var(--void);
  background: var(--c-cyan);
  padding: 5px 11px;
  font-weight: 500;
}
.statusbar-links a.is-primary:hover { background: var(--hi); color: var(--void); }

.statusbar-meta {
  font-size: var(--fs-micro);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: #3a3a3a;
  white-space: nowrap;
}

/* -- Load sequence --------------------------------------------------------- */

.rise {
  opacity: 0;
  transform: translateY(7px);
  animation: rise .38s cubic-bezier(.2, .7, .3, 1) forwards;
}
@keyframes rise { to { opacity: 1; transform: none; } }

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

@media (max-width: 1080px) {
  :root { --rail-w: 320px; --pad: 20px; }
  .monogram--letters { font-size: 10.5px; }
}

@media (max-width: 880px) {
  :root { --pad: 20px; }

  .monogram--letters { font-size: 12px; }

  body { height: auto; overflow: visible; display: block; }

  /* The rail dissolves so its blocks can sit around the main pane:
     identity first, then projects/experience, then education and skills. */
  .shell { display: flex; flex-direction: column; }
  .rail { display: contents; }
  .rail > .block { background: var(--panel); }
  .block--identity  { order: 1; }
  .main             { order: 2; overflow: visible; border-bottom: 1px solid var(--rule); }
  .block--education { order: 3; }
  .block--skills    { order: 4; }

  .main-head { position: static; }

  .card-notes li { font-size: var(--fs-sm); }
  .card-head { padding: 12px 16px; }

  /* Fit the prompt on one line. Its longest form,
     "pah@bc:~/{projects,experience}$ ls -lt", is 39 characters at 0.6em
     each plus the ~1em cursor — about 24.5em — so size the font to width / 25,
     never larger than on desktop. With more sections later it wraps before
     "$ ls" instead. */
  .prompt { font-size: min(var(--fs-lg), calc((100vw - 2 * var(--pad)) / 25)); }

  .btn { min-width: 0; }

  .statusbar {
    position: static;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
    padding: 20px var(--pad) 26px;
  }
  .statusbar-links { gap: 16px 20px; }
}

@media (max-width: 420px) {
  .monogram { font-size: 11px; }
  .monogram--letters { font-size: 10px; }
  .kv { grid-template-columns: 56px minmax(0, 1fr); }
}

/* -- Reduced motion -------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .rise { opacity: 1; transform: none; }
  .monogram--wave .mono-face,
  .monogram--wave .mono-edge { animation: none; }
  .caret { opacity: 1; }
}

/* -- Print ----------------------------------------------------------------- */

@media print {
  body { height: auto; overflow: visible; display: block; background: #fff; color: #000; }
  .shell { display: block; }
  .rail, .main { overflow: visible; border: 0; background: #fff; }
  .card { break-inside: avoid; border-color: #bbb; background: #fff; }
  .card-name, .name, .block-title { color: #000; }
  .btn, .skip, .prompt { display: none; }
  .panel[hidden] { display: block; }
  mark.hl { color: #000; background: #fff3b0; }
  .monogram--gradient { -webkit-text-fill-color: #000; background: none; }
  .mono-face { color: #000; }
  .mono-edge { color: #aaa; }
}
