/* panels.css — channel detail panels and the folder overlay.
 *
 * Grounded in two console-UI reference renders held in the sibling repo, not
 * invented:
 *   the boot-notice render   — rounded panel, soft bevel, and a wide pill bar
 *                              across the bottom carrying the action.
 *   the handheld list render — rows are rounded pills with a circular badge
 *                              OUTSIDE the row, and a pale gradient on the
 *                              active one.
 */

.scrim {
  position: fixed; inset: 0; z-index: 990;
  background: var(--scrim);
  /* No backdrop-filter. A full-viewport blur has to be recomputed on every
     frame the panel scales over it, which is the single most expensive thing
     that was happening during the open. The scrim is opaque enough without it. */
  animation: fade var(--d-mid) var(--ease) both;
}
.scrim[hidden] { display: none; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

.panel {
  position: fixed; z-index: 1000;
  --panel-rule: 3px;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: min(760px, calc(100vw - 32px));
  max-height: min(86vh, 780px);
  display: flex; flex-direction: column;
  background: var(--tile);
  border: 0;
  border-radius: 10px;
  box-shadow: 0 0 0 var(--panel-rule) var(--ink), var(--shadow-panel);
  overflow: hidden;
  /* NO ANIMATION HERE. panels.js owns the open, start to finish.
     This used to carry `animation: panelIn ... both`, disarmed by
     `.panel--zoom { animation: none !important }` while the scripted FLIP ran.
     Two authors of the same properties, and the class arrived too late at one
     end and was removed too early at the other: when the zoom finished and the
     class came off, `animation: none` lifted and the keyframe re-armed, so the
     panel settled into place and then flashed and re-scaled from .96. That was
     the reported flicker, and it is why there is nothing to disarm now. */
}
.panel[hidden] { display: none; }
/* Purely a state marker now — it carries no animation of its own. Kept because
   the suites and the close path both ask whether a zoom is in flight. */
.panel--zoom { will-change: transform, opacity; }

/* ── header ───────────────────────────────────────────────────────────────
 * The icon lives in a circular badge rather than sitting flat beside the text.
 * That badge is what makes the header read as console chrome instead of a
 * document heading. */
.panel__bar {
  flex: none;
  display: flex; align-items: center; gap: 14px;
  padding: 13px 18px;
  border-bottom: 0;
  background: var(--ink);
  color: var(--tile);
}
.panel__badge {
  flex: none;
  width: 46px; height: 46px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: #fff;
  background: var(--badge-tint, var(--sel-deep));
  box-shadow: 0 0 0 3px var(--ink);
}
.panel__badge .ico { width: 24px; height: 24px; stroke-width: 2; }

.panel__bar h2 {
  margin: 0; flex: 1 1 auto;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  font-family: var(--font-pix);
  font-size: 19px; letter-spacing: .08em; text-transform: uppercase;
}

.panel__body {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 22px 24px 26px;
  scrollbar-width: thin;
  scrollbar-color: var(--tile-edge) transparent;
}
.panel__body::-webkit-scrollbar { width: 10px; }
.panel__body::-webkit-scrollbar-thumb {
  background: var(--tile-edge); border-radius: var(--r-pill);
  border: 3px solid var(--tile);
}

/* ── bottom action bar ────────────────────────────────────────────────────
 * Straight from the boot-notice render: a wide rounded bar across the foot
 * carrying the action. It also replaces the corner X — closing was the one
 * thing with no visible affordance, and an X has no console equivalent. */
.panel__foot {
  flex: none;
  display: flex; align-items: center; gap: 10px;
  padding: 14px 18px 16px;
  border-top: 1px solid var(--rule);
  background: linear-gradient(180deg, var(--tile) 0%, var(--tile-2) 100%);
}
.panel__back {
  flex: 1 1 auto;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 46px; padding: 0 22px;
  background: var(--ground);
  border: 1px solid var(--tile-edge);
  border-radius: var(--r-pill);
  box-shadow: var(--bevel);
  font: inherit; font-weight: 800; color: var(--ink);
  cursor: pointer;
  position: relative;
  transition: transform var(--d-fast) var(--ease), background var(--d-fast) var(--ease);
}
.panel__back::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: var(--shadow-lift);
  opacity: 0; pointer-events: none;
  transition: opacity var(--d-fast) var(--ease);
}
.panel__back:hover { transform: translateY(-1px); background: var(--tile-2); }
.panel__back:hover::after { opacity: 1; }
.panel__back .ico { width: 19px; height: 19px; stroke-width: 2.2; }
.panel__foot .btn { flex: 0 0 auto; min-height: 46px; }

