/* FullCircle project page and comparisons page. Purple is FullCircle's colour (talk deck); green is SwitchSplat's. */
:root {
  --purple: #9e69da;          /* FullCircle only: its name and its results */
  --link: #1f3a60;            /* links: dark navy, never underlined */
  --link-hover: #3a5f8f;
  --btn: #1d1d22;             /* buttons: near-black with light grey text */
  --btn-hover: #34343c;
  --btn-text: #ececf0;
  --btn-light: #ececf0;       /* the Viewer button: the reverse */
  --btn-light-hover: #dfdfe5;
  --problem: #d92d20;         /* the operator, the problem we solve */
  --wash: #f4f4f6;            /* tinted panels */
  --switchsplat: #1f6f4a;
  --yellow: #c79a00;
  --ink: #16161b;
  --text: #3a3a44;
  --muted: #6b6b76;
  --line: #e6e6ea;
  --code-bg: #f6f6f8;
  --radius: 12px;
  --page: 1000px;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: #fff;
  color: var(--text);
  font: 400 17px/1.65 Inter, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}
/* Links are blue and never underlined; purple (.accent) marks FullCircle itself and is never a link. */
a { color: var(--link); text-decoration: none; }
a:hover { color: var(--link-hover); }
a.cite { font-weight: 500; }
/* FullCircle links (captions, labels) keep the FullCircle purple */
a.accent, .vlabels a.m.ours { color: var(--purple); }
a.accent:hover, .vlabels a.m.ours:hover { color: #b48be6; }
img, video { display: block; max-width: 100%; }
p { margin: 0 0 1rem; text-wrap: pretty; }
b, strong { color: var(--ink); font-weight: 600; }
.accent { color: var(--purple); }
.problem { color: var(--problem); }
.yellow { color: var(--yellow); }
.centered { text-align: center; }
/* key phrases: just bold, like <b> */
u {
  text-decoration: none;
  color: var(--ink);
  font-weight: 600;
}

/* header */
.hero {
  max-width: var(--page);
  margin: 0 auto;
  padding: 72px 24px 8px;
  text-align: center;
}
.paper-title { margin: 0 0 28px; color: var(--ink); letter-spacing: -0.02em; line-height: 1.12; }
.paper-name { display: block; font-size: clamp(2.4rem, 6vw, 3.6rem); font-weight: 700; }
.paper-subtitle { display: block; margin-top: 6px; font-size: clamp(1.35rem, 3.2vw, 2.1rem); font-weight: 300; }
.authors { font-size: 1.1rem; line-height: 1.8; margin: 0 auto 6px; max-width: 820px; }
.authors a { font-weight: 500; white-space: nowrap; }
.authors sup, .affiliations sup, .notes sup { font-size: 0.68em; }
.affiliations { color: var(--muted); font-size: 0.95rem; margin: 0 0 4px; }
.affiliations span { white-space: nowrap; margin: 0 8px; }
.notes { color: var(--muted); font-size: 0.85rem; margin: 0; }

/* buttons: near-black with light grey text and icons; .button-light is the reverse */
.buttons { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin: 28px 0 0; }
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 124px;
  height: 40px;
  padding: 0 20px;
  border-radius: 999px;
  background: var(--btn);
  color: var(--btn-text);
  font-size: 0.95rem;
  font-weight: 500;
  line-height: 1.2;
  border: 1px solid var(--btn);
  transition: background 0.15s ease, transform 0.15s ease;
}
.button:hover { background: var(--btn-hover); color: #fff; transform: translateY(-1px); }
.button .ai, .button svg { font-size: 1.05em; }
.button-light { background: var(--btn-light); color: var(--btn); border-color: var(--btn-light); }
.button-light:hover { background: var(--btn-light-hover); color: var(--btn); }
.hf-icon {
  width: 1.15em;
  height: 1.15em;
  background: currentColor;
  -webkit-mask: url(../../logos/huggingface.svg) center / contain no-repeat;
  mask: url(../../logos/huggingface.svg) center / contain no-repeat;
}

/* layout */
main { max-width: var(--page); margin: 0 auto; padding: 0 24px; }
section { margin-top: 72px; scroll-margin-top: 16px; }
h2 { margin: 0 0 16px; color: var(--ink); font-size: 1.6rem; font-weight: 600; letter-spacing: -0.01em; line-height: 1.25; text-wrap: balance; }
h3 { margin: 0; color: var(--ink); font-size: 1.05rem; font-weight: 500; }
figure { margin: 0; }
figcaption, .label-row { color: var(--muted); font-size: 0.88rem; text-align: center; margin-top: 8px; }

.tldr {
  margin: 40px 0 0;
  padding: 14px 20px;
  border-radius: var(--radius);
  background: var(--wash);
  color: var(--ink);
}
.tldr b { margin-right: 4px; }
.abstract { text-align: justify; hyphens: auto; font-size: 0.92em; line-height: 1.6; color: var(--text); }

/* text beside a video; .reverse puts the video first */
.row { display: grid; grid-template-columns: 7fr 5fr; gap: 40px; align-items: center; margin: 24px 0; }
.row.reverse { grid-template-columns: 5fr 7fr; }
.row.reverse > figure { order: -1; }
.row p:last-child { margin-bottom: 0; }
.media video { width: 100%; border-radius: 10px; margin: 0 auto; }
.media.narrow video { max-width: 260px; }
.media.wide { margin: 8px 0 16px; }
.cams { display: inline-flex; align-items: center; gap: 2px; margin-left: 4px; }
.cams img, .label-row img { display: inline; height: 1em; vertical-align: -0.12em; }
.label-row { display: grid; grid-template-columns: repeat(4, 1fr); }
.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 8px; }

