/* NETWAR — turn duel prototype (practice, 2026-10-02; public/rt-duel.js).
   The owner likes this look (flat neon panels, chamfered cards, bar meters, one turn clock): it is
   the base if the turn duel stays. Cards wear the game's categories: the role on the top edge
   (fighter green, wall blue, script violet, trap amber) and the rarity in the frame and its light
   (rare cyan, epic violet with a running light, legendary gold with a pulse and a sweep; a
   syndicate card breathes in its colour) — the same colours as the Safehouse (card-rarity.css). */
#rt-duel {
  --rt-bg: #070a10; --rt-panel: #0d1320; --rt-line: #1d2a3d; --rt-me: #45fff0; --rt-foe: #ff5c8a;
  --rt-good: #37f5a3; --rt-warn: #f0a020; --rt-text: #c9d6de; --rt-dim: #6b7d8f;
  position: fixed; inset: 0; z-index: 420; display: flex; flex-direction: column; gap: 10px; padding: 14px 18px 12px;
  box-sizing: border-box; overflow: hidden; color: var(--rt-text); font: 12px 'IBM Plex Mono', Consolas, monospace;
  background: radial-gradient(ellipse at 50% 40%, #0f1828 0%, var(--rt-bg) 70%);
}
#rt-duel::before { content: ''; position: absolute; inset: 0; pointer-events: none; opacity: 0.25;
  background: repeating-linear-gradient(0deg, rgba(69, 255, 240, 0.05) 0 1px, transparent 1px 3px); }
#rt-duel *, #rt-tip, .rt-cast { box-sizing: border-box; }

/* Roles and rarities (shared by units, hand cards, the cast card and the tip). */
#rt-duel .r-fighter, #rt-tip.r-fighter, .rt-cast.r-fighter { --role: #37f5a3; }
#rt-duel .r-wall, #rt-tip.r-wall, .rt-cast.r-wall { --role: #6d8bff; }
#rt-duel .r-script, #rt-tip.r-script, .rt-cast.r-script { --role: #c88dff; }
#rt-duel .r-trap, #rt-tip.r-trap, .rt-cast.r-trap { --role: #ffd23f; }
/* The card rework's roles (docs/CARD_REWORK_PLAN.md). */
#rt-duel .r-blocker, #rt-tip.r-blocker, .rt-cast.r-blocker { --role: #6d8bff; }
#rt-duel .r-lure, #rt-tip.r-lure, .rt-cast.r-lure { --role: #ff9f43; }
#rt-duel .r-answer, #rt-tip.r-answer, .rt-cast.r-answer { --role: #ffd23f; }
#rt-duel .r-trick, #rt-tip.r-trick, .rt-cast.r-trick { --role: #c88dff; }
#rt-duel .r-virus, #rt-tip.r-virus, .rt-cast.r-virus { --role: #b6ff3f; }
#rt-duel .r-steal, #rt-tip.r-steal, .rt-cast.r-steal { --role: #ff5cd6; }
#rt-duel .rar-rare, #rt-tip.rar-rare { --rar: #37d5f5; --rar-glow: rgba(55, 213, 245, 0.25); }
#rt-duel .rar-epic, #rt-tip.rar-epic { --rar: #a85cf6; --rar-glow: rgba(168, 92, 246, 0.3); }
#rt-duel .rar-legendary, #rt-tip.rar-legendary { --rar: #f5c842; --rar-glow: rgba(245, 200, 66, 0.35); }
#rt-duel .syn-techno_nomads, #rt-tip.syn-techno_nomads { --syn: 0, 148, 216; }
#rt-duel .syn-street_prolets, #rt-tip.syn-street_prolets { --syn: 245, 163, 55; }
#rt-duel .syn-neo_yakuza, #rt-tip.syn-neo_yakuza { --syn: 196, 77, 255; }
@property --rt-a { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
@keyframes rt-orbit { to { --rt-a: 360deg; } }
@keyframes rt-legend { 50% { box-shadow: inset 0 0 30px rgba(245, 200, 66, 0.45), 0 0 26px rgba(245, 180, 40, 0.55); } }
@keyframes rt-sweep { 0% { background-position: 160% 0; } 55%, 100% { background-position: -60% 0; } }
@keyframes rt-breathe { 50% { box-shadow: inset 0 0 18px rgba(var(--syn), 0.35), 0 0 16px rgba(var(--syn), 0.5); } }

/* Head and meters. */
#rt-duel .rt-head { display: flex; align-items: center; gap: 16px; }
#rt-duel .rt-title { flex: 1; display: flex; flex-direction: column; }
#rt-duel .rt-title b { font: 700 16px 'Chakra Petch', sans-serif; letter-spacing: 0.2em; color: var(--rt-me); text-shadow: 0 0 10px rgba(69, 255, 240, 0.5); }
#rt-duel .rt-title span { color: var(--rt-dim); letter-spacing: 0.12em; font-size: 11px; }
#rt-duel .rt-clock { font: 700 22px 'Chakra Petch', sans-serif; color: #fff; letter-spacing: 0.12em; }
#rt-duel .rt-btn, #rt-coach .rt-btn { background: transparent; border: 1px solid var(--rt-me, #45fff0); color: var(--rt-me, #45fff0); padding: 7px 16px; cursor: pointer;
  font: 700 12px 'Chakra Petch', sans-serif; letter-spacing: 0.16em; clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px); }
#rt-duel .rt-btn:hover:not(:disabled), #rt-coach .rt-btn:hover { background: rgba(69, 255, 240, 0.12); }
#rt-duel .rt-btn:disabled { opacity: 0.3; cursor: default; }
#rt-duel .rt-meters { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
#rt-duel .rt-mlabel { display: flex; justify-content: space-between; margin-bottom: 4px; letter-spacing: 0.12em; font-size: 11px; }
#rt-duel .rt-mlabel > span { color: #fff; font-weight: 700; }
#rt-duel .rt-bar { height: 12px; background: #0a1019; border: 1px solid var(--rt-line); position: relative; overflow: hidden; }
#rt-duel .rt-bar i { position: absolute; inset: 0 auto 0 0; width: 0; transition: width 0.45s ease-out; }
#rt-duel .breach .rt-mlabel b { color: var(--rt-me); }
#rt-duel .breach .rt-bar i { background: linear-gradient(90deg, #0f6f6a, var(--rt-me)); box-shadow: 0 0 12px var(--rt-me); }
#rt-duel .trace .rt-mlabel b { color: var(--rt-foe); }
#rt-duel .trace .rt-bar i { background: linear-gradient(90deg, #6f1430, var(--rt-foe)); box-shadow: 0 0 12px var(--rt-foe); }
#rt-duel .rt-meter.bump .rt-bar { animation: rt-bump 0.35s ease-out; }
@keyframes rt-bump { 40% { filter: brightness(1.9); transform: scaleY(1.35); } }
#rt-duel .rt-mfc { font-style: normal; font-weight: 700; margin-right: 4px; }
#rt-duel .rt-mfc.good { color: var(--rt-good); } #rt-duel .rt-mfc.bad { color: var(--rt-foe); }
#rt-duel .rt-foe-hand { display: flex; align-items: center; justify-content: center; gap: 4px; color: var(--rt-dim); letter-spacing: 0.14em; font-size: 10px; }
#rt-duel .rt-foe-hand i { display: inline-block; width: 12px; height: 17px; margin-left: 3px; border: 1px solid var(--rt-foe); background: rgba(255, 92, 138, 0.15); }

/* Board: five equal columns that never grow with their text (the lines stay straight). */
#rt-duel .rt-board { flex: 1; min-height: 0; display: grid; grid-template-rows: minmax(96px, 200px) auto auto minmax(96px, 200px); align-content: center;
  gap: 8px; max-width: 980px; width: 100%; margin: 0 auto; }
#rt-duel .rt-row, #rt-duel .rt-ports { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; min-width: 0; }
#rt-duel .rt-slot { position: relative; border: 1px dashed var(--rt-line); min-height: 96px; min-width: 0; display: flex; }
#rt-duel .rt-slot.pick { border: 1px solid var(--rt-me); box-shadow: inset 0 0 18px rgba(69, 255, 240, 0.25); cursor: pointer; }
#rt-duel .rt-row.foe .rt-slot.pick { border-color: var(--rt-foe); box-shadow: inset 0 0 18px rgba(255, 92, 138, 0.3); }
#rt-duel .rt-slot.pick .rt-unit { outline: 2px solid var(--rt-me); outline-offset: -3px; animation: rt-target 0.9s steps(2) infinite; }
#rt-duel .rt-row.foe .rt-slot.pick .rt-unit { outline-color: #fff; }
@keyframes rt-target { 50% { filter: brightness(1.5); } }
#rt-duel .rt-empty { margin: auto; color: #33435a; letter-spacing: 0.2em; font-size: 10px; }
#rt-duel .rt-slot.lane-go::after { content: ''; position: absolute; inset: -4px; pointer-events: none; border: 1px solid #fff;
  box-shadow: 0 0 24px rgba(255, 255, 255, 0.5), inset 0 0 24px rgba(69, 255, 240, 0.35); animation: rt-lane-go 0.35s ease-out forwards; }
@keyframes rt-lane-go { to { opacity: 0; } }

/* A unit on the board. */
#rt-duel .rt-unit { position: relative; isolation: isolate; flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; padding: 8px 8px 6px;
  border: 1px solid var(--rar, var(--rt-me)); border-top: 3px solid var(--role, var(--rt-me));
  background: linear-gradient(180deg, #102031, #0a121d); box-shadow: inset 0 0 18px var(--rar-glow, transparent);
  clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px); }
#rt-duel .rt-unit.foe { border-color: var(--rar, var(--rt-foe)); border-top-color: var(--role, var(--rt-foe)); background: linear-gradient(180deg, #2a0f1b, #150910); }
#rt-duel .rt-uhead { display: flex; align-items: center; gap: 5px; min-width: 0; }
#rt-duel .rt-uname { flex: 1; min-width: 0; font: 700 12px 'Chakra Petch', sans-serif; color: #fff; text-transform: uppercase; letter-spacing: 0.04em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#rt-duel .rt-ustats { display: flex; align-items: baseline; gap: 10px; font-weight: 700; font-size: 14px; min-width: 0; }
#rt-duel .rt-ustats .a { color: var(--rt-warn); } #rt-duel .rt-ustats .h { color: var(--rt-good); }
#rt-duel .rt-unit.foe .rt-ustats .h { color: #ff9ab4; }
#rt-duel .rt-urole { margin-left: auto; font-size: 8px; letter-spacing: 0.16em; color: var(--role); opacity: 0.85; }
#rt-duel .rt-utag, #rt-duel .rt-ufc { min-height: 12px; font-size: 9px; letter-spacing: 0.08em; color: var(--rt-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
#rt-duel .rt-ufc { font-size: 10px; font-weight: 700; }
#rt-duel .rt-ufc.bad { color: #ff5c8a; text-shadow: 0 0 6px rgba(255, 92, 138, 0.6); }
#rt-duel .rt-ufc.good { color: #37f5a3; text-shadow: 0 0 6px rgba(55, 245, 163, 0.5); }
#rt-duel .rt-unit.waiting .rt-utag { color: var(--rt-warn); }
#rt-duel .rt-unit.stun { filter: grayscale(0.8) brightness(0.7); }
#rt-duel .rt-unit.shield { outline: 2px solid #29b6d8; outline-offset: -4px; }
#rt-duel .rt-new { display: none; font: 700 8px 'Chakra Petch', sans-serif; letter-spacing: 0.16em; color: #071018; background: #fff; padding: 1px 5px; }
#rt-duel .rt-unit.newest { outline: 2px solid #fff; outline-offset: -3px; }
#rt-duel .rt-unit.newest .rt-new { display: inline-block; }
/* Rarity light: epic runs a light round its frame, legendary pulses and sweeps, a syndicate breathes. */
#rt-duel .rt-unit.rar-epic::after, #rt-duel .rt-card.rar-epic::after { content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: conic-gradient(from var(--rt-a), transparent 0 80%, rgba(210, 170, 255, 0.45) 88%, transparent 96%); animation: rt-orbit 5s linear infinite; }
#rt-duel .rt-unit.rar-legendary, #rt-duel .rt-card.rar-legendary { animation: rt-legend 2.6s ease-in-out infinite; }
#rt-duel .rt-unit.rar-legendary::before, #rt-duel .rt-card.rar-legendary::before { content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(110deg, transparent 30%, rgba(255, 236, 170, 0.3) 48%, rgba(255, 255, 255, 0.45) 50%, rgba(255, 236, 170, 0.3) 52%, transparent 70%);
  background-size: 250% 100%; animation: rt-sweep 3.4s ease-in-out infinite; mix-blend-mode: screen; }
#rt-duel .rt-unit.syn, #rt-duel .rt-card.syn { animation: rt-breathe 3.2s ease-in-out infinite; }
#rt-duel .syn-emblem { display: inline-flex; flex: none; }
/* Arriving: yours rises from your side, the enemy's drops from theirs, with a glitch. */
#rt-duel .rt-unit.enter.me { animation: rt-enter-me 0.5s cubic-bezier(.2, .9, .3, 1); }
#rt-duel .rt-unit.enter.foe { animation: rt-enter-foe 0.5s cubic-bezier(.2, .9, .3, 1); }
@keyframes rt-enter-me { 0% { opacity: 0; transform: translateY(70px) scale(0.85); filter: brightness(3); } 60% { opacity: 1; transform: translateY(-4px); } 75% { transform: translateX(3px); } }
@keyframes rt-enter-foe { 0% { opacity: 0; transform: translateY(-70px) scale(0.85); filter: brightness(3); } 60% { opacity: 1; transform: translateY(4px); } 75% { transform: translateX(-3px); } }
#rt-duel .rt-unit.hit { animation: rt-hit 0.35s steps(3); }
@keyframes rt-hit { 30% { transform: translateX(-4px); filter: brightness(2) hue-rotate(-40deg); } 60% { transform: translateX(3px); } }
#rt-duel .rt-unit.heal { animation: rt-heal 0.5s ease-out; }
@keyframes rt-heal { 40% { filter: brightness(1.6) hue-rotate(60deg); } }
#rt-duel .rt-unit.dying { animation: rt-dying 0.3s steps(4) forwards; }
@keyframes rt-dying { 0% { filter: brightness(2); } 50% { transform: translateX(4px) skewX(8deg); opacity: 0.7; clip-path: inset(20% 0 30% 0); }
  100% { transform: scale(0.8); opacity: 0; clip-path: inset(50% 0 50% 0); } }

/* Ports, under the enemy row; the forecast of each lane's meter gains sits in them. */
#rt-duel .rt-port { min-width: 0; text-align: center; padding: 3px 0; border-top: 1px solid var(--rt-line); border-bottom: 1px solid var(--rt-line);
  color: #33435a; font-size: 10px; letter-spacing: 0.14em; white-space: nowrap; overflow: hidden; }
