/* SG Systems microtools — the interactive model.
 *
 * One visual language for every scene: white line on black, weight used for
 * hierarchy rather than colour, and a single dashed treatment for anything
 * that marks a limit. Nothing here is tool-specific; a scene that needs a new
 * primitive adds it to app/scene/kit.js and styles it here, so the twelve
 * models keep looking like one product.
 */

/* A tool with a model uses the whole window — the heading, the deck and the
   results all have the width of the screen. Running prose keeps a readable
   measure inside it, because a paragraph does not become clearer by being
   two thousand pixels wide. */
.sg-wrap.is-wide { max-width: none; padding-inline: clamp(1rem, 3vw, 3rem); }
.sg-wrap.is-wide .sg-lead,
.sg-wrap.is-wide .t-subtitle,
.sg-wrap.is-wide .t-note,
.sg-wrap.is-wide .t-scope,
.sg-wrap.is-wide .t-steps,
.sg-wrap.is-wide .t-list,
.sg-wrap.is-wide .t-examples,
.sg-wrap.is-wide .t-production p { max-width: 54rem; }

.t-studio { margin-top: clamp(1.2rem, 3vh, 2rem); }

/* One screen: the console, the system and the readings share the window, so
   a reader can change a parameter and see every consequence without
   scrolling. */
.t-deck {
  display: grid;
  grid-template-columns: minmax(12.5rem, 15vw) minmax(0, 1fr) minmax(14rem, 17vw);
  gap: clamp(0.9rem, 1.8vw, 2rem);
  align-items: stretch;
  /* what is left of the window once the heading has had its say — a floor,
     not a ceiling: a tool with ten outputs may need a little more, and the
     readings must never spill over what comes after them */
  min-height: clamp(21rem, calc(100vh - 22rem), 44rem);
}

/* Both side columns have to fit what they hold: a scrollbar beside a model
   that is supposed to be read at a glance defeats the point. */
.t-console, .t-readout {
  display: grid;
  gap: 0.4rem;
  align-content: start;
  min-height: 0;
  position: relative;
}

/* Compact fields with a steady shape: nothing shifts under the hand when a
   value changes, and the guidance moves to a title rather than taking three
   lines of the console. */
/* one rule per field, not two: the shared stylesheet already draws a line
   above each one */
.t-console .t-field {
  margin: 0;
  display: grid;
  grid-template-rows: auto auto auto;
  row-gap: 0.25rem;
  padding: 0.5rem 0 0;
  border-bottom: 0;
}

.t-console .t-field > label {
  min-height: 1.9em;
  align-content: end;
  font-size: 0.6rem;
  letter-spacing: 0.1em;
}

.t-console .t-field input[type="number"] { padding: 0.25em 0.5em; font-size: 0.85rem; }
.t-console .t-field select { padding: 0.2em 0.3em; font-size: 0.72rem; }
.t-console .t-row { gap: 0.4rem; }
.t-console input[type="range"] { height: 0.9rem; }
/* the worked example is one line in the console; the full name is on the
   page below, where there is room for it */
.t-console .t-try { line-height: 1.4; min-width: 0; }
.t-console .t-try-lead { display: none; }      /* the console has no room for it */

.t-console .t-try .sg-link {
  font-size: 0.58rem;
  letter-spacing: 0.08em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.t-console .t-help { display: none; }
.t-console input[type="range"] { margin: 0; }
.t-console .t-try { font-size: 0.72rem; }
/* a disclosure that looks like one: label, count, chevron */
.t-console .t-advanced > summary {
  padding: 0.55rem 0;
  font-size: 0.6rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--dim);
  transition: color 0.2s;
}

.t-console .t-advanced > summary:hover { color: var(--fg); }
.t-console .t-advanced > summary .sg-index { flex: 1; }
.t-console .t-advanced > summary b {
  font-size: 0.6rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.1em 0.5em;
}

.t-chev { width: 0.75rem; height: 0.75rem; transition: transform 0.2s; flex: none; }
.t-advanced[open] .t-chev { transform: rotate(180deg); }

