/* grapholio — tokens, graph, cards, lightbox */

@font-face{
  font-family:'Instrument Sans';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('./fonts/instrument-sans-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:'Instrument Sans';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('./fonts/instrument-sans-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

:root{
  --bg:#f4f2ee;
  --ink:#1a1a1a;
  --ink-dim:#6b6b6b;
  --font:'Instrument Sans',system-ui,-apple-system,'Segoe UI',sans-serif;
  --card-bg:#fff;
  --card-radius:14px;
  --card-shadow:0 8px 30px rgba(0,0,0,.08);
  --dur:460ms;
  /* P6c: the width of the crystal seat in the project title's left gutter. The title
     reserves this plus a 20px gap as padding, so the body the solids layer paints there
     can never reach the type. */
  --gem:86px;
  --ease:cubic-bezier(.4,.01,.2,1);   /* soft at both ends, to match tweenCam */
  /* P8: one source for the panel's width — the stylesheet still owns the number, and
     render.js still reads the element's offsetWidth rather than restating it. The veil's
     ramp hangs off the panel's left edge by --veil and is the ONLY thing between the
     graph and the page: no border, no radius, no shadow. */
  --panel-w:min(60vw,1100px);
  --veil:220px;
}

/* The page ground, tinted by the open room. --tint is written by render.js on open and
   removed on close; the fallback is the plain field, so nothing depends on it.
   Mixed in OKLCH, not sRGB: at a flat 12% the sRGB mix moved the field by (+2,-10,-9)
   at hue 18 and by (-22,-4,-1) at hue 205, so the teal rooms washed visibly harder than
   the pink ones (VERIFY-P6 defect 8). A perceptual space evens that out at the one
   strength the user chose. The sRGB line is the step down for engines that mix but do not
   know oklch; the @supports is the step down for engines that do not mix at all. */
:root{
  --field:color-mix(in srgb,var(--bg) 88%,var(--tint,var(--bg)) 12%);
  --field:color-mix(in oklch,var(--bg) 88%,var(--tint,var(--bg)) 12%);
}
@supports not (background:color-mix(in srgb,red 50%,transparent)){
  :root{--field:var(--bg)}
}

*{box-sizing:border-box}
html,body{height:100%}
html{overflow:hidden}
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font);
  font-size:15px;
  line-height:1.45;
  overflow:hidden;
  overscroll-behavior:none;
  -webkit-text-size-adjust:100%;
}
body.locked{overflow:hidden}

/* ---------- canvas ---------- */

/* SPEC §10: the WebGL field sits behind the SVG and never takes a pointer. The SVG keeps
   every hit target, tab stop and card. */
#solids{
  position:fixed;
  inset:0;
  width:100%;
  height:100%;
  display:block;
  z-index:0;
  pointer-events:none;
}

/* The header crystal's own canvas: above the panel's ground (z-index 15), sized and
   placed by solids.js, hidden until there is a seat to draw. */
#seat{
  position:fixed;
  z-index:17;
  display:none;
  pointer-events:none;
}

/* The tether's own layer: over the panel plate (15), under the header crystal (17), so
   the run from the circle in the graph to the same circle in the title is never cut off
   at the panel's edge. Screen-space: 1 user unit = 1 px. */
#tetherlay{
  position:fixed;
  inset:0;
  width:100%;
  height:100%;
  z-index:16;
  pointer-events:none;
  overflow:visible;
}

#g{
  z-index:1;
  position:fixed;
  inset:0;
  width:100%;
  height:100%;
  display:block;
  touch-action:none;
  cursor:grab;
  --k:1;
}
#g.grabbing{cursor:grabbing}

.edge{
  stroke-width:1.25;
  vector-effect:non-scaling-stroke;
  opacity:.55;
  transition:opacity var(--dur) var(--ease);
}
.edge.dashed{stroke-dasharray:5 5;opacity:.42}
/* P7 hub spokes: lighter than a parent edge, no dash, neutral — the ring's hues stay on
   the bodies. Under every other edge (render.js inserts them first). */
.edge.spoke{stroke:var(--ink-dim);stroke-width:1;opacity:.2}

.node{cursor:pointer;outline:none}
.node.dragging{cursor:grabbing}
.node .hit{fill:transparent;stroke:none}

