/* ─────────────────────────────────────────────────────────────────────────
   surfaces/skymap/kit.css — the component kit for Overhead.

   Ether, 2026-08-13: "do a design revamp on Prahar, Overhead, Umbra and Yuti
   … deploy uiverse heavily on each one of them."

   ── THIS IS surfaces/almanac/kit.css's TWIN, AND THAT IS A PROBLEM ────────
   Everything down to "1 · THE SHELL FURNITURE" is copied VERBATIM from that
   file. Both copies say the same thing and both are wrong to exist: the token
   scale is network-wide and its home is `surfaces/_shell/shell.css`, beside
   `--mo-skin`. It is not there because `surfaces/_shell` was held by another
   wave (I1470) on the day this was written, and a design edit inside somebody
   else's live claim is how I352 happens.

   SO THE DRIFT IS REAL AND IT IS FILED. Lift the shared blocks into the shell,
   delete them from both surfaces, and nothing below changes. Until then: any
   edit to a token here has to be made in the almanac's copy in the same
   breath, or the network has two motion scales and no way to know it.

   ── WHY OVERHEAD'S HALF IS SHORTER THAN THE ALMANAC'S ─────────────────────
   Prahar, Umbra and Yuti are documents: cards, tables, forms, prose. Overhead
   is a live sky with a HUD over it, and almost none of the almanac kit applies
   — there is no form, no table of times, no grid of eight cards. What Overhead
   needs from a component library is glass that works on the floor device, a
   button that answers a thumb in the dark, and nothing that draws the eye off
   the sky. Sections 2 and 3 are that, and they are all of it.

       python3 surfaces/_shell/check_css.py
   before committing.
   ───────────────────────────────────────────────────────────────────────── */

/* ══ THE SCALE ═════════════════════════════════════════════════════════════
   Four durations and four curves, and the names say what they are FOR rather
   than how long they are — which is the thing that stops the next component
   from inventing a thirteenth curve. Pick by intent: a control acknowledging
   a touch is `--dur-tap`, a thing arriving on screen is `--dur-enter`.

   THE CURVES ARE THREE, NOT TWELVE. `--ease-out` is the only one most rules
   need: it leaves fast and lands soft, which is what "responsive" reads as.
   `--ease-move` is for anything travelling between two rests, where an
   asymmetric curve looks like a stumble. `--ease-press` overshoots by a
   hair and is for a control springing back — used exactly twice below, and
   deliberately: overshoot everywhere is a toy. */
:root{
  --dur-tap:120ms;     /* a state flips — focus ring, check, switch knob   */
  --dur-move:200ms;    /* a control responds — hover, press, tint          */
  --dur-enter:340ms;   /* something arrives — a card, a result, a sheet    */
  --dur-sweep:620ms;   /* something crosses a surface — a shine, a draw    */

  --ease-out:cubic-bezier(.22,1,.36,1);
  --ease-move:cubic-bezier(.45,0,.55,1);
  --ease-press:cubic-bezier(.2,1.3,.35,1);

  /* ══ THE ATMOSPHERE ══════════════════════════════════════════════════════
     Three shadow recipes and one hairline, so "raised" is a token rather than
     a number somebody picked. `adamgiebl_horrible-rabbit-39` is where the
     stacked-shadow idea comes from — eight shadows at doubling offsets, which
     is why its cards read as objects rather than as boxes with a drop shadow.
     Three is enough for a page this quiet.
       https://uiverse.io/adamgiebl/horrible-rabbit-39  (MIT)

     THESE ARE UNGUARDED AND THAT IS NOT THE SAME AS PERMITTED. check_css.py
     reads `background` and `color`, not `box-shadow` — the working agreement
     says so. The blacks here are shadow, not palette: a shadow is the absence
     of light in every skin, including the light ones, which is exactly why it
     does not take a token. The one INK value that is a palette decision is the
     top hairline, `--edge-lit`, and it is the standing documented exception —
     "lit from above", not a colour choice. */
  --rise-1:0 1px 2px rgb(0 0 0 / .18);
  --rise-2:0 2px 4px rgb(0 0 0 / .16), 0 6px 14px rgb(0 0 0 / .18);
  --rise-3:0 4px 8px rgb(0 0 0 / .14), 0 12px 28px rgb(0 0 0 / .22),
           0 24px 56px rgb(0 0 0 / .18);
  --edge-lit:inset 0 1px 0 rgb(255 255 255 / .06);

  /* THE HAIRLINE ITSELF, AS ONE VALUE. `.uv-card` below is not the only thing
     that wants a lit edge — `.al-now` has a verdict wash it cannot give up,
     `.ma-score` has its own ground, and each of those still wants the same
     border. Copying the gradient into three sheets is how a design language
     stops being one. So the gradient is a token and the two-layer recipe is
     written out wherever it is used:

         background:
           linear-gradient(var(--panel),var(--panel)) padding-box,
           var(--edge-grad) border-box;
         border:1px solid transparent;

     It needs no day override: every colour in it is a token, so it re-resolves
     on its own when the palette does. Light at the top-left, gone by the
     bottom-right — one light source, and the same one `--edge-lit` assumes. */
  --edge-grad:linear-gradient(150deg,
    color-mix(in srgb,var(--moon) 26%,var(--line)) 0%,
    var(--line) 42%,
    color-mix(in srgb,var(--line) 70%,var(--panel)) 100%);
}

