/* ==========================================================================
   Cyber City · graphic motifs v1.1 · 2026-10-02
   The static pieces drawn from the logo: traces that end in square pads, voxels
   that break off the line, one lime spark, dot grids, light pools, and the logo's
   chrome as the fill of one display phrase.
   No motion in this file: motion.css adds the moving states.
   Every lit point is a square voxel. Round belongs to the vias, as in the logo.

   Load order: tokens.css (v0.4 or later), foundations.css, then this file.
   From tokens.css it reads the colours, the product stage light recipes (--ecc-stage-*),
   --ecc-lime-edge, the chrome gradient (--ecc-chrome-gradient) and the dark panel context
   (.ecc-ctx-panel): every piece follows Day and Night
   by itself, and switches to its dark look inside a panel that carries .ecc-ctx-panel.
   From foundations.css it reuses .ecc-pip and .ecc-badge (it only adds one badge shape: the cut tag).
   The blocks between "@motif name" and "@end" are the copy-paste recipes shown
   in motifs.html (tools/motifs-sync.mjs keeps the page and this file identical).
   ========================================================================== */

/* ======================================================= 1 · pad, via, spark, voxel */
/* @motif points */
/* The pip (.ecc-pip, the "on" light of a label) lives in foundations.css. These are its relatives. */
/* Pad: where a trace starts, on a real part of the object. Via: where it passes on. */
.ecc-pad,
.ecc-via {
  display: inline-block; flex: none; box-sizing: border-box; width: 9px; height: 9px;
  border: 1.5px solid var(--ecc-trace); background: var(--ecc-surface);
}
.ecc-pad { border-radius: 1px; }
.ecc-via { border-radius: 50%; }
/* Spark: the one true-lime square, next to the answer. --ecc-lime-edge keeps it readable:
   a lime-ink hairline on light (lime on white is 1.47:1), a soft glow on dark.
   One per line, three lines per view at most. */
.ecc-spark {
  display: inline-block; flex: none; width: 9px; height: 9px; border-radius: 1px;
  background: var(--ecc-lime); box-shadow: var(--ecc-lime-edge);
}
/* Voxel: a square that broke off the line. Size, fade and drift come from the markup. */
.ecc-vox {
  display: block; flex: none; width: var(--s, 5px); height: var(--s, 5px);
  background: var(--ecc-spark); opacity: var(--o, 1); transform: translateY(var(--y, 0));
}
/* @end */

/* ======================================================= 2 · rules, dividers */
/* @motif rule */
/* Section rule: pad, hairline, spark. The line is its own element so the current can run along it. */
.ecc-rule { display: flex; align-items: center; width: 100%; min-height: 12px; }
.ecc-rule__line {
  display: block; flex: 1; min-width: 0; height: 1.5px;
  background: var(--ecc-trace); transform-origin: 0 50%;
}
/* @end */

/* @motif divider */
/* Voxel dissolve: the rule breaks into three voxels that gather into the spark. Fluid width. */
.ecc-divider { display: flex; align-items: center; width: 100%; min-height: 14px; }
.ecc-divider .ecc-vox { margin-left: 5px; }
.ecc-divider .ecc-spark { margin-left: 7px; }
/* The wide dissolve: a hairline with a fixed voxel tail (the SVG), for the end of a band or an image.
   The SVG keeps its pixel size; on a phone it is cropped from the right, so the tail just ends sooner. */
.ecc-dissolve { display: flex; align-items: center; width: 100%; }
.ecc-dissolve svg { display: block; flex: none; width: 240px; height: 32px; overflow: hidden; }
.ecc-dissolve rect { fill: var(--ecc-trace); shape-rendering: crispEdges; }
.ecc-dissolve .is-lime { fill: var(--ecc-spark); }
@media (max-width: 480px) {
  .ecc-dissolve svg { width: 160px; }
}
/* @end */

/* ======================================================= 3 · trace connectors */
/* @motif trace */
/* SVG traces. Lines run level and turn only at 45 degrees, the angle of the logo's traces.
   Size the SVG in CSS pixels (no scaling) so the 1.5px line stays 1.5px. */
