/* Oasis header menu — the mega-menu that hangs off the masthead.

   THE COMPONENT TIER. tokens.css is the design system; this block is the menu's
   third tier and the only place in the menu stylesheets that names a semantic
   role. Nothing carries a var() fallback — every token here is declared in
   tokens.css or theme.css, and check-menu-tokens.js rejects fallbacks because
   they paper over a rename instead of failing loudly. */
:root{
  /* Ink and surface */
  --ml-ink:var(--ink);
  --ml-muted:var(--steel-2);
  --ml-accent:var(--gold);
  --ml-panel:var(--paper);
  --ml-panel-2:var(--paper-2);
  --ml-line:var(--hair);
  --ml-glow:color-mix(in srgb,var(--gold) 14%,transparent);
  --ml-current-rail:var(--stroke-accent);

  /* Tone roles. The wireframe blocks each destination in its own pastel; these
     map that intent onto semantic colours so the dark tier moves them for free.
     A tone tints a surface — it never fills a shape at full strength, and it
     never carries meaning on its own, because colour alone is not a label. */
  /* --up and --down are NOT in this list, and were removed from it. They are the
     price-direction roles: on a trading product a green tile and a red tile say
     "rising" and "falling", not "marketplace" and "dashboard". Tinting menu
     categories with them made colour assert something untrue about the
     destination. These are hue primitives and neutral semantic roles instead —
     they carry no market meaning, and no tone is ever the only thing telling you
     what a group is; the label always is. */
  --ml-tone-lead:var(--secondary);
  --ml-tone-info:var(--info);
  --ml-tone-violet:var(--blue-700);
  --ml-tone-steel:var(--steel);
  --ml-tone-grow:var(--green-400);
  --ml-tone-sun:var(--gold-hi);
  --ml-tone-ember:var(--warn);
  --ml-tone-sky:var(--blue-400);
  --ml-tone-plain:var(--slate-300);
  /* Two more hues so the eleven news categories can each hold one. */
  --ml-tone-gold:var(--gold);
  --ml-tone-rose:var(--red-400);

  /* Space */
  --ml-space-hair:var(--sp-8);
  --ml-space-tight:var(--sp-12);
  --ml-space-snug:var(--sp-16);
  --ml-space-nav:var(--sp-20);
  --ml-space-room:var(--sp-24);
  --ml-space-wide:var(--sp-32);

  /* Radius */
  --ml-radius-tile:var(--radius-sm);
  --ml-radius-panel:var(--radius);
  --ml-radius-icon:var(--radius-avatar);
  --ml-radius-control:var(--radius-ctl);

  /* Type */
  --ml-fs-label:var(--fs-caption);
  --ml-fs-body:var(--fs-sm);
  --ml-fs-lead:var(--fs-body);
  --ml-fs-tile:var(--fs-h4);

  /* Elevation */
  --ml-shadow-shell:var(--shadow-menu);

  /* THE TINT LADDER. Six steps, and every tone-tinted surface in this file
     uses one of them. It exists because thirteen layouts were built over many
     passes and accumulated TWENTY-SEVEN different percentages — 46 and 48 and
     50 for the same job — so blocks that were meant to read as siblings did
     not. A ladder is not tidiness: an eye cannot tell 46 from 50, but it can
     tell that a set is inconsistent, and that is what reads as unfinished.
     Change a step here and every layout moves together. */
  --ml-fill-quiet:16%;
  --ml-fill-soft:30%;
  --ml-fill-rest:46%;
  --ml-fill-strong:62%;
  --ml-fill-hover:68%;
  --ml-edge:80%;

  /* Structural maxima — geometry, not design values. */
  --ml-search-max:380px;
  --ml-news-columns:3;
  /* Layout 2. The tile floor is the width of the longest label at --ml-fs-body
     without breaking mid-word; the icon holder is one tap target so the glyph is
     never the only thing you can hit. The news band owns the full width, so it
     carries one more column than the boxed board in layout 1. */
  --ml-tile-min:124px;
  --ml-tile-icon:var(--touch-target);
  --ml-news-columns-wide:4;
  /* Layout 5. One bento row; the tall blocks are four of these. */
  --ml-bento-row:74px;
  /* Layout 7. Frontage floor: the narrowest a facing may shrink to and still be
     a tap target with a readable Thai label. */
  --ml-facing-min:96px;
  /* Layout 5. The orbit field. Tall enough that the circle is a circle and the
     staggered satellites keep the offsets they were drawn at. */
  --ml-orbit-min:430px;
  /* Layout 6. The key rail is three-tenths, and its rows share one height so
     the run stays a legend rather than a list. */
  --ml-key-rail:310px;
  --ml-key-row:30px;
  /* Layout 7. The vendor rail and the stock floor. Both were shared with
     three culled layouts and went out with them, which left marquee pointing
     at two undefined vars - and an undefined var voids the whole declaration
     rather than falling back, so the layout silently lost its columns.
     Named for their one owner now so a future cull cannot repeat it. */
  --ml-marquee-rail:280px;
  --ml-marquee-min:400px;
  /* Layout 13. The Lodestone rail is wider than the others because it holds a
     featured block rather than only rows. */
  --ml-lode-rail:250px;
}

/* ---- the trigger ------------------------------------------------------- */

.site-nav,.mobile-menu{display:none!important}
.site-header-row{position:relative}
.header-actions{margin-inline-start:auto;gap:var(--header-action-gap)}
/* Centred on the row — the middle of the masthead, not the midpoint between a
   brand and an action cluster whose widths change per page and per locale. */
.menu-lab-trigger{
  position:absolute;inset-inline-start:50%;translate:-50% 0;z-index:2;
  display:inline-flex;align-items:center;gap:var(--ml-space-hair);
  min-block-size:var(--tap);padding-inline:var(--ml-space-tight);
  border:var(--hairline) solid var(--border);border-radius:var(--radius-ctl);
  background:transparent;color:var(--text);cursor:pointer;font-size:var(--ml-fs-body);
  transition:border-color var(--dur-fast) ease,background var(--dur-fast) ease;
}
/* It fills rather than lifts: a control that rises 1px and then unfolds the
   whole masthead beneath it reads as two separate events. */
