/* Design DNA — styles
 *
 * Design choices worth noting:
 * - Serif (Newsreader) for display, sans (Inter) for UI. The intent is
 *   the calm of a printed feature, not a clickable app.
 * - Editorial neutrals (gray on gray) carry the chrome; lineage tints
 *   are muted enough to read as paper tone rather than chart color.
 *   Dark mode flips automatically via prefers-color-scheme.
 * - All measurements in rem so the whole UI scales with browser font.
 */

:root {
  /* Editorial neutrals — a writerly grayscale that gives the page the
     calm of a printed feature. The palette is intentionally narrow so
     color comes from the four lineage tints (below), used softly.

     The chrome is truly flat: --bg-card matches --bg, so the tree and
     detail panels merge into the page. Only --bg-sunken stands proud,
     which is why chips and icon buttons (the only things that need to
     read as interactive) use it.

     Contrast notes (against --bg = #eeeeee):
       --ink         #1a1a1a  ~16:1  AAA body
       --ink-soft    #444444  ~9:1   AAA body
       --ink-faint   #777777  ~4.6:1 AA body / AAA large
  */
  --bg: #eeeeee;
  --bg-card: #eeeeee;
  --bg-sunken: #dddddd;
  --ink: #1a1a1a;
  --ink-soft: #444444;
  --ink-faint: #777777;
  --rule: #d4d4d4;
  --rule-strong: #a8a8a8;

  /* Lineage tints — muted enough to read as paper tone rather than as
     category color, but with enough hue to be quickly distinguishable
     at a glance. Borders carry a bit more saturation than fills so the
     nodes still group visually when scanned at a distance. */
  --scandi-fill: #e5edd2;
  --scandi-edge: #8a9970;
  --scandi-ink: #2c3320;
  --modernist-fill: #dde4ed;
  --modernist-edge: #7a8a9c;
  --modernist-ink: #1e2a36;
  --reaction-fill: #f0ddd2;
  --reaction-edge: #b48578;
  --reaction-ink: #3a221b;
  --neutral-fill: #ebe6d8;
  --neutral-edge: #a39a8a;
  --neutral-ink: #2a2620;

  /* type */
  --font-serif: "Newsreader", Georgia, "Times New Roman", serif;
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;

  /* layout */
  --radius: 3px;
  --radius-lg: 4px;
}

/* Dark mode is applied either by OS preference OR by an explicit
   .theme-dark class on <html>. The .theme-light class overrides the
   media query when a user has explicitly chosen light. Using :where()
   keeps specificity low so any class always wins over the @media. */
@media (prefers-color-scheme: dark) {
  :root:not(.theme-light) {
    --bg: #1a1a1a;
    --bg-card: #1a1a1a;
    --bg-sunken: #2c2c2c;
    --ink: #eeeeee;
    --ink-soft: #b8b8b8;
    --ink-faint: #888888;
    --rule: #383838;
    --rule-strong: #555555;

    --scandi-fill: #2e3522;
    --scandi-edge: #889670;
    --scandi-ink: #dde2cf;
    --modernist-fill: #232a32;
    --modernist-edge: #8090a0;
    --modernist-ink: #d2dce8;
    --reaction-fill: #322620;
    --reaction-edge: #a88578;
    --reaction-ink: #ebd5c8;
    --neutral-fill: #2c2924;
    --neutral-edge: #8a8272;
    --neutral-ink: #e0d8c8;
  }
}

