/* Callouts, part card extras, system picker and control sections.
 * Owned by engine/focus.js + engine/controls.js work. Self-contained so the quote page can
 * load it without app.css: every colour falls back when the page has no tokens, and the text
 * sizes use the course page's desktop type scale (--ui, --ui-floor: css/app.css) with fallbacks
 * that give the written px on any other page. */

/* ---------- 3D callouts (engine/focus.js) ---------- */
/* The page positions the root (#callouts); focus.js adds .fx-callouts. */
.fx-callouts { pointer-events: none; overflow: hidden; }
.fx-callout {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  opacity: 0;
  transition: opacity 0.35s ease;
  pointer-events: none;
  will-change: transform;
}
.fx-callout.on { opacity: 1; }
.fx-callout:not(.on) * { pointer-events: none !important; }
.fx-dot {
  position: absolute;
  left: -5px;
  top: -5px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--brand, #0ea9e2);
  border: 2px solid #fff;
  box-shadow: 0 0 0 3px rgba(14, 169, 226, 0.28), 0 1px 4px rgba(0, 0, 0, 0.5);
  pointer-events: auto;
  cursor: pointer;
  animation: fx-ping 2.4s ease-in-out infinite;
}
.fx-lead {
  position: absolute;
  left: 0;
  top: -0.5px;
  width: 1px;
  height: 1px;
  background: rgba(233, 238, 246, 0.6);
  transform-origin: 0 50%;
}
.fx-label {
  position: absolute;
  left: 0;
  top: 0;
  white-space: nowrap;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0.01em;
  color: var(--ink, #e9eef6);
  padding: 3px 9px;
  border-radius: 7px;
  background: rgba(8, 12, 20, 0.84);
  border: 1px solid var(--line-2, rgba(170, 190, 220, 0.26));
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  pointer-events: auto;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}
.fx-label:hover { border-color: var(--brand, #0ea9e2); }
.fx-callout.sel .fx-label { border-color: var(--brand, #0ea9e2); background: rgba(10, 60, 84, 0.9); }
.fx-callout.sel .fx-dot { background: #fff; border-color: var(--brand, #0ea9e2); }
@keyframes fx-ping {
  0%, 100% { box-shadow: 0 0 0 3px rgba(14, 169, 226, 0.3), 0 1px 4px rgba(0, 0, 0, 0.5); }
  50% { box-shadow: 0 0 0 7px rgba(14, 169, 226, 0.04), 0 1px 4px rgba(0, 0, 0, 0.5); }
}
/* A tiny part (a fuse, a sensor): a ring around it instead of a dot on top of it. focus.js sets
   --ring (the ring's diameter) and starts the lead at the ring's edge. */
.fx-callout.ring .fx-dot {
  width: var(--ring, 22px);
  height: var(--ring, 22px);
  left: calc(var(--ring, 22px) * -0.5);
  top: calc(var(--ring, 22px) * -0.5);
  background: transparent;
  border: 1.5px solid #fff;
  box-shadow: 0 0 0 1.5px var(--brand, #0ea9e2), 0 0 8px rgba(0, 0, 0, 0.55);
  animation: none;
}
.fx-callout.ring.sel .fx-dot { background: transparent; border-color: var(--brand, #0ea9e2); box-shadow: 0 0 0 1.5px #fff, 0 0 8px rgba(0, 0, 0, 0.55); }
/* The anchor is hidden behind another part (outside view, a back view, a part inside a panel):
   hollow dot, fainter dashed lead, dashed label that says so. */
.fx-callout.behind .fx-dot { background: rgba(8, 12, 20, 0.55); border-color: var(--brand-ink, #7fd6f6); animation: none; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5); }
.fx-callout.behind.ring .fx-dot { background: transparent; border-style: dashed; }
.fx-callout.behind .fx-lead { opacity: 0.55; }
.fx-callout.behind .fx-label { border-style: dashed; border-color: rgba(170, 190, 220, 0.5); color: var(--ink-2, #aab4c3); background: rgba(8, 12, 20, 0.72); }
.fx-callout.behind .fx-label::after { content: "喺入面"; margin-left: 6px; font-size: max(11px, 0.86em); font-weight: 400; color: var(--ink-3, #8390a3); }
html[lang="en"] .fx-callout.behind .fx-label::after { content: "inside"; }
html[lang="ja"] .fx-callout.behind .fx-label::after { content: "内部"; }
.fx-callout.behind.sel .fx-label { border-color: var(--brand, #0ea9e2); color: var(--ink, #e9eef6); }
/* Touch: a bigger invisible hit area on the dot; each label's hit area is 44px tall, or fills
   the gap to the next stacked label (at least the 34px pitch focus.js stacks them at on coarse
   pointers; focus.js sets --hit-y), so neighbours never share a tap. */
@media (pointer: coarse) {
  .fx-dot::after { content: ""; position: absolute; inset: -10px; border-radius: 50%; }
  .fx-label { padding: 4px 10px; font-size: 12px; }
  .fx-label::before { content: ""; position: absolute; inset: var(--hit-y, -5px) -4px; }
}

/* ---------- System picker (#sysPicker, first child of #panel) ---------- */
.sys-picker {
  padding: 12px 0 12px;
  border-bottom: 1px solid var(--line, rgba(170, 190, 220, 0.14));
}
.sys-picker[hidden] { display: none; }
.sys-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; min-height: 24px; }
.sys-title { font-size: calc(12.5 * var(--ui, 1px)); color: var(--ink-2, #aab4c3); }
.sys-hint { font-size: max(var(--ui-floor, 0px), calc(11 * var(--ui, 1px))); color: var(--ink-3, #6f7b8d); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sys-picker.active .sys-hint { visibility: hidden; }
.sys-back {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
  font-size: calc(12 * var(--ui, 1px));
  padding: 3px 8px 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--line-2, rgba(170, 190, 220, 0.26));
  background: rgba(255, 255, 255, 0.04);
  color: var(--ink, #e9eef6);
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s;
}
.sys-back:hover { border-color: var(--brand, #0ea9e2); background: rgba(14, 169, 226, 0.14); }
.sys-back svg { width: 10px; height: 10px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.sys-back[hidden] { display: none; }
.sys-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.sys-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: calc(12.5 * var(--ui, 1px));
  padding: 5px 11px 5px 9px;
  border-radius: 999px;
  border: 1px solid var(--line-2, rgba(170, 190, 220, 0.26));
  background: rgba(0, 0, 0, 0.22);
  color: var(--ink-2, #aab4c3);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s;
  -webkit-tap-highlight-color: transparent;
}
.sys-chip i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  opacity: 0.7;
  flex: none;
  transition: background 0.2s, border-color 0.2s;
}
.sys-chip:hover { color: var(--ink, #e9eef6); border-color: rgba(14, 169, 226, 0.6); }
.sys-chip.on {
  color: #04121a;
  font-weight: 700;
  background: var(--brand, #0ea9e2);
  border-color: var(--brand, #0ea9e2);
  box-shadow: 0 0 0 3px rgba(14, 169, 226, 0.2);
}
.sys-chip.on i { background: #04121a; border-color: #04121a; opacity: 1; }
.sys-desc {
  margin: 9px 0 0;
  font-size: calc(12.5 * var(--ui, 1px));
  line-height: 1.55;
  color: var(--ink-2, #aab4c3);
  animation: fx-in 0.3s ease;
}
.sys-desc[hidden] { display: none; }
.sys-desc b { color: var(--ink, #e9eef6); font-weight: 600; margin-right: 4px; }
.sys-parts { display: block; margin-top: 4px; font-size: calc(12 * var(--ui, 1px)); color: var(--brand-ink, #7fd6f6); }

/* ---------- Part card extras (#partInfo) ---------- */
.part-sys {
  flex: none;
  font-size: max(var(--ui-floor, 0px), calc(11 * var(--ui, 1px)));
  line-height: 1.4;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid rgba(14, 169, 226, 0.45);
  background: rgba(14, 169, 226, 0.1);
  color: var(--brand-ink, #7fd6f6);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.2s;
}
.part-sys:hover:not(:disabled) { background: rgba(14, 169, 226, 0.24); }
.part-sys:disabled { cursor: default; opacity: 0.8; }
.part-sys[hidden] { display: none; }
.part-repairs { margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--line, rgba(170, 190, 220, 0.14)); }
.part-repairs[hidden] { display: none; }
.part-repairs-label { display: block; font-size: max(var(--ui-floor, 0px), calc(11 * var(--ui, 1px))); color: var(--ink-3, #6f7b8d); margin-bottom: 6px; }
.part-repairs-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.rep-chip {
  font-size: calc(12 * var(--ui, 1px));
  padding: 4px 10px;
  border-radius: 8px;
  border: 1px solid var(--line-2, rgba(170, 190, 220, 0.26));
  background: rgba(255, 255, 255, 0.04);
  color: var(--ink, #e9eef6);
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s;
}
.rep-chip:hover:not(:disabled):not(.off) { border-color: var(--brand, #0ea9e2); background: rgba(14, 169, 226, 0.14); }
.rep-chip:disabled { opacity: 0.45; cursor: default; }
/* The item being previewed. */
.rep-chip[aria-pressed="true"] { border-color: var(--brand, #0ea9e2); background: rgba(14, 169, 226, 0.2); box-shadow: 0 0 0 2px rgba(14, 169, 226, 0.18); }
/* Nothing to show in 3D: dimmed, dashed, still tappable (it explains why in .rep-note). */
.rep-chip.off { opacity: 0.6; border-style: dashed; cursor: help; color: var(--ink-2, #aab4c3); }
/* 檢查費 (check-fee) items: a small tag, on the chip and in the preview's description. */
.rep-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 0 5px;
  border-radius: 4px;
  font-size: max(var(--ui-floor, 0px), calc(10.5 * var(--ui, 1px)));
  font-weight: 500;
  line-height: 1.5;
  vertical-align: 1px;
  color: var(--warn, #ffc24b);
  border: 1px solid rgba(255, 194, 75, 0.45);
  background: rgba(255, 194, 75, 0.08);
}
.sys-desc .rep-tag { margin: 0 6px 0 0; }
.rep-note { margin: 8px 0 0; font-size: calc(12.5 * var(--ui, 1px)); line-height: 1.55; color: var(--ink-2, #aab4c3); animation: fx-in 0.3s ease; }
.rep-note[hidden] { display: none; }
.rep-note b { color: var(--ink, #e9eef6); font-weight: 600; margin-right: 4px; }

/* ---------- Control sections + toggle + action feedback (engine/controls.js) ---------- */
.ctl-section { border-bottom: 1px solid var(--line, rgba(170, 190, 220, 0.14)); }
.ctl-section[hidden] { display: none; }
.ctl-section > summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 11px 0;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-3, #6f7b8d);
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.ctl-section > summary::-webkit-details-marker { display: none; }
.ctl-section > summary:hover { color: var(--ink-2, #aab4c3); }
.ctl-caret {
  width: 7px;
  height: 7px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.2s;
}
.ctl-section[open] .ctl-caret { transform: translateY(1px) rotate(-135deg); }
.ctl-section-body > .ctl:first-child { padding-top: 2px; }
.ctl-section-body > .ctl:last-child { border-bottom: 0; }
.ctl-section:last-child { border-bottom: 0; }

.ctl .toggle {
  position: relative;
  width: 40px;
  height: 22px;
  padding: 0;
  border-radius: 999px;
  border: 1px solid var(--line-2, rgba(170, 190, 220, 0.26));
  background: rgba(0, 0, 0, 0.3);
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s;
}
.ctl .toggle::after {
  content: "";
  position: absolute;
  left: 2px;
  top: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--ink-2, #aab4c3);
  transition: transform 0.2s, background 0.2s;
}
.ctl .toggle.on { background: var(--brand, #0ea9e2); border-color: var(--brand, #0ea9e2); }
.ctl .toggle.on::after { transform: translateX(18px); background: #fff; }
.ctl-toggle { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.ctl-toggle .ctl-head { margin-bottom: 0; flex: 1; }
.seg.actions button.fired { animation: fx-fire 0.45s ease; }
.seg.actions button:disabled { opacity: 0.4; cursor: default; }
@keyframes fx-fire { 0% { background: rgba(14, 169, 226, 0.55); color: #fff; } 100% { background: transparent; } }
@keyframes fx-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ---------- Phones ---------- */
@media (max-width: 900px) {
  /* scrollIntoView keeps the card clear of the fixed lesson switcher at the bottom. */
  #partInfo, #sysPicker { scroll-margin: 12px 0 96px; }
  /* One swipeable row of systems keeps the panel short; the active chip scrolls into view. */
  .sys-chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    scroll-snap-type: x proximity;
    margin: 0 -16px;
    padding: 2px 16px 4px;
    -webkit-overflow-scrolling: touch;
  }
  .sys-chips::-webkit-scrollbar { display: none; }
  .sys-chip { scroll-snap-align: center; padding: 7px 13px 7px 11px; font-size: 13px; }
  .sys-back { padding: 5px 10px 5px 12px; font-size: 12.5px; }
  .rep-chip { padding: 6px 11px; font-size: 12.5px; }
  .rep-tag { font-size: 11px; }
  .rep-note { font-size: 13.5px; }
  .ctl-section > summary { padding: 13px 0; }
}

@media (prefers-reduced-motion: reduce) {
  .fx-dot { animation: none; }
}

/* Staff feedback (engine/feedback.js, js/course-feedback.js): only exists inside the Claude app
   preview. The shell draws the pins and the composer; the page only offers an entry point. */
.part-note {
  flex: none;
  margin-left: auto;
  font: inherit;
  font-size: max(var(--ui-floor, 0px), calc(11 * var(--ui, 1px)));
  line-height: 1.4;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--line-2, rgba(170, 190, 220, 0.26));
  background: transparent;
  color: var(--ink-2, #aab4c3);
  cursor: pointer;
}
.part-note:hover { color: var(--ink, #e9eef6); border-color: var(--warn, #ffc24b); }
.part-note:focus-visible { outline: 2px solid var(--brand, #0ea9e2); outline-offset: 2px; }
.part-head .part-note + .icon-btn { margin-left: 0; }
html.fb-mode #scene { cursor: crosshair; }
@media (max-width: 900px) {
  .part-note { position: relative; min-height: 30px; padding: 5px 12px; font-size: 12px; }
  .part-note::after { content: ""; position: absolute; inset: -7px -3px; }
}
