/* ==========================================================================
   Aniam Benor - portfolio
   Dark-first "systems dashboard" theme with a light toggle and full RTL.
   Layout uses logical properties throughout so RTL flips for free.
   ========================================================================== */

/* ------------------------------------------------------------------ reset */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
img, svg { display: block; max-width: 100%; }
button, input, textarea { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }

/* Motion is gated on the resolved preference from motion.js, not on the media
   query alone, so a visitor can opt back in even with Reduce Motion on at the
   OS level. The media query still applies as a no-JS fallback, scoped to
   :not([data-motion]) so it stops applying the moment motion.js resolves. */
@media (prefers-reduced-motion: reduce) {
  html:not([data-motion]) { scroll-behavior: auto; }
  html:not([data-motion]) *,
  html:not([data-motion]) *::before,
  html:not([data-motion]) *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

html[data-motion="off"] { scroll-behavior: auto; }
html[data-motion="off"] *,
html[data-motion="off"] *::before,
html[data-motion="off"] *::after {
  animation-duration: .01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: .01ms !important;
}

/* ----------------------------------------------------------------- tokens */
:root {
  --bg:          #08090d;
  --bg-elev:     #0e1117;
  --surface:     #111520;
  --surface-2:   #161b28;
  --line:        #222839;
  --line-soft:   #1a1f2c;

  --text:        #e8ebf2;
  --text-strong: #ffffff;
  --muted:       #8a93a8;
  --faint:       #5b6377;

  --accent:      #5eead4;
  --accent-dim:  #2dd4bf;
  --accent-ink:  #042f2a;

  --live:        #34d399;
  --sched:       #fbbf24;
  --idle:        #64748b;

  --radius:   14px;
  --radius-s: 9px;
  --maxw:     1140px;

  --shadow: 0 1px 0 rgba(255,255,255,.03) inset, 0 18px 48px -24px rgba(0,0,0,.9);

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial,
          "Arial Hebrew", "Noto Sans Hebrew", "Heebo", "Assistant", sans-serif;
}

[data-theme="light"] {
  --bg:          #fbfbfc;
  --bg-elev:     #ffffff;
  --surface:     #ffffff;
  --surface-2:   #f4f5f8;
  --line:        #e2e5ec;
  --line-soft:   #edeff4;

  --text:        #1c2230;
  --text-strong: #05070c;
  --muted:       #5d677c;
  --faint:       #8b95a8;

  --accent:      #0d9488;
  --accent-dim:  #0f766e;
  --accent-ink:  #ecfdf8;

  --live:        #059669;
  --sched:       #b45309;
  --idle:        #94a3b8;

  --shadow: 0 1px 2px rgba(16,24,40,.05), 0 12px 32px -20px rgba(16,24,40,.28);
}

/* ------------------------------------------------------------------- base */
body {
  font-family: var(--sans);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: 24px; }

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip {
  position: absolute; inset-inline-start: -9999px; top: 0; z-index: 100;
  background: var(--accent); color: var(--accent-ink);
  padding: 10px 16px; border-radius: 0 0 8px 0; font-weight: 600;
}
.skip:focus { inset-inline-start: 0; }

/* ----------------------------------------------------------------- header */
.hdr {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  border-block-end: 1px solid var(--line-soft);
}
.hdr-in {
  display: flex; align-items: center; gap: 20px;
  height: 62px;
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 650; letter-spacing: -.01em; }
.brand-mark {
  width: 28px; height: 28px; border-radius: 8px;
  display: grid; place-items: center;
  background: linear-gradient(140deg, var(--accent), var(--accent-dim));
  color: var(--accent-ink);
  font-family: var(--mono); font-size: 11px; font-weight: 700; letter-spacing: .02em;
}
.brand-name { font-size: 15px; }

.nav { display: flex; gap: 4px; margin-inline-start: auto; }
.nav a {
  padding: 7px 12px; border-radius: 8px; font-size: 14px; color: var(--muted);
  transition: color .16s, background .16s;
}
.nav a:hover { color: var(--text); background: var(--surface-2); }

.hdr-tools { display: flex; align-items: center; gap: 6px; }

.tbtn {
  height: 32px; min-width: 32px; padding-inline: 9px;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--surface); color: var(--muted);
  font-size: 12px; font-weight: 600; cursor: pointer;
  font-family: var(--mono); letter-spacing: .03em;
  transition: color .16s, border-color .16s, background .16s;
}
.tbtn:hover { color: var(--text); border-color: var(--accent); }
.tbtn svg { width: 15px; height: 15px; }

