:root {
  color-scheme: light;
  --bg: #f5f5f7;
  --surface-solid: #ffffff;
  --surface-2: #f5f5f7;
  --surface-3: #e8e8ed;
  --text: #1d1d1f;
  --text-2: #6e6e73;
  --text-3: #86868b;
  --line: #d2d2d7;
  --line-strong: #c6c6cb;
  --blue: #0066cc;
  --blue-hover: #0077ed;
  --blue-solid: #0071e3;
  --blue-solid-hover: #0077ed;
  --blue-soft: #e8f2ff;
  --green: #147735;
  --green-soft: #eaf7ee;
  --red: #c0302e;
  --red-soft: #fff0ef;
  /* Admin is maroon, not the red used for losses and for anything that removes something,
     so a person's role never reads as a warning about their account. It was a lighter
     crimson, which against a white tag came out pink. */
  --crimson: #800020;
  /* A fourth role needs a fourth colour anybody can tell apart at tag size. Moderator sits
     between the maroon that runs the exchange and the blue that runs the market, and violet
     is the one hue on this palette that is neither and is not already saying something
     else: orange and yellow mean a warning here, and green and red mean money moving. */
  /* How many companies a mover card holds, and how tall one of them is. The card reserves
     the two multiplied together, so it does not resize as the rows arrive. */

  /* The second half of every tag colour. A tag stands on a 14 percent tint of its own
     colour, so the ground under the word moves toward the word as the word gets stronger,
     and about half a point of contrast disappears into it. The palette above was picked for
     text on a plain card, where that does not happen. These are the same colours held far
     enough from their own tint to stay readable at tag size on the lightest and the darkest
     card the site has. Where a colour was already clear enough, it is the same colour. */
  --orange: #a25100;
  --orange-soft: #fff4e8;
  --yellow: #856200;
  --shadow: 0 4px 14px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
  --radius-xs: 8px;
  --radius-sm: 12px;
  --radius: 18px;
  --radius-lg: 18px;
  /* A pill. Apple writes 980px rather than 999px, and it is the shape of every button they
     have: a capsule at any height, never a rounded rectangle. */
  --radius-pill: 980px;
  /* How far anything floating keeps off the bottom of a small screen. This used to be the
     height of the bar along the bottom, because everything down there had to sit above the
     bar. There is no bar now, so the gutter is the same one the card at the top keeps. */
  --float-inset: max(var(--island-side), env(safe-area-inset-bottom));
  /* How much room the island at the foot of the window takes, published by the page as it
     is drawn, because its height depends on how long its words are and on the reader's
     text size. Nought when there is no island. Everything else that lives down there
     measures from the line below rather than from a number worked out by hand. */
  --dock-height: 0px;
  /* What the cards at the top of the window actually take, measured and published rather
     than assumed, because the tape and a notice each change it. */
  --top-height: 116px;
  --float-bottom: calc(var(--float-inset) + var(--dock-height));
  /* How tall the panel somebody has open is, published by the page as it opens, so the
     things that share the foot of a phone screen with it can sit above it. Nought when
     nothing is open. */
  --panel-height: 0px;
  /* A square mark keeps its corner in proportion, so a 32px badge and a 54px one
     read as the same shape rather than two different ones. */
  --radius-mark: 28%;
  --radius-xl: 28px;
  --content: 1240px;
  /* The bar across the top. Apple's is 48. */
  --header: 48px;

  /* The header floats. It is a card with a gap above it and a gutter each side, not a
     band welded to the top of the window, and the navigation, the tape and any notice
     travel inside it together.

     One set of numbers, written once, because everything pinned to a corner of the
     window has to agree with it: the panels that drop from its buttons, the columns
     that stay put while a page scrolls, and the bar along the bottom of a phone, which
     is the same card at the other end of the screen. --island-height is measured from
     the header itself as the page runs, because it changes when a notice appears. */
  --island-top: 10px;
  --island-side: 10px;
  --island-x: max(var(--island-side), calc((100vw - var(--content)) / 2));
  --island-height: 96px;
  /* How tall the card offering a tour is right now, measured by the page as it is drawn
     because the height depends on how long the words are and on the reader's text size.
     Nothing is showing until it is. */
  --tour-height: 0px;
  --island-bottom: calc(var(--island-top) + var(--island-height));
  --row: 48px;
/* Apple's own curve. Everything that moves on their sites uses it, which is why a press,
   a panel and a page change all feel like the same hand did them. */
  --ease: cubic-bezier(.28,.11,.32,1);
  --transition: 200ms var(--ease);
  --transition-slow: 400ms var(--ease);

  /* Spacing runs on a 4 point grid with 8 as the working step, the convention Apple's
     own layouts follow. Every padding, gap and margin picks a step from this list
     instead of a number that looked about right, which is what left some panels
     sitting a pixel or two off from the ones beside them. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --card-pad: var(--space-6);
  --gap: var(--space-5);

  /* The material, in three weights.

     The floating layer is the thinnest and the most blurred, because things that sit
     above the page have to show that the page is still there underneath. Panels - cards,
     tables, the boxes a page is built out of - are the heaviest, because figures read
     through a blur are harder to scan and scanning figures is the point here. Controls
     sit between the two.

     --ambience was a wash of colour behind the whole page - three radial gradients in blue
     and green - so that a card blurred into something with depth rather than into flat
     grey. Apple's pages have no such thing: the ground is one flat colour and the depth
     comes from the hairline and the shadow on the card itself. It is none now, and kept as
     a token rather than deleted because the layer it paints is what every panel blurs. */
  --glass-panel: color-mix(in srgb, var(--surface-solid) 80%, transparent);
  --glass-panel-blur: saturate(165%) blur(18px);
  --ambience: none;
  --glass: color-mix(in srgb, var(--surface-solid) 72%, transparent);
  --glass-strong: color-mix(in srgb, var(--surface-solid) 86%, transparent);
  --glass-blur: saturate(180%) blur(22px);
  /* The header spans the whole width and stays there, so it is the one surface where the
     page really has to show through. It is thinner than the rest of the material and
     blurred harder, which is the trade Apple makes on a navigation bar: you can see that
     something is moving underneath without being able to read it. */
  /* The bar has to stop what is under it being read, not merely soften it. At 56% a blue
     button and its label came through the tape legibly, so the exchange's own tickers and
     a control from the page underneath were two lines of text in the same pixels. Glass
     that you can read a second page through is not glass, it is a tint. */
  --glass-bar: color-mix(in srgb, var(--bg) 86%, transparent);
  /* The seal is blue with a white tick, and stays blue with a white tick on either page.
     It is the one mark whose colours people already know from everywhere else, so it does
     not turn over with the theme the way the boxes below it do. */
  --badge-blue: #0071e3;
  --badge-seal-knock: #ffffff;
  /* The page colour. Every badge in a coloured box knocks its shape out in this, so the
     shape reads as a hole punched through the box rather than as white ink sitting on a
     dark ground. The seal does not use it: it has its own, above. */
  --badge-knock: #ffffff;
  /* One colour each, and the same one on either page, which is the point: a rank should not
     be a different red depending on the theme. Each is measured twice, against the box it
     sits in and against the page the box sits on.

     The old pair was a deep red for the light page and a pink-red for the dark one. Both
     read perfectly well as a box, so this is not a correction of a fault; it is one colour
     where there were two. The deep one would have failed had it been kept for both, at
     2.48 against a dark page, which is why the single value is the brighter of the two. */
  /* The two bug hunter tiers keep their real colours, and to do that they need a ground
     that does not turn over.
     
     They were on the same black-or-white box as the ranks, which meant every tone had to
     survive a white box, and no bright gold does: the gold this is meant to look like
     reads 1.30 against white. Held to that rule the gold came out mustard. The box is
     what was wrong, not the gold, so these two sit on a fixed dark ground the way the
     marks they are modelled on do, and the art is then free to be the colour it should. */
  --badge-hunter-box: #2a2d33;
  /* Nothing on a light page: the box is already 12.7 against it. The dark page cannot say
     that, so it draws a rim instead. */
  --badge-hunter-rim: #2a2d33;
  --badge-green: #a8e6c4;
  --badge-green-2: #34a853;
  --badge-hunter-gold: #ffd166;
  /* The bag, and the pale one of the pair. The first tier has its light tone on the hoop
     and its saturated tone on the bag; the second turns that round, which is what makes
     the two read as a pair rather than as the same picture twice. */
  --badge-hunter-gold-2: #fdf2da;
  /* The foot of the bag. It fades from the tone above to this one, which is what stops the
     bag reading as a flat shape sitting behind the hoop. */
  --badge-hunter-gold-3: #f3d295;
  /* The shine on the hoop, which only the second tier carries. White rather than a lighter
     gold: it is light on the thing, not a third colour of it. */
  --badge-hunter-shine: #ffffff;
  --badge-red: #dc1f3f;
  --badge-gold: #a76a00;
  /* The moderating box is not a hue. It is the reverse of the page, so it is black while
     the page is light and white while it is dark, and the wrench is the page showing
     through it. */
  --badge-steel: #0b0b0d;
  --glass-bar-blur: saturate(200%) blur(36px);
  /* Light catching the top edge and a darker lip along the bottom. Without these a
     translucent panel reads as fog; with them it reads as a pane of something. */
  --glass-rim: inset 0 1px 0 color-mix(in srgb, #fff 62%, transparent), inset 0 -1px 0 color-mix(in srgb, #000 6%, transparent);
  --glass-shadow: 0 12px 40px rgba(0,0,0,.14), 0 1px 2px rgba(0,0,0,.06);
  /* The same material at the size of a control. A panel is a sheet of glass you look
     through; a button is a lozenge of it you press, so it is a little denser, blurred a
     little less, and lit along its top edge rather than shadowed all round. Tinted
     controls keep their colour and take the same treatment, which is what makes a blue
     button and a grey one read as the same object in two shades. */
  --glass-control: color-mix(in srgb, var(--surface-solid) 64%, transparent);
  --glass-control-raised: color-mix(in srgb, var(--surface-solid) 84%, transparent);
  --glass-control-blur: saturate(180%) blur(14px);
  --glass-control-rim: inset 0 1px 0 color-mix(in srgb, #fff 58%, transparent), inset 0 -1px 0 color-mix(in srgb, #000 7%, transparent);
  --glass-tint-strength: 92%;
  /* The wash behind anything that takes over the screen. One value, so a search overlay
     and a confirmation do not dim and blur the page by different amounts. */
  --scrim: rgba(0,0,0,.28);
  --scrim-blur: saturate(140%) blur(14px);

  /* One type scale for the whole site, the way a document has one.

     Every heading, label, figure and caption picks a step from this list. Nothing on the
     site names a size of its own, which is what let panels drift into looking heavier
     than one another - and it is also what makes the text size control work: the whole
     scale is multiplied by one number, so asking for larger text moves everything
     together instead of moving nothing.

     Text that has to fit inside a box of a fixed size - a company's mark, the direction
     glyphs on the tape, the labels along a chart's axis - is sized in plain pixels where
     it is used, and says so, because growing it would push it out of the box it exists
     to fill. */
  --type-scale: 1;
  --text-hero: calc(52px * var(--type-scale));
  --text-title: calc(40px * var(--type-scale));
  --text-section: calc(24px * var(--type-scale));
  --text-card: calc(19px * var(--type-scale));
  --text-sub: calc(15px * var(--type-scale));
  --text-body: calc(17px * var(--type-scale));
  --text-label: calc(15px * var(--type-scale));
  --text-small: calc(14px * var(--type-scale));
  --text-caption: calc(12px * var(--type-scale));
  /* The smallest step never goes below eleven pixels, whatever the scale is set to.
     Smaller than that is not small text, it is text somebody cannot read. */
  --text-micro: max(11px, calc(11px * var(--type-scale)));
  --text-figure: calc(21px * var(--type-scale));
  --text-figure-lg: calc(34px * var(--type-scale));
  --tracking-tight: -.03em;
  --tracking-snug: -.02em;

  /* Form and toolbar controls share two sizes so a select never sits a few pixels
     taller than the input beside it. */
  /* ----- Layers ------------------------------------------------------------------------
     What sits on top of what, declared once, in the order it stacks. There were sixteen
     hand written numbers running from -1 to 9999 and nothing anywhere saying which of them
     should win, so every new floating thing was a guess against fifteen others. Read this
     list from the top of the page down and it is the order you see: the ground, then the
     page, then the chrome, then everything that opens over it, then the label you point
     at, then the link a keyboard reaches first. Nothing sets a raw number. */
  --layer-ground: -1;
  --layer-raised: 1;
  --layer-sticky: 5;
  --layer-header: 10;
  --layer-dock: 20;
  --layer-popover: 30;
  --layer-search: 40;
  --layer-drawer: 50;
  --layer-modal: 60;
  --layer-toast: 70;
  --layer-tour: 80;
  --layer-menu: 90;
  --layer-tip: 100;
  --layer-skip: 110;

  --control-height: 44px;
  --control-height-compact: 36px;
  --control-height-inline: 36px;
  --control-pad: 0 12px;
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #000000;
  --surface-solid: #1d1d1f;
  --surface-2: #2a2a2c;
  --surface-3: #333336;
  --text: #f5f5f7;
  --text-2: #a1a1a6;
  --text-3: #86868b;
  --line: #424245;
  --line-strong: #545457;
  --blue: #2997ff;
  --blue-hover: #57aaff;
  --blue-solid: #0071e3;
  --blue-solid-hover: #0077ed;
  --blue-soft: #102842;
  --green: #32d74b;
  --green-soft: #12351b;
  --red: #ff6960;
  --red-soft: #421b1a;
  /* As near maroon as a dark page allows. A colour has to be light to be legible against
     black, so this cannot be the maroon the light theme uses - it is the darkest, least
     pink red that still stands off the page at the contrast everything here is held to. */
  --crimson: #e0707f;

  /* Lifted away from their own tint rather than pushed into it: on a dark page the tint
     darkens the ground, so a tag colour has to be lighter here, not deeper. Green and yellow
     are already far enough clear of it to be left alone. */
  --orange: #ff9f0a;
  --orange-soft: #442b0d;
  --yellow: #ffd60a;
  --shadow: 0 4px 16px rgba(0,0,0,.5), 0 1px 3px rgba(0,0,0,.4);
  --glass-panel: color-mix(in srgb, var(--surface-solid) 74%, transparent);
  --ambience: none;
  --glass: color-mix(in srgb, var(--surface-solid) 66%, transparent);
  --glass-strong: color-mix(in srgb, var(--surface-solid) 82%, transparent);
  --glass-bar: color-mix(in srgb, var(--bg) 82%, transparent);
  /* Blue disc, white tick, exactly as on the light page. */
  --badge-blue: #0071e3;
  --badge-seal-knock: #ffffff;
  --badge-knock: #090a0c;
  /* The hunter box and its art are the same on either page, and stay that way.
     Inverting the tile to light on a dark page was tried and taken back out: the art is
     built for a dark ground - that is why the gold is bright - so a light tile forces the
     gold to go deep or disappear, and it did both in turn. The mark keeps the colours it
     has always had. Only the rim appears here: the box is 1.44 against a dark ground,
     which is not enough to find it by, so the boundary does that work instead. */
  --badge-hunter-rim: #6b6d70;
  --badge-red: #dc1f3f;
  --badge-gold: #a76a00;
  --badge-steel: #f2f3f5;
  --glass-rim: inset 0 1px 0 color-mix(in srgb, #fff 14%, transparent), inset 0 -1px 0 color-mix(in srgb, #000 26%, transparent);
  --glass-shadow: 0 14px 44px rgba(0,0,0,.5), 0 1px 2px rgba(0,0,0,.4);
  --glass-control: color-mix(in srgb, var(--surface-solid) 58%, transparent);
  --glass-control-raised: color-mix(in srgb, var(--surface-solid) 80%, transparent);
  --glass-control-rim: inset 0 1px 0 color-mix(in srgb, #fff 13%, transparent), inset 0 -1px 0 color-mix(in srgb, #000 28%, transparent);
  --glass-tint-strength: 92%;
  --scrim: rgba(0,0,0,.46);
}

/* Text and spacing together, which is what the control in Settings is called and what it
   has to do. Spacing was the only half that ever worked: the type scale was a list of
   fixed pixel sizes, so asking for larger text moved the padding and left every word on
   the site exactly the size it already was. */
:root[data-density="compact"] { --row: 40px; --card-pad: var(--space-4); --gap: var(--space-3); --type-scale: .92; }
:root[data-density="large"] { --row: 56px; --card-pad: var(--space-8); --gap: var(--space-6); --type-scale: 1.14; }

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin:0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
  font-size: var(--text-body);
  line-height: 1.45;
  letter-spacing: -.01em;
  -webkit-font-smoothing: antialiased;
}
/* The ground behind everything. Fixed, so it does not travel with the scroll. It carries
   --ambience, which is now flat: Apple's pages put one colour behind the content and let
   the card's own edge do the separating. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: var(--layer-ground);
  background: var(--ambience);
  pointer-events: none;
}
/* Browser defaults put paragraph and list spacing on the font size, which lands on
   values like 15px that sit off the grid. Everything is put back on the scale here. */
p { margin: 0 0 var(--space-3); }
p:last-child { margin-bottom: 0; }
ul, ol { margin: 0 0 var(--space-3); padding-left: var(--space-5); }
ul:last-child, ol:last-child { margin-bottom: 0; }
h1, h2, h3, h4 { margin: 0 0 var(--space-2); }

button, input, select, textarea { font: inherit; color: inherit; }
button, a { -webkit-tap-highlight-color: transparent; }
a { color: inherit; text-decoration: none; }
button { cursor: pointer; }
/* One icon, drawn one way.
 *
 * Every symbol on the site is a line drawing on a 24 unit grid, and they were each given
 * their own weight and their own corners as they were written: nine stroke widths between
 * 1.8 and 2.2, some with round ends and some with square, some rounding their joins and
 * some not. Two of them sit beside each other above the Markets table, so the difference
 * was on screen at the same time.
 *
 * The weight, the ends and the joins are set once here and nothing overrides them. A rule
 * further down says how big a symbol is and what colour it takes, which is what actually
 * varies between one place and another. */
svg { display: block; }
.icon {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* The two beads are drawn in index.html without the class, so they are named here rather
   than given a weight of their own. They used to carry 2.1, which is why the arrow that
   folds the places away looked heavier than every other symbol beside it. */
.guide-bead svg { stroke-width: 1.7; }
[hidden] { display: none !important; }

.sr-only {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding:0 !important;
  margin:-2px !important;
  overflow: hidden !important;
  clip: rect(0,0,0,0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}
.skip-link {
  position: fixed;
  top: 10px;
  left: 10px;
  z-index: var(--layer-skip);
  background: var(--text);
  color: var(--bg);
  border-radius: var(--radius-sm);
  padding:12px 16px;
  transform: translateY(-150%);
}
.skip-link:focus { transform: translateY(0); }

:focus-visible { outline: 3px solid color-mix(in srgb, var(--blue) 58%, transparent); outline-offset: 2px; }

/* Everything that floats above the page shares one material: a wash of the surface
   colour over a blur, a bright hairline along the top edge to catch the light, and a
   soft shadow underneath. Content surfaces are deliberately left solid.

   Two weights, and only two. A menu that sits beside the control that opened it is the
   lighter one, because you glance at it. Anything you read or type inside is the heavier
   one, because a paragraph over moving prices is not readable. Each surface picks a
   weight; none of them invents its own recipe. */
.popover, .modal, .guide-drawer, .search-panel, .walkthrough-card, .toast {
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}
.popover, .modal, .guide-drawer {
  background: var(--glass-strong);
  border: 1px solid var(--line);
  box-shadow: var(--glass-shadow), var(--glass-rim);
}
/* Controls are made of the same glass as the surfaces above, at the size of a thing you
   press. Every button on the site was flat paint before this: the bar along the bottom of
   a phone was glass but the six buttons inside it were not, and the same was true of the
   header on a desktop. The material is applied by what a control is, not by where it
   happens to sit, so a button reads the same on a card, on a bar and over a chart. */
.icon-button,
.account-button,
.quiet-button,
.secondary-button,
.chip,
.segmented,
.globalnav-links a,
.select-field,
.toggle,
.admin-nav button,
.tabs button,
.guide-send,
th button,
.popover-menu button, .popover-menu a {
  backdrop-filter: var(--glass-control-blur);
  -webkit-backdrop-filter: var(--glass-control-blur);
  box-shadow: var(--glass-control-rim);
}
/* A control that carries no weight of its own stays clear until it is pointed at, so a row
   of them does not read as a row of pills competing with the page. */
.secondary-button, .chip, .account-button { font-size: var(--text-small); font-weight: 600; gap: var(--space-2); white-space: nowrap; }
/* The name in the corner is the one thing on that list with a length it cannot choose, so
   it is the one that gets capped, and the cap sits on the name rather than on the button
   around it. It used to sit on every control on the list, which cut "Open or close the
   market" off mid word and left a row of buttons in the Admin panel each missing its last
   letter. A label is written to fit; a name is not. */
.account-button-name { max-width: 168px; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.secondary-button:hover, .chip:hover, .account-button:hover, .icon-button:hover, .quiet-button:hover {
  background: var(--glass-control-raised);
}
/* Tinted glass. The colour is kept and the material is added under it, rather than the
   colour being replaced by a wash, so a primary action still reads as the primary action. */
.primary-button, .danger-button {
  backdrop-filter: var(--glass-control-blur);
  -webkit-backdrop-filter: var(--glass-control-blur);
  box-shadow: var(--glass-control-rim);
}

/* Glass belongs to a surface, not to everything standing on one. A control inside a
   panel is blurring what the panel already blurred, which flattens the material instead
   of deepening it, and costs a compositing layer for each one. The panel keeps the
   blur; everything on it keeps its tint. */
.topbar .icon-button, .topbar .account-button, .popover .popover-menu button, .popover .popover-menu a, .menu-panel .menu-item, .modal .segmented, .guide-drawer .icon-button, .card .icon-button, .card .quiet-button, .card .secondary-button, .card .chip, .card .segmented, .card .select-field, .card .toggle, .card .tabs button, .admin-nav button, .empty .primary-button, .empty .secondary-button {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

@supports not (backdrop-filter: blur(1px)) {
  /* Without a blur the wash would read as a smear, so those surfaces stay solid. */
  .globalnav, .market-strip, .popover, .modal, .guide-drawer, .search-panel, .walkthrough-card, .toast { background: var(--surface-solid); }
  .card, .admin-nav, .empty, .footer-inner { background: var(--surface-solid); }

  .metric { background: var(--surface-solid); }
  .topbar { background: transparent; }
  body::before { display: none; }
  .secondary-button, .chip, .account-button { background: var(--surface-2); }
  .globalnav-links a[aria-current="page"], .tabs button.active, .admin-nav button.on { background: var(--surface-2); }
  .toggle { background: var(--surface-3); }
  
  .primary-button { background: var(--blue-solid); }
}
/* Someone who has asked their system to cut down on transparency gets solid surfaces.
   The header is the one place on the site where text sits over moving content, so this
   is the setting that matters most here. */

:root[data-reduce-transparency="true"] .card, :root[data-reduce-transparency="true"] .footer-inner, :root[data-reduce-transparency="true"] .metric, :root[data-reduce-transparency="true"] .admin-nav, :root[data-reduce-transparency="true"] .empty, :root[data-reduce-transparency="true"] .globalnav, :root[data-reduce-transparency="true"] .popover, :root[data-reduce-transparency="true"] .modal, :root[data-reduce-transparency="true"] .guide-drawer, :root[data-reduce-transparency="true"] .search-panel, :root[data-reduce-transparency="true"] .toast, :root[data-reduce-transparency="true"] .walkthrough-card, :root[data-reduce-transparency="true"] .market-strip {
  background: var(--surface-solid);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
:root[data-reduce-transparency="true"] .topbar { background: transparent; }
:root[data-reduce-transparency="true"] body::before { display: none; }

:root[data-reduce-transparency="true"] .icon-button, :root[data-reduce-transparency="true"] .account-button, :root[data-reduce-transparency="true"] .quiet-button, :root[data-reduce-transparency="true"] .secondary-button, :root[data-reduce-transparency="true"] .chip, :root[data-reduce-transparency="true"] .segmented, :root[data-reduce-transparency="true"] .primary-button, :root[data-reduce-transparency="true"] .danger-button, :root[data-reduce-transparency="true"] .select-field, :root[data-reduce-transparency="true"] .toggle, :root[data-reduce-transparency="true"] .tabs button, :root[data-reduce-transparency="true"] .guide-send, :root[data-reduce-transparency="true"] th button {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
:root[data-reduce-transparency="true"] .secondary-button, :root[data-reduce-transparency="true"] .chip, :root[data-reduce-transparency="true"] .account-button { background: var(--surface-2); }

:root[data-reduce-transparency="true"] .toggle { background: var(--surface-3); }
:root[data-reduce-transparency="true"] .primary-button { background: var(--blue-solid); }
:root[data-reduce-transparency="true"] .overlay, :root[data-reduce-transparency="true"] .modal-root:not(:empty) { backdrop-filter: none; -webkit-backdrop-filter: none; }

/* The bar across the top of every page.
 *
 * Flush to the window's edges, its own full width, translucent over whatever is behind it
 * - which is how apple.com opens every page it has. It was three rounded cards floating in
 * a gutter, with a fade drawn above them to dissolve the content passing underneath: a
 * different idea of a header entirely, and one that costs the top forty pixels of the
 * window to a margin.
 */
.topbar {
  position: sticky;
  top: 0;
  z-index: var(--layer-header);
  background: transparent;
  display: grid;
  /* One column that is allowed to be narrower than what is inside it. As a plain auto
     track the tape's full length counted toward the column's width, and on a phone the
     header came out twelve hundred pixels wide and took the whole page sideways with it. */
  grid-template-columns: minmax(0, 1fr);
}
.globalnav {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-6);
  min-height: var(--header);
  padding: 0 var(--space-5);
  background: var(--glass-bar);
  backdrop-filter: var(--glass-bar-blur);
  -webkit-backdrop-filter: var(--glass-bar-blur);
  border-bottom: 1px solid var(--line);
}
/* The places, spread across the middle. Apple's are 12px, weight 400, and dimmed until the
   pointer is on them, which is what keeps a bar this full from shouting. */
.globalnav-links {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-6);
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.globalnav-links::-webkit-scrollbar { display: none; }
.globalnav-links a {
  flex: 0 0 auto;
  color: var(--text);
  opacity: .82;
  font-size: var(--text-caption);
  font-weight: 400;
  letter-spacing: 0;
  text-decoration: none;
  white-space: nowrap;
  padding: 4px 0;
  transition: opacity var(--transition);
}
.globalnav-links a:hover { opacity: 1; }
.globalnav-links a[aria-current="page"] { opacity: 1; font-weight: 600; }
/* One or the other, never both: the row of places on a wide window, the button that holds
   them on a narrow one. Letting the row scroll instead left it sitting half way along,
   showing "Leaderboard" and half of "Listings" with the mark pushed off the front. */
.globalnav-menu { display: none; }
@media (max-width: 900px) {
  .globalnav-links { display: none; }
  .globalnav-menu { display: inline-flex; }
  .globalnav { grid-template-columns: auto minmax(0, 1fr); }
}
/* The tape and a notice, each a band of its own under the bar, flush like it. Written out
   one at a time rather than grouped, because the contract check reads each band's own rule
   to see that it takes the shared material rather than inventing one. */
.market-strip {
  position: relative;
  width: 100%;
  background: var(--glass-bar);
  backdrop-filter: var(--glass-bar-blur);
  -webkit-backdrop-filter: var(--glass-bar-blur);
  border-bottom: 1px solid var(--line);
}
.site-banner {
  position: relative;
  width: 100%;
  background: var(--glass-bar);
  backdrop-filter: var(--glass-bar-blur);
  -webkit-backdrop-filter: var(--glass-bar-blur);
  border-bottom: 1px solid var(--line);
}
/* The mark and the name, at the weight a bar of 12px links can carry without one of them
   shouting. It inherited the page's body size, which at 17px made the name half again as
   big as every place beside it. */
.brand { display: inline-flex; align-items: center; gap:10px; font-size: var(--text-label); font-weight: 620; white-space: nowrap; min-height: 24px; text-decoration: none; color: var(--text); }
/* The exchange's mark.
 *
 * A rising line inside a filled disc, standing where Apple stands their own mark: first
 * thing on the bar, the same size as the words beside it, and no colour of its own. The
 * disc takes the text colour and the line is cut out of it, so it is a black disc with a
 * white line on a light page and a white disc with a black line on a dark one, inverting
 * with the page rather than being drawn twice. It was the letters SE.
 */
.brand-mark {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  display: inline-grid;
  place-items: center;
}
.brand-mark svg { width: 22px; height: 22px; display: block; }
.brand-disc { fill: var(--text); }
.brand-line, .brand-tip {
  fill: none;
  stroke: var(--bg);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.brand-name { letter-spacing: -.025em; }
/* Where the links do not fit, the row scrolls and fades like every other row on the site
   that runs out of room, rather than pushing the page wider than the window. */
/* The island at the foot of the window.
   The same card as the one at the top: the same glass, the same blur, the same corner and
   the same gutter from the edge of the screen. That one carries who you are and what the
   market is doing; this one carries where you can go, which is the other half of the
   chrome and does not belong in the same card as the tape.
   It tucks itself away downward as you read toward the page and comes back the moment you
   turn around, so a long page is never read past it and it is never more than one small
   movement away. Same shape, same place, at every width. */
/* Guide keeps the bottom right corner.
 *
 * This whole region used to be the island: a bead above a pill of places, pinned to the
 * foot of the window, folding away as you read and coming back as you turned around. The
 * places are in the bar across the top now, which is where an Apple page keeps them, so
 * the island had nothing left to carry. Guide is the one thing that stays down here,
 * because a panel that answers questions belongs by the thumb rather than in a navigation
 * bar - which is where a support page puts it too. */
.top-actions { display: flex; align-items: center; gap:8px; }
.icon-button, .account-button, .quiet-button, .primary-button, .secondary-button, .danger-button, .segmented button, .chip {
  border: 0;
  border-radius: var(--radius-pill);
  transition: background var(--transition), transform var(--transition), opacity var(--transition), color var(--transition), border-color var(--transition);
}
.icon-button {
  position: relative;
  width: var(--control-height-compact);
  height: var(--control-height-compact);
  display: grid;
  place-items: center;
  background: transparent;
  /* It holds a symbol rather than a word, but it still says what size its words are. Left
     to inherit, it took the size of whatever it was standing in. */
  font-size: var(--text-small);
  font-weight: 600;
}
.icon-button:hover { background: var(--surface-2); }
/* One answer to a press, for everything that takes one. A control gives a little under
   the finger and comes back, which is the whole of the animation: enough to feel
   answered, short enough that it never delays what you asked for. */
.icon-button:active, .account-button:active, .quiet-button:active, .primary-button:active, .secondary-button:active, .danger-button:active, .segmented button:active, .chip:active, .menu-item:active {
  transform: scale(.965);
}
:root[data-reduce-motion="true"] .icon-button:active,
:root[data-reduce-motion="true"] .primary-button:active,
:root[data-reduce-motion="true"] .secondary-button:active{ transform: none; }
.icon-button svg { width: 18px; height: 18px; }
.account-button, .quiet-button {
  display: inline-flex;
  align-items: center;
  height: var(--control-height-inline);
  padding: 0 var(--space-3);
  background: transparent;
}
.account-button:hover, .quiet-button:hover { background: var(--surface-2); }
.account-button { background: var(--surface-2); font-size: var(--text-small); font-weight: 600; max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Market status board. The status stays pinned on the left the way an exchange board
   does, and only the tape to its right scrolls. */
.market-strip {
  display: flex;
  align-items: stretch;
  min-height: 40px;
  font-size: var(--text-caption);
  color: var(--text-2);
  /* clip, not hidden. A box with overflow hidden is still a scroll container: nothing can
     scroll it by hand, but scrollIntoView on anything inside it will, and then the tape
     sits permanently off to one side of its own box with no way back. clip is the same
     picture with no scrolling behind it. */
  overflow: clip;
  contain: content;
}
.strip-status-fixed {
  display: flex;
  align-items: center;
  gap:12px;
  flex: 0 0 auto;
  padding: 0 16px 0 24px;
  border-right: 1px solid var(--line);
  background: transparent;
  white-space: nowrap;
  z-index: var(--layer-raised);
}
.strip-session { color: var(--text-3); font-size: var(--text-caption); }
.strip-index strong { color: var(--blue); font-weight: 700; }
.strip-tape {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  /* A real scroller rather than a clipped box, so the tape can be dragged, flicked,
     wheeled and tabbed through - and so the auto-run and the person moving it are moving
     the same thing rather than fighting over two. */
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  touch-action: pan-x;
  cursor: grab;
  /* No fade at the ends. It reached 56 pixels in on one side and 64 on the other, which is
     not a fade anybody reads as deliberate: at the left it began behind the status pill so
     the first symbol arrived already half gone, and at the right it dimmed a price you
     were still trying to read. The card's own rounded edge cuts the tape cleanly, which is
     what a ticker board does. */
}
/* Centred, not sat on a baseline. Every part of an item is the same size, so the baseline
   and the centre agree about where the text goes - but a baseline stacks the line box at
   the top of the item and puts all of the spare height underneath it, so the whole tape
   was riding three pixels above the middle of the card it sits in. */
.strip-item {
  display: inline-flex;
  gap:8px;
  align-items: center;
  min-height: 24px;
  font-variant-numeric: tabular-nums;
  padding:0 2px;
  transition: opacity var(--transition);
  /* Every part of an item is one line. A tape item is a flex row, so each part lays out
     as its own block and breaks where it likes: giving the change a width to hold put the
     direction arrow on one line and the figure on the next, and the whole tape read as two
     rows of stacked fragments. */
  white-space: nowrap;
}
a.strip-item:hover { opacity: .62; }
.strip-item strong { color: var(--text); font-weight: 650; letter-spacing: .01em; }
/* Room for the number rather than room for today's number. A price crossing a hundred
   gains a digit, and every symbol to the right of it on the tape shifted along by the
   width of that digit while somebody was reading it - twice, because the tape carries two
   copies of itself. Held at the width of the widest ordinary price, a tick changes the
   digits and nothing moves. Right-aligned, so the ones column stays in one place. */
/* Left, not right. Holding the width is what stops the tape shifting under a reader; where
   the spare width sits inside it is a separate question, and putting it in front of the
   figure pushed every percentage away from the price it belongs to and left a hole between
   them. Held on the left, the spare falls after the figure, where it joins the gap to the
   next company and reads as the space between two things rather than a gap inside one. */
.strip-item [data-strip-price] { min-width: 7.4ch; text-align: left; }
.strip-item [data-strip-change] { min-width: 9.6ch; text-align: left; }

.strip-change { font-weight: 600; }
/* Direction is shown with a shape as well as colour, so it reads without colour vision. */
/* Sized to the box it sits in rather than to the type scale. These are shapes filling a
   space, and growing them along with the text pushes them out of it.

   All three states carry one, including flat, and all three are the same width. Flat had
   no shape at all, so the first move of the session grew every item on the tape by the
   width of an arrow and shunted every symbol to the right of it along - twice over, since
   the tape carries two copies of itself. A dash is also the honest thing to show: it says
   unchanged, rather than leaving somebody to work out that no shape means no move. */
.strip-change::before { content: "\2013"; font-size: 8px; margin-right:4px; vertical-align: 1px; display: inline-block; width: 8px; text-align: center; }
.strip-change.up::before { content: "\25B2"; }
.strip-change.down::before { content: "\25BC"; }
.strip-status {
  display: inline-flex;
  align-items: center;
  gap:8px;
  padding:4px 12px;
  border-radius: var(--radius-pill);
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.strip-status::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.status-open { background: var(--green-soft); color: var(--green); }
.status-closed { background: var(--surface-3); color: var(--text-2); }
.status-preopen { background: var(--blue-soft); color: var(--blue); }
.status-halted { background: var(--red-soft); color: var(--red); }

.up { color: var(--green) !important; font-variant-numeric: tabular-nums; }
.down { color: var(--red) !important; font-variant-numeric: tabular-nums; }
.neutral { color: var(--text-2) !important; font-variant-numeric: tabular-nums; }

/* A whole window, whatever the page holds. This used to leave a hundred and ninety pixels
   for the header and the footer, which is ten more than the two of them take, so the foot
   of the page finished just inside the window on a short page and just outside it on a
   long one. Loading a short page therefore ended with the footer rising into view, and
   that is movement under somebody reading. Filling the window means the footer sits below
   the fold on every page and in every state, so it never arrives and never leaves. */
#main { min-height: 100vh; }
/* Room kept for a page that has not arrived yet.
 *
 * The height above is what a short page needs for the footer to land neatly at the bottom
 * of the window. While the page is still being built there is no page, so on a phone the
 * footer sat inside the window and was then pushed out of it the moment the content
 * appeared. Every page on a phone moved by 0.091 as it loaded and the company page by
 * 0.101, which is past the point where a shift counts against a site. Filling the window
 * until there is something to show puts the footer below the fold from the start, so
 * nothing a reader can see moves. */
/* One rhythm down the page. Sections used to set their own margins, so the distance
   between two blocks depended on which two they happened to be: on one page the gaps ran
   32, 12 and 20 pixels. The page owns the spacing now and its sections do not add their
   own, so every page reads at the same pace. */
/* A page sits inside the same edges as the cards at the top of the window.
   The header is a card of its own, so the cards under it have to start and finish on the
   same two lines or the whole column reads as slightly crooked. It used to be inset by
   its own padding, which put every card twenty four pixels inside the header above it. */
.page {
  width: 100%;
  max-width: calc(var(--content) + var(--island-side) * 2);
  margin: 0 auto;
  padding: var(--space-6) var(--island-side) var(--space-12);
  /* Room at the foot for the island, so the last row of a long page can be read and
     pressed rather than sitting underneath it.
   *
   * After the shorthand, not before it. Written above, the shorthand that follows set the
   * bottom padding back to 48 pixels and this never applied at all: the island is 98 tall
   * and floats 10 clear of the window, so a hundred pixels of the end of every long page
   * on this site was underneath it. */
  padding-bottom: calc(var(--dock-height) + var(--space-4));
  display: grid;
  align-content: start;
  gap: var(--space-6);
}
.page.narrow { max-width: calc(900px + var(--island-side) * 2); }

/* A section heading belongs to what follows it, so it sits closer to that than to what
   came before. */

/* ----- Home ----------------------------------------------------------------------------
   Two cards: the index, and one line about what to do next. The index figure takes the
   largest size on the site because it is the answer to the only question the page asks.
   Everything else here is the same card, the same buttons and the same chart the rest of
   the site is built from. */
.home-index { display: flex; flex-direction: column; gap: var(--space-5); }
.home-index-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.home-index-value { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.home-index-value strong { font-size: var(--text-hero); font-weight: 680; letter-spacing: var(--tracking-tight); line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap; }
.home-index-value span { font-size: var(--text-card); font-weight: 620; font-variant-numeric: tabular-nums; white-space: nowrap; }
.home-next { display: flex; align-items: center; justify-content: space-between; gap: var(--space-6); flex-wrap: wrap; }
.home-next strong { display: block; font-size: var(--text-card); letter-spacing: var(--tracking-snug); font-weight: 650; font-variant-numeric: tabular-nums; }
.home-next p { margin: var(--space-1) 0 0; color: var(--text-2); font-size: var(--text-small); font-variant-numeric: tabular-nums; }
.home-next-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }

/* The card that says who the page is for. A stranger reads what the exchange is; somebody
   signed in reads what their account is worth. Same slot, same shape, so the page does not
   rearrange itself around who is looking at it. */
.home-welcome { display: flex; align-items: center; justify-content: space-between; gap: var(--space-6); flex-wrap: wrap; }
.home-welcome h1 { margin: 0; font-size: var(--text-section); letter-spacing: var(--tracking-snug); font-weight: 680; font-variant-numeric: tabular-nums; }
.home-welcome p { margin: var(--space-1) 0 0; max-width: 60ch; color: var(--text-2); font-variant-numeric: tabular-nums; }

/* ---- Markets -------------------------------------------------------------------------
   A table whose rows are grids rather than table rows, because a table's columns are set
   by the widest cell anywhere in it and one forty character company name then pushed every
   price on the page sideways. The heading row and the rows under it share one set of
   column widths, declared once here, so they cannot drift apart. */
/* The name takes the room and the two figures sit together on the right, the same three
   columns at every width. There was a fourth, the sector, and it was the one that had to
   go on a tablet, so the table read three different ways depending on the screen. */
.market-card { --market-columns: minmax(0, 1fr) 7rem 7rem; }
/* Watching from the list, for somebody signed in.
   A fourth track holds the button, and because the headings above read the same variable
   the three of them still sit over the three figures below. One grid, one variable, and
   nothing to keep in step by hand the next time a column moves. */
.market-card.market-watchable { --market-columns: minmax(0, 1fr) 7rem 7rem 6.5rem; }
.market-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.market-head h1 { margin: 0; font-size: var(--text-section); letter-spacing: var(--tracking-snug); font-weight: 680; }
.market-head p { margin: var(--space-1) 0 0; color: var(--text-2); font-size: var(--text-small); }
/* The box and the filters travel together, because they do the same job from two ends:
   one narrows the list by what a company is called, the other by what it is. */
.market-tools { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.market-find {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-2);
  width: 15rem;
  max-width: 100%;
  padding: 0 var(--space-4);
  height: var(--control-height);
  border-radius: var(--radius-pill);
  background: var(--glass-control);
  box-shadow: var(--glass-control-rim);
}
.market-find svg { width: 17px; height: 17px; color: var(--text-3); }
.market-find input { border: 0; outline: 0; background: transparent; color: var(--text); font-size: var(--text-body); font-family: inherit; min-width: 0; }
.market-find input::placeholder { color: var(--text-3); }
.market-find:focus-within { outline: 3px solid color-mix(in srgb, var(--blue) 58%, transparent); outline-offset: 2px; }
.market-filters svg { width: 17px; height: 17px; }
/* How many filters are on, before you open the menu. A page can otherwise be quietly
   showing eight companies out of forty with nothing on screen saying why. */
/* The range the index chart is on, worn by the same Filters button. It is the shape of the
   count badge beside it because it answers the same question - what is this control doing
   without opening it - but it is a word rather than a number, so it says so in its name. */
.market-filter-count, .range-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px; margin-left: -2px;
  border-radius: var(--radius-pill); background: var(--blue-solid); color: #fff;
  font-size: var(--text-micro); font-weight: 700; font-variant-numeric: tabular-nums;
}
.range-badge { letter-spacing: .02em; }

.market-table { margin-top: var(--space-5); }
/* One heading a column, each one the control that sorts by it. They were three one word
   buttons in a row above the list, which is a sort control that does not look like one and
   has room for exactly three answers. */
/* The same padding as the rows below it, so the two share one set of column edges. They
   had different padding and their own on top of that, which put every heading between 8
   and 24 pixels to the right of the figures it was heading. */
.market-columns { display: grid; grid-template-columns: var(--market-columns); align-items: center; gap: var(--space-2); padding: 0 var(--space-2); border-bottom: 1px solid var(--line-strong); }
.market-column {
  display: flex; align-items: center; gap: var(--space-1);
  min-height: var(--control-height-compact);
  /* No padding of its own: the button is the column, so its text sits exactly where the
     figures under it sit and its hover covers the column rather than part of it. */
  padding: 0;
  border: 0; background: transparent;
  color: var(--text-3);
  font-size: var(--text-micro); font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  border-radius: var(--radius-xs);
  transition: color var(--transition), background var(--transition);
}
.market-column:hover { color: var(--text); background: var(--surface-2); }
.market-column.sorted { color: var(--text); }
/* The two figures are read against one another down the page, so their headings sit over
   the right hand edge their figures line up on. */
.market-column:nth-child(2), .market-column:nth-child(3) { justify-content: flex-end; }
.market-arrow { font-size: var(--text-small); line-height: 1; }

.market-rows { display: grid; }
.market-row {
  display: grid;
  grid-template-columns: var(--market-columns);
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-2);
  border-top: 1px solid var(--line);
  color: var(--text);
  border-radius: var(--radius-xs);
  transition: background var(--transition);
}
.market-rows > .market-row:first-child { border-top: 0; }
a.market-row:hover { background: var(--surface-2); }
.market-name { display: grid; min-width: 0; }
/* Both lines have a line height of their own, so every row comes out the same height
   whichever letters are in it. Left to the font, a row of tall letters and a row of short
   ones differed by a pixel, which is not visible on its own and is visible down a column
   of forty. */
.market-name strong { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-body); line-height: 1.35; font-weight: 650; letter-spacing: var(--tracking-snug); }
.market-name > span { font-size: var(--text-small); line-height: 1.35; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Only on a company that is not simply trading. Thirty nine rows reading "Trading" is a
   column of one word, and the one row that is not gets lost in it. */
.market-status {
  flex: 0 0 auto;
  padding: 1px var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--orange-soft); color: var(--orange);
  font-size: var(--text-micro); font-weight: 700; letter-spacing: .02em; text-transform: uppercase;
}
/* The price and the change as one thing: two readings of the same company, which belong
   under one another on a narrow screen rather than either side of a name. */
.market-figures { display: contents; }
.market-price { font-size: var(--text-body); line-height: 1.35; font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }
.market-change { font-size: var(--text-body); line-height: 1.35; font-weight: 650; font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }
/* The row used to be one link. It cannot be, now that it holds a button, so the link is
   the company's name and the stylesheet stretches it back over the whole row: the same
   place to press as before, and a link that still reads as the company rather than as
   the row it sits in. The button is lifted over that cover so it stays pressable. */
.market-row.market-watch { position: relative; }
.market-row.market-watch:hover { background: var(--surface-2); }
.market-open::after { content: ''; position: absolute; inset: 0; border-radius: inherit; }
.market-watch-button { position: relative; width: 100%; }
.market-card .empty { margin-top: var(--space-4); }

/* ---- One trader ------------------------------------------------------------------------
   Who somebody is in a card of its own, and what their account is doing beside it. The
   figure, the chart and the four ranges are the same ones the home and company cards use,
   so the half of this page that is about the market has been read twice already before
   anybody arrives here from the board. */
.profile-page { grid-template-columns: 20rem minmax(0, 1fr); align-items: start; }
.profile-main { display: grid; gap: var(--space-6); min-width: 0; }
.profile-card { display: grid; justify-items: center; text-align: center; gap: var(--space-4); }
.profile-names { display: grid; min-width: 0; max-width: 100%; }
/* The same size every other page heading on this site is set at. At the display size it
   was, an ordinary name broke onto two lines inside a card this narrow. */
.profile-names h1 {
  margin: 0;
  font-size: var(--text-section);
  font-weight: 680;
  letter-spacing: var(--tracking-tight);
  line-height: 1.15;
  min-width: 0;
  overflow-wrap: anywhere;
}
.profile-handle { margin: var(--space-1) 0 0; color: var(--text-2); font-size: var(--text-body); }
/* Centred under the name rather than beside it. Beside a name that is centred, one badge
   pulls the name off centre and three pull it further, so the row of them is its own line
   and the name stays where it was put. */
.profile-marks { justify-content: center; }
/* What is true about somebody, rather than what their account is worth. Read down rather
   than across, because a column of three short facts in a narrow card reads faster than
   three columns of one. */
.profile-facts { display: grid; gap: var(--space-3); margin: 0; width: 100%; }
.profile-facts > div { display: grid; gap: 1px; }
.profile-facts dt { font-size: var(--text-small); color: var(--text-2); }
.profile-facts dd { margin: 0; font-size: var(--text-body); font-weight: 620; letter-spacing: var(--tracking-snug); }
/* The same five columns the holdings table has anywhere else it appears. */
.market-card.profile-holdings { --market-columns: minmax(0, 1fr) 5rem 7rem 8rem 6rem; }
.profile-holdings h2 { margin: 0; font-size: var(--text-section); letter-spacing: var(--tracking-snug); font-weight: 680; }
.profile-holdings p { margin: var(--space-1) 0 0; color: var(--text-2); font-size: var(--text-small); }
.profile-shares { font-size: var(--text-body); line-height: 1.35; font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.profile-holdings .market-column:not(:first-child) { justify-content: flex-end; }

@media (max-width: 480px) {
  /* Shares and price go and the ticker, what it is worth and today's move stay, because
     those three are what somebody is reading a holding for. A heading and the cell under
     it are dropped together, or the row has more cells than it has columns to put them in. */
  /* Sized to their contents rather than to a number. At a fixed 7rem and 5rem the two
     figures took 192 pixels of a 320 pixel screen and the Company heading was drawn 25
     pixels past its own column. */
  .market-card.profile-holdings { --market-columns: minmax(0, 1fr) auto auto; }
  .profile-holdings .market-row > :nth-child(4) { padding-left: var(--space-3); }
  .profile-holdings .market-column:nth-child(2), .profile-holdings .market-column:nth-child(3) { display: none; }
  .profile-row > :nth-child(2), .profile-row > :nth-child(3) { display: none; }
  .profile-card .avatar-large { width: 56px; height: 56px; font-size: var(--text-card); }
  .profile-names h1 { font-size: var(--text-section); }
}

@media (max-width: 900px) {
  /* One column under a certain width, because a 20rem card and a table beside it leaves
     the table too narrow to hold its own five columns. */
  .profile-page { grid-template-columns: minmax(0, 1fr); }
}

/* ---- The board -------------------------------------------------------------------------
   The same table, with two things in front of the figures rather than one: where somebody
   is, and who they are. Everything else it borrows, so a row here and a row on Markets are
   the same row with different contents.

   Written as two classes on purpose. The board is a market card too, so a single
   .leader-card is the same weight as the .market-card rules and loses to whichever of them
   is written later in this file: the phone rule below set the board back to two columns,
   and three things in two columns wrap. */
.market-card.leader-card { --market-columns: minmax(3.5rem, auto) minmax(0, 1fr) 8rem 7rem; }
/* The place is a figure read down a column, so it is lined up like the figures are. */
.leader-place {
  font-size: var(--text-body);
  line-height: 1.35;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--text-2);
}
.leader-who { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.leader-names { display: grid; min-width: 0; }
/* Beside the name, and beneath it when the row is too narrow for both. A phone with three
   badges on one row had nothing left for the name and printed "Dem...", so the badges drop
   to their own line rather than the name giving up its last few letters to them. */
.leader-names strong {
  display: flex; align-items: center; gap: var(--space-2);
  flex-wrap: wrap; row-gap: 2px;
  font-size: var(--text-body); line-height: 1.35; font-weight: 650;
  letter-spacing: var(--tracking-snug);
  min-width: 0;
}
/* The name gives way, and what somebody has earned does not. Written as one truncating
   line with the badges inside it, a narrow row spent its width on the name and cut the
   badges off the end: a moderator on a phone wore nothing at all. */
.leader-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* What somebody has earned, as one thing. Left as loose badges they wrapped one at a time,
   so a row could end with a seal beside the name and the other two on the line below it. */
.leader-marks { display: inline-flex; align-items: center; gap: var(--space-2); flex: 0 0 auto; }
.leader-handle {
  font-size: var(--text-small); line-height: 1.35; color: var(--text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.leader-card .market-column:nth-child(1) { justify-content: flex-start; }
.leader-card .market-column:nth-child(2) { justify-content: flex-start; }
.leader-card .market-column:nth-child(3), .leader-card .market-column:nth-child(4) { justify-content: flex-end; }

@media (max-width: 480px) {
  /* The figures stack against the right edge, and the place keeps its own column, because
     where somebody is on the board is the reason to be looking at it.

     The rank column takes whatever "Rank" and its arrow need rather than a number somebody
     guessed. At a fixed 2.25rem the heading ran into the one beside it and the two read as
     one word, and at the large text size it drew straight past its own edge. */
  .market-card.leader-card { --market-columns: minmax(2.5rem, auto) minmax(0, 1fr) auto; }
  .leader-card .market-column:nth-child(4) { display: none; }
  .leader-who { gap: var(--space-2); }
  /* Scoped to the board rather than written as a bare .avatar, because the rule that sizes
     one is further down this file and a later rule of the same weight wins whatever media
     query it was written in. */
  .leader-card .avatar { width: 32px; height: 32px; font-size: var(--text-small); }
  /* A phone leaves about 128 pixels for a name and its badges, which one badge misses by a
     pixel and three miss easily. Left to wrap on its own, some rows put the badges beside
     the name and some underneath, and a column of rows in two different shapes reads worse
     than a column all in one. Underneath, every row, at this width. */
  .leader-marks { flex-basis: 100%; }
}

@media (max-width: 480px) {
  /* The figures stack against the right edge and the headings above them go with it, so
     the heading row stays exactly as wide as the rows it heads. */
  /* The two figures stack against the right edge, and the heading over them goes with
     them, so nothing is dropped: the same three things are on a phone as on a desktop. */
  .market-card { --market-columns: minmax(0, 1fr) auto; }
  /* The figures fold into one cell here, so the watchable row is a name, that cell, and
     the button: three things, and three tracks to put them in.

     The button's track is a fixed width rather than auto, and that is the whole point of
     it. The headings and the rows are two grids reading one variable, and an auto track
     sizes to whatever is in it: the heading row holds nothing over the button, the rows
     hold a button, so the two grids disagreed and the Price heading sat 89px right of the
     prices. Fixed, both grids put the same edge in the same place, which is all a right
     aligned figure needs. The button gives back the padding to pay for it. */
  .market-card.market-watchable { --market-columns: minmax(0, 1fr) auto 5.5rem; }
  .market-watch-button { padding-left: var(--space-2); padding-right: var(--space-2); }
  .market-figures { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
  .market-column:nth-child(3) { display: none; }
  /* The box and the filters share one line rather than taking two: they are the same job
     from two ends, and a phone has more use for the row than the layout does. */
  .market-tools { width: 100%; flex-wrap: nowrap; }
  .market-find { flex: 1 1 auto; width: auto; min-width: 0; }
  .market-filters { flex: 0 0 auto; }
  /* The word goes and the symbol stays, because at this width the row is the label. It is
     hidden from sight and not from a screen reader, by the one rule on this site that does
     that, so the button is still called Filters to anybody who cannot see the symbol. */
  .market-filters .market-filters-word { position: absolute; width: 1px; height: 1px; padding: 0; margin: -2px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; }
  .market-filters { padding: 0 var(--space-4); }
}

/* Whether the market is open, on the card about the market. The tape says so too, in a
   line that scrolls; this one holds still under the figure it applies to. */
.home-index-state { display: flex; align-items: center; gap: var(--space-2); margin: var(--space-3) 0 0; font-size: var(--text-small); color: var(--text-2); }
.state-dot { width: 7px; height: 7px; border-radius: var(--radius-pill); background: var(--text-3); flex: 0 0 auto; }
.state-dot.status-open { background: var(--green); }
.state-dot.status-preopen { background: var(--orange); }
.state-dot.status-closed, .state-dot.status-halted { background: var(--red); }

/* ---- One company ---------------------------------------------------------------------
   Three cards, in the order somebody reads them: what the price is, what to do about it,
   and the figures behind it. The first card is the home page's index card with a company
   in it rather than the exchange, on purpose: a company and the market it trades on are
   the same kind of thing to look at, so they are the same card to look at.

   The detail lives here rather than in the table, because a table has one row per company
   and forty rows of eight figures is a spreadsheet. A page has one company on it and all
   the room in the world. */
.company-quote { display: flex; flex-direction: column; gap: var(--space-5); }
.company-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.company-title { min-width: 0; }
.company-title h1 { margin: 0; font-size: var(--text-section); font-weight: 680; letter-spacing: var(--tracking-snug); line-height: 1.2; }
.company-title p { display: flex; align-items: center; gap: var(--space-2); margin: var(--space-2) 0 0; }
.company-ticker { font-size: var(--text-small); font-weight: 650; letter-spacing: .04em; color: var(--text-2); }
/* The same figure and the same percentage beside it as the index, at the same sizes. The
   figure is the level and the percentage is the direction, so the figure takes no colour. */
.company-price { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.company-price strong { font-size: var(--text-hero); font-weight: 680; letter-spacing: var(--tracking-tight); line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap; }
.company-price span { font-size: var(--text-card); font-weight: 620; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* The ticket: buy or sell, how many, and go. One row on a desktop and a stack on a phone,
   with the two sentences under it saying what it would cost and what is already held. */
.company-trade { display: flex; flex-direction: column; gap: var(--space-4); }
.ticket { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
/* The same glass pill as the box on Markets, because it is the same job: one thing typed
   into one control. A second treatment for a second box is two things to keep true. */
.ticket-amount {
  display: flex; align-items: center;
  flex: 1 1 8rem; min-width: 0; max-width: 12rem;
  padding: 0 var(--space-4);
  height: var(--control-height);
  border-radius: var(--radius-pill);
  background: var(--glass-control);
  box-shadow: var(--glass-control-rim);
}
.ticket-amount input { width: 100%; min-width: 0; border: 0; outline: 0; background: transparent; color: var(--text); font-family: inherit; font-size: var(--text-body); font-variant-numeric: tabular-nums; }
.ticket-amount input::placeholder { color: var(--text-3); }
.ticket-amount:focus-within { outline: 3px solid color-mix(in srgb, var(--blue) 58%, transparent); outline-offset: 2px; }
.ticket-line, .ticket-position { margin: 0; font-size: var(--text-small); color: var(--text-2); font-variant-numeric: tabular-nums; }
.ticket-position { color: var(--text-3); }
.company-trade p:first-of-type { margin: 0; max-width: 60ch; color: var(--text-2); }

/* The figures behind the price. Two columns of pairs on a desktop, one on a phone, each
   pair a word and a number rather than a sentence: eight short readings somebody can find
   one of without reading the other seven. */
.company-facts { display: flex; flex-direction: column; gap: var(--space-4); }
/* Four, two, one. It was auto-fit, which gave a desktop eight columns and left the ninth
   figure alone on a row of its own: eight columns is a strip rather than a grid, and one
   orphan under it reads as something having gone wrong. Four across is two even rows. */
.fact-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-5) var(--space-4); margin: 0; }
.fact-grid > div { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.fact-grid dt { font-size: var(--text-small); color: var(--text-3); }
/* A value wraps rather than being cut off. Sector is a word rather than a figure and an
   Admin writes it, so it is the one of the eight that can be longer than its column, and a
   sector clipped to "Consumer Discretio" is worse than one on two lines. break-word only
   breaks what cannot fit, so a price never breaks across its own comma. */
.fact-grid dd { margin: 0; font-size: var(--text-figure); font-weight: 650; letter-spacing: var(--tracking-snug); line-height: 1.25; font-variant-numeric: tabular-nums; overflow-wrap: break-word; }
.company-about { margin: 0; max-width: 70ch; color: var(--text-2); line-height: 1.55; }

/* Watching, and being told.

   Two jobs in one card because they are the same job: keeping an eye on a company you do
   not hold. The two controls sit on one row and the alerts stack under them, so a card
   with no alerts on it is three lines tall rather than a heading over an empty box.

   The toggle is the one control on this site whose whole meaning is which of two states it
   is in, so the pressed state is drawn rather than only announced: filled in when it is on,
   the same weight as a chosen segment elsewhere. aria-pressed carries the same fact for a
   reader that cannot see the fill. */
.company-watch { display: flex; flex-direction: column; gap: var(--space-4); }
.company-watch > p { margin: 0; max-width: 60ch; color: var(--text-2); }
.watch-actions { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.watch-toggle.active { background: var(--blue-solid); color: #fff; }
.watch-toggle.active:hover { background: var(--blue-solid-hover); }

/* One alert per line: what was asked for, when it last went off, and the way to remove it.
   The same two-line-plus-control shape a market row has, so the eye reads it the same way
   without the column widths a table needs. */
.watch-alerts { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }
.watch-alerts > li {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-3) var(--space-2);
  border-top: 1px solid var(--line);
}
.watch-alerts > li:first-child { border-top: 0; }
.watch-alert-what { display: grid; min-width: 0; gap: var(--space-1); }
/* Both lines carry money - "Goes above $150.00", "Last sent just now" - and figures on
   this site are set in tabular numerals wherever they stack, so a column of prices lines
   up on its decimal point instead of wandering. */
.watch-alert-what strong { font-size: var(--text-body); font-weight: 620; line-height: 1.35; letter-spacing: var(--tracking-snug); font-variant-numeric: tabular-nums; }
.watch-alert-what .subtle { font-size: var(--text-small); line-height: 1.35; font-variant-numeric: tabular-nums; }

/* A watched company is a market row with a Stop beside it. The row keeps the table's
   column widths by moving them onto the link, because the row itself now has two children
   rather than the two figures a market row has, and a button inside a link is neither
   valid nor clickable. */
.profile-watching .market-row.watch-row { grid-template-columns: minmax(0, 1fr) auto; padding-right: var(--space-1); }
.watch-row-link {
  display: grid; grid-template-columns: var(--market-columns); align-items: center;
  gap: var(--space-2); min-width: 0; color: var(--text);
  padding: 0 var(--space-1); border-radius: var(--radius-xs);
}
.watch-row-link:hover .market-name strong { text-decoration: underline; text-underline-offset: 3px; }
.profile-alerts { display: flex; flex-direction: column; gap: var(--space-4); }
.profile-alerts > p { margin: 0; max-width: 60ch; color: var(--text-2); }
.profile-alerts .watch-alert-what a { color: inherit; font-weight: 700; }

/* Listing a company.

   Two fields across where two fields belong together - a name and its ticker, a price and
   a share count - and one across on a phone. The same shape the panel's dials take, under
   a name that is not about the panel, because this one is a page anybody can open. */
.field-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }
/* A number and the word it counts, sized to what each holds rather than to half the sheet. */
.suspend-long { grid-template-columns: 7rem minmax(0, 1fr); align-items: center; }
.suspend-note { margin-top: var(--space-2); font-size: var(--text-caption); }
.listing-form { display: grid; gap: var(--space-4); }
.listing-actions { display: flex; justify-content: flex-start; }
/* The page gap, the same one .page uses, so these two sit in the site's rhythm rather
   than two thirds of it. */
.listings-page { display: grid; gap: var(--space-6); }
/* The one heading on each of these pages. Without this they fall through to the browser's
   own 2em, which is not a step on the scale and moves with the density setting into three
   sizes the scale does not contain - the drift design-check names. Every other page
   heading on the site is this size, this weight and this tracking, so they are written
   once here rather than once per page. */
.listings-page h1, .guide-page h1, .news-top h1 {
  margin: 0 0 var(--space-3); font-size: var(--text-section); font-weight: 680; letter-spacing: var(--tracking-snug);
}
.listing-rows { display: grid; }
.listing-row { padding: var(--space-4) 0; border-top: 1px solid var(--line); }
.listing-rows > .listing-row:first-child { border-top: 0; padding-top: 0; }
.listing-row-head { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-3); }
.listing-row-head strong { font-size: var(--text-body); font-weight: 700; letter-spacing: var(--tracking-snug); font-variant-numeric: tabular-nums; }
/* Wider than the panel's, because this one carries "Asking" and "Said" rather than the
   panel's four-letter words, and 56px cuts both of them in half. */
.listing-row .admin-was { grid-template-columns: 72px minmax(0, 1fr); }
.listing-landed { margin: 0; }

/* Orders. One per line: what was asked for, how far through it is, and the way to take it
   back. The same shape the alerts list takes, because it is the same reading job - a
   sentence and a control - and two shapes for one job is one too many. */
.company-orders, .profile-orders { display: flex; flex-direction: column; gap: var(--space-4); }
.company-orders > p, .profile-orders > p { margin: 0; max-width: 60ch; color: var(--text-2); }
.order-rows { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }
.order-rows > li {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-3) var(--space-2);
  border-top: 1px solid var(--line);
}
.order-rows > li:first-child { border-top: 0; }
.order-what { display: grid; min-width: 0; gap: var(--space-1); }
/* Same rule, and the one that caught this: "Buy 2 shares at $54.00" is a figure in a
   stacked list and was drawn in proportional numerals, so the prices down the card did not
   line up with each other. */
.order-what strong { font-size: var(--text-body); font-weight: 620; line-height: 1.35; letter-spacing: var(--tracking-snug); font-variant-numeric: tabular-nums; }
.order-what strong a { color: inherit; font-weight: 700; }
.order-what .subtle { font-size: var(--text-small); line-height: 1.35; font-variant-numeric: tabular-nums; }
/* The state and the control travel together, so the column of pills stays a column. */
.order-end { display: flex; align-items: center; gap: var(--space-2); flex: 0 0 auto; }

/* The price a limit order names. Same pill as the shares box beside it, narrower, and it
   is only on the page for the kind of order that needs one. */
.ticket-limit { max-width: 10rem; }

/* News. Each item is a heading, who it is about, what happened and when - read down the
   page rather than scanned across a table, which is why it is not one. */
.news-page > .card { display: flex; flex-direction: column; gap: var(--space-5); }
.news-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.news-top p { margin: 0; max-width: 62ch; }
.news-items { display: grid; gap: 0; }
.news-item { padding: var(--space-5) 0; border-top: 1px solid var(--line); }
.news-items > .news-item:first-child { border-top: 0; padding-top: 0; }
.news-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
.news-head h3 { margin: 0; font-size: var(--text-card); font-weight: 680; letter-spacing: var(--tracking-snug); line-height: 1.3; font-variant-numeric: tabular-nums; }
.news-marks { display: flex; gap: var(--space-2); flex-wrap: wrap; flex: 0 0 auto; }
.news-marks a.admin-tag { text-decoration: none; }
.news-marks a.admin-tag:hover { background: var(--surface-3); }
.news-item > p { margin: var(--space-3) 0 0; max-width: 68ch; color: var(--text-2); line-height: 1.55; font-variant-numeric: tabular-nums; }
.news-when { margin-top: var(--space-2); font-size: var(--text-small); }
/* On a company's page the same items sit inside a card, so the card's own padding is the
   gutter and the list does not add a second one. */
.company-news { display: flex; flex-direction: column; gap: var(--space-4); }
.company-news > p { margin: 0; max-width: 60ch; color: var(--text-2); }
.company-news .news-item { padding: var(--space-4) 0; }
.company-news-more { margin: 0; font-size: var(--text-small); }

/* The Guide's own page: fifteen things it can explain, each a press away from being asked.
   A whole row is the control, because the question is the thing being pressed. */
.guide-page { display: grid; gap: var(--space-6); }
/* One list, not fifteen buttons.
   Each topic is the whole row, so each is a <button>, and given a filled pill apiece they
   read as fifteen of the largest controls on the site - a hundred pixels tall and eight
   hundred wide. The material moves to the seams: a hairline between rows, drawn as a one
   pixel gap over a line-coloured ground, so every row still carries a surface of its own
   (which is what stops a pressable thing reading as text) while the group reads as a list. */
.guide-topics {
  display: grid; gap: 1px; margin: 0; padding: 0; list-style: none;
  background: var(--line); border-radius: var(--radius-sm); overflow: hidden;
}
/* Every control on this site carries material - a surface or a shadow - so that a thing
   you press never reads as text that happens to respond. These were painted with nothing
   at all, which the accessibility check names as flat. Given the same surface the
   secondary buttons use, and separated by the gap rather than by a rule, because fifteen
   filled rows with lines between them is two separations doing one job. */
.guide-topic {
  display: grid; gap: 2px; width: 100%; text-align: left;
  padding: var(--space-3) var(--space-4); border: 0; border-radius: 0;
  background: var(--surface-2); color: var(--text); font-family: inherit; cursor: pointer;
  transition: background var(--transition);
}
.guide-topic:hover { background: var(--surface-3); }
.guide-topic strong { font-size: var(--text-body); font-weight: 650; letter-spacing: var(--tracking-snug); }
.guide-topic > span { font-size: var(--text-small); color: var(--text-2); line-height: 1.45; }
.guide-example { color: var(--text-3); }

/* The places no longer step aside for the Guide, because the two cannot reach each other.

   They used to share the foot of the window - the places centred, the Guide anchored right
   - and once the row grew to seven names it ran under the drawer: at 1440 the places ended
   at 1063 and the drawer began at 1040. The answer then was to slide the whole row left
   while the drawer was open and slide it back when it shut, which is a second thing moving
   every time the Guide is opened or closed.

   The drawer now starts above the island rather than beside it, so there is no width at
   which they overlap and nothing has to move at all. The accessibility check still measures
   the overlap; it just never finds one.
*/

@media (max-width: 600px) {
  .news-top .segmented { width: 100%; }
  .news-top .segmented button { flex: 1 1 0; }
}

@media (max-width: 600px) {
  .order-rows > li { flex-direction: column; align-items: flex-start; gap: var(--space-2); }
  .order-end { width: 100%; justify-content: space-between; }
  .ticket-limit { max-width: none; }
}

@media (max-width: 600px) {
  .field-row { grid-template-columns: minmax(0, 1fr); }
  .listing-actions .primary-button { width: 100%; }
}

@media (max-width: 600px) {
  /* Both controls to full width, the way the ticket above them already stacks. */
  .watch-actions { flex-direction: column; align-items: stretch; }
  .watch-actions .secondary-button { width: 100%; }
  /* The line and its Remove stop fighting for one row's width. */
  .watch-alerts > li { flex-direction: column; align-items: flex-start; gap: var(--space-2); }
}



@media (max-width: 600px) {
  /* The figure comes down to the size the index figure comes down to, and the ticket
     stops trying to be a row: a control per line is wider to hit and reads in order. */
  .company-price strong { font-size: var(--text-figure-lg); }
  .company-head { flex-direction: column; }
  .ticket { flex-direction: column; align-items: stretch; }
  .ticket-amount { max-width: none; }
  .ticket .segmented, .ticket .primary-button { width: 100%; }
  .ticket .segmented button { flex: 1 1 0; }
}

@media (max-width: 900px) { .fact-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 460px) { .fact-grid { grid-template-columns: minmax(0, 1fr); } }

/* No colour on the index figure at all, in front of it or behind it.
   It changed colour with the way it last moved, then a wash behind it did the same more
   quietly, and both were the same mistake: a second colour signal twenty pixels from the
   first one, saying something different. The index moves every two seconds, so a tick down
   inside a day that is up put red under a figure with a green plus eleven per cent beside
   it. The figure is the level and the percentage is the direction, and a figure this size
   changing every two seconds needs nothing to announce that it moved. */

/* Under centred words, centred. The row inherited flex-start, so the one button on the
   "Not here yet" page sat 375 pixels to the left of the heading and the sentence above it,
   against the left edge of a box whose every other line was centred. */
.empty-actions { display: flex; justify-content: center; gap:12px; flex-wrap: wrap; margin-top:24px; }

.primary-button { background: color-mix(in srgb, var(--blue-solid) var(--glass-tint-strength), transparent); color: #fff; }
.primary-button:hover { background: var(--blue-solid-hover); transform: translateY(-1px); }
.secondary-button { background: var(--surface-2); color: var(--text); }
.secondary-button:hover { background: var(--surface-3); }
.danger-button { background: var(--red-soft); color: var(--red); }
.danger-button:hover { filter: brightness(.98); }
button:disabled { opacity: .48; cursor: not-allowed; transform: none !important; }

.card.compact { padding:16px 20px; border-radius: var(--radius); }
.card h2, .card h3 { margin:0; }

.card-header h2 { font-size: var(--text-card); letter-spacing: -.02em; }
/* A text action: the quiet way to do something or go somewhere, used where a filled
   button would shout. One size, one weight, one height, and it underlines on hover like
   every other link on the site, so hovering tells you it is live rather than leaving you
   to read the address bar. No icons: a chevron on one and nothing on the next was the
   whole problem. */
.text-action {
  display: inline-flex;
  align-items: center;
  min-height: var(--control-height-compact);
  padding: 0;
  border: 0;
  background: none;
  color: var(--blue);
  font-size: var(--text-small);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: color var(--transition);
}.text-action:hover, .footer nav a:hover {
  color: var(--blue-hover);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1.5px;
}.text-action, .footer nav a { cursor: pointer; transition: color var(--transition); }

.metric { background: color-mix(in srgb, var(--surface-solid) 62%, transparent); padding:20px; min-width: 0; }

/* A mover card is one size whatever it is holding.
 *
 * These fill in as the market moves: a freshly opened exchange has nothing up and nothing
 * down, and a second later it has six of each. The card used to be as tall as however many
 * rows it happened to have, so those six arriving pushed three hundred pixels of page down
 * under whoever was reading it. The room for a full card is held from the start, which is
 * also why the three cards on the home page now line up with each other rather than being
 * three different heights. */
/* A row you can open and a control you can press are two different targets, so the company
   is the link and the action sits beside it rather than inside it. A watchlist could be
   added to from a company's own page but never emptied from here, because the whole row
   was one link with nowhere to put a second thing to press. */
/* A label and the choice of what the field is measured in, on one line. The choice belongs
   beside the label rather than above the field, because it changes what the label says. */

.toolbar { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }

.segmented { display: inline-flex; max-width: 100%; padding:4px; background: var(--glass-control); border-radius: var(--radius-pill); gap:2px; overflow-x: auto; scrollbar-width: none; }
.segmented::-webkit-scrollbar { display: none; }
.segmented button { display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: center; height: var(--control-height-compact); padding: 0 var(--space-3); background: transparent; color: var(--text-2); font-size: var(--text-caption); font-weight: 650; }
.segmented button.active { background: var(--glass-control-raised); color: var(--text); box-shadow: var(--glass-control-rim), 0 1px 5px rgba(0,0,0,.1); }

.chip { display: inline-flex; align-items: center; height: var(--control-height-compact); flex: 0 0 auto; border: 1px solid var(--line); background: var(--surface-solid); padding: 0 var(--space-3); font-size: var(--text-small); font-weight: 600; }
.chip.active { background: var(--glass-control-raised); color: var(--text); border-color: var(--line-strong); }

.table-scroll { overflow-x: auto; overflow-y: visible; }table { width: 100%; border-collapse: collapse; min-width: 760px; font-variant-numeric: tabular-nums; }
th { position: sticky; top: 0; z-index: var(--layer-sticky); background: color-mix(in srgb, var(--surface-solid) 88%, var(--bg)); text-align: left; color: var(--text-3); font-size: var(--text-micro); font-weight: 700; text-transform: uppercase; letter-spacing: .05em; border-bottom: 1px solid var(--line); padding:0 16px; height: 38px; white-space: nowrap; }
/* A header that is a sort button supplies its own padding, so the cell drops its own. */
th:has(button) { padding:0; }
/* A column heading you can press. It stays clear at rest, because a rim around every
   heading draws a box around the top of the table rather than a row of words, and it takes
   the material the moment you point at it or sort by it. */
th button { width: 100%; min-height: 38px; border: 0; background: transparent; color: inherit; padding:0 16px; text-align: inherit; text-transform: inherit; letter-spacing: inherit; font-weight: inherit; display: flex; align-items: center; gap:4px; white-space: nowrap; border-radius: var(--radius-sm); transition: background var(--transition), color var(--transition), transform var(--transition); }
th button:hover { color: var(--text); background: var(--glass-control); }
th button:active { transform: scale(.98); }
/* Centred against the row rather than sat on its own text baseline. A cell holding a badge
   and a cell holding plain figures have different first baselines, so on rows that mixed
   them - a role beside a Discord ID beside a date - every cell started at a slightly
   different height and the row read as crooked. A cell with two lines in it centres as one
   block, which keeps it level with the single-line cells beside it. */
td { height: var(--row); padding:0 16px; border-bottom: 1px solid var(--line); white-space: nowrap; vertical-align: middle; }
/* A cell carrying a sentence rather than a figure. Figures, tickers and dates must stay on
   one line or a column of them stops lining up; prose has to be allowed to wrap, or a
   table with a sentence in it cannot fit the width it has been given and pushes its last
   column off the edge. */
/* The prose column takes whatever room the other columns leave, and breaks inside a word
   if it has to. Without the first the table sizes itself to the longest sentence in it and
   pushes its last column off the edge; without the second one long unbroken string does
   the same thing on its own. */

tr:last-child td { border-bottom: 0; }
tbody tr { transition: background var(--transition); }
tbody tr:hover { background: var(--surface-2); }

.chart-wrap svg { width: 100%; height: 330px; overflow: visible; }

/* The same group of glass the segmented control is, rather than a row of words on a rule.
   These pick between four views of one page, which is what a segmented control is for, and
   it was the only group of its kind on the site carrying no material at all. */
.tabs { display: inline-flex; max-width: 100%; padding:4px; background: var(--glass-control); box-shadow: var(--glass-control-rim); border-radius: var(--radius-pill); gap:2px; margin-bottom:20px; overflow-x: auto; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tabs button { flex: 0 0 auto; border: 0; border-radius: var(--radius-pill); background: transparent; color: var(--text-2); min-height: var(--control-height-compact); padding:0 var(--space-4); font-weight: 600; }
.tabs button.active { color: var(--text); background: var(--glass-control-raised); box-shadow: var(--glass-control-rim); }
.tabs button:hover { color: var(--text); }
.tabs button:active { transform: scale(.97); }

.announcement { padding:12px 0; border-top: 1px solid var(--line); }
.announcement:first-child { border-top: 0; }
.announcement h3 { margin:0 0 4px; font-size: var(--text-label); }
.announcement p { margin:0; color: var(--text-2); }
.announcement time { display: block; margin-top:4px; color: var(--text-3); font-size: var(--text-micro); }

.empty { border: 1px dashed var(--line-strong); border-radius: var(--radius-lg); padding:32px; text-align: center; color: var(--text-2); }
/* One heading, whichever tag carries it. A page with nothing on it uses an h1, because it
   is a page and needs a heading a screen reader can land on; a slot inside a card uses a
   strong, because the card already has the heading. They came out at 30 and 18 pixels in
   the same box, and the 30 was the browser's own default rather than a size off this
   site's scale at all. */
.empty h1, .empty strong { display: block; color: var(--text); font-size: var(--text-section); font-weight: 700; letter-spacing: var(--tracking-snug); margin:0 0 4px; }
.initial-load .empty { animation: initial-load-pulse 1.4s ease-in-out infinite alternate; }
@keyframes initial-load-pulse { from { opacity: .62; } to { opacity: 1; } }
:root[data-reduce-motion="true"] .initial-load .empty { animation: none; }
/* A page that turns somebody away still needs a heading, so the title of an empty state is
   a real one. It reads at the same size it always did. */

.notice.warning { background: var(--orange-soft); color: var(--orange); }

.setting-row { background: var(--glass-control); backdrop-filter: var(--glass-control-blur); -webkit-backdrop-filter: var(--glass-control-blur); box-shadow: var(--glass-control-rim); border-radius: var(--radius); padding: var(--space-4); display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: center; gap: var(--space-5); }
.setting-row strong { display: block; }
/* One width for the choosers down the right of the sheet. Each was sized to whichever of
   its own words happened to be selected, so four rows in a column started at 780, 810, 814
   and 817 and the edge you read down was ragged by thirty seven pixels. They finish on the
   same line as the switches under them and now they start on one too. */
.setting-row .select-field { width: 160px; }
.setting-row p { margin:2px 0 0; color: var(--text-3); font-size: var(--text-caption); }
.toggle { width: 44px; height: 26px; padding:2px; border-radius: var(--radius-pill); border: 0; background: var(--glass-control-raised); }
.toggle::before { content: ""; display: block; width: 22px; height: 22px; border-radius: 50%; background: white; box-shadow: 0 1px 4px rgba(0,0,0,.22); transition: transform var(--transition); }
.toggle.on { background: var(--green); }
.toggle.on::before { transform: translateX(18px); }


.overlay {
  position: fixed;
  inset: 0;
  z-index: var(--layer-search);
  background: var(--scrim);
  backdrop-filter: var(--scrim-blur);
  -webkit-backdrop-filter: var(--scrim-blur);
  display: grid;
  place-items: start center;
  padding: min(16vh, 130px) 18px 18px;
}
.search-panel {
  width: min(680px,100%);
  max-height: min(620px,76vh);
  border-radius: var(--radius-xl);
  background: var(--glass-strong);
  border: 1px solid var(--line);
  box-shadow: var(--glass-shadow), var(--glass-rim);
  overflow: hidden;
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}
.search-input-wrap { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap:12px; padding:12px 16px; border-bottom: 1px solid var(--line); }
.search-input-wrap svg { width: 21px; height: 21px; color: var(--text-3); }
.search-input-wrap input { border: 0; outline: 0; background: transparent; font-size: var(--text-card); min-width: 0; }
.search-results { overflow-y: auto; max-height: 500px; padding:8px; }
.search-result { display: grid; grid-template-columns: 1fr auto; gap:12px; padding:12px 12px; border-radius: var(--radius-sm); }
.search-result:hover, .search-result.active { background: var(--surface-2); }
.search-result strong, .search-result span { display: block; }
.search-result span { color: var(--text-3); font-size: var(--text-caption); margin-top:2px; }
.search-result em { font-style: normal; color: var(--text-3); font-size: var(--text-micro); text-transform: uppercase; letter-spacing: .06em; }

/* The Guide panel. One rule for the whole thing, so its size never depends on which
   definition the browser reads last. */
/* The Guide sits in the corner of the window, on its own island, the way the places sit
   in the middle of the foot of it on theirs. The island is only as big as the bead; the
   panel hangs off it and never changes where the bead is, so the bead does not move when
   the panel opens and there is no gap between them for a press to fall into. */
/* A wrapper that draws nothing. The bead and the panel are both pinned to the window in
   their own right, off the same two measurements, so they cannot drift apart. It used to
   position them, which meant a transform on it and a panel positioned against it, and a
   transform makes an ancestor that anything pinned inside it is pinned to instead of to
   the window. This exists to group them and to carry whether the Guide is open. */
/* The same bead as the one that folds the places away: same size, same glass, same rim,
   same colour. Two beads at the foot of the window that are made differently read as two
   unrelated controls, and they are the same kind of thing. */
/* Guide sits on the island, on the line above the pill and beside the bead that folds the
   pill away. It was pinned to the right-hand corner instead and given a measured lift so it
   could climb over the pill on a narrow window - which is what made it jump: the lift is
   either nothing or a whole island's height, so every width change, every fold and every
   page with a longer pill snapped it from one to the other. In the island there is nothing
   to measure, nothing to collide with, and it is in the same place everywhere. */
.guide-bead {
  position: fixed;
  right: var(--float-inset);
  bottom: var(--float-inset);
  z-index: calc(var(--layer-drawer) + 2);
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--glass-bar);
  box-shadow: var(--glass-shadow), var(--glass-rim);
  backdrop-filter: var(--glass-bar-blur);
  -webkit-backdrop-filter: var(--glass-bar-blur);
  color: var(--text-2);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.guide-bead svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; }
.guide-bead:hover { color: var(--text); }
/* One shape at a time. Shut it is a chat bubble, which says what pressing it opens. Open
   it is an arrow pointing down at itself, which says where pressing it puts the panel. */
.guide-bead-shut { display: none; }
.guide-bead[aria-expanded="true"] .guide-bead-open { display: none; }
.guide-bead[aria-expanded="true"] .guide-bead-shut { display: block; }
.guide-drawer {
  position: fixed;
  right: var(--float-inset);
  /* Clear of the island its bead is part of - the same line the messages clear it by, so
     a message and the panel never land on top of each other. */
  bottom: calc(var(--float-bottom) + var(--space-2));
  z-index: calc(var(--layer-drawer) + 1);
  width: min(390px, calc(100vw - var(--float-inset) * 2));
  /* Between the bead and the cards at the top of the window, and never past either. */
  height: min(590px, calc(100vh - var(--top-height) - var(--float-bottom) - var(--space-8)));
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--glass-strong);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  /* Out of the bead and back into it, rather than up from nowhere. */
  transform-origin: 100% 100%;
  transform: translateY(10px) scale(.96);
  opacity: 0;
  pointer-events: none;
  transition: transform var(--transition), opacity var(--transition), bottom var(--transition-slow);
}
.guide-drawer.open { transform: none; opacity: 1; pointer-events: auto; }
.guide-drawer header { display: flex; align-items: center; justify-content: space-between; padding:20px; border-bottom: 1px solid var(--line); }
.guide-drawer h2 { margin:0; font-size: var(--text-section); letter-spacing: -.035em; }
.popover {
  position: fixed;
  z-index: var(--layer-popover);
  top: calc(var(--island-bottom) + 8px);
  right: calc(var(--island-x) + 24px);
  width: min(370px,calc(100vw - 32px));
  max-height: 76vh;
  overflow-y: auto;
  background: var(--glass);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--glass-shadow), var(--glass-rim);
  padding:12px;
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}

.popover-section { padding:12px; }
.popover-section + .popover-section { border-top: 1px solid var(--line); }
.popover h3 { margin:0 0 8px; font-size: var(--text-label); }
.popover-menu { display: grid; gap:2px; }
/* The compact height, like every other control. Sized by its own padding these came out
   at 38, which is not a step on the scale and not what the button beside them in the same
   panel is. */
.popover-menu button, .popover-menu a {
  display: flex; align-items: center; min-height: var(--control-height-compact);
  border: 0; background: transparent; border-radius: var(--radius-sm);
  text-align: left; padding: 0 var(--space-3); width: 100%;
}
.popover-menu button:hover, .popover-menu a:hover { background: var(--surface-2); }

.modal-root:not(:empty) { position: fixed; inset: 0; z-index: var(--layer-modal); display: grid; place-items: center; padding:20px; background: var(--scrim); backdrop-filter: var(--scrim-blur); -webkit-backdrop-filter: var(--scrim-blur); }
.modal { width: min(520px,100%); max-height: 88vh; overflow-y: auto; background: var(--glass-strong); border: 1px solid var(--line); border-radius: var(--radius-xl); box-shadow: var(--glass-shadow), var(--glass-rim); padding:24px; }
.modal-open { overflow: hidden; }

.modal p { color: var(--text-2); margin: 0 0 var(--space-4); }
.modal .field { min-width: 0; }
.modal .settings-grid { margin-top: var(--space-4); }
.modal-actions { display: flex; justify-content: flex-end; gap:8px; margin-top:20px; }

/* The region is a lane for messages, not a surface. It is pinned above everything and it
   is usually empty, so without this it silently swallowed every tap in the bottom right
   corner: on a phone that is the whole navigation bar. Only the messages themselves take
   a pointer, and they only exist while there is something to say. */
/* Messages arrive in the bottom left, because the bottom right is taken. The trade ticket
   is a tall sticky column down the right of a company page and the Guide panel opens into
   the same corner, so a message landing there sat on the quantity box you had just typed
   in. The left is the one corner with nothing pinned to it. On a phone there are no
   columns, so it spans the width above the bar instead. */
.toast-region { position: fixed; left: 18px; bottom: calc(var(--float-bottom) + var(--space-2)); z-index: var(--layer-toast); display: grid; gap:8px; width: min(360px,calc(100vw - 36px)); pointer-events: none; }
.toast-region > * { pointer-events: auto; }
/* The same material as everything else that floats over the page, and the same way round.
   It used to be inverted - light on a dark site and dark on a light one - which is a
   convention borrowed from products that have one theme, and here it read as a panel from
   somebody else's website landing on this one. It follows the theme now, the way the tour
   card and the Guide panel beside it always have. */
.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  background: var(--glass-strong);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--space-3) var(--space-4);
  box-shadow: var(--glass-shadow), var(--glass-rim);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  animation: toast-in 200ms ease-out;
}
.toast-words { min-width: 0; flex: 1; }
.toast strong { display: block; font-size: var(--text-small); overflow-wrap: anywhere; }
.toast span { display: block; margin-top:2px; font-size: var(--text-micro); color: var(--text-2); overflow-wrap: anywhere; }
/* A message that stays says so before it is read: the same crimson that marks a change to
   somebody's account, down the edge it is read from. */
.toast-stays { border-left: 3px solid var(--crimson); padding-left: calc(var(--space-4) - 4px); }
/* The X on a message is the X everywhere else on the site: .icon-button carries the round
   36px shape, the hover and the press, and this adds only the pull into the corner so the
   words keep the width. It had been drawn here a second time at 24px with a tinted ring of
   its own, which made the smallest tap target on the site out of the one control every
   message carries. */
.toast-close { flex: 0 0 auto; margin: -4px -6px 0 0; color: inherit; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px) scale(.98); } }

.walkthrough-root:not(:empty) { position: fixed; inset: 0; z-index: var(--layer-tour); pointer-events: none; }
/* The wash over the page, drawn as four panes around the hole rather than as one shadow
   spread out from the highlighted thing. A shadow is clipped by any ancestor that clips,
   and the tape lives inside a card with overflow clip, so on a phone the wash was cut down
   to the inside of that card: the page behind it was never dimmed and a dark band appeared
   across the strip instead. The panes are the tour's own, so nothing on the page can cut
   them, and pressing any of them leaves the tour. Their positions are set as the step is
   drawn, in window coordinates. */
.walkthrough-dim { position: fixed; inset: 0; background: transparent; pointer-events: auto; z-index: var(--layer-tour); }
.walkthrough-dim span { position: fixed; background: rgba(0,0,0,.62); }
/* The ring around what is being pointed at. Its corner is copied from the thing itself, so
   it never draws a rounded box around a square button or a square one around a pill. */
.walkthrough-ring { position: fixed; z-index: calc(var(--layer-tour) + 1); pointer-events: none; box-shadow: 0 0 0 3px var(--blue); }
.walkthrough-target { position: relative; z-index: calc(var(--layer-tour) + 1) !important; }
.walkthrough-card { position: fixed; left: 50%; bottom: calc(var(--float-bottom) + var(--space-3)); transform: translateX(-50%); z-index: calc(var(--layer-tour) + 2); width: min(420px,calc(100vw - 30px)); background: var(--glass-strong); border: 1px solid var(--line); border-radius: var(--radius-lg); padding:16px; box-shadow: var(--glass-shadow), var(--glass-rim); pointer-events: auto; }
/* Room at the foot of the page for the card, so nothing ends up stranded beneath it. The
   measure is published by the page as the card is drawn, because the card's height depends
   on how long its words are and on the reader's text size. */
body.tour-showing { padding-bottom: calc(var(--tour-height) + 56px); }
/* And on a phone it sits above the bar along the bottom rather than on top of it. The bar
   is how you leave the page; covering it leaves somebody who does not want a tour with
   nothing to press but the card. */
@media (max-width: 980px) {
  body.tour-showing { padding-bottom: calc(var(--float-bottom) + var(--tour-height) + 40px); }
  .walkthrough-card { left: var(--island-side); right: var(--island-side); width: auto; transform: none; bottom: var(--float-bottom); }
}
.walkthrough-card h3 { margin:0 0 4px; }
.walkthrough-card p { margin:0; color: var(--text-2); }
/* One row of moves, then the way out on a line of its own beneath it.
   The three buttons used to share one row, weighted apart, and the row wrapped on a narrow
   card: "Do not show again" dropped to its own line and left the other two hanging off the
   right edge with nothing under them. Two rows of full width buttons cannot wrap, so the
   card reads the same at every width and at every text size, and moving on and giving up
   are never next to each other under the same thumb. */
.walkthrough-actions { display: grid; gap: var(--space-2); margin-top: var(--space-4); }
.walkthrough-move { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: var(--space-2); }
/* Every button in the card is the same height and its words sit in the middle of it. The
   quiet one is the compact height everywhere else on the site, which under a full width
   button eight pixels taller read as a mistake rather than as a lesser choice. */
.walkthrough-actions .quiet-button { height: var(--control-height); justify-content: center; }
/* The offer and the tour are the same card, so they are the same width. They were 460 and
   420, which is close enough that nobody could name it and far enough that the card
   visibly changed size the moment you said yes. */

.admin-nav button:hover { background: var(--glass-control-raised); color: var(--text); }
.admin-nav button.on { background: var(--glass-control-raised); color: var(--text); font-weight: 650; }

/* What happened, laid out as a record rather than a paragraph, so the dates and the
   length can be read at a glance instead of hunted for in a sentence. */
.suspension-facts {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-5) 0 var(--space-4);
  text-align: left;
  width: 100%;
}
.suspension-facts > div {
  display: grid;
  grid-template-columns: minmax(96px, 34%) 1fr;
  gap: var(--space-2) var(--space-4);
  align-items: baseline;
  padding: var(--space-2) 0;
  border-top: 1px solid var(--line);
}
.suspension-facts dt { color: var(--text-3); font-size: var(--text-caption); font-weight: 650; text-transform: uppercase; letter-spacing: .05em; }
.suspension-facts dd { margin:0; color: var(--text); font-size: var(--text-small); overflow-wrap: anywhere; }
/* Centred, but never at the cost of the content.
   place-content: center on a grid taller than the window overflows in both directions, and
   the overflow above the top cannot be scrolled to - so the warning page, which is long
   enough to carry every rule, had its head cut off and its foot under the island. `safe`
   is the keyword for exactly this: centre while it fits, and fall back to the start when it
   does not. The foot also leaves room for the island now, the way .page does, so the last
   thing on the page can be read and pressed instead of being sat on. */
.suspension {
  max-width: 640px; margin: 0 auto; min-height: 100vh;
  display: grid; place-content: safe center; text-align: center;
  padding: var(--space-8) var(--space-6) calc(var(--dock-height) + var(--space-6));
}
/* A suspended account sees one page and nothing else. Every way off it is removed, so
   signing out is the only thing left to do. */
body.is-suspended .topbar,
body.is-suspended .footer,
body.is-suspended .skip-link,
body.is-suspended .guide-drawer,
body.is-suspended .popover,
body.is-suspended .overlay,
body.is-suspended .drawer-backdrop { display: none !important; }
.suspension .brand-mark { width: 44px; height: 44px; margin:0 auto 20px; }
.suspension .brand-mark svg { width: 44px; height: 44px; }
.suspension h1 { font-size: var(--text-title); letter-spacing: var(--tracking-tight); margin:12px 0 0; }
.suspension p { color: var(--text-2); margin:12px 0 0; }
.suspension-actions { display: flex; justify-content: center; gap:12px; margin:24px 0 16px; }
/* Agreeing to something, in the two places that ask: a warning somebody has to read, and
   the switch that decides whether a trader is told who acted. One row, the box against the
   words, and a target big enough to press without aiming. */
.agree-row {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--glass-control);
  box-shadow: var(--glass-control-rim);
  cursor: pointer;
  transition: border-color var(--transition);
}
.agree-row:hover { border-color: var(--line-strong); }
.agree-row:focus-within { border-color: var(--blue); }
.agree-row input { margin-top: 2px; width: 18px; height: 18px; accent-color: var(--blue); flex: 0 0 auto; }
.agree-row span { font-size: var(--text-small); color: var(--text-2); overflow-wrap: anywhere; }
.modal .agree-row { margin-top: var(--space-4); }

/* The rules, on the page that asks somebody to agree to them, because there is nowhere
   else they can go from here. */
.rules-recap { text-align: left; width: 100%; margin: var(--space-4) 0 var(--space-5); }
.rules-recap h2 { font-size: var(--text-card); margin: 0 0 var(--space-3); }
.rules-recap dl { display: grid; gap: var(--space-2); margin: 0; }
.rules-recap dl > div { padding: var(--space-2) 0; border-top: 1px solid var(--line); }
.rules-recap dt { font-size: var(--text-small); font-weight: 650; color: var(--text); }
.rules-recap dd { margin: 2px 0 0; font-size: var(--text-caption); color: var(--text-2); overflow-wrap: anywhere; }

:root[data-reduce-motion="true"] *, :root[data-reduce-motion="true"] *::before, :root[data-reduce-motion="true"] *::after { scroll-behavior: auto !important; animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }

/* Market state colours. A closed market is a normal condition, so it reads as calm and
   neutral. Only a halt, which is an interruption, uses a warning colour. */
.strip-status.status-open { background: var(--green-soft); color: var(--green); }
.strip-status.status-closed { background: var(--surface-3); color: var(--text-2); }
.strip-status.status-preopen { background: var(--blue-soft); color: var(--blue); }
.strip-status.status-halted { background: var(--orange-soft); color: var(--orange); }
.market-strip-track {
  display: flex;
  width: max-content;
}
.strip-tape::-webkit-scrollbar { display: none; }
.strip-tape:active { cursor: grabbing; }
/* A row that scrolls sideways fades on the side it can still be pushed toward. The two
   lengths are set by web/edges.ts and are zero while there is nothing more to see, so a
   row short enough to fit keeps its first and last item whole. */
[data-scroller] {
  --edge-start: 0px;
  --edge-end: 0px;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--edge-start), #000 calc(100% - var(--edge-end)), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 var(--edge-start), #000 calc(100% - var(--edge-end)), transparent 100%);
}
/* The same question asked downward, on a panel taller than the window. A settings sheet
   was cut off wherever the window happened to end: at 1440 by 900 that landed halfway
   through "Higher contrast", heading showing and its explanation sliced through the
   middle, with no sign at all that four more settings sat under it. */
[data-scroller-down] {
  --edge-top: 0px;
  --edge-bottom: 0px;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 var(--edge-top), #000 calc(100% - var(--edge-bottom)), transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0, #000 var(--edge-top), #000 calc(100% - var(--edge-bottom)), transparent 100%);
}
.market-strip-set { display: flex; align-items: center; gap:24px; padding:0 12px; }
/* Two identical sets sit side by side, so the run loops seamlessly: web/ticker.ts moves the
   tape's own scrollLeft and wraps at one set's length. It was a CSS animation once, and the
   keyframes outlived it by long enough to be the only thing in this file nothing used. */

.site-banner {
  padding: var(--space-2) var(--space-5);
  font-size: var(--text-small);
  font-weight: 650;
  text-align: center;
}
/* Only the tint, because the header behind it is already the glass. Painting a second
   wash here is what made the banner read as a solid strip of colour. */
.site-banner.severity-green { background: color-mix(in srgb, var(--green) 30%, var(--surface-solid)); color: var(--green); }
.site-banner.severity-yellow { background: color-mix(in srgb, var(--yellow) 32%, var(--surface-solid)); color: var(--yellow); }
.site-banner.severity-orange { background: color-mix(in srgb, var(--orange) 31%, var(--surface-solid)); color: var(--orange); }
.site-banner.severity-red { background: color-mix(in srgb, var(--red) 30%, var(--surface-solid)); color: var(--red); }
.site-banner-inner { display: inline-flex; align-items: center; gap: var(--space-2); justify-content: center; text-align: left; }
.site-banner-icon {
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
}

:root[data-reduce-motion="true"] .drawer-backdrop { position: fixed; inset: 0; z-index: var(--layer-drawer); background: rgba(0,0,0,.22); display: none !important; }

.accessibility-popover { right: calc(var(--island-x) + 150px); }
/* A label and its control, side by side while both fit and stacked when they do not.
   The control used to get whatever was left of a fixed two column grid, so Small, Default
   and Large needed 210 pixels and were given 198 at every width, and "Large" was cut in
   half in every panel on every screen. At 320 pixels the control column was 116 and all
   three rows were cut, so on the narrowest phone still sold you could not read any of the
   choices you were being asked to make. The control cannot be squeezed now: where the two
   of them do not fit on a line, it takes a line of its own. */
/* The quick panel in the header. Its settings are the Settings sheet's settings, under the
   same names and in the same order, so learning one is learning both. The groups here are
   headings rather than a run of rows, because six choices with nothing between them read
   as a list of six unrelated things. */
.quick-settings > h3 {
  margin: var(--space-5) 0 var(--space-2); padding-top: var(--space-4);
  border-top: 1px solid var(--line);
  font-size: var(--text-micro); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-2);
}
.quick-settings > h3:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.quick-setting { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap: var(--space-3); margin: var(--space-3) 0; }
/* The label and the line that says what the setting does, together. The help for three of
   these used to be one paragraph at the foot of the panel covering all three at once, so
   the sentence about animations sat four rows from the switch it was describing. */
.quick-setting > .quick-label { flex:1 1 132px; display:grid; gap:2px; min-width:0; }
.quick-hint { font-size: var(--text-micro); line-height:1.4; color: var(--text-3); }
/* A row of pills takes its own line, every time. Sized to its content, Theme and Text and
   spacing were too wide to sit beside their label and wrapped, while Time format was narrow
   enough to stay inline - so three rows doing the same job were laid out two ways. */
.quick-setting > .segmented { flex:1 0 100%; }
.quick-setting > .toggle { flex:0 0 auto; }
.quick-settings > .secondary-button { margin-top: var(--space-5); width:100%; }

/* The foot of the page is a card like everything else on the site, on the same material
   and between the same two edges. It used to run the full width of the window with a
   square top edge, which under a page made of floating cards looked like the page had
   fallen off the bottom of its own layout. */
/* The island floats over the foot of the window, so the last thing on the page has to end
   above it. The page leaves that room already; the footer sits outside the page and did
   not, so the island grew from one row to two and came down on the footer's own links. */
.footer {
  margin-top: var(--space-12);
  padding: var(--space-8) 0 var(--space-10);
  background: var(--surface-2);
  border-top: 1px solid var(--line);
  color: var(--text-3);
  font-size: var(--text-caption);
}
/* Apple's footer: the small print, then columns of links under their own headings, then a
   hairline and one quiet line. It was a rounded glass card holding a name and a flat row
   of every place on the site. */
.footer-inner {
  width: 100%;
  max-width: var(--content);
  margin: 0 auto;
  padding: 0 var(--space-5);
  display: grid;
  gap: var(--space-6);
}
.footer-note { margin: 0; max-width: 78ch; line-height: 1.5; }
.footer-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-6);
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--line);
}
.footer-column { display: grid; gap: 6px; align-content: start; min-width: 0; }
.footer-column h2 { margin: 0 0 2px; font-size: var(--text-caption); font-weight: 620; color: var(--text); }
.footer-column a { color: var(--text-3); text-decoration: none; }
.footer-column a:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.footer-legal { display: flex; flex-wrap: wrap; gap: var(--space-4); }
 

