/* Self-hosted only. No @import, no external fonts, no url() to another origin.
 *
 * Promoted from prototypes/urgent/house-perimeter.html ("cold instrument, warm home").
 * The page argues an urgent problem, sells a security product, and publishes its own
 * limitations -- so the visual language is MEASUREMENT (technical grid, radar sweep,
 * monospace verdicts) with exactly one warm element in the frame: the lit house.
 *
 * GEOMETRY LIVES HERE, NOT IN THE TEMPLATE. The CSP is style-src 'self' with no
 * 'unsafe-inline', so a style="transform:..." attribute is silently dropped by the
 * browser and the 3D scene collapses into a pile of divs. Every per-element transform
 * the prototype emitted inline is therefore an nth-child rule below. Element ORDER in
 * templates/index.html.j2 is load-bearing for the scene; reordering it re-aims the
 * geometry.
 */

:root {
  --ink:        #e6ecf3;
  --ink-soft:   #8e9bb0;
  --ink-faint:  #67738a;
  --paper:      #080b11;
  --paper-warm: #0d131b;
  --rule:       #151c26;
  --rule-lt:    #18202b;
  --accent:     #5adca0;
  --alarm:      #ff5f3d;
  --alarm-lt:   #ff7a5e;
  --warn:       #dfb98f;
  --max:        44rem;
  --mono:       ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  overflow-x: hidden;
  font: 400 17px/1.7 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 1.6rem; }
.wide { max-width: 56rem; }

a { color: inherit; }
p { margin: 0 0 1.05rem; color: var(--ink-soft); }

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--accent); color: #04150e; padding: .6rem 1rem; z-index: 50;
}
.skip:focus { left: 0; }
a:focus-visible, .skip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------------------------------------------------------------- masthead */

.masthead {
  position: sticky; top: 0; z-index: 20;
  backdrop-filter: blur(10px);
  background: rgba(8, 11, 17, .86);
  border-bottom: 1px solid var(--rule);
}
.masthead .wrap {
  display: flex; justify-content: space-between; align-items: center;
  padding: .85rem 1.6rem;
}
.wordmark { margin: 0; font-size: .95rem; font-weight: 700; letter-spacing: -.01em; color: var(--ink); }
.masthead-note {
  margin: 0; font-family: var(--mono); font-size: .64rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--alarm-lt);
  border: 1px solid rgba(255, 122, 94, .34); padding: .24rem .6rem;
}

/* ---------------------------------------------------------------- hero */

.hero { padding: 2.8rem 0 .5rem; text-align: center; }

.alert {
  display: inline-flex; align-items: center; gap: .55rem; margin: 0 0 1.3rem;
  padding: .34rem .8rem; font-family: var(--mono);
  background: rgba(255, 122, 94, .08); border: 1px solid rgba(255, 122, 94, .28);
  color: #ff9d86; font-size: .68rem; letter-spacing: .16em; text-transform: uppercase;
}
.pip { width: 6px; height: 6px; background: var(--alarm); animation: blip 1.5s ease-in-out infinite; }
@keyframes blip {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 95, 61, .55); }
  70%      { box-shadow: 0 0 0 9px rgba(255, 95, 61, 0); }
}

h1 {
  margin: 0 auto; font-size: clamp(2.05rem, 6.2vw, 3.4rem); line-height: 1.09;
  font-weight: 720; letter-spacing: -.034em; max-width: 17ch; text-wrap: balance;
}
h1 em { font-style: normal; color: var(--alarm-lt); }
.sub { margin: 1.25rem auto 0; max-width: 38ch; color: var(--ink-soft); font-size: 1.03rem; }

/* ---------------------------------------------------------------- instrument scene */

