/* Atmosphere — the material the app is made of.
 * ============================================================================
 *
 * Greg, on the version before this one: "this cant look like something from
 * 2015 i need this to be elite". He was right, and the reason it looked like
 * 2015 is worth naming precisely, because "make it look better" is not a brief
 * anybody can act on.
 *
 * Every surface in the app was one flat rectangle: a white fill, a one-pixel
 * grey border, a barely-there shadow, on a flat cream ground. Dark mode was
 * the same rectangles with the fill swapped for grey. Nothing was lit from
 * anywhere, nothing sat above anything else, and a $120,000 truck ready to
 * sell was drawn with exactly the same weight as a $1,000 mower. That is the
 * house style of every admin panel built between 2013 and about 2018, and it
 * is not a matter of taste — it is the absence of two things that real
 * interfaces have.
 *
 * The first is **a light source**. Surfaces in the physical world are lit from
 * somewhere, so their top edge catches light and their underside drops shadow.
 * One inset highlight on the top edge does more for how solid a card feels
 * than any amount of shadow underneath it. This file gives the whole app one
 * light, above and slightly behind the viewer, and every surface answers to it.
 *
 * The second is **that dark mode is not light mode inverted**. On paper, a
 * raised thing is darker underneath. On a screen in the dark, a raised thing is
 * *lighter*, because the screen emits: elevation reads as proximity to the
 * light, not distance from the paper. Shadows in the dark do almost nothing —
 * black on near-black is invisible — so the work is done by the surface
 * getting lighter and by the rim catching more light. The old dark mode kept
 * the light-mode instinct and so had no depth at all.
 *
 * Everything else here follows from those two.
 *
 * WHAT THIS FILE MAY NOT COST
 * ---------------------------
 * The first version of the drifting light behind the app used `filter:
 * blur(90px)` and cost 117 milliseconds a frame while scrolling — seven frames
 * a second, against 16.7 for a smooth one. It looked lovely and it made the app
 * measurably worse to use, and it was torn out. That is the standing rule here:
 * atmosphere that costs frames is not atmosphere, it is a stutter with a mood.
 *
 * So nothing in this file blurs anything per frame, and nothing that moves is
 * painted on more than a handful of elements. The grain is one static image on
 * one fixed layer. The lighting is baked into box-shadow, which the compositor
 * handles. `motion.mjs` measures the result on every run and fails the suite if
 * scrolling drops a frame.
 */

/* ---------------------------------------------------------------- 1. LIGHT
 *
 * One light, up and slightly left, consistent everywhere. These are the only
 * numbers in the file that describe the light itself; every surface below is
 * expressed in terms of them, so the whole app can be relit by editing four
 * lines rather than four hundred.
 */
:root{
  /* How strongly the top edge of a surface catches the light. */
  --rim: rgba(255,255,255,.75);
  /* What a surface drops onto whatever is under it. Two shadows, always: a
     tight one for contact, a wide soft one for the room. One shadow reads as a
     sticker; two read as an object at a height. */
  --sh-key: 18,17,15;
  /* Raised, deliberately, in v83.
   *
   * These were .04 and .035 — which is a shadow you can prove exists with a
   * colour picker and cannot see. Every card in the app therefore sat flat on
   * the page, and "flat, even, nothing stands out" is most of what Greg meant
   * by *"the look is still so boring"*. A real card shadow is three layers: a
   * contact edge that says the card touches the page, a short spread that says
   * how far off it, and a long soft one that carries the weight. One layer at
   * any opacity reads as a grey outline. */
  --e1: 0 1px 1.5px rgba(var(--sh-key),.055), 0 2px 5px -1px rgba(var(--sh-key),.05),
        0 6px 14px -6px rgba(var(--sh-key),.05);
  --e2: 0 1px 2px rgba(var(--sh-key),.06), 0 5px 12px -3px rgba(var(--sh-key),.07),
        0 14px 30px -10px rgba(var(--sh-key),.08);
  --e3: 0 2px 4px rgba(var(--sh-key),.07), 0 10px 22px -6px rgba(var(--sh-key),.10),
        0 28px 60px -20px rgba(var(--sh-key),.14);
  --e4: 0 4px 8px rgba(var(--sh-key),.08), 0 20px 40px -10px rgba(var(--sh-key),.14),
        0 50px 100px -30px rgba(var(--sh-key),.22);

  /* Surfaces, ground upward. `--sur-1` is a card, `--sur-2` is something on
     top of a card, `--sur-3` is a menu or a drawer over everything. */
  --sur-1: #ffffff;
  --sur-2: #ffffff;
  --sur-3: #ffffff;
  /* The hairline. Two of them: one for edges that separate, one fainter for
     edges that only need to imply. */
  --edge:   rgba(28,27,24,.10);
  --edge-2: rgba(28,27,24,.055);

  /* Grain. Kills the deadness of a large flat fill — the thing that makes a
     screen read as a screenshot of an interface rather than a surface.
     Two tiles rather than a blend mode: see the note beside `html` in section
     2 for what that cost when it was done the obvious way. */
  --grain-tile: var(--grain-dark);
  /* The speckle itself. `feTurbulence` makes noise, then `feColorMatrix`
     throws its colour away and maps the luminance onto the ALPHA channel — so
     the tile is transparent-to-solid speckle that can simply be drawn on top
     of the ground. Black on paper, white in the dark. Under a kilobyte each,
     no network, and no blend mode, which is the whole point. */
  --grain-dark:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .06 .06 .06 0 0'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
  --grain-coarse: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='.5' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .14 .14 .14 0 0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  --grain-light:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 .09 .09 .09 0 0'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
  /* The ground itself is not one colour. A very slight warm lift at the top
     and a cool settle at the bottom is most of what "depth" means before
     anything is drawn on it at all. */
  --ground: radial-gradient(120% 80% at 50% -10%,
              rgba(255,252,244,.9) 0%, rgba(255,252,244,0) 60%),
            linear-gradient(180deg, var(--bg) 0%, var(--bg) 60%,
              color-mix(in srgb, var(--bg) 94%, #6b6455) 100%);
}

/* Dark: surfaces climb toward the light rather than away from it, the rim does
   the work the shadow cannot, and the ground is a deep neutral with a little
   warmth left in it so the brass still belongs. */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --rim: rgba(255,255,255,.055);
    --sh-key: 0,0,0;
    --e1: 0 1px 2px rgba(0,0,0,.5);
    --e2: 0 2px 4px rgba(0,0,0,.55), 0 8px 20px rgba(0,0,0,.4);
    --e3: 0 4px 10px rgba(0,0,0,.6), 0 20px 48px rgba(0,0,0,.5);
    --e4: 0 8px 20px rgba(0,0,0,.65), 0 40px 90px rgba(0,0,0,.6);
    --sur-1: #171614;
    --sur-2: #1d1c1a;
    --sur-3: #232120;
    --edge:   rgba(255,255,255,.075);
    --edge-2: rgba(255,255,255,.04);
    --grain-tile: var(--grain-light);
    --ground: radial-gradient(120% 90% at 50% -20%,
                rgba(58,52,42,.55) 0%, rgba(58,52,42,0) 55%),
              linear-gradient(180deg, #100e0c 0%, #0a0908 100%);
  }
}
:root[data-theme="dark"]{
  --rim: rgba(255,255,255,.055);
  --sh-key: 0,0,0;
  --e1: 0 1px 2px rgba(0,0,0,.5);
  --e2: 0 2px 4px rgba(0,0,0,.55), 0 8px 20px rgba(0,0,0,.4);
  --e3: 0 4px 10px rgba(0,0,0,.6), 0 20px 48px rgba(0,0,0,.5);
  --e4: 0 8px 20px rgba(0,0,0,.65), 0 40px 90px rgba(0,0,0,.6);
  --sur-1: #171614;
  --sur-2: #1d1c1a;
  --sur-3: #232120;
  --edge:   rgba(255,255,255,.075);
  --edge-2: rgba(255,255,255,.04);
  --grain-tile: var(--grain-light);
  --ground: radial-gradient(120% 90% at 50% -20%,
              rgba(58,52,42,.55) 0%, rgba(58,52,42,0) 55%),
            linear-gradient(180deg, #100e0c 0%, #0a0908 100%);
}

/* ---------------------------------------------------------------- 2. GROUND
 *
 * The ground and its grain are painted as backgrounds ON THE ROOT ELEMENT, not
 * as fixed pseudo-elements. That is not a stylistic preference; it is the
 * difference between sixty frames a second and thirty, and it was measured
 * three times before it was believed.
 *
 * The obvious way to put a light and a film grain behind an app is two
 * `position:fixed` layers with `inset:0`. Written that way, scrolling the
 * inventory ran at 33.3ms a frame against 16.7 with them gone. Taking away one
 * of the two changed nothing at all — still 33.3 — and taking away both went
 * straight back to 16.7. So the cost is not the gradient, and not the grain,
 * and not the blend mode that was blamed first: it is that a full-viewport
 * fixed layer sitting under scrolling content forces the compositor to
 * re-rasterise the viewport on every frame, and one is as expensive as two.
 *
 * The root element's own background does not have that problem — the
 * compositor already owns it — so both live there now, as two background
 * layers on one element that never repaints.
 *
 * A warning about how this was nearly got wrong: the first attempt to measure
 * it set `link.disabled = true` on the stylesheet and compared, which reported
 * a difference of 0.0ms and was completely false. Disabling the link did not
 * take the composited layers down. The only measurement that told the truth
 * was moving the file off disk and restarting. Measure by removing the thing,
 * not by asking the page to pretend.
 */
/* On BODY, not on html, and that is deliberate too.
 *
 * With `html` painted, `body` no longer propagates its background to the
 * canvas, so `getComputedStyle(document.body).backgroundColor` comes back
 * `rgba(0,0,0,0)` — and `lookui.mjs`, which checks that the text on each of
 * the five papers stays above 7:1 against what is behind it, started reporting
 * 1.2:1 on a screen that was in fact perfectly readable. The check was right to
 * complain: the app had stopped telling the truth about its own background,
 * and any other contrast check would have been misled the same way.
 *
 * Painting `body` keeps the propagation-to-canvas behaviour — the same single
 * composited layer, the same cost — and leaves the background inspectable,
 * which is what the accessibility checks read.
 *
 * FIXED ATTACHMENT, and this is not optional.
 *
 * It shipped once as `scroll` with `background-size: cover`, on the reasoning
 * that fixed attachment can make a compositor re-raster. Measured, it made no
 * difference to the cost — and it was visibly wrong in two ways at once,
 * because with `scroll` the background's positioning area is the whole
 * DOCUMENT rather than the window.
 *
 * On a long page that means the light from above is stretched down five
 * thousand pixels, so it is a barely-there wash instead of a light, and the
 * Aurora scene's corner glows are scaled until they are not there at all.
 * Greg: "the aurora doesnt work".
 *
 * On a SHORT page — an inventory screen with nothing imported yet — `cover` on
 * a box that is wide and shallow scales the gradient enormously sideways
 * instead, and the dark end of it lands in the right-hand margin as a grey
 * smear with an edge on it. Greg: "this dark shadow is not right".
 *
 * One property, both faults. `fixed` makes the positioning area the viewport,
 * which is what a light behind an app is supposed to be measured against. */
/* WHY THERE IS NO `background-size` HERE, AND WHY THAT IS THE WHOLE FIX
 *
 * Greg, a second time, on the same thing: **"aurora still doesnt work"**. He was
 * right, and the reason had nothing to do with light paper.
 *
 * `--ground` is one variable holding a whole stack of gradients, and different
 * scenes hold different numbers of them: Aurora is four in the dark and five on
 * paper, Deep is one. The rule here listed three sizes, three repeats and three
 * positions — and when a background has more layers than the size list, CSS does
 * not complain and does not stretch the list. **It cycles it.** So Aurora's
 * fourth gradient was handed the grain tile's `120px 120px` and `repeat`, and
 * the coloured light that was supposed to wash across the bottom of the window
 * was instead chopped into a hundred and twenty pixel squares and tiled over the
 * whole page, on top of the other three. The corners measured two values off the
 * middle. It looked like nothing, because it had been shredded into nothing.
 *
 * There is no number of entries that fixes this, only a number that fixes it
 * until somebody writes a scene with one more gradient in it — which is exactly
 * how it broke. So the lists are gone instead:
 *
 *   - the grain is an SVG with `width='120' height='120'` on it, so its
 *     intrinsic size IS 120x120 and `auto` gives it that, and `repeat` is
 *     already the default;
 *   - a gradient has no intrinsic size, so `auto` fills the positioning area,
 *     which with `fixed` is the window — which is the `100% 100%` the old list
 *     was spelling out by hand;
 *   - `background-attachment: fixed` written once applies to every layer,
 *     however many there are.
 *
 * Every layer now gets what it needs no matter how many there are, and a scene
 * with nine gradients in it would work the same.
 *
 * `fixed` is doing the other job it was brought in for, in section 2 above: it
 * makes the positioning area the window rather than the document, so the scene
 * does not stretch over a four-thousand-pixel inventory page and show one flat
 * slice of itself. */
body{
  background-color: var(--bg);
  background-image: var(--grain-tile), var(--ground);
  background-attachment: fixed;
  min-height:100vh;
}

/* ------------------------------------------------------------ 3. SURFACES
 *
 * One rule, applied to everything that is meant to sit above the ground. The
 * rim is what does the work: a single inset hairline along the top edge, the
 * colour of the light. Cover it up and every card in the app goes flat again.
 */
.tile,
.pcard,
.statTile, .stat, .signinstat,
.rigpanel, .menu, .pop{
  background: var(--sur-1);
  border:1px solid var(--edge);
  box-shadow: var(--e1), inset 0 1px 0 var(--rim);
}

.tile{
  border-radius: var(--r);
  transition: box-shadow .22s cubic-bezier(.2,.7,.3,1),
              transform .22s cubic-bezier(.2,.7,.3,1),
              border-color .22s ease;
}

/* Lifting on hover is a physical claim: the thing came toward you, so it
   catches more light and drops a longer shadow. Doing one without the other is
   the uncanny bit that makes cheap hover states feel wrong. */
.tile.hover:hover{
  transform: translateY(-2px);
  box-shadow: var(--e3), inset 0 1px 0 var(--rim);
  border-color: color-mix(in srgb, var(--edge) 70%, var(--accent));
}
.tile.hover:active{
  transform: translateY(0);
  box-shadow: var(--e1), inset 0 1px 0 var(--rim);
  transition-duration: .07s;
}

/* Things that float over the app rather than sit in it. */
.rigpanel.rig-popup, .menu, .pop{
  background: var(--sur-3);
  box-shadow: var(--e4), inset 0 1px 0 var(--rim);
}

/* A CLOSED DRAWER CASTS NOTHING, and this is the second time that has had to
 * be said.
 *
 * A drawer is parked at `translateX(102%)` — about nine pixels past the right
 * edge — rather than removed, so it can slide in. Nine pixels is enough to
 * hide the drawer and nowhere near enough to hide its shadow: a 76px blur
 * reaches most of the way back across the margin and paints a grey band down
 * the side of every page in the app. It reads as the window being cut off.
 *
 * `style.css` already carried a comment about exactly this, and a fix — the
 * shadow was only ever on `.drawer.on`. The blanket rule above, which gave
 * every floating surface the deepest elevation, quietly undid it and made it
 * worse, because the new blur is nearly twice the old one. Greg found it
 * immediately: "this dark shadow is not right".
 *
 * The lesson is not about drawers. It is that a rule listing several selectors
 * at once inherits none of the reasons any of them were written the way they
 * were. `railui.mjs` now measures the actual pixels down the right-hand margin
 * so this cannot come back a third time. */
.drawer{ background: var(--sur-3); box-shadow: none; }
.drawer.on{ box-shadow: -16px 0 44px rgba(var(--sh-key), .22); }

/* ---------------------------------------------------------------- 4. RAIL
 *
 * The rail is the one part of the app that is always there, so it is the one
 * part allowed to be a different material: slightly recessed, like a panel the
 * screen is set into rather than a card lying on it.
 */
.rail{
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--rail) 100%, transparent) 0%,
      color-mix(in srgb, var(--rail) 92%, var(--bg)) 100%);
  box-shadow: 1px 0 0 var(--edge-2), inset -12px 0 24px -24px rgba(var(--sh-key),.5);
}