/* method labels under the comparison videos (the videos themselves carry no text) */
.vlabels { display: grid; margin-top: 10px; text-align: center; font-size: 0.88rem; line-height: 1.3; }
.vlabels.cols-2 { grid-template-columns: repeat(2, 1fr); }
.vlabels.cols-3 { grid-template-columns: repeat(3, 1fr); }
.vlabels.cols-5 { grid-template-columns: repeat(5, 1fr); }
.vlabels .m { display: block; color: var(--ink); font-weight: 500; }
.vlabels .m.ours { color: var(--purple); font-weight: 600; }
.vlabels .tt { display: inline-flex; align-items: center; gap: 4px; margin-top: 4px; color: var(--muted); }
.vlabels img, .vlegend img { display: inline; height: 1.05em; opacity: 0.75; }
.vlegend { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 16px; margin: 10px 0 0; color: var(--muted); font-size: 0.82rem; }
.vlegend span { display: inline-flex; align-items: center; gap: 5px; }

/* masking pipeline: an animated figure of the four steps on one real frame (Flat 2, frame 415).
   Without JS or with reduced motion it shows every step's end state. The timeline in index.html sets data-phase. */
.steps { margin: 0 0 20px; padding-left: 1.2rem; }
.steps li { margin: 4px 0; }
.pipeline { display: flex; align-items: stretch; gap: 8px; margin-top: 8px; }
.pipeline-step {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 12px 16px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: #fff;
  transition: border-color 0.4s ease, box-shadow 0.4s ease;
}
.pipeline-media { position: relative; flex: 1; display: grid; place-items: center; min-height: 170px; }
.pipeline-arrow { align-self: center; color: #b3b3bd; font-size: 1.3rem; }

/* fisheye stacks: a base image with overlays on top */
.fish { position: relative; width: min(100%, 180px); height: auto; aspect-ratio: 1 / 1; margin: 0 auto; }
.fish > img, .fish > video { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
.fish::after { content: ""; position: absolute; inset: 0; border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12); pointer-events: none; }
.dot {
  position: absolute; left: 50%; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px;
  border-radius: 50%; background: #f59e0b; box-shadow: 0 0 0 2px #fff, 0 0 0 6px rgba(245, 158, 11, 0.25);
}
.pipeline-cams { display: flex; align-items: center; justify-content: center; gap: 6px; }
.cam-pair { display: flex; flex-direction: column; gap: 8px; width: 100%; max-width: 104px; }
.cam-pair .fish { width: 100%; }
.cam-labels { align-self: stretch; display: flex; flex-direction: column; justify-content: space-around; }
.cam-labels small { writing-mode: vertical-rl; transform: rotate(180deg); color: var(--muted); font-size: 0.75rem; }

/* the cube map: six faces, folded into a cube or laid out flat as a cross */
.cube-stage { --s: 44px; perspective: 600px; }
.cube { position: relative; width: var(--s); height: var(--s); transform-style: preserve-3d;
  transform: translateX(calc(var(--s) * -0.5)) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1); }
