/* ==========================================================================
   Projects page — extends style.css, doesn't modify it.
   Reuses the site's existing tokens (--ink, --forest, --marigold, --paper,
   --sage, --f-display, --f-body, --r, --shadow, --wrap) defined in style.css.
   ========================================================================== */

/* --------------------------------------------------------- page intro --- */
.proj-hero {
  padding-top: clamp(7rem, 12vw, 9.5rem);
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
}
.proj-hero .section-head { margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }

.proj-note {
  max-width: 62rem;
  border: 1px dashed var(--paper-line);
  background: var(--paper-2);
  border-radius: var(--r);
  padding: 1.1rem 1.4rem;
  font-size: .92rem;
  color: var(--ink-on-light);
}
.proj-note b { color: var(--ink); }

/* ---------------------------------------------------------- group tag --- */
.proj-group {
  display: none;
  align-items: center;
  gap: 1rem;
  margin: clamp(3rem, 6vw, 4.5rem) 0 clamp(1.5rem, 3vw, 2.25rem);
}
.proj-group.is-visible { display: flex; }
.proj-group:first-of-type { margin-top: 0; }
.proj-group h2 {
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--marigold-d);
  white-space: nowrap;
}
.proj-group::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--paper-line);
}
.section--forest .proj-group::after { background: var(--forest-line); }
.section--forest .proj-group h2 { color: var(--marigold); }

/* --------------------------------------------------------- project entry --- */
.proj-entry {
  padding: clamp(1.5rem, 3vw, 2rem) 0 clamp(2.25rem, 4vw, 3rem);
  display: none;
}
.proj-entry.is-active {
  display: block;
  animation: projFadeIn var(--d-2) var(--e);
}
@media (prefers-reduced-motion: reduce) {
  .proj-entry.is-active { animation: none; }
}
@keyframes projFadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

.proj-head { display: flex; gap: 1.1rem; align-items: baseline; flex-wrap: wrap; }
.proj-num {
  font-family: var(--f-body);
  font-weight: 800;
  font-size: .85rem;
  letter-spacing: .06em;
  color: var(--marigold-d);
  flex-shrink: 0;
}
.proj-head h3 { font-size: clamp(1.5rem, 2.6vw, 2rem); margin: 0; }

/* Brand mark set beside a project title (currently only Claude Code on p11).

   Sized in em and placed INSIDE the h3, so it tracks the heading's
   clamp(1.5rem, 2.6vw, 2rem) automatically instead of needing its own
   breakpoints.

   The source viewBox is "0 0 24 24" but the mark itself only occupies
   y 5..20 — at height:1em it would have rendered 0.625em tall and read as
   too small next to the letters. The markup crops the viewBox to
   "0 5 24 15" so height maps 1:1 onto the drawn mark; --mark-h is therefore
   the real visible height. 0.72em approximates the cap height of Bricolage
   Grotesque, which is what makes it sit level with the text rather than with
   the em box. Width is derived from the 24:15 aspect (1.6) — do not set it
   to auto, some engines will not infer it from a cropped viewBox.

   vertical-align: baseline is the default for an inline SVG and is what puts
   the mark's bottom edge on the text baseline; stated explicitly so it is not
   "tidied" away. */
.proj-head h3 .title-mark {
  --mark-h: 0.72em;
  height: var(--mark-h);
  width: calc(var(--mark-h) * 1.6);
  vertical-align: baseline;
  flex-shrink: 0;
}
/* Standard project subtitle pair — EVERY .proj-entry carries both, in this
   order: a Title Case outcome tagline, then the sentence-case one-liner that
   explains what the project actually is. Keep the two visually distinct
   (weight + color + size) so the pair reads as an intentional hierarchy
   rather than two competing subtitles. */
.proj-tagline {
  max-width: 52rem;
  font-weight: 600;
  color: var(--marigold-text);
  font-size: .92rem;
  letter-spacing: .005em;
  margin: .45rem 0 0;
}
.proj-oneliner { max-width: 52rem; margin: .5rem 0 0; font-size: 1.02rem; color: var(--sage); }

.proj-callout {
  margin-top: 1.15rem;
  padding: .9rem 1.2rem;
  border-radius: var(--r);
  font-size: .92rem;
  max-width: 52rem;
}
.proj-callout.is-amber { background: var(--marigold-t); border: 1px solid var(--marigold); color: var(--ink-on-light); }
.proj-callout.is-red { background: #F6DFD5; border: 1px solid var(--clay); color: var(--ink-on-light); }

/* ------------------------------------------------------------ subsection --- */
.proj-sub { margin-top: 1.5rem; max-width: 54rem; }
.proj-sub h4 {
  font-family: var(--f-body);
  font-weight: 700;
  font-size: .85rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--marigold-d);
  margin: 0 0 .55rem;
}
.proj-sub p, .proj-sub li { font-size: .96rem; line-height: 1.65; margin: 0 0 .6rem; }
.proj-sub ul, .proj-sub ol { padding-left: 1.15rem; margin: 0; list-style: revert; }
.proj-sub ul { list-style-type: disc; }
.proj-sub ul li::marker { color: var(--marigold-d); }
.proj-sub li:last-child { margin-bottom: 0; }
.proj-sub strong { color: var(--ink); }
.proj-sub p {text-align: justify;}

.proj-fillin {
  display: inline-block;
  font-family: var(--f-body);
  font-weight: 700;
  font-size: .74rem;
  letter-spacing: .03em;
  color: var(--marigold-d);
  background: var(--marigold-t);
  border: 1px dashed var(--marigold-d);
  border-radius: 5px;
  padding: .05rem .5rem;
}

