/* styles/biomes/customs.css
   Biome 3 — The Customs House (Risk Engine).
   Cold blue, sterile, bureaucratic. SVG architecture suggests a long
   hall with pillars and a single counter line. The mini-game reveals
   in phases (posture → transactions → submit) so the player only
   sees one concept at a time. */

:root {
  --customs-bg:       #0a1828;
  --customs-bg-deep:  #02060c;
  --customs-pale:     #e0e8f0;
  --customs-blue:     #b8d4e8;
  --customs-cool:     #b4dcc8;   /* low-risk metadata — cool green-white */
  --customs-warm:     #e8c878;   /* med-risk — amber */
  --customs-hot:      #ff825a;   /* high-risk — hot orange */
}

#customs {
  background:
    radial-gradient(ellipse 80% 60% at 50% 50%,
      var(--customs-bg) 0%,
      #061018 70%,
      var(--customs-bg-deep) 100%);
}

#customs::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 100% 30% at 50% 0%,   rgba(120, 160, 200, 0.08), transparent 70%),
    radial-gradient(ellipse 100% 40% at 50% 100%, rgba(0, 0, 0, 0.6),        transparent 60%);
  pointer-events: none;
  z-index: 1;
}

/* SVG architectural background fills the scene */
.customs-architecture {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: none;
}

/* ---------- CENTRAL LAYOUT ---------- */

#customs-content {
  position: absolute;
  /* HORIZONTAL: respect the voice gutters explicitly. The Schema voice
     sits at right: 4vw with a width up to 24vw — its content reaches
     ~28vw inward from the right. Same on the left for Pulse. Without
     a hard right-side inset on the interactive area, transaction
     card #3 collides with Schema italic prose. Pillar-locked solution:
     pad horizontally by --voice-gutter so the central rectangle stops
     EXACTLY where the voice zones begin.
     VERTICAL: respect narrator + system zones (already was). */
  inset: var(--narrator-zone) var(--voice-gutter) var(--system-zone);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  z-index: 3;
  padding: 1vh 1vw 0;
  gap: 2vh;
  overflow-y: auto;
  /* Cap the maximum width so on ultra-wide screens (3440px+) the
     transaction row doesn't sprawl. Centered via margin auto via the
     parent's `align-items: center`. */
  max-width: calc(100vw - 2 * var(--voice-gutter));
  margin: 0 auto;
}

/* ---------- PHASED SECTIONS ---------- */

.customs-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.8em;
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity   1400ms ease,
    transform 1400ms ease;
  pointer-events: none;
}
.customs-section.revealed {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.customs-instruction {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.4em;
  color: rgba(232, 240, 248, 0.85);
  text-transform: uppercase;
  text-align: center;
}
.customs-instruction-sub {
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.95rem;
  color: rgba(184, 212, 232, 0.55);
  text-align: center;
  margin-top: -0.4em;
  letter-spacing: 0.01em;
}

/* ---------- POSTURE ROW ---------- */

#customs-postures {
  display: flex;
  gap: 14px;
  justify-content: center;
  margin-top: 0.5em;
}

.posture-btn {
  background: rgba(10, 24, 40, 0.85);
  border: 1px solid rgba(184, 224, 255, 0.25);
  color: var(--customs-pale);
  font-family: var(--mono);
  padding: 18px 22px;
  cursor: pointer;
  text-align: left;
  width: 220px;
  border-radius: 2px;
  transition: all 200ms ease;
  display: flex;
  flex-direction: column;
  gap: 6px;
  position: relative;
}
.posture-btn::before {
  /* small brass-cool corner sigil */
  content: '';
  position: absolute;
  top: 8px; right: 10px;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: rgba(184, 224, 255, 0.25);
}
.posture-btn:hover {
  border-color: rgba(184, 224, 255, 0.7);
  background: rgba(20, 40, 64, 0.9);
  transform: translateY(-2px);
}
.posture-btn:active {
  transform: translateY(0) scale(0.98);
  filter: brightness(1.15);
}
.posture-btn.selected {
  border-color: rgba(232, 240, 248, 0.95);
  background: rgba(40, 60, 84, 0.9);
  box-shadow: 0 0 22px rgba(184, 224, 255, 0.35);
}
.posture-btn.selected::before {
  background: rgba(232, 240, 248, 0.95);
  box-shadow: 0 0 8px rgba(232, 240, 248, 0.8);
}
.posture-label {
  font-size: 0.75rem;
  letter-spacing: 0.3em;
  font-weight: bold;
  color: rgba(232, 240, 248, 0.95);
}
.posture-what {
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.85rem;
  color: rgba(232, 240, 248, 0.82);
  line-height: 1.35;
  letter-spacing: 0.01em;
}
.posture-cost {
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  color: rgba(184, 212, 232, 0.55);
  text-transform: uppercase;
  margin-top: 2px;
}

