:root {
  color-scheme: dark light;
  --bg:#12151a; --panel:#181c23; --line:#2a303b;
  --fg:#e8eaed; --dim:#98a2b3; --accent:#7fd8e4;
  --pass:#5ac47f; --fail:#e2686a; --warn:#e0b24d;
}
@media (prefers-color-scheme: light) {
  :root { --bg:#f6f7f9; --panel:#fff; --line:#dfe3ea; --fg:#12151a; --dim:#5b6472; --accent:#0d7d8f;
          /* The dark-scheme status colours are tuned for a dark backdrop and are
             unreadable on white: measured on #fff they are --pass 2.18:1,
             --fail 3.27:1, --warn 1.97:1, all under the 4.5:1 floor. These are
             not decoration -- they carry the checkers' pass/fail verdicts in
             .s-pass/.s-fail/.s-warn. Darkened here to 5.35 / 6.54 / 5.32:1
             while keeping the hue that makes them readable AS status. */
          --pass:#1f7a45; --fail:#b3261e; --warn:#9e5b00; }
}
* { box-sizing: border-box; }
body { margin:0; background:var(--bg); color:var(--fg);
       font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif; }
a { color: var(--accent); }
code { font-family: ui-monospace,"Cascadia Code",monospace; font-size:.92em; }

header.site { padding:22px 20px 6px; display:flex; align-items:center; gap:14px; }
header.site h1 { margin:0; font-size:26px; letter-spacing:.01em; }
.tag { margin:2px 0 0; color:var(--dim); }
/* The mark is decorative: the h1 beside it already names the page and links
   home, and the brand name is in the <title>, so giving the image alt text too
   would just make a screen reader say it twice. */
.brand { flex:0 0 auto; width:48px; height:48px; }
@media (max-width:560px) { .brand { width:38px; height:38px; } }

.cards { display:grid; gap:16px; grid-template-columns:repeat(auto-fit,minmax(300px,1fr));
         padding:20px; max-width:1000px; }
.card { display:block; padding:18px; background:var(--panel); border:1px solid var(--line);
        border-radius:10px; text-decoration:none; color:inherit; }
.card:hover { border-color:var(--accent); }
.card h2 { margin:0 0 8px; font-size:18px; color:var(--accent); }
.card p { margin:0 0 8px; color:var(--dim); }
.feat { color:var(--fg) !important; font-size:13px; }

.note { margin:8px 20px 24px; padding:14px 16px; max-width:1000px;
        border-left:3px solid var(--accent); background:var(--panel); border-radius:0 8px 8px 0; }
.note h3 { margin:0 0 6px; font-size:15px; }
.note p { margin:0; color:var(--dim); }

footer.site { padding:16px 20px 30px; color:var(--dim); font-size:13px; }
footer.site p { margin:2px 0; }

/* ---- dropzone ---- */
.dropzone { border:2px dashed var(--line); border-radius:12px; background:var(--panel);
            padding:34px 20px; text-align:center; transition:border-color .12s, background .12s; }
.dropzone.dz-over { border-color:var(--accent); background:color-mix(in srgb,var(--accent) 8%,var(--panel)); }
.dz-title { margin:0 0 4px; font-size:17px; }
.dz-sub { margin:0 0 14px; color:var(--dim); font-size:13px; }
.dz-actions { display:flex; gap:10px; justify-content:center; flex-wrap:wrap; }
.dz-actions button { padding:8px 16px; border-radius:7px; border:1px solid var(--line);
                     background:var(--bg); color:var(--fg); cursor:pointer; font-size:14px; }
.dz-actions button:hover { border-color:var(--accent); color:var(--accent); }

/* ---- report ---- */
.report { width:100%; border-collapse:collapse; margin-top:16px; }
.report th, .report td { text-align:left; padding:7px 10px; border-bottom:1px solid var(--line);
                         vertical-align:top; }
.report th { color:var(--dim); font-weight:600; font-size:13px; }
.report .measured { font-family:ui-monospace,monospace; font-size:13px; }
.s-pass { color:var(--pass); } .s-fail { color:var(--fail); } .s-warn { color:var(--warn); }
.detail { color:var(--dim); font-size:13px; }

/* ---- render stage ---- */
#stage { margin-top:18px; }
.bgbar { display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-bottom:8px; }
.bglabel { color:var(--dim); font-size:13px; margin-right:2px; }
.bgbar button { padding:5px 11px; border-radius:6px; border:1px solid var(--line);
                background:var(--panel); color:var(--fg); cursor:pointer; font-size:13px; }
.bgbar button:hover { border-color:var(--accent); color:var(--accent); }
.bgbar input[type=color] { width:34px; height:28px; padding:0; border:1px solid var(--line);
                           border-radius:6px; background:none; cursor:pointer; }
#canvashost { border:1px solid var(--line); border-radius:10px; overflow:hidden;
              background:#12151a; }
/* Viewer size. Morning.star asked for "at least half more or double that size"
   as a low-vision accommodation -- the old min(62vh,560px) was too small to
   inspect a world in. Default is now roughly double the height, and the
   --viewer-h custom property lets the size buttons change it live. */
:root { --viewer-h: min(86vh, 1100px); }
x3d-canvas { display:block; width:100%; height:var(--viewer-h); min-height:420px; }
main { max-width:none !important; }
pre.bounds { background:var(--panel); border:1px solid var(--line); border-radius:8px;
             padding:12px 14px; overflow-x:auto; font-size:13px; margin:14px 0 4px; }
.bgbar select { padding:5px 8px; border-radius:6px; border:1px solid var(--line);
                background:var(--panel); color:var(--fg); font-size:13px; max-width:260px; }
.bgbar input[type=range] { width:110px; accent-color:var(--accent); }
.chk { display:inline-flex; align-items:center; gap:5px; font-size:13px; color:var(--dim); }
.chk input { accent-color:var(--accent); }
.mode-on { border-color:var(--accent) !important; color:var(--accent) !important; }


/* ---- low-vision accommodations ---------------------------------------------
   Raise contrast on the control strip. The dim grey used for secondary labels
   sat around 3:1 against the panel, which is under the WCAG AA 4.5:1 minimum
   for body text -- fine as decoration, not fine as the only label on a control. */
.bglabel { color: var(--fg); font-weight: 600; font-size: 13px; }
.chk { color: var(--fg); }
.bgbar button, .bgbar select { font-size: 14px; padding: 7px 13px; }
.bgbar button:focus-visible, .bgbar select:focus-visible,
.dz-actions button:focus-visible, .report a:focus-visible {
  outline: 3px solid var(--accent); outline-offset: 2px;
}
.viewer-size { display:inline-flex; gap:4px; }
.viewer-size button { min-width:34px; }
.report th { color: var(--fg); }
.detail { color: var(--dim); font-size: 13.5px; }

/* Fullscreen: the host element becomes the whole screen, so the canvas must
   fill it rather than keeping its --viewer-h height. */
#canvashost:fullscreen { background:#000; }
#canvashost:fullscreen x3d-canvas { height:100vh; }

/* ---- material previewer ------------------------------------------------------ */
.visually-hidden { position:absolute; width:1px; height:1px; overflow:hidden;
                   clip:rect(0 0 0 0); white-space:nowrap; }
/* Three columns at desktop width: swatch list, stage, controls beside the shape.
   The goal is the whole tool on ONE 1080p screen with no scrolling -- a creator
   picks a colour, judges the render, and copies the block without ever losing
   sight of any of the three. A single wide stage wasted ~500px on empty backdrop
   and pushed the paste block below the fold.
   The list column is wide enough for two swatch cards side by side; auto-fill
   drops it to one rather than squeezing names. */
/* The STAGE COLUMN is capped, not the <main>: `main { max-width:none !important }`
   above is a deliberate accommodation that frees the item/world viewers from
   their inline 1100px cap, and it would win here anyway. Capping the column and
   centring the row keeps a 2560px monitor from spending 700 extra pixels on
   empty backdrop, since the side columns stop growing at their own maximums. */
.mat-layout { display:grid; gap:18px; padding:0 20px 40px; align-items:start;
              justify-content:center;
              grid-template-columns:minmax(260px,370px) minmax(0,1000px) minmax(300px,400px);
              grid-template-areas:"list stage controls"; }
.mat-list    { grid-area:list; }
.mat-stage   { grid-area:stage; }
.mat-controls{ grid-area:controls; }

/* THE THREE PANES SHARE ONE HEIGHT, and it is measured rather than guessed:
   body becomes a flex column of fixed viewport height and .mat-layout takes the
   slack, so the grid row is exactly "viewport minus header minus footer" with no
   calc(100vh - 240px) fudge factor to go stale the moment the tagline wraps or
   the footer text changes length. Each pane then fills from the inside -- more
   swatches, a bigger preview, and the paste block absorbing the remainder.

   `height`, NOT `min-height`. A flex container needs a DEFINITE height for
   `flex:1` to mean "the leftover space"; with min-height the body sizes to its
   content, the content sizes to the body, and the circularity resolves by the
   swatch list growing to fit all 309 cards -- a 10,000px page.

   Gated on min-height too: this mode hides page overflow, so on a short viewport
   it would put the paste block out of reach. Below that, normal scrolling. */
@media (min-width:1181px) and (min-height:720px) {
  body.mat-page { height:100vh; overflow:hidden; display:flex; flex-direction:column; }
  body.mat-page .mat-layout { flex:1; min-height:0; align-items:stretch; }
  .mat-list, .mat-stage, .mat-controls { height:100%; min-height:0; }
  /* min-height:0 on every flex child, or each refuses to shrink below its
     content and the overflow reappears inside the pane instead. */
  .mat-list .swatches { flex:1; min-height:0; max-height:none; }
  .mat-stage { display:flex; flex-direction:column; }
  .mat-stage #canvashost { flex:1; min-height:0; }
  /* body.mat-page prefix is load-bearing, not decoration: the base
     `.mat-stage x3d-canvas { height:min(56vh,600px) }` below has equal
     specificity and comes later in the file, so it would win and leave the
     canvas short of its cell -- an empty band of backdrop under the scene. */
  body.mat-page .mat-stage x3d-canvas { height:100%; min-height:0; }
  .mat-controls { display:flex; flex-direction:column; }
  .mat-controls #vrmlout { flex:1; min-height:0; overflow:auto; margin-bottom:10px; }
  .mat-controls #copy { align-self:flex-start; }
}

/* Below three-column width the controls drop under the stage, with the list
   still beside both -- the stage stays as wide as it can for as long as it can. */
@media (max-width:1180px) {
  .mat-layout { grid-template-columns:minmax(240px,340px) minmax(0,1fr);
                grid-template-areas:"list stage" "list controls"; }
}
@media (max-width:900px) {
  .mat-layout { grid-template-columns:1fr;
                grid-template-areas:"list" "stage" "controls"; }
}
.mat-list { position:sticky; top:12px; display:flex; flex-direction:column; gap:8px; }
.mat-list input[type=search], .mat-list select {
  width:100%; padding:9px 11px; font-size:14px; border-radius:8px;
  border:1px solid var(--line); background:var(--panel); color:var(--fg); }

/* ---- library switch + category pills ---------------------------------------- */
.lib-seg { display:flex; }
.lib-seg button { flex:1; }
.lib-note { margin:0; font-size:13.5px; color:var(--dim); line-height:1.4; }

/* Pills rather than a <select>: every category is visible at once and each is a
   full-size click target. Capped and scrollable so 13 of them cannot push the
   swatch list off screen. */
.cat-tabs { display:flex; flex-wrap:wrap; gap:6px; max-height:132px; overflow-y:auto; }
.cat-tabs button { padding:6px 12px; border-radius:999px; border:1px solid var(--line);
                   background:var(--panel); color:var(--fg); cursor:pointer;
                   font-size:13.5px; font-weight:600; }
.cat-tabs button:hover { border-color:var(--accent); color:var(--accent); }
/* The blanket `.mode-on` rule near the top of this file sets accent text with
   !important, which on a filled accent pill is accent-on-accent -- invisible.
   Overriding it needs !important back. The fill is nudged toward --fg because
   the raw accent on near-white is only 4.8:1: at 88% it clears WCAG AA for
   13.5px text in both colour schemes, which the light scheme otherwise misses. */
.cat-tabs button.mode-on { background:color-mix(in srgb,var(--accent) 88%,var(--fg));
                           color:var(--bg) !important; }

/* ---- swatch cards ------------------------------------------------------------ */
/* Height is budgeted, not chosen: the list has to fit the one-page target
   alongside the header, the category pills and the footer. It scrolls
   internally, so a shorter box costs reach, not access. */
.swatches { max-height:min(48vh,520px); overflow-y:auto; display:grid; gap:6px;
            grid-template-columns:repeat(auto-fill,minmax(158px,1fr));
            border:1px solid var(--line); border-radius:8px; padding:6px;
            background:var(--panel); align-content:start; }
.swatch { display:grid; grid-template-columns:40px minmax(0,1fr); gap:9px;
          align-items:center; padding:7px; border:1px solid transparent;
          border-radius:8px; background:var(--bg); color:var(--fg); cursor:pointer;
          font-size:13.5px; text-align:left; }
.swatch:hover, .swatch:focus-visible { border-color:var(--accent);
          background:color-mix(in srgb,var(--accent) 14%,var(--bg)); }
.swatch.mode-on { border-color:var(--accent);
          background:color-mix(in srgb,var(--accent) 22%,var(--bg)); }
.sw-copy { min-width:0; }
/* Names like "Evergreen Midnight Cerulean Soft Sheen" do not fit one line in a
   two-column grid, and shrinking the text to fit is the one option not on the
   table. Three lines is what it takes for the longest name in the pack to land
   whole; short names still make short cards. */
.sw-name { display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical;
           overflow:hidden; font-weight:600; }
.sw-cat { display:block; font-size:13px; color:var(--dim); overflow:hidden;
          text-overflow:ellipsis; white-space:nowrap; }
.sw-clamped { color:var(--warn); }
.sw-empty { grid-column:1/-1; margin:0; padding:18px; text-align:center;
            color:var(--dim); font-size:13.5px; border:1px dashed var(--line);
            border-radius:8px; }

/* A shaded ball, not a flat square, so a material reads as a material: the
   checkerboard shows through anything transparent, ::before is the material
   itself (dimmed by transparency), and ::after is the gloss sheen and contact
   shadow that make it look round. */
.chip { position:relative; width:40px; height:40px; border-radius:50%;
        flex:0 0 auto; overflow:hidden;
        border:1px solid color-mix(in srgb,var(--fg) 28%,transparent);
        background-color:#8a8a8a;
        background-image:linear-gradient(45deg,#00000024 25%,transparent 25% 75%,#00000024 75%),
                         linear-gradient(45deg,#00000024 25%,transparent 25% 75%,#00000024 75%);
        background-size:12px 12px; background-position:0 0,6px 6px; }
.chip::before { content:""; position:absolute; inset:0; background:var(--chip-fill);
                opacity:var(--chip-alpha,1); }
.chip::after { content:""; position:absolute; inset:0; border-radius:50%;
               background:linear-gradient(135deg,#ffffff2e,transparent 44%,#0000001f);
               box-shadow:inset -6px -7px 10px #00000038; }
.mat-stage x3d-canvas { height:min(56vh,600px); }
.mat-controls { margin-top:14px; }
/* Beside the stage there is no toolbar above it to clear, so it starts level. */
@media (min-width:1181px) { .mat-controls { margin-top:0; } }
.mat-controls h2 { font-size:17px; margin:0 0 10px; color:var(--accent); }
.mat-provenance { margin:-4px 0 12px; font-size:13.5px; color:var(--dim); line-height:1.45; }
.mat-provenance[hidden] { display:none; }
.mat-provenance .clamp-warn { color:var(--warn); }
.mat-controls h3 { font-size:14px; margin:14px 0 6px; color:var(--dim); }
.sliders { display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); gap:10px; }
.ctl { display:grid; grid-template-columns:118px minmax(0,1fr) auto; align-items:center;
       gap:8px; font-size:13.5px; }
/* These are the numeric readouts a creator reads off the sliders to transcribe
   into their .wrl -- the last thing that should be the smallest, dimmest text on
   the page. Was 12.5px/--dim, the only sub-13px size in the stylesheet. */
.ctl code { font-size:13.5px; color:var(--fg); min-width:118px; text-align:right; }
.ctl input[type=range] { width:100%; accent-color:var(--accent); }
.ctl input[type=color] { width:44px; height:28px; padding:0; border:1px solid var(--line);
                         border-radius:6px; background:none; cursor:pointer; }
#copy, #shot { border-radius:7px; border:1px solid var(--line);
               background:var(--panel); color:var(--fg); cursor:pointer; font-size:14px; }
#copy { padding:8px 15px; }
#copy:hover, #shot:hover { border-color:var(--accent); color:var(--accent); }
/* Icon-only, so it keeps an explicit 36px box: dropping the text label must not
   also shrink the target. The label lives in aria-label + title instead. */
#shot { display:inline-flex; align-items:center; justify-content:center;
        width:36px; height:36px; padding:0; }
#shot svg { width:19px; height:19px; fill:none; stroke:currentColor;
            stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }

/* ---- backdrop mode switch (solid / gradient / image) ------------------------ */
.seg { display:inline-flex; gap:4px; }
.seg button { padding:6px 11px; border-radius:6px; border:1px solid var(--line);
              background:var(--panel); color:var(--fg); cursor:pointer; font-size:14px; }
.seg button:hover { border-color:var(--accent); color:var(--accent); }
.backdrop-sub { display:inline-flex; align-items:center; gap:6px; }
.backdrop-sub[hidden] { display:none; }
.filebtn { padding:6px 11px; border-radius:6px; border:1px solid var(--line);
           background:var(--panel); color:var(--fg); cursor:pointer; font-size:14px; }
.filebtn:hover { border-color:var(--accent); color:var(--accent); }
.backdrop-filename { color:var(--fg); font-size:13px; max-width:160px; overflow:hidden;
                      text-overflow:ellipsis; white-space:nowrap; }

/* ---- Mall Item Checker: the checking-room workspace --------------------------
   ONE WINDOW, NO PAGE SCROLL. A creator reading "lowest Y is -1.740, must be
   -1.750" has to be able to look at the item while reading it, and the previous
   single-column page put the rule table a screen and a half below the viewer.
   So: three columns that share the viewport's height, each filling from the
   inside, with contained scroll regions where the content genuinely overflows.

   Same mechanism as .mat-page above and for the same reason -- `height`, not
   `min-height`. A flex container needs a DEFINITE height for `flex:1` to mean
   "the leftover space"; with min-height the body sizes to its content and the
   content sizes to the body, and the circularity resolves by the rule table
   growing the page to 3,000px.

   Nothing here shrinks type to make it fit. The floor is 13px, values a creator
   reads off the screen are 13.5px, controls are 14px, body is 15px, exactly as
   the rest of the stylesheet. Where something did not fit, it got a scroll
   region or a wrap, not a smaller font. */

.item-page header.site { padding:12px 18px 4px; gap:12px; }
.item-page header.site h1 { font-size:22px; }
.item-page header.site .tag { font-size:13.5px; }
.item-page .brand { width:38px; height:38px; }

.item-layout { display:grid; gap:14px; padding:10px 16px 16px; align-items:start;
               grid-template-columns:minmax(258px,300px) minmax(0,1fr) minmax(300px,368px); }

/* The gate is BOTH dimensions. Below either, the page returns to ordinary
   scrolling: a 600px-tall window cannot hold three panes without either hiding
   controls or shrinking text, and only one of those is allowed. */
@media (min-width:1180px) and (min-height:640px) {
  body.item-page { height:100vh; overflow:hidden; display:flex; flex-direction:column; }
  body.item-page .item-layout { flex:1; min-height:0; align-items:stretch; }
  .item-rail, .item-stage, .item-panel { height:100%; min-height:0; }
}
@media (min-width:1600px) {
  .item-layout { grid-template-columns:minmax(300px,340px) minmax(0,1fr) minmax(360px,420px); }
}
/* Narrower than three columns: the report drops under the stage and the rail
   stays beside both, so the viewer keeps its width for as long as it can. */
@media (max-width:1179px) {
  .item-layout { grid-template-columns:minmax(250px,300px) minmax(0,1fr);
                 grid-template-areas:"rail stage" "rail panel"; }
  .item-rail { grid-area:rail; } .item-stage { grid-area:stage; } .item-panel { grid-area:panel; }
  .item-page x3d-canvas { height:min(60vh,620px); }
}
@media (max-width:860px) {
  .item-layout { grid-template-columns:1fr; grid-template-areas:"rail" "stage" "panel"; }
}

/* ---- left rail ---- */
.item-rail { display:flex; flex-direction:column; gap:10px; overflow-y:auto; }
.item-rail .dropzone { padding:14px 12px; }
.item-rail .dz-title { font-size:15px; margin-bottom:2px; }
.item-rail .dz-sub { margin-bottom:10px; }
.item-rail .dz-actions button { padding:7px 12px; }
.rail-file { margin:0; font-size:13.5px; color:var(--fg); word-break:break-all; }
.rail-block { background:var(--panel); border:1px solid var(--line); border-radius:9px;
              padding:10px 12px; }
.rail-block h2 { margin:0 0 7px; font-size:14px; color:var(--fg); font-weight:600;
                 letter-spacing:.02em; text-transform:uppercase; }
.rail-note { margin:8px 0 0; font-size:13px; color:var(--dim); line-height:1.4; }

/* The verdict is the first thing a creator looks for, so it is a block of its
   own rather than a line of coloured text. The tint is 14% over the panel, which
   leaves --fg body text at its normal contrast; the colour carries in the border
   and the status word, never in the readable text alone. */
.verdict { margin:0; padding:9px 12px; border-radius:9px; font-size:14px;
           border:1px solid var(--line); border-left-width:4px; background:var(--panel); }
.verdict.v-pass { border-left-color:var(--pass);
                  background:color-mix(in srgb,var(--pass) 12%,var(--panel)); }
.verdict.v-fail { border-left-color:var(--fail);
                  background:color-mix(in srgb,var(--fail) 12%,var(--panel)); }
.verdict.v-idle { border-left-color:var(--dim); color:var(--dim); }

/* Label/value rows. The value is the thing being read, so it gets the monospace
   and the full --fg; the label is allowed to be quieter but not smaller. */
.nums { margin:0; display:grid; gap:5px; }
.nums > div { display:flex; justify-content:space-between; align-items:baseline; gap:10px; }
.nums dt { font-size:13.5px; color:var(--dim); }
.nums dd { margin:0; font-family:ui-monospace,"Cascadia Code",monospace; font-size:13.5px;
           color:var(--fg); text-align:right; }
.nums.wide > div { border-bottom:1px solid var(--line); padding-bottom:5px; }
.nums.wide > div:last-child { border-bottom:0; }
.nums.wide dd { word-break:break-all; }

.toggles { display:flex; flex-wrap:wrap; gap:6px; }
.toggles button { padding:6px 11px; border-radius:7px; border:1px solid var(--line);
                  background:var(--bg); color:var(--fg); cursor:pointer; font-size:14px; }
.toggles button:hover { border-color:var(--accent); color:var(--accent); }

/* ---- centre stage ---- */
.item-stage { display:flex; flex-direction:column; gap:8px; min-width:0; }
.stagebar { display:flex; gap:7px; align-items:center; flex-wrap:wrap; }
.stagebar .seg { display:inline-flex; gap:4px; flex-wrap:wrap; }
.stagebar .bglabel { margin-left:4px; }
.stagebar .seg button, .stagebtn {
  padding:6px 11px; border-radius:6px; border:1px solid var(--line);
  background:var(--panel); color:var(--fg); cursor:pointer; font-size:14px; }
.stagebar .seg button:hover, .stagebtn:hover { border-color:var(--accent); color:var(--accent); }
.stagebtn { margin-left:auto; }
.stagebtn:disabled { opacity:.5; cursor:default; }
.stagebtn:disabled:hover { border-color:var(--line); color:var(--fg); }
.stagebar input[type=color] { width:34px; height:30px; padding:0; border:1px solid var(--line);
                              border-radius:6px; background:none; cursor:pointer; }
.stagebar button:focus-visible, .stagebar input:focus-visible,
.toggles button:focus-visible, .tabs button:focus-visible {
  outline:3px solid var(--accent); outline-offset:2px; }

.item-page #canvashost { position:relative; flex:1; min-height:0; }
body.item-page x3d-canvas { height:100%; min-height:0; }
@media (max-width:1179px) { body.item-page x3d-canvas { height:min(60vh,620px); } }

/* Sits ON the render, so it cannot rely on the page's colour scheme -- it gets
   its own opaque plate and a fixed light-on-dark pair (13.9:1). */
.stage-overlay { position:absolute; left:10px; bottom:10px; margin:0;
                 padding:5px 10px; border-radius:7px; font-size:13.5px;
                 font-family:ui-monospace,"Cascadia Code",monospace;
                 background:#0d1117e6; color:#e8eaed; border:1px solid #3a4250;
                 pointer-events:none; }
.stage-overlay:empty { display:none; }

.stage-empty { flex:1; min-height:260px; display:flex; align-items:center; justify-content:center;
               text-align:center; padding:24px; background:var(--panel);
               border:2px dashed var(--line); border-radius:10px; }
.stage-empty > div { max-width:44ch; }
.stage-empty h2 { margin:0 0 10px; font-size:19px; color:var(--accent); }
.stage-empty p { margin:0 0 8px; font-size:14.5px; line-height:1.5; }
.stage-empty p:last-child { margin-bottom:0; }
.stage-empty[hidden] { display:none; }

/* ---- right report panel ---- */
.item-panel { display:flex; flex-direction:column; min-width:0;
              background:var(--panel); border:1px solid var(--line); border-radius:10px; }
.tabs { display:flex; gap:4px; padding:8px 8px 0; border-bottom:1px solid var(--line); }
.tabs button { padding:7px 13px; border-radius:7px 7px 0 0; border:1px solid transparent;
               border-bottom:0; background:none; color:var(--fg); cursor:pointer;
               font-size:14px; font-weight:600; margin-bottom:-1px; }
.tabs button:hover { color:var(--accent); }
.tabs button[aria-selected=true] { border-color:var(--line); background:var(--bg);
                                   color:var(--accent) !important; }
.tabpanes { flex:1; min-height:0; overflow-y:auto; padding:10px 12px 14px; }
.tabpanes h3 { margin:14px 0 7px; font-size:14px; color:var(--fg); }
.tabpanes h3:first-child { margin-top:2px; }
.item-panel .report { margin-top:0; }
.item-panel .report th, .item-panel .report td { padding:6px 7px; }
.item-panel pre.bounds { margin:0 0 6px; }

/* Stacked rule rows, because the report lives in a ~370px column now. The
   status word carries a colour AND the word itself -- "pass"/"FAIL"/"soft" --
   so the verdict survives a colour-blind reader and a greyscale screenshot. */
.checks { list-style:none; margin:0; padding:0; }
.checks li { display:grid; grid-template-columns:auto minmax(0,1fr); gap:9px;
             padding:9px 0; border-bottom:1px solid var(--line); }
.checks li:last-child { border-bottom:0; }
.chk-mark { font-size:13px; font-weight:700; text-transform:uppercase;
            letter-spacing:.03em; padding-top:1px; min-width:3.2em; }
.chk-body { min-width:0; }
.chk-name { margin:0; font-size:14px; }
.chk-measured { margin:2px 0 0; font-size:13.5px; color:var(--fg); word-break:break-word; }
.chk-limit { color:var(--dim); }
.checks .detail { margin:2px 0 0; }

/* `code { font-size:.92em }` near the top of this file is fine at 15px body, but
   inside the 13.5px tagline and the 13.5px filename line it lands at 12.42px --
   below the 13px floor this project treats as a hard accessibility minimum, and
   the filename is something a creator actually reads. Floor it rather than
   dropping the ratio, so nothing that already clears 13px changes size.
   (The same 12.42px case exists in /world's and /materials' taglines; left
   alone here because this lane is /item.) */
.item-page code { font-size: max(13px, .92em); }

/* The blanket `.mode-on` sets raw --accent text, which on the light scheme's
   near-white --bg measures 4.51:1 -- over the AA floor, but only just, and this
   page has more selected-state controls than any other. Mixed 18% toward --fg it
   measures 5.6:1 light / 9.6:1 dark while still reading as the accent.
   !important because the rule it overrides uses it. */
.item-page .toggles button.mode-on,
.item-page .stagebar .seg button.mode-on,
.item-page .tabs button[aria-selected="true"] {
  color: color-mix(in srgb, var(--accent) 82%, var(--fg)) !important;
  border-color: color-mix(in srgb, var(--accent) 82%, var(--fg)) !important;
}

/* Short desktop viewports: tighten SPACING so every scale-aid toggle stays above
   the rail's fold. At 1366x768 the rail ran 27px long once the avatar toggle was
   relabelled "Cybertown avatar" and wrapped the group to three rows, which put
   the Mall-envelope toggle out of sight.

   Padding and gaps only. Type size is not a lever here -- see the accessibility
   rules in CLAUDE.md. */
@media (min-width:1180px) and (max-height:820px) {
  .item-rail { gap:6px; }
  .item-rail .dropzone { padding:11px 12px; }
  .item-rail .dz-sub { margin-bottom:8px; }
  .rail-block { padding:7px 11px; }
  .rail-block h2 { margin-bottom:5px; }
  .rail-block .nums { gap:4px; }
  .toggles { gap:5px; }
  /* Budgeted for the FAILING case, which is the tall one: "3 hard rule
     failure(s). This would be rejected." wraps to two lines in a 260px rail and
     is worth ~20px. Budgeting for the passing one-line verdict instead pushed
     the Mall-envelope toggle out of sight at 1366x768 exactly when a creator is
     looking at a rejection. */
  .verdict { padding:8px 11px; }
}