@media (max-width: 760px) {
  .nav { display: none; }
  .hdr-tools { margin-inline-start: auto; }
}

/* -------------------------------------------------------------- night sky */
/* Fixed starfield canvas sits above the body background and below all
   content. Hidden in the light theme (a night sky in daylight makes no
   sense) and paused by stars.js so it costs nothing while invisible.      */
#sky {
  position: fixed; inset: 0; z-index: 0;
  pointer-events: none; transition: opacity .5s ease;
}
[data-theme="light"] #sky { opacity: 0; }

/* When real footage is playing it brings its own sky, so stand the canvas
   starfield down rather than layering two skies on top of each other. */
[data-video="on"] #sky { opacity: 0; }

#app { position: relative; z-index: 1; }

/* ----------------------------------------------------------- hero video -- */
/* Mounted by scene.js outside #app, so a language re-render never restarts
   playback. Fixed and full bleed, with a scrim so copy stays readable. */
#herovid {
  position: fixed; inset: 0; z-index: 0;
  pointer-events: none; overflow: hidden;
  background: var(--bg);
}
#herovid video {
  inline-size: 100%; block-size: 100%;
  object-fit: cover; display: block;
}
#herovid::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to bottom,
    rgba(6,8,12,.42) 0%, rgba(6,8,12,.62) 45%, rgba(6,8,12,.88) 78%, var(--bg) 100%);
}
[data-theme="light"] #herovid { display: none; }

/* The drawn silhouette steps back when there is real footage behind it. */
[data-video-dim="on"] .scene { opacity: .3; }

/* ------------------------------------------------------------------- hero */
.hero {
  position: relative; overflow: hidden;
  padding-block: clamp(64px, 12vw, 128px) 40px;
  min-block-size: clamp(600px, 86vh, 880px);
}
.hero > .wrap { position: relative; z-index: 2; }

/* Milky Way band, angled like the reference photograph. */
.mway {
  position: absolute; z-index: 0; pointer-events: none;
  inset-block-start: -14%; inset-inline-start: -18%;
  inline-size: 95%; block-size: 80%;
  background: radial-gradient(50% 20% at 50% 50%,
    rgba(198,208,255,.15), rgba(150,170,235,.055) 46%, transparent 72%);
  filter: blur(26px);
  transform: rotate(-32deg);
}
[dir="rtl"] .mway { transform: rotate(32deg); }
[data-theme="light"] .mway { display: none; }

/* --------------------------------------------------- drifting clouds -- */
/* Three blurred masses crossing at different speeds. This is what sells the
   scene as moving footage rather than a still, and it is only compositor
   work so it costs almost nothing. */
/* .hero has overflow:hidden, so ANY decorative layer in here gets hard-clipped
   at the hero's bottom edge. A blurred layer that reaches that edge turns into
   a visible full-width seam - which is exactly what the old `.mist` band did
   (removed 2026-08-16). The mask below fades these out well before the cut, so
   the clip can never produce a line. Keep it on anything you add here. */