/* SPEC §10: once the solids are on, the SVG circle becomes a pure hit target — same
   radius, same tabindex, same events, no paint. The one exception is the keyboard focus
   ring: the solid's +8% scale and rim lift are a hover affordance, not an accessible
   focus indicator, so the ring stays (see BUILD-REPORT Phase 2).
   render.js paints the dot through an inline `style.fill`/`style.stroke`, which no
   selector can outrank — hence `!important` here rather than a change in render.js. */
body.solids .node .dot{fill:none !important;stroke:none !important}
body.solids .node:focus-visible .dot{stroke:var(--ink) !important;stroke-opacity:1;stroke-width:2}
.node .dot{
  stroke-width:1;
  stroke-opacity:.35;
  transition:transform 280ms var(--ease),filter 280ms var(--ease);
  transform-box:fill-box;
  transform-origin:center;
}
.node:hover .dot,.node:focus-visible .dot{transform:scale(1.08)}
.node:focus-visible .dot{
  stroke:var(--ink);
  stroke-opacity:1;
  stroke-width:2;
  paint-order:stroke;
}
.node.open .dot{stroke-opacity:.9;stroke-width:2}
.node.carded .dot{stroke-opacity:.9;stroke-width:2}

.lbl{
  font-family:var(--font);
  font-size:13px;
  font-weight:500;
  letter-spacing:.01em;
  fill:var(--ink-dim);
  pointer-events:none;
  transition:fill 280ms var(--ease);
}
.node:hover .lbl,.node:focus-visible .lbl,.node.open .lbl{fill:var(--ink)}
.node:not(.leaf) .lbl{font-weight:600}
.chip{
  font-family:var(--font);
  font-size:10.5px;
  letter-spacing:.06em;
  text-transform:uppercase;
  fill:var(--ink-dim);
  cursor:pointer;
}
.chip:hover{fill:var(--ink)}

.node.root .lbl{font-size:15px;font-weight:600}

.node.enter .dot,.node.enter .lbl,.node.enter .chip{
  animation:pop 640ms var(--ease) both;
  animation-delay:inherit;
}
.node.exit{
  opacity:0;
  transition:opacity 380ms var(--ease);
  pointer-events:none;
}
/* P8 veil (replaces the P6c eclipse): with a project open the camera still docks the graph
   into the strip on the left, but whatever reaches past that strip is no longer faded out
   node by node — the panel's own ground covers it, ramping in over --veil so a stone
   dissolves into the page instead of blinking off at an invisible line. Nothing here
   touches opacity: these nodes are hidden by the plate above them. What is still required
   is that they are OUT OF REACH — a node under an opaque overlay that answers a click, or
   holds a Tab stop, is the defect the eclipse was written for. render.js owns the set. */
.node.veiled{pointer-events:none}
/* A body dissolves into the ramp; type does not — a label whose tail crosses the plate
   reads as truncated, not as covered. The node stays live and reachable, the name goes. */
.node.veil-label .labelG,
.node.veil-label .chip{opacity:0;transition:opacity 380ms var(--ease)}
.node .labelG,.node .chip{transition:opacity 380ms var(--ease)}
@keyframes pop{
  from{opacity:0;transform:scale(.72)}
  to{opacity:1;transform:scale(1)}
}

/* ---------- breadcrumb ---------- */

.crumb-strip{
  position:fixed;
  top:max(18px,env(safe-area-inset-top));
  left:max(20px,env(safe-area-inset-left));
  z-index:4;
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:.35em;
  max-width:min(70vw,720px);
  font-size:13px;
  letter-spacing:.01em;
  /* The strip floats over the canvas and a node can drift under it. A soft plate keeps
     the path readable without introducing chrome. */
  padding:5px 11px;
  margin:-5px -11px;
  border-radius:9px;
  background:color-mix(in srgb,var(--bg) 84%,transparent);
  backdrop-filter:blur(3px);
}
@supports not (background:color-mix(in srgb,red 50%,transparent)){
  .crumb-strip{background:rgba(244,242,238,.84)}
}
.crumb{
  appearance:none;
  border:0;
  background:none;
  padding:2px 0;
  margin:0;
  font:inherit;
  font-weight:500;
  color:var(--hue-col,var(--ink));
  cursor:pointer;
  border-bottom:1px solid transparent;
}
.crumb:hover,.crumb:focus-visible{border-bottom-color:currentColor}
.crumb.home{
  color:var(--ink);
  font-weight:600;
  letter-spacing:.005em;
}
/* The credentials sit beside the name, quieter but never abbreviated away. */
.crumb.home .post{
  margin-left:.5em;
  font-weight:500;
  font-size:.93em;
  letter-spacing:.045em;
  color:var(--ink-dim);
}
.sep{color:var(--ink-dim);opacity:.6}

