/* ===========================================================================
   theme.css - THE LOOK FILE.

   Everything that decides how this site looks lives here and nowhere else.
   Change a number, save the file, press F5 in the browser - that is the whole
   workflow. The site is served without any caching, so your change is always
   visible immediately.

   The palette is the "Nebula Fog" abyss: a very dark blue-black void with gas
   clouds in the genre colours. The same colours carry the panels, the top bar
   and the tab buttons on every page, so all three tabs look like one place.
   =========================================================================== */

:root {
  /* This file paints the page, but not the things the browser owns: the
     scrollbars and the little built-in controls stay white unless the page
     asks for the dark ones. This is that ask, for the whole site. */
  color-scheme: dark;

  /* ---- 1. the void: the dark sky of the Starmap tab -------------------- */
  --void:            #04040c;   /* middle of the sky */
  --void-edge:       #010103;   /* the corners, a touch darker */

  /* how tall the control dock at the foot of Starmap stands. The legend and the
     note keep clear of it by this much. This is only the value before the page
     script runs - star.js measures the dock and overwrites it, so a change to
     the dock's padding or its one handle wants this number nudged to match. */
  --dock-h:          39px;

  /* ---- 2. the gas clouds ------------------------------------------------ */
  --cloud-size:      0.95;      /* size of one genre cloud (1 = 620 pixels) */
  --cloud-alpha:     0.28;      /* how thick the fog is */
  --cloud-grain:     118;       /* how many blobs make up one cloud */
  --cloud-bloom:     1.32;      /* how wide each blob spreads */
  --drift-speed:     0.00022;   /* how fast the clouds drift */
  --parallax:        0.075;     /* how far the clouds follow your mouse */
  --haze:            1.0;       /* brightness of the star dust */
  --cloud-density:   1.10;      /* MORE stars of one genre together = thicker fog
                                   (0 = the fog ignores the stars, 2 = very greedy) */
  --fog-rate:        0.55;      /* how fast fog brightness may change, per second -
                                   the ceiling. Lower = softer, slower fades */
  --fog-drift:       260;       /* how fast a cloud may move, pixels per second */

  /* ---- 3. the world hexagons -------------------------------------------- */
  --hex-size:        1.15;      /* size of a world hexagon (1 = 13.5px radius) */
  --hex-ring:        2.0;       /* thickness of the genre-coloured ring */
  --hex-glow:        2.2;       /* how much a hexagon glows */
  --hex-hover:       2.55;      /* extra growth under the mouse, on top of the front
                                   layer. Hovering pulls the star up to the nearest
                                   layer (--hover-front) AND makes it this much
                                   bigger, so it clearly stands out of the field.
                                   At 1 it would only be as big as the front layer.
                                   Was 5.1 (three times the old 1.7) until the user
                                   asked for the open star at half that: 2.55 is
                                   still more than twice the front layer, so the
                                   hovered star carries on being the biggest thing
                                   on the glass, at the size it was asked for */
  --hex-found:       2.2;       /* how much a star grows while it is a search hit */
  --search-same:     2.4;       /* while a search is on, every world it matched is drawn
                                   at this one size and at full strength, so the answers
                                   read as a set instead of as a sky you have to compare,
                                   and no two of them can come out differently sized. A
                                   world that stops being a hit eases back to the size and
                                   the light it had before. 0 turns it off and the hits
                                   simply grow as --hex-found says */
  --star-visit-size-min: 0.72;  /* smallest radius factor when visit sizing is on */
  --star-visit-size-max: 1.5;   /* largest radius factor when visit sizing is on */
  --thumb-dim:       0.92;      /* brightness of the picture inside it */
  --hex-ext:         1.20;      /* how far the hexagon stretches down in view
                                   mode (times the radius). The picture keeps to
                                   the top of the shape; the room that opens
                                   underneath carries the name, the maker, the
                                   platform and the numbers */
  --hex-upright:     1;         /* 1: every world stands the right way up on the
                                   screen, wherever it sits on the ball and
                                   however the ball is turned - roof up, tail
                                   and writing straight down the screen. The
                                   shape is lined up with your eye, not with the
                                   ball the sky is painted on, so a world stays
                                   readable as a world. 0 asks for the other
                                   reading: the shape is then glued to the ball
                                   and leans or turns over with it, the way a
                                   sticker on the inside of the ball would */
  --hex-lattice:     0.30;      /* the honeycomb ruled on that room under the
                                   picture, behind the writing: the size of one
                                   cell of it, as a share of the world's own
                                   radius. The cells are the same hexagon the
                                   world is cut from, one size down, in the
                                   world's own colour. 0 leaves the plate a
                                   plain dark panel */
  --hex-lattice-a:   0.60;      /* how strongly that honeycomb shows. It is at
                                   its loudest where the plate opens at the
                                   waist and thins as it runs down, so the words
                                   printed over it always keep the last word */

  /* ---- 3b. movement: roaming, hover, orbit ------------------------------ */
  --world-speed:     9;         /* how fast a star travels, pixels per second (0 = stones) */
  --world-turn:      0.9;       /* how often it changes direction (higher = more random) */
  --world-roam:      220;       /* how far it may travel from its genre patch (0 = tied down) */
  --search-pull:     20;        /* how hard a search drags its hits into the part of the sky
                                   you are looking at, x the star's own speed (0 = they
                                   stay wherever they were, the old behaviour) */
  --search-gather:   260px;     /* how near its own place the drag eases off, so the hits
                                   settle instead of slamming into it */
  --search-floor:    0.45;      /* how weak the drag is allowed to get at its very weakest, as a
                                   share of --search-pull. It never fades out completely: below
                                   this the star's own wandering would be stronger than the drag
                                   and it would circle its place forever instead of settling (0 =
                                   fade out completely, the old behaviour) */
  --spiral-snap:     4px;       /* how close to its place a star must be for the drag to count
                                   it as arrived and switch itself off (0 = never quite arrive) */
  --search-min:      3;         /* how many letters the search needs before the sky gathers at
                                   all - below that the matches still light up but the sky is
                                   left alone (0 = gather from the very first letter) */
  --search-hug:      90px;      /* how far out from the middle the spiral arm starts, so the
                                   first name settles around the middle and not onto it (0 =
                                   it starts at the one point) */
  --spiral-gap:      64px;      /* the smallest a step along that arm may ever be, whatever the
                                   stars' own sizes work out to - how far apart two neighbouring
                                   names really sit is set by the two of them: their radii at
                                   most touching, times --spiral-pad, so they never have to be
                                   shoved off their places by the crowd rule */
  --spiral-pad:      2.4;       /* the air left between two neighbouring names on top of the bare
                                   touching distance (1 = they settle exactly rim to rim) */
  --spiral-grow:     0.16;      /* how much wider the arm gets per step along it - this is the
                                   curl: 0 = a straight line of names running outward, 0.2 = a
                                   tight spiral. Keep it clear of what one turn's worth of steps
                                   eats up (roughly 1/6) or a long arm winds into itself */
  --start-spread:    520px;     /* how far from its nebula a star starts out (0 = right at home) */
  --pair-reach:      42px;      /* how close two stars must come to start circling (0 = never) */
  --pair-sep:        30px;      /* the distance they settle on while they circle */
  --pair-grip:       1;         /* how strongly they hold that circle (0 = no circling) */
  --orbit-speed:     0.22;      /* how fast neighbours circle a hovered star (radians/s) */
  --orbit-snap:      0.06;      /* how gently they slide into that circle (0.02 = lazy) */
  --orbit-reach:     190px;     /* how far around a hovered star its genre-mates join in */
  --star-curve:      valley;    /* valley = the slowest stars sit at BOTH ends of the
                                   visit scale (blockbusters and obscure ones drift,
                                   the middle of the field hurries);  slope = the more
                                   visits, the slower, all the way up */
  --star-slow:       0.5;       /* the slowest a star may ever go, x --world-speed */
  --star-fast:       1.8;       /* the fastest it may ever go, x --world-speed
                                   (both ends are hard limits - nothing outside) */
  --star-jitter:     0.08;      /* a pinch of chance on top, so equal counts differ */
  --star-collide:    1;         /* stars bump into each other (0 = they pass through) */
  --crowd-push:      3;         /* how much harder a gathered crowd is shoved apart than
                                   the loose sky (0 = the hits shove each other no
                                   harder than the rest of the field does) */
  --crowd-contact:   0.45;      /* the share of a crowd pair's leftover overlap that is
                                   taken back every frame, so the hits come to rest rim
                                   to rim - touching - instead of pressing into one
                                   another (0 = no contact, they overlap as they always
                                   did; 1 = the overlap is gone within the frame) */
  --star-touch:      0.9;       /* how much of two hexagons may overlap before the
                                   bump starts (1 = only when they really touch) */
  --hover-push:      2.4;       /* how much harder a hovered star shoves others away */
  --hover-clear:     1.2;       /* how far out a hovered star shoves them: 1 = they
                                  stop when the hexagons touch, 1.2 = a ring of
                                  clear sky is left around the opened star */
  --hover-front:     5;         /* how fast a hovered star is pulled up to the nearest
                                   layer (--depth-max size, drawn on top). It stays
                                   there until you move off, then drifts back out on
                                   its own. 0 leaves it in its own layer. */
  --depth-min:       0.6;       /* drawn size of the stars furthest back */
  --depth-max:       1.45;      /* drawn size of the stars in the very front */
  --depth-drift:     0.06;      /* how fast a star slips between the layers, per second */

  /* --- what the sky will hold ------------------------------------------------
     A map of ten thousand hexes is a smear to look at, so Starmap never
     carries more than --worlds-max worlds; past that line it keeps a random
     pick instead of the first thousand, so no world is buried for good.
     --worlds-min is the smallest sky the slider at the foot of the page may ask
     for. As the library grows past --size-drop-from the far layer is drawn
     progressively smaller - every --size-drop-step worlds it drops another
     --size-drop-each - until it reaches --size-drop-floor. The big end never
     moves: the current size stays the ceiling. */
  --worlds-max:      1000;      /* the most worlds the map will ever carry */
  --worlds-min:      12;        /* ... and the least the slider may ask for */
  --size-drop-from:  500;       /* world count where the far layer starts to shrink */
  --size-drop-step:  100;       /* ... one step every this many worlds past it */
  --size-drop-each:  0.06;      /* ... each step takes this off the far layer */
  --size-drop-floor: 0.22;      /* ... and it never falls below this */

  /* --- zoom -----------------------------------------------------------------
     The wheel over the sky and the slider at the foot of the page drive the
     same number. 1 is the map exactly as it has always looked. */
  --zoom-min:        0.5;
  --zoom-max:        4;
  --zoom-start:      1;
  --zoom-step:       0.08;      /* one wheel notch */
  --sky-size:        1.6;       /* how much bigger the SHEET the sky is painted on is than
                                   the window. It no longer means how far you can travel:
                                   you stand in the middle of the ball and the map scales
                                   with the sheet, so one look covers the same sky at any
                                   value. What it still moves is the loose roam of the
                                   worlds, the top and bottom padding, and how finely the
                                   fog is counted. */
  --sky-fov:         100;       /* how much sky fits across one screen, in degrees. The eye
                                   is in the middle of the ball, so this is really the lens:
                                   60 = a long look, few worlds, each one big; 120 = a wide
                                   look, many worlds, each one small. */
  --world-scale:     1.5;       /* how big the worlds are painted on the inside of the ball.
                                   The ball holds far more sky than the window used to show,
                                   so 1 looks bare; 1.5 keeps the screen as full as it was.
                                   The two knobs pull against each other: to have a few
                                   worlds far apart, raise this AND lower --sky-fov. */
  --pan-ease:        0.6;       /* how eagerly the view follows the pointer (1 = snapping) */
  --sky-tilt-limit:  90;        /* how far up and how far down the view is allowed to tip, in
                                   degrees away from level: 90 = you can look straight up at
                                   the top of the sky and straight down at the bottom, and
                                   the drag stops there instead of carrying you over the pole
                                   and out the other side. Raise it past 180 to take the stop
                                   away again (the old behaviour, endless tipping), or lower
                                   it to keep the eye nearer the horizon. */

  /* ---- 4. text and surfaces --------------------------------------------- */
  --page:            #06060f;   /* page background of Atlas and Library */
  --popup:           #0e0a20;   /* the dropdown lists: a solid sheet, because a
                                   list drawn by the system cannot be see-through */
  --panel-soft:      rgba(60, 44, 132, .35);   /* the violet glow at the top */
  --card:            rgba(255, 255, 255, .035);
  /* the rail's own sheet. Every panel down the side of the Atlas and the Library
     wears it, so the rail reads as one block of violet glass while the world
     cards beside it (plain --card, plus a wash of their own genre colour) read
     as something else entirely. These two move the whole rail at once. */
  --rail-card:       linear-gradient(180deg, rgba(143, 123, 255, .14),
                                              rgba(143, 123, 255, .05));
  --rail-card-line:  rgba(169, 156, 255, .22);
  --ink:             #e8ebff;   /* normal text */
  --ink-soft:        #b6bede;   /* a little quieter */
  --ink-faint:       #7e88ad;   /* labels and small print */
  --link:            #a99cff;
  --link-hover:      #ffffff;
  --hair:            rgba(169, 156, 255, .28);
  --hair-soft:       rgba(255, 255, 255, .07);

  /* ---- 5. the accent: buttons, active tab, badges ----------------------- */
  --accent:          #8f7bff;
  --accent-soft:     linear-gradient(180deg, rgba(143,123,255,.55), rgba(143,123,255,.26));
  --glow:            rgba(143, 123, 255, .55);

  /* ---- 6. shapes -------------------------------------------------------- */
  --radius:          10px;
  --bar-h:           56px;      /* height of the top bar */
  --tab-h:           32px;      /* height of a tab button */
  --tab-cut:         13px;      /* how much of the tab sides are cut (hexagon) */

  /* ---- 7. the ratio disc in the Atlas ------------------------------------ */
  --track:           rgba(255, 255, 255, .12);
  --track-fill:      #ffd76a;

  /* ---- 8. front-page atmosphere: edit these, not the renderer ----------- */
  --front-nebula-alpha:       .18;      /* 0 = no nebulae */
  --front-nebula-drift:       34px;     /* 0 = fixed in place */
  --front-nebula-speed:       .00012;   /* radians/ms; 0 = still */
  --front-nebula-scale:       .42;      /* fraction of the shorter screen edge; 0 = tiny */
  --front-nebula-count:       4;        /* 0 = none; maximum 4 */
  --front-watermark-alpha:    .022;     /* 0 = hide the icon */
  --front-watermark-scale:    .76;      /* fraction of shorter screen edge; 0 = hide */
  --front-reveal-alpha:       .34;      /* extra icon visibility under the pointer; 0 = off */
  --front-trail-life:         1050ms;   /* 0 = no fading trail */
  --front-trail-radius:       82px;     /* soft reveal radius; 0 = no reveal */
  --front-distortion:         16px;     /* icon shift along the pointer path; 0 = no shift */
  --front-trail-step:         7px;      /* distance between trail samples; 0 = every pointer move */
  --front-trail-cap:          16;       /* maximum trail samples; 0 = off */
  --front-canvas-dpr-max:     2;        /* render resolution cap; 1 = lighter */

  /* ---- 9. front-page magic circle: edit these, not front-sigil.js -------- */
  --front-magic-size:         820px;    /* square pentagon stage; shrinks with the viewport */
  --front-node-size:          140px;    /* desktop hex button */
  --front-mobile-node-size:   82px;     /* phone hex button */
  --front-route-texture-alpha: .23;     /* 0 = smooth, stronger grain as this approaches 1 */
  --front-sigil-reach:        140px;    /* pointer distance for a full sigil */
  --front-circle-opacity:     .13;      /* 0 = hide the circle and star lines */
  --front-circle-line-width:  1.2px;    /* decorative line thickness */
}