/* Explicit user choice: dark, no matter what the OS prefers. */
:root.theme-dark {
  --bg: #1a1a1a;
  --bg-card: #1a1a1a;
  --bg-sunken: #2c2c2c;
  --ink: #eeeeee;
  --ink-soft: #b8b8b8;
  --ink-faint: #888888;
  --rule: #383838;
  --rule-strong: #555555;

  --scandi-fill: #2e3522;
  --scandi-edge: #889670;
  --scandi-ink: #dde2cf;
  --modernist-fill: #232a32;
  --modernist-edge: #8090a0;
  --modernist-ink: #d2dce8;
  --reaction-fill: #322620;
  --reaction-edge: #a88578;
  --reaction-ink: #ebd5c8;
  --neutral-fill: #2c2924;
  --neutral-edge: #8a8272;
  --neutral-ink: #e0d8c8;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: underline; text-decoration-color: var(--rule-strong); text-underline-offset: 3px; }
a:hover { text-decoration-color: var(--ink); }

/* ---------- masthead ---------- */
/* Quietly editorial: small serif wordmark, italic tagline. No border
   underneath — the calm of negative space replaces the rule. */
.mast {
  max-width: 1600px;
  margin: 0 auto;
  padding: 1.6rem 2rem 0.4rem;
  display: flex;
  align-items: baseline;
  gap: 1.25rem;
  flex-wrap: wrap;
}
.mast h1 {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 1.6rem;
  letter-spacing: -0.01em;
  margin: 0;
  line-height: 1;
  color: var(--ink);
}
.mast h1 em {
  font-style: italic;
  color: var(--ink-faint);
  font-weight: 300;
}
.mast-tag {
  font-size: 0.82rem;
  color: var(--ink-faint);
  font-style: italic;
  flex: 1 1 auto;
}

/* Theme toggle — small text-style radiogroup at the far right of the
   masthead. The active option gets an underline rather than a fill,
   matching the tab style elsewhere. */
.theme-toggle {
  display: inline-flex;
  gap: 0.6rem;
  align-items: baseline;
  font-size: 0.76rem;
  color: var(--ink-faint);
}
.theme-opt {
  background: transparent;
  border: none;
  padding: 0.1rem 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  border-bottom: 1px solid transparent;
  transition: color 0.12s, border-color 0.12s;
}
.theme-opt:hover {
  color: var(--ink);
}
.theme-opt.active {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

/* ---------- main grid ---------- */
.layout {
  max-width: 1600px;
  margin: 0 auto;
  padding: 1.25rem 2rem 4rem;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 1.75rem;
  align-items: start;
}

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

/* ---------- left column: tree ---------- */
/* Tree column wraps the toolbar and the canvas. The card-style chrome
   is gone (background and border merge with the page), so we use
   simple spacing instead of internal padding. */
.tree-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin: 0 0 1.25rem;
}

.tabs {
  display: flex;
  gap: 1.2rem;
  flex-wrap: wrap;
  margin-bottom: 0;
}
.tab {
  background: transparent;
  border: none;
  color: var(--ink-faint);
  font-family: var(--font-sans);
  font-size: 0.82rem;
  padding: 0.35rem 0;
  margin-right: 0.3rem;
  cursor: pointer;
  border-bottom: 1px solid transparent;
  border-radius: 0;
  transition: color 0.12s, border-color 0.12s;
}
.tab:hover {
  color: var(--ink);
}
.tab.active {
  color: var(--ink);
  border-bottom-color: var(--ink);
  background: transparent;
}

.legend {
  display: flex;
  gap: 0.85rem;
  font-size: 0.72rem;
  color: var(--ink-soft);
  margin-bottom: 0;
  flex-wrap: wrap;
}
.legend-sw {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  margin-right: 0.4rem;
  vertical-align: -1px;
  border: 1px solid;
}
.legend-sw.scandi { background: var(--scandi-fill); border-color: var(--scandi-edge); }
.legend-sw.modernist { background: var(--modernist-fill); border-color: var(--modernist-edge); }
.legend-sw.reaction { background: var(--reaction-fill); border-color: var(--reaction-edge); }
.legend-sw.neutral { background: var(--neutral-fill); border-color: var(--neutral-edge); }

.tree-caption {
  font-size: 0.76rem;
  color: var(--ink-faint);
  margin-top: 0.7rem;
  max-width: 60ch;
  font-style: italic;
}

.tree {
  position: relative;
  background: var(--bg-card);
  border-radius: var(--radius-lg);
  padding: 0;
  min-height: 810px;
}
.tree-canvas {
  position: relative;
  width: 100%;
  height: 810px;
}
.tree-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.edge {
  fill: none;
  stroke: var(--rule-strong);
  stroke-width: 1;
  transition: stroke 0.18s ease, stroke-width 0.18s ease;
}
/* Edges touching the currently-selected node. Darker ink and slightly
   heavier stroke so the active movement's lineage stands out when
   nodes overlap visually. The transition gives a soft fade as you
   click between movements. */
.edge--active {
  stroke: var(--ink-soft);
  stroke-width: 1.4;
}
.edge--secondary {
  stroke-dasharray: 3 4;
  opacity: 0.55;
}

.node {
  position: absolute;
  /* The (left, top) we set in JS is the visual center of the node.
     translate -50%, -50% pulls the box so that center actually sits
     at that point. This means edges drawn between center coordinates
     naturally enter and exit at the visual center of each node, with
     the node's own background occluding the line where it overlaps. */
  transform: translate(-50%, -50%);
  padding: 0.4rem 0.6rem;
  border-radius: var(--radius);
  border: 1px solid;
  cursor: pointer;
  /* Sizing logic:
     - `width: max-content` shrinks the box to its actual text width
     - `min-width` floors it so single-word names don't collapse to a stub
     - `max-width` ceilings it so long names wrap onto a second line
       instead of stretching the whole row
     The net effect: short names get small boxes, long names break on
     word boundaries, and the rare extra-long single word can still
     overflow gracefully because max-width is in rem not ch. */
  width: max-content;
  min-width: 3rem;
  max-width: 7.5rem;
  text-align: left;
  background: var(--bg-card);
  transition: transform 0.12s, box-shadow 0.12s;
  user-select: none;
  word-break: normal;
  overflow-wrap: break-word;
}
.node:hover {
  transform: translate(-50%, calc(-50% - 1px));
}
.node.active {
  border-width: 2px;
  padding: calc(0.4rem - 1px) calc(0.6rem - 1px);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}
.node .yr {
  /* Temporarily hidden — felt cluttered with the caveat-bearing nodes
     like "16th c. Japan; absorbed into Western design 1990s–". Still
     visible in the detail panel meta line. */
  display: none;
  font-size: 0.68rem;
  opacity: 0.7;
  margin-bottom: 0.1rem;
  font-variant-numeric: tabular-nums;
}
.node .nm {
  font-size: 0.80rem;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.005em;
}

.node.scandi { background: var(--scandi-fill); border-color: var(--scandi-edge); color: var(--scandi-ink); }
.node.modernist { background: var(--modernist-fill); border-color: var(--modernist-edge); color: var(--modernist-ink); }
.node.reaction { background: var(--reaction-fill); border-color: var(--reaction-edge); color: var(--reaction-ink); }
.node.neutral { background: var(--neutral-fill); border-color: var(--neutral-edge); color: var(--neutral-ink); }

/* --- Per-Node Overrides --- */
/* Some nodes need a bit of extra love to fit their content. These are
    one-offs, not a general pattern. */

.node[data-id="vienna_secession"] { width: 5.5rem; }
.node[data-id="international"] { width: 6.5rem; }
.node[data-id="mid_century"] { width: 6.5rem; }
.node[data-id="modern_farmhouse"] { width: 6rem; }
.node[data-id="mexican_mod"] { width: 6rem; }
.node[data-id="brazilian_mod"] { width: 6rem; }
.node[data-id="california_mod"] { width: 6rem; }
.node[data-id="contemp_scandi"] { width: 7rem; }
.node[data-id="scandi_mod"] { width: 6.75rem; }
.node[data-id="cocaine_mod"] { width: 4.5rem; }
.node[data-id="tropical_mod"] { width: 5rem; }
.node[data-id="mcm_revival"] { width: 6.25rem; }
.node[data-id="industrial"] { width: 5rem; }
.node[data-id="suburban_traditional"] { width: 5.5rem; }
.node[data-id="hollywood_regency"] { width: 5.5rem; }
.node[data-id="dopamine_decor"] { width: 5.5rem; }
.node[data-id="modern_boho"] { width: 5rem; }
.node[data-id="dark_academia"] { width: 5.5rem; }
.node[data-id="modern_med"] { width: 7rem; }


/* ---------- right column: detail panel ---------- */
.detail {
  background: var(--bg-card);
  border-radius: var(--radius-lg);
  padding: 0;
  position: sticky;
  top: 1.25rem;
}

/* Empty state shown when no movement has been selected yet. The title
   matches .detail-title in scale so the panel doesn't visually jump
   when a movement is picked. */
.detail-empty {
  padding: 0.5rem 0 0;
}
.detail-empty-title {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 1.75rem;
  line-height: 1.15;
  letter-spacing: -0.015em;
  margin: 0 0 0.9rem;
  color: var(--ink);
}
.detail-empty-body {
  margin: 0;
  color: var(--ink-soft);
  font-size: 0.92rem;
  line-height: 1.55;
  max-width: 32ch;
}

/* The .detail h3 rule was previously here; .detail-title now controls
   the title's typography directly. */
.detail .meta {
  font-size: 0.78rem;
  color: var(--ink-faint);
  margin: 0.25rem 0 1.1rem;
  font-variant-numeric: tabular-nums;
  font-style: italic;
}

/* Hand-curated movement image. Sits between the meta and the first
   field, full panel width.

   When there's one image, it renders as an <a class="movement-image">
   wrapping an <img> (linked to its source) or a <div> wrapper if no
   source URL exists. When there are multiple images, it renders as a
   .movement-image-carousel containing a stack of slides and a row of
   dots beneath. Aspect ratios stay natural; no cropping. */
.movement-image {
  display: block;
  margin: 0 0 1.25rem;
  text-decoration: none;
  position: relative;
}
.movement-image img {
  display: block;
  width: 100%;
  height: auto;
  transition: opacity 0.15s;
  margin-top: auto;
  margin-bottom: auto;
}
/* Single-image hover dim. Scoped with :not(.movement-image-carousel)
   so it doesn't fire when hovering the chevron zones of a multi-image
   carousel — the carousel has its own .movement-image-slide.active:hover
   rule that only triggers from the middle (image) third. */
.movement-image:not(.movement-image-carousel):hover img {
  opacity: 0.92;
}

/* Carousel mode. The slide stack uses a CSS grid trick: all slides
   occupy the same grid cell, and only the active one is opaque. This
   gives us a crossfade without measuring image heights in JS, and the
   container takes the height of the tallest slide so layout doesn't
   jump as you flip through. */
.movement-image-carousel {
  /* Override the default 1.25rem bottom margin to leave room for dots. */
  margin-bottom: 0;
  position: relative;
}
.movement-image-carousel:focus-visible {
  outline: 2px solid var(--rule-strong);
  outline-offset: 4px;
  border-radius: 2px;
}
/* Hero image background: --bg-sunken auto-themes (light: #dddddd,
   dark: #2c2c2c) so the image area reads as a quiet raised surface in
   both modes rather than glaring white-tint against dark backgrounds. */
.movement-image-stack {
  display: grid;
  position: relative;
  background-color: var(--bg-sunken);
}
.movement-image-slide {
  grid-column: 1;
  grid-row: 1;
  opacity: 0;
  transition: opacity 0.35s ease;
  pointer-events: none;
  margin-top: auto;
  margin-bottom: auto;
}
.movement-image-slide.active {
  opacity: 1;
  pointer-events: auto;
}
.movement-image-slide a,
.movement-image-slide-link {
  display: block;
  text-decoration: none;
}
.movement-image-slide.active:hover img {
  opacity: 0.92;
}

/* Hover-only navigation zones. Each chevron covers the left or right
   third of the image area; the source-link icon sits centered in the
   middle third. All three fade in on hover at 50% opacity, firm up to
   85% when hovered directly. mix-blend-mode: difference (on the SVGs)
   keeps them legible against any background. */
.movement-image-nav,
.movement-image-source {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 33.333%;
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--ink);
  opacity: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.18s ease;
  padding: 0;
  /* Sit above slides so hover/click registers. */
  z-index: 2;
  /* Anchor reset for the source link, which is an <a>. */
  text-decoration: none;
}
.movement-image-nav.prev { left: 0; }
.movement-image-source { left: 33.333%; }
.movement-image-nav.next { right: 0; }
.movement-image-carousel:hover .movement-image-nav,
.movement-image-carousel:hover .movement-image-source,
.movement-image-nav:focus-visible,
.movement-image-source:focus-visible {
  opacity: 0.5;
}
.movement-image-carousel .movement-image-nav:hover,
.movement-image-carousel .movement-image-source:hover {
  opacity: 0.85;
}
.movement-image-nav:focus-visible,
.movement-image-source:focus-visible {
  outline: none;
}
.movement-image-nav svg,
.movement-image-source svg {
  /* mix-blend-mode: difference inverts the icon against whatever's
     behind it, so it stays legible whether the image is light or dark
     in that region. White color + difference = inverse of background.
     Drop-shadow stays as a soft secondary halo for the mid-gray case
     where difference produces less contrast. */
  color: white;
  mix-blend-mode: difference;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
}