.ecc-trace { display: block; overflow: visible; fill: none; max-width: 100%; height: auto; }
.ecc-trace__path {
  fill: none; stroke: var(--ecc-trace);
  stroke-width: 1.5; stroke-linejoin: miter; stroke-linecap: butt;
}
.ecc-trace__pad,
.ecc-trace__via {
  fill: var(--ecc-surface); stroke: var(--ecc-trace); stroke-width: 1.5;
}
.ecc-trace__pad { shape-rendering: crispEdges; }
.ecc-trace__vox { fill: var(--ecc-spark); shape-rendering: crispEdges; }
/* the spark: lime, with a lime-ink hairline that only shows on light (at night the two are the same lime) */
.ecc-trace__spark { fill: var(--ecc-lime); stroke: var(--ecc-spark); stroke-width: 1; shape-rendering: crispEdges; }
/* Flowing version for layouts: runs stretch, the bend keeps its size. */
.ecc-trace-flow { display: flex; align-items: flex-end; width: 100%; height: 22px; }
.ecc-trace-flow .ecc-rule__line.is-high { align-self: flex-start; }
.ecc-trace-flow svg { display: block; flex: none; width: 22px; height: 22px; overflow: visible; }
.ecc-trace-flow .ecc-pad,
.ecc-trace-flow .ecc-via { margin-bottom: -3.75px; }
.ecc-trace-flow .ecc-spark { align-self: flex-start; margin-top: -3.75px; }
/* @end */

/* ============================================ 4 · dot grid, LED screen, field */
/* @motif dotgrid */
/* The quiet dot grid of a module. Also the resting look of a panel when the field is not running.
   The dots are 2 px squares, like every pixel of the brand (round stays for the logo's vias only). */
.ecc-dotgrid {
  background-image: conic-gradient(at 2px 2px, transparent 75%, var(--ecc-line) 0);
  background-size: 12px 12px;
}
/* LED screen inset: for the ticker and for dot readouts. A screen is dark in both themes, and a
   little darker than the panel around it (--ecc-screen, tokens.css). */
.ecc-led {
  position: relative; overflow: hidden; border-radius: var(--ecc-r-sm);
  background: var(--ecc-screen); color: var(--ecc-on-panel);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ecc-on-panel) 9%, transparent);
}
.ecc-led::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: conic-gradient(at 2px 2px, transparent 75%, color-mix(in srgb, var(--ecc-on-panel) 6%, transparent) 0);
  background-size: 4px 4px;
}
/* What the screen says: a short LED word. Capitals and digits, 12 characters at most, never under 20px.
   No full stop, colon, percent or dollar sign: in Doto they do not read (typography.md 6). The one longer
   text on a screen is the hero ticker: the six pillar names, each its own element, a light between them. */
.ecc-led__text {
  margin: 0; font-family: var(--ecc-f-dot); font-variation-settings: var(--ecc-dot-settings); font-weight: var(--ecc-fw-dot);
  font-size: 25px; line-height: 1; letter-spacing: .06em; text-transform: uppercase;
}
/* @end */

/* @motif field-still */
/* Voxel Current, standing still: for print, for no-WebGL browsers and as the poster under the canvas.
   Small off-voxels everywhere, grown voxels where the 45 degree current runs. It follows the theme,
   and inside an .ecc-ctx-panel it takes the panel's colours.
   Both layers sit under everything in the box (z-index -2 inside its own stacking context). The live
   field's canvas mounts at z-index -1 (voxel-shader.js v1.1), so it covers them completely and any
   words in the box stay on top. */
.ecc-field-still {
  --_cell: 12px;
  position: relative; overflow: hidden; isolation: isolate;
  background: var(--ecc-canvas);
}
.ecc-field-still::before,
.ecc-field-still::after {
  content: ""; position: absolute; inset: 0; z-index: -2; pointer-events: none;
  -webkit-mask-size: var(--_cell) var(--_cell); mask-size: var(--_cell) var(--_cell);
}
.ecc-field-still::before {            /* off voxels: 3px in every cell */
  background: var(--ecc-line-strong);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'%3E%3Crect x='4.5' y='4.5' width='3' height='3'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'%3E%3Crect x='4.5' y='4.5' width='3' height='3'/%3E%3C/svg%3E");
}
.ecc-field-still::after {             /* the current: 10px voxels, coloured by two 45 degree bands */
  background:
    linear-gradient(135deg, transparent 24%, color-mix(in srgb, var(--ecc-spark) 24%, transparent) 28%, transparent 33%),
    linear-gradient(135deg, transparent 50%, color-mix(in srgb, var(--ecc-spark) 28%, transparent) 58%,
      color-mix(in srgb, var(--ecc-spark) 62%, transparent) 65%, var(--ecc-spark) 70%,
      color-mix(in srgb, var(--ecc-spark) 62%, transparent) 75%, color-mix(in srgb, var(--ecc-spark) 28%, transparent) 82%, transparent 90%);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'%3E%3Crect x='1' y='1' width='10' height='10'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'%3E%3Crect x='1' y='1' width='10' height='10'/%3E%3C/svg%3E");
}
/* @end */