/* ---------- TRANSACTION CARDS ---------- */

/* "Watch for" legend — pedagogical scaffold above the transaction cards.
   Explains what risk patterns the player should look for, in plain prose. */
#customs-watchfor {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 0.5em 0 0.3em 0;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  color: rgba(184, 212, 232, 0.55);
  text-transform: uppercase;
  flex-wrap: wrap;
  /* P1-4: smooth fade for teaching-done state. */
  transition: opacity 1200ms ease, max-height 1200ms ease;
  max-height: 60px;
  overflow: hidden;
}
/* P1-4: Once the player makes their first verdict, the "Watch for"
   callout has done its teaching job. Fade it out so the remaining
   transactions have less chrome competing for attention. */
#customs-watchfor.teaching-done {
  opacity: 0.25;
  max-height: 24px;
}
.watchfor-label {
  color: rgba(232, 200, 120, 0.85);
  letter-spacing: 0.35em;
  padding-right: 4px;
}
.watchfor-item   { color: rgba(184, 212, 232, 0.85); }
.watchfor-sep    { color: rgba(184, 212, 232, 0.3); }

/* Metadata rows now have hover affordance — visual hint they're hoverable. */
.tx-row {
  cursor: help;
  transition: background 150ms ease;
  position: relative;
}
.tx-row:hover {
  background: rgba(184, 212, 232, 0.06);
}

/* ---------- C9 — HOVER-AFFORDANCE TEACH ----------
   On the player's first Customs visit, the very first tx-row pulses
   gently with an outline + a small ↪ glyph at the right edge.
   Self-explanatory cue that the rows are interactive — closes the
   "I never noticed it was hoverable" gap from random-user playtest.
   Auto-stops after 4 pulses (~5.6s) OR on first mouseenter. */
.tx-row.hover-affordance {
  animation: tx-row-hover-pulse 1400ms ease-in-out 0s 4;
}
.tx-row.hover-affordance::after {
  content: '↪ hover';
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--mono);
  font-size: 0.55rem;
  letter-spacing: 0.18em;
  text-transform: lowercase;
  color: rgba(184, 212, 232, 0.85);
  text-shadow: 0 0 8px rgba(184, 212, 232, 0.45);
  pointer-events: none;
  animation: tx-row-hover-glyph 1400ms ease-in-out 0s 4;
}
@keyframes tx-row-hover-pulse {
  0%, 100% {
    background: rgba(184, 212, 232, 0);
    box-shadow: inset 0 0 0 0 rgba(184, 212, 232, 0);
  }
  50% {
    background: rgba(184, 212, 232, 0.12);
    box-shadow: inset 0 0 0 1px rgba(184, 212, 232, 0.55);
  }
}
@keyframes tx-row-hover-glyph {
  0%, 100% { opacity: 0; transform: translateY(-50%) translateX(0); }
  50%      { opacity: 0.95; transform: translateY(-50%) translateX(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .tx-row.hover-affordance {
    animation: none;
    background: rgba(184, 212, 232, 0.10);
    box-shadow: inset 0 0 0 1px rgba(184, 212, 232, 0.55);
  }
  .tx-row.hover-affordance::after { animation: none; opacity: 0.92; }
}

#customs-transactions {
  display: flex;
  /* flex-wrap so the 4th ambiguous intent (P3-E) doesn't overflow at
     narrow viewports — at 22vw per card, 4 cards × 22vw + gaps approaches
     90vw which clips on smaller screens. With wrap, cards reflow to a
     2x2 grid below ~1100px viewport width. */
  flex-wrap: wrap;
  gap: 14px;
  justify-content: center;
  align-items: stretch;
  margin-top: 0.5em;
}

/* Marketplace scenario produces 4 transaction cards; the default 3-card
   width pushes the row edge-to-edge and the magistrate's desk SVG
   below the fold. Narrower cards + tighter cap keep all 4 inside a
   reading frame, leaving room for the desk to breathe. */
body[data-scenario="marketplace"] #customs-transactions {
  max-width: 920px;
  margin-inline: auto;
  gap: 12px;
}
body[data-scenario="marketplace"] .tx-card {
  width: min(220px, 23vw);
  padding: 12px 14px;
}

