/* myportfolioos.com — landing page.
   Built from "Yehudi Baptiste Portfolio.dc.html" (Claude Design canvas).
   The canvas used inline styles and a `style-hover` attribute that only the
   design editor understands; both are real CSS here.
   /writing/ still uses style.css — do not merge the two. */

:root {
  --bg:        #f7f5f1;
  --surface:   #fbfaf7;
  --text:      #1c1a17;
  --text-soft: #3d3830;
  --muted:     #5d574e;
  --faint:     #8a837a;
  --line:      #e4e0d8;
  --line-soft: #ece8e1;
  --chip:      #d8d3c9;
  --dot-off:   #cfc9bd;
  --bubble:    #efece5;
  --accent:    oklch(0.55 0.14 42);
  --live:      oklch(0.62 0.13 150);

  --sans: 'Instrument Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Single-theme light on purpose: this is a controlled brand surface and the
     meddahabdallah.pro reference Yehudi named is light-only. No dark palette is
     defined anywhere in this file — a half-done dark mode reads worse than none. */
  color-scheme: light;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--text); text-decoration: none; }
a:hover { color: var(--accent); }

/* A visible focus ring is not optional: every "Try asking" card is reachable
   by keyboard and the design shipped no focus state at all. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 6px;
}

hr { border: 0; height: 1px; background: var(--line); margin: 0; }

.kicker {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 14px;
}

.spacer { flex: 1; min-width: 8px; }

/* ---------------------------------------------------------------- header */

.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 24px;
  padding: 18px 32px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.identity { display: flex; align-items: center; gap: 14px; }

.avatar {
  width: 44px; height: 44px;
  flex: none;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 0.02em;
}

.identity .name { font-size: 21px; font-weight: 600; letter-spacing: -0.015em; }

.status {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--muted);
}

.dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--live);
  animation: pulse 2.4s ease-in-out infinite;
}

.contact { display: flex; flex-wrap: wrap; align-items: center; gap: 20px; font-size: 14.5px; }
/* 21.8px of text is under the 24px minimum hit area; the padding buys the rest. */
.contact a { padding: 4px 0; }

/* ---------------------------------------------------------------- screen */

/* The portfolio + chat occupies exactly one viewport and never scrolls the page —
   the meddahabdallah.pro model. The rail and the transcript scroll inside
   themselves instead. There is no composer and no disclaimer line in v1 — Yehudi
   removed both on 2026-09-11 — so the transcript runs to the bottom edge.
   Below 900px this releases: a locked viewport with a two-column grid is
   unusable on a phone, and the stacked layout scrolls normally. */