/* ---------------------------------------------------------------------------
   base
   --------------------------------------------------------------------------- */
* { box-sizing: border-box; }

html, body {
  margin: 0; min-height: 100%;
  background: var(--void);
  color: var(--ink);
  font: 13.5px/1.5 "Segoe UI", system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--link); text-decoration: none; }
a:hover { color: var(--link-hover); text-decoration: underline; }

/* ---------------------------------------------------------------------------
   the slider - one bar, everywhere
   ---------------------------------------------------------------------------
   Every surface on this site that can scroll wears the same rail: 8px, a track
   you can see through, and a thumb of --hair that brightens to --accent-soft
   under the pointer. It is written once, here. A component whose list can
   overflow joins this list rather than growing a slider of its own - the bright
   system bar is the one thing never let through.

   The height is not a mistake. The playlist strip in the Library and on a
   profile scrolls sideways, and a bar given only a width would leave that one
   system-coloured.

   The strip wears this quiet bar only while it is a plain scroller. As soon as
   there is more of it than fits, slidebar.js sets the site's sigil bar on it -
   a strip you walk along is a range, and that is the bar for walking a range -
   and .lat-strip.has-slide takes this one away again. One strip, one slider.

   (The Look Studio keeps its own quiet colours and never loads this file, so
   its panels are deliberately not in this list.) */
