:root {
  --bg: #0b1020;
  --bg-soft: #131a30;
  --surface: #182038;
  --border: #2a3554;
  --text: #e8edf7;
  --text-muted: #9aa6c4;
  --accent: #7500c0; /* emphasis FILL (with white text) */
  --accent-text: #b57cff; /* lighter purple for accent-colored TEXT on dark bg (readability) */
  --accent-2: #e02fd0;
  --ok: #10b981;
  --danger: #ef4444;
  --radius: 14px;
  --font: "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Meiryo", system-ui, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, monospace;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: var(--font);
  background:
    radial-gradient(1200px 800px at 80% -10%, #1d2748 0%, transparent 60%),
    radial-gradient(900px 700px at -10% 110%, #2a1840 0%, transparent 55%),
    var(--bg);
  color: var(--text);
  line-height: 1.7;
  min-height: 100vh;
}
a { color: var(--accent-text); }
/* the hidden attribute must win over display-setting classes (e.g. .row) */
[hidden] { display: none !important; }

.app {
  max-width: 720px;
  margin: 0 auto;
  /* top clearance for the fixed header nav (grows with the notch safe-area) */
  padding: calc(3.4rem + env(safe-area-inset-top, 0px)) 1rem 4rem;
}

/* header nav: 🏠 ホーム | 🌌 スクリーン (top-left, tap-friendly, safe-area aware) */
.appnav {
  position: fixed;
  top: calc(0.5rem + env(safe-area-inset-top, 0px));
  left: calc(0.5rem + env(safe-area-inset-left, 0px));
  z-index: 45; /* below modals/sheets(80), toast/status(50-60); above canvas/log */
  display: flex;
  gap: 0.2rem;
  padding: 0.2rem;
  background: rgba(8, 12, 28, 0.85);
  backdrop-filter: blur(6px);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
  transition: opacity 0.35s ease;
}
.appnav.faded {
  opacity: 0;
  pointer-events: none;
}
.appnav a {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  min-height: 40px;
  padding: 0.4rem 0.85rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
}
.appnav a.active {
  background: var(--accent);
  color: #fff;
  /* the current page's tab glows (gentle pulse) so the lit side is obvious */
  animation: navglow 2.2s ease-in-out infinite;
}
@keyframes navglow {
  0%,
  100% {
    box-shadow: 0 0 6px 1px color-mix(in srgb, var(--accent) 55%, transparent);
  }
  50% {
    box-shadow: 0 0 16px 3px color-mix(in srgb, var(--accent) 85%, transparent);
  }
}
@media (prefers-reduced-motion: reduce) {
  .appnav a.active {
    animation: none;
    box-shadow: 0 0 10px 1px color-mix(in srgb, var(--accent) 70%, transparent);
  }
}
.appnav a:not(.active):hover,
.appnav a:not(.active):active {
  background: rgba(255, 255, 255, 0.1);
  color: var(--text);
}
/* JA / EN switch, separated from the page links by a hairline so it doesn't read
   as a third destination. Both codes always visible — see nav.js. */
.appnav-lang {
  display: inline-flex;
  gap: 0.1rem;
  margin-left: 0.2rem;
  padding-left: 0.3rem;
  border-left: 1px solid var(--border);
}
.appnav-lang button {
  min-height: 40px;
  padding: 0 0.5rem;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}
.appnav-lang button[aria-pressed="true"] {
  background: rgba(255, 255, 255, 0.14);
  color: var(--text);
}

/* on narrow phones, drop the demo scenario switcher below the nav so they don't collide */
@media (max-width: 520px) {
  .scenario-switch {
    top: calc(3.4rem + env(safe-area-inset-top, 0px));
  }
}
.brand { text-align: center; margin: 1rem 0 1.5rem; }
.brand h1 {
  font-size: 1.45rem;
  font-weight: 800;
  background: linear-gradient(90deg, #fff, var(--accent) 60%, var(--accent-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.brand p { color: var(--text-muted); font-size: .85rem; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
  margin-bottom: 1rem;
  box-shadow: 0 8px 30px rgba(0,0,0,.25);
}
.card h2 { font-size: 1rem; margin-bottom: .85rem; }

/* collapsible card: the whole header is the toggle, sized as a thumb target */
.sec-head {
  position: relative; /* containing block for the hit-area extension below */
  display: flex; align-items: center; gap: .5rem; width: 100%;
  min-height: 48px; padding: 0; margin-bottom: .85rem;
  background: transparent; border: none; border-radius: 8px;
  color: var(--text); font-size: 1rem; font-weight: 700; text-align: left;
}
/* The header row sits inside the card's 1.25rem padding, so the ~20px strip
   above and beside it LOOKS like part of the header but wasn't tappable. Extend
   the hit area out to the card's edges with a pseudo-element: negative insets
   reach past the button's own box, so no layout (and no .card rule) changes. */
.sec-head::after {
  content: ""; position: absolute; inset: -1.25rem -1.25rem -.2rem;
  border-radius: var(--radius);
}
.card.collapsed .sec-head::after { inset: -.85rem -1.25rem; }
/* a full-width row shifting 1px (the global button:active) is nearly invisible on
   a phone, so flash the strip instead — this is the only tap confirmation */
.sec-head:active::after { background: rgba(255,255,255,.05); }
.sec-title { flex: 1; }
/* Sized and filled so it reads as a control rather than as decoration; at .85rem
   bare it looked like punctuation. The row is what you actually tap. */
.sec-caret {
  flex: none; display: grid; place-items: center;
  width: 28px; height: 28px; border-radius: 50%;
  background: rgba(255,255,255,.06);
  color: var(--text-muted); font-size: .8rem; line-height: 1;
  transition: transform .15s ease, background .15s ease;
}
.sec-head:active .sec-caret { background: rgba(255,255,255,.18); color: var(--text); }
.card.collapsed .sec-caret { transform: rotate(-90deg); }
.card.collapsed .sec-head { margin-bottom: 0; }
.card.collapsed .sec-body { display: none; }
/* a collapsed card is just its header — drop the body's share of the padding */
.card.collapsed { padding-top: .85rem; padding-bottom: .85rem; }
@media (prefers-reduced-motion: reduce) {
  .sec-caret { transition: none; }
}

label { display: block; font-size: .82rem; color: var(--text-muted); margin: .75rem 0 .3rem; }
input, select, textarea {
  width: 100%;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  padding: .6rem .75rem;
  font-size: .95rem;
  font-family: inherit;
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent-text); border-color: transparent; }
textarea { resize: vertical; min-height: 3rem; }
.hint { font-size: .72rem; color: var(--text-muted); margin-top: .2rem; }

button {
  font-family: inherit;
  font-weight: 700;
  border: none;
  border-radius: 10px;
  padding: .65rem 1rem;
  cursor: pointer;
  font-size: .92rem;
  transition: transform .05s ease, opacity .15s ease;
}
button:active { transform: translateY(1px); }
button:disabled { opacity: .45; cursor: not-allowed; }
.btn-primary { background: linear-gradient(90deg, var(--accent), var(--accent-2)); color: #fff; width: 100%; }
.btn-ghost { background: var(--bg-soft); color: var(--text); border: 1px solid var(--border); }
.btn-danger { background: var(--danger); color: #fff; }
.row { display: flex; gap: .5rem; flex-wrap: wrap; }
.row > * { flex: 1; }

.pill { display: inline-flex; align-items: center; gap: .35rem; font-size: .72rem; padding: .15rem .55rem; border-radius: 999px; background: var(--bg-soft); border: 1px solid var(--border); }
.dot { width: .6rem; height: .6rem; border-radius: 50%; display: inline-block; }

.status { position: fixed; top: .6rem; right: .6rem; font-size: .72rem; padding: .25rem .6rem; border-radius: 999px; z-index: 50; }
.status.on { background: rgba(16,185,129,.15); color: var(--ok); border: 1px solid rgba(16,185,129,.4); }
.status.off { background: rgba(239,68,68,.15); color: var(--danger); border: 1px solid rgba(239,68,68,.4); }

.list { list-style: none; }
.list li {
  display: flex; align-items: center; gap: .6rem;
  padding: .55rem .25rem; border-bottom: 1px solid var(--border); font-size: .9rem;
}
.list li:last-child { border-bottom: none; }
.list .name { font-weight: 700; }
/* the emoji sits inside .name, not beside it: .list li's own gap is sized for
   separate columns and would push the glyph too far off its name */
.list .name .em { margin-right: .3em; font-weight: 400; }
.list .meta { color: var(--text-muted); font-size: .78rem; }
.spacer { flex: 1; }

.tag { font-size: .68rem; color: var(--text-muted); background: var(--bg-soft); border-radius: 6px; padding: .05rem .4rem; }
/* unread marker: Links somebody else drew to you since you last looked. Filled
   accent (not muted like .tag) because it's the one thing on the header that is
   asking to be noticed. */
.badge { font-size: .68rem; font-weight: 700; color: #fff; background: var(--accent-2); border-radius: 999px; padding: .05rem .4rem; margin-left: .3rem; }
.empty { color: var(--text-muted); font-size: .85rem; text-align: center; padding: 1rem; }

/* ---- first-run intro (3 slides) ----
   The track slides horizontally inside a clipped view; each slide is exactly the
   view's width so the transform lands on whole slides and nothing half-shows. */
.intro { position: relative; text-align: center; }
.intro-skip {
  position: absolute; top: .5rem; right: .5rem; z-index: 1;
  background: transparent; border: none; color: var(--text-muted); font-size: .78rem; font-weight: 700; padding: .4rem .6rem;
}
.intro-skip:active { color: var(--text); }
.intro-view { overflow: hidden; }
.intro-track { display: flex; transition: transform .25s ease; }
.intro-slide { flex: 0 0 100%; padding: 1.2rem .5rem .4rem; }
.intro-art { font-size: 3.4rem; line-height: 1.2; margin-bottom: .6rem; }
.intro-slide h2 { font-size: 1.05rem; margin-bottom: .5rem; }
.intro-slide p { font-size: .88rem; color: var(--text-muted); }
.intro-dots { display: flex; gap: .4rem; justify-content: center; margin-top: .6rem; }
.intro-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--border); }
.intro-dot.on { background: var(--accent); }
/* the ? that reopens it, sized like the nav links beside it */
.appnav-help {
  min-height: 40px; min-width: 40px; padding: 0 .6rem; border-radius: 999px;
  background: transparent; border: none; color: var(--text-muted); font-size: .9rem; font-weight: 700;
}
.appnav-help:hover, .appnav-help:active { background: rgba(255, 255, 255, 0.1); color: var(--text); }
@media (prefers-reduced-motion: reduce) {
  .intro-track { transition: none; }
}

/* Divider heading inside a card, for a section that holds two distinct tools
   (search + recommendations). Lighter than the card's own header so the
   hierarchy stays readable: one card, two parts. */
.subhead {
  margin-top: 1.1rem; padding-top: .8rem; border-top: 1px solid var(--border);
  font-size: .9rem; font-weight: 700;
}

/* ---- segmented view switch (名前順 / 趣味別) ----
   Both halves are always visible so the alternative view is discoverable — a
   single button that toggles a label would hide the fact that there are two.
   aria-pressed carries the state; the fill is just its visual form. */
.viewtoggle { display: flex; gap: .25rem; padding: .2rem; margin-bottom: .6rem; background: var(--bg-soft); border: 1px solid var(--border); border-radius: 999px; }
.viewtoggle button {
  flex: 1; min-height: 36px; padding: .3rem .6rem; border-radius: 999px;
  background: transparent; border: none; color: var(--text-muted); font-size: .8rem; font-weight: 700;
}
.viewtoggle button[aria-pressed="true"] { background: var(--accent); color: #fff; }

/* ---- 趣味でつながった人 ----
   One row per tag: the tag, how many others hold it, and the Links it produced.
   The names are buttons because they open that person's card, same as the Link
   list — a name that looks like text but reacts to a tap is worse than one that
   looks tappable. They wrap: a popular tag can carry several. */
.peers { display: flex; flex-wrap: wrap; gap: .3rem; justify-content: flex-end; }
.peer {
  font-size: .74rem; font-weight: 700; padding: .1rem .5rem; border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  border: 1px solid var(--accent); color: var(--accent-text); cursor: pointer;
}
.peer:active { background: var(--accent); color: #fff; }
.peer .em { margin-right: .18em; }
/* the tag list sits inside a card, so its category heading needs air above it */
#interestPeersList .tagcat-head { margin-top: .9rem; }
#interestPeersList .tagcat-head:first-child { margin-top: 0; }
/* ---- growth: level + progress + the ladder that explains it ----
   Showing only the level number made growth feel arbitrary, because nothing on
   screen said what it took to move. The bar answers "how close am I", the rungs
   answer "close to what". Used for the personal level and for the room-wide
   Link goal, which is why the block is generic. */
.growth { margin-top: .8rem; }
.growth-head { display: flex; align-items: center; gap: .4rem; margin-bottom: .35rem; }
.meter { height: 8px; border-radius: 999px; background: var(--bg-soft); border: 1px solid var(--border); overflow: hidden; }
.meter > span { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--accent), var(--accent-2)); transition: width .4s ease; }
.rungs { display: flex; gap: .3rem; margin-top: .4rem; }
/* every rung is always visible — the whole point is seeing the levels you have
   not reached yet, so nothing here is hidden or truncated */
.rung { flex: 1; text-align: center; font-size: .62rem; line-height: 1.35; color: var(--text-muted); background: var(--bg-soft); border: 1px solid var(--border); border-radius: 6px; padding: .1rem 0; }
.rung b { display: block; font-family: var(--mono); font-size: .72rem; font-weight: 700; }
.rung.done { color: var(--accent-text); border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
.rung.here { background: var(--accent); border-color: var(--accent); color: #fff; }
@media (prefers-reduced-motion: reduce) {
  .meter > span { transition: none; }
}
.toast { position: fixed; bottom: 1rem; left: 50%; transform: translateX(-50%); background: var(--surface); border: 1px solid var(--border); padding: .6rem 1rem; border-radius: 10px; font-size: .85rem; z-index: 60; box-shadow: 0 8px 30px rgba(0,0,0,.4); }

.counter { display: flex; gap: 1.5rem; justify-content: center; }
.counter .n { font-size: 1.6rem; font-weight: 900; font-family: var(--mono); }
.counter .l { font-size: .72rem; color: var(--text-muted); }

.qr-box { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--border); text-align: center; }
.qr-box .hint { margin-bottom: .6rem; }
.qr-img { display: inline-flex; padding: 10px; background: #fff; border-radius: 12px; line-height: 0; }
.qr-img img { display: block; width: 200px; height: 200px; image-rendering: pixelated; }

/* connect: search results */
.results { list-style: none; margin: .4rem 0 0; padding: 0; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; max-height: 16rem; overflow-y: auto; }
.results li { display: flex; align-items: center; gap: .6rem; padding: .55rem .7rem; border-bottom: 1px solid var(--border); font-size: .9rem; cursor: pointer; }
.results li:last-child { border-bottom: none; }
.results li:hover { background: var(--bg-soft); }
.results li.empty { cursor: default; color: var(--text-muted); justify-content: center; }
.results .name { font-weight: 700; }
.results .meta { color: var(--text-muted); font-size: .78rem; }

/* connect: partner card shown as a modal */
.modal { position: fixed; inset: 0; z-index: 80; display: flex; align-items: center; justify-content: center; padding: 1rem; }
.modal[hidden] { display: none; }
.modal-backdrop { position: absolute; inset: 0; background: rgba(4,7,18,.72); backdrop-filter: blur(2px); }
.modal-card { position: relative; z-index: 1; width: 100%; max-width: 26rem; max-height: 90vh; overflow-y: auto; margin: 0; animation: modal-pop .16s ease-out; }
@keyframes modal-pop { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
.commons { margin-top: .6rem; display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.chip { font-size: .72rem; font-weight: 700; color: #fff; background: var(--accent); border-radius: 999px; padding: .1rem .55rem; }

/* selectable interest-category chips (registration form) */
.chips { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .35rem; }
.chip-toggle { font-size: .82rem; padding: .3rem .7rem; border-radius: 999px; background: var(--bg-soft); border: 1px solid var(--border); color: var(--text); cursor: pointer; transition: background .12s, border-color .12s; }
.chip-toggle[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 700; }
/* per-category tag input (registration): chips + autocomplete dropdown */
.tag-area { display: flex; flex-direction: column; gap: .6rem; margin-top: .5rem; }
.tagcat { border: 1px solid var(--border); border-radius: 10px; padding: .5rem .6rem; background: var(--bg-soft); }
.tagcat-head { font-size: .82rem; font-weight: 700; margin-bottom: .35rem; }
.tagcat-chips { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .35rem; }
.tagchip { display: inline-flex; align-items: center; gap: .25rem; font-size: .78rem; padding: .12rem .5rem; border-radius: 999px; background: var(--accent); color: #fff; font-weight: 700; }
.tagchip-x { border: none; background: transparent; color: #fff; cursor: pointer; font-size: .95rem; line-height: 1; padding: 0; }
.tag-input-wrap { position: relative; }
.tag-input { width: 100%; box-sizing: border-box; }
.tag-suggest { list-style: none; margin: .25rem 0 0; padding: 0; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: var(--bg); }
.tag-suggest li { display: flex; align-items: center; gap: .5rem; padding: .45rem .6rem; font-size: .85rem; cursor: pointer; border-bottom: 1px solid var(--border); }
.tag-suggest li:last-child { border-bottom: none; }
.tag-suggest li:hover { background: var(--bg-soft); }
.tag-suggest li.new { color: var(--accent-text); font-weight: 700; }
.tag-suggest .meta { color: var(--text-muted); font-size: .78rem; }

/* recommendation list: strength badge (strong = shared exact tag, weak = shared category) */
.results .shared { font-size: .74rem; font-weight: 700; white-space: nowrap; }
.results .shared.strong { color: #f59e0b; }
/* near = 意味が近いだけの一致。strong(橙) と weak(灰) の中間に置く */
.results .shared.near { color: #22d3ee; }
.results .shared.weak { color: var(--text-muted); }
.chip.strong { background: #f59e0b; color: #241a00; }
.list li.tappable { cursor: pointer; border-radius: 8px; }
.list li.tappable:hover { background: var(--bg-soft); }

/* mock-only demo scenario switcher (top center) */
.scenario-switch { position: fixed; top: .5rem; left: 50%; transform: translateX(-50%); z-index: 60;
  display: flex; align-items: center; gap: .4rem; font-size: .75rem; color: var(--text-muted);
  background: rgba(8,12,28,.9); backdrop-filter: blur(6px); border: 1px solid var(--border);
  border-radius: 999px; padding: .25rem .6rem; box-shadow: 0 6px 20px rgba(0,0,0,.4); }
.scenario-switch select { background: transparent; color: var(--text); border: none; font-size: .8rem; font-weight: 700; cursor: pointer; outline: none; }
.scenario-switch select option { background: #0b1020; color: var(--text); }
/* ---- reveal modal ----
   Two groups, visually ranked: what you actually share reads as a finding, what
   is merely close reads as a footnote. Same distinction the wording makes. */
.reveal-group { margin-top: .9rem; padding: .7rem .8rem; border-radius: 10px; border: 1px solid var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.reveal-group.near { border-color: var(--border); background: var(--bg-soft); }
.reveal-head { font-size: .85rem; font-weight: 700; margin-bottom: .45rem; }
.reveal-row { display: flex; align-items: center; flex-wrap: wrap; gap: .35rem; padding: .2rem 0; font-size: .85rem; }
.reveal-group .hint { margin-top: .4rem; }

/* Similar-but-not-shared hobbies. Deliberately quieter than the shared reveal:
   these are a model's guess at closeness, not a fact about both people, and the
   visual weight should say so. */
.reveal.near { border-color: var(--border); background: var(--bg-soft); }
.chip.near { background: var(--bg-soft); border: 1px solid var(--border); color: var(--text-muted); font-weight: 400; }
.reveal { margin-top: .6rem; padding: .5rem .7rem; border-radius: 10px; background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid var(--accent); display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.reveal .teaser { color: var(--text-muted); font-size: .82rem; }

/* activity log panel (screen only): tabs + timestamped scrollable list */
/* top must clear the counters in the top-right HUD, which end around 5.2rem. Note
   the log is opaque and at a higher z-index than the HUD, so anything placed up
   there that it overlaps is hidden outright rather than pushed aside. */
.log { position: fixed; top: 5.5rem; right: 1.75rem; z-index: 30; width: 22rem; max-width: 38vw; display: flex; flex-direction: column; background: rgba(8,12,28,.9); backdrop-filter: blur(6px); box-shadow: 0 8px 30px rgba(0,0,0,.45); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
.log-header { display: flex; align-items: center; justify-content: space-between; padding: .35rem .4rem .35rem .7rem; }
.log-title { font-size: .72rem; font-weight: 700; letter-spacing: .06em; color: var(--text-muted); }
.log-toggle { width: 1.8rem; height: 1.8rem; padding: 0; background: transparent; color: var(--text-muted); border: 1px solid var(--border); border-radius: 8px; font-size: .8rem; cursor: pointer; }
.log-toggle:hover { color: var(--text); }
.log.minimized .log-body { display: none; }
.log-list { max-height: 50vh; overflow-y: auto; padding: .3rem .5rem; border-top: 1px solid var(--border); }
.log-item { display: flex; gap: .5rem; align-items: baseline; padding: .25rem .35rem; font-size: .85rem; border-bottom: 1px solid rgba(255,255,255,.05); }
.log-item:last-child { border-bottom: none; }
.log-time { flex: none; font-family: var(--mono); font-size: .72rem; color: var(--text-muted); }
.log-text { color: var(--text); }
.log-empty { color: var(--text-muted); font-size: .8rem; text-align: center; padding: .8rem; }
/* ---- names inside the activity log ----
   A row is a sentence with two people in it, and on the wall it is read from the
   back of the room. Boxing each name and leading it with that person's own star
   emoji makes the two subjects findable without parsing the sentence. Neutral
   fill, not the accent: two purple chips per row across 80 rows would read as a
   warning rather than a log. */
.starchip {
  display: inline-flex; align-items: baseline; gap: .22em;
  padding: .05em .45em; border-radius: 999px;
  background: var(--bg-soft); border: 1px solid var(--border);
  font-weight: 700; white-space: nowrap;
}
.starchip .em { font-size: .95em; }
/* The wall log is 22rem wide and its sentence already wrapped before the chips.
   Tighter there so the chips cost as little of that width as possible. */
.log .starchip { font-size: .92em; padding-inline: .3em; }
/* Rows I am part of, marked in the unfiltered view too — that is what makes the
   自分 toggle a shortcut instead of the only way to find them. */
/* Only the background differs. The horizontal padding lives on every row: putting
   it here alone shifted the timestamp of my own rows, and a column that moves
   row to row is harder to read than no highlight at all. */
.log-item.mine { background: color-mix(in srgb, var(--accent) 12%, transparent); border-radius: 6px; }
.starchip.me { border-color: var(--accent); color: var(--accent-text); }

/* connection celebration burst */
.confetti-layer { position: fixed; inset: 0; z-index: 90; pointer-events: none; overflow: hidden; }
.confetti { position: absolute; top: 50%; left: 50%; font-size: 1.8rem; will-change: transform, opacity; animation: confetti-burst 1.1s cubic-bezier(.15,.7,.3,1) forwards; }
@keyframes confetti-burst {
  0% { transform: translate(-50%, -50%) scale(.3); opacity: 0; }
  12% { opacity: 1; }
  100% { transform: translate(calc(-50% + var(--tx)), calc(-50% + var(--ty))) rotate(var(--rot)) scale(1.1); opacity: 0; }
}

/* tap-a-star popover: pops up just above the tapped star (positioned in JS) */
.sheet { position: fixed; inset: 0; z-index: 80; }
.sheet[hidden] { display: none; }
.sheet-backdrop { position: absolute; inset: 0; background: transparent; }
.sheet-panel { position: absolute; z-index: 1; width: 14rem; max-width: 88vw; padding: .8rem; border-radius: 12px; box-shadow: 0 10px 32px rgba(0,0,0,.5); transform-origin: bottom center; animation: pop-up .16s cubic-bezier(.2,.9,.3,1.25); }
.sheet-panel.below { transform-origin: top center; }
.sheet-panel.wide { width: 19rem; } /* detail / emoji picker need more room than the icon menu */
@keyframes pop-up { from { opacity: 0; transform: scale(.85) translateY(6px); } to { opacity: 1; transform: none; } }
.sheet-name { font-size: .95rem; font-weight: 800; text-align: center; margin-bottom: .15rem; }
.sheet-sub { font-size: .75rem; color: var(--text-muted); text-align: center; margin-bottom: .6rem; }
.sheet-view .row { gap: .6rem; }
.sheet-view .row .btn-ghost, .sheet-view .row .btn-primary { flex: 1; }
emoji-picker {
  width: 100%;
  height: 280px;
  margin-top: .5rem;
  --background: var(--surface);
  --border-color: var(--border);
  --input-border-color: var(--border);
  --input-font-color: var(--text);
  --input-placeholder-color: var(--text-muted);
  --category-font-color: var(--text-muted);
  --num-columns: 7;
  --emoji-size: 1.3rem;
}

/* ---- 近似スコアのゲージ（admin）----
   生のコサイン値は 0.6〜0.95 の狭い帯に固まるため、0〜1 で描くと全部が右端に
   張り付いて差が読めない。有効帯の下限（サーバの gaugeFloor）を 0% として
   引き伸ばし、閾値の位置に縦線を出す。「どこで切るか」を目で決めるための道具。 */
/* overflow は敢えて切らない。閾値マーカーはバーの上下にはみ出して初めて
   「線」として読めるので、clip すると目的を失う。塗りは自前の border-radius
   で丸めるため、clip は不要。 */
.gauge {
  position: relative;
  height: .5rem;
  border-radius: 999px;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  flex: 1 1 6rem;
  min-width: 4rem;
}
.gauge-fill {
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}
.gauge.below .gauge-fill { background: var(--border); }
/* 閾値マーカー。overflow:hidden の外に出すため親に重ねる */
.gauge-mark {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 2px;
  background: var(--ok);
  box-shadow: 0 0 4px 1px color-mix(in srgb, var(--ok) 70%, transparent);
}
.gauge-row { display: flex; align-items: center; gap: .5rem; width: 100%; }
.gauge-row .score { font-variant-numeric: tabular-nums; font-size: .72rem; color: var(--text-muted); min-width: 3rem; text-align: right; }
.gauge-row.below .name { color: var(--text-muted); }