/* ── prose ───────────────────────────────────────────────────────────── */
.prose { max-width: 66ch; }
/* `.prose p { margin: 0 }` is specificity (0,1,1) and was beating
   `.prose > * + *` at (0,1,0), so every paragraph gap collapsed. Reset the
   children first, then space them — same specificity, later rule wins. */
.prose > * { margin: 0; }
.prose > * + * { margin-top: 1em; }
.prose .lead { font-size: var(--fs-lead); color: var(--ink); font-weight: 500; }
.prose h3 {
  margin: 1.7em 0 0;
  font-size: var(--fs-h3); font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-2);
}
.prose code {
  font-family: var(--font-pix); font-size: 14px;   /* integer: .92em landed on 13.8 */
  background: var(--ground); padding: 1px 5px; border-radius: 4px;
}
/* :not(.btn) matters. `.prose a` is specificity (0,1,1) and was beating
   `.btn--primary` at (0,1,0), overwriting the pill's dark ink with a light cyan
   on a light cyan ground. Same trap as the .prose p margin bug. */
.prose a:not(.btn) { color: var(--sel-deep); text-underline-offset: 3px; }
.prose a:not(.btn):hover { color: var(--ink); }

.beats { margin: 0; padding-left: 1.15em; display: grid; gap: .6em; }
.beats li { padding-left: .15em; }

/* ── evidence ─────────────────────────────────────────────────────────────
 * The result as a number, and the screenshots. Both are optional in the data
 * and render nothing at all when absent — no heading, no empty frame, no
 * placeholder. A panel with no evidence looks exactly as it did before. */
.metric {
  display: flex; align-items: baseline; gap: 12px;
  padding: 12px 16px;
  background: var(--tile-2);
  border: 1px solid var(--tile-edge);
  border-left: 3px solid var(--sel-deep);
  border-radius: var(--r-sm);
}
.metric__value {
  font-family: var(--font-pix);
  font-size: 22px; line-height: 1;
  color: var(--sel-deep);
}
.metric__label { font-size: var(--fs-small); color: var(--ink-2); }

.shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 14px;
}
.shot { margin: 0; display: flex; flex-direction: column; gap: 6px; }
.shot__open {
  display: block; padding: 0; width: 100%;
  background: var(--tile-2);
  border: 1px solid var(--tile-edge);
  border-radius: var(--r-sm);
  overflow: hidden; cursor: zoom-in;
  transition: transform var(--d-fast) var(--ease);
}
.shot__open:hover,
.shot__open:focus-visible { transform: translateY(-2px); }
/* aspect-ratio + object-fit so a mixed bag of capture sizes still tiles evenly,
   and the reserved box stops the panel reflowing as lazy images arrive */
.shot__open img {
  display: block; width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover; object-position: top left;
}
.shot figcaption { font-size: var(--fs-small); color: var(--ink-2); line-height: 1.4; }

/* recency, which was in the data and rendered nowhere */
.stamp {
  font-family: var(--font-pix);
  font-size: var(--fs-micro);
  color: var(--ink-3);
  letter-spacing: .06em;
}

/* ── lightbox ─────────────────────────────────────────────────────────────
 * A sibling of the panels, not a child, so the panel's focus trap and this one
 * never argue about who owns Tab. */