/* opened, the extra parameters float over the model rather than stretching
   the deck — the stage keeps its height, and with it its proportions */
.t-console .t-advanced[open] .t-advanced-panel {
  position: absolute;
  left: calc(100% + 0.8rem);
  top: 0;
  z-index: 6;
  width: min(32rem, 44vw);
  max-height: 100%;
  overflow: auto;
  padding: 1.1rem 1.3rem;
  border: 1px solid var(--line);
  background: rgba(5, 5, 5, 0.94);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.t-console .t-advanced-panel .t-group { margin: 0 0 1.1rem; }
.t-console .t-advanced-panel .t-group-fields { gap: 0.8rem 1.4rem; }
.t-console .t-advanced-panel .t-help { display: block; min-height: 0; font-size: 0.7rem; }
.t-console .t-scene-actions {
  margin-top: 0.2rem;
  gap: 0.35rem;
  flex-wrap: nowrap;
  position: sticky;
  bottom: 0;
  padding: 0.45rem 0 0;
  background: #050505;
}
/* one button left, and the column to put it in */
.t-console .t-scene-actions .sg-btn {
  font-size: 0.72rem;
  padding: 0.9em 1.4em;
  white-space: nowrap;
  flex: 1;
}

/* the sensitivity curve belongs beside the model, not a screen below it */
/* the curve belongs on the model: where this calculation sits on it is part
   of reading the system, not an afterthought below the fold */
/* the box the stage and its chart share */
.t-field { position: relative; height: 100%; min-width: 0; }

.t-chart.is-overlay {
  position: absolute;
  left: 1rem;
  top: 1rem;
  z-index: 3;
  width: clamp(15rem, 27%, 23rem);
  margin: 0;
  padding: 0.7rem 0.9rem 0.6rem;
  border: 1px solid var(--line);
  background: rgba(5, 5, 5, 0.62);
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
  overflow: hidden;
}

.t-chart.is-overlay h3 { font-size: 0.58rem; letter-spacing: 0.14em; line-height: 1.5; color: var(--faint); }
.t-chart.is-overlay .t-chart-svg { margin-top: 0.4rem; width: 100%; height: auto; }
.t-chart.is-overlay .t-chart-svg text { display: none; }
.t-chart.is-overlay .t-chart-svg path,
.t-chart.is-overlay .t-chart-svg polyline { stroke-opacity: 1; }
.t-chart.is-overlay .t-chart-svg circle { opacity: 0.85; }
.t-chart.is-overlay::before { content: none; }

/* ------------------------------------------------------------- stage --- */

.t-stage {
  position: relative;
  width: 100%;
  height: 100%;
  /* a zoomed-in drawing stays inside its own box */
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 2px;
  /* the drifting field belongs behind the page, not inside the model: the
     stage sits on its own ground so thin technical lines stay readable */
  background: rgba(5, 5, 5, 0.86);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  overflow: hidden;
}

/* the zoom cluster: small, in the corner, out of the way of the drawing */
.t-zoom {
  position: absolute;
  right: 0.6rem;
  bottom: 0.6rem;
  z-index: 4;
  display: flex;
  gap: 0.3rem;
  pointer-events: none;
}

.t-zoom-btn {
  pointer-events: auto;
  min-width: 1.7rem;
  height: 1.7rem;
  padding: 0 0.4rem;
  border: 1px solid var(--line);
  border-radius: 2px;
  background: rgba(5, 5, 5, 0.72);
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
  color: rgba(255, 255, 255, 0.75);
  font: inherit;
  font-size: 0.78rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.t-zoom-btn.is-fit {
  font-size: 0.56rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.t-zoom-btn:hover:not(:disabled) { color: #fff; border-color: rgba(255, 255, 255, 0.5); }
.t-zoom-btn:disabled { opacity: 0.35; cursor: default; }

.t-stage .v-flow,
.t-stage .v-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform-origin: 50% 50%;
}

.t-stage .v-flow { z-index: 0; }
.t-stage .v-svg { z-index: 1; }

/* the solid model: canvas below, labels in HTML above it so the type stays
   the site's own and stays crisp */
.t-stage .v-gl { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; cursor: grab; }
.t-stage .v-gl.is-grabbed { cursor: grabbing; }
.t-stage .v-labels { position: absolute; inset: 0; z-index: 1; pointer-events: none; }

.v-tag {
  position: absolute;
  top: 0; left: 0;
  white-space: nowrap;
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
  text-shadow: 0 0 6px #050505, 0 0 14px #050505;
  transition: opacity 0.2s;
}

.v-tag.is-value {
  font-family: var(--display);
  font-size: 0.82rem;
  letter-spacing: 0.02em;
  text-transform: none;
  color: #fff;
}

.v-tag.is-flag {
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(5, 5, 5, 0.75);
  padding: 0.25em 0.6em;
  color: rgba(255, 255, 255, 0.9);
}

.v-tag.is-flag.is-warn { border-color: #fff; color: #fff; }
.v-tag.is-note { color: rgba(255, 255, 255, 0.25); letter-spacing: 0.1em; }

.t-stage.is-solid { background: radial-gradient(ellipse at 50% 60%, rgba(255,255,255,0.045), rgba(5,5,5,0.92) 70%); }

/* the poster: the static schematic, shown until the scene takes over */
.t-stage .t-schem { padding: 1rem; }

/* ------------------------------------------------------- scene parts --- */

.v-svg { font-family: var(--body); }

.v-line { fill: none; stroke: rgba(255, 255, 255, 0.9); stroke-width: 1.4; }
.v-band { fill: rgba(255, 255, 255, 0.05); stroke: none; }          /* past the limit */
.v-rail { stroke: rgba(255, 255, 255, 0.4); stroke-width: 1.2; }
.v-bracket { stroke: rgba(255, 255, 255, 0.22); stroke-width: 1; }
.v-bus { stroke: rgba(255, 255, 255, 0.7); stroke-width: 1.4; }
.v-dot { fill: rgba(255, 255, 255, 0.8); }
.v-fin { stroke: rgba(255, 255, 255, 0.3); stroke-width: 1; }
.v-insul { stroke: rgba(255, 255, 255, 0.16); stroke-width: 5; stroke-linecap: round; }
.v-core { stroke: rgba(255, 255, 255, 0.78); stroke-width: 1.4; }
.v-sheath { fill: none; stroke: rgba(255, 255, 255, 0.5); stroke-width: 1.2; }
.v-coreface { fill: rgba(255, 255, 255, 0.78); }
.v-inset-rule { stroke: rgba(255, 255, 255, 0.12); stroke-width: 1; }
.v-arc { fill: none; stroke: rgba(255, 255, 255, 0.4); stroke-width: 1; }
.v-plateBox { fill: rgba(255, 255, 255, 0.9); stroke: none; }
.v-plate { fill: #050505; font-family: var(--display); font-size: 11.5px; }
.v-phase { fill: rgba(255, 255, 255, 0.45); font-size: 9.5px; letter-spacing: 0.1em; }
.v-marks.is-beyond .v-threshold { opacity: 0.45; }
/* the pumped line */
.v-pipe { fill: none; stroke: rgba(255, 255, 255, 0.55); stroke-linecap: round; stroke-linejoin: round; }
.v-bore { fill: none; stroke: #0b0b0b; stroke-linecap: round; stroke-linejoin: round; }
.v-liquid { fill: rgba(255, 255, 255, 0.14); }
.v-bar-static { fill: rgba(255, 255, 255, 0.72); }
.v-bar-friction { fill: rgba(255, 255, 255, 0.2); }

/* the reconciliation flow */
.v-lane { fill: none; stroke: rgba(255, 255, 255, 0.22); stroke-width: 1; }
.v-card { fill: rgba(255, 255, 255, 0.75); }
.v-cost { fill: #fff; font-family: var(--display); font-size: 22px; }
.v-queue { }
.is-done .v-box { stroke: rgba(255, 255, 255, 0.4); }
.is-gate .v-box { stroke: rgba(255, 255, 255, 0.75); }
.is-desk .v-box { stroke: #fff; stroke-width: 1.6; }

.v-flag { fill: rgba(255, 255, 255, 0.1); stroke: rgba(255, 255, 255, 0.4); stroke-width: 1; }
.v-flag-lab { fill: rgba(255, 255, 255, 0.9); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; }
.v-fill { fill: rgba(255, 255, 255, 0.045); stroke: none; }
.v-rule { stroke: rgba(255, 255, 255, 0.3); stroke-width: 1; }
.v-box { fill: rgba(5, 5, 5, 0.9); stroke: rgba(255, 255, 255, 0.72); stroke-width: 1.2; }
.v-wire { stroke: rgba(255, 255, 255, 0.5); stroke-width: 1.4; }
.v-tick { stroke: rgba(255, 255, 255, 0.3); stroke-width: 1; }
.v-leg { stroke: rgba(255, 255, 255, 0.85); stroke-width: 3.2; stroke-linecap: round; }
.v-leg-x { stroke: rgba(255, 255, 255, 0.45); }

/* every limit in every scene is drawn the same way */
.v-threshold {
  stroke: rgba(255, 255, 255, 0.55);
  stroke-width: 1;
  stroke-dasharray: 4 4;
}

.v-over-line { stroke: #fff; stroke-width: 3; stroke-linecap: round; }

.v-lab,
.v-tick-lab {
  fill: rgba(255, 255, 255, 0.55);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.v-title { fill: rgba(255, 255, 255, 0.55); font-size: 10.5px; letter-spacing: 0.22em; text-transform: uppercase; }
.v-val { fill: #fff; font-size: 13px; font-family: var(--display); letter-spacing: 0.02em; }
.v-warn { fill: #fff; font-size: 11px; font-family: var(--display); letter-spacing: 0.12em; text-transform: uppercase; }
.v-note { fill: rgba(255, 255, 255, 0.28); font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase; }

/* the part a changed parameter acts on, lit for a moment */
.is-lit { animation: v-lit 1.2s ease-out; }

@keyframes v-lit {
  0% { filter: drop-shadow(0 0 0 rgba(255, 255, 255, 0)); }
  18% { filter: drop-shadow(0 0 7px rgba(255, 255, 255, 0.75)); }
  100% { filter: drop-shadow(0 0 0 rgba(255, 255, 255, 0)); }
}

/* ---------------------------------------------------------- live HUD --- */

/* the headline keeps the width; the rest pair up, so a long list of outputs
   does not push the column past the model beside it */
.t-hud {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem 1rem;
  margin: 0;
}

.t-hud .is-lead { grid-column: 1 / -1; }

.t-hud li { display: flex; flex-direction: column; gap: 0.15rem; }
.t-hud b { font-family: var(--display); font-size: 0.88rem; line-height: 1.1; }
.t-readout .t-interpret { min-height: 4.2em; }
/* the caption under a figure has to be read, not merely sensed: --faint is
   for things the eye may skip, and these are not that */
.t-hud span {
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}
.t-hud .is-lead b { font-size: clamp(1.5rem, 2.2vw, 2.2rem); line-height: 0.95; }
.t-hud .is-lead { padding-bottom: 0.4rem; border-bottom: 1px solid var(--line); }

/* both lines keep their room whatever they say, so the column below them
   does not shift every time a figure changes */
.t-changed {
  min-height: 4.4em;
  margin-top: 0.1rem;
  max-width: 44rem;
  color: rgba(255, 255, 255, 0.82);
  font-size: 0.78em;
  line-height: 1.4;
}

.t-scene-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1.2rem; }
.t-scene-actions .sg-btn { font-size: 0.72rem; padding: 0.7em 1.4em; }

/* keeping the calculation belongs beside it, not a screen below */
.t-keep { margin-top: 0.4rem; padding-top: 0.8rem; border-top: 1px solid var(--line); }
.t-keep .t-action-row { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.t-keep .sg-btn { font-size: 0.6rem; padding: 0.6em 1em; white-space: nowrap; }
.t-keep .t-note { margin-top: 0.6rem; font-size: 0.68rem; line-height: 1.5; }

/* the full output spreads across the page rather than hugging the left */
.sg-wrap.is-wide .t-values {
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1rem 1.6rem;
}

.sg-wrap.is-wide .t-result { margin-top: clamp(1.4rem, 3vh, 2.2rem); }

/* -------------------------------------------------------- annotations --- */

/* the walkthrough is part of the page, not something to open: four lines
   that say what the model is doing, under the deck where they can be read
   beside it */
/* the sentence that says the drawing is the calculation, not a decoration */
.t-model-note {
  margin-top: clamp(1rem, 2.4vh, 1.6rem);
  color: var(--faint);
  font-size: 0.82rem;
  line-height: 1.6;
  max-width: 48rem;
}

/* the experiment the page suggests: a reader should not have to stumble on
   the most telling behaviour of a model by accident */
.t-experiment {
  margin-top: clamp(1rem, 2.4vh, 1.5rem);
  padding: 1rem 1.2rem;
  border: 1px solid var(--line);
  border-left: 2px solid rgba(255, 255, 255, 0.55);
  background: rgba(255, 255, 255, 0.02);
}

.t-experiment h2 { margin: 0 0 0.45rem; }
.t-experiment p { margin: 0; max-width: 54rem; line-height: 1.7; }

.t-walkthrough {
  margin-top: clamp(1.4rem, 3vh, 2.2rem);
  padding-top: 1.2rem;
  border-top: 1px solid var(--line);
}

.t-annotations {
  list-style: none;
  counter-reset: step;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 1.4rem 2.6rem;
  align-items: start;
  margin-top: 1rem;
}

/* number and title on one line, the explanation under them across the whole
   width of the step — a column of prose beside a two-word heading wastes
   both */
.t-annotations li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 1.4rem 1fr;
  gap: 0.45rem 0.7rem;
  align-items: baseline;
  align-content: start;
}

.t-annotations li::before {
  content: counter(step);
  grid-column: 1;
  font-family: var(--display);
  font-size: 0.75rem;
  color: var(--faint);
}

.t-annotations b {
  grid-column: 2;
  font-family: var(--display);
  text-transform: uppercase;
  font-size: 0.78rem;
  letter-spacing: 0.1em;
}

.t-annotations span {
  grid-column: 1 / -1;
  color: var(--dim);
  font-size: 0.92em;
}

/* ------------------------------------------------------------ controls --- */

.t-advanced { margin-top: 0.4rem; }
.t-advanced > summary { cursor: pointer; display: flex; justify-content: space-between; gap: 1rem; padding: 0.8rem 0; border-top: 1px solid var(--line); }
.t-advanced > summary::-webkit-details-marker { display: none; }
.t-advanced > summary b { font-family: var(--display); font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; }

/* ------------------------------------------------------------- mobile --- */

@media (max-width: 1100px) {
  .t-deck { grid-template-columns: 1fr; height: auto; }
  .t-console, .t-readout { overflow: visible; }
  .t-console .t-help { display: block; min-height: 0; }
  .t-field { height: auto; order: -2; }
  .t-stage { height: clamp(20rem, 52vh, 30rem); }
  /* over the scene there is no room for it on a phone: the chart reads as a
     block of its own under the drawing, labels and all */
  .t-chart.is-overlay {
    position: static;
    width: auto;
    margin-top: 0.8rem;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .t-chart.is-overlay .t-chart-svg text { display: revert; }
  .t-readout { order: -1; }
  .t-hud { grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr)); }
  .t-console { grid-template-columns: repeat(2, 1fr); align-items: start; }
  .t-console .t-errors, .t-console .t-advanced, .t-console .t-scene-actions,
  .t-console .t-try { grid-column: 1 / -1; }
}

@media (max-width: 560px) {
  .t-console { grid-template-columns: 1fr; }
  .t-console .t-help { min-height: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .is-lit { animation: none; }
}

@media print {
  .t-scene-actions, .t-stage .v-flow { display: none; }
  .t-annotations { display: grid !important; }
}

/* ---- the flight demo ------------------------------------------------ */

.v-axis { stroke: rgba(255, 255, 255, 0.7); stroke-width: 1.4; }
.v-grid { stroke: rgba(255, 255, 255, 0.12); stroke-width: 1; }
.v-guide { stroke: rgba(255, 255, 255, 0.45); stroke-width: 1; stroke-dasharray: 5 6; }
.v-trace { stroke: rgba(255, 255, 255, 0.34); stroke-width: 1.2; }
.v-box-soft { fill: rgba(255, 255, 255, 0.1); stroke: rgba(255, 255, 255, 0.55); stroke-width: 1; }
.v-wheel { fill: rgba(5, 5, 5, 0.9); stroke: rgba(255, 255, 255, 0.6); stroke-width: 1.1; }

/* A plume is the valve that makes it: nothing is drawn where nothing fires,
   and the length is the duty cycle rather than a flourish. */
.v-jet { fill: rgba(255, 255, 255, 0.5); }
/* the flight path: present, but never competing with the car on it */
.v-trace { stroke-dasharray: 2 5; }

/* the altitude above the car in the solid flight scene */
.v-tag.is-figure {
  font-family: var(--display);
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.92);
  transform: translate(-50%, -140%);
}

/* A callout names a part of the machine. It is pinned to the part, so it
   points inward from whichever side it sits on. */
.v-tag.is-callout {
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  color: rgba(255, 255, 255, 0.52);
}
/* the black lower band of the car in the flat flight scene */
.v-band-dark { fill: rgba(5, 5, 5, 0.95); stroke: rgba(255, 255, 255, 0.4); stroke-width: 0.8; }

/* the labels on the valve-signal strips behind the car */
.v-tag.is-strip { font-size: 0.56rem; letter-spacing: 0.12em; color: rgba(255, 255, 255, 0.5); }
.v-tag.is-strip.is-note { color: rgba(255, 255, 255, 0.34); }

/* ------------------------------------------------- readability scrims ----
 * The landing's device, carried to every block of a tool page or a demo
 * that sits over the moving field and did not have one: a blur panel under
 * the words, so the field softens behind them and stays sharp elsewhere.
 *
 * Two shapes. A short line of text takes the landing's feathered ellipse.
 * A tall column — the console, the readout, a list of steps — takes a
 * rectangle feathered at its edges instead: an ellipse fitted to a tall box
 * leaves its corners outside the blur, and the first and last lines of a
 * column sit exactly there.
 */

.t-subtitle, .t-model-note,
.t-experiment, .t-walkthrough, .d-about-text { position: relative; }

.t-subtitle::before, .t-model-note::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -0.9rem -1.4rem;
  pointer-events: none;
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
  -webkit-mask-image: radial-gradient(ellipse 100% 100% at 50% 50%, #000 55%, transparent 99%);
  mask-image: radial-gradient(ellipse 100% 100% at 50% 50%, #000 55%, transparent 99%);
}

.t-console::before, .t-readout::before,
.t-experiment::before, .t-walkthrough::before, .d-about-text::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -1rem -1.4rem;
  pointer-events: none;
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
  -webkit-mask-image:
    linear-gradient(to right, transparent, #000 1.4rem, #000 calc(100% - 1.4rem), transparent),
    linear-gradient(to bottom, transparent, #000 1rem, #000 calc(100% - 1rem), transparent);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent, #000 1.4rem, #000 calc(100% - 1.4rem), transparent),
    linear-gradient(to bottom, transparent, #000 1rem, #000 calc(100% - 1rem), transparent);
  mask-composite: intersect;
}
