/* ===========================================================================
   THE MODULE WALL: Crest's modules, drawn live instead of described.
   2026-07-28.

   WHY THIS EXISTS. The modules section on /crest is twenty paragraphs of
   feature text. Nobody reads twenty paragraphs, and a paragraph cannot prove
   that a countdown counts, that an approval waits for you, or that a meter
   moves. Each tile below runs a small honest loop of the thing it names, so
   the wall is read by watching rather than by reading.

   WHAT IT IS NOT. These tiles are not screenshots and never claim to be. They
   are the panel's own vocabulary (the .dlbl label, the .num numeral, the 3.5px
   meter, the hairline row) rebuilt at tile scale, carrying sample content in
   the house register: "Chromatics", "Standup: design 4.0", "launch-reel.mp4".
   Never a real person's data, on any tile, ever.

   THE LAWS THIS FILE OBEYS (they are load-bearing, not taste):
     Chrome is monochrome. Grounds come from the --bg family, separation comes
     from hairlines, corners come from the existing radius family.
     Colour is only allowed in as CONTENT (an app square, a calendar dot),
     as MEANING (one small kin accent per module, 7px, cool-leaning so amber
     stays the loudest thing on the page), and as STATE (green / red / amber).
     Amber means needs-you, and amber is the ONLY thing that pulses. If a
     second pulse ever appears here the amber one stops meaning anything.
     No gradients, no glows, no blur, no purple, no bouncy overshoot.

   MOTION. Fast attack, damped settle. Micro-interactions are 170ms. The
   resting loops are slow on purpose: a tile ticks every two to six seconds.
   Twenty-four tiles all ticking at once is a casino, and a casino is the one
   thing a control room must never look like.
   =========================================================================== */

.mw{
  /* The site's own lattice: a 1px gap over a hairline ground reads as a ruled
     grid without drawing twenty-four borders. Same trick as .grid in suite.css,
     and it is why the tiles must never carry a border of their own. */
  display:grid;
  gap:1px;
  background:var(--hair2);
  border:1px solid var(--hair2);
  border-radius:14px;
  overflow:hidden;
  grid-template-columns:repeat(4,1fr);

  /* Both walls are multiples of 4, 3, 2 and 1 (12 and 24), so no breakpoint can
     ever strand a lone tile on a final row. Changing either count breaks that
     and the wall stops packing clean. */
  --mw-h:172px;

  /* The type ladder, stated locally. The site tokens are 92 / 60 / 38; a tile
     is a fifth the size of a card, so its lead has to sit a step brighter and
     its supporting text a step quieter or the whole wall greys out. */
  --mw-t1:rgba(245,245,244,.96);
  --mw-t2:rgba(245,245,244,.55);
  --mw-t3:rgba(245,245,244,.33);

  /* Motion. Deliberately NOT var(--spring): that curve overshoots, which is
     charming on a button and dishonest on a meter. This one lands. */
  --mw-fast:170ms;
  --mw-ease:cubic-bezier(.2,.75,.3,1);

  /* Kin accents. Six, not twenty-four, because the app's own catalog is
     grouped by kin (media, plan, dev, system, files, suite) and a wall with
     twenty-four hues is a paint chart. Every one of them is cool-leaning and
     desaturated so #ffb000 stays the loudest colour in the room. */
  --mw-media:#6fa0e8;
  --mw-plan:#6fb6a3;
  --mw-dev:#7fb2d6;
  --mw-sys:#8d9aa6;
  --mw-files:#8fb0bd;
  --mw-suite:#5f9fa8;
}
@media(max-width:1160px){ .mw{grid-template-columns:repeat(3,1fr)} }
@media(max-width:860px){ .mw{grid-template-columns:repeat(2,1fr)} }
@media(max-width:560px){ .mw{grid-template-columns:1fr} }

/* --------------------------------------------------------------- the tile
   Fixed height, and the height is the whole reason the rich states are built
   the way they are. A tile that grows on hover reflows its row, its row shoves
   the rows under it, and twenty-four tiles turn into a trampoline. Everything
   a rich state adds is either revealed in space the resting state already
   reserved, or cross-faded on a layer stacked in the same box. */
