/* ============================================================
   SOFTWIN PRECISION · dark-first industrial interface
   Cold technical neutrals with Softwin red reserved for live signals.
   ============================================================ */

/* ---------- 1. Tokens ---------- */

:root {
  --display: "Anton", "Arial Narrow", Impact, "PingFang SC", "Microsoft YaHei", sans-serif;
  --sans: "Space Grotesk", ui-sans-serif, -apple-system, "Segoe UI", Roboto,
          "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
  --sans-cjk-black: -apple-system, "PingFang SC", "Hiragino Sans GB",
          "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* marquee runs six scripts — latin mono first, then per-script system faces */
  --mono-multi: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas,
          "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic", Meiryo,
          "Apple SD Gothic Neo", "Malgun Gothic", "Noto Sans KR",
          "PingFang SC", "Microsoft YaHei", "Noto Sans SC",
          "PingFang TC", "Microsoft JhengHei", "Noto Sans TC",
          Thonburi, "Leelawadee UI", "Noto Sans Thai", monospace;
  --frame: 1280px;
  --pad: clamp(20px, 4.5vw, 56px);
  --rail-w: 46px;
  --topbar-h: 179px;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --amber: #d7222c;      /* Softwin signal red; retained token name for compatibility */

  /* Type scale. Three mono steps and one body step carry the whole page;
     anything off this scale is a deliberate one-off (hero, proof numerals,
     product names, the readout value) and should stay countable on one hand.
     Before adding a size, check whether one of these already fits. */
  --fm-1: 1rem;          /* mono: section tags, proof captions, readout labels */
  --fm-2: 0.875rem;      /* mono: nav, rail, meta, notes, log rows            */
  --fm-3: 0.8rem;        /* mono: dense lists — directory, equipment types    */
  --ft-body: 1.06rem;    /* sans: every supporting line under a heading       */
  --on-amber: #ffffff;
}

html[data-theme="dark"] {
  color-scheme: dark;
  --bg: #090c10;
  --bg-2: #0f141a;
  --ink: #edf1f3;
  --muted: #929da6;
  --accent: #e02a33;
  --line: rgba(221, 229, 234, 0.14);
  --line-strong: rgba(221, 229, 234, 0.4);
  --dot: rgba(221, 229, 234, 0.045);
  --ghost-stroke: rgba(221, 229, 234, 0.18);
  --inv-bg: #dfe4e7;
  --inv-ink: #0c1116;
  --inv-muted: #4f5b64;
  --inv-ghost: rgba(19, 19, 19, 0.14);
  --die-edge: rgba(19, 19, 19, 0.6);
  --sc-line: rgba(19, 19, 19, 0.3);
  --sc-fill: rgba(19, 19, 19, 0.1);
  --sc-fill-2: rgba(19, 19, 19, 0.055);
  --amb-l: #d29200;
  --amb-r: #a06f00;
  --m-top: #2f3238;
  --m-l: #23262b;
  --m-r: #1a1c20;
  --m-stroke: rgba(221, 229, 234, 0.2);
  --m-stroke-2: rgba(221, 229, 234, 0.42);
  --floor: #10151b;
  --iso-shadow: rgba(0, 0, 0, 0.32);
  --alarm: #ff5a5f;
  --thumb: #2b2d31;
}

html[data-theme="light"] {
  color-scheme: light;
  --bg: #e8ecef;
  --bg-2: #dce2e6;
  --ink: #10171e;
  --muted: #52606a;
  --accent: #b91f29;
  --line: rgba(16, 23, 30, 0.17);
  --line-strong: rgba(16, 23, 30, 0.46);
  --dot: rgba(16, 23, 30, 0.055);
  --ghost-stroke: rgba(16, 23, 30, 0.2);
  --inv-bg: #0c1116;
  --inv-ink: #edf1f3;
  --inv-muted: #98a3ab;
  --inv-ghost: rgba(237, 241, 243, 0.18);
  --die-edge: rgba(19, 19, 19, 0.6);
  --sc-line: rgba(242, 239, 232, 0.34);
  --sc-fill: rgba(242, 239, 232, 0.14);
  --sc-fill-2: rgba(242, 239, 232, 0.07);
  --amb-l: #e0a000;
  --amb-r: #b97f00;
  --m-top: #e7ecef;
  --m-l: #d4dce1;
  --m-r: #c2cdd4;
  --m-stroke: rgba(16, 23, 30, 0.34);
  --m-stroke-2: rgba(16, 23, 30, 0.55);
  --floor: #dbe2e6;
  --iso-shadow: rgba(16, 23, 30, 0.12);
  --alarm: #b3261e;
  --thumb: #bcc6cc;
}

/* ---------- 2. Base ---------- */

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  min-height: 100vh;
  overflow-x: clip;
  color: var(--ink);
  background:
    radial-gradient(var(--dot) 1px, transparent 1px) 0 0 / 30px 30px,
    var(--bg);
  font-family: var(--sans);
  font-size: 16.5px;
  font-weight: 500;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  transition: background-color 0.25s ease, color 0.25s ease;
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
p, h1, h2, h3, figure, ol, ul { margin: 0; padding: 0; }
ol, ul { list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
svg { display: block; }
u { text-decoration: none; }

::selection { background: var(--amber); color: var(--on-amber); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: var(--thumb); border: 2px solid var(--bg); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.frame {
  width: min(var(--frame), 100% - 2 * var(--pad));
  margin-inline: auto;
}

section[id] { scroll-margin-top: 136px; }

.logo-light { display: none; }
html[data-theme="light"] .logo-light { display: block; }
html[data-theme="light"] .logo-dark { display: none; }

.skip-link {
  position: fixed;
  top: 10px;
  left: 10px;
  z-index: 300;
  padding: 12px 18px;
  background: var(--amber);
  color: var(--on-amber);
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
  text-transform: uppercase;
  transform: translateY(-70px);
  transition: transform 0.2s var(--ease);
}
.skip-link:focus-visible { transform: translateY(0); outline-offset: 0; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.grain {
  position: fixed;
  inset: 0;
  z-index: 140;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.8'/%3E%3C/svg%3E");
}

/* ---------- 3. Display type ---------- */

.display {
  font-family: var(--display);
  font-weight: 400;
  letter-spacing: 0.012em;
  line-height: 0.98;
  text-transform: uppercase;
}
html[lang^="zh"] .display {
  font-family: var(--sans-cjk-black);
  font-weight: 800;
  letter-spacing: 0.02em;
  line-height: 1.12;
}

/* ---------- 4. Fixed rail ---------- */

.rail {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 90;
  display: flex;
  width: var(--rail-w);
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 16px 0;
  border-right: 1px solid var(--line);
  background:
    repeating-linear-gradient(180deg, var(--line) 0 1px, transparent 1px 12px) right center / 7px 100% no-repeat,
    var(--bg);
  transition: background-color 0.25s ease;
}
.rail span {
  writing-mode: vertical-rl;
  font-family: var(--mono);
  font-size: var(--fm-2);
  letter-spacing: 0.2em;
  color: var(--muted);
  text-transform: uppercase;
  white-space: nowrap;
}
/* Two axes, read like a controller's position registers. Y is the page's own
   travel (scrollY) and keeps the amber; X is the operator's — pointer position
   across the viewport — and stays ink, so the pair reads as one instrument
   rather than two accents competing. Both pad to six digits so the stack is a
   rectangle. The rail is hidden below 1101px, which is also where there is no
   pointer to report. */
/* horizontal-tb on the wrapper only: .rail span puts every span in vertical-rl,
   and in a vertical writing mode `flex-direction: column` runs left-to-right,
   which would sit the two axes side by side in a 46px rail. The children stay
   vertical-rl through that same .rail span rule. */
.rail .rail-axes {
  writing-mode: horizontal-tb;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}
.rail-axis b { font-weight: 600; }
.rail-axis-x b { color: var(--ink); }
.rail-axis-y b { color: var(--accent); }
/* The brand runs the full height of the window and now shares the rail with a
   two-axis readout, so it is sized off the viewport HEIGHT, not the width — a
   fixed 0.875rem collides with the axes in a 600px-tall window. The cap is the
   rail's normal size, so full-height screens look untouched. */
.rail .rail-brand { font-size: clamp(0.6rem, 1.6vh, 0.875rem); }

@media (min-width: 1101px) {
  body { padding-left: var(--rail-w); }
}
@media (max-width: 1100px) {
  .rail { display: none; }
}

/* ---------- 5. Top bar ---------- */

/* The whole header is fixed, not just the nav row: on a one-page site the
   anchors and the ask bar both need to stay reachable. It is FIXED with a
   constant-height spacer on <body> rather than sticky, because the row
   condenses on scroll and a sticky box changing height relayouts everything
   below it — a visible scroll jump. With the spacer the extra clearance simply
   scrolls under the bar and nothing moves. --topbar-h is the un-condensed
   height; setupTopbar() re-measures it, this value is the no-JS fallback. */
.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 220;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  transition: background-color 0.25s ease;
}
body { padding-top: var(--topbar-h); }
@media (min-width: 1101px) { .topbar { left: var(--rail-w); } }
/* On a phone the header wraps to two rows and even condensed it is 180px —
   a fifth of the screen, permanently. Below 900px it goes back to what it was:
   the header scrolls away and only the nav row sticks. */
@media (max-width: 900px) {
  .topbar { position: static; }
  body { padding-top: 0; }
  .topnav { position: sticky; top: 0; z-index: 100; }
}
.topbar-row {
  width: min(var(--frame), 100% - 2 * var(--pad));
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 20px 0 18px;
  transition: padding 0.2s var(--ease);
}
.brand img { width: 222px; transition: width 0.2s var(--ease); }
/* Condensed once you leave the hero: the logo halves, the clock goes, and the
   header drops from 179px to ~120px so it stops eating a fifth of the window. */
html[data-scrolled] .topbar-row { padding: 9px 0; }
html[data-scrolled] .brand img { width: 132px; }
html[data-scrolled] .clock { display: none; }
html[data-scrolled] .topnav a { padding: 12px 0; }

.topbar-meta { display: flex; align-items: center; gap: 18px; }
.clock {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--mono);
  font-size: var(--fm-2);
  color: var(--muted);
  letter-spacing: 0.07em;
}
.clock i {
  width: 6px;
  height: 6px;
  background: var(--amber);
  animation: lamp 2.6s ease-in-out infinite alternate;
}
.clock b { font-weight: 400; font-variant-numeric: tabular-nums; }
@keyframes lamp { from { opacity: 0.45; } to { opacity: 1; } }

.mode, .lang { display: inline-flex; gap: 4px; }
.mode button,
.lang button,
.lang a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 30px;
  padding: 0 9px;
  border: 1px solid transparent;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fm-2);
  letter-spacing: 0.04em;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.mode button:hover, .lang button:hover { color: var(--ink); }
.mode button[aria-pressed="true"],
.lang a { text-decoration: none; }
.lang button[aria-pressed="true"],
.lang a[aria-current="page"] { color: var(--accent); border-color: var(--accent); }
.mode button svg { width: 16px; height: 16px; }

.topnav {
  display: flex;
  align-items: center;
  gap: clamp(20px, 3vw, 38px);
  padding: 0 var(--pad);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  overflow-x: auto;
  scrollbar-width: none;
  transition: background-color 0.25s ease;
}
.topnav::-webkit-scrollbar { display: none; }
.topnav a {
  padding: 15px 0;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color 0.15s ease;
}
.topnav a:hover { color: var(--accent); }
.topnav-start {
  margin-left: auto;
  color: var(--accent) !important;
  border: 1px solid var(--accent);
  padding: 8px 18px !important;
  margin-block: 8px;
  transition: background-color 0.15s ease, color 0.15s ease !important;
}
.topnav-start:hover { background: var(--amber); color: var(--on-amber) !important; border-color: var(--amber); }

/* ---------- 6. Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 16px 26px;
  border: 1px solid transparent;
  font-size: 1.03rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: transform 0.16s var(--ease), box-shadow 0.16s var(--ease),
              background-color 0.16s ease, color 0.16s ease, border-color 0.16s ease;
}
.btn b { font-weight: 700; }
.btn-solid {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bg);
}
.btn-solid:hover {
  transform: translate(-3px, -3px);
  box-shadow: 5px 5px 0 var(--ink);
}
.btn-solid:active { transform: translate(0, 0); box-shadow: none; }
.btn-ghost {
  border-color: var(--line-strong);
  color: var(--ink);
}
.btn-ghost:hover {
  border-color: var(--accent);
  color: var(--accent);
  transform: translate(-3px, -3px);
  box-shadow: 5px 5px 0 rgba(215, 34, 44, 0.22);
}
.btn-ghost:active { transform: none; box-shadow: none; }
.btn-big { padding: 22px 44px; font-size: 1.03rem; }

/* ---------- 7. Section furniture ---------- */

.sec-tag {
  display: inline-flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: clamp(26px, 4vw, 44px);
  font-family: var(--mono);
  font-size: var(--fm-1);
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}
.sec-tag::before {
  content: "";
  align-self: center;
  width: 24px;
  height: 3px;
  background: var(--accent);
}
.sec-tag span { color: var(--muted); }
.sec-title {
  max-width: 900px;
  margin-bottom: clamp(18px, 3vw, 30px);
  font-size: clamp(2.3rem, 5.6vw, 4.6rem);
}
.co-title {
  max-width: 100%;
  font-size: clamp(1.6rem, 3.15vw, 2.85rem);
  line-height: 0.98;
}
.co-title span { display: block; }
.co-lead { max-width: 620px; }
.sec-lead {
  max-width: 720px;
  color: var(--muted);
  font-size: var(--ft-body);
  line-height: 1.65;
}

/* ---------- 8. Hero ---------- */