/* --------------------------------------------------------------- 5. INPUTS
 *
 * Inset rather than raised, because a box you type into is a hole in the
 * surface, not a thing sitting on it. The old ones were drawn identically to
 * cards, which is why the search bar never looked like somewhere to type.
 */
input[type="text"], input[type="search"], input[type="date"],
input[type="number"], input[type="password"], input[type="email"],
textarea, select, .fld{
  background: color-mix(in srgb, var(--sur-1) 60%, var(--bg));
  border:1px solid var(--edge);
  box-shadow: inset 0 1px 2px rgba(var(--sh-key),.05);
  transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
}
input[type="text"]:focus, input[type="search"]:focus, input[type="date"]:focus,
input[type="number"]:focus, input[type="password"]:focus, input[type="email"]:focus,
textarea:focus, select:focus, .fld:focus{
  background: var(--sur-1);
  border-color: color-mix(in srgb, var(--accent) 55%, var(--edge));
  box-shadow: inset 0 1px 2px rgba(var(--sh-key),.04),
              0 0 0 3.5px var(--accent-soft);
  outline:none;
}

/* -------------------------------------------------------------- 6. BUTTONS
 *
 * A button is a thing you press, so it has to look like it is standing up
 * before you press it and like it has gone down while you do. The travel is
 * one pixel — enough to feel, not enough to notice.
 */
button, .btn{
  transition: transform .12s cubic-bezier(.2,.7,.3,1),
              box-shadow .16s ease, background .16s ease, border-color .16s ease;
}
button:active:not(:disabled), .btn:active{ transform: translateY(1px); }

button.primary, .primary{
  box-shadow: var(--e2), inset 0 1px 0 rgba(255,255,255,.14);
}
button.primary:hover:not(:disabled){
  box-shadow: var(--e3), inset 0 1px 0 rgba(255,255,255,.18);
}
button.primary:active:not(:disabled){
  box-shadow: var(--e1), inset 0 1px 0 rgba(255,255,255,.1);
}

/* -------------------------------------------------- 7. WHAT THE MONEY DOES
 *
 * Figures are the whole point of most of these screens, and they were being
 * set in the same proportional face as the prose around them — so digits
 * jittered as they changed and columns of money did not line up. Tabular
 * numerals fix both, and cost nothing.
 */
.money, .big, .num, .stat b, .statTile b, td.num, .price,
.uprice, .signinstat b, .railstat b{
  font-variant-numeric: tabular-nums;
  font-feature-settings:"tnum" 1, "ss01" 1;
  letter-spacing:-.015em;
}

/* -------------------------------------------------------- 8. REDUCED MOTION
 *
 * The lighting stays — it is not motion, and somebody who asked their Mac for
 * less movement did not ask for a flatter app. Only the travel goes.
 */
@media (prefers-reduced-motion: reduce){
  .tile, button, .btn{ transition-duration:.01ms !important; }
  .tile.hover:hover, button:active, .btn:active{ transform:none !important; }
}

/* Movement switched off in the app's own settings means the same thing. */
:root.nomotion .tile,
:root.nomotion .scard,
:root.nomotion .lookcard,
:root.nomotion button,
:root.nomotion .btn,
:root.nomotion .chip,
:root.nomotion .vchip{ transition:none !important; }
:root.nomotion .tile.hover:hover,
:root.nomotion .scard:hover,
:root.nomotion .lookcard:hover{ transform:none !important; }

/* ============================================================ THE TRUCK CARD
 *
 * Four hundred of these on the busiest screen in the app, so it is the single
 * component most worth getting right — and the one that most looked like 2015.
 *
 * What was wrong with it, in order of how much it cost:
 *
 * 1. THE TITLES SHOUTED. Every description arrives from DealerCenter in
 *    capitals and the card printed them that way. Capitals strip out the word
 *    shapes that make skim-reading work, so a grid of forty had to be spelled
 *    out letter by letter. Fixed in `MM.titleCase`, not here, but it is the
 *    largest single change to how this screen reads.
 *
 * 2. THE EMPTY PHOTO BOX WAS THE LOUDEST THING ON THE PAGE. 381 of 407 trucks
 *    have no photograph, so the dominant visual was a dashed grey outline with
 *    a generic glyph in it, repeated down the screen — a lot that looks
 *    broken. It now carries the stock number, which is what a salesman
 *    searches by and says down the phone, and which is different on every card.
 *
 * 3. NOTHING HAD A HIERARCHY. Title, price, age, location and status were all
 *    within a few points of each other in size and weight, so the eye had
 *    nowhere to land and a $120,000 truck ready to sell looked exactly like a
 *    $1,000 mower. The price is now unmistakably the thing on the card.
 */

.scard{
  background: var(--sur-1);
  border:1px solid var(--edge);
  box-shadow: var(--e1), inset 0 1px 0 var(--rim);
  border-radius: calc(var(--r) + 2px);
  padding:16px 18px 16px 19px;
  transition: transform .22s cubic-bezier(.2,.7,.3,1),
              box-shadow .22s cubic-bezier(.2,.7,.3,1),
              border-color .22s ease;
}
.scard:hover{
  transform: translateY(-3px);
  box-shadow: var(--e3), inset 0 1px 0 var(--rim);
  border-color: color-mix(in srgb, var(--edge) 55%, var(--accent));
}
.scard:active{ transform: translateY(-1px); transition-duration:.08s }

/* The ready stripe, lit rather than painted. A flat 3px bar is a bar; one that
   fades at both ends and carries a little of its own glow reads as a light
   behind the edge of the card, which is the whole idea. */
.scard::before{
  width:3px; left:0; top:14px; bottom:14px;
  border-radius:0 4px 4px 0;
}
.scard.ready::before{
  background:linear-gradient(180deg,
    transparent 0%, var(--good) 18%, var(--good) 82%, transparent 100%);
  box-shadow:0 0 12px -2px color-mix(in srgb, var(--good) 60%, transparent);
}

/* The stock number, where the photograph is not.
 *
 * Set in the app's own numerals at a size that reads across a desk, on a plate
 * tinted with the accent rather than left grey — grey says "nothing here",
 * and there is something here: this is truck 4585 and that is worth knowing at
 * a glance. */
.sthumb{
  width:78px; height:60px; border-radius:10px;
  border:1px solid var(--edge);
  box-shadow: inset 0 1px 0 var(--rim), inset 0 -8px 16px -12px rgba(var(--sh-key),.4);
}
.sthumb.blank{
  background:
    linear-gradient(160deg,
      color-mix(in srgb, var(--accent) 11%, var(--sur-1)) 0%,
      color-mix(in srgb, var(--accent) 4%, var(--sur-1)) 100%);
  display:flex; align-items:center; justify-content:center;
  border-style:solid;
}
.sthumb.blank .stk{
  font-size:15px; font-weight:680; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;
  color: color-mix(in srgb, var(--accent) 78%, var(--ink));
  opacity:.92; padding:0 4px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100%;
}
.scard:hover .sthumb.blank .stk{ opacity:1 }

/* The title, now that it is no longer shouting: a shade larger, a touch
   tighter, and set at the weight of something you are meant to read rather
   than something you are meant to notice. */