/* Visually hidden but still announced: the arrival field carries no copy (SPEC §1),
   so the only description of what the circles do lives here for screen readers. */
.sr-only{
  position:absolute !important;
  width:1px;height:1px;
  margin:-1px;padding:0;border:0;
  clip:rect(0 0 0 0);
  clip-path:inset(50%);
  overflow:hidden;
  white-space:nowrap;
}

.hint{
  position:fixed;
  left:50%;
  bottom:max(26px,env(safe-area-inset-bottom));
  transform:translateX(-50%);
  margin:0;
  z-index:4;
  color:var(--ink-dim);
  font-size:12.5px;
  letter-spacing:.05em;
  pointer-events:none;
  opacity:.75;
}

/* ---------- the project panel ---------- */

/* Boundless still: no card, no border, no radius, no shadow. The type and the images sit
   directly on the tinted field and scroll with the column. What P8 adds is that the field
   travels WITH the panel — the aside carries the page ground itself, and ::before ramps
   that ground up from nothing over --veil to its left. So the panel is a layer over the
   graph rather than a hole cut in it: the graph runs on underneath, unbroken, and fades
   into the page as it goes under. The ramp is pointer-transparent; the opaque box is not,
   and render.js marks whatever sits under it `veiled` (inert). */
aside.panel{
  position:fixed;
  top:0;right:0;
  z-index:15;
  width:var(--panel-w);
  background:var(--field);
  height:100dvh;
  overflow-y:auto;
  overscroll-behavior:contain;
  padding:clamp(28px,5vh,64px) clamp(28px,4vw,72px) 20vh;
  opacity:0;
  transform:translateX(16px);
  transition:opacity 520ms var(--ease),transform 520ms var(--ease),
             background 900ms var(--ease);
}
/* Fixed, not absolute: the aside is its own scroll region, and an absolutely positioned
   ramp would scroll away with the content. Five stops, not two — a linear alpha ramp reads
   as a visible band edge against a busy field, an eased one does not. */
aside.panel::before{
  content:'';
  position:fixed;
  top:0;bottom:0;
  right:var(--panel-w);
  width:var(--veil);
  pointer-events:none;
  background:linear-gradient(to right,
    transparent 0%,
    color-mix(in srgb,var(--field) 12%,transparent) 34%,
    color-mix(in srgb,var(--field) 44%,transparent) 60%,
    color-mix(in srgb,var(--field) 82%,transparent) 82%,
    var(--field) 100%);
}
aside.panel.in{opacity:1;transform:none}
aside.panel[hidden]{display:none}
/* The page and the panel paint the same ground (--field, tokens above), so the ramp has
   nothing to blend TO but the page itself. */
body{
  background:var(--field);
  transition:background 900ms var(--ease);   /* the tint lands with the camera */
}
body.panel .crumb-strip{background:none;backdrop-filter:none}

.panel-back{display:none}
/* Fixed, not absolute: the aside is its own scroll region, and an absolutely positioned
   × rides the content out of the viewport (VERIFY-P6 defect 5 measured it at top:-1779px).
   The panel is flush to the right edge, so the viewport's right inset is the panel's. */