.hero { position: relative; overflow: hidden; }
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(600px circle at var(--mx, 74%) var(--my, 18%),
              rgba(255, 179, 0, 0.07), transparent 65%);
}
.hero-inner {
  position: relative;
  z-index: 1;
  padding: clamp(48px, 7vh, 96px) 0 clamp(40px, 5vh, 64px);
}
.kicker {
  display: inline-flex;
  gap: 12px;
  margin-bottom: clamp(18px, 3vh, 32px);
  font-family: var(--mono);
  font-size: clamp(1.12rem, 1.65vw, 1.55rem);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}
.kicker::before { content: "//"; color: var(--muted); }

.hero-title { display: grid; }
.hero-title .line {
  display: block;
  font-size: clamp(3.1rem, 10.2vw, 8.4rem);
}
/* zh does not port the English cliffhanger. English hangs a kicker on top
   ("Control machines with") and lets three display lines finish it; Chinese
   names the instrument first, so the hero is the whole sentence set as a
   two-line couplet — 以可控工业智能，/ 控制智能机器。 — and the kicker has
   nothing left to say, so it is dropped. Sized off the frame rather than the
   English clamp: 8.1em of CJK on the longer line, 10.4vw keeps ~4% clearance
   at 320px and the 9.4rem cap holds it inside the 1280px frame. */
html[lang^="zh"] .hero-title .line { font-size: min(8.4rem, 11.6vw); line-height: 1.03; }
/* Once the ask bar leaves the bottom edge and docks right (>560px) the couplet
   has to stop short of it. 7.6vw sets the CJK block to roughly the optical size
   of the English one — Anton's caps sit at ~0.72em while a CJK glyph fills
   ~0.86em, so equal em sizes would read much larger in Chinese — and the cap is
   the SAME 8.4rem as the English lines, so the two converge above ~1830px. */
@media (min-width: 561px) {
  html[lang^="zh"] .hero-title .line { font-size: min(8.4rem, 7.6vw); }
}
html[lang^="zh"] .hero-title .line-ghost { display: none; }
html[lang^="zh"] .kicker { display: none; }

/* The capability strip under the hero — what the couplet above actually rests
   on. Same `//` mark as the kicker but inverted in weight: the mark is amber,
   the words are muted, so it reads as the explanation and not a second
   headline. Parked for EN pending Maxx's call — delete the first rule to turn
   it on there. */
.hero-spec { display: none; }
html[lang^="zh"] .hero-spec {
  display: block;
  max-width: 46ch;
  margin-top: clamp(16px, 2.4vh, 28px);
  font-family: var(--mono-multi);
  font-size: clamp(0.95rem, 1.25vw, 1.16rem);
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.7;
  color: var(--muted);
  /* CJK breaks between any two characters, which stranded a lone 行 on its own
     line at 390px. keep-all holds each phrase together so the only break
     opportunities are the spaces around the · separators. */
  word-break: keep-all;
}
html[lang^="zh"] .hero-spec::before {
  content: "//";
  margin-right: 12px;
  color: var(--accent);
}
.line-ghost {
  color: transparent;
  -webkit-text-stroke: 1.5px var(--ink);
  paint-order: stroke;
}
.marked {
  font-style: normal;
  background: linear-gradient(var(--accent), var(--accent)) 0 96% / 34% 0.045em no-repeat;
}

/* With the strapline gone the left column is just the headline, so the calls to
   action sit right instead of hanging under it, filling the empty quarter.
   Above 1400px they also pull up level with the last headline line — measured,
   not guessed: at 1366px the headline still runs to x=785 and the buttons would
   collide, so the lift only switches on once there is real clearance. */
.hero-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: flex-end;
  gap: 26px 60px;
  margin-top: clamp(26px, 4vh, 46px);
}
@media (min-width: 1400px) {
  .hero-foot { margin-top: -4px; }
  /* the zh couplet is two lines, not three, so there is no tall column for the
     buttons to sit beside — they stay under it */
  html[lang^="zh"] .hero-foot { margin-top: clamp(26px, 4vh, 46px); }
}
.hero-actions { display: flex; flex-wrap: wrap; gap: 14px; }

/* — Isometric pick-and-place cell — */

.stage-band {
  position: relative;
  z-index: 1;
  border-top: 1px solid var(--line);
  background:
    linear-gradient(180deg, rgba(255, 179, 0, 0.03), transparent 42%),
    var(--bg-2);
  transition: background-color 0.25s ease;
}
.stage {
  width: min(var(--frame), 100% - 2 * var(--pad));
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(320px, 0.84fr);
  gap: clamp(20px, 3.2vw, 46px);
  align-items: center;
  padding: clamp(18px, 2.8vw, 34px) 0 clamp(16px, 2.4vw, 28px);
}
.stage-side {
  display: flex;
  flex-direction: column;
  gap: 4px;
  border-left: 1px solid var(--line);
  padding-left: clamp(18px, 2.6vw, 38px);
}
.pcx-svg { width: min(100%, 470px); height: auto; margin-inline: auto; }
.stage-tilt { perspective: 1100px; }
.stage-svg {
  width: 100%;
  height: auto;
  will-change: transform;
  transform: rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg));
}

/* machine metal faces (light comes from upper-left) */
.m .f-t { fill: var(--m-top); stroke: var(--m-stroke); stroke-width: 1; stroke-linejoin: round; }
.m .f-l { fill: var(--m-l); stroke: var(--m-stroke); stroke-width: 1; stroke-linejoin: round; }
.m .f-r { fill: var(--m-r); stroke: var(--m-stroke); stroke-width: 1; stroke-linejoin: round; }

/* amber product faces */
.amb .f-t { fill: var(--amber); stroke: var(--die-edge); stroke-width: 1; stroke-linejoin: round; }
.amb .f-l { fill: var(--amb-l); stroke: var(--die-edge); stroke-width: 1; stroke-linejoin: round; }
.amb .f-r { fill: var(--amb-r); stroke: var(--die-edge); stroke-width: 1; stroke-linejoin: round; }

.f-floor { fill: var(--floor); stroke: var(--m-stroke); stroke-width: 1; }

/* up-looking vision unit */
.cam-wall { fill: var(--m-r); stroke: var(--m-stroke); stroke-width: 1; }
/* Wafer. The disc reads as a disc on its own; the edge-exclusion ring and the
   notch are what stop it reading as a coin. Both are drawn on the top face, so
   nothing here depends on the arc bands underneath. */
.wafer-edge { fill: none; stroke: var(--m-stroke); stroke-width: 1; opacity: 0.55; }
/* The handler's fork is a flat plate, so it would otherwise be painted in the
   top-face tone — which is a hair off the canvas and reads as a hollow outline
   once the arm swings off the machine and sits against open background. Give it
   a side-face tone so it stays a solid object wherever it parks. */