/* ---------------------------------------------------------------- quote --- */
/* Distinguished from the page's other paper-2 cards by an oversized
   display-font quotation mark, not a colored accent border. */
.proj-quote {
  position: relative;
  margin: .9rem 0 0;
  padding: 1.1rem 1.35rem 1.1rem 2.15rem;
  background: var(--paper-2);
  border-radius: var(--r);
}
.proj-quote::before {
  content: "\201C";
  position: absolute;
  top: .3rem;
  left: .7rem;
  font-family: var(--f-display);
  font-weight: 700;
  font-style: normal;
  font-size: 2.25rem;
  line-height: 1;
  color: var(--marigold-text);
}
.proj-quote p { position: relative; font-style: italic; font-size: 1rem; margin: 0 0 .5rem; }
.proj-quote cite { font-style: normal; font-size: .84rem; color: var(--sage); font-weight: 600; }

/* Testimonial cards — 3-column grid (used for Customer Testimonials sections
   with several quotes; a lone .proj-quote elsewhere stays the full-width
   quote-mark style above). */
.proj-quote-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
  margin-top: .9rem;
}
.proj-quote-grid .proj-quote {
  margin: 0;
  display: flex;
  flex-direction: column;
  height: 100%;
}
.proj-quote-grid .proj-quote p { flex: 1 1 auto; }

@media (max-width: 900px) {
  .proj-quote-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .proj-quote-grid { grid-template-columns: 1fr; }
}

/* ----------------------------------------------------------- link chips --- */
.proj-links { margin-top: .9rem; display: flex; flex-wrap: wrap; gap: .55rem; }
.proj-chip {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-weight: 600;
  font-size: .84rem;
  color: var(--ink-on-light);
  background: #fff;
  border: 1.5px solid var(--paper-line);
  border-radius: 30px;
  padding: .38rem .85rem;
  transition: border-color var(--d-1) var(--e), color var(--d-1) var(--e), transform var(--d-1) var(--e);
}
.proj-chip:hover { border-color: var(--marigold); color: var(--marigold-d); transform: translateY(-1px); }

/* ------------------------------------------------------------- sub-project --- */
.proj-subcard {
  margin-top: 2rem;
  padding: clamp(1.5rem, 3vw, 2rem);
  background: var(--paper-2);
  border: 1px solid var(--paper-line);
  border-radius: var(--r-lg);
}
.proj-subcard .proj-eyebrow-sm {
  display: block;
  font-weight: 700;
  font-size: .74rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--marigold-d);
  margin-bottom: .4rem;
}
.proj-subcard h4.proj-subtitle { font-family: var(--f-display); font-size: 1.4rem; margin: 0 0 .3rem; }
.proj-subcard .proj-oneliner { margin-top: 0; }

@media (max-width: 640px) {
  .proj-head { flex-direction: column; gap: .25rem; }
}

/* ==========================================================================
   Sidebar + browsing layout
   --header-h is set at runtime by js/projects.js (measures the real height
   of #siteHeader), so this stays correct even if the header wraps to a
   second line on narrow widths or its height shifts on font load.
   ========================================================================== */
/* --header-h now lives in css/style.css :root so every page has it; this
   page's js/projects.js still overrides it with the measured height. */

.proj-body { padding-bottom: clamp(3rem, 6vw, 5rem); }

.proj-layout {
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: start;
}

.proj-sidebar {
  position: sticky;
  top: calc(var(--header-h) + 24px);
  max-height: calc(100vh - var(--header-h) - 48px);
  overflow-y: auto;
  padding-right: .25rem;
}
.proj-sidebar::-webkit-scrollbar { width: 5px; }
.proj-sidebar::-webkit-scrollbar-thumb { background: var(--paper-line); border-radius: 3px; }

.proj-nav-toggle {
  display: none;
  width: 100%;
  justify-content: space-between;
  align-items: center;
  background: #fff;
  border: 1.5px solid var(--paper-line);
  border-radius: var(--r-sm);
  padding: .65rem .9rem;
  font-weight: 600;
  font-size: .92rem;
  color: var(--ink);
  cursor: pointer;
  margin-bottom: .75rem;
}

.proj-nav-label {
  font-weight: 700;
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--marigold-d);
  margin: 1.3rem 0 .5rem;
}
.proj-nav-label:first-child { margin-top: 0; }

.proj-nav-list ul { list-style: none; margin: 0 0 .25rem; padding: 0; }

.proj-nav-link {
  display: flex;
  gap: .55rem;
  align-items: baseline;
  font-size: .89rem;
  font-weight: 600;
  color: var(--ink-on-light);
  padding: .4rem .55rem .4rem .75rem;
  border-radius: 9px;
  transition: background var(--d-1) var(--e), color var(--d-1) var(--e);
}
.proj-nav-link:hover { background: var(--paper-2); }
.proj-nav-link.active { background: var(--marigold-t); color: var(--ink); }
.proj-nav-link.active .n { color: var(--marigold-d); }
.proj-nav-link .n { font-size: .8rem; color: var(--sage); flex-shrink: 0; }
.proj-nav-link.is-sub { padding-left: 1.6rem; font-weight: 500; font-size: .85rem; color: var(--sage); }

/* Every scroll target gets breathing room above it equal to the fixed
   header's real height, so clicking a sidebar link never leaves the
   top of the section hidden behind the header. */