.screen {
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.site-header { flex: none; }

.stage {
  flex: 1 1 0;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(340px, 484px) minmax(0, 1fr);
  align-items: stretch;
  overflow: hidden;
}

/* ---------------------------------------------------------------- rail */

/* The rail FITS. Yehudi's instruction on 2026-09-11: "make the whole resume section on
   the left fit inside the panel. i should be able to see education without scrolling."
   So the type scale and the gaps below are sized to land experience AND education AND
   the résumé link inside one panel at 1280x720, the smallest common laptop.
   `overflow-y: auto` stays as a floor for a genuinely tiny window — it is a safety net,
   not the layout. The mask fade is gone with it: a fade over content that is fully
   visible tells the reader there is more when there is not. */
.rail {
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  overflow: hidden;
}

.rail-scroll {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  padding: 30px 34px 22px;
  display: flex;
  flex-direction: column;
  /* Distribution: tagline pinned to the top edge, Education pinned to the bottom,
     Experience distributed between them. Yehudi's ruling, 2026-09-11 — he saw the centred
     version first and asked for this instead.

     `gap` is the FLOOR, not the spacing. It only binds when the content nearly fills the
     column, which is what keeps the rail from scrolling if the real Instrument Sans turns
     out wider than the headless substitute. Above that, the gaps are whatever the height
     leaves over.

     The cost, stated because it is real and it is his call: the gaps track viewport height
     instead of holding a fixed rhythm. 90px at 1440x900, 230px at 1440x1200. The taller the
     window, the further the three groups drift apart. */
  gap: 48px;
  justify-content: space-between;
}
.rail-scroll::-webkit-scrollbar { width: 8px; }
.rail-scroll::-webkit-scrollbar-thumb { background: var(--chip); border-radius: 4px; }
.rail-scroll::-webkit-scrollbar-track { background: transparent; }

.lede {
  margin: 0;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-wrap: pretty;
}
.lede em { font-style: italic; color: var(--accent); }

/* Three pills under the tagline — his instruction 2026-09-12. They replace the "AI Product"
   chip that sat beside his name in the header: the same treatment, moved to where it
   qualifies the positioning statement rather than the masthead. */
.tags {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin: 0; padding: 0;
  list-style: none;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.tags li { border: 1px solid var(--chip); border-radius: 999px; padding: 5px 11px; }

.block { margin: 0; }

/* Experience takes the middle. With the tagline pinned top and Education pinned bottom,
   the leftover height was sitting in two large empty gaps; this puts it inside the section
   instead, so the five roles span the middle of the column rather than clumping at the top
   of it. The gaps between sections fall back to the 56px floor as a result.
   `space-between` on the timeline spreads the roles. The rule on the left is what keeps them
   reading as one list — see the --chip note on `.timeline`, and do not widen these gaps
   without checking that the role gap stays below the height of a role block. */
.block.grow {
  flex: 1 1 auto;
  /* NOT min-height: 0. With it, this block could be squeezed below its own content and
     the timeline silently overflowed it — on 2026-09-12 the last role rendered 39px BELOW
     its container and sat on top of the Education heading, while a box-edge measurement
     still reported a healthy 38px section gap. `auto` makes an overflow push the rail into
     a scroll, which tests.html already fails on, instead of overlapping in silence. */
  min-height: auto;
  /* Capped. Uncapped on a 1200px-tall window the five roles spread to 105px apart and
     stopped reading as one list. Past the cap the leftover goes back to the section gaps,
     where large empty space is harmless. */
  max-height: 470px;
  display: flex;
  flex-direction: column;
}
.block.grow .timeline {
  flex: 1 1 auto;
  justify-content: space-between;
}

.timeline {
  display: flex;
  flex-direction: column;
  gap: 13px;
  margin: 0;
  padding: 0 0 0 20px;
  list-style: none;
  /* --chip, not --line. The roles sit 30-45px apart so the timeline can fill the middle
     of the rail, and this rule is what is supposed to hold them together as one career
     rather than five detached items. At --line it measured 1.21:1 against the background
     — invisible, so the grouping was surviving on proximity alone with about 7px of margin
     at 1440x1200. --chip is already in the palette and actually reads. */
  border-left: 1px solid var(--chip);
}

.timeline li { position: relative; }

.timeline li::before {
  content: "";
  position: absolute;
  left: -24px; top: 7px;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--dot-off);
}
.timeline li.current::before { background: var(--accent); }

/* --faint on --bg measures 3.44:1, under the 4.5:1 AA floor for text below 18px. These
   are the date ranges — the first thing a recruiter scans for recency and tenure.
   --muted measures 6.56:1 and is already in the palette, so no new colour to rule on. */
.timeline .years {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.25;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.timeline .role {
  display: block;
  font-size: 15px;
  line-height: 1.3;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-top: 1px;
}
.timeline .org {
  display: block;
  font-size: 13px;
  line-height: 1.3;
  color: var(--muted);
  margin-top: 1px;
}

.edu {
  display: flex; flex-direction: column; gap: 6px;
  margin: 0; padding: 0;
  list-style: none;
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-soft);
}

.resume {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-top: 1px solid var(--line);
  background: var(--bg);
  padding: 14px 32px;
  font-size: 15px;
  font-weight: 500;
}
.resume { transition: background 0.15s, color 0.15s; }
.resume:hover { background: var(--surface); color: var(--accent); }
.resume .arrow { font-size: 15px; transition: transform 0.15s; }
.resume:hover .arrow { transform: translate(2px, -2px); }

/* ---------------------------------------------------------------- panel */

.panel { display: flex; flex-direction: column; min-width: 0; height: 100%; min-height: 0; overflow: hidden; }

.panel-head {
  flex: none;
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 28px 40px;
  border-bottom: 1px solid var(--line);
}

.panel-title { margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -0.015em; }
.panel-sub { margin: 4px 0 0; font-family: var(--mono); font-size: 12px; color: var(--faint); }

.reset {
  flex: none;
  background: none;
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 7px 10px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--faint);
  cursor: pointer;
}
.reset:hover { border-color: var(--chip); color: var(--text); }

/* Takes all the slack and scrolls inside itself, and is now the bottom edge of the
   screen: the composer and the disclaimer line were both removed on 2026-09-11. */