/* ==========================================================================
   Company marks
   Adaptive follows the theme. The two mono styles stay fixed in both themes.
   ========================================================================== */

.logo-mark {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-mark);
  display: grid;
  place-items: center;
  font-size: var(--text-micro);
  font-weight: 800;
  letter-spacing: -.02em;
  flex: 0 0 auto;
  overflow: hidden;
  user-select: none;
}
.logo-mark.logo-large { width: 54px; height: 54px; font-size: var(--text-card); }
.logo-adaptive { background: var(--text); color: var(--bg); }
.logo-mono-dark { background: #ffffff; color: #000000; box-shadow: inset 0 0 0 1px rgba(0,0,0,.14); }
.logo-mono-light { background: #000000; color: #ffffff; box-shadow: inset 0 0 0 1px rgba(255,255,255,.16); }
.logo-brand { background: var(--blue); color: #ffffff; }
.logo-image { overflow: hidden; padding:0; background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line); }
.logo-image img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* ==========================================================================
   Chart
   ========================================================================== */

.chart-toolbar-right { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }


/* Every control in the chart toolbar sits on the same baseline. */
.range-control button { min-width: 40px; height: var(--control-height-compact); box-sizing: border-box; }

/* Pressed is said by the material, not by the weight. Going a step heavier on selection
   made the word wider, so pressing one toggle nudged every toggle beside it along the row,
   which is movement a person did not ask for and cannot undo by looking away. */

.chart-tools { display: flex; gap:4px; flex-wrap: wrap; }
.chart-tools-right { display: flex; align-items: center; gap:4px; flex-wrap: wrap; }

/* A tool button that holds a symbol rather than a word, and nothing else. It used to take
   a larger type step and drop its side padding, so the two zoom buttons were a different
   size and shape from the Fit button sitting between them, in the same group of three. It
   keeps only the floor on its width, which is what makes a symbol big enough to press. */

.chart-wrap { min-height: 300px; display: grid; place-items: stretch; margin:0; overflow: hidden; position: relative; height: 340px; width: 100%; }
.chart-canvas { display: block; width: 100%; height: 100%; touch-action: pan-y; }

.chart-empty { color: var(--text-3); display: grid; place-items: center; height: 100%; }

body.chart-locked { overflow: hidden; }

/* ==========================================================================
   Stock page
   ========================================================================== */

.status-pill {
  display: inline-flex;
  align-items: center;
  padding:4px 8px;
  border-radius: var(--radius-pill);
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
}
.status-active, .status-filled, .status-approved { background: var(--green-soft); color: var(--green); }
.status-delisted, .status-canceled, .status-rejected { background: var(--red-soft); color: var(--red); }
.status-partially_filled, .status-pending, .status-submitted, .status-under_review { background: var(--blue-soft); color: var(--blue); }
.status-archived { background: var(--surface-3); color: var(--text-2); }
.tag {
  display: inline-block;
  padding:2px 8px;
  border-radius: var(--radius-pill);
  background: var(--surface-3);
  color: var(--text-2);
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: none;
}

@keyframes tick-flash-up { from { color: var(--green); } to { color: inherit; } }
@keyframes tick-flash-down { from { color: var(--red); } to { color: inherit; } }

/* Holding none of this company is a state of the strip, not a different kind of text. It
   used to borrow the .subtle role to go grey, and took that role's argument about its own
   size along with the colour, so on a narrow screen the two disagreed. */

/* The chart and the trade panel sit side by side while there is room for both, and the
   panel drops underneath when there is not. This is measured from the space actually
   available rather than from the window width, because zooming the browser shrinks the
   former and leaves the latter alone. That mismatch used to squeeze the chart into a
   sliver at high zoom. */

/* The fill sits behind the row as a background bar, so it must stay out of the grid
   flow. The selector is scoped to beat the generic span rule below it. */

@keyframes live-pulse { 50% { opacity: .35; } }

/* ==========================================================================
   Trade panel
   ========================================================================== */

/* ==========================================================================
   Portfolio
   ========================================================================== */

/* ==========================================================================
   News
   ========================================================================== */

/* What kind of thing, what it is tagged, and a box to search the lot. Most of this feed is
   company results published a minute at a time, so a reader looking for anything else was
   scrolling past forty of them. */

/* ==========================================================================
   Notifications
   ========================================================================== */

.notifications-popover { right: calc(var(--island-x) + 104px); width: min(400px, calc(100vw - 24px)); }
/* The title and its two actions. On a narrow popover the actions used to wrap a word at
   a time, so "Mark all read" became two ragged lines sitting over the title beside it.
   They keep their own line instead, which is the same shape at every width. */
.popover-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-2); flex-wrap: wrap; row-gap: var(--space-2); }
.popover-head h3 { margin:0; display: flex; align-items: center; gap: var(--space-2); }
.popover-head-actions { display: flex; gap:2px; flex: 0 0 auto; margin-left: auto; }
.popover-head-actions .quiet-button { white-space: nowrap; }
.count-pill { background: var(--blue); color: #fff; border-radius: var(--radius-pill); padding:2px 8px; font-size: var(--text-micro); font-weight: 700; }
.notification-list { display: grid; gap:2px; max-height: 60vh; overflow-y: auto; margin:0 -8px; }
/* No padding of its own: the link inside carries all of it, so every pixel the hover
   lights up is a pixel that opens the notice. With padding on both, a 12px ring around
   each row highlighted under the pointer and did nothing when clicked. */
.notification-item { display: block; border-radius: var(--radius-xs); position: relative; }
.notification-item:hover { background: var(--surface-2); }
.notification-item > a, .notification-item > .notification-body { display: grid; gap:4px; padding:12px 44px 12px 12px; }
.notification-item.unread > a { border-left: 3px solid var(--blue); padding-left:8px; }
.notification-kind { font-size: var(--text-micro); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--text-3); }
.notification-item strong { display: block; font-size: var(--text-small); }
.notification-item span { display: block; color: var(--text-2); font-size: var(--text-caption); margin-top:2px; }
.notification-item time { display: block; color: var(--text-3); font-size: var(--text-micro); margin-top:4px; }
/* Removing a notice was a word that only appeared under a pointer, so on a touch screen -
   where there is no hover - there was no way to see that a notice could be removed at all.
   It is the site's X now, and it is always there. It fades toward the text on hover rather
   than in from nothing, so it reads as quiet without being hidden. */