/* ============================================================ 5 · light pools */
/* @motif stage */
/* The light pool, as a class. The recipes themselves are tokens (tokens.css, --ecc-stage-*), the same
   ones the pixel kit's .pk-stage uses. Use .pk-stage for a product that assembles from voxels, and
   this static stage for everything else that stands under the light.
   Day: one soft studio light from above (direction B). Night: a dark plinth under a pool of warm
   case light (direction A). The two layers crossfade when the theme changes.
   A dark product never sits on flat black: it always gets one of these lights. */
.ecc-stage { position: relative; overflow: hidden; isolation: isolate; border-radius: var(--ecc-r-sm); }
.ecc-stage::before {                  /* Day studio light */
  content: ""; position: absolute; inset: 0; z-index: -2;
  background: var(--ecc-stage-studio); opacity: var(--ecc-stage-day);
}
.ecc-stage::after {                   /* Night light pool on the plinth */
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--ecc-stage-pool); opacity: var(--ecc-stage-night);
}
/* The floor under the product: a soft contact shadow by day, a pool of light by night. */
.ecc-stage__floor {
  position: absolute; left: 20%; right: 20%; bottom: calc(var(--ecc-floor) - 13px); height: 26px;
  z-index: 0; pointer-events: none;
  background: var(--ecc-stage-floor-shadow); opacity: var(--ecc-stage-day);
}
.ecc-stage__pool {
  position: absolute; left: 8%; right: 8%; bottom: calc(var(--ecc-floor) - 28px); height: 56px;
  z-index: 0; pointer-events: none;
  background: var(--ecc-stage-floor-pool); opacity: var(--ecc-stage-night);
}
/* The box the product stands in: the photo is contained and sits on the floor line. */
.ecc-stage__box { position: absolute; left: 12%; right: 12%; top: 17%; bottom: var(--ecc-floor); z-index: 1; }
.ecc-stage__box > img { display: block; width: 100%; height: 100%; max-width: none; object-fit: contain; object-position: 50% 100%; }
/* The product photo: a floor shadow by day; a thin rim light and a warm top light by night. */
.ecc-stage__img { position: relative; z-index: 1; filter: var(--ecc-stage-img-filter); }
/* The floor line: a hairline the current can run along (motion.css). Visible at rest only by night.
   The box is 3px tall so a passing pulse can be a little thicker than the hairline. */
.ecc-floorline {
  position: absolute; left: 14%; right: 14%; bottom: calc(var(--ecc-floor) - 1.5px); height: 3px;
  z-index: 2; pointer-events: none; overflow: hidden;
}
.ecc-floorline::before {
  content: ""; position: absolute; left: 0; right: 0; top: .75px; height: 1.5px;
  background: var(--ecc-stage-hairline); opacity: var(--ecc-stage-night);
}
/* Hold one look, whatever the theme. */
.ecc-stage--day { --ecc-stage-day: 1; --ecc-stage-night: 0; --ecc-stage-img-filter: var(--ecc-stage-shadow); }
.ecc-stage--night { --ecc-stage-day: 0; --ecc-stage-night: 1; --ecc-stage-img-filter: var(--ecc-stage-rim); }
/* @end */

/* ======================================================= 6 · brackets, corners */
/* @motif brackets */
/* Corner brackets: frame a module that is being pointed at, measured or selected.
   One element, eight tiny gradients. --b is the arm length, --t the thickness. */
.ecc-brackets {
  --b: 10px; --t: 1.5px; --c: var(--ecc-ink);
  background:
    linear-gradient(var(--c) 0 0) 0 0 / var(--b) var(--t),
    linear-gradient(var(--c) 0 0) 0 0 / var(--t) var(--b),
    linear-gradient(var(--c) 0 0) 100% 0 / var(--b) var(--t),
    linear-gradient(var(--c) 0 0) 100% 0 / var(--t) var(--b),
    linear-gradient(var(--c) 0 0) 0 100% / var(--b) var(--t),
    linear-gradient(var(--c) 0 0) 0 100% / var(--t) var(--b),
    linear-gradient(var(--c) 0 0) 100% 100% / var(--b) var(--t),
    linear-gradient(var(--c) 0 0) 100% 100% / var(--t) var(--b);
  background-repeat: no-repeat;
}
/* Corner pixels: the pixel cursor's frame as a resting state (the selected one of a set). */
.ecc-corners {
  --p: 5px; --c: var(--ecc-spark);
  background:
    linear-gradient(var(--c) 0 0) 0 0 / var(--p) var(--p),
    linear-gradient(var(--c) 0 0) 100% 0 / var(--p) var(--p),
    linear-gradient(var(--c) 0 0) 0 100% / var(--p) var(--p),
    linear-gradient(var(--c) 0 0) 100% 100% / var(--p) var(--p);
  background-repeat: no-repeat;
}
/* @end */