.menu-lab-trigger:hover,.menu-lab-trigger[aria-expanded="true"]{border-color:var(--text-2)}
.menu-lab-trigger[aria-expanded="true"]{background:color-mix(in srgb,var(--ml-accent) 12%,transparent)}
.menu-lab-trigger:focus-visible,.menu-lab-shell a:focus-visible,
.menu-lab-shell button:focus-visible,.menu-lab-shell input:focus-visible{
  outline:var(--focus-width) solid var(--focus);outline-offset:3px;
}
.menu-lab-trigger svg{
  inline-size:20px;block-size:20px;flex:0 0 auto;
  fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;
}
.menu-lab-trigger-text{white-space:nowrap;letter-spacing:var(--ls-wide)}

/* ---- the expansion ----------------------------------------------------- */

/* The panel HANGS. It stays a child of .site-header — it inherits the header's
   stacking and its sticky position, and mounting it on body would mean owning
   both from scratch — but it is taken out of the header's flow so opening it
   never reflows the page underneath. The header keeps its resting height and
   the panel is drawn over the content at top:100%, the header's own edge.

   It used to be a normal-flow child, which made the masthead grow and push
   every page down by the panel's full height on hover; a pointer brushing the
   trigger moved the thing the reader was looking at.

   The 0fr -> 1fr grid row survives the move: it is still the one way to
   transition to a content-derived height without measuring it in script, and it
   resolves the same against an out-of-flow box's indefinite height. */
.menu-lab-overlay{
  position:absolute;inset-inline:0;top:100%;
  display:grid;grid-template-rows:0fr;color:var(--ml-ink);
  transition:grid-template-rows var(--dur-base) var(--ease-standard);
}
.menu-lab-overlay.is-open{grid-template-rows:1fr}
/* Clipped, not hidden, so the collapse animates both ways. Keeping a collapsed
   menu out of the tab order is menu-lab.js's job — it sets inert.

   The clip and the scroller are deliberately two different boxes. This is the
   box the 0fr -> 1fr row resizes, so it clips and does nothing else: `auto`
   here means it spends the entire unfold shorter than its own content, which
   paints a scrollbar for the length of the animation and discards it the moment
   the row lands. The height cap belongs on a box the animation does not touch —
   see .menu-lab-inner. */
.menu-lab-shell{
  min-block-size:0;overflow:hidden;
  background:
    linear-gradient(180deg,color-mix(in srgb,var(--ml-panel-2) 96%,transparent),var(--ml-panel-2)),
    radial-gradient(120% 80% at 82% 0%,var(--ml-glow),transparent 60%);
  border-block-end:var(--hairline) solid var(--ml-line);
  box-shadow:var(--ml-shadow-shell);
}
/* The scroller. Out of flow, a panel taller than the window has nowhere to go:
   the page can no longer be scrolled to reach its foot, because the page never
   grew. So the menu caps against the space below the header and scrolls itself.
   Its height is content-derived and the row animation never touches it, so the
   scrollbar appears only when the menu genuinely outgrows the window — never as
   an artefact of opening.

   It carries the site rail as padding rather than wearing .wrap's width, so the
   scroll box is full-bleed and its scrollbar rides the panel's own edge instead
   of floating at the rail's. The max() is .wrap's min() restated: a gutter floor,
   and above that the leftover split either side. */
.menu-lab-inner{
  display:grid;gap:var(--ml-space-room);
  inline-size:100%;
  padding-block:var(--ml-space-room) var(--ml-space-nav);
  padding-inline:max(var(--site-rail-gutter),calc((100% - var(--site-rail-max)) / 2));
  max-block-size:calc(100dvh - var(--public-header-height));
  overflow:auto;overscroll-behavior:contain;
}

/* ---- minimal search ---------------------------------------------------- */

/* A rule and a glyph, no box. Every destination is already on screen, so the
   field narrows the list rather than inviting a query — it must not out-weigh
   the menu underneath it. */
.menu-lab-search{
  display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;
  gap:var(--ml-space-hair);max-inline-size:var(--ml-search-max);
  padding-block-end:var(--ml-space-hair);
  border-block-end:var(--hairline) solid var(--ml-line);
}
.menu-lab-search svg{
  inline-size:18px;block-size:18px;
  fill:none;stroke:var(--ml-muted);stroke-width:1.8;stroke-linecap:round;
}
.menu-lab-search input{
  min-inline-size:0;padding:0;border:0;outline:0;background:transparent;
  color:var(--ml-ink);font:var(--ml-fs-lead)/var(--lh-snug) var(--font);
}
.menu-lab-search input::placeholder{color:var(--ml-muted)}
.menu-lab-search:focus-within{border-block-end-color:var(--ml-accent)}
.menu-lab-search small{
  color:var(--ml-muted);font-family:var(--mono);font-size:var(--ml-fs-label);
  letter-spacing:var(--ls-wide);white-space:nowrap;
}

/* ---- the three columns ------------------------------------------------- */

/* Rail · stack · board. The proportions are the wireframe's: a narrow rail of
   primary destinations, a two-panel middle, and a news board wide enough to
   hold eleven topics without becoming a single tall list. */
.menu-lab-nav{
  display:grid;
  grid-template-columns:minmax(180px,.85fr) minmax(180px,.9fr) minmax(0,2.6fr);
  gap:var(--ml-space-snug);align-items:start;
}
.menu-lab-group{min-inline-size:0}
.menu-lab-links,.menu-lab-sublinks{margin:0;padding:0;list-style:none}
.menu-lab-links{display:grid;gap:var(--ml-space-hair);align-content:start}
[data-menu-column="stack"] .menu-lab-links{gap:var(--ml-space-snug)}