.panel-close{
  position:fixed;
  top:clamp(20px,3.4vh,40px);
  right:clamp(20px,3vw,44px);
  width:36px;height:36px;
  display:flex;align-items:center;justify-content:center;
  border:0;background:none;
  font:inherit;font-size:24px;line-height:1;
  color:var(--ink-dim);
  border-radius:50%;
  cursor:pointer;
  z-index:2;
}
.panel-close:hover{color:var(--ink);background:#0000000a}
.panel-close:focus-visible{outline:2px solid var(--ink);outline-offset:2px}

.panel-title{
  margin:0;
  position:relative;
  padding-right:48px;
  /* the gutter the header crystal sits in: seat + a 20px gap, so the two never touch */
  padding-left:calc(var(--gem) + 20px);
  font-size:clamp(40px,5.2vw,84px);
  line-height:.95;
  letter-spacing:-.02em;
  font-weight:600;
  outline:none;
}
/* The seat itself paints nothing: it reserves the gutter and reports its own rect, and the
   solids layer draws the crystal there (S.panelSeat). Height is the title's first LINE box
   (line-height .95), so the seat is centred on the first line however the title wraps. */
.panel-gem{
  position:absolute;
  left:0;
  top:0;
  width:var(--gem);
  height:.95em;
  pointer-events:none;
}

.panel-meta{
  margin:1em 0 0;
  font-size:12px;
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--hue-col,var(--ink-dim));
}
.panel-blurb{
  margin:.9em 0 0;
  max-width:60ch;
  font-size:17px;
  line-height:1.5;
  color:#2e2e2e;
}

/* Hero left, rail right. Nothing here crops: every image is width:100%/height:auto, so
   a tall phone shot in the rail stays tall — that is the point. */
.panel-media{
  margin-top:clamp(26px,4vh,48px);
  display:grid;
  grid-template-columns:minmax(0,1fr) clamp(120px,14vw,200px);
  gap:18px;
  align-items:start;
}
.panel-media.solo{grid-template-columns:minmax(0,1fr)}
.panel-hero{margin:0;grid-column:1}
.panel-media.solo .panel-hero{grid-column:1/-1}
.panel-hero figcaption{
  margin-top:.6em;
  font-size:11.5px;
  letter-spacing:.04em;
  color:var(--ink-dim);
}
.panel-rail{
  grid-column:2;
  display:flex;
  flex-direction:column;
  gap:14px;
}
/* P7 tiled: past a handful of images the rail runs several screens below a hero that
   ends at ~500px, and the hero column sits empty beside it. Here the hero takes the full
   width and the rest pack into masonry columns beneath it — column-count, not a row
   grid, so mixed aspect ratios (landscape sheets beside portrait pages) stack with no
   cropping and no rows of dead space. Columns: 3 wide, 2 at 1440, 1 on a phone. */
.panel-media.tiled{grid-template-columns:minmax(0,1fr)}
.panel-media.tiled .panel-hero{grid-column:1/-1}
.panel-tiles{
  grid-column:1/-1;
  column-count:3;
  column-gap:14px;
}
.panel-tiles .shot{
  break-inside:avoid;
  -webkit-column-break-inside:avoid;
  margin:0 0 14px;
}
@media (max-width:1600px){
  .panel-tiles{column-count:2}
}
aside.panel .shot{
  appearance:none;
  display:block;
  width:100%;
  padding:0;border:0;
  background:none;
  cursor:zoom-in;
  font:inherit;
}
aside.panel .shot img{
  width:100%;
  height:auto;
  display:block;
  transition:opacity 320ms var(--ease);
}
aside.panel .shot:hover img{opacity:.88}
aside.panel .shot:focus-visible{outline:2px solid var(--ink);outline-offset:3px}

.panel-video{margin-top:26px;display:grid;gap:8px;max-width:68ch}
.panel-video video{width:100%;height:auto;display:block}
.panel-video .cap{font-size:11.5px;letter-spacing:.04em;color:var(--ink-dim)}

