PageSourceSearch

https://asic42.ok.kimi.link/js/charts/eras_products.js

js asic42.ok.kimi.link collected 2026-10-03 04:51:16 UTC 26,335 bytes, 375 lines download raw bytes

1// Custom compute, decade by decade (host #eras-products-chart) · pure DOM
2// Answers §1's follow-up question under "Forty-two years on one line": what the ASIC
3// products of each era actually were — and which END APPLICATIONS they served. Five fixed
4// columns (1980s→2020s), hairline-separated, mono decade eyebrow + serif column title +
5// a hairline vector pictogram of the era's most tangible consumer device (ink lines, one
6// electric-blue accent, currentColor-driven so hover can recolor) above a row of mono
7// outline chips naming the era's terminal use cases. COLLAPSED BY DEFAULT: the five
8// wordmark columns fit one screen; the chips clamp to two lines with a fade. Click a
9// column header (or its "+ EXPAND" hint) to unfold that column's product detail in a
10// SHARED FULL-WIDTH stage below the grid (v8.6: was an in-column panel) — overview row
11// plus exactly TWO product rows side by side, each description clamped to two lines so
12// the open stage stays short; the full record lives inside each row's drill. Single-open
13// accordion. Keyboard: headers are <button>s, Enter/Space toggles; reduced motion snaps
14// without transition. Discipline: every fact is curated from sourced rows in js/data.js
15// (window.RPT — dataset key names cited in each drill), data-v52.js (mining) and
16// data-v51.js deepdive; names without a sourced record are omitted by design (宁缺勿编).
17// No card fills, no color bars. v8.6: decade eyebrow no longer force-uppercased ("1980s").
18(() => {
19  const host = document.getElementById("eras-products-chart");
20  if (!host) return;
21  const body = U.frame(host, {
22    title: "Custom compute, decade by decade",
23    sub: "Blue eyebrow = current decade · click a column to unfold products & dated sources",
24    src: "Kimi Research",
25  });
26
27  const css = `
28  #eras-products-chart .ep-grid { display: flex; align-items: stretch; }
29  #eras-products-chart .ep-col {
30    flex: 1 1 0; min-width: 0; padding: 4px 16px 6px; border-left: 1px solid var(--line);
31    opacity: 0; transform: translateY(10px); transition: opacity .5s ease, transform .5s ease;
32  }
33  #eras-products-chart .ep-col:first-child { border-left: 0; padding-left: 0; }
34  #eras-products-chart .ep-col:last-child { padding-right: 0; }
35  #eras-products-chart .ep-grid.ep-in .ep-col { opacity: 1; transform: none; }
36  #eras-products-chart .ep-head {
37    appearance: none; -webkit-appearance: none; display: block; width: 100%;
38    background: transparent; border: 0; margin: 0; padding: 0 0 6px;
39    font: inherit; color: inherit; text-align: left; cursor: pointer;
40  }
41  #eras-products-chart .ep-head:focus-visible { outline: 1px solid var(--blue); outline-offset: 3px; }
42  #eras-products-chart .ep-eye {
43    font-family: var(--mono); font-size: 10px; letter-spacing: .22em;
44    color: var(--ink-lo);
45  }
46  #eras-products-chart .ep-col.cur .ep-eye { color: var(--blue); }
47  #eras-products-chart .ep-ttl {
48    font-family: var(--sans); font-weight: 700; font-size: 14.5px; color: var(--ink);
49    margin-top: 4px; line-height: 1.35; min-height: 40px; /* 两行占位:五栏图标/chips 同行对齐 */
50  }
51  #eras-products-chart .ep-head:hover .ep-ttl { color: var(--blue); }
52  /* 栏内矢量小图:该年代消费者摸得到的最终产品 —— 墨线 hairline + 一处电蓝点缀,currentColor 驱动 */
53  #eras-products-chart .ep-ico { margin-top: 11px; color: var(--ink-md); line-height: 0; transition: color .14s ease; }
54  #eras-products-chart .ep-ico svg { width: 64px; height: 48px; display: block; }
55  #eras-products-chart .ep-ico svg * { stroke: currentColor; stroke-width: 1.2; fill: none; stroke-linecap: round; stroke-linejoin: round; }
56  #eras-products-chart .ep-ico svg .b { stroke: var(--blue); }
57  #eras-products-chart .ep-ico svg .bf { stroke: none; fill: var(--blue); }
58  #eras-products-chart .ep-head:hover .ep-ico { color: var(--ink); }
59  #eras-products-chart .ep-toggle {
60    font-family: var(--mono); font-size: 9px; letter-spacing: .18em; text-transform: uppercase;
61    color: var(--ink-lo); margin-top: 6px; transition: color .14s ease;
62  }
63  #eras-products-chart .ep-head:hover .ep-toggle,
64  #eras-products-chart .ep-col.open .ep-toggle { color: var(--blue); }
65  /* 共享展开台(v8.6):整表宽度,单开手风琴,高度+opacity 过渡,hairline 分隔 */
66  #eras-products-chart .ep-stage {
67    max-height: 0; opacity: 0; overflow: hidden;
68    transition: max-height .38s ease, opacity .28s ease;
69  }
70  #eras-products-chart .ep-stage.open { opacity: 1; }
71  #eras-products-chart .ep-stage-in { border-top: 1px solid var(--line); margin-top: 10px; }
72  #eras-products-chart .ep-overview {
73    font-family: var(--mono); font-size: 9px; letter-spacing: .12em; text-transform: uppercase;
74    color: var(--ink-lo); padding: 9px 6px 2px 0; cursor: pointer; transition: color .14s ease;
75  }
76  #eras-products-chart .ep-overview:hover { color: var(--blue); }
77  #eras-products-chart .ep-items { display: grid; grid-template-columns: 1fr 1fr; gap: 0 34px; }
78  #eras-products-chart .ep-item {
79    border-top: 1px solid var(--line-lo); padding: 9px 6px 9px 0;
80    cursor: pointer; transition: background .14s ease;
81  }
82  #eras-products-chart .ep-item:hover { background: var(--paper-hi); }
83  #eras-products-chart .ep-name {
84    font-family: var(--sans); font-weight: 700; font-size: 12.5px; color: var(--ink); line-height: 1.35;
85  }
86  #eras-products-chart .ep-item:hover .ep-name { color: var(--blue); }
87  #eras-products-chart .ep-line {
88    font-size: 11.5px; color: var(--ink-md); line-height: 1.55; margin-top: 3px;
89    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
90  }
91  #eras-products-chart .ep-note { font-size: 11.5px; color: var(--ink-lo); margin-top: 14px; line-height: 1.6; }
92  @media (prefers-reduced-motion: reduce) {
93    #eras-products-chart .ep-stage { transition: none; }
94  }
95  @media (max-width: 860px) {
96    #eras-products-chart .ep-grid { flex-direction: column; }
97    #eras-products-chart .ep-col { border-left: 0; border-top: 1px solid var(--line); padding: 14px 0; }
98    #eras-products-chart .ep-col:first-child { border-top: 0; }
99    #eras-products-chart .ep-items { grid-template-columns: 1fr; }
100  }
101  `;
102  const style = document.createElement("style");
103  style.textContent = css;
104  document.head.appendChild(style);
105
106  // cur:true marks the current window's decade (blue eyebrow, echoing timeline42's cur=blue)
107  // icon: hairline vector of the era's most tangible consumer device (viewBox 64×48,
108  //       currentColor strokes, one electric-blue accent — .b stroke / .bf fill)
109  // v9.1:折叠态的终端应用 chips(marks)已全部撤下——栏头只留年代/标题/图标/EXPAND。
110  const ERAS = [
111    {
112      decade: "1980s", title: "Glue logic to the first FPGA",
113      icon: '<svg viewBox="0 0 64 48" aria-hidden="true" focusable="false"><path d="M9 36 L16 24 H56 L60 36 Z"/><path d="M20 28.5 H43"/><path d="M17.5 32 H46.5"/><rect class="bf" x="49.5" y="26.5" width="3.2" height="3.2"/></svg>',
114      drill: {
115        title: "1980s · glue logic to the first FPGA",
116        value: "PAL → gate array → FPGA",
117        sub: "The decade opens on fuse-programmable glue logic and closes with the XC2064 launch release declaring war on gate arrays: 'all the benefits associated with other ASICs … with none of the time, cost and risk penalties' (1985-11-01).",
118        source: "Kimi Research",
119      },
120      items: [
121        { name: "PAL / gate-array ASIC · 1978–84", tip: "Programmable glue logic + the semi-custom route",
122          line: "→ Glue logic the customer writes, and the semi-custom route that reached the living room first: PAL sales doubled six years running; Ferranti's ULA cut the Sinclair ZX81 from 21 TTL chips to 4 at £49.95 — the first mass-consumer gate-array application; LSI Logic carried the model on a $6.0M first round.",
123          drill: {
124            title: "PAL / gate-array ASIC · 1978–84",
125            value: "PAL sales doubled six years running · LSI Logic first round $6.0M",
126            sub: "Signetics 82S100 FPLA (1975–77) and MMI's PAL16L8 (1978-03) let systems houses program the function after the chip left the fab — PAL sales doubled every year for six years, MMI's 1983 handbook called 
126it 'write on silicon', and Data General's team bet on PALs in 1981 as 'the coming thing in chips': custom logic without an ASIC's NRE or lead time. The semi-custom route — pre-diffused transistor arrays customized in the metal layers, faster and cheaper than full-custom — was the dominant ASIC model of the decade; its consumer proof point was the Ferranti ULA inside the £49.95 Sinclair ZX81 (21 TTL chips → 4).",
127            source: "Kimi Research",
128          } },
129        { name: "Xilinx XC2064 · 1985", tip: "The first FPGA — pitched as a better ASIC",
130          line: "→ Aimed at the gate array's own socket — custom logic inside systems products: 'all the benefits … none of the time, cost and risk penalties'. The first FPGA, launched as a better ASIC.",
131          drill: {
132            title: "Xilinx XC2064 · launched 1985-11-01",
133            value: "The first FPGA",
134            sub: "'Logic cell arrays provide all the benefits associated with other ASICs … with none of the time, cost and risk penalties' — the launch release positioned the new product not as a better PLD but directly as a better ASIC.",
135            source: "Company disclosure · Industry & official",
136          } },
137      ],
138    },
139    {
140      decade: "1990s", title: "The FPGA duopoly forms",
141      icon: '<svg viewBox="0 0 64 48" aria-hidden="true" focusable="false"><rect x="4" y="8" width="30" height="22" rx="1.5"/><rect x="8" y="12" width="22" height="13.5" rx="0.6"/><path d="M19 30 V34.5 M13 34.5 H25"/><rect x="42" y="9" width="16" height="27" rx="1"/><path d="M45.5 15 H54.5 M45.5 19 H51.5"/><circle class="bf" cx="53" cy="30.5" r="1.5"/></svg>',
142      drill: {
143        title: "1990s · the FPGA duopoly forms",
144        value: "The 'Fab Four': 64% of PLD, 80% of high-density (1994)",
145        sub: "Dataquest closed the formation phase in October 1995: Actel, Altera, Lattice and Xilinx held the market — and traditional gate-array ASIC still dwarfed all of them.",
146        source: "Kimi Research",
147      },
148      items: [
149        { name: "Xilinx SRAM FPGA", tip: "Took the PLD crown in 1994",
150          line: "→ Communications and network gear: took the PLD crown in 1994 and rode the internet build-out — FY1996 revenue $560M, on the way to $1,659M by FY2001. The incumbent custom route it attacked still dwarfed it mid-decade: LSI $1.3B (+41%), VLSI $590M (1995).",
151          drill: {
152            title: "Xilinx SRAM FPGA · 1990s",
153            value: "PLD crown 1994 · FY1996 $560M",
154            sub: "1990 IPO; took the programmable-logic crown from AMD's MMI-licensed PAL unit in 1994. By then Dataquest's 'Fab Four' — Actel, Altera, Lattice, Xilinx — held 64% of the PLD market and 80% of the high-density segment. The end market carrying it: communications — FY2001 revenue reached $1,659M on the internet build-out. The incumbent gate-array / standard-cell route it attacked still dwarfed programmable logic through the mid-1990s — LSI $1.3B (+41%) and VLSI $590M in 1995, the socket Spartan-3 would later assault; LSI sold its fabs in 2006 and merged into Avago in 2014.",
155            source: "Kimi Research",
156          } },
157        { name: "Altera EPLD → FLEX FPGA", tip: "The duopoly's other pole",
158          line: "→ The duopoly's other pole, wired into the same boom: by 2000, 67% of its revenue came from communications. FLEX 8000 grew ×6 in 1995; revenue $400M, doubled.",
159          drill: {
160            title: "Altera · EPLD → FLEX FPGA",
161            value: "1995: $400M, doubled — FLEX 8000 ×6",
162            sub: "The duopoly's other pole (1988 IPO): the FLEX 8000 SRAM-FPGA family grew sixfold in 1995, and by 2000 communications supplied 67% of revenue. Acquired by Intel in 2015; the asset changed hands again to Silver Lake in 2025.",
163            source: "Kimi Research",
164          } },
165      ],
166    },
167    {
168      decade: "2000s", title: "The cost-curve assault on ASIC",
169      icon: '<svg viewBox="0 0 64 48" aria-hidden="true" focusable="false"><circle cx="21" cy="16" r="8.5"/><circle cx="21" cy="16" r="2.4"/><rect x="5" y="25" width="54" height="13" rx="1"/><path d="M9.5 30 H33"/><path d="M45 30 H51.5"/><circle class="bf" cx="54.5" cy="34" r="1.3"/></svg>',
170      drill: {
171        title: "2000s · the cost-curve assault on ASIC",
172        value: "A $23B ASIC/ASSP market under attack",
173        sub: "Out of the 2001 clearing (industry −32%, both duopolists −39%), programmable logic counter-attacked on cost: Spartan-3 at under $12 per million gates. The decade's structured-ASIC and challenger-FPGA experiments did not survive.",
174        source: "Kimi Research",
175      },
176      items: [
177        { name: "Xilinx Spartan-3 · 2003", tip: "Million-gate FPGA under $12",
178          line: "→ Xilinx's own target list read like a living-room inventory: set-top boxes and PVRs, DVD-RW players, LCD/HDTVs, video-on-demand gear, residential gateways and low-cost routers — at $12, a million gates became a consumer part (1M units to 1,200+ customers within a year).",
179          drill: {
180            title: "Xilinx Spartan-3 · 2003-10-06",
181            value: "A million-gate FPGA under $12",
182            sub: "Two quarters out of the −32% trough, Xilinx's CEO declared an assault on the $23B ASIC/ASSP market: 'As traditional ASIC and ASSP design starts continue to decline … FPGA design starts using Spartan-3 will ultimately fuel higher growth.' The cost curve, weaponized — Xilinx's own target list ran set-top boxes and PVRs, DVD-RW, LCD/HDTV, VoD gear, residential gateways and low-cost routers; 1M units to 1,200+ customers within a year.",
183            source: "Kimi Research",
184          } },
185        { name: "Structured ASIC · eASIC / Tabula", tip: "The middle routes that failed",
186          line: "→ The middle routes aimed at the same consumer sockets — between FPGA flexibility and cell-based cost: eASIC kept raising through 2004–2012, absorbed by Intel in 2018; Tabula raised $214M, shut down 2015. The era's verdict: the experiments failed.",
187          drill: {
188            title: "Structured ASIC · eASIC / Tabula ABAX",
189            value: "Tabula $214M cumulative, shut down 2015-03 · eASIC absorbed 2018",
190            sub: "Between FPGA flexibility and cell-based cost: eASIC kept raising through 2004–2012 and was absorbed by Intel in 2018. Tabula's 3D time-multiplexed FPGA raised a Series D of $108M in 2011-03 and moved to Intel 22nm in 2012 — the WSJ flagged the 'programmable-chip startup graveyard' at the funding peak; the duopoly's moat sat in toolchains and ecosystem, not silicon. The report's clearing line for the era: 'structured-ASIC experiments failed.'",
191            source: "Kimi Research",
192          } },
193      ],
194    },
195    {
196      decade: "2010s", title: "The cloud builds its own",
197      icon: '<svg viewBox="0 0 64 48" aria-hidden="true" focusable="false"><rect x="22" y="4" width="20" height="40" rx="3.5"/><rect x="25.5" y="10.5" width="13" height="26.5" rx="0.8"/><path d="M30 7.4 H34"/><path d="M30.5 40.6 H33.5"/><circle class="bf" cx="32" cy="23.5" r="1.8"/></svg>',
198      items: [
199        { name: "Google TPU v1 · 2015", tip: "First in-house inference ASIC",
200          line: "→ Cloud inference behind search and apps: Microsoft wired 1,632 FPGA servers for Bing ranking by end-2012 (+95% throughput, disclosed 2014); Google's TPU v1 ran in production from 2015 at 92 TOPS INT8; Alibaba's Hanguang 800 followed in 2019.",
201          drill: {
202            title: "Google TPU v1 · deployed 2015",
203            value: "92 TOPS INT8 · 65,536 8-bit MACs",
204            sub: "In production since 2015, disclosed 2016-05, documented at ISCA 2017: an average 15–30× performance and 30–80× efficiency vs Haswell/K80 — inference only, exhibit zero of the inference-ASIC wave. The route opened with Microsoft Project Catapult: each server a Xeon plus a Stratix V PCIe daughter card, 1,632 servers wired by end-2012 and disclosed at ISCA 2014 — +95% throughput at a fixed latency distribution (Brainwave extended the FPGA route to real-time inference, Hot Chips 2017). It closed the decade in China: Alibaba's Hanguang 800 (2019-09-25), billed on stage as the world's highest-performance AI inference chip — 'the first step of a long march' (Zhang Jianfeng).",
205            source: "Kimi Research",
206          } },
207        { name: "Mining ASIC hash boards · 2013–19", tip: "55nm → 16nm in three years; two winters",
208          line: "→ Bitcoin mining: Butterfly Labs, Avalon and Bitmain raced hash boards from 55nm to 16nm FinFET in three years at unseen volumes — custom silicon's first mass-market rehearsal. Two winters followed: Bitmain's IPO lapsed and Alchip fell −19% (2019); the 2021–22 rerun ended in NVIDIA's $1.34B charge and the Ethereum merge.",
209          drill: {
210            title: "Mining ASIC hash boards · 2013–2022",
211            value: "55nm → 16nm FinFET in three years · two winters",
212            sub: "2013–17: Butterfly Labs, Avalon and Bitmain race nodes at mass-market volume; Bitmain even shipped an inference accelerator (Sophon BM1680, 2017) ahead of most AI-chip unicorns. Winter ①: BTC peaked Dec-2017; Bitmain's HKEX filing lapsed 2019-03; Alchip FY2018 revenue fell 19% (NT$4.27B→NT$3.45B) as mining programs widely attributed to Bitmain unwound. Winter ②: BTC peaked Nov-2021; GUC's crypto-linked AI/ML bucket rolled from ~35% (2022H1) to ~18% (9M 2022) within quarters; NVIDIA took a $1.34B inventory charge (2022-08-24); the Ethereum merge ended GPU mining (2022-09-15).",
213            source: "Kimi Research",
214          } },
215      ],
216    },
217    {
218      decade: "2020s", title: "Inference ASICs at fleet scale", cur: true,
219      icon: '<svg viewBox="0 0 64 48" aria-hidden="true" focusable="false"><rect x="13" y="8" width="38" height="25" rx="1.5"/><path d="M8 37 H56 L59.5 41 H4.5 Z"/><path class="b" d="M32 14.5 C32.9 18.2 33.8 19.1 37.5 20 C33.8 20.9 32.9 21.8 32 25.5 C31.1 21.8 30.2 20.9 26.5 20 C30.2 19.1 31.1 18.2 32 14.5 Z"/></svg>',
220      drill: {
221        title: "2020s · inference ASICs at fleet scale",
222        value: "1.4M TRN2 units deployed · TPU 2027E 6–12M units",
223        sub: "Cloud in-house silicon is now the demand pillar: hyperscaler fleets at million-unit scale, a merchant XPU duopoly (Broadcom / Marvell) behind them and a design-services bench beside — while the 2020–21 startup cohort clears through absorption.",
224        source: "Kimi Research",
225      },
226      items: [
227        { name: "Google TPU · fleet generation", tip: "2027E: 6–12M units (2× spread)",
228          line: "→ Google's AI datacenter fleet at million-unit scale: 2027 shipments estimated at 6–12M units (three houses, 2× spread); Broadcom co-design — Broadcom holds 80–85% of high-end custom silicon, Marvell is #2.",
229          drill: {
230            title: "Google TPU · the fleet generation",
231            value: "2027E shipments: 6–12M units",
232            sub: "Three sell-side estimates (UBS / CICC / Guosen) differ 2× and are listed side-by-side without reconciliation. Broadcom is the multi-generation co-design partner (renewed 2026-04); the TPU v9 ramp is set for 2028. The merchant supply behind the fleets: Broadcom holds 80–85% of high-end custom silicon; Marvell is number two at 10–12% (its Microsoft Maia 3nm design with CY2027 ramp is a sell-side attribution the company has not confirmed). The design bench: Alchip (widely identified with the AWS Trainium line), GUC (3nm-and-below 57% of revenue @2026Q1), MediaTek (TPU v8 on N3).",
233            source: "Kimi Research",
234          } },
235        { name: "AWS Trainium 2 / 3", tip: "1.4M TRN2 units, fully subscribed",
236          line: "→ AWS's in-house training/inference fleet: TRN2 1.4M units deployed, fully subscribed (2026-02); TRN3 on 3nm, next gen to 2nm. The 2020–21 startup cohort built for the same breakout cleared through absorption, not bankruptcy.",
237          drill: {
238            title: "AWS Trainium 2 / 3",
239            value: "TRN2: 1.4M units deployed, fully subscribed (2026-02)",
240            sub: "Trainium3 on 3nm entered volume production as AWS pulled its next-generation in-house chip forward to 2nm design finalization (Alchip results call, 2026-03) — in-house ASICs now track the merchant-GPU process cadence exactly. The 2020–21 startup cohort built for the same inference breakout — Graphcore (Series E $222M @ $2.77B), SambaNova ($5.1B), Cerebras (>$4B), Groq, Tenstorrent — cleared through absorption, not bankruptcy: Graphcore sold to SoftBank below cumulative funding; Groq licensed to NVIDIA (≈$20B, press); Cerebras listed 2026-05.",
241            source: "Kimi Research",
242          } },
243      ],
244    },
245  ];
246
247  const grid = document.createElement("div");
248  grid.className = "ep-grid";
249  grid.setAttribute("data-drill-keep", "1");
250  body.appendChild(grid);
251
252  // 共享展开台:整表宽度、单开手风琴(v8.6)
253  const stage = document.createElement("div");
254  stage.className = "ep-stage";
255  stage.setAttribute("data-drill-keep", "1");
256  const stageIn = document.createElement("div");
257  stageIn.className = "ep-stage-in";
258  const ov = document.createElement("div");
259  ov.className = "ep-overview";
260  ov.setAttribute("data-drill-keep", "1");
261  const items = document.createElement("div");
262  items.className = "ep-items";
263  stageIn.appendChild(ov);
264  stageIn.appendChild(items);
265  stage.appendChild(stageIn);
266  body.appendChild(stage);
267
268  let openIdx = -1;
269  const heads = [];
270
271  function syncHeads() {
272    heads.forEach((h, i) => {
273      const open = i === openIdx;
274      h.col.classList.toggle("open", open);
275      h.btn.setAttribute("aria-expanded", open ? "true" : "false");
276      h.tog.textContent = open ? "- COLLAPSE" : "+ EXPAND";
277    });
278  }
279
280  function fillStage(era) {
281    ov.textContent = "▸ " + era.decade + " overview — dated sources";
282    // v8.9:2010s 的 overview drill 零增量已撤(审计 A 级)——无 drill 的年代不挂点击。
283    ov.style.cursor = era.drill ? "" : "default";
284    ov.onclick = era.drill ? e => {
285      U.showDrill({ title: era.drill.title, value: era.drill.value, sub: era.drill.sub,
286        source: era.drill.source, x: e.clientX, y: e.clientY });
287    } : null;
288    items.innerHTML = "";
289    era.items.forEach(it => {
290      const row = document.createElement("div");
291      row.className = "ep-item";
292      row.setAttribute("data-drill-keep", "1");
293      const nm = document.createElement("div");
294      nm.className = "ep-name"; nm.textContent = it.name;
295      const ln = document.createElement("div");
296      ln.className = "ep-line"; ln.textContent = it.line;
297      row.appendChild(nm); row.appendChild(ln);
298      row.addEventListener("mouseenter", e => U.showTip(it.tip, e.clientX, e.clientY));
299      row.addEventListener("mouseleave", U.hideTip);
300      row.addEventListener("click", e => {
301        U.showDrill({ title: it.drill.title, value: it.drill.value, sub: it.drill.sub,
302          source: it.drill.source, x: e.clientX, y: e.clientY });
303      });
304      items.appendChild(row);
305    });
306  }
307
308  function closeStage() {
309    openIdx = -1;
310    stage.classList.remove("open");
311    stage.style.maxHeight = "0px";
312    syncHeads();
313  }
314  function openEra(i) {
315    fillStage(ERAS[i]);
316    openIdx = i;
317    stage.classList.add("open");
318    // 内容替换后下一帧量高,保证过渡从旧高度平滑到新高度
319    requestAnimationFrame(() => { stage.style.maxHeight = stage.scrollHeight + "px"; });
320    syncHeads();
321  }
322
323  ERAS.forEach((era, i) => {
324    const col = document.createElement("div");
325    col.className = "ep-col" + (era.cur ? " cur" : "");
326    col.style.transitionDelay = (i * 0.09) + "s";
327
328    // 栏头 = 折叠/展开开关(button → 键盘可达)
329    const head = document.createElement("button");
330    head.type = "button";
331    head.className = "ep-head";
332    head.setAttribute("data-drill-keep", "1");
333    head.setAttribute("aria-expanded", "false");
334    const eye = document.createElement("div");
335    eye.className = "ep-eye"; eye.textContent = era.decade;
336    const ttl = document.createElement("div");
337    ttl.className = "ep-ttl"; ttl.textContent = era.title;
338    const ico = document.createElement("div");
339    ico.className = "ep-ico"; ico.innerHTML = era.icon;
340    const tog = document.createElement("div");
341    tog.className = "ep-toggle"; tog.textContent = "+ EXPAND";
342    head.appendChild(eye); head.appendChild(ttl); head.appendChild(ico); head.appendChild(tog);
343    col.appendChild(head);
344    grid.appendChild(col);
345    heads.push({ col, btn: head, tog });
346
347    head.addEventListener("mouseenter", e => U.showTip("Click to unfold this decade's products", e.clientX, e.clientY));
348    head.addEventListener("mouseleave", U.hideTip);
349    head.addEventListener("click", () => { openIdx === i ? closeStage() : openEra(i); });
350  });
351
352  const note = document.createElement("p");
353  note.className = "ep-note";
354  note.textContent = "Clicking a column unfolds its products across the full width below — descriptions clamped to two lines, the full record 
354inside each drill. Products are listed only where the report dataset carries a sourced record; names without one are omitted by design. Figures and attributions are dated in each drill-down.";
355  body.appendChild(note);
356
357  // 重排后(换行/字号变化)重算展开台高度,避免 max-height 裁切
358  window.addEventListener("resize", () => {
359    if (openIdx >= 0) stage.style.maxHeight = stage.scrollHeight + "px";
360  });
361
362  // ── 入场:逐栏淡入(reduced-motion → 直接完成帧)──
363  const reduced = matchMedia("(prefers-reduced-motion: reduce)").matches;
364  if (reduced) {
365    grid.querySelectorAll(".ep-col").forEach(c => { c.style.transition = "none"; });
366    grid.classList.add("ep-in");
367  } else {
368    const io = new IntersectionObserver(es => {
369      if (!es[0].isIntersecting) return;
370      io.disconnect();
371      requestAnimationFrame(() => grid.classList.add("ep-in"));
372    }, { threshold: 0.15 });
373    io.observe(grid);
374  }
375})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.