.proj-entry, .proj-subcard { scroll-margin-top: calc(var(--header-h) + 20px); }

@media (max-width: 900px) {
  .proj-layout { grid-template-columns: 1fr; }
  .proj-sidebar {
    position: relative;
    top: auto;
    max-height: none;
    overflow: visible;
  }
  .proj-nav-toggle { display: flex; }
  .proj-nav-list {
    display: grid;
    grid-template-rows: 0fr;
    overflow: hidden;
    visibility: hidden;
    transition: grid-template-rows var(--d-2) var(--e), visibility 0s linear var(--d-2);
  }
  .proj-nav-list-inner { min-height: 0; overflow: hidden; }
  .proj-nav-list.is-open {
    grid-template-rows: 1fr;
    visibility: visible;
    transition: grid-template-rows var(--d-2) var(--e), visibility 0s linear;
  }
}

/* ==========================================================================
   Per-project photo galleries — each project's own "Photos" subsection.
   Uses auto-fill/minmax so it adapts cleanly to however many images a
   given project has (1, 2, 4, whatever) without needing breakpoint-specific
   column counts — a project with 1 photo just shows one tile; a project
   with 6 wraps naturally across as many rows as it needs.
   ========================================================================== */
.proj-photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: .75rem;
}

.photo-card {
  margin: 0;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--paper-2);
  box-shadow: var(--shadow-sm);
}
.photo-card img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  transition: transform var(--d-2) var(--e);
}
.photo-card:hover img { transform: scale(1.04); }

.photo-card figcaption {
  padding: .55rem .75rem;
  font-weight: 600;
  font-size: .8rem;
  color: var(--ink);
  border-top: 1px solid var(--paper-line);
}

@media (max-width: 480px) {
  .proj-photo-grid { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
}

/* ==========================================================================
   Photo trigger — resets the <button> wrapping each thumbnail so it looks
   identical to a plain image, but is properly focusable/clickable to open
   the lightbox.
   ========================================================================== */
.photo-trigger {
  all: unset;
  display: block;
  width: 100%;
  cursor: zoom-in;
}
.photo-trigger img { display: block; }
.photo-trigger:focus-visible {
  outline: 3px solid var(--marigold);
  outline-offset: 2px;
}

/* ==========================================================================
   Inline editorial image — a full-width image embedded within a project's
   body copy (inside .proj-sub), newspaper-article style: image spans the
   text column, with a small caption line underneath.
   ========================================================================== */
.proj-inline-figure {
  margin: 1.5rem 0;
  max-width: 54rem;
}
.proj-inline-figure .photo-trigger {
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.proj-inline-figure img {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  transition: transform var(--d-2) var(--e);
}
.proj-inline-figure:hover img { transform: scale(1.02); }

/* --fit modifier — for diagrams/screenshots that must show in full rather
   than being cropped to 16:9 (e.g. an IA tree that's naturally tall). */
.proj-inline-figure--fit img {
  aspect-ratio: auto;
  object-fit: contain;
  background: var(--paper);
}
.proj-inline-figure--fit:hover img { transform: none; }
.proj-inline-figure figcaption {
  margin-top: .6rem;
  font-family: var(--f-display);
  font-style: italic;
  font-size: .92rem;
  color: var(--sage);
  line-height: 1.5;
}

/* ==========================================================================
   Lightbox — single reusable overlay for every clickable image on the page
   (thumbnail galleries and inline editorial images alike). Vanilla JS,
   no libraries; see js/lightbox.js.
   ========================================================================== */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 3000;
  display: none;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 5vw, 3rem);
  background: rgba(20, 35, 28, .92);
}
.lightbox.is-open { display: flex; flex-direction: column; }

.lightbox-figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 100%;
  max-height: 100%;
}
.lightbox-img {
  max-width: 88vw;
  max-height: 78vh;
  width: auto;
  height: auto;
  border-radius: var(--r);
  box-shadow: 0 30px 70px -20px rgba(0,0,0,.6);
  background: var(--paper-2);
}
.lightbox-caption {
  margin-top: 1rem;
  color: var(--soft-on-dark);
  font-size: .92rem;
  text-align: center;
  max-width: 60ch;
}

.lightbox-close,
.lightbox-nav {
  all: unset;
  position: fixed;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: rgba(255,255,255,.12);
  color: #fff;
  cursor: pointer;
  transition: background var(--d-1) var(--e);
}
.lightbox-close:hover,
.lightbox-nav:hover { background: rgba(255,255,255,.24); }
.lightbox-close:focus-visible,
.lightbox-nav:focus-visible { outline: 3px solid var(--marigold); outline-offset: 2px; }

.lightbox-close { top: clamp(1rem, 4vw, 2rem); right: clamp(1rem, 4vw, 2rem); }
.lightbox-prev { left: clamp(.5rem, 3vw, 2rem); top: 50%; transform: translateY(-50%); }
.lightbox-next { right: clamp(.5rem, 3vw, 2rem); top: 50%; transform: translateY(-50%); }
.lightbox-nav[hidden] { display: none; }
.lightbox-close svg { width: 18px; height: 18px; }
.lightbox-nav svg { width: 20px; height: 20px; }

@media (max-width: 640px) {
  .lightbox-close { width: 40px; height: 40px; }
  .lightbox-nav { width: 38px; height: 38px; }
  .lightbox-img { max-width: 74vw; }
  .lightbox-prev { left: .5rem; }
  .lightbox-next { right: .5rem; }
}