.panel-text{margin-top:clamp(26px,4vh,48px);max-width:68ch}
.panel-text h3{
  margin:28px 0 .4em;
  font-size:13px;
  font-weight:600;
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--hue-col,var(--ink-dim));
}
.panel-text h3:first-child{margin-top:0}
.panel-text p{margin:0 0 1em;font-size:16px;line-height:1.55;color:#333}

/* ---------- the resume (SPEC §4.1) ---------- */

/* Structured like a resume: identity and the PDF at the top, then the sections in
   order, each timeline entry as role-left / dates-right with the bullets under both.
   Same face, same inks and the same 60ch measure as the rest of the panel. */
.resume{margin-top:clamp(26px,4vh,48px);max-width:68ch}
.resume-head{
  display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  gap:8px 28px;
  align-items:start;
}
.resume-name{
  margin:0;
  font-size:clamp(22px,2vw,28px);
  line-height:1.15;
  font-weight:600;
  letter-spacing:-.01em;
}
.resume-name .post{font-weight:500;color:var(--hue-col,var(--ink-dim))}
.resume-line{
  margin:.35em 0 0;
  font-size:13px;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--ink-dim);
}
.resume-contact{margin:.35em 0 0;font-size:14px;color:var(--ink-dim)}
.resume-contact a{color:inherit;text-decoration:none;border-bottom:1px solid currentColor}
.resume-summary{margin:1em 0 0;max-width:60ch;font-size:16px;line-height:1.55;color:#333}
.resume-pdf{
  grid-column:2;grid-row:1;
  justify-self:end;
  display:inline-block;
  padding:10px 18px;
  border:1.5px solid var(--hue-col,var(--ink));
  border-radius:999px;
  font-size:13px;
  font-weight:600;
  letter-spacing:.04em;
  color:var(--hue-col,var(--ink));
  text-decoration:none;
  white-space:nowrap;
  transition:background 240ms var(--ease),color 240ms var(--ease);
}
.resume-pdf:hover{background:var(--hue-col,var(--ink));color:var(--bg)}
.resume-pdf:focus-visible{outline:2px solid var(--ink);outline-offset:3px}

.resume-section{margin-top:34px}
.resume-section h3{
  margin:0 0 .7em;
  padding-bottom:.45em;
  border-bottom:1px solid color-mix(in srgb,var(--ink-dim) 35%,transparent);
  font-size:13px;
  font-weight:600;
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--hue-col,var(--ink-dim));
}
.entry{margin:0 0 18px}
.entry:last-child{margin-bottom:0}
/* role left, dates right; the date column is `auto` + nowrap so it can never fold into
   the title column at 1440 — the title column shrinks first (minmax(0,1fr)). */