.sname b{
  font-size:14.5px; font-weight:600; line-height:1.34;
  letter-spacing:-.014em; height:38.9px; color:var(--ink);
}
.sname span{ font-size:11.5px; color:var(--ink-3); letter-spacing:.001em }

/* The price is the card. Set in the serif, tabular, and large enough that a row
   of cards can be read for money alone without reading anything else. */
.sfoot{ margin-top:14px }
.sfoot .p{
  /* The same face the big numbers elsewhere in the app already use, named the
     same way rather than approximated — a second serif stack that is nearly
     the first one is how two screens end up quietly disagreeing. */
  font-family:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,"Times New Roman",serif;
  font-size:22px; font-weight:600; letter-spacing:-.022em;
  font-variant-numeric:tabular-nums; color:var(--ink);
}
.sfoot .p.none{
  font-family:inherit; font-size:10.5px; font-weight:640;
  border:1px solid var(--edge); background:transparent;
}

/* Status. One row, quiet by default, and coloured only where something is
   actually stopping a sale. */
.stags{ border-top:1px solid var(--edge-2); padding-top:12px; margin-top:13px }
.stags .tag{
  border-radius:7px; padding:3px 8px; font-size:10.5px; font-weight:600;
  letter-spacing:.005em; border:1px solid transparent;
}
.stags .tag.ok{
  background: color-mix(in srgb, var(--good) 13%, transparent);
  border-color: color-mix(in srgb, var(--good) 30%, transparent);
}

/* A card the app is not sure about should not be as bright as one it is.
   Sold trucks and units awaiting arrival step back rather than shouting. */
.scard.gone, .scard.waiting{ opacity:.72 }
.scard.gone:hover, .scard.waiting:hover{ opacity:1 }

/* ------------------------------------------------------------- a whole look
 *
 * The cards on the Appearance screen. Each one shows the paper and the accent
 * it stands for rather than describing them, because a person picking how
 * their app looks is making the decision by eye and should not have to read
 * six sentences to do it. */
.lookset{display:grid; gap:10px;
  grid-template-columns:repeat(auto-fill, minmax(178px, 1fr))}
.lookcard{
  display:flex; flex-direction:column; align-items:flex-start; gap:7px;
  text-align:left; padding:13px 14px 14px; cursor:pointer;
  background:var(--sur-1); color:var(--ink);
  border:1px solid var(--edge); border-radius:calc(var(--r) - 2px);
  box-shadow:var(--e1), inset 0 1px 0 var(--rim);
  transition:transform .2s cubic-bezier(.2,.7,.3,1), box-shadow .2s ease,
             border-color .2s ease;
}
.lookcard:hover{ transform:translateY(-2px); box-shadow:var(--e2), inset 0 1px 0 var(--rim) }
.lookcard.on{
  border-color:var(--accent);
  box-shadow:var(--e2), inset 0 1px 0 var(--rim), 0 0 0 3px var(--accent-soft);
}
.lookcard b{font-size:13px; font-weight:640; letter-spacing:-.01em}
.lookcard .cap{margin:0; font-size:11px; line-height:1.45; color:var(--ink-3)}

