/* ============================================================
   APPEARANCE

   Load order: juq.css -> patch.css -> system.css -> appearance.css -> page css.

   FOUR DIALS on <html>, set before first paint by the inline script every page
   carries:

     data-mode      dark | light
     data-skin      ember | cobalt | classic | spicy | sweet | terminal | grape | paper
     data-corners   sharp | soft | cloud
     data-depth     flat | raised | airy

   Default: classic, dark, cloud, airy.

   WHY THIS IS A SEPARATE FILE AND NOT AN EDIT TO juq.css. juq.css is a
   byte-for-byte copy of the approved mockup and is never edited; that is the
   only reason it cannot drift. This overrides it instead, which is exactly what
   the appearance mockup did, and the mockup is therefore a true preview rather
   than an approximation of one.

   It also means juq.css keeps its four old skin blocks and its 40
   [data-skin="sweet"] rules, which are now dead weight: the sweet rules are
   out-specified below rather than deleted. Deleting them is a cleanup with no
   visual result, and it is the one job in this feature that can only make
   things worse if it goes wrong.

   GENERATED FROM redesign/tools/appearance-mockup.html by
   scratchpad/build-appearance-css.mjs. Edit the mockup, not this file, or the
   preview stops being the thing that ships.
   ============================================================ */


/* ============================================================
   1. THE PALETTES

   Each sets the same fourteen tokens the site already reads, twice: once dark,
   once light. None of them sets --radius or a shadow depth, because those
   belong to the other two dials now.

   THE NEUTRALS ARE TINTED, NOT GREY. Every palette's greys carry a little of
   its own accent, which is the difference between a scheme that was chosen and
   one that was defaulted. The current Dark is #0c0c0e/#151518/#1d1d21: pure
   neutral, under a hot orange, which is why it reads as "a dark theme" rather
   than as this site's dark theme.

   Contrast is checked, not eyeballed: scratchpad/palette-contrast.mjs parses
   these blocks and computes the real ratios. Ink on background clears 7:1 in
   all sixteen, muted text and accents clear 4.5:1.
   ============================================================ */

/* ---------- EMBER: the orange the site already wears ---------- */
:root[data-skin="ember"] {
  --bg:#0d0c0b; --surface:#171512; --surface-2:#201d19;
  --ink:#f7f3ec; --muted:#a09587; --line:#2c2823; --line-strong:#3e3830;
  --accent:#ff5a1e; --accent-ink:#140b05; --accent-soft:rgba(255,90,30,0.14);
  --ok:#3ddc84; --scroll:#ff5a1e; --track:#2a251f; --shadow:rgba(0,0,0,0.62);
}
:root[data-mode="light"][data-skin="ember"] {
  --bg:#f4efe6; --surface:#fffdf8; --surface-2:#ebe4d7;
  --ink:#1a1712; --muted:#645a4e; --line:#ded4c4; --line-strong:#b8ab97;
  /* Deepened from #ff5a1e: the bright orange is 2.2:1 on bone and unreadable
     as a link or a button label. */
  --accent:#c0400a; --accent-ink:#fffdf8; --accent-soft:rgba(192,64,10,0.10);
  --ok:#1c7a49; --scroll:#c0400a; --track:#e4dbcb; --shadow:rgba(60,42,20,0.20);
}

/* ---------- COBALT: the blue that was hiding inside "Light" ---------- */
:root[data-skin="cobalt"] {
  --bg:#0a0b12; --surface:#12141f; --surface-2:#191c2a;
  --ink:#edeff8; --muted:#9096ad; --line:#242840; --line-strong:#333952;
  --accent:#6379ff; --accent-ink:#05070f; --accent-soft:rgba(99,121,255,0.16);
  --ok:#3ddc84; --scroll:#6379ff; --track:#21253a; --shadow:rgba(0,0,0,0.62);
}
:root[data-mode="light"][data-skin="cobalt"] {
  --bg:#eaedf7; --surface:#ffffff; --surface-2:#e0e5f3;
  --ink:#0e1020; --muted:#565d78; --line:#c9d0e6; --line-strong:#9aa4c6;
  --accent:#1c34ff; --accent-ink:#ffffff; --accent-soft:rgba(28,52,255,0.10);
  --ok:#0a7044; --scroll:#1c34ff; --track:#d9def0; --shadow:rgba(18,24,60,0.18);
}

/* ---------- CLASSIC: the site before the redesign ---------- */
/* Lifted from assets/theme.css rather than remembered: the cyan is its
   --cyan-500, the greys are its own dark ramp, the green is its --green. */