#rt-duel .rt-port b { margin-right: 6px; color: var(--rt-text); }
#rt-duel .rt-port span { color: var(--rt-dim); }
#rt-duel .rt-port.you { border-color: var(--rt-me); background: rgba(69, 255, 240, 0.08); }
#rt-duel .rt-port.you b, #rt-duel .rt-port.you span { color: var(--rt-me); }
#rt-duel .rt-port.them { border-color: var(--rt-foe); background: rgba(255, 92, 138, 0.08); }
#rt-duel .rt-port.them b, #rt-duel .rt-port.them span { color: var(--rt-foe); }
#rt-duel .rt-lfc { display: flex; gap: 6px; justify-content: center; margin-top: 2px; }
#rt-duel .rt-lfc em { font-style: normal; font-weight: 700; font-size: 10px; letter-spacing: 0.06em; }
#rt-duel .rt-lfc em.good { color: var(--rt-good); } #rt-duel .rt-lfc em.bad { color: var(--rt-foe); }

/* The turn: ENEMY TURN on their side of the centre, YOUR TURN on yours; the lit one is whose turn it is. */
#rt-duel .rt-turn { display: flex; flex-direction: column; align-items: stretch; gap: 3px; }
#rt-duel .rt-tw { text-align: center; font: 700 16px 'Chakra Petch', sans-serif; letter-spacing: 0.28em; opacity: 0.12; transition: opacity 0.2s; }
#rt-duel .rt-tw.me { color: var(--rt-me); } #rt-duel .rt-tw.foe { color: var(--rt-foe); }
#rt-duel .rt-tw.on { opacity: 1; text-shadow: 0 0 14px currentColor; }
#rt-duel .rt-turn-mid { display: flex; align-items: center; gap: 14px; }
#rt-duel .rt-turn-bar { flex: 1; height: 6px; background: #0a1019; border: 1px solid var(--rt-line); overflow: hidden; }
#rt-duel .rt-turn-bar i { display: block; height: 100%; width: 100%; transform: scaleX(0); transform-origin: left center; will-change: transform; background: linear-gradient(90deg, #2a3e57, var(--rt-me)); box-shadow: 0 0 10px var(--rt-me); }
#rt-duel .rt-turn.theirs .rt-turn-bar i { background: linear-gradient(90deg, #6f1430, var(--rt-foe)); box-shadow: 0 0 10px var(--rt-foe); }
#rt-duel .rt-turn.exec .rt-turn-bar i { background: #fff; box-shadow: 0 0 14px #fff; }
#rt-duel .rt-turn-n { font: 700 26px 'Chakra Petch', sans-serif; color: #fff; min-width: 64px; text-align: right; }
#rt-duel .rt-turn.soon .rt-turn-n { color: var(--rt-warn); text-shadow: 0 0 12px var(--rt-warn); animation: rt-blink 0.4s steps(2) infinite; }
#rt-duel .rt-turn.fire .rt-turn-bar { animation: rt-fire-bar 0.5s ease-out; }
@keyframes rt-fire-bar { 0% { background: #fff; box-shadow: 0 0 30px #fff; } }
#rt-duel .rt-pass { padding: 6px 18px; }
#rt-duel .rt-turn-sub { text-align: center; font-size: 9px; letter-spacing: 0.14em; color: var(--rt-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#rt-duel .rt-turn-sub.fc-lose { color: #ff2e5f; animation: rt-blink 0.8s steps(2) infinite; }
#rt-duel .rt-turn-sub.fc-win { color: var(--rt-good); }
@keyframes rt-blink { 50% { opacity: 0.35; } }

/* The rack: threads, hand, deck. */
#rt-duel .rt-rack { display: grid; grid-template-columns: 180px minmax(0, 1fr) 150px; gap: 14px; align-items: end; max-width: 1080px; width: 100%; margin: 0 auto; }
#rt-duel .rt-tlabel { letter-spacing: 0.14em; font-size: 10px; margin-bottom: 5px; }
#rt-duel .rt-tlabel b { color: var(--rt-me); font-size: 18px; margin-left: 6px; }
#rt-duel .rt-pips { display: grid; grid-template-columns: repeat(10, 1fr); gap: 3px; }
#rt-duel .rt-pips i { height: 16px; background: #0a1019; border: 1px solid var(--rt-line); }
#rt-duel .rt-pips i.on { background: var(--rt-me); box-shadow: 0 0 6px var(--rt-me); }
#rt-duel .rt-nomove { margin-left: 10px; color: #ff2e5f; font-weight: 700; letter-spacing: 0.16em; animation: rt-blink 0.8s steps(2) infinite; }
#rt-duel .rt-nomove[hidden] { display: none; }
#rt-duel .rt-threads.nomove .rt-tlabel b { color: #ff2e5f; text-shadow: 0 0 10px #ff2e5f; }
#rt-duel .rt-threads.nomove .rt-pips i { border-color: #ff2e5f; animation: rt-nomove-pip 0.8s steps(2) infinite; }
@keyframes rt-nomove-pip { 50% { background: rgba(255, 46, 95, 0.55); box-shadow: 0 0 8px #ff2e5f; } }
#rt-duel .rt-hand { display: flex; gap: 8px; min-width: 0; }
#rt-duel .rt-card { position: relative; isolation: isolate; flex: 1 1 0; min-width: 0; max-width: 170px; height: 128px; padding: 7px 8px; cursor: pointer;
  display: flex; flex-direction: column; gap: 3px; background: linear-gradient(180deg, #131c2c, #0b111b);
  border: 1px solid var(--rar, #2d4058); border-top: 3px solid var(--role, #2d4058); box-shadow: inset 0 0 18px var(--rar-glow, transparent);
  transition: transform 0.12s; }
#rt-duel .rt-card.rar-rare, #rt-duel .rt-card.rar-epic, #rt-duel .rt-card.rar-legendary { box-shadow: inset 0 0 18px var(--rar-glow), 0 0 12px var(--rar-glow); }
#rt-duel .rt-card:hover:not(.dis):not(.empty) { transform: translateY(-4px); }
#rt-duel .rt-card.sel { transform: translateY(-10px); outline: 2px solid var(--rt-me); box-shadow: 0 0 20px -4px var(--rt-me); }
#rt-duel .rt-card.dis { opacity: 0.45; cursor: default; }
#rt-duel .rt-card.empty { cursor: default; border: 1px dashed #2d4058; display: grid; place-items: center; color: #33435a; letter-spacing: 0.16em; font-size: 9px; text-align: center; }
#rt-duel .rt-ctop { display: flex; align-items: center; gap: 6px; }
#rt-duel .rt-cost { display: inline-grid; place-items: center; flex: none; width: 22px; height: 22px; background: var(--role, var(--rt-me)); color: #071018;
  font: 700 13px 'Chakra Petch', sans-serif; clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%); }
#rt-duel .rt-crole { flex: 1; font-size: 8px; letter-spacing: 0.16em; color: var(--role); }
#rt-duel .rt-key { color: var(--rt-dim); font-size: 10px; border: 1px solid var(--rt-line); padding: 0 5px; }
#rt-duel .rt-cname { display: flex; align-items: center; gap: 4px; font: 700 12px 'Chakra Petch', sans-serif; color: #fff; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#rt-duel .rt-cstats { font-weight: 700; color: var(--rt-warn); font-size: 11px; }
#rt-duel .rt-card.k-script .rt-cstats { color: var(--role); letter-spacing: 0.14em; font-size: 10px; }
#rt-duel .rt-ctext { font-size: 10px; line-height: 1.3; color: var(--rt-dim); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
#rt-duel .rt-deck { letter-spacing: 0.12em; font-size: 10px; text-align: right; }
#rt-duel .rt-deck b { color: #fff; font-size: 14px; }
#rt-duel .rt-deck span { display: block; color: var(--rt-me); margin-top: 4px; }
#rt-duel .rt-hint { text-align: center; min-height: 16px; color: var(--rt-dim); letter-spacing: 0.06em; }
#rt-duel .rt-hint.good { color: var(--rt-good); } #rt-duel .rt-hint.bad { color: var(--rt-foe); }

/* The card tip: the whole card, readable, on hover. */
#rt-tip { position: fixed; z-index: 2147483100; /* above the training coach (owner, 2026-10-06: cards went under it) */ pointer-events: none; padding: 10px 12px 12px; background: linear-gradient(180deg, #121a29, #0a0f18);
  border: 1px solid var(--rar, #2d4058); border-top: 3px solid var(--role, #45fff0); box-shadow: 0 16px 40px rgba(0, 0, 0, 0.7), 0 0 18px var(--rar-glow, transparent);
  font: 12px 'IBM Plex Mono', Consolas, monospace; color: #c9d6de; }
#rt-tip[hidden] { display: none; }
#rt-tip .tt-top { display: flex; align-items: center; gap: 8px; }
#rt-tip .tt-cost { display: inline-grid; place-items: center; width: 24px; height: 24px; background: var(--role); color: #071018;
  font: 700 13px 'Chakra Petch', sans-serif; clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%); }
#rt-tip .tt-role { font: 700 10px 'Chakra Petch', sans-serif; letter-spacing: 0.18em; color: var(--role); }
#rt-tip .tt-rar { margin-left: auto; font: 700 9px 'Chakra Petch', sans-serif; letter-spacing: 0.16em; color: var(--rar, #6b7d8f); }
#rt-tip .tt-name { margin: 8px 0 4px; font: 700 17px 'Chakra Petch', sans-serif; color: #fff; text-transform: uppercase; }
#rt-tip .tt-stats { font-weight: 700; color: #f0a020; margin-bottom: 6px; }
#rt-tip .tt-stats span { color: #6b7d8f; font-weight: 400; font-size: 10px; }
#rt-tip .tt-text { line-height: 1.45; color: #e6eef3; }
#rt-tip .tt-kw { margin-top: 6px; font-size: 11px; line-height: 1.4; color: #9fb0bf; }
#rt-tip .tt-kw b { color: #fff; letter-spacing: 0.08em; margin-right: 4px; }
#rt-tip .tt-state { margin-top: 6px; font-size: 11px; color: #f0a020; }

/* A script cast: it rises over its target, its text runs like a terminal, it drops in. */
.rt-cast { position: fixed; z-index: 427; pointer-events: none; padding: 10px 12px 12px; background: linear-gradient(180deg, #121826, #0a0e16);
  border: 1px solid currentColor; border-top: 3px solid var(--role, currentColor); font: 12px 'IBM Plex Mono', Consolas, monospace;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6), 0 0 28px -6px currentColor, 0 18px 40px rgba(0, 0, 0, 0.7); animation: rt-cast-in 0.3s cubic-bezier(.2, 1.3, .4, 1); }
.rt-cast.mine { color: #45fff0; } .rt-cast.theirs { color: #ff5c8a; }
.rt-cast .mc-top { display: flex; justify-content: space-between; align-items: center; }
.rt-cast .mc-cost { display: inline-grid; place-items: center; width: 24px; height: 24px; color: #071018; background: var(--role, #45fff0);
  font: 700 13px 'Chakra Petch', sans-serif; clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%); }
.rt-cast .mc-who { font: 700 10px 'Chakra Petch', sans-serif; letter-spacing: 0.18em; }
.rt-cast .mc-name { margin: 6px 0 4px; font: 700 16px 'Chakra Petch', sans-serif; color: #fff; text-transform: uppercase; }
.rt-cast .mc-text { color: #c9d6de; line-height: 1.4; animation: rt-run 0.5s steps(5) 2; }
@keyframes rt-cast-in { from { opacity: 0; transform: translateY(24px) scale(0.6); } to { opacity: 1; transform: none; } }
@keyframes rt-run { 0% { opacity: 0.2; clip-path: inset(0 100% 0 0); } 100% { opacity: 1; clip-path: inset(0 0 0 0); } }

/* Tags, shots and sparks live on the page, above the board. */
.rt-tag { position: fixed; z-index: 428; transform: translate(-50%, -50%); pointer-events: none; white-space: nowrap;
  padding: 3px 9px; font: 700 12px 'IBM Plex Mono', Consolas, monospace; letter-spacing: 0.06em; color: #fff; background: #0d1320; border: 1px solid currentColor;
  clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px); animation: rt-tag 1.1s steps(12) forwards; }
.rt-tag.hurt { color: #ff5c8a; } .rt-tag.dead { color: #ff2e5f; } .rt-tag.good { color: #37f5a3; } .rt-tag.bad { color: #ff8aa0; }
.rt-tag.foe { color: #ff5c8a; font-size: 11px; } .rt-tag.shield { color: #29b6d8; } .rt-tag.port { color: #f0a020; }
@keyframes rt-tag { 0% { opacity: 0; } 10% { opacity: 1; } 75% { opacity: 1; } 100% { opacity: 0; transform: translate(-50%, -150%); } }
.rt-spark { position: fixed; z-index: 429; width: 70px; height: 70px; transform: translate(-50%, -50%); pointer-events: none;
  background: radial-gradient(circle, #fff 0 12%, rgba(255, 220, 120, 0.9) 18%, rgba(255, 92, 138, 0.5) 38%, transparent 62%);
  clip-path: polygon(50% 0, 58% 38%, 100% 50%, 58% 62%, 50% 100%, 42% 62%, 0 50%, 42% 38%); animation: rt-spark 0.4s ease-out forwards; }
@keyframes rt-spark { 0% { transform: translate(-50%, -50%) scale(0.3) rotate(0deg); opacity: 1; } 100% { transform: translate(-50%, -50%) scale(1.6) rotate(45deg); opacity: 0; } }
.rt-bolt { position: fixed; z-index: 429; pointer-events: none; padding: 2px 8px; font: 700 12px 'IBM Plex Mono', Consolas, monospace; color: #071018;
  clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px); }
.rt-bolt.good { background: #45fff0; box-shadow: 0 0 16px #45fff0; }
.rt-bolt.bad { background: #ff5c8a; box-shadow: 0 0 16px #ff5c8a; }
.rt-bolt.noise { background: #f0a020; box-shadow: 0 0 16px #f0a020; }

/* The end. */
#rt-duel .rt-end { position: absolute; inset: 0; display: grid; place-items: center; background: rgba(4, 6, 10, 0.78); z-index: 2; }
#rt-duel .rt-end[hidden] { display: none; }
#rt-duel .rt-end-box { text-align: center; padding: 26px 40px; border: 1px solid currentColor; background: #0b111b; }
#rt-duel .rt-end.win { color: var(--rt-me); } #rt-duel .rt-end.lose { color: var(--rt-foe); }
#rt-duel .rt-end-word { font: 700 34px 'Chakra Petch', sans-serif; letter-spacing: 0.24em; text-shadow: 0 0 18px currentColor; }
#rt-duel .rt-end-sub { color: var(--rt-text); margin: 8px 0 18px; }
#rt-duel .rt-end-row { display: flex; gap: 12px; justify-content: center; }
/* Reduced motion quiets the decoration only — the fight's own feedback (blows, numbers, the ♥
   bar, the energy taken) stays: it is how the duel says what happened (owner, 2026-10-07). */
@media (prefers-reduced-motion: reduce) { #rt-duel .rt-bgterm, #rt-duel .rt-eterm div, #rt-duel .rt-row::before, #rt-duel .rt-row::after, #rt-duel .rt-chan i { animation: none !important; } }

/* Reserved space (owner, 2026-10-02): every text that comes, goes or changes length has a fixed
   box, so nothing on the board grows, wraps or pushes its neighbours. Long text is cut with "…"
   (the card tip shows it whole). */
#rt-duel .rt-clock { min-width: 150px; text-align: right; font-variant-numeric: tabular-nums; }
#rt-duel .rt-title { min-width: 0; }
#rt-duel .rt-title span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#rt-duel .rt-mlabel { height: 16px; line-height: 16px; white-space: nowrap; }
#rt-duel .rt-mfc { display: inline-block; min-width: 82px; text-align: right; font-variant-numeric: tabular-nums; }
#rt-duel .rt-mlabel > span { font-variant-numeric: tabular-nums; }
#rt-duel .rt-foe-hand { height: 18px; overflow: hidden; white-space: nowrap; }
#rt-duel .rt-port { height: 34px; display: flex; flex-direction: column; justify-content: flex-start; line-height: 15px; }
#rt-duel .rt-lfc { height: 14px; margin-top: 1px; overflow: hidden; white-space: nowrap; }
#rt-duel .rt-tw { height: 20px; line-height: 20px; white-space: nowrap; overflow: hidden; }
#rt-duel .rt-turn-mid { height: 34px; }
#rt-duel .rt-turn-n { flex: none; width: 76px; min-width: 0; font-variant-numeric: tabular-nums; white-space: nowrap; }
#rt-duel .rt-pass { flex: none; width: 92px; }
#rt-duel .rt-turn-sub { height: 13px; line-height: 13px; }
#rt-duel .rt-uhead { height: 16px; flex: none; }
#rt-duel .rt-ustats { height: 18px; flex: none; white-space: nowrap; }
#rt-duel .rt-utag, #rt-duel .rt-ufc { height: 13px; line-height: 13px; flex: none; }
#rt-duel .rt-ctop { height: 22px; flex: none; }
#rt-duel .rt-cname { height: 16px; flex: none; }
#rt-duel .rt-cstats { height: 14px; flex: none; white-space: nowrap; overflow: hidden; }
#rt-duel .rt-ctext { flex: 1; min-height: 0; }
#rt-duel .rt-tlabel { height: 22px; white-space: nowrap; }
#rt-duel .rt-nomove[hidden] { display: inline; visibility: hidden; }
#rt-duel .rt-deck { min-width: 0; }
#rt-duel .rt-deck span { height: 26px; line-height: 13px; overflow: hidden; }
#rt-duel .rt-hint { height: 16px; line-height: 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#rt-duel .rt-empty { white-space: nowrap; }

/* Lane channels (owner, 2026-10-02): from card to card down each lane, in the look of the turn bar.
   The signal shows who has the lane (from the forecast): yours green, flowing up into the enemy;
   theirs red, flowing down into you; a fight with no score flickers amber; empty is dark. */
#rt-duel .rt-row.foe { grid-row: 1; } #rt-duel .rt-ports { grid-row: 2; } #rt-duel .rt-turn { grid-row: 3; } #rt-duel .rt-row.mine { grid-row: 4; }
#rt-duel .rt-chans { grid-row: 2 / 4; grid-column: 1; margin: -8px 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; pointer-events: none; }
#rt-duel .rt-ports, #rt-duel .rt-turn { position: relative; z-index: 1; }
#rt-duel .rt-chan { --c: 69, 255, 240; --sp: 1s; justify-self: center; position: relative; width: 12px; height: 100%; overflow: hidden;
  border-left: 1px solid rgba(var(--c), 0.25); border-right: 1px solid rgba(var(--c), 0.25); background: rgba(8, 12, 20, 0.7); transition: border-color 0.3s; }
#rt-duel .rt-chan i { position: absolute; inset: 0; opacity: 0;
  background: repeating-linear-gradient(180deg, rgba(var(--c), 0.95) 0 5px, rgba(var(--c), 0.25) 5px 8px, transparent 8px 22px); }
#rt-duel .rt-chan.up { --c: 55, 245, 163; border-color: rgba(55, 245, 163, 0.6); box-shadow: 0 0 10px rgba(55, 245, 163, 0.25); }
#rt-duel .rt-chan.down { --c: 255, 46, 95; border-color: rgba(255, 46, 95, 0.6); box-shadow: 0 0 10px rgba(255, 46, 95, 0.25); }
#rt-duel .rt-chan.up i { opacity: 1; animation: rt-flow-up var(--sp) linear infinite; }
#rt-duel .rt-chan.down i { opacity: 1; animation: rt-flow-down var(--sp) linear infinite; }
#rt-duel .rt-chan.clash { --c: 240, 160, 32; border-color: rgba(240, 160, 32, 0.5); }
#rt-duel .rt-chan.clash i { opacity: 0.8; background: linear-gradient(180deg, transparent 35%, rgba(240, 160, 32, 0.9) 50%, transparent 65%); animation: rt-clash-flick 0.7s steps(2) infinite; }
#rt-duel .rt-chan.hold { --c: 109, 125, 143; }
#rt-duel .rt-chan.idle { --c: 51, 67, 90; opacity: 0.6; }
@keyframes rt-flow-up { from { background-position: 0 0; } to { background-position: 0 -22px; } }
@keyframes rt-flow-down { from { background-position: 0 0; } to { background-position: 0 22px; } }
@keyframes rt-clash-flick { 50% { opacity: 0.25; } }
/* Text over the channels sits on a plate, so the channel runs under it, not through it. */
#rt-duel .rt-port { border-top-color: transparent; border-bottom-color: transparent; }
#rt-duel .rt-port > b, #rt-duel .rt-port > span, #rt-duel .rt-lfc em { background: #0a0f18; padding: 0 4px; }
#rt-duel .rt-port.you > b, #rt-duel .rt-port.you > span { background: #08201f; }
#rt-duel .rt-port.them > b, #rt-duel .rt-port.them > span { background: #200a12; }
#rt-duel .rt-port.you, #rt-duel .rt-port.them { background: transparent; }
#rt-duel .rt-port.you { box-shadow: inset 0 1px 0 rgba(69, 255, 240, 0.6), inset 0 -1px 0 rgba(69, 255, 240, 0.6); }
#rt-duel .rt-port.them { box-shadow: inset 0 1px 0 rgba(255, 92, 138, 0.6), inset 0 -1px 0 rgba(255, 92, 138, 0.6); }
#rt-duel .rt-tw, #rt-duel .rt-turn-sub { width: fit-content; max-width: 100%; margin: 0 auto; padding: 0 12px; background: #0a0f18; }
#rt-duel .rt-turn-n, #rt-duel .rt-pass { background: #0a0f18; }

/* The forecast on a card, like a till receipt under its ♥: what comes off, a rule, what is left. */
#rt-duel .rt-ustats { display: grid; grid-template-columns: 46px 46px minmax(0, 1fr); gap: 0; }
#rt-duel .rt-ustats .rt-urole { margin-left: 0; justify-self: end; }
#rt-duel .rt-rcpt { flex: none; height: 32px; display: grid; grid-template-columns: 46px 46px minmax(0, 1fr); grid-template-rows: 13px 5px 13px;
  font-size: 11px; font-weight: 700; line-height: 13px; font-variant-numeric: tabular-nums; color: var(--rt-dim); }
#rt-duel .rt-rcpt .m { grid-column: 1; grid-row: 1; opacity: 0.7; }
#rt-duel .rt-rcpt .v1 { grid-column: 2; grid-row: 1; padding-left: 14px; white-space: nowrap; }
#rt-duel .rt-rcpt .rule { grid-column: 2; grid-row: 2; align-self: center; height: 0; margin-left: 12px; margin-right: 10px; }
#rt-duel .rt-rcpt .v2 { grid-column: 2; grid-row: 3; padding-left: 14px; white-space: nowrap; }
#rt-duel .rt-rcpt.on .rule { border-top: 1px dashed currentColor; }
#rt-duel .rt-rcpt.note .v1 { grid-column: 2 / 4; padding-left: 0; font-size: 9px; letter-spacing: 0.1em; }
#rt-duel .rt-rcpt.bad { color: #ff5c8a; text-shadow: 0 0 6px rgba(255, 92, 138, 0.5); }
#rt-duel .rt-rcpt.good { color: #37f5a3; text-shadow: 0 0 6px rgba(55, 245, 163, 0.45); }
#rt-duel .rt-rcpt.dies .v2 { animation: rt-blink 0.8s steps(2) infinite; }
/* Every board layer in the one column (the channels share rows 2–3 with the ports and the turn). */
#rt-duel .rt-board > * { grid-column: 1; min-width: 0; }

/* Second polish (owner, 2026-10-02). */
/* Ports are junction boxes on the channels: one even box per lane, three fixed lines — no plates. */
#rt-duel .rt-port { height: 46px; padding: 2px 0; background: #0b111b; border-top: 1px solid var(--rt-line); border-bottom: 1px solid var(--rt-line); box-shadow: none; }
#rt-duel .rt-port > b, #rt-duel .rt-port > span, #rt-duel .rt-lfc em { background: none; padding: 0; }
#rt-duel .rt-port .pl1, #rt-duel .rt-port .pl2, #rt-duel .rt-lfc { height: 14px; line-height: 14px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
#rt-duel .rt-port .pl1 i { font-style: normal; color: var(--rt-dim); letter-spacing: 0.08em; }
#rt-duel .rt-port .pl2 { color: var(--rt-dim); }
#rt-duel .rt-port.you { background: #0a1c1e; border-color: rgba(69, 255, 240, 0.7); box-shadow: none; }
#rt-duel .rt-port.you .pl1 b, #rt-duel .rt-port.you .pl2 { color: var(--rt-me); }
#rt-duel .rt-port.them { background: #1c0b12; border-color: rgba(255, 92, 138, 0.7); box-shadow: none; }
#rt-duel .rt-port.them .pl1 b, #rt-duel .rt-port.them .pl2 { color: var(--rt-foe); }
/* Text in the centre: no boxes — a soft halo in the page colour lets the channel pass under it. */
#rt-duel .rt-tw, #rt-duel .rt-turn-sub, #rt-duel .rt-turn-n { background: none;
  text-shadow: 0 0 4px #0a0f18, 0 0 8px #0a0f18, 0 0 12px #0a0f18; }
#rt-duel .rt-tw.on { text-shadow: 0 0 4px #0a0f18, 0 0 8px #0a0f18, 0 0 14px currentColor; }
#rt-duel .rt-pass { background: #0b111b; }
/* Channels: two hairlines and a thin line of light packets, fading out at both ends. */
#rt-duel .rt-chan { width: 8px; background: none; box-shadow: none !important; border-left: 1px solid rgba(var(--c), 0.16); border-right: 1px solid rgba(var(--c), 0.16);
  -webkit-mask: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent); mask: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent); }
#rt-duel .rt-chan i { left: 50%; right: auto; width: 2px; margin-left: -1px;
  background: repeating-linear-gradient(180deg, rgba(var(--c), 1) 0 7px, rgba(var(--c), 0.3) 7px 10px, transparent 10px 30px);
  filter: drop-shadow(0 0 3px rgba(var(--c), 0.9)); }
#rt-duel .rt-chan.up, #rt-duel .rt-chan.down { border-color: rgba(var(--c), 0.35); }
#rt-duel .rt-chan.clash { border-color: rgba(var(--c), 0.45); animation: rt-chan-pulse 1.1s ease-in-out infinite; }
#rt-duel .rt-chan.clash i { opacity: 0; animation: none; }
#rt-duel .rt-chan.hold { border-color: rgba(var(--c), 0.25); }
@keyframes rt-chan-pulse { 50% { border-color: rgba(var(--c), 0.12); } }
@keyframes rt-flow-up { from { background-position: 0 0; } to { background-position: 0 -30px; } }
@keyframes rt-flow-down { from { background-position: 0 0; } to { background-position: 0 30px; } }
/* The receipt: right under the ♥ number, digits right-aligned, like a till slip. */
#rt-duel .rt-ustats { display: flex; align-items: flex-start; gap: 16px; height: 50px; grid-template-columns: none; }
#rt-duel .rt-ustats .a { line-height: 18px; }
#rt-duel .hcol { display: inline-flex; flex-direction: column; align-items: flex-end; min-width: 34px; font-variant-numeric: tabular-nums; }
#rt-duel .hcol .h { line-height: 18px; }
#rt-duel .hcol .r1, #rt-duel .hcol .r2 { height: 14px; line-height: 14px; font-size: 13px; white-space: nowrap; }
#rt-duel .hcol .rule { align-self: stretch; height: 4px; }
#rt-duel .hcol.on .rule { border-top: 1px dashed currentColor; margin-top: 2px; height: 2px; }
#rt-duel .hcol.on { color: var(--rt-dim); }
#rt-duel .hcol.bad .r1, #rt-duel .hcol.bad .r2, #rt-duel .hcol.bad .rule { color: #ff5c8a; text-shadow: 0 0 6px rgba(255, 92, 138, 0.5); }
#rt-duel .hcol.good .r1, #rt-duel .hcol.good .r2, #rt-duel .hcol.good .rule { color: #37f5a3; text-shadow: 0 0 6px rgba(55, 245, 163, 0.45); }
#rt-duel .hcol.dies .r2 { animation: rt-blink 0.8s steps(2) infinite; }
#rt-duel .rt-ustats .rt-urole { margin-left: auto; line-height: 18px; }
/* A unit's state may take two lines (there is room) instead of being cut. */
#rt-duel .rt-utag { height: 24px; line-height: 12px; white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }

/* Channels as a river (owner, 2026-10-02): as fine as the turn bar — a 4 px track, a faint steady
   glow of the lane's colour and soft pulses gliding along it (up into the enemy when the lane is
   yours, down into you when it is theirs). Quiet on purpose: the text above must stay readable. */
#rt-duel .rt-chan { width: 4px; border: 1px solid rgba(255, 255, 255, 0.05); border-radius: 2px; background: rgba(8, 12, 20, 0.55);
  box-shadow: none !important; animation: none; opacity: 0.8; transition: box-shadow 0.4s, border-color 0.4s; }
#rt-duel .rt-chan i { left: 0; right: 0; width: auto; margin: 0; filter: none; opacity: 0; transition: opacity 0.5s;
  background: linear-gradient(180deg, rgba(var(--c), 0) 0%, rgba(var(--c), 0) 38%, rgba(var(--c), 0.7) 50%, rgba(var(--c), 0) 62%, rgba(var(--c), 0) 100%),
    linear-gradient(180deg, rgba(var(--c), 0.13), rgba(var(--c), 0.13));
  background-size: 100% 300%, 100% 100%; background-repeat: no-repeat; }
