/* Shared responsive layer for the public portfolio pages. */
/* `clip`, not `hidden`. `overflow-x: hidden` forces overflow-y to compute to
   `auto`, which turns <body> into a scroll container -- and a scroll container
   that never scrolls itself, so every `position: sticky` descendant (the latent
   zoom's pin) silently never engages. `overflow-x: clip` with an implied
   `overflow-y: visible` is a legal non-mutating pair and still stops sideways
   scroll. Do not "simplify" this back to hidden. */
html { overflow-x: clip; }
body { min-width: 0; overflow-x: clip; }
img, svg { max-width: 100%; }
button, input, textarea, select { font: inherit; }
.tag-row { min-width: 0; }

/* ---- hero highlight w/ product hover popover ---- */
.hero-hl { position: relative; font-weight: 600; cursor: default; padding: .05em .2em; border-radius: 3px; background: rgba(230,160,44,.32); -webkit-box-decoration-break: clone; box-decoration-break: clone; transition: background .2s ease; outline: none; }
.hero-hl:hover, .hero-hl:focus-visible { background: rgba(230,160,44,.62); }
/* This span carries tabIndex=0 so the popover is reachable by keyboard, but the
   rule above set `outline: none` and left only a background shift as the focus
   cue -- too weak to count as a visible indicator. Restore a real ring. */
.hero-hl:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
.hero-hl-pop { position: absolute; left: 50%; top: calc(100% + 12px); transform: translateX(-50%) translateY(6px); width: 272px; padding: 13px 15px; border-radius: 14px; background: var(--ink); color: var(--paper); box-shadow: 0 22px 55px -20px rgba(26,26,26,.55); text-align: left; opacity: 0; pointer-events: none; transition: opacity .22s ease, transform .22s ease; z-index: 30; }
.hero-hl-pop.is-open { opacity: 1; transform: translateX(-50%) translateY(0); }
.hero-hl-pop::before { content: ""; position: absolute; left: 50%; top: -6px; width: 12px; height: 12px; background: var(--ink); transform: translateX(-50%) rotate(45deg); border-radius: 2px; }
/* .hero-hl-pop is an INVERTED panel: background --ink, normal text --paper, so
   both flip together and stay correct. The muted label and tag colors must
   therefore be derived from --paper, not from --ink-soft (which is tuned for
   text on --paper). A hardcoded rgba here measured 1.02:1 in dark mode. */
.hero-hl-pop-label { display: block; margin-bottom: 9px; font-family: 'JetBrains Mono', monospace; font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: color-mix(in srgb, var(--paper) 60%, transparent); }
.hero-hl-pop-item { display: flex; align-items: center; gap: 9px; padding: 5px 0; font-size: 13.5px; line-height: 1; }
.hero-hl-pop-item b { font-weight: 600; }
.hero-hl-pop-item em { margin-left: auto; font-style: normal; font-family: 'JetBrains Mono', monospace; font-size: 10px; color: color-mix(in srgb, var(--paper) 60%, transparent); }
.hero-hl-dot { flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; }

@media (max-width: 760px) {
  /* No width override here any more: every content block is margin-aligned to
     --wrap-x, which already tightens on narrow screens, so forcing a width just
     fought those margins. */
  .home-personality-grid, .writing-hero-grid, .contact-grid { grid-template-columns: minmax(0, 1fr) !important; }
  .home-personality-grid { gap: 42px !important; }
  .home-photo { max-width: 420px; }
  .writing-hero-grid { gap: 30px !important; }
  .writing-hero-art { height: 230px !important; max-width: 440px; width: 100%; }
  .card-grid { grid-template-columns: minmax(0, 1fr) !important; gap: 38px !important; }
  .detail-cover { height: clamp(210px, 64vw, 300px) !important; margin-bottom: 30px !important; }
  .tag-row { flex-wrap: wrap; }
  .contact-grid a { justify-self: start !important; }
  .pf-bento { grid-template-columns: 1fr 1fr !important; grid-template-rows: 220px 220px 180px 180px !important; grid-template-areas: "A A" "B C" "D D" "E E" !important; }
  .pf-face { padding: 17px !important; }
}

@media (max-width: 480px) {
  .page-section { padding-top: 20px !important; padding-bottom: 50px !important; }
  .hero-title { font-size: clamp(44px, 17vw, 68px) !important; line-height: .94 !important; }
  .writing-hero-art { height: 200px !important; }
  .detail-body { font-size: 17px !important; line-height: 1.65 !important; }
  .detail-meta { flex-wrap: wrap; gap: 7px 10px !important; }
  .pf-bento { display: flex !important; flex-direction: column; gap: 9px !important; }
  .pf-slot { position: relative !important; min-height: 196px; }
  .pf-slot[data-slot="A"] { min-height: 224px; }
  .pf-slot[data-slot="E"] { min-height: 186px; }
  .pf-face { border-radius: 12px !important; }
}

@media (max-width: 700px) {
  .stats-band { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px; }
  .stats-band-fig { font-size: 42px; }
  /* Tray spacing lives on the item, never as a row gap: the marquee's seamless
     loop needs the row to measure exactly three copies of (set + its own
     spacing). See .tray-mark in theme.css. */
  .tray-mark { margin-inline-end: 34px; font-size: 14px; }
  .tray-pop { width: 240px; }
}
@media (max-width: 420px) {
  .stats-band { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  /* The row wraps and does not animate here, so the loop math no longer applies
     and the gap alone can carry the spacing -- but the per-item margin the
     animated row depends on has to be cleared, or the two stack up. */
  .tray-row { animation: none; flex-wrap: wrap; width: auto; gap: 32px; }
  .tray-mark { margin-inline-end: 0; }
  .tray-viewport::before, .tray-viewport::after { display: none; }
}

@media (hover: none) { .pf-slot:hover { transform: none; } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
}