.transcript {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  padding: 34px 40px 20px;
  display: flex;
  flex-direction: column;
  gap: 26px;
}

/* The questions sit at the TOP of the panel — Yehudi's ruling, 2026-09-11, when the intro
   bubble was removed. `is-empty` no longer changes the layout; it is kept because it is
   real state (no conversation yet) that site.js sets and v2 will need. */

.log { display: flex; flex-direction: column; gap: 26px; }
.log:empty { display: none; }

/* messages written by site.js */
.turn { display: flex; flex-direction: column; gap: 8px; animation: fadeUp 0.3s ease both; }
.turn.you { align-items: flex-end; }

.turn .who {
  margin: 0;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--faint);
}
.turn.you .who { color: var(--accent); }

.turn.you .bubble {
  max-width: 620px;
  background: var(--bubble);
  border-radius: 14px 14px 4px 14px;
  padding: 13px 17px;
  font-size: 16.5px;
  line-height: 1.55;
}

.turn.ai .bubble { max-width: 760px; }
.turn.ai .bubble p { margin: 0 0 14px; font-size: 17px; line-height: 1.65; text-wrap: pretty; }
.turn.ai .bubble p:last-child { margin-bottom: 0; }

/* Long-form answer structure. The first-principles answer has six sections, two lists
   and two formulas; the other three are plain paragraphs and are unaffected by these
   rules. Styled on `.turn.ai .bubble` and `.qa-item .answer` together so the no-JS
   fallback renders identically to the replayed version. */
.turn.ai .bubble h4,
.qa-item .answer h4 {
  margin: 26px 0 10px;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.35;
}
.turn.ai .bubble h4:first-child,
.qa-item .answer h4:first-child { margin-top: 0; }

.turn.ai .bubble ul,
.qa-item .answer ul {
  margin: 0 0 14px;
  padding-left: 20px;
}
.turn.ai .bubble li,
.qa-item .answer li {
  font-size: 17px;
  line-height: 1.6;
  margin-bottom: 6px;
  text-wrap: pretty;
}
.turn.ai .bubble li:last-child,
.qa-item .answer li:last-child { margin-bottom: 0; }

/* The two formulas — "Goal → Governance → …" and "Context + Memory + State". Mono and
   accented so they read as the spine of the argument rather than as another sentence. */
.turn.ai .bubble .chain,
.qa-item .answer .chain {
  font-family: var(--mono);
  font-size: 13.5px;
  line-height: 1.6;
  letter-spacing: 0.02em;
  color: var(--accent);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px 14px;
  margin: 0 0 16px;
}

/* ---------------------------------------------------------------- try asking */

.qa { margin-top: 6px; }

/* One column. Two columns orphaned the third card when the set went from six questions
   to three on 2026-09-11, and these questions are longer, so full width reads better. */
.qa-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  max-width: 760px;
}

.ask {
  text-align: left;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  /* Full-width and only three of them since 2026-09-11. At the old 15px/51px they read as
     thin strips in a large empty panel, and the empty space outgrew the conversation on a
     tall screen — the `void does not dominate` assertion caught it. More presence is the
     fix for both. */
  padding: 24px 20px;
  font-family: var(--sans);
  font-size: 15.5px;
  color: var(--text);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s, transform 0.15s, box-shadow 0.15s;
}
.ask:hover {
  border-color: var(--accent);
  background: #fff;
  transform: translateY(-1px);
  box-shadow: 0 2px 10px rgba(28, 26, 23, 0.05);
}
.ask:active { transform: translateY(0); box-shadow: none; }
.ask[aria-disabled="true"] { opacity: 0.45; cursor: default; }
.ask[aria-disabled="true"]:hover { border-color: var(--line); background: var(--surface); }
.ask .arrow {
  color: var(--chip);
  font-size: 13px;
  flex: none;
  transition: color 0.15s, transform 0.15s;
}
.ask:hover .arrow { color: var(--accent); transform: translate(2px, -2px); }

/* No-JS / pre-enhancement view: the questions and answers are plain readable
   content. site.js replaces this with the card grid. */