.notification-dismiss {
  position: absolute;
  top: 6px;
  right: 6px;
  color: var(--text-3);
  opacity: .55;
  transition: opacity var(--transition), background var(--transition), color var(--transition);
}
.notification-item:hover .notification-dismiss, .notification-dismiss:focus-visible { opacity: 1; }
.notification-dismiss:hover { background: var(--surface-3); color: var(--text); opacity: 1; }
.notification-dismiss svg { width: 13px; height: 13px; }
/* The count sits on the bell, so an unread notice is visible without opening anything.
   It carries the number rather than only a colour, which is what makes it readable for
   someone who cannot separate the red from the grey. */
.notification-dot {
  position: absolute;
  top: -1px;
  right: -2px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-pill);
  background: var(--red);
  color: #fff;
  font-size: var(--text-micro);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  line-height: 1;
  box-shadow: 0 0 0 2px var(--bg);
}
.icon-button.has-unread svg { color: var(--text); }

/* ==========================================================================
   Guide chat
   ========================================================================== */

.guide-message ul { margin:8px 0; padding-left:20px; }
.guide-message li { margin:4px 0; }

.guide-message.pending p { display: flex; align-items: center; min-height: 20px; }
.typing { display: inline-flex; gap:4px; }
.typing i { width: 6px; height: 6px; border-radius: 50%; background: var(--text-3); animation: typing-bounce 1.2s infinite ease-in-out; }
.typing i:nth-child(2) { animation-delay: .15s; }
.typing i:nth-child(3) { animation-delay: .3s; }
@keyframes typing-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .45; } 30% { transform: translateY(-4px); opacity: 1; } }
:root[data-reduce-motion="true"] .typing i { animation: none; }