.lightbox {
  position: fixed; inset: 0; z-index: 2000;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 18px;
  padding: clamp(16px, 4vw, 48px);
  background: rgb(6 9 12 / .92);
}
.lightbox[hidden] { display: none; }
.lightbox__figure { margin: 0; display: flex; flex-direction: column; gap: 12px; min-height: 0; }
.lightbox__img {
  max-width: 100%; max-height: 76vh;
  object-fit: contain;
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-panel);
  background: #fff;
}
.lightbox__cap {
  max-width: 70ch; text-align: center;
  font-size: var(--fs-small); line-height: 1.5;
  color: #d8dee6;
}
.lightbox__close {
  padding: 10px 22px;
  font: inherit; font-weight: 800;
  color: var(--sel-ink); background: var(--sel);
  border: 0; border-radius: var(--r-pill);
  cursor: pointer;
}

.facts { margin: 0; display: grid; gap: .55em; }
.facts dt { font-weight: 800; }
.facts dd { margin: 0; color: var(--ink-2); }

.skills {
  display: grid; gap: 18px 26px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.skills section > h3 { margin-top: 0; }
.skills ul { margin: .5em 0 0; padding-left: 1.1em; display: grid; gap: .25em; }
.skills li { color: var(--ink-2); font-size: var(--fs-small); }

.cta-row { display: flex; flex-wrap: wrap; gap: 10px; }
.btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 17px;
  background: var(--tile);
  border: 1px solid var(--tile-edge);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-tile);
  font-weight: 500; text-decoration: none; color: var(--ink);
  cursor: pointer; position: relative;
  transition: transform var(--d-fast) var(--ease);
}
.btn::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: var(--shadow-lift);
  opacity: 0; pointer-events: none;
  transition: opacity var(--d-fast) var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn:hover::after { opacity: 1; }
.btn--primary { background: var(--sel); border-color: var(--sel); color: var(--sel-ink); font-weight: 800; }