/* The swatch: the paper as the field, the accent as the mark on it. */
.lookswatch{
  display:block; width:100%; height:34px; border-radius:8px; position:relative;
  background:linear-gradient(160deg, #fffdf7 0%, #f2efe6 100%);
  border:1px solid var(--edge); overflow:hidden;
}
.lookswatch.dk{ background:linear-gradient(160deg, #201e1b 0%, #0d0c0a 100%) }
.lookswatch i{
  position:absolute; left:10px; top:50%; transform:translateY(-50%);
  width:38px; height:8px; border-radius:20px; display:block;
}
.lookswatch::after{
  content:""; position:absolute; left:56px; top:50%; transform:translateY(-50%);
  width:44px; height:6px; border-radius:20px;
  background:currentColor; opacity:.22;
}
.lookswatch{ color:#1c1b18 }
.lookswatch.dk{ color:#faf8f4 }

/* ======================================================= WHAT IT IS MADE OF
 *
 * Greg, on the first version of this section: **"the new options do nothing"**.
 *
 * He was right, and the way he was right is worth writing down because the
 * settings genuinely did change the computed style — the attribute landed, the
 * custom properties moved, a test that asked "did anything change?" said yes.
 * Four of the five moved a real value. And it was still useless, because:
 *
 *   - the differences were small enough to need a diff tool to see;
 *   - `glow` only ever touched focus rings, so nothing on screen changed at all
 *     unless something happened to be focused at the time;
 *   - and `depth: floating` was measurably WEAKER than `lifted` in dark mode,
 *     because it redefined the shadows with the light-mode opacities and threw
 *     away the heavier dark ones.
 *
 * "The computed value changed" is not the bar. **A person switching between two
 * options has to be able to see which one they are on without being told.**
 * Every axis below is now written to that bar, and `axestest.mjs` checks it by
 * screenshotting the same screen under each option and refusing any two that
 * come back as more than 99% the same picture.
 */

/* ---- DEPTH -------------------------------------------------------------
 * Shadows are scaled from the ones the current mode already defines rather
 * than replaced with new numbers. That is what went wrong before: hardcoding
 * `rgba(var(--sh-key),.06)` in here meant dark mode got light mode's opacities
 * and the deepest setting came out the shallowest. */
:root[data-depth="flat"]{
  --e1:none; --e2:none;
  --e3:0 0 0 1px var(--edge); --e4:0 0 0 1px var(--edge);
  --rim:transparent;
  --lift-1:0px; --lift-2:0px;
}
:root[data-depth="flat"] .tile,
:root[data-depth="flat"] .scard,
:root[data-depth="flat"] .lookcard{ border-width:1px }
:root[data-depth="flat"] .tile.hover:hover,
:root[data-depth="flat"] .scard:hover,
:root[data-depth="flat"] .lookcard:hover{ transform:none }
:root[data-depth="flat"] .scard:hover{ border-color:var(--accent) }

:root{ --lift-1:-2px; --lift-2:-3px }

/* Floating: much bigger, much softer, and it really lifts. The numbers are
   deliberately far from `lifted` — a depth setting somebody cannot see is a
   depth setting that does not exist. */
:root[data-depth="floating"]{
  --e1: 0 2px 6px rgba(var(--sh-key),.10), 0 8px 24px rgba(var(--sh-key),.10);
  --e2: 0 4px 10px rgba(var(--sh-key),.13), 0 18px 44px rgba(var(--sh-key),.16);
  --e3: 0 8px 18px rgba(var(--sh-key),.16), 0 40px 90px rgba(var(--sh-key),.26);
  --e4: 0 14px 28px rgba(var(--sh-key),.20), 0 70px 150px rgba(var(--sh-key),.38);
  --lift-1:-5px; --lift-2:-8px;
}
.tile.hover:hover{ transform:translateY(var(--lift-1)) }
.scard:hover{ transform:translateY(var(--lift-2)) }
.lookcard:hover{ transform:translateY(var(--lift-1)) }

/* ---- TEXTURE -----------------------------------------------------------
 * Coarse is now genuinely coarse: a bigger tile, four octaves and roughly
 * three times the alpha, so it reads as paper across a desk rather than as a
 * slightly dirty screen. */
:root[data-texture="none"]{ --grain-tile:none }
:root[data-texture="coarse"]{ --grain-tile:var(--grain-coarse) }

/* ---- GLOW --------------------------------------------------------------
 * The old version only lit focus rings, which is why it looked like nothing:
 * on a screen full of trucks nothing is focused. It now lights the things that
 * are on screen all the time — the ready stripe down a card, the count badges,
 * the page you are on in the rail, and the primary button. */
:root{ --halo:0 0 0 3.5px var(--accent-soft); --halo-strong:0 0 0 3.5px var(--accent-soft) }
:root[data-glow="off"]{ --halo:none; --halo-strong:none }
:root[data-glow="neon"]{
  --halo: 0 0 0 1px color-mix(in srgb, var(--accent) 60%, transparent),
          0 0 20px -2px color-mix(in srgb, var(--accent) 65%, transparent);
  --halo-strong: 0 0 0 1px color-mix(in srgb, var(--accent) 75%, transparent),
          0 0 30px -2px color-mix(in srgb, var(--accent) 80%, transparent),
          0 0 70px -8px color-mix(in srgb, var(--accent) 55%, transparent);
}
input:focus, textarea:focus, select:focus, .fld:focus{
  box-shadow: inset 0 1px 2px rgba(var(--sh-key),.04), var(--halo) }
.lookcard.on{ box-shadow:var(--e2), inset 0 1px 0 var(--rim), var(--halo-strong) }

/* Visible without touching anything. */
:root[data-glow="soft"] .scard.ready::before{
  box-shadow:0 0 14px -1px color-mix(in srgb, var(--good) 55%, transparent) }
:root[data-glow="neon"] .scard.ready::before{
  box-shadow:0 0 10px 0 color-mix(in srgb, var(--good) 95%, transparent),
             0 0 34px 2px color-mix(in srgb, var(--good) 65%, transparent) }
:root[data-glow="off"] .scard.ready::before{ box-shadow:none }

:root[data-glow="neon"] .railnav a.on,
:root[data-glow="neon"] .pip,
:root[data-glow="neon"] #tabs button[aria-pressed="true"],
:root[data-glow="neon"] button.primary,
:root[data-glow="neon"] .chip.on,
:root[data-glow="neon"] .vchip.on{ box-shadow: var(--halo) }
:root[data-glow="neon"] .sthumb.blank .stk{
  text-shadow:0 0 14px color-mix(in srgb, var(--accent) 70%, transparent) }
:root[data-glow="off"] .railnav a.on{ box-shadow:none }

/* ---- EDGES -------------------------------------------------------------
 * None means none — no hairline anywhere, shape carried entirely by shadow.
 * Glass means the edge is a lit rim rather than a drawn line, brightest along
 * the top where the light is. */
:root[data-edge="none"] .tile,
:root[data-edge="none"] .scard,
:root[data-edge="none"] .lookcard,
:root[data-edge="none"] .stags,
:root[data-edge="none"] input,
:root[data-edge="none"] textarea,
:root[data-edge="none"] select{ border-color:transparent !important }
:root[data-edge="none"]{ --edge:transparent; --edge-2:transparent }

:root[data-edge="glass"]{
  --edge: color-mix(in srgb, var(--rim) 80%, transparent);
  --edge-2: color-mix(in srgb, var(--rim) 45%, transparent);
  --rim: rgba(255,255,255,.9);
}
:root[data-theme="dark"][data-edge="glass"],
:root[data-edge="glass"]:not([data-theme="light"]){ --rim: rgba(255,255,255,.14) }
:root[data-edge="glass"] .tile,
:root[data-edge="glass"] .scard{
  border-color:transparent;
  box-shadow: var(--e2),
              inset 0 1px 0 var(--rim),
              inset 0 0 0 1px color-mix(in srgb, var(--rim) 35%, transparent),
              inset 0 -14px 24px -20px color-mix(in srgb, var(--rim) 60%, transparent);
}

/* ---- THE LIGHT BEHIND IT ----------------------------------------------- */
:root[data-scene="off"]{ --ground:linear-gradient(180deg, var(--bg), var(--bg)) }
/* Warm, strengthened in v83.
 *
 * Measured with the app's own content hidden — which is the only way to see the
 * ground at all — the old warm wash moved 7 values from the top of the window to
 * the middle and 4 across it. That is a setting called "a soft light from above"
 * that does not light anything. It read as "pass" for a year because the probe
 * happened to sample a white card for its second point.
 *
 * Three layers now: the light itself, a soft vignette so the corners settle, and
 * the settle down the page that was always there. */
:root[data-scene="warm"]{
  --ground: radial-gradient(112% 58% at 50% -8%,
              rgba(255,253,247,1) 0%, rgba(255,253,247,0) 64%),
            radial-gradient(135% 96% at 50% 42%, rgba(107,100,85,0) 38%,
              rgba(107,100,85,.16) 100%),
            linear-gradient(180deg, var(--bg) 0%, var(--bg) 48%,
              color-mix(in srgb, var(--bg) 88%, #6b6455) 100%);
}
:root[data-theme="dark"][data-scene="warm"]{
  --ground: radial-gradient(112% 64% at 50% -12%,
              rgba(84,74,58,.95) 0%, rgba(84,74,58,0) 60%),
            radial-gradient(135% 96% at 50% 42%, rgba(0,0,0,0) 36%,
              rgba(0,0,0,.5) 100%),
            linear-gradient(180deg, #131110 0%, #080707 100%);
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"])[data-scene="warm"]{
    --ground: radial-gradient(112% 64% at 50% -12%,
                rgba(84,74,58,.95) 0%, rgba(84,74,58,0) 60%),
              radial-gradient(135% 96% at 50% 42%, rgba(0,0,0,0) 36%,
                rgba(0,0,0,.5) 100%),
              linear-gradient(180deg, #131110 0%, #080707 100%);
  }
}
:root[data-scene="deep"]{
  --ground: radial-gradient(78% 58% at 50% 34%,
              color-mix(in srgb, var(--bg) 78%, #ffffff) 0%,
              var(--bg) 46%,
              color-mix(in srgb, var(--bg) 58%, #000000) 100%);
}
/* Aurora was here. It is not any more, and the reason is worth keeping.
 *
 * Greg, three times: "the aurora doesnt work", "aurora still doesnt work", and
 * then "if you cant figure it out just delete it".
 *
 * Two of the three faults were real and are fixed above — the `background-size`
 * list shorter than the layer list, and `.shell` painting the page colour back
 * over the top. After both, the pixel probe read 68 values between the corner of
 * the window and the middle, and that got called working. On cream paper it
 * looked like a grey-brown stain with a purple smudge in one corner, because
 * brass at 30% over an off-white is mud by construction — and a coffee stain
 * would have measured 68 too.
 *
 * "Is it different" is not "is it good", and no probe that can be written here
 * answers the second one. Looking at the screenshot did, three rounds later
 * than it should have.
 *
 * Warm and Deep both read properly on paper and in the dark. This one only ever
 * did in the dark, and a setting that has to be qualified costs more than it
 * gives. `prefs.RETIRED` moves anybody still on it to Warm.
 */

/* ================================================== FOUR MORE, ALL VISIBLE
 *
 * Same bar as above: if you cannot tell which one is on by looking, it does
 * not belong here.
 */

/* ---- HOW MUCH COLOUR --------------------------------------------------
 * The accent was used in exactly one strength. Minimal keeps it for the one
 * thing that is genuinely selected; Vivid runs it through headings, badges,
 * card edges and the price. */
:root[data-colour="minimal"]{
  --accent-soft: color-mix(in srgb, var(--accent) 8%, transparent);
}
:root[data-colour="minimal"] .tl,
:root[data-colour="minimal"] .secttl{ color:var(--ink-3) }
:root[data-colour="minimal"] .scard.ready::before{ background:var(--ink-3) }

:root[data-colour="vivid"]{
  --accent-soft: color-mix(in srgb, var(--accent) 30%, transparent);
}
:root[data-colour="vivid"] .secttl,
:root[data-colour="vivid"] .tl{ color:var(--accent) }
:root[data-colour="vivid"] .sfoot .p{ color:var(--accent) }
:root[data-colour="vivid"] .scard{
  border-color: color-mix(in srgb, var(--accent) 28%, var(--edge)) }
:root[data-colour="vivid"] .scard:hover{
  border-color: color-mix(in srgb, var(--accent) 65%, transparent) }
:root[data-colour="vivid"] .pip,
:root[data-colour="vivid"] .chip.on{
  background:var(--accent); border-color:var(--accent); color:#fff }
:root[data-colour="vivid"] .sthumb.blank{
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--accent) 26%, var(--sur-1)) 0%,
    color-mix(in srgb, var(--accent) 10%, var(--sur-1)) 100%) }

/* ---- HOW IT MOVES -----------------------------------------------------
 * Not whether it moves — that is the existing Movement setting — but the
 * character of it. Calm is slow and even; Springy overshoots and settles. */
:root{ --ease:cubic-bezier(.2,.7,.3,1); --quick:.22s; --slow:.34s }
:root[data-feel="calm"]{ --ease:cubic-bezier(.4,0,.2,1); --quick:.38s; --slow:.6s }
:root[data-feel="springy"]{ --ease:cubic-bezier(.34,1.56,.64,1); --quick:.3s; --slow:.44s }
.tile, .scard, .lookcard, button, .btn, .chip, .vchip{
  transition-timing-function:var(--ease) !important;
  transition-duration:var(--quick) !important;
}
:root[data-feel="springy"] .scard:hover{ transform:translateY(var(--lift-2)) scale(1.012) }
:root[data-feel="springy"] .lookcard:hover{ transform:translateY(var(--lift-1)) scale(1.02) }
:root[data-feel="calm"] .scard:hover{ transform:translateY(calc(var(--lift-2) * .5)) }

/* ---- WHAT THE MENU IS MADE OF ----------------------------------------- */
:root[data-railmat="solid"] .rail{
  background:var(--sur-1);
  box-shadow:1px 0 0 var(--edge);
}
:root[data-railmat="none"] .rail{
  background:transparent; box-shadow:none;
}
:root[data-railmat="glass"] .rail{
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--sur-2) 82%, transparent) 0%,
    color-mix(in srgb, var(--sur-1) 62%, transparent) 100%);
  box-shadow: inset -1px 0 0 var(--rim), 1px 0 0 var(--edge-2);
}
/* The one place a blur is affordable: the rail is a fixed-width column that
   does not scroll, so it composites once rather than every frame. Measured at
   0.1ms — the full-viewport version of this is what cost 117ms and was torn
   out years ago. */
@supports (backdrop-filter: blur(1px)){
  :root[data-railmat="glass"] .rail{ backdrop-filter:blur(14px) saturate(1.4) }
}

/* ---- WHAT A CARD IS ---------------------------------------------------- */
:root[data-cardstyle="outline"] .scard,
:root[data-cardstyle="outline"] .tile{
  background:transparent; box-shadow:none;
  border:1px solid color-mix(in srgb, var(--edge) 180%, transparent);
}
:root[data-cardstyle="inset"] .scard,
:root[data-cardstyle="inset"] .tile{
  background: color-mix(in srgb, var(--bg) 55%, var(--sur-1));
  box-shadow: inset 0 2px 6px rgba(var(--sh-key),.10),
              inset 0 -1px 0 var(--rim);
  border-color:transparent;
}
:root[data-cardstyle="tint"] .scard{
  background: linear-gradient(168deg,
    color-mix(in srgb, var(--accent) 9%, var(--sur-1)) 0%,
    var(--sur-1) 62%);
}
:root[data-cardstyle="tint"] .tile{
  background: linear-gradient(168deg,
    color-mix(in srgb, var(--accent) 6%, var(--sur-1)) 0%,
    var(--sur-1) 70%);
}

/* ============================================== THE SMALL THINGS THAT ANSWER
 *
 * Greg: "just little cool details that make this fun and easier to use as well
 * not just all looks".
 *
 * The "easier to use" half is what earns these. Every one of them closes a gap
 * where the app used to say nothing and somebody had to guess whether it had
 * heard them.
 */

/* ---- the ripple ------------------------------------------------------- */
/* One layer for every ripple in the app, over everything and touchable by
   nothing. The circles are placed in viewport coordinates and clipped to the
   control they belong to — see the note in common.js for why they are not
   simply put inside it. */
#ripples{
  position:fixed; inset:0; z-index:9998; pointer-events:none; overflow:hidden;
  contain:strict;
}
.ripple{
  position:fixed; border-radius:50%; pointer-events:none;
  background: currentColor; opacity:.16;
  transform:scale(0);
  animation: rippleout .55s cubic-bezier(.22,.8,.3,1) forwards;
  /* Its own layer, so a press on a card in a grid of four hundred does not
     make the browser think about the other three hundred and ninety-nine. */
  will-change: transform, opacity;
}
@keyframes rippleout{
  from{ transform:scale(0); opacity:.20 }
  to  { transform:scale(1); opacity:0 }
}
/* On a dark surface the ripple has to be light, and `currentColor` is already
   the text colour, which is light. Nothing to do — but on the primary button,
   whose text is white on a dark fill, it wants to be gentler. */
button.primary .ripple, .primary .ripple{ opacity:.22 }
:root[data-glow="neon"] .ripple{ background:var(--accent); opacity:.3 }
:root.nomotion .ripple{ display:none }
@media (prefers-reduced-motion: reduce){ .ripple{ display:none } }

/* ---- where the keyboard is -------------------------------------------
 * A focus ring that only appears for somebody actually using the keyboard.
 * `:focus-visible` is what makes that possible — a mouse press does not draw
 * it, so it never looks like a stuck highlight, and a Tab press always does.
 * Driving this app by keyboard was possible before and invisible. */
:where(button, a, input, select, textarea, .chip, .vchip, .scard,
       .lookcard, [tabindex]):focus-visible{
  outline:2px solid var(--accent);
  outline-offset:2px;
  border-radius:inherit;
}
.scard:focus-visible{
  outline-offset:3px;
  box-shadow:var(--e3), inset 0 1px 0 var(--rim), var(--halo);
}

/* ---- a press that is felt --------------------------------------------
 * Everything pressable goes down by a pixel and comes back. It is the
 * cheapest possible confirmation and it is the one people notice missing
 * without being able to say what is wrong. */
.chip:active, .vchip:active, .tag:active, .lnk:active{ transform:translateY(1px) }

/* ---- something just changed ------------------------------------------
 * A number that was updated by somebody else, or by an import, used to
 * silently be a different number. It flashes its colour once, briefly, so a
 * screen somebody is not staring at still tells them what moved. */
@keyframes justchanged{
  0%  { background:color-mix(in srgb, var(--accent) 34%, transparent) }
  100%{ background:transparent }
}
.changed{ animation:justchanged 1.5s ease-out 1; border-radius:6px }
:root.nomotion .changed{ animation:none }

/* ---- copied ----------------------------------------------------------
 * Copy is the loud button on a truck's links, and the clipboard gives no
 * feedback of its own at all. */
@keyframes copiedpop{
  0%  { transform:scale(.8); opacity:0 }
  35% { transform:scale(1.06); opacity:1 }
  100%{ transform:scale(1); opacity:1 }
}
.copied{ animation:copiedpop .34s cubic-bezier(.34,1.56,.64,1) 1 }

/* ---- something is on its way -----------------------------------------
 * A row waiting on the server gets a slow sheen rather than a spinner, so the
 * shape of what is coming is already on screen. */
@keyframes shimmer{ from{ background-position:-200% 0 } to{ background-position:200% 0 } }
.waitingrow{
  background-image:linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, var(--ink) 7%, transparent) 50%,
    transparent 100%);
  background-size:200% 100%;
  animation:shimmer 1.4s linear infinite;
}
:root.nomotion .waitingrow{ animation:none }

/* ---- dragging photos in ----------------------------------------------
 * The drop area used to change one border colour. It now lifts, lights and
 * says it is ready, because dropping forty photos on a target you are not
 * sure about is a thing people do slowly and twice. */
.drop.over{
  border-color:var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  box-shadow: var(--halo-strong), var(--e3);
  transform: scale(1.008);
}

/* Aurora is a dark-mode effect, and the app says so rather than pretending.
 *
 * Greg: "the aurora doesnt work". Half of that was the background being sized
 * to the document instead of the window, which is fixed. The other half is
 * real and is not fixable by trying harder.
 *
 * A coloured light needs something to be brighter than. On cream paper the
 * content covers nearly all the ground, and what little shows is already
 * near-white — measured on the front page, the corners came out two values out
 * of 255 from the middle. Two attempts went into closing that: stronger
 * gradients, and letting the surfaces go slightly translucent so the colour
 * could come through them. The first was invisible. The second was invisible
 * AND cost compositing on every scrolled frame, so it was taken out again.
 *
 * Pushing it far enough to see on paper does not produce atmosphere; it
 * produces an app that looks tinted, which is worse than an app that looks
 * plain. So the effect stays as strong as it honestly can be, and the
 * Appearance screen tells anybody who picks it in light mode that it is built
 * for the dark and offers them the switch. An option that quietly does nothing
 * on your screen is the thing worth avoiding here — not the admission.
 */

/* A short warning inside a settings panel — for the one case where an option
   is honest about not doing much on your screen. */
.note.warn{
  border:1px solid var(--warn-line);
  background:var(--warn-bg);
  color:var(--warn-2);
  border-radius:calc(var(--r) - 4px);
  padding:11px 13px;
  font-size:12px; line-height:1.5;
}
.note.warn b{ font-weight:650 }
.note.warn .btnrow{ margin-top:9px }

/* =====================================================================
   SKINS — the theme picker, made to actually change the app
   =====================================================================

   Greg: *"I want the theme picker to change the app drastically to these
   options also add more get very creative"*.

   The old picker had twenty axes and every combination still looked like the
   same app in a different beige. A skin is not an axis: it is a complete
   identity — paper, ink, accent, typeface, corner radius, whether a card even
   HAS a border, what a shadow is made of, and what the light behind the app is
   doing — set in one press.

   Everything below is token overrides. No component knows a skin exists.

   WHY THE SELECTORS LOOK LIKE THAT. Every skin is written
   `:root[data-skin="x"][data-skin]` and not the obvious form,
   a type selector plus one attribute.
   That obvious form is specificity (0,1,1).
   The mode it has to beat is `:root[data-theme="dark"]`, which is (0,2,0) --
   `:root` is a PSEUDO-CLASS, not a type selector, so it counts in the same
   column as an attribute and is worth more than `html`. For a year every skin
   silently lost to dark mode: Greg had newsprint and dark set together and saw
   neither, just the default dark app with a serif face, and reasonably said
   nothing had changed. Repeating the attribute costs nothing and puts a skin at
   (0,3,0), above dark mode and above the `[data-theme][data-paper]` pairs.
   A skin owns the palette; that is the whole point of a skin. */

/* ---------- 1. GRAPHITE — near-black, acid lime, no borders anywhere ------ */
:root[data-skin="graphite"][data-skin]{
  color-scheme:dark;
  --bg:#08090a; --panel:#0f1113; --panel-2:#141719; --rail:#0a0b0c;
  --line:rgba(255,255,255,.07); --line-2:rgba(255,255,255,.05); --line-3:rgba(255,255,255,.035);
  --ink:#eceef1; --ink-2:#9aa1a8; --ink-3:#6b6f76;
  --accent:#c6f24e; --brass:#c6f24e; --brass-soft:rgba(198,242,78,.13);
  --accent-soft:rgba(198,242,78,.13);
  --good:#5fe08f; --good-2:#5fe08f; --warn:#ffc247; --warn-2:#ffc247;
  --bad:#ff6a5c; --bad-2:#ff6a5c; --pos:#5fe08f; --neg:#ff6a5c;
  --warn-bg:rgba(255,194,71,.09); --warn-line:rgba(255,194,71,.24);
  --mute:#2a2e32; --deemph:#4e5257; --grid:#191c1f; --axis:#23272b;
  --r:15px; --r-sm:12px; --r-xs:9px;
  --face:system-ui,-apple-system,"SF Pro Text","Segoe UI",sans-serif;
  --sur-1:#0f1113; --sur-2:#141719; --sur-3:#1a1e21;
  --edge:rgba(255,255,255,.07); --edge-2:rgba(255,255,255,.045);
  --rim:rgba(255,255,255,.06); --sh-key:0,0,0;
  --e1:0 1px 2px rgba(0,0,0,.5); --e2:0 2px 6px rgba(0,0,0,.55),0 10px 26px -12px rgba(0,0,0,.6);
  --e3:0 6px 18px rgba(0,0,0,.6),0 26px 60px -24px rgba(0,0,0,.7);
  --e4:0 10px 28px rgba(0,0,0,.66),0 50px 110px -40px rgba(0,0,0,.8);
  --lift:0 1px 2px rgba(0,0,0,.5); --lift-2:0 6px 18px rgba(0,0,0,.6);
  --ground:radial-gradient(90% 55% at 78% -12%, rgba(198,242,78,.075), transparent 60%),
           radial-gradient(70% 50% at 8% 108%, rgba(110,107,255,.07), transparent 62%),
           linear-gradient(180deg,#08090a,#08090a);
}
:root[data-skin="graphite"][data-skin] .tile,
:root[data-skin="graphite"][data-skin] .scard,
:root[data-skin="graphite"][data-skin] .numtile,
:root[data-skin="graphite"][data-skin] .chanlist,
:root[data-skin="graphite"][data-skin] .hublist,
:root[data-skin="graphite"][data-skin] .dotile{border-color:transparent;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.055), inset 0 1px 0 rgba(255,255,255,.045)}
:root[data-skin="graphite"][data-skin] .railnav a.on{background:rgba(255,255,255,.075); color:#eceef1}
:root[data-skin="graphite"][data-skin] .railnav a.on .ico{color:var(--accent)}
:root[data-skin="graphite"][data-skin] button.primary,
:root[data-skin="graphite"][data-skin] .btn.primary{background:#c6f24e; color:#0b0d0a; border-color:#c6f24e}

/* ---------- 2. AURORA — colour mesh behind frosted glass ------------------ */
:root[data-skin="aurora"][data-skin]{
  color-scheme:light;
  --bg:#f4f2fb; --panel:rgba(255,255,255,.68); --panel-2:rgba(255,255,255,.54);
  --rail:rgba(255,255,255,.6);
  --line:rgba(255,255,255,.85); --line-2:rgba(255,255,255,.7); --line-3:rgba(255,255,255,.5);
  --ink:#221f33; --ink-2:#5c5675; --ink-3:#8b849f;
  --accent:#5b4bdd; --brass:#5b4bdd; --brass-soft:rgba(124,92,255,.16);
  --accent-soft:rgba(124,92,255,.16);
  --good:#12a37a; --good-2:#0e7f5f; --warn:#e08b1f; --warn-2:#9a5c0a;
  --bad:#e0413a; --bad-2:#b52f29; --pos:#0e7f5f; --neg:#b52f29;
  --warn-bg:rgba(255,196,120,.24); --warn-line:rgba(224,139,31,.32);
  --mute:#cdc7de; --deemph:#a29bb5; --grid:#e6e2f2; --axis:#d5cfe6;
  --r:20px; --r-sm:15px; --r-xs:11px;
  --face:"Avenir Next",Avenir,system-ui,-apple-system,"Segoe UI",sans-serif;
  --sur-1:rgba(255,255,255,.68); --sur-2:rgba(255,255,255,.56); --sur-3:rgba(255,255,255,.46);
  --edge:rgba(255,255,255,.85); --edge-2:rgba(255,255,255,.6);
  --rim:rgba(255,255,255,.9); --sh-key:60,50,110;
  --e1:0 1px 2px rgba(60,50,110,.05),0 10px 24px -14px rgba(60,50,110,.3);
  --e2:0 1px 2px rgba(60,50,110,.06),0 20px 44px -24px rgba(60,50,110,.38);
  --e3:0 2px 6px rgba(60,50,110,.08),0 34px 70px -30px rgba(60,50,110,.45);
  --e4:0 4px 12px rgba(60,50,110,.1),0 60px 120px -46px rgba(60,50,110,.55);
  --lift:0 1px 2px rgba(60,50,110,.05),0 10px 24px -14px rgba(60,50,110,.3);
  --lift-2:0 2px 6px rgba(60,50,110,.08),0 30px 64px -28px rgba(60,50,110,.44);
  --ground:radial-gradient(48% 46% at 12% 8%, rgba(124,92,255,.42), transparent 62%),
           radial-gradient(42% 44% at 88% 12%, rgba(46,196,182,.36), transparent 62%),
           radial-gradient(46% 48% at 74% 96%, rgba(255,138,76,.30), transparent 62%),
           radial-gradient(40% 40% at 26% 92%, rgba(88,140,255,.28), transparent 62%),
           linear-gradient(180deg,#f4f2fb,#eeebf8);
}
:root[data-skin="aurora"][data-skin] .tile,
:root[data-skin="aurora"][data-skin] .scard,
:root[data-skin="aurora"][data-skin] .numtile,
:root[data-skin="aurora"][data-skin] .chanlist,
:root[data-skin="aurora"][data-skin] .hublist,
:root[data-skin="aurora"][data-skin] .rail,
:root[data-skin="aurora"][data-skin] .topbar,
:root[data-skin="aurora"][data-skin] .dotile{backdrop-filter:blur(22px) saturate(165%);
  -webkit-backdrop-filter:blur(22px) saturate(165%); border-color:transparent;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.85), var(--lift)}
:root[data-skin="aurora"][data-skin] button.primary,
:root[data-skin="aurora"][data-skin] .btn.primary{background:linear-gradient(140deg,#7c5cff,#4f46e5);
  border-color:transparent; color:#fff; box-shadow:0 10px 24px -10px rgba(79,70,229,.95)}
:root[data-skin="aurora"][data-skin] .railnav a.on{background:linear-gradient(140deg,#7c5cff,#4f46e5);
  color:#fff; box-shadow:0 8px 20px -10px rgba(79,70,229,.9)}

/* ---------- 3. BENTO — light, zero borders, big soft shadows -------------- */
:root[data-skin="bento"][data-skin]{
  color-scheme:light;
  --bg:#f6f5f3; --panel:#ffffff; --panel-2:#faf9f7; --rail:#f6f5f3;
  --line:transparent; --line-2:transparent; --line-3:#f0eeeb;
  --ink:#14120f; --ink-2:#4a4741; --ink-3:#8e8b86;
  --accent:#e8430f; --brass:#e8430f; --brass-soft:#fdece6; --accent-soft:#fdece6;
  --good:#1a8f4c; --good-2:#0f7a3f; --warn:#c97a10; --warn-2:#8a5306;
  --bad:#d1372b; --bad-2:#a92c22; --pos:#0f7a3f; --neg:#a92c22;
  --warn-bg:#fdf4e6; --warn-line:#f2e2c4;
  --mute:#e3e0dc; --deemph:#b8b4ae; --grid:#f0eeeb; --axis:#e3e0dc;
  --r:18px; --r-sm:14px; --r-xs:10px;
  --face:system-ui,-apple-system,"SF Pro Text","Segoe UI",sans-serif;
  --sur-1:#ffffff; --sur-2:#faf9f7; --sur-3:#f2f0ed;
  --edge:transparent; --edge-2:transparent; --rim:rgba(255,255,255,.9); --sh-key:20,18,15;
  --e1:0 1px 2px rgba(20,18,15,.045),0 8px 22px -14px rgba(20,18,15,.18);
  --e2:0 1px 2px rgba(20,18,15,.05),0 14px 34px -20px rgba(20,18,15,.22);
  --e3:0 2px 4px rgba(20,18,15,.06),0 26px 56px -28px rgba(20,18,15,.3);
  --e4:0 4px 10px rgba(20,18,15,.08),0 50px 100px -40px rgba(20,18,15,.4);
  --lift:0 1px 2px rgba(20,18,15,.045),0 8px 22px -14px rgba(20,18,15,.18);
  --lift-2:0 2px 6px rgba(20,18,15,.07),0 22px 48px -24px rgba(20,18,15,.28);
  --ground:linear-gradient(180deg,#f6f5f3,#f2f0ed);
}
:root[data-skin="bento"][data-skin] .tile,
:root[data-skin="bento"][data-skin] .scard,
:root[data-skin="bento"][data-skin] .numtile,
:root[data-skin="bento"][data-skin] .chanlist,
:root[data-skin="bento"][data-skin] .hublist,
:root[data-skin="bento"][data-skin] .dotile{border:none; box-shadow:var(--lift)}
:root[data-skin="bento"][data-skin] .chip{border-color:transparent; background:#f2f0ed}
:root[data-skin="bento"][data-skin] .chip.on{background:#14120f; color:#fff}

/* ---------- 4. BLUEPRINT — drafting office: navy, cyan, grid, mono ------- */
:root[data-skin="blueprint"][data-skin]{
  color-scheme:dark;
  --bg:#081521; --panel:#0d1f30; --panel-2:#112838; --rail:#061019;
  --line:rgba(77,216,230,.19); --line-2:rgba(77,216,230,.12); --line-3:rgba(77,216,230,.07);
  --ink:#dff2f7; --ink-2:#8fb4c4; --ink-3:#5d8598;
  --accent:#4dd8e6; --brass:#4dd8e6; --brass-soft:rgba(77,216,230,.14);
  --accent-soft:rgba(77,216,230,.14);
  --good:#4be08a; --good-2:#4be08a; --warn:#ffc247; --warn-2:#ffc247;
  --bad:#ff6b6b; --bad-2:#ff6b6b; --pos:#4be08a; --neg:#ff6b6b;
  --warn-bg:rgba(255,194,71,.1); --warn-line:rgba(255,194,71,.26);
  --mute:#1b3040; --deemph:#3f6274; --grid:rgba(77,216,230,.09); --axis:rgba(77,216,230,.2);
  --r:4px; --r-sm:3px; --r-xs:2px;
  --face:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  --sur-1:#0d1f30; --sur-2:#112838; --sur-3:#153044;
  --edge:rgba(77,216,230,.2); --edge-2:rgba(77,216,230,.12);
  --rim:rgba(77,216,230,.14); --sh-key:0,0,0;
  --e1:none; --e2:0 0 0 1px rgba(77,216,230,.14);
  --e3:0 0 0 1px rgba(77,216,230,.2),0 18px 44px -20px #000;
  --e4:0 0 0 1px rgba(77,216,230,.26),0 36px 80px -30px #000;
  --lift:none; --lift-2:0 0 0 1px rgba(77,216,230,.2);
  --ground:linear-gradient(rgba(77,216,230,.055) 1px, transparent 1px) 0 0/28px 28px,
           linear-gradient(90deg, rgba(77,216,230,.055) 1px, transparent 1px) 0 0/28px 28px,
           linear-gradient(180deg,#081521,#050e16);
}
:root[data-skin="blueprint"][data-skin] .tile,
:root[data-skin="blueprint"][data-skin] .scard,
:root[data-skin="blueprint"][data-skin] .numtile,
:root[data-skin="blueprint"][data-skin] .dotile{border:1px solid rgba(77,216,230,.2); box-shadow:none}
:root[data-skin="blueprint"][data-skin] .secttl,
:root[data-skin="blueprint"][data-skin] .hubhead h2{text-transform:uppercase; letter-spacing:.14em}
:root[data-skin="blueprint"][data-skin] button.primary,
:root[data-skin="blueprint"][data-skin] .btn.primary{background:#4dd8e6; color:#04121b; border-color:#4dd8e6}

/* ---------- 5. TERMINAL — phosphor green on black, no corners ------------- */
:root[data-skin="terminal"][data-skin]{
  color-scheme:dark;
  --bg:#000000; --panel:#050805; --panel-2:#0a0f0a; --rail:#000000;
  --line:rgba(51,255,122,.26); --line-2:rgba(51,255,122,.15); --line-3:rgba(51,255,122,.08);
  --ink:#c8ffd8; --ink-2:#5fcf85; --ink-3:#3d8f5c;
  --accent:#33ff7a; --brass:#33ff7a; --brass-soft:rgba(51,255,122,.13);
  --accent-soft:rgba(51,255,122,.13);
  --good:#33ff7a; --good-2:#33ff7a; --warn:#ffd23d; --warn-2:#ffd23d;
  --bad:#ff4d4d; --bad-2:#ff4d4d; --pos:#33ff7a; --neg:#ff4d4d;
  --warn-bg:rgba(255,210,61,.09); --warn-line:rgba(255,210,61,.3);
  --mute:#123018; --deemph:#2c6b41; --grid:rgba(51,255,122,.09); --axis:rgba(51,255,122,.22);
  --r:0px; --r-sm:0px; --r-xs:0px;
  --face:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  --sur-1:#050805; --sur-2:#0a0f0a; --sur-3:#0f170f;
  --edge:rgba(51,255,122,.26); --edge-2:rgba(51,255,122,.14);
  --rim:rgba(51,255,122,.14); --sh-key:0,0,0;
  --e1:none; --e2:0 0 0 1px rgba(51,255,122,.22);
  --e3:0 0 0 1px rgba(51,255,122,.3),0 0 26px -6px rgba(51,255,122,.24);
  --e4:0 0 0 1px rgba(51,255,122,.4),0 0 44px -6px rgba(51,255,122,.3);
  --lift:none; --lift-2:0 0 0 1px rgba(51,255,122,.3);
  --ground:repeating-linear-gradient(180deg, rgba(51,255,122,.028) 0 1px, transparent 1px 3px),
           linear-gradient(180deg,#000,#000);
}
:root[data-skin="terminal"][data-skin] .tile,
:root[data-skin="terminal"][data-skin] .scard,
:root[data-skin="terminal"][data-skin] .numtile,
:root[data-skin="terminal"][data-skin] .dotile{border:1px solid rgba(51,255,122,.26); box-shadow:none}
:root[data-skin="terminal"][data-skin] .secttl,
:root[data-skin="terminal"][data-skin] .hubhead h2,
:root[data-skin="terminal"][data-skin] .topbar h1{text-transform:uppercase; letter-spacing:.16em}
:root[data-skin="terminal"][data-skin] button.primary,
:root[data-skin="terminal"][data-skin] .btn.primary{background:#33ff7a; color:#001a09; border-color:#33ff7a}
:root[data-skin="terminal"][data-skin] .railnav a.on{background:#33ff7a; color:#001a09}

/* ---------- 6. NEWSPRINT — printed page: serif, hairlines, no shadow ------ */
:root[data-skin="newsprint"][data-skin]{
  color-scheme:light;
  --bg:#f2efe7; --panel:#faf8f2; --panel-2:#f6f3ec; --rail:#eae6db;
  --line:#1a1815; --line-2:#c4beb0; --line-3:#ddd8ca;
  --ink:#100f0d; --ink-2:#48453e; --ink-3:#78736a;
  --accent:#a8231b; --brass:#a8231b; --brass-soft:#f6e4e2; --accent-soft:#f6e4e2;
  --good:#14663a; --good-2:#0f5230; --warn:#8a5a08; --warn-2:#6b4506;
  --bad:#a8231b; --bad-2:#8a1a14; --pos:#0f5230; --neg:#8a1a14;
  --warn-bg:#f7f0dd; --warn-line:#d8caa4;
  --mute:#d3cec0; --deemph:#a8a294; --grid:#e2ddd0; --axis:#c4beb0;
  --r:0px; --r-sm:0px; --r-xs:0px;
  --face:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,"Times New Roman",serif;
  --sur-1:#faf8f2; --sur-2:#f6f3ec; --sur-3:#f0ece2;
  --edge:#1a1815; --edge-2:#c4beb0; --rim:transparent; --sh-key:26,24,21;
  --e1:none; --e2:none; --e3:0 0 0 1px #1a1815; --e4:0 0 0 2px #1a1815;
  --lift:none; --lift-2:none;
  --ground:linear-gradient(180deg,#f2efe7,#eeeade);
}
:root[data-skin="newsprint"][data-skin] .tile,
:root[data-skin="newsprint"][data-skin] .scard,
:root[data-skin="newsprint"][data-skin] .numtile,
:root[data-skin="newsprint"][data-skin] .dotile{border:1px solid #1a1815; box-shadow:none}
:root[data-skin="newsprint"][data-skin] .secttl,
:root[data-skin="newsprint"][data-skin] .hubhead h2{border-bottom:2px solid #1a1815;
  text-transform:uppercase; letter-spacing:.1em}
:root[data-skin="newsprint"][data-skin] button.primary,
:root[data-skin="newsprint"][data-skin] .btn.primary{background:#100f0d; color:#faf8f2; border-color:#100f0d}
:root[data-skin="newsprint"][data-skin] .railnav a.on{background:#100f0d; color:#faf8f2}

/* ---------- 7. NEON — magenta and cyan, and everything glows ------------- */
:root[data-skin="neon"][data-skin]{
  color-scheme:dark;
  --bg:#0a0614; --panel:#130c22; --panel-2:#19102c; --rail:#08040f;
  --line:rgba(255,61,154,.22); --line-2:rgba(255,61,154,.13); --line-3:rgba(255,61,154,.07);
  --ink:#f4ecff; --ink-2:#b4a2d4; --ink-3:#7f6fa0;
  --accent:#ff3d9a; --brass:#ff3d9a; --brass-soft:rgba(255,61,154,.16);
  --accent-soft:rgba(255,61,154,.16);
  --good:#3df0d0; --good-2:#3df0d0; --warn:#ffd23d; --warn-2:#ffd23d;
  --bad:#ff5470; --bad-2:#ff5470; --pos:#3df0d0; --neg:#ff5470;
  --warn-bg:rgba(255,210,61,.1); --warn-line:rgba(255,210,61,.26);
  --mute:#2b1f45; --deemph:#5a4a7a; --grid:#1c1330; --axis:#2b1f45;
  --r:14px; --r-sm:11px; --r-xs:8px;
  --face:"Avenir Next",Avenir,system-ui,-apple-system,sans-serif;
  --sur-1:#130c22; --sur-2:#19102c; --sur-3:#1f1436;
  --edge:rgba(255,61,154,.22); --edge-2:rgba(255,61,154,.12);
  --rim:rgba(255,255,255,.07); --sh-key:0,0,0;
  --e1:0 0 0 1px rgba(255,61,154,.16);
  --e2:0 0 0 1px rgba(255,61,154,.2),0 0 30px -10px rgba(255,61,154,.5);
  --e3:0 0 0 1px rgba(255,61,154,.28),0 0 50px -12px rgba(255,61,154,.6);
  --e4:0 0 0 1px rgba(61,240,208,.3),0 0 80px -14px rgba(255,61,154,.7);
  --lift:0 0 0 1px rgba(255,61,154,.16);
  --lift-2:0 0 0 1px rgba(255,61,154,.26),0 0 40px -12px rgba(255,61,154,.55);
  --ground:radial-gradient(60% 50% at 15% 0%, rgba(255,61,154,.20), transparent 62%),
           radial-gradient(60% 50% at 88% 100%, rgba(61,240,208,.16), transparent 62%),
           linear-gradient(180deg,#0a0614,#07040f);
}
:root[data-skin="neon"][data-skin] button.primary,
:root[data-skin="neon"][data-skin] .btn.primary{background:linear-gradient(135deg,#ff3d9a,#c026d3);
  color:#fff; border-color:transparent; box-shadow:0 0 26px -8px rgba(255,61,154,.9)}
:root[data-skin="neon"][data-skin] .railnav a.on{background:linear-gradient(135deg,#ff3d9a,#c026d3);
  color:#fff; box-shadow:0 0 22px -8px rgba(255,61,154,.9)}
:root[data-skin="neon"][data-skin] .railnav a.on .ico{color:#fff}

/* ---------- 8. STEEL — industrial: cool grey, safety orange, sharp -------- */
:root[data-skin="steel"][data-skin]{
  color-scheme:light;
  --bg:#e4e7ea; --panel:#f5f7f8; --panel-2:#eceff1; --rail:#1b2024;
  --line:#c3cad0; --line-2:#d3d9de; --line-3:#e2e6e9;
  --ink:#12171b; --ink-2:#454f57; --ink-3:#78848c;
  --accent:#e35205; --brass:#e35205; --brass-soft:#fde8dc; --accent-soft:#fde8dc;
  --good:#0f7a44; --good-2:#0b6236; --warn:#b06f00; --warn-2:#7d4f00;
  --bad:#c62828; --bad-2:#9e1f1f; --pos:#0b6236; --neg:#9e1f1f;
  --warn-bg:#fdf3e0; --warn-line:#e8d3a8;
  --mute:#cfd6db; --deemph:#a3adb4; --grid:#dde2e6; --axis:#c3cad0;
  --r:3px; --r-sm:2px; --r-xs:2px;
  --face:"Helvetica Neue",Helvetica,system-ui,-apple-system,"Segoe UI",sans-serif;
  --sur-1:#f5f7f8; --sur-2:#eceff1; --sur-3:#e2e6e9;
  --edge:#c3cad0; --edge-2:#d8dde1; --rim:rgba(255,255,255,.85); --sh-key:18,23,27;
  --e1:0 1px 0 rgba(18,23,27,.08); --e2:0 1px 0 rgba(18,23,27,.1),0 4px 10px -6px rgba(18,23,27,.28);
  --e3:0 2px 0 rgba(18,23,27,.12),0 12px 26px -12px rgba(18,23,27,.4);
  --e4:0 3px 0 rgba(18,23,27,.14),0 26px 50px -22px rgba(18,23,27,.5);
  --lift:0 1px 0 rgba(18,23,27,.08); --lift-2:0 2px 0 rgba(18,23,27,.12),0 10px 22px -12px rgba(18,23,27,.35);
  --ground:linear-gradient(180deg,#e9ecee,#dde1e5);
  /* Dark column, light page -- the thing Steel does that makes it read as
     equipment. Was four hard-coded greys further down this file; it is a
     token set now so the next skin with a dark rail inherits the idea
     rather than the bug. */
  --rail-ink:#f0f3f5; --rail-ink-2:#c7ced4; --rail-ink-3:#9dabb5;
  --rail-line:rgba(240,243,245,.17); --rail-line-2:rgba(240,243,245,.11);
  --rail-line-3:rgba(240,243,245,.07);
  --rail-panel:#1b2024; --rail-panel-2:rgba(240,243,245,.06);
}
:root[data-skin="steel"][data-skin] .secttl,
:root[data-skin="steel"][data-skin] .hubhead h2{text-transform:uppercase; letter-spacing:.12em}
:root[data-skin="steel"][data-skin] button.primary,
:root[data-skin="steel"][data-skin] .btn.primary{background:#e35205; color:#fff; border-color:#c04604}
:root[data-skin="steel"][data-skin] .railnav a.on{background:#e35205; color:#fff}
:root[data-skin="steel"][data-skin] .railnav a.on .ico{color:#fff}


/* ---------- 9. SUNSET — warm gradient, coral, soft and light ------------- */
:root[data-skin="sunset"][data-skin]{
  color-scheme:light;
  --bg:#fff5ee; --panel:#fffaf6; --panel-2:#fff1e8; --rail:#fff0e4;
  --line:#f3d9c6; --line-2:#f8e5d6; --line-3:#fcf0e6;
  --ink:#2b1a14; --ink-2:#6b4a3c; --ink-3:#a1786a;
  --accent:#e8563f; --brass:#e8563f; --brass-soft:#ffe3da; --accent-soft:#ffe3da;
  --good:#1a8a6a; --good-2:#0f6e53; --warn:#c9760c; --warn-2:#8f5306;
  --bad:#c9342a; --bad-2:#a02821; --pos:#0f6e53; --neg:#a02821;
  --warn-bg:#fff3e0; --warn-line:#f5d9b0;
  --mute:#f0d6c6; --deemph:#c9a897; --grid:#fbe7db; --axis:#f3d9c6;
  --r:16px; --r-sm:12px; --r-xs:9px;
  --face:ui-rounded,"SF Pro Rounded",system-ui,-apple-system,"Segoe UI",sans-serif;
  --sur-1:#fffaf6; --sur-2:#fff1e8; --sur-3:#ffe9dc;
  --edge:#f3d9c6; --edge-2:#f8e5d6; --rim:rgba(255,255,255,.9); --sh-key:120,60,40;
  --e1:0 1px 2px rgba(120,60,40,.06),0 8px 20px -14px rgba(120,60,40,.3);
  --e2:0 1px 3px rgba(120,60,40,.07),0 16px 34px -20px rgba(120,60,40,.36);
  --e3:0 2px 6px rgba(120,60,40,.09),0 28px 56px -26px rgba(120,60,40,.44);
  --e4:0 4px 12px rgba(120,60,40,.11),0 52px 100px -40px rgba(120,60,40,.52);
  --lift:0 1px 2px rgba(120,60,40,.06),0 8px 20px -14px rgba(120,60,40,.3);
  --lift-2:0 2px 6px rgba(120,60,40,.09),0 22px 46px -24px rgba(120,60,40,.4);
  --ground:radial-gradient(70% 55% at 50% -8%, rgba(255,186,120,.5), transparent 64%),
           radial-gradient(60% 50% at 88% 104%, rgba(255,120,110,.32), transparent 62%),
           linear-gradient(180deg,#fff5ee,#ffece0);
}
:root[data-skin="sunset"][data-skin] button.primary,
:root[data-skin="sunset"][data-skin] .btn.primary{background:linear-gradient(135deg,#ff7a4d,#e8563f);
  color:#fff; border-color:transparent}
:root[data-skin="sunset"][data-skin] .railnav a.on{background:linear-gradient(135deg,#ff7a4d,#e8563f); color:#fff}
:root[data-skin="sunset"][data-skin] .railnav a.on .ico{color:#fff}

/* ---------- 10. LEDGER — dense, light, monospaced figures ---------------- */
:root[data-skin="ledger"][data-skin]{
  color-scheme:light;
  --bg:#f2f0ea; --panel:#ffffff; --panel-2:#faf8f2; --rail:#16150f;
  --line:#dbd7cb; --line-2:#e5e1d6; --line-3:#eeebe2;
  --ink:#16150f; --ink-2:#4b463c; --ink-3:#7c766a;
  --accent:#8a5a00; --brass:#8a5a00; --brass-soft:#f7ecd8; --accent-soft:#f7ecd8;
  --good:#2e7d4f; --good-2:#226039; --warn:#a06f00; --warn-2:#6f4c00;
  --bad:#b0392f; --bad-2:#8d2d25; --pos:#226039; --neg:#8d2d25;
  --warn-bg:#fdf6e6; --warn-line:#e8d9b0;
  --mute:#d5d0c3; --deemph:#aaa494; --grid:#e9e5da; --axis:#dbd7cb;
  --r:3px; --r-sm:2px; --r-xs:2px;
  --face:system-ui,-apple-system,"SF Pro Text","Segoe UI",sans-serif;
  --sur-1:#ffffff; --sur-2:#faf8f2; --sur-3:#f4f1e9;
  --edge:#dbd7cb; --edge-2:#e5e1d6; --rim:rgba(255,255,255,.8); --sh-key:22,21,15;
  --e1:none; --e2:0 1px 0 rgba(22,21,15,.06);
  --e3:0 1px 0 rgba(22,21,15,.08),0 10px 22px -14px rgba(22,21,15,.3);
  --e4:0 2px 0 rgba(22,21,15,.1),0 24px 48px -24px rgba(22,21,15,.4);
  --lift:none; --lift-2:0 1px 0 rgba(22,21,15,.08),0 8px 18px -12px rgba(22,21,15,.28);
  --ground:linear-gradient(180deg,#f2f0ea,#eeebe2);
  /* The column is the opposite material from the page, so it gets its own
     ink. Without this the signed-in name at the foot of it was #4b463c
     on #16150f -- there, technically, and unreadable. */
  --rail-ink:#f5f3ec; --rail-ink-2:#c3bdae; --rail-ink-3:#948d7e;
  --rail-line:rgba(245,243,236,.16); --rail-line-2:rgba(245,243,236,.11);
  --rail-line-3:rgba(245,243,236,.07);
  --rail-panel:#16150f; --rail-panel-2:rgba(245,243,236,.06);
}
:root[data-skin="ledger"][data-skin] .cv, :root[data-skin="ledger"][data-skin] .nv,
:root[data-skin="ledger"][data-skin] .money, :root[data-skin="ledger"][data-skin] .stat b,
:root[data-skin="ledger"][data-skin] td.n{font-family:var(--num,ui-monospace,SFMono-Regular,Menlo,monospace);
  letter-spacing:-.02em}
/* The gold pill stays -- that is Ledger's identity. The three colours that
   used to sit here with it do not: they were a hand-made copy of what
   --rail-ink now does for every skin at once, and the nav labels in the copy
   were #8a8474 on #16150f, which is 3.4:1 and the reason the column looked
   switched off. */
:root[data-skin="ledger"][data-skin] .railnav a.on{background:#e8b73a; color:#16150f}
:root[data-skin="ledger"][data-skin] .railnav a.on .ico{color:#16150f}
:root[data-skin="ledger"][data-skin] .secttl,
:root[data-skin="ledger"][data-skin] .hubhead h2{text-transform:uppercase; letter-spacing:.12em}

/* ---- the scene still wins over the skin -------------------------------
 * Each skin sets its own `--ground`, which is most of what makes Graphite
 * glow and Terminal scan. But `scene` is a separate control meaning "what is
 * the light behind the app doing", and a skin setting --ground later in the
 * file silently took it over: on any skin but Showroom, all three scenes drew
 * the same picture and the setting did nothing.
 *
 * So the two scenes that are a deliberate statement — off and deep — are
 * restated here, after every skin, in terms of each skin's own --bg. Turning
 * the light off means off in Terminal too; deep means a vignette in whatever
 * colour that skin is printed on. A skin's signature ground is what you get on
 * "warm", which is the default.
 *
 * The doubled attribute is the same trick, and the same reason, as the skins
 * themselves. A skin is (0,3,0) now; a plain [data-scene] is (0,2,0) and lost
 * to it, so this whole section quietly stopped working the hour the skins
 * were strengthened -- warm and deep drew the identical picture again. Two
 * rules that have to out-specify each other have to be written knowing it,
 * and it is source order that settles the tie: this comes after every skin in
 * the file, on purpose. */
:root[data-scene="off"][data-scene]{
  --ground:linear-gradient(180deg, var(--bg), var(--bg));
}
:root[data-scene="deep"][data-scene]{
  --ground:radial-gradient(78% 58% at 50% 34%,
             color-mix(in srgb, var(--bg) 76%, #ffffff) 0%,
             var(--bg) 46%,
             color-mix(in srgb, var(--bg) 56%, #000000) 100%);
}

/* The drifting light is tuned for the warm default paper. Over a skin that
   brings its own strong ground — black, navy, near-black — it reads as a grey
   smear across the top rather than as light. Kept (it is what makes the app
   look awake) and turned down to where it is atmosphere instead of haze. */
:root[data-skin="terminal"][data-skin] .ambient,
:root[data-skin="blueprint"][data-skin] .ambient{ opacity:.06 }
:root[data-skin="graphite"][data-skin] .ambient,
:root[data-skin="neon"][data-skin] .ambient{ opacity:.12 }
:root[data-skin="newsprint"][data-skin] .ambient{ opacity:.08 }

/* =====================================================================
   THE MASTHEAD, PER SKIN
   =====================================================================

   Greg, looking at eleven skins: *"these designs put yours to shame ... the
   stuff still changes barely anything all it does is change the font and
   colours"*. He was looking at this band. It is the biggest thing on the front
   page and it was the same glossy accent-coloured blob in all eleven, because
   the recipe was written once in style.css with --accent poured into it.

   A skin gets to compose here, not just recolour: Newsprint prints a masthead,
   Ledger rules a white box, Blueprint draws on it, Terminal scans it. The four
   showy ones -- Showroom, Aurora, Neon, Sunset -- keep the gradient, because a
   gradient is what they are for. Everything below is tokens the base rule
   already reads; .hero itself does not know a skin exists. */

/* ---- Newsprint: a masthead. Hard rules, flat paper, no light in it at all. */
:root[data-skin="newsprint"][data-skin]{
  /* Spelled out rather than var(--panel) so the contrast check can read it;
     a masthead nobody can check is how the last one got through. */
  --hero:#faf8f2; --hero-ink:#100f0d; --hero-ink-2:#48453e;
  --hero-face:#f2efe7; --hero-face-2:#eae6db; --hero-edge:#1a1815;
  --hero-r:0px; --hero-border:2px solid #1a1815; --hero-shadow:none;
  --hero-field-o:0; --hero-bad:#a8231b; --hero-warn:#8a5a08;
  --hero-key:#e0dbcd;
}
:root[data-skin="newsprint"][data-skin] .herohi b{letter-spacing:-.02em}
:root[data-skin="newsprint"][data-skin] .herohi span{text-transform:uppercase;
  letter-spacing:.14em; font-size:11px}
:root[data-skin="newsprint"][data-skin] .herostat{border:1px solid #1a1815}
:root[data-skin="newsprint"][data-skin] .herofind{border:1px solid #1a1815}

/* ---- Ledger: a ruled white box with a gold rule across the top of it. */
:root[data-skin="ledger"][data-skin]{
  --hero:#ffffff; --hero-ink:#16150f; --hero-ink-2:#4b463c;
  --hero-face:#faf8f2; --hero-face-2:#f4f1e9; --hero-edge:#dbd7cb;
  --hero-r:3px; --hero-border:1px solid #dbd7cb;
  --hero-shadow:0 1px 0 rgba(22,21,15,.06);
  --hero-field-o:0; --hero-bad:#b0392f; --hero-warn:#a06f00;
  --hero-key:#efeade;
}
:root[data-skin="ledger"][data-skin] .hero{border-top:3px solid #e8b73a}
:root[data-skin="ledger"][data-skin] .herostat b{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace; letter-spacing:-.03em}

/* ---- Blueprint: drafting paper. The grid is the field, drawn at 26mm. */
:root[data-skin="blueprint"][data-skin]{
  --hero:linear-gradient(180deg,#0d1f30,#081521);
  --hero-ink:#dff6fa; --hero-ink-2:#8fc4d0;
  --hero-face:rgba(77,216,230,.09); --hero-face-2:rgba(77,216,230,.17);
  --hero-edge:rgba(77,216,230,.28);
  --hero-shadow:0 0 0 1px rgba(77,216,230,.22);
  --hero-field:linear-gradient(rgba(77,216,230,.55) 1px,transparent 1px),
               linear-gradient(90deg,rgba(77,216,230,.55) 1px,transparent 1px);
  --hero-field-size:26px 26px; --hero-field-o:.2;
  --hero-bad:#ff9d8a; --hero-warn:#ffd88a; --hero-key:rgba(0,0,0,.35);
}
:root[data-skin="blueprint"][data-skin] .herohi span,
:root[data-skin="blueprint"][data-skin] .herostat span{text-transform:uppercase;
  letter-spacing:.11em; font-size:11px}

/* ---- Terminal: a screen. Scan lines, square, phosphor. */
:root[data-skin="terminal"][data-skin]{
  --hero:#000000; --hero-ink:#33ff7a; --hero-ink-2:#1c9c4b;
  --hero-face:rgba(51,255,122,.07); --hero-face-2:rgba(51,255,122,.15);
  --hero-edge:rgba(51,255,122,.3);
  --hero-r:0px; --hero-border:1px solid rgba(51,255,122,.3); --hero-shadow:none;
  --hero-field:repeating-linear-gradient(180deg,
    rgba(51,255,122,.6) 0 1px, transparent 1px 4px);
  --hero-field-size:auto; --hero-field-o:.11;
  --hero-bad:#ff6b5f; --hero-warn:#ffd23d; --hero-key:rgba(51,255,122,.16);
}
:root[data-skin="terminal"][data-skin] .herohi b::before{content:"> "}
:root[data-skin="terminal"][data-skin] .herohi b{letter-spacing:0; font-size:25px}

/* ---- Bento: a white card, no edge, one big soft shadow under it. */
:root[data-skin="bento"][data-skin]{
  --hero:#ffffff; --hero-ink:#111214; --hero-ink-2:#5b6068;
  --hero-face:#f6f5f3; --hero-face-2:#edece9; --hero-edge:transparent;
  --hero-r:26px; --hero-border:none;
  --hero-shadow:0 20px 50px -22px rgba(17,18,20,.3),0 2px 6px rgba(17,18,20,.05);
  --hero-field-o:0; --hero-bad:#c3341a; --hero-warn:#8a5a00;
  --hero-key:#e7e5e1;
}
:root[data-skin="bento"][data-skin] .herostat b{color:#e8430f}

/* ---- Graphite: a black slab, and the figures are the only colour on it. */
:root[data-skin="graphite"][data-skin]{
  --hero:linear-gradient(160deg,#16181a,#0a0b0c);
  --hero-ink:#f2f4f5; --hero-ink-2:#979da3;
  --hero-face:rgba(255,255,255,.05); --hero-face-2:rgba(255,255,255,.1);
  --hero-edge:rgba(255,255,255,.08);
  --hero-shadow:0 24px 60px -30px rgba(0,0,0,.9);
  --hero-field-o:0; --hero-bad:#ff8672; --hero-warn:#ffd45e;
  --hero-key:rgba(0,0,0,.45);
}
:root[data-skin="graphite"][data-skin] .herostat b{color:#c6f24e}

/* ---- Steel: a brushed panel with a safety-orange rule under it. */
:root[data-skin="steel"][data-skin]{
  --hero:linear-gradient(178deg,#2c3339,#1b2024);
  --hero-ink:#f0f3f5; --hero-ink-2:#b6c0c7;
  --hero-face:rgba(255,255,255,.06); --hero-face-2:rgba(255,255,255,.12);
  --hero-edge:rgba(255,255,255,.1);
  --hero-r:2px; --hero-shadow:0 3px 0 #e35205;
  --hero-field:repeating-linear-gradient(90deg,
    rgba(255,255,255,.5) 0 1px, transparent 1px 6px);
  --hero-field-size:auto; --hero-field-o:.05;
  --hero-bad:#ff9478; --hero-warn:#ffcf6b; --hero-key:rgba(0,0,0,.35);
}
:root[data-skin="steel"][data-skin] .herohi span,
:root[data-skin="steel"][data-skin] .herostat span{text-transform:uppercase;
  letter-spacing:.1em; font-size:11px}

/* Skin flourishes that only work when there is room for them.
   Steel and Blueprint set the masthead's small print in uppercase with a tenth
   of an em of tracking, which reads as stencilled equipment on a laptop and as
   three wrapped lines on a 390-point phone -- "TITLES / GONE / LATE" stacked
   under a number. The look is the wide screen's; the phone keeps the words. */
@media (max-width: 760px){
  :root[data-skin="steel"][data-skin] .herostat span,
  :root[data-skin="blueprint"][data-skin] .herostat span,
  :root[data-skin="newsprint"][data-skin] .herohi span,
  :root[data-skin="steel"][data-skin] .herohi span,
  :root[data-skin="blueprint"][data-skin] .herohi span{
    text-transform:none; letter-spacing:normal; font-size:12.5px}
}

/* ---- DEPTH, AFTER THE SKINS -------------------------------------------
 * `axestest` caught this and I nearly wrote it off as a flaky test: the three
 * Depth settings measured identically, but only inside the runner, and only
 * sometimes. The "sometimes" was which skin the account happened to be left on.
 *
 * Four skins -- blueprint, terminal, newsprint and ledger -- deliberately have
 * no card shadow, and they say so with `--e1:none`. They are written as
 * `:root[data-skin="x"][data-skin]`, which is specificity (0,3,0), while the
 * depth blocks further up are `:root[data-depth="floating"]` at (0,2,0). So on
 * those four skins the skin won and **the Depth control did nothing at all** --
 * a setting in the appearance panel that moved a slider and changed nothing on
 * screen. That is the exact fault this axis system was built to prevent, and it
 * had been shipping.
 *
 * These repeat the two depth settings that carry shadows at (0,3,0), after the
 * skins, so depth wins wherever it is set. The flat skins still look flat at
 * `flat` and at their own default -- they only stop overriding somebody who has
 * deliberately asked for more.
 */
:root[data-depth="floating"][data-depth]{
  --e1: 0 2px 6px rgba(var(--sh-key),.10), 0 8px 24px rgba(var(--sh-key),.10);
  --e2: 0 4px 10px rgba(var(--sh-key),.13), 0 18px 44px rgba(var(--sh-key),.16);
  --e3: 0 8px 18px rgba(var(--sh-key),.16), 0 40px 90px rgba(var(--sh-key),.26);
  --e4: 0 14px 28px rgba(var(--sh-key),.20), 0 70px 150px rgba(var(--sh-key),.38);
}
:root[data-depth="lifted"][data-depth]{
  --e1: 0 1px 1.5px rgba(var(--sh-key),.055), 0 2px 5px -1px rgba(var(--sh-key),.05),
        0 6px 14px -6px rgba(var(--sh-key),.05);
  --e2: 0 2px 4px rgba(var(--sh-key),.07), 0 10px 22px -6px rgba(var(--sh-key),.10);
}
/* Flat stays flat everywhere, including over a skin that wanted shadows. */
:root[data-depth="flat"][data-depth]{
  --e1:none; --e2:none;
  --e3:0 0 0 1px var(--edge); --e4:0 0 0 1px var(--edge);
}

/* And the three skins that paint the card flat themselves.
 *
 * blueprint, terminal and newsprint do not merely set `--e1:none` -- they write
 * `box-shadow:none` straight onto `.scard` and `.tile`, so no amount of fixing
 * the token reaches them. Their flatness is deliberate and it is kept: at their
 * own default depth they look exactly as they were designed to.
 *
 * But somebody who goes into the appearance panel and asks for `floating` has
 * asked for it, and a control that moves and does nothing is worse than no
 * control. Same specificity as the skin rules (0,3,1) and later in the file, so
 * a deliberate choice wins over a default. */
:root[data-depth="floating"][data-depth] .scard,
:root[data-depth="floating"][data-depth] .tile{
  box-shadow: var(--e1), inset 0 1px 0 var(--rim);
}
:root[data-depth="lifted"][data-depth] .scard,
:root[data-depth="lifted"][data-depth] .tile{
  box-shadow: var(--e1), inset 0 1px 0 var(--rim);
}
/* Flat has to reach them too, and `aurora` proved it: it paints its own card
   shadow directly, so asking for flat left a 24px drop shadow sitting there.
   Found by walking all eleven skins rather than testing whichever one was on. */
:root[data-depth="flat"][data-depth] .scard,
:root[data-depth="flat"][data-depth] .tile{
  box-shadow:none;
}