/* ==========================================================================
   Shared bits
   ========================================================================== */

.card-header > div:first-child { min-width: 0; }

/* A price and a share count read down this list against a name and a date, so the digits
   are held to one width like every other figure on the site. Left proportional, the price
   was the one number on the panel whose columns did not line up with anything. */

.notice { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; border-radius: var(--radius-sm); padding: var(--space-3) var(--space-4); background: var(--blue-soft); color: color-mix(in srgb, var(--blue) 75%, var(--text)); margin-bottom: 0; font-size: var(--text-small); }
.notice strong { display: block; }
.notice span { display: block; margin-top: var(--space-1); }
.notice > div { min-width: 0; }

.notice.danger { background: var(--red-soft); color: var(--red); }

/* On a narrow screen the nine range buttons are wider than the viewport, so the
   control scrolls inside itself instead of stretching the page. */
.range-control, .chart-tools, .chart-tools-right, .chart-toolbar-right {
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior-x: contain;
}
.range-control::-webkit-scrollbar, .chart-tools::-webkit-scrollbar, .chart-tools-right::-webkit-scrollbar, .chart-toolbar-right::-webkit-scrollbar { display: none; }
.range-control button, .chart-tools button { flex: 0 0 auto; white-space: nowrap; }
.chart-toolbar { display: flex; align-items: center; justify-content: space-between; gap:12px; flex-wrap: wrap; min-width: 0; max-width: 100%; }