/* ==========================================================================
   Component sticker sheet — a live, interactive reference sheet of the
   REAL Elemental Design System, pulled from FourKites' actual EDS Figma
   file (colors, typography, buttons, text input, dropdown, toggle,
   checkbox, and radio all pulled node-for-node, states included). Uses
   hardcoded EDS hex values throughout, deliberately NOT the portfolio
   site's own --marigold/--forest/--sage/etc. custom properties.
   ========================================================================== */
.sticker-sheet {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
  margin-top: 1.25rem;
  padding: clamp(1.25rem, 3vw, 1.75rem);
  background: #FAFAFA;
  border: 1px solid #E9EAEB;
  border-radius: 12px;
}

/* RULE: every piece of type inside the sticker sheet renders in Lato —
   the official EDS typeface. The sheet is a live reproduction of the real
   design system, so the portfolio site's own display/body fonts
   (Bricolage Grotesque / Hanken Grotesk, via --f-display / --f-body) must
   never leak into it. This single scoped rule covers group labels,
   captions, swatch names/hexes, and anything added to the sheet later, so
   new sticker-sheet components do not each need their own font-family
   declaration. Do not remove this or override font-family inside
   .sticker-sheet with a site font. */
.sticker-sheet,
.sticker-sheet * {
  font-family: 'Lato', sans-serif;
}
/* Headings need their own guard: `.proj-sub h4` (0,1,1) outranks
   `.sticker-sheet *` (0,1,0), so a heading placed inside the sheet would
   otherwise fall back to the site body font. This selector matches that
   specificity and, sitting later in the file, wins the tie. */
.sticker-sheet h1, .sticker-sheet h2, .sticker-sheet h3,
.sticker-sheet h4, .sticker-sheet h5, .sticker-sheet h6 {
  font-family: 'Lato', sans-serif;
}

.sticker-group-label {
  display: block;
  font-weight: 700;
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #717680;
  margin-bottom: .75rem;
}
.eds-approx {
  display: block;
  font-style: normal;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  font-size: .78rem;
  color: #a4a7ae;
  margin-top: .2rem;
}
.eds-caption {
  font-size: .8rem;
  color: #717680;
  margin: .6rem 0 0;
}

.control-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .85rem;
}

/* --- color swatches --- */
.swatch-row { display: flex; flex-wrap: wrap; gap: .65rem; }
.swatch {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: .15rem;
  width: 100px;
  height: 72px;
  border-radius: 8px;
  padding: .55rem .65rem;
  box-shadow: 0 1px 2px 0 rgba(10,13,18,.05);
}
.swatch-name { font-weight: 700; font-size: .74rem; }
.swatch-hex { font-size: .68rem; opacity: .85; }
@media (max-width: 480px) { .swatch { width: 88px; height: 66px; } }