:root[data-skin="classic"] {
  --bg:#0e0e12; --surface:#16161b; --surface-2:#1d1d23;
  --ink:#f3f3f5; --muted:#9296a0; --line:#2a2a33; --line-strong:#36363f;
  --accent:#06c2f0; --accent-ink:#04222b; --accent-soft:rgba(6,194,240,0.14);
  --ok:#2dce7a; --scroll:#06c2f0; --track:#26262e; --shadow:rgba(0,0,0,0.58);
}
:root[data-mode="light"][data-skin="classic"] {
  --bg:#eceff2; --surface:#ffffff; --surface-2:#e3e8ec;
  --ink:#12161a; --muted:#566069; --line:#cbd3d9; --line-strong:#a0acb5;
  /* The v1 cyan is 1.9:1 on white. This is --cyan-700, its own darker step. */
  --accent:#00697f; --accent-ink:#ffffff; --accent-soft:rgba(0,105,127,0.12);
  --ok:#1a7248; --scroll:#00697f; --track:#dbe2e7; --shadow:rgba(14,28,38,0.18);
}

/* ---------- SPICY ---------- */
:root[data-skin="spicy"] {
  --bg:#120807; --surface:#1e0f0c; --surface-2:#2a1611;
  --ink:#fbeee9; --muted:#c19b90; /* was #b28a7d, 3.9:1 on its own surface */
  --line:#3a1e17; --line-strong:#5e3122; /* lifted: #52281c was 1.58:1 on this bg */
  --accent:#ff5137; /* was #ff2f1c, 3.6:1 */ --accent-ink:#140503;
  --accent-soft:rgba(255,81,55,0.16);
  --ok:#f0b93f; --scroll:#ff5137; --track:#331a11; --shadow:rgba(0,0,0,0.66);
}
:root[data-mode="light"][data-skin="spicy"] {
  --bg:#f7ebe7; --surface:#fffaf8; --surface-2:#f1ded7;
  --ink:#2a100a; --muted:#78493d; --line:#e6c9be; --line-strong:#c69c8c;
  --accent:#bf2408; --accent-ink:#fffaf8; --accent-soft:rgba(191,36,8,0.10);
  --ok:#7d5a0f; --scroll:#bf2408; --track:#ecd8d0; --shadow:rgba(90,32,16,0.20);
}

/* ---------- SWEET ---------- */
:root[data-skin="sweet"] {
  --bg:#150a11; --surface:#20101a; --surface-2:#2b1624;
  --ink:#fdeaf4; --muted:#c290ab; --line:#3b1f30; --line-strong:#52293f;
  --accent:#ff5aa8; --accent-ink:#1a0610; --accent-soft:rgba(255,90,168,0.16);
  --ok:#4ade80; --scroll:#ff5aa8; --track:#331a28; --shadow:rgba(0,0,0,0.62);
}
:root[data-mode="light"][data-skin="sweet"] {
  --bg:#fff1f7; --surface:#ffffff; --surface-2:#ffe6f1;
  --ink:#3a1030; --muted:#8a5473; /* was #a3708f, 3.5:1 */
  --line:#f6cfe2; --line-strong:#e19dc2;
  --accent:#d4126f; /* was #ff3d97, 3.0:1 and used on buttons */
  --accent-ink:#ffffff; --accent-soft:rgba(212,18,111,0.10);
  --ok:#1c7a49; --scroll:#d4126f; --track:#fbdcea; --shadow:rgba(150,40,100,0.20);
}

/* ---------- TERMINAL ---------- */
:root[data-skin="terminal"] {
  --bg:#050806; --surface:#0b110c; --surface-2:#111a13;
  --ink:#dcf7e1; --muted:#87a88f; --line:#1b2a1e; --line-strong:#294231;
  --accent:#3ef07a; --accent-ink:#04140a; --accent-soft:rgba(62,240,122,0.13);
  --ok:#3ef07a; --scroll:#3ef07a; --track:#16221a; --shadow:rgba(0,0,0,0.7);
}
:root[data-mode="light"][data-skin="terminal"] {
  --bg:#ecf3ee; --surface:#ffffff; --surface-2:#e1ebe4;
  --ink:#0d1a10; --muted:#4c6153; --line:#c9dace; --line-strong:#9db4a5;
  --accent:#0d6f37; --accent-ink:#ffffff; --accent-soft:rgba(13,111,55,0.12);
  --ok:#0d6f37; --scroll:#0d6f37; --track:#d9e6dd; --shadow:rgba(16,44,26,0.18);
}