/* At viewports below 1100px every scenario wraps to a 2-row grid so
   cards don't compress to unreadable widths. */
@media (max-width: 1100px) {
  .tx-card { width: min(280px, 44vw); }
  body[data-scenario="marketplace"] .tx-card { width: min(240px, 44vw); }
}

.tx-card {
  background:
    linear-gradient(180deg, rgba(20, 40, 60, 0.4) 0%, transparent 40%),
    rgba(10, 24, 40, 0.92);
  border: 1px solid rgba(184, 224, 255, 0.3);
  padding: 14px 18px;
  width: min(260px, 22vw);
  font-family: var(--mono);
  display: flex;
  flex-direction: column;
  gap: 10px;
  border-radius: 2px;
  position: relative;
  transition: border-color 600ms ease, box-shadow 600ms ease, transform 200ms ease;
}
.tx-card:hover {
  border-color: rgba(184, 224, 255, 0.55);
  transform: translateY(-2px);
}

/* Paper stamp in the top-right corner — bureaucratic theater */
.tx-card::after {
  content: 'EXAMINED';
  position: absolute;
  top: 10px; right: 10px;
  padding: 2px 5px;
  border: 1.5px solid rgba(220, 80, 60, 0.45);
  border-radius: 2px;
  font-family: var(--mono);
  font-size: 0.45rem;
  letter-spacing: 0.28em;
  color: rgba(220, 80, 60, 0.55);
  transform: rotate(-8deg);
  opacity: 0.7;
}

/* Faint ink-smudge texture on the card background — paper feel */
.tx-card::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 2px;
  pointer-events: none;
  background-image:
    radial-gradient(ellipse 30% 12% at 75% 18%, rgba(184, 212, 232, 0.04), transparent 70%),
    radial-gradient(ellipse 40% 8% at 25% 78%, rgba(120, 80, 60, 0.06), transparent 70%);
  opacity: 0.9;
}

.tx-header {
  /* Bumped from 0.7rem/0.75 alpha → 0.75rem/0.88 alpha. Small bump
     clears AA comfortably and improves scan-ability of intent labels. */
  font-size: 0.75rem;
  letter-spacing: 0.4em;
  color: rgba(184, 212, 232, 0.88);
  text-align: center;
  text-transform: uppercase;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(184, 224, 255, 0.2);
}