/* ONE mapping, on the attribute itself, for every component that carries a
   tone. This used to be written three times over — once for .menu-lab-branch,
   once for .menu-lab-fold, once for [data-menu-desk] — and every new layout
   that introduced its own element silently missed out. A missing --ml-tone is
   not a missing colour: color-mix() with an undefined var is invalid at
   computed-value time, so the ENTIRE background declaration is thrown away and
   the control renders as bare panel. That is what made the bento read white.
   Bound to the attribute, a layout gets its tones by declaring them. */
[data-menu-tone="lead"]{--ml-tone:var(--ml-tone-lead)}
[data-menu-tone="info"]{--ml-tone:var(--ml-tone-info)}
[data-menu-tone="violet"]{--ml-tone:var(--ml-tone-violet)}
[data-menu-tone="steel"]{--ml-tone:var(--ml-tone-steel)}
[data-menu-tone="grow"]{--ml-tone:var(--ml-tone-grow)}
[data-menu-tone="sun"]{--ml-tone:var(--ml-tone-sun)}
[data-menu-tone="ember"]{--ml-tone:var(--ml-tone-ember)}
[data-menu-tone="sky"]{--ml-tone:var(--ml-tone-sky)}
[data-menu-tone="gold"]{--ml-tone:var(--ml-tone-gold)}
[data-menu-tone="rose"]{--ml-tone:var(--ml-tone-rose)}
[data-menu-tone="plain"]{--ml-tone:var(--ml-tone-plain)}

/* ---- destinations: type and tone, not pictures ------------------------- */

/* No background image anywhere. The old board sliced one 2.3MB sprite atlas
   across twelve buttons, which forced one aspect ratio and one theme on all of
   them. A label, a tint and a rail carry the same hierarchy for nothing. */
.menu-lab-branch{
  min-inline-size:0;border-radius:var(--ml-radius-tile);
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-quiet),var(--ml-panel-2));
  transition:background var(--dur-fast) ease;
}
/* The two column families are panels: taller blocks that hold a heading and a
   list, rather than single-line tiles. */
.menu-lab-branch.is-panel{padding-block-end:var(--ml-space-tight);border-radius:var(--ml-radius-panel)}

.menu-lab-link{
  display:flex;align-items:baseline;gap:var(--ml-space-hair);
  padding:var(--ml-space-tight) var(--ml-space-tight);
  color:var(--ml-ink);text-decoration:none;border-radius:inherit;
  transition:background var(--dur-fast) ease;
}
.menu-lab-link strong{font-weight:var(--fw-semibold);line-height:var(--lh-tight)}
.menu-lab-link.is-primary strong{font-size:var(--ml-fs-tile)}
.menu-lab-link.is-lead strong{font-size:var(--fs-h3)}
a.menu-lab-link:hover{background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-quiet),transparent)}
.menu-lab-link.is-current{box-shadow:inset var(--ml-current-rail) 0 var(--ml-accent)}

/* Children sit inside their parent's block, indented under a hairline that
   reads as descent. The news board is the one that would run too tall as a
   single column, so it splits. */
.menu-lab-sublinks{
  display:grid;margin-inline:var(--ml-space-nav) var(--ml-space-tight);
  padding-inline-start:var(--ml-space-tight);
  border-inline-start:var(--hairline) solid color-mix(in srgb,var(--ml-ink) 16%,transparent);
}
/* ---- the news folds ---------------------------------------------------- */

/* Nine disclosures in three columns. The folds themselves are laid out as
   masonry-ish columns so a tall group does not leave a tall gap beside it; each
   fold stays whole because break-inside is forbidden. */
.menu-lab-folds{
  columns:var(--ml-news-columns);column-gap:var(--ml-space-room);
  margin-inline:var(--ml-space-nav) var(--ml-space-tight);
  padding-block-end:var(--ml-space-hair);
}
/* Each news category owns a tone and keeps it in both layouts. The colour is
   carried by a rail and the marker, never by a filled block behind the text:
   eleven saturated panels stacked in one band would fight each other and the
   labels both. Colour is a second cue here — the heading is always the first. */
.menu-lab-fold{
  break-inside:avoid;margin-block-end:var(--ml-space-hair);
  padding-inline-start:var(--ml-space-hair);
  border-inline-start:var(--stroke-accent) solid color-mix(in srgb,var(--ml-tone) var(--ml-edge),transparent);
  border-block-end:var(--hairline) solid color-mix(in srgb,var(--ml-ink) 12%,transparent);
  transition:border-color var(--dur-fast) ease,background var(--dur-fast) ease;
}
.menu-lab-fold[open]{background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-quiet),transparent)}
.menu-lab-fold:hover{border-inline-start-color:var(--ml-tone)}
.menu-lab-fold-head{
  display:flex;align-items:baseline;gap:var(--ml-space-hair);
  padding-block:var(--ml-space-hair);cursor:pointer;list-style:none;
  color:var(--ml-ink);font-size:var(--ml-fs-body);font-weight:var(--fw-semibold);
}
/* The default triangle is inconsistent across browsers and sits on the wrong
   side for a Thai-first layout, so it is replaced with one drawn glyph that
   rotates on open. */
.menu-lab-fold-head::-webkit-details-marker{display:none}
.menu-lab-fold-head::before{
  content:"";flex:0 0 auto;inline-size:7px;block-size:7px;
  border-inline-end:var(--stroke-strong) solid var(--ml-tone);
  border-block-end:var(--stroke-strong) solid var(--ml-tone);
  rotate:45deg;transition:rotate var(--dur-fast) ease;
}
.menu-lab-fold[open] .menu-lab-fold-head::before{rotate:225deg}
.menu-lab-fold-head:hover{color:var(--ml-accent)}
.menu-lab-fold-head small{
  margin-inline-start:auto;color:var(--ml-muted);font-family:var(--mono);
  font-size:var(--ml-fs-label);font-weight:var(--fw-normal);
}
.menu-lab-fold .menu-lab-sublinks{
  margin-inline:0;padding-block-end:var(--ml-space-hair);
  border-inline-start:0;padding-inline-start:var(--ml-space-snug);
}
.menu-lab-fold.is-filtered-out{opacity:.28}
.menu-lab-link.is-sub{padding-block:var(--sp-5);padding-inline:var(--ml-space-hair)}
.menu-lab-link.is-sub strong{font-size:var(--ml-fs-body);font-weight:var(--fw-normal);color:var(--ml-muted)}
a.menu-lab-link.is-sub:hover strong{color:var(--ml-ink)}