/* Dots row. Sits beneath the image with quiet spacing. Each dot is a
   small circle; the active one is filled, the others outlined. Hover
   firms up the outline. No labels, no counter text — the dots carry
   all the position information. */
.movement-image-dots {
  display: flex;
  gap: 0.4rem;
  justify-content: center;
  padding: 0.6rem 0 1.25rem;
}
.movement-image-dot {
  width: 6px;
  height: 6px;
  padding: 0;
  border-radius: 50%;
  background: transparent;
  border: 1px solid var(--rule-strong);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, transform 0.12s;
}
.movement-image-dot:hover {
  border-color: var(--ink-soft);
}
.movement-image-dot.active {
  background: var(--ink-soft);
  border-color: var(--ink-soft);
}
.movement-image-dot:focus-visible {
  outline: 2px solid var(--rule-strong);
  outline-offset: 2px;
}

/* Fields are stacked: a small uppercase label on its own line, content
   flowing the full panel width beneath. The label uses tracked
   uppercase for an editorial feel. Field text is slightly larger and
   more leaded than before, to favor readability over density. */
.field {
  padding: 0.65rem 0 0.7rem;
  border-top: 1px solid var(--rule);
  font-size: 0.92rem;
}
.field:first-of-type { border-top: none; padding-top: 0; }
.lbl {
  color: var(--ink-faint);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  margin-bottom: 0.35rem;
  font-weight: 500;
}
.field .val {
  color: var(--ink);
  line-height: 1.55;
}
.field .val.empty {
  color: var(--ink-faint);
  font-style: italic;
}
/* Optional curator's note shown beneath the Defining text. Italic,
   smaller, and a touch quieter so it reads as a footnote / sidebar
   rather than competing with the main editorial copy. */