.tx-metadata {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.tx-row {
  display: flex;
  justify-content: space-between;
  font-size: 0.7rem;
  padding: 2px 0;
}
.tx-key {
  /* Bumped from 0.45 → 0.70 alpha. Player reads these field labels
     during the verdict phase, so they must clear AA on the cool-blue
     biome background; 0.45 fell to ~2.8:1 (fail), 0.70 lands at ~5.5:1. */
  color: rgba(184, 212, 232, 0.70);
  letter-spacing: 0.18em;
}
.tx-val {
  color: rgba(224, 232, 240, 0.92);
  font-weight: bold;
}

.tx-row.tx-risk-low  .tx-val { color: var(--customs-cool); }
.tx-row.tx-risk-med  .tx-val { color: var(--customs-warm); }
.tx-row.tx-risk-high .tx-val { color: var(--customs-hot);  }

/* Secondary cue alongside color tint — for non-colour users (colour
   blindness, monochrome displays). Pure mono glyph, low visual weight,
   reads as "risk indicator" rather than decoration. */
.tx-row .tx-val::after {
  margin-left: 6px;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0;
  opacity: 0.85;
}
.tx-row.tx-risk-low  .tx-val::after { content: '·';  color: var(--customs-cool); }
.tx-row.tx-risk-med  .tx-val::after { content: '◆';  color: var(--customs-warm); }
.tx-row.tx-risk-high .tx-val::after { content: '▲';  color: var(--customs-hot);  }

/* ---------- ACTION BUTTONS ---------- */

.tx-actions {
  display: flex;
  gap: 8px;
  margin-top: 6px;
}
.tx-btn {
  flex: 1;
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid rgba(184, 224, 255, 0.3);
  color: rgba(224, 232, 240, 0.78);
  font-family: var(--mono);
  font-size: 0.65rem;
  letter-spacing: 0.22em;
  padding: 9px 0;
  cursor: pointer;
  text-transform: uppercase;
  transition: all 150ms ease;
  border-radius: 2px;
}
.tx-btn:hover {
  border-color: rgba(184, 224, 255, 0.7);
  color: var(--customs-pale);
}
.tx-btn:active {
  transform: scale(0.97);
  filter: brightness(1.15);
}
.tx-btn:disabled,
.tx-card[data-outcome] .tx-btn {
  cursor: default;
  opacity: 0.55;
  pointer-events: none;
}
.tx-card[data-decision="block"]   .tx-btn-block {
  background: rgba(220, 80, 60, 0.28);
  border-color: rgba(255, 130, 90, 0.85);
  color: rgba(255, 200, 180, 0.95);
  box-shadow: 0 0 10px rgba(255, 130, 90, 0.25);
}
.tx-card[data-decision="approve"] .tx-btn-approve {
  background: rgba(80, 200, 140, 0.22);
  border-color: rgba(120, 220, 170, 0.75);
  color: rgba(180, 240, 200, 0.95);
  box-shadow: 0 0 10px rgba(80, 200, 140, 0.25);
}

/* ---------- TRUTH REVEAL ---------- */

.tx-truth {
  font-size: 0.65rem;
  letter-spacing: 0.32em;
  text-align: center;
  margin-top: 4px;
  padding: 4px 0;
  opacity: 0;
  transition: opacity 800ms ease;
  text-transform: uppercase;
  font-weight: bold;
}
.tx-card[data-outcome] .tx-truth { opacity: 1; }
.tx-card[data-outcome="correct-block"]   .tx-truth,
.tx-card[data-outcome="correct-approve"] .tx-truth { color: rgba(120, 220, 170, 0.95); }
.tx-card[data-outcome="false-decline"]   .tx-truth { color: rgba(232, 200, 120, 0.95); }
.tx-card[data-outcome="chargeback"]      .tx-truth { color: rgba(255, 130, 90, 0.95);  }

.tx-card[data-outcome="correct-block"],
.tx-card[data-outcome="correct-approve"] {
  border-color: rgba(120, 220, 170, 0.55);
  box-shadow: 0 0 16px rgba(80, 200, 140, 0.2);
}
.tx-card[data-outcome="false-decline"] {
  border-color: rgba(232, 200, 120, 0.6);
  box-shadow: 0 0 16px rgba(200, 160, 80, 0.2);
}
.tx-card[data-outcome="chargeback"] {
  border-color: rgba(255, 130, 90, 0.7);
  box-shadow: 0 0 20px rgba(220, 80, 60, 0.3);
}

/* ---------- DECISION PIPS (verdict scorecard above the submit button)
   Replaces the silent "submit becomes clickable when all decided"
   pattern with a glanceable per-intent state. Pips fill as verdicts
   are made — ✓ on approve (cool blue), ✗ on block (warm orange). */

.customs-decisions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 14px;
  font-family: var(--mono);
}
.cd-label {
  font-size: 0.55rem;
  letter-spacing: 0.36em;
  text-transform: uppercase;
  color: rgba(184, 224, 255, 0.55);
  margin-right: 4px;
}
.cd-pip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 2px;
  border: 1px solid rgba(184, 224, 255, 0.35);
  background: rgba(20, 40, 60, 0.5);
  color: transparent;
  font-size: 0.85rem;
  line-height: 1;
  transition: background 240ms ease, border-color 240ms ease, color 240ms ease;
}
.cd-pip.cd-approve {
  border-color: rgba(120, 220, 170, 0.75);
  background: rgba(40, 88, 70, 0.55);
  color: rgba(180, 240, 210, 0.95);
}
.cd-pip.cd-block {
  border-color: rgba(255, 130, 90, 0.75);
  background: rgba(80, 32, 22, 0.55);
  color: rgba(255, 200, 180, 0.95);
}