/* ---- layout 2: tile row + news band ------------------------------------ */

/* A flat grid of icon tiles, after the row of round tiles at the top of Canva's
   home. It WRAPS rather than scrolling sideways: a horizontal scroller inside a
   panel that is already the full width of the page hides destinations behind a
   gesture for no gain, and the "more" arrow at its end is a second menu inside
   the menu. Every tile is on screen at once. */
/* One column: the tile row and the news band stack, they do not sit beside each
   other. Higher specificity than the three-column rule above and than the narrow
   overrides at the foot of this file, both of which only speak for layout 1. */
.menu-lab-nav.is-tiles{grid-template-columns:minmax(0,1fr);gap:var(--ml-space-snug)}
.menu-lab-tiles{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--ml-tile-min),1fr));
  gap:var(--ml-space-hair);margin:0;padding:0;list-style:none;
}
/* The tile's block is the icon holder, not the row behind it — a tinted
   rectangle under every tile would be thirteen competing blocks. */
.menu-lab-branch.is-tile{background:transparent}

/* ---- family brackets --------------------------------------------------- */

/* Flattening the tree into one row threw away the nesting, and shared colour was
   left carrying the relationship alone. It cannot: colour does not survive
   greyscale, a colour-blind reader, or a print. So a family is drawn as a tinted
   tray with a rule under it — proximity, a shape and a line, with colour as the
   fourth cue rather than the only one.

   It brackets families, not neighbours. A rule between every tile would be a
   grid, which groups nothing. */
.menu-lab-branch.is-tile.in-family{
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-quiet),transparent);
  box-shadow:inset 0 calc(-1 * var(--stroke-strong)) color-mix(in srgb,var(--ml-tone) var(--ml-fill-rest),transparent);
}
/* The tray is one continuous shape across the family: only its first tile is
   rounded at the start, only its last at the end. */
.menu-lab-branch.is-tile.in-family{border-radius:0}
.menu-lab-branch.is-tile.opens-family{
  border-start-start-radius:var(--ml-radius-tile);border-end-start-radius:var(--ml-radius-tile);
  margin-inline-start:var(--ml-space-hair);
}
.menu-lab-branch.is-tile.closes-family{
  border-start-end-radius:var(--ml-radius-tile);border-end-end-radius:var(--ml-radius-tile);
  margin-inline-end:var(--ml-space-hair);
}
/* A family that wraps to the next row would otherwise show two open ends and no
   closed one, so the tray reads as broken. Keeping members on one line is worth
   more than filling the row edge-to-edge. */
.menu-lab-branch.is-tile.in-family{break-inside:avoid}
.menu-lab-link.is-tile{
  flex-direction:column;align-items:center;gap:var(--ml-space-hair);
  padding:var(--ml-space-tight) var(--ml-space-hair);
  border-radius:var(--ml-radius-tile);text-align:center;
}
.menu-lab-link.is-tile strong{font-size:var(--ml-fs-body);font-weight:var(--fw-medium)}
a.menu-lab-link.is-tile:hover{background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-quiet),transparent)}
/* The tone tints the holder and the glyph keeps ink contrast. Colour here is
   how you tell tiles apart at a glance, never what tells you what one does —
   the label does that, and it is always there. */
.menu-lab-tile-icon{
  display:grid;place-items:center;flex:0 0 auto;
  inline-size:var(--ml-tile-icon);block-size:var(--ml-tile-icon);
  border-radius:var(--ml-radius-icon);
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-quiet),var(--ml-panel));
  box-shadow:inset 0 0 0 var(--hairline) color-mix(in srgb,var(--ml-tone) var(--ml-fill-rest),transparent);
  transition:background var(--dur-fast) ease;
}
.menu-lab-tile-icon svg{
  inline-size:22px;block-size:22px;
  fill:none;stroke:currentColor;stroke-width:var(--stroke-medium);
  stroke-linecap:round;stroke-linejoin:round;
}
a.menu-lab-link.is-tile:hover .menu-lab-tile-icon{background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-soft),var(--ml-panel))}
.menu-lab-link.is-tile.is-unbuilt .menu-lab-tile-icon{opacity:var(--component-placeholder-opacity)}
.menu-lab-link.is-tile .menu-lab-soon{margin-block-start:calc(var(--sp-4)*-1)}
/* The left rail that marks the current page on a list row would sit off the
   side of a centred tile, so the ring moves onto the holder and the label is
   underlined with it — the shape changes, not only the colour. */
.menu-lab-link.is-tile.is-current{box-shadow:none}
.menu-lab-link.is-tile.is-current .menu-lab-tile-icon{
  box-shadow:inset 0 0 0 var(--stroke-strong) var(--ml-accent);
}
.menu-lab-link.is-tile.is-current strong{
  font-weight:var(--fw-semibold);
  border-block-end:var(--stroke-strong) solid var(--ml-accent);
}

/* ข่าวสาร leaves the column set and becomes a band under the tiles: ~64 topics
   are a browsing surface, and browsing them a third of the width at a time is
   what made the board in layout 1 the tall part of the panel. */
.menu-lab-news{
  padding-block-start:var(--ml-space-snug);
  border-block-start:var(--hairline) solid var(--ml-line);
}
.menu-lab-branch.is-news{
  padding-block-end:var(--ml-space-tight);
  border-radius:var(--ml-radius-panel);
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-quiet),var(--ml-panel-2));
}
.menu-lab-news-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--ml-space-tight)}
/* ปฏิทินเศรษฐกิจ is a tool, not a topic, so it sits beside the heading instead
   of pretending to be a twelfth group. */