/* ── THE DAY VALUES, WHICH check_css.py DEMANDED AND WAS RIGHT TO ──────────
   Rule 2(a) fails the build on any token declared for night with no day value,
   and it caught all four of these on the first run. The rule is aimed at
   colours and these are shadows, so it is worth saying why it applies anyway
   rather than reaching for an exemption:

     · A SHADOW ON PAPER IS A DIFFERENT SHADOW. The night values are tuned
       against `--panel` at #10141C, where a 22% black at 28px reads as depth.
       The same shadow under a white card on a #EFF3F8 ground reads as dirt.
       Paper wants shorter, tighter, and much weaker.
     · `--edge-lit` IS NOT A SHADOW AT ALL. It is a 6% white inset hairline
       meaning "lit from above" — the one documented exception in the working
       agreement — and 6% white on a #FFFFFF panel is nothing. On paper the
       light comes from the page, so the top edge stops being the lit one and
       the token goes to none.

   So the token that looked like it needed an exemption turned out to need a
   design decision, which is what that check is for. */
:root[data-theme="day"]{
  --rise-1:0 1px 2px rgb(0 0 0 / .06);
  --rise-2:0 1px 2px rgb(0 0 0 / .05), 0 4px 10px rgb(0 0 0 / .07);
  --rise-3:0 2px 4px rgb(0 0 0 / .05), 0 8px 18px rgb(0 0 0 / .08),
           0 18px 40px rgb(0 0 0 / .06);
  --edge-lit:none;
}
:root[data-skin="3"]{
  --rise-1:0 1px 2px rgb(0 0 0 / .06);
  --rise-2:0 1px 2px rgb(0 0 0 / .05), 0 4px 10px rgb(0 0 0 / .07);
  --rise-3:0 2px 4px rgb(0 0 0 / .05), 0 8px 18px rgb(0 0 0 / .08),
           0 18px 40px rgb(0 0 0 / .06);
  --edge-lit:none;
}

/* Plain is the floor skin — no gradients, no translucency, no backdrop-filter
   (shell.css says so and enforces the last one globally). It gets no shadow
   either: an 8-bit look is carried by its edges, and a soft shadow under a
   pure-black card on a pure-black ground is invisible work. */