/* --- typography sample --- */
.eds-type-sample p { font-family: 'Lato', sans-serif; color: #181D27; margin: 0; }

/* Shared focus-ring effect — same token used across dropdown, checkbox,
   radio, and toggle in the real Figma file ("Focus rings/focus-ring"):
   a 2px white inset ring plus a 4px brand-blue outer ring. */
:root { --eds-focus-ring: 0 0 0 2px #ffffff, 0 0 0 6px #0E65E5; }

/* ==========================================================================
   Buttons — Solid / Outline / Flat, real EDS colors & measurements
   (40px height, 14px/10px padding, 8px radius, Lato Semibold 16/24).
   ========================================================================== */
.eds-btn {
  font-family: 'Lato', sans-serif;
  font-weight: 600;
  font-size: 16px;
  line-height: 24px;
  height: 40px;
  padding: 10px 14px;
  border-radius: 8px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  transition: background var(--d-1) var(--e), border-color var(--d-1) var(--e), color var(--d-1) var(--e);
}
.eds-btn:focus-visible { outline: none; box-shadow: var(--eds-focus-ring); }

.eds-btn--solid-primary {
  background: #0E65E5;
  border: 2px solid rgba(255,255,255,.12);
  color: #ffffff;
  box-shadow: 0 1px 2px 0 rgba(10,13,18,.05), inset 0 0 0 1px rgba(10,13,18,.18), inset 0 -2px 0 0 rgba(10,13,18,.05);
}
.eds-btn--solid-primary:hover { background: #0B51B7; }
.eds-btn--solid-primary:disabled {
  background: #CFE1FC;
  box-shadow: none;
  border-color: transparent;
  cursor: not-allowed;
}

.eds-btn--solid-secondary {
  background: #E9EAEB;
  border: 1px solid rgba(255,255,255,.12);
  color: #181D27;
  box-shadow: 0 1px 2px 0 rgba(10,13,18,.05), inset 0 0 0 1px rgba(10,13,18,.18), inset 0 -2px 0 0 rgba(10,13,18,.05);
}

.eds-btn--outline-primary {
  background: #ffffff;
  border: 2px solid #0E65E5;
  color: #0E65E5;
  box-shadow: 0 1px 2px 0 rgba(10,13,18,.05);
}
.eds-btn--outline-primary:hover { background: #F1F6FE; }

.eds-btn--flat-primary {
  background: transparent;
  border: none;
  color: #0E65E5;
}
.eds-btn--flat-primary:hover { background: #F1F6FE; }

/* ==========================================================================
   Text input — white bg, #A4A7AE border, 8px radius, 40px height,
   12px/8px padding, Lato Regular 16/24; focus = 2px brand border;
   error = 2px red border + red hint; disabled = muted gray bg.
   ========================================================================== */
.eds-field { display: flex; flex-direction: column; gap: 6px; width: 220px; max-width: 100%; }
.eds-label { font-family: 'Lato', sans-serif; font-size: 16px; line-height: 24px; color: #535862; }
.eds-input-wrap {
  background: #ffffff;
  border: 1px solid #A4A7AE;
  border-radius: 8px;
  padding: 8px 12px;
  box-shadow: 0 1px 1px 0 rgba(10,13,18,.05);
}
.eds-input {
  all: unset;
  width: 100%;
  font-family: 'Lato', sans-serif;
  font-size: 16px;
  line-height: 24px;
  color: #181D27;
}
.eds-input::placeholder { color: #A4A7AE; }
.eds-input-wrap:has(.eds-input:focus) { border: 2px solid #0E65E5; padding: 7px 11px; }
.eds-input-wrap.is-error { border: 2px solid #F04438; padding: 7px 11px; }
.eds-input-wrap.is-disabled { background: #FAFAFA; border-color: #D5D7DA; opacity: .8; }
.eds-hint { font-family: 'Lato', sans-serif; font-size: 14px; line-height: 20px; color: #717680; margin: 0; }
.eds-hint.is-error { color: #D92D20; }

/* ==========================================================================
   Dropdown — same shell spec as text input (white bg, #A4A7AE border,
   8px radius, 40px height) with a trailing caret; focus/error/disabled
   pulled from the real Dropdown Input component.
   ========================================================================== */
.eds-select-wrap {
  position: relative;
  display: flex;
  align-items: center;
  background: #ffffff;
  border: 1px solid #A4A7AE;
  border-radius: 8px;
  padding: 8px 12px;
  box-shadow: 0 1px 2px 0 rgba(10,13,18,.05);
}
.eds-select {
  all: unset;
  width: 100%;
  padding-right: 24px;
  font-family: 'Lato', sans-serif;
  font-size: 16px;
  line-height: 24px;
  color: #181D27;
  cursor: pointer;
}
.eds-caret {
  position: absolute;
  right: 12px;
  color: #717680;
  font-size: 14px;
  pointer-events: none;
}
.eds-select-wrap:has(.eds-select:focus) { border: 2px solid #0E65E5; padding: 7px 11px; }
.eds-select-wrap.is-error { border: 2px solid #F04438; padding: 7px 11px; }
.eds-select-wrap.is-disabled { background: #FAFAFA; border-color: #D5D7DA; opacity: .8; }
.eds-select-wrap.is-disabled .eds-select { cursor: not-allowed; color: #A4A7AE; }

/* ==========================================================================
   Toggle — real EDS spec (md size): 44×24px track, 20px thumb, 2px
   padding, fully-rounded. Off = white bg + #D5D7DA border, thumb
   #535862. On = brand-blue bg + #0B51B7 border, thumb white. Hover
   darkens the On fill; Focus adds the shared focus-ring; Disabled uses
   flat #E9EAEB (off) / #CFE1FC (on) with no border.

   One live, fully-interactive control per sheet — no static "state
   copy" instances. Every state below is reachable by actually hovering,
   tabbing to, or clicking the control. `position: relative` on the
   label is required so the visually-hidden input lines up exactly over
   the visible track (without it, the input's hit target drifts and the
   control stops responding to clicks — this was the "broken toggle" /
   "checkbox not interactive" bug).
   ========================================================================== */
.eds-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-family: 'Lato', sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: #181D27;
  cursor: pointer;
}
.eds-toggle:has(input:disabled) { cursor: not-allowed; }
.eds-toggle input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}
.eds-toggle .track {
  width: 44px;
  height: 24px;
  border-radius: 999px;
  padding: 2px;
  display: flex;
  align-items: center;
  background: #ffffff;
  border: 1px solid #D5D7DA;
  transition: background var(--d-1) var(--e), border-color var(--d-1) var(--e);
  flex-shrink: 0;
}
.eds-toggle .thumb {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #535862;
  box-shadow: 0 2px 4px 0 rgba(10,13,18,.12), 0 1px 2px -1px rgba(10,13,18,.1);
  transition: transform var(--d-1) var(--e), background var(--d-1) var(--e);
}
.eds-toggle input:checked + .track { background: #0E65E5; border-color: #0B51B7; }
.eds-toggle input:checked + .track .thumb { background: #ffffff; transform: translateX(20px); }

/* hover */
.eds-toggle:hover input:checked + .track { background: #0B51B7; border-color: #0B51B7; }

/* focus */
.eds-toggle input:focus-visible + .track { box-shadow: var(--eds-focus-ring); }

/* disabled */
.eds-toggle input:disabled + .track { background: #E9EAEB; border-color: transparent; }
.eds-toggle input:disabled + .track .thumb { background: #A4A7AE; box-shadow: none; }
.eds-toggle input:checked:disabled + .track { background: #CFE1FC; border-color: transparent; }
.eds-toggle input:checked:disabled + .track .thumb { background: #FAFAFA; }

/* ==========================================================================
   Checkbox & Radio — real EDS spec (20px box, "Medium (16)" variant):
   unchecked = white bg + #A4A7AE border; checked = brand-blue bg, white
   check/dot; hover adds pointer cursor; focus = shared focus-ring;
   disabled-unchecked = #F5F5F5 bg + #D5D7DA border; disabled-checked =
   #9FC3F9 bg + #CFE1FC border. Checkbox radius 6px; Radio fully round.

   Same one-live-control approach as Toggle above. Indeterminate is set
   with real JavaScript (`input.indeterminate = true`, see projects.html)
   rather than faked with a CSS class, since it's a genuine native input
   state that can't be reached through a plain HTML attribute.
   ========================================================================== */
.eds-checkbox, .eds-radio {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-family: 'Lato', sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: #181D27;
  cursor: pointer;
}
.eds-checkbox:has(input:disabled), .eds-radio:has(input:disabled) { cursor: not-allowed; }
.eds-checkbox input, .eds-radio input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.eds-checkbox .box {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  border: 1px solid #A4A7AE;
  background: #fff;
  display: grid;
  place-items: center;
  transition: background var(--d-1) var(--e), border-color var(--d-1) var(--e);
  flex-shrink: 0;
}
.eds-radio .dot {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1px solid #A4A7AE;
  background: #fff;
  display: grid;
  place-items: center;
  transition: background var(--d-1) var(--e), border-color var(--d-1) var(--e);
  flex-shrink: 0;
}

/* checked */
.eds-checkbox input:checked + .box { background: #0E65E5; border-color: #0E65E5; }
.eds-checkbox input:checked + .box::after {
  content: "";
  width: 11px; height: 7px;
  border-left: 2px solid #fff; border-bottom: 2px solid #fff;
  transform: rotate(-45deg) translateY(-1px);
}
.eds-radio input:checked + .dot { background: #0E65E5; border-color: #0E65E5; }
.eds-radio input:checked + .dot::after {
  content: "";
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #fff;
}

/* indeterminate (checkbox only — set via JS, real :indeterminate pseudo-class) */
.eds-checkbox input:indeterminate + .box { background: #0E65E5; border-color: #0E65E5; }
.eds-checkbox input:indeterminate + .box::after {
  content: "";
  width: 10px; height: 0;
  border-bottom: 2px solid #fff;
  transform: none;
}

/* focus */
.eds-checkbox input:focus-visible + .box,
.eds-radio input:focus-visible + .dot { box-shadow: var(--eds-focus-ring); }

/* disabled */
.eds-checkbox input:disabled + .box,
.eds-radio input:disabled + .dot {
  background: #F5F5F5; border-color: #D5D7DA;
}
.eds-checkbox input:checked:disabled + .box,
.eds-radio input:checked:disabled + .dot {
  background: #9FC3F9; border-color: #CFE1FC;
}
.eds-checkbox input:checked:disabled + .box::after {
  border-color: #fff;
}

/* ==========================================================================
   Tag — built from real EDS color tokens (Brand/25 bg, Brand/100 border,
   Brand/700 text); exact component spec not individually pulled.
   ========================================================================== */
.eds-tag {
  display: inline-flex;
  align-items: center;
  font-family: 'Lato', sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: #083B87;
  background: #E7F0FE;
  border: 1px solid #CFE1FC;
  border-radius: 6px;
  padding: 2px 10px;
}

/* ==========================================================================
   Design Process project — interactive process-map widget
   (My Design Process, "Interactive Process Map"). Namespaced with a dp-
   prefix so it can't collide with anything else on the page.
   ========================================================================== */
.dp-flow {
  display: flex;
  align-items: flex-start;
  gap: 0;
  margin-bottom: 20px;
}
.dp-node {
  all: unset;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  position: relative;
  padding: 6px 4px;
  border-radius: 10px;
}
.dp-node:hover { background: var(--paper-2); }
.dp-node:focus-visible { outline: 2px solid var(--marigold-d); outline-offset: 2px; }

.dp-badge {
  font-family: var(--f-body);
  font-weight: 700;
  font-size: 10.5px;
  color: var(--sage);
  background: var(--paper-2);
  border: 1px solid var(--paper-line);
  border-radius: 999px;
  padding: 2px 8px;
}
.dp-node.is-ai .dp-badge {
  color: var(--ink);
  background: var(--marigold);
  border-color: var(--marigold-d);
  font-weight: 800;
}

.dp-circle {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: #fff;
  border: 1.5px solid var(--paper-line);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--sage);
  transition: border-color var(--d-1) var(--e), color var(--d-1) var(--e), background-color var(--d-1) var(--e), box-shadow var(--d-1) var(--e), transform var(--d-1) var(--e);
}
.dp-node.is-ai .dp-circle {
  border: 2px solid var(--marigold-d);
  color: var(--marigold-d);
  background: var(--marigold-t);
  box-shadow: 0 0 0 4px rgba(230,160,23,0.22);
}
.dp-circle svg { width: 22px; height: 22px; }

.dp-node-label { font-size: 12.5px; font-weight: 600; color: var(--ink); }
.dp-node.is-ai .dp-node-label { color: var(--marigold-d); font-weight: 700; }

/* Currently-selected step. Layers on top of the permanent is-ai / --eng
   category coloring rather than replacing it, via an outer ink-colored
   ring plus a scale bump — so "what's flagged AI/engineering" and "what's
   open right now" read as two independent, stackable signals. */
.dp-node.is-active .dp-circle { transform: scale(1.08); }
.dp-node.is-active .dp-node-label { font-weight: 800; }

.dp-node.is-active:not(.is-ai):not(.dp-node--eng) .dp-circle {
  border-color: var(--ink);
  color: var(--ink);
  box-shadow: 0 0 0 4px rgba(20,35,28,0.14);
}
.dp-node.is-active:not(.is-ai):not(.dp-node--eng) .dp-node-label { color: var(--ink); }

.dp-node.is-ai.is-active .dp-circle {
  box-shadow: 0 0 0 4px rgba(230,160,23,0.28), 0 0 0 7px rgba(20,35,28,0.14);
}
.dp-node--eng.is-active .dp-circle {
  box-shadow: 0 0 0 4px rgba(28,58,46,0.24), 0 0 0 7px rgba(20,35,28,0.14);
}

.dp-arrow-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--marigold-d);
  font-size: 15px;
  padding-top: 22px;
  width: 20px;
  flex-shrink: 0;
}

.dp-legend {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--sage);
  margin: 0 0 20px;
}
.dp-legend-dot {
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--marigold); border: 1.5px solid var(--marigold-d);
  display: inline-block;
  box-shadow: 0 0 0 3px rgba(230,160,23,0.22);
}

.dp-bars-title {
  font-family: var(--f-body);
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--sage);
  margin: 0 0 14px;
}
.dp-bars-title em { font-style: normal; font-weight: 500; text-transform: none; letter-spacing: 0; color: #A9A08C; }

.dp-bar-row { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.dp-bar-era { font-size: 12.5px; font-weight: 700; color: var(--ink); width: 52px; flex-shrink: 0; }
.dp-bar-track { display: flex; height: 36px; border-radius: 8px; overflow: hidden; background: var(--paper-2); }
.dp-bar-row[data-era="pre"] .dp-bar-track { width: 100%; }
.dp-bar-row[data-era="ai"] .dp-bar-track { width: 63.4%; }

.dp-segment {
  all: unset;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--f-body);
  font-weight: 700;
  font-size: 11px;
  color: var(--sage);
  background: #fff;
  border-right: 2px solid var(--paper);
  cursor: pointer;
}
.dp-segment:last-child { border-right: none; }
.dp-segment:hover { background: var(--paper-2); }
.dp-segment:focus-visible { outline: 2px solid var(--marigold-d); outline-offset: -2px; }
.dp-segment.is-ai { background: var(--marigold); color: var(--ink); font-weight: 800; }
.dp-segment.is-ai:hover { background: var(--marigold-d); color: #fff; }

/* Currently-selected step — mirrors .dp-node.is-active so a click on
   either the phase row or a bar segment highlights the same phase
   everywhere it appears. */
.dp-segment.is-active { box-shadow: inset 0 0 0 2px var(--ink); }
.dp-segment.is-ai.is-active { box-shadow: inset 0 0 0 2px var(--ink); }

.dp-detail {
  margin-top: 20px;
  padding: 18px 20px;
  background: var(--paper-2);
  border: 1px solid var(--paper-line);
  border-radius: 12px;
  min-height: 56px;
}
.dp-detail-empty { margin: 0; color: var(--sage); font-size: 13.5px; }
.dp-detail-title { font-family: var(--f-display); font-weight: 700; font-size: 17px; margin: 0 0 4px; }
.dp-detail-tag {
  display: inline-block;
  font-size: 11.5px;
  color: var(--ink);
  font-weight: 800;
  background: var(--marigold);
  border-radius: 999px;
  padding: 2px 10px;
  margin-bottom: 2px;
}
.dp-detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 10px; }
.dp-detail-col-label { font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--sage); margin: 0 0 6px; }
.dp-detail-step { font-size: 13.5px; margin: 0 0 6px; line-height: 1.4; }

@media (max-width: 640px) {
  .dp-flow { flex-wrap: wrap; row-gap: 20px; }
  .dp-node { flex: 0 0 33.33%; }
  .dp-arrow-slot { display: none; }
  .dp-detail-grid { grid-template-columns: 1fr; }
  .dp-bar-era { width: 44px; font-size: 11.5px; }
}

/* ==========================================================================
   Before/After compare slider — drag-to-reveal comparison between the
   classic and redesigned tracking UI (FourKites Redesign, "Before & After").
   Sits in the same newspaper-editorial figure chrome as .proj-inline-figure
   (rounded corners, shadow, italic caption below) but the image area is an
   interactive drag slider rather than a single static photo. Vanilla
   JS/CSS, no dependencies — see js/projects.js.
   ========================================================================== */
.compare-figure { margin: 1.5rem 0; max-width: 54rem; }
.compare-figure figcaption {
  margin-top: .6rem;
  font-family: var(--f-display);
  font-style: italic;
  font-size: .92rem;
  color: var(--sage);
  line-height: 1.5;
}

.compare-slider {
  position: relative;
  width: 100%;
  aspect-ratio: var(--ratio, 3452 / 1924); /* falls back to the redesign screenshots' ratio; override per-instance with --ratio to match different source images */
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  background: var(--paper-2);
  cursor: ew-resize;
  -webkit-user-select: none;
  user-select: none;
  touch-action: none; /* dragging is handled entirely via Pointer Events */
}
.compare-slider img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  -webkit-user-drag: none;
}
.compare-slider__before-wrap {
  position: absolute;
  inset: 0;
  clip-path: inset(0 calc(100% - var(--pos, 50%)) 0 0);
}

.compare-slider__label {
  position: absolute;
  bottom: .85rem;
  font-family: var(--f-body);
  font-weight: 700;
  font-size: .74rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #fff;
  background: rgba(20, 35, 28, .78);
  padding: .32rem .8rem;
  border-radius: 999px;
  pointer-events: none;
}
.compare-slider__label--before { left: .85rem; }
.compare-slider__label--after { right: .85rem; }

.compare-slider__handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--pos, 50%);
  width: 0;
}
.compare-slider__handle::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 3px;
  background: #fff;
  transform: translateX(-50%);
  box-shadow: 0 0 0 1px rgba(20, 35, 28, .18);
}
.compare-slider__grip {
  position: absolute;
  top: 50%; left: 0;
  transform: translate(-50%, -50%);
  width: 44px; height: 44px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--marigold);
  display: grid;
  place-items: center;
  box-shadow: var(--shadow-sm);
  color: var(--ink);
  cursor: ew-resize;
  transition: border-color var(--d-1) var(--e);
}
.compare-slider__handle:hover .compare-slider__grip { border-color: var(--marigold-d); }
.compare-slider__handle:focus-visible { outline: none; }
.compare-slider__handle:focus-visible .compare-slider__grip {
  outline: 3px solid var(--marigold);
  outline-offset: 2px;
}

@media (max-width: 480px) {
  .compare-slider__grip { width: 36px; height: 36px; }
  .compare-slider__label { font-size: .68rem; padding: .26rem .6rem; }
}

/* --------------------------------------------------------------------------
   Design Process project — full step-by-step box-diagram reference
   ("Full Step-by-Step Reference"). Also dp- namespaced.
   -------------------------------------------------------------------------- */
.dp-board {
  display: flex;
  background: var(--paper-2);
  border: 1px solid var(--paper-line);
  border-radius: 14px;
  padding: 22px 16px 26px;
  flex-wrap: wrap;
}
.dp-phase { flex: 1; min-width: 140px; display: flex; flex-direction: column; padding: 0 10px; position: relative; }
.dp-phase + .dp-phase { border-left: 1px dashed var(--paper-line); }

.dp-phase-label {
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--forest);
  background: rgba(230,160,23,0.16);
  border: 1px solid rgba(230,160,23,0.4);
  border-radius: 999px;
  padding: 4px 10px;
  text-align: center;
  margin: 0 0 16px;
}

.dp-steps { display: flex; flex-direction: column; gap: 8px; flex: 1; }
.dp-step {
  background: #fff;
  border: 1px solid var(--paper-line);
  border-radius: 8px;
  padding: 9px 10px;
  font-size: 12.3px;
  line-height: 1.35;
  color: var(--ink);
  box-shadow: 0 1px 2px rgba(20,35,28,0.06);
}
.dp-step--ai {
  border: 1.5px solid var(--marigold-d);
  background: var(--marigold-t);
  box-shadow: 0 1px 3px rgba(230,160,23,0.28);
}
.dp-step-num { font-weight: 700; font-size: 10px; color: var(--marigold-d); display: block; margin-bottom: 2px; }
.dp-step--ai .dp-step-num { color: var(--ink); }
.dp-connector { width: 1px; height: 8px; background: var(--paper-line); margin: 0 auto; }

.dp-arrow {
  position: absolute;
  top: 6px;
  right: -13px;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--marigold-d);
  font-size: 15px;
  background: var(--paper-2);
  z-index: 2;
}

@media (max-width: 900px) {
  .dp-board { flex-direction: column; }
  .dp-phase + .dp-phase { border-left: none; border-top: 1px dashed var(--paper-line); padding-top: 14px; margin-top: 14px; }
  .dp-arrow { display: none; }
}

/* ==========================================================================
   Vibe-Coding process rail (Vibe-Coding with Claude — "Process").
   Reuses the exact .dp-flow / .dp-node / .dp-circle / .dp-detail styling
   from the Design Process project's "Interactive Process Map" so the two
   widgets look identical. The only addition is a --eng modifier (forest,
   instead of marigold) to mark the one step engineering owns instead of
   the rest, which are solo/with Claude. See js/projects.js for the wiring
   and note it's scoped to #vcFlow / #vcDetail so it can't collide with the
   Design Process widget's own #p12-scoped click handling.
   ========================================================================== */
.dp-node--eng .dp-badge { color: #FBFAF4; background: var(--forest); border-color: var(--forest-line); font-weight: 800; }
.dp-node--eng .dp-circle { border: 2px solid var(--forest-line); color: var(--forest); background: var(--paper-2); box-shadow: 0 0 0 4px rgba(28,58,46,0.15); }
.dp-node--eng .dp-node-label { color: var(--forest); font-weight: 700; }

.dp-detail-tag--eng { background: var(--forest); color: #FBFAF4; }

/* ==========================================================================
   Back to top
   Fixed circular button, bottom-right. Hidden until the user scrolls down —
   visibility is toggled via `.is-visible` by js/projects.js.
   ========================================================================== */
.back-to-top {
  position: fixed;
  right: clamp(1.25rem, 4vw, 2.5rem);
  bottom: clamp(1.25rem, 4vw, 2.5rem);
  width: 48px;
  height: 48px;
  border: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--marigold);
  color: var(--ink);
  box-shadow: 0 12px 26px -8px rgba(192, 129, 10, .55);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity var(--d-2) var(--e), transform var(--d-2) var(--e), visibility var(--d-2) var(--e), background var(--d-1) var(--e);
  z-index: 500;
}
.back-to-top svg { width: 20px; height: 20px; }
.back-to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.back-to-top:hover,
.back-to-top:focus-visible { background: var(--marigold-d); }
.back-to-top:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .back-to-top { transition: opacity .01s linear; }
}

@media (max-width: 640px) {
  .back-to-top { width: 44px; height: 44px; right: 1.1rem; bottom: 1.1rem; }
}