/* ---------- SUBMIT BUTTON ---------- */

#customs-submit {
  background: rgba(20, 40, 60, 0.6);
  border: 1px solid rgba(184, 224, 255, 0.22);
  color: rgba(224, 232, 240, 0.45);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.4em;
  padding: 12px 40px;
  cursor: not-allowed;
  text-transform: uppercase;
  border-radius: 2px;
  transition: all 200ms ease;
}
#customs-submit.enabled {
  border-color: rgba(232, 240, 248, 0.9);
  color: rgba(232, 240, 248, 0.95);
  cursor: pointer;
  background: rgba(40, 60, 80, 0.85);
  box-shadow: 0 0 18px rgba(184, 224, 255, 0.28);
}
#customs-submit.enabled:hover {
  background: rgba(60, 88, 110, 0.85);
  box-shadow: 0 0 24px rgba(184, 224, 255, 0.45);
}
#customs-submit.enabled:active {
  transform: scale(0.98);
  filter: brightness(1.2);
}

/* ---------- T3-G UPLIFT DECISION-BOUNDARY VISUALIZATION ----------
   Cinematic overlay that fires between submission and truth-reveal.
   ~2.2s total; SVG scatter-plot with a glowing decision curve and
   the player's three verdicts as labelled pulses. Wow-moment teaching
   "the ML model sees these signals as a boundary, not a binary." */

#uplift-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(8, 14, 22, 0.92);
  opacity: 0;
  transition: opacity 700ms ease;
  /* Block hover-through to Customs UI behind. Player dismisses via
     Continue button. */
  pointer-events: none;
  padding: 4vh 4vw;
}
#uplift-overlay.active {
  opacity: 1;
  pointer-events: auto;
}

.up-eyebrow {
  font-family: var(--mono);
  font-size: 0.55rem;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: rgba(120, 220, 170, 0.85);
  margin-bottom: 16px;
}

.up-svg {
  width: min(640px, 80vw);
  height: auto;
  aspect-ratio: 320 / 220;
  background: rgba(0, 10, 16, 0.85);
  border: 1px solid rgba(120, 220, 170, 0.4);
  border-radius: 2px;
  box-shadow: 0 0 36px rgba(120, 220, 170, 0.2);
}

.up-axis-label {
  font-family: var(--mono);
  font-size: 8px;
  letter-spacing: 0.32em;
  fill: rgba(184, 212, 232, 0.5);
  text-transform: uppercase;
}

.up-dot-fraud,
.up-dot-legit {
  opacity: 0.6;
}
.up-dot-fraud  { fill: rgba(255, 130, 90, 0.5); }
.up-dot-legit  { fill: rgba(120, 220, 170, 0.5); }