/* ---------- GRAPE ---------- */
:root[data-skin="grape"] {
  --bg:#0d0a16; --surface:#150f22; --surface-2:#1d152e;
  --ink:#f0eaff; --muted:#9d92b8; --line:#2a2040;
  --line-strong:#463663; /* lifted: #3a2c56 was 1.56:1 on this bg */
  --accent:#a970ff; --accent-ink:#0d0518; --accent-soft:rgba(169,112,255,0.16);
  --ok:#4ade80; --scroll:#a970ff; --track:#241a38; --shadow:rgba(0,0,0,0.64);
}
:root[data-mode="light"][data-skin="grape"] {
  --bg:#efecf8; --surface:#ffffff; --surface-2:#e6e0f5;
  --ink:#170f26; --muted:#5c5174; --line:#d5cbe8; --line-strong:#ab9dca;
  --accent:#6423cf; --accent-ink:#ffffff; --accent-soft:rgba(100,35,207,0.10);
  --ok:#1c7a49; --scroll:#6423cf; --track:#e1d9f1; --shadow:rgba(46,26,86,0.20);
}

/* ---------- PAPER: the quiet one ---------- */
/* Umber rather than orange, so it is not Ember with the lights on. */
:root[data-skin="paper"] {
  --bg:#100e0b; --surface:#1a1713; --surface-2:#241f19;
  --ink:#f2ece1; --muted:#a1957f; --line:#2e2820; --line-strong:#40382c;
  --accent:#d99a4e; --accent-ink:#14100a; --accent-soft:rgba(217,154,78,0.14);
  --ok:#63b06a; --scroll:#d99a4e; --track:#2b251d; --shadow:rgba(0,0,0,0.6);
}
:root[data-mode="light"][data-skin="paper"] {
  --bg:#f3ece0; --surface:#fbf7ef; --surface-2:#eae0cd;
  --ink:#241f18; --muted:#665b4a; --line:#ddd1bd; --line-strong:#b8a88c;
  --accent:#8a5a1c; --accent-ink:#fbf7ef; --accent-soft:rgba(138,90,28,0.10);
  --ok:#456f38; --scroll:#8a5a1c; --track:#e6dbc8; --shadow:rgba(60,45,25,0.20);
}

/* ============================================================
   2. CORNERS

   One token. Every card, button, chip and panel on the site already reads
   --radius, which is why this dial costs three lines and works everywhere at
   once. The small radius is separate because a 20px chip is a pill, and pills
   are the one shape this site has ruled out.
   ============================================================ */
:root[data-corners="sharp"] { --radius:2px;  --radius-sm:2px; }
:root[data-corners="soft"]  { --radius:8px;  --radius-sm:5px; }
:root[data-corners="cloud"] { --radius:20px; --radius-sm:11px; }

:root[data-corners] .chip,
:root[data-corners] .btn,
:root[data-corners] .card-flag,
:root[data-corners] .k { border-radius: var(--radius-sm); }
/* juq.css makes these circles under Sweet alone. The shape dial owns shape. */
:root[data-corners] .avatar,
:root[data-corners] .dot { border-radius: var(--radius-sm); }

/* ============================================================
   3. DEPTH

   FLAT     the border does the work, nothing casts anything
   RAISED   a hard offset block, the brutalist shadow the site ships today
   AIRY     a soft spread, borders step back, things lift on hover

   Two tokens, so no page ever writes a shadow itself.
   ============================================================ */
/* RAISED IS THE DEFAULT, BECAUSE RAISED IS WHAT THE SITE ALREADY IS.
   This started with `flat` as the default and that was simply wrong about the
   live site: .featured, .u-card-loud, .spot-detail and .app-hero all cast
   `8px 8px 0 var(--accent)` today, and .btn casts `5px 5px 0 var(--ink)` and
   presses INTO it on hover. Ordinary cards cast nothing. So the values below
   are not chosen, they are copied, and a visitor who never opens this panel
   sees exactly the site they saw yesterday. */
:root[data-depth="flat"] {
  --elev: none; --elev-loud: none; --elev-btn: none;
  --line-mix: var(--line-strong);
}
:root[data-depth="raised"] {
  /* Ordinary cards cast nothing even here, which is today's behaviour: the
     offset block is what marks something OUT, and giving it to everything
     would flatten the difference it exists to make. */
  --elev: none;
  --elev-loud: 8px 8px 0 var(--accent);
  --elev-btn: 5px 5px 0 var(--ink);
  --line-mix: var(--line-strong);
}
:root[data-depth="airy"] {
  --elev: 0 6px 18px var(--shadow);
  --elev-loud: 0 18px 44px var(--shadow);
  --elev-btn: 0 9px 22px var(--shadow);
  /* Recedes rather than disappearing: removed entirely, a light palette loses
     the edge of every card against the page. */
  --line-mix: var(--line);
}