#rt-duel .rt-chan.up, #rt-duel .rt-chan.down { border-color: rgba(var(--c), 0.18); box-shadow: 0 0 6px rgba(var(--c), 0.12) !important; }
#rt-duel .rt-chan.up i { opacity: 1; animation: rt-river-up var(--sp) cubic-bezier(.45, 0, .55, 1) infinite; }
#rt-duel .rt-chan.down i { opacity: 1; animation: rt-river-down var(--sp) cubic-bezier(.45, 0, .55, 1) infinite; }
#rt-duel .rt-chan.clash { border-color: rgba(var(--c), 0.16); animation: none; }
#rt-duel .rt-chan.clash i { opacity: 1; animation: rt-river-still 2.4s ease-in-out infinite;
  background: radial-gradient(ellipse 100% 18% at 50% 50%, rgba(var(--c), 0.55), transparent 70%), linear-gradient(180deg, rgba(var(--c), 0.08), rgba(var(--c), 0.08)); background-size: 100% 100%; }
#rt-duel .rt-chan.hold, #rt-duel .rt-chan.idle { border-color: rgba(255, 255, 255, 0.05); }
@keyframes rt-river-up { from { background-position: 0 0%, 0 0; } to { background-position: 0 100%, 0 0; } }
@keyframes rt-river-down { from { background-position: 0 100%, 0 0; } to { background-position: 0 0%, 0 0; } }
@keyframes rt-river-still { 50% { opacity: 0.35; } }