.entry-head{
  display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  column-gap:24px;
  align-items:baseline;
}
.entry-lead{display:flex;flex-direction:column;gap:2px;min-width:0}
.entry-title{font-size:16px;font-weight:600;color:var(--ink)}
.entry-org{font-size:15px;color:#3a3a3a}
.entry-when{
  grid-column:2;
  justify-self:end;
  white-space:nowrap;
  font-size:13px;
  font-variant-numeric:tabular-nums;
  letter-spacing:.02em;
  color:var(--ink-dim);
}
.entry-bullets{
  margin:.5em 0 0;
  padding-left:1.1em;
  max-width:60ch;
  font-size:15px;
  line-height:1.5;
  color:#333;
}
.entry-bullets li{margin:0 0 .25em}
.skill-groups{
  margin:0;
  display:grid;
  grid-template-columns:max-content minmax(0,1fr);
  gap:8px 20px;
  font-size:15px;
  line-height:1.5;
}
.skill-groups dt{font-weight:600;color:var(--ink)}
.skill-groups dd{margin:0;color:#333}

.panel-links{margin-top:30px;display:flex;flex-wrap:wrap;gap:1em}
.panel-links a{
  font-size:14px;
  color:var(--hue-col,var(--ink));
  text-decoration:none;
  border-bottom:1px solid currentColor;
}

/* ---------- related links + tether ---------- */

.rel{
  stroke-width:1;
  vector-effect:non-scaling-stroke;
  stroke-dasharray:1 5;
  stroke-linecap:round;
  opacity:.34;
  transition:opacity var(--dur) var(--ease);
}
.rel.enter{opacity:0}
.rel.exit{opacity:0}
.tether{
  stroke-width:1.25;
  vector-effect:non-scaling-stroke;
  stroke-dasharray:5 6;
  opacity:.6;
  transition:opacity 320ms var(--ease);
}

/* ---------- lightbox ---------- */

.lightbox{
  position:fixed;
  inset:0;
  z-index:20;
  background:#141311e8;
  backdrop-filter:blur(6px);
  display:grid;
  grid-template-rows:1fr auto;
  padding:max(24px,env(safe-area-inset-top)) 24px 20px;
}
.lightbox[hidden]{display:none}
.lb-stage{display:flex;align-items:center;justify-content:center;min-height:0}
.lb-img{
  max-width:min(94vw,1500px);
  max-height:78vh;
  object-fit:contain;
  border-radius:6px;
  background:#00000022;
}
.lb-bar{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:2em;
  color:#f4f2eecc;
  font-size:12.5px;
  letter-spacing:.04em;
  padding-top:14px;
}
.lb-close,.lb-prev,.lb-next{
  position:absolute;
  border:0;
  background:#f4f2ee1a;
  color:#f4f2ee;
  font:inherit;
  border-radius:50%;
  cursor:pointer;
  display:flex;align-items:center;justify-content:center;
}
.lb-close{top:18px;right:18px;width:40px;height:40px;font-size:22px;line-height:1}
.lb-prev,.lb-next{top:50%;transform:translateY(-50%);width:44px;height:44px;font-size:26px;line-height:1}
.lb-prev{left:14px}
.lb-next{right:14px}
.lb-close:hover,.lb-prev:hover,.lb-next:hover{background:#f4f2ee33}
.lb-close:focus-visible,.lb-prev:focus-visible,.lb-next:focus-visible{outline:2px solid #f4f2ee;outline-offset:2px}

/* ---------- mobile ---------- */

@media (max-width:900px){
  .crumb-strip{font-size:12px;max-width:calc(100vw - 40px)}
  .lbl{font-size:11px}
  .node.root .lbl{font-size:11.5px}
  /* The project owns the whole screen here, so the graph is not just covered: it is
     switched off, which parks the WebGL layer's per-frame work while it cannot be seen.
     The hash still carries the open path, so Back restores the expanded graph. */
  aside.panel{
    inset:0;
    width:100%;
    height:100%;
    padding:20px 20px 30vh;
    transform:none;
    background:var(--field);
  }
  /* Full-screen here: there is no graph beside the panel to fade into. */
  aside.panel::before{display:none}
  body.panel #g,
  body.panel #solids,
  body.panel #seat,
  body.panel .crumb-strip{visibility:hidden}
  .panel-back{
    display:flex;
    align-items:center;justify-content:center;
    width:44px;height:44px;
    margin:0 0 10px -10px;
    border:0;background:none;
    font:inherit;font-size:24px;line-height:1;
    color:var(--ink);
    cursor:pointer;
  }
  .panel-back:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
  .panel-close{display:none}
  /* The graph layer is switched off at these widths, so there is no crystal to seat and
     no tether to land: the gutter goes with them. */
  .panel-title{font-size:clamp(30px,9vw,44px);padding-right:0;padding-left:0}
  .panel-gem{display:none}
  .panel-blurb{font-size:16px}
  /* One column: hero, then every rail image under it, all full width, none cropped. */
  .panel-media{grid-template-columns:minmax(0,1fr);gap:14px}
  .panel-hero,.panel-rail{grid-column:1}
  .panel-tiles{column-count:1}
  /* the resume stacks: PDF button under the summary, dates under the role */
  .resume-head{grid-template-columns:minmax(0,1fr)}
  .resume-pdf{grid-column:1;grid-row:auto;justify-self:start}
  .entry-head{grid-template-columns:minmax(0,1fr)}
  .entry-when{grid-column:1;justify-self:start;margin-top:2px}
  .skill-groups{grid-template-columns:minmax(0,1fr);gap:2px 0}
  .skill-groups dd{margin-bottom:8px}
  .lb-prev,.lb-next{width:38px;height:38px}
}

/* ---------- print: the resume alone, Letter ---------- */

@page{size:Letter;margin:.75in}
@media print{
  html{overflow:visible}
  html,body{height:auto;background:#fff !important}
  body{transition:none}
  #g,#solids,#seat,.crumb-strip,.hint,#lightbox,.panel-back,.panel-close{display:none !important}
  aside.panel{
    position:static;
    width:auto;height:auto;
    padding:0;
    overflow:visible;
    opacity:1;transform:none;
    background:none !important;
  }
  /* only the resume prints: title, meta, blurb, links and any media are the screen's */
  aside.panel > :not(.resume){display:none !important}
  .resume{margin-top:0;max-width:none;color:#000}
  .resume-pdf{display:none}
  .resume-name .post,.resume-section h3,.entry-when,.resume-line{color:#000}
  .resume-section{break-inside:auto}
  .entry{break-inside:avoid}
  .resume-section h3{break-after:avoid}
  .entry-bullets,.resume-summary,.entry-org,.skill-groups dd{color:#111}
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-delay:0ms !important;
    transition-duration:.001ms !important;
  }
}