.clouds {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none; overflow: hidden;
  mask-image: linear-gradient(to bottom, #000 0%, #000 62%, transparent 92%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 62%, transparent 92%);
}
.clouds i {
  position: absolute; display: block; border-radius: 50%;
  background: radial-gradient(closest-side,
    rgba(126,158,226,.17), rgba(96,126,200,.07) 55%, transparent 76%);
  filter: blur(26px);
  animation: drift linear infinite;
  will-change: transform;
}
.clouds i:nth-child(1) { inline-size: 62%; block-size: 40%; top:  4%; animation-duration: 168s; }
.clouds i:nth-child(2) { inline-size: 44%; block-size: 30%; top: 26%; animation-duration: 232s; animation-delay: -70s; opacity: .75; }
.clouds i:nth-child(3) { inline-size: 78%; block-size: 34%; top: 48%; animation-duration: 296s; animation-delay: -150s; opacity: .55; }

@keyframes drift {
  from { transform: translate3d(-70%, 0, 0); }
  to   { transform: translate3d(170%, 0, 0); }
}


[data-theme="light"] .clouds { display: none; }

/* The distant village.
   NOTE: a warm `.horizon` gradient used to sit here (orange, 26% of the hero).
   It worked over the plain canvas but read as a muddy grey-brown band under
   the stats panel once real footage went in behind it. Removed 2026-08-16.
   Do not reintroduce a full-width warm wash over the video. */
.village {
  position: absolute; z-index: 0; pointer-events: none;
  inset-block-end: 7%; inset-inline-start: 4%;
  inline-size: min(320px, 34vw); block-size: 44px;
}
.village i {
  position: absolute; inline-size: 2px; block-size: 2px; border-radius: 50%;
  background: #ffd9a8; box-shadow: 0 0 5px 1.5px rgba(255,186,110,.7);
  animation: flick 4.5s ease-in-out infinite;
}
@keyframes flick { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }
[data-theme="light"] .village { display: none; }

/* ------------------------------------------------------- the flute player */
.scene {
  position: absolute; z-index: 1; pointer-events: none;
  /* Anchored to the TOP of the hero, not the bottom. The stats row sits at a
     roughly fixed distance from the hero top regardless of viewport height, so
     a percentage anchored to the bottom drifts into it on tall screens.
     Sized by height so the figure always stays slender. */
  inset-block-start: clamp(56px, 7vh, 104px);
  inset-inline-end: 6%;
  block-size: min(430px, 50vh);
  aspect-ratio: 32 / 62;
}
[dir="rtl"] .scene { transform: scaleX(-1); }

.scene .aura {
  position: absolute; inset: -15% -48% 2% -48%;
  background:
    radial-gradient(44% 40% at 52% 30%, rgba(104,198,255,.92), transparent 66%),
    radial-gradient(62% 56% at 50% 44%, rgba(40,122,255,.5),  transparent 74%);
  filter: blur(26px);
  animation: breathe 9s ease-in-out infinite;
}
@keyframes breathe {
  0%, 100% { transform: scale(1);    opacity: .82; }
  50%      { transform: scale(1.05); opacity: 1;   }
}

/* Motes canvas, drawn by scene.js. Sits above the figure so the sparks read
   as being in front of him, drifting out over the valley. */
.scene .motes { position: absolute; inset: 0; z-index: 2; pointer-events: none; }

.scene .fig { position: absolute; inset: 0; z-index: 1; }
.scene .fig > * {
  inline-size: 100%; block-size: 100%;
  object-fit: contain; object-position: bottom center;
  display: block;
}

/* In the light theme the silhouette stays fully black - fading it just turns
   it into a grey blob. Only the aura softens, so it reads like a woodcut. */
[data-theme="light"] .scene { opacity: 1; }
[data-theme="light"] .scene .aura {
  opacity: .5; filter: blur(30px);
  background:
    radial-gradient(46% 42% at 52% 32%, rgba(56,150,240,.5),  transparent 68%),
    radial-gradient(64% 58% at 50% 46%, rgba(30,90,220,.26), transparent 74%);
}

@media (max-width: 900px) {
  /* Only ever set ONE axis here. Setting inline-size as well as block-size
     makes both definite, which silently cancels the aspect-ratio and renders
     the figure squashed. Let block-size drive it and pull it off the edge so
     it stays atmosphere rather than competing with the headline. */
  .scene {
    block-size: min(280px, 32vh);
    inset-block-start: clamp(40px, 6vh, 80px);
    inset-inline-end: -10%;
    opacity: .5;
  }
  .village { inline-size: 200px; }
}

.hero::before {
  content: ""; position: absolute; inset: -40% -20% auto -20%; height: 620px;
  background:
    radial-gradient(50% 60% at 22% 0%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 70%),
    radial-gradient(40% 50% at 78% 10%, color-mix(in srgb, #7c8cff 13%, transparent), transparent 70%);
  filter: blur(10px); pointer-events: none;
}
.hero::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to right, var(--line-soft) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line-soft) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(72% 58% at 50% 22%, #000 0%, transparent 76%);
  -webkit-mask-image: radial-gradient(72% 58% at 50% 22%, #000 0%, transparent 76%);
  opacity: .22;                 /* the starfield carries the texture now */
}
[data-theme="light"] .hero::after { opacity: .55; }
/* NOTE: do not add `.hero > * { position: relative }` back. It outranks the
   absolute positioning on .scene / .village / .mway and drops them into normal
   flow, which pushes the hero copy off the screen. .hero > .wrap above already
   lifts the content over the decorative layers.                              */

.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 34%, transparent);
  background: color-mix(in srgb, var(--accent) 9%, transparent);
  padding: 5px 12px; border-radius: 999px;
}

h1 {
  margin-block-start: 22px;
  font-size: clamp(2.4rem, 7.2vw, 4.4rem);
  line-height: 1.03;
  letter-spacing: -.035em;
  font-weight: 700;
  color: var(--text-strong);
  max-width: 15ch;
}
.hero-sub {
  margin-block-start: 22px;
  font-size: clamp(1rem, 1.9vw, 1.175rem);
  color: var(--muted);
  max-width: 62ch;
}

.hero-cta { margin-block-start: 32px; display: flex; flex-wrap: wrap; gap: 12px; }

.btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 12px 22px; border-radius: 11px;
  font-size: 15px; font-weight: 600; cursor: pointer;
  border: 1px solid transparent;
  transition: transform .16s, background .16s, border-color .16s, color .16s;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: var(--accent-dim); }