.face { position: absolute; inset: 0; backface-visibility: hidden; }
.face img { position: absolute; inset: 0; width: 100%; height: 100%; }
.face-front  { transform: translate3d(0, 0, 0) rotateX(0deg) rotateY(0deg) translateZ(0); }
.face-right  { transform: translate3d(var(--s), 0, 0) rotateX(0deg) rotateY(0deg) translateZ(0); }
.face-back   { transform: translate3d(calc(var(--s) * 2), 0, 0) rotateX(0deg) rotateY(0deg) translateZ(0); }
.face-left   { transform: translate3d(calc(var(--s) * -1), 0, 0) rotateX(0deg) rotateY(0deg) translateZ(0); }
.face-top    { transform: translate3d(0, calc(var(--s) * -1), 0) rotateX(0deg) rotateY(0deg) translateZ(0); }
.face-bottom { transform: translate3d(0, var(--s), 0) rotateX(0deg) rotateY(0deg) translateZ(0); }

/* end states are the default; .animating gates each one behind its phase */
.animating .pipeline-step { opacity: 0.35; transition: opacity 0.5s ease, border-color 0.4s ease, box-shadow 0.4s ease; }
.animating[data-phase="fold"] [data-step="1"], .animating[data-phase="flat"] [data-step="1"], .animating[data-phase="coarse"] [data-step="1"],
.animating[data-phase="recenter"] [data-step="2"], .animating[data-phase="center"] [data-step="2"],
.animating[data-phase="mask"] [data-step="3"], .animating[data-phase="propagate"] [data-step="4"] {
  border-color: #c9c9d1; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
.animating[data-phase="fold"] [data-step="1"], .animating[data-phase="flat"] [data-step="1"], .animating[data-phase="coarse"] [data-step="1"],
.animating[data-phase="recenter"] :is([data-step="1"], [data-step="2"]),
.animating[data-phase="center"] :is([data-step="1"], [data-step="2"]),
.animating[data-phase="mask"] :is([data-step="1"], [data-step="2"], [data-step="3"]),
.animating[data-phase="propagate"] .pipeline-step { opacity: 1; }

/* each loop restarts instantly, without animating back */
.animating[data-phase="start"] * { transition: none !important; }

/* 1. coarse: the cube turns, unfolds into the cross, then SAM 3's rough mask appears */
.animating .cube { transition: transform 1.1s cubic-bezier(.5, 0, .2, 1); }
.animating .face { transition: transform 1.1s cubic-bezier(.5, 0, .2, 1); }
.animating:is([data-phase="start"], [data-phase="fold"]) .cube { transform: translateX(0px) rotateX(-24deg) rotateY(-32deg) scale3d(1.9, 1.9, 1.9); }
.animating[data-phase="start"] .cube { transform: translateX(0px) rotateX(-24deg) rotateY(-150deg) scale3d(1.9, 1.9, 1.9); transition: none; }
.animating[data-phase="fold"] .cube { transition: transform 1.6s ease-out; }
.animating:is([data-phase="start"], [data-phase="fold"]) .face { transition: none; }
.animating:is([data-phase="start"], [data-phase="fold"]) .face-front  { transform: translate3d(0, 0, 0) rotateX(0deg) rotateY(0deg) translateZ(calc(var(--s) / 2)); }
.animating:is([data-phase="start"], [data-phase="fold"]) .face-right  { transform: translate3d(0, 0, 0) rotateX(0deg) rotateY(90deg) translateZ(calc(var(--s) / 2)); }
.animating:is([data-phase="start"], [data-phase="fold"]) .face-back   { transform: translate3d(0, 0, 0) rotateX(0deg) rotateY(180deg) translateZ(calc(var(--s) / 2)); }
.animating:is([data-phase="start"], [data-phase="fold"]) .face-left   { transform: translate3d(0, 0, 0) rotateX(0deg) rotateY(-90deg) translateZ(calc(var(--s) / 2)); }
.animating:is([data-phase="start"], [data-phase="fold"]) .face-top    { transform: translate3d(0, 0, 0) rotateX(90deg) rotateY(0deg) translateZ(calc(var(--s) / 2)); }
.animating:is([data-phase="start"], [data-phase="fold"]) .face-bottom { transform: translate3d(0, 0, 0) rotateX(-90deg) rotateY(0deg) translateZ(calc(var(--s) / 2)); }
.animating .coarse { opacity: 0; transition: opacity 0.6s ease; }
.animating:not(:is([data-phase="start"], [data-phase="fold"], [data-phase="flat"])) .coarse { opacity: 1; }

/* 2. re-center: the view turns onto the operator, then the centre point appears */
.recenter-end { opacity: 1; }
.animating .recenter-end { opacity: 0; }
.animating:is([data-phase="center"], [data-phase="mask"], [data-phase="propagate"]) .recenter-end { opacity: 1; }
.animating .dot { transform: scale(0); transition: transform 0.35s cubic-bezier(.3, 1.6, .5, 1); }
.animating:is([data-phase="center"], [data-phase="mask"], [data-phase="propagate"]) [data-step="2"] .dot,
.animating:is([data-phase="mask"], [data-phase="propagate"]) [data-step="3"] .dot { transform: scale(1); }

/* 3. mask: SAMv2's mask grows out from the centre point */
.grow { clip-path: circle(75% at 50% 50%); }
.animating .grow { clip-path: circle(0% at 50% 50%); transition: clip-path 1.2s ease-out; }
.animating:is([data-phase="mask"], [data-phase="propagate"]) .grow { clip-path: circle(75% at 50% 50%); }

/* 4. propagate: the mask lands on both original fisheyes */
.animating .final { opacity: 0; transform: scale(0.85); transition: opacity 0.6s ease, transform 0.6s ease; }
.animating[data-phase="propagate"] .final { opacity: 1; transform: none; }
.animating[data-phase="propagate"] .cam-pair .fish:nth-child(2) .final { transition-delay: 0.25s; }

/* scene grid: one orb per scene, each opens the viewer */
.scene-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 18px 12px; margin-top: 20px; }
.scene-orb { display: flex; flex-direction: column; align-items: center; color: var(--text); }
.scene-orb img {
  width: 100%;
  max-width: 100px;
  aspect-ratio: 1;
  border-radius: 50%;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.16);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.scene-orb:hover img { transform: translateY(-3px) scale(1.04); box-shadow: 0 10px 24px rgba(0, 0, 0, 0.2), 0 0 0 2px var(--purple); }