.links { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.links a {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 12px;
  border-radius: var(--r-sm);
  text-decoration: none;
  color: var(--ink);
  transition: background var(--d-fast) var(--ease);
}
.links a:hover { background: var(--ground); }
.links .ico { color: var(--ink-2); }

.address {
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
  width: 100%; padding: 15px 18px;
  background: var(--ground);
  border: 1px dashed var(--tile-edge);
  border-radius: var(--r-sm);
  font: inherit; color: inherit; text-align: left;
  cursor: pointer;
  transition: border-color var(--d-fast) var(--ease), background var(--d-fast) var(--ease);
}
.address:hover { border-color: var(--sel-deep); background: var(--tile-2); }
.address__value { font-family: var(--font-pix); font-size: var(--fs-lead); }
.address__hint  { font-size: var(--fs-micro); color: var(--ink-2); letter-spacing: .08em; text-transform: uppercase; }
.address.is-copied { border-color: var(--ok); border-style: solid; }
.address.is-copied .address__hint { color: var(--ok); }

/* ── settings ────────────────────────────────────────────────────────── */
.setting + .setting { margin-top: 22px; }
.setting__note { margin: 6px 0 0 55px; font-size: var(--fs-small); color: var(--ink-2); }
.switch { display: flex; align-items: center; gap: 13px; cursor: pointer; font-weight: 500; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch__ui {
  flex: none; width: 42px; height: 24px;
  background: var(--ground-edge);
  border-radius: var(--r-pill);
  position: relative;
  transition: background var(--d-fast) var(--ease);
}
.switch__ui::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 18px; height: 18px;
  background: var(--tile); border-radius: 50%;
  box-shadow: 0 1px 3px rgb(0 0 0 / .3);
  transition: transform var(--d-fast) var(--ease);
}
.switch input:checked + .switch__ui { background: var(--sel-deep); }
.switch input:checked + .switch__ui::after { transform: translateX(18px); }
.switch input:focus-visible + .switch__ui { outline: 3px solid var(--focus-core); outline-offset: 2px; box-shadow: 0 0 0 5px var(--focus-halo); }

/* ── project panel ───────────────────────────────────────────────────── */
.meta { display: flex; flex-wrap: wrap; gap: 7px; margin: 0; padding: 0; list-style: none; }
.meta li {
  font-family: var(--font-pix); font-size: var(--fs-micro);
  padding: 4px 9px;
  background: var(--ground);
  border: 1px solid var(--tile-edge);
  border-radius: var(--r-pill);
  color: var(--ink-2);
}
.note {
  margin: 0; padding: 11px 14px;
  background: var(--ground);
  border-left: 3px solid var(--warn);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  font-size: var(--fs-small); color: var(--ink-2);
}


@media (max-width: 600px) {
  /* Full screen, and transform:none rather than the desktop centring. panelZoom
     READS this resting transform instead of assuming translate(-50%, -50%), so
     the phone panel no longer animates from half a viewport away. The
     phone-only @keyframes panelIn that used to live here went with the keyframe
     it overrode. */
  .panel { width: 100vw; max-height: 100vh; height: 100%; border-radius: 0; border: 0; top: 0; left: 0; transform: none; }
  .panel__body { padding: 16px 18px 30px; }
}

@media (prefers-reduced-motion: reduce) {
  .panel, .scrim { animation: none; }
}
:root[data-motion='off'] .panel,
:root[data-motion='off'] .scrim { animation: none; }

@media print {
  /* .pages was the old grid container and has not existed for three commits,
     which is why the home screen has been printing. .stage is the element
     that is actually there. */
  .hud, .dock, .scrim, .boot, .stage, .lightbox, .stars { display: none !important; }
  .panel { position: static; transform: none; max-height: none; box-shadow: none; border: 0; width: auto; }
  .panel[hidden] { display: block !important; }
}

/* the repo slug next to the display title, so the GitHub link is unambiguous */
.panel__slug {
  font-family: var(--font-pix);
  font-size: var(--fs-small);
  font-weight: 400;
  color: var(--ink-3);
  letter-spacing: .02em;
}

/* date on the right of an experience entry */
.facts dt { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.facts__when { font-weight: 400; color: var(--ink-3); font-size: var(--fs-small); font-variant-numeric: tabular-nums; }

/* quiet attribution line — small, last, and not a headline */
.fineprint {
  margin-top: 26px; padding-top: 14px;
  border-top: 1px solid var(--rule);
  font-size: var(--fs-micro); line-height: 1.5; color: var(--ink-3);
}


/* ── grouped card overlay ─────────────────────────────────────────────────
 * PROJECTS spans two folders, so each gets a labelled band. Rows follow
 * the handheld list render: a rounded pill with a CIRCULAR BADGE sitting
 * outside it on the left, and a pale gradient on the active one.
 *
 * Rows rather than an icon grid because the grid had nowhere to put the blurb —
 * which is the part someone scanning thirteen labs actually reads. */
.panel--wide { width: min(900px, calc(100vw - 32px)); }

.group + .group { margin-top: 30px; }
.group__head {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 16px;
  margin-bottom: 14px;
  background: var(--ground);
  border-radius: var(--r-pill);
}
.group__name {
  margin: 0; font-family: var(--font-pix); font-size: 12px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink);
}
.group__n {
  font-family: var(--font-pix); font-size: var(--fs-micro);
  min-width: 22px; height: 22px; padding: 0 7px;
  display: grid; place-items: center;
  background: var(--tile); border: 1px solid var(--tile-edge);
  border-radius: var(--r-pill); color: var(--ink-2);
}
.group__blurb { margin: -6px 0 14px 16px; font-size: var(--fs-small); color: var(--ink-2); }

/* A grid of bordered cards rather than a stack of soft pills — the panel used
   to share no language at all with the wall outside it. Two columns because a
   blurb needs the width; auto-fit so a narrow window collapses to one. */


/* a setting that is a plain button, not a switch — no toggle to indent past */
.setting--action .setting__note { margin-left: 0; }