.menu-lab-news-pins{
  margin-inline:0 var(--ml-space-tight);padding-inline-start:0;
  border-inline-start:0;grid-auto-flow:column;justify-content:start;
}
.menu-lab-news .menu-lab-folds{
  columns:var(--ml-news-columns-wide);
  margin-inline:var(--ml-space-tight);
}

/* ---- layout 5: the bento ------------------------------------------------ */

.menu-lab-nav.is-bento{grid-template-columns:minmax(0,1fr);gap:var(--ml-space-snug)}
/* Six columns, four rows, explicit areas per block — the sketch's proportions
   are the layout, so they are declared rather than left to auto-placement. */
/* The eight areas tile all 24 cells — no holes — and the rows share the band's
   height rather than each sitting at its content height, so the blocks grow to
   fill the space instead of leaving gutters of panel showing through. */
.menu-lab-bento{
  display:grid;grid-template-columns:repeat(6,minmax(0,1fr));
  grid-template-rows:repeat(4,minmax(var(--ml-bento-row),1fr));
  gap:var(--ml-space-hair);margin:0;padding:0;list-style:none;
}
/* Area says rank, so the fill is stronger than anywhere else in the menu — a
   block this size at the 14% tint the list rows use reads as a panel, not as
   something you press. It is still a TINT and not the raw hue: a tone never
   fills a shape at full strength here, because a saturated block would make
   colour the loudest thing on a control whose label is the actual message. */
.menu-lab-block{
  display:grid;border-radius:var(--ml-radius-panel);
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-rest),var(--ml-panel));
}
.menu-lab-block:has(.menu-lab-sublinks){grid-template-rows:auto 1fr}
/* The whole block is the target. A button that is only pressable across its top
   line is a label with a coloured box behind it, which is what this was. */
.menu-lab-block .menu-lab-link{
  padding:var(--ml-space-tight);block-size:100%;align-items:flex-start;
}
.menu-lab-block a.menu-lab-link:hover{
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-strong),var(--ml-panel));
}
/* Type scales with the block, so size is legible as rank even in greyscale and
   even if the reader never compares two blocks side by side. */
.menu-lab-block.is-xl .menu-lab-link strong{font-size:var(--fs-h2)}
.menu-lab-block.is-tall .menu-lab-link strong,
.menu-lab-block.is-m .menu-lab-link strong{font-size:var(--ml-fs-tile)}
.menu-lab-block.is-s .menu-lab-link strong{font-size:var(--ml-fs-lead)}
.menu-lab-block .menu-lab-sublinks{
  margin-inline:var(--ml-space-tight);padding-inline-start:0;border-inline-start:0;
  gap:var(--ml-space-hair);
}
.menu-lab-block .menu-lab-link.is-sub{padding-block:var(--sp-4)}

/* ---- layout 7: the shelf planogram -------------------------------------- */

.menu-lab-nav.is-planogram{grid-template-columns:minmax(0,1fr);gap:var(--ml-space-snug)}
/* A shelf: a label on the rail, then facings across the full fixture width. The
   rule under each shelf is the shelf itself, so the run reads as one surface
   rather than as a row of separated boxes. */
.menu-lab-shelf + .menu-lab-shelf{margin-block-start:var(--ml-space-tight)}
.menu-lab-shelf-label{
  margin:0 0 var(--sp-4);color:var(--ml-muted);
  font-family:var(--mono);font-size:var(--ml-fs-label);letter-spacing:var(--ls-wide);
}
.menu-lab-facings{
  display:flex;gap:var(--ml-space-hair);margin:0;padding:0 0 var(--ml-space-hair);
  list-style:none;border-block-end:var(--stroke-strong) solid var(--ml-line);
}
/* flex-grow carries the frontage, and flex-basis:0 is what makes the growth
   proportional rather than "content width plus a share of the remainder" —
   without it a long Thai label would buy itself extra frontage it did not earn. */
.menu-lab-facing{
  flex-basis:0;min-inline-size:var(--ml-facing-min);
  border-radius:var(--ml-radius-tile);
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-rest),var(--ml-panel));
}
.menu-lab-facing .menu-lab-link{
  block-size:100%;align-items:flex-start;padding:var(--ml-space-hair) var(--ml-space-tight);
}
.menu-lab-facing a.menu-lab-link:hover{
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-strong),var(--ml-panel));
}
/* A narrow facing is still a control. Frontage may shrink to show low rank; the
   tap target may not. */
.menu-lab-facing .menu-lab-link strong{font-size:var(--ml-fs-body)}
.menu-lab-facings>li:first-child .menu-lab-link strong{font-size:var(--ml-fs-tile)}

/* ---- layout 5: the hub -------------------------------------------------- */

.menu-lab-nav.is-hub{grid-template-columns:minmax(0,1fr);gap:var(--ml-space-snug)}
/* A 16 x 13 field, so the sketch's offsets survive as fractions rather than
   being rounded into a tidy grid. The blocks are placed on it; they are not
   packed into it, and the space between them is the drawing, not a gap. */
.menu-lab-orbit{
  display:grid;grid-template-columns:repeat(16,minmax(0,1fr));
  grid-template-rows:repeat(13,minmax(0,1fr));
  gap:0;margin:0;padding:0;list-style:none;
  min-block-size:var(--ml-orbit-min);
}
.menu-lab-sat{
  display:grid;align-content:start;margin:var(--sp-4);
  border-radius:var(--ml-radius-tile);
  border:var(--stroke-strong) solid color-mix(in srgb,var(--ml-tone) var(--ml-edge),var(--ml-panel));
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-rest),var(--ml-panel));
}
.menu-lab-sat>.menu-lab-link{
  block-size:100%;align-items:flex-start;padding:var(--ml-space-hair) var(--ml-space-tight);
}
.menu-lab-sat a.menu-lab-link:hover{background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-hover),var(--ml-panel))}
/* Children live inside their block, as drawn — ระบบเทรด / หนังสือ / EA sit in
   the Marketplace box rather than beside it. */
