/* The Traveler Card — moss & brass, matched to #plancard .card.
   Self-contained on purpose: the card mounts its own root (#travelercard) rather
   than borrowing the shared #plancard container, so nothing here depends on a
   selector another surface owns. Tokens mirror viewer/game-ui.css :root; the
   fallbacks keep the card legible if it is ever mounted without that sheet.

   Design law (research/menu-design-rehaul.md): one bordered container (the card
   itself), interior structure by background steps not borders, one butter-gold CTA
   per screen (send), 11px type floor, 44px targets on coarse pointers. */

#travelercard {
  position: fixed;
  inset: 0;
  z-index: 26;
  display: none;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  padding: max(14px, env(safe-area-inset-top, 0px)) 16px max(14px, env(safe-area-inset-bottom, 0px));
  background:
    radial-gradient(circle at 50% 16%, rgba(91, 142, 105, .2), transparent 40%),
    rgba(2, 7, 4, .72);
  font-family: var(--font-body, ui-rounded, "Avenir Next", "Trebuchet MS", system-ui, sans-serif);
}

#travelercard.show,
#travelercard.closing { display: flex; }
#travelercard.closing { pointer-events: none; opacity: 0; transition: opacity .17s ease; }

.tcard {
  position: relative;
  box-sizing: border-box;
  width: min(420px, calc(100vw - 32px));
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 16px;
  color: var(--ui-ink, #f2e6bd);
  background: linear-gradient(150deg, rgba(30, 50, 38, .99), rgba(10, 20, 14, .995));
  border: 1px solid rgba(198, 168, 91, .6);
  border-radius: 16px;
  box-shadow: 0 24px 90px rgba(0, 0, 0, .8);
  animation: tcard-in .24s cubic-bezier(.2, .9, .3, 1.2);
}

.tcard:focus { outline: none; }
.tcard :focus-visible { outline: 3px solid #d6e9a7; outline-offset: 2px; }

@keyframes tcard-in {
  from { opacity: 0; transform: translateY(10px) scale(.97); }
  to { opacity: 1; transform: none; }
}

.tcard-sr {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

.tcard-x {
  position: absolute;
  top: 8px;
  right: 8px;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  color: var(--ui-muted, #a9b79e);
  background: transparent;
  border: 0;
  border-radius: 50%;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}

.tcard-x:hover { color: var(--ui-ink, #f2e6bd); background: rgba(255, 255, 255, .06); }
.tcard-x .ui-icon { width: 14px; height: 14px; }

/* 1-5: portrait, name + crest, standing, duel record, what they said.
   The bottom hairline is the sanctioned row separator (rgba(198,168,91,.16)),
   the same one #plancard .hdr::after draws under the duel card's header. */
.tcard-top {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  gap: 12px;
  align-items: start;
  padding-right: 34px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--ui-hairline-soft, rgba(198, 168, 91, .16));
}

.tcard-portrait {
  position: relative;
  width: 76px;
  height: 76px;
  overflow: hidden;
  border-radius: 14px;
  background:
    radial-gradient(circle at 50% 62%, rgba(116, 176, 112, .22), transparent 66%),
    linear-gradient(160deg, rgba(46, 72, 54, .8), rgba(9, 17, 12, .9));
  box-shadow: inset 0 0 0 1px rgba(198, 168, 91, .22);
}

.tcard-canvas {
  display: block;
  width: 76px;
  height: 76px;
  image-rendering: pixelated;
}

.tcard-canvas[hidden],
.tcard-blank[hidden],
.tcard-note[hidden],
.tcard-line[hidden] { display: none; }

/* The honest placeholder: a silhouette, sunk far enough into the frame to read as
   an empty portrait slot rather than a shipped emoji. Used whenever the host
   cannot paint a sprite — which is always true for a cross-world traveler. */
.tcard-blank {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
}

.tcard-blank-bunny {
  font-size: 42px;
  line-height: 1;
  filter: grayscale(1) brightness(.34) contrast(.85);
  opacity: .85;
}

/* Which world they stand in, as a badge on the portrait rather than a loose glyph
   floating over it. The disc is load bearing: Aster's bloom is bright pink and
   Cairn's new moon is near black, and without a common ground one shouted and the
   other disappeared. */
.tcard-crest-badge {
  position: absolute;
  right: 3px;
  bottom: 3px;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  background: rgba(6, 14, 9, .92);
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(198, 168, 91, .35);
  font-size: 11px;
  line-height: 1;
}

.tcard-id { min-width: 0; }

.tcard-namerow {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
}

.tcard-name {
  min-width: 0;
  margin: 0;
  overflow: hidden;
  color: #f4efd9;
  font: 700 18px/1.25 var(--font-display, inherit);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* THE one kicker on this panel (T6: 11px, uppercase, .06em, brass). */
.tcard-crest {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--ui-brass, #c6a85b);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.tcard-crest[hidden] { display: none; }
.tcard-crest-glyph { font-size: 13px; letter-spacing: 0; }

.tcard-line {
  margin: 5px 0 0;
  color: var(--ui-muted, #a9b79e);
  font-size: 13px;
  line-height: 1.4;
}

.tcard-standing { color: #dde4d5; }
.tcard-away { color: var(--ui-muted, #a9b79e); }
/* Meta, a step below the two lines that carry meaning. */
.tcard-mood,
.tcard-duel { font-size: 12px; }
.tcard-duel { color: var(--ui-brass-hi, #f2e6bd); font-variant-numeric: tabular-nums; }
/* The only italic on the card, because it is the only thing here a player wrote
   (type law: italic is for player-quoted prompts at 13px and up). */
.tcard-said { margin-top: 7px; color: #e8ddb9; font-style: italic; }

/* 6: the inline whisper composer. It sits directly under the identity block, and
   above the note, because it is the verb the card exists for: the gold CTA has to
   land in the eye's first sweep, not halfway down. Edge and focus glow copy the
   game's own composer (#chatmsg) so a text field looks like a text field. */
.tcard-whisper {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  padding: 7px 8px 7px 10px;
  background: rgba(10, 20, 15, .95);
  border-radius: 11px;
  box-shadow: inset 0 0 0 1px rgba(198, 168, 91, .28);
}

/* Focus was completely invisible here: the card focuses this box on open and the
   input's own outline was suppressed with nothing put back. */
.tcard-whisper:focus-within {
  box-shadow: inset 0 0 0 1px rgba(149, 207, 139, .7), 0 0 0 2px rgba(149, 207, 139, .1);
}

.tcard-whisper.off { opacity: .55; }

.tcard-whisper-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 32px;
  padding: 0;
  overflow: hidden;
  color: var(--ui-ink, #f2e6bd);
  background: transparent;
  border: 0;
  font: inherit;
  font-size: 13px;
  text-overflow: ellipsis;      /* a long name must trail off, not get guillotined */
}

.tcard-whisper-input::placeholder { color: var(--ui-dim, #73806b); }
.tcard-whisper-input:focus { outline: none; }

/* THE one butter-gold CTA on this surface. */
.tcard-send {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex: 0 0 auto;
  min-height: 34px;
  padding: 6px 14px;
  color: #22170e;
  background: linear-gradient(180deg, #f1d27d, #c99443);
  border: 1px solid #f1d27d;
  border-radius: 9px;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.tcard-send.off {
  color: var(--ui-dim, #73806b);
  background: rgba(15, 26, 20, .74);
  border-color: rgba(111, 133, 116, .3);
  cursor: help;
}

.tcard-send:not(.off):active { transform: translateY(2px); }

/* 7: the private note — local only, never broadcast. Quieter than the composer on
   purpose: same shape, one surface step flatter and a size smaller. */
.tcard-note {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding: 7px 9px;
  background: rgba(4, 12, 7, .46);
  border-radius: 10px;
}

.tcard-note:focus-within { box-shadow: inset 0 0 0 1px rgba(149, 207, 139, .45); }

.tcard-note-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 30px;
  padding: 0;
  overflow: hidden;
  color: #e8ddb9;
  background: transparent;
  border: 0;
  font: inherit;
  font-size: 12px;
  text-overflow: ellipsis;
}

.tcard-note-input::placeholder { color: var(--ui-dim, #73806b); }
.tcard-note-input:focus { outline: none; }
.tcard-note-input:disabled { opacity: .5; }

/* 8: the action row. Mute and Report are top level, never a submenu. */
.tcard-acts { margin-top: 11px; }

.tcard-actrow {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.tcard-guardrow {
  margin-top: 6px;
  padding-top: 8px;
  border-top: 1px solid var(--ui-hairline-soft, rgba(198, 168, 91, .16));
}

.tcard-act {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex: 1 1 88px;
  min-height: 38px;
  padding: 7px 9px;
  color: #efe9d0;
  background: linear-gradient(160deg, #31543d, #15271c);
  border: 1px solid var(--ui-hairline, rgba(198, 168, 91, .5));
  border-radius: 10px;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.tcard-act:not(.off):hover { border-color: var(--ui-brass-hi, #f2e6bd); }
.tcard-act:not(.off):active { transform: translateY(2px); }

/* Greyed, never gone: an unavailable verb still teaches the world, and Report has
   to stay findable when everything else is out of reach. `cursor: help` is honest
   about what the button now does — it answers instead of acting.
   Draining the glyph matters more than draining the label, so an unavailable
   action cannot read as live at phone size. */
.tcard-act.off {
  color: var(--ui-dim, #73806b);
  background: rgba(15, 26, 20, .74);
  border-color: rgba(111, 133, 116, .3);
  cursor: help;
}

.tcard-act.off .tcard-glyph {
  opacity: .38;
  filter: grayscale(1) brightness(.85);
}

/* Quiet by size as well as by fill: content width, matching the plan card's ghost
   decline button rather than stretching to half the panel each. */
.tcard-guardrow .tcard-act {
  flex: 0 1 auto;
  min-height: 34px;
  padding: 6px 16px;
  color: #9dac98;
  background: transparent;
  border-color: rgba(131, 149, 122, .25);
  font-size: 12px;
  font-weight: 600;
}

/* Guard glyphs stay quieter than the gold CTA. Report remains top level and
   fully labelled — findable is the safety floor, not shouty. */
.tcard-guardrow .tcard-glyph { opacity: .8; filter: grayscale(.5) brightness(.92); }

.tcard-guardrow .tcard-act-report:not(.off):hover {
  color: var(--ui-danger, #e77d72);
  border-color: rgba(231, 125, 114, .55);
}

.tcard-guardrow .tcard-act-report:not(.off):hover .tcard-glyph { opacity: 1; filter: none; }

.tcard-glyph { width: 16px; height: 16px; flex: none; color: currentColor; }

/* Not a footnote any more: this line now carries the reason a greyed verb refused,
   so it is sized to be read rather than to be tucked away. */
.tcard-status {
  margin: 9px 0 0;
  min-height: 0;
  color: var(--ui-muted, #a9b79e);
  font-size: 12px;
  line-height: 1.4;
}

.tcard-status.bad { color: var(--ui-danger, #e77d72); }
.tcard-status:empty { margin: 0; }

/* Phone: a bottom sheet, not a centred modal. --kb is set on documentElement by the
   game, so the sheet rides above a raised keyboard instead of under it. */
@media (max-width: 560px) {
  #travelercard {
    align-items: flex-end;
    padding: 10px max(7px, env(safe-area-inset-left, 0px))
      calc(7px + env(safe-area-inset-bottom, 0px) + var(--kb, 0px))
      max(7px, env(safe-area-inset-right, 0px));
  }

  .tcard {
    width: 100%;
    max-width: none;
    max-height: calc(100dvh - var(--kb, 0px) - env(safe-area-inset-bottom, 0px) - 18px);
    border-radius: 16px 16px 12px 12px;
    animation-name: tcard-sheet-in;
  }

  .tcard-name { font-size: 19px; }
  .tcard-line { font-size: 13.5px; }
  .tcard-mood,
  .tcard-duel { font-size: 12.5px; }           /* sheet meta floor is 12.5px, not 12px */
  .tcard-note-input { font-size: 16px; }       /* 16px or iOS zooms the page on tap */
  .tcard-whisper-input { font-size: 16px; }
  .tcard-act { flex: 1 1 46%; font-size: 13px; }
  .tcard-guardrow .tcard-act { flex: 0 1 auto; font-size: 12.5px; }
  .tcard-status { font-size: 12.5px; }
}

@keyframes tcard-sheet-in {
  from { opacity: 0; transform: translateY(22px); }
  to { opacity: 1; transform: none; }
}

@media (pointer: coarse) {
  .tcard-x { width: 44px; height: 44px; top: 4px; right: 4px; }
  .tcard-act { min-height: 44px; }
  .tcard-guardrow .tcard-act { min-height: 44px; }
  .tcard-send { min-height: 44px; min-width: 44px; }
  .tcard-note-input,
  .tcard-whisper-input { min-height: 44px; font-size: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  .tcard { animation: none !important; }
  #travelercard.closing { transition: none; }
  .tcard-act:active,
  .tcard-send:active { transform: none; }
}