.field-note {
  margin: 0.7rem 0 0;
  color: var(--ink-soft);
  font-size: 0.85rem;
  line-height: 1.5;
}

/* Chips render as inline-flex runs so a 4-parent inherits row reads as
   a wrapping sentence rather than a stack. Composite chips (name +
   camera icon) stay together via .chip-group below. */
.chips {
  display: flex;
  gap: 0.3rem 0.35rem;
  flex-wrap: wrap;
  align-items: center;
}
.chip {
  font-size: 0.78rem;
  padding: 0.2rem 0.55rem;
  border-radius: var(--radius);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  cursor: pointer;
  color: var(--ink);
  transition: all 0.12s;
  font-family: var(--font-sans);
}
.chip:hover {
  background: var(--bg);
  border-color: var(--rule-strong);
}

.actions {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
}
.action-btn {
  font-family: var(--font-sans);
  font-size: 0.8rem;
  padding: 0.4rem 0.75rem;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--bg);
  border: 1px solid var(--ink);
  cursor: pointer;
  transition: opacity 0.12s;
}
.action-btn.secondary {
  background: transparent;
  color: var(--ink);
}
.action-btn:hover { opacity: 0.82; }

/* ---------- examples ---------- */
.examples {
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
}
.example {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.45rem 0.5rem;
  cursor: pointer;
  transition: background 0.12s;
  margin: 0 -0.5rem;
  border-radius: var(--radius);
  /* Reset anchor defaults since .example is now an <a> tag. */
  color: inherit;
  text-decoration: none;
  line-height: 1rem;
}
.example:hover { background: var(--bg-sunken); }
.example:first-child { border-top: none; }
.example .term {
  font-size: 0.88rem;
  color: var(--ink);
  font-weight: 500;
}
.example .term::after {
  content: " ↗";
  color: var(--ink-faint);
  font-weight: 400;
}
.example .note {
  font-size: 0.78rem;
  color: var(--ink-faint);
  font-style: italic;
  line-height: 1.4;
  margin-top: 0.1rem;
}