.rfork > .f-t { fill: var(--m-r); }   /* direct children only — the wafer it carries and that wafer's dies are nested, and must keep their own tones */
.wafer-notch { fill: var(--m-r); stroke: var(--m-stroke); stroke-width: 1; stroke-linejoin: round; }
.cam-top { fill: var(--m-top); stroke: var(--m-stroke-2); stroke-width: 1; }
.cam-ring { fill: none; stroke: var(--amber); stroke-width: 2.2; opacity: 0.6; }
.cam-lens { fill: #0a0b0c; stroke: var(--m-stroke-2); stroke-width: 1; }
.cam-glint { fill: rgba(255, 255, 255, 0.8); }
.cam-led { fill: var(--amber); }
.cam-cable { stroke: var(--m-stroke-2); stroke-width: 1.6; }
.iso-leader { stroke: var(--m-stroke-2); stroke-width: 1; }

/* NG defect dies + reject bin */
.defect .f-t { fill: #e5484d; }
.defect .f-l { fill: #c1383c; }
.defect .f-r { fill: #992e32; }
.sv-vision-ring.ng { stroke: var(--alarm); }
.ro-state b.alarm, .ro-agent b.alarm { color: var(--alarm); }
.bin-cavity { fill: rgba(0, 0, 0, 0.55); }
html[data-theme="light"] .bin-cavity { fill: rgba(19, 19, 19, 0.45); }
.bin-mark { fill: #e5484d; }

/* AI-PC — screen HMI drawn in true screen pixels (unsheared plane, no text distortion) */
.pc-vents line { stroke: var(--m-stroke); stroke-width: 1.4; }
.pc-screen { fill: #0b0d11; stroke: var(--m-stroke-2); stroke-width: 1.2; }
.pc-cabname { font-size: 14px; fill: var(--ink); opacity: 0.82; letter-spacing: 0.1em; }
.pc-t {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.03em;
}
.pc-card { fill: rgba(255, 255, 255, 0.045); stroke: rgba(255, 255, 255, 0.09); stroke-width: 1; }
.pc-bullet { fill: var(--amber-fill, #ffb300); }
.pc-sect { font-size: 14.5px; fill: #ffb300; letter-spacing: 0.15em; }
.pc-state { font-size: 15px; fill: #eae8e1; letter-spacing: 0.08em; }
.pc-colh { font-size: 13px; fill: #83817b; letter-spacing: 0.1em; }
.pc-rowline { stroke: rgba(255, 255, 255, 0.09); stroke-width: 1; }
.pc-axis { font-size: 16.5px; fill: #b6b4ac; }
.pc-pos { font-size: 17.5px; fill: #eae8e1; font-variant-numeric: tabular-nums; }
.pc-vel { font-size: 17.5px; fill: #ffb300; font-variant-numeric: tabular-nums; }
.pc-rej { font-size: 14px; fill: #96948c; letter-spacing: 0.08em; }
.pc-grid { stroke: rgba(255, 255, 255, 0.06); stroke-width: 1; }
.pc-sparkbase { stroke: rgba(255, 255, 255, 0.14); stroke-width: 1; }
.pc-sparkfill { fill: rgba(255, 179, 0, 0.1); }
.pc-spark { stroke: #ffb300; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.pc-spark-ng { fill: #ff5a5f; stroke: rgba(255, 90, 95, 0.35); stroke-width: 5; }
.pc-strip {
  fill: rgba(255, 179, 0, 0.12);
  stroke: rgba(255, 179, 0, 0.4);
  stroke-width: 1;
  transition: fill 0.2s ease, stroke 0.2s ease;
}
.pc-strip.alarm { fill: #e5484d; stroke: #ff8589; }
.pc-strip-dot { fill: #ffb300; }
.pc-strip-dot.alarm { fill: #fff; }
.pc-strip-text { fill: #d9d6cd; font-size: 14px; letter-spacing: 0.06em; }
.pc-strip-text.alarm { fill: #fff; font-weight: 700; }
.pc-log { font-size: 14px; fill: #96948c; }
.pc-log.alarm { fill: #ff6b6e; }
@media (prefers-reduced-motion: no-preference) {
  .pc-strip.alarm { animation: strip-pulse 0.9s ease-in-out infinite; }
}
@keyframes strip-pulse {
  0%, 100% { fill-opacity: 1; }
  50% { fill-opacity: 0.62; }
}
.iso-shadow { fill: var(--iso-shadow); }
.iso-headshadow { fill: var(--iso-shadow); }
.iso-guide { stroke: var(--m-stroke); stroke-width: 1; stroke-dasharray: 2 7; }
.iso-lens { fill: var(--bg); stroke: var(--accent); stroke-width: 1.5; }
.iso-tip { fill: var(--amber); stroke: var(--die-edge); stroke-width: 1; }
.sv-lamp { fill: var(--amber); }
.sv-vision-ring { fill: none; stroke: var(--accent); stroke-width: 1.6; stroke-dasharray: 5 5; }

.sv-die, .sv-carried, .sv-placed { transition: opacity 0.15s ease; }
.sv-die.taken { opacity: 0; }

.sv-belt {
  stroke: var(--m-stroke-2);
  stroke-width: 2.5;
  stroke-dasharray: 12 9;
  animation: belt 0.28s linear infinite;
}
@keyframes belt { to { stroke-dashoffset: -21; } }

.sv-pad {
  fill: transparent;
  stroke: var(--m-stroke-2);
  stroke-width: 1.1;
  stroke-dasharray: 3 3;
}

.sv-zone {
  fill: var(--muted);
  font-family: var(--mono);
  font-size: 22px; /* viewBox units */
  font-weight: 600;
  letter-spacing: 0.1em;
}

/* readout rows under the AI-PC */
.stage-readout { margin-top: 2px; }
.ro {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 11px 0 12px;
  border-bottom: 1px solid var(--line);
}
.ro:last-child { border-bottom: 0; }
.ro i {
  font-style: normal;
  font-family: var(--mono);
  font-size: var(--fm-1);
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--muted);
  text-transform: uppercase;
}
.ro b {
  font-family: var(--mono);
  font-size: 1.22rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ro-state b { color: var(--accent); }
.ro-gate b { font-size: var(--fm-2); letter-spacing: 0.02em; }

/* — Ticker — */

/* One sentence, seven languages, plain scroll. A lens/gate treatment was tried
   in v12 and cut in v14 — it read as a gimmick against the industrial-minimal
   rest of the page. */
.ticker {
  overflow: hidden;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  transition: background-color 0.25s ease;
}
.ticker-track {
  display: flex;
  width: max-content;
  /* 97s, not the old 76s: the mantra grew ~27% when it became Software-defined
     Motion Control · Memory-Compute-Control Integration · Authority-Gated
     Execution, and the duration is fixed per cycle, so keeping 76s would have
     sped the scroll up by the same 27%. Re-derive as 76 × width/10649 whenever
     the copy changes (current track: 13523px). */
  animation: tick 97s linear infinite;
}
.ticker-track span {
  display: block;
  padding: clamp(13px, 1.6vw, 18px) 0;
  font-family: var(--mono-multi);
  font-size: clamp(0.92rem, 1.05vw, 1.06rem);
  font-weight: 600;
  letter-spacing: 0.11em;
  color: var(--muted);
  text-transform: uppercase;
  white-space: nowrap;
}
.ticker-track span[lang="ja"],
.ticker-track span[lang="ko"],
.ticker-track span[lang="th"],
.ticker-track span[lang="zh-Hans"],
.ticker-track span[lang="zh-Hant"] { letter-spacing: 0.05em; }
/* diamond between languages */
.ticker-track span::after {
  content: "◆";
  padding: 0 1.5em;
  color: var(--accent);
  opacity: 0.7;
}

.ticker:hover .ticker-track { animation-play-state: paused; }
@keyframes tick { to { transform: translateX(-50%); } }

/* ---------- 9. Technology ---------- */
/* The figure borrows the application-pictogram grammar wholesale: construction
   grid, registration marks, one machine stroke weight, and amber reserved for
   the one thing the drawing is about. There the subject was the axes; here it
   is the memory the two products share, so amber marks the overlap, the two
   interfaces crossing it, and the signal moving between them — nothing else.

   The motion carries the asymmetry rather than decorating it. The read path
   runs on a 2 s cadence and fires three times for every one action: state is
   always there for the taking. The write path runs on 6 s, moves at less than
   half the speed, and visibly HOLDS at the Runtime Action Interface while it
   is simulated and verified before release — that pause is the argument of
   point 03. 6 s is exactly three read cycles, so the two never drift. The
   whole sequence stops dead under reduced motion, where the guides and
   arrowheads still carry the topology. No JS: four dashed paths, four
   opacity ramps. */
.tech { padding: clamp(80px, 11vw, 150px) 0; }
.tech-head { margin-bottom: 0; font-size: clamp(1.6rem, 3.15vw, 2.85rem); line-height: 1.02; }
.tech-head span { display: block; }
.tech-head-2 { color: var(--accent); }

.tech-fig { margin: clamp(34px, 5vw, 60px) 0 0; padding: clamp(16px, 2.2vw, 28px); border: 1px solid var(--line); }
.tf { display: block; width: 100%; height: auto; }
.tf-o, .tf-o2, .tf-k, .tf-g, .tf-grid, .tf-reg, .tf-ax, .tf-guide, .tf-guide-head, .tf-pulse { fill: none; stroke: currentColor; stroke-linejoin: round; }
.tf-k    { stroke-width: 5;   opacity: 0.42; stroke-linejoin: miter; }
.tf-o    { stroke-width: 2.2; opacity: 0.58; stroke-linejoin: miter; }
.tf-o2   { stroke-width: 2.2; opacity: 0.26; stroke-linejoin: miter; stroke-dasharray: 6 5; }
.tf-g    { stroke-width: 2.2; opacity: 0.16; }
.tf-grid { stroke-width: 0.7; opacity: 0.075; }
.tf-reg  { stroke-width: 1.1; opacity: 0.24; }
.tf-ax   { stroke: var(--accent); stroke-width: 2.1; stroke-linecap: round; }
.tf-fill { fill: currentColor; opacity: 0.04; }
.tf-mem  { fill: var(--amber); opacity: 0.1; }
.tf-o, .tf-grid, .tf-mem { transition: opacity 0.18s ease; }
.tech-fig:hover .tf-o    { opacity: 0.78; }
.tech-fig:hover .tf-grid { opacity: 0.12; }
.tech-fig:hover .tf-mem  { opacity: 0.15; }

.tf-n       { font-family: var(--mono-multi); font-size: 21px;   font-weight: 700; letter-spacing: 0.1em;  fill: currentColor; }
.tf-p       { font-family: var(--mono-multi); font-size: 15px;   font-weight: 700; letter-spacing: 0.12em; fill: currentColor; opacity: 0.82; }
.tf-l       { font-family: var(--mono-multi); font-size: 13px;   font-weight: 700; letter-spacing: 0.08em; fill: currentColor; opacity: 0.74; }
.tf-l2      { font-family: var(--mono-multi); font-size: 13px;   font-weight: 700; letter-spacing: 0.08em; fill: currentColor; opacity: 0.4; }
.tf-t       { font-family: var(--mono-multi); font-size: 12px;   font-weight: 700; letter-spacing: 0.08em; fill: var(--accent); }
.tf-tb      { font-family: var(--mono-multi); font-size: 15px;   font-weight: 700; letter-spacing: 0.14em; fill: var(--accent); }
.tf-note    { font-family: var(--mono-multi); font-size: 12px;   font-weight: 700; letter-spacing: 0.12em; fill: currentColor; opacity: 0.42; }
.tf-note-ax { fill: var(--accent); opacity: 0.72; }
.tf-chassis { font-family: var(--mono-multi); font-size: 16px;   font-weight: 700; letter-spacing: 0.16em; fill: currentColor; opacity: 0.55; }
.tf-side    { font-family: var(--mono-multi); font-size: 12.5px; font-weight: 700; letter-spacing: 0.1em;  fill: currentColor; opacity: 0.46; }

/* the signal path -------------------------------------------------------- */
.tf-guide      { stroke-width: 1.6; opacity: 0.26; stroke-dasharray: 3 5; }
.tf-guide-head { stroke-width: 1.8; opacity: 0.3;  stroke-linecap: round; }
.tf-pulse      { stroke: var(--accent); stroke-width: 3.4; stroke-linecap: round;
                 stroke-dasharray: 14 600; stroke-dashoffset: 14; }
.tf-glow       { fill: var(--amber); opacity: 0; }

@media (prefers-reduced-motion: no-preference) {
  /* The read path gets its own 2 s cadence and runs three times per action —
     that ratio IS the claim: state is always available, an action is an event.
     6 s = 3 x 2 s, so the two stay in phase instead of drifting. */
  .tf-p1 { animation: tfP1 2s linear infinite; }
  .tf-p2 { animation: tfP2 2s linear infinite; }
  .tf-g-data  { animation: tfGData  2s linear infinite; }
  .tf-g-agent { animation: tfGAgent 2s linear infinite; }
  .tf-p3 { animation: tfP3 6s linear infinite; }
  .tf-p4 { animation: tfP4 6s linear infinite; }
  .tf-g-act { animation: tfGAct 6s linear infinite; }
  .tf-g-eng { animation: tfGEng 6s linear infinite; }
}
/* read leg — 2 s cycle. engine -> data interface (118) at ~270 px/s */
@keyframes tfP1 { 0% { stroke-dashoffset: 14; } 22%, 100% { stroke-dashoffset: -132; } }
/* data interface -> agent (68) */
@keyframes tfP2 { 0%, 34% { stroke-dashoffset: 14; } 50%, 100% { stroke-dashoffset: -82; } }
@keyframes tfGData  { 0%, 19% { opacity: 0; } 26% { opacity: 0.34; } 44%, 100% { opacity: 0; } }
@keyframes tfGAgent { 0%, 47% { opacity: 0; } 56% { opacity: 0.18; } 74%, 100% { opacity: 0; } }

/* write leg — 6 s cycle, deliberately slower. agent -> action interface (68) */
@keyframes tfP3 { 0%, 40% { stroke-dashoffset: 14; } 54%, 100% { stroke-dashoffset: -82; } }
/* action interface -> engine (118) at ~120 px/s, and only once the gate opens */
@keyframes tfP4 { 0%, 76% { stroke-dashoffset: 14; } 92%, 100% { stroke-dashoffset: -132; } }
/* arrives, is HELD while it is simulated and verified, then released */
@keyframes tfGAct   { 0%, 52% { opacity: 0; } 58% { opacity: 0.18; } 72% { opacity: 0.18; }
                      76% { opacity: 0.48; } 86%, 100% { opacity: 0; } }
@keyframes tfGEng   { 0%, 91% { opacity: 0; } 94% { opacity: 0.34; } 100% { opacity: 0; } }

.tech-points { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin-top: clamp(28px, 4vw, 48px); border-top: 1px solid var(--line); }
.tp { padding: clamp(20px, 2.6vw, 30px) clamp(16px, 2.2vw, 26px) 0; border-left: 1px solid var(--line); }
.tp:first-child { border-left: 0; padding-left: 0; }
.tp-no { display: block; margin-bottom: clamp(12px, 1.6vw, 18px); font-family: var(--mono); font-size: var(--fm-2); font-weight: 700; letter-spacing: 0.16em; color: var(--accent); }
.tp-name { font-size: clamp(1.05rem, 1.9vw, 1.45rem); line-height: 1.06; }
.tp-text { margin-top: 12px; font-size: var(--ft-body); line-height: 1.55; color: var(--muted); }

/* Below tablet the drawing scrolls rather than shrinking its labels into fog —
   the same reason the application pictograms cap their stroke-weight count. */
@media (max-width: 900px) {
  .tech-fig { overflow-x: auto; }
  .tf { min-width: 880px; }
}

/* ---------- 10. Products / inverted field ---------- */

.systems {
  position: relative;
  overflow: hidden;
  padding: clamp(76px, 10vw, 140px) 0;
}
.inverted {
  background: var(--inv-bg);
  color: var(--inv-ink);
  transition: background-color 0.25s ease, color 0.25s ease;
}
.inverted ::selection { background: var(--inv-ink); color: var(--inv-bg); }
.giant-index {
  position: absolute;
  top: -0.1em;
  right: clamp(14px, 3vw, 46px);
  z-index: 0;
  font-family: var(--display);
  font-size: clamp(5.5rem, 13vw, 12rem);
  line-height: 1;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--inv-ghost);
  pointer-events: none;
  user-select: none;
}
.systems .frame { position: relative; z-index: 1; }
.systems .sec-tag::before { background: var(--inv-ink); }
.systems .sec-tag span { color: var(--inv-muted); }
.systems .sec-lead { color: var(--inv-muted); margin-bottom: clamp(40px, 6vw, 64px); }

.index-table { border-top: 2px solid var(--inv-ink); }
.index-row {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.25fr) 216px;
  gap: 22px;
  align-items: baseline;
  padding: clamp(20px, 3vw, 28px) 10px;
  margin-inline: -10px;
  border-bottom: 2px solid var(--inv-ink);
  transition: background-color 0.15s ease;
}
.index-row:hover { background: var(--amber); }
.index-row:hover .ix-name,
.index-row:hover .ix-io { color: var(--on-amber); }
.ix-name {
  font-size: clamp(1.15rem, 2vw, 1.45rem);
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}
.ix-desc { color: var(--inv-muted); font-size: var(--ft-body); line-height: 1.55; }
.index-row:hover .ix-desc { color: var(--on-amber); }
/* What the series is FOR, lifted out of the sentence and marked in amber so the
   two rows can be told apart at a glance without reading either of them. */
.ix-for {
  display: block;
  margin-top: 9px;
  color: var(--accent);
  font-style: normal;
  font-weight: 600;
}
.index-row:hover .ix-for { color: var(--on-amber); }
/* The spec column carries three tokens now, so it wraps. The tokens themselves
   are glued with &nbsp; in the markup and the separator is bound to the token
   before it, so a break can only ever land after a "·" — never inside "128 AXES"
   and never with a "·" orphaned at the start of a line. */
.ix-io {
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.04em;
  text-align: right;
}

/* ---------- 12. Proof band (unlabelled) ---------- */

/* the closing 'and their equipment suppliers.' used to sit on the seam with the
   inverted Products block; it needs room before the colour changes */
.proof { padding: clamp(80px, 11vw, 150px) 0 clamp(48px, 6vw, 84px); }
.proof-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.proof-cell {
  padding: clamp(30px, 4.2vw, 50px) clamp(18px, 2.4vw, 34px);
  border-left: 1px solid var(--line);
}
.proof-cell:first-child { border-left: 0; padding-left: 0; }
.proof-num {
  display: block;
  font-size: clamp(2.7rem, 4.5vw, 4.25rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.proof-num i { font-style: normal; color: var(--accent); font-size: 0.62em; }
.proof-num i.u { margin-left: 0.1em; text-transform: none; }
.proof-cap {
  display: block;
  margin-top: 16px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fm-1);
  font-weight: 600;
  letter-spacing: 0.06em;
  line-height: 1.4;
  text-transform: uppercase;
  max-width: 24ch;
}

/* ---------- 15. Log (Latest Highlights) ---------- */

.log { padding: clamp(80px, 11vw, 150px) 0 0; }
/* — Updates: three cards, each with a thumbnail, a standfirst and a link.
     The thumbnail takes a real photo when one exists at assets/updates/<slug>.jpg;
     until then a registration-marked panel with the category set large stands in,
     which is a deliberate placeholder rather than a broken image.
     The frame is 5:4, not 16:9: the source photographs are event and cover shots
     that carry their identifying mark (the Intel Connection lockup, a white-paper
     title block) near an edge, and a wide letterbox crops exactly that away. — */

.log-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  border: 1px solid var(--line);
  background: var(--line);
}
.log-card { background: var(--bg-2); }
.log-link {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: clamp(16px, 2vw, 22px);
  transition: background-color 0.16s ease, color 0.16s ease;
}
.log-thumb {
  position: relative;
  display: block;
  aspect-ratio: 5 / 4;
  margin-bottom: clamp(16px, 2vw, 22px);
  overflow: hidden;
  background: var(--bg);
}
.log-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.log-thumb-mark {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
}
.log-card.has-img .log-thumb-mark { display: none; }
.log-reg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.4;
  opacity: 0.3;
}
.log-thumb-mark b {
  font-size: clamp(1.3rem, 2.4vw, 2.1rem);
  letter-spacing: 0.04em;
  color: var(--ink);
  opacity: 0.16;
  text-transform: uppercase;
}
.log-meta {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 10px;
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
}
.log-meta time { color: var(--muted); font-variant-numeric: tabular-nums; }
.log-meta i {
  font-style: normal;
  letter-spacing: 0.11em;
  color: var(--accent);
  text-transform: uppercase;
}
.log-title {
  font-size: clamp(1.02rem, 1.6vw, 1.28rem);
  font-weight: 700;
  line-height: 1.22;
}
.log-sum {
  margin-top: 10px;
  color: var(--muted);
  font-size: var(--ft-body);
  line-height: 1.5;
}
.log-more {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: auto;
  padding-top: clamp(16px, 2vw, 22px);
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
  letter-spacing: 0.13em;
  color: var(--muted);
  text-transform: uppercase;
}
.log-more b { transition: transform 0.18s var(--ease); }
.log-link:hover { background: var(--amber); color: var(--on-amber); }
.log-link:hover .log-meta time,
.log-link:hover .log-meta i,
.log-link:hover .log-sum,
.log-link:hover .log-more { color: var(--on-amber); }
.log-link:hover .log-more b { transform: translateX(4px); }
.log-link:hover .log-reg { stroke: var(--on-amber); opacity: 0.4; }
.log-link:hover .log-thumb-mark b { color: var(--on-amber); }
@media (max-width: 900px) { .log-grid { grid-template-columns: 1fr; } }

/* — The archive slot under the grid. No frame and no fill: it sits at the grid's
     right edge as a small dim run-on from the last card, so it reads as "the list
     continues" rather than as a button that happens to be broken. `a.log-all` is
     the enabled form, pre-written for when an archive exists. — */
.log-all {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  margin-top: clamp(12px, 1.4vw, 16px);
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: 0.42;
  cursor: default;
}
.log-all b { transition: transform 0.18s var(--ease); }
a.log-all {
  opacity: 1;
  cursor: pointer;
  transition: background-color 0.16s ease, color 0.16s ease;
}
a.log-all:hover { color: var(--accent); }
a.log-all:hover b { transform: translateX(4px); }

/* ---------- 16. Start ---------- */

.start { position: relative; }
/* Moved out of Contact in v42: it is the page's chapter break between the
   machines and the company, so it needs air above or it reads as a bottom
   border on the Applications grid rather than a divider between two zones. */
.hazard {
  margin-top: clamp(64px, 8vw, 112px);
  height: 16px;
  background: repeating-linear-gradient(-45deg,
    var(--amber) 0 26px, var(--on-amber) 26px 52px);
}
.start-inner {
  padding: clamp(70px, 10vw, 140px) 0 clamp(60px, 8vw, 110px);
  text-align: center;
}
.start-tag { justify-content: center; display: flex; }
/* Contact's second button carries the agent's own mark — the same amber bot as
   the ask bar, blinking and scanning exactly like it — and the ask bar's 1.5px
   frame. Side by side that reads as "email a person" vs "ask the agent" rather
   than primary vs secondary. The clipPath id is botHeadCta, not botHead: two
   identical ids in one document and the first one wins for both. */
.btn-agent { border-width: 1.5px; padding-left: 18px; gap: 16px; }
.btn-agent-mark {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  margin: -6px 0;
  background: var(--amber);
  flex: none;
}
.btn-agent-mark svg { width: 32px; height: 32px; overflow: visible; }
.btn-agent:hover .bot-mouth { d: path("M17.5 27.6 Q22 32 26.5 27.6"); opacity: 1; }
.btn-agent:hover .bot-scan { animation-duration: 1.5s; }

/* The headline is gone — two buttons under the tag, nothing else. */
.start-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-top: clamp(30px, 4.4vw, 48px);
}

/* ---------- 17. Footer ---------- */

.foot { border-top: 1px solid var(--line); }
.foot-grid {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 30px;
  padding: clamp(36px, 5vw, 56px) 0;
}
.foot-brand img { width: 246px; }
.foot-brand p { margin-top: 16px; color: var(--muted); font-size: var(--ft-body); }
/* 注册名。比主题句小半级、字重高一点 —— 它是标识的一部分，不是又一句文案。 */
.foot-brand .foot-legal {
  margin-top: 14px;
  font-size: var(--fm-1);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--ink);
}
.foot-brand .foot-legal + p { margin-top: 8px; }
.foot-meta p {
  color: var(--muted);
  font-size: var(--fm-2);
  line-height: 1.75;
  text-align: right;
  font-family: var(--mono);
}
.foot-top {
  display: block;
  border-top: 1px solid var(--line);
  transition: background-color 0.16s ease, color 0.16s ease;
}
.foot-top .frame {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 0;
  font-family: var(--mono);
  font-size: var(--fm-1);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.foot-top:hover { background: var(--amber); color: var(--on-amber); }

/* ---------- 18. Reveal ---------- */

html.js [data-reveal] {
  opacity: 0;
  transform: translateY(26px);
}
html.js [data-reveal].is-in {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
  transition-delay: var(--rd, 0ms);
}
/* ---------- 19. Responsive ---------- */

@media (max-width: 1024px) {
  .index-row { grid-template-columns: 86px minmax(0, 1fr) 200px; }
  .ix-desc { grid-column: 2 / 3; grid-row: 2; }
  .ix-io { grid-row: 1; grid-column: 3; }
}

@media (max-width: 900px) {
  .stage { grid-template-columns: 1fr; gap: 16px; }
  .stage-side { border-left: 0; padding-left: 0; border-top: 1px solid var(--line); padding-top: 16px; }
  .stage-readout {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 28px;
  }
}

@media (max-width: 780px) {
  .topbar-row { flex-wrap: wrap; padding-block: 16px 12px; }
  .brand img { width: 168px; }
  .clock { display: none; }
  .foot-grid { flex-direction: column; align-items: flex-start; }
  .foot-meta p { text-align: left; }
  .ro-gate { display: none; }
}

@media (max-width: 560px) {
  .index-row { grid-template-columns: minmax(0, 1fr) 200px; }
  .ix-name { grid-column: 1; grid-row: 2; }
  .ix-desc { grid-column: 1 / -1; grid-row: 3; }
  .ix-io { grid-column: 2; grid-row: 1; }
  .hero-actions { width: 100%; }
  .hero-actions .btn { flex: 1 1 auto; justify-content: center; }
  .stage-readout .ro { padding-block: 10px 12px; }
  .ro-acc { display: none; }
}

/* ---------- 20. Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .clock i { animation: none; }
  .ticker-track { animation: none; }
  .sv-belt { animation: none; }
  .stage-svg { transform: none; }
  html.js [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .btn-solid:hover, .btn-ghost:hover { transform: none; box-shadow: none; }
  .log-more b { transition: none; }
  .dir-panel { transition: none; }
  .hero::after { background: radial-gradient(600px circle at 74% 18%, rgba(255, 179, 0, 0.07), transparent 65%); }
}

/* ============================================================
   21. Legacy template component styles retained for compatibility
   ============================================================ */

/* — Shared small note — */

.sec-note {
  margin-top: 14px;
  font-family: var(--mono);
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.inverted .sec-note { color: var(--inv-muted); }

/* — Trust wall (Proof section) — */

.trust { padding-top: clamp(34px, 5vw, 56px); }
.trust-logos {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 38px) clamp(20px, 3vw, 40px);
}
.trust-logos li {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--mark-h, 70px);
  transition: opacity 0.15s ease, color 0.15s ease;
}
/* fallback wordmark — shown until an official logo file is present */
.tl-name {
  font-family: var(--display);
  font-size: clamp(1.5rem, 2.7vw, 2.2rem);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}
.trust-logos li:hover .tl-name { color: var(--accent); }
/* Official marks. They are pre-balanced by ink area in make_logos.py and all
   share one canvas, so the wall only needs a single height here. */
.tl-mark {
  display: none;
  width: auto;
  height: var(--mark-h, 70px);
  max-width: 100%;
  object-fit: contain;
  opacity: 0.82;
  transition: opacity 0.15s ease;
}
.trust-logos li.has-mark .tl-mark { display: block; }
.trust-logos li.has-mark .tl-name { display: none; }
.trust-logos li.has-mark:hover .tl-mark { opacity: 1; }
html[data-theme="dark"] .tl-mark { filter: invert(1) brightness(1.9) grayscale(1); }
html[data-theme="light"] .tl-mark { filter: grayscale(1) brightness(0.35); }
@media (max-width: 900px) { .trust-logos { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 560px) { .trust-logos { grid-template-columns: repeat(2, minmax(0, 1fr)); --mark-h: 54px; } }
/* the two small lines that bracket the wall — same voice, above and below.
   v37 tried promoting the top one to a product-tagline size; it was reverted
   the same round. They read as one sentence wrapped around the wall, and
   breaking their voice breaks the sentence. Do not re-propose. */
.trust-lead {
  margin-bottom: 22px;
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.trust-note {
  margin-top: 22px;
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--muted);
}

/* — Products blocks — */

.prod-block { margin-top: clamp(48px, 7vw, 84px); }
/* the Products section has no visible H2 — keep the first block near its tag */
.prod-block:first-of-type { margin-top: clamp(18px, 2.6vw, 34px); }
.prod-head {
  display: grid;
  grid-template-columns: 60px minmax(0, 1fr);
  gap: 8px 22px;
  align-items: baseline;
  margin-bottom: clamp(20px, 3vw, 30px);
}
.prod-idx {
  font-family: var(--mono);
  font-size: var(--fm-1);
  font-weight: 600;
  color: var(--inv-muted);
}
.prod-name { font-size: clamp(2rem, 4.6vw, 3.7rem); }
.prod-tagline {
  grid-column: 2;
  color: var(--inv-muted);
  font-size: clamp(1.02rem, 1.6vw, 1.28rem);
  line-height: 1.55;
  max-width: 700px;
}

/* — Agent lifecycle: four steps, each showing its own work — */

.flow {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border: 2px solid var(--inv-ink);
}
.flow-step {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(20px, 2.6vw, 30px) clamp(18px, 2.2vw, 28px) clamp(20px, 2.6vw, 28px);
  border-left: 2px solid var(--inv-ink);
  border-top: 2px solid var(--inv-ink);
}
.flow-step:nth-child(odd) { border-left: 0; }
.flow-step:nth-child(-n+2) { border-top: 0; }
.flow-no {
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
  color: var(--inv-muted);
}
.flow-name {
  margin: 10px 0 8px;
  font-size: clamp(1.02rem, 1.6vw, 1.28rem);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1.25;
}
.flow-text { color: var(--inv-muted); font-size: var(--ft-body); line-height: 1.5; max-width: 46ch; }

/* ---- the scenes ----------------------------------------------------
   Flat wireframes in the same language as the AI-PC screen above: hairline
   rules, placeholder bars for prose, amber only where the agent is acting.
   Every element carries its own cue time in the markup; app.js drives them. */
.flow-scene {
  margin-top: clamp(18px, 2.4vw, 26px);
  padding-top: clamp(14px, 1.8vw, 20px);
  border-top: 1px solid var(--sc-line);
}
.sc { width: 100%; height: auto; overflow: visible; }
.sc [data-at] {
  opacity: 0;
  transition: opacity 0.3s var(--ease);
}
.sc [data-at].on { opacity: 1; }

.sc-q {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 600;
  fill: var(--inv-ink);
}
.sc-qmark { fill: var(--amber); }
.sc-dot { fill: var(--amber); }
.sc-bar { fill: var(--sc-fill); }
.sc-bar-2 { fill: var(--sc-fill-2); }
.sc-rule { fill: var(--sc-line); }
.sc-rule-2 { fill: var(--sc-fill); }
.sc-fig { fill: none; stroke: var(--sc-line); stroke-width: 1; }
.sc-fig-tr { fill: none; stroke: var(--sc-line); stroke-width: 1.3; }
.sc-cyc { fill: var(--amber); }
.sc-hist { fill: var(--amber); }
.sc-fig-ax { fill: none; stroke: var(--sc-line); stroke-width: 1; }
.sc-fig-gd {
  fill: none;
  stroke: var(--sc-line);
  stroke-width: 1;
  stroke-dasharray: 2 3;
}
.sc-fig-t, .sc-tag {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.13em;
  fill: var(--inv-muted);
}
.sc-tag { font-size: 10px; }
.sc-underline { fill: var(--amber); }
.sc-link {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  fill: var(--inv-ink);
}
.sc-panel { fill: none; stroke: var(--sc-line); stroke-width: 1.4; }
.sc-panel-bar { fill: var(--sc-fill-2); }
.sc-btn { fill: none; stroke: var(--sc-line); stroke-width: 1.2; }
.sc-plot { fill: none; stroke: var(--amber); stroke-width: 1.5; }
.sc-code { fill: var(--sc-fill-2); stroke: var(--sc-line); stroke-width: 1; }
.sc-kw { fill: var(--amber); }
.sc-traj {
  fill: none;
  stroke: var(--amber);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-dasharray: 320;
  stroke-dashoffset: 320;
}
.sc-traj.on { stroke-dashoffset: calc(320 - var(--p, 0) * 320); }
.sc-param, .sc-val, .sc-dlg-t, .sc-sig-t, .sc-axis, .sc-note-t {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  fill: var(--inv-muted);
}
.sc-param { fill: var(--inv-ink); }
.sc-val { fill: var(--amber); }
.sc-dialog { fill: var(--inv-bg); stroke: var(--inv-ink); stroke-width: 1.6; }
.sc-chip { fill: none; stroke: var(--inv-ink); stroke-width: 1.6; }
.sc-chip-solid { fill: var(--amber); }
.sc-chip-t, .sc-chip-t-inv {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
}
.sc-chip-t { fill: var(--inv-ink); }
.sc-chip-t-inv { fill: var(--on-amber); }
.sc-press-ring { fill: none; stroke: var(--inv-ink); stroke-width: 2; }
.sc-press.on .sc-press-ring { animation: sc-press 0.6s var(--ease) 2; }
@keyframes sc-press {
  0% { transform: scale(1); opacity: 0.9; }
  100% { transform: scale(1.14); opacity: 0; }
}
.sc-ok, .sc-ok-lg {
  font-family: var(--mono);
  font-weight: 700;
  letter-spacing: 0.06em;
  fill: var(--amber);
}
.sc-ok { font-size: 11px; }
.sc-ok-lg { font-size: 13.5px; }
.sc-sig { fill: none; stroke: var(--sc-line); stroke-width: 1.4; }
.sc-sig-alarm { stroke: var(--alarm); stroke-width: 2; }
.sc-alarm-strip { fill: none; stroke: var(--alarm); stroke-width: 1.6; }
.sc-alarm-t {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  fill: var(--alarm);
}
.sc-axis { font-size: 11.5px; letter-spacing: 0.12em; }
.sc-note-t { font-size: 11.5px; letter-spacing: 0.08em; }
.sc-cell { fill: none; stroke: var(--sc-line); stroke-width: 1.2; }
.sc-cell-hit { fill: var(--sc-fill); stroke: var(--inv-ink); stroke-width: 2; }
.sc-hit { fill: var(--amber); }
.flow-cap {
  margin-top: 18px;
  font-family: var(--mono);
  font-size: var(--fm-1);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--inv-ink);
}

/* — Applications grid — */

.apps { padding: clamp(80px, 11vw, 150px) 0 0; }
/* — Applications head: the lead carries the section now that the title is
     gone, and four claims sit on the same four columns as the tiles below,
     so the two blocks read as one aligned system. — */

.apps-head {
  margin-bottom: clamp(30px, 4.4vw, 54px);
  font-size: clamp(1.6rem, 3.15vw, 2.85rem);
  line-height: 1.02;
}
.apps-head span { display: block; }
.apps-head-2 { color: var(--accent); }
.claims {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-bottom: clamp(28px, 4vw, 48px);
  border-top: 1px solid var(--line);
}
.claim {
  padding: clamp(20px, 2.6vw, 30px) clamp(16px, 2.2vw, 26px) clamp(20px, 2.6vw, 28px);
  border-left: 1px solid var(--line);
}
.claim:first-child { border-left: 0; padding-left: 0; }
.claim::before {
  content: "";
  display: block;
  width: 22px;
  height: 2px;
  margin-bottom: clamp(12px, 1.6vw, 18px);
  background: var(--accent);
}
.claim-name {
  font-size: clamp(1.05rem, 1.9vw, 1.55rem);
  line-height: 1;
}
.claim-spec {
  margin-top: 10px;
  font-size: var(--ft-body);
  line-height: 1.5;
  color: var(--muted);
}

.app-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  border: 1px solid var(--line);
  background: var(--line);
}
.app-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 8px;
  min-height: clamp(206px, 22vw, 300px);
  padding: clamp(14px, 2vw, 22px);
  background: var(--bg-2);
  transition: background-color 0.16s ease, color 0.16s ease;
}

/* ---- application machines ------------------------------------------
   A measured sheet per tile: one machine stroke weight (plus a thick link
   for arm segments) on a 12-unit construction grid, registration marks and
   a spec tag at the edges. Amber means AXIS here and nothing else — the
   tiles say "these are the axes we control", which is the actual product. */
.ap {
  width: 100%;
  height: auto;
  margin: auto 0 14px;
}
.ap-o, .ap-g, .ap-k, .ap-grid, .ap-reg, .ap-ax {
  fill: none;
  stroke: currentColor;
  stroke-linejoin: round;
}
.ap-o { stroke-width: 2.2; opacity: 0.58; stroke-linejoin: miter; }
.ap-k { stroke-width: 6; opacity: 0.4; stroke-linecap: round; }
.ap-g { stroke-width: 2.2; opacity: 0.16; }
.ap-grid { stroke-width: 0.7; opacity: 0.075; }
.ap-reg { stroke-width: 1.1; opacity: 0.24; }
.ap-f { fill: currentColor; opacity: 0.13; }
.ap-ax { stroke: var(--accent); stroke-width: 2.1; stroke-linecap: round; }
.ap-spec {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.14em;
  fill: currentColor;
  opacity: 0.5;
}
.ap-t {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  fill: var(--accent);
}
.app-tile:hover .ap-o { opacity: 0.8; }
.app-tile:hover .ap-grid { opacity: 0.12; }
.app-tile:hover .ap-ax { stroke: var(--on-amber); }
.app-tile:hover .ap-t { fill: var(--on-amber); }
.app-tile .display { font-size: clamp(1.05rem, 1.9vw, 1.55rem); line-height: 1.05; }
.app-sub {
  position: absolute;
  right: clamp(14px, 2vw, 22px);
  bottom: calc(clamp(14px, 2vw, 22px) + 3.3em);
  left: clamp(14px, 2vw, 22px);
  font-family: var(--mono);
  font-size: var(--fm-3);
  font-weight: 600;
  line-height: 1.72;
  letter-spacing: 0.02em;
  white-space: pre-line;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.18s var(--ease), transform 0.18s var(--ease);
  pointer-events: none;
}
.app-tile:hover .ap,
.app-tile:focus-within .ap { opacity: 0.1; }
.app-tile:hover .app-sub,
.app-tile:focus-within .app-sub { opacity: 1; transform: none; }
.app-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }
.ap { transition: opacity 0.18s var(--ease); }

.app-tile:hover { background: var(--amber); color: var(--on-amber); }

/* — Company directory — */

.company { padding: clamp(80px, 11vw, 150px) 0; }
.dir {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  margin-top: clamp(30px, 4.5vw, 48px);
  border: 1px solid var(--line);
  background: var(--line);
}
.dir-item { background: var(--bg-2); }
.dir-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 15px clamp(14px, 2vw, 22px);
  font-family: var(--mono);
  font-size: var(--fm-3);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
  transition: background-color 0.15s ease, color 0.15s ease;
}
.dir-in b { color: var(--muted); font-weight: 600; transition: transform 0.18s var(--ease), color 0.15s ease; }
span.dir-in { color: var(--muted); }
a.dir-in:hover, button.dir-in:hover { background: var(--amber); color: var(--on-amber); }
a.dir-in:hover b, button.dir-in:hover b { color: var(--on-amber); transform: translateX(4px); }
button.dir-in {
  width: 100%;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  color: inherit;
}
button.dir-in b { transition: transform 0.18s var(--ease), color 0.15s ease; }
button.dir-in[aria-expanded="true"] { background: var(--amber); color: var(--on-amber); }
button.dir-in[aria-expanded="true"] b { color: var(--on-amber); transform: rotate(45deg); }

/* One strip under the whole grid rather than a panel per cell: the content is
   long-form, and the row of labels should stay a row. */
.dir-panels { border-inline: 1px solid var(--line); border-bottom: 1px solid var(--line); }
/* No height here on purpose: with JS off every panel stays open and readable,
   and setupDirectory() collapses them on init. Progressive enhancement only
   works if the enhanced state is the one that gets added. */
.dir-panel {
  overflow: hidden;
  background: var(--bg-2);
  transition: height 0.28s var(--ease);
}
.dir-panel + .dir-panel { border-top: 1px solid var(--line); }
.dir-panel[data-open] { height: auto; }
.dir-panel-in {
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr);
  gap: clamp(18px, 3vw, 44px);
  padding: clamp(26px, 3.4vw, 40px) clamp(14px, 2vw, 22px);
}
.dir-panel-tag {
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--accent);
  text-transform: uppercase;
}
.dir-panel-body { color: var(--muted); font-size: var(--ft-body); line-height: 1.6; }
.dir-panel-body > p { max-width: 74ch; }
.dir-strategic-copy > span { display: block; }
.dir-strategic-vision {
  display: block;
  max-width: 34ch;
  margin-top: clamp(16px, 2.2vw, 24px);
  color: var(--accent);
  font-family: var(--mono);
  font-size: clamp(1.04rem, 1.55vw, 1.28rem);
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.45;
}
/* History's milestone rail. The years are the spine: a hairline per column with
   an amber fill that draws in when the panel opens, a node on each junction, and
   the last one solid because that is where the company is now. The reveal is
   keyed off [data-open], which setupDirectory() already sets — no extra JS. */
.ml {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-top: clamp(26px, 3vw, 36px);
}
.ml-item {
  position: relative;
  padding: clamp(20px, 2.2vw, 26px) clamp(16px, 1.8vw, 24px) 2px 0;
  border-top: 1px solid var(--line);
}
.ml-item + .ml-item { padding-left: clamp(16px, 1.8vw, 24px); border-left: 1px solid var(--line); }
/* the amber fill rides on top of the hairline. Drawn by default: with JS off the
   rail is simply there. setupDirectory() sets [data-dir-js] once it has taken
   over, and only then does the rail start collapsed and draw in on open. */
.ml-item::before {
  content: "";
  position: absolute;
  inset: -1px 0 auto 0;
  height: 1px;
  background: var(--accent);
  transform-origin: left center;
}
.ml-node {
  position: absolute;
  top: -5px;
  left: 0;
  width: 9px;
  height: 9px;
  border: 1.6px solid var(--accent);
  border-radius: 50%;
  background: var(--bg-2);
}
.ml-item + .ml-item .ml-node { left: -5px; }
/* today: filled, with a halo, so the last stop reads as the current one */
.ml-item:last-child .ml-node {
  background: var(--accent);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 22%, transparent);
}
/* The transition lives on the open rule, not the closed one, for two reasons:
   adding [data-dir-js] at init changes transform none -> scaleX(0), and a
   transition there would animate the rail *out* on every page load; and on
   close the rail should snap back instantly, ready to draw again. */
@media (prefers-reduced-motion: no-preference) {
  [data-dir-js] .ml-item::before { transform: scaleX(0); }
  [data-dir-js] .ml-node { opacity: 0; transform: scale(0.4); }
  [data-dir-js] .dir-panel[data-open] .ml-item::before {
    transform: scaleX(1);
    transition: transform 0.42s var(--ease) calc(var(--i) * 0.13s);
  }
  [data-dir-js] .dir-panel[data-open] .ml-node {
    opacity: 1;
    transform: scale(1);
    transition: opacity 0.24s ease calc(var(--i) * 0.13s + 0.3s),
                transform 0.24s var(--ease) calc(var(--i) * 0.13s + 0.3s);
  }
}
.ml-year {
  display: block;
  font-family: var(--mono);
  font-size: clamp(1.2rem, 1.85vw, 1.5rem);
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1;
  color: var(--accent);
}
.ml-what {
  display: block;
  margin-top: 12px;
  font-size: var(--ft-body);
  line-height: 1.5;
  color: var(--ink);
}
@media (max-width: 900px) {
  .ml { grid-template-columns: 1fr; }
  .ml-item,
  .ml-item + .ml-item {
    padding: 16px 0 18px 26px;
    border-top: 0;
    border-left: 1px solid var(--line);
  }
  .ml-item::before {
    inset: 0 auto 0 -1px;
    width: 1px;
    height: auto;
    transform-origin: center top;
  }
  .ml-item .ml-node,
  .ml-item + .ml-item .ml-node { top: 20px; left: -5px; }
}

/* A ruled 4-up: a hairline across the top, an amber tick per cell, a name and a
   sub-line. Locations and Careers both need exactly this, and the Applications
   claims row is the same idea — one component instead of three near-copies. */
.ruled {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-top: clamp(24px, 2.8vw, 34px);
  border-top: 1px solid var(--line);
}
.ruled-item { padding: clamp(18px, 2.2vw, 26px) clamp(16px, 1.8vw, 24px) 2px 0; }
/* One long name ("Application Engineer") wraps and the sub-lines beside it stop
   agreeing. Subgrid puts tick / name / sub on shared rows so they line up
   whatever the copy does. Without support this is just the normal flow. */
@supports (grid-template-rows: subgrid) {
  .ruled { grid-template-rows: auto auto auto; }
  .ruled-item { display: grid; grid-template-rows: subgrid; grid-row: span 3; }
}
.ruled-item + .ruled-item { padding-left: clamp(16px, 1.8vw, 24px); border-left: 1px solid var(--line); }
.ruled-item::before {
  content: "";
  display: block;
  width: 18px;
  height: 2px;
  margin-bottom: clamp(12px, 1.5vw, 16px);
  background: var(--accent);
}
/* Locations and Careers name their cells in the same voice as the milestone
   years: mono, set up in size, spacing pulled in so a long title still reads as
   one word-block. One step under .ml-year so a four-up of words does not shout
   louder than the rail of numbers. */
.ruled-name {
  font-family: var(--mono);
  font-size: clamp(1.04rem, 1.55vw, 1.28rem);
  font-weight: 600;
  letter-spacing: 0.03em;
  line-height: 1.16;
  color: var(--accent);
  text-transform: uppercase;
}
.ruled-sub {
  margin-top: 9px;
  font-size: var(--ft-body);
  line-height: 1.55;
  color: var(--muted);
  white-space: pre-line;
}
@media (max-width: 900px) {
  .ruled { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ruled-item:nth-child(3) { border-left: 0; padding-left: 0; }
  .ruled-item:nth-child(n + 3) { border-top: 1px solid var(--line); margin-top: 4px; }
}
@media (max-width: 520px) {
  .ruled { grid-template-columns: 1fr; }
  .ruled-item + .ruled-item { border-left: 0; padding-left: 0; border-top: 1px solid var(--line); margin-top: 4px; }
}

.dir-panel-note {
  margin-top: clamp(18px, 2vw, 24px);
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--ink);
}
.dir-panel-note a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
}
/* an em dash, not a colon — Maxx's call, applied to both contact notes so the
   Careers and Strategic panels stay one component */
.dir-panel-note > span::after { content: " —"; }
.dir-panel-note a:hover { border-bottom-color: var(--accent); }
@media (max-width: 780px) { .dir-panel-in { grid-template-columns: 1fr; gap: 12px; } }

/* — Legacy interactive dock (not rendered by the Softwin site) — */

.agent-dock {
  position: fixed;
  right: clamp(14px, 2.4vw, 26px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 220;
  display: none;
  flex-direction: column;
  align-items: flex-end;
  gap: 0;
  --dock-w: clamp(272px, 25vw, 360px);
}
html.js .agent-dock { display: flex; }

/* HEADER MODE. The dock lives in the top-bar row in the DOM either way; in edge
   mode the rules above pull it back out to the right edge with position:fixed,
   which ignores its parent. Only ≥1024px — below that the header has no room
   and the edge / bottom-bar behaviour above is the better answer. */
@media (min-width: 1024px) {
  html[data-agent-dock="header"] .agent-dock {
    position: relative;
    top: auto;
    right: auto;
    transform: none;
    --dock-w: clamp(258px, 22vw, 320px);
  }
  /* a header bar has to be shorter than a floating one */
  html[data-agent-dock="header"] .agent-bar {
    padding: 5px;
    gap: 10px;
    box-shadow: none;
  }
  html[data-agent-dock="header"] .agent-bot { width: 34px; height: 34px; }
  html[data-agent-dock="header"] .agent-bot svg { width: 28px; height: 28px; }
  /* the conversation drops from under the bar instead of rising above it */
  html[data-agent-dock="header"] .agent-panel {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    border-bottom: 1.5px solid var(--line-strong);
    max-height: min(520px, calc(100vh - var(--topbar-h) - 48px));
  }
}

/* The dock is the site's signature. Not a button — an ask bar: a live input
   the agent is waiting in, with a blinking caret, a bot avatar that blinks and
   scans, and a slow amber sweep along the top edge. All motion off under
   reduced motion. */
.agent-bar {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: 14px;
  width: var(--dock-w);
  padding: 8px 8px 8px 8px;
  border: 1.5px solid var(--line-strong);
  background: var(--bg);
  color: var(--ink);
  font-family: var(--mono);
  text-align: left;
  box-shadow: 0 16px 44px rgba(0, 0, 0, 0.34), 0 0 0 6px rgba(255, 179, 0, 0.07);
  transition: transform 0.16s var(--ease), box-shadow 0.16s var(--ease),
              border-color 0.16s ease;
}
/* amber read-head sweeping the top edge — the bar is listening */
.agent-sweep {
  position: absolute;
  top: 0;
  left: 0;
  width: 34%;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--amber), transparent);
  animation: agent-sweep 4.6s var(--ease) infinite;
  pointer-events: none;
}
@keyframes agent-sweep {
  0%        { transform: translateX(-110%); opacity: 0; }
  12%, 88%  { opacity: 1; }
  100%      { transform: translateX(330%); opacity: 0; }
}

/* bot avatar — doubles as the open/close control */
.agent-bot {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  padding: 0;
  background: var(--amber);
  flex: none;
  cursor: pointer;
}
.agent-bot svg { width: 38px; height: 38px; overflow: visible; }
.bot-head {
  fill: none;
  stroke: var(--on-amber);
  stroke-width: 2;
}
.bot-ant { stroke: var(--on-amber); stroke-width: 2; }
.bot-ant-dot { fill: var(--on-amber); animation: lamp 1.5s ease-in-out infinite alternate; }
.bot-eye {
  fill: var(--on-amber);
  transform-box: fill-box;
  transform-origin: center;
  animation: bot-blink 5.4s steps(1, end) infinite;
}
.bot-eye-r { animation-delay: 0.04s; }
@keyframes bot-blink {
  0%, 88%, 100% { transform: scaleY(1); }
  92%           { transform: scaleY(0.12); }
  96%           { transform: scaleY(1); }
}
.bot-mouth {
  fill: none;
  stroke: var(--on-amber);
  stroke-width: 1.8;
  stroke-linecap: round;
  opacity: 0.85;
}
.bot-scan {
  stroke: var(--on-amber);
  stroke-width: 1.5;
  animation: bot-scan 3.4s var(--ease) infinite;
}
@keyframes bot-scan {
  0%        { transform: translateY(0); opacity: 0; }
  14%, 82%  { opacity: 0.38; }
  100%      { transform: translateY(19px); opacity: 0; }
}

/* the field itself — a real input, so the bar is the agent's only field */
.agent-input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  padding: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: var(--ft-body);
  font-weight: 500;
  letter-spacing: 0.01em;
}
.agent-input::placeholder { color: var(--muted); opacity: 1; }
/* the ring lives on the bar, not the bare input */
.agent-input:focus { outline: none; }
.agent-bar:focus-within {
  border-color: var(--accent);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.38), 0 0 0 6px rgba(255, 179, 0, 0.18);
}

.agent-go {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  background: var(--amber);
  color: var(--on-amber);
  font-size: 1.1rem;
  font-weight: 700;
  transition: transform 0.16s var(--ease);
}

.agent-bar:hover {
  transform: translateY(-3px);
  border-color: var(--accent);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.38), 0 0 0 6px rgba(255, 179, 0, 0.16);
}
.agent-bar:hover .agent-go { transform: translateX(3px); }
.agent-bar:hover .bot-mouth { d: path("M17.5 27.6 Q22 32 26.5 27.6"); opacity: 1; }
.agent-bar:hover .bot-scan { animation-duration: 1.5s; }
.agent-dock.is-open .agent-sweep { display: none; }
.agent-panel {
  display: flex;
  flex-direction: column;
  width: var(--dock-w);
  max-height: min(560px, calc(100vh - 160px));
  border: 1.5px solid var(--line-strong);
  border-bottom: 0;
  background: var(--bg);
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.35);
}
.agent-panel[hidden] { display: none; }
/* 对话内容必须能选中、能复制 —— 有人会把回答粘给同事。写死而不是靠继承：
   祖先里任何一条 user-select: none 都会顺着传下来，而这个组件挂在
   header 里，祖先不完全在我们眼皮底下。cursor: text 让它看起来就可选。 */
.agent-log,
.agent-log * {
  -webkit-user-select: text;
  user-select: text;
}
.agent-msg { cursor: text; }
.agent-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-2);
}
.agent-title {
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 700;
  letter-spacing: 0.14em;
}
.agent-pill {
  margin-right: auto;
  padding: 3px 8px;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-family: var(--mono);
  font-size: var(--fm-3);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.agent-close { padding: 4px 8px; color: var(--muted); font-size: 1.05rem; }
.agent-close:hover { color: var(--ink); }
.agent-log {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 132px;
  padding: 14px;
  overflow-y: auto;
}
.agent-msg {
  max-width: 88%;
  padding: 9px 12px;
  /* 正文字阶（1.06rem）是给整页宽度设计的；对话框只有 272–360px 宽，
     同样的字号一行装不下几个字，读起来像在看放大镜。降到 0.94rem 并
     收紧行距 —— 这是一个窄栏，不是页面正文。 */
  font-size: 0.94rem;
  line-height: 1.55;
}
.agent-msg-user {
  align-self: flex-end;
  background: var(--amber);
  color: var(--on-amber);
  font-weight: 600;
}
.agent-msg-bot {
  align-self: flex-start;
  border: 1px solid var(--line);
  background: var(--bg-2);
}
/* 等模型回话时的占位。不做转圈动画 —— 三个点自己呼吸就够了，
   而且 reduced-motion 下它会停下来变成静止的省略号，语义不丢。 */
.agent-msg-wait { color: var(--muted); letter-spacing: 0.3em; animation: agentWait 1.2s ease-in-out infinite; }
@keyframes agentWait { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .agent-msg-wait { animation: none; opacity: 0.6; } }

.agent-cta {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border: 1.5px solid var(--accent);
  color: var(--accent);
  font-family: var(--mono);
  font-size: var(--fm-2);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.agent-cta:hover { background: var(--amber); border-color: var(--amber); color: var(--on-amber); }
.agent-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 0 14px 13px;
}
/* 这三个是**建议**，不是内容。它们原来用 0.875rem + 较重的描边，在一个
   272–360px 的窄栏里比访客自己的问题还显眼。压到 0.7rem、描边转淡、
   字重回到常规 —— 需要时看得见，不需要时退到背景里去。 */
.agent-chips button {
  padding: 5px 8px;
  border: 1px solid var(--line);
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.35;
  opacity: 0.85;
  transition: color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
}
.agent-chips button:hover { opacity: 1; }
.agent-chips button:hover { color: var(--accent); border-color: var(--accent); }
/* flash highlight when the agent navigates somewhere */
.agent-flash {
  outline: 3px solid var(--amber);
  outline-offset: 4px;
  animation: agent-flash-fade 2.4s ease forwards;
}
@keyframes agent-flash-fade {
  0%, 70% { outline-color: var(--amber); }
  100% { outline-color: transparent; }
}

/* — V8 responsive — */

@media (max-width: 860px) {
  .flow { grid-template-columns: 1fr; }
  .flow-step { border-left: 0; }
  .flow-step:nth-child(2) { border-top: 2px solid var(--inv-ink); }
}
@media (max-width: 1024px) {
  .app-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tech-points { grid-template-columns: 1fr; }
  .tp { padding-left: 0; padding-right: 0; border-left: 0; }
  .tp + .tp { border-top: 1px solid var(--line); padding-top: clamp(20px, 2.6vw, 30px); }
  .claims { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .claim:nth-child(odd) { border-left: 0; padding-left: 0; }
  .claim:nth-child(n+3) { border-top: 1px solid var(--line); }
  .proof-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .proof-cell:nth-child(odd) { border-left: 0; padding-left: 0; }
  .proof-cell:nth-child(n+3) { border-top: 1px solid var(--line); }
  .prod-head { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .prod-idx { display: none; }
  .prod-tagline { grid-column: 1; }
}
@media (max-width: 780px) {
  .dir { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .app-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .app-sub { font-size: 0.7rem; line-height: 1.6; }
  .proof-grid { grid-template-columns: 1fr; }
  .proof-cell { border-left: 0; padding-inline: 0; }
  .proof-cell + .proof-cell { border-top: 1px solid var(--line); }
  .agent-dock {
    right: 12px;
    left: 12px;
    top: auto;
    bottom: 12px;
    transform: none;
    align-items: stretch;
  }
  .agent-dock { --dock-w: auto; }
  .agent-bar { width: 100%; gap: 10px; padding: 6px; }
  .agent-panel { width: 100%; }
  .agent-bot { width: 38px; height: 38px; }
  .agent-bot svg { width: 32px; height: 32px; }
  .agent-go { width: 38px; height: 38px; }
  .agent-input { font-size: 0.94rem; }
  .ticker-track span { letter-spacing: 0.09em; }
}

/* — V8 reduced motion — */

@media (max-width: 900px) and (prefers-reduced-motion: no-preference) {
  [data-dir-js] .ml-item::before { transform: scaleY(0); }
  [data-dir-js] .dir-panel[data-open] .ml-item::before { transform: scaleY(1); }
}

@media (prefers-reduced-motion: reduce) {
  .sc [data-at] { opacity: 1; transition: none; }
  .app-sub { transition: none; transform: none; }
  .ap { transition: none; }
  .sc-traj { stroke-dashoffset: 0; }
  .sc-press.on .sc-press-ring { animation: none; opacity: 0; }
  .sc-transient { opacity: 0 !important; }
  .bot-ant-dot,
  .bot-eye,
  .bot-scan { animation: none; }
  .agent-sweep { display: none; }
  .bot-scan { opacity: 0.5; }
  .agent-bar:hover { transform: none; box-shadow: 0 16px 44px rgba(0, 0, 0, 0.34); }
  .agent-bar:hover .agent-go { transform: none; }
  .agent-flash { animation: none; }
  a.dir-in:hover b { transform: none; }
}

/* ============================================================
   POST — 动态详情页
   原型没有这一层（那时动态只是首页的三张卡片），所以这是**新增**的样式。
   只用已有的 token 和字阶，不引入新的颜色、字体或间距语言。
   ============================================================ */
.post { padding: clamp(96px, 14vh, 168px) 0 clamp(72px, 10vh, 120px); }

.post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  margin: 26px 0 10px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fm-2);
  letter-spacing: 0.04em;
}
.post-meta i { font-style: normal; color: var(--accent); }
/* 地点 —— 和日期同级的事实，所以同色同字阶，不再加一层强调。 */
.post-meta em { font-style: normal; }

.post-title {
  margin: 0;
  font-size: clamp(2.4rem, 6vw, 4.6rem);
  line-height: 1.04;
  max-width: 22ch;
}
html[lang^="zh"] .post-title { font-size: clamp(2rem, 5vw, 3.8rem); line-height: 1.18; }

.post-sum {
  margin: 22px 0 0;
  max-width: 62ch;
  font-size: var(--ft-body);
  line-height: 1.62;
  color: var(--muted);
}

.post-fig { margin: clamp(34px, 5vh, 56px) 0 0; }
.post-fig img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
}
/* 竖幅顶图（封面、竖版海报）。铺满 1280px 的框会有 1700px 高，所以收窄。
   **左对齐，不居中** —— 页面上其他所有块（标题、正文、正文插图）都从 frame 左边起，
   一张居中的图会自己开一条轴线，和下面靠左的插图对不齐，看着像没对准而不像设计。
   横图不受影响，仍然铺满 frame。 */
.post-fig-tall img { max-width: min(100%, 620px); }

.post-body {
  margin: clamp(34px, 5vh, 56px) 0 0;
  max-width: 68ch;
  font-size: var(--ft-body);
  line-height: 1.72;
}
.post-body > * + * { margin-top: 1.15em; }
.post-body h2 { font-family: var(--display); font-size: 1.8rem; line-height: 1.2; margin-top: 1.8em; }
/* Anton 没有汉字，中文标题会一半 Anton 一半回退字体。全站 .display 已经这么处理了
   （第 204 行），正文小标题跟同一套，不另立规矩。 */
html[lang^="zh"] .post-body h2 {
  font-family: var(--sans-cjk-black);
  font-weight: 800;
  letter-spacing: 0.02em;
  line-height: 1.3;
}
.post-body h3 { font-family: var(--sans); font-weight: 700; font-size: 1.16rem; margin-top: 1.6em; }
.post-body a { color: var(--accent); }
.post-body img { display: block; width: 100%; height: auto; border: 1px solid var(--line); }
.post-body ul, .post-body ol { padding-left: 1.3em; }
.post-body li + li { margin-top: 0.4em; }
.post-body blockquote {
  padding-left: 18px;
  border-left: 2px solid var(--accent);
  color: var(--muted);
}

/* 正文里的插图。跟着正文栏宽走（68ch），不越到 frame 宽度去 ——
   顶部那张 .post-fig 是这一条的主图，正文插图不该和它抢。
   这两条要写在 `.post-body > * + *` 之后：同权重，靠顺序覆盖它的 1.15em。 */
.post-fig-in { margin: clamp(28px, 4vh, 44px) 0; }
.post-fig-in figcaption {
  margin-top: 10px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fm-2);
  letter-spacing: 0.03em;
  line-height: 1.5;
}

/* 正文开头的技术副题（"工业 AI + Soft-Motion · MCCoder"）。
   mono + 琥珀色，和 .sec-tag 同一个语气：它说的是"这一条讲什么技术"，不是标题。 */
.post-kicker {
  margin: 16px 0 0;
  color: var(--accent);
  font-family: var(--mono);
  font-size: var(--fm-2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* 文末标签。# 用琥珀色，词本身是 muted —— 标签是索引，不是标题。 */
.post-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin-top: clamp(34px, 5vh, 52px);
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fm-2);
  letter-spacing: 0.04em;
}
.post-tags span::before { content: "#"; margin-right: 1px; color: var(--accent); }

.post-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px clamp(20px, 3vw, 36px);
  margin: clamp(40px, 6vh, 64px) 0 0;
  padding-top: clamp(24px, 3vh, 34px);
  border-top: 1px solid var(--line);
}
.post-links .log-all { margin: 0; }
.post-links .log-all b { margin-right: 8px; }

/* ============================================================
   SOFTWIN HOMEPAGE
   ============================================================ */

.sw-brand {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 7px;
  color: var(--ink);
}
.sw-brand-plaque {
  display: inline-flex;
  align-items: center;
  min-height: 46px;
  padding: 6px 12px 6px 8px;
  border: 1px solid rgba(16, 23, 30, 0.18);
  background: #f3f5f6;
}
.sw-brand-plaque img { width: 197px; height: auto; }
.sw-brand-sub {
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.56rem;
  font-weight: 600;
  letter-spacing: 0.16em;
}
html[data-scrolled] .sw-brand-plaque { min-height: 38px; padding-block: 4px; }
html[data-scrolled] .sw-brand-plaque img { width: 158px; }
html[data-scrolled] .sw-brand-sub { display: none; }

.sw-hero::after {
  background: radial-gradient(760px circle at var(--mx, 76%) var(--my, 18%), rgba(215, 34, 44, 0.075), transparent 68%);
}
.sw-hero-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(360px, 0.82fr) minmax(500px, 1.18fr);
  gap: clamp(34px, 4.5vw, 66px);
  align-items: center;
  min-height: min(800px, calc(100vh - var(--topbar-h)));
  padding: clamp(56px, 8vh, 104px) 0 clamp(64px, 9vh, 116px);
}
.sw-hero-copy { min-width: 0; }
.sw-hero .hero-title .line { font-size: clamp(3rem, 6.8vw, 6.6rem); }
html[lang^="zh"] .sw-hero .hero-title .line {
  font-size: clamp(3.35rem, 6.8vw, 6.4rem);
  line-height: 1.12;
}
.sw-hero .hero-spec {
  display: block;
  margin-top: clamp(20px, 2.5vw, 30px);
  color: var(--accent);
  font-family: var(--mono-multi);
  font-size: var(--fm-2);
  font-weight: 600;
  letter-spacing: 0.09em;
  line-height: 1.65;
  text-transform: uppercase;
  word-break: keep-all;
}
.sw-hero .hero-spec::before { content: "//"; margin-right: 10px; color: var(--muted); }
.sw-hero-lead {
  max-width: 62ch;
  margin-top: 22px;
  color: var(--muted);
  font-size: var(--ft-body);
  line-height: 1.72;
}
.sw-hero .hero-actions { margin-top: clamp(28px, 4vw, 44px); }

.sw-hero-visual {
  position: relative;
  border: 1px solid var(--line-strong);
  background: #080a0d;
  box-shadow: 18px 18px 0 rgba(0, 0, 0, 0.22);
  overflow: hidden;
}
.sw-hero-visual::before,
.sw-hero-visual::after {
  content: "";
  position: absolute;
  z-index: 3;
  width: 18px;
  height: 18px;
  border-color: var(--accent);
}
.sw-hero-visual::before { top: -1px; left: -1px; border-top: 2px solid; border-left: 2px solid; }
.sw-hero-visual::after { right: -1px; bottom: -1px; border-right: 2px solid; border-bottom: 2px solid; }
.sw-hero-visual-bar,
.sw-hero-visual figcaption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 14px;
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: #9ba5ad;
}
.sw-hero-visual-bar { border-bottom: 1px solid rgba(237, 241, 243, 0.18); }
.sw-console-running { display: inline-flex; align-items: center; gap: 7px; color: var(--accent); }
.sw-console-running i { width: 7px; height: 7px; background: currentColor; }
.sw-hero-visual-screen { aspect-ratio: 1.22; background: #080a0d; overflow: hidden; }
.sw-hero-visual-screen img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: right center;
  transform: scale(1.12);
  transform-origin: right center;
}
.sw-hero-visual figcaption { align-items: flex-end; border-top: 1px solid rgba(237, 241, 243, 0.18); }
.sw-hero-visual figcaption strong { color: #edf1f3; font-family: var(--sans); font-size: 0.92rem; letter-spacing: 0.03em; }
.sw-hero-visual figcaption span { color: #9ba5ad; text-align: right; }

.sw-proof { padding-top: clamp(56px, 7vw, 92px); }

.sw-technology,
.sw-applications,
.sw-support,
.sw-company { padding: clamp(82px, 11vw, 150px) 0; }
.sw-technology .sec-title span,
.sw-applications .sec-title span,
.sw-support .sec-title span,
.sw-company .sec-title span { display: block; }
.sw-technology .sec-title span:last-child,
.sw-applications .sec-title span:last-child,
.sw-support .sec-title span:last-child,
.sw-company .sec-title span:last-child { color: var(--ink); }

.sw-tech-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(300px, 0.8fr);
  gap: clamp(38px, 7vw, 94px);
  align-items: center;
  margin-top: clamp(46px, 7vw, 80px);
}
.sw-stack { border: 1px solid var(--line-strong); background: var(--bg-2); }
.sw-stack-cap,
.sw-stack-bus,
.sw-stack-machine,
.sw-stack-bridge {
  padding: 13px 18px;
  font-family: var(--mono-multi);
  font-size: var(--fm-2);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-align: center;
  text-transform: uppercase;
}
.sw-stack-cap { background: var(--ink); color: var(--bg); }
.sw-stack-layer { padding: clamp(24px, 4vw, 44px); }
.sw-stack-layer span { display: block; color: var(--accent); font-family: var(--mono); font-size: var(--fm-2); letter-spacing: 0.12em; }
.sw-stack-layer strong { display: block; margin-top: 10px; font-size: clamp(1.05rem, 2vw, 1.35rem); line-height: 1.45; }
.sw-stack-windows { border-bottom: 1px solid var(--line); }
.sw-stack-rt { background: var(--ink); color: var(--bg); }
.sw-stack-bridge { position: relative; z-index: 1; width: fit-content; margin: -17px auto; border: 1px solid var(--accent); background: var(--bg); color: var(--accent); }
.sw-stack-bus { border-top: 1px solid var(--line-strong); color: var(--accent); line-height: 1.6; }
.sw-stack-machine { border-top: 1px solid var(--line); color: var(--muted); }
.sw-tech-points { border-top: 1px solid var(--line); }
.sw-tech-points li { display: grid; grid-template-columns: 42px 1fr; gap: 18px; padding: 28px 0; border-bottom: 1px solid var(--line); }
.sw-tech-points > li > span { color: var(--accent); font-family: var(--mono); font-size: var(--fm-2); }
.sw-tech-points h3 { font-size: 1.18rem; }
.sw-tech-points p { margin-top: 8px; color: var(--muted); line-height: 1.65; }

.sw-products {
  padding: clamp(82px, 11vw, 150px) 0;
  overflow: hidden;
  background: var(--inv-bg);
  color: var(--inv-ink);
  transition: background-color .25s ease, color .25s ease;
}
.sw-products .sec-tag span,
.sw-products .sec-lead { color: var(--inv-muted); }
.sw-products .sec-lead { margin-bottom: clamp(44px, 7vw, 76px); }
.sw-product-grid { border-top: 1px solid var(--inv-ink); }
.sw-product-card {
  display: grid;
  grid-template-columns: minmax(230px, .68fr) minmax(0, 1.32fr);
  min-height: 390px;
  border-bottom: 1px solid var(--inv-ink);
}
.sw-product-media {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 300px;
  padding: clamp(26px, 4vw, 54px);
  border-right: 1px solid var(--inv-ink);
  background: #d3dbe0;
  overflow: hidden;
}
.sw-product-media > span { position: absolute; top: 18px; left: 18px; color: #52606a; font-family: var(--mono); font-size: var(--fm-2); }
.sw-product-media img { width: min(100%, 320px); max-height: 280px; object-fit: contain; transition: transform .28s var(--ease); }
.sw-product-card:hover .sw-product-media img { transform: scale(1.035); }
.sw-product-copy { display: flex; flex-direction: column; justify-content: center; padding: clamp(34px, 6vw, 76px); }
.sw-eyebrow { color: var(--inv-muted); font-family: var(--mono); font-size: var(--fm-2); font-weight: 600; letter-spacing: .13em; text-transform: uppercase; }
.sw-product-copy h3 { margin-top: 8px; font-size: clamp(2.5rem, 5vw, 4.9rem); }
.sw-product-copy > p:not(.sw-eyebrow) { max-width: 64ch; margin-top: 20px; color: var(--inv-muted); font-size: var(--ft-body); }
.sw-product-copy ul { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 28px; }
.sw-product-copy li { padding: 7px 10px; border: 1px solid var(--inv-ghost); color: var(--inv-ink); font-family: var(--mono-multi); font-size: var(--fm-3); }

.sw-applications .sec-lead { margin-bottom: clamp(44px, 7vw, 78px); }
.sw-case-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border-top: 1px solid var(--line); border-left: 1px solid var(--line); }
.sw-case-card { min-width: 0; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--bg-2); }
.sw-case-image { position: relative; display: grid; place-items: center; min-height: 260px; padding: clamp(20px, 3vw, 38px); overflow: hidden; background: #dfe5e8; }
.sw-case-image img { width: 100%; height: 230px; object-fit: contain; transition: transform .3s var(--ease); }
.sw-case-card:hover .sw-case-image img { transform: scale(1.025); }
.sw-case-image span { position: absolute; top: 14px; left: 14px; padding: 4px 7px; background: var(--amber); color: var(--on-amber); font-family: var(--mono); font-size: var(--fm-3); }
.sw-case-copy { padding: clamp(24px, 3vw, 36px); }
.sw-case-copy h3 { font-size: clamp(1.25rem, 2.2vw, 1.7rem); }
.sw-case-copy p { margin-top: 12px; color: var(--muted); line-height: 1.65; }

.sw-support { background: var(--bg-2); border-block: 1px solid var(--line); }
.sw-support-grid { display: grid; grid-template-columns: minmax(0, .9fr) minmax(320px, 1.1fr); gap: clamp(42px, 8vw, 110px); align-items: start; }
.sw-service-list { border-top: 1px solid var(--line); }
.sw-service-list li { display: grid; grid-template-columns: 44px 1fr; gap: 18px; padding: 26px 0; border-bottom: 1px solid var(--line); }
.sw-service-list > li > span { color: var(--accent); font-family: var(--mono); font-size: var(--fm-2); }
.sw-service-list h3 { font-size: 1.15rem; }
.sw-service-list p { margin-top: 7px; color: var(--muted); line-height: 1.6; }

.sw-company-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(320px, .78fr); gap: clamp(42px, 8vw, 110px); }
.sw-company-body { padding-top: 5px; border-top: 1px solid var(--line-strong); }
.sw-company-body p { padding: 22px 0; border-bottom: 1px solid var(--line); color: var(--muted); font-size: var(--ft-body); line-height: 1.72; }
.sw-global { margin-top: clamp(50px, 8vw, 92px); padding-top: 18px; border-top: 1px solid var(--line-strong); }
.sw-global > p { color: var(--muted); font-family: var(--mono); font-size: var(--fm-2); letter-spacing: .12em; text-transform: uppercase; }
.sw-global ul { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-top: 20px; border-top: 1px solid var(--line); border-left: 1px solid var(--line); }
.sw-global li { min-height: 118px; padding: 22px; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.sw-global li i { display: block; width: 8px; height: 8px; margin-bottom: 22px; background: var(--accent); }
.sw-global li span { font-weight: 700; }

.sw-contact { border-top: 3px solid var(--accent); }
.sw-contact > .frame { display: grid; grid-template-columns: minmax(0, 1fr) minmax(340px, .7fr); gap: clamp(44px, 8vw, 110px); padding-block: clamp(74px, 10vw, 130px); }
.sw-contact-head .start-tag { justify-content: flex-start; }
.sw-contact-head h2 { max-width: 760px; font-size: clamp(3rem, 7vw, 6.4rem); line-height: .98; }
.sw-contact-head > p:not(.sec-tag) { max-width: 60ch; margin-top: 26px; color: var(--muted); font-size: var(--ft-body); }
.sw-contact-head .start-actions { justify-content: flex-start; }
.sw-contact-details { align-self: end; border-top: 1px solid var(--line-strong); }
.sw-contact-details > div { padding: 22px 0; border-bottom: 1px solid var(--line); }
.sw-contact-details dt { color: var(--muted); font-family: var(--mono); font-size: var(--fm-2); letter-spacing: .08em; text-transform: uppercase; }
.sw-contact-details dd { margin: 8px 0 0; font-size: 1.02rem; line-height: 1.6; }
.sw-contact-details a:hover { color: var(--accent); }

.sw-foot-logo { width: fit-content; }
.sw-foot-logo img { width: 197px; }

@media (max-width: 1024px) {
  .sw-hero-grid { grid-template-columns: minmax(320px, .9fr) minmax(400px, 1.1fr); gap: 32px; }
  .sw-hero .hero-title .line { font-size: clamp(2.7rem, 6.7vw, 5rem); }
  .sw-tech-grid { grid-template-columns: 1fr; }
  .sw-global ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .sw-hero-grid { grid-template-columns: 1fr; min-height: auto; }
  .sw-hero-visual { width: min(760px, 100%); }
  .sw-hero-visual-screen { aspect-ratio: 1.904; }
  .sw-hero-visual-screen img { object-fit: contain; transform: none; }
  .sw-support-grid,
  .sw-company-grid,
  .sw-contact > .frame { grid-template-columns: 1fr; }
  .sw-contact-details { margin-top: 12px; }
}

@media (max-width: 780px) {
  .sw-brand-plaque img { width: 168px; }
  .sw-brand-sub { font-size: .5rem; }
  .sw-product-card { grid-template-columns: 1fr; }
  .sw-product-media { min-height: 260px; border-right: 0; border-bottom: 1px solid var(--inv-ink); }
  .sw-case-grid { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .topbar-meta { width: 100%; justify-content: space-between; gap: 10px; }
  .sw-hero-grid { padding-top: 48px; }
  .sw-hero .hero-title .line,
  html[lang^="zh"] .sw-hero .hero-title .line { font-size: clamp(3rem, 15vw, 4.5rem); }
  .sw-hero-visual figcaption { align-items: flex-start; flex-direction: column; }
  .sw-hero-visual figcaption span { text-align: left; }
  .sw-global ul { grid-template-columns: 1fr; }
  .sw-contact-head h2 { font-size: 3.25rem; }
  .sw-contact .start-actions .btn { width: 100%; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .sw-console-running i { animation: none; }
  .sw-product-media img,
  .sw-case-image img { transition: none; }
  .sw-product-card:hover .sw-product-media img,
  .sw-case-card:hover .sw-case-image img { transform: none; }
  .sw-hero::after { background: radial-gradient(760px circle at 76% 18%, rgba(215, 34, 44, 0.075), transparent 68%); }
}

/* ============================================================
   SOFTWIN WHITE EDITION · original-site content first
   ============================================================ */

html[data-theme="light"],
html[data-theme="dark"] {
  color-scheme: light;
  --bg: #ffffff;
  --bg-2: #f7f8fa;
  --ink: #252525;
  --muted: #666666;
  --accent: #d1151a;
  --amber: #d1151a;
  --on-amber: #ffffff;
  --line: #e5e5e5;
  --line-strong: #c9c9c9;
  --dot: transparent;
  --ghost-stroke: rgba(37, 37, 37, 0.14);
  --inv-bg: #ffffff;
  --inv-ink: #252525;
  --inv-muted: #666666;
  --inv-ghost: rgba(37, 37, 37, 0.14);
  --thumb: #c8c8c8;
}

body {
  padding-left: 0;
  background: #ffffff;
  color: var(--ink);
  font-weight: 400;
}
@media (min-width: 1101px) { body { padding-left: 0; } }
.grain,
.rail { display: none; }

.topbar {
  left: 0;
  background: rgba(255, 255, 255, 0.98);
  border-bottom-color: var(--line);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.02);
}
@media (min-width: 1101px) { .topbar { left: 0; } }
.topbar-row { padding-block: 20px 16px; }
.sw-brand { gap: 8px; }
.sw-brand > img {
  width: 197px;
  height: auto;
}
.sw-brand-sub {
  color: #3f3f3f;
  font-family: var(--sans);
  font-size: 0.76rem;
  font-weight: 500;
  letter-spacing: 0.025em;
  line-height: 1.35;
}
html[data-scrolled] .sw-brand > img { width: 158px; }
html[data-scrolled] .sw-brand-sub { display: block; font-size: 0.68rem; }
.topbar-meta { margin-left: auto; }
.lang a { color: var(--muted); }
.lang a[aria-current="page"] { color: var(--accent); border-color: var(--accent); }
.topnav {
  border-color: var(--line);
  background: #ffffff;
}
.topnav a { color: #555555; letter-spacing: 0.07em; }
.topnav a:hover { color: var(--accent); }
.topnav-start {
  color: var(--accent) !important;
  border-color: var(--accent);
}

.btn { letter-spacing: 0.025em; text-transform: none; }
.btn-solid {
  border-color: var(--accent);
  background: var(--accent);
  color: #ffffff;
}
.btn-solid:hover { box-shadow: 4px 4px 0 rgba(209, 21, 26, 0.16); }
.btn-ghost { border-color: #bdbdbd; color: #333333; }
.btn-ghost:hover { color: var(--accent); box-shadow: 4px 4px 0 rgba(209, 21, 26, 0.1); }

.sec-tag {
  margin-bottom: 16px;
  color: var(--accent);
  font-family: var(--sans);
  font-size: 0.88rem;
  letter-spacing: 0.08em;
}
.sec-tag::before { width: 18px; height: 2px; }
.sec-tag span { color: var(--accent); }
.sec-title,
.sw-contact-head h2 {
  max-width: 920px;
  margin-bottom: 18px;
  color: #292929;
  font-family: var(--sans-cjk-black);
  font-size: clamp(2rem, 4vw, 3.2rem);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.18;
}
.sec-lead { color: var(--muted); line-height: 1.8; }

.sw-hero::after { display: none; }
.sw-hero-grid {
  grid-template-columns: minmax(360px, 0.92fr) minmax(500px, 1.08fr);
  gap: clamp(36px, 5vw, 74px);
  min-height: auto;
  padding: clamp(66px, 8vw, 104px) 0;
}
.sw-hero .hero-title,
html[lang^="zh"] .sw-hero .hero-title {
  display: block;
  max-width: 720px;
  margin: 0;
  color: var(--accent);
  font-family: var(--sans-cjk-black);
  font-size: clamp(2.5rem, 4.5vw, 4rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.15;
}
.sw-hero .hero-spec {
  display: block;
  margin-top: 22px;
  color: #555555;
  font-family: var(--sans);
  font-size: clamp(1rem, 1.35vw, 1.18rem);
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.75;
  text-transform: none;
  word-break: normal;
}
.sw-hero .hero-spec::before { display: none; }
.sw-hero-lead {
  max-width: 64ch;
  margin-top: 20px;
  color: #666666;
  font-size: 1rem;
  line-height: 1.8;
}
.sw-hero .hero-actions { margin-top: 30px; }
.sw-hero-visual {
  border: 1px solid #d8d8d8;
  background: #090b0e;
  box-shadow: none;
}
.sw-hero-visual::before,
.sw-hero-visual::after { display: none; }
.sw-hero-visual-screen { aspect-ratio: 1.3; }
.sw-hero-visual-screen img {
  object-fit: cover;
  object-position: right center;
  transform: scale(1.2);
  transform-origin: right center;
}

.sw-proof {
  padding: 52px 0 64px;
  border-block: 1px solid var(--line);
  background: #fafafa;
}
.proof-grid { border-color: var(--line); }
.proof-cell { border-color: var(--line); }
.proof-num { color: #333333; }
.proof-cap { color: var(--muted); }
.trust {
  margin-top: 48px;
  padding-top: 34px;
  border-top: 1px solid var(--line);
}
.trust-lead,
.trust-note {
  color: var(--muted);
  font-family: var(--sans);
  font-size: 0.95rem;
  letter-spacing: 0.02em;
}
.trust-lead { margin-bottom: 22px; }
.trust-note { margin-top: 22px; }
.trust-logos {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 18px 28px;
}
.trust-logos li {
  display: grid;
  place-items: center;
  min-height: 76px;
}
.trust-logos img {
  width: 100%;
  max-width: 210px;
  height: 60px;
  object-fit: contain;
  filter: grayscale(1) brightness(0.45);
  opacity: 0.72;
}

.sw-technology,
.sw-applications,
.sw-support,
.sw-company { padding: clamp(72px, 9vw, 116px) 0; }
.sw-tech-articles { border-top: 1px solid var(--line); }
.sw-tech-article {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(360px, 0.82fr);
  gap: clamp(38px, 7vw, 100px);
  align-items: center;
  padding: clamp(44px, 6vw, 72px) 0;
  border-bottom: 1px solid var(--line);
}
.sw-tech-article:nth-child(even) .sw-tech-copy { order: 2; }
.sw-tech-article:nth-child(even) img { order: 1; }
.sw-tech-copy h2 {
  color: #333333;
  font-family: var(--sans-cjk-black);
  font-size: clamp(1.7rem, 3vw, 2.5rem);
  font-weight: 700;
  line-height: 1.3;
}
.sw-tech-copy p {
  margin-top: 18px;
  color: var(--muted);
  font-size: 1.03rem;
  line-height: 1.85;
}
.sw-tech-article img {
  width: 100%;
  max-height: 380px;
  object-fit: contain;
}

.sw-products {
  padding: clamp(72px, 9vw, 116px) 0;
  background: #ffffff;
  color: var(--ink);
}
.sw-products .sec-tag span { color: var(--accent); }
.sw-products .sec-lead { color: var(--muted); margin-bottom: 42px; }
.sw-product-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
  border: 0;
}
.sw-product-card {
  display: flex;
  min-height: 0;
  flex-direction: column;
  border: 1px solid var(--line);
  background: #ffffff;
}
.sw-product-media {
  display: grid;
  place-items: center;
  min-height: 320px;
  padding: 28px;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: #ffffff;
}
.sw-product-media > span { color: #999999; }
.sw-product-media img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 260px;
  object-fit: contain;
  transform: none !important;
}
.sw-product-copy {
  display: block;
  padding: 30px 32px 34px;
}
.sw-eyebrow { color: var(--accent); }
.sw-product-copy h3 {
  margin-top: 8px;
  color: #2d2d2d;
  font-family: var(--sans-cjk-black);
  font-size: clamp(1.45rem, 2.5vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.3;
}
.sw-product-copy > p:not(.sw-eyebrow) { color: var(--muted); line-height: 1.75; }
.sw-product-copy li {
  border-color: #d9d9d9;
  color: #555555;
  background: #fafafa;
}

.sw-case-grid { border-color: var(--line); }
.sw-case-card { border-color: var(--line); background: #ffffff; }
.sw-case-image {
  min-height: 260px;
  border-bottom: 1px solid var(--line);
  background: #ffffff;
}
.sw-case-image img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 230px;
  object-fit: contain;
  transform: none !important;
}
.sw-case-image span { background: var(--accent); }
.sw-case-copy h3 { color: #333333; }

.sw-support {
  border-color: var(--line);
  background: #fafafa;
}
.sw-service-list,
.sw-service-list li { border-color: var(--line); }
.sw-service-list > li > span { color: var(--accent); }
.sw-company-body,
.sw-company-body p,
.sw-global,
.sw-global ul,
.sw-global li { border-color: var(--line); }
.sw-global li i { background: var(--accent); }

.sw-contact {
  border-top: 3px solid var(--accent);
  background: #fafafa;
}
.sw-contact-head h2 { font-size: clamp(2.2rem, 4.5vw, 3.6rem); }
.sw-contact-details,
.sw-contact-details > div { border-color: var(--line); }

.foot { border-color: var(--line); background: #ffffff; }
.sw-foot-logo { width: 197px; height: auto; }
.foot-brand .foot-legal { color: #333333; }
.foot-top { border-color: var(--line); }
.foot-top:hover { background: var(--accent); color: #ffffff; }

@media (max-width: 1024px) {
  .sw-hero-grid { grid-template-columns: minmax(320px, 0.9fr) minmax(400px, 1.1fr); }
}

@media (max-width: 900px) {
  .sw-hero-grid { grid-template-columns: 1fr; }
  .sw-hero-visual { width: min(760px, 100%); }
  .sw-hero-visual-screen { aspect-ratio: 1.45; }
  .sw-hero-visual-screen img { object-fit: cover; transform: scale(1.2); }
  .sw-tech-article { grid-template-columns: 1fr; }
  .sw-tech-article:nth-child(even) .sw-tech-copy,
  .sw-tech-article:nth-child(even) img { order: initial; }
  .trust-logos { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 780px) {
  .sw-brand > img { width: 168px; }
  .sw-brand-sub { max-width: 34ch; font-size: 0.7rem; }
  .sw-product-grid { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .topbar-meta { width: auto; }
  .sw-hero-grid { padding-top: 54px; }
  .sw-hero .hero-title,
  html[lang^="zh"] .sw-hero .hero-title { font-size: clamp(2.15rem, 10vw, 3rem); }
  .sw-hero-visual-screen { aspect-ratio: 1.25; }
  .trust-logos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .trust-logos img { height: 50px; }
  .sw-product-media { min-height: 270px; }
  .sw-product-media img { max-height: 220px; }
}