.menu-lab-sat .menu-lab-sublinks{
  margin-inline:var(--ml-space-tight) var(--sp-4);
  padding-inline-start:0;border-inline-start:0;gap:0;
}
.menu-lab-sat .menu-lab-link.is-sub{padding-block:var(--sp-4)}

/* The one circle. aspect-ratio keeps it round whatever its grid area does, and
   place-self:center stops it stretching into an oval when the area is not
   square. It is the only round thing in the menu and must stay that way — a
   second circle spends the effect that makes this one read as the centre. */
.menu-lab-sat.is-hub{
  aspect-ratio:1;place-self:center;block-size:100%;margin:0;
  border-radius:50%;align-content:center;
  border-width:var(--stroke-strong);
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-strong),var(--ml-panel));
}
.menu-lab-sat.is-hub>.menu-lab-link{
  align-items:center;justify-content:center;text-align:center;
  border-radius:50%;padding:var(--ml-space-room);
}
.menu-lab-sat.is-hub .menu-lab-link strong{font-size:var(--fs-h2)}
.menu-lab-sat.is-hub a.menu-lab-link:hover{
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-hover),var(--ml-panel));
}

/* ---- layout 6: the keyed rail ------------------------------------------- */

/* Seven-tenths plates, three-tenths key panel. The rail is visually subordinate
   to the plates — that subordination is what makes a legend read as a legend
   rather than as a second menu competing with the first. */
.menu-lab-nav.is-keyrail{
  grid-template-columns:minmax(0,1fr) minmax(0,var(--ml-key-rail));
  gap:var(--ml-space-snug);align-items:stretch;
}
.menu-lab-plates{
  display:grid;grid-template-columns:repeat(6,minmax(0,1fr));
  grid-template-rows:repeat(5,minmax(var(--ml-bento-row),1fr));
  gap:var(--ml-space-hair);margin:0;padding:0;list-style:none;
}
.menu-lab-plate{
  display:grid;align-content:start;border-radius:var(--ml-radius-tile);
  border:var(--stroke-strong) solid color-mix(in srgb,var(--ml-tone) var(--ml-edge),var(--ml-panel));
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-rest),var(--ml-panel));
}
.menu-lab-plate>.menu-lab-link{
  block-size:100%;align-items:flex-start;padding:var(--ml-space-hair) var(--ml-space-tight);
}
.menu-lab-plate a.menu-lab-link:hover{background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-hover),var(--ml-panel))}
.menu-lab-plate.is-xl .menu-lab-link strong{font-size:var(--fs-h3)}
.menu-lab-plate.is-m .menu-lab-link strong{font-size:var(--ml-fs-tile)}
/* Children dock inside their own plate's lower edge, as in a loadout slot. */
.menu-lab-plate .menu-lab-sublinks{
  margin-inline:var(--ml-space-tight) var(--sp-4);
  padding-inline-start:0;border-inline-start:0;gap:0;
}
.menu-lab-plate .menu-lab-link.is-sub{padding-block:var(--sp-4)}

/* The key panel. Header bars, not headings — a legend labels its sections with
   a filled strip so the rows below read as one run. */
.menu-lab-key{
  display:flex;flex-direction:column;gap:var(--sp-4);
  padding-inline-start:var(--ml-space-tight);
  border-inline-start:var(--hairline) solid var(--ml-line);
}
.menu-lab-keybar{
  margin:var(--sp-4) 0 0;padding:var(--sp-4) var(--ml-space-hair);
  background:color-mix(in srgb,var(--ml-tone-info) 30%,var(--ml-panel));
  color:var(--ml-ink);font-family:var(--mono);font-size:var(--ml-fs-label);
  letter-spacing:var(--ls-wide);text-transform:uppercase;
}
/* One rhythm, unbroken. Every row the same height and the same alignment is the
   whole reason a legend is scannable; a row that breaks it stops being a key. */
.menu-lab-keyrows{display:grid;gap:0;margin:0;padding:0;list-style:none}
.menu-lab-keyrow{
  display:grid;min-block-size:var(--ml-key-row);align-content:center;
  border-inline-start:var(--stroke-accent) solid var(--ml-tone);
  padding-inline-start:var(--ml-space-hair);
}
.menu-lab-keyrow:hover{background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-quiet),transparent)}
.menu-lab-keyrow .menu-lab-link{padding:0}
.menu-lab-keyrow .menu-lab-link strong{font-size:var(--ml-fs-body);font-weight:var(--fw-normal)}
.menu-lab-keyrow.is-cat .menu-lab-fold{
  margin-block-end:0;border-block-end:0;border-inline-start:0;padding-inline-start:0;
}
.menu-lab-keyrow.is-cat .menu-lab-fold-head{padding:0;font-size:var(--ml-fs-body)}

/* ---- layout 11: the vendor marquee -------------------------------------- */

.menu-lab-nav.is-marquee{
  grid-template-columns:minmax(0,1fr) minmax(0,var(--ml-marquee-rail));
  gap:var(--ml-space-snug);align-items:stretch;
}
.menu-lab-nav.is-marquee .menu-lab-group[data-menu-column="stock"]{
  display:grid;grid-template-rows:minmax(0,1fr) minmax(0,2fr);
  gap:var(--ml-space-hair);min-block-size:var(--ml-marquee-min);
}
.menu-lab-marquee{display:grid;margin:0;padding:0;list-style:none}
/* Even wares. Rank appears exactly twice in this layout — the marquee, and
   left-to-right order. A shop does not shrink its eighth item, it just puts it
   further along the shelf, and copying that is the whole point of the family. */