.btn-ghost { background: var(--surface); border-color: var(--line); color: var(--text); }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn .arw { transition: transform .18s; }
[dir="rtl"] .btn .arw { transform: scaleX(-1); }
.btn:hover .arw { transform: translateX(3px); }
[dir="rtl"] .btn:hover .arw { transform: scaleX(-1) translateX(3px); }

/* ------------------------------------------------------------------ stats */
.stats {
  margin-block-start: 56px;
  display: grid; grid-template-columns: repeat(4, 1fr);
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); box-shadow: var(--shadow);
  overflow: hidden;
}
.stat { padding: 22px 24px; border-inline-end: 1px solid var(--line-soft); }
.stat:last-child { border-inline-end: 0; }
.stat-v {
  font-family: var(--mono); font-size: clamp(1.7rem, 4vw, 2.3rem);
  font-weight: 600; letter-spacing: -.03em; color: var(--text-strong); line-height: 1.1;
}
.stat-l { margin-block-start: 5px; font-size: 12.5px; color: var(--faint); line-height: 1.35; }

@media (max-width: 720px) {
  .stats { grid-template-columns: repeat(2, 1fr); }
  .stat:nth-child(2) { border-inline-end: 0; }
  .stat:nth-child(-n+2) { border-block-end: 1px solid var(--line-soft); }
}

/* --------------------------------------------------------------- sections */
/* scroll-margin keeps section titles clear of the sticky header when an
   anchor link jumps to them. */
section { padding-block: clamp(56px, 8vw, 92px); scroll-margin-block-start: 74px; }
.sec-head { margin-block-end: 30px; }
.sec-title {
  font-size: clamp(1.6rem, 3.4vw, 2.15rem); font-weight: 680;
  letter-spacing: -.028em; color: var(--text-strong);
}
.sec-sub { margin-block-start: 8px; color: var(--muted); max-width: 60ch; font-size: 15.5px; }

.sec-bar {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
}

/* -------------------------------------------------------------- filter UI */
.filters { display: flex; gap: 7px; flex-wrap: wrap; }
.chip {
  padding: 6px 13px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--line); background: transparent; color: var(--muted);
  font-size: 12.5px; font-weight: 600;
  transition: color .16s, border-color .16s, background .16s;
}
.chip:hover { color: var(--text); border-color: var(--faint); }
.chip[aria-pressed="true"] {
  color: var(--accent-ink); background: var(--accent);
  border-color: var(--accent);
}

