daemon-sec-lotl

DÆMONBins: GTFOBins × LOLBAS × WADComs × LOOBins in one filterable catalog
git clone https://git.daemon-sec.xyz/daemon-sec-lotl.git
Log | Files | Refs | Submodules | README | LICENSE

chrome.css (15535B)


      1 /* ============================================================================
      2    Chrome — the site's form language, ported from the main DÆMON build.
      3 
      4    This file replaces the old glass.css. Where that file made a container
      5    out of translucency (blur, tint, inner highlight, 14px radius), this one
      6    makes one out of a hairline and a value change. The objects below are
      7    the whole vocabulary; every page is assembled from them.
      8 
      9      .slab      flat panel — 1px rule, square, no shadow
     10      .plate     inverse (night) panel, defined in tokens.css
     11      .grain     the film over everything
     12      .micro     10px mono label — the site's furniture type
     13      .eyebrow   `03 ^: LABEL` lockup with a keyed rule
     14      .btn       flat control
     15      .wipe      ink wipe for index rows
     16      .clip / .stretch  the lockup's scale rig
     17      .corners   cyberpunk corner brackets
     18      .segbar / .seg / .seg--accent   tmux-style segmented status bar
     19      .glitch    RGB-split wordmark glitch, keyed off `data-text`
     20      .scanlines CRT scanline overlay for dark plates
     21    ========================================================================== */
     22 
     23 /* ---- The film ------------------------------------------------------------ */
     24 /* Fractal noise laid over the page so a flat colour reads as stock rather
     25    than as a swatch. It is the one thing standing in for the texture the
     26    glass build got from blur, and it is why removing the blur does not
     27    leave the page feeling like unpainted CSS.
     28 
     29    Multiply on paper, screen on ink (tokens.css) — noise has to be laid
     30    *into* a light ground and *added* to a dark one; the same blend on both
     31    is invisible on one of them. */
     32 .grain {
     33   position: fixed;
     34   inset: 0;
     35   z-index: 1;
     36   pointer-events: none;
     37   background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.6'/%3E%3C/svg%3E");
     38   opacity: var(--grain-opacity);
     39   mix-blend-mode: var(--grain-blend);
     40 }
     41 
     42 /* A plate carries its own grain, because it pins the night palette for its
     43    subtree and therefore needs the dark blend while the page around it is
     44    still on the light one. */
     45 .grain--local {
     46   position: absolute;
     47   z-index: 2;
     48 }
     49 
     50 /* ---- Panels -------------------------------------------------------------- */
     51 .slab {
     52   border: 1px solid var(--rule);
     53   background: var(--surface);
     54 }
     55 /* The heavier variant, for the one panel on a screen that is the point of
     56    it — the site draws these at full ink rather than at rule weight. */
     57 .slab--ink {
     58   border-color: var(--fg);
     59   background: var(--base);
     60 }
     61 
     62 /* ---- Type furniture ------------------------------------------------------ */
     63 /* 10px mono, uppercase, widely tracked. Every eyebrow, kind mark, stat
     64    label, tab and caption on the site is this object. */
     65 .micro {
     66   font-family: var(--font-mono);
     67   font-size: var(--step-micro);
     68   letter-spacing: var(--track-micro);
     69   text-transform: uppercase;
     70   line-height: 1.6;
     71 }
     72 .micro--wide { letter-spacing: var(--track-wide); }
     73 
     74 /* The section lockup: an index, the site's self-naming `^:` mark, a label,
     75    then a rule that runs out to the end of the line in the section's own
     76    hue. It is what tells you which of the twelve domains you are in
     77    without a heading having to say it twice. */
     78 .eyebrow {
     79   display: flex;
     80   align-items: center;
     81   gap: 0.9rem;
     82   font-family: var(--font-mono);
     83   font-size: var(--step-micro);
     84   letter-spacing: var(--track-wide);
     85   text-transform: uppercase;
     86   color: var(--fg-faint);
     87 }
     88 .eyebrow__n { color: var(--acc, var(--accent)); }
     89 .eyebrow__mark { color: var(--fg-faint); opacity: 0.7; }
     90 .eyebrow__rule {
     91   flex: 1;
     92   height: 1px;
     93   background: var(--acc, var(--accent));
     94   opacity: 0.5;
     95 }
     96 
     97 /* Section heading — Archivo at its heaviest, condensed, tracked in tight.
     98    Uppercase is load-bearing: at this weight and width the lowercase
     99    letterforms lose their counters and the word turns into a block. */
    100 .display {
    101   font-family: var(--font-display);
    102   font-weight: 700;
    103   font-stretch: 84%;
    104   letter-spacing: -0.03em;
    105   line-height: 0.94;
    106   text-transform: uppercase;
    107 }
    108 
    109 /* ---- Controls ------------------------------------------------------------ */
    110 .btn {
    111   display: inline-flex;
    112   align-items: center;
    113   gap: 0.55rem;
    114   padding: 0.72rem 1.1rem;
    115   font-family: var(--font-mono);
    116   font-size: 11px;
    117   letter-spacing: var(--track-micro);
    118   text-transform: uppercase;
    119   /* The label is a single tracked line. Without this it wraps at the
    120      button's intrinsic width and the control turns into a three-line
    121      block, which at this letter-spacing is unreadable. */
    122   white-space: nowrap;
    123   border: 1px solid transparent;
    124   background: var(--fg);
    125   color: var(--base);
    126   transition: background-color 240ms ease, color 200ms ease, border-color 220ms ease;
    127 }
    128 /* An inline SVG with no intrinsic size resolves to 300×150 and detonates
    129    the control. Every icon in a button is a 14px mark beside the label. */
    130 .btn svg { width: 14px; height: 14px; flex: none; }
    131 .btn:hover { background: var(--accent-2); }
    132 .btn--ghost {
    133   background: transparent;
    134   color: var(--fg);
    135   border-color: var(--rule-hi);
    136 }
    137 .btn--ghost:hover { background: var(--fg); color: var(--base); border-color: var(--fg); }
    138 
    139 /* A chip is a bordered label, never a filled pill. Square, hairline, hue
    140    from whatever it qualifies. */
    141 .chip {
    142   display: inline-flex;
    143   align-items: center;
    144   gap: 0.5rem;
    145   padding: 0.36rem 0.7rem;
    146   font-family: var(--font-mono);
    147   font-size: var(--step-micro);
    148   letter-spacing: var(--track-micro);
    149   text-transform: uppercase;
    150   border: 1px solid color-mix(in oklab, var(--acc, var(--accent)) 55%, transparent);
    151   color: var(--acc, var(--accent));
    152   transition: background-color 240ms ease, color 200ms ease;
    153 }
    154 a.chip:hover { background: var(--acc, var(--accent)); color: var(--base); }
    155 
    156 /* The live dot — a filled core with a ring expanding off it. Used for
    157    anything the page wants to claim is current rather than static. */
    158 .dot {
    159   position: relative;
    160   display: block;
    161   width: 6px;
    162   height: 6px;
    163   flex: none;
    164 }
    165 .dot i,
    166 .dot u {
    167   position: absolute;
    168   inset: 0;
    169   border-radius: 50%;
    170   display: block;
    171 }
    172 .dot i { background: currentColor; }
    173 .dot u { border: 1px solid currentColor; }
    174 @media (prefers-reduced-motion: no-preference) {
    175   .dot i { animation: dmn-pulse 2.4s ease-in-out infinite; }
    176   .dot u { animation: dmn-ring 4.2s ease-out infinite; }
    177 }
    178 
    179 /* ---- The index row's ink wipe -------------------------------------------- */
    180 /* Hovering a row fills it with ink from the left. Driven by
    181    `background-position` over a hard-stop gradient rather than by
    182    `background-color`, and the transition list deliberately has no `color`
    183    in it — dragging a pointer down a fifty-row index is the one interaction
    184    here that can drop frames, and a colour transition on every row it
    185    crosses is what does it. The text colour flips instantly instead. */
    186 .wipe {
    187   background-image: linear-gradient(90deg, var(--fg) 0 50%, transparent 50% 100%);
    188   background-size: 200% 100%;
    189   background-position: 100% 0;
    190   background-repeat: no-repeat;
    191   transition: background-position 380ms var(--ease-in), color 1ms;
    192 }
    193 .wipe:hover { background-position: 0 0; }
    194 
    195 /* ---- Corner brackets ----------------------------------------------------- */
    196 /* The cyberdeck frame: four ~10px L-ticks sitting just outside the element's
    197    hairline, drawn by the two pseudo-elements — ::before carries the left
    198    pair, ::after the right, each tick a 10px hard-stop gradient tile. The
    199    colour is `--bracket` when set, else the theme's love; on a `.plate` the
    200    pinned night palette resolves both to their night values, so the brackets
    201    stay visible on dark grounds without a special case.
    202 
    203    One caveat: both pseudos are spent on the brackets, so an element that
    204    already needs ::before/::after for something else cannot also be
    205    .corners. */
    206 .corners { position: relative; }
    207 .corners::before,
    208 .corners::after {
    209   content: "";
    210   position: absolute;
    211   /* -3px: the tick straddles the corner — 3px out past the hairline,
    212      7px back in over it. */
    213   inset-block: -3px;
    214   width: 10px;
    215   z-index: 2;
    216   pointer-events: none;
    217 }
    218 .corners::before {
    219   inset-inline-start: -3px;
    220   background:
    221     linear-gradient(var(--bracket, var(--love)) 0 0) left top / 10px 1px no-repeat,
    222     linear-gradient(var(--bracket, var(--love)) 0 0) left top / 1px 10px no-repeat,
    223     linear-gradient(var(--bracket, var(--love)) 0 0) left bottom / 10px 1px no-repeat,
    224     linear-gradient(var(--bracket, var(--love)) 0 0) left bottom / 1px 10px no-repeat;
    225 }
    226 .corners::after {
    227   inset-inline-end: -3px;
    228   background:
    229     linear-gradient(var(--bracket, var(--love)) 0 0) right top / 10px 1px no-repeat,
    230     linear-gradient(var(--bracket, var(--love)) 0 0) right top / 1px 10px no-repeat,
    231     linear-gradient(var(--bracket, var(--love)) 0 0) right bottom / 10px 1px no-repeat,
    232     linear-gradient(var(--bracket, var(--love)) 0 0) right bottom / 1px 10px no-repeat;
    233 }
    234 /* The accent variant re-keys the ticks to iris — the site's signature hue —
    235    without touching the geometry. `--bracket` inherits into the pseudos. */
    236 .corners--accent { --bracket: var(--iris); }
    237 
    238 /* ---- Segmented status bar ------------------------------------------------ */
    239 /* tmux chrome: a ruled strip of square segments divided by hairlines. The
    240    bar is a flex row; segments are JetBrains Mono at furniture size; and the
    241    dividers are each segment's own inline-start border rather than a
    242    separate element, so an empty bar draws nothing. `--font-term` comes from
    243    tokens.css — the fallback keeps this intact if that token lands later in
    244    the cascade. */
    245 .segbar {
    246   display: flex;
    247   align-items: stretch;
    248   border-block: 1px solid var(--rule);
    249 }
    250 .seg {
    251   display: inline-flex;
    252   align-items: center;
    253   gap: 0.55rem;
    254   padding: 0.62rem 0.9rem;
    255   font-family: var(--font-term, 'JetBrains Mono', 'IBM Plex Mono', ui-monospace, monospace);
    256   font-size: 10.5px;
    257   letter-spacing: var(--track-micro);
    258   line-height: 1;
    259   text-transform: uppercase;
    260   white-space: nowrap;
    261   color: var(--fg-dim);
    262 }
    263 .seg + .seg { border-inline-start: 1px solid var(--rule); }
    264 /* The filled segment — the wordmark block, the active window. Accent ground,
    265    base ink; the divider hairline after it still belongs to the next seg. */
    266 .seg--accent {
    267   background: var(--accent);
    268   color: var(--base);
    269 }
    270 
    271 /* ---- The wordmark glitch ------------------------------------------------- */
    272 /* An RGB split keyed off `data-text`: the element carries its own string in
    273    the attribute, and the pseudos replay it as love/foam copies stacked on
    274    the real text, each clipped to a thin horizontal slice and nudged a pixel
    275    or two sideways. `glitch-shift` is a 5s loop that spends ~92% of itself
    276    idle — the tear is the first 0.4s — so the mark reads clean and only
    277    occasionally breaks. Under reduced motion the animation is never applied
    278    and the copies sit fully clipped: the mark is completely static. */
    279 .glitch { position: relative; }
    280 .glitch::before,
    281 .glitch::after {
    282   content: attr(data-text);
    283   position: absolute;
    284   inset: 0;
    285   pointer-events: none;
    286   user-select: none;
    287   /* Idle = invisible; the burst keyframes open and reclose the slice. */
    288   clip-path: inset(50% 0 50% 0);
    289 }
    290 .glitch::before { color: var(--love); }
    291 .glitch::after { color: var(--foam); }
    292 @media (prefers-reduced-motion: no-preference) {
    293   .glitch::before { animation: glitch-shift 5s linear infinite; }
    294   /* Reversed and offset, so the two copies never tear on the same line. */
    295   .glitch::after { animation: glitch-shift 5s linear 0.2s infinite reverse; }
    296 }
    297 
    298 /* ---- Scanlines ----------------------------------------------------------- */
    299 /* The CRT film for dark plates: a 3px-period repeating gradient at very low
    300    alpha, laid over the plate as an absolutely positioned sheet. It is its
    301    own element rather than a pseudo because the plates that want it — code
    302    panes, the footer, banners — already spend their pseudos on .corners. The
    303    host plate supplies the positioning context; events pass straight
    304    through. */
    305 .scanlines {
    306   position: absolute;
    307   inset: 0;
    308   z-index: 1;
    309   pointer-events: none;
    310   background: repeating-linear-gradient(0deg, rgb(0 0 0 / 0.09) 0 1px, transparent 1px 3px);
    311 }
    312 /* The rolling variant drifts the film slowly downward. 120px is a whole
    313    number of 3px periods, so the loop is seamless; under reduced motion the
    314    animation is never applied and the film lies still. */
    315 @media (prefers-reduced-motion: no-preference) {
    316   .scanlines--roll { animation: scanlines-roll 14s linear infinite; }
    317 }
    318 
    319 /* ---- Shared timing ------------------------------------------------------- */
    320 .dmn-t {
    321   transition:
    322     background-color 240ms ease,
    323     color 200ms ease,
    324     border-color 220ms ease,
    325     transform 220ms var(--ease-in),
    326     opacity 200ms ease;
    327 }
    328 
    329 /* ---- The lockup's scale rig ---------------------------------------------- */
    330 /* `scaleY` overflows its own line box, so a stretched display line has to
    331    sit in a fixed-height wrapper that clips it — otherwise it collides with
    332    whatever is under it and no amount of margin fixes it, because the
    333    overflow is not in the layout. */
    334 .clip { overflow: hidden; }
    335 .stretch {
    336   transform-origin: 0 0;
    337   white-space: nowrap;
    338   user-select: none;
    339 }
    340 
    341 /* ---- Keyframes ----------------------------------------------------------- */
    342 @keyframes dmn-up {
    343   from { opacity: 0; transform: translateY(18px); }
    344   to { opacity: 1; transform: translateY(0); }
    345 }
    346 @keyframes dmn-track-in {
    347   from { letter-spacing: 0.075em; transform: scaleX(0.93); }
    348   to { letter-spacing: 0.012em; transform: scaleX(1); }
    349 }
    350 @keyframes dmn-draw {
    351   from { transform: scaleX(0); }
    352   to { transform: scaleX(1); }
    353 }
    354 @keyframes dmn-wipe-in {
    355   from { clip-path: inset(0 100% 0 0); }
    356   to { clip-path: inset(0 0 0 0); }
    357 }
    358 @keyframes dmn-pulse {
    359   0%, 100% { opacity: 1; }
    360   50% { opacity: 0.25; }
    361 }
    362 @keyframes dmn-ring {
    363   0% { transform: scale(1); opacity: 0.7; }
    364   70%, 100% { transform: scale(2.6); opacity: 0; }
    365 }
    366 @keyframes dmn-blink {
    367   50% { opacity: 0; }
    368 }
    369 /* The glitch burst. Mostly idle by construction: every tear lives in the
    370    first 8% of the 5s loop (~0.4s), then the slice closes back to the
    371    invisible mid-line for the rest of the cycle. */
    372 @keyframes glitch-shift {
    373   0%    { clip-path: inset(8% 0 76% 0);  transform: translate(-2px, -1px); }
    374   1.5%  { clip-path: inset(52% 0 30% 0); transform: translate(2px, 1px); }
    375   3%    { clip-path: inset(24% 0 58% 0); transform: translate(-2px, 0); }
    376   4.5%  { clip-path: inset(70% 0 12% 0); transform: translate(1px, -1px); }
    377   6%    { clip-path: inset(40% 0 44% 0); transform: translate(-1px, 1px); }
    378   8%, 100% { clip-path: inset(50% 0 50% 0); transform: none; }
    379 }
    380 /* A whole number of scanline periods, so the drift loops seamlessly. */
    381 @keyframes scanlines-roll {
    382   from { background-position-y: 0; }
    383   to { background-position-y: 120px; }
    384 }
    385 
    386 /* Under reduced motion every entrance collapses to a single 0.01ms pass,
    387    which lands on the same rest state the animation would have reached —
    388    so the markup needs no second code path. */
    389 @media (prefers-reduced-motion: reduce) {
    390   *,
    391   *::before,
    392   *::after {
    393     animation-duration: 0.01ms !important;
    394     animation-iteration-count: 1 !important;
    395     transition-duration: 0.01ms !important;
    396     scroll-behavior: auto !important;
    397   }
    398 }