/* Selectors carry :root[data-depth] so they outrank juq.css's
   [data-skin="sweet"] rules, which are the same idea hard-coded to one
   palette and would otherwise keep overriding this. In the real build those 25
   rules are deleted, not out-specified. */
:root[data-depth] .card,
:root[data-depth] .u-card,
:root[data-depth] .settings,
:root[data-depth] .juqbal-pop,
:root[data-depth] .tip,
:root[data-depth] .mk-panel {
  box-shadow: var(--elev);
  border-color: var(--line-mix);
  transition: box-shadow .18s ease, transform .18s ease, border-color .18s ease;
}
:root[data-depth] .featured,
:root[data-depth] .u-card-loud,
:root[data-depth] .fc-card,
:root[data-depth] .spot-detail,
:root[data-depth] .app-hero,
:root[data-depth] .panel {
  box-shadow: var(--elev-loud);
  border-color: var(--line-mix);
  transition: box-shadow .18s ease, transform .18s ease, border-color .18s ease;
}
/* THE BUTTON PRESS IS PART OF THE DEPTH, not decoration on top of it. Raised
   presses INTO its own shadow, which is the site's signature interaction and
   is copied exactly. Airy lifts, which is what Sweet already does today. Flat
   has no shadow to move, so it answers with its border instead: a press that
   moves nothing reads as a dead button. */
:root[data-depth] .btn { box-shadow: var(--elev-btn); }
:root[data-depth="flat"] .btn:hover { transform: none; border-color: var(--accent); }
:root[data-depth="raised"] .btn:hover { transform: translate(5px, 5px); box-shadow: 0 0 0 transparent; }
:root[data-depth="airy"] .btn { border-color: transparent; }
:root[data-depth="airy"] .btn:hover { transform: translateY(-3px); box-shadow: 0 16px 34px var(--shadow); }

/* Only the floating one floats. On flat that is motion with nothing behind it;
   on raised the block shadow already says "solid". */
:root[data-depth="airy"] .card:hover,
:root[data-depth="airy"] .featured:hover { transform: translateY(-3px); }
:root[data-depth="airy"] .card:hover { box-shadow: 0 12px 28px var(--shadow); }

/* ============================================================
   3b. CHANGING A DIAL IS A MOVE, NOT A CUT

   Depth already eased, because those components carry a transition for their
   own hover. Colour and radius had none, so a palette change was a hard cut
   and switching corners snapped.

   ONLY WHILE SOMETHING IS ACTUALLY CHANGING. The obvious version is to leave
   these transitions on everything permanently, and that is the wrong trade: a
   card that eases its background over 300ms also eases it on hover, so every
   hover in the site goes soft and late. The class is added when a dial moves
   and taken off ~340ms later, so the rest of the time nothing here applies.

   `*` is a big hammer and is the right one here: a palette touches every
   surface, every border and every piece of text on the page, and listing them
   would be listing the stylesheet. It is only ever live for a third of a
   second.

   TRANSFORM IS DELIBERATELY NOT IN THE LIST. The airy depth lifts cards on
   hover with it, and sweeping it up here makes a hover that happens mid-change
   crawl at the morph's pace instead of its own.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  :root.is-morphing,
  :root.is-morphing *,
  :root.is-morphing *::before,
  :root.is-morphing *::after {
    transition:
      background-color .3s ease,
      color .3s ease,
      border-color .3s ease,
      box-shadow .3s ease,
      border-radius .26s cubic-bezier(.4,0,.2,1),
      outline-color .3s ease,
      fill .3s ease !important;
  }
}

/* ============================================================
   4. THE CONTROL

   In the navbar, NOT in the account menu. The skin picker lives inside the
   signed-in drop-down today, so a visitor who has never signed in cannot
   change how the site looks at all. Appearance is a preference of the person
   looking at the screen, not a property of an account.
   ============================================================ */
.ap-navbtn { display:inline-flex; align-items:center; gap:var(--s-3); }
.ap-swatch { width:13px; height:13px; border-radius:3px; background:var(--accent);
  border:1px solid var(--line-strong); }

/* ANCHORED UNDER ITS OWN BUTTON, like every other drop-down on the bar. The
   first version pinned it to the viewport corner, which looked fine here and
   wrong on the real navbar: it was the one menu that opened somewhere other
   than under the thing you clicked. These values are the ones .settings and
   .juqbal-pop already use, down to the 10px gap and the offset shadow, so it
   is the same object as its neighbours rather than a lookalike. */