.up-curve {
  fill: none;
  stroke: rgba(232, 216, 255, 0.75);
  stroke-width: 1.5;
  stroke-dasharray: 4 4;
  filter: drop-shadow(0 0 6px rgba(232, 216, 255, 0.6));
  /* Draw-on animation */
  stroke-dashoffset: 600;
  animation: up-curve-draw 900ms ease-out 200ms forwards;
}
@keyframes up-curve-draw {
  from { stroke-dashoffset: 600; }
  to   { stroke-dashoffset: 0; }
}

.up-intent {
  opacity: 0;
  animation: up-intent-appear 700ms ease-out forwards;
}
@keyframes up-intent-appear {
  from { opacity: 0; transform: scale(0.5); }
  to   { opacity: 1; transform: scale(1); }
}
.up-intent-halo {
  fill: none;
  stroke-width: 1;
}
.up-intent-core {
  filter: drop-shadow(0 0 6px currentColor);
}
.up-intent-correct .up-intent-halo { stroke: rgba(120, 220, 170, 0.7); }
.up-intent-correct .up-intent-core { fill: rgba(120, 220, 170, 1); color: rgba(120, 220, 170, 0.8); }
.up-intent-wrong   .up-intent-halo { stroke: rgba(255, 130, 90, 0.7); }
.up-intent-wrong   .up-intent-core { fill: rgba(255, 130, 90, 1); color: rgba(255, 130, 90, 0.8); }
.up-intent-label {
  font-family: var(--mono);
  font-size: 7px;
  letter-spacing: 0.18em;
  fill: rgba(232, 248, 240, 0.95);
  text-anchor: middle;
}

.up-caption {
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.85rem;
  color: rgba(184, 224, 255, 0.65);
  margin-top: 14px;
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
}
.up-legend {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.75rem;
  font-style: italic;
  color: rgba(184, 224, 255, 0.7);
}
.up-dot-correct,
.up-dot-wrong {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
}
.up-dot-correct {
  background: rgba(120, 220, 170, 0.95);
  box-shadow: 0 0 6px rgba(120, 220, 170, 0.7);
}
.up-dot-wrong {
  background: rgba(255, 130, 90, 0.95);
  box-shadow: 0 0 6px rgba(255, 130, 90, 0.7);
}

.up-continue {
  margin-top: 22px;
  background: rgba(120, 220, 170, 0.18);
  border: 1px solid rgba(120, 220, 170, 0.8);
  color: rgba(180, 255, 220, 0.95);
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.36em;
  text-transform: uppercase;
  padding: 12px 28px;
  cursor: pointer;
  border-radius: 2px;
  transition: all 200ms ease;
  opacity: 0;
  animation: up-continue-fade-in 700ms ease 1100ms forwards;
}
.up-continue:hover {
  background: rgba(120, 220, 170, 0.32);
  box-shadow: 0 0 22px rgba(120, 220, 170, 0.5);
  transform: translateY(-2px);
}
.up-continue:active {
  transform: translateY(0) scale(0.97);
  filter: brightness(1.15);
}
@keyframes up-continue-fade-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  #uplift-overlay { transition-duration: 200ms; }
  .up-curve { animation-duration: 300ms; }
  .up-intent { animation-duration: 200ms; }
  .up-continue { animation-duration: 200ms; animation-delay: 400ms; }
}

/* ---------- T2-E EXPERT-MODE RISK SCORE ----------
   Trust-gated readout next to each intent's header. Replaces the
   guessing the color tints implied with a numerical score (0–100). */

.tx-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.tx-risk-score {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-family: var(--mono);
  padding: 2px 8px;
  border: 1px solid rgba(184, 212, 232, 0.35);
  border-radius: 2px;
  background: rgba(0, 0, 0, 0.25);
  transition: box-shadow 600ms ease, border-color 600ms ease;
}
/* Glow on the FIRST risk-score box when expert-mode unlocks for the
   first time — paired with the first-encounter hint pointing at it. */