/* ------------------------------------------------------------- system row */
.panel {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); box-shadow: var(--shadow); overflow: hidden;
}

.sys {
  border-block-end: 1px solid var(--line-soft);
  transition: background .18s;
}
.sys:last-child { border-block-end: 0; }
.sys:hover { background: var(--surface-2); }
.sys.is-open { background: var(--surface-2); }

.sys-btn {
  width: 100%; text-align: start; cursor: pointer;
  background: none; border: 0;
  display: grid;
  grid-template-columns: 18px minmax(0,1fr) auto 20px;
  align-items: center; gap: 16px;
  padding: 17px 22px;
}
[dir="rtl"] .sys-btn { text-align: start; }

.dot {
  inline-size: 8px; block-size: 8px; border-radius: 50%;
  background: var(--idle); justify-self: center; position: relative;
}
.dot[data-s="live"], .dot[data-s="scheduled"] { background: var(--live); }
.dot[data-s="scheduled"] { background: var(--sched); }
.dot[data-s="live"]::after {
  content: ""; position: absolute; inset: -4px; border-radius: 50%;
  border: 1px solid var(--live); opacity: .55;
  animation: ping 2.4s cubic-bezier(0,0,.2,1) infinite;
}
@keyframes ping {
  0%   { transform: scale(.7); opacity: .7; }
  70%  { transform: scale(1.9); opacity: 0; }
  100% { transform: scale(1.9); opacity: 0; }
}

.sys-main { min-width: 0; }
.sys-title {
  font-size: 15.5px; font-weight: 620; color: var(--text-strong); letter-spacing: -.012em;
}
.sys-meta {
  margin-block-start: 3px; font-size: 13px; color: var(--muted);
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
.sys-client {
  font-family: var(--mono); font-size: 11px; color: var(--faint);
  letter-spacing: .02em; white-space: nowrap;
}
.sys-sum { color: var(--muted); }

.sys-metric { text-align: end; white-space: nowrap; }
/* These are spans, so they need an explicit block display or the value and
   its label run together on one line ("07:00every day"). */
.sys-metric-v {
  display: block;
  font-family: var(--mono); font-size: 13.5px; font-weight: 600; color: var(--accent);
}
.sys-metric-l { display: block; font-size: 11px; color: var(--faint); margin-block-start: 2px; }

.caret { color: var(--faint); transition: transform .22s; justify-self: center; }
.sys.is-open .caret { transform: rotate(180deg); }

.sys-body {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .3s ease;
}
.sys.is-open .sys-body { grid-template-rows: 1fr; }
.sys-body > div { overflow: hidden; }
.sys-detail {
  padding: 0 22px 20px calc(22px + 18px + 16px);
  color: var(--muted); font-size: 14.5px; max-width: 78ch;
}
[dir="rtl"] .sys-detail { padding: 0 calc(22px + 18px + 16px) 20px 22px; }

.tags { display: flex; flex-wrap: wrap; gap: 6px; margin-block-start: 14px; }
.tag {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .04em;
  color: var(--faint); border: 1px solid var(--line);
  padding: 3px 8px; border-radius: 6px; background: var(--bg-elev);
}

.asof {
  margin-block-start: 14px; font-family: var(--mono);
  font-size: 11.5px; color: var(--faint); letter-spacing: .03em;
}

@media (max-width: 700px) {
  .sys-btn { grid-template-columns: 14px minmax(0,1fr) 18px; gap: 12px; padding: 15px 16px; }
  .sys-metric { display: none; }
  .sys-detail { padding: 0 16px 18px calc(16px + 14px + 12px); }
  [dir="rtl"] .sys-detail { padding: 0 calc(16px + 14px + 12px) 18px 16px; }
}

/* ------------------------------------------------------------- site cards */
.grid {
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}

.card {
  display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); box-shadow: var(--shadow); overflow: hidden;
  transition: transform .2s, border-color .2s;
}
.card:hover { transform: translateY(-3px); border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); }