.menu-lab-stock{
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  grid-auto-rows:minmax(0,1fr);
  gap:var(--ml-space-hair);margin:0;padding:0;list-style:none;
}
.menu-lab-ware{
  display:grid;align-content:start;border-radius:var(--ml-radius-tile);
  border:var(--stroke-strong) solid color-mix(in srgb,var(--ml-tone) var(--ml-edge),var(--ml-panel));
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-rest),var(--ml-panel));
}
.menu-lab-ware.is-headline{
  align-content:center;
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-strong),var(--ml-panel));
}
.menu-lab-ware.is-headline .menu-lab-link strong{font-size:var(--fs-h2)}
.menu-lab-ware>.menu-lab-link{
  block-size:100%;align-items:flex-start;padding:var(--ml-space-hair) var(--ml-space-tight);
}
.menu-lab-ware a.menu-lab-link:hover{background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-hover),var(--ml-panel))}
.menu-lab-ware .menu-lab-sublinks{
  margin-inline:var(--ml-space-tight) var(--sp-4);
  padding-inline-start:0;border-inline-start:0;gap:0;
}
.menu-lab-ware .menu-lab-link.is-sub{padding-block:var(--sp-4)}
.menu-lab-catalogue{
  padding-inline-start:var(--ml-space-tight);
  border-inline-start:var(--hairline) solid var(--ml-line);
}
.menu-lab-catalogue .menu-lab-branch{background:none}
.menu-lab-catalogue .menu-lab-folds{columns:1;margin-inline:0}

/* ---- layout 13: the lodestone -------------------------------------------- */

.menu-lab-nav.is-lodestone{
  grid-template-columns:minmax(0,1fr) minmax(0,var(--ml-lode-rail));
  gap:var(--ml-space-room);align-items:stretch;
}
.menu-lab-nav.is-lodestone .menu-lab-group[data-menu-column="lode"]{
  display:grid;grid-template-rows:auto minmax(0,1fr);
  gap:var(--ml-space-room);min-block-size:var(--ml-marquee-min);
}
/* A row can hold sections of different widths, divided by a rule. flex-grow is
   the item count, so a three-item section is half again the width of a two —
   the section is sized by what it holds, not by a track. */
.menu-lab-lode-row{display:flex;gap:0}
.menu-lab-lode-section{
  flex-basis:0;min-inline-size:0;padding-inline:var(--ml-space-snug);
}
.menu-lab-lode-row>.menu-lab-lode-section + .menu-lab-lode-section{
  border-inline-start:var(--hairline) solid var(--ml-line);
}
.menu-lab-lode-row>.menu-lab-lode-section:first-child{padding-inline-start:0}
.menu-lab-lode-row.is-wide{
  padding-block-start:var(--ml-space-snug);
  border-block-start:var(--hairline) solid var(--ml-line);
}
/* The header is quiet on purpose. It names the group and then gets out of the
   way — on the reference it is grey, small, and lighter than every label under
   it, which is what stops a page of sections becoming a page of headings. */
.menu-lab-lode-head{
  display:flex;align-items:center;gap:var(--sp-4);
  margin:0 0 var(--ml-space-tight);color:var(--ml-muted);font-size:var(--ml-fs-label);
}
.menu-lab-lode-glyph svg{
  inline-size:14px;block-size:14px;display:block;
  fill:none;stroke:var(--ml-muted);stroke-width:1.8;stroke-linecap:round;
}
.menu-lab-lode-items{
  display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);
  gap:var(--ml-space-hair);margin:0;padding:0;list-style:none;
}
/* Glyph over a centred caption — the reference's anatomy — but FILLED. The
   reference is unfilled white and I built it that way first; the owner's call is
   that these read as buttons, which is the same call made on the bento. So the
   cell keeps the Lodestone's centred glyph-over-caption and takes the fill and
   edge every surviving layout uses.

   The whole cell is the target, not just the caption line: a coloured box you
   can only press across its text is a label with a background. */
.menu-lab-lode-item{
  display:grid;border-radius:var(--ml-radius-tile);
  border:var(--stroke-strong) solid color-mix(in srgb,var(--ml-tone) var(--ml-edge),var(--ml-panel));
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-rest),var(--ml-panel));
}
.menu-lab-lode-item .menu-lab-link.is-lode{
  flex-direction:column;align-items:center;justify-content:center;
  gap:var(--ml-space-hair);block-size:100%;
  padding:var(--ml-space-tight) var(--sp-4);text-align:center;
  border-radius:inherit;
}
.menu-lab-lode-item .menu-lab-link.is-lode strong{font-size:var(--ml-fs-body)}
.menu-lab-lode-item .menu-lab-tile-icon{
  inline-size:var(--ml-tile-icon);block-size:var(--ml-tile-icon);
  display:grid;place-items:center;background:none;
}
/* currentColor now the cell is filled: a tone-coloured stroke on a tone-tinted
   ground is the one place this anatomy loses its contrast, and the glyph is
   already carrying no meaning the label does not. */
.menu-lab-lode-item .menu-lab-tile-icon svg{
  inline-size:28px;block-size:28px;
  fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;
}
.menu-lab-lode-item a.menu-lab-link.is-lode:hover{
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-hover),var(--ml-panel));
}

/* The rail: a featured block, then marked rows, then the standing sections —
   the Forums / New Posts / Dev Tracker shape. */
.menu-lab-lode-rail{
  display:flex;flex-direction:column;gap:var(--ml-space-tight);
  padding-inline-start:var(--ml-space-snug);
  border-inline-start:var(--hairline) solid var(--ml-line);
}
.menu-lab-feature{
  border:var(--stroke-strong) solid color-mix(in srgb,var(--ml-tone) var(--ml-edge),var(--ml-panel));
  border-radius:var(--ml-radius-tile);
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-soft),var(--ml-panel));
}
.menu-lab-feature .menu-lab-link{padding:var(--ml-space-tight)}
.menu-lab-feature .menu-lab-link strong{font-size:var(--ml-fs-lead)}
/* A marked row: the small round marker the Lodestone puts before New Posts and
   Dev Tracker. Drawn, not a bullet, so it can carry the tone. */
