:root {
  --bg: #0d1024;
  --bg-deep: #05060f;
  --gold: #f0d060;
  --gold-soft: #d8c98a;
  --lavender: #6b64a8;
  --lavender-soft: #9a94b8;
  --ink: #e8e4d8;
  --ink-dim: #8b84b8;
  --pink: #e8608f;
  --violet: #4a3a8a;
  --panel: #14172e;
  --panel-border: #4a4580;
  --panel-glow: rgba(216,201,138,.18);
  --font-display: "Cormorant Garamond", Georgia, serif;
  --font-body: Georgia, "Iowan Old Style", "Times New Roman", serif;
  --font-ui: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--ink); font-family: var(--font-body); overflow: hidden; height: 100%; }
/* Sem isto o Safari do iPhone "infla" o texto por conta própria em layouts
   posicionados (o texto aparecia gigante e desformatado num iPhone real). */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
/* O arrasto da linha do tempo/campo nunca deve virar pull-to-refresh ou
   gesto de navegação do browser. */
html, body { overscroll-behavior: none; }
button, .char, .event-marker, .family-chip, .search-result, .progress-dot { -webkit-tap-highlight-color: transparent; }
.scroll-arrows button, .zoom-controls button, .back-btn, .panel-close, .family-chip, .progress-dot { touch-action: manipulation; }
.app { display: flex; flex-direction: column; height: 100vh; height: 100dvh; overflow: hidden; }