/* Pointer tilt, like the mirror duel's cards: the card leans toward the pointer, a sheen follows. */
#rt-duel .rt-slot, #rt-duel .rt-hand { perspective: 700px; }
#rt-duel .rt-unit, #rt-duel .rt-card { transform-style: preserve-3d; transition: transform 0.3s cubic-bezier(.2, .9, .3, 1); }
#rt-duel .rt-unit.tilting { transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(1.02); transition: transform 0.08s linear; }
#rt-duel .rt-card.tilting:not(.dis) { transform: translateY(-6px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)); transition: transform 0.08s linear; }
#rt-duel .rt-card.sel.tilting { transform: translateY(-10px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)); }
#rt-duel .rt-sheen { position: absolute; inset: 0; pointer-events: none; z-index: 1; opacity: 0; transition: opacity 0.25s; mix-blend-mode: screen;
  background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%), rgba(255, 255, 255, 0.16), rgba(var(--sheen, 69, 255, 240), 0.06) 30%, transparent 60%); }
#rt-duel .rt-unit.foe .rt-sheen { --sheen: 255, 92, 138; }
#rt-duel .tilting .rt-sheen { opacity: 1; }

/* Out of the hand: a played unit flies from its hand into its lane (a script card does the same). */
.rt-cast { animation: none; }
.rt-fly { position: fixed; z-index: 427; pointer-events: none; display: flex; flex-direction: column; gap: 6px; padding: 8px;
  background: linear-gradient(180deg, #121826, #0a0e16); border: 1px solid currentColor; border-top: 3px solid var(--role, currentColor);
  box-shadow: 0 0 22px -4px currentColor; font: 700 12px 'Chakra Petch', sans-serif; text-transform: uppercase; }
.rt-fly.mine { color: #45fff0; } .rt-fly.theirs { color: #ff5c8a; }
.rt-fly b { color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rt-fly .mc-cost { display: inline-grid; place-items: center; width: 22px; height: 22px; color: #071018; background: var(--role, currentColor);
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%); }
.rt-fly.r-fighter { --role: #37f5a3; } .rt-fly.r-wall { --role: #6d8bff; } .rt-fly.r-trap { --role: #ffd23f; }
.rt-fly.r-blocker { --role: #6d8bff; } .rt-fly.r-lure { --role: #ff9f43; } .rt-fly.r-answer { --role: #ffd23f; }
.rt-fly.r-trick { --role: #c88dff; } .rt-fly.r-virus { --role: #b6ff3f; } .rt-fly.r-steal { --role: #ff5cd6; }

/* No pointer tilt, no sheen following the pointer (owner, 2026-10-02): one shine sweeps across a
   card when the pointer comes onto it. */
#rt-duel .rt-unit.tilting, #rt-duel .rt-card.tilting:not(.dis), #rt-duel .rt-card.sel.tilting { transform: none; }
#rt-duel .rt-card.sel { transform: translateY(-10px); }
#rt-duel .rt-sheen { opacity: 0; transition: none; mix-blend-mode: screen; background-size: 250% 100%; background-position: 150% 0;
  background-image: linear-gradient(110deg, transparent 35%, rgba(255, 255, 255, 0.07) 44%, rgba(255, 255, 255, 0.24) 50%, rgba(255, 255, 255, 0.07) 56%, transparent 65%); }
#rt-duel .rt-unit:hover .rt-sheen, #rt-duel .rt-card[data-slot]:hover .rt-sheen { animation: rt-shine 0.75s ease-out 1 forwards; }
@keyframes rt-shine { 0% { opacity: 1; background-position: 150% 0; } 85% { opacity: 1; } 100% { opacity: 0; background-position: -50% 0; } }
/* Landing out of the hand: a short flash, no fade. */
#rt-duel .rt-unit.landed { animation: rt-landed 0.35s ease-out; }
@keyframes rt-landed { 0% { filter: brightness(2.2); } 100% { filter: none; } }

/* Channels: no track, no lines — only the pulse, in the lane's colour, gliding through now and
   then (owner, 2026-10-02). */
#rt-duel .rt-chan, #rt-duel .rt-chan.up, #rt-duel .rt-chan.down, #rt-duel .rt-chan.clash, #rt-duel .rt-chan.hold, #rt-duel .rt-chan.idle {
  border: 0; background: none; box-shadow: none !important; width: 4px; }
#rt-duel .rt-chan i { background-image: linear-gradient(180deg, rgba(var(--c), 0) 0%, rgba(var(--c), 0) 40%, rgba(var(--c), 0.75) 50%, rgba(var(--c), 0) 60%, rgba(var(--c), 0) 100%);
  background-size: 100% 300%; filter: drop-shadow(0 0 4px rgba(var(--c), 0.6)); }
#rt-duel .rt-chan.up i { animation: rt-pulse-up calc(var(--sp) * 2) cubic-bezier(.45, 0, .55, 1) infinite; }
#rt-duel .rt-chan.down i { animation: rt-pulse-down calc(var(--sp) * 2) cubic-bezier(.45, 0, .55, 1) infinite; }
#rt-duel .rt-chan.clash i { background-image: radial-gradient(ellipse 100% 14% at 50% 50%, rgba(var(--c), 0.6), transparent 70%); background-size: 100% 100%;
  animation: rt-pulse-still 2.6s ease-in-out infinite; }
/* The pulse crosses in the first half of the cycle, then the lane rests. */
@keyframes rt-pulse-up { 0% { background-position: 0 0%; } 55%, 100% { background-position: 0 100%; } }
@keyframes rt-pulse-down { 0% { background-position: 0 100%; } 55%, 100% { background-position: 0 0%; } }
@keyframes rt-pulse-still { 0%, 100% { opacity: 0; } 50% { opacity: 1; } }

/* Epic and legendary cards keep their own light: no hover shine over it (owner, 2026-10-02). */
#rt-duel .rt-unit.rar-epic .rt-sheen, #rt-duel .rt-unit.rar-legendary .rt-sheen,
#rt-duel .rt-card.rar-epic .rt-sheen, #rt-duel .rt-card.rar-legendary .rt-sheen { display: none; }
/* A fight: two pulses leave the two cards, meet in the middle and go out — not a light standing still. */
#rt-duel .rt-chan.clash i { opacity: 1;
  background-image: linear-gradient(180deg, rgba(var(--c), 0) 0%, rgba(var(--c), 0) 42%, rgba(var(--c), 0.7) 50%, rgba(var(--c), 0) 58%, rgba(var(--c), 0) 100%),
    linear-gradient(180deg, rgba(var(--c), 0) 0%, rgba(var(--c), 0) 42%, rgba(var(--c), 0.7) 50%, rgba(var(--c), 0) 58%, rgba(var(--c), 0) 100%);
  background-size: 100% 300%, 100% 300%; background-repeat: no-repeat; animation: rt-pulse-meet 3s cubic-bezier(.45, 0, .55, 1) infinite; }
@keyframes rt-pulse-meet {
  0% { background-position: 0 100%, 0 0%; opacity: 1; }
  42% { background-position: 0 50%, 0 50%; opacity: 1; }
  52%, 100% { background-position: 0 50%, 0 50%; opacity: 0; } }
/* The final round is marked: nobody full by its EXECUTE and the defence holds. */
#rt-duel .rt-clock { min-width: 230px; }
#rt-duel .rt-clock.final { color: var(--rt-warn); text-shadow: 0 0 12px var(--rt-warn); }

/* Meters beside the board (owner, 2026-10-02): TRACE on the left, BREACH on the right, filling
   upward, next to the lanes — the eye stays on the action and the shots fly a short way. */
#rt-duel .rt-arena { flex: 1; min-height: 0; display: grid; grid-template-columns: 74px minmax(0, 1fr) 74px; gap: 18px; max-width: 1140px; width: 100%; margin: 0 auto; }
#rt-duel .rt-arena > .rt-board { min-height: 0; max-width: none; width: 100%; }
#rt-duel .rt-vmeter { display: flex; flex-direction: column; align-items: center; gap: 2px; min-height: 0; padding: 6px 0; }
#rt-duel .rt-vmeter .vm-word { font: 700 13px 'Chakra Petch', sans-serif; letter-spacing: 0.16em; }
#rt-duel .rt-vmeter .vm-who { font-size: 9px; letter-spacing: 0.18em; color: var(--rt-dim); }
#rt-duel .rt-vmeter .vm-n { height: 22px; line-height: 22px; font: 700 18px 'Chakra Petch', sans-serif; color: #fff; font-variant-numeric: tabular-nums; white-space: nowrap; }
#rt-duel .rt-vmeter .rt-mfc { height: 14px; line-height: 14px; min-width: 0; text-align: center; font-size: 11px; margin: 0; }
#rt-duel .rt-vmeter .rt-bar { flex: 1; width: 16px; height: auto; min-height: 120px; margin-top: 4px; }
#rt-duel .rt-vmeter .rt-bar i { inset: auto 0 0 0; width: auto; height: 0; transition: height 0.45s ease-out; }
#rt-duel .rt-vmeter.breach .vm-word { color: var(--rt-me); }
#rt-duel .rt-vmeter.trace .vm-word { color: var(--rt-foe); }
#rt-duel .rt-vmeter.breach .rt-bar i { background: linear-gradient(0deg, #0f6f6a, var(--rt-me)); }
#rt-duel .rt-vmeter.trace .rt-bar i { background: linear-gradient(0deg, #6f1430, var(--rt-foe)); }
#rt-duel .rt-vmeter.bump .rt-bar { animation: rt-vbump 0.35s ease-out; }
@keyframes rt-vbump { 40% { filter: brightness(1.9); transform: scaleX(1.5); } }
/* The enemy's hand and threads, side by side, in fixed boxes. */
#rt-duel .rt-foe-hand { gap: 26px; }
#rt-duel .fh-cards, #rt-duel .fh-thr { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
#rt-duel .fh-backs { display: inline-flex; width: 160px; }
#rt-duel .fh-thr b { color: var(--rt-foe); font-size: 13px; min-width: 16px; text-align: right; font-variant-numeric: tabular-nums; }
#rt-duel .fh-pips { display: inline-flex; gap: 2px; }
#rt-duel .fh-pips u { display: inline-block; width: 9px; height: 12px; border: 1px solid #3a1f2a; background: #0a1019; text-decoration: none; }
#rt-duel .fh-pips u.on { background: var(--rt-foe); border-color: var(--rt-foe); box-shadow: 0 0 5px rgba(255, 92, 138, 0.6); }
/* No move: the turn word says so, in red. */
#rt-duel .rt-tw.me.nomove { color: #ff2e5f; }

/* The enemy's hand as real card backs (owner, 2026-10-02): bigger, a framed back with a hatched
   ground and a mark, fanned a little — not boxes like the thread pips. */
#rt-duel .rt-foe-hand { height: 40px; }
#rt-duel .fh-backs { width: 250px; height: 36px; align-items: center; justify-content: flex-start; }
#rt-duel .fh-backs i { position: relative; flex: none; width: 24px; height: 33px; margin: 0 -4px 0 0; border: 1px solid #ff5c8a;
  background:
    radial-gradient(circle at 50% 50%, rgba(255, 92, 138, 0.55) 0 3px, transparent 3.5px),
    radial-gradient(circle at 50% 50%, transparent 0 6px, rgba(255, 92, 138, 0.5) 6.5px 7.5px, transparent 8px),
    repeating-linear-gradient(135deg, rgba(255, 92, 138, 0.16) 0 2px, transparent 2px 5px),
    linear-gradient(180deg, #2a0f1b, #120810);
  box-shadow: inset 0 0 0 2px #120810, inset 0 0 0 3px rgba(255, 92, 138, 0.35), 0 2px 6px rgba(0, 0, 0, 0.6);
  clip-path: polygon(4px 0, 100% 0, 100% calc(100% - 4px), calc(100% - 4px) 100%, 0 100%, 0 4px); }
#rt-duel .fh-backs i:nth-child(odd) { transform: rotate(-3deg); }
#rt-duel .fh-backs i:nth-child(even) { transform: rotate(3deg) translateY(1px); }

/* The background terminal (owner, 2026-10-02): decoration only — two faint shells in the empty
   corners, a shade off the background, a cursor blinking; and a slow live dot by the title. */
#rt-duel .rt-bgterm { position: absolute; z-index: -1; pointer-events: none; width: 420px; overflow: hidden; white-space: pre;
  font: 11px/16px 'IBM Plex Mono', Consolas, monospace; color: rgba(110, 170, 190, 0.11); }
#rt-duel .rt-bgterm.top { top: 120px; left: 120px; }
#rt-duel .rt-bgterm.low { bottom: 170px; right: 120px; text-align: left; }
#rt-duel .rt-bgcur { color: rgba(69, 255, 240, 0.28); animation: rt-cursor 1.05s steps(2) infinite; }
@keyframes rt-cursor { 50% { opacity: 0; } }
#rt-duel .rt-live { display: inline-block; width: 7px; height: 7px; margin-right: 8px; border-radius: 50%; vertical-align: 2px;
  background: var(--rt-good); box-shadow: 0 0 6px var(--rt-good); animation: rt-live 2.4s ease-in-out infinite; }
@keyframes rt-live { 50% { opacity: 0.25; box-shadow: none; } }
#rt-duel .rt-bgterm.top { top: 104px; left: 240px; }
#rt-duel .rt-bgterm.low { bottom: 168px; right: 150px; }