:is(.rail, .lat-strip, .pl-pop, .prof-pop, #card, .ft-card,
    .rvlist, .rv-picklist, .frags, .seals-list,
    .spell .col-list, .spell .rack) {
  scrollbar-width: thin;
  scrollbar-color: var(--hair) transparent;
}
:is(.rail, .lat-strip, .pl-pop, .prof-pop, #card, .ft-card,
    .rvlist, .rv-picklist, .frags, .seals-list,
    .spell .col-list, .spell .rack)::-webkit-scrollbar {
  width: 8px; height: 8px;
}
:is(.rail, .lat-strip, .pl-pop, .prof-pop, #card, .ft-card,
    .rvlist, .rv-picklist, .frags, .seals-list,
    .spell .col-list, .spell .rack)::-webkit-scrollbar-track {
  background: transparent;
}
:is(.rail, .lat-strip, .pl-pop, .prof-pop, #card, .ft-card,
    .rvlist, .rv-picklist, .frags, .seals-list,
    .spell .col-list, .spell .rack)::-webkit-scrollbar-thumb {
  background: var(--hair); border-radius: 4px;
}
:is(.rail, .lat-strip, .pl-pop, .prof-pop, #card, .ft-card,
    .rvlist, .rv-picklist, .frags, .seals-list,
    .spell .col-list, .spell .rack)::-webkit-scrollbar-thumb:hover {
  background: var(--accent-soft);
}
:is(.rail, .lat-strip, .pl-pop, .prof-pop, #card, .ft-card,
    .rvlist, .rv-picklist, .frags, .seals-list,
    .spell .col-list, .spell .rack)::-webkit-scrollbar-corner {
  background: transparent;
}