/* Owner reset */
/* The two that empty the board or put every setting back are marked out from the ones
   that clear a session, because they are a different kind of decision. */

/* The usual answer to a row of boxes, offered as something to press rather than as
   something already ticked. */

/* The one currently showing is marked the way a chosen thing is marked everywhere else. */

/* Mode pickers show which option is selected rather than colouring one option
   differently from the rest. A paused market is the one state that earns a warning
   colour, because it is an interruption and not a normal setting. */

/* ==========================================================================
   Type scale
   Applied last so every page shares one rhythm. Sizes come from the tokens at
   the top of this file rather than being set per component.
   ========================================================================== */

.card-header h2, .card > h2 { font-size: var(--text-card); font-weight: 650; letter-spacing: var(--tracking-snug); line-height: 1.25; }
.card h3, .announcement h3 { font-size: var(--text-sub); font-weight: 650; letter-spacing: var(--tracking-snug); }

/* One definition for the muted helper text, instead of five sizes across the site. */
.subtle { color: var(--text-3); font-size: var(--text-small); }
.muted { color: var(--text-3); }
.eyebrow { display: block; color: var(--text-3); text-transform: uppercase; letter-spacing: .08em; font-size: var(--text-micro); font-weight: 700; margin-bottom:4px; }

/* Figures share a scale so a number never looks louder than the number beside it. */
.metric strong { display: block; font-size: var(--text-figure); letter-spacing: var(--tracking-snug); font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; font-weight: 650; }
.metric span { display: block; color: var(--text-3); font-size: var(--text-caption); margin-bottom:4px; }

.modal h2 { font-size: var(--text-section); font-weight: 680; letter-spacing: var(--tracking-snug); margin: 0; }

/* Duration picker, used instead of a raw date and time field */

.mono { font-variant-numeric: tabular-nums; font-size: var(--text-caption); color: var(--text-2); }

/* Higher contrast. Strengthens separators and lifts muted text so it clears the
   4.5 to 1 ratio, without changing the layout or the palette people already know. */