.qa-item { max-width: 760px; margin: 0 0 28px; }
.qa-item h3 { margin: 0 0 10px; font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.qa-item .answer p { margin: 0 0 14px; font-size: 17px; line-height: 1.65; text-wrap: pretty; }
.qa-item .answer p:last-child { margin-bottom: 0; }

/* The panel's bottom edge. Two things were true after the composer came out: the right
   column just stopped mid-air while the rail terminated deliberately, and nothing on the
   first screen pointed at the Portfolio OS section — the Loom demo, the essay and the
   booking link all live below a fold with no scrollbar to hint at it. One quiet row fixes
   both. It is NOT the disclaimer Yehudi deleted: different words, different position,
   and it is a link to somewhere rather than a caption about the page. */
.panel-foot {
  flex: none;
  border-top: 1px solid var(--line);
  padding: 13px 40px;
  background: var(--surface);
}
.panel-foot a {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.04em;
  color: var(--muted);
  display: inline-block;
  padding: 4px 0;
}
.panel-foot a:hover { color: var(--accent); }

/* ---------------------------------------------------------------- portfolio os */

.product {
  border-top: 1px solid var(--line);
  background: var(--surface);
  padding: 64px 32px 72px;
}

.product-inner { max-width: 720px; margin: 0 auto; }

.product-title {
  margin: 0 0 18px;
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.25;
}

.product-lede {
  margin: 0 0 24px;
  font-size: 19px;
  line-height: 1.55;
  letter-spacing: -0.01em;
  color: var(--text);
  text-wrap: pretty;
}

.product p { font-size: 16.5px; line-height: 1.65; color: var(--text-soft); text-wrap: pretty; }

.product h4 {
  margin: 36px 0 12px;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.product a { text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--chip); }
.product a:hover { text-decoration-color: var(--accent); }

.principles { margin: 0; padding-left: 20px; }
.principles li { font-size: 16.5px; line-height: 1.65; color: var(--text-soft); margin-bottom: 12px; }

.cta {
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--bg);
  padding: 20px 22px;
  margin: 32px 0;
}
.cta p { margin: 0 0 10px; }
.cta p:last-child { margin-bottom: 0; }

.writing-list { margin: 0; padding-left: 20px; }
.writing-list li { font-size: 16.5px; line-height: 1.65; }
.writing-list .meta { color: var(--faint); font-size: 14px; }

/* ---------------------------------------------------------------- footer */

.site-footer {
  border-top: 1px solid var(--line);
  padding: 28px 32px 40px;
  text-align: center;
}
.site-footer p { margin: 0; font-family: var(--mono); font-size: 11px; color: var(--faint); }

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

@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@keyframes fadeUp { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .dot { animation: none; }
  .turn { animation: none; }
  .ask:hover { transform: none; }
  * { transition-duration: 0.01ms !important; }
}

/* SPARE HEIGHT GOES TO THE SECTION BOUNDARIES FIRST.
   `.block.grow .timeline` uses space-between, so on a short screen it claimed the leftover
   height before `.rail-scroll` could — roles spread to 26px while the section gaps stayed
   pinned at their 24px floor. At 1366x768 and 1024x768 that produced a 25px gap above
   EDUCATION against a 26px gap between roles: a ratio of 0.96, so the heading read as a
   sixth entry in the timeline. Separation WITHIN a group was being funded ahead of
   separation BETWEEN groups, which is backwards.
   Below 850px tall the timeline holds its 12px floor and stops growing, so everything left
   over flows to the rail's own space-between and widens the boundaries instead. Above that
   there is genuine surplus and filling the middle is the better use of it. */
@media (max-height: 890px) {
  .block.grow { flex: 0 0 auto; }
  .block.grow .timeline { flex: 0 0 auto; justify-content: flex-start; }
}

/* ---------------------------------------------------------------- responsive */

/* 1280x720 and 1366x768 are the common laptop sizes. At 720px tall the transcript
   had 394px of room for 423px of content and clipped the bottom two cards —
   including "Why should we hire you?". Tightening the vertical rhythm buys it back
   without touching the 1440x900 reference rendering. */
/* 890px, not 800px. A 1440x900 display does NOT give the page 900px — Chrome's tab strip
   and URL bar take ~85px, so the real viewport is ~812px. Every tier in this file was
   originally cut against screen dimensions, which left 801-889 uncovered: the full-size
   layout needs ~759px of rail and does not fit until ~890, so a 1440x900 Mac landed in a
   dead band and the rail scrolled with Education below the cut. Verified 2026-09-12 at
   1440x812, 1366x681 and 1280x633. Cut tiers against VIEWPORT height, never screen size. */