/* ---------------------------------------------------------------------------
   the top bar - identical on every page, so the tabs never move
   --------------------------------------------------------------------------- */
.topbar {
  position: fixed; top: 0; left: 0; right: 0; height: var(--bar-h);
  z-index: 30;
  display: flex; align-items: center; gap: 18px; padding: 0 18px;
  background: linear-gradient(180deg, rgba(6,6,18,.94), rgba(6,6,18,.76));
  border-bottom: 1px solid var(--hair-soft);
  backdrop-filter: blur(10px);
}
.topbar .spacer { flex: 1 1 auto; }
/* The bar is one row, and the page must never scroll sideways for it. So the
   pieces have an order of giving way: the name, the tabs and the account chip
   keep the size they were given, and the search field is the one that narrows.
   Everything below is the base of that order; the widths where the bar runs out
   of room to narrow into are at the end of this file. */
.topbar > .brand,
.topbar > .tabs,
.topbar > #prof { flex: 0 0 auto; }
.topbar > .search-stack {
  --search-cut: 17px;
  position: relative; isolation: isolate;
  display: flex; flex-direction: column; align-items: stretch;
  flex: 0 1 auto; min-width: 0; padding: 1px;
  background: var(--hx-edge, linear-gradient(90deg, #ffb8f4, #c46bff 48%, #7a34ff));
  clip-path: polygon(
    var(--search-cut) 0,
    calc(100% - var(--search-cut)) 0,
    100% 50%,
    calc(100% - var(--search-cut)) 100%,
    var(--search-cut) 100%,
    0 50%);
}
.topbar > .search-stack::before {
  content: ""; position: absolute; z-index: 0; inset: 1px;
  background: linear-gradient(180deg, rgba(14, 11, 31, .98), rgba(5, 5, 15, .98));
  clip-path: polygon(
    calc(var(--search-cut) - 1px) 0,
    calc(100% - var(--search-cut) + 1px) 0,
    100% 50%,
    calc(100% - var(--search-cut) + 1px) 100%,
    calc(var(--search-cut) - 1px) 100%,
    0 50%);
}
.topbar > .search-stack .search {
  position: relative; z-index: 1;
  flex: 0 1 auto; min-width: 0; height: 34px; padding: 0 20px;
  border: 0; border-radius: 0; background: transparent;
}
.topbar > .search-stack .search input { flex: 1 1 190px; width: auto; min-width: 0; }

/* The site's name, the way the tabs are: a long hexagon. Only it is not a plain
   button - it holds a slow wheel of rainbow colour with a light shower of stars
   drifting over it, so the front page and the name read as one piece of magic. */
.brand { display: inline-flex; align-items: center; gap: 8px; font-size: 16px; }
.brand:hover { text-decoration: none; }
.brand-icon {
  width: 34px; height: 39px; flex: 0 0 auto; object-fit: contain;
  filter: drop-shadow(0 0 8px rgba(143,123,255,.42));
}
.brand:hover .brand-icon { filter: drop-shadow(0 0 12px rgba(169,156,255,.72)); }
.bx {
  position: relative; display: inline-flex; align-items: center; gap: 6px;
  height: 34px; padding: 0 20px;
  background: #0c0719;
  clip-path: polygon(
    var(--tab-cut) 0,
    calc(100% - var(--tab-cut)) 0,
    100% 50%,
    calc(100% - var(--tab-cut)) 100%,
    var(--tab-cut) 100%,
    0 50%);
}
/* the colour inside it is not a band any more: it is gas, like the sky behind
   the stars. Six soft blobs, each a colour of its own, wander slowly across the
   hexagon and pass through one another. Where two of them cross they mix into a
   third colour and the spot turns brighter for it, the way two lights on top of
   each other add up, and the more of them that pile into one place the brighter
   that place glows. */
.bx::before {
  content: ''; position: absolute; inset: 0;
  background-image:
    radial-gradient(circle closest-side, hsla(338,84%,66%,.95), hsla(338,84%,66%,0.4) 62%, hsla(338,84%,66%,0)),
    radial-gradient(circle closest-side, hsla(26,88%,64%,.92), hsla(26,88%,64%,0.39) 62%, hsla(26,88%,64%,0)),
    radial-gradient(circle closest-side, hsla(56,90%,66%,.86), hsla(56,90%,66%,0.36) 62%, hsla(56,90%,66%,0)),
    radial-gradient(circle closest-side, hsla(146,78%,60%,.88), hsla(146,78%,60%,0.37) 62%, hsla(146,78%,60%,0)),
    radial-gradient(circle closest-side, hsla(196,88%,66%,.92), hsla(196,88%,66%,0.39) 62%, hsla(196,88%,66%,0)),
    radial-gradient(circle closest-side, hsla(272,88%,72%,.94), hsla(272,88%,72%,0.39) 62%, hsla(272,88%,72%,0));
  background-repeat: no-repeat;
  /* added together, not laid over one another: two colours in the same spot make
     a brighter, mixed colour instead of hiding the one underneath */
  background-blend-mode: screen;
  background-size: 46px 46px, 40px 40px, 54px 54px, 42px 42px, 50px 50px, 38px 38px;
  background-position: 2px -6px, 62px 4px, 108px -8px, 150px 5px, 182px -7px, 38px 8px;
  animation: bxNebula 26s ease-in-out infinite alternate;
  /* the gas glows over the dark glass instead of sitting dull on it */
  mix-blend-mode: screen;
  opacity: .84;
}
@keyframes bxNebula {
  0% {
    background-position: 2px -6px, 62px 4px, 108px -8px, 150px 5px, 182px -7px, 38px 8px;
    background-size: 46px 46px, 40px 40px, 54px 54px, 42px 42px, 50px 50px, 38px 38px;
  }
  50% {
    background-position: 38px 2px, 40px -6px, 132px 5px, 122px -8px, 152px 3px, 72px -5px;
    background-size: 58px 58px, 34px 34px, 64px 64px, 52px 52px, 42px 42px, 48px 48px;
  }
  100% {
    background-position: 20px -9px, 82px 5px, 90px 1px, 172px -6px, 170px -8px, 24px 2px;
    background-size: 42px 42px, 50px 50px, 46px 46px, 38px 38px, 60px 60px, 42px 42px;
  }
}
/* a soft light through the middle of the glass, so the colour reads as lit from
   within rather than painted on flat. */
.bx > .bglow {
  position: absolute; inset: 0;
  background: radial-gradient(120% 150% at 50% 50%, rgba(255,255,255,.14), rgba(255,255,255,0) 72%);
}
/* the stars: a scatter of pinpricks over the colour, breathing in and out. */
.bx::after {
  content: ''; position: absolute; inset: 0;
  background-image:
    radial-gradient(2.0px 2.0px at 14% 30%, #fff, transparent 70%),
    radial-gradient(1.5px 1.5px at 33% 74%, #fff, transparent 70%),
    radial-gradient(2.2px 2.2px at 52% 22%, #fff, transparent 70%),
    radial-gradient(1.6px 1.6px at 68% 62%, #fff, transparent 70%),
    radial-gradient(2.0px 2.0px at 84% 36%, #fff, transparent 70%),
    radial-gradient(1.5px 1.5px at 24% 54%, #fff, transparent 70%),
    radial-gradient(1.8px 1.8px at 76% 82%, #fff, transparent 70%),
    radial-gradient(1.5px 1.5px at 45% 44%, #fff, transparent 70%),
    radial-gradient(1.4px 1.4px at 61% 84%, #fff, transparent 70%),
    radial-gradient(1.4px 1.4px at 8% 62%, #fff, transparent 70%);
  animation: bxTwinkle 4.2s ease-in-out infinite;
}
.brand b { position: relative; z-index: 1; font-weight: 700; letter-spacing: .01em; text-shadow: 0 0 9px rgba(0,0,0,.75); }
/* The name is three words and each one wears its own colour: Akashic gold, Abyss the
   hot pink #E70069, Atlas plain white. All three are bold, so the mark reads as one name
   with three faces rather than a name and a qualifier. */
.brand .bk { color: #f3d078; }
.brand .by {
  /* plain hot pink, no pattern and no outline.
     This word used to be painted on as a background clipped to its letters, because it
     carried a scatter of black spots and a text colour cannot hold a pattern. The spots are
     gone (2026-10-07), so the whole painting apparatus went with them: it is an ordinary
     colour again and picks up the same dark halo as its two siblings from `.brand b` above,
     which is what keeps it readable over the nebula.
     (A rim was tried and taken back off again on 2026-10-07: a -webkit-text-stroke paints
     over the fill and eats the letters, and a stack of drop-shadow copies reads as clutter on
     16px type. So: colour, no outline.) */
  color: #e70069;
}
.brand .at { color: #fff; }
.brand:hover .bx::before { opacity: .78; }
.brand:hover .bk { color: #ffe7ab; }
.brand:hover .by { filter: brightness(1.2); }
/* the magic spills past the cut edges: the glow goes on the anchor, because the
   hexagon's own clip would cut a shadow off at the same line. */
.brand { filter: drop-shadow(0 0 9px rgba(143,123,255,.30)); }
.brand:hover { filter: drop-shadow(0 0 13px rgba(160,140,255,.55)); }
@keyframes bxTwinkle { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .bx::before, .bx::after { animation: none; } }
/* The World Spell is the front page and has no tab of its own - the site's name is the way in, so
   on that page the name is what reads as "you are here". The harder glow is the cue: there is no
   smaller qualifier word left in the name to turn white instead. */
body.tab-spell .brand { filter: drop-shadow(0 0 12px rgba(143,123,255,.5)); }

/* ---------------------------------------------------------------------------
   the tab buttons - long hexagons
   --------------------------------------------------------------------------- */
.tabs { display: flex; align-items: center; gap: 8px; }

.tab {
  height: var(--tab-h);
  padding: 0 22px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12.5px; letter-spacing: .03em;
  color: var(--ink-soft);
  background: rgba(255, 255, 255, .045);
  clip-path: polygon(
    var(--tab-cut) 0,
    calc(100% - var(--tab-cut)) 0,
    100% 50%,
    calc(100% - var(--tab-cut)) 100%,
    var(--tab-cut) 100%,
    0 50%);
  transition: color .15s, background .15s;
}
.tab:hover { color: #fff; background: rgba(143,123,255,.22); text-decoration: none; }
.tab.on {
  color: #fff; font-weight: 600;
  background: var(--accent-soft);
  box-shadow: inset 0 0 16px var(--glow);
}

/* ---------------------------------------------------------------------------
   the search field
   --------------------------------------------------------------------------- */
.search {
  display: flex; align-items: center; gap: 2px; height: 30px; padding: 0 10px;
  border: 1px solid var(--hair); border-radius: 15px;
  background: rgba(0, 0, 0, .35);
}
.search input {
  width: 190px; border: 0; outline: 0; background: transparent;
  color: var(--ink); font: 12.5px "Segoe UI", system-ui, sans-serif;
}
.search input::placeholder { color: var(--ink-faint); }
.search button {
  border: 0; background: transparent; color: var(--ink-faint);
  cursor: pointer; padding: 0 6px;
  font: 12px "Segoe UI", system-ui, sans-serif;
}
.search button:hover { color: #fff; }
.search .clear { display: none; font-size: 13px; }
body.has-query .search .clear { display: block; }

/* Reach lives inside the lower band of the primary search. The shared outlined
   hexagon makes the slider read as the field's lower edge, not a second card.
   Its range input retains the accessible label even though its visual title is
   intentionally absent here. */
.search-reach {
  position: static; z-index: 1;
  box-sizing: border-box; width: 100%;
  min-height: 20px; padding: 0 19px;
  border: 0; border-radius: 0;
  background: transparent;
}
.search-reach[hidden] { display: none; }
.search-reach .num-h { display: none; }
.search-reach::before {
  content: ""; display: block; height: 1px; margin: 0 -1px;
  background: linear-gradient(90deg, transparent, var(--hair), transparent);
}
.search-reach .dual { position: relative; z-index: 1; margin: 0; }
.topbar > .search-stack:focus-within { filter: brightness(1.16); }

/* ---------------------------------------------------------------------------
   Starmap only: legend, tooltip, info card, match counter
   --------------------------------------------------------------------------- */
.legend {
  position: fixed; left: 16px; bottom: calc(var(--dock-h) + 14px); z-index: 20;
  display: flex; gap: 14px; flex-wrap: wrap;
  max-width: calc(100% - 32px);
  pointer-events: none;
}
.legend div { display: flex; align-items: center; gap: 6px;
  font-size: 11.5px; color: var(--ink-faint); }
.legend i { width: 8px; height: 8px; border-radius: 2px;
  background: currentColor; box-shadow: 0 0 9px currentColor; }
.legend b { color: var(--ink-soft); font-weight: 500; }
.legend .n { opacity: .6; font-variant-numeric: tabular-nums; }

#found {
  position: fixed; z-index: 22; display: none;
  top: calc(var(--bar-h) + 12px); left: 50%; transform: translateX(-50%);
  padding: 5px 13px; border-radius: 12px;
  font-size: 12px; color: var(--ink-soft);
  background: rgba(8, 8, 20, .9);
  border: 1px solid var(--hair);
}
#found b { color: #fff; }

#card {
  position: fixed; z-index: 40; display: none;
  top: calc(var(--bar-h) + 16px); right: 16px; width: 330px;
  max-height: calc(100vh - var(--bar-h) - 34px); overflow: auto;
  padding: 15px 16px 16px; border-radius: 12px;
  background: rgba(7, 7, 18, .96);
  border: 1px solid var(--hair);
  box-shadow: 0 20px 60px rgba(0, 0, 0, .7);
}
#card h3 { margin: 0 46px 3px 0; font-size: 15px; color: #fff; }
#card .byline { font-size: 12px; color: var(--ink-soft); margin-bottom: 10px; }
#card .byline a { color: inherit; text-decoration: none; }
#card .byline a:hover { color: var(--accent-lit, #ff6aa8); text-decoration: underline; }
#card .rows { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-bottom: 10px; }
#card .rows span { font-size: 11.5px; color: var(--ink-faint); }
#card .rows b { color: var(--ink); font-weight: 600;
  font-variant-numeric: tabular-nums; }
#card p { margin: 0 0 12px; font-size: 12px; line-height: 1.6; color: var(--ink-soft); }
#card .acts { display: flex; gap: 8px; flex-wrap: wrap; }
#card .acts a {
  font-size: 12px; padding: 6px 11px; border-radius: 8px;
  border: 1px solid var(--hair); color: var(--ink);
}
#card .acts a:hover { color: #fff; border-color: var(--accent); text-decoration: none; }
#c-close {
  position: absolute; top: 10px; right: 10px; width: 26px; height: 26px;
  border-radius: 50%; border: 1px solid var(--hair); background: transparent;
  color: var(--ink-faint); cursor: pointer; font-size: 13px; line-height: 1; padding: 0;
}
#c-close:hover { color: #fff; border-color: var(--accent); }

/* ---------------------------------------------------------------------------
   sizes shared by Atlas and Library
   --------------------------------------------------------------------------- */
:root { --grid-gap: 20px 16px; --card-min: 215px; }

/* ---------------------------------------------------------------------------
   the dropdown lists
   ---------------------------------------------------------------------------
   A field we can paint ourselves, but the list that falls out of it is drawn by
   the system, not by the page - so on a dark theme it comes up in the light
   palette and the two do not belong together. `color-scheme: dark` hands the
   whole popup over to the dark side; the rows inside still need their colours
   spelled out, because the browser ignores the field's own background for them.
   The accent on the highlighted row is best-effort: Chrome paints that row
   itself and takes the colour from nowhere but its own dark palette.
   --------------------------------------------------------------------------- */
select { color-scheme: dark; }
select option { background-color: var(--popup); color: var(--ink); }
select option:hover, select option:focus,
select option:checked { background-color: var(--accent); color: #fff; }

/* ---------------------------------------------------------------------------
   the bar on a narrow window
   ---------------------------------------------------------------------------
   The bar has four pieces and the page underneath it may never scroll sideways,
   so the pieces give way in an order. Down to 821px that order is the search
   field's: it narrows, from its full 190px of text down to a stub, and the
   name, the tabs and the account chip stay exactly as they were.
   Past that there is nothing left to narrow into, so the bar takes a second
   row instead and grows to hold it: the field and the chip go down there
   together, where the field has the whole width to itself. Everything that
   measures itself from --bar-h (the pages' top padding, the star map's panels
   and info card, the found-counter) follows the taller bar on its own.
   The two steps below that buy back the width the tabs and the name need, so
   the bar stays two rows all the way down to a phone held upright.
   --------------------------------------------------------------------------- */

@media (max-width: 820px) {
  :root { --bar-h: 96px; }
  .topbar {
    flex-wrap: wrap; height: var(--bar-h);
    align-content: center; padding: 6px 14px; gap: 8px 12px;
  }
  /* the chip is the last thing on the first row, the field takes the second */
  .topbar > #prof { order: 2; }
  .topbar > .search-stack { order: 3; }
}

@media (max-width: 520px) {
  .topbar { gap: 8px; }
  .bx { padding: 0 12px; }
  .brand-icon { width: 30px; height: 35px; }
  .tab { padding: 0 10px; }
  /* The chip keeps its avatar and its live dot. Its name is still the button's
     name for anyone listening, it is only taken out of the row: on a narrow bar
     it is the widest thing there and the least needed, since the avatar already
     says whose account this is. */
  .prof-nm {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
}

@media (max-width: 420px) {
  /* the shortest form of the name that still says which site this is */
  .brand .by, .brand .at { display: none; }
}

@media (max-width: 380px) {
  /* A window this narrow cannot hold the name and the tabs side by side, so the
     bar needs three rows: the name, then the tabs, then the field with the chip.
     It grows to hold them rather than let them spill over the page. */
  :root { --bar-h: 136px; }
}

/* A world VRChat no longer answers for. It stays in the atlas and the library so that a
   finished world does not simply vanish, and it says what it is instead of looking broken.
   Only the star map leaves it out, because the sky is what you can go and visit. */
.badge.off,
.gi.off {
  color: #ffb765;
  border-color: currentColor;
}