.topbar {
  position: relative; z-index: 20; padding: 12px 28px;
  border-bottom: 1px solid rgba(74,69,128,.5);
  background: linear-gradient(180deg, rgba(15,17,38,.92), rgba(13,16,36,.15));
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  transition: padding .35s ease;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 24px;
}
body.in-event .topbar { padding: 6px 28px; }
body.in-event .hint, body.in-event .eyebrow { display: none; }
.eyebrow { font-family: var(--font-ui); font-size: 10.5px; font-weight: 600; letter-spacing: .22em; text-transform: uppercase; color: var(--gold-soft); margin: 0 0 6px; opacity: .85; }
h1 { margin: 0; font-family: var(--font-display); font-size: 27px; font-weight: 600; color: #f5ecd8; text-wrap: balance; letter-spacing: .01em; transition: font-size .35s ease; }
body.in-event h1 { font-size: 16px; }
.topbar-title { min-width: 0; }
.hint { margin: 6px 0 0; font-family: var(--font-ui); font-size: 12px; color: var(--ink-dim); line-height: 1.55; max-width: 68ch; }

/* pesquisa no canto superior direito */
.search-wrap { position: relative; width: 340px; max-width: 90vw; margin: 2px 0 0; flex-shrink: 0; }
.search-box { width: 100%; padding: 10px 16px; border-radius: 999px; border: 2px solid var(--panel-border); background: var(--panel); color: var(--ink); font-family: var(--font-body); font-size: 14px; outline: none; }
.search-box:focus { border-color: var(--gold-soft); }
.search-box::placeholder { color: var(--ink-dim); }
.search-results { position: absolute; top: calc(100% + 6px); left: 0; right: 0; background: var(--panel); border: 1px solid var(--panel-border); border-radius: 12px; overflow: hidden; z-index: 15; box-shadow: 0 8px 24px rgba(0,0,0,.4); }
.search-result { padding: 9px 16px; cursor: pointer; font-family: var(--font-ui); font-size: 13px; color: var(--ink); display: flex; justify-content: space-between; align-items: baseline; }
.search-result:hover { background: #2a2650; }
.search-result .sr-era { font-size: 10px; color: var(--ink-dim); }

.stage { position: relative; flex: 1; min-height: 0; perspective: 1400px; overflow: hidden; }
#bgStars { position: absolute; inset: 0; z-index: 0; }
.nebula { position: absolute; z-index: 1; border-radius: 50%; filter: blur(60px); opacity: .55; pointer-events: none; mix-blend-mode: screen; transition: background 1.2s ease; }
.nebula.n1 { width: 46vw; height: 46vw; left: -12vw; top: -14vw; background: radial-gradient(circle, var(--violet), transparent 68%); animation: drift1 26s ease-in-out infinite; }
.nebula.n2 { width: 38vw; height: 38vw; right: -10vw; bottom: -12vw; background: radial-gradient(circle, #5a2a4a, transparent 68%); animation: drift2 32s ease-in-out infinite; }
.nebula.n3 { width: 30vw; height: 30vw; left: 38vw; top: 30vh; background: radial-gradient(circle, #3a3060, transparent 70%); animation: drift1 22s ease-in-out infinite reverse; }
@keyframes drift1 { 0%,100% { transform: translate(0,0); } 50% { transform: translate(3vw,2vh); } }
@keyframes drift2 { 0%,100% { transform: translate(0,0); } 50% { transform: translate(-3vw,-2vh); } }

#timelineView { position: absolute; inset: 0; z-index: 5; display: flex; align-items: center; transition: opacity .65s ease, transform .65s cubic-bezier(.3,.7,.4,1); transform-style: preserve-3d; cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }
#timelineView.dragging { cursor: grabbing; }
#timelineView.diving { opacity: 0; pointer-events: none; }
.timeline-track { position: relative; width: 100%; height: 1px; }
#timelineRail { position: absolute; top: 0; left: 0; will-change: transform; }
#railSvg { position: absolute; top: -140px; left: 0; overflow: visible; pointer-events: none; }
.event-marker { position: absolute; top: 0; transform: translate(-50%, -50%); display: flex; flex-direction: column; align-items: center; cursor: pointer; background: none; border: none; color: inherit; }
.event-avatars { display: flex; margin-bottom: 12px; height: 34px; }
.event-avatar { width: 32px; height: 32px; border-radius: 50%; margin-left: -10px; overflow: hidden; background: radial-gradient(circle at 35% 30%, #efe9ff, var(--lavender) 58%, #362f5e 100%); border: 2px solid var(--bg-deep); box-shadow: 0 2px 8px rgba(0,0,0,.5), 0 0 10px rgba(107,100,168,.45); transition: transform .25s cubic-bezier(.3,1.4,.5,1); }
.event-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.event-avatar:first-child { margin-left: 0; }
.event-marker:hover .event-avatar, .event-marker:focus-visible .event-avatar { transform: translateY(-3px); }
.event-dot-wrap { position: relative; width: 26px; height: 26px; }
.event-dot-ring { position: absolute; inset: -10px; border-radius: 50%; border: 1px solid var(--tint, var(--gold)); opacity: .35; animation: ringPulse 3.2s ease-out infinite; }
@keyframes ringPulse { 0% { transform: scale(.7); opacity: .5; } 100% { transform: scale(1.9); opacity: 0; } }
.event-marker:nth-of-type(2n) .event-dot-ring { animation-delay: -1.1s; }
.event-marker:nth-of-type(3n) .event-dot-ring { animation-delay: -2.3s; }
.event-marker:nth-of-type(5n) .event-dot-ring { animation-delay: -0.6s; }
.event-dot { position: absolute; inset: 0; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #fffaf0, var(--tint, var(--gold)) 55%, #7a5f1e 100%); box-shadow: 0 0 18px 3px color-mix(in srgb, var(--tint, var(--gold)) 60%, transparent); transition: transform .25s cubic-bezier(.3,1.4,.5,1); }
.event-marker:hover .event-dot, .event-marker:focus-visible .event-dot { transform: scale(1.3); }
.event-marker:active .event-dot { transform: scale(1.12); }
.event-marker:active .event-avatar { transform: translateY(-3px) scale(.96); }
.event-label { margin-top: 14px; font-family: var(--font-display); font-size: 17px; font-weight: 600; text-align: center; white-space: nowrap; color: #f0ead8; }
.event-era { display: block; margin-top: 3px; font-family: var(--font-ui); font-size: 9.5px; font-weight: 500; color: var(--ink-dim); text-transform: uppercase; letter-spacing: .1em; }

.timeline-chrome { position: absolute; bottom: 0; left: 0; right: 0; z-index: 9; display: flex; flex-direction: column; align-items: center; gap: 14px; padding-bottom: calc(22px + env(safe-area-inset-bottom, 0px)); pointer-events: none; }
.progress-dots { display: flex; gap: 6px; pointer-events: auto; flex-wrap: wrap; justify-content: center; max-width: 90vw; }
.progress-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--panel-border); cursor: pointer; transition: all .3s ease; border: none; padding: 0; }
.progress-dot.active { background: var(--gold-soft); width: 20px; border-radius: 3px; box-shadow: 0 0 8px rgba(240,208,96,.6); }
.scroll-hint { font-family: var(--font-ui); font-size: 10.5px; color: var(--ink-dim); letter-spacing: .04em; display: flex; align-items: center; gap: 12px; pointer-events: none; }
.scroll-arrows { display: flex; gap: 8px; pointer-events: auto; }
.scroll-arrows button, .zoom-controls button, .controls-btn { width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--panel-border); background: rgba(22,25,51,.7); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); color: var(--gold-soft); cursor: pointer; font-size: 14px; font-family: var(--font-body); transition: border-color .2s, background .2s; }
.scroll-arrows button:hover, .zoom-controls button:hover { background: rgba(42,38,80,.85); border-color: var(--gold-soft); }
.scroll-arrows button:disabled { opacity: .3; cursor: default; pointer-events: none; }
.scroll-arrows button, .zoom-controls button, .back-btn, .panel-close { transition: transform .12s ease, border-color .2s, background .2s, color .2s; }
.scroll-arrows button:active, .zoom-controls button:active, .back-btn:active, .panel-close:active { transform: scale(.88); }
.progress-dot:active { transform: scale(1.4); }

/* `visibility: hidden` além de `opacity: 0`: garante que, mesmo que uma
   transição seja interrompida (visto num iPhone real), a camada do
   acontecimento NUNCA fica pintada por cima da linha do tempo. A visibility
   transita como passo discreto no fim do fade — o fade-out continua a ver-se. */
#eventView { position: absolute; inset: 0; z-index: 8; display: flex; flex-direction: column; opacity: 0; visibility: hidden; pointer-events: none; transform: scale(.04); transition: opacity .65s ease, transform .65s cubic-bezier(.3,.7,.4,1), visibility .65s; transform-style: preserve-3d; }
#eventView.shown { opacity: 1; visibility: visible; pointer-events: auto; transform: scale(1); }
.event-ambient { position: absolute; top: -10%; left: -10%; width: 60%; height: 70%; border-radius: 50%; filter: blur(90px); opacity: .38; background: radial-gradient(circle, var(--tint, var(--gold)), transparent 70%); pointer-events: none; z-index: 0; }

#eventScroll { position: relative; z-index: 2; flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; }
/* Coluna direita: título da secção no topo (mais para a direita) + árvore. */
.event-main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.event-heading { display: flex; align-items: center; gap: 14px; padding: 16px 28px 4px 32px; }
/* Botão voltar: ícone circular no topo do cartão de detalhes. */
.back-btn { width: 34px; height: 34px; border-radius: 50%; padding: 0; display: inline-flex; align-items: center; justify-content: center; color: var(--gold-soft); background: linear-gradient(180deg, rgba(44,40,84,.6), rgba(22,25,51,.6)); border: 1px solid var(--panel-border); cursor: pointer; -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); transition: border-color .2s, background .2s, box-shadow .25s, transform .1s; margin-bottom: 14px; }
.back-btn .bk-arrow { display: inline-block; font-size: 16px; line-height: 1; transition: transform .22s cubic-bezier(.34,1.56,.64,1); }
.back-btn:hover { border-color: var(--gold-soft); background: linear-gradient(180deg, rgba(56,50,104,.85), rgba(30,34,66,.85)); box-shadow: 0 0 0 1px rgba(216,201,138,.35) inset, 0 4px 16px rgba(240,208,96,.16); }
.back-btn:hover .bk-arrow { transform: translateX(-3px); }
.back-btn:active { transform: scale(.92); }
.back-btn:focus-visible { outline: 2px solid var(--gold-soft); outline-offset: 2px; }
.event-icon { width: 46px; height: 46px; flex-shrink: 0; color: var(--tint, var(--gold)); opacity: .9; }
.event-icon svg { width: 100%; height: 100%; }
.event-title-wrap { display: flex; flex-direction: column; }
.event-title { font-family: var(--font-display); font-size: 26px; font-weight: 600; color: #f5ecd8; line-height: 1.1; }
.event-era-tag { font-family: var(--font-ui); font-size: 10.5px; font-weight: 600; color: var(--ink-dim); text-transform: uppercase; letter-spacing: .12em; margin-top: 2px; }

/* Cartão "Sobre" sempre visível à esquerda da árvore (deixou de ser colapsado):
   Importância/Mensagem/Contexto/Passagens ficam de primeira classe, ao lado do
   grafo (simétrico ao painel de personagem à direita). Em mobile empilha por
   cima do grafo (ver @media). */
.event-info { flex-shrink: 0; width: 21rem; align-self: stretch; overflow-y: auto; padding: 18px 20px 20px; margin: 0; background: rgba(20,23,46,.5); border-right: 1px solid var(--panel-border); z-index: 2; }
.event-info-label { display: block; font-family: var(--font-ui); font-size: 9.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--gold-soft); margin-bottom: 8px; }
.event-desc { font-family: var(--font-body); font-size: 13px; line-height: 1.6; color: #c8c3e0; font-style: italic; margin: 0 0 14px; }
.event-info-grid { display: flex; flex-direction: column; gap: 14px; }
.event-info-block h3 { margin: 0 0 4px; font-family: var(--font-ui); font-size: 9.5px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--gold-soft); }
.event-info-block p { margin: 0; font-family: var(--font-ui); font-size: 12.5px; line-height: 1.6; color: var(--ink); }
.event-info-block ul { margin: 0; padding-left: 16px; font-family: var(--font-ui); font-size: 12px; line-height: 1.6; color: var(--ink-dim); }

.event-body { position: relative; z-index: 1; flex: 1; min-height: 0; display: flex; }
.char-field { flex: 1; position: relative; overflow: hidden; cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }
.char-field.panning { cursor: grabbing; }
.char-orbit { position: relative; width: 100%; height: 100%; }
#camLayer { position: absolute; inset: 0; transform-origin: 50% 50%; will-change: transform; }
.char-lines { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.cline { stroke: var(--lavender); stroke-width: 1.6; opacity: .75; stroke-linecap: round; }
.cline.casamento { stroke: var(--pink); opacity: .85; stroke-width: 1.6; }
.marriage-mark { position: absolute; transform: translate(-50%, -50%); color: var(--pink); font-size: 15px; line-height: 1; text-shadow: 0 0 8px rgba(232,96,143,.85); pointer-events: none; z-index: 1; }
.rel-label { position: absolute; transform: translate(-50%, -50%); font-family: var(--font-ui); font-size: 10.5px; font-weight: 600; letter-spacing: .06em; color: var(--ink-dim); background: rgba(20,23,46,.72); padding: 1px 6px; border-radius: 999px; white-space: nowrap; pointer-events: none; z-index: 1; }
.group-brace { position: absolute; height: 10px; border-top: 1.6px solid var(--lavender); border-left: 1.6px solid var(--lavender); border-right: 1.6px solid var(--lavender); border-radius: 6px 6px 0 0; opacity: .55; transform: translateY(46px); pointer-events: none; }
.group-label { position: absolute; transform: translate(-50%, 60px); font-family: var(--font-ui); font-size: 11px; font-weight: 600; letter-spacing: .06em; color: var(--gold-soft); background: rgba(20,23,46,.72); padding: 1px 7px; border-radius: 999px; white-space: nowrap; pointer-events: none; z-index: 1; }
.zoom-controls { position: absolute; bottom: calc(20px + env(safe-area-inset-bottom, 0px)); right: calc(20px + env(safe-area-inset-right, 0px)); z-index: 4; display: flex; flex-direction: column; gap: 8px; }

.char { position: absolute; display: flex; flex-direction: column; align-items: center; gap: 8px; cursor: pointer; background: none; border: none; color: inherit; transform: translate(-50%, -50%); animation: charEnter .55s cubic-bezier(.34, 1.56, .64, 1) both; }
.char-orb { width: 56px; height: 56px; border-radius: 50%; overflow: hidden; background: radial-gradient(circle at 35% 30%, #efe9ff, var(--lavender) 58%, #362f5e 100%); box-shadow: 0 4px 14px rgba(0,0,0,.5), 0 0 14px 2px rgba(107,100,168,.4); transition: transform .18s cubic-bezier(.3,1.4,.5,1), box-shadow .18s ease; }
.char-orb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.char.focused .char-orb { box-shadow: 0 0 0 3px var(--gold-soft), 0 0 24px 6px rgba(240,208,96,.55), 0 4px 14px rgba(0,0,0,.5); }
.char:hover .char-orb, .char:focus-visible .char-orb { transform: scale(1.14); }
.char:active .char-orb { transform: scale(.9); box-shadow: 0 0 0 3px rgba(240,208,96,.55), 0 4px 14px rgba(0,0,0,.5), 0 0 26px 8px rgba(240,208,96,.45); }
/* Nome posicionado de forma absoluta por baixo do orbe: assim o centro do
   elemento .char coincide com o centro do CÍRCULO, e as linhas de família
   ligam ao meio do círculo (antes ancoravam no centro de círculo+nome, ~13px
   abaixo, e pareciam desligadas). */
.char-label { position: absolute; top: 100%; left: 50%; transform: translateX(-50%); margin-top: 8px; font-family: var(--font-display); font-size: 15px; font-weight: 600; color: #ece7f5; white-space: nowrap; text-shadow: 0 2px 6px rgba(0,0,0,.6); text-align: center; }
@keyframes charEnter {
  from { opacity: 0; transform: translate(-50%, -50%) scale(.3); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

aside#panel { position: absolute; top: 24px; right: 24px; bottom: 24px; width: 22rem; z-index: 3; background: rgba(20,23,46,.85); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); border: 1px solid var(--panel-glow); border-radius: 20px; padding: 1.6rem 1.7rem; overflow-y: auto; box-shadow: 0 20px 50px rgba(0,0,0,.4); transform: translateX(calc(100% + 40px)); transition: transform .4s cubic-bezier(.3,.8,.4,1); }
aside#panel.open { transform: translateX(0); }
.panel-close { position: absolute; top: 14px; right: 14px; width: 28px; height: 28px; border-radius: 50%; border: 1px solid var(--panel-border); background: rgba(22,25,51,.6); color: var(--ink-dim); font-size: 14px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: color .2s, border-color .2s; }
.panel-close:hover { color: var(--gold-soft); border-color: var(--gold-soft); }
/* Pega do bottom sheet — só existe visualmente em mobile; a área de toque é
   generosa (30px de altura, largura toda) para o swipe-down começar sempre bem. */
.sheet-handle { display: none; }
/* Backdrop do bottom sheet — só em mobile: escurece a cena atrás da ficha
   (o sheet a 62dvh cobre o campo todo, por isso "tocar fora" precisa de uma
   superfície própria) e fecha a ficha ao toque. Padrão nativo de bottom sheet. */
.sheet-backdrop { display: none; }
.panel-empty { font-family: var(--font-ui); color: var(--ink-dim); font-size: .85rem; margin-top: 2.4rem; text-align: center; line-height: 1.7; }
#panelBody { transition: opacity .18s ease; }
.card-portrait { width: 112px; height: 112px; border-radius: 50%; overflow: hidden; margin: 0 auto 1rem; border: 3px solid var(--gold-soft); box-shadow: 0 0 20px rgba(240,208,96,.3); background: radial-gradient(circle at 35% 30%, #efe9ff, var(--lavender) 58%, #362f5e 100%); }
.card-portrait img { width: 100%; height: 100%; object-fit: cover; display: block; }
.card-era { font-family: var(--font-ui); font-size: .68rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--gold-soft); text-align: center; display: block; }
.card-name { font-family: var(--font-display); font-size: 2.1rem; font-weight: 600; margin: .3rem 0 0; color: #f5ecd8; text-align: center; }
.card-refs { font-family: var(--font-ui); font-size: .72rem; color: var(--ink-dim); text-align: center; margin: .2rem 0 0; }
.card-summary { font-family: var(--font-body); font-size: .95rem; line-height: 1.7; color: var(--ink); margin: 0 0 1.1rem; }
.card-section-title { font-family: var(--font-ui); font-size: .64rem; font-weight: 600; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-dim); margin: 1.15rem 0 .5rem; }
.card-section-title:first-of-type { margin-top: 0; }
.card-body { font-family: var(--font-ui); font-size: .86rem; line-height: 1.65; color: var(--ink); }
.card-highlight { margin: 1rem 0; padding: .8rem 1rem; border-radius: 12px; border-left: 3px solid var(--accent, var(--gold-soft)); background: color-mix(in srgb, var(--accent, #f0d060) 12%, transparent); }
.card-highlight-label { display: block; font-family: var(--font-ui); font-size: .62rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--accent, var(--gold-soft)); margin-bottom: .35rem; }
.card-highlight p { margin: 0; font-family: var(--font-body); font-size: .95rem; line-height: 1.6; color: var(--ink); }
.card-quote { font-family: var(--font-display); font-size: 1.18rem; font-style: italic; line-height: 1.5; color: var(--gold-soft); border-left: 3px solid var(--gold-soft); padding-left: .9rem; margin: 1.1rem 0; }
.card-context-toggle { margin-top: 1.2rem; font-family: var(--font-ui); font-size: .68rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-dim); background: none; border: none; cursor: pointer; padding: 0; display: flex; align-items: center; gap: 6px; }
.card-context-toggle .arrow { display: inline-block; transition: transform .2s ease; font-size: .8em; }
.card-context-toggle.open .arrow { transform: rotate(90deg); }
.card-context-body { margin-top: .5rem; }
.family-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.family-chip { font-family: var(--font-ui); font-size: 12.5px; font-weight: 500; color: var(--gold-soft); background: rgba(216,201,138,.08); border: 1px solid rgba(216,201,138,.3); border-radius: 999px; padding: 6px 13px; cursor: pointer; transition: background .2s, border-color .2s; }
.family-chip:hover { background: rgba(216,201,138,.18); border-color: var(--gold-soft); }
.family-chip .rel { color: var(--ink-dim); font-size: 10px; margin-left: 5px; }
.cross-event-ref { color: var(--gold-soft); cursor: pointer; text-decoration: underline; text-decoration-style: dotted; }
.no-family { font-family: var(--font-ui); font-size: 12.5px; color: var(--ink-dim); }

footer.note { padding: .4rem 1.4rem; font-size: .68rem; color: var(--ink-dim); font-family: var(--font-ui); }
footer.note a { color: var(--ink-dim); text-decoration: none; }
footer.note a:hover { color: var(--gold-soft); text-decoration: underline; }

/* A barra de app do acontecimento só existe em mobile (ver @media). */
.event-appbar { display: none; }

/* Alvos de toque num ecrã tátil (telemóvel, tablet, portátil touch):
   controlos primários ≥44px; os pontos de progresso mantêm 6px visuais mas
   a hitbox cresce por padding (41 pontos a 44px não cabem em lado nenhum). */
@media (pointer: coarse) {
  .scroll-arrows button, .zoom-controls button { width: 44px; height: 44px; font-size: 17px; }
  .back-btn { width: 44px; height: 44px; }
  .panel-close { width: 40px; height: 40px; font-size: 17px; top: 10px; right: 10px; }
  .progress-dots { gap: 2px; }
  .progress-dot { width: 18px; height: 18px; padding: 6px; background-clip: content-box; }
  .progress-dot.active { width: 30px; }
  .family-chip { padding: 10px 16px; font-size: 13px; }
  .card-context-toggle { padding: 8px 0; }
}

@media (max-width: 720px) {
  /* iOS Safari ignora overflow:hidden no body para scroll por toque — sem
     isto a página inteira podia deslizar/fazer rubber-band e desalinhar tudo. */
  body { position: fixed; inset: 0; width: 100%; }
  .hint { display: none; }
  .topbar { padding: 10px 16px; }
  body.in-event .topbar { padding: 6px 16px; }
  h1 { font-size: 22px; }
  /* Ficha da personagem como ecrã de detalhe de app: sheet OPACO (a árvore não
     transparece por trás — era o "desformatado"), alto (88dvh, leitura sem
     aperto), com sombra a separar do fundo. Fecha por swipe/pega, X ou backdrop. */
  aside#panel {
    position: fixed; left: 0; right: 0; bottom: 0; top: auto; width: auto; max-height: 88vh; max-height: 88dvh; border-radius: 20px 20px 0 0;
    transform: translateY(100%); z-index: 10;
    background: var(--panel); backdrop-filter: none;
    border: 1px solid var(--panel-border); border-bottom: none;
    box-shadow: 0 -14px 44px rgba(0,0,0,.55);
    /* padding no CORPO, não no sheet: a pega sticky fica colada ao topo sem
       margens negativas, e o conteúdo (retrato incluído) começa sempre limpo
       por baixo dela — sem sobreposições ao abrir. */
    padding: 0;
  }
  #panelBody { padding: 4px 1.4rem calc(1.4rem + env(safe-area-inset-bottom, 0px)); }
  #panel .panel-empty { padding: 0 1.4rem; }
  aside#panel.open { transform: translateY(0); }
  .card-portrait { width: 92px; height: 92px; margin-bottom: .7rem; }
  .card-name { font-size: 1.8rem; }
  /* Backdrop acima da appbar (z4): com a ficha aberta, tudo o que está atrás
     fica escurecido e um toque em qualquer sítio fora do sheet fecha-a. */
  .sheet-backdrop { display: block; position: absolute; inset: 0; z-index: 9; background: rgba(5,6,15,.72); opacity: 0; pointer-events: none; transition: opacity .3s ease; }
  .sheet-backdrop.show { opacity: 1; pointer-events: auto; }
  /* Sticky no topo do sheet: mesmo com o conteúdo scrollado, a pega fica
     sempre acessível para o swipe-down fechar (senão desaparecia por cima). */
  .sheet-handle { display: flex; justify-content: center; align-items: center; height: 34px; position: sticky; top: 0; z-index: 3; margin: 0; padding: 0; background: var(--panel); border-radius: 20px 20px 0 0; cursor: grab; touch-action: none; }
  .sheet-handle span { width: 42px; height: 5px; border-radius: 999px; background: var(--panel-border); }
  footer.note { display: none; }
  /* topbar: em mobile a pesquisa ocupa a largura toda, por baixo do título.
     16px no input é obrigatório: abaixo disso o iOS faz zoom automático da
     página ao focar, e o utilizador fica com a interface ampliada e cortada. */
  .search-wrap { width: 100%; }
  .search-box { font-size: 16px; padding: 8px 14px; }
  .search-results { max-height: 40vh; max-height: 40dvh; overflow-y: auto; }
  /* O × fica ACIMA da pega sticky (fundo sólido, z3) — senão o botão de fechar
     a ficha ficava tapado e "não se via o botão de saída" (bug real de iPhone). */
  .panel-close { z-index: 4; top: 12px; right: 12px; }
  /* --- Interior do acontecimento em MOBILE: app com separadores Árvore/Sobre.
     Cada separador ocupa o ecrã TODO (a árvore é o conteúdo principal; o texto
     "Sobre" tem leitura confortável) — em vez de espremer os dois numa coluna.
     Dentro de um acontecimento o topo passa a ser a barra do acontecimento,
     escondendo a topbar de pesquisa (padrão de app: o detalhe tem o seu header). */
  body.in-event .topbar { display: none; }
  .event-appbar {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    padding: calc(8px + env(safe-area-inset-top, 0px)) 12px 8px;
    background: linear-gradient(180deg, rgba(15,17,38,.97), rgba(15,17,38,.88));
    border-bottom: 1px solid rgba(74,69,128,.5);
    position: relative; z-index: 4;
  }
  .appbar-back { width: 40px; height: 40px; flex-shrink: 0; border-radius: 50%; border: 1px solid var(--panel-border); background: rgba(22,25,51,.75); color: var(--gold-soft); display: inline-flex; align-items: center; justify-content: center; font-size: 18px; padding: 0; }
  .appbar-title { flex: 1 1 auto; min-width: 0; font-family: var(--font-display); font-size: 19px; font-weight: 600; color: #f5ecd8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .appbar-seg { flex: 1 0 100%; display: flex; gap: 4px; padding: 3px; border-radius: 999px; background: rgba(20,23,46,.85); border: 1px solid var(--panel-border); }
  .seg-btn { flex: 1; padding: 9px 0; border: none; border-radius: 999px; background: none; color: var(--ink-dim); font-family: var(--font-ui); font-size: 13px; font-weight: 600; letter-spacing: .02em; transition: background .18s, color .18s; }
  .seg-btn.active { background: var(--gold-soft); color: #1a1730; }

  /* Mostrar só o separador ativo, em ecrã cheio. */
  #eventScroll { overflow: hidden; }
  .event-body { flex-direction: column; height: 100%; }
  #eventView.tab-arvore .event-info { display: none; }
  #eventView.tab-arvore .event-main { display: flex; }
  #eventView.tab-sobre .event-main { display: none; }
  #eventView.tab-sobre .event-info {
    display: block; width: auto; max-height: none; flex: 1 1 auto; min-height: 0;
    align-self: stretch; border: none; overflow-y: auto;
    padding: 16px 18px calc(20px + env(safe-area-inset-bottom, 0px));
  }
  .event-info .back-btn, .event-info .event-info-label { display: none; }
  .event-heading { display: none; }
  .char-field { min-height: 0; flex: 1; }

  /* O scrubber da linha do tempo não faz sentido dentro de um acontecimento
     num telemóvel (confunde e sobrepunha-se ao zoom) — voltar à timeline é a
     navegação; o botão "voltar" da barra é o caminho. */
  body.in-event .timeline-chrome { display: none; }

  /* Zoom: o pinch faz +/−; fica só o "ajustar vista" (evita a coluna de 3
     botões a tapar personagens). */
  .zoom-controls #zoomIn, .zoom-controls #zoomOut { display: none; }

  /* Transição app-like: substituição limpa por fade, sem o "zoom-encolher"
     (scale .04→1) que dava o ar meio-desenhado; a timeline sai depressa para
     não ficar em fantasma por baixo do acontecimento a entrar. Os streaks do
     warp continuam a tocar. */
  #eventView { transform: none; transition: opacity .28s ease, visibility .28s; }
  #eventView.shown { transform: none; }
  /* Garantia: dentro de um acontecimento a linha do tempo fica MESMO invisível
     (marcadores/calha apareciam por trás da árvore num iPhone real quando a
     classe .diving se perdia) — amarrado à mesma classe que mostra a appbar. */
  body.in-event #timelineView { opacity: 0; visibility: hidden; transition: opacity .2s ease, visibility .2s; }
  /* Saída: o acontecimento desaparece quase de imediato, para NÃO ficar por
     cima da timeline a desvanecer (o "ficam elementos anteriores" ao voltar).
     A entrada mantém-se suave (.28s). */
  #eventView.leaving { transition: opacity .1s ease, visibility .1s; }
  #timelineView { transition: opacity .22s ease; }
  #timelineView.diving { transform: none; }
}
/* 41 pontos de progresso num ecrã de telemóvel são ruído (3+ filas com a
   hitbox tátil) — escondem-se; ficam o arrasto, as setas e os marcadores. */
@media (max-width: 540px) {
  .progress-dots { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .char { animation: none; opacity: 1; }
  .event-dot-ring { animation: none; }
  .nebula { animation: none; transition: none; }
  .sheet-backdrop { transition: none; }
  aside#panel { transition: none; }
}
