/* ========================================================== TYPEFACES ====
   All self-hosted, latin-subset woff2: no third-party request, nothing for
   the CSP to block, no render-blocking round trip. Licences in assets/fonts/.

   Classic · Softer (v84): four faces, one job each.
     Signika Negative (Anna Giedryś, SIL OFL; one variable file, 300-700) is
       drawn for light text on dark grounds: it carries the words.
     JetBrains Mono (JetBrains, SIL OFL; one variable file, 400-800) carries
       the table figures; its code ligatures are switched off with the body.
     VT323 (Peter Hull, SIL OFL) carries only the big figures in stat wells
       (the overview's six, Wyrm Picks' cards), like the game's own stat
       numerals.
     Alagard (Hewett Tsoi / Pix3M; pixel blackletter on a 16-pixel em) is the
       ONE display face, in both games and on the neutral pages. It is pixel
       art: only at 16, 20 or 32px (24px for the phone page title), never
       tracked, never faux-bold. Its range is the characters it draws; any
       other (an em dash, a curly quote) goes straight to the text face, so no
       second display file is ever fetched for one glyph.
   Signika and VT323 are Google Fonts' own latin files, byte for byte, and each
   unicode-range is Google's latin range for them.
   The faces v84 retired have no @font-face here, so no rule can fetch them;
   their files stay on disk for the older release folders, which still name
   them. Nothing preloads or precaches them.
   Where the display face may appear is set down with the DISPLAY TIER rules. */
@font-face{font-family:"Signika Negative";src:url("/assets/fonts/signika-negative-var.woff2") format("woff2");
  font-weight:300 700;font-style:normal;font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"JetBrains Mono";src:url("/assets/fonts/jetbrains-mono-var.woff2") format("woff2");
  font-weight:400 800;font-style:normal;font-display:swap}   /* the file's wght axis is 400-800 */
@font-face{font-family:"Alagard";src:url("/assets/fonts/alagard.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap;
  unicode-range:U+0020-007E,U+00A2-00A3,U+00A5,U+20AC}
@font-face{font-family:"VT323";src:url("/assets/fonts/vt323.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

/* ====================================================== DESIGN TOKENS ====
   One token system; components use these, never literals.
     1. :root          tokens no edition changes: type, shape, elevation,
                       the grain, game marks, indicator hues, motion
     2. RS3 edition    :root[data-theme=rs3] and the RS3 subtree hosts
     3. OSRS edition   :root[data-theme=osrs] and the OSRS subtree hosts; ALSO
                       the neutral edition: the bare :root, home, admin and
                       the sign-in card (#login)
     4. roles          what each primitive is FOR, on :root and every host
   Classic · Softer: the site dressed as the game's own interface windows.
   OSRS and RS3 are two EDITIONS of one skin. OSRS: brown stone with a faint
   grain, orange titles, yellow figures. RS3: slate metal, bronze trim, gold
   titles, cream figures. Only colours differ (plus the RS3 brushed title
   strip and bronze corner ticks, both token-driven); type, shape and layout
   are identical. The pages that show both games (home, admin) and the sign-in
   card wear the OSRS edition exactly (owner, v84: no separate neutral look),
   so one rule serves both and they cannot drift apart.
   app.js stamps <html data-theme> at boot and in setGame(); every page's
   inline head script stamps data-theme and data-page before first paint.
   Home and admin get a data-theme too, which is why rule 3 comes AFTER rule
   2: at equal specificity, :root:is([data-page=home],[data-page=admin]) beats
   :root[data-theme=rs3] by order. Rules 2 and 3 must set the SAME list of
   tokens: rule 3 also matches the bare :root on RS3 pages, so a token only it
   set would leak into RS3.
   Subtree hosts: inside a neutral page, the home portal cards, the home
   totals cards and the admin game areas wear their own game's edition. The
   edition rules list them, and every alias (rule 4) is declared on every
   host, because a custom property resolves WHERE IT IS DECLARED: an alias set
   only on :root would carry the root's colour into the RS3 card. For the same
   reason, paint built from primitives (window bodies, title strips) is
   composed at the element, never stored in a :root token.
   The gold law: solid gold (--btn-*) is the primary action, nothing else. */
:root{
  /* ---- type ---- */
  --sans:"Signika Negative","Trebuchet MS",system-ui,-apple-system,"Segoe UI",sans-serif;
  --mono:"JetBrains Mono",ui-monospace,"Cascadia Code",Menlo,monospace;
  --pix:"VT323","Lucida Console",ui-monospace,monospace;   /* the stat wells' big figures only */
  /* The one display face. Its fallback is the text face, never another
     display file: one would be DOWNLOADED just to draw an em dash. */
  --display:"Alagard","Signika Negative","Trebuchet MS",system-ui,sans-serif;
  /* Alagard's three sizes. It is drawn on a 16-pixel em (1024 units, a 64-unit
     grid), so it is pixel-exact where size x devicePixelRatio / 16 is whole:
     32px at 1x, 1.5x, 2x and 3x; 16px at 1x, 2x and 3x. 20px is exact at none
     of them but is the approved window-title size (owner, from 1x renders). */
  --dt-s:16px;   /* small headings inside a panel */
  --dt-m:20px;   /* every title in a title strip */
  --dt-l:32px;   /* page titles, gate titles, the sign-in title, the home hero */
  /* Seven steps, one unit:
     1 micro-label · 2 meta and units · 3 secondary UI · 4 table body
     5 body · 6 heading and window title · 7 the big stat figures.
     Signika Negative is wider and taller than the v83 text face it replaced,
     so the reading steps sit half a step lower. Step 1 (11px) is the floor: no
     text anywhere is smaller (look-rules.test.mjs). The auth card deliberately
     opts out: it scales in em from one viewport-keyed knob (15px floor,
     SIGN-IN) so the whole panel resizes as one unit. Do not tokenise it. */
  --fs-1:11px; --fs-2:12px; --fs-3:13px; --fs-4:15px;
  --fs-5:15.5px; --fs-5b:16px; --fs-6:20px; --fs-7:27px;
  /* Roles the steps do not name. */
  --fs-num:14.5px;   /* mono figures inside 15px table rows */
  --fs-nav:14.5px;   /* header navigation tabs */
  --fs-lede:15.5px;  /* the one-line description under a page title (the title is --dt-l) */
  /* ---- shape ---- Square corners everywhere, as the game's windows are.
     Written once; no edition changes them. */
  --panel-radius:0; --r-1:0; --r-2:0; --r-3:0; --r-4:0; --r-pill:0;
  /* ---- elevation ---- A window is a pair of 1px hairlines (lighter top-left,
     darker bottom-right) on one soft drop: no black ring, no catchlight.
     Popovers and modals keep the deeper drops. --edge (the old top catchlight)
     is an EMPTY shadow, not `none`: it sits inside shadow lists
     (var(--edge),var(--sh-2)), where `none` would void the whole declaration. */
  --panel-shadow:0 6px 14px -8px rgba(0,0,0,.65);
  --edge:0 0 transparent;
  --sh-1:0 4px 13px -6px rgba(0,0,0,.78);
  --sh-2:0 10px 28px -12px rgba(0,0,0,.82);
  --sh-3:0 24px 54px -18px rgba(0,0,0,.9);
  /* ---- grain ---- Fine grain over slow mottling, grey so it suits stone and
     metal alike. Tiled at 240px on windows, strips, the header and footer,
     and (OSRS only) the page. */
  --tex:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Cfilter id='b'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.03' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23b)' opacity='.12'/%3E%3Crect width='240' height='240' filter='url(%23a)' opacity='.075'/%3E%3C/svg%3E");
  /* ---- marks that name a game ---- On the neutral pages (home chart lines
     and legend, typeahead game tags, admin marks): OSRS orange, RS3 steel
     blue (the RS3 open-tab hue; gold sits too close to orange for two chart
     lines). On the neutral (= OSRS) stone the orange is 5.6:1, the steel blue
     only 4.7:1 (4.2 on a window's top, 4.0 on a hovered row or a lifted
     face). So the marks colour small TEXT only on a well (the typeahead's
     game tags, 6.8:1); elsewhere a game is named by a line, a square swatch
     or a bar beside words in the ink (home's chart legend and totals, the
     admin nav, tiles and open section), or by a 20px title on the page
     (the admin areas', 7.5:1). */
  --accent-osrs:#ff981f; --accent-rs3:#6aa6e0;
  /* ---- chart ---- chartColors() in app.js reads these once per draw; the
     .t-leg legend chips and the canvas must stay in lockstep through them.
     Indicator hues are identical in every edition: an indicator must not
     change meaning per game, nor look like a level or like the price. MA90 is
     a neutral grey; bid/ask are teal/pink AND dashed, so no two lines share a
     look. The price, grid and label hues are each edition's. */
  --ch-res:#af95df; --ch-sup:#6ebe80; --ch-exit:#e8796e; --ch-proj:#a99e7f;
  --ch-bid:#4fd1c5; --ch-ask:#ff8fa3;
  --ch-sma7:#62b6e0; --ch-sma30:#e08fcf; --ch-sma90:#cfcfcf; --ch-rsi:#bda0ff;
  /* ---- motion ---- Four durations by role, three easings. Never animate
     `all`, never width/height: a 250-row table cannot afford layout animation. */
  --dur-1:110ms; --dur-2:180ms; --dur-3:240ms; --dur-4:380ms;
  --ease-out:cubic-bezier(.22,.61,.36,1);
  --ease-emph:cubic-bezier(.16,.84,.28,1);
  --ease-in:cubic-bezier(.45,0,1,1);
}
/* RS3: slate-blue metal, bronze trim, gold titles, cream figures. A deep
   blue-black page under the metal windows, with no grain on the page; its
   fade is painted once (no-repeat) and --page carries on below it, so no seam
   appears every screen-height on a long page. */
:root[data-theme="rs3"],.adm-area[data-game="rs3"],.home-rs3-column,.home-total.rs3{
  --page:#04070b;
  --page-paint:radial-gradient(1400px 700px at 50% -8%,rgba(120,170,220,.09),transparent 62%) no-repeat,
    linear-gradient(180deg,#0a1119,#04070b 60%) no-repeat;
  /* surfaces: window metal, the title strip (top, mid, bottom; brushed), the
     footer ledge, wells, the column-head band, the alternating row bands */
  --stone:#1a2633; --stone-top:#213042;
  --bar-top:#2f4257; --bar-mid:#22344a; --bar-bot:#1b2938;
  /* the title strip's top layers (PANELS): brushed steel, no grain */
  --strip-brush:repeating-linear-gradient(180deg,rgba(255,255,255,.02) 0 1px,rgba(255,255,255,0) 1px 3px);
  --strip-grain:none;
  --foot-top:#152130; --foot-bot:#0c141d;
  --well:#0a1017; --head-band:#0e1822;
  --row-a:#132030; --row-stripe:#182838; --row-hover:#22374f;
  /* lines: the window hairlines; a muted bronze divider under each title strip
     and rule under the header / over the footer; slate under column heads; the
     1px line round wells and slots */
  --edge-hi:#3e5167; --edge-lo:#020407;
  --div:#7c6136; --div2:#2c3d51; --rule:#8a6c3a; --inset:rgba(0,0,0,.5);
  --line:#0f1925; --line-strong:#384a5e; --row-line:rgba(0,0,0,.35); --row-line2:rgba(0,0,0,.35);
  /* flat interface faces; the open tab (a deep blue a clear step brighter than
     the idle slate, with a warm 1px edge); the gold action button */
  --face:#203041; --face-hover:#293b50; --face-hi:#3a4e64; --face-edge:#0f1925; --face-off:#142030;
  --on-fill:#234870; --on-edge:#b08a46; --on-ink:#ffe8a8;
  --btn-top:#f2d07a; --btn-bot:#d2a042; --btn-edge:#8a6326; --btn-hi:rgba(255,246,214,.6); --btn-ink:#1a1206;
  --btn-hov-top:#fbe09c; --btn-hov-bot:#e0b25a;
  --ring:#4d6480;     /* the one thin ring round each orb */
  --corner:#9c7b3e;   /* bronze corner ticks, no brighter than the other bronze */
  /* text: titles, figures, item names and column heads, body steps */
  --title:#f0c35c; --title-hot:#ffe39a; --fig:#f5dc8f; --name:#ece6d6;
  --ink:#ece6d6; --dim:#c9cdcf; --faint:#a1adb9; --flat:#a3adb7;
  --gold:#ddae4c; --gold-quiet:#f0c35c; --gold-bg:rgba(240,195,92,.13); --emph:#ffe39a; --on-gold:#1a1206;
  /* other grounds */
  --panel:#132030; --panel2:#182838; --input-bg:#070b10; --inset-bg:#070b10;
  --skel-sheen:#26394f; --backdrop:rgba(3,3,4,.78);
  /* direction: a gain is green and a loss red in both games; zero movement is
     not a gain (--flat). Chips are a soft tint of the row, never lighter than
     it. Loss red is a step lighter than the approved #ff7065 so it keeps 4.5:1
     on a hovered row. Never put signed text on the open-tab fill: 3.5-3.8:1
     whatever the red. */
  --up:#62de6b; --up-bg:#15301c; --down:#ff7d72; --down-bg:#3a161a;
  --chip-up:rgba(20,96,34,.36); --chip-down:rgba(110,16,16,.42); --chip-flat:rgba(0,0,0,.2);
  --warn:#ee9a52; --warn-bg:rgba(238,154,82,.13);
  /* the accent (paper.js reads --theme-accent) and the overview orbs */
  --theme-accent:#f0c35c;
  --orb-a:#4f6f8f; --orb-b:#1f9fc4; --orb-c:#d89a1c;
  /* chart */
  --ch-price:#f5dc8f; --ch-grid:#16263a; --ch-label:#a1adb9; --ch-fill:rgba(245,220,143,.10);
  --ch-tag-bg:rgba(4,7,11,.94); --ch-cross:rgba(236,230,214,.44);
  scrollbar-color:#384a5e var(--page);
}
/* OSRS: brown-grey stone with a faint grain, orange titles, yellow figures.
   Also the neutral edition (the bare :root default, home and admin whatever
   game the head script stamped, the sign-in card), so it stays AFTER RS3; see
   the section head. */
:root,:root[data-theme="osrs"],:root:is([data-page="home"],[data-page="admin"]),#login,
.adm-area[data-game="osrs"],.home-osrs-column,.home-total.osrs{
  --page:#120e0a;
  --page-paint:var(--tex) 0 0/240px 240px repeat,
    radial-gradient(1400px 700px at 50% -8%,rgba(255,152,31,.07),transparent 62%) no-repeat;
  /* surfaces (as RS3) */
  --stone:#3e3529; --stone-top:#463c2f;
  --bar-top:#372f25; --bar-mid:#30291f; --bar-bot:#29221a;
  /* the title strip's top layers: no brush (an empty layer), the grain */
  --strip-brush:linear-gradient(transparent,transparent);
  --strip-grain:var(--tex);
  --foot-top:#2e271d; --foot-bot:#241e16;
  --well:#1d1812; --head-band:#2a231a;
  --row-a:#2e271d; --row-stripe:#372e23; --row-hover:#4b3e2c;
  /* lines (as RS3). --line is mostly control borders and separators across
     the site, so it is the face edge, a mid-dark stone: near-black would read
     as a ring round every control */
  --edge-hi:#5a4d3a; --edge-lo:#0b0805;
  --div:#4f4334; --div2:#463b2d; --rule:#5c4f3c; --inset:rgba(0,0,0,.42);
  --line:#261e15; --line-strong:#5c4f3c; --row-line:rgba(0,0,0,.30); --row-line2:rgba(0,0,0,.30);
  /* faces, the open tab (a calm dark red with a warm 1px edge), the gold
     action button */
  --face:#3f3529; --face-hover:#4a3f31; --face-hi:#5b4e3b; --face-edge:#261e15; --face-off:#2c251c;
  --on-fill:#5a2013; --on-edge:#a14f2c; --on-ink:#ffe14a;
  --btn-top:#f8c552; --btn-bot:#e39a22; --btn-edge:#9c6110; --btn-hi:rgba(255,241,190,.6); --btn-ink:#1e1103;
  --btn-hov-top:#ffd877; --btn-hov-bot:#f0ac38;
  --ring:#6a5a43;
  --corner:transparent;   /* OSRS windows are plain matte stone: no metal corners */
  /* text */
  --title:#ff981f; --title-hot:#ffd84d; --fig:#ffe14a; --name:#f4ead3;
  --ink:#f4ead3; --dim:#ddcfb0; --faint:#bcab8a; --flat:#b9ad97;
  --gold:#f2a92c; --gold-quiet:#ff981f; --gold-bg:rgba(255,152,31,.14); --emph:#ffef5a; --on-gold:#1e1103;
  /* other grounds */
  --panel:#2a231a; --panel2:#2e271d; --input-bg:#15110c; --inset-bg:#15110c;
  --skel-sheen:#4a3f30; --backdrop:rgba(11,8,4,.8);
  /* direction (as RS3). Loss red is a step lighter than the approved #ff6b57,
     which measured 4.29:1 on bare stone and 3.70:1 on a hovered row */
  --up:#5fe05a; --up-bg:#1c3518; --down:#ff8a76; --down-bg:#3d1912;
  --chip-up:rgba(24,96,18,.38); --chip-down:rgba(96,14,5,.45); --chip-flat:rgba(0,0,0,.16);
  /* lifted a step from the old #f08f4a, which fell to 4.3:1 on a hovered row */
  --warn:#f39752; --warn-bg:rgba(243,151,82,.13);
  /* the accent and the overview orbs: a neutral stone orb for the plain
     counts, blue and gold for the others */
  --theme-accent:#ff981f;
  --orb-a:#8c7a52; --orb-b:#1f9fc4; --orb-c:#d89a1c;
  /* chart */
  --ch-price:#ffe14a; --ch-grid:#2f281e; --ch-label:#bcab8a; --ch-fill:rgba(255,225,74,.10);
  --ch-tag-bg:rgba(18,14,10,.94); --ch-cross:rgba(244,234,211,.44);
  scrollbar-color:#5c4f3c var(--page);
}
/* Roles: what each primitive is FOR. One rule on :root and on every subtree
   host, so each host re-resolves the aliases from its own edition's
   primitives (see the section head). */
:root,#login,.adm-area[data-game],.home-game-column,.home-total{
  --th-ink:var(--name);         /* column heads */
  --accent:var(--gold);         /* checkbox accent, admin chart line, progress fills */
  --surface-top:var(--stone-top); --surface-bottom:var(--stone);
  --chrome-top:var(--stone-top); --chrome-bottom:var(--stone);
  --chrome-rule:linear-gradient(var(--rule),var(--rule));
  --ico-bg:var(--well); --seg-on:var(--on-fill);
  --ch-up:var(--up); --ch-down:var(--down); --ch-ring:var(--page);
  /* quiet candles (no trades, the last price held): the edition's muted
     chart ink, drawn dotted (line) or as a thin flat mark (candles) */
  --ch-quiet:var(--ch-label);
}
*{box-sizing:border-box}
/* The hidden attribute must beat every display rule (v1 lesson: #loginview's
   flex kept the login form on screen after signing in). */
[hidden]{display:none!important}
html,body{margin:0;height:100%}
/* Use a real scrollbar only when needed. Reserving an empty lane on short
   pages left the header/footer rule and background short of the right edge. */
html{scrollbar-gutter:auto}
/* The page paint is one token per edition, and each layer carries its own
   repeat INSIDE it (OSRS: the grain tiles, its glow does not; RS3: a glow
   and a fade painted once). So no background-repeat longhand here: one would
   stop the OSRS grain tiling. Below the painted layers the ground is --page. */
body{background:var(--page-paint);background-color:var(--page);color:var(--ink);font-family:var(--sans);
  font-size:var(--fs-5);line-height:1.5;font-variant-numeric:lining-nums;font-variant-ligatures:no-contextual;
  -webkit-font-smoothing:antialiased}
/* Form controls take the document's face AND its figure and ligature settings
   (the UA font shorthand would otherwise reset them to old-style figures). */
button,select,input{font-family:inherit;font-size:var(--fs-5);font-variant-numeric:inherit;
  font-variant-ligatures:inherit;color:var(--ink)}
/* An interface button is a flat face: a 1px edge a step darker than the face
   and a 1px highlight along its top; no ring, no glow. Gold actions, trays
   and link-like buttons paint themselves. */
button{cursor:pointer;border-radius:var(--r-3);border:1px solid var(--face-edge);
  background:var(--face);box-shadow:inset 0 1px 0 var(--face-hi);padding:8px 14px}
/* A plain face lifts on hover, its label to the bright yellow, its edge
   unchanged. :where() holds it at class level (the :hover alone counts), as
   the press below: it beats the element rule above, and any classed button
   that paints itself (gold, a tray, a ghost, a row), all of them later in
   the sheet, keeps its own paint. Inside :where() it counted for nothing
   and lost to `button` itself, so no plain face ever lifted. */
:where(button):hover{background-color:var(--face-hover);color:var(--emph)}
/* A real disabled treatment: opacity:.4 dropped labels under 3:1. Colour and
   surface carry the state instead (a dimmer face without its highlight, like
   the header's locked tools), so it stays legible while clearly inert. */
button:is(:disabled,[aria-disabled="true"]){cursor:default;color:var(--faint);background:var(--face-off);
  border-color:var(--face-edge);box-shadow:none;filter:none}
/* Keyboard focus is one 2px ring in the action gold on every control, link and
   card, here and in the components (one colour site-wide). */
button:focus-visible,select:focus-visible,input:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
/* Links, link-cards and the brand get the same gold ring as controls (they
   showed the UA blue ring); text selection stops being UA blue on a gold UI. */
a:focus-visible,.pick:focus-visible,.cat-tile:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
a:not([class]):focus-visible{border-radius:var(--r-1)}
.brand:focus-visible{outline-offset:4px}
::selection{background:var(--gold);color:var(--on-gold)}
input[type=checkbox],input[type=radio]{accent-color:var(--accent)}
button.ghost{background:transparent}
/* A text box is recessed: a dark field, one 1px edge, a 1px shade along its
   top; focus turns the edge to the title colour. */
select,input{background:var(--input-bg);border:1px solid var(--face-edge);border-radius:var(--r-3);
  box-shadow:inset 0 1px 0 var(--inset);padding:8px 10px}
/* :not(:focus-visible) is load-bearing — the bare `outline:none` that used to be
   here deleted the ONLY focus ring in the app, leaving keyboard users a 1px
   border tint. Mouse focus stays clean; keyboard focus keeps the ring above. */
input:focus:not(:focus-visible),select:focus:not(:focus-visible){outline:none}
input:focus,select:focus{border-color:var(--title)}
::placeholder{color:var(--faint);opacity:1}
/* Links default to the action gold (they fell to UA blue wherever a component
   didn't set its own colour — e.g. inside prose in the gate cards). */
a{color:var(--gold)} a:hover{color:var(--emph)}
.num{font-family:var(--mono);font-variant-numeric:lining-nums tabular-nums}
.up{color:var(--up)} .down{color:var(--down)}
/* Neutral delta. Zero movement is not a gain — app.js picks this class at 0. */
.flat{color:var(--flat)}

/* ---- interaction states -------------------------------------------------
   One button family (CONTROLS): gold actions brighten, faces lift, ghosts
   gain a face, everything presses. A face (a tab, a game, a tray button, a
   link drawn as a button) lifts to the lighter face, its label to the bright
   yellow, its edge unchanged; the open tab and a chosen tray face stay as
   they are. A face that paints itself in its own section is listed here, so
   its section never needs a hover of its own. A red (danger) face keeps its
   red hover with its own rule: loss red on the lifted face is under 4.5:1. */
.tabs :is(button,a):not(.on):hover,.games :is(button,a):not(.on):hover,
:is(.ch-tf,.ch-chip,.ch-mode,.ch-ci,.wy-rng,.home-range-tabs button,.home-view-tabs button,.pt-chart-tools button,.pt-side button,
  .pt-ledger-tabs button):not(.on,:disabled,[aria-disabled="true"]):hover,
:is(.wy-seg-opts,.wy-yn) label:hover>input:not(:checked)+span,.wy-checks label:not(:has(input:checked)):hover,
.adm-opt:not(:has(input:checked,input:disabled)):hover,
:is(.doc-links a,.ca-more a,.home-game-actions a,.home-tool,.pager a,.catalogue-page-links>button,.wl-follow,.t-back,.t-burger,
  .wy-vchip,.wy-mod:not([aria-disabled="true"]),.wy-pre,.wy-add,.wy-ungroup,.wy-btn,.wy-sumbtn,.wy-pick-adv,
  button.ghost:not(.wy-danger)):hover{
  background:var(--face-hover);color:var(--emph);border-color:var(--face-edge)}
.mclose:hover{color:var(--ink);background:var(--face-hover)}
/* The secondary is a face: it lifts like one, its gold label to the bright
   yellow. */
.msecondary:hover{border-color:var(--face-edge);color:var(--emph);background:var(--face-hover)}
/* The gold action buttons (Sign in, .mprimary, .t-follow until the item is
   followed, the end tile's "All items", a house panel's call to action, which
   lights with its whole panel) brighten to the lighter pair of golds; the
   .on chip's own hover (unfollow → red) is defined with the .t-follow rules. */
.btn-signin:hover,.mprimary:hover,.t-follow:not(.on):hover,.cat-all .ca-go:hover,.mw-house:hover .mw-house-cta,
.contact-card .mail:hover{
  background:linear-gradient(180deg,var(--btn-hov-top),var(--btn-hov-bot));border-color:var(--btn-edge);color:var(--btn-ink)}
/* Every button presses, in every edition (touch has no hover to fall back
   on): it drops a pixel, and a plain face sinks to the dimmer face with a
   shade along its top. :where() holds the sink at class level, so a classed
   button that paints itself (gold, a tray, a ghost) keeps its paint and only
   drops. */
button:active{transform:translateY(1px)}
:where(button):active{background-color:var(--face-off);box-shadow:inset 0 1px 0 rgba(0,0,0,.35)}
.mprimary:active{filter:brightness(.94)}
button,tbody tr,.pick,.cat-tile,.t-item{
  -webkit-tap-highlight-color:var(--gold-bg)}
/* Motion: explicit property lists only — never `all`, never width/height. */
button,.tabs :is(button,a),.games :is(button,a),.menu button,
.btn-signin,.mprimary,.msecondary,.t-follow,.mclose,.acct-chip,
select,input,tbody tr,.t-item,.pick,.cat-tile,a{
  transition:background-color var(--dur-1) var(--ease-out),
             color var(--dur-1) var(--ease-out),
             border-color var(--dur-2) var(--ease-out),
             box-shadow var(--dur-2) var(--ease-out),
             transform var(--dur-1) var(--ease-out),
             filter var(--dur-1) var(--ease-out)}
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:1ms!important;animation-duration:1ms!important}
}

/* ============================================================= PANELS ====
   ONE frame for every window, card and tile: the game's interface window.
   A pair of 1px hairlines (--edge-hi along the top and left, --edge-lo along
   the bottom and right), the grain over a stone body lit from the top, and
   one soft drop; no ring, no catchlight. The body is composed HERE, from the
   primitives, at the element: a subtree host (a home card, an admin area,
   DESIGN TOKENS) re-declares --stone, and its windows must paint that stone,
   which a gradient stored in a :root token would not. Every member matches at
   class specificity, so a component's own state rules win without
   !important.
   A tint, hover or state sets --panel-body (the whole body gradient) and, for
   a toned frame, --panel-hi / --panel-lo, ON THE MEMBER ITSELF; never
   `background:`, which would drop the grain. Never on :root or a container
   either: they inherit, and a member inside would wear the tint.
   A card whose words sit straight on its body (not on a well, a row or a
   strip, as the overview's always do) sets --panel-grain:none on itself: the
   grain lifts the stone's rendered luminance by about half (measured on the
   pixels: the OSRS title colour on stone-top, 5.0:1 flat, reads 4.1:1 under
   the grain, the faint words 4.0:1), which would put them under AA. Its
   frame, body and hover are unchanged (CATEGORIES, LIST CARDS, the drawers
   in MARKET).
   A table sitting inside a panel drops its own frame: no double frames. */
:is(.board,.cat-tile,.list-card,.perf-grid,.wy-cl-sum,.perf-note,.perf-t,.wy-edit,.wy-pane,.wy-admin,.wy-item,
  .pt-panel,.pt-cards,.gate,.pick,.t-lock,.t-panel,.t-stats,.t-sim,.list-empty-related,.seo-related,.modal,.tldr,
  .contact-card,.doc-links,.home-total,.home-game-column,.home-value-panel,.wl-pick,.mw-house,.adm-nav),
:where(.market.overview)>.pulse,.pt-modal>:where(div),
.seo-list-links>:where(a),:is(.about-feats,.about-games)>:where(li){
  border:1px solid;border-color:var(--panel-hi,var(--edge-hi)) var(--panel-lo,var(--edge-lo))
    var(--panel-lo,var(--edge-lo)) var(--panel-hi,var(--edge-hi));
  border-radius:var(--panel-radius);
  background:var(--panel-grain,var(--tex)) 0 0/240px 240px,var(--panel-body,linear-gradient(180deg,var(--stone-top),var(--stone) 140px));
  background-color:var(--stone);
  box-shadow:var(--panel-shadow)}
:is(.board,.pt-panel,.adm) .perf-t{border:0;border-radius:0;background:none;box-shadow:none}
/* Cards that are links lift on hover: the body brightens to the hovered
   row's stone; the frame stays. House panels are not in the list: their call
   to action brightens instead (HOUSE PANELS). */
:is(.cat-tile,.list-card,.pick,.wy-item,.wl-pick):hover,.seo-list-links>a:hover{
  --panel-body:linear-gradient(180deg,var(--row-hover),var(--stone) 140px)}

/* RS3 corner ticks. The RS3 interface trims its windows in metal, so every
   window (not the small cards and tiles: too busy) carries a 12x2px L of
   --corner over each corner of its frame. One rule for every edition:
   --corner is transparent in OSRS and on the neutral pages, so an RS3 home
   card or admin area gets its ticks from its own edition. The ticks sit
   over the hairlines (inset:-1px); a window that clips its overflow keeps
   them just inside its frame (inset:0). */
:is(.board,:where(.market.overview)>.pulse,.perf-grid,.wy-cl-sum,.wy-pane,.wy-edit,.wy-admin,.t-panel,.t-lock,.t-stats,.t-sim,.gate,
  .modal,.tldr,.contact-card,.home-value-panel,.home-total,.home-game-column,.pt-panel){position:relative}
:is(.board,:where(.market.overview)>.pulse,.perf-grid,.wy-cl-sum,.wy-pane,.wy-edit,.wy-admin,.t-panel,.t-lock,.t-stats,.t-sim,.gate,
  .modal,.tldr,.contact-card,.home-value-panel,.home-total,.home-game-column,.pt-panel)::before{
  --t:linear-gradient(var(--corner),var(--corner));
  content:"";position:absolute;inset:-1px;z-index:2;pointer-events:none;
  background:var(--t) left top/12px 2px,var(--t) left top/2px 12px,var(--t) right top/12px 2px,var(--t) right top/2px 12px,
    var(--t) left bottom/12px 2px,var(--t) left bottom/2px 12px,var(--t) right bottom/12px 2px,var(--t) right bottom/2px 12px;
  background-repeat:no-repeat}
:is(.board,.pt-panel,.home-value-panel,.home-game-column)::before{inset:0}

/* Title strips: a window's head is the game's darker title bar under its top
   hairline, closed by one quiet divider (RS3: brushed steel and a muted
   bronze divider; the brush and grain layers are edition tokens). Painted
   here from the primitives, as the body is; the title in it, its size and
   the strip's layout stay with the component, and a strip inside a padded
   window pulls out to the frame with negative margins in its own rule. Class
   specificity, like the frame (:where() holds the qualifiers), so print and
   a component's state rules can still repaint it. A strip built of two
   stacked rows (the item list's filter row over its label, ITEM TERMINAL)
   gives each row its half of the bar through --strip-body, on the row
   itself, so the bar runs on unbroken. */
:is(:where(.board) .b-head,.wy-pane-head,:where(.wy-res)>.wy-res-head,.adm-head,.home-value-head,.home-updatebar,
  .ht-head,.pt-panel-head,.pt-market-head,.pt-ledger-tabs,.t-search,.t-lhead,:where(.t-panel,.t-lock,.t-sim)>.t-shead:where(:first-child),
  :where(.tldr)>h2:where(:first-child),.wy-filters-toggle){
  background:var(--strip-brush),var(--strip-grain) 0 0/240px 240px,
    var(--strip-body,linear-gradient(180deg,var(--bar-top),var(--bar-mid) 45%,var(--bar-bot)));
  background-color:var(--bar-bot);box-shadow:inset 0 -1px 0 var(--div)}

/* =============================================================== HEADER ====
   The header is viewport chrome, not part of any page or advertising grid.
   One markup on every page (the index.html shell, which also carries every
   SEO page, the static pages and 404) and one size: 58px at every width with
   a 48px logo, in one row from 1280px. Narrower, the section tabs take a
   second row; on phones they become the fixed bottom nav. The neutral pages
   (home, admin) hide the game switch and the game-scoped tabs. Layering: the
   header (55) > the phone bottom nav (45) > the detail overlay (40), so the
   chrome works from item pages too; the account dropdown (.menu, 30) lives
   inside the header's stacking context. app.js measures the live height into
   --chrome-h for the overlay and rails.
   Paint: a ledge of the edition's stone (RS3: slate) with the grain, one
   --rule line along its foot (a stone ledge on OSRS, a bronze rule on RS3)
   and a soft drop. Its controls are the interface faces: flat tabs, the game
   switch in a well, the status slot, a plain text box, the gold Sign in. */
.hdr{position:sticky;top:0;z-index:55;display:flex;align-items:center;gap:6px 10px;min-height:58px;
  /* viewport-fit=cover + a translucent status bar (index.html) means the bar
     draws UNDER the notch unless it pads the top inset itself. */
  padding:calc(5px + env(safe-area-inset-top)) max(18px,env(safe-area-inset-right)) 5px max(18px,env(safe-area-inset-left));
  background:var(--chrome-rule) left bottom/100% 1px no-repeat,var(--tex) 0 0/240px 240px,
    linear-gradient(180deg,var(--chrome-top),var(--chrome-bottom));background-color:var(--chrome-bottom);
  box-shadow:0 6px 16px -10px rgba(0,0,0,.75)}
@media(min-width:1544px){.hdr{padding-left:max(22px,env(safe-area-inset-left));padding-right:max(22px,env(safe-area-inset-right))}}
/* The owner's complete v2 wordmark, dragon and market orb, scaled as one unit
   and never cropped. The 512×256 WebP keeps the 48px render sharp; the
   1774×887 original stays in design-assets/brand. */
.brand{display:flex;align-items:center;flex:none}
.brand-logo{display:block;height:48px;width:auto;filter:drop-shadow(0 2px 6px rgba(0,0,0,.5))}
/* Game switch: a shallow well holding two small faces. The selected game is
   the open tab; the other is plain idle text, never a colour of its own. */
.games{display:flex;flex:none;gap:2px;padding:2px;border:1px solid var(--face-edge);
  border-radius:var(--r-3);background:var(--well)}
/* The shell ships the switch hidden for the neutral home and admin. A game
   page (the head script stamps data-page before first paint) shows it at once,
   as app.js will, so the section tabs never jump right when the app starts. */
:root:is([data-page="app"],[data-page="paper-trading"]) #games[hidden]{display:flex!important}
/* A face: a 1px edge a step darker than the face and a 1px highlight along
   its top; a plain label, no shadow. The 1px edge stands in for a pixel of
   the old padding, so the switch keeps its size. */
.games :is(button,a){display:inline-flex;align-items:center;padding:3px 8px;border:1px solid var(--face-edge);border-radius:var(--r-2);
  background:var(--face);box-shadow:inset 0 1px 0 var(--face-hi);color:var(--dim);text-shadow:none;
  font-size:var(--fs-nav);font-weight:600;line-height:1.5;text-decoration:none}
/* Section tabs: text only on desktop, one 38px height whether a tab holds one
   line or two (a locked tool stacks its COMING SOON tag under the label).
   Each tab is a face, as the game switch's buttons are; its 1px edge stands
   in for a pixel of side padding, so the row keeps its measured widths (the
   status pill's room at 1280-1366 and the one-row fit at 1280). */
.hdr>.tabs{display:flex;flex:none;align-items:center;gap:3px;min-width:0}
.hdr>.tabs>:is(button,a){position:relative;display:inline-flex;flex-direction:column;align-items:center;justify-content:center;
  height:38px;padding:0 8px;border:1px solid var(--face-edge);border-radius:var(--r-2);background:var(--face);
  box-shadow:inset 0 1px 0 var(--face-hi);text-shadow:none;
  color:var(--dim);font-size:var(--fs-nav);font-weight:500;line-height:1.15;white-space:nowrap;text-decoration:none}
.tabs .ico{display:none}
.tabs .lk{display:inline-block;margin-left:.3em}
.tabs .lk .ico{display:inline-block;width:.8em;height:.8em;margin:0;vertical-align:-.05em}
/* Locked tools: a dimmer face without its highlight (a disabled interface
   button) with a faint slow sheen; the name in the idle tone, only the small
   COMING SOON tag in the title colour. Shown while the tab is a teaser
   (app.js syncAdminChrome). Not while hovered: it lifts like every face
   (interaction states), which this rule would otherwise out-rank. */
.hdr>.tabs>.coming-soon{overflow:hidden}
.hdr>.tabs>.coming-soon:not(.on,:hover){color:var(--dim);border-color:var(--face-edge);background:var(--face-off);box-shadow:none}
.hdr>.tabs>.coming-soon::before{content:"";position:absolute;inset:-20% auto -20% -42%;width:28%;
  pointer-events:none;transform:skewX(-18deg);opacity:0;
  background:linear-gradient(90deg,transparent,rgba(255,225,140,.07),transparent);
  animation:soon-sheen 4.5s ease-in-out infinite}
.tabs .soon-tag{display:none}
.tabs .coming-soon .soon-tag{display:block;margin-top:1px;color:var(--title);
  font:600 var(--fs-1)/1 var(--sans);letter-spacing:.05em}
@keyframes soon-sheen{0%,70%{left:-42%;opacity:0}76%{opacity:.8}92%{left:120%;opacity:0}100%{left:120%;opacity:0}}
@media(prefers-reduced-motion:reduce){.hdr>.tabs>.coming-soon::before{animation:none}}
/* The selected game and the current section (a locked one too): the open
   tab, a calm dark-red fill (RS3: deep blue) with a warm 1px edge and a
   yellow label; no inner ring, no glow. Never signed text on it (RS3 loss
   red is 3.5-3.8:1 on the blue). */
.games .on,.hdr>.tabs>.on{color:var(--on-ink);background:var(--on-fill);border-color:var(--on-edge);box-shadow:none}
/* Neutral pages hide the game-scoped tabs from first paint (the inline theme
   script stamps data-page before the stylesheet applies; app.js then sets
   [hidden]), and the tab group leaves the layout when no tab is visible. */
:root:is([data-page="home"],[data-page="admin"]) #tabs>[data-game-scoped]{display:none!important}
#tabs:not(:has(>:not([hidden]))),
:root:is([data-page="home"],[data-page="admin"]) #tabs:not(:has(>:not([hidden],[data-game-scoped]))){display:none}
/* Data-freshness pill, filling the space between the tabs and the search: a
   state dot and one line that ellipsises, down to the dot alone when the row
   is tight (the text stays readable to assistive tech). It is a shallow
   slot holding a minimap orb, one state per class, each written out so no
   state can mask another: green = feed current (OSRS: live prices <=12 min
   old; RS3: guide price <26 h); amber, with amber words = delayed; a plain
   stone orb = transient messages (lookups, errors); busy = the wyrm mascot.
   Home has no pill: it names no game. */
.hdr>.tools{container:hdr-tools/inline-size;display:flex;flex:1 1 0;align-items:center;min-width:34px}
:root[data-page="home"] .hdr>.tools{display:none}
.status{position:relative;display:block;max-width:100%;height:30px;padding:0 12px 0 31px;
  border:1px solid var(--face-edge);border-radius:var(--r-pill);background:var(--well);
  color:var(--dim);font-size:var(--fs-3);line-height:28px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* One fixed 16px slot for every state, so a state change never reflows the
   pill. Each orb is lit from its top left, inside one thin ring. */
.status::before{content:"";position:absolute;top:6px;left:8px;width:16px;height:16px;border-radius:50%;
  background:radial-gradient(circle at 35% 30%,#f4efe4 0 14%,#a39a8a 46%,#3d372f 100%);box-shadow:0 0 0 1px var(--ring);
  transition:box-shadow var(--dur-2) var(--ease-out)}
.status.live::before{background:radial-gradient(circle at 35% 30%,#d7ffc9 0 14%,#3fc449 46%,#11591a 100%);
  box-shadow:0 0 0 1px var(--ring),0 0 5px rgba(80,220,90,.35)}
.status.stale{color:var(--warn)}
.status.stale::before{background:radial-gradient(circle at 35% 30%,#ffe8c2 0 14%,#e8892e 46%,#6b3408 100%);
  box-shadow:0 0 0 1px var(--ring)}
/* busy: the orb gives way to the wyrm mascot, drawn whole (contain, no round
   clip, no ring) and softly pulsing while a scan or lookup runs. */
.status.busy::before{border-radius:0;box-shadow:none;background:url("/assets/hero-alpha.webp") center/contain no-repeat;
  animation:coinpulse 1.2s ease-in-out infinite}
@keyframes coinpulse{50%{opacity:.4}}
@media(prefers-reduced-motion:reduce){.status.busy::before{animation:none}}
@container hdr-tools (max-width:149px){.status{width:34px;padding:0;color:transparent}}
/* Before the line would cut its figure ("updated 25h ag…"), a narrow pill
   drops "· daily guide", then the game (the switch beside it names it). */
@container hdr-tools (max-width:279px){.status .st-x{display:none}}
@container hdr-tools (max-width:219px){.status .st-g{display:none}}
/* Search and account, pinned right. The search is one size per viewport on
   every page, so it never moves or resizes between pages. */
.hdr>.hdr-right{display:flex;flex:none;align-items:center;gap:8px;margin-left:auto}
.search-wrap{position:relative}
.hdr .search-wrap{width:clamp(190px,15vw,280px)}
/* A plain dark text box: the shared input (one 1px edge, a shade along its
   top, the title-colour edge on focus; base elements), at the header's
   38px. */
.hdr .search{width:100%;height:38px;padding:0 12px}
/* The typeahead is a small window (the PANELS hairlines and stone body on
   the deepest drop), anchored to the input's right edge so it can grow
   leftwards on desktop without leaving the viewport. A hovered or
   arrow-keyed row lifts, its name to the bright yellow. */
.search-dd{position:absolute;top:calc(100% + 6px);right:0;width:max(100%,320px);z-index:60;
  background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--stone-top),var(--stone));background-color:var(--stone);
  border:1px solid;border-color:var(--edge-hi) var(--edge-lo) var(--edge-lo) var(--edge-hi);border-radius:var(--r-3);
  box-shadow:var(--sh-3);max-height:min(380px,60vh);overflow-y:auto;padding:4px}
.search-dd .dd-row{display:flex;align-items:center;gap:9px;width:100%;text-align:left;color:var(--ink);
  background:none;border:none;box-shadow:none;padding:7px 9px;border-radius:var(--r-2)}
.search-dd .dd-row:hover,.search-dd .dd-row.on{background:var(--row-hover);color:var(--emph)}
.search-dd .dd-row .mi-ico{width:26px;height:26px;flex-shrink:0}
.search-dd .dd-row .mi-ico img{width:22px;height:22px}
.search-dd .dd-row>span:not(.mi-ico){min-width:0;flex:1}
.search-dd .dd-row span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.search-dd .dd-empty{color:var(--faint);font-size:var(--fs-3);padding:9px}
/* home searches both games: each result names its game in that game's mark
   (OSRS orange, RS3 steel blue; DESIGN TOKENS) on a small square well, the
   one ground the steel blue keeps AA on as small text (6.8:1). */
.search-dd .dd-game{flex:none;margin-left:auto;padding:2px 5px;border:1px solid var(--inset);border-radius:var(--r-1);
  background:var(--well);color:var(--faint);font:700 var(--fs-1)/1.2 var(--mono);letter-spacing:.04em}
.search-dd .dd-game.dd-osrs{color:var(--accent-osrs);border-color:color-mix(in srgb,var(--accent-osrs) 35%,var(--well))}
.search-dd .dd-game.dd-rs3{color:var(--accent-rs3);border-color:color-mix(in srgb,var(--accent-rs3) 35%,var(--well))}
/* Sign in is the header's one filled control: the primary action (gold law),
   the gold button: two stops, a darker-gold edge and a hairline highlight
   along its top; it brightens to the lighter pair on hover (interaction
   states, with the rest of the gold family). */
.acct-slot{display:flex;flex:none}
.btn-signin{display:inline-flex;align-items:center;justify-content:center;flex:none;height:38px;padding:0 18px;
  border:1px solid var(--btn-edge);border-radius:var(--r-3);background:linear-gradient(180deg,var(--btn-top),var(--btn-bot));
  box-shadow:inset 0 1px 0 var(--btn-hi);color:var(--btn-ink);text-shadow:none;
  font-size:var(--fs-nav);font-weight:700;white-space:nowrap;text-decoration:none}
/* Signed in: the account chip is a face (it lifts on hover, the name to the
   bright yellow); the initial sits in a small well. */
.acct{position:relative}
.acct-chip{display:flex;align-items:center;gap:8px;max-width:150px;height:38px;padding:0 10px 0 6px;
  border:1px solid var(--face-edge);border-radius:var(--r-3);background:var(--face);box-shadow:inset 0 1px 0 var(--face-hi);
  color:var(--ink);font-size:var(--fs-4);text-decoration:none}
.acct-chip:hover{color:var(--emph);border-color:var(--face-edge);background:var(--face-hover)}
.acct-chip .av{flex:none;width:24px;height:24px;border:1px solid var(--inset);border-radius:var(--r-2);background:var(--well);
  color:var(--title);display:flex;align-items:center;justify-content:center;font-weight:500;font-size:var(--fs-3)}
.acct-chip .nm{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acct-chip .cv{color:var(--faint);font-size:var(--fs-2)}
.acct-chip .cv.ico{width:12px;height:12px;margin-left:2px}
/* The account menu is a small window: the PANELS hairlines and stone body,
   on the deeper popover drop. */
.menu{position:absolute;top:44px;right:0;width:190px;
  background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--stone-top),var(--stone));background-color:var(--stone);
  border:1px solid;border-color:var(--edge-hi) var(--edge-lo) var(--edge-lo) var(--edge-hi);border-radius:var(--r-3);
  padding:6px;z-index:30;box-shadow:var(--edge),var(--sh-2)}
.menu[hidden]{display:none}
.menu button{display:flex;align-items:center;gap:9px;width:100%;text-align:left;background:transparent;
  border:none;padding:8px 10px;border-radius:var(--r-2);font-size:var(--fs-4);color:var(--dim);box-shadow:none}
.menu button .ico{color:var(--faint);width:16px;height:16px;margin-right:0}
.menu button:hover .ico{color:var(--gold)}
.menu button:hover{background:var(--row-hover);color:var(--emph)}
.menu .sep{height:1px;background:var(--div2);margin:5px 6px}
/* Below 1280px the tabs take their own row; so do an admin's three extra
   tabs below 1600px. The quiet divider (--div2) parts the two rows. */
@media(min-width:641px) and (max-width:1279px){
  .hdr{flex-wrap:wrap}
  .hdr>.tabs{order:5;flex:1 1 100%;flex-wrap:wrap;justify-content:center;padding-top:5px;
    border-top:1px solid var(--div2)}
}
@media(min-width:1280px) and (max-width:1599px){
  .hdr:has(#tabs>[data-mode="WyrmPicks"]:not([hidden])){flex-wrap:wrap}
  .hdr:has(#tabs>[data-mode="WyrmPicks"]:not([hidden]))>.tabs{order:5;flex:1 1 100%;justify-content:center;padding-top:5px;
    border-top:1px solid var(--div2)}
}
/* Up to 760px the search row spans the header under the logo row. */
@media(max-width:760px){
  .hdr{flex-wrap:wrap}
  .hdr>.hdr-right{order:4;flex:1 1 100%;margin-left:0;position:relative}
  .hdr .search-wrap{flex:1;width:auto;min-width:0;position:static}
  /* The typeahead spans the whole search row (anchored to .hdr-right above):
     a 320px panel hung off the input's right edge overhung the left edge of a
     375px phone, and the item icons were the part that got cut. */
  .search-dd{left:0;right:0;width:auto;top:calc(100% + 4px)}
}
/* Phones: the tabs become the app-style bottom nav: an opaque ledge of the
   header's stone with one --rule line along its top and one equal face per
   visible tab (the open tab as in the header). A locked tool shows its
   COMING SOON tag in its icon's place, two 11px lines in the icon's 20px
   slot, so the tag is readable and every cell keeps one height. */
@media(max-width:640px){
  .hdr{gap:8px;padding:calc(6px + env(safe-area-inset-top)) max(12px,env(safe-area-inset-right)) 6px max(12px,env(safe-area-inset-left))}
  .status{font-size:var(--fs-2)}
  .games :is(button,a){padding:3px 6px}
  /* Every cell stretches to the tallest (a locked tool's two-line name), so
     the faces' edges line up along the bar. */
  .hdr>.tabs{position:fixed;left:0;right:0;bottom:0;z-index:45;display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:3px;
    align-items:stretch;
    padding:4px calc(6px + env(safe-area-inset-right)) calc(4px + env(safe-area-inset-bottom)) calc(6px + env(safe-area-inset-left));
    background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--chrome-top),var(--chrome-bottom));background-color:var(--chrome-bottom);
    border-top:1px solid var(--rule);box-shadow:0 -6px 16px -8px rgba(0,0,0,.7)}
  /* No side padding and a hair of negative tracking: "Categories" needs the
     whole cell inside its 1px edges at 390px in the text face. The edge
     stands in for a pixel of the top padding. */
  .hdr>.tabs>:is(button,a){justify-content:flex-start;gap:3px;height:auto;min-width:0;min-height:50px;padding:11px 0 4px;
    border-radius:var(--r-3);font-size:var(--fs-1);line-height:1.2;letter-spacing:-.01em}
  .tabs .ico{display:block;width:20px;height:20px;margin:0;stroke-width:1.75}
  .tabs .tl{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis}
  .tabs .lk{position:absolute;top:4px;right:6px;margin:0}
  .tabs .lk .ico{width:9px;height:9px;stroke-width:2.2}
  .hdr>.tabs>.coming-soon{overflow:visible}
  .hdr>.tabs>.coming-soon::before{display:none}
  .hdr>.tabs>.coming-soon .ico{display:none}
  .tabs .coming-soon .soon-tag{order:-1;display:grid;width:min-content;height:20px;margin:0 auto;place-content:center;
    font-size:var(--fs-1);line-height:10px;letter-spacing:.02em;text-align:center;white-space:normal}
  /* A coming-soon tool's name takes two short lines ("Paper" / "Trading")
     rather than being cut ("Paper Tra…"); its cell starts a little higher so
     the bar keeps its height. */
  .hdr>.tabs>.coming-soon{padding-top:5px}
  .tabs .coming-soon .tl{overflow:visible;line-height:1;text-overflow:clip;white-space:normal}
}
/* Narrow phones (360-380px): seven faces leave "Categories" (49px at 11px)
   less than its cell, so the bar's gaps and sides tighten a little and the
   labels track in a hair more: 47.7px cells at 360px hold its 46.8px. */
@media(max-width:380px){
  .hdr>.tabs{gap:1px;padding-left:calc(3px + env(safe-area-inset-left));padding-right:calc(3px + env(safe-area-inset-right))}
  .hdr>.tabs>:is(button,a){letter-spacing:-.03em}
}

/* ===================================================== SEARCH RESULTS ====
   The /search page: one window, its title strip naming the query (sans: it
   is the visitor's own words, DISPLAY TIER) beside the mascot, a row with
   the count and the pager, then the results table. Rows click through to the
   item. The mascot is used whole, with a dark drop shadow only. */
.srch-t tbody tr{cursor:pointer}
/* The figures' columns are the catalogue's 118px, so a unit line such as
   "items, last full hour" stays on one line (MARKET). */
.perf-t.srch-t :is(th,td):not(:first-child){width:118px}
.search-head{align-items:center}
.search-title{display:flex;align-items:center;gap:11px;min-width:0}
.search-title img{width:42px;height:42px;object-fit:contain;filter:drop-shadow(0 2px 5px rgba(0,0,0,.6))}
.search-title span{display:flex;flex-direction:column;gap:1px;min-width:0}
.search-title b{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* The count and the pager sit on the window's stone between its strip and
   the column heads, each of which draws its own edge. The pager is a tray
   (CONTROLS) of faces round its page count. */
.search-tools{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:5px 14px}
.search-pager{align-items:center;justify-content:flex-end;flex-wrap:wrap}
.search-pager button{height:24px;padding:0 11px;font-size:var(--fs-3)}
.search-pager>span{padding:0 8px}
.back{background:transparent;border:none;color:var(--dim);font-size:var(--fs-5);padding:6px 4px;box-shadow:none}
.back:hover{color:var(--emph)}
.ctl{display:flex;align-items:center;gap:6px;color:var(--dim);font-size:var(--fs-3)}
.ctl select{padding:6px 8px}

/* ---- icon set: the inline sprite at the top of the page, used via <use>. 1em,
   currentColor stroke, so an icon takes the size and colour of its text — drop
   it in front of a label and it just fits. pointer-events off so click
   delegation sees the button, not the svg. ---- */
.sprite{position:absolute;width:0;height:0;overflow:hidden}
.ico{width:1em;height:1em;display:inline-block;vertical-align:-.15em;fill:none;stroke:currentColor;
  stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex:none;pointer-events:none}
button .ico,.t-chip .ico,.t-back .ico{margin-right:.4em}
button .ico:only-child,.mclose .ico,.t-burger .ico,.wl-actions .ico{margin-right:0}
.t-back .ico{margin-right:.2em}
.t-chip .ico{width:.85em;height:.85em;margin:0 0 0 .15em;order:2}
.t-follow .ico{width:1.05em;height:1.05em;vertical-align:-.2em}
.t-follow.on .ico{fill:currentColor}
.mclose .ico{width:18px;height:18px}
.t-burger .ico{width:17px;height:17px}
.wl-actions .ico{width:14px;height:14px;vertical-align:-.1em}
.ch-lk .ico{width:.85em;height:.85em;vertical-align:-.1em}

/* ============================================================== SHELL ====
   One layout shell on every page (v80). #main is a column: the page head,
   #results and the server-rendered #seo-item block (the static pages' .doc
   in place of #results) share ONE content column, capped by one rule, so a
   title always starts and ends where its content does. The column is up to
   1500px while ads may show, and up to 1860px for an ad-free visitor (ads.js
   stamps data-ad-free): the rails' footprint, 160 + 20 + 1500 + 20 + 160.
   From 1560px a page with side rails (ads.js stamps data-ad-rail-layout, or
   data-ad-rail-hold while the policy and the visitor load) pads #main by a
   gutter, a rail and its gap on each side, and the rails are fixed into those
   gutters, centred on the viewport and hugging the column. Fixed rails take
   no part in the page's height, so a short page never grows a blank band.
   The column is centred, so from 1904px rails arriving or leaving move
   nothing; below that the hold keeps the gutters until ads.js resolves. Only
   a resolved no-placement state (ads off, an excluded or ad-free account)
   removes them; a block, a refusal or a no-fill keeps them (house panels fill
   them). Keep 1560/160/20 in step with RAIL_MIN and the rail unit in ads.js.
   Scope to #main only: the item terminal's .t-mid is also a <main>. */
:root{--gutter:22px;--rail-w:160px;--rail-gap:20px;--col-max:1500px;--col-max-free:1860px;--content-max:var(--col-max)}
:root[data-ad-free="1"]{--content-max:var(--col-max-free)}
#main{width:100%;max-width:none;margin:0;padding:18px var(--gutter) 24px;display:flex;flex-direction:column}
#main>:is(#page-head,#results,#seo-item,.doc){width:100%;max-width:var(--content-max);margin-inline:auto;min-width:0}
#main>#results{flex:1 0 auto}
@media(min-width:1560px){
  :root:is([data-ad-rail-layout="1"],[data-ad-rail-hold="1"]) #main,
  :root[data-page="home"]:not([data-ad-surface]) #main{padding-inline:calc(var(--gutter) + var(--rail-w) + var(--rail-gap))}
  /* Every visible rail: fixed in its gutter, viewport-centred (ADS), hugging
     the 1500px column; the max() keeps it inside the gutter below 1904px. */
  #main>:is(.ad-rail.ad-template,.mw-brand-rail){position:fixed;top:var(--ad-rail-sticky-top);z-index:2;display:flex!important;
    min-height:var(--ad-rail-zone-h);margin:0;flex-direction:column;justify-content:center}
  #main>:is(.ad-homeleft.ad-template,.mw-brand-homeleft){left:max(var(--gutter),calc((100% - var(--col-max))/2 - var(--rail-gap) - var(--rail-w)))}
  #main>:is(.ad-railright.ad-template,.mw-brand-railright){right:max(var(--gutter),calc((100% - var(--col-max))/2 - var(--rail-gap) - var(--rail-w)))}
}
/* The fill contract: a view that should reach the footer carries .view-fill
   (the catalogue and list tables, the game overview, the category directory,
   the item-list cards, a gate, an empty watchlist, the account check). #results becomes a
   column and that view takes the spare height; any other view keeps its
   natural height at the top of #results. */
#results:has(>.view-fill){display:flex;flex-direction:column}
#results>.view-fill{flex:1 1 auto;min-height:0}
/* Up to 900px #results is a horizontal scroll container, so a wide table
   scrolls inside it on a phone instead of panning the page. From 901px it is
   not, so sticky parts (the admin's section nav, a tool's action bar) stick
   to the viewport. The admin page keeps its sticky section strip at every
   width; its wide tables scroll in their own wrappers. */
@media(max-width:900px){:root:not([data-page="admin"]) #results{overflow-x:auto}}

/* ONE page head everywhere: the display-face h1 (Alagard 32px, 24px on
   phones, with its 2px black shadow: DISPLAY TIER) and a one-line description
   on the left. Its right side holds either the 468×60 title-row
   unit (the public directory and list pages; a row that reserves it keeps one
   height whatever the ad does, ADS) or the tool's own controls in
   .page-head-tools (GE Screener, Wyrm Picks, Backtest, Paper Trading: app.js
   setHeadTools fills it). The static pages and 404 carry the same markup. */
.page-head{margin:0 0 10px;min-width:0}
.page-head:empty{display:none}
/* From 1280px every head is one height, the 468×60 title row's (ADS), with
   its title at the top: moving between pages never moves the title or the
   content under it. */
@media(min-width:1280px){#main>#page-head:not(:empty){min-height:calc(63px + var(--fs-1)*1.4)}}
/* Size, weight, tracking and shadow are the DISPLAY TIER's; the head keeps
   colour and leading. 35.2 + 6 + 21.7 = 62.9px, inside the 1280px head. */
.page-head h1{margin:0;color:var(--title);font-family:var(--display);line-height:1.1}
.page-head p{margin:6px 0 0;color:var(--dim);font-size:var(--fs-lede);line-height:1.4}
@media(max-width:640px){.page-head h1{line-height:1.15}}
.page-head.has-tools{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;align-content:start;gap:8px 24px}
.page-head-copy{min-width:0}
.page-head-tools{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px}
.page-head-tools:empty{display:none}
@media(max-width:900px){
  .page-head.has-tools{grid-template-columns:minmax(0,1fr)}
  .page-head-tools{justify-content:flex-start}
}
/* A tool's status in its head: a small square mono chip on a well, edged in
   its tone, with up, paused and muted variants, and a quiet note beside it.
   Its dot is a plain lamp inside the orbs' thin ring, no halo. */
.head-chip{display:inline-flex;align-items:center;gap:6px;min-height:25px;padding:3px 9px;
  border:1px solid color-mix(in srgb,var(--gold) 52%,var(--well));border-radius:var(--r-pill);
  color:var(--gold);background:var(--well);
  font:700 var(--fs-1)/1 var(--mono);letter-spacing:.05em;text-transform:uppercase;white-space:nowrap}
.head-chip.is-up{border-color:color-mix(in srgb,var(--up) 52%,var(--well));color:var(--up)}
.head-chip.is-paused{border-color:color-mix(in srgb,var(--warn) 52%,var(--well));color:var(--warn)}
.head-chip.is-muted{border-color:var(--face-edge);color:var(--faint);font-weight:500}
.head-chip>i{display:inline-block;width:7px;height:7px;border-radius:50%;background:currentColor;
  box-shadow:0 0 0 1px var(--ring)}
.head-note{color:var(--faint);font-size:var(--fs-3);white-space:nowrap}
a.head-note{color:var(--dim);text-decoration:underline;text-underline-offset:3px}
a.head-note:hover{color:var(--ink)}
/* A section a head link jumps to (Backtest's saved reports) clears the
   sticky header. */
.head-target{scroll-margin-top:calc(var(--chrome-h,58px) + 14px)}
/* Related-list links in the server-rendered list drawers (the item-list
   directory itself is with the app pages, LIST CARDS). */
.seo-list-links{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:8px}
.seo-list-links a{display:block;padding:9px 11px;text-decoration:none}

/* =============================================================== FOOTER ====
   One <footer class="site-foot">, a direct child of body after the body-level
   footer ad mount, on every page: the legal links and the Jagex disclaimer
   (consent.js appends "Privacy choices"). The body is a viewport-filling
   column, so spare height belongs to #main, never to a blank strip after the
   footer, and grid content keeps its natural spacing instead of stretching
   the title and table tracks. Paint: a darker ledge of the edition's stone
   (RS3: metal) with the grain and the header's --rule line along its top;
   the words in the dim tone, the links (and consent.js's "Privacy choices"
   button) in the title colour, bright yellow on hover. */
body:has(>.site-foot){display:flex;height:auto;min-height:100dvh;flex-direction:column}
body:has(>.site-foot)>#main{flex:1 0 auto;align-content:start}
.site-foot{width:100%;max-width:none;flex-shrink:0;margin:0;padding:10px max(18px,calc((100% - 1500px)/2)) 14px;color:var(--dim);
  font-size:var(--fs-2);line-height:1.6;text-align:center;border-top:0;box-shadow:inset 0 1px 0 var(--rule);
  background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--foot-top),var(--foot-bot));background-color:var(--foot-bot)}
.site-foot :is(a,button){color:var(--title)}
.site-foot :is(a,button):hover{color:var(--emph)}
@media(max-width:640px){
  .site-foot{padding:14px max(12px,env(safe-area-inset-right)) calc(14px + env(safe-area-inset-bottom)) max(12px,env(safe-area-inset-left))}
  /* Clear the fixed bottom nav whenever it holds a visible tab (HEADER). */
  :root:not([data-page="home"],[data-page="admin"]) body:has(#tabs>:not([hidden]))>.site-foot,
  :root:is([data-page="home"],[data-page="admin"]) body:has(#tabs>:not([hidden],[data-game-scoped]))>.site-foot{
    padding-bottom:calc(76px + env(safe-area-inset-bottom))}
}

/* ===================================================== STATIC DOCUMENTS ====
   About, Privacy, Terms, Contact and the 404 page: the shared header, the
   one page head, then a single reading column on the page head's left edge
   (.doc sits in the SHELL's content column; its children keep 820px). They
   wear the last game's edition, as the app does. Section heads are window
   titles on the page (DISPLAY TIER, 20px); the summary box and the contact
   card are windows, the feature lists cards (PANELS), all on flat stone
   (no grain: their words sit straight on the body); the 404's links and
   the about page's two calls are the shared buttons (CONTROLS). The mascot
   is the owner's art, whole, with a dark drop shadow only (GATES). */
.doc{color:var(--dim);font-size:var(--fs-5);line-height:1.7}
.doc>*{max-width:820px}
.doc h2{margin:34px 0 10px;color:var(--title);line-height:1.25}
.doc h2:first-child{margin-top:4px}
.doc p{margin:0 0 12px}
/* a bulleted list; the card lists below set their own box (:where keeps
   this rule's weight, which beat theirs and set the cards 22px in) */
.doc ul:where(:not(.about-feats,.about-games)){margin:0 0 12px;padding-left:22px}
.doc li{margin:0 0 6px}
.doc b{color:var(--ink)}
/* the lead's first sentence is bold ink (the page's one emphasis colour for
   words; yellow is the figures' and the hover's) */
.about-lead{color:var(--ink);font-size:var(--fs-5b)}
.about-lead b{color:var(--name)}
/* The mascot floats at the reading column's right edge (820px, .doc>*),
   beside the lead, not at the far edge of a wide content column: the right
   margin is whatever the column has beyond 820px. */
.about-mascot{float:right;width:150px;max-width:38%;height:auto;margin:4px max(0px,calc(100% - 820px)) 10px 18px;
  filter:drop-shadow(0 8px 22px rgba(0,0,0,.55))}
.about-feats,.about-games{display:grid;gap:14px;margin:16px 0 6px;padding:0;list-style:none}
.about-feats{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}
.about-feats.cols-2{grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}   /* four cards → 2×2, no orphan */
.about-games{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
/* a card's name is its title, in the text face and the title colour */
.about-feats>li,.about-games>li{margin:0;padding:14px 16px;font-size:var(--fs-4);line-height:1.6;--panel-grain:none}
.about-feats b,.about-games b{display:block;margin-bottom:4px;color:var(--title)}
/* the two directions wear the up / down channel: a toned frame and the name
   in the tone, on the plain body (a wash of the tone under the name lifted
   the ground enough to put OSRS loss red at 4.4:1; plain, 4.7:1) */
.about-games>li.g-up{--tone:var(--up)}
.about-games>li.g-down{--tone:var(--down)}
.about-games>li{--panel-hi:color-mix(in srgb,var(--tone) 55%,var(--edge-hi))}
.about-games b{color:var(--tone)}
.about-cta{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:36px}
.about-cta :is(.mprimary,.msecondary){display:inline-block;width:auto;margin:0;padding:11px 24px;text-align:center;text-decoration:none}
/* the global a{} paints links gold; the gold button's label stays its dark ink */
.about-cta .mprimary,.about-cta .mprimary:hover{color:var(--btn-ink)}
.tldr{margin:0 0 10px;padding:16px 18px;--panel-grain:none}
/* its heading is the window's title strip (PANELS), out to the frame */
.doc .tldr>h2:first-child{margin:-16px -18px 10px;padding:7px 18px 6px}
.tldr p:last-child{margin-bottom:0}
.contact-card{margin:6px 0 18px;padding:26px 24px;text-align:center;--panel-grain:none}
.contact-card p{margin:0 0 10px}
/* The address is the page's one action, so it is the gold button (the
   header Sign in's paint; it brightens with them, interaction states). */
.contact-card .mail{display:inline-block;margin:6px 0 4px;padding:11px 26px;border:1px solid var(--btn-edge);
  border-radius:var(--r-3);background:linear-gradient(180deg,var(--btn-top),var(--btn-bot));box-shadow:inset 0 1px 0 var(--btn-hi);
  color:var(--btn-ink);font-size:var(--fs-6);font-weight:600;text-decoration:none}
.contact-card .contact-note{margin:10px 0 0;color:var(--faint);font-size:var(--fs-3)}
.contact-mascot{display:block;width:120px;height:auto;margin:0 auto 6px;
  filter:drop-shadow(0 8px 22px rgba(0,0,0,.55))}
/* 404: the useful destinations, one panel of link buttons, each a face
   with a gold label (CONTROLS; it lifts with the faces, interaction states) */
.doc-links{display:flex;flex-wrap:wrap;gap:10px;padding:18px 20px}
.doc-links a{display:inline-flex;align-items:center;min-height:40px;padding:8px 16px;
  border:1px solid var(--face-edge);border-radius:var(--r-3);background:var(--face);box-shadow:inset 0 1px 0 var(--face-hi);
  color:var(--gold);font-weight:500;text-decoration:none}

/* ============================================================= MARKET ====
   Public browse: the dashboard grid, boards, sparklines, the paged
   catalogue tables and their pager. */
/* Dashboard grid: boards pack two-up on wide screens instead of stretching
   a three-column table across the whole viewport; picks and the big paged
   tables span the full row. Numeric columns get a fixed width so the
   item name column absorbs the slack — no more empty chasm mid-table.
   Its width is the SHELL's content column, so the page head, the boards and
   the tables share both edges at every width. The overview's board grid
   and its stat strip (the pulse) live with the app pages (OVERVIEW). */
.market{display:grid;grid-template-columns:repeat(auto-fit,minmax(430px,1fr));
  gap:16px;align-items:start}
@media(max-width:900px){.market{grid-template-columns:1fr}}

.market>.b-full,.market>.empty,.market>.cat-grid{grid-column:1/-1}
.board td:not(.l),.board th:not(.l){width:118px}
/* A board is a window (PANELS). It clips its table to its frame, and that
   also holds it to its track: a wide table never widens the board (a
   clipping box takes no content-based minimum width). */
.board{overflow:hidden}
/* Board head: the window's title strip (PANELS). */
.board .b-head{display:flex;align-items:baseline;justify-content:space-between;
  padding:11px 16px 9px;gap:10px}
/* GOLD TIERS: titles take --title, the pale accent; full --gold is reserved for
   ACTION, so the primary button stays the brightest gold on the page. */
.board .b-head b{color:var(--title);font-size:var(--fs-6);line-height:1.2}
/* The strip's small text is --dim: --faint is 4.5:1 at the top of the RS3
   strip, too tight. A strip's link ("See all") is a quiet link at the bar's
   end, not a second button. */
.board .b-head a{color:var(--dim);font-size:12.5px;font-weight:500;text-decoration:none}
.board .b-head a:hover{color:var(--emph);text-decoration:underline;text-underline-offset:3px}
.board .b-sub{color:var(--dim);font-size:var(--fs-2)}
.board tbody td{padding:9px 14px}
.board thead th{padding:8px 14px}
/* A figure's head is right-aligned over its figures, so its left padding is
   only the gutter to the column before it: 4px holds the widest unit line
   ("items, 30 Sep guide", 91.3px in Signika at 11px) on one line in a 118px
   column instead of breaking it and growing the head band. Not the first
   column (a rank sits under its "#"); no stronger than the rule above, so
   the overview's and the phones' own paddings still win. */
.board thead th:where(:not(.l,:first-child)){padding-left:4px}
.board td.market-data-none{color:var(--faint);font-family:var(--sans);font-size:var(--fs-2);
  font-variant-numeric:lining-nums;white-space:nowrap}
.board .mi-ico{width:30px;height:30px}
.board .mi-ico img{width:26px;height:26px}
/* Members-only marker: the OSRS gold star (wiki Member_icon.png), inlined as a
   data URI so it costs no request and needs no sw precache entry. It's a 16px
   sprite, so keep it pixelated rather than letting it blur when scaled down. */
.mbadge{display:inline-block;width:12px;height:12px;margin-left:6px;vertical-align:0;
  background:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IB2cksfwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABm0lEQVR42qWR20sCQRTG+zN6DbKiG90ou2ltUalhhUQRFb1UDz31z3lFSnIzNO9JF3rUNci77qq7xteMxSqYW9LAxwwz5/zON+d0tVvq3m40q12cIuDtaha1Gv4BcKplQMfJSfsgks45lILHMqSz6o4RpNwMyrFzZQB9+ElZVouizwDx6Qwfr5doF/ddbRRploEQ3oUYO0QluodycBuVsBHS4xEFUBd1CZEDutOcBiBu6UfCSiA3i+D9elQjRojRTYgRHaSYCbXnU0gvFxCiJ0i715Cwj9Ec+VtfEHMvkQoZ1zh43yLE0Aqk8Cqk6AaBbUEIGpFxaxC3DtK41p7Qi4S5B5y1D3l2CtWglgCWiRhyZpC/nSOTGQJnUSk3NGlTIeeeRCWwRFwwRMvkrEXhbh5p17ScrAAYQI5VoxzSk0bqwHs14H0L4O9XwQcMvwM4CvAs1SdR8huRcs3g/XoMWY8GQmhH2T5n7yMaRsG7jurDvjzrhIXc24aRYVeIM5MMabVv7SfVpiAE9HJQo8EqcI4JFL269oBm/fX9Eyx6ibFdmY1ZAAAAAElFTkSuQmCC") center/contain no-repeat;
  image-rendering:pixelated}
/* Sparkline cells: a 100px sprite in a 14px-padded cell = a 128px well, the
   same height as a number cell, reserved before the series arrive (no shift
   when they do). Colour follows the 30-day direction through the same
   --up/--down/--flat channel the percent cells use; the area fill is the
   line's own colour at 12%.
   The SVG is fluid (preserveAspectRatio none, non-scaling strokes) up to a
   320px cap; past that the row's spare width is shared by every column. */
.board td.spk,.board th.spk{width:128px;min-width:118px;text-align:right}
/* A column shows or it doesn't — never a header over clipped cells. The
   wide-only extras (.w-only, .w-only2) stay off until a table's own rules
   turn them on (Long-term Trends by window width, the overview boards by
   board width). THE BAND IS CAPPED AT 320px (owner: "the graph is too
   long"): spare width is shared by every column as breathing room, never
   one giant cell. */
.w-only,.w-only2{display:none}
.spk-svg,.spk-ph{max-width:320px;margin-left:auto}
.spk-ph{display:block;width:100%;min-width:100px;height:30px;border-radius:var(--r-1);
  background:linear-gradient(90deg,var(--panel2) 25%,var(--skel-sheen) 50%,var(--panel2) 75%);
  background-size:200% 100%;animation:skel 1.2s linear infinite;opacity:.6}
.spk-ph.none{background:none;animation:none;color:var(--faint);text-align:right;line-height:30px;opacity:1;font-family:var(--mono)}
@media(prefers-reduced-motion:reduce){.spk-ph{animation:none;background:var(--panel2)}}
.spk-svg{display:block;width:100%;height:30px;overflow:visible}
.spk-svg .spk-l{fill:none;stroke:var(--flat);stroke-width:1.5;stroke-linejoin:round;stroke-linecap:round}
.spk-svg .spk-a{fill:var(--flat);opacity:.12}
.spk-svg .spk-e{fill:none;stroke:var(--flat);stroke-width:4;stroke-linecap:round}
.spk-svg.up .spk-l,.spk-svg.up .spk-e{stroke:var(--up)} .spk-svg.up .spk-a{fill:var(--up)}
.spk-svg.down .spk-l,.spk-svg.down .spk-e{stroke:var(--down)} .spk-svg.down .spk-a{fill:var(--down)}
.picks{display:flex;gap:10px;padding:4px 14px 14px;overflow-x:auto}
/* A pick is a card (PANELS) whose words sit on its body, so it is flat stone,
   without the grain (the item page's loss red read 3.9:1 on it) */
.pick{--panel-grain:none;flex:0 0 150px;padding:10px 12px;font-size:var(--fs-2);text-decoration:none;color:var(--dim);cursor:pointer;text-align:left}
.pick b{display:block;color:var(--ink);font-size:var(--fs-3);margin-bottom:3px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pick .v{font-family:var(--mono);color:var(--up);display:block}
.pick .lk{font-size:var(--fs-1);display:block;margin-top:4px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pick .lk:not(.up):not(.down):not(.flat){color:var(--faint)}   /* the P/L line keeps its sign colour */
/* A pager's page links are faces with gold labels (CONTROLS; they lift with
   the faces, interaction states), the current page the open tab, an end
   that goes nowhere a dimmer face without its highlight. */
.pager{display:flex;gap:10px;justify-content:center;padding:12px}
.pager a{color:var(--gold);text-decoration:none;padding:5px 10px;border:1px solid var(--face-edge);border-radius:var(--r-2);
  background:var(--face);box-shadow:inset 0 1px 0 var(--face-hi)}
.pager a[aria-disabled="true"]{color:var(--faint);pointer-events:none}
.pager span{align-self:center;color:var(--dim)}
/* A table's pager is its window's foot strip: the footer's darker ledge
   (FOOTER) under the column heads' quiet divider, the drawer's disclosure on
   the left, the page links in the middle as a tray (CONTROLS), the count on
   the right. 34px: 24px faces in the 30px tray, 2px of ledge round it. */
.catalogue-pager{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);align-items:center;gap:8px;padding:2px 14px;
  background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--foot-top),var(--foot-bot));background-color:var(--foot-bot);
  box-shadow:inset 0 1px 0 var(--div2)}
.catalogue-page-links{display:flex;align-items:center;justify-content:center}
.catalogue-pager .catalogue-label,.catalogue-pager .catalogue-page-info{min-width:0;font-size:var(--fs-2);line-height:1.3;color:var(--faint)}
.catalogue-pager .catalogue-label{justify-self:start;color:var(--gold-quiet)}
.catalogue-pager .catalogue-disclosure{display:inline-flex;align-items:center;gap:6px;min-height:26px;
  padding:0 4px;margin-left:-4px;border:1px solid transparent;border-radius:var(--r-2);background:transparent;
  box-shadow:none;font-family:inherit;white-space:nowrap;cursor:pointer}
.catalogue-disclosure>span{color:var(--gold);transition:transform var(--dur-2)}
.catalogue-disclosure[aria-expanded="true"]>span{transform:rotate(90deg)}
.catalogue-pager .catalogue-disclosure:hover{border-color:var(--face-edge);background:var(--face-hover)}
.catalogue-pager .catalogue-disclosure:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
.catalogue-pager .catalogue-page-info{justify-self:end;text-align:right}
.catalogue-label-group{display:flex;min-width:0;align-items:center;gap:10px}
.catalogue-pager .catalogue-page-info{display:flex;align-items:center;justify-content:flex-end;gap:7px}
.catalogue-label-group .list-toolbar{display:flex;min-width:0;align-items:center;gap:5px;margin:0}
.list-toolbar .ctl{max-width:160px;min-height:24px;padding:1px 5px;font-size:var(--fs-2)}
.list-toolbar .ctl select{min-width:0;max-width:124px;min-height:24px;padding:1px 4px;font-size:var(--fs-2)}
.catalogue-pager .list-expand{display:inline-flex;flex:none;align-items:center;justify-content:center;
  width:26px;min-height:26px;padding:0;border:1px solid transparent;border-radius:var(--r-2);
  background:transparent;box-shadow:none;color:var(--gold);font-size:15px;line-height:1;cursor:pointer}
.catalogue-pager .list-expand:hover{border-color:var(--face-edge);background:var(--face-hover)}
.catalogue-pager .list-expand:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
.catalogue-table[aria-busy="true"] .catalogue-page-info{color:var(--gold-quiet)}
.catalogue-table[aria-busy="true"] .catalogue-page-info::before{content:"Loading… ";font-size:var(--fs-1)}
.catalogue-retry{padding:0 4px;font-size:inherit;line-height:inherit;background:transparent;color:var(--gold)}
.catalogue-page-links>:is(a,span,button){display:inline-flex;align-items:center;justify-content:center;min-width:32px;
  height:24px;padding:0 7px;white-space:nowrap;font-size:var(--fs-3);border:1px solid transparent;border-radius:var(--r-2)}
.catalogue-pager a,.catalogue-page-links>button{color:var(--gold);border-color:var(--face-edge);background:var(--face);
  box-shadow:inset 0 1px 0 var(--face-hi);text-decoration:none}
.catalogue-pager .page-current{color:var(--on-ink);background:var(--on-fill);border-color:var(--on-edge);font-weight:700;
  box-shadow:none}
.catalogue-page-links>[aria-disabled="true"]{color:var(--faint);border-color:var(--face-edge);background:var(--face-off);box-shadow:none}
.catalogue-pager .page-ellipsis{min-width:16px;padding:0 2px;color:var(--faint)}
/* One compact shell for table-based collections. Overview dashboards and
   directory pages retain their own layouts. Expanded lists scroll normally. */
:root:is([data-ad-surface="items"],[data-ad-surface="ranked-list"],[data-ad-surface="trend-list"],[data-ad-surface="category-items"],[data-ad-surface="watchlist-ready"]){scrollbar-gutter:auto}
:root:is([data-ad-surface="items"],[data-ad-surface="ranked-list"],[data-ad-surface="trend-list"],[data-ad-surface="category-items"],[data-ad-surface="watchlist-ready"]) #main{padding-bottom:0}
:root:is([data-ad-surface="items"],[data-ad-surface="ranked-list"],[data-ad-surface="trend-list"],[data-ad-surface="category-items"],[data-ad-surface="watchlist-ready"]) body>.ad-footer{display:none!important}
:root:is([data-ad-surface="items"],[data-ad-surface="ranked-list"],[data-ad-surface="trend-list"],[data-ad-surface="category-items"],[data-ad-surface="watchlist-ready"]) body>.mw-brand-footer{display:none!important}
@media(min-width:641px){
  /* Use spare desktop height for data rows, not a void below Explore. The
     table is a .view-fill (SHELL), so only it grows; the title, pager and
     legal footer stay compact. Intrinsic table height remains the minimum on
     shorter windows. */
  .market.catalogue-table{display:flex;align-items:stretch;margin-block:0}
  .catalogue-table>.board{display:flex;flex:1;min-width:0;flex-direction:column}
  .catalogue-table .board table{flex:1;height:100%}
  .catalogue-table .board thead{height:1px}
  .catalogue-table .catalogue-pager{flex-shrink:0}
  .catalogue-table .board tbody td{padding-block:8px}
  /* A short saved list should look intentional, not like two enormous rows.
     The longer-view control also keeps the established natural row pitch. */
  #results>.catalogue-table:is(.list-short,.list-expanded){flex-grow:0}
  .catalogue-table:is(.list-short,.list-expanded) .board table{flex:none;height:auto}
}
/* A 1440x800-class window: a tighter natural row pitch (41px: the 30px icon
   well, 5px above and below, the row's line) lets the twelve-row page end
   above the window's foot with the legal footer in view (786px of 800 with
   the one-line column heads and the 34px pager strip); the rows then stretch
   to fill. Taller windows stretch them from the 8px pitch. */
@media(min-width:641px) and (max-height:860px){.catalogue-table .board tbody td{padding-block:5px}}
@media(max-width:900px){
  .catalogue-pager{grid-template-columns:1fr 1fr;gap:1px 8px}
  .catalogue-page-links{grid-column:1/-1;grid-row:2;justify-self:center}   /* the tray hugs its faces */
  .catalogue-pager .catalogue-page-info{grid-column:2;grid-row:1}
}
@media(max-width:640px){
  .catalogue-pager{gap:2px;padding:3px 4px}
  .catalogue-pager .catalogue-disclosure{min-height:32px;margin-left:0}
  .catalogue-pager .list-expand{width:32px;min-height:32px}
  .catalogue-label-group{gap:4px}
  .list-toolbar .ctl{max-width:104px;min-height:30px}
  .list-toolbar .ctl select{max-width:76px;min-height:30px}
  .catalogue-page-links>:is(a,span,button){min-width:27px;height:32px;padding:0 5px;font-size:var(--fs-2)}
}
th.sortable{cursor:pointer}
th.sortable:hover{color:var(--title-hot)}   /* as a sorted column's head (.wy-lp-t) */
/* Dedicated sheen token: the shimmer once used the row hover, which was BELOW
   --panel2 in OSRS, so the highlight ran darker than the track and read
   inverted. */
.skel{background:linear-gradient(90deg,var(--panel2) 25%,var(--skel-sheen) 50%,var(--panel2) 75%);
  background-size:200% 100%;animation:skel 1.2s linear infinite;border-radius:var(--r-2);color:transparent}
@keyframes skel{to{background-position:-200% 0}}
/* Substitute a gentler cue rather than deleting feedback entirely. */
@media(prefers-reduced-motion:reduce){
  .skel{animation:none;background:var(--skel-sheen)}
}

/* ================================================================ ADS ====
   Mount geometry (see ads.js). Nothing is placed until the server policy and
   the audience resolve. From then on an eligible mount is a first-party
   house panel (.mw-brand-slot; HOUSE PANELS draws it) at the unit's exact
   size, with a live creative possibly layered over it, or, in the admin's
   spacer preview, a dashed template (.ad-slot.ad-template). An ineligible
   mount collapses completely (.ad-hidden). Either visible form reserves the
   unit's true size, so a fill, a block or a preview never moves content. */
.ad-slot{position:relative;width:100%;margin:14px auto}
.ad-slot.ad-hidden{display:none}
.mw-brand-slot{position:relative;display:flex;flex-direction:column;width:100%;margin:14px auto;
  align-items:center;justify-content:center}
/* The honest label above a live unit keeps the creative distinct from content.
   ads.js shows it only over a creative that has drawn; while one loads, and
   after a no-fill, it keeps its space invisibly, so the panel never moves. */
.ad-tag{display:block;font-size:var(--fs-1);line-height:1.4;letter-spacing:.08em;
  text-transform:uppercase;color:var(--faint);margin-bottom:3px;text-align:center}
/* The admin's spacer preview: a labelled dashed box at the unit's size. */
.ad-tpl{display:flex;align-items:center;justify-content:center;margin:0 auto;
  border:1px dashed var(--line);border-radius:var(--r-2);background:var(--inset-bg);
  color:var(--faint);font-size:var(--fs-2);letter-spacing:.08em;text-transform:uppercase}
/* One footer unit for one mount width on every footer surface: 728x90 where
   it fits, 320x50 below. A live footer adds its label above the panel, so the
   wide house footer reserves both from the first paint. */
.ad-footer,.mw-brand-footer{max-width:728px;margin:12px auto;text-align:center}
.ad-footer.ad-template,.mw-brand-footer{min-height:68px}
.mw-brand-footer[data-house-size="728x90"]{min-height:108px}
/* While ads.js waits for the policy and the visitor (data-ad-footer-hold,
   also stamped by the Worker for the first paint), the empty slot keeps the
   house panel's footprint: the 728x90 panel where it fits, 320x50 below. */
:root[data-ad-footer-hold="1"] body>.ad-footer{display:block;min-height:68px}
@media(min-width:728px){:root[data-ad-footer-hold="1"] body>.ad-footer{min-height:108px}}
/* The 468×60 overview/directory/compact-list unit sits in the title row's
   already-empty right side. The row's two-column geometry and its height are
   stable whatever policy does to the slot: it always reserves the live
   creative's footprint (the Advertisement label above the 60px iframe), so an
   impression, a template or an ad-free account never moves the content below. */
.page-head>.page-head-ad,.page-head>.mw-brand-head{display:none}
@media(min-width:1280px){
  .page-head.has-compact468{display:grid;grid-template-columns:minmax(0,1fr) 468px;
    align-items:start;gap:24px;min-height:calc(63px + var(--fs-1)*1.4)}
  .page-head>:is(.page-head-ad.ad-template,.mw-brand-head){
    display:block;width:468px;min-height:60px;margin:0;justify-self:end;align-self:center;text-align:center}
}
/* Desktop content normally carries 24px of its own bottom breathing room.
   When the shared footer slot is actually visible, let the slot's equal 12px
   margins own that separation so the space above and below the creative is
   visually identical. Hidden/ad-free slots never match and keep no ghost gap. */
@media(min-width:901px){
  body:has(>:is(.ad-footer.ad-template,.mw-brand-footer)) #main{padding-bottom:0}
  :root[data-ad-footer-hold="1"] #main{padding-bottom:0}
}
/* Rails: a fixed 160x600 skyscraper (and the 160x300 left unit), so the slot
   is sized, not fluid. The gutters it sits in only exist from 1560px, so it
   is hidden below. Hiding it HERE keeps .ad-hidden winning on specificity, so
   a collapsed rail stays collapsed on a wide screen. Where a visible rail
   sits is the SHELL's rule (fixed in the gutter, beside the column). */
.ad-rail,.mw-brand-rail{width:160px;margin:0}
@media(max-width:1559px){.ad-rail,.mw-brand-rail{display:none}}
@media(min-width:1560px){
  /* Center the fixed 618px rail zone in the VISIBLE viewport below the live-
     measured header. Page height is deliberately absent from this equation:
     tables below the fold must never drag a side ad down the document. The
     first max() arm keeps the rail safely below the header on short screens.
     Both creatives (the 160x300 left, the 160x600 right) are centred in the
     same zone. */
  .ad-rail,.mw-brand-rail{--ad-rail-zone-h:618px;
    --ad-rail-sticky-top:max(calc(var(--chrome-h,70px) + 12px),calc((100dvh + var(--chrome-h,70px) - var(--ad-rail-zone-h))/2))}
}
.ad-rail.ad-template,.mw-brand-rail{min-height:618px}
/* The item page has two mutually exclusive units: from 901px the small
   banner at the foot of the left rail (ads.js itemleft; ITEM PAGE), at 900px
   and narrower this rectangle after the complete stacked page. Neither takes
   chart space, and the right column holds none. */
.ad-detail,.mw-brand-detail{margin:12px auto 16px;flex-shrink:0}
.t-ad-mobile.ad-template,.mw-brand-mobile{min-height:268px}
.t-ad-mobile,.mw-brand-mobile{width:100%;flex:none}
/* Both mounts stay in the detail DOM so ads.js can swap them after a live
   resize. CSS mirrors the runtime arbitration as a no-flash guard (the
   rail itself is display:none at 900px and narrower); only one mount is
   ever eligible or executable at a time. */
@media(min-width:901px){.t-ad-mobile,.mw-brand-mobile{display:none}}
@media(max-width:900px){.term>:is(.t-ad-mobile,.mw-brand-mobile){border-top:1px solid var(--line);padding-top:12px}}

/* ============================================================= TABLES ====
   The GE offer list: words in the text face, figures in mono in the figure
   colour, item names in the name colour. Column heads sit on a darker band
   closed by one quiet divider, in sentence case; the rows of a table in a
   window alternate two stone bands. Up to 900px #results is a horizontal
   scroll container (SHELL), so a wide table scrolls within itself on a phone
   instead of panning the whole page. */
table{width:100%;border-collapse:collapse;font-size:var(--fs-4)}
/* `cursor:pointer` on every th LIED on five of six tables — only the screener
   has sortable headers. app.js adds .sortable where sorting is real. */
thead th{text-align:right;padding:10px 14px;font-size:var(--fs-3);font-weight:600;text-transform:none;
  letter-spacing:.01em;color:var(--th-ink);border-bottom:0;background:var(--head-band);box-shadow:inset 0 -1px 0 var(--div2);
  font-variant-numeric:lining-nums tabular-nums;cursor:default;user-select:none;white-space:nowrap}
thead th:first-child,thead th.l{text-align:left}
/* v81: a numeric column head is two lines: what the figure is and, under
   it, its unit and window ("gp, last trade", "items, last hour", "today
   (UTC)"), so no number relies on a tooltip for its meaning. The second line
   is the quiet one (the faint ink, regular weight, the 11px floor) and wraps
   in a narrow column rather than being cut. */
thead th small.th-u{display:block;margin-top:1px;color:var(--faint);font-size:var(--fs-1);font-weight:400;line-height:1.25;
  letter-spacing:0;text-transform:none;white-space:normal}
/* The rows' first band: under a window's grain, the table is its own stone
   (a standalone ledger, itself a window, swaps its body for it and drops the
   grain, PANELS, so its rows are as flat as a board's and match the pinned
   name cell on a phone, RESPONSIVE). */
:is(.board,.wy-res) table{background-color:var(--row-a)}
table.perf-t{--panel-body:linear-gradient(var(--row-a),var(--row-a));--panel-grain:none}
/* Row pitch 67px -> ~48px. At the old density a 1366x768 laptop showed eight
   rows and no second board; a screener should show data, not whitespace. */
tbody td{text-align:right;padding:9px 14px;border-bottom:1px solid var(--row-line);
  font-variant-numeric:lining-nums tabular-nums;white-space:nowrap}
tbody td:first-child,tbody td.l{text-align:left}
tbody td.num,tbody td .num{font-size:var(--fs-num)}
/* A figure cell is the figure colour (a cell that means something else,
   like "No recent trades" or a buy limit, sets its own). */
tbody td.num{color:var(--fig);font-weight:500;line-height:1.2;letter-spacing:-.01em}
/* Zebra stripes count only the rows on screen: client-paged rows are [hidden]
   and an ad row (the retained in-feed inventory, unplaced today) is not an
   item, so neither may flip the parity. The :where() keeps the stripe below
   the hover and row-state rules. */
tbody tr:where(:nth-child(even of :not([hidden],.ad-row))) td{background-color:var(--row-stripe)}
tbody tr{cursor:pointer}
tbody tr:hover td{background-color:var(--row-hover)}
/* The game's tell, in every edition: a hovered row's name lights yellow. */
tbody tr:hover .mi b{color:var(--emph)}
tbody tr:not(.ad-row):hover td:first-child{box-shadow:inset 2px 0 0 var(--theme-accent)}
/* Price-change values (fmtDay / pctCell spans) are chips: a soft tint of the
   row behind the signed figure, never lighter than it, square, with no edge,
   bevel or shadow (a level change gets a plain shade). In table cells and in
   the few other places that show a change: a list card's "Right now" rows,
   the overview's "Across the market" band, a watchlist suggestion and the
   item page's price. A table row's and the band's chip is one 24px line;
   the others keep their own line. */
:is(tbody td,.lcn-value,.wl-pick-px,.t-px,.ov-band) span.num:is(.up,.down,.flat){display:inline-block;padding:1px 7px;
  border:0;border-radius:0;font-weight:600;letter-spacing:-.01em;line-height:1.45;box-shadow:none;text-shadow:none}
:is(tbody td,.lcn-value,.wl-pick-px,.t-px,.ov-band) span.num.up{background:var(--chip-up)}
:is(tbody td,.lcn-value,.wl-pick-px,.t-px,.ov-band) span.num.down{background:var(--chip-down)}
:is(tbody td,.lcn-value,.wl-pick-px,.t-px,.ov-band) span.num.flat{background:var(--chip-flat)}
:is(.lcn-value,.wl-pick-px,.t-px) span.num:is(.up,.down,.flat){font-size:var(--fs-num)}
:is(tbody td,.ov-band) span.num:is(.up,.down,.flat){padding-block:0;font-size:13.5px;line-height:24px}
/* watchlist: inline editable targets, gap-to-target, alert status, live meta */
.wl-tgt{text-align:right}
/* A target box is the shared text box (base elements: one 1px edge, a shade
   along its top) holding a figure; the edge turns the title colour on focus,
   and the global :focus-visible ring stays (the bare outline:none here was
   the one input in the app with no keyboard ring). */
.wl-tin{width:84px;text-align:right;font:inherit;font-variant-numeric:lining-nums tabular-nums;
  color:var(--emph);background:var(--input-bg);border:1px solid var(--face-edge);box-shadow:inset 0 1px 0 var(--inset);
  border-radius:var(--r-2);padding:5px 8px}
.wl-tin:focus{border-color:var(--title)}
.wl-tin::placeholder{color:var(--faint)}
.wl-gap{display:block;font-size:var(--fs-1);color:var(--faint);margin-top:3px}
/* the price's unit and basis, in the head's words: shown only by the phone card,
   which hides the column heads (RESPONSIVE) */
.wl-cu{display:none}
/* "hit" is the product's payoff — it reads as a gold badge, not 11.5px text in
   a routine-gain green. Green/red stay reserved for the SIGN of a number
   (dcls); a fired alert is an event, and a buy hit is often a price DROP, so
   green-for-hit collided with that channel. The badge is square, as every
   chip: a gold tint inside a 1px gold edge, its words in the bright yellow. */
.wl-al{font-size:var(--fs-3);white-space:nowrap;font-weight:500}
.wl-al.hit{color:var(--emph);background:var(--gold-bg);border:1px solid color-mix(in srgb,var(--gold) 55%,transparent);
  border-radius:var(--r-pill);padding:1px 8px;font-weight:600}
.wl-al.armed{color:var(--gold-quiet)} .wl-al.none{color:var(--faint);font-weight:400}
.wl-load{color:var(--faint)}
.wl-tval{display:inline-block} .wl-tval.muted{color:var(--faint)}
.wl-editing>td{background-color:var(--row-hover)}
.wl-actions{white-space:nowrap}
.wl-actions .ghost{padding:4px 9px}
.wl-actions .ghost+.ghost{margin-left:6px}
/* Save-targets tick is the editing row's PRIMARY action → action gold, not the
   up/down channel. */
.wl-act.on{color:var(--gold);border-color:var(--gold)}
/* The icon well — not the text — sets the row height, so density work has to
   start here: 40px well + 9px cell padding was a 67px pitch and eight rows on a
   1366x768 laptop. 32px brings the pitch to ~48 without shrinking the artwork
   much (the sprites are 32px native anyway, so they actually sharpen). */
/* The icon sits in a small dark slot (the well, one shade along its top). */
.mi{display:flex;align-items:center;gap:11px}
.mi-ico{width:32px;height:32px;border-radius:var(--r-3);background:var(--ico-bg);display:flex;
  align-items:center;justify-content:center;font-size:var(--fs-4);color:var(--gold);
  flex-shrink:0;overflow:hidden;box-shadow:inset 0 1px 0 var(--inset)}
.mi-ico img{width:28px;height:28px;object-fit:contain;image-rendering:auto}
/* An item sprite casts the game's hard 1px shadow; the well itself casts
   none, and nothing glows. */
.mi-ico img{filter:drop-shadow(1px 1px 0 #000)}
.mi b{color:var(--name);font-weight:500;font-size:var(--fs-4)} .mi em{font-style:normal;color:var(--faint);font-size:var(--fs-2)}
/* The members star stays outside the name's ellipsis, so it always shows: on
   the overview's boards, and on the full-width item tables from 641px. On a
   phone those tables give a long name a second line instead (RESPONSIVE),
   which a one-line name beside its star would stop. */
.market.overview .board .mi>span:not(.mi-ico){display:flex;align-items:center;gap:5px;min-width:0;overflow:visible}
.market.overview .board .mi>span:not(.mi-ico)>b{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.market.overview .board .mi .mbadge{flex:none;margin-left:0}
@media(min-width:641px){
  .catalogue-table .board .mi>span:not(.mi-ico){display:flex;align-items:center;gap:5px;min-width:0;overflow:visible}
  .catalogue-table .board .mi>span:not(.mi-ico)>b{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .catalogue-table .board .mi .mbadge{flex:none;margin-left:0}
}
.dir{font-weight:500;font-size:var(--fs-2)}
/* Gated values (the wyrm's read for guests) show a quiet lock: a line-icon
   at reduced opacity, so the padlocks never outrank the real numbers. Not
   below .85: the old .72 dropped them to ~2:1. */
.sig-band .lk,.menu .lk,.t-leg .lk{opacity:.85}
.lk.ico{vertical-align:-.1em}
.sig-band{white-space:nowrap} .sig-band .lk{font-size:var(--fs-1)}
.empty{text-align:center;color:var(--dim);padding:56px 20px;line-height:1.7}

/* ============================================================== GATES ====
   Gated watchlist + empty states — the cartoon mascot owns the friendly
   moments; photo-real art never appears on data screens. Signed-out and
   private empty states are still product surfaces: a window (PANELS) with
   no title strip, its display-face title (DISPLAY TIER) over the mascot and
   the single call to action. */
.gate{text-align:center;padding:60px 24px}
/* The mascots are the owner's art, used whole and at full strength: a dark
   drop shadow only, never a coloured halo or a fade. */
.gate-img{width:158px;max-width:58%;height:auto;display:block;margin:0 auto 18px;
  filter:drop-shadow(0 8px 22px rgba(0,0,0,.55))}
.empty-img{width:110px;height:auto;display:block;margin:0 auto 14px;
  filter:drop-shadow(0 6px 16px rgba(0,0,0,.5))}
.gate h3{margin:0 0 8px;color:var(--title)}
.gate p{color:var(--dim);font-size:var(--fs-4);margin:0 auto 22px;max-width:420px;line-height:1.6}
.gate-btns{display:flex;gap:10px;justify-content:center}
/* A coming-soon gate (the GE Screener's) leads with its kicker, a small
   square chip on a well in the title colour (as a tool's status chip, SHELL);
   like every gate it fills the column between the page head and the footer
   (WATCHLIST). */
.gate-coming{position:relative;padding-top:46px}
.gate-kicker{display:inline-flex;margin:0 auto 18px;padding:4px 9px;
  border:1px solid color-mix(in srgb,var(--title) 45%,var(--well));border-radius:var(--r-pill);color:var(--title);background:var(--well);
  font:700 var(--fs-1)/1.3 var(--mono);letter-spacing:.1em}

/* ====================================================== ITEM TERMINAL ====
   The detail overlay starts BELOW the sticky chrome instead of covering it, so
   the logo / game switch / search / account and the tabs work from any item.
   It is the page it covers: the edition's page paint (each layer carries its
   own repeat, base elements), over --page. */
.overlay{position:fixed;left:0;right:0;bottom:0;top:var(--chrome-h,70px);
  z-index:40;background:var(--page-paint);background-color:var(--page);
  display:flex;flex-direction:column;overflow:hidden}
.overlay[hidden]{display:none}
/* Seal the background while an item is open: lock the document scroll so the
   page behind the overlay can't move (it was dragging the sticky chrome
   off-screen). The overlay's own panes still scroll — .t-mid / .t-side on
   desktop, the whole .term-scroll on mobile. */
html:has(#detail:not([hidden])){overflow:hidden}
/* ☰ opens/closes the terminal's item list (#detail.nolist = closed). Absolute
   against the overlay; whatever sits leftmost (the list's filter row, a
   guest's list head, or the ticker header once the list is closed) pads left
   to clear it. */
/* a face (base button) with the dim label; it lifts with the faces
   (interaction states) */
.t-burger{position:absolute;top:9px;left:10px;z-index:6;width:34px;height:34px;
  display:flex;align-items:center;justify-content:center;padding:0;border-radius:var(--r-2);
  color:var(--dim);font-size:15px}
/* Hiding the list (and the ad at its foot) is a premium choice, today the
   admin's (app.js canHideItemList): without it no ☰ is drawn and the rail's
   head takes back the room it kept clear for one. */
#detail:not(.can-hide-list) .t-burger{display:none}
#detail:not(.can-hide-list) .t-search{padding-left:11px}
#detail:not(.can-hide-list) .t-lhead.t-lhead-gate{padding-left:14px}
/* Desktop-only: the ≤900px stacked layout has no list (and its .term
   min-width:0 must not lose to these higher-specificity rules). The closed
   list's two-column grid is with the item page (ITEM PAGE). */
@media(min-width:901px){
  #detail.nolist .t-list{display:none}
}
.term-scroll{flex:1;min-height:0;overflow-x:auto;overflow-y:hidden}
/* Watchlist rail · chart and analysis · the side reads. Phones stack it
   (the max-width:900px block below resets the min-width). */
.term{display:grid;grid-template-columns:230px minmax(360px,1fr) 300px;
  height:100%;min-width:890px}
/* The watchlist rail is a window standing full height at the overlay's left
   edge: the PANELS stone and grain, closed by its darker hairline on the
   right (its top and left meet the chrome and the screen edge). Every
   visitor has it (a guest's asks them to sign in, ITEM PAGE). Its foot holds
   the desktop item page's one ad, the small side banner (ITEM PAGE).
   The rail fits the window without scrolling as a whole: the rows box
   (.t-items) takes the height the head and the banner leave and scrolls
   inside itself, down to one whole row (80px, a two-line name included).
   So the head, the rows box and the whole banner fit any window from about
   620px tall at every width that has the rail. Signed in: the header (58px
   from 1280px wide, 108px narrower, where the tabs take a second row) +
   48px filter + 31px label + 80px rows + 346px banner = 563px / 613px; a
   guest's rail (52px head + 114px sign-in row + banner) needs 570px / 620px.
   On a shorter window the rail scrolls as a whole instead, so the banner is
   never cut, and the row the ☰ sits on (its first) stays pinned at the
   top, so the ☰ never covers a watchlist row. */
.t-list{min-height:0;display:flex;flex-direction:column;overflow:hidden auto;
  background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--stone-top),var(--stone) 140px);background-color:var(--stone);
  border-right:1px solid var(--edge-lo)}
/* Its head is one title strip in two rows (PANELS): the filter box, clear of
   the ☰ face, over the label. Each row paints its half of the bar and only
   the label closes it with the divider. */
.t-search{--strip-body:linear-gradient(180deg,var(--bar-top),var(--bar-mid));
  padding:9px 11px 7px 50px;box-shadow:none;flex-shrink:0}
.t-search input{width:100%;padding:7px 10px;font-size:var(--fs-3)}
.t-list>:first-child{position:sticky;top:0;z-index:1}
.t-items{flex:1;overflow-y:auto;min-height:80px}
/* the label: a small sentence-case heading in the name colour (not the
   display face: it is under 16px) */
.t-lhead{--strip-body:linear-gradient(180deg,var(--bar-mid),var(--bar-bot));
  padding:2px 14px 9px;font-size:var(--fs-3);font-weight:600;color:var(--name);flex-shrink:0}
/* The followed items are GE rows: two alternating stone bands (counted over
   the rows the filter leaves on screen), the hovered row's lift and its name
   in the bright yellow. */
.t-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 14px;
  background:var(--row-a);border-bottom:1px solid var(--row-line2);cursor:pointer}
.t-item:nth-child(even of :not([style*="none"])){background:var(--row-stripe)}
.t-item:hover{background:var(--row-hover)}
.t-item:hover .nm{color:var(--emph)}
/* The open item: the striped row's stone and a 2px title-colour bar, never
   the open-tab fill (RS3's loss red is 3.5:1 on it). Drawn inset, so the
   row's text does not move. */
.t-item.sel{background:var(--row-stripe);box-shadow:inset 2px 0 0 var(--title)}
.t-item .nm{min-width:0;color:var(--name);font-size:var(--fs-3)} .t-item .nm em{display:block;font-style:normal;color:var(--faint);font-size:var(--fs-1)}
/* the price in the figure colour, its unit and window under it */
.t-item .pc{flex:none;text-align:right} .t-item .pc b{color:var(--fig);font-size:var(--fs-3);font-weight:500}
.t-item .pc span{display:block;color:var(--faint);font-size:var(--fs-1)}
.t-mid{display:flex;flex-direction:column;min-width:0;overflow:hidden;container:t-mid/inline-size}
/* The ticker: the item's icon and name (the page's de-facto H1, 32px, in the
   text face: it is data, never the display face) beside the big price, its
   change chip and Follow; the game tag is a small square well chip. */
.t-tick{display:flex;align-items:center;justify-content:space-between;gap:12px 18px;padding:10px 22px 4px;
  flex-wrap:wrap;flex-shrink:0}
#t-name{color:var(--ink);font-size:32px;font-weight:700;letter-spacing:-.01em;line-height:1.1}
.t-tick .sub{color:var(--faint);font-size:var(--fs-1);margin-left:8px;letter-spacing:.06em;background:var(--well);
  border:1px solid var(--inset);border-radius:var(--r-pill);padding:1px 7px;vertical-align:2px}
.t-tick-l{display:flex;align-items:center;gap:12px;min-width:0;flex-wrap:wrap}
.t-tick-l .mi-ico{flex:none;width:48px;height:48px}
.t-tick-l .mi-ico img{width:40px;height:40px}
/* The OSRS members chip at the start of the links row: a well chip, as the
   game tag. */
.t-chip{display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-2);color:var(--dim);background:var(--well);
  border:1px solid var(--inset);border-radius:var(--r-pill);padding:2px 9px;text-decoration:none;white-space:nowrap;
  font-family:var(--sans);line-height:1.5;box-shadow:none}
.t-chip b{color:var(--ink);font-weight:500}
.t-chip .mbadge{margin:0}
/* Similar items: a window under the chart, its head the title strip (PANELS),
   holding one row of six cards (three, then two, as the chart column
   narrows; ITEM PAGE). */
.t-sim{margin:6px 22px 18px;padding:12px 14px 14px;flex-shrink:0}
.t-sim>.t-shead:first-child{margin:-12px -14px 12px;padding:7px 14px 6px}
.t-sim-sub{color:var(--faint);font-weight:400;text-transform:none;letter-spacing:0;font-family:var(--sans);font-size:var(--fs-3);text-shadow:none}
.picks.sim{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:10px;padding:0;overflow:visible}
.picks.sim .pick{display:flex;align-items:center;gap:9px;min-width:0;padding:8px 10px}
.picks.sim .pick .mi-ico{width:28px;height:28px;flex:none}
.picks.sim .pick .mi-ico img{width:24px;height:24px}
.picks.sim .pk-t{min-width:0}
.picks.sim .pick b{font-size:var(--fs-3);margin-bottom:1px}
.picks.sim .pick .v{color:var(--dim);font-size:var(--fs-2)}
/* the price's unit and window ("gp, last trade", "gp, latest guide"):
   words, so the text face (as every label), whole on one line; the change
   chip after it is bare (its window is hidden words, for screen readers) */
.picks.sim .pk-w{font-family:var(--sans);white-space:nowrap}
/* ← Back: the overlay's only visible exit (the tabs/logo above it are exits
   too, but nothing SAID "close"). A small face (base button) with the dim
   label, lifting with the faces; Escape is the keyboard twin (app.js). The
   focused item name takes the gold ring like every other focus target, but
   only for keyboard focus — it is focused programmatically on open, and a
   ring on a heading after a mouse click reads as a glitch. */
.t-back{border-radius:var(--r-pill);color:var(--dim);
  font-size:var(--fs-3);padding:4px 11px 4px 9px;white-space:nowrap;flex:none}
#t-name:focus:not(:focus-visible),#t-name.quiet-focus:focus-visible{outline:none}
/* The overlay shell takes focus on open (app.js) purely to move the caret out
   of the header search; it is a region, not a control — no ring on it. */
.overlay:focus{outline:none}
#t-name:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:2px}
.t-px{display:flex;flex-direction:column;align-items:flex-end;gap:4px;margin-left:auto;text-align:right}
.t-livepx{font-size:var(--fs-2);color:var(--faint);margin-top:2px;font-variant-numeric:tabular-nums}
.t-livepx .t-sep{color:var(--line-strong)}
.t-livepx b{font-size:var(--fs-2);font-weight:500;color:var(--dim)}
/* Canvas is taken OUT OF FLOW so its intrinsic width attribute can't collapse
   the middle grid column. .t-mid then stretches to the full 1fr track and the
   chart fills every pixel of it, scaling with the window. */
.t-chart{flex:1;min-height:300px;position:relative}
.ch-empty{position:absolute;z-index:4;inset:20% 12%;display:grid;place-items:center;
  color:var(--faint);font:12px/1.55 var(--mono);text-align:center;pointer-events:none}
.t-chart.rsi-on{min-height:360px}
.t-chart canvas{position:absolute;top:10px;left:20px;
  width:calc(100% - 40px);height:calc(100% - 14px);display:block}
.t-leg{display:flex;flex-wrap:wrap;gap:4px 15px;padding:0 22px 14px;font-size:var(--fs-2);color:var(--dim)}
.t-leg i{display:inline-block;width:14px;height:2px;vertical-align:middle;margin-right:5px}
/* the quiet-candle key: the chart's dotted muted line, in the legend's ink */
.t-leg .ch-quiet-key{margin-left:15px;white-space:nowrap}
.t-leg .ch-quiet-sw{background:repeating-linear-gradient(90deg,var(--ch-quiet) 0 2px,transparent 2px 5px)}
.t-cap{color:var(--faint);font-size:var(--fs-2);padding:0 22px 16px}
/* Interactive chart surface. Vertical touch gestures still scroll the detail;
   a deliberate horizontal drag pans the chart after zooming. Mouse-wheel zoom
   is armed by clicking/focusing the canvas first, so page scrolling is never
   hijacked just because the pointer crosses the graph. */
#dchart-ov{touch-action:pan-y;cursor:crosshair}
#dchart-ov.nav-active{cursor:grab}
#dchart-ov.dragging{cursor:grabbing}
#dchart-ov:focus-visible{outline:1px solid var(--line-strong);outline-offset:-1px}
/* the crosshair's readout: a small window (the PANELS hairlines on stone) */
.t-tip{position:absolute;z-index:5;pointer-events:none;
  background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--stone-top),var(--stone));background-color:var(--stone);
  border:1px solid;border-color:var(--edge-hi) var(--edge-lo) var(--edge-lo) var(--edge-hi);border-radius:var(--r-2);padding:5px 9px;font-size:var(--fs-2);
  line-height:1.5;font-family:var(--mono);font-variant-numeric:tabular-nums;
  white-space:nowrap;box-shadow:var(--edge),var(--sh-2)}
.t-tip .tt-d{color:var(--dim)}
/* The side: Trend read, the wyrm's read and the price alert (a guest's
   carries the one Sign in), each its own panel. It holds no ad: the desktop
   page's one unit is at the foot of the watchlist rail (ITEM PAGE). */
.t-side{display:flex;flex-direction:column;gap:12px;padding:14px 16px;
  overflow-y:auto;min-height:0}
/* Item-page panel titles (DISPLAY TIER sets the face and size). A side
   panel's first one is its window's title strip (PANELS), pulled out to the
   frame over the panel's padding. */
.t-shead{margin:0 0 10px;color:var(--title);line-height:1.2}
.t-panel>.t-shead:first-child{margin:-12px -14px 10px;padding:7px 14px 6px}
.t-lock>.t-shead:first-child{margin:-12px -13px 10px;padding:7px 13px 6px}
/* A row's figure keeps one line; a long label wraps beside it instead. */
.t-row{display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:6px 0;font-size:var(--fs-4);color:var(--dim)}
.t-row b{color:var(--fig);font-weight:500}
.t-row>b{white-space:nowrap;text-align:right}
/* The sign colour must win in the panel too: `.t-row b` (0-1-1) used to beat
   `.up/.down` (0-1-0), so Direction / Slope / 30d·90d read neutral here while
   the header slope span was green or red — same number, two vocabularies. */
.t-row b.up,.t-row .up{color:var(--up)} .t-row b.down,.t-row .down{color:var(--down)} .t-row b.flat,.t-row .flat{color:var(--flat)}
.t-row .dir{font-size:inherit}
.t-note{font-size:var(--fs-3);color:var(--dim);padding:3px 0;line-height:1.5} .t-note b{color:var(--ink)}
/* ===== chart toolbar: Range, Chart and Overlays groups (ITEM PAGE) ===== */
.ch-bar{display:flex;align-items:center;justify-content:flex-start;gap:8px;
  padding:10px 22px 4px;flex-wrap:wrap;flex-shrink:0}
/* Each labelled group (Range, Chart, Overlays; ITEM PAGE) is a tray of
   faces, the chosen one the open tab (CONTROLS); the timeframes and the
   candle sizes inside it are rows of faces 2px apart, and the view reset is
   one face on its own. */
.ch-tools,.ch-mode-wrap,.ch-candle-tray,.ch-tfs{display:flex;align-items:center;gap:2px}
.ch-tools{flex-wrap:wrap;justify-content:flex-end}
.ch-tfs{flex-wrap:wrap}
.ch-group-label{color:var(--faint);font-size:var(--fs-1);font-weight:600}
.ch-tf,.ch-chip,.ch-mode,.ch-ci{padding:3px 9px;font-size:var(--fs-2)}
.ch-tf:focus-visible,.ch-mode:focus-visible,.ch-ci:focus-visible{outline-offset:-2px}   /* the ring inside the face, clear of its neighbours */
.ch-chip.on::before{content:"";display:inline-block;width:10px;height:2px;margin-right:6px;vertical-align:middle;
  border-radius:1px;background:var(--sw,var(--gold))}   /* swatch = the overlay's line colour (renderChartBar sets --sw) */
.ch-levels{display:inline-flex;align-items:center;gap:5px}
.ch-levels.on::before{content:none}
.ch-levels .ico{width:13px;height:13px;margin:0}
.ch-lk{font-style:normal;font-size:var(--fs-1);margin-left:4px;opacity:.8}
.ch-busy{color:var(--faint);filter:saturate(.4);cursor:progress} .ch-busy button{pointer-events:none}

/* The wyrm's read: its own panel in the side (a sign-in teaser for guests).
   The side panels' rows sit straight on the window's body, so it is flat
   stone, without the grain (PANELS; under it the quiet unit words, "of 1",
   "2 touches", read 4.0:1 on OSRS stone). */
.t-lock{--panel-grain:none;padding:12px 13px}
.t-lock .t-note{padding:2px 0 10px}
/* Gold law: solid --gold is the loudest thing and belongs to the ACTION. The
   states were inverted — the inert "Following" was a full gold slab while the
   real CTA (Follow) was a tint outline. Now Follow is the gold button beside
   the price and the followed state is a state, not an action: the open tab
   (its fill, warm edge and yellow label), which turns to unfollow red on
   hover. */
.t-follow{flex:none;background:linear-gradient(180deg,var(--btn-top),var(--btn-bot));color:var(--btn-ink);
  border:1px solid var(--btn-edge);border-radius:var(--r-3);box-shadow:inset 0 1px 0 var(--btn-hi);
  padding:10px 16px;font-weight:700;font-size:var(--fs-4)}
.t-follow.on{background:var(--on-fill);color:var(--on-ink);border-color:var(--on-edge);box-shadow:none}
.t-follow.on:hover{border-color:var(--down);color:var(--down);background:var(--down-bg)}
/* The alert's label and its box share a row where they fit (the stacked
   layout); in the 300px side column the box takes the row under its label,
   at the panel's full width, rather than running out of the panel. */
.t-tgt{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:6px 10px;margin-bottom:8px}
.t-tgt label{flex:1 0 auto;font-size:var(--fs-3);color:var(--dim);white-space:nowrap}
.t-tin{flex:1 1 110px;width:110px;min-width:0;text-align:right;padding:6px 9px;font-size:var(--fs-3)}
/* the saved-state line under the alert inputs: chip + the levels in mono, so the
   sidebar confirms exactly what the watchlist shows */
#tgt-hint .t-hint-lv{font-family:var(--mono);color:var(--dim);margin-left:6px}

/* ============================================================= MODALS ====
   The sign-in card and the settings card: a window (PANELS) on the deepest
   drop, its title in the display face (DISPLAY TIER: 20px here, 32px on the
   sign-in card), its fields the shared text boxes, its buttons the gold
   action and faces (CONTROLS). Their labels, hints and notes sit straight on
   the body, so the stone under them is flat (no grain, PANELS). */
.modal-bg{position:fixed;inset:0;z-index:60;background:var(--backdrop);
  display:flex;align-items:center;justify-content:center;padding:24px;overflow-y:auto}
/* The sign-in splash art and its geometry contract: SIGN-IN SPLASH, at the
   end of this sheet. */
.modal-bg[hidden]{display:none}
/* margin:auto + the overlay's overflow-y:auto = centered when it fits, fully
   scrollable (top reachable) when the card is taller than the viewport. */
/* width:min(340px,100%) + min-width:0 on EVERY modal (it used to be #login's
   alone): the settings card is a flex child of a 24px-padded backdrop, so on a
   320px phone a fixed 340px was wider than the space it sat in. */
.modal{width:min(340px,100%);min-width:0;padding:26px 24px;position:relative;margin:auto;box-shadow:var(--sh-3);
  --panel-grain:none}
.mclose{position:absolute;top:14px;right:14px;background:transparent;border:none;color:var(--faint);font-size:var(--fs-5);box-shadow:none}
.mlogo{color:var(--title);text-align:center}
.msub{text-align:center;color:var(--dim);font-size:var(--fs-4);margin:6px 0 20px}
.fl{display:block;font-size:var(--fs-2);color:var(--dim);margin:0 0 5px}
.fin{width:100%;margin-bottom:13px}
/* The gold action button: two stops of gold, a darker-gold edge and a 1px
   highlight along its top. The edge is drawn inset (box-shadow), so the
   button keeps the size every caller pads it to. */
.mprimary{width:100%;background:linear-gradient(180deg,var(--btn-top),var(--btn-bot));color:var(--btn-ink);border:none;
  border-radius:var(--r-3);box-shadow:inset 0 0 0 1px var(--btn-edge),inset 0 2px 0 var(--btn-hi);
  padding:11px;font-weight:500;font-size:var(--fs-4)}
.mfoot{text-align:center;font-size:var(--fs-3);color:var(--faint);margin:15px 0 0}
.mfoot.err{color:var(--down)}
.mfoot.ok{color:var(--up)}
/* auth card: secondary (Register) button + inline links, and the switchable
   views. Hiding is the global [hidden] rule. The sign-in card's own sizes and
   colours are in SIGN-IN below; these are the shared defaults. */
.mlink{color:var(--gold);text-decoration:none;font-weight:500}
.mlink:hover{text-decoration:underline}
/* The secondary action is a face (the base button) with a gold label. */
.msecondary{width:100%;margin-top:11px;background:var(--face);color:var(--gold);
  border:1px solid var(--face-edge);border-radius:var(--r-3);box-shadow:inset 0 1px 0 var(--face-hi);
  padding:11px;font-weight:500;font-size:var(--fs-4)}
/* Registration closed (Admin → Settings): a plain notice above the Register
   form, the form itself dimmed and inert, and the sign-in view's Register
   button relabelled — the state reads the same in every view. */
.auth-closed{margin:0 0 14px;padding:10px 12px;border:1px solid var(--warn);border-left-width:3px;
  border-radius:var(--r-2);background:var(--warn-bg);text-align:left}
.auth-closed b{display:block;color:var(--warn);font-size:var(--fs-4);margin-bottom:2px}
.auth-closed span{display:block;color:var(--dim);font-size:var(--fs-3);line-height:1.5}
.auth-closed[hidden]{display:none}
/* Closed, every control is the locked face (the header's COMING SOON tabs):
   the dimmer face without its highlight, its label quiet, no hover. */
#register-form.is-closed{pointer-events:none}
#register-form.is-closed .fl{color:var(--faint)}
#register-form.is-closed .fin{color:var(--faint);background:var(--face-off);border-color:var(--face-edge);box-shadow:none}
#register-form.is-closed .mprimary{background:var(--face-off);color:var(--faint);border:1px solid var(--face-edge);box-shadow:none}
.msecondary.is-closed,.msecondary.is-closed:hover{background:var(--face-off);color:var(--dim);border-color:var(--face-edge);
  box-shadow:none;cursor:default}
/* Turnstile box (app.js ensureCaptcha): compact 150x140 on the phone card, whose
   form is narrower than flexible's 300px minimum, and flexible 100%x65 on the
   desktop card. data-size lands before api.js does, so the height is reserved
   and the submit button doesn't jump when the widget draws; no size, no gap. */
.ts-box{display:flex;justify-content:center;margin:0 0 13px}
.ts-box:not([data-size]){margin:0}
.ts-box[data-size="compact"]{min-height:140px}
.ts-box[data-size="flexible"]{display:block;min-height:65px}
#register-form.is-closed .ts-box{opacity:.5}
/* ============================================================ SIGN-IN ====
   The auth splash (#login, index.html): full screen over the wyrm art
   (SIGN-IN SPLASH, end of this sheet), the site header's slot as its top row
   (the same v2 brand at the header's 48px, and a plain Close face), and one
   card in the arc's opening.
   SITE-WIDE, like home and admin: whichever game page opened it, the card
   wears the neutral edition, which is the OSRS edition exactly (#login is
   one of its hosts, DESIGN TOKENS), so it pins no colour, face or radius of
   its own. It is the settings card's window (MODALS): square hairlines on
   flat stone, a deep dark drop and no glow, the display-face title (32px,
   24px on phones; DISPLAY TIER), the shared text boxes, the gold action
   button and a face for the secondary action (CONTROLS). What #login sets
   here is geometry; its id specificity keeps that ahead of the shared rules.
   SIZES: one knob. The card's font-size is the only size; everything inside
   is in em except the title, which is pixel art and so stays at its two
   sizes whatever the knob. Desktop takes the knob from the viewport height
   (clamp(15px,1.31vh,24px): 15px up to a 1145px-tall window, the owner's
   signed-off 17px at ~1300px, a 24px cap on 4K), so the card keeps its
   proportion of the screen; the 15px floor keeps labels >= 14px and fields
   16px tall-text on any laptop (the v79 12px floor gave 11px labels). Phones
   and short windows (<= 640px wide or < 600px tall) get a fixed 15px card. */
#login{
  /* the top 64px is the header row's; the card centres in what is left, which
     sits it 20px under the viewport centre (the art's arc opening). The bottom
     adds the consent banner's height while it shows (app.js authConsentGap). */
  padding:calc(64px + env(safe-area-inset-top)) 24px calc(24px + var(--consent-h,0px) + env(safe-area-inset-bottom));
  overscroll-behavior:contain}
/* The page behind can't scroll while the card is up (#detail does the same). */
html:has(#login:not([hidden])){overflow:hidden}
/* the header's slot, insets and all (viewport-fit=cover: an iPhone home-screen
   app draws under the status bar unless the row pads it, as .hdr does) */
#login .auth-top{position:absolute;z-index:3;top:0;left:0;right:0;height:calc(58px + env(safe-area-inset-top));
  padding:calc(5px + env(safe-area-inset-top)) max(18px,env(safe-area-inset-right)) 5px max(18px,env(safe-area-inset-left));
  display:flex;align-items:center;justify-content:space-between;gap:12px;pointer-events:none}
#login .auth-top>*{pointer-events:auto}
#login .auth-brand{display:block;height:48px;width:auto;filter:drop-shadow(0 2px 8px rgba(0,0,0,.7))}
/* Close is a face, as the header's buttons are, with the header's own drop
   under it so it stands off the art. */
#login .auth-close{display:inline-flex;align-items:center;gap:7px;min-height:38px;padding:0 15px 0 12px;
  border:1px solid var(--face-edge);border-radius:var(--r-3);background:var(--face);
  color:var(--ink);font-size:var(--fs-4);font-weight:600;box-shadow:inset 0 1px 0 var(--face-hi),0 4px 14px rgba(0,0,0,.45)}
#login .auth-close:hover{background:var(--face-hover);color:var(--emph)}
#login .auth-close .ico{width:16px;height:16px;margin:0}
/* Over the bright art the window takes a deeper, two-layer dark drop than
   the settings card's; nothing round it glows. */
#login .modal{position:relative;z-index:2;margin:auto;min-width:0;overflow-wrap:anywhere;
  font-size:15px;width:min(27em,100%);padding:1.85em 2.1em 1.7em;
  box-shadow:0 30px 70px -16px rgba(0,0,0,.85),0 8px 22px rgba(0,0,0,.5)}
@media(min-width:641px) and (min-height:600px){
  #login .modal{font-size:clamp(15px,1.31vh,24px);width:min(27em,92vw)}
}
/* the title: the display face, as every page and gate titles itself; its
   size, face and shadow are the page title's (DISPLAY TIER) */
#login .auth-h{margin:0 0 .3em;color:var(--title);line-height:1.15}
#login .auth-h:focus{outline:none}
#login .msub{margin:0 0 1.15em;text-align:left;font-size:1em;line-height:1.5;color:var(--dim)}
#login .fl{margin:0 0 .35em;font-size:.93em;font-weight:600;color:var(--ink)}
#login .fin{display:block;width:100%;min-height:2.8em;margin:0 0 .85em;padding:.55em .8em;
  font-size:1.0667em;border-radius:var(--r-3)}
/* hints sit tight under their field: the field's own margin is pulled back */
#login .fhint,#login .pw-rules{margin:-.45em 0 .9em;font-size:.87em;line-height:1.45;color:var(--faint)}
#login .fhint.ok{color:var(--up)}
#login .fhint.no{color:var(--down)}
/* the password's needs on one line (two on a phone), each ticking when met */
#login .pw-rules{list-style:none;padding:0;display:flex;flex-wrap:wrap;gap:.2em 1em}
#login .pw-rules li{display:flex;align-items:center;gap:.45em}
#login .pw-rules li::before{content:"";flex:none;width:.55em;height:.55em;border:1.5px solid currentColor;border-radius:50%}
#login .pw-rules li.ok{color:var(--up)}
#login .pw-rules li.ok::before{background:currentColor}
/* the two password fields share a row: half the height for the same fields */
#login .pw-pair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 .75em}
#login .fin-row{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.4em .9em;
  margin:-.45em 0 1.05em;font-size:.93em}
#login .pw-toggle{display:inline-flex;align-items:center;gap:.45em;min-height:0;padding:.2em 0;
  border:0;background:none;box-shadow:none;color:var(--dim);font-size:1em;font-weight:500}
#login .pw-toggle:hover{color:var(--ink)}
#login .pw-toggle .ico{width:1.2em;height:1.2em;margin:0}
#login .pw-match{color:var(--faint)}
#login .pw-match.ok{color:var(--up)}
#login .pw-match.no{color:var(--warn)}
#login .caps-note{margin:-.55em 0 1em;font-size:.9em;font-weight:600;color:var(--warn)}
/* text buttons that switch views read as links: underlined gold */
#login .mlink{display:inline;min-height:0;padding:0;border:0;background:none;box-shadow:none;
  font:inherit;font-weight:600;color:var(--gold);text-decoration:underline;text-underline-offset:.18em;cursor:pointer}
#login .mlink:hover{color:var(--emph)}
#login .ts-box[data-size]{margin-bottom:1.05em}
/* The two actions keep the shared paint, hover and press (the gold button,
   the face with a gold label; CONTROLS): only their em sizes are set here,
   and the header Sign in's weight. */
#login .mprimary{display:block;width:100%;min-height:2.9em;padding:.6em 1em;
  font-size:1.03em;font-weight:700;letter-spacing:.01em}
#login .msecondary{display:block;width:100%;min-height:2.75em;margin:0;padding:.55em 1em;
  font-size:1em;font-weight:700}
/* "New to MarketWyrm?" sits under a quiet divider, apart from the sign-in form */
#login .auth-alt{display:flex;flex-wrap:wrap;align-items:center;gap:.6em .9em;
  margin-top:1.3em;padding-top:1.2em;border-top:1px solid var(--div2)}
#login .auth-alt p{flex:0 0 auto;margin:0;font-size:.93em;color:var(--dim)}
#login .auth-alt .msecondary{flex:1 1 auto;width:auto}
#login .mfoot{margin:1.05em 0 0;font-size:.9em;line-height:1.5;color:var(--dim);text-align:center}
#login .auth-terms{margin-top:.6em;font-size:.84em;color:var(--faint)}
/* a note is a boxed message right under the button it answers: a notice in
   its tone (a tone border, heavier down its left, on the tone's dark ground) */
#login .mfoot:is(.err,.ok){margin-top:1em;padding:.65em .85em;border:1px solid;border-left-width:3px;
  border-radius:var(--r-2);text-align:left;font-size:.93em}
#login .mfoot.err{color:var(--down);background:var(--down-bg);border-color:color-mix(in srgb,var(--down) 45%,transparent)}
#login .mfoot.ok{color:var(--up);background:var(--up-bg);border-color:color-mix(in srgb,var(--up) 45%,transparent)}
#login .auth-closed{margin:0 0 1em;padding:.75em .9em}
#login .auth-closed span{font-size:.93em}
/* the update form's account line exists only for password managers */
#login .auth-user{position:absolute;width:1px;height:1px;padding:0;border:0;opacity:0;pointer-events:none}
/* Phones and short windows: the header row and gutters shrink with the
   site header's; 12px gutters keep a 360px phone's form at the 300px the
   full-width Turnstile widget needs (app.js turnstileSize). */
@media(max-width:640px),(max-height:599px){
  #login{padding:calc(64px + env(safe-area-inset-top)) 12px calc(16px + var(--consent-h,0px) + env(safe-area-inset-bottom))}
  #login .auth-top{height:calc(56px + env(safe-area-inset-top));
    padding:calc(6px + env(safe-area-inset-top)) max(12px,env(safe-area-inset-right)) 6px max(12px,env(safe-area-inset-left))}
  #login .auth-brand{height:40px}
  #login .modal{width:min(360px,100%);padding:20px 16px 18px}
}
@media(pointer:coarse){
  #login .auth-close{min-height:44px}
  #login .pw-toggle,#login button.mlink{min-height:44px;display:inline-flex;align-items:center;vertical-align:middle}
  /* the two actions' em heights are 43.5px and 41.25px at the 15px knob: under
     the touch minimum (RESPONSIVE), which #login's id would otherwise beat */
  #login .mprimary{min-height:max(44px,2.9em)}
  #login .msecondary{min-height:max(44px,2.75em)}
}
/* A cached previous-release shell (v82: v83 never went live on its own, so
   v84 replaces v82) still carries the in-card logo and no top row; size it to
   the card. Delete one release after this sign-in card first goes live. */
#login .mbrand{display:block;width:250px;max-width:100%;height:auto;margin:0 auto .8em}
.field{margin-bottom:15px} .field label{display:block;font-size:var(--fs-3);color:var(--dim);margin-bottom:5px}
.field input,.field select{width:100%} .hint{font-size:var(--fs-2);color:var(--faint);margin:5px 0 0;line-height:1.5}
.row-btns{display:flex;gap:10px;justify-content:flex-end;margin-top:6px}

/* ---- entrances ----------------------------------------------------------
   Everything that appears used to be a hard cut: a 2600ms toast popped into
   existence and vanished mid-read, and the account menu — carrying a 30px-blur
   shadow — materialised with no origin. [hidden]{display:none} is the app's
   only show/hide mechanism, so animating :not([hidden]) is what makes these
   possible at all. Reduced motion is handled by the global guard near the top. */
@keyframes pop-in{from{opacity:0;transform:translateY(-6px) scale(.97)}to{opacity:1;transform:none}}
@keyframes toast-in{from{opacity:0;transform:translateX(-50%) translateY(10px)}
                    to{opacity:1;transform:translateX(-50%)}}
@keyframes card-in{from{opacity:0;transform:translateY(14px) scale(.985)}to{opacity:1;transform:none}}
@keyframes fade-in{from{opacity:0}to{opacity:1}}
.menu:not([hidden]){animation:pop-in var(--dur-3) var(--ease-emph);transform-origin:top right}
.search-dd:not([hidden]){animation:pop-in var(--dur-2) var(--ease-emph);transform-origin:top right}
.modal-bg:not([hidden]){animation:fade-in var(--dur-3) var(--ease-out)}
.modal-bg:not([hidden]) .modal{animation:card-in var(--dur-3) var(--ease-emph)}
.overlay:not([hidden]){animation:fade-in var(--dur-4) var(--ease-out)}
.toast:not([hidden]){animation:toast-in var(--dur-3) var(--ease-emph)}
/* A left:50% fixed box shrink-wraps to at most ~50vw, so a long message on a
   360px phone folded into a ~180px-wide multi-line pill. Give it real width. */
/* ---- tooltips ---- one bubble (#tip, app.js tipEngine); carriers wear a
   quiet dotted underline (a third of their own ink) so the explanation is
   discoverable, and cursor:help. The bubble is a small window (the PANELS
   hairlines on stone, the popover drop); its arrow is cut from the side it
   points from: the stone and dark hairline of the foot above a carrier, the
   lighter top and hairline below one. */
[data-tip]{cursor:help}
th[data-tip],.t-row span[data-tip],.t-tgt label[data-tip],.b-head b[data-tip],.pulse>div[data-tip] span,.pulse a[data-tip] span{
  text-decoration:underline dotted;text-decoration-color:color-mix(in srgb,currentColor 35%,transparent);
  text-underline-offset:3px;text-decoration-thickness:1px}
.tip{position:fixed;z-index:90;max-width:300px;
  background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--stone-top),var(--stone));background-color:var(--stone);
  border:1px solid;border-color:var(--edge-hi) var(--edge-lo) var(--edge-lo) var(--edge-hi);
  border-radius:var(--r-2);padding:8px 11px;font-size:var(--fs-3);line-height:1.5;color:var(--ink);
  font-family:var(--sans);font-weight:400;text-transform:none;letter-spacing:0;text-align:left;
  box-shadow:var(--sh-2);pointer-events:none;opacity:0;transform:translateY(2px);
  transition:opacity var(--dur-1) var(--ease-out),transform var(--dur-1) var(--ease-out)}
.tip.on{opacity:1;transform:none}
.tip::after{content:"";position:absolute;left:50%;bottom:-5px;width:8px;height:8px;margin-left:-4px;
  background:var(--stone);border-right:1px solid var(--edge-lo);border-bottom:1px solid var(--edge-lo);transform:rotate(45deg)}
.tip.below::after{bottom:auto;top:-5px;transform:rotate(225deg);background:var(--stone-top);border-color:var(--edge-hi)}
/* A toast is a small window, like the account menu (HEADER). */
.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);z-index:80;
  width:max-content;max-width:min(92vw,520px);text-align:center;
  background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--stone-top),var(--stone));background-color:var(--stone);
  border:1px solid;border-color:var(--edge-hi) var(--edge-lo) var(--edge-lo) var(--edge-hi);border-radius:var(--r-3);
  padding:12px 18px;font-size:var(--fs-4);box-shadow:var(--edge),var(--sh-2)}
.toast[hidden]{display:none}

/* ========================================================= RESPONSIVE ====
   Phones, touch, tablets and the stacked item terminal, for the shared
   components above (each page's own breakpoints stay with the page). */
@media(max-width:640px){
  /* Overview boards were being amputated: min-content ~497px against ~346px of
     available width, cut off by the card's own overflow:hidden with NO scrollbar
     and no affordance — the last column simply vanished. Tighten the gutters,
     shrink the icon well, drop one numeric column, and let the item name
     ellipsis instead of forcing the table wider than the screen. */
  #main{padding-left:max(12px,env(safe-area-inset-left));padding-right:max(12px,env(safe-area-inset-right))}
  .board table{table-layout:fixed;width:100%}
  .board thead th,.board tbody td{padding-left:9px;padding-right:9px}
  .board .mi{gap:9px;min-width:0}
  .board .mi-ico{width:26px;height:26px}
  .board .mi-ico img{width:22px;height:22px}
  .board .mi>span:not(.mi-ico){min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}   /* not the icon's well: it centres its sprite */
  .board th:not(.l),.board td:not(.l){width:88px}
  .board thead th{font-size:var(--fs-2);letter-spacing:0}   /* 88px wells: the 13px desktop head would wrap */
  .board td span.num:is(.up,.down,.flat){padding-inline:5px}     /* and a seven-glyph change pill still fits them */
  /* WHICH column drops is the table builder's call, not position's: app.js /
     wyrm.js mark it .p-hide (Buy limit on All Items, 24h on Most traded, volume
     on risers/fallers, rank + volume on Long-term Trends). The old
     `tr>:nth-child(3)` rule hid Price on Long-term Trends and the ranked-by
     volume on Most traded while the inert Buy limit column survived. */
  thead th.p-hide,tbody td.p-hide{display:none}
  /* The full-width item tables keep two figures on a phone (app.js marks the
     rest p-hide), so the name has about half the row; a long one takes a
     second line instead of an ellipsis. */
  .catalogue-table .board table:not(.wl-table) .mi>span:last-child{display:-webkit-box;white-space:normal;line-height:1.25;
    -webkit-box-orient:vertical;-webkit-line-clamp:2}
  /* Toast cleared the fixed bottom nav (it used to land on top of it). */
  .toast{bottom:calc(84px + env(safe-area-inset-bottom))}
  /* The bottom nav now floats over the detail terminal — give its stacked
     content room to scroll clear of it. */
  .overlay .term{padding-bottom:calc(76px + env(safe-area-inset-bottom))}
  /* Watchlist at phone width: volume + since-followed already drop via .m-hide,
     so Item · Alert · Price · 24h · Buy · Sell · actions fit. Tighten gutters and
     let the (sticky) item name ellipsis instead of forcing a wider table. */
  .wl-table th,.wl-table td{padding-left:9px;padding-right:9px}
  .wl-table td.l:first-child{max-width:130px}
  .wl-table .mi{gap:8px;min-width:0}
  .wl-table .mi>span:not(.mi-ico){min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}   /* not the icon's well */
  /* Watchlist actions need more width than a market quote table. On phones,
     give each item a readable name/price row and a target/actions row instead
     of squeezing its name to zero between fixed-width numeric columns. */
  .catalogue-table .wl-table,.catalogue-table .wl-table tbody{display:block;width:100%}
  .catalogue-table .wl-table thead{display:none}
  /* each item is a GE row: the two stone bands, the hovered row's lift */
  .catalogue-table .wl-table tbody tr{display:grid;grid-template-columns:minmax(0,1fr) auto;
    gap:2px 8px;padding:7px 9px;border-bottom:1px solid var(--row-line);background:var(--row-a)}
  .catalogue-table .wl-table tbody tr:where(:nth-child(even of :not([hidden],.ad-row))){background:var(--row-stripe)}
  .catalogue-table .wl-table tbody tr:hover{background:var(--row-hover)}
  #results .catalogue-table .wl-table tbody td{position:static;width:auto;max-width:none;
    padding:2px 0;border:0;background:transparent}
  .catalogue-table .wl-table tbody td:nth-child(1){grid-column:1;grid-row:1}
  .catalogue-table .wl-table tbody td:nth-child(3){grid-column:2;grid-row:1;align-self:center}
  .catalogue-table .wl-table tbody td:nth-child(7){grid-column:1;grid-row:2;align-self:center;text-align:left}
  .catalogue-table .wl-table tbody td:nth-child(8){grid-column:2;grid-row:2}
  .catalogue-table .wl-table tbody td:nth-child(2),.catalogue-table .wl-table tbody td:nth-child(5){display:none}
  .catalogue-table .wl-tgt::before{content:"Target, gp ";color:var(--faint);font-size:var(--fs-2)}
  .catalogue-table .wl-table .wl-cu{display:block;font:400 var(--fs-1)/1.25 var(--sans);color:var(--faint);letter-spacing:0;margin-top:2px}
  .catalogue-table .wl-table .mi>span:not(.mi-ico){white-space:normal;overflow-wrap:anywhere}
}

/* Touch devices: nothing in the app reached the 44px minimum — the tallest
   control measured 39px. Scoped to `pointer:coarse` so mouse users keep the
   tighter desktop rhythm, and applied via min-height + centring rather than
   padding so nothing reflows. */
@media(pointer:coarse){
  button,.btn-signin,.mprimary,.msecondary,.acct-chip,
  .tabs :is(button,a),.games :is(button,a),select,input,.t-follow{min-height:44px}
  /* The game switch is 50px tall at touch size; the logo row matches it, so
     the neutral home and admin header (no switch) is exactly as tall as
     every game page's. */
  .brand{min-height:50px}
  .mclose{min-width:44px;min-height:44px;display:flex;align-items:center;justify-content:center}
  /* keep the ☰ square when the coarse-pointer min-height bumps it to 44 */
  .t-burger{width:44px;height:44px}
  .t-lhead.t-lhead-gate{min-height:62px}
  .menu button{min-height:44px;display:flex;align-items:center}
  /* the ✎/✕ row-actions set min-height above but never min-width, so they stayed
     ~32px wide — below the 44px target on touch. */
  .wl-actions .ghost{min-width:44px}
}

/* THE TABLET DEAD BAND. .m-hide used to fire only below 760px, but the Long
   Plays screener needs ~1250px to lay out — so from 761px to ~1250px it hid
   nothing and simply overflowed, pushing the gated SIGNAL column (the entire
   sign-up mechanic) off the right edge on every tablet and small laptop. Drop
   the low-priority columns from 1180px down instead, which is the widest point
   the screener still fits without them. */
@media(max-width:1180px){
  thead th.m-hide,tbody td.m-hide{display:none}
}
@media(max-width:760px){
  /* Item name stays put while the numbers scroll (#results is the horizontal
     scroll container), so a row never loses its subject.
     :first-child, not every td.l — the watchlist has TWO left cells (Item + the
     Alert chip); only the item name should pin, or they'd stack at left:0. */
  /* A pinned cell is opaque in its own row's paint (the head band, the two
     row bands, the hovered row), so what scrolls under it never shows. */
  #results thead th.l:first-child,#results tbody td.l:first-child{position:sticky;left:0;z-index:1;
    background:var(--row-a)}
  #results thead th.l:first-child{background:var(--head-band)}
  #results tbody tr:where(:nth-child(even of :not([hidden],.ad-row))) td.l:first-child{background:var(--row-stripe)}
  #results tbody tr:hover td.l:first-child{background:var(--row-hover)}
  /* pin the watchlist action buttons to the right edge the same way — scoped
     to the watchlist table: a bare `thead th:last-child` grabbed whatever
     column came last in ANY table under #results. */
  #results tbody td.wl-actions,#results .wl-table thead th:last-child{position:sticky;right:0;z-index:1;
    background:var(--row-a)}
  #results .wl-table thead th:last-child{background:var(--head-band)}
  /* (a phone lays a watchlist row out as a card with clear cells instead,
     RESPONSIVE above) */
  @media(min-width:641px){
    #results tbody tr:where(:nth-child(even of :not([hidden],.ad-row))) td.wl-actions{background:var(--row-stripe)}
    #results tbody tr:hover td.wl-actions{background:var(--row-hover)}
  }
}
@media(max-width:640px){
  #main{padding-top:12px}
  .search-board{margin-top:2px}
  .search-head{align-items:flex-start}
  .search-tools{align-items:flex-start;flex-direction:column}
  .search-pager{width:100%;justify-content:space-between}
}
/* Detail terminal stacks at 900, not 760: .term has min-width:820px, so
   between 761-819px it stayed a 3-column grid and overflowed horizontally —
   an iPad-portrait dead band. Stacking from 900 down closes it. Kept separate
   from the 760 block so the #results rules there are unaffected. */
@media(max-width:900px){
  .term-scroll{overflow-y:auto;overflow-x:hidden}
  .term{display:flex;flex-direction:column;min-width:0;height:auto;min-height:100%}
  .t-list{display:none}
  /* No list to toggle in the stacked layout — the ☰ goes too. */
  .t-burger{display:none}
  .t-mid{flex:none}
  .t-chart{height:46vh;flex:none}
}

/* ======================================================= DISPLAY TIER ====
   Alagard (TYPEFACES) is the one display face, in every edition. It is pixel
   art on a 16px em, so it is set at three sizes only (DESIGN TOKENS --dt-*):
   32px for the page title, gate titles and the sign-in title (24px on
   phones), and the home hero;
   20px for every title in a title strip and the panel titles that stand for
   one; 16px for a small heading inside a panel. One weight (400), never
   synthesised, never tracked in or out. A hard black shadow, as the game
   draws its interface text: 1px under a 20px title, 2px under a 32px one
   (the hero keeps its own soft shadow over its art).
   NEVER on the detail-overlay item name, the visitor's or any dynamic text
   (the search title, a filter or report name), any numeral, or anything
   under 16px: those titles stay in the text face (.search-title b,
   .wy-sum-title, .wy-res-title, .wy-bt-rep-head h3, .list-card-copy h2,
   #seo-item h2, the .wr-tf and .t-sim-sub notes inside a title).
   Each rule carries the specificity of the most specific title it lists
   (:is() takes it), so no component's size, weight or tracking overrides
   the tier from anywhere in the sheet; colour and line-height stay with the
   components. */
:root :is(.page-head h1,.gate h3,.home-hero h1){font-size:var(--dt-l)}
:root :is(.board .b-head b:not(.search-title b),.market.overview .ov-bp .b-head b,.t-shead,
  .wy-pane-head :is(h2,h4):not(.wy-sum-title),.adm-head h3,.adm-area-head h2,.home-value-head h2,.ht-head h3,
  .pt-panel-head b,.pt-modal h3,.doc h2,.wl-grow-head h2,.mlogo){font-size:var(--dt-m)}
:root .home-game-copy strong{font-size:var(--dt-m)}
:root .home-totals-title{font-size:var(--dt-s)}
@media(max-width:640px){
  :root :is(.page-head h1,.gate h3){font-size:24px}
  :root .home-game-copy strong{font-size:var(--dt-s)}
}
:root :is(.page-head h1,.gate h3){text-shadow:2px 2px 0 #000}
:root :is(.board .b-head b:not(.search-title b),.market.overview .ov-bp .b-head b,.t-shead,
  .wy-pane-head :is(h2,h4):not(.wy-sum-title),.adm-head h3,.adm-area-head h2,.home-value-head h2,.ht-head h3,
  .pt-panel-head b,.pt-modal h3,.doc h2,.wl-grow-head h2,.mlogo,.home-game-copy strong){text-shadow:1px 1px 0 #000}
/* The face itself, last: one weight, no synthesis, no tracking. */
:root :is(.page-head h1,.gate h3,.home-hero h1,.board .b-head b:not(.search-title b),.market.overview .ov-bp .b-head b,
  .t-shead,.wy-pane-head :is(h2,h4):not(.wy-sum-title),.adm-head h3,.adm-area-head h2,.home-value-head h2,.ht-head h3,
  .pt-panel-head b,.pt-modal h3,.doc h2,.wl-grow-head h2,.mlogo,.home-game-copy strong,.home-totals-title){
  font-family:var(--display);font-weight:400;font-synthesis:none;letter-spacing:0}
/* The sign-in title is a page title on a card that sizes everything else in
   em from one knob (SIGN-IN): the face keeps the page title's two pixel
   sizes and its shadow whatever the knob. #login's id carries the weight. */
#login .auth-h{font-size:var(--dt-l);text-shadow:2px 2px 0 #000;
  font-family:var(--display);font-weight:400;font-synthesis:none;letter-spacing:0}
@media(max-width:640px){#login .auth-h{font-size:24px}}

/* ---- Ledgers and stat cards (perf-*) -----------------------------------
   The stat cards, notes and ledger tables of Wyrm Picks, Long-term Trends
   and the search results, on the shared tokens and table rules. The cards
   are the overview's skills strip (OVERVIEW): one window (PANELS) of wells
   5px apart, each well its label, its figure in the pixel numerals at 27px
   in the figure yellow, and the words that say what the figure counts or
   when (sentence case, like the column heads). */
.perf-grid{display:grid;gap:5px;margin:13px 0 16px;padding:4px;
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}
/* Wyrm Picks opens with its cards: the page head's own 10px is the gap. */
.wy-picks>.perf-grid:first-child{margin-top:0}
.perf-card{display:flex;flex-direction:column;gap:2px;min-width:0;padding:8px 11px 7px 10px;border:1px solid var(--inset);
  background:var(--row-a)}
.perf-card .pk{color:var(--dim);font-size:var(--fs-2);font-weight:600}
.perf-card .pv{color:var(--fig);font-family:var(--pix);font-size:var(--fs-7);font-weight:400;line-height:1;
  letter-spacing:.01em;font-variant-numeric:tabular-nums}
.perf-card .pv small{margin-left:4px;color:var(--dim);font:500 var(--fs-3) var(--sans);letter-spacing:0}   /* the unit beside a figure */
.perf-card .ps{color:var(--faint);font-size:var(--fs-2)}
.perf-h{margin:18px 0 7px;color:var(--name);font-size:var(--fs-3);font-weight:600}
/* A note is a window marked by a 2px title-colour bar down its left. */
.perf-note{padding:10px 13px;margin:10px 0 16px;font-size:var(--fs-3);line-height:1.5;color:var(--dim);
  box-shadow:inset 2px 0 0 var(--title),var(--panel-shadow)}
.perf-note b{color:var(--ink)}
/* display:table so it actually fills the column; the scroll moves to a wrapper
   at phone width instead of crippling the desktop layout. A standalone ledger
   is itself a panel, so its borders stay separate for the radius to apply;
   inside a panel it drops the frame (PANELS). Heads and rows use the shared
   table rules. */
.perf-t{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--fs-4);
  display:table;table-layout:auto}
.perf-t th{padding:9px 12px}
.perf-t td{padding:11px 12px;color:var(--ink)}
.perf-t th:first-child,.perf-t td:first-child{text-align:left;width:auto}
.perf-t th:not(:first-child),.perf-t td:not(:first-child){width:110px}
.perf-t .muted{color:var(--faint)}
@media(max-width:760px){.perf-t{display:block;overflow-x:auto}}
/* From 901px #results no longer scrolls sideways (SHELL), so the Wyrm Picks
   ledger, whose ten-column trade table needs about 925px, scrolls inside its
   own host on narrower windows instead of widening the page. */
@media(max-width:1100px){#results>.wy-picks{overflow-x:auto}}

/* ============================================== SCREENER AND WYRM TOOLS ====
   The saved-filter screener, its editors, Long-term Trends, Wyrm Picks, the
   admin panels' shared controls and the wyrm's read. The GE Screener's own
   layout follows the shared controls (GE SCREENER, below).
   Every pane (.wy-pane, and the editor, .wy-edit) is a window with its
   title strip; a filter or report row (.wy-item) is a card. All carry their
   words straight on their stone (the faint counts and units, a warning, a
   field's help), so none wears the grain (PANELS): under it the OSRS faint
   words fell to about 4.2:1. Their strips keep it. Groups of controls sit in wells (the
   preset bar, a condition row, the column list, a test date); a rule or a
   condition in words is a well with a title-colour bar down its left; a
   notice is a 1px tone edge on the tone's tint, its words in the ink.
   Labels are sentence case in the column-head ink, as the column heads. */
.wy-pane,.wy-edit,.wy-item{--panel-grain:none}
.wy-item{display:flex;align-items:center;gap:10px;padding:8px 10px 8px 12px;margin-bottom:6px;cursor:pointer}
/* the open row: its lit hairlines take the open tab's warm edge */
.wy-item.sel{--panel-hi:var(--on-edge)}
/* enabled/disabled reads at a glance: coloured left edge + the pill toggle */
.wy-item.en{box-shadow:inset 3px 0 0 var(--up),var(--panel-shadow)}
.wy-item.dis{box-shadow:inset 3px 0 0 var(--down),var(--panel-shadow)}
.wy-item-main{flex:1 1 auto;display:flex;flex-direction:column;gap:2px;min-width:0}
.wy-item-n{font-weight:600}
.wy-item-m{color:var(--dim);font-size:var(--fs-3)}
.wy-tog{flex-shrink:0;font-size:var(--fs-2);padding:4px 10px;border-radius:var(--r-pill);white-space:nowrap;
  display:inline-flex;align-items:center;border:1px solid var(--line)}
.wy-tog.on{color:var(--up);border-color:color-mix(in srgb,var(--up) 50%,transparent);background:var(--up-bg)}
.wy-tog.off{color:var(--down);border-color:color-mix(in srgb,var(--down) 50%,transparent);background:var(--down-bg)}
.wy-actions{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap}
.wy-err{color:var(--down);margin-top:8px;font-size:var(--fs-4)}
.wy-note{color:var(--warn);font-size:var(--fs-3);margin:6px 0}
.wy-empty{color:var(--dim);padding:14px;border:1px dashed var(--line);border-radius:var(--r-3);line-height:1.6}
/* both editors read as one designed card, not bare inputs on the page */
.wy-edit{padding:14px}
/* labeled field grid: a label above each control — a settings form that
   reads as tidy columns instead of a run of inline boxes */
.wy-fgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;margin-bottom:8px}
.wy-f{display:flex;flex-direction:column;gap:4px;min-width:0}
.wy-f>span{color:var(--th-ink);font-size:var(--fs-2);font-weight:600}
/* sentence case, as every label: the brain editor's labels are written in
   lower case in wyrm.js ("max picks"); a flex item is a block, so its first
   letter can be raised here */
.wy-f>span::first-letter{text-transform:uppercase}
.wy-f select,.wy-f input{width:100%;min-width:0}
/* config/filter editors: view/edit mode */
.wy-edit input:disabled,.wy-edit select:disabled{color:var(--dim);background:var(--inset-bg);
  border-color:var(--line);opacity:1;cursor:default}
.wy-actions .mprimary{width:auto;padding:8px 18px}
.wy-actions .wy-right{margin-left:auto}
/* A destructive first step (Discard, Delete) is a face with a red label and
   edge; it warms to the red tint on hover, never the lifted face (loss red
   is under 4.5:1 on it). Its confirmation is the red tone button (CONTROLS). */
.wy-actions .wy-danger{color:var(--down);border-color:color-mix(in srgb,var(--down) 55%,var(--face-edge))}
.wy-actions .wy-danger:hover{background:var(--down-bg);color:var(--down);border-color:var(--down)}

/* ---- GE SCREENER (wyrm.js paintScreener) ---------------------------------
   Admin only for now; everyone else gets the COMING SOON gate. Inside the
   content column: "Your filters" (300px, the full height down to the footer;
   the host is a .view-fill, SHELL) beside the workspace. The workspace holds
   a short guide, the filter editor (also the Admin page's site-list editor)
   or a saved filter's summary, and takes the height while nothing has run.
   Once a filter has run, its summary keeps its own height and the results
   panel under it takes the rest, so the results start right below the
   summary. Every surface is a window (PANELS) whose head is its title
   strip. On phones the list folds into a "Your filters (N)" disclosure (its
   strip) above the workspace. */
.wy-screener{display:grid;grid-template-columns:300px minmax(0,1fr);grid-template-rows:auto 1fr;gap:16px;align-content:start}
.wy-screener>.wy-filters{grid-column:1;grid-row:1/-1}
.wy-screener>.wy-work{grid-column:2;grid-row:1/-1}
.wy-screener>.wy-res{grid-column:2;grid-row:2}
.wy-screener:has(>.wy-res:not([hidden]))>.wy-work{grid-row:1}
.wy-work{display:flex;flex-direction:column;min-width:0}
.wy-work>*{flex:1 0 auto}
.wy-pane{min-width:0}
.wy-pane-head{display:flex;align-items:center;gap:8px 10px;min-height:46px;padding:9px 16px 8px}
/* the title: DISPLAY TIER sets its face and size (the summary's filter name,
   dynamic, stays in the text face at the same 20px) */
.wy-pane-head :is(h2,h4){margin:0;min-width:0;color:var(--title);line-height:1.2}
.wy-pane-body{padding:12px 16px 16px}
.page-head-tools .wy-head-new,.wy-guide .mprimary{width:auto;padding:9px 18px}

/* The list: one row per filter, its name and a one-line summary (a single
   button that opens it) beside its On/Off switch; the coloured left edge
   says on or off at a glance (above). */
.wy-filters .wy-pane-body{padding:10px}
.wy-filters-toggle{display:none}
.wy-flist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.wy-flist+.wy-fed-h{margin-top:16px}
.wy-flist>.wy-item{margin:0;padding:0 10px 0 0;gap:6px;cursor:default}
.wy-item-open{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:2px;
  padding:9px 4px 9px 13px;border:0;border-radius:inherit;background:transparent;box-shadow:none;
  color:var(--ink);text-align:left}
.wy-item-open:focus-visible{outline-offset:-2px}
.wy-item-open .wy-item-n{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fs-4)}
.wy-item-open .wy-item-m{color:var(--faint);font-size:var(--fs-2);line-height:1.35}
/* The open filter: the open tab's warm edge all round, its fill washed
   into the body, and its name in the bright yellow, beside the on/off
   edge. */
.wy-flist>.wy-item.sel{--panel-hi:var(--on-edge);--panel-lo:var(--on-edge);
  --panel-body:linear-gradient(90deg,color-mix(in srgb,var(--on-fill) 55%,var(--stone-top)),var(--stone) 85%)}
.wy-item.sel .wy-item-n{color:var(--emph)}
.wy-item.sel .wy-item-m{color:var(--dim)}
/* On/Off: a switch in a well, a sliding knob and the word (a status, so
   the mono caps of the head's chips); read-only rows show the same face
   without the button. */
.wy-switch{flex:none;display:inline-flex;align-items:center;gap:7px;min-height:30px;padding:4px 10px 4px 5px;
  border:1px solid var(--face-edge);border-radius:var(--r-pill);background:var(--well);box-shadow:none;
  color:var(--faint);font:700 var(--fs-1)/1 var(--mono);letter-spacing:.06em;text-transform:uppercase;white-space:nowrap}
.wy-switch>i{position:relative;flex:none;width:28px;height:16px;border-radius:var(--r-pill);background:var(--line);
  transition:background-color var(--dur-2) var(--ease-out)}
.wy-switch>i::after{content:"";position:absolute;top:2px;left:2px;width:12px;height:12px;
  border-radius:max(1px,calc(var(--r-pill) - 1px));background:var(--faint);
  transition:transform var(--dur-2) var(--ease-out),background-color var(--dur-2) var(--ease-out)}
.wy-switch.is-on{color:var(--up);border-color:color-mix(in srgb,var(--up) 45%,var(--face-edge))}
.wy-switch.is-on>i{background:color-mix(in srgb,var(--up) 32%,var(--well))}
.wy-switch.is-on>i::after{transform:translateX(12px);background:var(--up)}
button.wy-switch:hover{border-color:var(--line-strong);color:var(--ink)}
button.wy-switch.is-on:hover{border-color:var(--up);color:var(--up)}
.wy-switch.is-static{border-color:transparent;background:transparent;cursor:default}

/* The guide, when nothing is open: "Start from a preset" (the open game's
   screens, each naming its thresholds) and + New filter. Plain stone: nothing
   glows. */
.wy-guide{display:flex;flex-direction:column}
.wy-guide>.wy-pane-body{flex:1 1 auto;display:flex;flex-direction:column;gap:6px;padding:14px 16px 18px}
.wy-guide-lede{margin:0 0 4px;max-width:80ch;color:var(--dim);font-size:var(--fs-4);line-height:1.55}
.wy-guide .wy-actions{margin-top:8px}

/* Presets: chip groups (the guide and the editor's preset bar). Each chip is
   a face (base button; it lifts with the faces, interaction states): its
   name in the action gold over the line that names every threshold with its
   unit. */
.wy-pre-groups{display:flex;flex-direction:column;gap:12px}
.wy-pre-gh{margin:0 0 6px;color:var(--th-ink);font-size:var(--fs-3);font-weight:600}
.wy-pre-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,250px),1fr));gap:8px}
.wy-pre{display:flex;flex-direction:column;align-items:flex-start;gap:3px;min-height:44px;padding:9px 12px;text-align:left;
  color:var(--ink);font-size:var(--fs-3);line-height:1.4;white-space:normal}
.wy-pre b{color:var(--gold);font-size:var(--fs-4);font-weight:600}
.wy-pre:hover b{color:var(--emph)}
.wy-pre span{color:var(--dim)}
.wy-presets{margin:0 0 14px;border:1px solid var(--inset);border-radius:var(--r-3);background:var(--well)}   /* a well */
.wy-presets>summary{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px;min-height:44px;padding:11px 12px;
  cursor:pointer;color:var(--title);font-weight:600;list-style:none}
.wy-presets>summary::-webkit-details-marker{display:none}
.wy-presets>summary::before{content:"▸";color:var(--faint)}
.wy-presets[open]>summary::before{content:"▾"}
.wy-presets>summary:focus-visible{outline:2px solid var(--gold);outline-offset:-2px}
.wy-presets>.wy-pre-groups{padding:2px 12px 12px}

/* The editor: a summary of any problems at the top (the cursor moves there
   on Save, so nothing covers it); name, game and description; the
   conditions; sort and limit; then the action bar, right after the form. The
   bar sticks to the bottom of the window only while the form is taller than
   the window. Labels wear the column-head ink. The rows reflow by the
   editor's own width (a container), not the window's. */
.wy-edit.wy-fed{position:relative;display:flex;flex-direction:column;padding:0;scroll-margin:calc(var(--chrome-h,58px) + 14px) 0 14px}
.wy-fed-body{flex:none;container:wy-fed/inline-size;padding:14px 16px 4px}
.wy-fed-body>*{max-width:1120px}   /* a form reads best at a form's width, even in an 1860px column */
.wy-fed-top{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:0 16px;align-items:start}
.wy-fld{position:relative;min-width:0;margin:0 0 12px;padding:0;border:0}
.wy-lab{display:block;margin:0 0 5px;padding:0;color:var(--th-ink);font-size:var(--fs-2);font-weight:600}
.wy-opt{color:var(--faint);font-weight:400}
.wy-name{width:100%}
.wy-count{position:absolute;top:0;right:0;color:var(--faint);font:var(--fs-1)/1.6 var(--mono)}
/* The description is the shared text box (base elements), as a textarea. */
.wy-desc{display:block;width:100%;min-height:62px;resize:vertical;padding:8px 10px;border:1px solid var(--face-edge);
  border-radius:var(--r-3);background:var(--input-bg);box-shadow:inset 0 1px 0 var(--inset);color:var(--ink);
  font:inherit;font-size:var(--fs-4);line-height:1.45}
.wy-desc:focus{border-color:var(--title)}
.wy-desc:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
.wy-desc:focus:not(:focus-visible){outline:none}
/* Game: one tray of three radios (CONTROLS: a well of faces, the chosen
   one the open tab); each face is the radio's span. */
.wy-seg-opts{display:inline-flex}
.wy-seg-opts label{position:relative;display:block;cursor:pointer}
.wy-seg-opts input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer}
.wy-seg-opts span{display:block;padding:7px 13px;font-size:var(--fs-3);white-space:nowrap}
.wy-seg-opts input:focus-visible+span{outline:2px solid var(--gold);outline-offset:-2px}
/* A section's head inside a pane (Conditions, Sort & limit, Summary), as
   the ledgers' section heads (.perf-h), over the quiet divider */
.wy-fed-h{margin:16px 0 6px;padding-top:14px;border-top:1px solid var(--div2);color:var(--th-ink);
  font-size:var(--fs-3);font-weight:600}
.wy-pane-body>.wy-fed-h:first-child,.wy-filters-body>.wy-fed-h{padding-top:0;border-top:0}
.wy-fed-lede{margin:0 0 8px;color:var(--dim);font-size:var(--fs-3)}
.wy-conds{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.wy-clause{padding:8px 8px 8px 10px;border:1px solid var(--inset);border-radius:var(--r-3);background:var(--well)}   /* a well */
.wy-clause:focus-within{border-color:var(--line-strong)}
.wy-clause-ctl{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(0,.9fr) minmax(0,1fr) auto;gap:8px;align-items:center}
.wy-clause-ctl>select{width:100%;min-width:0}
/* The field: a button that opens the field picker, drawn as the shared text
   box (a select's look); its edge takes the title colour while the picker is
   open, as a box does on focus. */
.wy-field{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;min-width:0;min-height:40px;
  padding:8px 10px;background:var(--input-bg);box-shadow:inset 0 1px 0 var(--inset);color:var(--ink);text-align:left;font-weight:600}
.wy-field>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wy-field::after{content:"▾";flex:none;color:var(--faint)}
.wy-field[aria-expanded="true"]{border-color:var(--title)}
.wy-op-fixed{padding:0 4px;color:var(--dim)}
/* The value: one or two boxes and their unit, and the amount read back. */
.wy-val-wrap{display:flex;flex-direction:column;gap:4px;min-width:0}
.wy-boxes{display:flex;align-items:center;gap:6px;min-width:0}
.wy-val{width:100%;min-width:0}
.wy-boxes>.wy-val{flex:1 1 0}
.wy-val:not(select),.wy-limit{font-family:var(--mono);font-size:var(--fs-num)}
.wy-unit,.wy-and{flex:none;color:var(--faint);font-size:var(--fs-3);white-space:nowrap}
.wy-unitsel{flex:none;width:auto}
.wy-echo{color:var(--dim);font:var(--fs-2)/1.3 var(--mono)}
.wy-echo:empty{display:none}
.wy-clause-ctl>.wy-val-wrap.is-wide{grid-column:1/-1;grid-row:2}
/* Yes / No (/ Unknown): one tray of radios, as the Game tray. */
.wy-yn{display:inline-flex;align-self:flex-start}
.wy-yn label{position:relative;display:block;cursor:pointer}
.wy-yn input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer}
.wy-yn span{display:block;padding:7px 13px;font-size:var(--fs-3);white-space:nowrap}
.wy-yn input:focus-visible+span{outline:2px solid var(--gold);outline-offset:-2px}
.wy-yn:focus{outline:none}
/* A tick list of named values, each a face with its box, a ticked one the
   open tab (CONTROLS); the category list scrolls and has a search. */
.wy-checks{display:flex;flex-wrap:wrap;gap:6px}
.wy-checks:focus{outline:none}
.wy-checks label{display:inline-flex;align-items:center;gap:6px;min-height:34px;padding:4px 10px;
  border-radius:var(--r-3);font-size:var(--fs-3);cursor:pointer}
.wy-checks input{margin:0;accent-color:var(--gold)}
.wy-cat{display:flex;flex-direction:column;gap:6px}
.wy-cat-find{width:100%;max-width:360px}
.wy-cat-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,190px),1fr));max-height:236px;overflow:auto;
  padding:2px;align-content:start}
.wy-cat-n{margin:0;color:var(--faint);font-size:var(--fs-2)}
/* Quick values on a row (10K / 100K / 1M gp): small faces (base button;
   they lift with the faces, interaction states). */
.wy-vchips{display:flex;flex-wrap:wrap;gap:6px;margin:6px 2px 0}
.wy-vchip{padding:3px 10px;font-size:var(--fs-2)}
.wy-clause .wy-del{display:grid;place-items:center;width:36px;height:36px;padding:0;border-color:transparent;color:var(--faint)}
.wy-clause .wy-del:hover{color:var(--down);border-color:var(--down);background:var(--down-bg)}
/* Under every row: what the field is, its unit and its window (always
   shown), then a hint, a warning and an error, each only when it applies. */
.wy-def{margin:5px 2px 0;color:var(--faint);font-size:var(--fs-3);line-height:1.4}
.wy-hint{margin:3px 2px 0;color:var(--faint);font-size:var(--fs-2)}
.wy-warn{margin:5px 2px 0;color:var(--warn);font-size:var(--fs-3);line-height:1.4}
.wy-fed-sort .wy-warn{margin:5px 0 0}
@container wy-fed (max-width:620px){
  .wy-fed-top{grid-template-columns:minmax(0,1fr)}
  .wy-clause-ctl{grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto}
  .wy-clause-ctl>.wy-field{grid-column:1/3}
  .wy-clause-ctl>.wy-del{grid-column:3;grid-row:1}
  .wy-clause-ctl>.wy-val-wrap{grid-column:2/4}
  /* A wide value (two boxes, a tick list) takes a row of its own UNDER the
     test, so a row still reads field, test, then values. */
  .wy-clause-ctl:has(>.wy-val-wrap.is-wide)>.wy-op{grid-column:1/-1;grid-row:2;justify-self:stretch}
  .wy-clause-ctl>.wy-val-wrap.is-wide{grid-column:1/-1;grid-row:3}
}
/* Quick conditions: chips that add or replace their own row, each a face
   (base button); one that cannot apply is the dimmer face on a dashed edge.
   Adding a row (or ungrouping) is a face with a gold label on a dashed edge:
   it makes something new. All lift with the faces (interaction states). */
.wy-mods{display:flex;flex-wrap:wrap;gap:8px 16px;margin:0 0 10px}
.wy-mod-g{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.wy-mod-l{color:var(--faint);font-size:var(--fs-2)}
.wy-mod{display:inline-flex;flex-direction:column;align-items:flex-start;padding:4px 10px;
  font-size:var(--fs-3);line-height:1.25}
.wy-mod small{color:var(--faint);font-size:var(--fs-1)}
.wy-mod[aria-disabled="true"]{color:var(--faint);border-style:dashed;cursor:default}
.wy-mod-why{flex-basis:100%;margin:0;color:var(--faint);font-size:var(--fs-2);line-height:1.4}
.wy-add,.wy-ungroup{margin-top:10px;border-style:dashed;color:var(--gold)}
.wy-fed-sort{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr));gap:0 14px}
.wy-fed-sort select{width:100%}
.wy-lim{display:flex;align-items:center;gap:8px;color:var(--dim);font-size:var(--fs-3)}
.wy-limit{width:96px}
.wy-ferr{margin:5px 0 0;color:var(--down);font-size:var(--fs-3);line-height:1.4}
/* The rule in words: a well with a title-colour bar down its left, as a
   condition sentence and the backtest's plan are. */
.wy-rule,.wy-sum-rule{max-width:90ch;margin:4px 0 12px;padding:10px 14px;border:1px solid var(--inset);border-left:2px solid var(--title);
  border-radius:0;background:var(--well);color:var(--ink);font-size:var(--fs-4);line-height:1.55}
.wy-sum-rule{margin:12px 0 0}
.wy-rule-gap{color:var(--down);font-weight:600}
.wy-fed :is(input,select,textarea)[aria-invalid="true"]{border-color:var(--down);box-shadow:0 0 0 1px var(--down)}
/* the bar is the window's foot ledge: the footer's darker stone under a
   divider */
.wy-fed-bar{position:sticky;bottom:0;z-index:3;padding:10px 16px 12px;border-top:1px solid var(--div);
  background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--foot-top),var(--foot-bot));background-color:var(--foot-bot);
  box-shadow:0 -14px 22px -18px rgba(0,0,0,.9)}
.wy-fed-bar .wy-actions{margin-top:0;align-items:center}
/* Up to 900px the Screener's #results scrolls sideways, which stops sticky:
   wyrm.js floatBar fixes the bar to the bottom (above the phone tab bar,
   whose height it sets as bottom) only while sticky would have held it. It
   stays under the field picker's sheet (z-index 30) and the tab bar (45). */
.wy-fed-bar.is-floating{position:fixed;left:0;right:0;z-index:29;
  padding:10px max(16px,env(safe-area-inset-right)) calc(12px + env(safe-area-inset-bottom)) max(16px,env(safe-area-inset-left))}
.wy-fed-bar.is-floating.over-nav{padding-bottom:12px}
.wy-fed-slot{flex:none}
.wy-fed-note{color:var(--warn);font-size:var(--fs-3)}
.wy-errsum{margin:0 0 14px;padding:9px 12px;scroll-margin-top:calc(var(--chrome-h,58px) + 14px);border:1px solid color-mix(in srgb,var(--down) 50%,transparent);
  border-radius:var(--r-3);background:var(--down-bg);color:var(--ink);font-size:var(--fs-3);line-height:1.45}
.wy-errsum:focus:not(:focus-visible){outline:none}
.wy-errsum>b{color:var(--down)}
.wy-errsum ul{margin:4px 0 0;padding-left:18px}
.wy-errlink{padding:0;border:0;border-radius:0;background:none;box-shadow:none;color:var(--ink);font-size:inherit;
  text-align:left;text-decoration:underline;text-underline-offset:3px}
.wy-errlink:hover{color:var(--emph)}
/* An inline question (discard changes, delete) in place of the buttons. */
.wy-confirm{align-items:center}
.wy-confirm-q{margin-right:4px;color:var(--ink);font-weight:600}
/* (its Yes is the red tone button, CONTROLS) */

/* The summary: the name, a game chip and the switch; the conditions as
   sentences; the sort and limit; the actions. */
.wy-sum-head{flex-wrap:wrap}
.wy-pane-head .wy-sum-title{flex:0 1 auto;font-family:var(--sans);font-size:var(--fs-6);font-weight:700;letter-spacing:0;overflow-wrap:anywhere}
.wy-sum-head .wy-chip{margin-left:0}
.wy-sum-head .wy-switch{margin-left:auto}
.wy-sum-title:focus{outline:none}
.wy-sum-desc{max-width:80ch;margin:0 0 4px;color:var(--dim);font-size:var(--fs-4);line-height:1.5}
.wy-sentences{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.wy-sentences li{padding:7px 12px;border:1px solid var(--inset);border-left:2px solid var(--title);
  border-radius:0;background:var(--well);color:var(--ink);font-size:var(--fs-4)}
.wy-sentences ul{list-style:none;margin:6px 0 0;padding:0;display:flex;flex-direction:column;gap:5px}
.wy-sentences ul li{border-left-color:var(--div2)}   /* a group's own conditions: the quiet bar */
.wy-s-o{color:var(--dim)}
.wy-s-v{color:var(--emph);font-weight:600}
.wy-s-g{color:var(--th-ink);font-size:var(--fs-3);font-weight:700}
.wy-s-d{display:block;margin-top:2px;color:var(--faint);font-size:var(--fs-2);line-height:1.35}

/* The field picker (wyrm.js openPicker): a search box over the grouped
   fields, under the field button; a full-width bottom sheet on a phone. A
   field the filter's game can't use stays listed, dimmed, with the reason.
   It is a small window, as the typeahead is (HEADER): the PANELS hairlines
   and stone on the deepest drop; a hovered or arrow-keyed field lifts to the
   hovered row's stone, its name to the bright yellow, the active one marked
   by a 2px bar in the title colour. */
.wy-pick{position:absolute;z-index:30;display:flex;flex-direction:column;max-height:min(460px,70vh);
  border:1px solid;border-color:var(--edge-hi) var(--edge-lo) var(--edge-lo) var(--edge-hi);border-radius:var(--r-4);
  background:var(--tex) 0 0/240px 240px,linear-gradient(180deg,var(--stone-top),var(--stone));background-color:var(--stone);
  box-shadow:var(--sh-3)}
.wy-pick-head{display:flex;gap:6px;padding:8px}
.wy-pick-q{flex:1 1 auto;min-width:0}
.wy-pick-x{flex:none;display:grid;place-items:center;width:40px;padding:0}
.wy-pick-lb{flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain;padding:0 6px 6px}
.wy-pick-gh{padding:8px 8px 4px;color:var(--th-ink);font-size:var(--fs-2);font-weight:600}
.wy-po{display:flex;flex-direction:column;gap:1px;min-height:44px;padding:7px 10px;border-radius:var(--r-2);cursor:pointer}
.wy-po:hover,.wy-po.is-active{background:var(--row-hover)}
.wy-po.is-active{box-shadow:inset 2px 0 0 var(--title)}
.wy-po:not([aria-disabled="true"]):is(:hover,.is-active) .wy-po-l{color:var(--emph)}
.wy-po-l{color:var(--ink);font-size:var(--fs-4);font-weight:600}
.wy-po[aria-selected="true"] .wy-po-l{color:var(--emph)}
.wy-po-u{color:var(--faint);font-size:var(--fs-2);line-height:1.35}
.wy-po-why{color:var(--warn);font-size:var(--fs-2);line-height:1.35}
.wy-po-tag{margin-left:8px;padding:1px 6px;border:1px solid var(--line);border-radius:var(--r-pill);color:var(--faint);
  font-size:var(--fs-1);font-weight:600;vertical-align:1px}
.wy-po[aria-disabled="true"]{cursor:default}
.wy-po[aria-disabled="true"] .wy-po-l{color:var(--faint)}
.wy-pick-none{margin:8px;color:var(--dim);font-size:var(--fs-3)}
.wy-pick-adv{margin:0 8px 8px;border-style:dashed;color:var(--gold);font-size:var(--fs-3)}   /* a face, as .wy-add */
@media(max-width:600px){
  .wy-pick{position:fixed;left:0;right:0;bottom:0;top:auto;width:auto;max-height:80vh;padding:4px 16px 16px;
    border-width:1px 0 0;border-radius:var(--r-4) var(--r-4) 0 0}
  .wy-pick-head,.wy-pick-lb{padding-left:0;padding-right:0}
  .wy-pick-adv{margin:4px 0 0}
}
/* Touch screens: every small control here is at least 44px tall. */
@media(pointer:coarse){
  .wy-field,.wy-mod,.wy-vchip,.wy-checks label,.wy-yn span,.wy-sumbtn,.wy-cols>summary,.wy-pick-adv{min-height:44px}
  .wy-yn span{display:flex;align-items:center}
  .wy-clause .wy-del{width:44px;height:44px}
}
.wy-sum .wy-confirm{margin-top:12px;padding:10px 12px;border:1px solid color-mix(in srgb,var(--down) 45%,transparent);
  border-radius:var(--r-3);background:var(--down-bg)}

/* Results: the count in the head, a notice when the list stops at the
   filter's limit, then the table (a header button sorts it; the name links
   to the item). The Admin page's preview uses the same markup. */
.wy-res-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px}
.wy-res>.wy-res-head{min-height:46px;padding:11px 16px 9px}
.wy-res-title{margin:0;color:var(--title);font-size:var(--fs-5b);font-weight:700;line-height:1.3;overflow-wrap:anywhere}
.wy-res-n{color:var(--name);font-weight:500}
.wy-res-fresh{display:flex;flex-wrap:wrap;gap:2px 16px;margin:8px 16px 0;color:var(--faint);font-size:var(--fs-3);line-height:1.45}
.adm-preview .wy-res-fresh{margin:6px 0 0}
.wy-res-tools{display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px;margin:10px 16px 0}
.adm-preview .wy-res-tools{margin:8px 0 0}
.wy-res-find{flex:1 1 240px;min-width:0;max-width:420px}
/* "Columns ▾" opens like a select, so it wears the shared text box. */
.wy-cols>summary{display:flex;align-items:center;min-height:40px;padding:8px 14px;border:1px solid var(--face-edge);
  border-radius:var(--r-3);background:var(--input-bg);box-shadow:inset 0 1px 0 var(--inset);color:var(--ink);cursor:pointer;list-style:none}
.wy-cols[open]>summary{border-color:var(--title)}
.wy-cols>summary::-webkit-details-marker{display:none}
.wy-cols>summary::after{content:"▾";margin-left:8px;color:var(--faint)}
.wy-cols[open]{flex-basis:100%}
.wy-cols-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,220px),1fr));gap:4px 12px;margin-top:8px;
  padding:10px 12px;border:1px solid var(--inset);border-radius:var(--r-3);background:var(--well)}   /* a well */
.wy-cols-list label{display:flex;align-items:flex-start;gap:8px;font-size:var(--fs-3);cursor:pointer}
.wy-cols-list input{margin-top:3px;accent-color:var(--gold)}
.wy-cols-list small{display:block;color:var(--faint);font-size:var(--fs-1)}
.wy-res-none{margin:10px 16px;color:var(--dim);font-size:var(--fs-3)}
.wy-cell-sub{display:block;color:var(--faint);font-size:var(--fs-1);white-space:nowrap}
.wy-sumbtn{display:block;margin:4px 0 0 auto;padding:2px 8px;color:var(--gold);font-size:var(--fs-2)}   /* a face (base button) */
.wy-sumrow td{color:var(--dim);font-size:var(--fs-3);text-align:left;white-space:normal}
.wy-res-cut,.wy-res-empty{margin:12px 16px;font-size:var(--fs-3);line-height:1.5}
.wy-res-cut{padding:8px 12px;border:1px solid color-mix(in srgb,var(--warn) 45%,transparent);border-radius:var(--r-3);
  background:var(--warn-bg);color:var(--ink)}
.wy-res-empty{color:var(--dim)}
.adm-preview :is(.wy-res-cut,.wy-res-empty){margin:8px 0}
.wy-res-scroll{overflow-x:auto}
.wy-res-t thead th{padding:0}
.wy-th{width:100%;padding:10px 14px;border:0;border-radius:0;background:none;box-shadow:none;color:inherit;font:inherit;
  letter-spacing:inherit;text-transform:inherit;text-align:inherit;white-space:nowrap}
.wy-th:focus-visible{outline-offset:-2px}
/* the sorted column's head (and one under the pointer) in the bright title
   colour, as every sortable head (.wy-lp-t, TABLES th.sortable): a state,
   not the action gold */
.wy-res-t thead th:hover,.wy-res-t thead th.s-on{color:var(--title-hot)}
.wy-res-t thead th.s-asc .wy-th::after{content:" ▲";font-size:var(--fs-1)}
.wy-res-t thead th.s-desc .wy-th::after{content:" ▼";font-size:var(--fs-1)}
.wy-res-t .wy-res-rank{width:56px;color:var(--faint)}
.wy-res-link{color:var(--ink);text-decoration:none}
.wy-res-link:hover{color:var(--emph);text-decoration:underline}

@media(max-width:760px){
  /* The results table scrolls inside .wy-res-scroll: the Item column stays
     put (the # column scrolls away first), so a row never loses its name. */
  .wy-res-t thead th.l,.wy-res-t tbody td.l{position:sticky;left:0;z-index:1;background:var(--panel)}
  /* opaque in the row's own paint (TABLES): the head band, the row bands */
  .wy-res-t thead th.l{background:var(--head-band)}
  .wy-res-t tbody td.l{background:var(--row-a)}
  .wy-res-t tbody tr:where(:nth-child(even of :not([hidden],.ad-row))) td.l{
    background:linear-gradient(var(--row-stripe),var(--row-stripe)),var(--panel)}
  .wy-res-t tbody tr:hover td.l{background:var(--row-hover)}
  /* "Show the sum": the line spans the whole table, so its text is pinned to
     the visible part and wraps there. */
  .wy-sumrow td>.wy-sum-text{position:sticky;left:12px;display:block;max-width:calc(100vw - 2*var(--gutter) - 40px)}
  .wy-screener{grid-template-columns:minmax(0,1fr);grid-template-rows:none;gap:12px}
  .wy-screener>:is(.wy-filters,.wy-work,.wy-res),.wy-screener:has(>.wy-res:not([hidden]))>.wy-work{grid-column:1;grid-row:auto}
  .wy-filters>.wy-pane-head{display:none}
  /* the folded list's title strip (PANELS) */
  .wy-filters-toggle{display:flex;align-items:center;justify-content:space-between;width:100%;min-height:46px;padding:10px 16px;
    border:0;border-radius:inherit;color:var(--title);font-size:var(--fs-4);
    font-weight:700;text-align:left}
  .wy-filters-toggle::after{content:"▾";color:var(--faint);transition:transform var(--dur-2) var(--ease-out)}
  .wy-filters.is-open>.wy-filters-toggle::after{transform:rotate(180deg)}
  .wy-filters:not(.is-open)>.wy-filters-body{display:none}
}

/* ---- BACKTEST (wyrm.js renderBacktest) ------------------------------------
   Admin only; everyone else gets the COMING SOON gate. Three windows down
   the content column, each with its title strip (PANELS): Set up a test,
   Results and Saved reports. The host is a .view-fill (SHELL) and Results
   takes the spare height, so a page with no test yet still reaches the
   footer. The setup reads at a form's width; the tables sit in
   .wy-res-scroll, so a phone scrolls them inside their panel, never the page. */
.wy-backtest{display:flex;flex-direction:column;gap:16px;min-width:0}
.wy-bt-res{display:flex;flex-direction:column;flex:1 0 auto}
.wy-bt-res-body{flex:1 0 auto;display:flex;flex-direction:column;min-width:0}
.wy-backtest .wy-pane-head h2:focus,.wy-bt-rep-head h3:focus,.wy-bt-saved:focus{outline:none}
.wy-bt-setup-body{container:wy-bt/inline-size}
.wy-bt-setup-body>*{max-width:1120px}
/* The item list's names are the longest ("The brain's own list: Long-term
   uptrends"), so its column is the widest and the form a little wider than
   the other forms. */
.wy-bt-setup-body>.wy-bt-grid{max-width:1240px}
.wy-bt-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.5fr) minmax(0,.75fr) minmax(0,.75fr);gap:0 16px}
.wy-bt-grid :is(select,input){width:100%;min-width:0}
.wy-bt-grid .wy-help{margin:5px 0 0;font-size:var(--fs-3);line-height:1.4}
.wy-bt-n{font-family:var(--mono);font-size:var(--fs-num)}
.wy-bt-n[aria-invalid="true"],.wy-bt-save input[aria-invalid="true"]{border-color:var(--down);box-shadow:0 0 0 1px var(--down)}
@container wy-bt (max-width:960px){.wy-bt-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@container wy-bt (max-width:520px){.wy-bt-grid{grid-template-columns:minmax(0,1fr)}}
/* What the test will do, in one sentence (the condition sentences' look),
   then anything that keeps Run off. */
.wy-bt-plan{margin:2px 0 0;padding:10px 14px;border:1px solid var(--inset);border-left:2px solid var(--title);
  border-radius:0;background:var(--well);color:var(--dim);font-size:var(--fs-4);line-height:1.55}
.wy-bt-plan b{color:var(--ink);font-weight:600}
.wy-bt-pre{display:flex;flex-direction:column;gap:6px;margin-top:10px}
.wy-bt-pre:empty{display:none}
.wy-bt-pre .wy-note{margin:0;padding:8px 12px;border:1px solid color-mix(in srgb,var(--warn) 45%,transparent);
  border-radius:var(--r-3);background:var(--warn-bg);color:var(--ink);font-size:var(--fs-3);line-height:1.45}
.wy-bt-setup .wy-actions{margin-top:14px}
:is(.wy-bt-setup,.wy-bt-save) .mprimary{width:auto;padding:9px 20px}

/* Results: the running clock, a guide before the first test, a refusal in
   plain words, or the test itself (what ran, the summary and its notes, the
   trades by test date) with Save report under it. */
/* plain stone, the mascot whole (GATES' .empty-img): nothing glows */
.wy-bt-guide,.wy-bt-prog{flex:1 1 auto;display:flex;flex-direction:column;align-items:center;justify-content:center;
  min-height:220px;padding:24px;text-align:center}
:is(.wy-bt-guide,.wy-bt-prog) p{margin:0;max-width:56ch;color:var(--dim);font-size:var(--fs-4);line-height:1.6}
.wy-bt-guide b{color:var(--ink);font-weight:600}
.wy-bt-prog .wy-bar{width:min(100%,520px)}
/* the running clock: a square well track, a sliding gold fill */
.wy-bar{height:6px;border-radius:var(--r-pill);background:var(--well);overflow:hidden;
  border:1px solid var(--inset);margin-bottom:12px}
.wy-bar i{display:block;height:100%;width:38%;border-radius:var(--r-pill);background:var(--accent);
  animation:wybar 1.1s ease-in-out infinite alternate;will-change:transform}
@keyframes wybar{from{transform:translateX(-26%)}to{transform:translateX(190%)}}
/* the global 1ms clamp would turn this into a strobe; a still, half-lit bar says "busy" instead */
@media(prefers-reduced-motion:reduce){.wy-bar i{animation:none;width:100%;opacity:.45}}
.wy-bt-res-body>.wy-res-cut{margin:0 0 12px}
.wy-bt-fail{padding:12px 14px;border:1px solid color-mix(in srgb,var(--down) 45%,transparent);
  border-radius:var(--r-3);background:var(--down-bg)}
.wy-bt-fail h3{margin:0 0 4px;color:var(--ink);font-size:var(--fs-5);font-weight:700}
.wy-bt-fail p{margin:0;color:var(--ink);font-size:var(--fs-4);line-height:1.5}
.wy-bt-meta{margin:0;color:var(--dim);font-size:var(--fs-4);line-height:1.55}
.wy-bt-meta b{color:var(--ink);font-weight:600}
:is(.wy-bt-res-body,.wy-bt-rep-view) .wy-res-empty{margin:4px 0}
/* The summary: plain group names over mono figures; nothing here sorts. */
.wy-bt-sum tbody tr{cursor:default}
.wy-bt-sum td.l{min-width:150px;color:var(--ink);font-weight:600;white-space:normal}
.wy-bt-notes{list-style:none;margin:10px 0 0;padding:0;display:flex;flex-direction:column;gap:3px;
  color:var(--faint);font-size:var(--fs-3);line-height:1.5}
/* Trades by test date: one group per date, the first open. The groups share
   their column widths, so together they read as one table. */
.wy-bt-days{display:flex;flex-direction:column;gap:8px}
.wy-bt-day{border:1px solid var(--inset);border-radius:var(--r-3);background:var(--well);overflow:hidden}   /* a well */
.wy-bt-day>summary{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 14px;padding:10px 14px;
  cursor:pointer;list-style:none}
.wy-bt-day>summary::-webkit-details-marker{display:none}
.wy-bt-day>summary::before{content:"▸";flex:none;width:10px;color:var(--faint);transition:transform var(--dur-2) var(--ease-out)}
.wy-bt-day[open]>summary::before{transform:rotate(90deg)}
.wy-bt-day>summary:hover{background:var(--row-hover)}
.wy-bt-day>summary:focus-visible{outline:2px solid var(--gold);outline-offset:-2px}
.wy-bt-day[open]>summary{border-bottom:1px solid var(--div2)}
.wy-bt-day-d{color:var(--title);font-size:var(--fs-4);font-weight:700}
.wy-bt-day-s{color:var(--dim);font-size:var(--fs-3)}
/* the rows' first band, as a board's (TABLES): a well or a pane under the
   rows never shows through the odd ones */
.wy-bt-t{background-color:var(--row-a)}
.wy-bt-trades{table-layout:fixed;min-width:640px}
.wy-bt-trades .c-rank{width:72px}
.wy-bt-trades .c-score{width:110px}
.wy-bt-trades .c-band{width:112px}
.wy-bt-trades .c-chg{width:124px}
.wy-bt-trades .mi>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Phones keep the figures that answer "did it work": the summary keeps
   Group, Median change, Rose and Worst; the trades keep Rank, Item and
   Change (the .bt-wide columns drop), so nothing hides behind a sideways
   scroll. */
@media(max-width:640px){
  .wy-backtest .bt-wide{display:none}
  .wy-bt-trades{min-width:0}
  .wy-bt-trades .c-rank{width:52px}
  .wy-bt-trades .c-chg{width:88px}
  .wy-bt-sum td.l{min-width:0}
  .wy-bt-sum :is(th,td).l{width:40%}
  .wy-bt-sum thead th{white-space:normal}
  .wy-bt-t :is(th,td){padding-inline:8px}
}
/* Save this report: the name and the button on one line. */
.wy-bt-save-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px}
.wy-bt-save-row input{flex:1 1 280px;max-width:560px;min-width:0}
.wy-bt-saved{margin:16px 0 0;color:var(--dim);font-size:var(--fs-3)}

/* Saved reports: one row per report (open it, or Delete, which asks first);
   an open report reads under the list with the same tables. */
.wy-bt-replist>.wy-item{flex-wrap:wrap}
.wy-bt-replist .wy-item-open{flex:1 1 0}
/* Delete is a face with the dim label (it asks first), warming to the red
   tint on hover. */
.wy-bt-rm{flex:none;padding:6px 12px;background:var(--face);color:var(--dim);font-size:var(--fs-3)}
.wy-bt-rm:hover{color:var(--down);border-color:var(--down);background:var(--down-bg)}
.wy-bt-replist .wy-confirm{flex:1 0 100%;margin:0;padding:10px 12px 12px 13px;border-top:1px solid var(--row-line)}
.wy-bt-rep-view:not(:empty){margin-top:16px}
.wy-bt-rep-head{display:flex;align-items:center;gap:10px;margin:0 0 8px}
.wy-bt-rep-head h3{flex:1 1 auto;min-width:0;margin:0;color:var(--title);font-size:var(--fs-5b);font-weight:700;overflow-wrap:anywhere}
.wy-rep-cfg{margin:14px 0 0}
.wy-rep-cfg>summary{cursor:pointer;color:var(--dim);font-size:var(--fs-3)}
.wy-rep-cfg pre{max-height:320px;overflow:auto;margin:8px 0 0;background:var(--well);
  border:1px solid var(--inset);border-radius:var(--r-2);padding:10px;font-size:var(--fs-2)}   /* a well */
@media(max-width:640px){.wy-backtest{gap:12px}}

.wy-lp-note{color:var(--faint);font-size:var(--fs-2);margin:10px 0 4px}
.wy-lp-t th:nth-child(2),.wy-lp-t td:nth-child(2){text-align:left;width:auto}
.wy-lp-t th:first-child,.wy-lp-t td:first-child{width:44px}
.wy-lp-t th:not(:first-child):not(:nth-child(2)):not(.spk),.wy-lp-t td:not(:first-child):not(:nth-child(2)):not(.spk){width:96px}
/* the sparkline column: 128px well from .board td.spk, flexible past 1180px (below) */
/* Long-term Trends fills the column like everything above it; past 1180px the
   sparkline column takes the row's slack (name stays min-content), so the
   width reads as a 30-day band per row rather than an empty name cell. */
@media(min-width:1181px){
  /* Fixed layout, known shares (clamp() is not honoured on table columns, so
     plain percentages per tier): rank 44px, the band 14% (the SVG caps itself
     at 320px), wells 7.5% with up to eight of them (tier 1) and 5.5% with
     twelve (tier 2) — both sum well under 100% — and the item name takes the
     rest and ellipsises. The wells pad 8px a side, not 14px: at the narrowest
     width of each tier that still leaves ~70px, which holds a 14px mono change
     pill such as +12.3% (66px with its tint) without clipping. */
  .wy-lp-t{table-layout:fixed;width:100%}
  .wy-lp-t th.l,.wy-lp-t td.l{white-space:nowrap}
  .wy-lp-t .mi{min-width:0}
  .wy-lp-t .mi>span:not(.mi-ico){display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .wy-lp-t th:first-child,.wy-lp-t td:first-child{width:44px}
  .wy-lp-t th:not(:first-child):not(.l):not(.spk),.wy-lp-t td:not(:first-child):not(.l):not(.spk){width:7.5%;
    padding-left:8px;padding-right:8px}
  .wy-lp-t th.spk,.wy-lp-t td.spk{width:14%}
}
@media(min-width:1990px){
  .wy-lp-t th:not(:first-child):not(.l):not(.spk),.wy-lp-t td:not(:first-child):not(.l):not(.spk){width:5.5%}
}
/* Trends' wide-only extras come in two tiers as the table gets room (base
   table with the band ≈ 891px; each extra is a 96px well; column = window −
   44 below the rails):
     tier 1 — 7d, 30-day low, 30-day high        (≥1179px table; with the rails
              on from 1560 that is a ≥1590px window — and it must stay off
              below that too, or it would flip when the rails arrive)
     tier 2 — daily volume, buy limit, 24h turnover, 1y range (≥1563px table
              → ≥1990px window)
   The band itself is capped at 320px; the rest is shared spacing. */
@media(min-width:1590px){.wy-lp-t .w-only{display:table-cell}}
@media(min-width:1990px){.wy-lp-t .w-only2{display:table-cell}}
.wy-lp-t tbody tr{cursor:pointer}
/* click-to-sort headers: pointer, and the sorted column's head (and a head
   under the pointer) in the bright title yellow with a direction arrow: a
   state, so not the action gold. */
.wy-lp-t thead th{cursor:pointer;user-select:none}
.wy-lp-t thead th:hover{color:var(--title-hot)}
.wy-lp-t thead th.s-on{color:var(--title-hot)}
.wy-lp-t thead th.s-asc::after{content:" ▲";font-size:var(--fs-1)}
.wy-lp-t thead th.s-desc::after{content:" ▼";font-size:var(--fs-1)}
.dim{color:var(--dim)}

/* ---------- Wyrm Picks board + admin panels ---------- */
/* An admin panel is a window in the edition of the area it sits in (ADMIN:
   its padding, strip and flat stone are set there). */
.wy-admin{padding:12px 14px;margin:14px 0}
.wy-tr-t tbody tr,.wy-cl-t tbody tr{cursor:pointer}
.wy-tr-t thead th,.wy-cl-t thead th{cursor:pointer;user-select:none}
.wy-tr-t thead th:hover,.wy-cl-t thead th:hover,.wy-tr-t thead th.s-on,.wy-cl-t thead th.s-on{color:var(--title-hot)}   /* as .wy-res-t */
.wy-tr-t thead th.s-asc::after,.wy-cl-t thead th.s-asc::after{content:" ▲";font-size:var(--fs-1)}
.wy-tr-t thead th.s-desc::after,.wy-cl-t thead th.s-desc::after{content:" ▼";font-size:var(--fs-1)}
/* An open trade's progress to its target: a square well track and the gain
   green fill (wyrm.js turns a loss's red). */
.prog{display:inline-block;width:64px;height:7px;border-radius:var(--r-1);background:var(--well);
  border:1px solid var(--inset);vertical-align:middle;overflow:hidden}
.prog i{display:block;height:100%;background:var(--up);border-radius:var(--r-1)}
.prog-n{font-size:var(--fs-2);margin-left:7px}
/* A closed trade's outcome: a square chip, the tone's tint inside a 1px edge
   of the tone at half strength; the words stay the engine's caps (a status,
   as the head's chips). The outcome colours the chip itself (<span class="cs
   cs-win">, no nested <b>), and by the MONEY, not the mechanism: a trailing
   stop that banked a profit is a win and must not read in loss-red; a flat
   expiry is neither. */
.cs{flex-shrink:0;font-size:var(--fs-3);font-weight:500;color:var(--dim);background:var(--chip-flat);
  border:1px solid var(--face-edge);border-radius:var(--r-pill);padding:2px 9px;white-space:nowrap;letter-spacing:.04em}
.cs-exp{color:var(--warn);background:var(--warn-bg)}
.cs-win{color:var(--up);background:var(--up-bg)}
.cs-loss{color:var(--down);background:var(--down-bg)}
.cs:is(.cs-exp,.cs-win,.cs-loss){border-color:color-mix(in srgb,currentColor 50%,transparent)}
/* Closed trades in six figures: one window of wells, as the cards above
   (.perf-grid): each well its figure in the pixel numerals (a gain green, a
   loss red), under it what the figure is, its unit and the trades it
   covers. */
.wy-cl-sum{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:5px;margin:10px 0 14px;padding:4px}
.wy-cl-sum>div{display:flex;flex-direction:column;gap:3px;min-width:0;padding:8px 11px 7px 10px;border:1px solid var(--inset);
  background:var(--row-a)}
.wy-cl-sum b{color:var(--fig);font-family:var(--pix);font-size:var(--fs-7);font-weight:400;line-height:1;letter-spacing:.01em;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.wy-cl-sum b.up{color:var(--up)} .wy-cl-sum b.down{color:var(--down)}
.wy-cl-sum span{color:var(--dim);font-size:var(--fs-2);font-weight:600;line-height:1.3}

/* ---------- Admin page ---------- */
/* A tag beside a name (a list's slug, its game, a brain's state): a square
   well chip, its words in the dim ink, as the overview's slots (the faint
   ink straight on stone was 4.2:1). */
.wy-chip{display:inline-block;font-size:var(--fs-1);padding:1px 6px;border:1px solid var(--inset);
  border-radius:var(--r-pill);background:var(--well);color:var(--dim);vertical-align:middle;margin-left:6px}
.wy-help{display:block;font-size:var(--fs-2);color:var(--faint);font-style:normal;margin-top:2px}
.wy-sl-vis{font-size:var(--fs-3);background:var(--input-bg);color:var(--ink);box-shadow:inset 0 1px 0 var(--inset);
  border:1px solid var(--face-edge);border-radius:var(--r-2);padding:4px 6px;flex-shrink:0}   /* the shared text box */
.wy-brain-ed .wy-fgrid{grid-template-columns:repeat(auto-fit,minmax(210px,1fr))}
/* ---------- Admin: traffic and search stats ---------- */
/* The counts are wells in their section's window, as the overview's skills
   strip and Wyrm Picks' cards: each figure in the pixel numerals in the
   figure yellow, under it what it counts and its window ("views · 30d"). */
.wy-stat-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:5px;margin:10px 0}
.wy-stat-tiles>div{display:flex;flex-direction:column;gap:3px;min-width:0;padding:8px 11px 7px 10px;border:1px solid var(--inset);
  background:var(--row-a)}
.wy-stat-tiles b{color:var(--fig);font-family:var(--pix);font-size:var(--fs-7);font-weight:400;line-height:1;letter-spacing:.01em;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.wy-stat-tiles span{color:var(--dim);font-size:var(--fs-2);font-weight:600;line-height:1.3}
.wy-chart{width:100%;height:auto;margin-top:6px}
.wy-chart .ax{stroke:var(--line);stroke-width:1}
.wy-chart .s1{fill:none;stroke:var(--accent);stroke-width:2}
.wy-chart .s2{fill:none;stroke:var(--dim);stroke-width:1.5;stroke-dasharray:4 3}
.wy-chart .lb{fill:var(--faint);font-size:var(--fs-1)}
.wy-chart .lb.e{text-anchor:end}
.wy-chart .k1{fill:var(--accent)} .wy-chart .k2{fill:var(--dim)}
.wy-stat-cols{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media(max-width:700px){.wy-stat-cols{grid-template-columns:1fr}}
/* a small heading over a ledger, in the column-head ink (as .perf-h) */
.wy-sub{display:block;margin:8px 0 4px;color:var(--name);font-size:var(--fs-3);font-weight:600}
/* The stat ledgers are the GE offer list at a compact pitch (TABLES): heads
   on the head band, rows on the two stone bands, counts in the figure
   yellow. Only a row that opens an item is a link. */
.wy-stat-tbl{width:100%;border-collapse:collapse;background-color:var(--row-a)}
.wy-stat-tbl :is(td,th){padding:5px 8px;font-size:var(--fs-3)}
.wy-stat-tbl td{border-bottom:1px solid var(--row-line)}
.wy-stat-tbl th{text-align:right}
.wy-stat-tbl th.l,.wy-stat-tbl td.l{text-align:left}
.wy-stat-tbl td.n{text-align:right;font-variant-numeric:lining-nums tabular-nums;color:var(--fig)}
.wy-stat-tbl tbody tr:not([data-h]){cursor:default}
/* the traffic ranges: a tray of faces (CONTROLS) */
.wy-rngs{display:inline-flex}
.wy-rng{padding:2px 11px;font-size:var(--fs-2)}
/* The admin's key boxes are the shared text box (written out: one is a
   textarea, which the base input rule does not reach); its button is a face
   with a gold label. */
.wy-inp{background:var(--input-bg);border:1px solid var(--face-edge);border-radius:var(--r-2);box-shadow:inset 0 1px 0 var(--inset);
  color:var(--ink);padding:7px 10px;min-width:260px;margin:6px 8px 0 0}
.wy-inp:focus{border-color:var(--title)}
.wy-ta{display:block;width:100%;max-width:720px;font-family:inherit;font-size:var(--fs-3)}
.wy-btn{border-radius:var(--r-2);color:var(--gold);padding:7px 14px}

/* ---------- Wyrm's read: ladder legibility ----------
   One line per row where it fits. A figure is never cut: a label too long
   for its row (RS3's "vs all-time high · low") wraps beside it instead, as
   in every side panel (.t-row, ITEM TERMINAL); the ellipsis that was here
   cut RS3's "75% · +150%" once the text face grew wider. */
#wyrm-read .wr-px b{color:var(--fig)}
#wyrm-read .wr-px{border-top:1px dashed var(--div2);border-bottom:1px dashed var(--div2);margin:2px 0}
.wr-sub{color:var(--faint);font-weight:400;font-size:var(--fs-2);margin-left:5px}
.wr-tf{float:right;color:var(--faint);font-family:var(--sans);font-weight:400;font-size:var(--fs-2);letter-spacing:.05em;text-shadow:none}

/* ---------- OSRS Paper Trading -----------------------------------------
   A compact three-column trading terminal in the shared shell: its title is
   the page head, its status chips (Simulated, the generation, Live prices;
   .head-chip, SHELL) and Reset sit in the head's tool slot, and it takes the
   side rails like every tool page. The account ledger remains
   server-authoritative; the chart reuses the item-page transport cache.
   Dressed as every other tool: the account's five figures are one window of
   wells (the Wyrm Picks cards, .perf-grid); each panel is a window whose
   head is its title strip (the market panel's is the strip that holds the
   item and its four figures); the watch list, the ledger and the orders are
   GE rows under the head band (TABLES); the chart's choices and Buy / Sell
   are trays; the order is its side's tone button (CONTROLS). The panels
   carry words straight on their stone (field labels, the chart's key, a
   note), so they wear no grain (PANELS); the cards' window keeps it, its
   words sitting in wells. At 1920x1080 the page is one screen: the head,
   the cards, the 530px workspace and the ledger's three rows fit above the
   footer, so nothing here may grow a line without checking that sum. */
.pt-host{min-width:0;width:100%}
.pt-page{width:100%;max-width:none;margin:0;padding:0}
.pt-account-menu{flex:0 0 auto;padding:6px 10px;color:var(--dim);font-size:var(--fs-2)}
.pt-loading{min-height:260px;display:grid;place-items:center;color:var(--dim)}
.pt-panel,.pt-cards{min-width:0;overflow:hidden}
.pt-panel,.pt-modal>div{--panel-grain:none}
/* The account: five wells, each a small orb (the overview's stone orb on its
   one ring, the glyph in the title colour) beside what the figure is, the
   figure in the pixel numerals with its unit (a P/L in its direction), and
   what it covers. */
.pt-cards{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:5px;margin-bottom:9px;padding:4px}
.pt-metric{display:flex;align-items:center;gap:10px;min-width:0;padding:6px 10px 5px;border:1px solid var(--inset);
  background:var(--row-a)}
.pt-metric-icon{display:grid;place-items:center;flex:0 0 34px;width:34px;height:34px;border-radius:50%;
  background:radial-gradient(circle at 40% 32%,#3a3a36,#0c0b09 75%);box-shadow:0 0 0 2px var(--ring);
  color:var(--title);font:700 15px/1 var(--mono)}
.pt-metric-copy{min-width:0}
.pt-cards .pt-metric-copy>span,.pt-cards small{display:block;color:var(--faint);font-size:var(--fs-1);line-height:1.25}
.pt-cards .pt-metric-copy>span{color:var(--dim);font-weight:600}
.pt-cards b{display:block;margin:2px 0 1px;color:var(--fig);font:400 var(--fs-7)/1 var(--pix);letter-spacing:.01em;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.pt-cards b .num{font:inherit}
.pt-cards b small{display:inline;margin-left:4px;color:var(--dim);font:500 var(--fs-3) var(--sans)}   /* the unit */
.pt-metric.is-up b{color:var(--up)}.pt-metric.is-down b{color:var(--down)}
.pt-workspace{display:grid;grid-template-columns:minmax(270px,.78fr) minmax(430px,2.1fr) minmax(290px,.92fr);
  gap:9px;align-items:stretch;margin-bottom:9px}
/* each panel's head is its title strip (PANELS): the title (DISPLAY TIER)
   over what the panel holds */
.pt-panel-head{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:45px;
  padding:7px 12px 6px}
.pt-panel-head b{display:block;color:var(--title);line-height:1.2}
.pt-panel-head span{display:block;margin-top:2px;color:var(--dim);font-size:var(--fs-2)}
.pt-watch,.pt-market,.pt-ticket{height:530px}
.pt-watch{display:flex;flex-direction:column}.pt-watch-search{display:block;padding:9px 10px;border-bottom:1px solid var(--div2)}
.pt-watch-search input{width:100%;height:34px;padding:6px 10px}
/* The list's column heads sit on the head band, as a table's (TABLES): what
   each column is over its unit and window, in sentence case. */
.pt-watch-cols{display:grid;grid-template-columns:minmax(0,1fr) 72px 58px;align-items:center;gap:7px;padding:5px 9px 4px;
  background:var(--head-band);box-shadow:inset 0 -1px 0 var(--div2);color:var(--th-ink);font-size:var(--fs-2);font-weight:600;line-height:1.3}
.pt-watch-cols small{display:block;color:var(--faint);font-size:var(--fs-1);font-weight:400;line-height:1.25}
.pt-watch-cols span:not(:first-child){text-align:right}.pt-watch-list{min-height:0;flex:1;overflow:auto}
/* GE rows: two stone bands, the hovered row lifted with its name in the
   bright yellow; the open item is the lifted stone with a 2px title-colour
   bar. Prices in the figure yellow, a change in its direction. */
.pt-watch-row{display:grid;grid-template-columns:minmax(0,1fr) 72px 58px;align-items:center;gap:7px;width:100%;
  min-height:54px;padding:6px 9px;border:0;border-bottom:1px solid var(--row-line);border-radius:0;
  color:var(--ink);background:var(--row-a);box-shadow:none;text-align:left}
.pt-watch-row:nth-child(even){background:var(--row-stripe)}
.pt-watch-row:hover,.pt-watch-row.on{background:var(--row-hover)}
.pt-watch-row.on{box-shadow:inset 2px 0 0 var(--title)}
.pt-watch-row:is(:hover,.on) .mi b{color:var(--emph)}
/* The list scrolls in its panel: until it reaches its end its foot fades out
   (paper.js marks .is-end), so the last row reads as "more below", never as
   a row cut in half. */
.pt-watch-list:not(.is-end){-webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 44px),transparent);
  mask-image:linear-gradient(180deg,#000 calc(100% - 44px),transparent)}
.pt-watch-row>.num{text-align:right;font-size:var(--fs-2);white-space:nowrap}
.pt-watch-row>.num:not(.up,.down,.flat){color:var(--fig)}
.pt-watch-row .mi,.pt-order-row .mi,.pt-table .mi{display:flex;align-items:center;gap:8px;min-width:0;text-align:left}
.pt-watch-row .mi>span,.pt-order-row .mi>span,.pt-table .mi>span{min-width:0}
.pt-watch-row .mi b,.pt-watch-row .mi small,.pt-order-row .mi b,.pt-order-row .mi small,.pt-table .mi b,.pt-table .mi small{display:block;line-height:1.3}
.pt-watch-row .mi b,.pt-order-row .mi b,.pt-table .mi b{overflow:hidden;text-overflow:ellipsis;color:var(--name);white-space:nowrap;font-size:var(--fs-2)}
.pt-watch-row .mi small,.pt-order-row .mi small,.pt-table .mi small{color:var(--faint);font-size:var(--fs-1)}
.pt-watch-row img,.pt-ticket-instrument img,.pt-table .mi img,.pt-order-row .mi img{width:31px;height:31px;object-fit:contain;image-rendering:auto;flex:0 0 auto}
/* The market panel's head is its title strip (PANELS), holding the item and
   its four figures: each under what it is and its window, its unit beside
   it, split by quiet dividers. */
.pt-market{display:flex;min-width:0;flex-direction:column}.pt-market-head{display:flex;align-items:center;justify-content:space-between;
  gap:18px;min-height:87px;padding:10px 13px}
.pt-instrument{display:flex;align-items:center;gap:10px;min-width:0}.pt-instrument-icon{display:grid;place-items:center;flex:0 0 52px;width:52px;height:52px;
  border:1px solid var(--inset);border-radius:var(--r-3);background:var(--well)}   /* a well */
.pt-instrument img{width:44px;height:44px;object-fit:contain}.pt-instrument b,.pt-instrument small{display:block}.pt-instrument b{overflow:hidden;text-overflow:ellipsis;
  color:var(--name);font-size:var(--fs-5);font-weight:600;white-space:nowrap}.pt-instrument small{color:var(--faint);font-size:var(--fs-1)}
.pt-market-stats{display:grid;grid-template-columns:repeat(4,minmax(74px,1fr));gap:0;min-width:min(55%,520px)}
.pt-market-stats>div{min-width:0;padding:2px 10px;border-left:1px solid var(--div2);text-align:right}
.pt-market-stats span,.pt-market-stats b{display:block}.pt-market-stats span{color:var(--dim);font-size:var(--fs-1);font-weight:600;line-height:1.3}
.pt-market-stats b{margin-top:3px;color:var(--fig);font:600 var(--fs-4)/1.1 var(--mono);white-space:nowrap}
.pt-market-stats b small{margin-left:3px;color:var(--dim);font:500 var(--fs-1) var(--sans)}   /* the unit */
/* the sign colour wins over the figure yellow, as in the side panels (.t-row) */
.pt-market-stats b.up{color:var(--up)}.pt-market-stats b.down{color:var(--down)}.pt-market-stats b.flat{color:var(--flat)}
/* Instant buy and sell are two prices, not a gain and a loss: both are the
   figure yellow (the sign colours mean direction only), in the order the
   label names them, parted by a dim slash. */
.pt-market-stats .pt-spread b{display:flex;justify-content:flex-end;align-items:baseline;gap:5px}.pt-market-stats .pt-spread i{font-style:normal}
.pt-market-stats .pt-spread .pt-sep{color:var(--dim);font-weight:400}
.pt-market-stats .pt-spread b small{margin-left:-4px}
/* the chart's choices: a band under the head holding two trays of faces,
   the chosen one the open tab (CONTROLS) */
.pt-chart-tools{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:7px 9px;border-bottom:1px solid var(--div2);background:var(--head-band)}
.pt-chart-ranges,.pt-chart-modes{display:flex}.pt-chart-tools button{min-width:39px;padding:3px 7px;font-size:var(--fs-1)}
.pt-chart-modes button{min-width:auto}.pt-chart-stage{position:relative;min-height:0;flex:1;background:color-mix(in srgb,var(--inset-bg) 86%,transparent)}
.pt-chart-stage canvas{display:block;width:100%;height:100%;min-height:330px}.pt-chart-status{position:absolute;inset:0;display:none;place-items:center;color:var(--faint);font-size:var(--fs-2)}
.pt-chart-stage.is-loading .pt-chart-status,.pt-chart-status:not(:empty){display:grid}.pt-chart-stage.is-loading canvas{opacity:.35}
/* The chart's key: each swatch in the canvas's own colour (paper.js reads
   the same tokens). */
.pt-chart-foot{display:flex;align-items:center;gap:15px;min-height:27px;padding:5px 11px;border-top:1px solid var(--div2);
  color:var(--faint);font-size:var(--fs-1)}.pt-chart-foot>span{display:inline-flex;align-items:center;gap:5px}.pt-chart-foot>span:last-child{margin-left:auto}
.pt-chart-foot i{display:inline-block;width:13px;height:2px;background:var(--ch-price)}.pt-chart-foot .pt-key-volume{height:7px;background:var(--theme-accent);opacity:.45}
.pt-market-empty{color:var(--faint)}
.pt-ticket{position:relative;overflow:auto}.pt-ticket form{padding:9px 11px 10px}/* Buy / Sell: a tray of two faces; the chosen side is its tone button
   (CONTROLS), green or red. */
.pt-side{display:grid;grid-template-columns:1fr 1fr;margin-bottom:8px}
.pt-side button{padding:5px;text-transform:uppercase;font-weight:700}
/* the item being ordered and what the order comes to are wells; the field
   labels are in the column-head ink, as the screener's (.wy-lab) */
.pt-ticket-instrument{display:flex;align-items:center;gap:9px;min-height:48px;margin-bottom:8px;padding:6px 8px;border:1px solid var(--inset);
  border-radius:var(--r-2);background:var(--well)}.pt-ticket-instrument span{min-width:0}.pt-ticket-instrument b,.pt-ticket-instrument small{display:block}
.pt-ticket-instrument b{overflow:hidden;text-overflow:ellipsis;color:var(--name);font-size:var(--fs-3);font-weight:600;white-space:nowrap}.pt-ticket-instrument small,.pt-muted{color:var(--faint);font-size:var(--fs-1)}
.pt-field{position:relative;display:block;margin-bottom:7px}.pt-field>span{display:flex;justify-content:space-between;margin:0 0 3px;color:var(--th-ink);font-size:var(--fs-2);font-weight:600}
.pt-field em{color:var(--faint);font-style:normal;font-weight:400}.pt-field input,.pt-field select{display:block;width:100%;min-width:0;height:34px}
.pt-grid2{display:grid;grid-template-columns:1fr 1fr;gap:7px}.pt-estimate{margin:2px 0 8px;padding:7px 9px;border:1px solid var(--inset);border-radius:var(--r-2);background:var(--well)}
.pt-estimate>div{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:2px 0;color:var(--dim);font-size:var(--fs-1)}
.pt-estimate b{color:var(--fig);font:600 var(--fs-3)/1.2 var(--mono)}.pt-estimate b small{margin-left:3px;color:var(--dim);font:500 var(--fs-1) var(--sans)}
.pt-estimate>small{display:block;margin-top:4px;color:var(--faint);font-size:var(--fs-1);line-height:1.3}
.pt-submit{width:100%;font-weight:800}   /* the tone button (CONTROLS) of the chosen side */.pt-note{min-height:15px;margin-top:5px;color:var(--down);font-size:var(--fs-1)}
/* The ledger's head is a title strip (PANELS) holding its tabs as faces, the
   open one the open tab (CONTROLS), as the header's tabs sit on its bar; a
   tab's count sits in a small well. */
.pt-ledger{min-height:132px}.pt-ledger-tabs{display:flex;align-items:center;gap:3px;min-height:43px;padding:0 8px}
.pt-ledger-tabs button{min-width:142px;padding:5px 12px;text-align:left;white-space:nowrap}   /* the strip scrolls on a phone */
.pt-ledger-tabs button i{display:inline-grid;place-items:center;min-width:21px;height:21px;margin-left:6px;border:1px solid var(--inset);border-radius:var(--r-2);
  background:var(--well);color:var(--dim);font:normal var(--fs-1)/1 var(--mono)}
.pt-ledger-tabs>span{margin-left:auto;padding-right:8px;color:var(--faint);font-size:var(--fs-1)}
/* The ledger's tables are GE rows (TABLES: the head band, the second stone
   band, the lift), the first band --row-a and every figure the figure
   yellow; compact, with a 12px head line and 47px rows. */
.pt-table-wrap{width:100%;overflow:auto}.pt-table{width:100%;border-collapse:collapse;white-space:nowrap;font-size:var(--fs-2);background-color:var(--row-a)}
.pt-table th{padding:6px 10px;font-size:var(--fs-2);line-height:1.3}
.pt-table td{padding:7px 10px;text-align:right;font-family:var(--mono);font-variant-numeric:tabular-nums}
.pt-table td:not(.l){color:var(--fig)}
.pt-table th.l,.pt-table td.l{text-align:left}
.pt-table td.l{font-family:var(--sans)}   /* the item's name in the text face; only figures are mono */
.pt-badge{display:inline-block;min-width:40px;padding:2px 5px;border-radius:var(--r-1);text-align:center;font:600 var(--fs-1)/1.4 var(--mono)}
.pt-badge.buy{color:var(--up);background:var(--up-bg)}.pt-badge.sell{color:var(--down);background:var(--down-bg)}
.pt-order-list{max-height:300px;overflow:auto}.pt-order-row{display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:10px;padding:8px 12px;
  border-bottom:1px solid var(--row-line);background:var(--row-a);font-size:var(--fs-2)}
.pt-order-row:nth-child(even){background:var(--row-stripe)}
.pt-order-row:last-child{border-bottom:0}.pt-order-row>span{color:var(--faint);white-space:nowrap}.pt-order-row button,.pt-table button{padding:5px 9px;font-size:var(--fs-1)}
.pt-empty{min-height:86px;display:grid;place-items:center;padding:18px;color:var(--faint);text-align:center;font-size:var(--fs-2)}
/* Reset: a window (PANELS) on the deepest drop, its title in the display
   face at 20px (DISPLAY TIER). */
.pt-modal{position:fixed;z-index:90;inset:0;display:grid;place-items:center;padding:18px;background:var(--backdrop);backdrop-filter:blur(5px)}
.pt-modal>div{width:min(480px,100%);padding:19px;box-shadow:var(--sh-3)}
.pt-modal h3{margin:0 0 7px;color:var(--title);line-height:1.2}.pt-modal p{margin:0 0 15px;color:var(--dim);font-size:var(--fs-3)}
.pt-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:13px}.pt-reset-go{font-weight:700}   /* the red tone button (CONTROLS) */

/* The terminal keeps the content column's edges at every width (no padding
   of its own), and stacks its ticket below the chart before the three
   columns' 963px minimum stops fitting the column. The cards' wells reflow
   in their window: 5, 3, 2, then 1 across. */
@media(max-width:1260px){
  .pt-workspace{grid-template-columns:260px minmax(400px,1fr) 285px}
  .pt-market-stats{grid-template-columns:1fr 1fr;min-width:245px;row-gap:9px}.pt-market-stats>div:nth-child(odd){border-left:0}
  .pt-watch,.pt-market,.pt-ticket{height:520px}.pt-chart-stage canvas{min-height:315px}
}
@media(max-width:1010px){
  .pt-cards{grid-template-columns:repeat(3,minmax(0,1fr))}
  .pt-workspace{grid-template-columns:minmax(210px,.75fr) minmax(430px,1.7fr)}.pt-ticket{grid-column:1/-1;height:auto;max-height:none}.pt-ticket form{display:grid;grid-template-columns:220px 1fr 1fr;gap:8px 10px}.pt-ticket .pt-side,.pt-ticket-instrument{grid-column:1}.pt-ticket .pt-grid2,.pt-ticket #pt-limit-row,.pt-ticket #pt-protect{grid-column:2}.pt-ticket .pt-estimate,.pt-ticket .pt-submit,.pt-ticket .pt-note{grid-column:3}.pt-ticket .pt-submit{align-self:end}
}
@media(max-width:720px){
  .pt-page{padding:0 0 90px}
  .pt-cards{grid-template-columns:1fr 1fr}.pt-metric:last-child{grid-column:1/-1}
  /* the market panel takes its parts' height, the chart a definite one: a
     fixed panel left the canvas's own minimum running under the chart's key */
  .pt-workspace{display:flex;flex-direction:column}.pt-watch{height:330px}.pt-market{height:auto}.pt-chart-stage{flex:none;height:315px}.pt-ticket{height:auto}.pt-market-head{align-items:flex-start;flex-direction:column;gap:8px}.pt-market-stats{width:100%;min-width:0}.pt-ticket form{display:block}.pt-ledger-tabs{overflow-x:auto}.pt-ledger-tabs button{min-width:126px}.pt-ledger-tabs>span{display:none}
}
@media(max-width:450px){
  .pt-generation{display:none}.pt-account-menu{font-size:0}.pt-account-menu::after{content:"Reset";font-size:var(--fs-1)}
  .pt-cards{grid-template-columns:1fr}.pt-metric:last-child{grid-column:auto}.pt-metric-icon{width:31px;height:31px;flex-basis:31px}
  .pt-market-stats{grid-template-columns:1fr 1fr}.pt-chart-modes{display:none}.pt-chart-stage{height:270px}.pt-chart-stage canvas{min-height:270px}.pt-grid2{grid-template-columns:1fr}.pt-order-row{grid-template-columns:minmax(0,1fr) auto}.pt-order-row>span{display:none}
}

/* Screen-reader-only: real content for crawlers and assistive tech, zero pixels. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* ---------- #seo-item: the SEO worker's server-rendered content ----------
   This block used to be injected inside #results, where the app's first
   render() deleted it — which also meant nobody ever saw it, so it needed no
   styling. It now lives OUTSIDE #results so it survives into the DOM that
   crawlers index (see the seo-worker header), which means humans see it too.
   Hiding it would be both a lie to the reader and a hidden-text risk at
   19,650 pages, so it is styled as what it honestly is: a plain-text summary
   of the same facts the app shows above, sitting quietly at the foot of the
   page. On item pages the terminal overlay covers it entirely. Its words are
   the dim tone, its headings sans in the title colour (they name data, and
   are too small for the display face), its figures the figure yellow, every
   divider the quiet --div2. */
#seo-item{box-sizing:border-box;width:100%;min-width:0;margin:26px auto 40px;padding:20px 20px 0;
  border-top:1px solid var(--div2);color:var(--dim);font-size:var(--fs-3);line-height:1.65}
#seo-item h2{margin:22px 0 8px;color:var(--title);font-size:15px;font-weight:500}
#seo-item h3{margin:16px 0 4px;color:var(--ink);font-size:13.5px;font-weight:500}
#seo-item p{margin:0 0 10px;max-width:74ch}
#seo-item img{float:left;margin:2px 10px 6px 0}
#seo-item table{border-collapse:collapse;margin:10px 0 14px;min-width:min(420px,100%)}
#seo-item th{text-align:left;font-weight:400;color:var(--faint);padding:3px 18px 3px 0;
  white-space:nowrap}
#seo-item td{padding:3px 0;color:var(--fig);font-variant-numeric:lining-nums tabular-nums}
#seo-item a{color:var(--gold)}
#seo-item time{color:var(--faint)}
/* Hub pages are a long two-column list of item → price. */
#seo-item table td:first-child{padding-right:22px}

/* Core market/trend pages already explain themselves in the live board. Their
   server-rendered block exists to keep useful crawlable navigation in the
   rendered DOM, so present it as a compact related-pages footer instead of a
   duplicate article. Crucially it stays in #main's centre track above 1560px;
   without the explicit grid placement it auto-flowed into the right ad rail.
   Every related block and drawer is a panel (PANELS), so its top edge is its
   frame, not the article's rule. */
#seo-item.seo-related{display:flex;align-items:center;gap:18px;margin-top:22px;
  padding:13px 16px;border-top-color:transparent}
/* A drawer's words sit straight on its stone, so it has no grain (PANELS):
   the disclosure's title colour and the faint counts keep 4.5:1. */
#seo-item.seo-related,.list-empty-related{--panel-grain:none}
#seo-item.seo-related h2{flex:0 0 auto;margin:0;color:var(--title);font-size:var(--fs-3);
  font-weight:600;letter-spacing:.02em}
#seo-item.seo-related p{display:flex;flex-wrap:wrap;gap:4px 9px;margin:0;max-width:none}
#seo-item.seo-related a{white-space:nowrap}
/* Category cards already carry the explanation and counts. Their crawlable
   links stay in a native, keyboard-accessible drawer, sharing the heading and
   grid's exact width (the SHELL's column) in every layout. Closed, it is one
   30px line inside its 1px frame: the 11px marker (never under the 11px
   floor) sits in the summary's 16px line. */
#seo-item.seo-related.seo-category-links{display:block;margin:6px auto 0;
  padding:0;font-size:var(--fs-2);line-height:1.4}
#seo-item.seo-category-links .category-directory-links{min-width:0}
#seo-item.seo-category-links summary{min-height:28px;padding:6px 12px;cursor:pointer;
  color:var(--gold-quiet);font-size:var(--fs-2);line-height:16px}
#seo-item.seo-category-links summary::marker{font-size:var(--fs-1);color:var(--gold-quiet)}
#seo-item.seo-category-links summary:focus-visible{outline:2px solid var(--gold);outline-offset:-2px}
#seo-item.seo-category-links .category-directory-count{margin-left:8px;color:var(--faint);font-size:var(--fs-1)}
#seo-item.seo-category-links .category-directory-content{padding:0 12px 10px}
#seo-item.seo-category-links .category-directory-context{display:flex;flex-wrap:wrap;align-items:center;
  gap:5px 16px;padding:6px 0 8px;border-top:1px solid var(--div2)}
#seo-item.seo-category-links .category-directory-index{display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,210px),1fr));gap:4px 18px}
#seo-item.seo-category-links .category-directory-index a{display:flex;min-width:0;
  align-items:baseline;justify-content:space-between;gap:8px;font-size:var(--fs-2);text-decoration:none;white-space:normal}
#seo-item.seo-category-links .category-directory-index a:hover span:first-child{text-decoration:underline}
#seo-item.seo-category-links .category-link-count{flex:none;color:var(--faint);font-variant-numeric:lining-nums tabular-nums}
/* All items in the pager owns this drawer. No extra strip, margin or border
   exists when closed. Context links are part of the expanded content only.
   An item's link wraps rather than cutting: its price, unit and window
   ("1.66M gp (last trade)") stay together on one line, under the name when
   the name is long. */
#seo-item.seo-related.seo-all-items-links{display:block;min-height:0;margin:0 auto;padding:4px 10px}
#seo-item.seo-all-items-links[hidden]{display:none!important}
.market.catalogue-table{width:100%}
#seo-item.seo-all-items-links .seo-index-drawer{padding:2px 2px 7px}
#seo-item.seo-all-items-links .seo-index-drawer>nav:last-child{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));
  gap:4px 14px;padding-top:9px;border-top:1px solid var(--div2)}
#seo-item.seo-all-items-links .seo-index-drawer>nav:last-child a{min-width:0;overflow-wrap:anywhere;white-space:normal;font-size:var(--fs-2)}
#seo-item.seo-all-items-links .seo-index-drawer>nav:last-child span{color:var(--faint);font-family:var(--mono);font-size:var(--fs-1);
  white-space:nowrap}
#seo-item.seo-all-items-links .seo-context{display:flex;min-height:24px;align-items:center;justify-content:center;gap:0}
#seo-item.seo-all-items-links .seo-context strong{margin-right:12px;color:var(--dim);font-size:var(--fs-2);font-weight:600}
#seo-item.seo-all-items-links .seo-context a{padding:0 12px;border-left:1px solid var(--div2);font-size:var(--fs-2)}
#seo-item.list-seo-drawer .list-related-links{display:flex;flex-wrap:wrap;justify-content:center;gap:4px 14px;
  padding:4px 0 8px;font-size:var(--fs-2)}
#seo-item.list-seo-drawer .list-item-links:empty{display:none}
#seo-item.list-seo-drawer [hidden],.catalogue-table tr[hidden]{display:none!important}
#seo-item.list-seo-drawer .list-methodology{max-width:none;margin:0;padding:2px 0 8px;
  color:var(--faint);font-size:var(--fs-2);line-height:1.45}
.list-empty-related{margin:8px auto 0;padding:5px 10px;color:var(--faint);font-size:var(--fs-2)}
.list-empty-related>summary{cursor:pointer;color:var(--gold-quiet)}
.list-empty-related .list-related-links,.list-empty-related .seo-context{display:flex;flex-wrap:wrap;
  align-items:center;gap:4px 14px;padding:7px 0 2px;font-size:var(--fs-2)}
.list-empty-related .seo-context strong{color:var(--dim);font-weight:600}
@media(max-width:640px){
  #seo-item.seo-related{display:block;margin-top:16px;padding:12px}
  #seo-item.seo-related h2{margin-bottom:5px}
  #seo-item.seo-related.seo-category-links{margin-bottom:0}
  #seo-item.seo-related.seo-all-items-links{min-height:0;margin-top:0;padding:4px 8px}
  #seo-item.seo-all-items-links .seo-context{min-height:32px;justify-content:flex-start;overflow-x:auto;white-space:nowrap}
  #seo-item.seo-all-items-links .seo-context strong{margin-right:8px}
  #seo-item.seo-all-items-links .seo-context a{padding:0 10px}
}

/* =========================================================== CONTROLS ====
   The controls are one flat family in every edition, and nothing glows: a
   control is lit by its own face, never by a halo. Where each part lives:
     the face         base `button` (top of the sheet): --face, a 1px
                      --face-edge, a 1px --face-hi along its top; its hover
                      (the lighter face, a bright-yellow label) and press are
                      the interaction states beside it. A neutral face has the
                      dim label, an action face the gold one: .msecondary
                      (MODALS), .wl-follow (WATCHLIST), .doc-links a (STATIC
                      DOCUMENTS), .home-game-actions a (HOME), .ca-more a
                      (CATEGORIES), the pager links (MARKET), .t-back and
                      .t-burger (ITEM TERMINAL), the screener's chips (.wy-pre,
                      .wy-vchip, .wy-mod, .wy-add, .wy-sumbtn, .wy-btn)
     the gold action  two golds (--btn-*), a darker edge, a top highlight;
                      the primary action only (gold law): .btn-signin
                      (HEADER), .mprimary (MODALS; .wy-head-new, the gates'
                      and About's calls), .t-follow (ITEM TERMINAL), .ca-go
                      (CATEGORIES), .mw-house-cta (HOUSE PANELS). One hover
                      for all of them, in the interaction states
     the open tab     a state, never an action: --on-fill, a 1px --on-edge,
                      the --on-ink label (the header's open tab, the chosen
                      tray face, .page-current, .t-follow.on, .adm-nav a.on;
                      a ticked option card wears it washed, below)
     a tray           below
     a tone button    below: buy, sell and a destructive confirmation
     the text box     base `select,input`: --input-bg, a 1px --face-edge, a
                      1px shade along its top; focus turns the edge --title
                      (written out where a textarea or a button wears it:
                      .wy-desc, .wy-inp, .wy-field, .wy-cols>summary)
     a small window   the menus, the typeahead, the tooltip, the chart
                      readout, the toast and the field picker: the PANELS
                      hairlines on stone and the popover drops (--sh-2/3)
     dividers         --div under a strip, --div2 between a menu's groups
                      (.menu .sep)
     item sprites     a hard 1px black drop, no glow (.mi-ico img, TABLES;
                      .cat-tile .ct-i, CATEGORIES)
   Layout, density, advertising and responsive contracts live with their
   components; the header and footer paint themselves (HEADER, FOOTER).

   Trays: a row of choices is a shallow well (--well, one --face-edge line,
   2px of padding) holding faces 2px apart; the chosen one is the open tab,
   as the game switch is in the header. Only the paint and the tray's gap
   and padding are here; each tray's layout (flex or grid, its faces'
   padding and type) stays with its component, which must not repaint them.
   A pager's page links (MARKET, SEARCH RESULTS) are a tray of its faces. */
:is(.ch-group,.wy-seg-opts,.wy-yn,.wy-rngs,.home-range-tabs,.home-view-tabs,.pt-chart-ranges,.pt-chart-modes,.pt-side,
  .catalogue-page-links,.search-pager){
  gap:2px;padding:2px;border:1px solid var(--face-edge);border-radius:var(--r-2);background:var(--well);box-shadow:none}
:is(.ch-tf,.ch-mode,.ch-ci,.ch-chip,.wy-seg-opts span,.wy-yn span,.wy-rng,.home-range-tabs button,.home-view-tabs button,
  .pt-chart-tools button,.pt-side button,.pt-ledger-tabs button,.wy-checks label,.adm-opt){
  border:1px solid var(--face-edge);border-radius:var(--r-2);background:var(--face);box-shadow:inset 0 1px 0 var(--face-hi);color:var(--dim)}
:is(.ch-tf,.ch-mode,.ch-ci,.ch-chip,.wy-rng,.home-range-tabs button,.home-view-tabs button,.pt-chart-tools button,
  .pt-ledger-tabs button):is(:disabled,[aria-disabled="true"]){
  border-color:var(--face-edge);background:var(--face-off);box-shadow:none;color:var(--faint)}
:is(.ch-tf,.ch-mode,.ch-ci,.ch-chip,.wy-rng,.home-range-tabs button,.home-view-tabs button,.pt-chart-tools button,
  .pt-ledger-tabs button).on,
:is(.wy-seg-opts,.wy-yn) input:checked+span,.wy-checks label:has(input:checked){
  border-color:var(--on-edge);background:var(--on-fill);box-shadow:none;color:var(--on-ink)}
/* A ticked option card (ADMIN: a name over a help line, often three ticked
   in a row) is the calm open tab: a row of solid fills read as one heavy
   band. It keeps its face, takes the open tab's warm edge, and the fill
   washes in from its left, as the open filter's does (SCREENER AND WYRM
   TOOLS); the tick and the yellow name say the rest. */
.adm-opt:has(input:checked){border-color:var(--on-edge);
  background:linear-gradient(90deg,color-mix(in srgb,var(--on-fill) 60%,var(--face)),var(--face) 70%)}
/* Tone buttons: buy and sell (Paper Trading's chosen side and its submit)
   and a destructive confirmation. Two stops of the tone, a darker edge, a
   light line along the top and a near-black label (9-12:1); no glow. A
   white label on loss red was 2.3:1. */
.pt-submit,.pt-side button.on,.wy-confirm .wy-danger,.wy-confirm .wy-danger:hover,.pt-reset-go{--tone:var(--up);--tone-ink:#03120a;
  border:1px solid color-mix(in srgb,var(--tone) 45%,#000);border-radius:var(--r-3);
  background:linear-gradient(180deg,color-mix(in srgb,var(--tone) 85%,#fff),var(--tone));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45);color:var(--tone-ink)}
.pt-submit.is-sell,.pt-side button[data-side="sell"].on,.wy-confirm .wy-danger,.wy-confirm .wy-danger:hover,.pt-reset-go{
  --tone:var(--down);--tone-ink:#170304}
.pt-submit:hover,.pt-side button.on:hover,.wy-confirm .wy-danger:hover,.pt-reset-go:hover{filter:brightness(1.08)}

/* ===================================================== APP PAGES (v79) ====
   The game overview, the category and item-list directories, the watchlist,
   the homepage dashboard and the item page, on the shared tokens, the PANELS
   frame (their surfaces .t-panel, .t-stats, .t-sim, .home-total and .wl-pick
   are PANELS members) and the change pills in TABLES. Generic boards and tables
   stay in the MARKET and TABLES sections; what follows is each page's own
   layout. */

/* =========================================================== OVERVIEW ====
   /osrs and /rs3: the pulse strip, four equal boards and the "Across the
   market" band fill the screen from the header to the site footer (footer ad
   included) with no blank band. The grid answers to the width it actually
   gets (#results is the container, so the ad rails count): four boards once
   each can hold its name beside two numeric wells, two by two below that,
   one column on phones. The overview is a .view-fill (SHELL): its last row,
   the band, takes the height the boards leave, and app.js fitOverview picks
   the boards' and the band's row counts from the measured space (four
   across the band keeps its heads and at least two rows; on a window too
   short for that the page scrolls a little). On phones everything keeps its
   natural height. */
#results:has(>.market.overview){container:ov-results/inline-size}
.market.overview{grid-template-columns:minmax(0,1fr);gap:10px;align-items:stretch;align-content:start}
@container ov-results (min-width:700px){.market.overview{grid-template-columns:repeat(2,minmax(0,1fr));
  grid-template-rows:auto auto auto minmax(150px,1fr)}}
@container ov-results (min-width:1360px){.market.overview{grid-template-columns:repeat(4,minmax(0,1fr));
  grid-template-rows:auto auto minmax(50px,1fr)}}

/* Pulse: the game's skills strip. One window (PANELS) holding six stat
   slots, each a shallow well (one 1px inset line, no shadow) led by a
   minimap orb, its figure in the pixel numerals (VT323, used only in stat
   wells: these and Wyrm Picks' cards, perf-*) and, under it, the words that
   say what the figure is, its unit and its window. Every slot is
   top-aligned, so the six figures share one line whatever their captions
   wrap to. */
.market.overview>.pulse{grid-column:1/-1;display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:5px;padding:4px}
/* six across: the short counts take less room, the long captions more */
@container ov-results (min-width:1100px){
  .market.overview>.pulse{grid-template-columns:.8fr .8fr 1.24fr 1.04fr 1.04fr 1.08fr}}
.market.overview .pulse>*{min-width:0;min-height:58px;padding:9px 11px 6px 10px;border:1px solid var(--inset);
  background:var(--row-a);color:inherit;text-decoration:none}
.market.overview .pulse>a.pt:hover{background:var(--row-hover)}
.market.overview .pulse>div{display:grid;grid-template-columns:38px minmax(0,1fr);column-gap:10px;
  align-content:start;align-items:start}
.market.overview .pulse>div>:not(.bd){grid-column:2}
/* The orbs, each with one thin ring: a stone clock (prices as of), a blue
   grid (items tracked) and a gold up-down (breadth), the glyph a mask in
   the orb's centre. A slot that has no item yet (a skeleton, a fact the data
   cannot support) keeps an empty item orb, as an item slot draws it. */
.market.overview .pulse>div::before{content:"";grid-column:1;grid-row:1/span 2;justify-self:center;align-self:start;
  width:34px;height:34px;margin-top:2px;border-radius:50%;
  background:radial-gradient(circle at 40% 32%,#3a3a36,#0c0b09 75%);box-shadow:0 0 0 2px var(--ring)}
.market.overview .pulse>div:is(:nth-child(1),:nth-child(2),#pt-breadth)::before{
  background:radial-gradient(circle at 36% 30%,color-mix(in srgb,var(--orb),#fff 55%) 0 10%,var(--orb) 48%,color-mix(in srgb,var(--orb),#000 62%) 100%)}
.market.overview .pulse>div:is(:nth-child(1),:nth-child(2),#pt-breadth)::after{content:"";grid-column:1;grid-row:1/span 2;
  justify-self:center;align-self:start;width:18px;height:18px;margin-top:10px;background:#fff7e0;
  -webkit-mask:var(--orb-i) center/contain no-repeat;mask:var(--orb-i) center/contain no-repeat}
.market.overview .pulse>div:nth-child(1){--orb:var(--orb-a);
  --orb-i:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='M12 7.4V12l3.2 2.2'/%3E%3C/svg%3E")}
.market.overview .pulse>div:nth-child(2){--orb:var(--orb-b);
  --orb-i:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Crect x='3.5' y='3.5' width='7.5' height='7.5'/%3E%3Crect x='13' y='3.5' width='7.5' height='7.5'/%3E%3Crect x='3.5' y='13' width='7.5' height='7.5'/%3E%3Crect x='13' y='13' width='7.5' height='7.5'/%3E%3C/svg%3E")}
.market.overview .pulse>#pt-breadth{--orb:var(--orb-c);
  --orb-i:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 19.5V5M3.8 9.2 8 5l4.2 4.2M16 4.5V19M11.8 14.8 16 19l4.2-4.2'/%3E%3C/svg%3E")}
/* Item slots (busiest, top riser, top faller) are links to the item: the
   whole slot is clickable and the item sits in an orb of its own, ringed
   green or red for the riser and the faller. */
.market.overview .pulse a.pt{display:flex;align-items:flex-start;gap:10px}
.market.overview .pulse a.pt .mi-ico{flex:none;width:34px;height:34px;margin:2px 2px 0;border-radius:50%;
  background:radial-gradient(circle at 40% 32%,#3a3a36,#0c0b09 75%);box-shadow:0 0 0 2px var(--ring);filter:none}
.market.overview .pulse a.pt.t-up .mi-ico{box-shadow:0 0 0 2px #2f7d2b}
.market.overview .pulse a.pt.t-down .mi-ico{box-shadow:0 0 0 2px #8e2a1e}
.market.overview .pulse a.pt .mi-ico img{width:26px;height:26px}
.market.overview .pulse .pt-t{display:block;min-width:0;margin:0}
/* The six figures: VT323 at 27px (24 on phones), the figure yellow, a
   riser's or faller's in its direction; never clipped mid-glyph. The unit
   word beside a figure ("7.3M items") is text. */
.market.overview .pulse b{display:block;font-family:var(--pix);font-size:var(--fs-7);font-weight:400;line-height:1;
  letter-spacing:.01em;font-variant-numeric:tabular-nums;color:var(--fig);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.market.overview .pulse b.up{color:var(--up)}
.market.overview .pulse b.down{color:var(--down)}
.market.overview .pulse b small{font:500 var(--fs-3) var(--sans);letter-spacing:0;color:var(--dim)}
/* The caption: what the figure is, its unit and its window, in sentence
   case. v81: it names them in full, so it wraps (never cut); an item slot's
   caption ends in the item's name, the only text that may be cut, after
   three lines. A count is kept with its word ("1,888 up"). */
.market.overview .pulse :is(div,.pt-t)>span:not(.bd){display:block;margin:3px 0 0;color:var(--faint);
  font-size:var(--fs-2);line-height:1.28;letter-spacing:.01em;white-space:normal;overflow-wrap:break-word}
.market.overview .pulse :is(div,.pt-t)>span:not(.bd)::first-letter{text-transform:uppercase}
.market.overview .pulse .pt-t>span:not(.bd){display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:3}
.market.overview .pulse span i{font-style:normal;letter-spacing:0;color:var(--ink)}
.market.overview .pulse span i.nw{white-space:nowrap}
/* The freshness slot's live light: green = live, like the header status. */
.pt-dot{display:inline-block;width:9px;height:9px;margin-right:7px;vertical-align:3px;border-radius:50%;
  background:radial-gradient(circle at 35% 30%,#d7ffc9 0 18%,#3fc449 55%,#145f1c);box-shadow:0 0 0 1px rgba(0,0,0,.55);
  animation:coinpulse 1.2s ease-in-out infinite}
/* Breadth: the GE offer's progress bar (the green share of the moving
   items over a red track) beside its figure, on the figure's line, so it
   never adds height when its count lands. */
.market.overview .pulse>#pt-breadth{grid-template-columns:38px auto minmax(0,1fr)}
.market.overview #pt-breadth>b{grid-row:1}
.market.overview #pt-breadth>span:not(.bd){grid-column:2/4;grid-row:2}
.market.overview .pulse .bd{display:block;grid-column:3;grid-row:1;align-self:center;height:9px;margin:0 0 0 12px;
  overflow:hidden;background:linear-gradient(180deg,#a93a2c,#74201a);box-shadow:0 0 0 1px rgba(0,0,0,.5)}
.market.overview .pulse .bd i{display:block;height:100%;background:linear-gradient(180deg,#72e263,#319d2c)}
.market.overview .pulse b.skel{width:70%}
.market.overview .pulse span.skel{width:50%}

/* Boards: a 36px title strip (PANELS) with the list's glyph in a dark 26px
   slot (CSS only, keyed on the board), the title centred in the strip with
   the window it covers, and "See all" at the strip's end. */
.market.overview .board{display:flex;flex-direction:column;container:ov-board/inline-size}
/* Nothing in an overview board overflows it (fitOverview hides the rows
   that do not fit; a band list clips its own), and its track is
   minmax(0,1fr), so it need not clip: the RS3 corner ticks then sit over
   its frame, as on every other window (PANELS). */
.market.overview .board{overflow:visible}
.market.overview .board::before{inset:-1px}
.market.overview .ov-traded,.market.overview .ov-valuable{--ov-mark:var(--gold);
  --ov-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round'%3E%3Cpath d='M5 20v-6M10 20V5M15 20v-9M20 20v-4'/%3E%3C/svg%3E")}
.market.overview .ov-risers{--ov-mark:var(--up);
  --ov-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 15l7-7 7 7'/%3E%3C/svg%3E")}
.market.overview .ov-fallers{--ov-mark:var(--down);
  --ov-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 9l7 7 7-7'/%3E%3C/svg%3E")}
.market.overview .board .b-head{position:relative;align-items:center;justify-content:flex-start;gap:8px;
  min-height:36px;padding:3px 12px 3px 46px}
.market.overview .board .b-head::before,.market.overview .board .b-head::after{content:"";position:absolute;top:50%;translate:0 -50%}
/* the list's badge: a dark slot with a single light lip under it, the glyph
   in the list's own colour (gold, green, red) */
.market.overview .board .b-head::before{left:11px;width:26px;height:26px;background:var(--well);box-shadow:0 1px 0 var(--div2)}
.market.overview .board .b-head::after{left:16px;width:16px;height:16px;background:var(--ov-mark);
  -webkit-mask:var(--ov-icon) center/contain no-repeat;mask:var(--ov-icon) center/contain no-repeat}
.market.overview .board .b-head b{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.1}
/* Centred: the title and "See all" share the strip's free space (two auto
   margins), so the title and its window sit in the middle of the strip. */
.market.overview .board:not(.ov-bp) .b-head b{margin-left:auto}
.market.overview .board .b-head .b-sub{flex:none;white-space:nowrap}
.market.overview .board .b-head a{flex:none;margin-left:auto;padding:2px 0 2px 6px;white-space:nowrap}
.market.overview .board>.empty{display:grid;flex:1;place-items:center;padding:24px 18px}

/* Rows: one 43px pitch (the 30px icon well plus 6px padding and the row's
   1px line) and fixed columns, so names ellipsise and no board ever clips
   its last column. Separate borders: collapsed, the first row is half a
   line shorter than the rest (the column heads' line is a shadow, not a
   border), and fitOverview, which measures it as the pitch, would come out
   short by half a pixel a row and push the page past the window. */
.market.overview .board table{table-layout:fixed;width:100%;border-collapse:separate;border-spacing:0}
.market.overview .board td:not(.l):not(.spk),.market.overview .board th:not(.l):not(.spk){width:96px}
.market.overview .board th.c-day:not(.l):not(.spk){width:100px}
/* "items, last full hour" (92px in Signika) on one line, so every board's
   heads are two lines and the four boards' rows line up. The head gives up
   most of its left padding for it (as in the approved renders); its right
   padding stays the figures' 9px, so it still stands over them. */
.market.overview .board th.c-vol:not(.l):not(.spk){width:106px}
.market.overview .board th.c-vol:not(.l):not(.spk){padding-left:4px}
/* The Price column gives 6px back to the names: "214.00B" is 61px in the
   14.5px mono, and its unit line "gp, last trade" still fits on one line. */
.market.overview .board th.c-mid:not(.l):not(.spk){width:90px;padding-left:3px}
.market.overview .board th.spk,.market.overview .board td.spk{width:22%}
.market.overview .board thead th{padding:4px 9px 5px;letter-spacing:.01em}
.market.overview .board tbody td{padding:6px 9px}
.market.overview .board :is(th,td).l{padding-right:4px}
.market.overview .board .mi{min-width:0;gap:9px}
.market.overview .board .mi span{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.skel-tr{pointer-events:none}
.skel-tr .skel{display:block;height:14px}
.skel-tr .mi b.skel{width:72%}
.catalogue-table .skel-tr .mi>span:last-child{flex:1;max-width:320px}
.catalogue-table .skel-tr td.num .skel{width:64px;margin-left:auto}
.catalogue-pager[aria-hidden="true"] .skel{display:inline-block;width:96px;height:14px}

/* A column shows only on a board wide enough for it: the third numeric well
   (p-hide), then the 30-day band, then 7d / 30d from the band's series. */
.market.overview .board :is(th,td).p-hide,
.market.overview .board :is(th,td).spk,
.market.overview .board :is(th,td).w-only{display:none}
@container ov-board (min-width:440px){.market.overview .board :is(th,td).p-hide{display:table-cell}}
@container ov-board (min-width:620px){.market.overview .board :is(th,td).spk{display:table-cell}}
@container ov-board (min-width:840px){.market.overview .board :is(th,td).w-only{display:table-cell}}

/* Rows shown per board: app.js fitOverview measures the space between the
   boards' top and the footer and stamps data-rows (5 to 10; five two by two
   and on phones), so all four boards end on one line over the band's two or
   more rows. Until it runs a board shows five. */
.market.overview .board tbody tr:nth-child(n+11),
.market.overview:not([data-rows]) .board tbody tr:nth-child(n+6),
.market.overview[data-rows="5"] .board tbody tr:nth-child(n+6),
.market.overview[data-rows="6"] .board tbody tr:nth-child(n+7),
.market.overview[data-rows="7"] .board tbody tr:nth-child(n+8),
.market.overview[data-rows="8"] .board tbody tr:nth-child(n+9),
.market.overview[data-rows="9"] .board tbody tr:nth-child(n+10){display:none}

/* Across the market: four panels under the four boards (a subgrid, so each
   lines up under its board), two by two below them in that layout, stacked
   on phones. Each is a small headed table: a one-line head (its title and
   the window), a row of column heads (.ov-cols: what each column is, its
   unit and window) and a list of 34px rows whose cells carry their units.
   The column heads and the rows share one grid template per panel, so the
   heads stand over their figures. The list is a size container: a row shows
   only when the list is tall enough for all of it, so a panel never shows
   half a row (up to ten). On phones a panel keeps its natural height with
   four rows. v86: the columns give
   the category names room for the longest official name (at most 20
   characters, Signika 13.5px: "Cooking ingredients", 115px) on one line
   from 1920x1080 with the ad rails; narrower still, a name takes a second
   15px line inside its 34px row, never an ellipsis, so the rows' height and
   fitOverview's maths never change. */
.market.overview>.ov-band{grid-column:1/-1;display:grid;grid-template-columns:subgrid;grid-auto-rows:minmax(50px,1fr);
  row-gap:12px;min-height:0}
.market.overview .ov-bp{min-height:0}
.market.overview .ov-bp .b-head{flex:none;justify-content:center;min-height:36px;padding:3px 12px;gap:8px}
.market.overview .ov-bp .b-head::before,.market.overview .ov-bp .b-head::after{content:none}
/* The band's titles are window titles like the boards' (the display face at
   20px in the title colour, DISPLAY TIER), centred in their strips with the
   window beside them at every width. Each is its panel's tooltip carrier,
   marked by a small info sign rather than an underline (it is not a link),
   and reachable by keyboard: a 16px dark well holding an 11px "i". */
.market.overview .ov-bp .b-head b{display:inline-flex;flex:none;align-items:center;gap:6px;font-family:var(--display);
  font-synthesis:none;letter-spacing:0;text-decoration:none}
.market.overview .ov-bp .b-head b::after{content:"i";display:inline-grid;place-items:center;flex:none;width:16px;height:16px;
  border-radius:50%;background:var(--well);box-shadow:0 0 0 1px var(--div2);color:var(--title-hot);
  font:italic 700 var(--fs-1)/1 var(--sans);text-shadow:none}
.market.overview .ov-bp .b-head b:hover::after,.market.overview .ov-bp .b-head b:focus-visible::after{
  box-shadow:0 0 0 1px var(--title);color:var(--emph)}
.market.overview .ov-bp .b-head b:focus-visible{outline:2px solid var(--gold);outline-offset:2px;border-radius:var(--r-1)}
.market.overview .ov-bp .b-head .b-sub{flex:none}
/* The column heads sit on the tables' head band (TABLES): cream names, the
   unit line under them in --faint, one quiet divider. */
.market.overview .ov-cols{display:grid;flex:none;align-items:end;gap:10px;padding:4px 12px 5px;
  background:var(--head-band);box-shadow:inset 0 -1px 0 var(--div2);color:var(--faint);font-size:var(--fs-1);line-height:1.2}
/* Each column head is two lines (what it is; its unit, window or rule),
   held whole (nowrap), so every panel's heads are one height and its rows
   line up with the neighbouring panels' rows. */
.market.overview .ov-cols>span{display:flex;min-width:0;flex-direction:column;white-space:nowrap}
.market.overview .ov-cols>span:not(:first-child){align-items:flex-end;text-align:right}
.market.overview .ov-cols b{color:var(--name);font-size:12.5px;font-weight:600}
.market.overview .ov-cols small{color:var(--faint);font-size:inherit}
.market.overview .ov-bl a:hover{color:var(--emph);text-decoration:underline}
.market.overview .ov-none{color:var(--faint)}
/* The rows: the GE offer list's alternating stone bands, as the boards'. */
.market.overview .ov-bl{flex:1 1 0;min-height:0;margin:0;padding:0;list-style:none;overflow:hidden;background-color:var(--row-a);
  display:grid;grid-auto-rows:34px;align-content:start;container:ov-band-list/size}
.market.overview .ov-bl>li{display:none;align-items:center;gap:10px;
  padding:0 12px;border-bottom:1px solid var(--row-line);color:var(--dim);font-size:13.5px;white-space:nowrap}
.market.overview .ov-bl>li:nth-child(even){background:var(--row-stripe)}
/* v86: the figure columns hold their widest head and figure and no more
   (Traded: RS3 "30 Sep guide", "1.10T gp"; Share: "OSRS trade"; Change:
   RS3 "since last guide", "+148.6%"), so the names get the rest: the
   risers' and fallers' item and category share it evenly. */
.market.overview .ov-bp-cats :is(.ov-cols,.ov-bl>li){grid-template-columns:minmax(0,1fr) 80px 58px}
.market.overview .ov-bp-totals :is(.ov-cols,.ov-bl>li){grid-template-columns:minmax(0,1fr) auto}
.market.overview .ov-bp:is(.ov-bp-up,.ov-bp-down) :is(.ov-cols,.ov-bl>li){grid-template-columns:minmax(0,1fr) minmax(0,1fr) 76px}
.market.overview .ov-bl>li>:not(:first-child){text-align:right}
.market.overview .ov-bl>li>span.num:is(.up,.down,.flat){justify-self:end}
/* Figures yellow, as on the boards; a change chip (TABLES) keeps the rows'
   weight. */
.market.overview .ov-bl .num{color:var(--fig);font-size:var(--fs-num);text-align:right}
.market.overview .ov-bl span.num{font-weight:500;letter-spacing:-.01em}
.market.overview .ov-band .num.up{color:var(--up)}
.market.overview .ov-band .num.down{color:var(--down)}
.market.overview .ov-band .num.flat{color:var(--flat)}
.market.overview .ov-bl .ov-faint{min-width:46px;color:var(--dim)}
.market.overview .ov-bl a{min-width:0;color:var(--name);text-decoration:none}
.market.overview .ov-l,.market.overview .ov-c,.market.overview .ov-item,.market.overview .ov-cat>span{
  min-width:0;overflow:hidden;text-overflow:ellipsis}
/* A category name in a row: up to two 15px lines (30px, inside the 34px
   row; Signika's descenders end on the second line's foot), broken between
   words, never cut. */
.market.overview .ov-bl :is(.ov-c,.ov-cat>span){display:-webkit-box;white-space:normal;line-height:15px;
  -webkit-box-orient:vertical;-webkit-line-clamp:2}
.market.overview .ov-l i{color:var(--faint);font-style:normal}
.market.overview .ov-c{color:var(--faint)}
.market.overview .ov-cat{display:flex;min-width:0;align-items:center;gap:7px}
.market.overview .ov-cat img{flex:none;width:20px;height:20px;object-fit:contain}
@container ov-band-list (min-height:33.5px){.market.overview .ov-bl>li:nth-child(-n+1){display:grid}}
@container ov-band-list (min-height:67.5px){.market.overview .ov-bl>li:nth-child(-n+2){display:grid}}
@container ov-band-list (min-height:101.5px){.market.overview .ov-bl>li:nth-child(-n+3){display:grid}}
@container ov-band-list (min-height:135.5px){.market.overview .ov-bl>li:nth-child(-n+4){display:grid}}
@container ov-band-list (min-height:169.5px){.market.overview .ov-bl>li:nth-child(-n+5){display:grid}}
@container ov-band-list (min-height:203.5px){.market.overview .ov-bl>li:nth-child(-n+6){display:grid}}
@container ov-band-list (min-height:237.5px){.market.overview .ov-bl>li:nth-child(-n+7){display:grid}}
@container ov-band-list (min-height:271.5px){.market.overview .ov-bl>li:nth-child(-n+8){display:grid}}
@container ov-band-list (min-height:305.5px){.market.overview .ov-bl>li:nth-child(-n+9){display:grid}}
@container ov-band-list (min-height:339.5px){.market.overview .ov-bl>li:nth-child(-n+10){display:grid}}
/* Four across, fitOverview picks the band's rows with the boards' rows
   (data-band-rows: 2 to 10, never fewer: owner, 2026-10-18) and their
   height (--ov-band-row, 34 to 42px). The list fills its window and its
   rows stretch into the room left (never below that height), so each lower
   window ends on a row, not on an empty strip of stone. This is the CSS
   stretch past fitOverview's 42px cap, on purpose: the 1px frames leave a
   few pixels a fitted row height alone no longer fills. The heads keep
   their natural height: fitOverview reads them. */
.market.overview[data-band-rows] .ov-bl{flex:1 1 auto;container-type:normal;
  grid-auto-rows:minmax(var(--ov-band-row,34px),1fr)}
.market.overview[data-band-rows] .ov-bl>li{display:none}
.market.overview[data-band-rows="2"] .ov-bl>li:nth-child(-n+2),
.market.overview[data-band-rows="3"] .ov-bl>li:nth-child(-n+3),
.market.overview[data-band-rows="4"] .ov-bl>li:nth-child(-n+4),
.market.overview[data-band-rows="5"] .ov-bl>li:nth-child(-n+5),
.market.overview[data-band-rows="6"] .ov-bl>li:nth-child(-n+6),
.market.overview[data-band-rows="7"] .ov-bl>li:nth-child(-n+7),
.market.overview[data-band-rows="8"] .ov-bl>li:nth-child(-n+8),
.market.overview[data-band-rows="9"] .ov-bl>li:nth-child(-n+9),
.market.overview[data-band-rows="10"] .ov-bl>li:nth-child(-n+10){display:grid}
@container ov-results (max-width:699px){
  .market.overview>.ov-band{grid-auto-rows:auto}
  .market.overview .ov-bl{flex:none;container-type:normal}
  .market.overview .ov-bl>li:nth-child(-n+4){display:grid}
}
/* Two across (fitOverview sets no data-band-rows: the page scrolls, nothing
   is fitted) the panels size to their content, so a flex:1 1 0 list had no
   height and its size container showed none of its rows: four empty boxes on
   a 1366x768 laptop (v80-v82). There the band lists five rows, like the
   boards above it. */
@container ov-results (min-width:700px){
  .market.overview:not([data-band-rows]) .ov-bl{flex:none;container-type:normal}
  .market.overview:not([data-band-rows]) .ov-bl>li:nth-child(-n+5){display:grid}
}
/* Phones: the strip's slots two across with the figures at 24px; the boards
   keep the desktop's 13px column heads and the chips' 7px sides (the
   RESPONSIVE phone steps are for the wider item tables), as the approved
   phone renders draw them. */
@media(max-width:640px){
  .market.overview>.pulse{padding:5px}
  .market.overview .pulse>*{padding-right:8px}
  .market.overview .pulse b{font-size:24px}
  .market.overview .pulse b small{font-size:var(--fs-2)}
  .market.overview .board thead th{font-size:var(--fs-3);letter-spacing:.01em}
  .market.overview .board td span.num:is(.up,.down,.flat){padding-inline:7px}
}

/* ========================================================= CATEGORIES ====
   The directory fills the height between its head and the footer: tile rows
   stretch (never below the 126px a tile's content needs, so shorter windows
   scroll a little) and the columns come from the width. v86 (option 1,
   owner 2026-10-18): a tile is its icon, its name (in the pale title accent,
   up to two lines) with "585 items" on its own line under it, then under a
   quiet divider one figure: what the category traded, "151B gp", its unit
   beside it. The figure's label line ("Traded in 24h", RS3 "Traded, 4 Oct
   guide") is gone (owner: "that entire line of text needs to go"); its words
   are in the tooltip and, for screen readers, a hidden label (app.js
   paintCategoryStats). The share of trade and the top mover are gone too.
   The end tile closes the last row (app.js fitCategoryEnd spans it over the
   empty cells) and shows more as it widens. The directory's .market is a
   .view-fill (SHELL): it takes the spare height and its grid fills it. */
@media(min-width:641px){
  #results>.market:has(>.cat-grid){display:flex;flex-direction:column;align-items:stretch}
  #results .cat-grid{flex:1}
}
.cat-grid{display:grid}
/* A grid row is at least 126px, the tile's content (below), so every tile
   shows all of it; taller windows share the spare height.
   The narrowest tile (--ct-w) is the one that holds every live name of both
   games in at most two lines without breaking a word, beside the 44px icon
   and its 12px gap, inside the 14px sides and 1px frame: measured in Signika
   at 16px bold, the widest word is "Miscellaneous", 99.4px, so 186px tiles
   hold it (188px leaves a browser's rounding room); the widest figure
   ("1.10T gp", 75.6px) fits far inside. One width for both games: the label
   that made RS3's tiles wider is gone. Below that a name would break inside
   a word, and a name is never cut. */
#results .cat-grid{--ct-w:188px;grid-template-columns:repeat(auto-fill,minmax(var(--ct-w),1fr));grid-auto-rows:minmax(126px,1fr);gap:8px}
.cat-tile{color:var(--dim);text-decoration:none}
/* A tile's words sit straight on its stone: no grain (PANELS), so its name
   in the title colour and its faint count keep 4.5:1. */
#results .cat-tile{--panel-grain:none}
#results a.cat-tile{cursor:pointer}
/* A tile is two parts, one above the other: the head (icon, then the name
   and its count) and, under its divider, the figure. Each starts at a fixed
   height, the head 79px (11px, a two-line name with the count under it,
   58px, then 10px) and the figure 45px (the 1px rule, 7px, a 26px line,
   11px), which with the 1px frame is the 126px row floor. A taller row
   shares its extra height equally between the two, and each holds its
   content in its middle, so the space above the name, under it, over the
   figure and under the figure stay about even, and every tile in a grid row
   (they share one height) has its divider and figure on the same line
   whatever its name does. A one-line name sits level with the icon's
   middle. */
#results .cat-tile{container:cat-tile/size;display:flex;flex-direction:column;padding:0 14px}
#results .cat-tile .ct-h{display:flex;flex:1 0 79px;align-items:center;gap:12px;min-width:0;padding-block:11px 10px}
/* The category icons are 160px sources drawn small with smooth downscaling
   in both games (nearest-neighbour shredded the OSRS art): 44px on a tile,
   32px on phones. */
.cat-tile .ct-i{flex:none;object-fit:contain;filter:drop-shadow(1px 1px 0 #000)}   /* the sprite's hard shadow (TABLES) */
#results .cat-tile .ct-i{width:44px;height:44px}
/* The name, and the item count always on its own line under it. */
#results .cat-tile .ct-hn{display:flex;flex:1 1 auto;min-width:0;flex-direction:column;align-items:flex-start}
.cat-tile b{display:block;color:var(--title);font-size:var(--fs-4);font-weight:600;overflow-wrap:break-word}
#results .cat-tile b{display:-webkit-box;max-width:100%;min-width:0;margin:0;overflow:hidden;font-size:var(--fs-5b);font-weight:700;line-height:20px;
  -webkit-box-orient:vertical;-webkit-line-clamp:2}
#results .cat-tile .ct-c{margin-top:2px;color:var(--faint);font-size:var(--fs-2);line-height:16px;white-space:nowrap}
/* The figure (.ct-f, app.js paintCategoryStats): the gp traded in the
   figure colour, mono numerals, its unit beside it in the dim tone, under a
   quiet divider across the tile. Until the stats land (and where a category
   has none) its place holds a faint dash, as the end tile's figures do, so
   nothing moves when it fills. "Everything else" says there, on up to two
   13px lines, that it has none. */
#results .cat-tile .ct-v{display:flex;flex:1 0 45px;flex-direction:column;justify-content:center;padding-block:7px 11px;
  border-top:1px solid var(--div2);color:var(--dim);font-size:var(--fs-3);line-height:26px;white-space:nowrap}
/* line-height 1: the larger mono figure never grows its 26px line. */
#results .cat-tile .ct-v .num{color:var(--fig);font-size:var(--fs-6);font-weight:600;letter-spacing:-.01em;line-height:1}
#results .cat-tile .ct-v:empty::before{content:"—";color:var(--faint)}
#results .cat-tile .ct-note{color:var(--faint);font-size:var(--fs-1);line-height:13px;white-space:normal}
/* The end tile: a row of blocks, then its links. One column wide it names
   the whole catalogue and links to it; from 410px it adds the trade total
   ("4.82T gp"); from 640px, on OSRS, the members and free-to-play lists;
   from 740px the busiest categories (links, with each one's share of the
   game's trade, under the label that names the window). Each block shows
   only where it fits whole (v81); the total keeps its width beside a long
   busiest line, whose entries drop out whole instead (v86). Its name, count
   and figure read like a tile's (v86, option 1): the name in the tile's
   bold title type with the count small and faint under it, the total as a
   tile's figure (mono numerals in the figure colour, the unit beside it in
   the dim tone) and, like a tile's, with no label line (owner,
   2026-10-18): its words, OSRS's "Traded in the last 24h, to 21:30 UTC" and
   RS3's "Traded, 4 Oct guide", are its tooltip and its hidden label (app.js
   paintCategoryStats). Not a link itself (it holds links), so it does not
   lift on hover. Its content sits in the middle of its height. */
#results .cat-tile.cat-all{display:flex;flex-direction:row;align-items:center;padding:8px 18px;
  --panel-body:linear-gradient(180deg,color-mix(in srgb,var(--title) 6%,var(--stone-top)),var(--stone) 70%)}
.cat-all .ca-in{display:flex;flex-wrap:wrap;width:100%;min-width:0;align-items:center;justify-content:space-between;gap:10px 28px}
.cat-all .ca-main{display:flex;flex:1 1 0;min-width:min(100%,150px);align-items:flex-start;gap:8px 36px}
.cat-all .ca-blk{flex:0 1 auto;min-width:0}
.cat-all .ca-cat{flex:none}
/* The total has no label line (owner, 2026-10-18), so its one 26px line sits
   level with the middle of the name block (38px: the 20px name, 2px, the
   16px count), not up against the top: 6px down. The blocks keep their
   tops, so the name and the busiest line's label stay level. */
.cat-all .ca-tot{flex:none;margin-top:6px}
.cat-all .ca-tot:focus-visible{outline:2px solid var(--gold);outline-offset:4px;border-radius:var(--r-1)}
.cat-all .ca-bus{flex:1 1 auto}
.cat-all p{margin:0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.35}
.cat-all .ca-head{display:flex;flex-direction:column;gap:2px}
#results .cat-all .ca-head b{display:block}
.cat-all .ca-n{color:var(--faint);font-size:var(--fs-2);line-height:16px}
/* The busiest line's label names its figures in sentence case, like a
   column head; the total is set as a tile's figure (.ct-v). */
.cat-all .ca-l{margin-bottom:3px;color:var(--name);font-size:var(--fs-2);font-weight:600}
/* min-width: the widest total, five mono characters and " gp" ("4.82T gp",
   75.6px), so neither the faint dash before the stats land nor a shorter
   figure moves the busiest line beside it (no label line holds the width
   now). */
.cat-all .ca-total{min-width:76px;color:var(--dim);font-size:var(--fs-3);line-height:26px}
.cat-all .ca-total .num{color:var(--fig);font-size:var(--fs-6);font-weight:600;letter-spacing:-.01em;line-height:1}
.cat-all .ca-total:empty::before,.cat-all .ca-busy:empty::before{content:"—";color:var(--faint)}
/* The busiest categories stay on one line: one that does not fit wraps to
   a hidden second line, so it is left out whole, never cut. */
.cat-all .ca-busy{display:flex;flex-wrap:wrap;gap:0 16px;height:1.5em;overflow:hidden;font-size:var(--fs-4);line-height:1.5}
.cat-all .ca-busy a{display:inline-flex;align-items:center;gap:6px;color:var(--ink);text-decoration:none;white-space:nowrap}
.cat-all .ca-busy a:hover{color:var(--emph);text-decoration:underline}
.cat-all .ca-busy img{width:18px;height:18px;object-fit:contain}
.cat-all .ca-busy .num{color:var(--dim);font-size:var(--fs-num)}
.cat-all :is(.ca-tot,.ca-bus){display:none}
.cat-all .ca-links{display:flex;flex-direction:column;align-items:flex-start;gap:8px;font-size:var(--fs-3);line-height:1.35}
.cat-all .ca-links a{white-space:nowrap}
/* "All items" is the tile's one action, the gold button (CONTROLS; its 1px
   edge stands in for a pixel of padding, so the tile's fit is unchanged);
   the members and free-to-play lists are faces with the dim label. Both
   light with their families (interaction states). */
.cat-all .ca-go{display:inline-flex;align-items:center;gap:6px;padding:6px 15px;border:1px solid var(--btn-edge);border-radius:var(--r-3);
  background:linear-gradient(180deg,var(--btn-top),var(--btn-bot));box-shadow:inset 0 1px 0 var(--btn-hi);
  color:var(--btn-ink);font-weight:700;text-decoration:none}
.cat-all .ca-more{display:none;flex-wrap:wrap;gap:6px 8px}
.cat-all .ca-more a{padding:4px 11px;border:1px solid var(--face-edge);border-radius:var(--r-pill);background:var(--face);
  box-shadow:inset 0 1px 0 var(--face-hi);color:var(--dim);text-decoration:none}
/* The queries read the tile's content box. Measured in the real faces
   (v86, the total without its label line): the name, the total ("4.82T gp",
   75.6px) and the links share one row from 383px of content (OSRS; RS3
   373px), so the total shows from 410px; the busiest line, its label whole
   ("Busiest · share of OSRS trade in 24h"; RS3's longest, "Busiest · share
   of RS3 trade, May 28 guide") and at least its first entry whole (the
   widest live names), joins them from 708px (OSRS, beside its members and
   free-to-play lists; RS3 623px), so it shows from 740px. The space the
   total's label line took goes to the busiest line. */
@container cat-tile (min-width:410px){.cat-all .ca-tot{display:block}}
@container cat-tile (min-width:640px){
  .cat-all .ca-more{display:flex}
  .cat-all .ca-links{align-items:flex-end}
}
@container cat-tile (min-width:740px){.cat-all .ca-bus{display:block}}
/* Phones: the page scrolls, so each row is the phone tile's content, 116px:
   the head 73px (9px, a 32px icon with a 10px gap beside 15px names on 19px
   lines and the count, 56px, then 8px), the figure 41px (the rule, 5px, an
   18px figure on the 26px line, 9px) and the frame. The sides narrow to
   10px, so the narrowest tile is 160px (the widest word, "Miscellaneous",
   is 93.2px at 15px bold): two tiles share a 360px screen; below that a
   tile takes the row. */
@media(max-width:640px){
  #results .cat-grid{--ct-w:160px;grid-auto-rows:116px}
  #results .cat-tile{padding-inline:10px}
  #results .cat-tile .ct-h{flex-basis:73px;gap:10px;padding-block:9px 8px}
  #results .cat-tile .ct-i{width:32px;height:32px}
  #results .cat-tile b{font-size:var(--fs-4);line-height:19px}
  #results .cat-tile .ct-v{flex-basis:41px;padding-block:5px 9px}
  #results .cat-tile .ct-v .num{font-size:18px}
}

/* ========================================================= LIST CARDS ====
   The item-list directory (/osrs/lists, /rs3/lists): six cards, 3/2/1 up.
   Each card's tone (.is-up / .is-down / .is-gold) tints its lit hairlines
   and, at 3%, its body (PANELS); a hovered card lifts to the hovered row's
   stone. Its words sit straight on the body, so it has no grain (PANELS),
   and no more tone than 3%: measured on the pixels, the OSRS title colour
   then reads 4.9:1 and the faint labels 4.7:1, at rest and hovered (a 7%
   tone under the grain read 3.7:1). The list's emblem (transparent WebP,
   used whole: no mask, no crop) sits on the card's right edge over the
   panel body; the title, description, the "Right now" rows and the call to
   action run down the left. The directory is a .view-fill (SHELL): on
   desktop its rows share the height down to the footer (never under 205px),
   and "Right now" shows as many whole rows as the taller cards hold, up to
   ten. Phones keep natural height.
   Links: the card is a box, not a link, because each row's item name is a
   link to its item (no anchor inside another). The title's link is
   stretched over the whole card (its ::after), so the card still opens its
   list from anywhere, "View list →" included; the item names sit above that
   layer. Hovering a name lifts the name (the hovered-link gold, underlined),
   not the card; keyboard focus rings the card in its tone when its list link
   has focus, and rings a name in the site's gold. */
.list-directory-featured{display:grid;min-width:0;
  grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;align-content:start;align-items:stretch}
@media(min-width:1100px){.list-directory-featured{grid-template-rows:repeat(2,minmax(205px,1fr))}}
@media(min-width:761px) and (max-width:1099px){.list-directory-featured{grid-template-rows:repeat(3,minmax(205px,1fr))}}
.list-directory-featured .list-card{--list-accent:var(--gold);position:relative;isolation:isolate;
  container:list-card/inline-size;display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto 1fr auto;
  align-items:start;gap:8px;min-width:0;min-height:205px;padding:16px 20px 14px;overflow:hidden;color:var(--ink);
  --panel-grain:none;--panel-hi:color-mix(in srgb,var(--list-accent) 55%,var(--edge-hi));
  --list-body:linear-gradient(125deg,color-mix(in srgb,var(--list-accent) 3%,var(--stone-top)),var(--stone) 64%);
  --panel-body:var(--list-body)}
.list-directory-featured .list-card.is-up{--list-accent:var(--up)}
.list-directory-featured .list-card.is-down{--list-accent:var(--down)}
.list-directory-featured .list-card.is-gold{--list-accent:var(--gold)}
.list-directory-featured .list-card:hover{--panel-body:linear-gradient(125deg,var(--row-hover),var(--stone) 72%)}
.list-directory-featured .list-card:hover:has(.list-card-now a:hover){--panel-body:var(--list-body)}
.list-directory-featured .list-card-link{color:inherit;text-decoration:none}
.list-directory-featured .list-card-link::after{content:"";position:absolute;inset:0}
.list-directory-featured .list-card:has(.list-card-link:focus-visible){outline:2px solid var(--list-accent);outline-offset:3px}
@supports selector(:has(*)){.list-directory-featured .list-card-link:focus-visible{outline:none}}
.list-directory-featured .list-card>:not(.list-card-art){grid-column:1}
.list-directory-featured :is(.list-card-copy,.list-card-now){padding-right:calc(clamp(96px,32cqi,164px) + 4px)}
.list-directory-featured .list-card-art{position:absolute;z-index:-1;top:50%;right:4px;width:clamp(96px,32cqi,164px);
  height:auto;aspect-ratio:1;translate:0 -50%;pointer-events:none}
.list-directory-featured .list-card-copy{min-width:0}
.list-directory-featured .list-card-copy h2{margin:0 0 6px;color:var(--title);font-family:var(--sans);
  font-size:var(--fs-5b);font-weight:700;line-height:1.25;letter-spacing:-.01em}
.list-directory-featured .list-card-copy p{max-width:34ch;margin:0;color:var(--dim);font-size:var(--fs-3);line-height:1.45}
/* The narrowest three-up cards (1100-1279px) keep every description to two
   lines beside the emblem. */
@container list-card (max-width:360px){.list-directory-featured .list-card-copy p{font-size:var(--fs-2)}}
.list-directory-featured .list-card-cta{display:inline-flex;align-items:center;gap:8px;justify-self:start;margin:0;
  color:var(--gold);font-size:var(--fs-2);font-weight:700;line-height:1.4;white-space:nowrap}
/* "Right now" reserves its filled height from the first paint (the label and
   three rows, each tall enough for a change pill), so the previews landing
   never move the cards. It takes the card's middle row; on desktop its list
   is a size container and a row shows only when the list is tall enough for
   all of it (rows are 22px, 2px apart), so a taller card shows more whole
   rows and never half of one. Phones show three. */
.list-card-now{display:flex;min-height:92px;flex-direction:column;font-size:var(--fs-3);line-height:1.5}
.list-directory-featured .list-card-now{align-self:stretch;min-width:0}
.list-card-now .lcn-label{display:block;margin-bottom:4px;color:var(--faint);font-size:var(--fs-1);font-weight:600}
.list-card-now ol{display:grid;grid-auto-rows:22px;gap:2px;align-content:start;margin:0;padding:0;list-style:none}
.list-card-now li{display:flex;min-width:0;align-items:center;justify-content:space-between;gap:10px}
.list-card-now .lcn-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink)}
/* An item name is its item's link, above the card's list link (LIST CARDS):
   ink at rest like every name, the hovered-link gold and an underline on
   hover, the site's gold ring on keyboard focus. app.js fitListNames trims a
   long name to a clean ellipsis (the full name in its title); the CSS
   ellipsis above is the fallback. */
.list-card-now a.lcn-name{position:relative;z-index:1;text-decoration:none}
.list-card-now a.lcn-name:hover{color:var(--emph);text-decoration:underline;text-underline-offset:3px}
.list-card-now .lcn-value{flex:none;color:var(--dim)}
/* The label names the rows' figure and its window ("Change today (UTC)",
   "Last trade price") in sentence case, like a column head, and a price
   wears its unit. */
.list-card-now .lcn-u{color:var(--faint);font-size:var(--fs-2)}
.list-card-now .lcn-note{color:var(--faint)}
@media(min-width:761px){
  /* clip, not hidden: a name's focus ring may draw 4px past the list's edge */
  .list-directory-featured .list-card-now ol{flex:1 1 auto;min-height:70px;overflow:clip;overflow-clip-margin:4px;container:lcn-list/size}
  .list-directory-featured .list-card-now li:nth-child(n+4){display:none}
  @container lcn-list (min-height:93.5px){.list-directory-featured .list-card-now li:nth-child(4){display:flex}}
  @container lcn-list (min-height:117.5px){.list-directory-featured .list-card-now li:nth-child(5){display:flex}}
  @container lcn-list (min-height:141.5px){.list-directory-featured .list-card-now li:nth-child(6){display:flex}}
  @container lcn-list (min-height:165.5px){.list-directory-featured .list-card-now li:nth-child(7){display:flex}}
  @container lcn-list (min-height:189.5px){.list-directory-featured .list-card-now li:nth-child(8){display:flex}}
  @container lcn-list (min-height:213.5px){.list-directory-featured .list-card-now li:nth-child(9){display:flex}}
  @container lcn-list (min-height:237.5px){.list-directory-featured .list-card-now li:nth-child(10){display:flex}}
}
@media(max-width:1099px){.list-directory-featured{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:760px){
  .list-directory-featured{grid-template-columns:minmax(0,1fr);gap:12px}
  .list-directory-featured .list-card{min-height:200px;padding:16px;gap:8px}
  .list-card-now li:nth-child(n+4){display:none}
}

/* ========================================================== WATCHLIST ====
   One head in every state. The signed-out gate and an empty list fill the
   band between the head and the footer (both are a .view-fill, SHELL); a
   short list keeps its rows at the top of the panel and fills the rest with
   ways to grow it. Every gate fills the same way: the watchlist's, and a tool
   page's (the GE Screener, Wyrm Picks, Backtest and Paper Trading mark their
   host .view-fill while they show one), its mascot and words centred. */
#results>.view-fill:has(>.gate){display:flex;flex-direction:column}
#results>.view-fill>.gate{flex:1 1 auto}
#results>.gate,#results>.view-fill>.gate{display:flex;flex-direction:column;align-items:center;justify-content:center}
@media(min-width:641px){
  #results>.catalogue-table.wl-host.list-short{flex-grow:1}
}
.gate-btns :is(.mprimary,.msecondary){width:auto;margin:0;padding:9px 20px}
.wl-host .board>.wl-empty{padding:30px 20px 10px}
/* Ways to grow the list sit in the same window under its rows, past one
   quiet divider; the heading is a window title (DISPLAY TIER: face, size,
   shadow). */
.wl-grow{display:flex;flex:1;flex-direction:column;gap:14px;padding:18px 18px 20px;border-top:1px solid var(--div2)}
.wl-grow-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px 18px}
.wl-grow-head h2{margin:0;color:var(--title);line-height:1.2}
.wl-grow-head p{flex:1 1 320px;margin:0;color:var(--dim);font-size:var(--fs-3)}
.wl-grow-head .msecondary{width:auto;margin:0;padding:8px 16px;font-size:var(--fs-3)}
.wl-suggest{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px;align-content:start}
/* the note sits on the window's grain, so it takes the dim step: the faint
   one falls under 4.5:1 there (PANELS) */
.wl-suggest-note{margin:0;color:var(--dim);font-size:var(--fs-3)}
/* a suggestion is a card whose words sit on its body: flat stone (PANELS) */
.wl-pick{--panel-grain:none;display:flex;min-width:0;align-items:center;gap:10px;padding:8px 10px}
.wl-pick-item{display:flex;flex:1;min-width:0;align-items:center;gap:10px;color:var(--ink);text-decoration:none}
.wl-pick-item>span:last-child{display:flex;min-width:0;flex-direction:column}
.wl-pick-item b{overflow:hidden;font-weight:500;text-overflow:ellipsis;white-space:nowrap}
/* The price with its unit and window ("gp, last trade", "gp, latest
   guide"), then the change chip with its window ("today (UTC)", "since last
   guide"), in the tables' words; the line wraps between them,
   never inside the chip or a window. */
.wl-pick-px{display:block;color:var(--dim);font-size:var(--fs-3);line-height:1.6}
.wl-pick-w{white-space:nowrap}
/* Follow on a suggestion is a face with a gold label (CONTROLS; it lifts
   with the faces): the page's gold button stays the one primary action. */
.wl-pick .wl-follow{flex:none;display:inline-flex;align-items:center;padding:6px 11px;color:var(--gold);font-size:var(--fs-3);font-weight:600}

/* ============================================================== HOME ====
   The root page names no game: it introduces both Grand Exchanges (each
   portal card in its own game's edition), then one aggregate data surface,
   the trade-value chart beside the market-totals panel. Its ground, tokens
   and header are the neutral page's (the OSRS edition, DESIGN TOKENS); the
   portal cards and the two totals windows are edition hosts, so the RS3 ones
   paint RS3 slate, strips, faces, titles and corner ticks. A game is named
   on this page by its mark (DESIGN TOKENS) as a chart line or a swatch,
   never as small words on stone (the RS3 steel blue is 4.0-4.7:1 there).
   Words that sit straight on a window's body sit on flat stone (no grain,
   PANELS): the cards' counts and the chart's axis labels are the faint ink.
   The whole
   desktop dashboard is one screen: the page is a viewport-filling column and
   the data grid takes the spare height. It has no page head and keeps its
   8px gutter, but otherwise wears the SHELL like every page: the same
   content column (1500px, 1860px ad-free) and the same side rails. */
:root[data-page="home"]{scrollbar-gutter:auto;--gutter:8px}
:root[data-page="home"] body{display:flex;height:auto;min-height:100dvh;flex-direction:column}
/* Only the vertical padding is the homepage's own: the sides are the SHELL's
   (its --gutter, plus the rail gutters from 1560px). */
:root[data-page="home"] #main{flex:1 0 auto;padding-top:0;padding-bottom:8px}
:root[data-page="home"] #page-head{display:none!important}
:root[data-page="home"] #results{display:flex;min-height:0;overflow:visible;background:transparent}
:root[data-page="home"] body>:is(.ad-footer,.mw-brand-footer){display:none!important}
/* One colour per chart series (the game marks, and a paler mix for the tax
   estimates), shared by the chart lines and the legend's and the totals
   rows' swatches. */
.home-landing{display:flex;width:100%;min-height:100%;flex:1;flex-direction:column;color:var(--ink);
  --hs-osrs:var(--accent-osrs);--hs-rs3:var(--accent-rs3);
  --hs-osrs-tax:color-mix(in srgb,var(--accent-osrs) 55%,#fff);--hs-rs3-tax:color-mix(in srgb,var(--accent-rs3) 55%,#fff)}

/* Hero: the supplied 1920×240 banner, cover-cropped (approved scenery, as
   v79), with the copy on its dark left side; phones get the square crop
   above the copy. Its frame is a window's hairlines (none along its top:
   the header's rule is there) on one soft drop, closed along its foot by
   the header's rule colour. The shade's near-black is matched to the
   banner's own left edge (art, not UI paint). */
.home-hero{position:relative;isolation:isolate;height:clamp(145px,11.4vw,174px);min-height:0;overflow:hidden;
  border:1px solid;border-color:var(--edge-hi) var(--edge-lo) var(--edge-lo) var(--edge-hi);border-top-style:none;
  background:var(--page);box-shadow:var(--panel-shadow)}
.home-hero::after{content:"";position:absolute;z-index:2;inset:auto 0 0;height:1px;background:var(--rule)}
.home-hero-picture{position:absolute;inset:0;display:block}
.home-hero-art{position:static;display:block;width:100%;height:100%;object-fit:cover;object-position:center 49%}
.home-hero-shade{position:absolute;z-index:1;inset:0;
  background:linear-gradient(90deg,#040403 0%,rgba(4,4,3,.97) 23%,rgba(4,4,3,.72) 43%,rgba(4,4,3,.06) 69%)}
.home-hero-copy{position:relative;z-index:3;display:flex;width:49%;max-width:690px;min-height:100%;flex-direction:column;
  justify-content:center;padding:18px clamp(24px,3.5vw,54px)}
.home-kicker{color:var(--gold-quiet);font-size:var(--fs-1);font-weight:700;letter-spacing:.2em;text-transform:uppercase}
/* the title is the display face at 32px at every width (DISPLAY TIER),
   with its own soft shadow over the art */
.home-hero h1{max-width:640px;margin:6px 0 4px;color:var(--title);line-height:1;text-shadow:0 2px 22px #000;text-wrap:balance}
.home-lede{max-width:570px;margin:0;color:var(--dim);font-size:var(--fs-3);line-height:1.4;text-shadow:0 1px 9px #000}

/* Portals: one PANELS window per game, each in its own game's edition (an
   edition host, DESIGN TOKENS: the RS3 card is slate with bronze corner
   ticks, and its title, figures, faces and focus ring are RS3's), its
   freshness line as the window's title strip, its words on flat stone. */
.home-portals{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:8px}
.home-game-column{display:flex;min-width:0;flex-direction:column;overflow:hidden;--panel-grain:none}
/* the card is a link: it lifts like one (PANELS), its frame stays */
.home-game-column:hover{--panel-body:linear-gradient(180deg,var(--row-hover),var(--stone) 140px)}
/* The freshness strip, in sentence case like every label: the game's short
   name in the title colour, when it last updated, a small orb (as the
   header's status pill, HEADER: green = current, amber with amber words =
   delayed, plain stone = not known yet; lit from its top left inside a dark
   ring, no glow), then the game's cadence in the dim ink. */
.home-updatebar{display:flex;min-width:0;min-height:28px;align-items:center;gap:8px;padding:5px 12px 6px;
  color:var(--faint);font-size:var(--fs-2);line-height:1.2;white-space:nowrap}
.home-updatebar strong{color:var(--title);font-weight:700}
.home-updatebar b{color:var(--ink);font-family:var(--mono);font-weight:500}
.home-updatebar i{flex:none;width:9px;height:9px;border-radius:50%;box-shadow:0 0 0 1px rgba(0,0,0,.55);
  background:radial-gradient(circle at 35% 30%,#f4efe4 0 14%,#a39a8a 46%,#3d372f 100%)}
.home-updatebar.is-fresh i{background:radial-gradient(circle at 35% 30%,#d7ffc9 0 18%,#3fc449 55%,#145f1c)}
.home-updatebar.is-stale i{background:radial-gradient(circle at 35% 30%,#ffe8c2 0 14%,#e8892e 46%,#6b3408 100%)}
.home-updatebar small{min-width:0;overflow:hidden;text-overflow:ellipsis;color:var(--dim);font:inherit}
.home-updatebar.is-stale small{color:var(--warn)}
.home-game{position:relative;display:block;min-height:116px;flex:1;overflow:hidden;padding:13px 12px 48px 112px;
  color:var(--ink);text-decoration:none;container:home-game/inline-size}
.home-game-medallion{position:absolute;z-index:1;top:9px;left:9px;width:92px;height:92px;object-fit:contain;
  filter:drop-shadow(0 8px 13px #000);transition:transform var(--dur-3) var(--ease-emph)}
.home-game-column:hover .home-game-medallion{transform:scale(1.035)}
.home-game-copy{position:relative;z-index:2;display:block;min-width:0}
.home-game-copy strong,.home-game-copy small,.home-game-copy>span{display:block}
/* the game's name is a window title (DISPLAY TIER: 20px, 16px on phones)
   in its edition's title colour; the count is a figure */
.home-game-copy strong{color:var(--title);line-height:1.1;white-space:nowrap}
.home-game-copy small{margin-top:3px;color:var(--dim);font-size:var(--fs-3);line-height:1.35}
.home-game-copy>span{margin-top:4px;color:var(--faint);font-size:var(--fs-2)}
.home-game-copy>span b{color:var(--fig);font-family:var(--mono);font-weight:500}
.home-game-actions{position:absolute;z-index:2;right:10px;bottom:9px;left:112px;display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));gap:5px}
/* The card's ways in are its edition's faces with gold labels (CONTROLS;
   they lift with the faces, interaction states): OSRS stone in the OSRS
   card, RS3 slate in the RS3 card. */
.home-game-actions a{display:flex;min-width:0;min-height:31px;align-items:center;justify-content:space-between;padding:6px 8px;
  border:1px solid var(--face-edge);border-radius:var(--r-2);background:var(--face);box-shadow:inset 0 1px 0 var(--face-hi);
  color:var(--gold);font-size:var(--fs-1);font-weight:700;
  overflow:hidden;text-decoration:none;white-space:nowrap;transition:border-color var(--dur-2),background-color var(--dur-2),color var(--dur-2)}
.home-game-actions a::after{content:"›";margin-left:5px;color:var(--dim);font-size:14px;font-weight:400;line-height:1}
.home-game-actions a:hover::after{color:var(--emph)}
.home-game-actions a:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
/* A narrow card (two portals side by side below 1120px) drops the arrows so
   the four 11px labels keep their cells. */
@media(min-width:641px){@container home-game (max-width:360px){
  .home-game-actions a{justify-content:center;padding:6px 4px}
  .home-game-actions a::after{display:none}
}}
/* The coming tools: two tiles in the card's free top-right corner when the
   card is wide enough (its content box, right of the medallion, holds the
   game's name and both tiles), otherwise in the flow under the game's name.
   Each is a locked tool, as the header's COMING SOON tabs (HEADER): the
   dimmer face without its highlight, the tool's name in the ink beside its
   icon in the dim ink, and only the small COMING SOON tag in the title
   colour; it lifts like every face (interaction states). */
.home-tools{position:relative;z-index:2;display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
@container home-game (min-width:540px){.home-tools{position:absolute;top:12px;right:12px;margin:0;flex-wrap:nowrap}}
.home-tool{display:flex;align-items:center;gap:8px;padding:7px 11px 7px 9px;border:1px solid var(--face-edge);
  border-radius:var(--r-3);background:var(--face-off);color:var(--ink);text-decoration:none}
.home-tool:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
.home-tool .ico{width:18px;height:18px;color:var(--dim)}
.home-tool:hover .ico{color:var(--emph)}
.home-tool>span{display:flex;flex-direction:column;line-height:1.2}
.home-tool b{font-size:var(--fs-3);font-weight:700;white-space:nowrap}
.home-tool small{align-self:flex-start;margin-top:3px;color:var(--title);font:600 var(--fs-1)/1 var(--sans);letter-spacing:.05em}

/* Data grid: the trade-value chart (a window on the neutral page, its head
   the title strip, its body flat stone) and the market-totals panel. It
   takes the spare height from a 350px start, and never less than its
   content (its automatic minimum): the old fixed 350px floor let the two
   totals windows run over the footer on a 1366x768 laptop. */
.home-data-grid{display:grid;flex:1 0 350px;grid-template-columns:minmax(0,2.6fr) minmax(350px,.95fr);gap:10px;margin-top:9px}
.home-value-panel{display:flex;min-width:0;overflow:hidden;flex-direction:column;--panel-grain:none}
.home-market-rail{min-width:0}
.home-value-head{display:flex;min-height:54px;align-items:center;justify-content:space-between;gap:18px;padding:10px 14px 9px}
.home-value-head>div:first-child{min-width:0}
.home-value-head h2{margin:0;color:var(--title);line-height:1.2}
.home-value-head p{margin:2px 0 0;color:var(--dim);font-size:var(--fs-2);line-height:1.3}
.home-value-head .home-coverage-note{color:var(--faint);font:500 var(--fs-1)/1.3 var(--mono)}
.home-value-head .home-coverage-note.has-partial{color:var(--warn)}
.home-chart-controls{display:flex;flex:none;align-items:center;justify-content:flex-end;gap:8px}
/* The range and view tabs are trays of faces, the chosen one the open tab;
   a view the data cannot show yet is the dimmer face (CONTROLS). */
.home-range-tabs,.home-view-tabs{display:flex;flex:none}
.home-view-tabs[hidden]{display:none}
.home-range-tabs button,.home-view-tabs button{min-width:36px;padding:4px 6px;font:600 var(--fs-1)/1.2 var(--mono)}
.home-view-tabs button{min-width:56px;font-family:var(--sans)}
.home-view-tabs button[aria-disabled="true"]{cursor:not-allowed}
/* The legend names each series in the ink beside a swatch of its colour (a
   square for a trade line, a dash for a tax line): no series colours its
   own label, as the steel blue is under 4.5:1 as small words on stone. */
.home-chart-legend{display:flex;flex-wrap:wrap;align-items:center;gap:6px 16px;padding:7px 14px 3px}
.home-chart-legend button{display:flex;align-items:center;gap:6px;padding:2px 0;border:0;background:transparent;box-shadow:none;
  color:var(--dim);font-size:var(--fs-2);font-weight:500}
.home-chart-legend button i{flex:none;width:9px;height:9px;background:var(--hs);box-shadow:0 0 0 1px rgba(0,0,0,.55)}
.home-chart-legend .osrs{--hs:var(--hs-osrs)}
.home-chart-legend .rs3{--hs:var(--hs-rs3)}
.home-chart-legend .osrs-tax{--hs:var(--hs-osrs-tax)}
.home-chart-legend .rs3-tax{--hs:var(--hs-rs3-tax)}
.home-chart-legend :is(.osrs-tax,.rs3-tax) i{width:14px;height:0;border-top:2px dashed var(--hs);background:transparent;box-shadow:none}
/* A switched-off series reads as off by colour, not by fading the label
   below AA (aria-pressed carries the state to assistive tech). */
.home-chart-legend button:not(.on){color:var(--faint)}
.home-chart-legend button:not(.on) i{opacity:.5}
.home-chart-legend button:hover{color:var(--emph)}
.home-value-chart{position:relative;min-height:220px;height:auto;flex:1;padding:0 3px 2px;transition:opacity .15s}
.home-value-chart.loading{opacity:.55}
.home-value-chart>p{display:grid;height:100%;place-items:center;margin:0;color:var(--faint);font-size:var(--fs-3)}
.home-value-chart svg{display:block;width:100%;height:100%;overflow:visible}
.home-value-grid line{stroke:var(--ch-grid);stroke-width:1;vector-effect:non-scaling-stroke}
.home-value-grid text,.home-axis-title{fill:var(--ch-label);font:500 var(--fs-1) var(--mono)}
.home-value-series path{fill:none;stroke-width:1.7;vector-effect:non-scaling-stroke}
.home-value-series circle{stroke-width:1.5;vector-effect:non-scaling-stroke}
.home-value-series circle.home-series-point{stroke:var(--surface-bottom);stroke-width:1.2}
.home-value-series circle.home-series-point.is-current{stroke:var(--emph);stroke-width:2}
.home-series-osrs{stroke:var(--hs-osrs);fill:var(--hs-osrs)}
.home-series-rs3{stroke:var(--hs-rs3);fill:var(--hs-rs3)}
.home-series-osrs-tax{stroke:var(--hs-osrs-tax);fill:var(--hs-osrs-tax);stroke-dasharray:4 3}
.home-series-rs3-tax{stroke:var(--hs-rs3-tax);fill:var(--hs-rs3-tax);stroke-dasharray:4 3}
.home-value-chart>.home-chart-note{position:absolute;right:12px;bottom:25px;left:64px;display:block;height:auto;
  color:var(--faint);font-size:var(--fs-1);text-align:center}

/* Hovering or focusing a totals row or a legend chip picks its line out. */
.home-value-chart[data-focus] .home-value-series>*{opacity:.18;transition:opacity var(--dur-2) var(--ease-out)}
.home-value-chart[data-focus="osrs"] .home-series-osrs,
.home-value-chart[data-focus="rs3"] .home-series-rs3,
.home-value-chart[data-focus="osrsTax"] .home-series-osrs-tax,
.home-value-chart[data-focus="rs3Tax"] .home-series-rs3-tax{opacity:1}

/* Market totals: a window per game in that game's edition (an edition
   host, DESIGN TOKENS), its head a title strip pulled out to the frame (the
   game's short name, a window title in the edition's title colour); two
   rows (trade value, GE tax) over three fixed periods, each column naming
   its exact period. The small heading over both is the display face at
   16px (DISPLAY TIER). */
.home-totals{display:flex;height:100%;flex-direction:column;gap:8px}
.home-totals-title{margin:0;color:var(--title);line-height:1.25}
.home-totals-title small{margin-left:6px;color:var(--faint);font-family:var(--sans);font-size:var(--fs-2);font-weight:500}
.home-total{display:flex;flex:1;flex-direction:column;padding:9px 12px 7px}
.ht-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin:-9px -12px 4px;padding:5px 12px 6px}
.ht-head h3{margin:0;color:var(--title);line-height:1.2}
.ht-fresh{color:var(--faint);font-size:var(--fs-2);text-align:right}
/* The table takes the block's spare height: the head row keeps its size and
   the two metric rows share the rest. Its rows are the GE offer list's
   first stone band (TABLES), so no word sits on the window's grain; no
   zebra stripe on a two-row grid. Amounts are figures. */
.ht-grid{flex:1;table-layout:fixed;background-color:var(--row-a)}
.ht-grid thead{height:1px}
.ht-grid thead th{padding:4px 6px;border-bottom-color:var(--row-line);vertical-align:bottom;white-space:normal}
.ht-grid thead th small{display:block;margin-top:1px;color:var(--faint);font-size:var(--fs-1);font-weight:500;letter-spacing:0;
  text-transform:none;white-space:normal}
.ht-grid thead td{width:38%;background:var(--head-band);box-shadow:inset 0 -1px 0 var(--div2)}   /* the head band (TABLES) */
.ht-grid tbody th{padding:4px 4px 4px 0;border-bottom:1px solid var(--row-line);font-weight:400;text-align:left}
.ht-grid tbody td{padding:5px 6px;background-color:transparent}
.ht-grid tbody tr:hover :is(th,td){background-color:var(--row-hover)}
.ht-grid tbody tr:last-child :is(th,td){border-bottom:0}
.ht-grid td b{display:block;color:var(--fig);font-size:var(--fs-num);font-weight:600}
.ht-grid [data-total-change]{display:block;margin-top:2px}
.ht-grid [data-total-change]:empty{display:none}
/* v81: each amount wears its unit, and the change names what it compares
   against, in the cell itself. */
.ht-grid td b .ht-u{color:var(--faint);font:500 var(--fs-1) var(--sans)}
.ht-grid [data-total-change] .ht-chg{display:block;margin-top:2px;color:var(--faint);font-size:var(--fs-1);line-height:1.2;white-space:normal}
[data-total-series="osrs"]{--hs:var(--hs-osrs)}
[data-total-series="osrsTax"]{--hs:var(--hs-osrs-tax)}
[data-total-series="rs3"]{--hs:var(--hs-rs3)}
[data-total-series="rs3Tax"]{--hs:var(--hs-rs3-tax)}
.ht-key{display:flex;width:100%;align-items:center;gap:7px;padding:4px 2px;border:0;border-radius:var(--r-2);
  background:none;box-shadow:none;color:var(--dim);font-size:var(--fs-3);text-align:left;white-space:nowrap}
/* Off reads by colour (--faint stays above 4.5:1 on both editions' row and
   hovered row), not by fading the label; aria-pressed carries the state to
   assistive tech. Its row already lifts to the hovered row's stone under
   the pointer (a background of its own matched it, so it showed nothing):
   the key itself answers with the bright yellow label. */
.ht-key:not(.on){color:var(--faint)}
.ht-key:not(.on) :is(.ht-swatch,.ht-glyph){opacity:.45}
.ht-key:hover{color:var(--emph)}
.ht-key:disabled{background:none;filter:none;color:var(--dim);cursor:default}
.ht-swatch{flex:none;width:16px;height:0;border-top:2px solid var(--hs)}
[data-total-series$="Tax"] .ht-swatch{border-top-style:dashed}
.ht-key .ht-glyph{width:16px;height:16px;margin:0;color:var(--hs)}

@media(max-width:1120px){
  .home-game{padding-left:102px}
  .home-game-medallion{width:82px;height:82px}
  .home-game-actions{left:102px}
  .home-data-grid{grid-template-columns:minmax(0,2.15fr) minmax(330px,1fr)}
}
@media(max-width:880px){
  .home-hero{height:170px}
  .home-hero-copy{width:62%}
  .home-portals,.home-data-grid{grid-template-columns:1fr}
  .home-data-grid{min-height:0;flex:none}
  .home-value-chart{height:210px;min-height:210px;flex:none}
}
@media(max-width:780px){.home-hero-picture{height:min(78vw,350px)}}
@media(max-width:640px){
  :root[data-page="home"] #main{padding:0 6px 8px}
  .home-hero{height:330px}
  .home-hero-picture{inset:0 0 auto;height:215px}
  .home-hero-art{object-position:center 42%}
  .home-hero-shade{background:linear-gradient(180deg,rgba(3,3,2,.05),rgba(3,3,2,.22) 48%,#050503 68%,#050503)}
  .home-hero-copy{width:100%;min-height:330px;justify-content:flex-end;padding:210px 17px 18px}
  .home-lede{font-size:var(--fs-2)}
  .home-game{min-height:190px;padding:13px 12px 83px 100px}
  .home-game-medallion{top:11px;left:7px;width:86px;height:86px}
  .home-game-copy strong{white-space:normal}
  .home-game-actions{right:9px;bottom:9px;left:9px;grid-template-columns:repeat(2,minmax(0,1fr))}
  .home-data-grid{margin-top:8px}
  .home-value-head{align-items:flex-start;flex-direction:column}
  .home-chart-controls{width:100%;flex-wrap:wrap;justify-content:flex-start}
  .home-range-tabs{width:100%}
  .home-range-tabs button{flex:1}
  .home-chart-legend{gap:5px 10px}
  .home-value-chart{height:175px;min-height:175px}
}
@media(max-width:390px){
  .home-updatebar small{display:none}
  .home-value-chart{height:160px}
}
@media(prefers-reduced-motion:reduce){.home-game-medallion,.home-game-actions a,.home-value-chart{transition:none}}

/* ========================================================= ITEM PAGE ====
   The item terminal's v79 additions to the detail overlay above: a
   breadcrumb, the price block beside the 32px title, the links row, four fact
   wells over the chart, grouped chart controls and the side panels. Every
   visitor has the watchlist rail and its ☰ (v85); closed, the chart takes
   its column. */
@media(min-width:901px){
  #detail.nolist .term{grid-template-columns:minmax(360px,1fr) 300px;min-width:660px}
  #detail.nolist .t-crumbs-row{padding-left:54px}
  .t-mid{overflow-y:auto}
}
/* A guest's rail (v85): the head is one title strip, its label clear of the
   ☰ face, with the site's lock as the Watchlist tab wears it; under it one GE
   row band holds what signing in gives and a Sign in face, so its words sit
   on a row's flat stone, not on the rail's grain. No filter box: there is no
   list to filter. */
.t-lhead.t-lhead-gate{--strip-body:linear-gradient(180deg,var(--bar-top),var(--bar-mid) 45%,var(--bar-bot));
  display:flex;align-items:center;min-height:52px;padding:9px 14px 9px 52px}
.t-lhead .lk{width:.9em;height:.9em;margin-left:.4em}
.t-list-gate{flex:none;padding:12px 14px 14px;background:var(--row-a);border-bottom:1px solid var(--row-line2)}
.t-list-gate p{margin:0 0 10px;color:var(--dim);font-size:var(--fs-3);line-height:1.5}
.t-list-gate button{width:100%}
/* The small side banner at the foot of the left rail, the desktop item
   page's one ad (ads.js itemleft: the 160x300 unit, for every visitor ads
   are shown to): over a hairline, below the rows, the house panel, template
   or creative centred at its exact size. It reserves the live unit's label
   as well, so a fill never moves the rows; the rows box gives up the height
   it takes (ITEM TERMINAL). */
.t-list>:is(.ad-itemleft,.mw-brand-itemleft){flex:none;width:100%;margin:auto 0 0;padding:12px 0 14px;
  border-top:1px solid var(--line)}
.t-list>.ad-itemleft.ad-template,.t-list>.mw-brand-itemleft{display:flex;flex-direction:column;
  justify-content:center;min-height:346px}
/* While ads.js waits for the policy and the visitor (data-ad-item-hold), the
   empty mount keeps that footprint, so the panel's arrival never shortens the
   rows box; a resolved exclusion clears the hold. */
:root[data-ad-item-hold="1"] .t-list>.ad-itemleft{display:block;min-height:346px}
.t-crumbs-row{display:flex;flex-shrink:0;align-items:center;gap:12px;padding:12px 22px 0}
.t-crumbs{display:flex;min-width:0;flex-wrap:wrap;align-items:center;gap:4px 7px;color:var(--faint);font-size:var(--fs-3)}
.t-crumbs a{color:var(--dim);text-decoration:none}
.t-crumbs a:hover{color:var(--ink)}
.t-crumbs [aria-current]{overflow:hidden;color:var(--ink);text-overflow:ellipsis;white-space:nowrap}
.t-px-main{display:flex;align-items:baseline;gap:10px}
.t-px .t-price{color:var(--fig);font-size:36px;font-weight:700;line-height:1}
.t-px .t-gp{color:var(--dim);font-size:var(--fs-4)}
/* v81: the big price says what it is ("Last trade price", "Guide price,
   4 Oct"). v86: its change pill is the daily change, bare (owner: no "since
   last guide" beside it); its window is in its tooltip and hidden words. */
.t-px .t-px-l{color:var(--dim);font-size:var(--fs-2);font-weight:600}
.t-links{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;gap:6px 16px;padding:0 22px 4px 82px}
.t-link{display:inline-flex;align-items:center;gap:4px;min-height:0;padding:0;border:0;background:none;box-shadow:none;
  color:var(--dim);font-size:var(--fs-3);text-decoration:none}
.t-link:hover{color:var(--ink)}
.t-link .ico{width:.85em;height:.85em;margin:0}
/* The four facts are the overview's skills strip (OVERVIEW) and the perf
   cards' family: one window (PANELS) of wells 5px apart, each its label in
   sentence case (as the column heads), its figure in mono in the figure
   colour, and the quiet words that give its unit or reading. */
.t-stats{display:grid;flex-shrink:0;grid-template-columns:repeat(4,minmax(0,1fr));gap:5px;margin:12px 22px 4px;padding:4px}
.t-stat{display:flex;min-width:0;flex-wrap:wrap;align-items:baseline;column-gap:6px;padding:8px 11px 7px 10px;
  border:1px solid var(--inset);background:var(--row-a)}
.t-stat>span{flex-basis:100%;color:var(--dim);font-size:var(--fs-2);font-weight:600}
.t-stat b{margin-top:3px;overflow:hidden;color:var(--fig);font-size:17px;font-weight:500;text-overflow:ellipsis;white-space:nowrap}
.t-stat small{color:var(--faint);font-size:var(--fs-2)}
.t-stat b .t-u{color:var(--faint);font-size:var(--fs-2);font-weight:500}
@container t-mid (max-width:620px){
  .t-stats{grid-template-columns:repeat(2,minmax(0,1fr))}
  .t-links{padding-left:22px}
}
/* Chart controls under three labels: Range, Chart, Overlays, each a tray
   (CONTROLS) led by its label. */
.ch-group{display:flex;flex-wrap:wrap;align-items:center}
.ch-group .ch-group-label{padding:0 6px}
.ch-group .ch-tools{justify-content:flex-start}
.ch-bar>.ch-fit{margin-left:auto}
@container t-mid (max-width:960px){.picks.sim{grid-template-columns:repeat(3,minmax(0,1fr))}}
@container t-mid (max-width:440px){.picks.sim{grid-template-columns:repeat(2,minmax(0,1fr))}}
.t-panel{--panel-grain:none;padding:12px 14px}   /* flat stone, as .t-lock (ITEM TERMINAL) */
/* A guest's Price alert (v85): the lock in its strip, one line of what
   signing in gives and the gold Sign in, the column's one sign-in prompt
   (the lock is the 20px title's, at the Watchlist tab's proportion). */
.t-shead .lk{width:.7em;height:.7em;margin-left:.35em;vertical-align:0}
.t-alert-gate .t-note{margin:0 0 10px;padding:0;line-height:1.5}
@media(max-width:640px){
  #t-name{font-size:24px}
  .t-px .t-price{font-size:28px}
  .t-crumbs-row,.t-tick,.ch-bar,.t-leg,.t-cap,.t-links{padding-inline:14px}
  .t-stats,.t-sim{margin-inline:14px}
}

/* ====================================================== ROUTE PENDING ====
   Every cold SEO page ships its own crawlable links in #results until the
   app's first render replaces them (seo-worker.js pendingResults): one quiet
   text row. The viewport-filling page column already holds the footer at
   the bottom, so nothing jumps when the real view arrives. */
#results>nav.route-pending{display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;
  margin:0;padding:6px 2px;color:var(--faint);font-size:var(--fs-3)}
#results>nav.route-pending a{color:var(--dim);text-decoration:none}
#results>nav.route-pending a:hover{color:var(--ink);text-decoration:underline}
/* On a phone or a window under 800px tall the page scrolls and every real
   view is taller than the screen, so the pending row holds one screen: the
   footer starts below the fold instead of rising into view and being pushed
   out again. Taller desktop views fit one screen and keep the footer put. */
@media(max-width:640px),(max-height:799px){#results:has(>nav.route-pending){min-height:100dvh}}

/* ============================================================== ADMIN ====
   /admin (wyrm.js renderAdminPage): the whole site on one page. A sticky
   section nav on the left (a sideways strip under the header on narrow
   screens) beside the content: Overview, Site settings and Traffic & search
   on the neutral page (the OSRS edition, DESIGN TOKENS), then an OSRS area
   and an RS3 area, each an edition host: every window, strip, face, well and
   tray inside paints that game's edition (RS3: slate, a brushed strip and
   bronze corner ticks). Each section is a window with its head as the title
   strip and its words on flat stone (no grain, PANELS: its help lines are
   the faint ink); counts sit in wells, choices are faces. Nothing here sets
   `background:` on a panel member, and a ledger inside a panel drops its own
   frame (PANELS). The section nav sticks to the viewport, so #results is
   never a scroll container here (SHELL); the wide tables scroll inside their
   own wrappers. The page sits in the SHELL's content column.
   A game is named on this neutral page by its mark (DESIGN TOKENS, --mark
   below) as a bar, a square swatch or a 20px title on the page, never as
   small words on stone: the RS3 steel blue is 4.0-4.7:1 there. */
.adm{display:grid;grid-template-columns:minmax(0,1fr);gap:12px}
.adm-main{min-width:0}
@media(min-width:900px){.adm{grid-template-columns:200px minmax(0,1fr);gap:26px;align-items:start}}
.adm [data-game="osrs"]{--mark:var(--accent-osrs)}
.adm [data-game="rs3"]{--mark:var(--accent-rs3)}

/* ---- section nav ---- A window column (PANELS) of quiet rows: a link is
   the dim ink straight on the stone, lifting to the hovered row's stone and
   the bright yellow; the open section is the open tab (CONTROLS), and a
   game's section adds a 2px bar of its game's mark along its leading side.
   The group labels (each a link to its area) are the column-head ink in
   sentence case, a game's led by a square swatch of its mark. */
.adm-nav{position:sticky;top:calc(var(--chrome-h,58px) + 14px);display:flex;flex-direction:column;gap:1px;padding:4px;
  max-height:calc(100vh - var(--chrome-h,58px) - 28px);overflow-y:auto;scrollbar-width:thin}
.adm-nav a{display:block;padding:6px 12px 6px 22px;border-radius:var(--r-2);color:var(--dim);
  font-size:var(--fs-4);line-height:1.3;text-decoration:none}
.adm-nav .adm-nav-top{display:flex;align-items:center;gap:7px;margin-top:8px;padding-left:12px;
  color:var(--th-ink);font-size:var(--fs-2);font-weight:600}
.adm-nav .adm-nav-top:first-child{margin-top:0}
.adm-nav .adm-nav-top[data-game]::before{content:"";flex:none;width:8px;height:8px;background:var(--mark);
  box-shadow:0 0 0 1px rgba(0,0,0,.55)}
.adm-nav a:hover{color:var(--emph);background:var(--row-hover)}
.adm-nav a.on{color:var(--on-ink);background:var(--on-fill);box-shadow:inset 0 0 0 1px var(--on-edge)}
.adm-nav a.on[data-game]{box-shadow:inset 2px 0 0 var(--mark),inset 0 0 0 1px var(--on-edge)}
@media(max-width:899px){
  .adm-nav{top:var(--chrome-h,58px);z-index:20;flex-direction:row;align-items:center;gap:2px;max-height:none;
    overflow-x:auto;overflow-y:hidden;box-shadow:var(--sh-2)}
  .adm-nav a{flex:none;padding:6px 10px;white-space:nowrap}
  .adm-nav .adm-nav-top{margin:0 0 0 8px;padding-left:10px}
  .adm-nav a.on[data-game]{box-shadow:inset 0 -2px 0 var(--mark),inset 0 0 0 1px var(--on-edge)}
}

/* ---- areas and panels ---- */
.adm-area,.adm .adm-sec{scroll-margin-top:calc(var(--chrome-h,58px) + 14px)}
@media(max-width:899px){.adm-area,.adm .adm-sec{scroll-margin-top:calc(var(--chrome-h,58px) + 60px)}}
.adm-area{margin:0 0 28px}
.adm-area:last-child{margin-bottom:0}
.adm-area-head{display:flex;align-items:center;gap:10px;margin:0 0 10px}
.adm-area-head::after{content:"";flex:1 1 40px;height:1px;background:var(--rule)}
.adm-area-head img{flex:none;width:36px;height:36px;filter:drop-shadow(0 4px 8px rgba(0,0,0,.6))}
/* The area's title is a display title on the page (DISPLAY TIER): the title
   colour, as every display title and the page's own h1 above it (the
   column-head ink is cream since v84, which made these two the only cream
   Alagard on the site), or a game area's mark (20px on the dark page, 7:1
   and up); the game's full name beside it is a small note in the text face. */
.adm-area-head h2{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px;margin:0;color:var(--title)}
.adm-area[data-game] .adm-area-head h2{color:var(--mark)}
.adm-area-head h2 span{color:var(--faint);font:400 var(--fs-3) var(--sans);text-shadow:none}
.adm :is(h2,h3)[tabindex]:focus{outline:none}
.adm :is(h2,h3)[tabindex]:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:var(--r-1)}
/* A section is a window on flat stone; its head (always its first child)
   is the title strip, pulled out to the frame over the section's padding.
   A window that is a section editor's (.wy-edit, inside .adm-editor) is a
   plain inner frame: no drop and no corner ticks of its own, so the RS3
   areas do not draw a window of ticks inside a window of ticks. */
.adm .adm-sec{margin:0 0 14px;padding:16px 18px;--panel-grain:none}
.adm .adm-sec:last-child{margin-bottom:0}
.adm-head{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:4px 12px;
  margin:-16px -18px 14px;padding:10px 18px 9px}
@media(max-width:640px){
  .adm .adm-sec{padding:14px 12px}
  .adm-head{margin:-14px -12px 14px;padding:10px 12px 9px}
}
.adm-head h3{grid-column:1;margin:0;line-height:1.2;color:var(--title)}
.adm-head p{grid-column:1;margin:0;max-width:78ch;color:var(--dim);font-size:var(--fs-3);line-height:1.45}
.adm-head>:not(h3,p){grid-column:2;grid-row:1/span 2;align-self:center}
.adm-editor>.wy-edit{box-shadow:none}
.adm-editor>.wy-edit::before{content:none}
/* a sub-heading inside a section: the column-head ink, sentence case (as
   .perf-h) */
.adm-sub{margin:18px 0 8px;color:var(--name);font-size:var(--fs-3);font-weight:600}
.adm-body>.adm-form:first-child>.adm-sub:first-child,.wy-brain-ed>.adm-sub:first-child{margin-top:0}
.adm-wait{padding:6px 0;color:var(--faint);font-size:var(--fs-3)}

/* ---- overview tiles ---- The overview is one window of wells, as the
   overview's skills strip (OVERVIEW): each well a link to its section, its
   label in sentence case over the state (a word, so the text face, in the
   figure yellow) and the line that explains it; a game's well carries a
   3px bar of its mark down its left. */
.adm .adm-sec:has(>.adm-body>.adm-tiles){padding:4px}
.adm-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr));gap:5px}
.adm-tile{display:flex;flex-direction:column;gap:2px;min-width:0;padding:8px 11px 7px 10px;border:1px solid var(--inset);
  border-radius:var(--r-3);background:var(--row-a);color:var(--ink);text-decoration:none}
.adm-tile:hover{background:var(--row-hover);color:var(--ink)}
.adm-tile[data-game]{box-shadow:inset 3px 0 0 var(--mark)}
.adm-tile-k{color:var(--dim);font-size:var(--fs-2);font-weight:600}
.adm-tile b{color:var(--fig);font-size:var(--fs-6);font-weight:600;line-height:1.25}
.adm-tile:hover b{color:var(--emph)}
.adm-tile-s{color:var(--faint);font-size:var(--fs-3)}

/* ---- settings forms ---- */
.adm-opts{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,250px),1fr));gap:8px;
  min-width:0;margin:0 0 10px;padding:0;border:0}
.adm-choice{grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr))}
.adm-choice legend{padding:0;margin:0 0 6px;color:var(--name);font-size:var(--fs-3);font-weight:600}
.adm-group legend{padding:0;margin:4px 0 6px;font-size:var(--fs-4);font-weight:600;color:var(--ink)}
.adm-choice>.wy-help{grid-column:1/-1;margin:2px 0 0}
/* A setting's choices are faces; a ticked or chosen one is the calm open
   tab (CONTROLS: the warm edge, the fill washed in from its left), its name
   in the open tab's yellow and its help line in the dim ink (the faint one
   is under 4.5:1 on the RS3 wash); a choice that cannot be made now is the
   dimmer face. */
.adm-opt{display:flex;align-items:flex-start;gap:10px;padding:10px 12px;
  border-radius:var(--r-3);cursor:pointer}
.adm-opt:has(input:disabled){cursor:default;border-color:var(--face-edge);background:var(--face-off);box-shadow:none}
.adm-opt input{flex:none;width:16px;height:16px;margin:3px 0 0;padding:0}
.adm-opt b{display:block;font-weight:600;color:var(--ink)}
.adm-opt:has(input:checked) b{color:var(--on-ink)}
.adm-opt:has(input:checked) .wy-help{color:var(--dim)}
.adm-opt:has(input:disabled) b{color:var(--dim)}
.adm-form+.adm-form{margin-top:22px}
.adm-group{min-width:0;margin:0 0 8px;padding:0;border:0}
.adm-form .wy-fgrid{grid-template-columns:repeat(auto-fit,minmax(min(100%,230px),1fr))}
.adm-limit{max-width:180px;font-family:var(--mono);font-size:var(--fs-num)}
/* The brain editor's two multi-control fields. */
.wb-t-bases{display:flex;flex-wrap:wrap;gap:4px 14px;padding:4px 0}
.wb-t-bases label{display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-3);color:var(--ink);cursor:pointer}
.wy-f .wb-t-bases input{width:auto;padding:0}
.wb-t-times{display:flex;gap:8px}
/* Numerals in the traffic ledgers set in mono, like every other figure. */
.adm .wy-stat-tbl td.n{font-family:var(--mono);font-size:var(--fs-num)}

/* ---- lists, editors, previews ---- */
/* Rows here are not links: no pointer and no hover lift. */
.adm .wy-item{flex-wrap:wrap;cursor:default}
.adm .wy-item:hover{--panel-body:initial}
.adm .wy-item-main{flex:1 1 240px}
.adm .wy-item>:is(button,select){flex:none}
.adm-editor{margin-top:14px}
.adm-verdict{margin:0 0 12px;padding:8px 12px;border:1px solid color-mix(in srgb,var(--warn) 45%,transparent);
  border-radius:var(--r-3);background:var(--warn-bg)}
.adm-verdict.is-ok{color:var(--up);border-color:color-mix(in srgb,var(--up) 45%,transparent);background:var(--up-bg)}
.adm-preview{margin-top:16px}
.adm-preview-res{overflow-x:auto}

/* ======================================================= HOUSE PANELS ====
   House by default (see ads.js and ADS). Once the server policy and the
   audience resolve, every eligible placement becomes a first-party house
   panel at the unit's exact size, whatever the visitor's consent or blocker;
   a live creative is a frame layered over it that stays invisible and
   unclickable until the creative has drawn (ads.js), so the panel is what
   shows while it loads, and stays if nothing draws. The frame is declared
   light like its own document: a frame whose colour scheme differs from this
   dark page gets an opaque white backdrop. The mount itself carries no chrome:
   the panel is drawn by .mw-house inside a stage of exactly W x H, so the
   mount's measured width is always the space a unit actually has. */
.mw-ad-stage{position:relative;flex:none;max-width:100%;margin:0 auto}
.mw-ad-stage>iframe{position:absolute;inset:0;z-index:1}
/* The panel is a PANELS member laid out per unit size, in its own frame
   variant: one dark 1px line all round with the light hairline drawn inside
   along its top (a sign, not a window), the grain over stone lit from the
   top, the soft drop. Its size stays the unit's exact size and the art is
   never cut. It is not in the cards' hover lift: the whole panel is its
   link, so its call to action, the gold button, brightens instead
   (interaction states). The logo is the owner's file used whole; the emblem
   is decorative; tagline and call to action are live text. Display faces
   stay off it: it runs down to 50px tall. */
.mw-house{display:grid;width:100%;height:100%;overflow:hidden;align-items:center;justify-items:center;
  gap:6px;padding:10px;color:var(--ink);font-family:var(--sans);text-align:center;text-decoration:none;
  --panel-hi:var(--edge-lo);--panel-body:linear-gradient(180deg,var(--stone-top),var(--stone));
  box-shadow:inset 0 1px 0 var(--edge-hi),var(--panel-shadow)}
.mw-house:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.mw-house>*{min-width:0}
.mw-house img{display:block;max-width:100%;height:auto;user-select:none}
.mw-house-logo{grid-area:logo}
.mw-house-emblem{grid-area:art}
.mw-house-tag{grid-area:tag;font-size:var(--fs-3);font-weight:500;line-height:1.3}
/* The gold button, at one padding in every unit (as approved); its 1px edge
   takes a pixel of the old vertical padding, so its height is unchanged. */
.mw-house-cta{grid-area:cta;padding:4px 12px;border:1px solid var(--btn-edge);border-radius:var(--r-pill);
  background:linear-gradient(180deg,var(--btn-top),var(--btn-bot));box-shadow:inset 0 1px 0 var(--btn-hi);color:var(--btn-ink);
  font-size:var(--fs-3);font-weight:700;line-height:1.2;white-space:nowrap}
.mw-house-160x600{grid-template:"logo" "tag" "art" "cta"/100%;align-content:space-evenly;gap:12px;padding:18px 11px}
.mw-house-160x600 .mw-house-logo,.mw-house-160x600 .mw-house-emblem{width:136px}
.mw-house-160x600 .mw-house-tag{font-size:var(--fs-4)}
.mw-house-160x300{grid-template:"logo" auto "art" 1fr "tag" auto "cta" auto/100%;padding:10px 9px 12px}
.mw-house-160x300 .mw-house-logo{width:128px}
.mw-house-160x300 .mw-house-emblem{width:96px}
.mw-house-160x300 .mw-house-tag{font-size:var(--fs-2)}
.mw-house-300x250{grid-template:"logo logo" auto "art tag" 1fr "art cta" auto/auto 1fr;gap:8px 12px;padding:12px 14px}
.mw-house-300x250 .mw-house-logo{width:176px}
.mw-house-300x250 .mw-house-emblem{width:112px}
.mw-house-300x250 :is(.mw-house-tag,.mw-house-cta){justify-self:start;text-align:left}
.mw-house-300x250 .mw-house-tag{font-size:var(--fs-4)}
.mw-house-728x90{grid-template:"art logo tag cta" 1fr/auto auto 1fr auto;gap:16px;padding:6px 16px 6px 10px}
.mw-house-728x90 .mw-house-emblem{width:150px}
.mw-house-728x90 .mw-house-logo{width:140px}
/* 14px (one line in the approved render) and balanced, so a narrower
   column would take two even lines rather than leave one word alone. */
.mw-house-728x90 .mw-house-tag{justify-self:start;text-align:left;font-size:14px;text-wrap:balance}
.mw-house-468x60{grid-template:"art logo tag cta" 1fr/auto auto 1fr auto;gap:10px;padding:4px 10px 4px 6px}
.mw-house-468x60 .mw-house-emblem{width:100px}
.mw-house-468x60 .mw-house-logo{width:96px}
.mw-house-468x60 .mw-house-tag{justify-self:start;text-align:left;font-size:var(--fs-2);line-height:1.25}
.mw-house-468x60 .mw-house-cta{font-size:var(--fs-2)}
.mw-house-320x50{grid-template:"art logo cta" 1fr/auto auto 1fr;gap:8px;padding:3px 8px 3px 4px}
.mw-house-320x50 .mw-house-emblem{width:84px}
.mw-house-320x50 .mw-house-logo{width:80px}
.mw-house-320x50 .mw-house-tag{display:none}
.mw-house-320x50 .mw-house-cta{justify-self:end}

/* Ad-free layout: a visitor with no placements anywhere (the admin outside a
   template preview, Pro, or ads switched off for them; ads.js stamps
   data-ad-free) gets the rails' footprint as content width on every page,
   160 + 20 + 1500 + 20 + 160 = 1860px. That is one token, --content-max, set
   in SHELL: the page head and the content widen together, so they keep both
   edges. The static pages' 820px reading column keeps its own measure. */

/* ===================================================== SIGN-IN SPLASH ====
   Sign-in splash: full-bleed `cover`, edge-to-edge, and NOTHING ELSE.
   ABSOLUTE RULE (Diego, rejected ~8 times): never `contain`, never letterbox
   bars, never a blurred/darkened backdrop layer, never any side fill of any
   kind. If the wyrm is clipped at some aspect, the ONLY acceptable fix is
   different SOURCE ART composed with croppable dark margin — never a CSS
   arrangement. The dark base colour shows only if the image fails to load.

   GEOMETRY CONTRACT — art set B, three compositions. The owner chose set B and
   had its detached left coil removed (2026-10-04; masters and prompts in
   output/art-2026-10-v79/). The wyrm (crest, head, coils, tail and the scales
   coin) was measured on each pre-fix source by thresholding its bright gold
   pixels; removing the coil can only shrink these boxes, so every threshold
   below still keeps the wyrm whole:
     login-portrait   940x1672  wyrm box x 82-917,  y 188-1505
     login-room      1586x992   wyrm box x 388-1215, y 172-800
     login-ultrawide 2172x724   wyrm box x 565-1500, y 24-685
   `cover` shows a canvas_h*A-wide slice below the canvas aspect and a
   canvas_w/A-tall slice above it, so with the positions below the wyrm stays
   whole for viewport aspect A in:
     portrait   0.528 - 0.714   (60% 53%: keeps the off-centre wyrm centred)
     room       0.834 - 2.45    (51% 50%)
     ultrawide  1.32  - 3.21    (calc(50% + 6vh) to 26/9, then 50% 20%)
   Takeover thresholds: portrait below 19/25 (0.76), room up to 4/3, ultrawide
   from 4/3. The ultrawide composition takes 4:3 through 21:9 because the
   auth card is part of the geometry too. Since v83 (SIGN-IN) it is 27em wide,
   the sign-in view ~36em tall, em = clamp(15px,1.31vh,24px): 405x545 below a
   1145px-tall window, 509x668 at 1440 tall; centred in the room under the 64px
   header row, i.e. 20px below the viewport centre. (v79-v82: 33em x ~44em at
   em clamp(12px,1.31vh,30px), a fixed 396x529 below 916px tall.) Only the
   zoomed ultrawide hall frames that inside
   the wyrm's arc; the room composition puts its head and arc behind the card
   at every desktop aspect, so it serves only 5:4-ish screens where nothing
   else keeps the wyrm whole. The +6vh offset (height-bound below A 3, so 6vh
   is a fixed 43 canvas px) centres the card in the arc's opening rather than
   on the wyrm's box; it is dropped from 26/9, where the canvas runs out of
   side overflow, and 20% there keeps the crest whole first.
   CHECKED against the measured wyrm pixels with the v79 card (edge clearance /
   card-to-wyrm gap, px; negative = clipped / behind the card):
     1920x1080 36 / +3     2560x1080 36 / +3     2560x1440 48 / +4
     3440x1440 48 / +4     1440x900  30 / -1     1366x768  25 / -36
     1280x720  24 / -50    (card is 73% of a 720px viewport: the arc's
                           underside and the snout sit behind its edges)
     768x1024  -28 / -42   390x844  -22 / -90   (see GAPS)
   RE-MEASURED with the v83 sign-in view (edge clearance px / share of the
   wyrm's measured box behind the card; the edge numbers are the art's alone,
   so they did not move):
     1920x1080 36 / 16%    1440x900 30 / 23%    1366x768 25 / 32%
     1280x720  24 / 36%    2560x1440 48 / 14%   3440x1440 48 / 14%
     768x1024 -28 / 30%    390x844 -22 / 70% (v79 card: 80%)
     The v79 card measured 15-25% at 1440x900 and up, 30-42% on laptops.
   GAPS IN ART SET B (a SOURCE ART fix, never CSS):
     A 0.714 - 0.834 (portrait tablets): neither composition fits the wyrm; the
       portrait image loses ~25px of crest and of tail at 768x1024.
     A < 0.528 (tall phones, e.g. 390x844 with no browser bars): the portrait
       image loses its outermost dorsal spikes (~20px) and the coin's rim.
     A > 3.21 (32:9): the crest stays whole but the tail tip is lost (~120px
       at 5120x1440) and the arc dips ~17px behind the card.
     Phones: the 360px card (v83; 340px before) covers ~92% of a 390px width,
       so the card sits over the wyrm's body on every phone with any art. */
#login{background:#050403 url("/assets/login/login-ultrawide.webp") calc(50% + 6vh) 50%/cover no-repeat}
@media (min-aspect-ratio:26/9){#login{background-position:50% 20%}}
@media (max-aspect-ratio:1333/1000){
  #login{background-image:url("/assets/login/login-room.webp");background-position:51% 50%}}
@media (max-aspect-ratio:19/25){
  #login{background-image:url("/assets/login/login-portrait.webp");background-position:60% 53%}}

/* ===== print ===== a price table on paper: no chrome, no ads, dark ink on white */
@media print{
  .hdr,.ad-slot,.ad-rail,.mw-brand-slot,.site-foot,.toast,.modal-bg,.overlay,.page-head-tools{display:none!important}
  body{background:#fff;color:#111}
  /* Panels print as a plain ruled box: the shorthand drops the grain and the
     body. The list is the PANELS rule's member list (plus the stat wells:
     the overview's, Wyrm Picks', the item page's, Paper Trading's and the
     admin's);
     title and foot strips and the pagers' trays print plain, the corner
     ticks not at all, and no title keeps its shadow. */
  :is(.board,.cat-tile,.list-card,.perf-grid,.wy-cl-sum,.perf-note,.perf-t,.wy-edit,.wy-pane,.wy-admin,.wy-item,
    .pt-panel,.pt-cards,.gate,.pick,.t-lock,.t-panel,.t-stats,.t-sim,.list-empty-related,.seo-related,.modal,.tldr,
    .contact-card,.doc-links,.home-total,.home-game-column,.home-value-panel,.wl-pick,.mw-house,.adm-nav),
  .pulse,.market.overview .pulse>*,.perf-card,.t-stat,.wy-stat-tiles>div,.adm-tile,.wy-cl-sum>div,.pt-metric,.pt-modal>div,.seo-list-links>a,
  :is(.about-feats,.about-games)>li{
    background:#fff;border-color:#bbb;box-shadow:none}
  :is(.board .b-head,.wy-pane-head,.wy-res>.wy-res-head,.adm-head,.home-value-head,.home-updatebar,.ht-head,
    .pt-panel-head,.pt-market-head,.pt-ledger-tabs,.t-search,.t-lhead,.t-shead,.tldr>h2,.wy-filters-toggle,.catalogue-pager,
    .catalogue-page-links,.search-pager){background:none;box-shadow:none}
  :is(.board,.pulse,.perf-grid,.wy-cl-sum,.wy-pane,.wy-edit,.wy-admin,.t-panel,.t-lock,.t-stats,.t-sim,.gate,.modal,.tldr,
    .contact-card,.home-value-panel,.home-total,.home-game-column,.pt-panel)::before{display:none}
  *{text-shadow:none!important}
  /* No fills on paper: the column-head band, the row bands, the hovered and
     pinned cells (TABLES, RESPONSIVE) and the icon wells all print as white,
     ruled by the rows' own lines. */
  table,:is(th,td),.mi-ico{background:none!important;box-shadow:none!important}
  /* The two quiet text tones print as greys, so text the builders tint with
     them inline (app.js, wyrm.js: the Buy limit column in the dim tone, a
     missing figure's dash in the faint) stays legible on white. :root:root
     comes after every edition rule at their specificity. */
  :root:root{--dim:#444;--faint:#666}
  tbody td,tbody td.num,thead th,.board .b-head b,.up,.down,.flat,.mi b,.mi em,.t-row,.board .b-head a,.board .b-sub,.wl-al,.wl-tval.muted,.perf-t .muted{color:#111}
  /* the overview's stat strip and band paint their figures by state (OVERVIEW) */
  .market.overview :is(.pulse,.ov-band) :is(b,span,i,small,a,li),.perf-card *,.wy-cl-sum *,.pt-cards *,.wy-stat-tiles *,
  .adm-tile *{color:#111!important}
  thead th small.th-u{color:#444}
  /* the pager's faces and the static pages' link buttons (the 404's links,
     the contact address, the about page's two calls) print as plain ruled
     boxes */
  .pager :is(a,span,button,.page-current){border-color:#bbb;background:none;box-shadow:none;color:#111}
  .doc-links a,.contact-card .mail,.about-cta :is(.mprimary,.msecondary){border:1px solid #bbb;background:none;box-shadow:none;color:#111}
  /* The shared page title, the static pages' reading column and the cards'
     own text keep their dark-theme light inks otherwise. */
  .page-head :is(h1,p),.doc,.doc :is(h1,h2,h3,b,strong,li,p),.cat-tile :is(b,span),.list-card *,.t-shead,
  :is(.home-game-column,.home-total,.home-value-panel) *{color:#111}
  a{color:#111;text-decoration:underline}
}