:root[data-contrast="high"] {
  --line: rgba(0,0,0,.28);
  --line-strong: rgba(0,0,0,.44);
  --text-2: #35353a;
  --text-3: #4a4a50;
  --green: #0f6b2e;
  --red: #a8231f;
  --crimson: #66101f;
  --blue: #0059b3;
}
:root[data-contrast="high"][data-theme="dark"] {
  --line: rgba(255,255,255,.34);
  --line-strong: rgba(255,255,255,.52);
  --text-2: #e6e6ea;
  --text-3: #c2c2c8;
  --green: #4ce065;
  --red: #ff6a60;
  --crimson: #e08791;
  --blue: #64b5ff;
}
:root[data-contrast="high"] .card,
:root[data-contrast="high"] .metric,
:root[data-contrast="high"] .select-field{ border-width: 1.5px; }
:root[data-contrast="high"] :focus-visible { outline-width: 3px; outline-offset: 3px; }


/* A grid item defaults to a minimum width of its content, so a wide control inside a
   card can push the card past its column. These let cards shrink and their headers
   wrap instead. */
/* Every box a page is built out of, on one material. Written once, in one place, so a
   card on the home page and a table on the Admin panel cannot drift apart.

   The blur goes on the box, never on the rows inside it: a table of twenty five rows
   each blurring its own backdrop is twenty five compositing layers for one picture, and
   the second blur would be working on the first one's output anyway. */
.admin-nav, .empty {
  background: var(--glass-panel);
  backdrop-filter: var(--glass-panel-blur);
  -webkit-backdrop-filter: var(--glass-panel-blur);
}
.card {
  background: var(--glass-panel);
  backdrop-filter: var(--glass-panel-blur);
  -webkit-backdrop-filter: var(--glass-panel-blur);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--card-pad);
  box-shadow: var(--glass-rim), 0 1px 2px rgba(0,0,0,.03);
  min-width: 0;
  /* The page owns the distance between one card and the next, so a card never adds its
     own and two cards from different pages are never a different distance apart. */
  margin-bottom: 0;
}
.card-header { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); margin-bottom: var(--space-5); flex-wrap: wrap; row-gap: var(--space-2); }
.segmented.small { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.segmented.small::-webkit-scrollbar { display: none; }
.segmented.small button { padding:4px 8px; font-size: var(--text-caption); flex: 0 0 auto; }

/* Company marks size their text to the length of the ticker so a four letter symbol
   still fits the same square as a two letter one. */
.logo-len-2 { font-size: var(--text-micro); letter-spacing: -.01em; }
/* A company's mark is a square of a fixed size with its symbol lettered inside. The
   letters are sized to the square, not to the scale, so a longer symbol still fits. */
.logo-len-3 { font-size: 10.5px; letter-spacing: -.02em; }
/* Four wide letters are the worst case: WWER at ten pixels is three wider than the square
   it has to sit in, and a mark that spills is a mark sitting on the name beside it. */
.logo-len-4 { font-size: 8.5px; letter-spacing: -.06em; }
.logo-large.logo-len-2 { font-size: var(--text-card); }
.logo-large.logo-len-3 { font-size: 15px; }
.logo-large.logo-len-4 { font-size: 13px; }

/* Sector cards lead with the sector name, then its move, then the volume footnote. */

/* The index sits in the ticker beside the companies, so it gets its own accent to make
   clear it is an aggregate rather than a listing you can trade. */
a.strip-index:hover { opacity: 1; }
a.strip-index:hover strong { text-decoration: underline; text-underline-offset: 3px; }

/* ==========================================================================
   Guide chat
   ========================================================================== */

.guide-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap:12px;
  padding:16px 16px 16px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
  flex: 0 0 auto;
}
.guide-identity { display: flex; align-items: center; gap:12px; min-width: 0; }
.guide-avatar {
  width: 34px;
  height: 34px;
  border-radius: var(--radius-mark);
  display: grid;
  place-items: center;
  background: var(--blue);
  color: #fff;
  font-weight: 700;
  font-size: var(--text-body);
  flex: 0 0 auto;
}
.guide-identity h2 { margin:0; font-size: var(--text-body); font-weight: 650; letter-spacing: var(--tracking-snug); }
.guide-provider { display: block; font-size: var(--text-micro); color: var(--text-3); line-height: 1.3; }
.guide-provider-warn { color: var(--orange); font-weight: 600; }
.guide-header-actions { display: flex; gap:2px; flex: 0 0 auto; }
.guide-header-actions .quiet-button { white-space: nowrap; }

.guide-messages { overflow-y: auto; padding:16px; display: flex; flex-direction: column; gap:12px; flex: 1 1 auto; scroll-behavior: smooth; }
:root[data-reduce-motion="true"] .guide-messages { scroll-behavior: auto; }

.guide-message { max-width: 88%; padding:12px 16px; border-radius: var(--radius); background: var(--surface-2); font-size: var(--text-label); line-height: 1.45; align-self: flex-start; border-bottom-left-radius: 5px; }
.guide-message.user { align-self: flex-end; background: var(--blue); color: #fff; border-bottom-left-radius: 16px; border-bottom-right-radius: 5px; }
.guide-message p { margin:0; }
.guide-message p + p { margin-top:8px; }
.guide-message.user .subtle, .guide-message.user code { color: rgba(255,255,255,.82); }
.guide-message code { background: var(--surface-3); padding:2px 4px; border-radius: var(--radius-xs); font-size: var(--text-caption); }
.guide-welcome { background: transparent; padding:4px 0; max-width: 100%; }
.guide-notice { margin:8px 0 0; font-size: var(--text-caption); color: var(--text-3); font-style: italic; padding-top:8px; border-top: 1px solid var(--line); }

/* Something the panel wants to say. Plain by default, because most of what it has to say
   is an offer rather than an alarm, and orange on this site means a fault somebody can do
   something about. Only a model that will not answer gets that colour. */
.guide-setup-notice {
  display: grid;
  gap:4px;
  padding:12px 16px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: var(--text-caption);
  line-height: 1.4;
}
.guide-setup-notice.is-problem { background: var(--orange-soft); color: var(--orange); }
.guide-setup-notice strong { font-size: var(--text-small); }
.guide-setup-notice a { text-decoration: underline; text-underline-offset: 2px; font-weight: 600; }

.guide-form { flex: 0 0 auto; padding:12px 16px 16px; border-top: 1px solid var(--line); background: var(--surface-2); }
.guide-compose {
  display: flex;
  align-items: flex-end;
  gap:8px;
  padding:8px 8px 8px 16px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  background: var(--surface-solid);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.guide-compose:focus-within { border-color: var(--blue); box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 16%, transparent); }
.guide-compose textarea {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  resize: none;
  outline: none;
  font-size: var(--text-label);
  line-height: 1.45;
  padding:8px 0;
  max-height: 140px;
}
.guide-compose-actions { display: flex; align-items: center; gap:4px; flex: 0 0 auto; }
.guide-send {
  width: var(--control-height-compact);
  height: var(--control-height-compact);
  border-radius: 50%;
  display: grid;
  place-items: center;
  border: 0;
  cursor: pointer;
  flex: 0 0 auto;
  background: var(--blue);
  color: #fff;
}
.guide-send:hover { background: var(--blue-hover); }
.guide-send svg { width: 16px; height: 16px; }
.guide-compose-footer { display: flex; justify-content: space-between; gap:12px; margin-top:8px; font-size: var(--text-micro); }

/* Three dots. A square the same height as the buttons beside it, so a row of actions has
   one baseline whether the last thing on it is a word or a menu. */

/* The dropdown that opens under a button. Drawn in a layer of its own at the end of the
   page, because a row lives in a table that scrolls sideways and anything drawn inside one
   is cut off at the edge of that scroll. */
/* Above everything. A menu can be opened from a table, from a sheet, or from a panel that
   is itself floating, and it has to sit over whichever of those it came from. Only the
   skip link, which exists to be reachable before anything else, goes higher. */
.menu-layer { position: fixed; inset: 0; z-index: var(--layer-menu); pointer-events: none; }
.menu-panel {
  position: fixed;
  min-width: 200px;
  max-width: min(300px, calc(100vw - 16px));
  display: grid;
  gap: 2px;
  padding: var(--space-2);
  /* The same corner, the same wash and the same blur as the panel that opens from the
     button beside it. It was the one surface on the site made of --glass-strong, which is
     86 per cent of the paper colour: the most solid thing on a site built out of glass,
     and carrying a 16 pixel corner among 22s. */
  border-radius: var(--radius-lg);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--line);
  box-shadow: var(--glass-shadow), var(--glass-rim);
  pointer-events: auto;
  /* A long list of choices scrolls rather than running off the screen, and says so at the
     edge it can still be pushed toward, the same way every other panel does. */
  max-height: min(60vh, 420px);
  overflow-y: auto;
  scrollbar-width: none;
}
.menu-panel::-webkit-scrollbar { display: none; }
.menu-item {
  display: flex;
  align-items: center;
  min-height: var(--control-height-compact);
  gap: var(--space-3);
  padding: 0 var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-size: var(--text-small);
  font-weight: 600;
  text-align: left;
  white-space: nowrap;
}
/* The question a group of choices answers, above them. Without it, "All", "Trading" and
   "Paused" one after another say nothing about what they are all. */
/* Inset to the line the rows under it start on, so a heading and its choices begin
   together. One group is separated from the last by the space above its heading. */
/* The heading that starts a group of choices, and the line that separates it from the
   group above.

   Markets asks two different questions from one button - a status and a sector - and the
   menu had them labelled but not divided: the headings were set in the faintest colour on
   the site with nothing between the groups, so twenty odd choices read as one run-on list
   rather than as two questions. A rule above each group, and a colour a person can
   actually read, is what makes them separate without giving the table a second button and
   breaking the rule that every table on this site narrows the same way. */
.menu-group {
  margin: var(--space-4) var(--space-3) var(--space-2);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
  font-size: var(--text-micro); font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-2);
}
.menu-panel > .menu-group:first-child { margin-top: var(--space-1); padding-top: 0; border-top: 0; }
/* The choice in force carries a mark rather than only a tint, because a tint is only
   legible next to the ones without it and a menu can be read one line at a time. */
.menu-item.checked { color: var(--text); }
/* Content box on purpose. Everything on this site is a border box, and a five pixel wide
   border box holding a two pixel border and twelve pixels of padding cannot be five pixels
   wide, so the tick came out as a chevron four times the size of the word beside it. */
.menu-item.checked::after {
  content: "";
  box-sizing: content-box;
  margin: -3px 0 0 auto;
  width: 4px;
  height: 9px;
  border: solid var(--blue);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
  flex: 0 0 auto;
}
.menu-item:hover:not(:disabled) { background: var(--glass-control-raised); }
.menu-item:disabled { color: var(--text-3); }
.menu-item.danger { color: var(--red); }
@supports not (backdrop-filter: blur(1px)) {
  .menu-panel { background: var(--surface-solid); }
}
:root[data-reduce-transparency="true"] .menu-panel {
  background: var(--surface-solid);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* ==========================================================================
   Admin
   ========================================================================== */

.admin-nav {
  position: sticky;
  top: calc(var(--island-bottom) + var(--space-5));
  align-self: start;
  display: grid;
  /* The gap between groups. The buttons inside a group sit tight against each other. */
  gap: var(--space-4);
  padding:8px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  box-shadow: var(--glass-rim);
}
/* Sections, in the four groups an exchange is actually run in. The heading is a label on
   a list rather than a control, so it is quiet and small, and the first group carries none
   because the overview is not part of any of them. */

/* Everything open, one line each, with the way to it on the right. */

.admin-nav button {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%;
  border: 0;
  background: transparent;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
  /* A row in a list, so it takes the row shape rather than the pill one. */
  border-radius: var(--radius-sm);
  padding:8px 12px;
  color: var(--text-2);
  font-size: var(--text-small);
  font-weight: 550;
  transition: background var(--transition), color var(--transition);
}

/* A form is a layout boundary. The Admin panel cannot space the cards inside it, so the
   settings form owns the same gap the panel uses between every other card. */

/*
 * Admin settings sits on one grid at every width.
 *
 * The count of columns is chosen so each card divides evenly: eight market settings, four
 * account settings and four Discord channels all fit four, two or one across, and nothing
 * is left as a lone control beside an empty half of a row. The measurement is of the panel
 * rather than the window, because the panel loses two hundred pixels to the section list
 * beside it and the window cannot see that.
 *
 * Rows are spaced further apart than columns on purpose. Each field carries a line or two
 * of explanation under its control, and with an equal gap the explanation of one field sat
 * as close to the label below it as to the control it belongs to.
 */

/*
 * Descriptions get the room for two lines whether they use it or not. Letting each one
 * take its own height meant a field explained in six words ended well above the field
 * beside it explained in twelve, and the gap to the row underneath looked different under
 * every control even though the grid was even. Two lines is what almost all of them need,
 * so this costs nothing and the column edges line up.
 */

/* A field that cannot be used says so under its own control, in the same place every time. */
.field-error { margin: 0; color: var(--red); font-size: var(--text-micro); font-weight: 600; }
.field-error:empty { display: none; }
.field-invalid .select-field { border-color: var(--red); }
.field-invalid .select-field:focus {
  border-color: var(--red); box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 22%, transparent);
}


/* Written down once and folded away. What each role may do is worth reading when somebody
   is deciding what to give a person, and is in the way every other time they open this
   page - which is most times, because the page is where accounts are dealt with. */

/* A trusted operator has one identity treatment that can move from the account menu to
   profiles or a future forum without being rebuilt. Text carries the role; the mark is
   confirmation, never the only signal. */
/* The role tags used to be words in a pill. They are shapes now, styled with the rest of
   the badges above, so nothing here is left to say. */

/* The verified mark. A scalloped check, the shape one has had for long enough that it does
   not need a caption, sized to sit on the line beside a name without pushing it about. */
/* A name and everything beside it, spaced once. The mark used to carry a margin of its own
   and the tags carried none, so the gap either side of a name changed depending on what
   the person happened to have. */
/* A name and whatever it has earned, inside whatever room the row gives it. It was
   inline-flex with no ceiling, so a long name simply made the group wider than the cell and
   pushed the tag out past the edge of the table with it. */

/* A name is a way to somebody, so it is coloured and underlined like every other way to
   somewhere, and it keeps the ceiling the name already had. */

/* The name at the top of a profile carries its marks on the same line as the heading. */

/* ----- Badges --------------------------------------------------------------------------
   Five shapes, drawn one way: a solid hue, a second piece of it a tone lighter where the
   shape has one, and the seal's tick knocked out in the page colour. No outline, no disc
   and no words. The knockout is the page rather than plain white, so the tick reads as a
   hole punched through the seal on either ground rather than as white ink on a dark one. */
/* A rank is a shape in a rounded box, the same corner the avatars and the Guide's mark
   already use. The box carries the colour and the shape is knocked out of it, so a badge
   is one solid block of one hue at fifteen pixels rather than a thin silhouette that loses
   its edge in a busy row. Told apart by shape and by colour together, which is two ways
   rather than one. */
.badge { display: inline-flex; align-items: center; justify-content: center; position: relative;
  cursor: default; flex: 0 0 auto; width: 18px; height: 18px;
  border-radius: var(--radius-mark); background: var(--badge-tile); }
.badge svg { width: 13px; height: 13px; display: block; }
.badge:focus-visible { border-radius: var(--radius-mark); }
.badge-shield { --badge-tile: var(--badge-red); }
.badge-wrench { --badge-tile: var(--badge-steel); }
.badge-bell { --badge-tile: var(--badge-gold); }
/* The bug hunter is a granted mark rather than a rank, and it keeps the art it had. It
   sits on the plain box, which turns over with the page. */
.badge-net, .badge-net-gold { --badge-tile: var(--badge-hunter-box); box-shadow: inset 0 0 0 1px var(--badge-hunter-rim); }
/* The verified seal is in no box at all. It is a scalloped disc whose edge is the whole
   mark, and inside a rounded square that is two competing corners in one badge. */
.badge-seal { width: 16px; height: 16px; border-radius: 50%; background: none; }
.badge-seal svg { width: 16px; height: 16px; }
.badge-seal:focus-visible { border-radius: 50%; }

/* The seal, unchanged: its own blue, and its tick knocked out in white on either page. */
.badge-seal .bg-1 { fill: var(--badge-blue); }
.badge-seal .bg-knock { fill: none; stroke: var(--badge-seal-knock); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
/* A rank is the page showing through its box. One knockout colour for all three, so they
   cannot drift apart the way a hue each would. */
.badge-shield .bg-1,
.badge-wrench .bg-1,
.badge-bell .bg-1 { fill: var(--badge-knock); }
/* The bug hunter keeps its own two greens on top of the box. */
.badge-net .bg-1 { fill: var(--badge-green); }
.badge-net .bg-2 { fill: var(--badge-green-2); }
.badge-net .bg-1s { fill: none; stroke: var(--badge-green); stroke-width: 2.9; stroke-linecap: round; }
/* The same net, one tier up. */
.badge-net-gold .bg-1 { fill: var(--badge-hunter-gold); }
.badge-net-gold .bg-2 { fill: var(--badge-hunter-gold-2); }
.badge-net-gold .bg-fade { fill: url(#hunter-bag); }
.badge-net-gold .bg-2-top { stop-color: var(--badge-hunter-gold-2); }
.badge-net-gold .bg-2-foot { stop-color: var(--badge-hunter-gold-3); }
.badge-net-gold .bg-1s { fill: none; stroke: var(--badge-hunter-gold); stroke-width: 2.9; stroke-linecap: round; }
.badge-net-gold .bg-shine, .badge-net-gold .bg-shine-2 { fill: var(--badge-hunter-shine); }

/* What kind of change this was, coloured so a page of them reads by shape before it reads
   by word. The same glass as every other tag on the site: the tint and the rim are taken
   from the tag's own colour, so there is one rule here rather than one per kind. */

/* The tag above where it came from, rather than the two side by side. On one line the tag
   was squeezed between the column edge and the words beside it, and no two rows lined up.
 *
 * The stacking goes inside the cell, not on it. This class sat on the cell itself, and a
 * table cell made into a flex container stops behaving like a cell: it takes the height of
 * its own contents rather than the row's. On every row taller than the tag - which in the
 * record is every row - the cell ended short and drew its rule partway up, so the line
 * between one entry and the next arrived at two different heights and the whole column
 * stepped down the page. */

/* Every cell on a row starts on the same line.
   A row here is as tall as whatever happened on it, and what happened can run to a sentence,
   a subject and two changes. Cells sit in the middle of their row by default, so a tall row
   left the date floating halfway down it and nothing on the line agreed with anything else.
   They start at the top now, and the row breathes rather than being held to one height. */

/* What actually changed, on the row. The log used to name the action and stop there, so
   every row had to be opened to learn which company it was about and what it became. */

/* The count of what did not fit belongs to the row of chips it is counting. It carried no
   material of its own, so it sat loose against the chips beside it and read as a caption
   that had come away from something. Same shape, same height, quieter, and marked as the
   one that is not itself a change. */

/* A label that appears when you point at something, made of the same glass as every other
   floating surface. Written as a pseudo-element on the thing it describes rather than as a
   panel somewhere else in the page, so it cannot be left behind on screen after whatever
   it belonged to has gone. */
/* One label, drawn on top of the whole page.
 *
 * It used to be a pseudo-element on the thing it described, which puts it inside whatever
 * that thing is inside: in the panel behind your name it was cut off by the panel's edge,
 * drawn under the row beneath it, and pushed off the side of the screen when the words were
 * longer than the panel was wide. Nothing about that is fixable from inside the box.
 *
 * It is positioned by the page, in window coordinates, clamped so it never leaves the
 * screen, and it flips below whatever it describes when there is no room above.
 */
.tip-layer {
  position: fixed;
  z-index: var(--layer-tip);
  /* Wide enough for a sentence and no wider. A label that widens to fit its words ends up
     one line running most of the way across a desktop, which is slower to read than three
     short ones, so this one grows downward instead. */
  max-width: min(19rem, calc(100vw - 24px));
  padding: var(--space-2) var(--space-4);
  /* Half the height of one closed line, so a name on its own is a pill and the opened
     version is the same shape softened. One radius does both. */
  border-radius: var(--radius);
  background: var(--glass-strong);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--line);
  box-shadow: var(--glass-shadow), var(--glass-rim);
  color: var(--text);
  font-size: var(--text-micro);
  font-weight: 650;
  letter-spacing: .01em;
  line-height: 1.45;
  text-align: center;
  overflow-wrap: break-word;
  white-space: normal;
  pointer-events: none;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity var(--transition), transform var(--transition);
}
.tip-layer.showing { opacity: 1; transform: translateY(0); }
/* The name reads at full strength and the sentences behind it a step quieter, so opening
   one adds detail rather than adding shouting. */
.tip-name { display: block; color: var(--text); }
.tip-more {
  display: block;
  margin-top: var(--space-1);
  max-width: 30ch;
  margin-inline: auto;
  color: var(--text-2);
  font-weight: 500;
  /* Four lines is the guard, not the shape: every description here is one to three. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
}
/* Says there is more behind it without printing a word to say so. */
.tip-layer.has-more .tip-name::after {
  content: '';
  display: inline-block;
  width: 4px; height: 4px;
  margin-left: 6px;
  vertical-align: 2px;
  border-radius: var(--radius-pill);
  background: currentColor;
  opacity: .45;
}
[data-tip] { cursor: default; }
@supports not (backdrop-filter: blur(1px)) {
  .tip-layer { background: var(--surface-solid); }
}
:root[data-reduce-transparency="true"] .tip-layer {
  background: var(--surface-solid);
}

/* Account menu */
.account-identity { display: flex; align-items: center; gap:12px; }
.account-identity h3 { margin:0; font-size: var(--text-label); font-weight: 650; }
.account-name-row { display: flex; align-items: center; gap: var(--space-2); min-width: 0; flex-wrap: wrap; }
/* Somebody's picture, with their initial behind it.
   The letter is a real element underneath rather than a fallback that has to be triggered,
   so an account with no picture, one whose picture has been deleted, and one on a
   connection that cannot reach Discord all show the same readable initial. */
.avatar {
  position: relative;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--text);
  color: var(--bg);
  font-weight: 700;
  font-size: var(--text-body);
  flex: 0 0 auto;
  overflow: hidden;
}
.avatar img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}
.avatar-large { width: 64px; height: 64px; font-size: var(--text-section); }

/* ==========================================================================
   Control sizing
   One height and one radius for every form control, so a row of them lines up.
   ========================================================================== */

.select-field {
  outline: 0;
  transition: border-color var(--transition), box-shadow var(--transition);
  height: var(--control-height);
  padding: var(--control-pad);
  padding-right: 32px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-solid);
  font-size: var(--text-body);
  width: 100%;
  min-width: 0;
}

.select-field:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 16%, transparent);
}
/* A file picker cannot take a fixed height without clipping its own button. */