/* ============================================================ 7 · section marks */
/* @motif mark */
/* Section mark: a dot-matrix number. It numbers a real sequence (steps, the tiles of a set,
   the sections of a board). Doto never goes under 20px, and never under 24px on a light surface.
   Under 40px the mark is one step heavier than a readout (900 against 800): at 20 to 30px the
   pixels of the numerals are thin on a light tile. */
.ecc-mark {
  display: inline-block; font-family: var(--ecc-f-dot); font-variation-settings: var(--ecc-dot-settings);
  font-weight: 900; font-size: 30px; line-height: 1; letter-spacing: .04em; color: var(--ecc-ink);
}
.ecc-mark--sm { font-size: 24px; }
.ecc-mark--lg { font-size: clamp(44px, 5vw, 72px); letter-spacing: .02em; font-weight: var(--ecc-fw-dot); }
/* On an LED screen: the number sits in a dark inset with one lit voxel. The light is a square, like the
   pixels of the numerals and like every pip. Round belongs to the vias, as in the logo, and to nothing else. */
.ecc-mark--led {
  display: inline-flex; align-items: center; gap: 8px; min-height: 40px; padding: 0 12px 0 10px;
  border-radius: var(--ecc-r-sm); background: var(--ecc-screen); color: var(--ecc-on-panel);
  font-size: 24px; font-weight: var(--ecc-fw-dot);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ecc-on-panel) 9%, transparent);
}
.ecc-mark--led::before {
  content: ""; width: 6px; height: 6px; border-radius: var(--ecc-r-voxel); background: var(--ecc-lime);
  box-shadow: 0 0 8px color-mix(in srgb, var(--ecc-lime) 55%, transparent);
}
/* @end */

/* ================================================================== 8 · badges */
/* @motif badge */
/* The badge itself is in foundations.css (.ecc-badge: a mono label behind a pip or a 16px icon;
   .ecc-badge--cat: the department label, behind a pip). A badge names: a department, or a status
   ("By appointment", "Off-road only"). It never carries a promise. The store's three promises
   (lease-to-own options, set up before you leave, store pickup in Fullerton) are claims: sentences in
   Archivo behind their icon (.ecc-claim and .ecc-claim--static, foundations.css).
   No rating, stock, price or countdown badge exists in the system.
   This file adds one shape. Cut tag: the logo's 45 degree cut on one corner. It inverts its surface
   (ink on a light stage, light on a dark one), so it holds on a product photo in both themes. */
.ecc-badge--cut {
  padding-right: 18px; border-color: transparent; border-radius: 2px;
  background: var(--ecc-ink); color: var(--ecc-canvas);
  clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 0 100%);
}
.ecc-badge--cut .ecc-pip { background: var(--ecc-btn-pip); }
/* @end */

/* ============================================================= 9 · chrome text */
/* @motif chrome */
/* Chrome text: the logo's material on one display phrase. The gradient is a token of tokens.css
   (--ecc-chrome-gradient); this file does not restate it. Under the gradient sits the flat chrome
   (--ecc-chrome): it fills the letters if the gradient is ever missing, and it is the text colour where
   a browser cannot clip a background to text.
   The rule: display sizes only (32px and up), on dark panels only, one phrase per screen, never body text. */
.ecc-chrome-text { color: var(--ecc-chrome); }
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .ecc-chrome-text {
    background-color: var(--ecc-chrome); background-image: var(--ecc-chrome-gradient);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent;
  }
  /* selected: the letters take the selection colour, or they would vanish into the highlight */
  .ecc-chrome-text::selection { -webkit-text-fill-color: var(--ecc-selection-fg); }
}
/* forced colours (Windows contrast themes) remove backgrounds: the letters go back to plain text, in the
   text colour the visitor chose (the system colour itself: currentColor would still resolve to the chrome) */
@media (forced-colors: active) {
  .ecc-chrome-text { background: none; -webkit-text-fill-color: CanvasText; }
}
/* @end */