.ap-wrap { position:relative; }
.ap-panel { position:absolute; top:calc(100% + 10px); right:0; z-index:60; width:340px;
  max-width:calc(100vw - 24px);
  background:var(--surface); border:var(--bw) solid var(--ink);
  border-radius:var(--radius); box-shadow:var(--elev-loud);
  /* THE SCROLL IS ON THE INSIDE, and this is why. A scrollbar is painted
     outside the rounded clip, so a panel that scrolls ITSELF gets a hard bar
     running straight through its right-hand corners and squaring them off. The
     shell is `overflow:hidden`, which DOES clip a child's scrollbar to the
     radius, and the child scrolls. clip-path would also work and is wrong here:
     it clips the box-shadow too, and this panel casts one. */
  overflow:hidden;
  opacity:0; transform:translateY(-12px); pointer-events:none;
  transition:opacity .22s ease, transform .24s cubic-bezier(.2,.75,.2,1); }
.ap-panel.open { opacity:1; transform:translateY(0); pointer-events:auto; }
.ap-scroll { max-height:calc(100vh - 96px); overflow-y:auto; padding:var(--s-6); }
.ap-h { font-family:var(--f-mono); font-size:var(--t-label); letter-spacing:.12em;
  text-transform:uppercase; color:var(--muted); margin-bottom:var(--s-4); }
.ap-h:not(:first-child) { margin-top:var(--s-8); }

/* Mode is a two-way switch, so it looks like one rather than like a third
   option in a row of three. */
.ap-mode { display:flex; border:var(--bw) solid var(--line-strong);
  border-radius:var(--radius); overflow:hidden; }
.ap-mode button { flex:1; padding:var(--s-4); cursor:pointer; font:inherit;
  font-size:var(--t-sm); background:var(--surface-2); color:var(--muted); border:0;
  display:flex; align-items:center; justify-content:center; gap:var(--s-3); }
.ap-mode button + button { border-left:var(--bw) solid var(--line-strong); }
.ap-mode button.on { background:var(--accent); color:var(--accent-ink); font-weight:700; }

/* Each option DRAWS what it does rather than naming it: a word cannot show you
   what "airy" means and a 40px square can. */
.ap-row { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--s-4); }
.ap-opt { display:flex; flex-direction:column; align-items:center; gap:var(--s-3);
  padding:var(--s-5) var(--s-3); cursor:pointer; font:inherit; color:var(--ink);
  background:var(--surface-2); border:var(--bw) solid var(--line); border-radius:var(--radius); }
.ap-opt:hover { border-color:var(--line-strong); }
.ap-opt.on { border-color:var(--accent); background:var(--accent-soft); }
.ap-opt-n { font-size:var(--t-micro); font-family:var(--f-mono); letter-spacing:.08em;
  text-transform:uppercase; }
.ap-demo { width:40px; height:30px; background:var(--surface); border:var(--bw) solid var(--line-strong); }
.ap-demo[data-r="sharp"] { border-radius:2px; }
.ap-demo[data-r="soft"]  { border-radius:7px; }
.ap-demo[data-r="cloud"] { border-radius:14px; }
.ap-demo[data-d="flat"]   { border-radius:var(--radius); }
.ap-demo[data-d="raised"] { border-radius:var(--radius); box-shadow:4px 4px 0 var(--accent); margin:-2px 4px 4px -2px; }
.ap-demo[data-d="airy"]   { border-radius:var(--radius); box-shadow:0 7px 14px var(--shadow); border-color:var(--line); }

/* Palettes as what they ARE: three of their own colours, in the mode you are
   actually in. A name and a single dot cannot tell you that Terminal has no
   second hue in it. */
.ap-pals { display:grid; grid-template-columns:repeat(2,1fr); gap:var(--s-4); }
.ap-pal { display:flex; align-items:center; gap:var(--s-4); padding:var(--s-4);
  cursor:pointer; font:inherit; color:var(--ink); text-align:left;
  background:var(--surface-2); border:var(--bw) solid var(--line); border-radius:var(--radius); }
.ap-pal:hover { border-color:var(--line-strong); }
.ap-pal.on { border-color:var(--accent); }
.ap-chips { display:flex; flex:0 0 auto; border-radius:3px; overflow:hidden;
  border:1px solid rgba(128,128,128,.35); }
.ap-chips i { display:block; width:9px; height:22px; }
.ap-pal-n { font-size:var(--t-sm); font-weight:600; }
.ap-note { font-size:var(--t-mono); font-family:var(--f-mono); color:var(--muted);
  margin-top:var(--s-6); line-height:1.5; }
.ap-reset { margin-top:var(--s-5); width:100%; }