.primary-button, .secondary-button, .danger-button { padding: 0 var(--space-5); font-weight: 600; display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); height: var(--control-height); font-size: var(--text-label); }
/*
 * A control says how big its own words are, and the size follows its height.
 *
 * Four sizes were in use across eleven treatments, and two of them - the plain text button
 * and the icon button - declared none at all, so they took whatever the page around them
 * was set in: fifteen pixels at normal weight, which is the size of a paragraph. A control
 * the size of the paragraph beside it does not read as a control, and it changed size
 * depending on where it was put, which is the one thing a shared treatment exists to stop.
 *
 * There are two control heights on this site, so there are two sizes and nothing is set in
 * a third. The chips and the table actions came up from twelve pixels, which is also the
 * smallest thing anybody has to read here.
 */
.quiet-button { height: var(--control-height-compact); padding:0 12px; font-size: var(--text-small); font-weight: 600; background: transparent; color: var(--text-2); }

.quiet-button:hover { background: var(--surface-2); color: var(--text); }

.field { display: grid; gap:8px; min-width: 0; align-content: start; }
.field label { font-size: var(--text-small); color: var(--text-2); font-weight: 600; }

/* A form grid, the same one used everywhere else. It used to paint its background with
   the line colour so hairlines would show through the gaps, but nothing inside it ever
   painted a surface of its own, so the whole thing rendered as a grey slab with the
   labels sitting on top of it. */
/* Settings, in named groups.
   Eleven rows used to flow into whatever columns fitted, so what somebody can see of your
   account sat beside what time of day looks like and neither said which was which. The
   sections carry the names the header's quick panel uses, in the same order. */
.settings-section { display: grid; gap: var(--space-3); }
.settings-section + .settings-section { margin-top: var(--space-6); padding-top: var(--space-5); border-top: 1px solid var(--line); }
.settings-section > h3 { margin: 0; font-size: var(--text-micro); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-2); }
.settings-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-4); margin: 0; }
.modal .settings-section:last-of-type { margin-bottom: var(--space-5); }

/* A control sitting inside a field matches the field it sits beside.
   This comment sat here on its own with no rule under it, so every text box and every
   message box on the site fell back to what the browser draws: square corners and a grey
   inset border, next to selects and buttons rounded to the scale. Seventeen inputs and
   seven message boxes, on the panel, in the forum and in every modal. */
.field input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.field textarea,
.forum-reply textarea,
.forum-edit textarea,
.modal textarea {
  outline: 0;
  transition: border-color var(--transition), box-shadow var(--transition);
  padding: var(--control-pad);
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-solid);
  font-size: var(--text-body);
  width: 100%;
  min-width: 0;
}
.field input:not([type="checkbox"]):not([type="radio"]):not([type="file"]) { height: var(--control-height); }
.field textarea, .forum-reply textarea, .forum-edit textarea, .modal textarea {
  padding-top: 10px; padding-bottom: 10px; line-height: 1.5; resize: vertical;
}
.field input:focus, .field textarea:focus,
.forum-reply textarea:focus, .forum-edit textarea:focus, .modal textarea:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 16%, transparent);
}
.field input::placeholder, .field textarea::placeholder,
.forum-reply textarea::placeholder, .modal textarea::placeholder { color: var(--text-3); }
.field-invalid input { border-color: var(--red); }

/* An exchange tape is one unbroken rhythm of symbol, price, change. A boxed label sat
   taller than everything beside it and broke that rhythm, so the index is set apart the
   way a tape does it: by the colour of its symbol, not by a chip around it. */