/* ---------- footer ---------- */
footer {
  max-width: 1600px;
  margin: 0 auto;
  padding: 2.5rem 2rem 3rem;
  color: var(--ink-faint);
  font-size: 0.78rem;
  font-style: italic;
  text-align: center;
}

/* ---------- designer notes ---------- */
.designer-note {
  color: var(--ink-faint);
  font-size: 0.85em;
  font-style: italic;
}

/* ============================================================
   Clickable affordances in the detail panel
   ============================================================
   Anything the user can click in the detail panel uses these:
     .prose-link             inline anchor (designers, see-in frags)
     .chip-group             a name-chip + camera + Pinterest pill
     .chip                   the name half of a chip (button, navigates tree)
     .chip-cam               the camera or Pinterest half (anchor, opens URL)
     .chip-pin               the Pinterest variant of .chip-cam
     .detail-title-row       title plus action buttons toolbar
     .detail-title-action    a single icon link in that toolbar
     .detail-title-pin       the Pinterest variant of .detail-title-action
     .example                a canonical-example tile (anchor)
   The .js-* prefix marks JS hooks; cosmetic classes are separate.
   ============================================================ */

/* Inline text links — used for designers and see-in fragments. Native
   anchors that flow as prose. A hairline underline at rest hints at
   clickability without shouting; the underline firms up on hover. */