:root[data-skin="7"]{
  --rise-1:none; --rise-2:none; --rise-3:none; --edge-lit:none;

  /* AND THE HAIRLINE GOES FLAT. shell.css's doctrine for Plain is no gradients,
     no translucency and no backdrop-filter, and `--edge-grad` is a gradient —
     so on this skin the token resolves to the flat `--line` every other rule
     would have used, and every `padding-box, border-box` recipe in the network
     quietly becomes the plain 1px border it was before. One override, no
     exceptions written anywhere else, and the floor skin keeps its 8-bit look
     carried entirely by its edges. */
  --edge-grad:linear-gradient(var(--line),var(--line));
}

@media (prefers-reduced-motion:reduce){
  :root{--dur-tap:0ms; --dur-move:0ms; --dur-enter:0ms; --dur-sweep:0ms;}
}

/* ══ 1 · THE SHELL FURNITURE, LIFTED ═══════════════════════════════════════
   `.sh-card` and `.sh-btn` are shell classes on every page of every surface —
   eight cards on Overhead's about page, ten buttons on its index. Restyling
   them from a surface sheet is the sanctioned override: build.py links a
   surface's stylesheets AFTER shell.css precisely so a surface can, and its
   comment at `styles =` says so.

   NOTHING HERE REDECLARES THE SHELL'S GEOMETRY. Padding, margin, radius and
   type are all still the shell's. What is added is depth, and only depth.

   THIS IS THE SAME BLOCK THE ALMANAC'S KIT CARRIES, minus the card's gradient
   hairline. Overhead's cards live below the fold on a page whose whole first
   screen is a photograph of the sky; a lit edge on a card down there is
   detail nobody is looking for, and the shadow alone does the job of
   separating one card from the next. */
.sh-card{box-shadow:var(--rise-1),var(--edge-lit);}

/* THE BUTTON. Overhead's ten controls are all `.sh-btn`, and this page is the
   reason the press state matters more here than anywhere else in the network:
   a sky map is used one-handed, outdoors, in the dark, with the other arm in
   the air. A control that gives nothing back when a thumb lands on it is a
   control the reader presses twice.

   `outline-offset` IS THE HOVER, from `rrr63_empty-cow-96` — it reads on a
   touch screen, where a hover shadow does not, and it costs no layout, which
   on a row that scrolls horizontally is the difference between a press and a
   reflow.
       https://uiverse.io/rrr63/empty-cow-96  (MIT)

   THE `:active` SCALE IS THE ONE THAT ACTUALLY SHIPS HERE. Hover does not
   exist on the device this page is designed for; `translateY(1px) scale(.985)`
   under `--dur-tap` is what a thumb gets, and it is 120ms because anything
   slower than that stops reading as the control moving and starts reading as
   the page being slow. */
.sh-btn{
  outline:1px solid transparent;
  outline-offset:0;
  box-shadow:var(--rise-1);
  transition:
    outline-offset var(--dur-move) var(--ease-out),
    outline-color  var(--dur-move) var(--ease-out),
    border-color   var(--dur-move) var(--ease-out),
    background     var(--dur-move) var(--ease-out),
    box-shadow     var(--dur-move) var(--ease-out),
    transform      var(--dur-tap)  var(--ease-press);}
.sh-btn:hover{
  outline-color:color-mix(in srgb,var(--moon) 26%,transparent);
  outline-offset:3px;
  box-shadow:var(--rise-2);}
.sh-btn:focus-visible{outline:2px solid var(--moon);outline-offset:3px;}
.sh-btn:active{transform:translateY(1px) scale(.985);}
.sh-btn[disabled]:hover{outline-offset:0;outline-color:transparent;
  box-shadow:var(--rise-1);}
.sh-btn[disabled]:active{transform:none;}

/* The primary pill — "Use my location" — gets the sweep from
   `KINGFRESS_nice-deer-12`, in ink over moon.
       https://uiverse.io/KINGFRESS/nice-deer-12  (MIT)

   ONE BUTTON ON THIS PAGE IS THE POINT OF IT and this is that button: a sky
   map with no location is a sky map of nowhere. `overflow:hidden` is added
   here and not on `.sh-btn`, so the other nine do not pay a clip to give this
   one a highlight. */