.scene-orb span { margin-top: 8px; font-size: 0.88rem; font-weight: 500; }
.scene-orb:hover span { color: var(--purple); }

/* related work: SwitchSplat in its own green */
.related-card {
  display: flex;
  gap: 20px;
  align-items: center;
  padding: 18px 22px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--switchsplat);
  border-radius: var(--radius);
}
.related-card > a { flex: none; }
.related-orb { width: 76px; height: 76px; border-radius: 50%; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.16); }
.related-card p { margin: 2px 0; font-size: 0.95rem; }
.related-title { color: var(--switchsplat); font-weight: 600; }
.related-title:hover { color: #185a3c; }
main p a.related-link { color: var(--switchsplat); font-weight: 500; }
main p a.related-link:hover { color: #185a3c; }
.related-meta { color: var(--muted); }
.related-card details { margin-top: 6px; font-size: 0.9rem; }
.related-card summary { cursor: pointer; color: var(--switchsplat); font-weight: 500; }

/* bibtex */
pre {
  margin: 8px 0 0;
  padding: 16px 18px;
  overflow-x: auto;
  background: var(--code-bg);
  border: 1px solid var(--line);
  border-radius: 10px;
  font: 0.8rem/1.55 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: var(--ink);
}
.bibtex { position: relative; }
.copy-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  padding: 4px 12px;
  border: 0;
  border-radius: 999px;
  background: var(--btn);
  color: var(--btn-text);
  font: 500 0.8rem Inter, system-ui, sans-serif;
  cursor: pointer;
}
.copy-btn:hover { background: var(--btn-hover); color: #fff; }

footer { margin: 80px auto 0; padding: 24px; border-top: 1px solid var(--line); color: var(--muted); font-size: 0.82rem; text-align: center; }

/* results page */
.page-head { max-width: var(--page); margin: 0 auto; padding: 40px 24px 0; }
.page-head .back { display: inline-flex; align-items: center; gap: 8px; font-weight: 500; font-size: 0.95rem; }
.page-head h1 { margin: 20px 0 6px; color: var(--ink); font-size: clamp(2rem, 5vw, 2.8rem); font-weight: 700; letter-spacing: -0.02em; }
.page-head .lead { color: var(--muted); margin: 0; }
.compare section { margin-top: 56px; }
.compare h2 small { margin-left: 8px; color: var(--muted); font-size: 0.95rem; font-weight: 400; }
.compare .set-title { font-size: 1.25rem; font-weight: 400; }
.compare .set-title b { font-weight: 600; }
.picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; margin: 16px 0 18px; }
.chip {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;  /* the scene orb sits at the same spot on every button */
  gap: 10px;
  min-width: 150px;
  height: 40px;
  padding: 0 20px 0 6px;
  border: 1px solid var(--btn);
  border-radius: 999px;
  background: var(--btn);
  color: var(--btn-text);
  font: 500 0.95rem Inter, system-ui, sans-serif;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.15s ease;
}
.chip img { width: 28px; height: 28px; border-radius: 50%; }
.chip.text-only { justify-content: center; padding: 0 20px; }
.chip:hover { background: var(--btn-hover); color: #fff; transform: translateY(-1px); }
.chip:hover img { box-shadow: 0 0 0 2px var(--purple); }
.chip[aria-pressed="true"] { background: var(--btn-light); border-color: var(--btn-light); color: var(--btn); }
.chip[aria-pressed="true"] img { box-shadow: 0 0 0 2px var(--purple); }
.stage video { width: 100%; border-radius: 10px; background: var(--code-bg); }
.stage .stage-meta { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-top: 10px; color: var(--muted); font-size: 0.9rem; }

@media (max-width: 768px) {
  body { font-size: 16px; }
  .hero { padding-top: 48px; }
  .authors { font-size: 1rem; }
  .authors a { white-space: normal; }
  main { padding: 0 16px; }
  section { margin-top: 56px; }
  h2 { font-size: 1.35rem; }
  .row, .row.reverse { grid-template-columns: 1fr; gap: 16px; }
  .row.reverse > figure { order: 0; }
  .pair { grid-template-columns: 1fr; }
  .pipeline { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
  .cube-stage { --s: 32px; }
  .pipeline-media { min-height: 140px; }
  .pipeline-arrow { display: none; }
  .scene-grid { grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); }
  .related-card { flex-direction: column; align-items: flex-start; }
  .label-row { font-size: 0.75rem; }
  .vlabels { font-size: 0.68rem; }
  .vlabels img { height: 0.95em; }
  .page-head { padding: 28px 16px 0; }
}