.prose-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--rule);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  cursor: pointer;
  transition: color 0.12s, text-decoration-color 0.12s;
}
.prose-link:hover {
  color: var(--ink);
  text-decoration-color: var(--ink);
}
.prose-link:focus-visible {
  outline: 2px solid var(--rule-strong);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Composite lineage chip: name + camera icon + Pinterest icon side by
   side. Square corners and a hairline border keep things editorial. */
.chip-group {
  display: inline-flex;
  align-items: stretch;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--rule);
  background: var(--bg-sunken);
  transition: border-color 0.12s;
}
.chip-group:hover {
  border-color: var(--rule-strong);
}
.chip-group .chip {
  border: none;
  background: transparent;
  border-radius: 0;
  padding: 0.2rem 0.55rem;
  font-size: 0.78rem;
}
.chip-group .chip:hover {
  background: var(--bg);
  border-color: transparent;
}
.chip-cam {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-left: 1px solid var(--rule);
  padding: 0 0.4rem;
  cursor: pointer;
  color: var(--ink-soft);
  /* Anchor reset. */
  text-decoration: none;
  transition: background 0.12s, color 0.12s;
}
.chip-cam:hover {
  background: var(--bg);
  color: var(--ink);
}
.chip-cam:focus-visible {
  outline: 2px solid var(--rule-strong);
  outline-offset: -2px;
}

/* Title row: name on the left, action buttons (Google Images, Pinterest)
   grouped on the right. Both buttons share styling so they read as a
   paired toolbar; only the hover color distinguishes them. */
.detail-title-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.1rem;
}
.detail-title {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 1.75rem;
  line-height: 1.15;
  letter-spacing: -0.015em;
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--ink);
}
.detail-title-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  flex: 0 0 auto;
}
.detail-title-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 0.3rem 0.4rem;
  cursor: pointer;
  color: var(--ink-faint);
  /* Anchor reset: defaults to underlined-blue otherwise. */
  text-decoration: none;
  transition: color 0.12s, border-color 0.12s, background 0.12s;
}
.detail-title-action:hover {
  color: var(--ink-soft);
  border-color: var(--rule-strong);
}
.detail-title-action:focus-visible {
  outline: 2px solid var(--rule-strong);
  outline-offset: 2px;
}
/* Pinterest action gets brand red on hover so the destination is clear. */
.detail-title-pin:hover {
  color: #e60023;
  border-color: var(--rule-strong);
}

/* Pinterest icon inside lineage chip groups — follows the chip-cam
   styling pattern, but uses brand red on hover to distinguish from the
   Google camera. */
.chip-pin:hover {
  color: #e60023;
}

/* See-in fragments need a bit of comma-spacing love so the inline
   links feel like a sentence. */
.see-in .prose-link + .prose-link {
  margin-left: 0; /* commas come from the rendered text */
}