.menu-lab-marked{display:grid;gap:0;margin:0;padding:0;list-style:none}
.menu-lab-marked>li{display:grid}
.menu-lab-marked .menu-lab-link{
  padding:var(--sp-4) 0 var(--sp-4) var(--ml-space-nav);position:relative;
}
.menu-lab-marked .menu-lab-link::before{
  content:"";position:absolute;inset-inline-start:0;inset-block-start:50%;
  translate:0 -50%;inline-size:14px;block-size:14px;border-radius:50%;
  background:color-mix(in srgb,var(--ml-tone) var(--ml-fill-hover),var(--ml-panel));
}
.menu-lab-lode-rail .menu-lab-folds{
  columns:1;margin-inline:0;padding-block-start:var(--ml-space-tight);
  border-block-start:var(--hairline) solid var(--ml-line);
}

/* ---- the layout picker ------------------------------------------------- */

/* Exploration chrome for the selection round, sized down so it never competes
   with a destination. It comes out with the losing layout. */
.menu-lab-variant{
  display:inline-flex;align-items:center;gap:var(--ml-space-hair);
  margin-inline-start:auto;color:var(--ml-muted);
}
.menu-lab-variant select{
  min-block-size:var(--ct-floor);
  padding-inline:var(--ml-space-hair);
  border:var(--hairline) solid var(--ml-line);border-radius:var(--ml-radius-control);
  background:var(--ml-panel);color:var(--ml-ink);
  font-family:var(--font);font-size:var(--ml-fs-label);
}

/* Designed but not built. It must not look clickable, must not take focus, and
   must say why — a greyed label with no explanation reads as broken. */
.menu-lab-link.is-unbuilt{cursor:default}
.menu-lab-link.is-unbuilt strong{color:var(--ml-muted)}
.menu-lab-soon{
  flex:0 0 auto;color:var(--ml-muted);font-family:var(--mono);
  font-size:var(--ml-fs-label);font-style:normal;letter-spacing:var(--ls-wide);
  opacity:var(--component-placeholder-opacity);
}

/* Searching dims rather than removes. A row that vanishes takes its position
   with it, so the shape of the menu changes under the hands of someone who is
   still typing. */
.menu-lab-branch.is-filtered-out>.menu-lab-link,
.menu-lab-branch.is-filtered-out>.menu-lab-news-head,
.menu-lab-sublinks li.is-filtered-out,
.menu-lab-utility li.is-filtered-out{opacity:.28}

.menu-lab-empty{margin:0;color:var(--ml-muted);font-size:var(--ml-fs-body)}

/* ---- the utility rule -------------------------------------------------- */

/* Account and legal pages are not on the wireframe but they exist, and a menu
   that covers the whole site cannot be the reason someone loses the way to the
   terms they agreed to. Quiet, single line, never gated. */
.menu-lab-foot{
  display:flex;flex-wrap:wrap;align-items:center;gap:var(--ml-space-tight);
  padding-block-start:var(--ml-space-tight);
  border-block-start:var(--hairline) solid var(--ml-line);
  color:var(--ml-muted);font-size:var(--ml-fs-label);
}
.menu-lab-utility{
  display:flex;flex-wrap:wrap;gap:var(--ml-space-tight);
  margin:0;padding:0;list-style:none;
}
.menu-lab-utility a{color:var(--ml-muted);text-decoration:none}
.menu-lab-utility a:hover{color:var(--ml-ink)}
/* The picker takes the free space, so the shortcut hint just follows it. */
.menu-lab-shortcut{margin-inline-start:0}
.menu-lab-shortcut kbd{
  padding:0 var(--sp-4);border:var(--hairline) solid var(--ml-line);
  border-radius:var(--radius-rule);color:var(--ml-ink);font-family:var(--mono);
}

/* ---- narrow widths ----------------------------------------------------- */

/* Desktop is the design case. These blocks only keep the menu readable on a
   smaller screen; they are not a phone design. */
@media(max-width:1100px){
  .menu-lab-nav{grid-template-columns:minmax(0,1fr) minmax(0,1.6fr)}
  [data-menu-column="news"]{grid-column:1/-1}
  .menu-lab-news .menu-lab-folds{columns:var(--ml-news-columns)}
}
@media(max-width:760px){
  .menu-lab-news .menu-lab-folds{columns:1}
  .menu-lab-news-pins{margin-inline-end:0}
  .site-header-row .brand .wm,.site-header-row .header-login-full,.site-header-row .header-user-name{display:none}
  .site-header-row .header-login-short{display:inline}
  .menu-lab-trigger-text{display:none}
  .menu-lab-trigger{padding-inline:0;inline-size:var(--tap);justify-content:center}
  .menu-lab-nav{grid-template-columns:1fr;gap:var(--ml-space-nav)}
  [data-menu-column="news"] .menu-lab-sublinks{grid-template-columns:1fr}
  .menu-lab-search{max-inline-size:none}
  /* Tighter than the general cap: on a phone the panel should stop short of the
     window edge so it is obvious the page is still behind it. */
  .menu-lab-inner{max-block-size:78dvh}
}
/* ---- coarse pointers ----------------------------------------------------- */

/* A protected contract, and the polish audit found it missing across every
   layout added after the tile row. These panels are desktop-first, but "desktop
   first" is not "mouse only" — a touchscreen laptop reports a coarse pointer at
   1400px wide, and a 30px legend row is not pressable with a thumb.

   Applied to the cell families rather than to .menu-lab-link, because the link
   fills its cell: raising the cell raises the target, while raising the link
   alone would leave it floating inside a box that is still too small. */
@media(pointer:coarse){
  .menu-lab-keyrow,.menu-lab-marked>li,.menu-lab-entry-row,.menu-lab-stash-cell,
  .menu-lab-lode-item,.menu-lab-post,.menu-lab-card-unit,.menu-lab-ware,
  .menu-lab-op,.menu-lab-plate,.menu-lab-block,.menu-lab-facing,.menu-lab-sat,
  .menu-lab-slot{
    min-block-size:var(--touch-target);
  }
  .menu-lab-fold-head{min-block-size:var(--touch-target);align-items:center}
}

@media(prefers-reduced-motion:reduce){
  .menu-lab-overlay,.menu-lab-branch,.menu-lab-link,.menu-lab-trigger{transition:none!important}
}