.card-vis {
  position: relative; block-size: 132px; overflow: hidden;
  background:
    radial-gradient(120% 120% at 18% 0%, hsl(var(--h) 72% 52% / .28), transparent 62%),
    linear-gradient(155deg, hsl(var(--h) 60% 46% / .16), transparent 70%),
    var(--bg-elev);
  border-block-end: 1px solid var(--line-soft);
  display: grid; place-items: center;
}
.card-vis::before {
  content: ""; position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, var(--line-soft) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line-soft) 1px, transparent 1px);
  background-size: 26px 26px; opacity: .5;
}
.card-mono {
  position: relative; font-family: var(--mono); font-weight: 700;
  font-size: 2.6rem; letter-spacing: -.05em;
  color: hsl(var(--h) 68% 62%);
  text-shadow: 0 0 34px hsl(var(--h) 70% 50% / .5);
}
[data-theme="light"] .card-mono { color: hsl(var(--h) 62% 40%); text-shadow: none; }

.card-chrome {
  position: absolute; inset-block-start: 0; inset-inline: 0; height: 30px;
  display: flex; align-items: center; gap: 6px; padding-inline: 11px;
  border-block-end: 1px solid var(--line-soft);
  background: color-mix(in srgb, var(--bg-elev) 84%, transparent);
}
.card-chrome i { inline-size: 7px; block-size: 7px; border-radius: 50%; background: var(--line); }
.card-url {
  margin-inline-start: 6px; font-family: var(--mono); font-size: 10.5px;
  color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.card-body { padding: 18px 20px 20px; display: flex; flex-direction: column; flex: 1; }
.card-client {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--faint);
}
.card-title {
  margin-block-start: 6px; font-size: 17px; font-weight: 650;
  color: var(--text-strong); letter-spacing: -.018em;
}
.card-sum { margin-block-start: 8px; font-size: 14px; color: var(--muted); flex: 1; }
.card-foot {
  margin-block-start: 16px; padding-block-start: 14px;
  border-block-start: 1px solid var(--line-soft);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.card-visit {
  font-size: 13.5px; font-weight: 620; color: var(--accent);
  display: inline-flex; align-items: center; gap: 6px;
}
[dir="rtl"] .card-visit svg { transform: scaleX(-1); }

/* ------------------------------------------------------------- stack grid */
.stack-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.stack-card {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); padding: 20px; box-shadow: var(--shadow);
}
.stack-label {
  font-family: var(--mono); font-size: 11px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent); margin-block-end: 13px;
}
.stack-items { display: flex; flex-wrap: wrap; gap: 6px; }
.stack-items li {
  font-size: 12.5px; color: var(--muted);
  border: 1px solid var(--line); border-radius: 7px;
  padding: 4px 10px; background: var(--bg-elev);
}

/* ---------------------------------------------------------------- contact */
.contact-box {
  border: 1px solid var(--line); border-radius: var(--radius);
  background:
    radial-gradient(80% 140% at 8% 0%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 62%),
    var(--surface);
  box-shadow: var(--shadow);
  padding: clamp(30px, 5vw, 52px);
}
.contact-box h2 { font-size: clamp(1.5rem, 3.2vw, 2.1rem); letter-spacing: -.028em; color: var(--text-strong); max-width: 20ch; }
.contact-box p { margin-block-start: 12px; color: var(--muted); max-width: 56ch; }
.contact-actions { margin-block-start: 26px; display: flex; flex-wrap: wrap; gap: 12px; }

/* ----------------------------------------------------------------- footer */
.ftr { border-block-start: 1px solid var(--line-soft); padding-block: 30px; }
.ftr-in {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  font-size: 13px; color: var(--faint);
}
.ftr-links { display: flex; gap: 16px; }
.ftr-links a { color: var(--muted); }
.ftr-links a:hover { color: var(--accent); }

/* ---------------------------------------------------------------- reveals */
.rv { opacity: 0; transform: translateY(14px); transition: opacity .55s ease, transform .55s ease; }
.rv.in { opacity: 1; transform: none; }

/* --------------------------------------------------------------- noscript */
.ns { padding: 32px 0; }
.ns h2 { font-size: 1.2rem; margin-block-end: 10px; }
.ns li { margin-block-start: 6px; }
.ns a { color: var(--accent); text-decoration: underline; }