.stage {
  position: relative; height: min(31rem, 80vw); margin: 1.2rem auto 0; max-width: 47rem;
  perspective: 1150px; perspective-origin: 50% 44%;
}
.hud { position: absolute; inset: 0; pointer-events: none; z-index: 6; }
.br { position: absolute; width: 16px; height: 16px; border: 1px solid rgba(120, 190, 255, .28); }
.tl  { left: 0;  top: 0;    border-right: 0; border-bottom: 0; }
.tr  { right: 0; top: 0;    border-left: 0;  border-bottom: 0; }
.bl  { left: 0;  bottom: 0; border-right: 0; border-top: 0; }
.br2 { right: 0; bottom: 0; border-left: 0;  border-top: 0; }

.tilt {
  position: absolute; inset: 0; transform-style: preserve-3d;
  transform: translateY(7%) rotateX(-23deg);
}
.world {
  position: absolute; left: 50%; top: 50%; width: 0; height: 0;
  transform-style: preserve-3d; animation: orbit 38s linear infinite;
}
@keyframes orbit { to { transform: rotateY(360deg); } }
.stage:hover .world, .stage:hover .sweep { animation-play-state: paused; }

.grid {
  position: absolute; left: -400px; top: -400px; width: 800px; height: 800px;
  transform: translateY(66px) rotateX(90deg);
  background:
    repeating-linear-gradient(0deg,  rgba(120, 190, 255, .09) 0 1px, transparent 1px 40px),
    repeating-linear-gradient(90deg, rgba(120, 190, 255, .09) 0 1px, transparent 1px 40px),
    repeating-linear-gradient(0deg,  rgba(120, 190, 255, .17) 0 1px, transparent 1px 200px),
    repeating-linear-gradient(90deg, rgba(120, 190, 255, .17) 0 1px, transparent 1px 200px);
  -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 26%, transparent 70%);
          mask-image: radial-gradient(circle at 50% 50%, #000 26%, transparent 70%);
}
.sweep {
  position: absolute; left: -260px; top: -260px; width: 520px; height: 520px;
  border-radius: 50%; transform: translateY(65px) rotateX(90deg);
  background: conic-gradient(from 0deg, rgba(90, 220, 160, .30), rgba(90, 220, 160, .05) 26%, transparent 40%);
  -webkit-mask-image: radial-gradient(circle, #000 30%, transparent 78%);
          mask-image: radial-gradient(circle, #000 30%, transparent 78%);
  animation: orbit 6s linear infinite;
}
.perimeter {
  position: absolute; left: -206px; top: -206px; width: 412px; height: 412px;
  border-radius: 50%; border: 1px solid rgba(90, 220, 160, .42);
  transform: translateY(65px) rotateX(90deg);
  box-shadow: 0 0 26px rgba(90, 220, 160, .18), inset 0 0 40px rgba(90, 220, 160, .06);
  animation: hum 3.6s ease-in-out infinite;
}
@keyframes hum { 0%, 100% { opacity: .6; } 50% { opacity: 1; } }

.ticks { position: absolute; inset: 0; }
.ticks span {
  position: absolute; left: 50%; top: 50%; width: 1px; height: 9px;
  background: rgba(90, 220, 160, .55); transform-origin: 50% 0;
}
/* Twelve marks at 30deg spacing. Inline transforms would be dropped by the CSP. */
.ticks span:nth-child(1)  { transform: rotate(0deg)   translateY(-206px); }
.ticks span:nth-child(2)  { transform: rotate(30deg)  translateY(-206px); }
.ticks span:nth-child(3)  { transform: rotate(60deg)  translateY(-206px); }
.ticks span:nth-child(4)  { transform: rotate(90deg)  translateY(-206px); }
.ticks span:nth-child(5)  { transform: rotate(120deg) translateY(-206px); }
.ticks span:nth-child(6)  { transform: rotate(150deg) translateY(-206px); }
.ticks span:nth-child(7)  { transform: rotate(180deg) translateY(-206px); }
.ticks span:nth-child(8)  { transform: rotate(210deg) translateY(-206px); }
.ticks span:nth-child(9)  { transform: rotate(240deg) translateY(-206px); }
.ticks span:nth-child(10) { transform: rotate(270deg) translateY(-206px); }
.ticks span:nth-child(11) { transform: rotate(300deg) translateY(-206px); }
.ticks span:nth-child(12) { transform: rotate(330deg) translateY(-206px); }

.arc {
  position: absolute; left: -206px; top: -206px; width: 412px; height: 412px;
  border-radius: 50%; border: 1px solid rgba(120, 190, 255, .16);
  border-bottom-color: transparent; border-left-color: transparent;
}
.a1 { transform: translateY(-140px) rotateY(0deg); }
.a2 { transform: translateY(-140px) rotateY(90deg); }

/* house: cold steel shell, warm interior -- the only warm thing in the frame */
.house {
  position: absolute; left: -90px; top: -72px; width: 180px; height: 138px;
  transform-style: preserve-3d;
}
.wall { position: absolute; inset: 0; border-top: 1px solid rgba(150, 205, 255, .3); }
.wall.f { background: linear-gradient(170deg, #2c3a4e, #1b2634); transform: rotateY(0deg)   translateZ(90px); }
.wall.r { background: linear-gradient(170deg, #263343, #17212c); transform: rotateY(90deg)  translateZ(90px); }
.wall.b { background: linear-gradient(170deg, #1b2531, #101720); transform: rotateY(180deg) translateZ(90px); }
.wall.l { background: linear-gradient(170deg, #212c3a, #141c26); transform: rotateY(270deg) translateZ(90px); }
.wall::after {
  content: ""; position: absolute; left: -2px; right: -2px; bottom: -3px; height: 10px;
  background: linear-gradient(180deg, #3c4c62, #232e3c);
}

/* Base half-width 90, apex rise 72 -> slant sqrt(90^2+72^2)=115.2, lean asin(90/115.2)
 * = 51.3deg. The angle is POSITIVE: negative leans the apex outward and leaves the
 * roof open, which is how the first attempt at this shape failed. */
.roof {
  position: absolute; left: 0; top: 0; width: 180px; height: 115.2px;
  transform-origin: 50% 100%; clip-path: polygon(50% 0, 100% 100%, 0 100%);
  border-bottom: 1px solid rgba(150, 205, 255, .35);
}
.roof.f { background: linear-gradient(180deg, #425468, #26323f); transform: translateY(-115.2px) rotateY(0deg)   translateZ(90px) rotateX(51.3deg); }
.roof.r { background: linear-gradient(180deg, #3a4a5c, #202b36); transform: translateY(-115.2px) rotateY(90deg)  translateZ(90px) rotateX(51.3deg); }
.roof.b { background: linear-gradient(180deg, #2b3846, #151d25); transform: translateY(-115.2px) rotateY(180deg) translateZ(90px) rotateX(51.3deg); }
.roof.l { background: linear-gradient(180deg, #334252, #1b242e); transform: translateY(-115.2px) rotateY(270deg) translateZ(90px) rotateX(51.3deg); }

.win {
  position: absolute; left: 24px; bottom: 34px; width: 40px; height: 34px;
  background: #ffc46b;
  box-shadow: 0 0 30px rgba(255, 190, 100, .75), inset 0 0 8px rgba(255, 238, 200, .9);
  animation: lamp 5s ease-in-out infinite;
}
.win.w2 { left: auto; right: 24px; background: #ffd489; animation-delay: 1.7s; }
.win.w3 { left: 24px; background: #8fc0ff; box-shadow: 0 0 30px rgba(143, 192, 255, .7); animation-delay: 3s; }
@keyframes lamp { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }

.door3 {
  position: absolute; left: 50%; bottom: 0; width: 34px; height: 48px; margin-left: -17px;
  background: linear-gradient(180deg, #2f6b5c, #1b4038);
  border: 1px solid rgba(90, 220, 160, .4);
}

/* inbound requests, refused at the perimeter */
.swarm { position: absolute; left: 50%; top: 50%; width: 0; height: 0; transform-style: preserve-3d; }
.swarm i {
  position: absolute; width: 8px; height: 8px; margin: -4px;
  background: var(--alarm); box-shadow: 0 0 12px 2px rgba(255, 95, 61, .7);
  animation-name: incoming; animation-timing-function: linear;
  animation-iteration-count: infinite; opacity: 0;
}
/* Start vector + timing per packet. Magnitude ~760 so the refusal lands on the ring. */
.swarm i:nth-child(1)  { --x: -540px; --y: -340px; --z:  320px; animation-duration: 3.4s; animation-delay: 0s; }
.swarm i:nth-child(2)  { --x:  580px; --y: -270px; --z: -250px; animation-duration: 4.0s; animation-delay: .5s; }
.swarm i:nth-child(3)  { --x: -290px; --y:  220px; --z:  600px; animation-duration: 3.7s; animation-delay: 1s; }
.swarm i:nth-child(4)  { --x:  400px; --y:  350px; --z:  450px; animation-duration: 4.5s; animation-delay: 1.5s; }
.swarm i:nth-child(5)  { --x: -640px; --y:   80px; --z: -260px; animation-duration: 3.2s; animation-delay: 2s; }
.swarm i:nth-child(6)  { --x:  190px; --y: -490px; --z: -490px; animation-duration: 4.2s; animation-delay: .3s; }
.swarm i:nth-child(7)  { --x:  660px; --y:  130px; --z:  240px; animation-duration: 3.8s; animation-delay: 1.3s; }
.swarm i:nth-child(8)  { --x: -390px; --y: -240px; --z: -550px; animation-duration: 4.7s; animation-delay: 2.5s; }
.swarm i:nth-child(9)  { --x:  120px; --y:  530px; --z: -470px; animation-duration: 3.5s; animation-delay: .8s; }
.swarm i:nth-child(10) { --x: -580px; --y:  310px; --z:  190px; animation-duration: 4.4s; animation-delay: 1.9s; }
.swarm i:nth-child(11) { --x:  480px; --y: -390px; --z:  350px; animation-duration: 3.6s; animation-delay: 2.9s; }
.swarm i:nth-child(12) { --x: -170px; --y: -560px; --z:  410px; animation-duration: 4.1s; animation-delay: 2.2s; }

@keyframes incoming {
  0%   { opacity: 0; transform: translate3d(var(--x), var(--y), var(--z)) scale(.4) rotate(45deg); }
  10%  { opacity: 1; }
  66%  { opacity: 1; background: var(--alarm);
         transform: translate3d(calc(var(--x) * .3), calc(var(--y) * .3), calc(var(--z) * .3)) scale(1) rotate(45deg); }
  73%  { opacity: 1; background: var(--accent); box-shadow: 0 0 22px 6px rgba(90, 220, 160, .8);
         transform: translate3d(calc(var(--x) * .28), calc(var(--y) * .28), calc(var(--z) * .28)) scale(2.4) rotate(45deg); }
  81%, 100% { opacity: 0; background: var(--accent);
         transform: translate3d(calc(var(--x) * .27), calc(var(--y) * .27), calc(var(--z) * .27)) scale(3.2) rotate(45deg); }
}

/* ---------------------------------------------------------------- verdict readout
 * Demonstrates the query-log capability. Sits BELOW the scene in normal flow:
 * overlaid on the animation it competed for the same pixels and read as clutter.
 * The "Illustrative" badge is content, not decoration -- these are example verdicts,
 * never measurements from the reader's own network. */

.readout { max-width: var(--max); margin: 1.4rem auto 0; padding: 0 1.6rem; font-family: var(--mono); text-align: left; }
.rbar {
  display: flex; justify-content: space-between; align-items: center;
  padding: .4rem .6rem; background: var(--paper-warm);
  border: 1px solid var(--rule-lt); border-bottom: 0;
}
.rtitle { font-size: .6rem; letter-spacing: .2em; text-transform: uppercase; color: #5d6c80; }
.rtag {
  font-size: .6rem; letter-spacing: .14em; text-transform: uppercase;
  color: #9a7a4a; border: 1px solid rgba(190, 150, 90, .32); padding: .08rem .4rem;
}
.log {
  display: grid; gap: 1px; grid-template-columns: repeat(2, 1fr);
  background: var(--rule-lt); border: 1px solid var(--rule-lt);
}
.row {
  display: flex; gap: .7rem; align-items: baseline; font-size: .68rem; line-height: 1.5;
  padding: .34rem .6rem; background: #0b1017;
  border-left: 2px solid transparent; opacity: .34;
  animation: tick 7.2s linear infinite;
}
.row b { font-weight: 600; letter-spacing: .08em; flex: none; width: 4.4rem; }
.row span { color: #7d8a9c; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row.refused { color: var(--alarm-lt); }
.row.allowed { color: var(--accent); }
.row.refused b { color: var(--alarm-lt); }
.row.allowed b { color: var(--accent); }
.row:nth-child(1) { animation-delay: 0s; }
.row:nth-child(2) { animation-delay: .9s; }
.row:nth-child(3) { animation-delay: 1.8s; }
.row:nth-child(4) { animation-delay: 2.7s; }
.row:nth-child(5) { animation-delay: 3.6s; }
.row:nth-child(6) { animation-delay: 4.5s; }
.row:nth-child(7) { animation-delay: 5.4s; }
.row:nth-child(8) { animation-delay: 6.3s; }
@keyframes tick {
  0%   { opacity: .3; border-left-color: transparent; }
  6%   { opacity: 1; border-left-color: currentColor; background: #131c26; }
  18%  { opacity: .72; background: #0b1017; }
  100% { opacity: .3; border-left-color: transparent; }
}

/* ---------------------------------------------------------------- page sections */

section { padding: 4.5rem 0; border-top: 1px solid var(--rule); }
h2 {
  margin: 0 0 .8rem; font-size: clamp(1.45rem, 3.9vw, 2rem); line-height: 1.2;
  font-weight: 720; letter-spacing: -.028em; text-wrap: balance; color: var(--ink);
}
.lead { margin: 0 0 2rem; color: var(--ink-soft); max-width: 46ch; }
.ic { width: 22px; height: 22px; flex: none; }

.cards { display: grid; align-items: stretch; }

.cards.threats { gap: .8rem; grid-template-columns: repeat(2, 1fr); }
.cards.threats .card {
  display: flex; gap: .9rem; padding: 1.3rem;
  background: rgba(255, 95, 61, .05); border: 1px solid rgba(255, 95, 61, .17);
}
.cards.threats .ic { color: var(--alarm-lt); margin-top: .15rem; }
.cards.threats h3 { margin: 0 0 .3rem; font-size: .95rem; font-weight: 650; color: #ffd6cb; }
.cards.threats p { margin: 0; font-size: .86rem; line-height: 1.55; color: #a3abb9; }

.cards.features {
  gap: 1px; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  background: var(--rule); border: 1px solid var(--rule);
}
.cards.features .card {
  display: block; padding: 1.6rem 1.5rem; background: var(--paper-warm);
  transition: background .15s;
}
.cards.features .card:hover { background: #111a24; }
.cards.features .ic { color: var(--accent); width: 24px; height: 24px; }
.cards.features h3 {
  margin: .9rem 0 .5rem; font-size: 1.02rem; font-weight: 650; line-height: 1.35;
  color: #e9eff6; letter-spacing: -.012em;
}
.cards.features p { margin: 0; font-size: .9rem; line-height: 1.6; color: #8896aa; }

/* ---------------------------------------------------------------- evidence + claims */

.argument { margin: 0 0 2.6rem; }
.argument h3 {
  margin: 0 0 .7rem; font-size: 1.05rem; font-weight: 650; color: var(--ink);
  letter-spacing: -.012em;
}

.claims { list-style: none; margin: 1.3rem 0 0; padding: 0; }
.claims li {
  margin: 0 0 1rem; display: grid; grid-template-columns: auto 1fr; gap: 1.4rem;
  align-items: start; padding: 1.3rem 1.4rem;
  background: var(--paper-warm); border: 1px solid var(--rule-lt);
  border-left: 2px solid var(--alarm);
}
.claim-value {
  font-size: clamp(2.2rem, 8vw, 3.1rem); line-height: .9; font-weight: 800;
  letter-spacing: -.045em; color: var(--alarm-lt); font-variant-numeric: tabular-nums;
}
.claim-value:empty { display: none; }
.claim-value:empty + .claim-body { grid-column: 1 / -1; }
.claim-text { display: block; font-size: 1rem; line-height: 1.55; color: #d3dbe6; }
.contested {
  display: block; margin-top: .9rem; padding: .75rem .95rem;
  background: rgba(190, 150, 90, .07); border-left: 2px solid rgba(190, 150, 90, .5);
  color: var(--warn); font-size: .82rem; line-height: 1.55;
}
.claims cite {
  display: block; margin-top: .65rem; font-size: .66rem; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-faint); font-family: var(--mono);
  font-style: normal;
}

/* ---------------------------------------------------------------- coverage table
 * Rendered as a real <table> with <tr data-capability>, because that is the shape
 * gate_capability_boundary verifies. The "door" look is styling on top of it, not a
 * different element. */

.coverage table { width: 100%; border-collapse: separate; border-spacing: 0 2px; margin-top: 1.6rem; }
.coverage tr { background: var(--paper-warm); }
.coverage td { padding: .85rem 1.05rem; font-size: .94rem; line-height: 1.5; vertical-align: top; }
.coverage td.cap-status {
  font-family: var(--mono); font-size: .6rem; font-weight: 600; letter-spacing: .13em;
  text-transform: uppercase; white-space: nowrap; width: 8.5rem; padding-top: 1.05rem;
  border-left: 2px solid;
}
.coverage tr.works-at-launch td.cap-status { border-left-color: var(--accent); color: var(--accent); }
.coverage tr.does-not-work  td.cap-status { border-left-color: var(--alarm); color: var(--alarm-lt); }
.coverage tr.works-at-launch td.cap-text { color: #c8dbd0; }
.coverage tr.does-not-work  td.cap-text { color: #95a0ae; }

.honest {
  margin-top: 1.6rem; padding: 1rem 1.2rem; background: #0b1017;
  border: 1px dashed #27313f; color: #8896aa; font-size: .88rem; line-height: 1.6;
}

/* ---------------------------------------------------------------- prose pages */

.prose h2 { margin-bottom: 1.2rem; }
.prose p { max-width: 46ch; }

/* ---------------------------------------------------------------- footer */

footer {
  padding: 3rem 0 4.5rem; border-top: 1px solid var(--rule);
  font-size: .76rem; line-height: 1.62; color: var(--ink-faint);
}
footer p { margin: 0 0 .6rem; max-width: 48ch; color: var(--ink-faint); }
footer a { color: var(--accent); }

/* ---------------------------------------------------------------- small screens */

@media (max-width: 40rem) {
  .cards.threats { grid-template-columns: 1fr; }
  .log { grid-template-columns: 1fr; }
}

@media (max-width: 34rem) {
  body { font-size: 1rem; }
  .stage { height: 22rem; perspective: 820px; }
  .claims li { grid-template-columns: 1fr; gap: .5rem; }
  .claim-value:empty + .claim-body { grid-column: 1; }
  .coverage td.cap-status { width: auto; display: block; padding-bottom: 0; }
  .coverage td.cap-text { display: block; padding-top: .3rem; }
  .masthead .wrap { flex-direction: column; align-items: flex-start; gap: .25rem; }
}

/* Motion is decoration here; the verdict rows must stay legible without it. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; }
  .world { transform: rotateY(-26deg); }
  .row { opacity: .85; }
}