/* Lines from the duel itself: a touch brighter than the filler, still in the background. */
#rt-duel .rt-bgterm .ev { color: rgba(140, 200, 215, 0.24); }
#rt-duel .rt-bgterm.top .ev { color: rgba(255, 140, 170, 0.24); }
/* Fixed room for the shells (nine lines), so whether they fit can be measured. */
#rt-duel .rt-bgterm { height: 160px; }
#rt-duel .rt-bgterm.low { display: flex; flex-direction: column; justify-content: flex-end; }
#rt-duel .rt-bgterm.low { bottom: 196px; }
#rt-duel .rt-bgterm.low { right: 240px; }

/* Scores as circuits (owner, 2026-10-02): a thin board trace from the card to its meter, 45° corners
   and vias, a bright pulse running it; the trace fades once the meter has filled. */
#rt-circuit { position: fixed; inset: 0; width: 100vw; height: 100vh; z-index: 428; pointer-events: none; overflow: visible; }
#rt-circuit .rt-trace { transition: opacity 0.4s ease-out; }
#rt-circuit .rt-trace.out { opacity: 0; }
#rt-circuit .tr-line { fill: none; stroke: rgba(var(--c), 0.28); stroke-width: 1.5; stroke-linejoin: miter; }
#rt-circuit .tr-pulse { fill: none; stroke: rgb(var(--c)); stroke-width: 2.5; stroke-linecap: round; filter: drop-shadow(0 0 4px rgb(var(--c))); }
#rt-circuit .tr-via { fill: #0a0f18; stroke: rgba(var(--c), 0.7); stroke-width: 1.2; }

/* A mine in the lane (TRAPNET, Minefield): in plain sight on the defending slot. */
#rt-duel .rt-slot.mined::after { content: attr(data-mine); position: absolute; left: 50%; bottom: 6px; transform: translateX(-50%); z-index: 2; pointer-events: none;
  padding: 1px 6px; font: 700 10px 'IBM Plex Mono', Consolas, monospace; letter-spacing: 0.06em; color: #ffd23f; background: #1a1508;
  border: 1px solid #ffd23f; white-space: nowrap; max-width: calc(100% - 8px); overflow: hidden; text-overflow: ellipsis; box-sizing: border-box; }

/* Whose meter it is follows the seat (stage 3): yours cyan, the enemy's red, wherever it stands. */
#rt-duel .rt-vmeter.mine .vm-word { color: var(--rt-me); }
#rt-duel .rt-vmeter.theirs .vm-word { color: var(--rt-foe); }
#rt-duel .rt-vmeter.mine .rt-bar i { background: linear-gradient(0deg, #0f6f6a, var(--rt-me)); box-shadow: 0 0 12px var(--rt-me); }
#rt-duel .rt-vmeter.theirs .rt-bar i { background: linear-gradient(0deg, #6f1430, var(--rt-foe)); box-shadow: 0 0 12px var(--rt-foe); }

/* Why the duel was lost (owner, 2026-10-03): where the points came from, and what to change. */
#rt-duel .rt-end-why { margin-top: 10px; font-size: 13px; color: var(--rt-text); letter-spacing: .04em; }
#rt-duel .rt-end-hint { margin-top: 4px; font-size: 14px; color: var(--rt-warn); letter-spacing: .04em; }
#rt-duel .rt-end-hint b { margin-right: 6px; padding: 0 5px; border: 1px solid var(--rt-warn); font-size: 11px; letter-spacing: .12em; }

/* ARM (card rework): an armed lane reads like a mine, in the arming side's colour; counters and a
   sinkhole show beside the threads they were paid from. */
#rt-duel .rt-slot.armed::after { color: #ffd23f; border-color: #ffd23f; }
#rt-duel .fh-arm, #rt-duel .rt-myarm { margin-left: 10px; color: #ffd23f; font-size: 10px; letter-spacing: 0.12em; white-space: nowrap; }

/* Performance (owner, 2026-10-03: "the duel feels heavy again"). The always-running effects
   repainted every frame: lane pulses moved a background under a drop-shadow, epic frames turned a
   conic gradient through a custom property, legendary and syndicate cards pulsed a box-shadow and
   swept a blended gradient. With the reworked NPC decks more rare and epic cards stand on the
   board. Now they animate only transform, opacity and filter, which the compositor runs without a
   repaint; the look stays close. */
#rt-duel .rt-chan i { top: 0; bottom: auto; height: 300%; background-size: 100% 100%; will-change: transform; }
#rt-duel .rt-chan.up i { animation: rt-pulse-up-t calc(var(--sp) * 2) cubic-bezier(.45, 0, .55, 1) infinite; }
#rt-duel .rt-chan.down i { animation: rt-pulse-down-t calc(var(--sp) * 2) cubic-bezier(.45, 0, .55, 1) infinite; }
#rt-duel .rt-chan.clash i { height: 100%; }
@keyframes rt-pulse-up-t { 0% { transform: translateY(0); } 55%, 100% { transform: translateY(-66.667%); } }
@keyframes rt-pulse-down-t { 0% { transform: translateY(-66.667%); } 55%, 100% { transform: translateY(0); } }
#rt-duel .rt-unit.rar-epic::after, #rt-duel .rt-card.rar-epic::after {
  background: conic-gradient(from 200deg, transparent 0 70%, rgba(210, 170, 255, 0.45) 84%, transparent 96%);
  animation: rt-glow 2.5s ease-in-out infinite alternate; will-change: opacity; }
#rt-duel .rt-unit.rar-legendary, #rt-duel .rt-card.rar-legendary {
  box-shadow: inset 0 0 26px rgba(245, 200, 66, 0.35), 0 0 20px rgba(245, 180, 40, 0.4); animation: rt-legend-f 2.6s ease-in-out infinite; }
#rt-duel .rt-unit.rar-legendary::before, #rt-duel .rt-card.rar-legendary::before {
  background-size: 100% 100%; background-position: 50% 0; mix-blend-mode: normal; animation: rt-glow 1.7s ease-in-out infinite alternate; will-change: opacity; }
#rt-duel .rt-unit.syn, #rt-duel .rt-card.syn {
  box-shadow: inset 0 0 14px rgba(var(--syn), 0.25), 0 0 12px rgba(var(--syn), 0.35); animation: rt-legend-f 3.2s ease-in-out infinite; }
@keyframes rt-glow { from { opacity: 0.25; } to { opacity: 1; } }
@keyframes rt-legend-f { 50% { filter: brightness(1.18); } }
@keyframes rt-live { 50% { opacity: 0.25; } }
/* Under the duel the page's own looping effects (map flicker, glowing buttons, banners) pause:
   the duel covers them, and some repaint every frame. */
body.rt-open > :not(#rt-duel), body.rt-open > :not(#rt-duel) *,
body.rt-open > :not(#rt-duel)::before, body.rt-open > :not(#rt-duel)::after,
body.rt-open > :not(#rt-duel) *::before, body.rt-open > :not(#rt-duel) *::after { animation-play-state: paused !important; }

/* TRAINING RELAY coach (owner, 2026-10-03): one bubble beside what it talks about. */
#rt-coach { position: fixed; z-index: 2147483000; max-width: 300px; padding: 10px 12px; background: #0d1626; border: 1px solid var(--rt-warn, #f0a020);
  box-shadow: 0 0 18px rgba(240, 160, 32, 0.35); color: #e6eef5; font: 12px/1.45 'IBM Plex Mono', Consolas, monospace; }
#rt-coach b { display: block; margin-bottom: 4px; color: #f0a020; font-size: 10px; letter-spacing: 0.16em; }
#rt-coach p { margin: 0; }
#rt-coach .rt-btn { margin-top: 8px; } /* the bubble sits outside #rt-duel: the duel button look is shared above */
#rt-duel .rt-coach-focus { outline: 2px solid #f0a020; outline-offset: 3px; }

/* Their move (owner, 2026-10-06: waiting did not read as waiting): the hand dims, the footer blinks. */
#rt-duel.foe-move .rt-hand, #rt-duel.hand-frozen .rt-hand { opacity: 0.45; filter: saturate(0.4); transition: opacity 0.25s, filter 0.25s; }
#rt-duel.hand-frozen .rt-hand { pointer-events: none; }
/* Frozen while the cards fight (owner, 2026-10-10: "my cards still glow as if I could play them"):
   grey, no rarity glow or motion, a thin layer of ice over each card. */
#rt-duel.hand-frozen .rt-hand { opacity: 0.6; filter: grayscale(1) brightness(0.65); }
#rt-duel.hand-frozen .rt-card { animation: none !important; box-shadow: none !important; transform: none !important; outline: none !important; cursor: default; }
#rt-duel.hand-frozen .rt-card:not(.empty)::after { content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: linear-gradient(140deg, rgba(170, 215, 255, 0.22), rgba(170, 215, 255, 0.04) 55%, rgba(170, 215, 255, 0.16));
  border: 1px solid rgba(170, 215, 255, 0.45); animation: none; opacity: 1; filter: none; }
#rt-duel.hand-frozen .rt-card::before { animation: none !important; }
#rt-duel .rt-hint.wait { color: var(--rt-foe); animation: rt-wait 1.4s ease-in-out infinite; }
@keyframes rt-wait { 50% { opacity: 0.35; } }
#rt-duel .rt-tw.foe.on { animation: rt-wait 1.4s ease-in-out infinite; }
/* The last seconds of your move: the clock itself warns — no red frame on the screen (owner,
   2026-10-07: "looks like you're wounded"). The digits and the bar turn red and pulse, faster under 1.5 s. */
#rt-duel.clock-low .rt-turn-n { color: #ff5c7a; text-shadow: 0 0 12px rgba(255, 46, 95, 0.8); animation: rt-clock-low 0.8s ease-in-out infinite; }
#rt-duel.clock-low .rt-turn-bar i { background: linear-gradient(90deg, #6f1430, #ff2e5f); box-shadow: 0 0 12px #ff2e5f; }
#rt-duel.clock-crit .rt-turn-n { animation-duration: 0.4s; }
@keyframes rt-clock-low { 50% { transform: scale(1.12); opacity: 0.7; } }
/* An armed lane in plain sight for both seats (owner, 2026-10-06: "nothing shows the script is
   there"): the whole slot is fenced off, the tag sits in the middle. */
#rt-duel .rt-slot.armed { outline: 2px dashed #ffd23f; outline-offset: -5px; background-image: repeating-linear-gradient(135deg, rgba(255, 210, 63, 0.07) 0 10px, transparent 10px 20px); }
#rt-duel .rt-slot.armed::after { top: 50%; bottom: auto; transform: translate(-50%, -50%); padding: 3px 10px; font-size: 12px;
  box-shadow: 0 0 14px rgba(255, 210, 63, 0.45); animation: rt-wait 1.6s ease-in-out infinite; }
/* REBOOTING (owner, 2026-10-06): played where its side lost a unit this round — out of this EXECUTE. */
#rt-duel .rt-unit.rebooting { opacity: 0.5; outline: 2px dashed rgba(255, 92, 138, 0.8); outline-offset: -4px; filter: grayscale(0.6); }

/* --- Whose move, at a glance (owner, 2026-10-07) ----------------------------------------------
   The half whose move it is glows and is swept by a scan line — cyan for you, red for them — and
   names itself; the other half steps back. */
#rt-duel .rt-row { position: relative; transition: filter 0.3s, opacity 0.3s; }
#rt-duel .rt-row::before { content: ''; position: absolute; inset: -6px; pointer-events: none; z-index: 0; border: 1px solid transparent;
  opacity: 0; transition: opacity 0.3s; background-repeat: no-repeat; background-size: 100% 38%; }
#rt-duel .rt-row::after { position: absolute; left: 0; pointer-events: none; z-index: 2; opacity: 0; transition: opacity 0.3s;
  font: 700 10px 'IBM Plex Mono', Consolas, monospace; letter-spacing: 0.16em; white-space: nowrap; }
/* The words come from data-shell (rt-duel.js), translated (docs/I18N.md). */
#rt-duel .rt-row.mine::after { content: attr(data-shell); bottom: -16px; color: var(--rt-me); text-shadow: 0 0 8px var(--rt-me); }
#rt-duel .rt-row.foe::after { content: attr(data-shell); top: -16px; color: var(--rt-foe); text-shadow: 0 0 8px var(--rt-foe); }
#rt-duel.my-move .rt-row.mine::before { opacity: 1; border-color: rgba(69, 255, 240, 0.55);
  box-shadow: 0 0 22px rgba(69, 255, 240, 0.25), inset 0 0 26px rgba(69, 255, 240, 0.08);
  background-image: linear-gradient(180deg, transparent, rgba(69, 255, 240, 0.12) 85%, rgba(69, 255, 240, 0.45));
  animation: rt-scan-down 2.4s linear infinite; }
#rt-duel.foe-move .rt-row.foe::before { opacity: 1; border-color: rgba(255, 46, 95, 0.6);
  box-shadow: 0 0 22px rgba(255, 46, 95, 0.28), inset 0 0 26px rgba(255, 46, 95, 0.1);
  background-image: linear-gradient(0deg, transparent, rgba(255, 46, 95, 0.12) 85%, rgba(255, 46, 95, 0.5));
  animation: rt-scan-up 2.4s linear infinite; }
#rt-duel.my-move .rt-row.mine::after, #rt-duel.foe-move .rt-row.foe::after { opacity: 1; animation: rt-wait 1.6s ease-in-out infinite; }
#rt-duel.my-move .rt-row.foe, #rt-duel.foe-move .rt-row.mine { filter: saturate(0.55) brightness(0.72); }
@keyframes rt-scan-down { from { background-position: 0 -40%; } to { background-position: 0 140%; } }
@keyframes rt-scan-up { from { background-position: 0 140%; } to { background-position: 0 -40%; } }

/* The lane shells: an empty lane types a little; game lines brighter. Faint (owner, 2026-10-09):
   decoration only, never competing with the cards. */
#rt-duel .rt-empty { position: absolute; inset: 0; margin: 0; overflow: hidden; }
#rt-duel .rt-slot > .rt-empty ~ * { position: relative; z-index: 1; }
#rt-duel .rt-eterm { position: absolute; left: 8px; right: 8px; bottom: 26px; font: 10px/1.45 'IBM Plex Mono', Consolas, monospace;
  text-align: left; white-space: nowrap; overflow: hidden; pointer-events: none; }
#rt-duel .rt-eterm div { overflow: hidden; text-overflow: ellipsis; opacity: 0.14; animation: rt-eline 0.35s steps(6, end); }
#rt-duel .rt-eterm div:last-child { opacity: 0.24; }
#rt-duel .rt-eterm div.ev { opacity: 0.34; font-weight: 700; }
#rt-duel .rt-slot[data-side] .rt-eterm { color: rgba(69, 255, 240, 0.6); }
#rt-duel .rt-row.foe .rt-eterm { color: rgba(255, 92, 138, 0.6); }
#rt-duel .rt-elbl { position: absolute; left: 0; right: 0; bottom: 8px; text-align: center; }
@keyframes rt-eline { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }

/* Port numbers on the lane labels. */
#rt-duel .rt-pnum { font-style: normal; color: var(--rt-dim); opacity: 0.8; letter-spacing: 0.04em; }
#rt-duel .rt-port.you .rt-pnum { color: var(--rt-me); } #rt-duel .rt-port.them .rt-pnum { color: var(--rt-foe); }

/* A played unit's command over its lane. */
.rt-tag.cmd { color: #45fff0; font: 700 12px 'IBM Plex Mono', Consolas, monospace; text-shadow: 0 0 10px rgba(69, 255, 240, 0.8); }
.rt-tag.foecmd { color: #ff5c8a; font: 700 12px 'IBM Plex Mono', Consolas, monospace; text-shadow: 0 0 10px rgba(255, 46, 95, 0.8); }

/* --- EXECUTE as an attack (owner, 2026-10-07) --------------------------------------------------- */
#rt-duel .rt-board { position: relative; }
#rt-duel .rt-exec-sweep { position: absolute; inset: -8px; pointer-events: none; z-index: 6; overflow: hidden; }
#rt-duel .rt-exec-sweep::before { content: ''; position: absolute; left: 0; right: 0; height: 3px; top: 0;
  background: linear-gradient(90deg, transparent, #fff 20%, #45fff0 50%, #fff 80%, transparent);
  box-shadow: 0 0 18px #45fff0, 0 0 40px rgba(69, 255, 240, 0.6); animation: rt-sweep 0.75s cubic-bezier(.3, 0, .7, 1) forwards; }
#rt-duel .rt-exec-sweep span { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  font: 700 34px 'Chakra Petch', sans-serif; letter-spacing: 0.4em; color: #fff;
  text-shadow: -2px 0 #ff2e5f, 2px 0 #45fff0, 0 0 20px rgba(69, 255, 240, 0.8); animation: rt-exec-word 0.9s steps(1, end) forwards; }
@keyframes rt-sweep { from { top: 0; opacity: 1; } 90% { opacity: 1; } to { top: 100%; opacity: 0; } }
@keyframes rt-exec-word { 0% { opacity: 0; } 8% { opacity: 1; transform: translate(-52%, -50%); } 14% { transform: translate(-48%, -50%); }
  20% { transform: translate(-50%, -50%); } 70% { opacity: 1; } 78% { opacity: 0.2; } 84% { opacity: 0.9; } 100% { opacity: 0; } }

/* Packets into a port, and the port lighting up. */
.rt-packet { position: fixed; z-index: 429; width: 7px; height: 7px; pointer-events: none; border-radius: 1px; }
.rt-packet.mine { background: #45fff0; box-shadow: 0 0 8px #45fff0, 0 0 16px rgba(69, 255, 240, 0.7); }
.rt-packet.foe { background: #ff2e5f; box-shadow: 0 0 8px #ff2e5f, 0 0 16px rgba(255, 46, 95, 0.7); }
#rt-duel .rt-slot.breached { animation: rt-port-hit 0.6s ease-out; }
#rt-duel .rt-slot.traced { animation: rt-port-hit-foe 0.6s ease-out; }
@keyframes rt-port-hit { 0% { box-shadow: inset 0 0 0 2px #45fff0, 0 0 30px rgba(69, 255, 240, 0.8); background: rgba(69, 255, 240, 0.18); } 100% { box-shadow: none; background: transparent; } }
@keyframes rt-port-hit-foe { 0% { box-shadow: inset 0 0 0 2px #ff2e5f, 0 0 30px rgba(255, 46, 95, 0.8); background: rgba(255, 46, 95, 0.2); } 100% { box-shadow: none; background: transparent; } }

/* A hit glitches the unit: a jitter and a colour split. */
#rt-duel .rt-unit.glitch { animation: rt-glitch 0.32s steps(2, end); }
@keyframes rt-glitch {
  0% { transform: translate(0, 0); filter: none; }
  20% { transform: translate(-4px, 1px); filter: drop-shadow(3px 0 0 rgba(255, 46, 95, 0.9)) drop-shadow(-3px 0 0 rgba(69, 255, 240, 0.9)); }
  40% { transform: translate(3px, -1px); clip-path: inset(10% 0 55% 0); }
  60% { transform: translate(-2px, 0); clip-path: inset(50% 0 8% 0); filter: drop-shadow(-3px 0 0 rgba(255, 46, 95, 0.9)) drop-shadow(3px 0 0 rgba(69, 255, 240, 0.9)); }
  80% { transform: translate(1px, 0); clip-path: none; }
  100% { transform: translate(0, 0); filter: none; } }

/* The duel's last word. */
#rt-duel .rt-outcome-flash { position: absolute; inset: 0; z-index: 7; display: grid; place-items: center; pointer-events: none;
  background: rgba(4, 6, 10, 0.55); animation: rt-of-bg 1.1s ease-out forwards; }
#rt-duel .rt-outcome-flash span { position: relative; font: 700 56px 'Chakra Petch', sans-serif; letter-spacing: 0.22em; animation: rt-of-word 1.1s steps(1, end) forwards; }
#rt-duel .rt-outcome-flash.won span { color: #45fff0; text-shadow: -3px 0 #ff2e5f, 3px 0 #fff, 0 0 30px rgba(69, 255, 240, 0.9); }
#rt-duel .rt-outcome-flash.lost span { color: #ff2e5f; text-shadow: -3px 0 #45fff0, 3px 0 #fff, 0 0 30px rgba(255, 46, 95, 0.9); }
@keyframes rt-of-bg { 0% { opacity: 0; } 10% { opacity: 1; } 85% { opacity: 1; } 100% { opacity: 0; } }
@keyframes rt-of-word { 0% { opacity: 0; } 10% { opacity: 1; transform: translateX(-6px); } 16% { transform: translateX(5px); } 22% { transform: none; }
  60% { opacity: 1; } 66% { opacity: 0.3; } 72% { opacity: 1; } 100% { opacity: 1; } }

/* --- the handover and the fights (owner, 2026-10-07) -------------------------------------------- */
/* The card just played commits: a lock-in flash. */
#rt-duel .rt-unit.applied { animation: rt-applied 0.55s ease-out; }
#rt-duel .rt-unit.applied-foe { animation: rt-applied-foe 0.55s ease-out; }
@keyframes rt-applied { 0% { box-shadow: 0 0 0 0 rgba(69, 255, 240, 0); filter: brightness(1); }
  25% { box-shadow: 0 0 0 3px #45fff0, 0 0 28px rgba(69, 255, 240, 0.85); filter: brightness(1.5); transform: scale(1.04); }
  100% { box-shadow: 0 0 0 0 rgba(69, 255, 240, 0); filter: brightness(1); transform: scale(1); } }
@keyframes rt-applied-foe { 0% { box-shadow: 0 0 0 0 rgba(255, 46, 95, 0); filter: brightness(1); }
  25% { box-shadow: 0 0 0 3px #ff2e5f, 0 0 28px rgba(255, 46, 95, 0.85); filter: brightness(1.5); transform: scale(1.04); }
  100% { box-shadow: 0 0 0 0 rgba(255, 46, 95, 0); filter: brightness(1); transform: scale(1); } }
/* Then the turn crosses the board: a band travels from the half that moved to the one that moves now. */
#rt-duel .rt-handover { position: absolute; left: -8px; right: -8px; height: 46px; pointer-events: none; z-index: 5; }
#rt-duel .rt-handover.to-foe { background: linear-gradient(0deg, transparent, rgba(255, 46, 95, 0.35) 50%, transparent);
  border-top: 1px solid rgba(255, 46, 95, 0.8); animation: rt-hand-up 0.75s cubic-bezier(.5, 0, .3, 1) 0.25s both; }
#rt-duel .rt-handover.to-me { background: linear-gradient(180deg, transparent, rgba(69, 255, 240, 0.32) 50%, transparent);
  border-bottom: 1px solid rgba(69, 255, 240, 0.8); animation: rt-hand-down 0.75s cubic-bezier(.5, 0, .3, 1) 0.25s both; }
@keyframes rt-hand-up { from { top: calc(100% - 46px); opacity: 0; } 15% { opacity: 1; } 85% { opacity: 1; } to { top: 0; opacity: 0; } }
@keyframes rt-hand-down { from { top: 0; opacity: 0; } 15% { opacity: 1; } 85% { opacity: 1; } to { top: calc(100% - 46px); opacity: 0; } }
/* The new half lights after the band reaches it. */
#rt-duel.my-move .rt-row.mine::before, #rt-duel.foe-move .rt-row.foe::before,
#rt-duel.my-move .rt-row.mine::after, #rt-duel.foe-move .rt-row.foe::after { transition-delay: 0.6s; }

/* Fights by the card. */
.rt-slash { position: fixed; z-index: 429; width: 110px; height: 4px; pointer-events: none; --sc: #45fff0;
  background: linear-gradient(90deg, transparent, #fff 40%, var(--sc) 60%, transparent); box-shadow: 0 0 14px var(--sc);
  transform: translate(-50%, -50%) rotate(-28deg) scaleX(0); animation: rt-slash 0.34s cubic-bezier(.2, .8, .3, 1) forwards; }
.rt-slash.foe { --sc: #ff2e5f; }
@keyframes rt-slash { 0% { transform: translate(-50%, -50%) rotate(-28deg) scaleX(0); opacity: 1; }
  45% { transform: translate(-50%, -50%) rotate(-28deg) scaleX(1); opacity: 1; } 100% { transform: translate(-50%, -50%) rotate(-28deg) scaleX(1.2); opacity: 0; } }
.rt-ring { position: fixed; z-index: 429; width: 30px; height: 30px; border-radius: 50%; pointer-events: none; --rc: #45fff0;
  border: 3px solid var(--rc); box-shadow: 0 0 16px var(--rc), inset 0 0 10px var(--rc);
  transform: translate(-50%, -50%) scale(0.3); animation: rt-ring 0.5s ease-out forwards; }
@keyframes rt-ring { to { transform: translate(-50%, -50%) scale(3.4); opacity: 0; border-width: 1px; } }
.rt-pixel { position: fixed; z-index: 429; width: 5px; height: 5px; pointer-events: none; box-shadow: 0 0 6px currentColor; }

/* The receipt draws itself: the rule is drawn left to right as the numbers decrypt (owner, 2026-10-07). */
#rt-duel .hcol.on.draw .rule { animation: rt-rule-draw 0.45s ease-out 0.12s both; transform-origin: right center; }
@keyframes rt-rule-draw { from { transform: scaleX(0); opacity: 0; } to { transform: scaleX(1); opacity: 1; } }
#rt-duel .hcol .r1, #rt-duel .hcol .r2 { min-width: 2ch; text-align: right; }

/* --- fights that read (owner, 2026-10-07) -------------------------------------------------------- */
/* The striking unit leaves a light trail. */
#rt-duel .rt-unit.lunge { animation: rt-lunge 0.56s ease-out; }
#rt-duel .rt-unit.lunge-foe { animation: rt-lunge-foe 0.56s ease-out; }
@keyframes rt-lunge { 0% { box-shadow: none; } 40% { box-shadow: 0 -14px 26px rgba(69, 255, 240, 0.55), 0 0 0 2px #45fff0; filter: brightness(1.35); } 100% { box-shadow: none; filter: none; } }
@keyframes rt-lunge-foe { 0% { box-shadow: none; } 40% { box-shadow: 0 14px 26px rgba(255, 46, 95, 0.55), 0 0 0 2px #ff2e5f; filter: brightness(1.35); } 100% { box-shadow: none; filter: none; } }
/* The ♥ taken: a big number that pops, bounces and floats away. */
.rt-dmg { position: fixed; z-index: 430; pointer-events: none; transform: translate(-50%, -50%);
  font: 900 40px 'Chakra Petch', sans-serif; letter-spacing: 0.02em; animation: rt-dmg 1.05s cubic-bezier(.2, .8, .3, 1) forwards; }
.rt-dmg.hurt { color: #ff2e5f; text-shadow: 0 0 2px #fff, 0 0 18px rgba(255, 46, 95, 0.95), 3px 3px 0 #2a0610; }
.rt-dmg.dealt { color: #ffd23f; text-shadow: 0 0 2px #fff, 0 0 18px rgba(255, 210, 63, 0.95), 3px 3px 0 #2a1f04; }
@keyframes rt-dmg {
  0% { transform: translate(-50%, -50%) scale(0.3); opacity: 0; }
  15% { transform: translate(-50%, -60%) scale(1.5); opacity: 1; }
  30% { transform: translate(-50%, -62%) scale(1); }
  70% { transform: translate(-50%, -120%) scale(1); opacity: 1; }
  100% { transform: translate(-50%, -170%) scale(0.9); opacity: 0; } }
/* The ♥ on the unit flashes while it counts down. */
#rt-duel .hcol .h.hp-hit { animation: rt-hp-hit 0.5s ease-out; }
@keyframes rt-hp-hit { 0% { color: #fff; text-shadow: 0 0 12px #ff2e5f; transform: scale(1.35); } 100% { transform: scale(1); } }

/* --- the energy taken, visible (owner, 2026-10-07) ----------------------------------------------- */
/* The ♥ bar: a segment a point. */
#rt-duel .rt-hpbar { display: flex; gap: 2px; height: 7px; margin-top: 2px; }
#rt-duel .rt-hpbar i { flex: 1; min-width: 0; background: rgba(255, 255, 255, 0.07); border: 1px solid rgba(255, 255, 255, 0.08); transition: background 0.15s; }
#rt-duel .rt-unit.me .rt-hpbar i.on { background: #37f5a3; border-color: #37f5a3; box-shadow: 0 0 6px rgba(55, 245, 163, 0.6); }
#rt-duel .rt-unit.foe .rt-hpbar i.on { background: #ff5c8a; border-color: #ff5c8a; box-shadow: 0 0 6px rgba(255, 92, 138, 0.6); }
#rt-duel .rt-hpbar.low i.on { animation: rt-hp-low 0.9s ease-in-out infinite; }
@keyframes rt-hp-low { 50% { opacity: 0.45; } }
/* A segment lost: it flashes white and shatters. */
#rt-duel .rt-hpbar i.lost { animation: rt-seg-break 0.55s ease-out forwards; }
@keyframes rt-seg-break { 0% { background: #fff; box-shadow: 0 0 12px #fff; transform: none; }
  40% { background: #fff; transform: translateY(-3px) scale(1.3, 0.6); opacity: 1; }
  100% { background: transparent; transform: translateY(6px) scale(0.4); opacity: 0; } }
/* The energy flying into the attacker. */
.rt-orb { position: fixed; z-index: 430; width: 10px; height: 10px; border-radius: 50%; pointer-events: none; }
.rt-orb.mine { background: radial-gradient(circle, #fff 0 25%, #37f5a3 55%, transparent 72%); box-shadow: 0 0 12px #37f5a3, 0 0 22px rgba(55, 245, 163, 0.6); }
.rt-orb.foe { background: radial-gradient(circle, #fff 0 25%, #ff2e5f 55%, transparent 72%); box-shadow: 0 0 12px #ff2e5f, 0 0 22px rgba(255, 46, 95, 0.6); }
/* The attacker takes it in. */
#rt-duel .rt-unit.absorb { animation: rt-absorb 0.5s ease-out; }
#rt-duel .rt-unit.absorb-foe { animation: rt-absorb-foe 0.5s ease-out; }
@keyframes rt-absorb { 0% { box-shadow: 0 0 0 0 rgba(55, 245, 163, 0); } 35% { box-shadow: 0 0 0 3px #37f5a3, 0 0 30px rgba(55, 245, 163, 0.85); filter: brightness(1.4); } 100% { box-shadow: none; filter: none; } }
@keyframes rt-absorb-foe { 0% { box-shadow: 0 0 0 0 rgba(255, 46, 95, 0); } 35% { box-shadow: 0 0 0 3px #ff2e5f, 0 0 30px rgba(255, 46, 95, 0.85); filter: brightness(1.4); } 100% { box-shadow: none; filter: none; } }

/* --- 3D board, variant A (owner, 2026-10-08) -------------------------------------------------------
   Since the same day: the FLAT variant — the board stays flat (no tilt, no table grid: owner); the
   units are the preview's slabs — a thin edge, a light shadow — that bob a little and lean toward
   the mouse. Always on (the toggle went, owner 2026-10-08). */
#rt-duel.d3 .rt-board { transform-style: preserve-3d; }
#rt-duel.d3 .rt-row, #rt-duel.d3 .rt-slot { transform-style: preserve-3d; }
/* Each slot is its own small stage, so a card leans in its own perspective, as in the preview. */
#rt-duel.d3 .rt-slot { perspective: 900px; }
/* A slab: the face stands --slab above the table; four walls run down to it; a shadow lies on it.
   Overflow, isolation and the sheen would flatten it, so they step aside in 3D. */
#rt-duel.d3 .rt-unit { --slab: 16px; --edge: color-mix(in srgb, var(--rt-me) 45%, #03060a); transform: translateZ(var(--slab));
  transform-style: preserve-3d; overflow: visible; isolation: auto; transition: translate 0.2s ease-out, rotate 0.2s ease-out; }
#rt-duel.d3 .rt-unit.foe { --edge: color-mix(in srgb, var(--rt-foe) 45%, #03060a); }
#rt-duel.d3 .rt-unit .rt-sheen { display: none; }
#rt-duel .rt-edge, #rt-duel .rt-ushadow { display: none; }
#rt-duel.d3 .rt-edge { display: block; position: absolute; pointer-events: none; background: var(--edge); }
#rt-duel.d3 .rt-edge.eb { left: -1px; right: -1px; top: calc(100% + 1px); height: var(--slab); transform-origin: top; transform: rotateX(-90deg);
  background: linear-gradient(180deg, var(--edge), color-mix(in srgb, var(--edge) 60%, #000)); }
#rt-duel.d3 .rt-edge.et { left: -1px; right: -1px; bottom: calc(100% + 1px); height: var(--slab); transform-origin: bottom; transform: rotateX(90deg); filter: brightness(1.5); }
#rt-duel.d3 .rt-edge.el { top: -1px; bottom: -1px; right: calc(100% + 1px); width: var(--slab); transform-origin: right; transform: rotateY(-90deg); filter: brightness(0.75); }
#rt-duel.d3 .rt-edge.er { top: -1px; bottom: -1px; left: calc(100% + 1px); width: var(--slab); transform-origin: left; transform: rotateY(90deg); filter: brightness(0.75); }
#rt-duel.d3 .rt-ushadow { display: block; position: absolute; inset: 6% 4% -4%; pointer-events: none; transform: translateZ(calc(-1 * var(--slab) - 1px));
  background: radial-gradient(ellipse, rgba(0, 0, 0, 0.8), transparent 70%); filter: blur(7px); }
/* In 3D the waiting half is not dimmed with a filter (a filter flattens it): the active half's glow says whose move. */
#rt-duel.d3.my-move .rt-row.foe, #rt-duel.d3.foe-move .rt-row.mine { filter: none; }
/* Idle: a slow bob, out of step lane by lane. */
#rt-duel.d3 .rt-slot .rt-unit { animation: rt-bob 3.6s ease-in-out infinite; }
#rt-duel.d3 .rt-slot:nth-child(2) .rt-unit { animation-delay: -0.7s; } #rt-duel.d3 .rt-slot:nth-child(3) .rt-unit { animation-delay: -1.4s; }
#rt-duel.d3 .rt-slot:nth-child(4) .rt-unit { animation-delay: -2.1s; } #rt-duel.d3 .rt-slot:nth-child(5) .rt-unit { animation-delay: -2.8s; }
@keyframes rt-bob { 0%, 100% { transform: translateZ(var(--slab)); } 50% { transform: translateZ(calc(var(--slab) + 6px)); } }
/* The hit and glitch animations take the transform for their moment; the bob comes back after. */
#rt-duel.d3 .rt-unit.glitch, #rt-duel.d3 .rt-unit.lunge, #rt-duel.d3 .rt-unit.lunge-foe { animation-delay: 0s; }
@media (prefers-reduced-motion: reduce) { #rt-duel.d3 .rt-slot .rt-unit { animation: none; } }
/* 3D units dressed like the preview (owner, 2026-10-08, design/duel-3d-preview.html): one frame in
   the side's colour with a soft glow, the dark diagonal face, a thin coloured edge, a light shadow. */
#rt-duel.d3 .rt-unit { --slab: 10px; --side: var(--rt-me);
  border: 1px solid color-mix(in srgb, var(--side) 70%, transparent);
  background: linear-gradient(160deg, #0f1c2c 0%, #0a121d 55%, #070c14 100%);
  box-shadow: 0 0 18px color-mix(in srgb, var(--side) 25%, transparent), inset 0 0 20px color-mix(in srgb, var(--side) 10%, transparent); }
#rt-duel.d3 .rt-unit.foe { --side: var(--rt-foe); }
#rt-duel.d3 .rt-unit, #rt-duel.d3 .rt-unit.foe { --edge: color-mix(in srgb, var(--side) 35%, #05080d); }
#rt-duel.d3 .rt-edge.eb { background: color-mix(in srgb, var(--side) 55%, #05080d); }
#rt-duel.d3 .rt-ushadow { background: radial-gradient(ellipse, rgba(0, 0, 0, 0.55), transparent 70%); filter: blur(5px); }
/* Flat board: no table to cast a shadow on — and inside the unit it showed through the face. */
#rt-duel.d3 .rt-ushadow { display: none; }
/* No text selection anywhere in the duel (owner, 2026-10-08: dragging over the cards selected
   their text by accident); an input, if one is ever added, stays selectable. */
#rt-duel { user-select: none; -webkit-user-select: none; }
#rt-duel input, #rt-duel textarea { user-select: text; -webkit-user-select: text; }

/* --- A phone in landscape (2026-10-09) ----------------------------------------------------------
   The desktop duel is drawn for 1160×680 and only scaled to fit, which on a phone (≈740×360) shrank
   it to half with the desktop's big pieces. Here the pieces are finer — slimmer rows, the decorative
   terminals gone, one-line unit tags, two-line card text — at the same scale (rt-duel.js fit()), so
   they sit with room around them; the owner picked this look on a real phone. Same pieces, same
   order. */
html[data-phone="land"] #rt-duel { gap: 3px; padding: 4px 8px 3px; font-size: 11px; }
html[data-phone="land"] #rt-duel .rt-bgterm { display: none; }
/* Head: one line. */
html[data-phone="land"] #rt-duel .rt-head { gap: 8px; min-height: 22px; height: auto; }
html[data-phone="land"] #rt-duel .rt-title > :not(:first-child) { display: none; }
html[data-phone="land"] #rt-duel .rt-title b { font-size: 12px; }
html[data-phone="land"] #rt-duel .rt-clock { font-size: 15px; min-width: 120px; }
html[data-phone="land"] #rt-duel .rt-btn { padding: 2px 10px; font-size: 10px; }
/* The screen's safe area (owner, 2026-10-09: on an iPhone QUIT sat in the rounded corner and could
   not be tapped). The duel is zoomed, so the inset is divided by the zoom to stay real px. QUIT is a
   finger-sized target. */
html[data-phone="land"] #rt-duel {
  padding-top: max(4px, calc(env(safe-area-inset-top) / var(--rt-zoom, 1)));
  padding-right: max(8px, calc((env(safe-area-inset-right) + 6px) / var(--rt-zoom, 1)));
  padding-bottom: max(3px, calc(env(safe-area-inset-bottom) / var(--rt-zoom, 1)));
  padding-left: max(8px, calc((env(safe-area-inset-left) + 6px) / var(--rt-zoom, 1)));
}
html[data-phone="land"] #rt-duel #rt-quit { min-height: calc(32px / var(--rt-zoom, 1)); min-width: calc(56px / var(--rt-zoom, 1)); font-size: calc(10px / var(--rt-zoom, 1)); }
html[data-phone="land"] #rt-duel .rt-foe-hand { height: 16px; gap: 14px; font-size: 9px; }
html[data-phone="land"] #rt-duel .rt-foe-hand .fh-backs { transform: scale(0.5); transform-origin: center; }
/* Arena: slim side meters, rows that fit. */
html[data-phone="land"] #rt-duel .rt-arena { grid-template-columns: 44px minmax(0, 1fr) 44px; gap: 8px; }
html[data-phone="land"] #rt-duel .rt-vmeter { padding: 2px 0; }
html[data-phone="land"] #rt-duel .vm-word { font-size: 9px; }
html[data-phone="land"] #rt-duel .vm-who { font-size: 7px; }
html[data-phone="land"] #rt-duel .vm-n { font-size: 15px; }
html[data-phone="land"] #rt-duel .rt-board { grid-template-rows: 76px auto auto 76px; row-gap: 3px; }
html[data-phone="land"] #rt-duel .rt-row, html[data-phone="land"] #rt-duel .rt-ports,
html[data-phone="land"] #rt-duel .rt-chans { gap: 6px; }
html[data-phone="land"] #rt-duel .rt-slot { min-height: 76px; }
/* A unit: name, the stats line, a one-line state, the ♥ bar. */
html[data-phone="land"] #rt-duel .rt-unit { gap: 1px; padding: 4px 5px 3px; }
html[data-phone="land"] #rt-duel .rt-uname { font-size: 11px; }
html[data-phone="land"] #rt-duel .rt-ustats { height: 34px; gap: 10px; font-size: 13px; }
html[data-phone="land"] #rt-duel .rt-ustats .a, html[data-phone="land"] #rt-duel .hcol .h, html[data-phone="land"] #rt-duel .rt-ustats .rt-urole { line-height: 15px; }
html[data-phone="land"] #rt-duel .hcol .r1, html[data-phone="land"] #rt-duel .hcol .r2 { height: 9px; line-height: 9px; font-size: 9px; }
html[data-phone="land"] #rt-duel .rt-utag { height: 11px; line-height: 11px; font-size: 8px; -webkit-line-clamp: 1; }
html[data-phone="land"] #rt-duel .rt-hpbar { height: 5px; margin-top: 1px; }
/* The middle: ports and the turn strip, thinner. */
html[data-phone="land"] #rt-duel .rt-port { height: 32px; padding: 1px 0; font-size: 8px; }
html[data-phone="land"] #rt-duel .rt-port .pl1, html[data-phone="land"] #rt-duel .rt-port .pl2, html[data-phone="land"] #rt-duel .rt-lfc { height: 10px; line-height: 10px; margin-top: 0; }
html[data-phone="land"] #rt-duel .rt-lfc em { font-size: 8px; }
html[data-phone="land"] #rt-duel .rt-tw { height: 12px; line-height: 12px; font-size: 10px; }
html[data-phone="land"] #rt-duel .rt-turn { gap: 1px; }
html[data-phone="land"] #rt-duel .rt-turn-mid { height: 22px; gap: 8px; }
html[data-phone="land"] #rt-duel .rt-turn-sub { height: 9px; line-height: 9px; font-size: 8px; }
/* The rack: smaller threads and deck, cards that still read. */
html[data-phone="land"] #rt-duel .rt-rack { grid-template-columns: 104px minmax(0, 1fr) 84px; gap: 8px; }
html[data-phone="land"] #rt-duel .rt-tlabel { font-size: 9px; margin-bottom: 2px; }
html[data-phone="land"] #rt-duel .rt-tlabel b { font-size: 14px; }
html[data-phone="land"] #rt-duel .rt-pips i { height: 9px; }
html[data-phone="land"] #rt-duel .rt-hand { gap: 5px; }
html[data-phone="land"] #rt-duel .rt-card { height: 80px; max-width: 150px; padding: 4px 6px; gap: 1px; }
html[data-phone="land"] #rt-duel .rt-ctop { height: 17px; gap: 4px; }
html[data-phone="land"] #rt-duel .rt-cost { width: 17px; height: 17px; font-size: 11px; }
html[data-phone="land"] #rt-duel .rt-cname { height: 14px; font-size: 11px; }
html[data-phone="land"] #rt-duel .rt-cstats { height: 12px; font-size: 10px; }
html[data-phone="land"] #rt-duel .rt-ctext { font-size: 9px; line-height: 1.25; -webkit-line-clamp: 2; }
html[data-phone="land"] #rt-duel .rt-deck { font-size: 9px; }
html[data-phone="land"] #rt-duel .rt-deck b { font-size: 12px; }
html[data-phone="land"] #rt-duel .rt-hint { min-height: 11px; font-size: 9px; }

/* The 3D duel (desktop by default, public/rt-3d.js; ?3d=0 for the plain one): the three.js world under the
   duel's own pieces. Every #rt-duel.three rule below dresses the duel for it. */
#rt-3d { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }
/* In the 3D duel the lanes are drawn as network links by rt-3d.js. */
#rt-duel.three .rt-chan { visibility: hidden; }
/* In the 3D duel the port row goes (owner, 2026-10-15): no port names, no holder boxes — only the lane's
   forecast stays, small, on the lane's link, and only where there is one. */
#rt-duel.three .rt-port, #rt-duel.three .rt-port.you, #rt-duel.three .rt-port.them { height: 16px; padding: 0; background: none; border-color: transparent; box-shadow: none; }
#rt-duel.three .rt-port .pl1, #rt-duel.three .rt-port .pl2 { display: none; }
#rt-duel.three .rt-lfc { margin: 0; height: 16px; line-height: 14px; }
#rt-duel.three .rt-lfc em { padding: 0 6px; background: #070a10; border: 1px solid currentColor; border-radius: 2px; }
/* In the 3D duel the board breathes (owner, 2026-10-15: "everything is squeezed together"): taller rows,
   room above and below the turn panel for the links and the lane forecasts. */
#rt-duel.three .rt-board { grid-template-rows: minmax(96px, 230px) auto auto minmax(96px, 230px); }
#rt-duel.three .rt-ports { margin-top: 12px; }
#rt-duel.three .rt-turn { margin: clamp(14px, 6vh, 72px) 0; }
/* Units as small panes of glass set into their slots: a tinted see-through face with a highlight
   along the top and a reflection across the corner, thick glass walls in the side's colour. */
#rt-duel.three .rt-unit { --slab: 14px; }
#rt-duel.three .rt-edge { background: linear-gradient(180deg, color-mix(in srgb, var(--side) 60%, transparent), color-mix(in srgb, var(--side) 22%, transparent)); }
#rt-duel.three .rt-edge.eb { background: linear-gradient(180deg, color-mix(in srgb, var(--side) 70%, #fff 10%), color-mix(in srgb, var(--side) 25%, transparent)); }
#rt-duel.three .rt-edge.et { background: color-mix(in srgb, var(--side) 40%, #fff 35%); filter: none; }
/* The hand: the same glass, lying flat — frosted, with its thickness along the bottom edge. */
#rt-duel.three .rt-card:not(.empty) { --side: var(--role, var(--rt-me));
  background:
    linear-gradient(150deg, rgba(255, 255, 255, 0.13) 0%, rgba(255, 255, 255, 0.03) 28%, transparent 44%),
    linear-gradient(180deg, color-mix(in srgb, var(--side) 10%, transparent), transparent 70%),
    rgba(8, 13, 22, 0.7);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), inset 0 0 18px var(--rar-glow, transparent),
    0 2px 0 color-mix(in srgb, var(--side) 55%, transparent), 0 4px 0 color-mix(in srgb, var(--side) 25%, transparent), 0 12px 18px rgba(0, 0, 0, 0.55); }
/* Cards as loaded scripts (owner, 2026-10-15: "not plain — scripts being loaded"). The glass stays,
   the glow goes down; the frame is a module's: a thin border with bright corner brackets, faint
   scanlines, and the script's code scrolling dimly behind the stats in the side's colour. A unit
   coming in loads: it is drawn in line by line from the top. */
#rt-duel.three .rt-unit { clip-path: none; border-radius: 3px;
  border: 1px solid color-mix(in srgb, var(--side) 38%, transparent);
  background:
    linear-gradient(var(--side), var(--side)) top left / 12px 2px no-repeat,
    linear-gradient(var(--side), var(--side)) top left / 2px 12px no-repeat,
    linear-gradient(var(--side), var(--side)) top right / 12px 2px no-repeat,
    linear-gradient(var(--side), var(--side)) top right / 2px 12px no-repeat,
    linear-gradient(var(--side), var(--side)) bottom left / 12px 2px no-repeat,
    linear-gradient(var(--side), var(--side)) bottom left / 2px 12px no-repeat,
    linear-gradient(var(--side), var(--side)) bottom right / 12px 2px no-repeat,
    linear-gradient(var(--side), var(--side)) bottom right / 2px 12px no-repeat,
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.025) 0 1px, transparent 1px 3px),
    linear-gradient(150deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.02) 26%, transparent 42%),
    linear-gradient(180deg, color-mix(in srgb, var(--side) 12%, transparent), color-mix(in srgb, var(--side) 3%, transparent) 70%),
    rgba(6, 10, 17, 0.8);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), inset 0 0 12px color-mix(in srgb, var(--side) 10%, transparent),
    0 0 10px color-mix(in srgb, var(--side) 16%, transparent); }
#rt-duel.three .rt-unit .rt-sheen { display: block; inset: 52% 2px 2px 2px; opacity: 0.11; mix-blend-mode: normal; background: var(--side);
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='264'><g font-family='Consolas,monospace' font-size='9' fill='white'><text x='6' y='9'>push  rbp</text><text x='6' y='20'>mov   rbp, rsp</text><text x='6' y='31'>sub   rsp, 0x40</text><text x='6' y='42'>mov   eax, [rdi+0x18]</text><text x='6' y='53'>xor   ecx, ecx</text><text x='6' y='64'>cmp   eax, 0x1f</text><text x='6' y='75'>jne   short 0x4012af</text><text x='6' y='86'>lea   rsi, [rip+0x2e1]</text><text x='6' y='97'>call  sock_send</text><text x='6' y='108'>mov   [rbp-8], rax</text><text x='6' y='119'>test  rax, rax</text><text x='6' y='130'>jz    0x4013c0</text><text x='6' y='141'>shl   edx, 4</text><text x='6' y='152'>or    edx, 0x80</text><text x='6' y='163'>syscall</text><text x='6' y='174'>inc   ecx</text><text x='6' y='185'>cmp   ecx, 0x10</text><text x='6' y='196'>jl    0x401290</text><text x='6' y='207'>pop   rbp</text><text x='6' y='218'>ret</text><text x='6' y='229'>0x7ffe 48 8b 05 9a</text><text x='6' y='240'>0x7ff2 c3 90 90 ff</text><text x='6' y='251'>nop</text><text x='6' y='262'>jmp   0x401200</text></g></svg>"); mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='264'><g font-family='Consolas,monospace' font-size='9' fill='white'><text x='6' y='9'>push  rbp</text><text x='6' y='20'>mov   rbp, rsp</text><text x='6' y='31'>sub   rsp, 0x40</text><text x='6' y='42'>mov   eax, [rdi+0x18]</text><text x='6' y='53'>xor   ecx, ecx</text><text x='6' y='64'>cmp   eax, 0x1f</text><text x='6' y='75'>jne   short 0x4012af</text><text x='6' y='86'>lea   rsi, [rip+0x2e1]</text><text x='6' y='97'>call  sock_send</text><text x='6' y='108'>mov   [rbp-8], rax</text><text x='6' y='119'>test  rax, rax</text><text x='6' y='130'>jz    0x4013c0</text><text x='6' y='141'>shl   edx, 4</text><text x='6' y='152'>or    edx, 0x80</text><text x='6' y='163'>syscall</text><text x='6' y='174'>inc   ecx</text><text x='6' y='185'>cmp   ecx, 0x10</text><text x='6' y='196'>jl    0x401290</text><text x='6' y='207'>pop   rbp</text><text x='6' y='218'>ret</text><text x='6' y='229'>0x7ffe 48 8b 05 9a</text><text x='6' y='240'>0x7ff2 c3 90 90 ff</text><text x='6' y='251'>nop</text><text x='6' y='262'>jmp   0x401200</text></g></svg>"); -webkit-mask-size: 220px 264px; mask-size: 220px 264px;
  -webkit-mask-repeat: repeat; mask-repeat: repeat; animation: rt3-code 16s linear infinite; }
#rt-duel.three .rt-unit:hover .rt-sheen { animation: rt3-code 4s linear infinite; opacity: 0.2; }
#rt-duel.three .rt-unit.rar-epic .rt-sheen, #rt-duel.three .rt-unit.rar-legendary .rt-sheen { display: block; }
@keyframes rt3-code { from { -webkit-mask-position: 0 0; mask-position: 0 0; } to { -webkit-mask-position: 0 -264px; mask-position: 0 -264px; } }
/* Loading in: the module is drawn from the top down in steps, bright, then settles into its bob. */
#rt-duel.three .rt-slot .rt-unit.enter, #rt-duel.three .rt-slot .rt-unit.landed { animation: rt3-load 0.6s steps(12) both, rt-bob 3.6s ease-in-out 0.6s infinite; }
@keyframes rt3-load {
  0% { clip-path: inset(0 0 100% 0); filter: brightness(2.2); }
  80% { clip-path: inset(0 0 0 0); filter: brightness(1.6); }
  100% { clip-path: inset(0 0 0 0); filter: none; } }
/* The turn panel in the 3D duel (owner, 2026-10-15: the bar, its glow and its words did not sit well):
   a slim bar in a dark track, its fill solid with only a faint glow; whose move it is in one clear line with a prompt and a cursor; the other word
   gone (it showed as a ghost); EXECUTE in amber, not a white blaze. */
#rt-duel.three .rt-turn-bar { --c: var(--rt-me); position: relative; height: 10px; padding: 2px; background: #05080d; border: 1px solid #1b2738; }
#rt-duel.three .rt-turn.theirs .rt-turn-bar { --c: var(--rt-foe); }
#rt-duel.three .rt-turn.exec .rt-turn-bar, #rt-duel.three.clock-low .rt-turn-bar { --c: var(--rt-warn); }
#rt-duel.three .rt-turn-bar i, #rt-duel.three .rt-turn.theirs .rt-turn-bar i, #rt-duel.three .rt-turn.exec .rt-turn-bar i, #rt-duel.three.clock-low .rt-turn-bar i {
  background: linear-gradient(90deg, color-mix(in srgb, var(--c) 35%, transparent), var(--c)); box-shadow: 0 0 6px color-mix(in srgb, var(--c) 45%, transparent); }
#rt-duel.three .rt-tw:not(.on) { visibility: hidden; }
#rt-duel.three .rt-tw.on { font-size: 15px; letter-spacing: 0.32em; text-shadow: 0 0 8px color-mix(in srgb, currentColor 55%, transparent); }
#rt-duel.three .rt-tw.on::before { content: '▸ '; opacity: 0.7; }
#rt-duel.three .rt-tw.on::after { content: '_'; margin-left: 2px; animation: rt-blink 1s steps(2) infinite; }
#rt-duel.three .rt-turn-sub { color: #8296a8; letter-spacing: 0.12em; }
#rt-duel.three .rt-turn.exec .rt-turn-n { color: var(--rt-warn); text-shadow: 0 0 8px rgba(240, 160, 32, 0.45); }
/* A unit that dies at this EXECUTE (its ♥ forecast shows ✖ 0) is corrupted: it turns red, its code
   races, and now and then it glitches — the colours split, it tears, it flickers dark. */
#rt-duel.three .rt-unit.rt3-doomed { --side: #ff2e5f; }
#rt-duel.three .rt-unit.rt3-doomed .rt-sheen { opacity: 0.3; animation: rt3-code 1.4s steps(10) infinite; }
@keyframes rt3-corrupt {
  0%, 100% { filter: none; clip-path: none; }
  58% { filter: drop-shadow(3px 0 0 rgba(255, 46, 95, 0.9)) drop-shadow(-3px 0 0 rgba(69, 255, 240, 0.8)) brightness(1.3); }
  61% { filter: none; }
  74% { clip-path: inset(0 0 46% 0); filter: brightness(1.5); }
  75% { clip-path: inset(38% 0 0 0); }
  76% { clip-path: none; filter: none; }
  88% { filter: brightness(0.45); }
  90% { filter: drop-shadow(-2px 0 0 rgba(255, 46, 95, 0.9)) drop-shadow(2px 0 0 rgba(69, 255, 240, 0.7)); }
  92% { filter: none; } }
/* In the 3D duel a drain is a stream of hex glyphs (rt-3d.js), not the orbs. */
html.rt3 .rt-orb { visibility: hidden; }
/* In the 3D duel the hand's cards tip toward the mouse (rt-3d.js sets rotate/translate): smoothly. */
#rt-duel.three .rt-card { transition: transform 0.12s, rotate 0.15s ease-out, translate 0.15s ease-out; }
/* A unit marked to die stays corrupted to the very end (owner, 2026-10-15): its own fight moves
   (lunge, hit, glitch) still play, with the corruption running beside them; the flashes that would
   turn it another colour (the green drain, the APPLIED flash, the landing) do not; only its death
   takes over. Placed last and specific enough to win over those. */
#rt-duel.three .rt-slot .rt-unit.rt3-doomed:not(.dying) { animation: rt3-corrupt 2.4s steps(1) infinite, rt-bob 3.6s ease-in-out infinite; }
#rt-duel.three .rt-slot .rt-unit.rt3-doomed.lunge:not(.dying) { animation: rt3-lunge-doomed 0.56s ease-out, rt3-corrupt 2.4s steps(1) infinite; }
/* your doomed unit still strikes, but in red: the cyan strike glow read as the unit turning green */
@keyframes rt3-lunge-doomed { 0% { box-shadow: none; } 40% { box-shadow: 0 -14px 26px rgba(255, 46, 95, 0.55), 0 0 0 2px #ff2e5f; } 100% { box-shadow: none; } }
#rt-duel.three .rt-slot .rt-unit.rt3-doomed.lunge-foe:not(.dying) { animation: rt-lunge-foe 0.56s ease-out, rt3-corrupt 2.4s steps(1) infinite; }
#rt-duel.three .rt-slot .rt-unit.rt3-doomed.hit:not(.dying) { animation: rt-hit 0.35s steps(3), rt3-corrupt 2.4s steps(1) infinite; }
#rt-duel.three .rt-slot .rt-unit.rt3-doomed.glitch:not(.dying) { animation: rt-glitch 0.32s steps(2, end), rt3-corrupt 2.4s steps(1) infinite; }
#rt-duel.three .rt-slot .rt-unit.rt3-doomed.dying { animation: rt-dying 0.3s steps(4) forwards; }
/* In the 3D duel the side shells are the history of the moves (owner, 2026-10-16): the enemy's on the
   left, yours on the right, out in the empty margins beside the board and readable. Where the
   margins are too narrow for them they are not shown at all (and placeBgTerm still hides one that
   would touch a piece). */
#rt-duel.three .rt-bgterm { width: min(340px, calc((100vw - 1180px) / 2 - 16px)); font-size: 11px; }
#rt-duel.three .rt-bgterm.top { left: 16px; top: 140px; }
#rt-duel.three .rt-bgterm.low { left: auto; right: 16px; bottom: 196px; }
#rt-duel.three .rt-bgterm > div { overflow: hidden; text-overflow: ellipsis; }
#rt-duel.three .rt-bgterm .ev { color: rgba(140, 200, 215, 0.4); }
#rt-duel.three .rt-bgterm.top .ev { color: rgba(255, 140, 170, 0.4); }
@media (max-width: 1540px) { #rt-duel.three .rt-bgterm { display: none; } }
/* Phone, round 2 (owner, 2026-10-16): taller board cards (there was room) so they hold their text;
   QUIT a bigger target, off the screen's top edge where Safari takes the first touch. */
html[data-phone="land"] #rt-duel .rt-board { grid-template-rows: 104px auto auto 104px; }
html[data-phone="land"] #rt-duel .rt-slot { min-height: 104px; }
html[data-phone="land"] #rt-duel .rt-utag { height: auto; -webkit-line-clamp: 3; line-height: 11px; }
html[data-phone="land"] #rt-duel .rt-head { padding-top: calc(8px / var(--rt-zoom, 1)); }
html[data-phone="land"] #rt-duel #rt-quit { min-height: calc(40px / var(--rt-zoom, 1)); min-width: calc(72px / var(--rt-zoom, 1)); }