.strip-index-tag {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   Page rhythm
   Last word on the spacing between top level blocks. A page is a grid, and margins
   do not collapse inside one, so a block that sets its own vertical margin has it
   added to the page gap rather than absorbed by it. That is how the markets page
   ended up with 60 pixels under its heading on a phone and 24 everywhere else.
   Both directions are cleared here, not just the bottom.

   The same arithmetic applies to any container that lays out with a gap. A wrapping row
   of cards put a bottom margin on each child, so wrapped rows sat 24 apart where the gap
   says 12 and 40 apart where it says 20, and a phone spaced page blocks 36 apart where a
   desktop spaced them 24, with nothing on screen explaining the difference.
   ========================================================================== */
.page > * { min-width: 0; margin-block: 0; }


/* What an account holds now, so a balance can be changed without working it out first. */

/* Text that a person typed can be anything, including a three hundred character address
   with no spaces in it. Without this a single announcement pushed the news page eleven
   thousand pixels sideways. Tables are left out on purpose: a cell keeps its own wrapping
   rules so a column of figures does not break mid-number. */
.announcement p, .announcement h3, .card p, .card h2, .card h3, .empty, .guide-message, .guide-message p, .modal p, .notice, .subtle, .toast span, .toast strong { overflow-wrap: anywhere; }

/* ==========================================================================
   Responsive adjustments

   Every media query lives here, at the end, because a rule that adjusts another
   rule has to come after it. Thirty six declarations in this file were being
   undone by a base rule written further down: the assistant button never moved
   clear of the mobile navigation bar, so it sat on top of the Menu button and
   ate every tap meant for it, and the chart heights, hero sizes and popover
   positions written for a phone were never the ones that applied.
   ========================================================================== */

@media (prefers-reduced-transparency: reduce) {
  .globalnav, .market-strip, .popover, .modal, .guide-drawer, .search-panel, .toast { background: var(--surface-solid); backdrop-filter: none; -webkit-backdrop-filter: none; }
  .card, .admin-nav, .empty, .footer-inner { background: var(--surface-solid); backdrop-filter: none; -webkit-backdrop-filter: none; }

  .metric { background: var(--surface-solid); }
  .topbar { background: transparent; }
  .strip-status-fixed { background: transparent; }
  body::before { display: none; }
  .overlay, .modal-root:not(:empty) { backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* Below this width the links across the top do not fit, so navigation moves to the card
   along the bottom. The two used to change over at different widths - the links stopped at
   980 and the bar did not appear until 700 - which left every screen between them, an iPad
   held upright among them, with no way to move around the site at all. With the bar gone
   the links do not stop at all: they are the only way around the site now, so hiding them
   below 980 left every phone and every tablet with no navigation whatsoever. They already
   scroll sideways in a column allowed to shrink to nothing, so they fit any width there is
   by scrolling rather than by disappearing. */
@media (max-width: 980px) {
  /* Anything sitting at the foot of a small screen keeps the same gutter and clears the
     island. Full width down here, so a message and the island cannot be side by side: one
     of them is on top of the other, and it was the message on top of the island. Both beads
     are on the island now, so clearing the island clears them - this used to add the Guide
     bead's own lift on top, back when the bead was pinned to the corner by itself. */
  .toast-region, .walkthrough-card {
    bottom: calc(var(--float-bottom) + var(--space-2));
  }
  .toast-region { left: var(--island-side); right: var(--island-side); width: auto; }
  /* An open panel takes that corner while it is open, so a message and the tour card go
     above it rather than over it. A message that covers Sign out leaves the menu looking
     present and answering nothing. */
  body.panel-open .toast-region,
  body.panel-open .walkthrough-card { bottom: calc(var(--float-bottom) + var(--panel-height) + var(--space-3)); }

  /* No column to group on a phone: the sections scroll sideways in one row, so the
     headings would be four more things to scroll past rather than a way through them. */
  .admin-nav { position: static; display: flex; overflow-x: auto; }

}

@media (max-width: 700px) {
  :root { --card-pad: var(--space-4); --gap: var(--space-3); }
  .globalnav { padding:0 var(--space-4); gap: var(--space-4); }
  .brand-name { display: none; }  .strip-status-fixed { padding-left:16px; padding-right:12px; gap:8px; }
  /* Where the message wraps to a second line, it reads from the left beside its symbol
     rather than centred away from it. */
  .site-banner { text-align: left; }
  .site-banner-inner { align-items: flex-start; }
  .site-banner-icon { margin-top: 1px; }
  .strip-session { display: none; }
  /* The legend is a live readout, so its content changes width on every tick. A change
     that flips from +2.40% to -12.40% is wider, and in a wrapping row that pushes it onto
     a new line, grows the card by a row, and moves the chart under whoever is reading it.
     One part per row is the same height whatever the figures say. */

  /* The same room at the foot as every other width. Written as the shorthand alone, this
     set the bottom back to 40 pixels and the island covered the end of every long page on
     a phone, which is the width where the island is closest to the reading. */
  .page { padding: var(--space-5) var(--island-side) calc(var(--dock-height) + var(--space-4)); }

  .home-index-value strong { font-size: var(--text-title); }
  .home-next { align-items: flex-start; flex-direction: column; }

    .table-scroll { max-height: 62vh; }

                                .footer-inner { flex-direction: column; align-items: flex-start; }
  .search-panel { border-radius: var(--radius-lg); }
  .overlay { padding-top:72px; }
  .popover, .notifications-popover { right: var(--island-side); top: calc(var(--island-bottom) + 8px); }
  .chart-wrap, .chart-wrap svg { min-height: 270px; height: 270px; }

}

@media (max-width: 430px) {
  /* The index figure and the four stretches of time cannot share a line on the narrowest
     phone, so they take one each rather than the buttons running off the card. Even on its
     own line the figure has to come down a step: five digits and a change beside them do
     not fit across 320px at the size the figure is given anywhere else. */
  .home-index-head { flex-direction: column; }
  .home-index-value strong { font-size: var(--text-figure-lg); }
  /* Four labelled figures on one line, and the index runs to four digits and a comma, so
     at 320px the readout is two pixels too long. It is held to one line on purpose, so the
     line comes down to the smallest size on the scale rather than wrapping and taking the
     chart with it. Every figure stays visible, which a truncation would not manage. */

}

/* An operating system asking for less motion is honoured, and is also seeded into this
   site's own Reduce motion switch, so the switch shows what is actually happening. It
   used to sit here alone and unannounced: the switch in Settings read "off" while every
   transition on the site was dead and the tape along the top never moved once, with
   nothing anywhere to explain it or turn it back on. Someone who has looked at the
   switch and turned it off has said what they want on this site, and that wins. */
@media (prefers-reduced-motion: reduce) {
  :root:not([data-reduce-motion="false"]), :root:not([data-reduce-motion="false"]) *,
  :root:not([data-reduce-motion="false"]) *::before, :root:not([data-reduce-motion="false"]) *::after {
    scroll-behavior: auto !important;
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

@media (max-width: 700px) {
  .accessibility-popover { right: var(--island-side); }
}

@media (max-width: 700px) {

  .chart-wrap { height: 300px; }

}

@media (max-width: 900px) {

  .metric strong { font-size: var(--text-card); }
}

@media (max-width: 900px) {

  .admin-nav { position: static; display: flex; overflow-x: auto; scrollbar-width: none; }
  .admin-nav::-webkit-scrollbar { display: none; }
  .admin-nav button { flex: 0 0 auto; white-space: nowrap; }
}

/* ----- The control panel ------------------------------------------------------------------
 *
 * A rail of sections gathered into the parts of running an exchange, and whichever one is
 * open beside it. The rail is a card and every control on it is the site's own, so the
 * panel is the same material as the rest of the site rather than an admin theme bolted on.
 */
.admin-split { display: grid; grid-template-columns: 210px minmax(0, 1fr); gap: var(--space-4); align-items: start; }
.admin-group { display: grid; gap: 2px; min-width: 0; }
.admin-group h3 {
  margin: 0 0 6px;
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-3);
}
/* Last on the rail and the one thing here that throws work away. */
.admin-nav button.danger { color: var(--red); }

/* On a phone the rail lies down. A 210px column beside the section pushed the page 73px
   sideways at 320, and eleven sections do not fit down the side of a screen that narrow
   anyway. Laid out in a row it is one of the site's sideways scrollers, so it fades at
   its edges like every other one. */
@media (max-width: 720px) {
  .admin-split { grid-template-columns: minmax(0, 1fr); }
  .admin-nav {
    position: static;
    grid-auto-flow: column;
    grid-auto-columns: max-content;
    align-items: center;
    overflow-x: auto;
    gap: var(--space-3);
  }
  .admin-group { grid-auto-flow: column; grid-auto-columns: max-content; align-items: center; gap: 2px; width: max-content; min-width: max-content; }
  .admin-group h3 { margin: 0 4px 0 0; align-self: center; }
  .admin-nav button { width: auto; }
}
/* The right column: the section's name, then the section. */
.admin-side { display: grid; gap: var(--space-4); align-content: start; }
.admin-title { display: grid; gap: 4px; }
.admin-title h1 { margin: 0; font-size: var(--text-section); letter-spacing: var(--tracking-snug); font-weight: 680; }
.admin-title p { margin: 0; }
.admin-head { align-items: center; }
/* Sections that are a run of cards rather than a list. */
.admin-stack { display: grid; gap: var(--space-4); }
/* The same gap .admin-block uses everywhere else. Written as a raw 10px it was the one
   block in the panel spacing its own contents off the scale. */
.admin-stack .admin-block { display: grid; gap: var(--space-3); padding-top: var(--card-pad); border-top: 0; }
.admin-stack .admin-block > .segmented,
.admin-stack .admin-block > .admin-acts,
.admin-stack .admin-block > .agree-row,
.admin-stack .admin-block > .admin-now { justify-self: start; }
/* A field holds one value, so it is as wide as reading that value needs and no wider. */
.admin-stack .admin-block > .field,
.admin-stack .admin-banner > .field { max-width: 30rem; }
.admin-stack .admin-block h2 { margin: 0; }
.admin-stack .admin-block p { margin: 0; }
.admin-now { display: inline-flex; align-items: center; gap: 8px; }

/* A form inside a section, spaced like the section around it. */
.admin-form { display: grid; gap: var(--space-3); width: 100%; max-width: 520px; }

/* What has been announced. */
.admin-notices { display: grid; gap: var(--space-3); width: 100%; }
.admin-notice { display: grid; gap: var(--space-2); padding: var(--space-4) 0; border-top: 1px solid var(--line); }
.admin-notice:first-child { border-top: 0; padding-top: 0; }
.admin-notice-head { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.admin-notice-head strong { min-width: 0; font-size: var(--text-label); font-weight: 650; }
.admin-notice p { margin: 0; }
.admin-notice-body { max-width: 72ch; color: var(--text-2); line-height: 1.55; }
.admin-notice-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
.admin-notice-acts { display: flex; align-items: center; gap: var(--space-2); }

/* An application, shown whole, because it is somebody's work rather than a row - and on a
   surface of its own, because a hairline between two of them is not enough to say where
   one person's application stops and the next begins. */
.admin-applications { display: grid; gap: var(--space-4); width: 100%; }
.admin-application {
  display: grid; gap: var(--space-4);
  padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.admin-application p { margin: 0; }
.admin-application-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
.admin-application-name { display: flex; align-items: baseline; gap: var(--space-2); min-width: 0; flex-wrap: wrap; }
.admin-application-name strong { font-size: var(--text-body); font-weight: 700; letter-spacing: var(--tracking-snug); font-variant-numeric: tabular-nums; }
.admin-application-about { max-width: 68ch; color: var(--text-2); line-height: 1.55; }
/* Four short facts read across, not down a 56px gutter.

   The shared fact grid sets its values at figure size, which is right where they are
   figures - a company's open, high and low. These are mostly prose, and "Demo Trader,
   September 10" at 21px bold wrapped to two lines and shouted louder than the company
   name above it. Same grid, values at reading size. */
.admin-application-facts { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--space-4); }
.admin-application-facts dd {
  font-size: var(--text-label); font-weight: 550; letter-spacing: 0; line-height: 1.4;
}
.admin-application-said { display: grid; gap: var(--space-1); max-width: 68ch; color: var(--text-2); }
.admin-application .admin-acts { justify-self: start; }

/* What the exchange says about itself.

   Sixteen answers with no rules between them and a name column sized to its own longest
   word, so every row's detail started at a different place and the whole card read as
   ragged prose. A fixed column for the name puts the details in a line, and a hairline
   between rows makes it a list rather than a paragraph.

   The state is a word as well as a dot. Two of sixteen being wrong was said in red and
   nothing else, and this site's rule everywhere else - the unread count, the market
   pill - is that colour is never the only thing carrying the message. */
.admin-checks { display: grid; width: 100%; }
.admin-check {
  display: grid; grid-template-columns: 74px minmax(150px, 200px) minmax(0, 1fr);
  align-items: baseline; gap: var(--space-3);
  padding: var(--space-3) var(--space-2); border-top: 1px solid var(--line);
}
.admin-check:first-child { border-top: 0; }
.admin-check strong { font-size: var(--text-label); font-weight: 650; }
.admin-check .subtle { font-size: var(--text-small); line-height: 1.45; overflow-wrap: anywhere; }
.admin-check-state { display: inline-flex; align-items: center; gap: var(--space-2); align-self: center; }
.admin-check-word { font-size: var(--text-micro); font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-3); }
.admin-check.bad .admin-check-word { color: var(--red); }
/* The ones worth looking at carry a tint as well, so they are findable in a long card
   without reading every row. */
.admin-check.bad { background: color-mix(in srgb, var(--red) 6%, transparent); border-radius: var(--radius-xs); }

@media (max-width: 700px) {
  .admin-check { grid-template-columns: 74px minmax(0, 1fr); }
  .admin-check .subtle { grid-column: 2; }
}

/* The companies list is a symbol and a price. Whether it is trading is drawn beside the
   symbol, so there is no third column standing empty on every row that is. */
.admin-company, .admin-company-head { grid-template-columns: minmax(150px, 1fr) minmax(96px, auto); }
.admin-company .admin-who strong { display: flex; align-items: center; gap: var(--space-2); }
.admin-company .admin-who { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.admin-company .admin-who .subtle { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Dials, and the two switches beside them. */
/* The banner's own settings, which go quiet with the switch that turns the banner on.
   A disabled fieldset carries no border or padding of its own here; it is a grouping for
   the browser and for a screen reader, not a box drawn on the page. */
.admin-banner { display: grid; gap: var(--space-4); margin: 0; padding: 0; border: 0; }
.admin-banner[disabled] { opacity: .45; }

.admin-dials { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 250px)); gap: var(--space-4); }
.admin-switches { display: grid; justify-items: start; gap: 8px; }

/* What Reset clears. Every row was a pill sized to its own sentence, so ten of them made a
   staircase down the card with ten different right-hand edges and no column to read down.
   One list, one width, one rule between each. */
.admin-reset-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.admin-reset-head > div { display: grid; gap: var(--space-1); min-width: 0; }
.admin-reset-head h2 { margin: 0; }
.admin-reset-head p { margin: 0; max-width: 62ch; }
/* The per-account Clear modal asks the same question about one person that Reset asks
   about the whole exchange, in the same shape, so it gets the same list rather than a
   second look at it. */
/* A name, and the line that says what it takes, under it. Written side by side in one
   span they ran together - "Trading Holdings, orders and trades." reads as one phrase
   rather than a thing and its description. */
.admin-wipe-what { display: grid; gap: 2px; min-width: 0; }
.admin-wipe-what strong { font-weight: 650; }
.admin-wipe-what .subtle { font-size: var(--text-caption); line-height: 1.4; }
.admin-wipes, .admin-switches.admin-wipes { display: grid; width: 100%; }
.admin-wipe {
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  padding: var(--space-3) var(--space-2);
  /* An agree-row draws its own box, which is right where one of them stands alone in a
     settings card. Ten in a column is ten boxes, so here they give up the box and take a
     rule between them: one list with one edge, rather than a stack of ten. */
  border: 0; border-top: 1px solid var(--line); border-radius: var(--radius-xs);
  background: transparent; cursor: pointer;
  transition: background var(--transition);
}
.admin-wipe:first-child { border-top: 0; }
/* Focus is shown, not cancelled. Re-stating the border colour did nothing visually and
   quietly overrode .agree-row:focus-within, so tabbing onto a row lost its tint. */
.admin-wipe:focus-within { background: var(--surface-2); box-shadow: inset 2px 0 0 var(--blue); }
.admin-wipe:hover { background: var(--surface-2); }
.admin-wipe:has(input:checked) { background: color-mix(in srgb, var(--red) 7%, transparent); }
.admin-wipe span { font-size: var(--text-label); }
.field-hint { margin: 0; color: var(--text-3); font-size: var(--text-micro); }

/* How the exchange is doing, one figure a card. */
.admin-figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--space-4); }
.admin-figure { display: grid; gap: 6px; align-content: start; }
.admin-figure h2 { margin: 0; font-size: var(--text-label); font-weight: 650; color: var(--text-2); }
.admin-figure p { margin: 0; }
.admin-figure-count { font-size: var(--text-section); font-weight: 680; letter-spacing: var(--tracking-snug); font-variant-numeric: tabular-nums; }
.admin-figure-now { display: inline-flex; align-items: center; gap: 8px; font-size: var(--text-body); font-weight: 620; }
.admin-figure.wide { grid-column: 1 / -1; }

/* What happened, one line each, opened to show what changed. */
.admin-kinds { justify-self: start; max-width: 100%; }
/* The record, narrowed to one account, saying so and offering the way back. */
.admin-only-one {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap;
  padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm);
  background: var(--blue-soft); color: var(--text-2); font-size: var(--text-small);
}
/* The record, read as a log.

   Every entry used to be a row the height of three lines carrying one, with the action at
   the left, a gulf, a name, and a date stacked over a time at the right. Eight orders
   placed inside the same minute came out as eight identical hundred-pixel blocks.

   A log is ordered by time, so the time leads, in one narrow column somebody can run their
   eye down. The day above it is said once rather than repeated on every row. And the rows
   are the height of what is in them. */
.admin-record { display: grid; gap: var(--space-5); width: 100%; }
.admin-day { display: grid; gap: var(--space-2); }
.admin-day-name {
  margin: 0; font-size: var(--text-micro); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-3);
}
.admin-day-events { display: grid; }
.admin-event { display: grid; gap: 0; padding: 0; border-top: 1px solid var(--line); }
.admin-day-events > .admin-event:first-child { border-top: 0; }
.admin-event-head {
  display: grid; grid-template-columns: 68px minmax(0, 1fr) minmax(0, 140px);
  align-items: baseline; gap: var(--space-3);
  width: 100%; padding: var(--space-2); border: 0; border-radius: var(--radius-xs); background: transparent;
  color: var(--text); font-size: var(--text-small); text-align: left; cursor: pointer;
  transition: background var(--transition);
}
.admin-event-head:hover { background: var(--surface-2); }
.admin-event.on .admin-event-head { background: var(--surface-2); }
.admin-event-when {
  font-size: var(--text-micro); color: var(--text-3);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
/* What happened, and what it was about, on one line that can wrap once rather than being
   cut off - the company an order was for is the part that tells two of them apart. */
.admin-event-what { display: flex; align-items: baseline; gap: var(--space-2); min-width: 0; flex-wrap: wrap; }
.admin-event-what strong { font-weight: 650; }
.admin-event-about { color: var(--text-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.admin-event-who { color: var(--text-3); text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.admin-event-more { padding: 0 var(--space-2) var(--space-3); }
/* What an entry changed, laid out. This was a bare <dl> with no styling of its own, so the
   browser's own list defaults applied: every term on its own line and every value indented
   by forty pixels off nothing, under a row that is a three column grid. The labels sit in a
   column of their own now, against the values they name. */
.admin-was { display: grid; grid-template-columns: 68px minmax(0, 1fr); gap: var(--space-2) var(--space-3); margin: 0; align-items: baseline; }
.admin-was dt { font-size: var(--text-micro); font-weight: 650; letter-spacing: .05em; text-transform: uppercase; color: var(--text-3); }
.admin-was dd { margin: 0; min-width: 0; font-size: var(--text-small); }
.admin-was dd code { display: block; padding: var(--space-3); border-radius: var(--radius-sm); background: var(--surface-2); font-size: var(--text-caption); line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
.admin-was { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 6px 12px; margin: 0 0 12px; }
.admin-was dt { color: var(--text-3); font-size: var(--text-micro); font-weight: 700; }
.admin-was dd { margin: 0; min-width: 0; font-variant-numeric: tabular-nums; }
/* Facts about what is running: a label and a value, in a row that wraps. */
.admin-facts { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-6); margin: 0; }
.admin-facts > div { display: grid; gap: 2px; min-width: 0; }
.admin-facts dt { font-size: var(--text-micro); font-weight: 650; letter-spacing: .05em; text-transform: uppercase; color: var(--text-3); }
.admin-facts dd { margin: 0; font-size: var(--text-label); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.admin-was code {
  display: block; overflow-x: auto; padding: 8px 10px; border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--text-2);
  font-size: var(--text-micro); white-space: pre;
}
@media (max-width: 720px) {
  /* The time keeps its column and the rest stacks under it, so the log still reads down
     one edge on a screen too narrow for three columns. */
  .admin-event-head { grid-template-columns: 62px minmax(0, 1fr); gap: var(--space-1) var(--space-3); }
  .admin-event-who { grid-column: 2; text-align: left; }
}

/* The list, and one person opened beside it. */
.admin-people { display: grid; gap: var(--space-4); }
.admin-people.with-one { grid-template-columns: minmax(0, 1fr) 366px; align-items: start; }
.admin-rows { display: grid; }
.admin-row {
  display: grid;
  grid-template-columns: minmax(150px, 1.5fr) 118px minmax(72px, auto) 108px;
  gap: var(--space-4); align-items: center;
}
.admin-row-head {
  padding: 0 var(--space-2) var(--space-2); border-bottom: 1px solid var(--line-strong);
  font-size: var(--text-micro); font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-3);
}
.admin-row-head span:last-child { text-align: right; }
.admin-person, .admin-company {
  padding: var(--space-3) var(--space-2); border-bottom: 1px solid var(--line);
  border-radius: var(--radius-xs); cursor: pointer; transition: background var(--transition);
}
.admin-person:last-child, .admin-company:last-child { border-bottom: 0; }
.admin-person:hover, .admin-company:hover { background: var(--surface-2); }
.admin-person.on, .admin-company.on { background: var(--surface-2); }
.admin-person:focus-visible, .admin-company:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
.admin-who { display: flex; align-items: center; gap: 9px; min-width: 0; }
.admin-who strong { font-size: var(--text-label); font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.admin-rank { font-size: var(--text-label); color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.admin-marks { display: flex; gap: 5px; align-items: center; min-height: 18px; }
.admin-cash { font-variant-numeric: tabular-nums; text-align: right; font-size: var(--text-label); color: var(--text-2); }
.admin-flag {
  display: inline-flex; align-items: center; height: 18px; padding: 0 7px; border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--orange) 16%, transparent); color: var(--orange);
  font-size: var(--text-micro); font-weight: 700; flex: 0 0 auto;
}
.admin-flag.stop { background: color-mix(in srgb, var(--red) 15%, transparent); color: var(--red); }
.admin-tag {
  display: inline-flex; align-items: center; height: 18px; padding: 0 7px; border-radius: var(--radius-pill);
  background: var(--surface-2); color: var(--text-2);
  font-size: var(--text-micro); font-weight: 650; flex: 0 0 auto;
}
/* One person, and everything that can be done to them. */
/* One person, opened.

   Eight blocks down a narrow column, so the rhythm between them is what makes it readable:
   each block is a heading, a line saying what the block is for, and the controls. Those
   three were 8px apart and the blocks 16px apart, which is nearly the same number - so the
   card read as one long run rather than as eight things. The gap between blocks is now
   twice the gap inside one, which is the only rule that makes a stack legible. */
.admin-one { display: grid; gap: var(--space-5); position: sticky; top: var(--space-4); }
.admin-card { display: flex; align-items: flex-start; gap: var(--space-3); }
.admin-card > div { min-width: 0; display: grid; gap: var(--space-1); }
/* The name is the heading of this card, not of the page: a section heading here competed
   with People above it, and wrapped to two lines on any name of normal length. */
.admin-card h2 {
  margin: 0; font-size: var(--text-card); font-weight: 680; letter-spacing: var(--tracking-snug);
  line-height: 1.25; display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
}
.admin-card .subtle { font-size: var(--text-small); line-height: 1.4; }
.admin-shut { margin-left: auto; flex: 0 0 auto; }
.admin-block { display: grid; gap: var(--space-3); padding-top: var(--space-5); border-top: 1px solid var(--line); }
/* Owner is not a rank. It is not on the ladder, it cannot be granted, and every profile on
   the site shows that account as Admin like any other. The panel is the one place where
   saying which account the exchange belongs to is useful rather than a rung nobody can
   reach, so it is said here and nowhere else. */
.admin-owns {
  margin-top: 4px; font-size: var(--text-caption); color: var(--text-2);
}
.admin-block h3 { margin: 0; font-size: var(--text-label); font-weight: 650; letter-spacing: var(--tracking-snug); }
.admin-block p { margin: 0; color: var(--text-2); font-size: var(--text-caption); line-height: 1.45; }
.admin-line { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) 0; }
.admin-line + .admin-line { border-top: 1px solid var(--line); }
.admin-name { display: flex; align-items: center; gap: var(--space-2); min-width: 0; font-size: var(--text-label); font-weight: 600; }
.admin-acts { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.admin-acts > .subtle { font-variant-numeric: tabular-nums; }
/* Five ranks will not sit on one line in a 366px column, and a segmented control that
   wraps draws its pill around the first row only. Laid out as a grid of two, it wraps on
   purpose and every rank is the same width as every other. */
/* A grid, not a row, so the pill radius that suits one line of chips is wrong for three
   rows of them: rounded to the same corner the cards use instead. */
/* A segmented group, so it is spaced like every other segmented group on the site: the
   track pads by 4 and the pills sit 2 apart. Written as 3 and 3, it was the one control
   of twelve that did not match the other eleven. */
.admin-ranks { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2px; padding: 4px; border-radius: var(--radius-sm); }
.admin-ranks button { width: 100%; }
/* The last rank on an odd list takes the whole row rather than leaving a gap beside it. */
.admin-ranks button:last-child:nth-child(odd) { grid-column: 1 / -1; }

/* ==========================================================================
   The forum
   ==========================================================================

   Built around the answer rather than around the conversation, because that is
   what somebody arriving from a search came for. A board says how many of its
   questions nobody has answered, a list marks the ones that are settled, and a
   thread lifts the answer to just under the question.

   Generous vertical rhythm and one accent. Green appears in exactly one place
   on these pages, on the mark that says a question has an answer, so it means
   that and nothing else. */

/* The forum's blocks are children of .page, which is a grid already spacing them by the
   page gap. A margin-bottom here adds to that gap rather than replacing it, so the forum
   sat at 48px between blocks where every other page on the site sits at 24, and the board
   and the thread came out at 40, 48 and 56 depending on which block was above. The gap
   does the spacing; nothing here sets a margin of its own. */
.forum-head { display: grid; gap: var(--space-2); }
.forum-head h1 { margin: 0; font-size: var(--text-section); letter-spacing: var(--tracking-snug); font-weight: 680; }
.forum-head p { margin: 0; max-width: 62ch; }
.forum-head-row { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.forum-head-row > div { display: grid; gap: var(--space-2); min-width: 0; }

/* Where you are, and the way back up. */
.crumbs {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  font-size: var(--text-caption); color: var(--text-2);
}
.crumbs a { color: var(--text-2); text-decoration: none; }
.crumbs a:hover { color: var(--text); text-decoration: underline; }
.crumbs span[aria-current] { color: var(--text-3); max-width: 40ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The boards. */
/* The Forum's own front page.
 *
 * A bar of its own above the title, because the forum is a place inside the site rather
 * than another list page: one box that searches it, and the one button that adds to it.
 */
.forum-bar { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.forum-bar .forum-find { flex: 1 1 12rem; min-width: 0; }
.forum-bar .primary-button { flex: 0 0 auto; }
.forum-find {
  display: flex; align-items: center; gap: var(--space-2);
  height: var(--control-height); padding: 0 var(--space-4);
  border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--surface-solid);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.forum-find svg { width: 17px; height: 17px; color: var(--text-3); flex: 0 0 auto; }
.forum-find input {
  border: 0; outline: 0; background: transparent; color: var(--text);
  font-size: var(--text-body); font-family: inherit; min-width: 0; flex: 1 1 auto;
}
.forum-find input::placeholder { color: var(--text-3); }
.forum-find:focus-within { outline: 3px solid color-mix(in srgb, var(--blue) 58%, transparent); outline-offset: 2px; }
.forum-title { margin: 0; font-size: var(--text-title); font-weight: 680; letter-spacing: var(--tracking-tight); }
.forum-tabs { align-self: start; width: max-content; max-width: 100%; }

/* One card a board, wearing the board's own colour down its edge. The colour is named on
   the board in src/forum.ts and arrives as data-tint, so a sixth board is coloured by
   being added rather than by somebody remembering to come here. */
.forum-topics { display: grid; gap: var(--space-4); }
.forum-topic {
  --tint: var(--blue);
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: var(--space-6); align-items: start;
  border-left: 4px solid var(--tint);
}
.forum-topic[data-tint="crimson"] { --tint: var(--crimson); }
.forum-topic[data-tint="blue"] { --tint: var(--blue); }
.forum-topic[data-tint="green"] { --tint: var(--green); }
.forum-topic[data-tint="yellow"] { --tint: var(--yellow); }
.forum-topic[data-tint="orange"] { --tint: var(--orange); }
.forum-topic-about { display: grid; gap: var(--space-2); min-width: 0; }
.forum-topic-about h2 { margin: 0; font-size: var(--text-card); font-weight: 680; letter-spacing: var(--tracking-snug); }
.forum-topic-about h2 a { color: inherit; text-decoration: none; }
.forum-topic-about h2 a:hover { text-decoration: underline; text-underline-offset: 3px; }
.forum-topic-about p { margin: 0; max-width: 52ch; }
.forum-topic-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }

/* A tag, tinted by whatever it belongs to.
 *
 * The colour is inherited rather than declared here, so a chip inside a board card takes
 * that board's colour without being told which one it is. Declaring --tint on the chip
 * itself would win over the value coming down from the card no matter how the selectors
 * are weighted, which is how every chip on the page came out blue. */
.forum-page { --tint: var(--blue); }
.forum-chip {
  display: inline-flex; align-items: center; height: 22px; padding: 0 10px;
  border-radius: var(--radius-xs);
  background: color-mix(in srgb, var(--tint) 12%, transparent);
  color: var(--tint); font-size: var(--text-micro); font-weight: 620;
  text-decoration: none; white-space: nowrap;
  transition: background var(--transition);
}
.forum-chip:hover { background: color-mix(in srgb, var(--tint) 20%, transparent); }
.forum-chip[data-tint="crimson"] { --tint: var(--crimson); }
.forum-chip[data-tint="blue"] { --tint: var(--blue); }
.forum-chip[data-tint="green"] { --tint: var(--green); }
.forum-chip[data-tint="yellow"] { --tint: var(--yellow); }
.forum-chip[data-tint="orange"] { --tint: var(--orange); }
.forum-chip-plain { background: var(--surface-2); color: var(--text-3); }
.forum-chip-plain:hover { background: var(--surface-2); }

/* What is live on a board, which is what the front page is for. */
.forum-topic-latest { list-style: none; margin: 0; padding: 0; display: grid; align-content: start; }
.forum-topic-latest li { min-width: 0; }
.forum-topic-latest a {
  display: flex; align-items: center; gap: var(--space-2);
  padding: 9px var(--space-3); border-radius: var(--radius-xs);
  color: var(--text); text-decoration: none; font-size: var(--text-small);
  transition: background var(--transition);
}
.forum-topic-latest a:hover { background: var(--surface-2); }
.forum-topic-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.forum-topic-when { flex: 0 0 auto; font-size: var(--text-micro); font-variant-numeric: tabular-nums; }
.forum-topic-quiet { margin: 0; align-self: center; }
.forum-mark { flex: 0 0 auto; display: inline-flex; }
.forum-mark svg { width: 15px; height: 15px; }
.forum-mark.answered { color: var(--green); }
.forum-mark.locked, .forum-mark.pinned { color: var(--text-3); }

/* The page that says what the forum is for, and the line that leads to it. */
.forum-title-line { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.forum-guide { display: grid; gap: var(--space-3); }
.forum-guide h2 { margin: 0; font-size: var(--text-card); font-weight: 680; letter-spacing: var(--tracking-snug); }
.forum-guide p { margin: 0; max-width: 68ch; }
.forum-guide ul { margin: 0; padding-left: var(--space-5); display: grid; gap: var(--space-2); max-width: 68ch; }
/* The boards read as a list of names with what each is for beside it, rather than as
   bullets: the chip is the name, so it does not need a marker in front of it as well. */
.forum-guide-boards { list-style: none; padding: 0; gap: var(--space-3); }
.forum-guide-boards li { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; min-width: 0; }
.forum-guide-boards .forum-chip { flex: 0 0 auto; }
.forum-guide-actions { display: flex; gap: var(--space-3); flex-wrap: wrap; }

/* The four figures over a discussion. A row of name-over-value pairs, the way the rest of
   the site writes a fact grid, so a discussion is measured in the same shape a company is. */
.forum-figures {
  display: flex; flex-wrap: wrap; gap: var(--space-6);
  margin: var(--space-4) 0 0; padding: 0;
}
.forum-figures > div { display: grid; gap: 2px; min-width: 0; }
.forum-figures dt { margin: 0; color: var(--text-3); font-size: var(--text-micro); font-weight: 600; }
.forum-figures dd { margin: 0; font-size: var(--text-small); font-weight: 620; font-variant-numeric: tabular-nums; }

/* Every discussion on the exchange, in the table the figures are named in. */
.forum-all-top { display: flex; justify-content: flex-end; margin-bottom: var(--space-3); }
.forum-found-count { margin: 0 0 var(--space-3); }
.forum-table-card { padding: 0; overflow: hidden; }
.forum-table { display: grid; }
.forum-columns, .forum-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 5rem 5rem 5rem 6rem;
  gap: var(--space-3); align-items: start;
  padding: var(--space-4) var(--space-5);
}
.forum-columns {
  border-bottom: 1px solid var(--line);
  color: var(--text-3); font-size: var(--text-micro); font-weight: 650;
  letter-spacing: .06em; text-transform: uppercase;
}
.forum-columns > span:not(:first-child), .forum-row-figure { text-align: right; }
.forum-row { border-bottom: 1px solid var(--line); transition: background var(--transition); }
.forum-row:last-child { border-bottom: 0; }
.forum-row:hover { background: var(--surface-2); }
.forum-row-post { display: grid; gap: 6px; min-width: 0; }
.forum-row-title {
  display: flex; align-items: center; gap: var(--space-2);
  color: var(--text); text-decoration: none; min-width: 0;
}
.forum-row-title strong { font-size: var(--text-body); font-weight: 650; letter-spacing: var(--tracking-snug); min-width: 0; }
.forum-row-title:hover strong { text-decoration: underline; text-underline-offset: 3px; }
/* Two lines of what is inside the title, and never a third. */
.forum-row-excerpt {
  font-size: var(--text-caption); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.forum-row-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.forum-row-figure { font-size: var(--text-small); font-variant-numeric: tabular-nums; color: var(--text-2); }
.forum-row-when { color: var(--text-3); }
.forum-more { display: flex; justify-content: center; margin-top: var(--space-4); }

/* Narrow: the card stacks, and the table's figures come out from under their headings and
   sit under the title wearing the names the headings were carrying. */
@media (max-width: 900px) {
  .forum-topic { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
}
@media (max-width: 760px) {
  .forum-columns { display: none; }
  .forum-row { grid-template-columns: minmax(0, 1fr); gap: var(--space-2); }
  .forum-row-figure { text-align: left; font-size: var(--text-caption); color: var(--text-3); }
  .forum-row-figure::before { content: attr(data-name) " "; }
  .forum-row { position: relative; }
  .forum-row-figure { display: inline; }
  .forum-row > .forum-row-figure + .forum-row-figure::before { content: " \00b7  " attr(data-name) " "; }
}

/* A board's discussions. */
.forum-sorts { justify-self: start; max-width: 100%; }
.forum-threads { display: grid; }
.forum-thread {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 76px 92px;
  align-items: center; gap: var(--space-4);
  padding: 14px 0; border-top: 1px solid var(--line);
  text-decoration: none; color: inherit;
}
.forum-thread:first-child { border-top: 0; }
.forum-thread:hover .forum-thread-title strong { text-decoration: underline; }
.forum-thread-main { display: grid; gap: 4px; min-width: 0; }
.forum-thread-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.forum-thread-title strong { font-weight: 620; }
.forum-thread-by, .forum-thread-when { font-size: var(--text-caption); }
.forum-thread-count { display: grid; justify-items: end; gap: 0; text-align: right; }
.forum-thread-count strong { font-variant-numeric: tabular-nums; font-weight: 650; }
.forum-thread-count span { font-size: var(--text-micro); }
.forum-thread-when { text-align: right; }
.forum-more { display: flex; justify-content: center; margin-top: var(--space-4); }

/* Pinned, locked, removed. Quiet, because they are conditions rather than news. */
.forum-tag {
  display: inline-flex; align-items: center; height: 18px; padding: 0 7px; border-radius: var(--radius-pill);
  background: var(--surface-2); color: var(--text-2);
  font-size: var(--text-micro); font-weight: 650; flex: 0 0 auto;
}
.forum-tag.stop { background: color-mix(in srgb, var(--red) 15%, transparent); color: var(--red); }

/* Answered. The one green thing on the page. */
.forum-answered { display: inline-flex; align-items: center; gap: 5px; color: var(--green); font-size: var(--text-caption); font-weight: 650; flex: 0 0 auto; }
.forum-answered .icon { width: 15px; height: 15px; }

/* One discussion. */
.forum-title-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.forum-post { display: grid; gap: var(--space-3); }
.forum-post + .forum-post { margin-top: var(--space-3); }
.forum-question { border-color: var(--line-strong, var(--line)); }
.forum-post-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
.forum-who { display: inline-flex; align-items: center; gap: 8px; text-decoration: none; color: inherit; min-width: 0; }
.forum-who:hover .forum-who-name { text-decoration: underline; }
.forum-who-name { font-weight: 650; font-size: var(--text-label); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.forum-post-head-end { display: inline-flex; align-items: center; gap: 12px; flex: 0 0 auto; }
.forum-post-when { font-size: var(--text-caption); flex: 0 0 auto; }
.forum-body { display: grid; gap: var(--space-3); }
.forum-body p { margin: 0; line-height: 1.55; overflow-wrap: anywhere; }
.forum-post-acts { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.forum-helpful.on, .forum-post-acts .quiet-button.on { color: var(--blue); }
.forum-helpful-count { font-size: var(--text-caption); }

/* The answer, lifted to where somebody who came for it will see it. */
.forum-lift { display: grid; gap: var(--space-3); margin-top: var(--space-5); }
.forum-lift-head { display: flex; align-items: center; gap: 6px; margin: 0; font-size: var(--text-label); font-weight: 680; color: var(--green); }
.forum-lift-head .icon { width: 16px; height: 16px; }
.forum-answer-card { box-shadow: var(--glass-rim), inset 0 0 0 1px color-mix(in srgb, var(--green) 34%, transparent); }
.forum-answer-card .forum-answered { display: none; }
.forum-post.is-answer { box-shadow: var(--glass-rim), inset 0 0 0 1px color-mix(in srgb, var(--green) 34%, transparent); }

/* A section heading belongs to what follows it, which is the rule stated beside .page.
   The page gap sits above and below it already, so the margins here are measured against
   that gap rather than added to it blindly: a little more above, and the gap below pulled
   back in, giving 32 above and 12 below instead of 48 and 36 - which had the heading
   nearer what came before it than what it names. */
.forum-replies-head { margin: var(--space-2) 0 calc(var(--space-3) * -1); font-size: var(--text-label); font-weight: 680; color: var(--text-2); }
.forum-replies { display: grid; gap: var(--space-3); }

/* A reply that was taken down keeps its place so the conversation still reads. */
.forum-removed { display: grid; gap: 4px; padding: 12px 14px; border-radius: var(--radius-sm); background: var(--surface-2); }
.forum-removed strong { font-size: var(--text-label); }
.forum-removed-body { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line); }
.forum-removed-body p { margin: 0 0 6px; font-size: var(--text-caption); color: var(--text-2); }

.forum-reply, .forum-edit { display: grid; gap: var(--space-3); }
.forum-reply > label { font-size: var(--text-small); color: var(--text-2); font-weight: 600; }
.forum-moderation { display: grid; gap: var(--space-3); }
.forum-moderation h2 { margin: 0; font-size: var(--text-label); font-weight: 650; }
.forum-moderation p { margin: 0; }

@media (max-width: 720px) {
  .forum-thread { grid-template-columns: minmax(0, 1fr) auto; gap: 8px 12px; }
  .forum-thread-count { grid-column: 1; justify-items: start; text-align: left; flex-direction: row; }
  .forum-thread-count { display: flex; align-items: baseline; gap: 5px; }
  .forum-thread-when { grid-column: 2; text-align: right; }
}

/* One person, opened: what they hold, and what colleagues have written down. */
.admin-holdings, .admin-notes { display: grid; gap: 6px; }
.admin-note { display: grid; gap: 4px; padding: 10px 12px; border-radius: var(--radius-sm); background: var(--surface-2); }
.admin-note p { margin: 0; font-size: var(--text-caption); color: var(--text); overflow-wrap: anywhere; }
.admin-note-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.admin-note-foot .subtle { font-size: var(--text-micro); }