@media (max-height: 890px) {
  .panel-head { padding: 18px 40px; }
  .transcript { padding: 22px 40px 22px; gap: 20px; }
  .qa-grid { gap: 10px; }
  .ask { padding: 12px 15px; }
  /* The lede is the <h1> and the only statement of positioning. At 14.5px it rendered
     SMALLER than the 15px card labels — inverted hierarchy on the commonest laptop.
     Floored at 16px; the space comes back out of padding, not out of type.
     The section gap stays generous even here — the whole point of the wider column is
     that the rhythm survives the short-laptop tier instead of being the first thing cut. */
  /* 2026-09-12: the three pills cost the rail ~71px, and it came straight out of the
     space Experience was using to fill the middle — role gaps fell to 7px here and 4px at
     1280x720, where the gap between roles equalled the leading INSIDE a role and five
     entries read as ten alternating lines.
     The pixels come back from the section gap and the padding, not from role separation.
     38px between sections is still roughly 3x the gap between roles, so the three groups
     stay obviously separate while the roles read as five entries again. */
  .rail-scroll { padding: 8px 30px 6px; gap: 24px; }
  .tags li { padding: 4px 9px; font-size: 10px; }
  .lede { font-size: 16px; line-height: 1.4; }
  /* 12px is the floor, not a preference: internal leading inside a role is ~4px, so the
     separator has to beat it by about 3x to read as a separator at all. `space-between` on
     .block.grow pushes this above 12 whenever there is slack; this is what it falls back to
     when there is none. tests.html asserts 12 <= roleGap <= roleBlockHeight. */
  .timeline { gap: 12px; padding-left: 18px; }
  .timeline li::before { left: -22px; top: 6px; width: 6px; height: 6px; }
  .timeline .years { font-size: 10.5px; line-height: 1.2; }
  .timeline .role { font-size: 14px; line-height: 1.25; margin-top: 0; }
  .timeline .org { font-size: 12.5px; line-height: 1.25; }
  .edu { gap: 3px; font-size: 12px; line-height: 1.35; }
  .kicker { margin-bottom: 10px; }
  .resume { padding: 10px 28px; font-size: 14px; }
}

/* Third tier. A 1366x768 laptop gives ~681px of viewport and a 1280x720 gives ~633px —
   below what the compact tier can hold once the pills are in. Everything here is squeezed
   from padding, leading and the section gap; the 12px role floor and the 16px lede are NOT
   touched, because those are the two constraints that stop the timeline collapsing and the
   h1 falling below the card labels. */
@media (max-height: 700px) {
  .rail-scroll { padding: 2px 28px 2px; gap: 20px; }
  .lede { font-size: 16px; line-height: 1.35; }
  .tags li { padding: 3px 8px; }
  .kicker { margin-bottom: 4px; }
  .timeline .years { font-size: 10px; line-height: 1.15; }
  .timeline .role { font-size: 13px; line-height: 1.2; }
  .timeline .org { font-size: 11.5px; line-height: 1.2; }
  .edu { gap: 2px; font-size: 11px; line-height: 1.25; }
  .resume { padding: 8px 28px; font-size: 13.5px; }
}

@media (max-width: 900px) {
  .screen { height: auto; overflow: visible; }
  .panel-foot { padding: 12px 24px; }
  /* `flex: none` is load-bearing. .stage is `flex: 1 1 0` in the desktop rule; once
     .screen stops being a fixed-height flex column, a flex-basis of 0 collapses the
     grid to 0px and every child paints on top of everything below it. Measured at
     390x844 before this line: stage height 0, content 1072px, unreadable. */
  .stage { flex: none; grid-template-columns: 1fr; overflow: visible; }
  .rail { height: auto; overflow: visible; }
  .rail-scroll { flex: none; overflow: visible; padding: 32px 24px 24px; gap: 24px; }
  .resume { padding: 18px 24px; }
  .panel { height: auto; overflow: visible; }
  .transcript { flex: none; overflow: visible; }

  .rail {
    border-right: 0;
    border-bottom: 1px solid var(--line);
    padding: 32px 24px 40px;
  }

  .site-header { padding: 16px 24px; gap: 12px 18px; }
  .identity .name { font-size: 19px; }
  .panel-head { padding: 24px 24px; }
  .transcript { padding: 28px 24px 28px; }
  .product { padding: 48px 24px 56px; }
  .qa-grid { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .status { order: 3; width: 100%; }
  .contact { order: 4; width: 100%; gap: 14px; font-size: 13.5px; }
  .product-title { font-size: 24px; }
  .product-lede { font-size: 17.5px; }
}