.sh-btn.primary{position:relative;overflow:hidden;}
.sh-btn.primary::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,
    transparent 20%,
    color-mix(in srgb,var(--ink) 24%,transparent) 50%,
    transparent 80%);
  transform:translateX(-100%);
  transition:transform var(--dur-sweep) var(--ease-move);
  pointer-events:none;}
.sh-btn.primary:hover::after{transform:translateX(100%);}
.sh-btn.primary > *{position:relative;z-index:1;}

/* ══ 2 · THE GLASS, AND THE FLOOR DEVICE ═══════════════════════════════════
   ⚠ THIS IS A BUG FIX, NOT A DESIGN CHANGE, and it is the most load-bearing
   line in this file.

   `.sky-first .sky-read` — the readout, the largest type on the page and the
   thing the whole product exists to print — declares `backdrop-filter` with
   NO `-webkit-` form. Unprefixed `backdrop-filter` is Safari 18.0. This
   network's floor is iOS Safari 16.4, measured from the app's own CSS and
   printed by `./uv`. So on the floor device that rule has been doing NOTHING:
   the readout is a 62%-translucent panel laid over a photograph of the Milky
   Way with no blur behind it, which is the one background translucency cannot
   survive.

   `./uv` prices "missing -webkit- forms" as an adoption cost for exactly this,
   and its note is the whole story: *backdrop-filter works on iOS only with the
   prefix, and a Chrome author never notices.* The Browser pane is Chromium and
   can never be evidence about iOS, so this was never going to be caught by
   looking at it.

   IT IS ALREADY WRITTEN CORRECTLY TWICE IN THIS REPO — `skymap.css:394` on
   the layer drawer, and every one of the nine occurrences in
   `product/app/app.css`, which always writes both forms. The readout is the
   one that was missed.

   THE PREFIXED FORM GOES FIRST so the unprefixed one wins wherever both are
   understood. It is applied HERE rather than in skymap.css so that the fix and
   the reasoning arrive together, and so `:root[data-skin="7"] *`'s global
   `backdrop-filter:none !important` — which Plain relies on — is not the only
   thing standing between the floor skin and a blur it does not want. Plain is
   handled below in its own right, because `!important` on the unprefixed
   property does not touch the prefixed one. THAT is the trap this file's
   comment exists to stop: adding `-webkit-backdrop-filter` anywhere in the
   network re-opens a hole in Plain unless it is closed in the same change. */
.sky-first .sky-read{
  -webkit-backdrop-filter:blur(14px);
  backdrop-filter:blur(14px);}

/* Plain paints flat, and shell.css's global rule only covers the unprefixed
   property. Every place the network gains a `-webkit-` form needs its Plain
   counterpart, and this is the network's second one. */
:root[data-skin="7"] .sky-first .sky-read{-webkit-backdrop-filter:none;}
:root[data-skin="7"] .sh-btn{-webkit-backdrop-filter:none;}

/* The two other blurred surfaces on this page, for the same reason. The layer
   drawer already carries both forms in skymap.css and is not repeated here. */
.sh-btn{-webkit-backdrop-filter:blur(10px);}

/* ══ 3 · THE READOUT, LIT ══════════════════════════════════════════════════
   Overhead's one hero, and the only element in the network that sits directly
   on a photograph rather than on a palette ground.

   IT DOES NOT GET `.uv-aura`. A halo behind a glass panel over a starfield is
   a smear over the exact pixels the product is asking the reader to look at,
   and the aura's own rule — one card per page, and only where there is
   something to make luminous — points the other way here: the luminous thing
   is the sky, and it is real.

   WHAT IT GETS IS AN EDGE AND A LIFT. `--rise-2` under a glass panel is what
   separates it from the sky behind it without tinting a single pixel of that
   sky, and the lit top hairline is what makes it read as a pane held in front
   of the view rather than a hole cut in it. Both are `none` on Plain, which is
   the floor skin and carries its look on edges. */
.sky-first .sky-read{box-shadow:var(--rise-2),var(--edge-lit);}