.tx-risk-score.expert-glow {
  border-color: rgba(184, 224, 255, 0.85);
  box-shadow: 0 0 18px rgba(184, 224, 255, 0.45);
  animation: expert-glow-pulse 1600ms ease-in-out infinite;
}
@keyframes expert-glow-pulse {
  0%, 100% { box-shadow: 0 0 18px rgba(184, 224, 255, 0.45); }
  50%      { box-shadow: 0 0 26px rgba(184, 224, 255, 0.65); }
}
@media (prefers-reduced-motion: reduce) {
  .tx-risk-score.expert-glow { animation: none; }
}
.trs-label {
  font-size: 0.5rem;
  letter-spacing: 0.35em;
  color: rgba(184, 212, 232, 0.55);
}
.trs-value {
  font-size: 0.95rem;
  font-weight: bold;
  letter-spacing: 0.05em;
  color: rgba(232, 248, 255, 0.95);
  text-shadow: 0 0 10px rgba(184, 212, 232, 0.35);
}

/* ---------- DISTANT QUEUE (implied-presence pattern) ----------
   The middle figure has a very slow opacity pulse so the queue
   reads as alive (people shifting weight, breathing) without being
   visibly animated. 12s cycle is below conscious-motion threshold. */
.customs-queue-pulse {
  animation: customs-queue-pulse 12s ease-in-out infinite;
}
@keyframes customs-queue-pulse {
  0%, 100% { opacity: 0.16; }
  50%      { opacity: 0.28; }
}
@media (prefers-reduced-motion: reduce) {
  .customs-queue-pulse { animation: none; opacity: 0.20; }
}

/* ---------- AMBIENT — paper-document flicker on back wall ----------
   Spawned by engine/ambient.js every 14–22s. A faint blue document
   rectangle briefly appears in the hall, hinting at the bureaucracy
   continuing around the player. */
.customs-paper-flicker {
  position: absolute;
  z-index: 2;
  width: 64px;
  height: 42px;
  background: rgba(184, 212, 232, 0.05);
  border: 1px dashed rgba(184, 212, 232, 0.22);
  border-radius: 2px;
  pointer-events: none;
  animation: customs-paper-flicker 2400ms ease-out forwards;
}
.customs-paper-flicker::before {
  /* Faint inner line — suggests a stamped page, no readable text. */
  content: '';
  position: absolute;
  left: 8px; right: 8px; top: 12px;
  height: 1px;
  background: rgba(184, 212, 232, 0.18);
}
@keyframes customs-paper-flicker {
  0%   { opacity: 0; transform: scale(0.94); }
  18%  { opacity: 0.7; }
  82%  { opacity: 0.7; }
  100% { opacity: 0; transform: scale(1.02); }
}

@media (prefers-reduced-motion: reduce) {
  .customs-section { transition-duration: 300ms; }
  .tx-truth, .tx-btn, .posture-btn, #customs-submit, .tx-card {
    transition-duration: 150ms;
  }
  .customs-paper-flicker { animation-duration: 800ms; }
}

/* ---------- MOBILE (C7) ----------
   Posture row collapses to a column; transaction cards stack;
   button heights snap to the 44px touch-target minimum. */
@media (max-width: 520px) {
  #customs-content {
    inset: var(--narrator-zone) 4vw var(--system-zone);
  }
  #customs-postures {
    flex-direction: column;
    gap: 10px;
    align-items: stretch;
  }
  .posture-btn {
    width: 100%;
    min-height: 56px;
    padding: 12px 14px;
    text-align: left;
  }
  #customs-transactions {
    flex-direction: column;
    gap: 10px;
    align-items: stretch;
  }
  .tx-card {
    width: 100%;
    max-width: none;
    padding: 12px 14px;
  }
  .tx-row { font-size: 0.78rem; padding: 4px 0; }
  .tx-btn { min-height: 44px; padding: 10px 14px; font-size: 0.78rem; }
  .tx-actions { gap: 8px; }
  #customs-submit { min-height: 48px; padding: 12px 24px; }
}