.mw-t{
  position:relative;
  height:var(--mw-h);
  padding:13px 14px 11px;
  background:var(--bg2);
  display:flex;
  flex-direction:column;
  overflow:hidden;
  cursor:default;
  transition:background var(--mw-fast) var(--mw-ease);
}
/* A lifted section is already one step up, so the tiles take the next step up
   from it. Two explicit rules beat one clever inherited one. */
section.lift .mw-t{background:var(--bg3)}
.mw-t:hover,.mw-t.is-rich{background:#141518}
section.lift .mw-t:hover,section.lift .mw-t.is-rich{background:#171a1e}
.mw-t:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;border-radius:2px}

/* The datum leads, the name follows. Information first, name second: you
   should be able to read the wall without reading a single module name. */
.mw-body{position:relative;flex:1;min-width:0;min-height:0}
/* Tiles whose main object has to fill whatever height is left (the snapping
   desktop) ask for a column here rather than doing arithmetic on --mw-h. */
.mw-body.col{display:flex;flex-direction:column}
.mw-foot{
  display:flex;align-items:center;gap:7px;
  margin-top:9px;padding-top:8px;border-top:1px solid var(--hair2);flex:none;
}
.mw-name{font-size:10.5px;line-height:1.35;color:var(--mw-t2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mw-kin{width:7px;height:7px;border-radius:2px;flex:none;background:var(--mw-sys)}
.mw-t[data-kin="media"] .mw-kin{background:var(--mw-media)}
.mw-t[data-kin="plan"]  .mw-kin{background:var(--mw-plan)}
.mw-t[data-kin="dev"]   .mw-kin{background:var(--mw-dev)}
.mw-t[data-kin="sys"]   .mw-kin{background:var(--mw-sys)}
.mw-t[data-kin="files"] .mw-kin{background:var(--mw-files)}
.mw-t[data-kin="suite"] .mw-kin{background:var(--mw-suite)}

/* Two layers in one box, cross-faded. Used only where the rich state genuinely
   REPLACES the resting one (Battery's detail rows, Bluetooth's levels). Where
   the rich state merely adds, the resting layout reserves the space instead,
   because a cross-fade of near-identical content reads as a flicker. */
.mw-layer{position:absolute;inset:0;transition:opacity var(--mw-fast) var(--mw-ease)}
.mw-layer.rich{opacity:0;pointer-events:none}
.mw-t.is-rich .mw-layer.rest{opacity:0}
.mw-t.is-rich .mw-layer.rich{opacity:1}

/* ------------------------------------------------------------- primitives
   Every one of these is the panel's own idiom at tile scale. Nothing here is
   invented for the website; if the app does not draw it, it is not below. */
/* Every text primitive states its own line-height. The body's 1.6 is written
   for paragraphs; inside a 172px tile it wastes about a third of the box, and
   the layouts below are budgeted to the pixel against 1.35. */
.mw-lbl{
  font-size:8.5px;line-height:1.35;letter-spacing:.14em;text-transform:uppercase;color:var(--mw-t3);
  display:flex;align-items:center;gap:6px;white-space:nowrap;
}
.mw-lbl .sp{flex:1}
.mw-line{font-size:11.5px;line-height:1.35;color:var(--mw-t1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mw-sub{font-size:9.5px;line-height:1.35;color:var(--mw-t3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mw-mid{font-size:10.5px;line-height:1.35;color:var(--mw-t2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mw-mono{font-family:var(--mono);font-size:9.5px;line-height:1.35;color:var(--mw-t2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}

/* Thin numerals. Large-ish and light, tabular so a ticking digit never shifts
   the ones beside it: the single most common way a live counter looks cheap. */
.mw-big{
  font-size:27px;line-height:1.05;font-weight:300;letter-spacing:-.02em;
  color:var(--mw-t1);font-variant-numeric:tabular-nums;
}
.mw-num{font-variant-numeric:tabular-nums;font-weight:400;color:var(--mw-t1);font-size:11px;line-height:1.35}
.mw-num.q{color:var(--mw-t3);font-weight:300}
.mw-num.amber{color:var(--amber)}

/* Two state classes rather than per-frame style writes. Toggling a class the
   element already has costs nothing; assigning element.style.color sixty times
   a second costs something on every one of twenty-four tiles. */
.mw-off{color:var(--mw-t3)}
.mw-lit{color:var(--mw-t1)}
.mw-dim{opacity:.28}

.mw-hair{height:1px;background:var(--hair2);border:0;margin:8px 0}
.mw-row{display:flex;align-items:center;gap:8px;min-width:0}
.mw-row .grow{flex:1;min-width:0}
.mw-stack{display:flex;flex-direction:column;gap:7px;min-width:0}

/* The 3.5px meter, scaled with transform rather than width. Width is layout;
   transform is not, and twenty-four meters animating width is how a page
   built out of small live things ends up costing more than a video. */
.mw-bar{position:relative;height:3.5px;border-radius:2px;background:rgba(255,255,255,.09);overflow:hidden}
.mw-bar > i{
  position:absolute;left:0;top:0;bottom:0;right:0;border-radius:2px;
  background:rgba(245,245,244,.5);transform-origin:left center;transform:scaleX(0);
}
.mw-bar.accent > i{background:var(--amber)}
.mw-bar > b{
  position:absolute;top:50%;left:0;width:8px;height:8px;border-radius:50%;background:#f5f5f4;
  margin:-4px 0 0 -4px;opacity:0;transition:opacity var(--mw-fast) var(--mw-ease);
}
.mw-t.is-rich .mw-bar > b{opacity:1}

/* Segments, for anything counted in rounds. Never a ring: a ring gauge in a
   140px tile is unreadable and it is the house tell of a dashboard template. */
.mw-seg{display:flex;gap:3px;height:3.5px}
.mw-seg > i{flex:1;border-radius:2px;background:rgba(255,255,255,.09);position:relative;overflow:hidden}
.mw-seg > i::after{
  content:"";position:absolute;inset:0;border-radius:2px;background:rgba(245,245,244,.5);
  transform-origin:left center;transform:scaleX(var(--f,0));
}

.mw-dot{width:7px;height:7px;border-radius:50%;flex:none;background:rgba(245,245,244,.28);
  transition:background var(--mw-fast) var(--mw-ease)}
.mw-dot.g{background:var(--green)}
.mw-dot.a{background:var(--amber)}
.mw-dot.r{background:var(--rec)}
/* The one pulse on the whole wall. It says an agent is waiting on you, which
   is the only thing Crest ever asks a person to look at. */
.mw-dot.pulse{animation:mwPulse 1.6s ease-in-out infinite}
@keyframes mwPulse{50%{opacity:.28}}

.mw-chip{
  font:inherit;font-size:9.5px;font-weight:600;border-radius:6px;padding:4px 8px;
  border:1px solid var(--hair);background:transparent;color:var(--mw-t2);
  white-space:nowrap;display:inline-flex;align-items:center;gap:5px;
  transition:border-color var(--mw-fast) var(--mw-ease),color var(--mw-fast) var(--mw-ease),
             background var(--mw-fast) var(--mw-ease),opacity var(--mw-fast) var(--mw-ease),
             transform var(--mw-fast) var(--mw-ease);
}
.mw-chip.key{font-family:var(--mono);letter-spacing:.04em;font-weight:500}
.mw-chip.on{background:var(--fill2);color:var(--mw-t1);border-color:transparent}
.mw-chip.go{background:var(--amber);color:var(--amber-ink);border-color:transparent}
/* The self-tap. 170ms, no overshoot: it should look like a finger landed, not
   like the chip is pleased with itself. */
.mw-chip.press{transform:scale(.955)}
.mw-chip.gone{opacity:0;pointer-events:none}

.mw-sw{position:relative;width:26px;height:15px;border-radius:8px;background:rgba(255,255,255,.12);
  flex:none;transition:background var(--mw-fast) var(--mw-ease)}
.mw-sw > i{position:absolute;top:2px;left:2px;width:11px;height:11px;border-radius:50%;
  background:#f5f5f4;transition:transform var(--mw-fast) var(--mw-ease)}
.mw-sw.on{background:var(--amber)}
.mw-sw.on > i{transform:translateX(11px)}

.mw-sq{width:9px;height:9px;border-radius:2.5px;flex:none}

/* A checkbox that draws its tick rather than swapping to a filled state. The
   draw is the point: it is the app confirming it did the thing you asked. */
.mw-chk{width:14px;height:14px;border-radius:50%;border:1.5px solid rgba(245,245,244,.28);
  flex:none;display:grid;place-items:center;transition:border-color var(--mw-fast) var(--mw-ease)}
.mw-chk svg{width:9px;height:9px;fill:none;stroke:var(--green);stroke-width:2.6;
  stroke-linecap:round;stroke-linejoin:round;display:block}
.mw-chk svg path{stroke-dasharray:22;stroke-dashoffset:22;transition:stroke-dashoffset 260ms var(--mw-ease)}
.mw-chk.done{border-color:rgba(53,192,106,.55)}
.mw-chk.done svg path{stroke-dashoffset:0}

/* The equaliser. Five bars, scaleY from the bottom, nothing else. */
.mw-eq{display:flex;align-items:flex-end;gap:2px;height:20px;flex:none}
.mw-eq > i{width:2.5px;height:20px;border-radius:1px;background:rgba(245,245,244,.55);
  transform-origin:bottom center;transform:scaleY(.15)}

/* ------------------------------------------------------- tile-local pieces */

/* Window snapping needs a desktop to snap into. Flat rectangles, one hairline
   for the menu bar, and the window itself moves on transform alone. */
.mw-desk{position:relative;flex:1;min-height:0;border:1px solid var(--hair);border-radius:6px;
  background:var(--inset);overflow:hidden}
.mw-desk::before{content:"";position:absolute;left:0;right:0;top:0;height:5px;
  border-bottom:1px solid var(--hair2)}
.mw-win{position:absolute;left:0;top:5px;width:100%;height:calc(100% - 5px);
  transform-origin:top left;
  transition:transform 340ms var(--mw-ease)}
.mw-win > i{position:absolute;inset:2px;border-radius:3px;background:rgba(245,245,244,.14);
  border:1px solid var(--hair3);display:block}

/* Camera check draws a person the same way the site draws album art: flat
   shapes, no photograph, obviously a placeholder to anyone looking. */
.mw-cam{position:relative;width:52px;height:38px;border-radius:6px;border:1px solid var(--hair);
  background:var(--inset);overflow:hidden;flex:none}
.mw-cam .fig{position:absolute;inset:0;opacity:.34;transition:opacity var(--mw-fast) var(--mw-ease)}
.mw-t.is-rich .mw-cam .fig{opacity:.62}

/* Files on the shelf, and the notch's own file chip shape. */
.mw-file{display:inline-flex;align-items:center;gap:6px;font-size:9.5px;color:var(--mw-t2);
  border:1px solid var(--hair);border-radius:6px;padding:4px 8px;background:var(--inset);
  max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mw-file .glyph{width:7px;height:9px;border-radius:1.5px;background:rgba(245,245,244,.24);flex:none}

/* The selection bar that sweeps a list of hosts. Absolute, so the rows never
   move; only the highlight does. */
.mw-sel{position:absolute;left:-6px;right:-6px;height:26px;border-radius:6px;
  background:var(--fill);transition:transform 240ms var(--mw-ease),opacity var(--mw-fast) var(--mw-ease)}

/* Reveals. Anything that arrives does it in space already reserved, sliding a
   short distance and settling. 8px, never more: further than that and it reads
   as a slide deck transition. */
.mw-rev{opacity:0;transform:translateY(7px);
  transition:opacity var(--mw-fast) var(--mw-ease),transform var(--mw-fast) var(--mw-ease)}
.mw-rev.in{opacity:1;transform:none}

/* ------------------------------------------------------- reduced motion
   The tile must still tell the truth. Everything is drawn, every number is
   present and plausible, and nothing moves. The rich state becomes an instant
   swap, which is what a person who asked for less motion actually wants: the
   information, immediately, with no journey attached. */
@media(prefers-reduced-motion:reduce){
  .mw *,.mw *::before,.mw *::after{
    transition-duration:0s!important;
    animation:none!important;
  }
}

/* ---------------------------------------------------------------- fallback
   A tile that cannot build must not leave a hole that reads as a broken image.
   It falls back to the module's name and its one line, which is exactly the
   text this wall was built to replace: worse, but never wrong. */
.mw-t.is-dead{justify-content:center}
.mw-t.is-dead .mw-body{display:flex;flex-direction:column;justify-content:center;gap:5px}
