:root {
  --cursor-default: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAGYktHRAAAAAAAAPlDu38AAAAHdElNRQfqBx4TFSBrVrUNAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDI2LTA3LTMwVDE5OjIwOjExKzAwOjAwT+K1yAAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyNi0wNy0zMFQxOToyMDoxMSswMDowMD6/DXQAAAAodEVYdGRhdGU6dGltZXN0YW1wADIwMjYtMDctMzBUMTk6MjE6MzIrMDA6MDD1pVp1AAAJC0lEQVRYw8XUSYwcVx0G8O/Ve7V29d7TPT3TMx6PZzw2djyO8CITJZAQJTiRSWyCUBASQko4cAAkTkEcyDVikTggIRTEAQmFSCgiAiEggZDFOGA7jrPYY8+4Z/N0z/RW1dXd1VVv4WAFlNVmCXynd3jS/6e/3veA/3PoW4c77vrks/P75ycrM5W173/5B+1BsofMeBo7d84CuxU6C96HC8hkc3dmk5mv5jP5u8+snRmLedx8dfmVxu7xPcocGDiw/yCi/BCtlfaHA3AzGRIP42O2aZRNpt9KNfP4tuLUnlhEgd/za4X0SGxpFhYXFrH/E/tQq9b/u4DsaKEjOY4SGY1+bJcNW4cbDNR+qlkn0m76yDAOMYzDjaN33NtXQgFZgpm5GdBHYnhP9/5zwBfdzweXjSu7oejhckrg1vkcSimJXhAYvZDM6LrzaddJ3un1O8lBNKj94bHfdp5+/tcgZymmZ6YhjsTong/+fYBfCSEhGQH9DJRgk6MZHL7tKLaNaEhpbQRBoAUDjDlO6u58NnvvUy/+quIHfuNi4/zWjtycMtsm9s7thZoUaF/p/OuA9GgOEsqn0I5p1BgpJzl2zx/C3IG7MFoexUQeSDEPvaCLMKY5QL8FkhwvJyd2cxH7vWG3nraznHEdj3/t5zjdeQlba40bB9iVNJafXAiKvxi9iWjGgbQlMJqzMDI+jeLkLhTK21EqlVBOc1hiC81mC8FAuYyZNxvMOGGxxKFhPBTDONyohWsDKRTCRA8zO2dRW6ldH5ArFVB5YhICwtBAT1gGo+NZgnyhBMvNwE6k4aayKIxNY2RkBCV3iATpoBt0EQxgWpazM+Ek7k+5yduDQWCHcbhx/NCDftNrIFVOYtuOKYhbBwheHbw3wLrLgV7XISG7FPQ+jZr5kcQQk9smYRgGTDsBBQVGGVK5IooTsygVi5jIcOTsPrxugE7AqaHbFdu2j+pUv2d580ox5tHmyT+ebMzftA9Gy8Ls7CzUHgHvov92QO+cD2csjSuDi0HJGNtPqXFz0hSYGsshky9BN0wwpgMgICBghoFcsYLixByKI3lsK0gkWYC1jS10gpgkHLeQdN2PW4Z5//Yd0ztiEbVr3ka9kpuQDrdRvbT8dgAA5PNFTNlT4BCOqVvHDZ1pEzmF8amdoFSHbiWuATQCpRSU4DBMC9mRCrKj0yhkkpjMRkhoPazXW2j7ESzLTjm2fdBgxomMnd0nwQPbNTcvvrYQvQtg3ZmEtqlBSB5o0O4zTCebswbYPj0Dy3bATBuUalBKAUohDvvgwxCCR9B1A7nRKRTKMyjmEtheiGHTAVauttALBdyEaxtM3ytifiLwgo9cWao++S5A8FoH7ngaDbS7SeEcUJLu00mEmYkccqUKlJRgugkoCYAABJAihpICUdhHt9NE2A+giI5+P4TL+iimgMXlOurNPmq1Otav1gYdr/PjVrP1NwBg76yFKXRsJ5OCk/h3EY8f3ApMbaW6iKndH4WUErplgzEdSkloGgWhDPGgh67fwVr1ErrNVawsr2KhWke1FqIvLCjmwu96aLc7Umniu1dp9UdvzdPeCWgUfERaBKHJl4Tg60HEcGWlBq9ZhxQcUTgAyLU3IHgEEUeguoFsoYRMroD6ahXnL6zi1GWOtsgj4AY2NlvodgMQiicEi79XVpPyXTV8K4MrPhLjafgk8G1hHdZ1a49OOLaNuiiUJwGloFEKEYXgUQjJYxAQUKYjkytCQQMGGwiGCpdX2thqNOQgHKyDqF8Spr5FBduCUvA63nsDAKCcqyCHlIwVT1NCjxmGQUaTMSam58CYDsoM+F4Lw7APw7QgOL+2TqojXxpHNIyQpg10Q4LukDQ1Qz20tHD5O5lszmMw0J1roX85fH8AmacwQxNKUz2qtBO64aQc0kVlfBROIg3BYyy9cQpLb56BmyrATriQgkMBYLqB/GgFfruFSjpEu8+cWJrJ8vbSM5lsppfOJ3H55UXIUL4/oL/URWosg57q+zaxjzBq7DaZQKVgIZMfBY+HOH/6BTz34iuIgk2kM3m4qSyk4IBSsJwEcqUJeFurGMtwrDXkXBSzgtDDZzRCo0plAiuLK+8PAIBKfhJ5MycFRIZSdkwjFAV7iMrUDIJOHSdPnsKpS0PU6w1o4QYSrgs7kQIfXvvrnWQKbrYMr7aEco5ivanmCUytS9rPaZLJtaXVDwaQXQYsYUIR1adSOwFNTzokwOTkGDavLuIv59bRjpPY9ATa7Q7QW0fCsZBIFUAIIOIIiWQaup0F95YxkrPJ6qY4KEPWfOFzf/7ro08/+sGA3rKHVDmHSOM+jbRbiMbmTCZRdDmq1VVcqGuoN3z4QQ+xlkTb60H215FOmkhlS6BMBx8O4bhJeP4ANpoII8k2O/LwT9/4ydXqUvX8BwIAYCY9Cx1MxOB5ptF7GDOQYR0s1WKsexSbW1tyMBy8IqRMCeoaLS+E6K4jaROYTho8juB3mlhbfB3Pv/Qqzi1sot4KnSgaBrWN2lPXBWCvDiPSAaIGGrQHKDMTiHuo92ys1T0Mo7CqdPFZHos3oyg+wonjNP0YYXsVNg1h2Cl4W1WcO3saL19oY2lTIOLRn/ye9/Vup9u5LqBbbSMzPgKuCV9X7Daq0dmh0LHeCOB3u9AofljgU08w3zwdWt03OecHB5zlG74A79aRNgfw2nU8f2YVCzUFoXCJMPGwTowL7VYL198AgD1iHmaK8ZiIEUbop/zeEO2OB0rJbwTjjwyo3+86LVjcWRBafFJwcdMgIhOtHjDwW1jd6OBsNcZQaE2J+Cs67OeWrYsQm7gxgDhEwGIGRdQQEg/4XtcBkWfB5MNUslUiNcQ6R8OqI8UzVyM5fFYJNdUfyl1bvsDVVoxgSIaEym/e7X7hZ+ejF2FJB0Gzd2MAv9pGdqIAMOVrMbld8NhUmniISv3seGcOa7kL2Hy9jmwhB3eQhtR4R1LxeygkIk72x0rTpOLf90T7saX4dQkA65c2/ln36wEAQEFhfmY/eEJ9g0dRxxbu4017HUoQrL929R/3cgcKSDUzUEyCU2Fb0vw21bRdsRZ+SZNaS0iJ6kL1Rkb+7/J3ttJzezQt/+QAAAAASUVORK5CYII=') 2 2, default;
  --cursor-action: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAGYktHRAAAAAAAAPlDu38AAAAHdElNRQfqBx4TFSEcUYWbAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDI2LTA3LTMwVDE5OjIwOjEzKzAwOjAw2H2k4QAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyNi0wNy0zMFQxOToyMDoxMyswMDowMKkgHF0AAAAodEVYdGRhdGU6dGltZXN0YW1wADIwMjYtMDctMzBUMTk6MjE6MzIrMDA6MDD1pVp1AAAI70lEQVRYw8XWSYwcVxkH8P97r/buru7qnp59sWfGThxnGYwdB2IlBBxlgSxeIjhwTC4ckLhEiuCSM9spkEMEJ4SUA0pQBBEQBYWEhGyjxAm2x54Z22PP9Ez3dFdXdXV11ds4hICy2QEC/E/v8vR++t73SR/wfw57/3D83luf/8KBa2dGdk5cfOLrP+6EQwkqkz527Z5D8RYHW4vb/11AUKkcnqhWvl31q3f+aXNxIpd8+51L7zR3j1ytSZdg4eobwK4iaC59tpB/ABy/TLJU3BN45hghxiHAPjJdm9nLFe9FWbdR94e5JS2cXV7B/jsXsH6m8dkCamNDHZ7jbsHz0dv3lVB0ZLETqQVCnWMlp3xTLjKdy3zj8I2395VQMIYNzO+ahf2wRueZ+D8HfNM40lv2Lu5Rih2cqXDce6iKsWKCqNuzeimbN0zvPs8pHo4G3VKWZ41nH3k2/PWrz4D8lWLn7A7Yxy20X+r8+4DejIAmmkHTY5ILYzqgWLjpIGYqXZRpiCTJaJyS8UKhcke1XPnq068/NRX3e63V9HRzxp3TrEGxZ3YPvP0Wtt5t/euA8mgARVRMNb2HUKs+VkgwNzuO+QO3oe51MOUPENgZ+v0UA2FWoa2btcSRujW6R2gR91XcKLFA0AHDT25+EidHX0FjeevTA7zpMs69eaY38vjodRrG/ooL1FkDtbF5jF5zAFW3jaqbY7TAUSA9hGGEuI+CwZwFi1lHbbgHucpEpvKNhrOaylxBBRy7ds9j/dzGlQHV4TomHpuEhLQJ2FHXsdmEz1EQGyhM7ENhZAYlM0SlkCPwJOpejpKZIUlSxAPYjuXtLriF+33Xvy3Je24mso2vzN8Vhf0OypMlzMzOAIcl4jd7Hw9gtxpw2jY0dMTA7qPMrg0XBOolDhshiuPToFTDIAIlR6LqU9RKwERFo17SiHopwp5ipulOOrZzN4Nx13p4aZgrvvXyc39pXb/3Otihhfm5eRhfYmgvdj4ISN9NUJj0sWIt9UbU6AKh1ufKLjBVIyiaKVzfheVQEMMENRxYJkEtcFALDNRKBDvqBsquwqWNNrqJgOcWhvxi8VbbtO/bObtzVkB0munm5nhxXHmZg9WT5z8IAIBafRgzagckpOeYzhHLsuhURaBepjAYgVcdAtEC1LQAakBxCdt1UanY8IsUFVtgusZQNDnWm12EMYfreL7nejea1DzqG+UbFJU9r+RsnnprKf8IgBxyYHdMCC17DPR+y/aCITfH5JAJExm82ggYA7TIAK2QNDfQD0PkaQbTMhEELio+Q61EMTdiomBxnN8IkQwUioWia5nWtSITR+N2b+/qyrknPwJIT8bwpwJ0jCj2cueAVPQ6x9DYUSfwXQ1CCZxiAZqn712gBkTSheA54rCH1maEOM4hpUI/FaiUPIyWCc6eb2Kzk6Kx2cT6eiMNo/CJ9nb7NQAwPjwWjrDgq1HJifgdF+IbW4lNG9sc43ULnfV1eEEFlkGgBYflFSDKAbJWG1E8wFojA9cWtjo5VhoZVpsKfeVCmyXEcYROJ1Sayh9ulNYe/8gUvB/5eQNuYkMTnTBNjxqWV67YOSZqFBAZTNdDIahACYksjtALe7BsA+WyA0UYLqynOLHax+sXTXCzioGg2O50kSR9aCJ/qaz8uyVezrrt6OMB6ZkYhfEyIvQiRzoHTdPZaxsa475EyaUg0HA9E2nrEjobW+g0IxDGUPQLqJQt8JyDEYqEU5xZ66K53ZL9QbpOqP4VMfT3qGRNKKAbdj8eAAAT1SkEtKwERJlRdo9lOWSsmGOkasF2GIq+i26nj3YrBdEaaT8HCINbcBH4JrKMo1Y0EGcMcc7azMWDK6eXf1AJgq6pHHQXOkhPpZ8MwD4GO7UB+t43mJbn+8YAdZ/Acw0QlWF5NcKFjRyOSWEYBGl/AEIMeAUb1YqFMBxgZthDe2B5uXaK4/Ojf6gE5b4/VMDKm6uQPfnJgP5yjNJ4BYlOIo+4X2TM3uOYwJgvUfQIGCV4dznBS2+3ARAUHQOOzZANMoBS+L6NamAjDPuYHHKx1tRX5TmrCnvwHAPjk2OTuHD2wmUqAGC6NI2aW1WSyopBja8RamDIGWB82IZQBC+/3cWfVzRa4QCuSeBaBgg04iiFVkC5WoJf8RC2IkyOFLDWJgtU20jd6AUimFpbvnh5ADlgwU4tKOiUKHIMMIpFI8PMqI12l+OlUxwd4WOzKxElHI6hYZsMjBIoLpDEKTzXhu1a0HmOkSGfXGiqG3lCtl8cffG1R99+9PKA3tku/MkAwpBdxukhSo2rXBMYrxCcW89wqulhsx0h6vXBmY9uIuAaCoHvwDIpoDXibh9EKYRxjqDkYMBhbIX64M+Tn62fWzl/4rIAAJgvzsNUhhSQNUrY3YZpoWrnOLNFcTE2sdVsqUE+WORC+oIWrU5PwSIC5aINnivESY5WO0XYk3j1nQbeOruNrc7Ay3nWa2xsPnVFANtvw8xMaKpTqskxZtgF8BSNvotLW11kebaqmXxASnmK5+ImQVxvO1bQPEPJM6ClBDFMrLU4Xl2KsdJUyEX+fNTvficOe+EVAd3lDqpTdSgTkSHpLZSwXQNl4lIzRhwnoAyPDQ+mnkTTfiMr9U5yLg+kwqi1YgWmOSZGfUhi4sUTbZzeAqTWSzDUQxasU+3Oh/aBT8oefQ1MlwkOMcwouyNKMnTCCIzhN9LIH0nNuJ8EXdi5s6SYeFkIcX2fk8lOQpAPclzc6mPxgkSu6LYi4lsW8V5YcpeAv6+LVwRgnwlDMIAgg8TxKIo9ELUIQz3EFFujkoFbEtulJnxeWc+RPw+pd/QG6upmrHCpIxFnJAOTj9y+ffwXJwqvwOMOknb/0wG659sYmq6DmIhIji8LwS3N5INMmouTG3NYmzuLzcVNlKsBKmkVgvKOMuTvIVHIBRa4ZlRq/qMQ7e+f804rUGB9afOffXbFCgDYeqCBn77xGOdM1KUSv3Wz0tNR0EIraGDz9SYAoN9MIOZyeKkHUKTcEn80NHMJ0S3JsocduIkGcOHUxU/z5P8ufwOKnVyMWe/wEwAAAABJRU5ErkJggg==') 2 2, pointer;
}

html,
body {
  cursor: var(--cursor-default);
}

/* Above every HUD window, floating number and lifted action bar: the badge is
   part of the pointer, so nothing the pointer travels over may cover it. */

.world-cursor-badge {
  position: fixed;
  inset: 0 auto auto 0;
  z-index: 140;
  width: 28px;
  height: 28px;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
  filter: drop-shadow(0 1px 1px rgb(0 0 0 / 68%));
  transform-origin: 0 0;
}

.world-cursor-badge[data-state='pressed'] {
  filter: drop-shadow(0 1px 0 rgb(0 0 0 / 72%));
}

/* Same badge, less weight: the armed skill stays named while the spot under the
   pointer says it cannot take the cast. */

.world-cursor-badge[data-legality='blocked'] {
  opacity: 0.42;
  filter: saturate(0.25) drop-shadow(0 1px 1px rgb(0 0 0 / 68%));
}

/* The HUD gauge: every proportional readout is this one box, so a monster at 40% looks the same overhead, in the target frame and in the party rail. No surface may invent its own track-and-fill.
   Knobs a surface may set on `.hud-gauge`:
     --gauge-h        row height, a whole number of HUD pixels (--gp)
     --gauge-clip     the box's outline; `none` for a bar too narrow to notch
     --gauge-ring     the state edge inside the ink outline — this is how a
                      gauge shows state; transparent at rest
     --gauge-ring-w   the edge width
     data-band        a banded state — health or carried load — which paints the
                      edge from the same table the fill reads
   and on `.hud-gauge-fill`:
     --gauge-fill     the share filled, as a percentage (hud-gauge.ts writes it)
     background       the fill's paint
     data-band        the band's fill paint
*/

.hud-gauge {
  --gauge-h: calc(7 * var(--gp));
  --gauge-clip: var(--pixel-notch);
  --gauge-ring: transparent;
  --gauge-ring-w: var(--gp);
  position: relative;
  width: 100%;
  height: max(var(--gauge-h), calc(var(--type-metadata-readable-size) * 1.2 + 2 * var(--gp)));
  box-sizing: border-box;
  background: var(--pixel-night);
  border: var(--gp) solid var(--pixel-ink);
  overflow: hidden;
  clip-path: var(--gauge-clip);
}

/* The state edge and end caps ride a pseudo-element above the fills; an inset shadow paints on the background layer and a full gauge would bury it. */

.hud-gauge::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  box-shadow: inset 0 0 0 var(--gauge-ring-w) var(--gauge-ring);
  background:
    linear-gradient(
      180deg,
      rgb(255 255 255 / 30%) 0 var(--gp),
      transparent var(--gp) calc(100% - 2 * var(--gp)),
      rgb(0 0 0 / 22%) calc(100% - 2 * var(--gp)) calc(100% - var(--gp)),
      rgb(0 0 0 / 40%) calc(100% - var(--gp))
    ),
    linear-gradient(
        90deg,
        var(--pixel-lilac) 0 var(--gp),
        var(--pixel-slate) var(--gp) calc(2 * var(--gp)),
        var(--pixel-ink) calc(2 * var(--gp)) calc(3 * var(--gp))
      )
      left / calc(3 * var(--gp)) 100% no-repeat,
    linear-gradient(
        90deg,
        var(--pixel-ink) 0 var(--gp),
        var(--pixel-slate) var(--gp) calc(2 * var(--gp)),
        var(--pixel-dusk) calc(2 * var(--gp)) calc(3 * var(--gp))
      )
      right / calc(3 * var(--gp)) 100% no-repeat;
}

.hud-gauge--sm {
  --gauge-h: calc(5 * var(--gp));
}

/* Progression strips are a line, not a row: one lit row and narrower caps. */

.hud-gauge--xs {
  --gauge-h: calc(4 * var(--gp));
  height: var(--gauge-h);
}

.hud-gauge--xs::after {
  background:
    linear-gradient(180deg, rgb(255 255 255 / 30%) 0 var(--gp), rgb(0 0 0 / 30%) var(--gp)),
    linear-gradient(
        90deg,
        var(--pixel-lilac) 0 var(--gp),
        var(--pixel-ink) var(--gp) calc(2 * var(--gp))
      )
      left / calc(2 * var(--gp)) 100% no-repeat,
    linear-gradient(
        90deg,
        var(--pixel-ink) 0 var(--gp),
        var(--pixel-dusk) var(--gp) calc(2 * var(--gp))
      )
      right / calc(2 * var(--gp)) 100% no-repeat;
}

/* Registered so the share animates and the drawn width snaps to the grid every frame. */

@property --gauge-fill {
  syntax: '<length-percentage>';
  inherits: false;
  initial-value: 0%;
}

.hud-gauge-fill {
  position: absolute;
  inset: 0 auto 0 0;
  z-index: 1;
  /* The fill ends on a whole HUD pixel: any nonzero share shows at least one, and only a full share covers the track. */
  width: max(
    min(var(--gp), calc(var(--gauge-fill, 0%) * 10000)),
    min(
      round(nearest, var(--gauge-fill, 0%), var(--gp)),
      calc(round(up, 100%, var(--gp)) - var(--gp))
    ),
    calc((var(--gauge-fill, 0%) - 100%) * 10000 + 100%)
  );
  height: 100%;
  background: var(--hud-hp-healthy-fill);
  box-shadow: inset calc(-1 * var(--gp)) 0 0 rgb(255 255 255 / 35%);
  transition: --gauge-fill 0.2s ease-out;
}

/* Health is banded, not a fixed red: the colour is the triage read, the same everywhere. The percentage carries the number. */

.hud-gauge-fill[data-band='healthy'] {
  background: var(--hud-hp-healthy-fill);
}

.hud-gauge-fill[data-band='hurt'] {
  background: var(--hud-hp-hurt-fill);
}

.hud-gauge-fill[data-band='execute'] {
  background: var(--hud-hp-execute-fill);
}

/* Load is banded by what it costs, not how full the bag looks, so an unencumbered bag is pewter. One table keeps the panel and the inventory footer in agreement. */

.hud-gauge-fill[data-band='light'] {
  background: var(--hud-load-light-fill);
}

.hud-gauge-fill[data-band='heavy'] {
  background: var(--hud-load-heavy-fill);
}

.hud-gauge-fill[data-band='overloaded'] {
  background: var(--hud-load-overloaded-fill);
}

/* The worst band adds a one-pixel diagonal hatch so overload reads in greyscale and to red-blind players. */

.hud-gauge-fill[data-band='overloaded']::after {
  --hatch: conic-gradient(at var(--gp) var(--gp), transparent 270deg, rgb(0 0 0 / 28%) 0);
  content: '';
  position: absolute;
  inset: 0;
  background:
    var(--hatch) 0 calc(2 * var(--gp)) / calc(3 * var(--gp)) calc(3 * var(--gp)),
    var(--hatch) var(--gp) var(--gp) / calc(3 * var(--gp)) calc(3 * var(--gp)),
    var(--hatch) calc(2 * var(--gp)) 0 / calc(3 * var(--gp)) calc(3 * var(--gp));
}

.hud-gauge[data-band='heavy'] {
  --gauge-ring: var(--hud-load-heavy-ring);
}

.hud-gauge[data-band='overloaded'] {
  --gauge-ring: var(--hud-load-overloaded-ring);
}

/* High contrast swaps the resting ring for white, but an edge that carries meaning keeps its colour; stated at this specificity so the blanket white edge below does not erase the band. */

body.high-contrast .hud-gauge[data-band='heavy'] {
  --gauge-ring: var(--hud-load-heavy-ring);
}

body.high-contrast .hud-gauge[data-band='overloaded'] {
  --gauge-ring: var(--hud-load-overloaded-ring);
}

/* Recent-damage ghost: JS snaps it up on a heal and lets it lag on a hit, so the strip shows the last hit's size. */

.hud-gauge-fill--ghost {
  z-index: 0;
  background: var(--hud-hp-ghost-fill);
  transition: --gauge-fill 0.4s ease-out;
}

body.reduce-flashing .hud-gauge-fill--ghost {
  transition: none;
}

.hud-gauge-label,
.hud-gauge-pct {
  position: absolute;
  inset-block: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  font: var(--type-weight-strong) var(--type-metadata-readable-size) / var(--type-leading-solid)
    var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
  color: #fff;
  text-shadow: var(--hud-vitals-text-shadow);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.2px;
  white-space: nowrap;
  pointer-events: none;
}

.hud-gauge-label {
  inset-inline: 0;
  justify-content: center;
  padding-inline: calc(4 * var(--gp));
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Current/max and percentage take separate columns; long readings ellipsise, never wrap. */

.hud-gauge--split {
  display: flex;
  align-items: center;
}

.hud-gauge--split .hud-gauge-label {
  position: relative;
  inset: auto;
  flex: 1;
  min-width: 0;
  display: block;
  text-align: start;
  padding-inline-end: calc(2 * var(--gp));
  line-height: max(
    calc(var(--gauge-h) - 2 * var(--gp)),
    calc(var(--type-metadata-readable-size) * 1.2)
  );
}

.hud-gauge--split .hud-gauge-pct {
  position: relative;
  inset: auto;
  flex: none;
  padding-inline-end: calc(4 * var(--gp));
}

.hud-gauge-max {
  white-space: pre;
}

.hud-gauge-pct {
  inset-inline: auto calc(4 * var(--gp));
  justify-content: flex-end;
}

.hud-gauge--sm .hud-gauge-label,
.hud-gauge--sm .hud-gauge-pct {
  font-size: var(--type-glyph-readable-size);
  font-family: var(--type-glyph-readable-family);
  -webkit-font-smoothing: var(--type-glyph-readable-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.03em;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

/* No reading must not look like an empty bar: a lighter track, a paler edge and a dash, none of them a hue. */

.hud-gauge--unknown {
  --gauge-ring: var(--pixel-lilac);
  background: var(--pixel-dusk);
}

.hud-gauge--unknown .hud-gauge-label {
  color: var(--pixel-lilac);
  text-shadow: none;
}

@media (prefers-reduced-motion: reduce) {
  .hud-gauge,
  .hud-gauge-fill {
    transition: none !important;
  }
}

body.reduce-motion .hud-gauge,
body.reduce-motion .hud-gauge-fill {
  transition: none !important;
}

/* High contrast gives every gauge a white inner edge; an edge that carries meaning (rank, cast tier) keeps its colour. */

body.high-contrast .hud-gauge {
  --gauge-ring: rgba(255, 255, 255, 0.82);
}

/* ===== The cast bar ====================================================
   Every windup the HUD draws is this one instrument: the focused target's in
   its frame and the character's own under their feet. The skill's icon in a
   notched chip, then a gauge (hud-gauge.css) in the cast's colour. Same parts,
   same height; the target's gauge also carries the name and the clock, which
   the player casting their own skill already knows.
   Knobs on `.hud-cast`:
     --cast-fill   the fill's paint; data-tier picks it from the tier table
     --cast-h      the bar's height, a whole number of HUD pixels
   and on `.hud-cast-fill`:
     --cast-p      the share drawn (0–1), rounded down to whole HUD pixels
   Structure:
     <host class="hud-cast" data-tier>
       <img class="hud-cast-icon">
       <div class="hud-gauge hud-cast-track">
         <div class="hud-gauge-fill hud-cast-fill" style="--cast-p: .4"></div>
         <span class="hud-gauge-label">…</span>          (optional)
         <span class="hud-gauge-pct">…</span>            (optional)
       </div>
     </host>
*/

.hud-cast {
  --cast-h: max(
    calc(9 * var(--gp)),
    round(up, calc(var(--type-metadata-readable-size) * 1.2 + 2 * var(--gp)), var(--gp))
  );
  --cast-fill: var(--cast-strong);
  display: grid;
  grid-template-columns: var(--cast-h) minmax(0, 1fr);
  column-gap: var(--gp);
  align-items: center;
  height: var(--cast-h);
}

.hud-cast[data-tier='routine'] {
  --cast-fill: var(--cast-routine);
}

.hud-cast[data-tier='strong'] {
  --cast-fill: var(--cast-strong);
}

.hud-cast[data-tier='signature'] {
  --cast-fill: var(--cast-signature);
}

.hud-cast[data-tier='critical'] {
  --cast-fill: var(--cast-critical);
}

/* A windup that broke, or that hits are pushing back, outranks its tier. */

.hud-cast.interrupted {
  --cast-fill: var(--danger);
}

.hud-cast.pushback {
  --cast-fill: var(--warn);
}

.hud-cast-icon {
  display: block;
  box-sizing: border-box;
  width: var(--cast-h);
  height: var(--cast-h);
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  object-fit: contain;
  clip-path: var(--pixel-notch);
}

.hud-cast-track {
  --gauge-h: var(--cast-h);
  --gauge-ring: color-mix(in srgb, var(--cast-fill) 62%, var(--pixel-ink));
}

/* A block, so a long name ends in an ellipsis (a flex label just overflows),
   short of the clock. */

.hud-cast-track .hud-gauge-label {
  display: block;
  /* The row inside the gauge's one-pixel border. */
  line-height: calc(var(--cast-h) - 2 * var(--gp));
  text-align: center;
}

.hud-cast-track.hud-gauge--split .hud-gauge-label {
  text-align: start;
}

body.high-contrast .hud-cast-track {
  --gauge-ring: color-mix(in srgb, var(--cast-fill) 82%, #fff);
}

.hud-cast-fill {
  --cast-p: 0;
  width: round(down, calc(var(--cast-p) * 100%), var(--gp));
  /* A step toward ink, so a bright tier reads as a fill and not a slab under
     the white name. */
  background: color-mix(in srgb, var(--cast-fill) 78%, var(--pixel-ink));
  transition: none;
}

/* Ront typography design system.
 * The interface face is a pixel font drawn on a 9px grid. It is sharp only when
 * each of its pixels covers a whole number of screen pixels, so this file names a
 * logical size for every pixel role and rounds it up to the next size that is
 * sharp on the screen in front of the player. No text is drawn smaller than its role:
 *   small    12px    numbers in gauges, timers, key hints, metadata
 *   text     14px    labels, body text, chat, quest lines
 *   reading  18px    names, headings, window titles
 *   3x/4x/5x 27-45px display titles, the pre-game wordmark
 * Small and text roles use a smooth face: the pixel face has no sharp 9-18px size at 1x.
 *   --font-ui-compact  bold only      small and text roles
 *   --font-ui          regular, bold  names, numbers, body text, titles
 *   --font-ui-large    bold only      headings
 * Silkscreen, the display voice for titles, draws at 8/9 size on its own 8px grid.
 * A role's size, family and smoothing travel together: a rule that sets
 * `--type-X-size` sets `--type-X-family` and `--type-X-smoothing` beside it.
 * text-size.ts is the only writer of the two inputs: `--type-scale`, the player's
 * Text size times a desktop HUD's growth past 1x, and `--type-device-ratio`,
 * screen pixels per CSS pixel. A box that holds text sizes itself from these
 * roles, never from `--ui-scale` or `--gp`. */

:root {
  --font-display: 'Silkscreen', 'Ront UI', monospace;
  --font-ui: 'Ront UI', 'Ront UI Small', monospace;
  --font-ui-small: 'Ront UI Small', 'Ront UI', monospace;
  --font-ui-large: 'Ront UI Large', 'Ront UI', monospace;
  --font-ui-compact: 'Ront UI Compact', 'Ront UI', sans-serif;

  --type-grid: 9px;
  --type-scale: 1;
  --type-device-ratio: 1;
  /* One face pixel on one screen pixel: every size is a whole number of these.
     The 0.01px keeps a size that already is one, but reads a hair over after
     the division, from rounding up a whole step. */
  --type-step: calc(var(--type-grid) / var(--type-device-ratio));
  --type-small-size: calc(12px * var(--type-scale));
  --type-text-size: calc(14px * var(--type-scale));
  --type-compact-size: round(
    up,
    calc(1.5 * var(--type-grid) * var(--type-scale) - 0.01px),
    var(--type-step)
  );
  --type-reading-size: round(
    up,
    calc(2 * var(--type-grid) * var(--type-scale) - 0.01px),
    var(--type-step)
  );
  --type-tier-3x: round(
    up,
    calc(3 * var(--type-grid) * var(--type-scale) - 0.01px),
    var(--type-step)
  );
  --type-tier-4x: round(
    up,
    calc(4 * var(--type-grid) * var(--type-scale) - 0.01px),
    var(--type-step)
  );
  --type-tier-5x: round(
    up,
    calc(5 * var(--type-grid) * var(--type-scale) - 0.01px),
    var(--type-step)
  );

  /* Cockpit roles share the compact and reading sizes; hierarchy comes from
     weight, colour and case. */
  --type-ornament-size: var(--type-small-size);
  --type-ornament-family: var(--font-ui-compact);
  --type-ornament-smoothing: antialiased;
  --type-badge-size: var(--type-small-size);
  --type-badge-family: var(--font-ui-compact);
  --type-badge-smoothing: antialiased;
  --type-glyph-size: var(--type-small-size);
  --type-glyph-family: var(--font-ui-compact);
  --type-glyph-smoothing: antialiased;
  --type-micro-size: var(--type-small-size);
  --type-micro-family: var(--font-ui-compact);
  --type-micro-smoothing: antialiased;
  --type-metadata-size: var(--type-small-size);
  --type-metadata-family: var(--font-ui-compact);
  --type-metadata-smoothing: antialiased;
  --type-label-size: var(--type-text-size);
  --type-label-family: var(--font-ui-compact);
  --type-label-smoothing: antialiased;
  --type-relative-secondary-size: var(--type-text-size);
  --type-relative-secondary-family: var(--font-ui-compact);
  --type-relative-secondary-smoothing: antialiased;
  --type-body-compact-size: var(--type-text-size);
  --type-body-compact-family: var(--font-ui-compact);
  --type-body-compact-smoothing: antialiased;
  --type-body-size: var(--type-text-size);
  --type-body-family: var(--font-ui-compact);
  --type-body-smoothing: antialiased;
  --type-prose-size: var(--type-text-size);
  --type-prose-family: var(--font-ui-compact);
  --type-prose-smoothing: antialiased;
  --type-heading-size: var(--type-reading-size);
  --type-heading-family: var(--font-ui-large);
  --type-heading-smoothing: none;
  --type-section-heading-size: var(--type-reading-size);
  --type-section-heading-family: var(--font-ui-large);
  --type-section-heading-smoothing: none;

  /* Titles take the weight their own rule asks for; display roles step up the grid. */
  --type-window-title-size: var(--type-reading-size);
  --type-window-title-family: var(--font-ui);
  --type-window-title-smoothing: none;
  --type-title-size: var(--type-reading-size);
  --type-title-family: var(--font-ui);
  --type-title-smoothing: none;
  --type-callout-size: var(--type-reading-size);
  --type-callout-family: var(--font-ui);
  --type-callout-smoothing: none;
  --type-screen-heading-size: var(--type-reading-size);
  --type-screen-heading-family: var(--font-ui);
  --type-screen-heading-smoothing: none;
  --type-display-size: var(--type-tier-3x);
  --type-display-family: var(--font-ui);
  --type-display-smoothing: none;
  --type-death-heading-size: var(--type-tier-3x);
  --type-death-heading-family: var(--font-ui);
  --type-death-heading-smoothing: none;
  --type-overlay-heading-size: var(--type-tier-3x);
  --type-overlay-heading-family: var(--font-ui);
  --type-overlay-heading-smoothing: none;
  --type-screen-display-size: var(--type-tier-3x);
  --type-screen-display-family: var(--font-ui);
  --type-screen-display-smoothing: none;
  --type-screen-hero-size: var(--type-tier-3x);
  --type-screen-hero-family: var(--font-ui);
  --type-screen-hero-smoothing: none;
  --type-hero-size: var(--type-tier-3x);
  --type-hero-family: var(--font-ui);
  --type-hero-smoothing: none;
  --type-gameover-size: var(--type-tier-4x);
  --type-gameover-family: var(--font-ui);
  --type-gameover-smoothing: none;

  /* Composition roles for story and entry screens. */
  --type-narrative-lead-size: var(--type-reading-size);
  --type-narrative-lead-family: var(--font-ui);
  --type-narrative-lead-smoothing: none;
  --type-prologue-lead-size: var(--type-reading-size);
  --type-prologue-lead-family: var(--font-ui);
  --type-prologue-lead-smoothing: none;
  --type-cinematic-title-size: var(--type-tier-4x);
  --type-cinematic-title-family: var(--font-ui);
  --type-cinematic-title-smoothing: none;
  --type-pregame-hero-size: var(--type-tier-5x);
  --type-pregame-hero-family: var(--font-display);
  --type-pregame-hero-smoothing: none;
  --type-pregame-title-size: var(--type-reading-size);
  --type-pregame-title-family: var(--font-ui);
  --type-pregame-title-smoothing: none;
  --type-pregame-heading-size: var(--type-tier-3x);
  --type-pregame-heading-family: var(--font-display);
  --type-pregame-heading-smoothing: none;
  --type-pregame-body-size: var(--type-reading-size);
  --type-pregame-body-family: var(--font-ui);
  --type-pregame-body-smoothing: none;
  --type-pregame-metadata-size: var(--type-small-size);
  --type-pregame-metadata-family: var(--font-ui-compact);
  --type-pregame-metadata-smoothing: antialiased;
  --type-pregame-badge-size: var(--type-small-size);
  --type-pregame-badge-family: var(--font-ui-compact);
  --type-pregame-badge-smoothing: antialiased;

  /* Named floors and bounds from the fractional ramp. Every role is now at or
     above its floor, so each one is its base role. */
  --type-badge-readable-size: var(--type-badge-size);
  --type-badge-readable-family: var(--type-badge-family);
  --type-badge-readable-smoothing: var(--type-badge-smoothing);
  --type-glyph-readable-size: var(--type-glyph-size);
  --type-glyph-readable-family: var(--type-glyph-family);
  --type-glyph-readable-smoothing: var(--type-glyph-smoothing);
  --type-micro-readable-size: var(--type-micro-size);
  --type-micro-readable-family: var(--type-micro-family);
  --type-micro-readable-smoothing: var(--type-micro-smoothing);
  --type-metadata-readable-size: var(--type-metadata-size);
  --type-metadata-readable-family: var(--type-metadata-family);
  --type-metadata-readable-smoothing: var(--type-metadata-smoothing);
  --type-label-readable-size: var(--type-label-size);
  --type-label-readable-family: var(--type-label-family);
  --type-label-readable-smoothing: var(--type-label-smoothing);
  --type-body-compact-readable-size: var(--type-body-compact-size);
  --type-body-compact-readable-family: var(--type-body-compact-family);
  --type-body-compact-readable-smoothing: var(--type-body-compact-smoothing);
  --type-body-readable-size: var(--type-body-size);
  --type-body-readable-family: var(--type-body-family);
  --type-body-readable-smoothing: var(--type-body-smoothing);
  --type-prose-readable-size: var(--type-prose-size);
  --type-prose-readable-family: var(--type-prose-family);
  --type-prose-readable-smoothing: var(--type-prose-smoothing);
  --type-badge-bounded-size: var(--type-badge-size);
  --type-badge-bounded-family: var(--type-badge-family);
  --type-badge-bounded-smoothing: var(--type-badge-smoothing);
  --type-glyph-bounded-size: var(--type-glyph-size);
  --type-glyph-bounded-family: var(--type-glyph-family);
  --type-glyph-bounded-smoothing: var(--type-glyph-smoothing);

  /* Handheld layouts fold and scroll; they share the readable logical ramp. */
  --type-handheld-glyph-size: var(--type-small-size);
  --type-handheld-glyph-family: var(--font-ui-compact);
  --type-handheld-glyph-smoothing: antialiased;
  --type-handheld-micro-size: var(--type-small-size);
  --type-handheld-micro-family: var(--font-ui-compact);
  --type-handheld-micro-smoothing: antialiased;
  --type-handheld-metadata-size: var(--type-small-size);
  --type-handheld-metadata-family: var(--font-ui-compact);
  --type-handheld-metadata-smoothing: antialiased;
  --type-handheld-label-size: var(--type-text-size);
  --type-handheld-label-family: var(--font-ui-compact);
  --type-handheld-label-smoothing: antialiased;
  --type-handheld-body-compact-size: var(--type-text-size);
  --type-handheld-body-compact-family: var(--font-ui-compact);
  --type-handheld-body-compact-smoothing: antialiased;
  --type-handheld-body-size: var(--type-text-size);
  --type-handheld-body-family: var(--font-ui-compact);
  --type-handheld-body-smoothing: antialiased;
  --type-handheld-prose-size: var(--type-text-size);
  --type-handheld-prose-family: var(--font-ui-compact);
  --type-handheld-prose-smoothing: antialiased;
  --type-handheld-heading-size: var(--type-reading-size);
  --type-handheld-heading-family: var(--font-ui-large);
  --type-handheld-heading-smoothing: none;
  --type-handheld-title-size: var(--type-reading-size);
  --type-handheld-title-family: var(--font-ui);
  --type-handheld-title-smoothing: none;
  --type-handheld-screen-heading-size: var(--type-reading-size);
  --type-handheld-screen-heading-family: var(--font-ui);
  --type-handheld-screen-heading-smoothing: none;

  /* Approved emphasis. The face has a regular and a bold; every weight between
     answers with one of them, never a synthesized smear. */
  --type-weight-normal: 400;
  --type-weight-regular: 500;
  --type-weight-medium: 600;
  --type-weight-strong: 700;
  --type-weight-label: 700;
  --type-weight-display: 700;
  --type-weight-emphasis: 700;

  /* Leading follows content density rather than surface ownership. */
  --type-leading-solid: 1;
  --type-leading-tight: 1.2;
  --type-leading-compact: 1.3;
  --type-leading-body: 1.4;
  --type-leading-reading: 1.55;

  font-family: var(--font-ui);
  font-synthesis: none;
  /* macOS otherwise antialiases the glyph edges on a fractional x. */
  -webkit-font-smoothing: none;
}

/* Text no rule sizes would otherwise draw at the browser's 16px (13.33px in a
   button), which no cut is drawn for. `rem` stays on the root's 16px. */

body {
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
}

button,
input,
select,
textarea {
  font-size: inherit;
  font-family: inherit;
}

/* Numeric columns keep their rhythm without introducing another typeface. */

.type-data {
  font-variant-numeric: tabular-nums;
}

:root {
  --bg: #091013;
  --panel: #11191d;
  --panel-2: #192327;
  --panel-raised: #202c30;
  --accent: #c9a45e;
  --accent-2: #9e7138;
  --gold: #d9a441;
  --gold-value: #ffe066;
  --gold-ink: #ffe0a0;
  --gold-label: #f0d999;
  --text: #eee9de;
  --muted: #98a4a3;
  --danger: #d85b48;
  --ui-line: #344247;
  --ui-line-soft: rgba(133, 151, 153, 0.2);
  --ui-line-bright: rgba(188, 201, 196, 0.34);
  --ui-surface: #0d1417;
  --ui-surface-raised: #161f22;
  /* Hard offset shadow, no penumbra; blur stays 0 everywhere so the edge reads as a drawn line. */
  --ui-shadow: 4px 4px 0 rgba(0, 0, 0, 0.55);
  --ui-frame-fill: #151f23;
  --ui-frame-shadow:
    inset 2px 2px 0 rgba(236, 228, 205, 0.07), inset -2px -2px 0 rgba(0, 0, 0, 0.4);
  /* A surface with its own tone (only the death card) restates these three, inheriting the rest. */
  --ui-frame-glow: rgba(201, 164, 94, 0.08);
  --ui-tick-fill: linear-gradient(180deg, #ead8a5 0 55%, var(--accent-2) 55% 100%);
  --ui-tick-glow: rgba(201, 164, 94, 0.2);
  --ui-head-rule-lead: rgba(201, 164, 94, 0.42);
  --ui-control-fill: #0a1013;
  --ui-control-fill-hover: #253031;
  --ui-control-line: rgba(133, 151, 153, 0.28);
  --ui-control-line-hover: rgba(201, 164, 94, 0.58);
  /* Focus bracket drawn inside the piece so a notched piece's clip can't cut it off. */
  --ui-focus-ring: inset 0 0 0 var(--gp) var(--bg), inset 0 0 0 calc(2 * var(--gp)) var(--accent);
  /* How far a control sinks while held; a scrolling panel reserves this room to avoid scrollbar flicker. */
  --ui-press-travel: 1px;
  /* Device insets as one token set; surfaces read these rather than env() itself. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --good: #6fd06a;
  --info: #3498db;
  --skillmsg: #b48ce0;
  --warn: var(--accent-2);
  --grid-line: var(--ui-line);
  --row-hover: rgba(255, 255, 255, 0.04);
  --hotbar-h: calc(96px * var(--ui-scale));
  /* Accessibility UI scale: applyUiScale() overrides it on :root; HUD sizes scale off it via calc(). */
  --ui-scale: 1;
  --hud-edge: round(calc(12px * var(--ui-scale)), 1px);
  --hud-safe-top: max(var(--hud-edge), var(--safe-top));
  --hud-safe-right: max(var(--hud-edge), var(--safe-right));
  --hud-safe-bottom: max(var(--hud-edge), var(--safe-bottom));
  --hud-safe-left: max(var(--hud-edge), var(--safe-left));
  --hud-dock-row-right: calc(
    var(--hud-safe-right) + mod(100vw - var(--hud-safe-left) - var(--hud-safe-right), 2px)
  );
  --hud-gap: round(
    calc(8px * var(--ui-scale)),
    1px
  ); /* whole px; the row's right is an even width */
  /* Mobile Safari auto-inflates text, which would double up with sizes derived from the accessibility scale. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

* {
  box-sizing: border-box;
}

/* Every scrolling surface wears the slim brass bar; both properties inherit from the root, so a shadow-root surface wanting a different bar must restate it. */

:root {
  --ui-scrollbar-thumb: rgba(201, 164, 94, 0.45);
  --ui-scrollbar-track: rgba(7, 12, 14, 0.5);
  scrollbar-width: thin;
  scrollbar-color: var(--ui-scrollbar-thumb) var(--ui-scrollbar-track);
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* The page is a game: a press is a gesture, not text selection. Surfaces needing a caret opt back in below; `browser-menu-lock` handles menus CSS cannot reach. */

html,
body,
#app {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* Anything a caret goes into keeps selection working: an inherited `none` breaks `select()` on iOS. A shadow-rendered field must restate it. */

input,
textarea,
select,
[contenteditable]:not([contenteditable='false']) {
  -webkit-touch-callout: default;
  -webkit-user-select: text;
  user-select: text;
}

#app {
  display: flex;
  align-items: center;
  justify-content: center;
}

.screen {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.panel {
  padding: calc(12px * var(--ui-scale)) calc(14px * var(--ui-scale));
  width: calc(360px * var(--type-scale, 1));
}

.panel h1 {
  margin: 0 0 calc(8px * var(--ui-scale));
  font-size: var(--type-title-size);
  font-family: var(--type-title-family);
  -webkit-font-smoothing: var(--type-title-smoothing);
  letter-spacing: 0.15px;
}

.panel .subtitle {
  color: var(--muted);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  margin-bottom: 20px;
}

.field {
  margin-bottom: 14px;
}

.field label {
  display: block;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  color: var(--muted);
  margin-bottom: 6px;
}

.field input {
  width: 100%;
  padding: 10px 12px;
  background: var(--panel-2);
  border: 1px solid var(--ui-control-line);
  color: var(--text);
  font-size: var(--type-prose-size);
  font-family: var(--type-prose-family);
  -webkit-font-smoothing: var(--type-prose-smoothing);
}

.field input:focus {
  outline: none;
  border-color: var(--accent);
}

.status {
  margin-top: 14px;
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  min-height: 18px;
}

.status.error {
  color: var(--danger);
}

.status.info {
  color: var(--muted);
}

.char-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}

.char-card {
  background: var(--panel-2);
  border: 1px solid var(--ui-control-line);
  padding: 14px;
  cursor: var(--cursor-action);
  text-align: center;
  transition:
    border-color 0.15s,
    transform 0.1s;
}

.char-card:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}

.char-card .name {
  font-weight: var(--type-weight-medium);
  margin-bottom: 4px;
}

.char-card .meta {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  color: var(--muted);
}

.char-card.empty {
  color: var(--muted);
  cursor: var(--cursor-default);
  opacity: 0.5;
}

#game-canvas {
  width: 100vw;
  height: 100vh;
  display: block;
}

.hud {
  position: fixed;
  top: 12px;
  left: 12px;
  background: #0a0e14;
  border: 2px solid var(--ui-line-soft);
  padding: 10px 14px;
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  pointer-events: none;
}

.hud .row {
  margin: 2px 0;
}

.hud .label {
  color: var(--muted);
}

/* Containers do not capture clicks, so the canvas under them stays usable for movement. */

.overlay {
  position: fixed;
  pointer-events: none;
  z-index: 10;
}

/* A dock pins to one corner; a rail stacks widgets with a shared gap. Dragged widgets gain .hud-layout-detached and leave the flow. */

/* A rail widget whose reveal moment (onboarding-disclosure.ts) has not arrived. Important beats the widget's own visibility logic; the system behind it keeps running. */

.hud-disclosure-hidden {
  display: none !important;
}

/* One gold swell when the reveal arrives mid-session; removed on animationend (hud.ts). */

.hud-disclosure-revealed {
  animation: hud-disclosure-reveal 1.2s ease-out 2;
}

@keyframes hud-disclosure-reveal {
  0%,
  100% {
    filter: none;
  }
  50% {
    filter: brightness(1.25) drop-shadow(0 0 10px color-mix(in srgb, var(--gold) 60%, transparent));
  }
}

.hud-dock-row {
  position: fixed;
  display: grid;
  align-items: start;
  gap: var(--hud-gap);
  pointer-events: none;
  z-index: 10;
}

.hud-dock-row--top {
  top: var(--hud-safe-top);
  left: var(--hud-safe-left);
  right: var(--hud-dock-row-right);
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
}

:root:not([data-ui-profile='handheld']) .hud-dock-row--top {
  grid-template-columns: minmax(0, 1fr) minmax(var(--hud-center-width, 0px), auto) minmax(0, 1fr);
}

/* Only the centre column drops under the toolbar; side clusters carry tall rails that would reach the bottom docks. */

.hud-layout-editing .hud-dock--topCenter {
  margin-top: max(
    0px,
    calc(var(--hud-layout-bar-reserve, 0px) + var(--hud-gap) - var(--hud-safe-top))
  );
}

.hud-dock-row--bottom {
  right: var(--hud-dock-row-right);
  bottom: var(--hud-safe-bottom);
  left: var(--hud-safe-left);
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: end;
  z-index: 30;
}

.hud-dock {
  display: flex;
  align-items: flex-start;
  gap: var(--hud-gap);
  min-width: 0;
  /* A dock parked at its lane's edge is sized by content and would grow past the lane over its neighbour; the lane is the budget. */
  max-width: 100%;
  pointer-events: none;
}

/* Each top dock stops above the measured bottom dock; growing lists scroll within the remaining room. */

.hud-dock-row--top > .hud-dock {
  --hud-dock-room: 100dvh;
  max-block-size: calc(var(--hud-dock-room) - var(--hud-gap));
  min-block-size: 0;
}

.hud-dock-row--top > .hud-dock--topLeft {
  --hud-dock-room: var(--hud-dock-left-room, 100dvh);
}

.hud-dock-row--top > .hud-dock--topCenter {
  --hud-dock-room: var(--hud-dock-center-room, 100dvh);
}

.hud-dock-row--top > .hud-dock--topRight {
  --hud-dock-room: var(--hud-dock-right-room, 100dvh);
}

/* A rail holds its size unless a member can give ground; shrinking fixed shells would spill out. */

.hud-dock-row--top .hud-rail {
  max-block-size: 100%;
  min-block-size: 0;
  flex-shrink: 0;
}

.hud-dock-row--top .hud-rail:has(> [data-hud-widget='questTracker']) {
  flex-shrink: 1;
}

:root:not([data-ui-profile='handheld'])
  .hud-dock-row--top
  .hud-rail:has(> [data-hud-widget='partyFrames']) {
  flex-shrink: 1;
}

.hud-dock--topCenter {
  align-items: center;
  justify-self: center;
}

.hud-dock--topRight {
  align-items: flex-end;
  justify-self: end;
}

.hud-dock--bottomLeft {
  width: 100%;
  min-width: 0;
  align-items: flex-start;
  align-self: end;
  justify-self: start;
}

.hud-dock--bottomCenter {
  align-items: center;
  align-self: end;
  justify-self: center;
}

.hud-dock--bottomRight {
  align-items: flex-end;
  align-self: end;
  justify-self: end;
}

.hud-rail {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--hud-gap);
  pointer-events: none;
  /* Size to the widest widget so a widget sizing against 100% still measures its own width. */
  width: max-content;
  max-width: 100%;
}

.hud-rail:empty {
  display: none;
}

.hud-dock--topRight .hud-rail,
.hud-dock--bottomRight .hud-rail {
  align-items: flex-end;
}

/* A centre rail is as wide as its widest widget so narrower ones centre on it; otherwise an NPC conversation would drag the action bars off centre. */

.hud-dock--topCenter .hud-rail,
.hud-dock--bottomCenter .hud-rail {
  align-items: center;
}

.hud-dock--bottomLeft .hud-rail {
  width: 100%;
  min-width: 0;
}

.hud-dock--bottomLeft .chat-wrap.hud-railed:not(.hud-layout-detached):not(.is-collapsed) {
  width: min(var(--chat-w, calc(340px * var(--ui-scale))), 100%);
  min-width: 0;
  max-width: 100%;
}

/* A railed widget contributes height only; the rail owns where it lands, so its own anchor is dropped. */

.hud-railed:not(.hud-layout-detached) {
  position: relative;
  top: auto;
  left: auto;
  right: auto;
  bottom: auto;
  transform: none;
  flex: 0 0 auto;
}

.hud-dock-row--top
  .hud-rail
  > [data-hud-widget='questTracker'].hud-railed:not(.hud-layout-detached) {
  flex-shrink: 1;
  min-block-size: 0;
}

.hud-layout-detached {
  position: fixed;
}

:root:not([data-ui-profile='handheld'])
  .hud-dock-row--top
  .hud-rail
  > [data-hud-widget='partyFrames'].hud-railed:not(.hud-layout-detached) {
  flex-shrink: 1;
  min-block-size: calc(24 * var(--gp));
}

.hud-layout-seat {
  flex: 0 0 auto;
  visibility: hidden;
  pointer-events: none;
}

.hud-safe-area-probe {
  position: fixed;
  inset: 0;
  z-index: -1;
  padding: var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left);
  visibility: hidden;
  pointer-events: none;
}

.overlay button,
.overlay input,
.inv-cell,
.npc-menu-item,
.hot-slot {
  pointer-events: auto;
  cursor: var(--cursor-action);
}

.panel-box {
  background: #0a0e14;
  border: 2px solid var(--ui-line-soft);
}

:root {
  /* Cast-danger tier accents, one table for every surface that draws a windup. */
  --cast-routine: #9ba7b8;
  --cast-strong: #d7aa38;
  --cast-signature: #db8cff;
  --cast-critical: #f05c50;
  --hud-vitals-track: #05090c;
  /* Gauge bands are quantized: hard steps, not a ramp. */
  --hud-sp-fill: linear-gradient(90deg, #276e8c 0 45%, #4ba8c2 45% 100%);
  --hud-exp-fill: linear-gradient(180deg, #ffd98a 0 40%, var(--accent) 40% 72%, #b9822c 72% 100%);
  --hud-hp-ghost-fill: linear-gradient(90deg, #7a1f17 0 50%, #a3392f 50% 100%);
  /* Health bands: one table so a band is the same colour on every bar, ally, target frame and plate. */
  --hud-hp-healthy-fill: linear-gradient(180deg, #6ee06e 0 40%, #3fae3f 40% 72%, #2b8a2b 72% 100%);
  --hud-hp-hurt-fill: linear-gradient(180deg, #f2d268 0 40%, #e0a020 40% 72%, #b87a12 72% 100%);
  /* Hotter than hurt on purpose so nearly dead separates from wounded at a glance. */
  --hud-hp-execute-fill: linear-gradient(180deg, #ffa24a 0 40%, #f0561f 40% 72%, #b83a10 72% 100%);
  /* Load bands: unpaid weight is pewter, not green, so amber/danger mean only that this load costs movement. */
  --hud-load-light-fill: linear-gradient(180deg, #a3b0bb 0 40%, #6c7c88 40% 72%, #4d5b66 72% 100%);
  --hud-load-heavy-fill: linear-gradient(180deg, #f2d268 0 40%, #e0a020 40% 72%, #b87a12 72% 100%);
  --hud-load-overloaded-fill: linear-gradient(
    180deg,
    #ec8a72 0 40%,
    var(--danger) 40% 72%,
    #9c3a2c 72% 100%
  );
  /* The band edge, brighter than its fill so the ring reads as an outline; `light` keeps the resting ring. */
  --hud-load-heavy-ring: #e8bb46;
  --hud-load-overloaded-ring: #ef7359;
  --hud-hp-healthy-line: #3fae3f;
  --hud-hp-hurt-line: #e0a020;
  --hud-hp-execute-line: #f0561f;
  --hud-hp-line: var(--hud-hp-healthy-line);
  --hud-vitals-text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.9);
}

/* Health hairlines state their band including the default; the property inherits, so a healthy hairline inside a hurt one would take its colour. */

[data-hp-band='healthy'] {
  --hud-hp-line: var(--hud-hp-healthy-line);
}

[data-hp-band='hurt'] {
  --hud-hp-line: var(--hud-hp-hurt-line);
}

[data-hp-band='execute'] {
  --hud-hp-line: var(--hud-hp-execute-line);
}

.ront-frame {
  border: 1px solid var(--ui-line-soft);
}

.ront-ring {
  border: 1px solid color-mix(in srgb, var(--ui-line) 76%, transparent);
}

.hud-guild {
  display: flex;
  align-items: center;
  gap: calc(4px * var(--ui-scale));
  min-width: 0;
  padding-left: calc(6px * var(--ui-scale));
  border-left: 1px solid color-mix(in srgb, var(--ui-line) 70%, transparent);
}

.hud-guild-emblem {
  width: calc(19px * var(--ui-scale));
  height: calc(19px * var(--ui-scale));
  flex: 0 0 auto;
  overflow: hidden;
  border: 1px solid rgba(197, 211, 232, 0.34);
  background: rgba(4, 7, 12, 0.78);
  box-shadow: 0 1px 0px rgba(0, 0, 0, 0.55);
}

.hud-guild-emblem img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  image-rendering: pixelated;
}

.hud-guild-copy {
  display: grid;
  gap: calc(1px * var(--ui-scale));
  min-width: 0;
}

.hud-guild-label {
  color: color-mix(in srgb, var(--muted) 72%, transparent);
  font-size: var(--type-badge-size);
  font-family: var(--type-badge-family);
  -webkit-font-smoothing: var(--type-badge-smoothing);
  font-weight: var(--type-weight-label);
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hud-guild-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-medium);
  line-height: 1.15;
  text-shadow:
    0 1px 0px #000,
    0 0 5px rgba(0, 0, 0, 0.9);
}

/* The character's own vitals and progression are the shared `.hud-gauge`; only
   the fill colour is theirs. */

.hud-gauge-fill.sp {
  background: var(--hud-sp-fill);
}

.hud-gauge-fill.exp {
  background: var(--hud-exp-fill);
  box-shadow: inset 0 1px 0 rgba(255, 240, 200, 0.5);
}

/* An ally's status strip, in their row and in the focus panel alike. */

.pf-buffs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
}

.party-focus {
  width: max(200px, calc(210px * var(--ui-scale)));
  pointer-events: auto;
  background: rgba(7, 12, 14, 0.76);
  border: 1px solid var(--ui-line-soft);
  padding: calc(9px * var(--ui-scale));
  display: flex;
  flex-direction: column;
  gap: calc(5px * var(--ui-scale));
  box-shadow: 0 8px 0px rgba(0, 0, 0, 0.24);
}

.party-focus.pf-oor,
.party-focus.pf-offline {
  opacity: 0.72;
}

.party-focus.pf-dead,
.party-focus.pf-lowhp {
  box-shadow:
    inset calc(3px * var(--ui-scale)) 0 var(--danger),
    0 8px 0px rgba(0, 0, 0, 0.35);
}

.party-focus:hover {
  filter: brightness(1.08);
}

.pf-focus-head {
  display: flex;
  align-items: center;
  gap: calc(6px * var(--ui-scale));
  min-width: 0;
}

.pf-focus-copy {
  min-width: 0;
  flex: 1;
}

.pf-focus-name {
  color: var(--text);
  font-size: var(--type-body-compact-readable-size);
  font-family: var(--type-body-compact-readable-family);
  -webkit-font-smoothing: var(--type-body-compact-readable-smoothing);
  font-weight: var(--type-weight-label);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pf-focus-meta,
.pf-focus-state {
  color: var(--muted);
  font-size: var(--type-metadata-readable-size);
  font-family: var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
  line-height: 1.15;
}

.pf-focus-close,
.pf-focus-action {
  border: 1px solid #354050;
  background: rgba(19, 26, 36, 0.92);
  color: var(--text);
  min-height: calc(22px * var(--ui-scale));
}

.pf-focus-close {
  width: calc(22px * var(--ui-scale));
  padding: 0;
  line-height: 1;
}

.pf-focus-close img {
  display: block;
  width: calc(16px * var(--ui-scale));
  height: calc(16px * var(--ui-scale));
  margin: auto;
  object-fit: contain;
}

.pf-focus-action {
  width: 100%;
  padding: calc(4px * var(--ui-scale)) calc(7px * var(--ui-scale));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-label);
}

.pf-focus-action:hover:not(:disabled),
.pf-focus-close:hover {
  border-color: var(--accent);
  background: rgba(27, 36, 48, 0.95);
}

.pf-focus-action:disabled {
  color: var(--muted);
  cursor: var(--cursor-default);
  opacity: 0.75;
}

/* Window-toggle dock — the single consolidated command bar that opens the
   standard windows. Its default bottom-right anchor shares the action bar's
   baseline and the minimap's right edge; player layout customization can detach
   it to any other saved position. */

.menu-buttons {
  position: fixed;
  right: var(--hud-safe-right);
  bottom: var(--hud-safe-bottom);
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 6px;
  /* The commands grow with the rest of the HUD. Handheld sizes its buttons for
     the thumb and resets this to 1. */
  --menu-scale: var(--ui-scale);
  --menu-pad-block: round(calc(6px * var(--ui-scale)), 1px);
  --menu-pad-inline: round(calc(6px * var(--ui-scale)), 1px);
  padding: var(--menu-pad-block) var(--menu-pad-inline);
  pointer-events: auto;
  background: rgba(7, 12, 14, 0.72);
  border: 1px solid var(--ui-line-soft);
  box-shadow: 0 8px 0px rgba(0, 0, 0, 0.28);
}

/* Placement stays on `.menu-buttons` alone. Restating it here would carry two
   classes, tying with the rail's own two-class claim and winning on source order
   — the dock would keep `position: fixed` inside a rail, drop out of flow, and
   land at its static position below the screen edge. */

.menu-buttons.is-collapsible {
  gap: 0;
  overflow: visible;
  isolation: isolate;
  background: transparent;
  border: 0;
  box-shadow: none;
}

.menu-buttons.is-collapsible:not(.is-collapsed) {
  z-index: 48;
  background: transparent;
  border: 0;
  box-shadow: none;
}

/* The command panel is placed in dock-local pixels: JavaScript picks the corner it
   grows from and clamps it inside the visible viewport, so the panel never depends
   on a transition landing to sit where it belongs. */

.menu-buttons.is-collapsible .menu-items {
  position: absolute;
  top: var(--menu-panel-y, 0px);
  left: var(--menu-panel-x, 0px);
  z-index: 42;
  display: grid;
  grid-template-columns: repeat(var(--menu-panel-columns, 3), auto);
  align-items: center;
  justify-items: center;
  gap: calc(6px * var(--menu-scale, 1));
  /* Bounds only for a viewport no arrangement of the grid fits; unset otherwise,
     so nothing can clip a panel that had the room. */
  max-width: var(--menu-panel-max-width, none);
  max-height: var(--menu-panel-max-height, none);
  /* The panel scrolls, so it clips: its rows keep the room a lit command's halo
     hop and shake need (pixel-chrome.css). */
  padding: max(var(--menu-pad-block), var(--pixel-halo-reach, 0px))
    max(var(--menu-pad-inline), var(--pixel-halo-reach, 0px));
  overflow: auto;
  overscroll-behavior: contain;
  background: rgba(7, 12, 14, 0.86);
  border: 1px solid var(--ui-line-soft);
  box-shadow: 0 10px 0px rgba(0, 0, 0, 0.42);
}

.menu-buttons[data-menu-open-x='left'][data-menu-open-y='up'] .menu-items {
  transform-origin: bottom right;
}

.menu-buttons[data-menu-open-x='left'][data-menu-open-y='down'] .menu-items {
  transform-origin: top right;
}

.menu-buttons[data-menu-open-x='right'][data-menu-open-y='up'] .menu-items {
  transform-origin: bottom left;
}

.menu-buttons[data-menu-open-x='right'][data-menu-open-y='down'] .menu-items {
  transform-origin: top left;
}

.menu-collapse-btn {
  z-index: 43;
}

.hud-layout-editing .hud-layout-widget {
  outline: 2px solid color-mix(in srgb, var(--gold) 85%, transparent);
  outline-offset: 3px;
  opacity: 0.72;
  cursor: move;
  pointer-events: auto !important;
  touch-action: none;
  user-select: none;
}

.hud-layout-editing .hud-layout-widget.hud-layout-dragging {
  cursor: grabbing;
}

.hud-layout-editing .hud-layout-widget.hud-layout-custom {
  outline-color: var(--accent);
  box-shadow: none;
}

.hud-layout-editing .hud-layout-widget.hud-layout-keyboard-focus {
  outline: 3px solid rgba(74, 163, 255, 0.9);
}

.hud-layout-editing.hud-layout-snap::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  background-image:
    linear-gradient(color-mix(in srgb, var(--gold) 14%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--gold) 14%, transparent) 1px, transparent 1px);
  background-size: 8px 8px;
}

.hud-layout-handle {
  position: fixed;
  display: none;
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  opacity: 0;
  pointer-events: none;
}

.hud-layout-bar {
  top: 12px;
  left: 50%;
  z-index: 63;
  transform: translateX(-50%);
  align-items: center;
  gap: 8px;
  padding: 5px 6px 5px 10px;
  pointer-events: auto;
  background: rgba(10, 14, 20, 0.9);
  border: 1px solid color-mix(in srgb, var(--gold) 55%, transparent);
  box-shadow: 0 10px 0px rgba(0, 0, 0, 0.38);
}

.hud-layout-title {
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-label);
}

.hud-layout-action {
  border: 1px solid rgba(116, 132, 156, 0.42);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
  padding: 4px 9px;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
}

.hud-layout-action:hover {
  border-color: color-mix(in srgb, var(--gold) 70%, transparent);
  color: var(--accent);
}

/* Copy, restore-default and confirm are their icons. Padding is set so the box
   lands on the same height as the snap toggle beside them, which is still a word
   because its label carries the state it is in. */

.hud-layout-icon-action {
  display: grid;
  place-items: center;
  padding: 2px;
}

.hud-layout-icon-action .hud-layout-icon {
  display: block;
  width: 18px;
  height: 18px;
  object-fit: contain;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.75));
}

.hud-layout-icon-action:disabled .hud-layout-icon,
.hud-layout-icon-action[aria-disabled='true'] .hud-layout-icon {
  opacity: 0.45;
}

/* A word is its own thumb target; an 18px mark is not. On handheld the icons take
   the same square as other icon controls, and the snap toggle rises to meet them so the row
   stays one line. The bar is taller for it, but only in layout mode, which is the
   one mode whose bar is allowed to cost height. */

[data-ui-profile='handheld'] .hud-layout-action {
  min-height: var(--hud-touch-min);
}

[data-ui-profile='handheld'] .hud-layout-icon-action {
  width: var(--hud-touch-min);
  min-width: var(--hud-touch-min);
  height: var(--hud-touch-min);
}

[data-ui-profile='handheld'] .hud-layout-icon-action .hud-layout-icon {
  width: 24px;
  height: 24px;
}

.hud-layout-action:disabled,
.hud-layout-action[aria-disabled='true'] {
  cursor: var(--cursor-default);
  border-color: rgba(116, 132, 156, 0.26);
  color: rgba(214, 223, 237, 0.68);
  background: rgba(255, 255, 255, 0.025);
}

.hud-layout-action:disabled:hover,
.hud-layout-action[aria-disabled='true']:hover {
  border-color: rgba(116, 132, 156, 0.26);
  color: rgba(214, 223, 237, 0.68);
}

.hud-layout-action[aria-pressed='true'] {
  border-color: color-mix(in srgb, var(--gold) 75%, transparent);
  background: color-mix(in srgb, var(--gold) 14%, transparent);
  color: #ffe6a6;
}

.hud-layout-editing.hud-layout-precision .hud-layout-action[aria-pressed='true'] {
  border-color: rgba(74, 163, 255, 0.78);
  background: rgba(74, 163, 255, 0.13);
  color: #b8e4ff;
}

.hud-layout-action.primary {
  background: color-mix(in srgb, var(--gold) 18%, transparent);
  border-color: color-mix(in srgb, var(--gold) 75%, transparent);
  color: #ffe6a6;
}

.hud-layout-bar textarea[data-hud-layout-debug='fallback'] {
  width: min(52vw, 280px);
  height: 4.5rem;
  margin: 0;
  padding: 4px 6px;
  border: 1px solid color-mix(in srgb, var(--gold) 55%, transparent);
  background: rgba(10, 14, 20, 0.92);
  color: var(--text);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: 1.3;
  pointer-events: auto;
}

.hud-layout-placeholder {
  min-width: 132px;
  min-height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5px 9px;
  border: 1px dashed color-mix(in srgb, var(--gold) 65%, transparent);
  color: var(--accent);
  background: rgba(10, 14, 20, 0.62);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-label);
}

/* Thin divider fencing the system/Options button off from the window toggles. It
   takes a row of its own so the commands above it keep the grid's columns. */

.menu-divider {
  grid-column: 1 / -1;
  justify-self: stretch;
  height: 1px;
  margin: 2px 4px;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(109, 124, 146, 0.62) 18%,
    rgba(109, 124, 146, 0.62) 82%,
    transparent
  );
}

.menu-btn {
  --plate-line: var(--pixel-ink);
  --plate-face: var(--pixel-night);
  --plate-rim: var(--pixel-rim);
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(42px * var(--menu-scale, 1));
  height: calc(42px * var(--menu-scale, 1));
  padding: 0;
  overflow: hidden;
  background: none;
  border: 0;
  color: var(--muted);
  cursor: var(--cursor-action);
  box-shadow: none;
  transition:
    color 0.12s ease,
    filter 0.12s ease;
}

/* The fold trigger's plate over a night face (hud-fold.css says why it is a
   pseudo-element); a state repaints --plate-*. */

.menu-btn::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border: var(--gp) solid var(--plate-line);
  background: var(--plate-face);
  box-shadow: var(--plate-rim);
  clip-path: var(--pixel-notch);
  pointer-events: none;
}

.menu-glyph {
  display: grid;
  place-items: center;
  width: calc(34px * var(--menu-scale, 1));
  height: calc(34px * var(--menu-scale, 1));
  background: transparent;
}

.menu-icon {
  display: block;
  width: calc(34px * var(--menu-scale, 1));
  height: calc(34px * var(--menu-scale, 1));
  object-fit: contain;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.75));
}

.menu-label {
  display: none;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  padding-right: calc(16px * var(--ui-scale));
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: 1.1;
  text-align: left;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu-btn:hover {
  color: var(--text);
  filter: brightness(1.15);
}

.menu-btn:active {
  filter: brightness(0.92);
}

/* An open window's command: the accent outline over a lifted face. */

.menu-btn[aria-pressed='true'] {
  color: var(--accent);
  --plate-line: var(--accent);
  --plate-face: var(--pixel-dusk);
}

.menu-btn:focus-visible {
  outline: none !important;
  box-shadow: none !important;
  --plate-rim:
    inset 0 0 0 var(--gp) var(--pixel-ink), inset 0 0 0 calc(2 * var(--gp)) var(--accent);
}

/* Hotkey badge: runtime layer, not baked into icon art. The hotbar's key
   plate: notched ink, a lit top row, sized by its text. */

.menu-key {
  position: absolute;
  right: calc(2 * var(--gp));
  bottom: calc(2 * var(--gp));
  min-width: calc(7 * var(--gp));
  height: auto;
  box-sizing: border-box;
  padding: 0 calc(2 * var(--gp));
  background: var(--pixel-ink);
  color: #e9edf4;
  font-size: var(--type-glyph-size);
  font-family: var(--type-glyph-family);
  -webkit-font-smoothing: var(--type-glyph-smoothing);
  font-weight: var(--type-weight-label);
  line-height: var(--type-leading-tight);
  text-align: center;
  box-shadow: inset 0 var(--gp) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  pointer-events: none;
}

.menu-btn:hover .menu-key,
.menu-btn[aria-pressed='true'] .menu-key {
  color: #ffe2a0;
}

.target-panel {
  background: rgba(10, 14, 20, 0.82);
  border: 1px solid var(--ui-line-soft);
  padding: 6px 16px;
}

/* The one button family for in-game surfaces: a button states a variant (primary=brass/go, secondary=matte, ghost=steps aside, danger=destroys),
   never its own paint. Pre-game keeps .menu-button; the hotbar slot is its own grammar. Pixel material from pixel-chrome.css. */

.ron-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(3 * var(--gp));
  box-sizing: border-box;
  min-height: calc(14 * var(--gp));
  padding: 0 calc(6 * var(--gp));
  background: var(--pixel-dusk);
  border: var(--gp) solid var(--pixel-ink);
  color: var(--pixel-cream);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  text-align: center;
  cursor: var(--cursor-action);
  position: relative;
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
  transition: none;
}

.ron-btn:hover:not(:disabled):not([aria-disabled='true']):not(.is-loading):not([data-locked]) {
  border-color: var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-slate) 45%, var(--pixel-dusk));
  color: var(--pixel-cream);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-lilac),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}

.ron-btn:active:not(:disabled):not([aria-disabled='true']):not(.is-loading):not([data-locked]) {
  transform: translateY(var(--gp));
}

.ron-btn:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.ron-btn:disabled,
.ron-btn[aria-disabled='true'] {
  opacity: 0.5;
  cursor: var(--cursor-default);
}

/* Locked: gated by the game, not off. A flat muted plate reads as not yet where a dimmed one reads as broken. It is an attribute so identity stays stable. */

.ron-btn[data-locked],
.ron-btn[data-locked]:disabled {
  opacity: 1;
  background: var(--pixel-night);
  color: var(--pixel-lilac);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
  cursor: var(--cursor-default);
}

.ron-btn--primary,
.ron-btn--primary:hover:not(:disabled):not([aria-disabled='true']):not(.is-loading):not(
    [data-locked]
  ) {
  background: var(--pixel-ochre);
  color: var(--pixel-ink);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-honey),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0
      color-mix(in srgb, var(--pixel-ochre) 60%, var(--pixel-ink));
}

.ron-btn--primary:hover:not(:disabled):not([aria-disabled='true']):not(.is-loading):not(
    [data-locked]
  ) {
  background: color-mix(in srgb, var(--pixel-honey) 35%, var(--pixel-ochre));
}

.ron-btn--ghost,
.ron-btn--ghost:hover:not(:disabled):not([aria-disabled='true']):not(.is-loading):not(
    [data-locked]
  ) {
  background: var(--pixel-night);
  color: var(--pixel-lilac);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
}

.ron-btn--ghost:hover:not(:disabled):not([aria-disabled='true']):not(.is-loading):not(
    [data-locked]
  ) {
  color: var(--pixel-cream);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-slate);
}

.ron-btn--danger,
.ron-btn.is-confirming,
.ron-btn--danger:hover:not(:disabled):not([aria-disabled='true']):not(.is-loading):not(
    [data-locked]
  ),
.ron-btn.is-confirming:hover:not(:disabled):not([aria-disabled='true']):not(.is-loading):not(
    [data-locked]
  ) {
  background: color-mix(in srgb, var(--pixel-debuff) 45%, var(--pixel-night));
  color: var(--pixel-cream);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-debuff),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-ink);
}

.ron-btn--sm {
  min-height: calc(12 * var(--gp));
  padding: 0 calc(4 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.ron-btn--block {
  width: 100%;
}

/* Busy: the press was taken and the game is working. The label stays in place, invisible, so the button does not shift under the cursor. */

.ron-btn.is-loading {
  pointer-events: none;
  color: transparent;
}

.ron-btn.is-loading::after {
  content: '';
  width: calc(6 * var(--gp));
  height: calc(6 * var(--gp));
  /* The border spinner tumbles when squared; the kit paint stays round, stated here to outrank the pixel-chrome sweep. */
  border-radius: 50% !important;
  border: var(--gp) solid var(--pixel-dusk);
  border-top-color: var(--accent);
  animation: ui-spin 700ms linear infinite;
}

/* The one spin keyframe every spinner shares; private copies drift into divergent timing. */

@keyframes ui-spin {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ron-btn.is-loading::after {
    animation-duration: 1600ms;
  }
}

body.reduce-motion .ron-btn.is-loading::after,
body.reduce-flashing .ron-btn.is-loading::after {
  animation-duration: 1600ms;
}

body.high-contrast .ron-btn {
  border-color: #8fa0b5;
}

body.high-contrast .ron-btn--ghost {
  background: #0a0e14;
}

body.high-contrast .ron-btn:disabled,
body.high-contrast .ron-btn[aria-disabled='true'] {
  border-color: #6f7d92;
}

/* The key that presses this button, worn inside it. Place-specific keycaps stay where they live. */

.ron-btn__key {
  display: grid;
  place-items: center;
  min-width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  padding: 0 calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--pixel-ink);
  color: var(--pixel-lilac);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-label);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.ron-btn:hover .ron-btn__key,
.ron-btn:focus-visible .ron-btn__key {
  border-color: var(--accent);
  color: var(--accent);
}

/* The one dropdown family: native <select> cannot wear Ront paint, so the kit owns trigger and list.
   The open list is a popover (fixed, above WINDOW_Z_CEIL) since a GameWindow clips overflow and isolates stacking. */

.ron-select {
  display: inline-flex;
  min-width: 0;
  vertical-align: middle;
}

.ron-select--block {
  width: 100%;
}

.ron-select__trigger {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  min-height: calc(15 * var(--gp));
  padding: calc(2 * var(--gp)) calc(14 * var(--gp)) calc(2 * var(--gp)) calc(5 * var(--gp));
  background: var(--pixel-ink);
  border: var(--gp) solid var(--pixel-ink);
  color: var(--pixel-cream);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  text-align: left;
  cursor: var(--cursor-action);
  position: relative;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.ron-select__trigger::after {
  content: '';
  position: absolute;
  top: round(down, calc(50% - 1.5 * var(--gp)), 1px);
  right: calc(5 * var(--gp));
  width: calc(5 * var(--gp));
  height: calc(3 * var(--gp));
  background:
    linear-gradient(var(--accent), var(--accent)) 0 0 / 100% var(--gp) no-repeat,
    linear-gradient(var(--accent), var(--accent)) var(--gp) var(--gp) / calc(3 * var(--gp))
      var(--gp) no-repeat,
    linear-gradient(var(--accent), var(--accent)) calc(2 * var(--gp)) calc(2 * var(--gp)) /
      var(--gp) var(--gp) no-repeat;
  pointer-events: none;
}

.ron-select.is-open .ron-select__trigger::after {
  transform: rotate(180deg);
}

.ron-select__trigger:hover:not(:disabled):not([aria-disabled='true']),
.ron-select.is-open .ron-select__trigger:not(:disabled):not([aria-disabled='true']) {
  background: var(--pixel-night);
}

.ron-select__trigger:active:not(:disabled):not([aria-disabled='true']) {
  transform: translateY(var(--gp));
}

.ron-select__trigger:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.ron-select__trigger:disabled,
.ron-select__trigger[aria-disabled='true'] {
  opacity: 0.5;
  cursor: var(--cursor-default);
}

.ron-select.is-active .ron-select__trigger {
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
  color: var(--gold-label);
}

.ron-select--sm .ron-select__trigger {
  min-height: calc(11 * var(--gp));
  padding: var(--gp) calc(11 * var(--gp)) var(--gp) calc(5 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.ron-select--sm .ron-select__trigger::after {
  right: calc(4 * var(--gp));
}

/* Z_POPOVER — above WINDOW_Z_CEIL and the system menu, with context menus. */

.ron-select__menu {
  position: fixed;
  z-index: 200;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: var(--gp);
  max-height: calc(8 * 14 * var(--gp));
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: calc(3 * var(--gp));
  background: var(--pixel-night);
  border: var(--gp) solid var(--pixel-ink);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
}

.ron-select__menu[hidden] {
  display: none;
}

.ron-select__option {
  box-sizing: border-box;
  width: 100%;
  margin: 0;
  padding: calc(2 * var(--gp)) calc(4 * var(--gp));
  background: transparent;
  border: var(--gp) solid transparent;
  color: var(--pixel-cream);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: 1.2;
  text-align: left;
  cursor: var(--cursor-action);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ron-select--sm .ron-select__option {
  padding: var(--gp) calc(3 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.ron-select__option:hover:not(:disabled),
.ron-select__option.is-active:not(:disabled),
.ron-select__option.is-selected:not(:disabled) {
  border-color: var(--accent);
  background: var(--pixel-dusk);
}

.ron-select__option:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.ron-select__option:disabled {
  opacity: 0.5;
  cursor: var(--cursor-default);
}

/* The one text-field family: a field states width/height/type size, never its own paint. The chat composer and modal `.field` keep their own grammar. */

.ron-field {
  min-width: 0;
  box-sizing: border-box;
  padding: calc(2 * var(--gp)) calc(4 * var(--gp));
  background: var(--pixel-ink);
  border: var(--gp) solid var(--pixel-ink);
  color: var(--pixel-cream);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.ron-field::placeholder {
  color: var(--muted);
  opacity: 1;
}

.ron-field:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.ron-field:disabled,
.ron-field[aria-disabled='true'] {
  opacity: 0.5;
  cursor: var(--cursor-default);
}

body.high-contrast .ron-field {
  border-color: #8fa0b5;
  background: #0a0e14;
}

body.high-contrast .ron-field:disabled,
body.high-contrast .ron-field[aria-disabled='true'] {
  border-color: #6f7d92;
}

/* Window size is decided once for every floating window: a window states only what is its own, as plain pixel numbers at UI scale 1:
     .shop-panel { --win-frame-w: 430; --win-frame-h: 620; }
   Scale, unit, viewport clamp and handheld safe box live here. Extra margin is named (`--win-frame-inset-*` / `--win-frame-fill-*`), never a `height` of its own. */

.win-frame {
  /* Bigger than any glass: bounded only by the viewport share it may fill. Use it when a window has no size of its own. */
  --win-frame-unbounded: 100000;

  /* The width the window was designed at, in px at --ui-scale 1; the default is the base panel width. */
  --win-frame-w: 360;
  /* The height it was designed at; unbounded by default, so most windows are held by the glass alone. */
  --win-frame-h: var(--win-frame-unbounded);

  --win-frame-inset-x: 32px;
  --win-frame-inset-y: 48px;

  /* The most of the glass a window asks for. `dvh`/`dvw`, not `vh`/`vw`: a sliding browser toolbar must not push a window off screen. */
  --win-frame-fill-w: calc(100dvw - var(--win-frame-inset-x));
  --win-frame-fill-h: calc(100dvh - var(--win-frame-inset-y));

  /* The most the glass will give. The profile sets it, the window never does, so a window that keeps more margin than its siblings keeps it on a phone too. */
  --win-frame-glass-h: 100dvh;

  /* What the window ends up allowed, read by `is-stable` so a stated and a capped frame agree. Rounds up to whole pairs of HUD pixels (--gp). */
  --win-frame-width: min(
    round(up, calc(var(--win-frame-w) * 1px * var(--ui-scale, 1)), calc(2 * var(--gp))),
    var(--win-frame-fill-w)
  );
  --win-frame-height: min(
    round(up, calc(var(--win-frame-h) * 1px * var(--ui-scale, 1)), calc(2 * var(--gp))),
    var(--win-frame-fill-h),
    var(--win-frame-glass-h)
  );

  width: var(--win-frame-width);
  max-height: var(--win-frame-height);
}

/* A window whose body swaps faces or fills in a round trip states its frame instead of following content; `latchWindowHeight`
   holds it at its tallest so a centred modal cannot move under the cursor. `.win-frame-body` takes the room the frame holds open. */

.win-frame.is-stable {
  height: var(--win-frame-height);
}

.win-frame.is-stable > .win-frame-body {
  flex: 1 1 0;
  min-height: 0;
}

/* A glass states its own budget (safe insets, sliding toolbar); it lowers what a window asked for and never raises it. */

[data-ui-profile='handheld'] .win-frame {
  --win-frame-glass-h: var(--hud-window-max-h);
}

/* These five counters take the shared wide-glass width and give up their desktop height preference to the profile ceiling; size decisions are made once, in this file. */

[data-ui-profile='handheld'] .shop-panel,
[data-ui-profile='handheld'] .cashshop-panel,
[data-ui-profile='handheld'] .mail-panel,
[data-ui-profile='handheld'] .itemsvc-panel,
[data-ui-profile='handheld'] .trade-panel {
  --win-frame-w: var(--win-frame-unbounded);
  --win-frame-h: var(--win-frame-unbounded);
  --win-frame-fill-w: min(var(--hud-window-max), calc(100dvw - 48px));
  --win-frame-fill-h: 100dvh;
  max-width: var(--win-frame-width);
}

.window,
.death-card,
.enhance-panel {
  overflow: hidden;
  isolation: isolate;
  background: var(--ui-frame-fill);
  border: 1px solid var(--ui-line-bright);
  box-shadow: var(--ui-frame-shadow);
}

.window {
  top: 80px;
  left: 50%;
  transform: translateX(-50%);
  width: calc(300px * var(--type-scale, 1));
  flex-direction: column;
  pointer-events: auto;
}

.window::before,
.death-card::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(circle at 14% 0, var(--ui-frame-glow), transparent 28%),
    linear-gradient(
      90deg,
      rgba(255, 255, 255, 0.025),
      transparent 24%,
      transparent 76%,
      rgba(0, 0, 0, 0.12)
    );
}

/* Separate defaults keep simultaneous windows clear of the status and menu HUD; makeDraggable overrides them only with a saved position. */

.window.win-stats {
  top: 80px;
  left: auto;
  right: 70px;
  transform: none;
}

.window.win-inv {
  top: 130px;
  left: auto;
  right: 24px;
  transform: none;
  width: min(calc(430px * var(--ui-scale)), calc(100vw - 32px));
}

.window.win-skills {
  top: 72px;
  left: 50%;
  right: auto;
  transform: translateX(-50%);
  width: min(calc(1520px * var(--ui-scale)), calc(100vw - 24px));
  max-width: calc(100vw - 24px);
}

.window.win-skills:has(.skill-mode-adventurer) {
  width: min(calc(940px * var(--ui-scale)), calc(100vw - 24px));
}

.window.win-bank {
  top: 185px;
  left: auto;
  right: 90px;
  transform: none;
  width: calc(320px * var(--ui-scale));
  max-width: calc(100vw - 48px);
}

.window.win-chat-rooms {
  top: 190px;
  left: 50%;
  transform: translateX(-50%);
  width: calc(460px * var(--ui-scale));
  max-width: calc(100vw - 48px);
}

.window.win-quests {
  top: 150px;
  left: auto;
  right: 150px;
  transform: none;
  width: calc(460px * var(--ui-scale));
  max-width: calc(100vw - 48px);
}

.window.win-achievements {
  top: 190px;
  left: auto;
  right: 180px;
  transform: none;
  width: calc(460px * var(--ui-scale));
  max-width: calc(100vw - 48px);
}

.window.win-worldmap {
  top: 64px;
  left: 50%;
  right: auto;
  transform: translateX(-50%);
  width: min(calc(300 * var(--gp)), calc(100vw - 32px));
}

.win-worldmap .win-body {
  max-height: calc(100dvh - 140px);
}

.window.win-season {
  top: 88px;
  left: 50%;
  right: auto;
  transform: translateX(-50%);
  width: min(calc(310 * var(--gp)), calc(100vw - 32px));
}

.win-season .win-body {
  max-height: calc(100vh - 152px);
  overflow-y: auto;
}

.season-body {
  display: grid;
  align-content: start;
  gap: calc(5 * var(--gp));
  --season-well-light: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

.season-crown,
.season-front,
.season-intel-service,
.season-intel-block,
.season-armory-rows,
.season-history-rows {
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  clip-path: var(--pixel-notch);
}

.season-waiting {
  margin: 0;
  color: var(--muted, #9ba5b4);
}

.season-head {
  display: grid;
  gap: var(--gp);
}

.season-head h3 {
  margin: 0;
  color: #f7e3a5;
  font-size: var(--type-prose-readable-size);
  font-family: var(--type-prose-readable-family);
  -webkit-font-smoothing: var(--type-prose-readable-smoothing);
  font-weight: var(--type-weight-label);
  line-height: 1.2;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.season-began {
  margin: 0;
  color: var(--muted, #9ba5b4);
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
}

.season-crowns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(5 * var(--gp));
}

.season-crown {
  display: grid;
  align-content: start;
  gap: calc(2 * var(--gp));
  padding: calc(4 * var(--gp));
  box-shadow:
    inset 0 var(--gp) 0 var(--crown, var(--pixel-slate)),
    var(--season-well-light);
}

.season-crown-head {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  min-width: 0;
}

.season-crown-head .identity-chip,
.season-crown-head .identity-body {
  min-width: 0;
}

.season-crown-head .identity-primary {
  font-size: var(--type-body-compact-readable-size);
  font-family: var(--type-body-compact-readable-family);
  -webkit-font-smoothing: var(--type-body-compact-readable-smoothing);
}

/* Label left, value right, same columns on every row of both Crowns, so an unknown value is a "?" where the number would sit. */

.season-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(3 * var(--gp));
  margin: 0;
  color: #cbd2dc;
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.season-row strong {
  color: var(--text, #fff);
  font-variant-numeric: tabular-nums;
}

.season-row[title] {
  cursor: help;
}

/* Purple is the informant's colour wherever a bought fact, or the absence of one, is drawn. */

.season-unknown {
  color: #c6a7de;
}

.season-muster strong {
  color: var(--text, #fff);
}

.season-intel-ends {
  color: #c6a7de;
  font-weight: var(--type-weight-label);
}

/* The same <ront-war-lane> element as the rail, at window size; the section only adds the wave clock and the bonuses on the line. */

.season-front {
  display: grid;
  gap: calc(3 * var(--gp));
  padding: calc(4 * var(--gp));
  box-shadow:
    inset 0 var(--gp) 0 var(--pixel-slate),
    var(--season-well-light);
}

.season-front-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(4 * var(--gp));
}

.season-front-head h4 {
  margin: 0;
  color: #f7e3a5;
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.season-front-wave {
  display: flex;
  align-items: baseline;
  gap: calc(3 * var(--gp));
  margin: 0;
  color: var(--muted, #9ba5b4);
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.season-front-wave strong {
  color: #f7e3a5;
  font-variant-numeric: tabular-nums;
}

.season-front-power {
  color: #ffb48f;
}

.season-front-marks {
  display: flex;
  flex-wrap: wrap;
  gap: calc(3 * var(--gp));
  margin: 0;
  padding: 0;
  list-style: none;
}

.season-front-marks li {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  padding: var(--gp) calc(3 * var(--gp));
  color: #ffe0a0;
  background: var(--pixel-ink);
  font-size: var(--type-metadata-readable-size);
  font-family: var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
  font-variant-numeric: tabular-nums;
  font-weight: var(--type-weight-label);
}

.season-front-marks :is(img, ront-pixel-portrait) {
  width: calc(6 * var(--gp));
  height: calc(6 * var(--gp));
  object-fit: contain;
}

.season-front-lane {
  display: block;
  min-width: 0;
}

body.high-contrast .season-body {
  --season-well-light: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-lilac);
}

/* The paid-intelligence service is visible before a Crown owns a report; buying still happens by speaking to Neris Veyl on East Shardmarch. */

.season-intel-service {
  display: grid;
  grid-template-columns: calc(22 * var(--gp)) minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(4 * var(--gp));
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  box-shadow:
    inset var(--gp) 0 0 #b98ad8,
    var(--season-well-light);
}

.season-intel-service-mark {
  width: calc(20 * var(--gp));
  height: calc(20 * var(--gp));
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.season-intel-service-copy {
  display: grid;
  gap: var(--gp);
  min-width: 0;
}

.season-intel-service-copy p,
.season-intel-service-copy h4 {
  margin: 0;
}

.season-intel-service-name {
  color: #c9a6e8;
  font-size: var(--type-metadata-readable-size);
  font-family: var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
  font-weight: var(--type-weight-emphasis);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.season-intel-service-copy h4 {
  color: var(--gold-ink, #f7e3a5);
  font-size: var(--type-body-readable-size);
  font-family: var(--type-body-readable-family);
  -webkit-font-smoothing: var(--type-body-readable-smoothing);
}

.season-intel-service-copy > p:last-child {
  color: #cbd2dc;
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  line-height: 1.3;
}

.season-intel-service-status {
  display: grid;
  justify-items: end;
  gap: var(--gp);
  border-inline-start: var(--gp) solid var(--pixel-dusk);
  padding-inline-start: calc(5 * var(--gp));
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.season-intel-service-status strong {
  color: #c9a6e8;
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
}

.season-intel-service-status span {
  color: var(--muted, #9ba5b4);
  font-size: var(--type-metadata-readable-size);
  font-family: var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
}

/* Bought intel wears the informant's tint, so a paid figure is never mistaken for the public read. */

.season-intel {
  display: grid;
  gap: calc(2 * var(--gp));
}

.season-intel-blocks {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(3 * var(--gp));
}

/* A block with no partner on its row takes the row; which blocks those are depends on what the Crown bought. */

.season-intel-block.is-wide {
  grid-column: 1 / -1;
}

.season-intel-title {
  margin: 0;
  color: #c9a6e8;
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  font-weight: var(--type-weight-label);
  line-height: 1.2;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.season-intel-block {
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  box-shadow:
    inset var(--gp) 0 0 #b98ad8,
    var(--season-well-light);
}

.season-intel-head {
  display: flex;
  align-items: baseline;
  gap: calc(3 * var(--gp));
}

.season-intel-name {
  color: var(--gold-ink, #f7e3a5);
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.season-intel-ends {
  margin-inline-start: auto;
  color: #8fb8d8;
  font-size: var(--type-metadata-readable-size);
  font-family: var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
  font-variant-numeric: tabular-nums;
  font-weight: var(--type-weight-label);
}

.season-intel-rows {
  display: grid;
  gap: var(--gp);
  margin: calc(2 * var(--gp)) 0 0;
  padding: 0;
  list-style: none;
}

.season-intel-row {
  display: flex;
  align-items: baseline;
  gap: calc(3 * var(--gp));
  color: #cbd2dc;
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
}

.season-intel-row strong {
  margin-inline-start: auto;
  color: var(--text, #fff);
  font-variant-numeric: tabular-nums;
}

.season-intel-row.is-muted {
  color: var(--muted, #9ba5b4);
  font-style: italic;
}

.season-intel-armory {
  display: grid;
  gap: calc(2 * var(--gp));
  margin-block-start: calc(2 * var(--gp));
}

.season-intel-armory-type {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(3 * var(--gp));
}

.season-intel-type {
  overflow: hidden;
  color: #cbd2dc;
  text-align: end;
  font-size: var(--type-metadata-readable-size);
  font-family: var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.04em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.season-intel-cells {
  display: grid;
  grid-template-columns: repeat(5, calc(17 * var(--gp)));
  gap: calc(2 * var(--gp));
}

.season-intel-cell {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  overflow: hidden;
  border: var(--gp) solid var(--pixel-ink);
  background:
    linear-gradient(
      0deg,
      color-mix(in srgb, var(--rarity-color) 34%, transparent) 0 var(--intel-progress),
      transparent var(--intel-progress)
    ),
    var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) color-mix(in srgb, var(--rarity-color) 42%, var(--pixel-dusk));
  clip-path: var(--pixel-notch);
}

.season-intel-cell img {
  width: 82%;
  height: 82%;
  object-fit: contain;
  opacity: 0.58;
  filter: saturate(0.7);
}

.season-intel-cell.is-unlocked {
  background: color-mix(in srgb, var(--rarity-color) 18%, var(--pixel-ink));
  box-shadow: inset 0 0 0 var(--gp) var(--rarity-color);
}

.season-intel-cell.is-unlocked img {
  opacity: 1;
  filter: none;
}

.season-armory {
  display: grid;
  gap: calc(2 * var(--gp));
}

.season-armory-head {
  display: flex;
  align-items: baseline;
  gap: calc(3 * var(--gp));
}

.season-armory-title {
  margin: 0;
  color: var(--gold-ink, #f7e3a5);
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  font-weight: var(--type-weight-label);
  line-height: 1.2;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.season-armory-total {
  margin-inline-start: auto;
  color: var(--text, #fff);
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  font-variant-numeric: tabular-nums;
  font-weight: var(--type-weight-label);
}

.season-armory-rows {
  display: grid;
  gap: var(--gp);
  margin: 0;
  padding: calc(2 * var(--gp)) calc(4 * var(--gp));
  list-style: none;
  box-shadow: var(--season-well-light);
}

.season-armory-row {
  display: flex;
  align-items: baseline;
  gap: calc(3 * var(--gp));
  color: #cbd2dc;
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
}

.season-armory-rarity {
  color: var(--rarity-color, #cbd2dc);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.04em;
}

.season-armory-count {
  margin-inline-start: auto;
  font-variant-numeric: tabular-nums;
}

.season-history {
  display: grid;
  gap: calc(2 * var(--gp));
}

.season-history-title {
  margin: 0;
  color: var(--muted, #9ba5b4);
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  font-weight: var(--type-weight-label);
  line-height: 1.2;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.season-history-rows {
  display: grid;
  gap: var(--gp);
  margin: 0;
  padding: calc(2 * var(--gp)) calc(4 * var(--gp));
  list-style: none;
  box-shadow: var(--season-well-light);
}

.season-history-row {
  display: flex;
  align-items: baseline;
  gap: calc(3 * var(--gp));
  padding-inline-start: calc(4 * var(--gp));
  border-inline-start: var(--gp) solid var(--muted, #9ba5b4);
  color: #cbd2dc;
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  line-height: 1.35;
}

.season-history-text {
  min-width: 0;
}

.season-history-go {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: max(22px, calc(11 * var(--gp)));
  height: max(22px, calc(11 * var(--gp)));
  padding: 0;
  border: var(--gp) solid color-mix(in srgb, var(--wayfind-accent, #d8c798) 48%, var(--pixel-ink));
  background: var(--pixel-ink);
  clip-path: var(--pixel-notch);
  cursor: var(--cursor-action, pointer);
}

.season-history-go img {
  display: block;
  width: 86%;
  height: 86%;
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.season-history-go:hover {
  background: color-mix(in srgb, var(--wayfind-accent, #d8c798) 16%, var(--pixel-ink));
}

.season-history-go:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

body.high-contrast .season-history-go {
  border-color: var(--wayfind-accent, #d8c798);
  background: color-mix(in srgb, var(--wayfind-accent, #d8c798) 22%, var(--pixel-ink));
}

/* The age sits on its own edge so the clocks read as a column; it never wraps, since a second row would cost more height than the line it stamps. */

.season-history-age {
  margin-inline-start: auto;
  color: var(--muted, #9ba5b4);
  font-size: var(--type-metadata-readable-size);
  font-family: var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.season-history-row.is-positive {
  border-inline-start-color: var(--good, #63c08a);
}

.season-history-row.is-negative {
  border-inline-start-color: var(--danger, #e0533d);
}

.season-history-row.is-notable {
  border-inline-start-color: var(--gold-ink, #f7e3a5);
}

@media (max-width: 520px) {
  .season-intel-blocks {
    grid-template-columns: 1fr;
  }
  .season-intel-service {
    grid-template-columns: calc(18 * var(--gp)) minmax(0, 1fr);
  }
  .season-intel-service-mark {
    width: calc(16 * var(--gp));
    height: calc(16 * var(--gp));
  }
  .season-intel-service-status {
    grid-column: 2;
    grid-row: 2;
    justify-items: start;
    border: 0;
    padding: 0;
  }
}

/* Combat meter fold: the fixed corner is only its resting place; in a dock rail it stands there like every other widget. */

.combat-telemetry-fold.hud-fold-surface {
  --hud-fold-reserve-gap: 6px;
  position: fixed;
  right: calc(88px * var(--ui-scale));
  bottom: calc(12px * var(--ui-scale));
  left: auto;
  top: auto;
  z-index: 30;
  box-sizing: border-box;
  width: min(calc(320px * var(--ui-scale)), calc(100vw - 220px * var(--ui-scale)));
  min-width: var(--hud-fold-shell-size, calc(44px * var(--ui-scale)));
  pointer-events: none;
  padding-top: var(--hud-fold-reserve-top);
  padding-bottom: var(--hud-fold-reserve-bottom);
  transition: none;
  --hud-fold-expanded-width: min(
    calc(320px * var(--ui-scale)),
    calc(100vw - 220px * var(--ui-scale))
  );
  --hud-fold-expanded-min-width: var(--hud-fold-shell-size, calc(44px * var(--ui-scale)));
  --hud-fold-expanded-height: auto;
  --hud-fold-expanded-min-height: var(--hud-fold-shell-size, calc(44px * var(--ui-scale)));
  --ct-bar-0: #c9a45e;
  --ct-bar-1: #d85b48;
  --ct-bar-2: #6fd06a;
  --ct-bar-3: #3498db;
  --ct-bar-4: #b48ce0;
  --ct-bar-5: #ffb84d;
  --ct-bar-6: #9bd0ff;
  --ct-bar-7: #e0533d;
  --ct-bar-8: #d7aa38;
  --ct-bar-9: #db8cff;
  --ct-bar-10: #f05c50;
  --ct-bar-11: #9e7138;
  --ct-bar-12: #4aa86a;
  --ct-bar-13: #9ba7b8;
  --ct-bar-14: #e8c34a;
  --ct-bar-15: #c8821f;
}

/* A railed fold keeps its rail slot while folded; this free-floating one must hand the screen back, and a content-sized seat has no height to interpolate.
   So the panel clips into the trigger corner first, then the empty seat closes in one step; unfolding takes the seat back at once. */

.combat-telemetry-fold.hud-fold-surface.is-collapsed {
  padding-top: 0;
  padding-bottom: 0;
  transition-property: width, min-width, height, min-height, padding-top, padding-bottom;
  transition-duration: 0s;
  transition-delay: var(--hud-fold-duration);
  transition-behavior: allow-discrete;
}

.combat-telemetry-fold .hud-fold-surface-trigger {
  pointer-events: auto;
}

.hud-layout-editing .combat-telemetry-fold.hud-fold-surface {
  pointer-events: auto;
}

/* Host is display:contents so the trigger positions against the fold surface (stable corner). */

.combat-telemetry-fold-slot {
  display: contents;
}

.combat-telemetry-fold-icon {
  object-fit: contain;
}

.combat-telemetry-fold-leader {
  position: absolute;
  top: 50%;
  right: calc(100% - 1px);
  z-index: 0;
  display: grid;
  width: max(88px, calc(82px * var(--ui-scale)));
  box-sizing: border-box;
  gap: 2px;
  padding: calc(4px * var(--ui-scale)) calc(8px * var(--ui-scale)) calc(5px * var(--ui-scale))
    calc(16px * var(--ui-scale));
  translate: 0 -50%;
  color: var(--text);
  background: linear-gradient(
    to left,
    rgba(7, 14, 16, 0.9),
    rgba(7, 14, 16, 0.62) 68%,
    transparent
  );
  text-align: right;
  text-shadow: 0 1px 0px #000;
  cursor: var(--cursor-action);
  pointer-events: auto;
}

.combat-telemetry-fold-leader::after {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 28%;
  height: 1px;
  content: '';
  background: linear-gradient(to left, color-mix(in srgb, var(--accent) 74%, #fff), transparent);
}

.combat-telemetry-fold-leader[hidden] {
  display: none;
}

.combat-telemetry-fold-leader-name,
.combat-telemetry-fold-leader-metric {
  overflow: hidden;
  line-height: 1;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.combat-telemetry-fold-leader-name {
  font-size: var(--type-micro-readable-size);
  font-family: var(--type-micro-readable-family);
  -webkit-font-smoothing: var(--type-micro-readable-smoothing);
  font-weight: var(--type-weight-label);
}

.combat-telemetry-fold-leader-metric {
  color: var(--muted);
  font-size: var(--type-micro-readable-size);
  font-family: var(--type-micro-readable-family);
  -webkit-font-smoothing: var(--type-micro-readable-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
}

.combat-telemetry-fold[data-hud-anchor-x='left'] .combat-telemetry-fold-leader {
  right: auto;
  left: calc(100% - 1px);
  padding-right: calc(16px * var(--ui-scale));
  padding-left: calc(8px * var(--ui-scale));
  background: linear-gradient(
    to right,
    rgba(7, 14, 16, 0.9),
    rgba(7, 14, 16, 0.62) 68%,
    transparent
  );
  text-align: left;
}

.combat-telemetry-fold[data-hud-anchor-x='left'] .combat-telemetry-fold-leader::after {
  right: 28%;
  left: 0;
  background: linear-gradient(to right, color-mix(in srgb, var(--accent) 74%, #fff), transparent);
}

.combat-telemetry-panel {
  pointer-events: auto;
  position: relative;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: calc(8px * var(--ui-scale));
  padding: calc(10px * var(--ui-scale));
  height: auto;
  max-height: none;
  min-height: 0;
  overflow: visible;
  background: rgba(7, 12, 14, 0.72);
  border: 1px solid var(--grid-line);
  box-shadow: 0 6px 0px rgba(0, 0, 0, 0.35);
}

.combat-telemetry-title {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--text);
  flex-shrink: 0;
}

.combat-telemetry-toolbar {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: calc(8px * var(--ui-scale));
}

.combat-telemetry-tabs {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  gap: calc(2px * var(--ui-scale));
}

.combat-telemetry-tab {
  flex: 1 1 0;
  margin: 0;
  padding: calc(4px * var(--ui-scale)) calc(6px * var(--ui-scale));
  font: inherit;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: var(--muted);
  background: var(--ui-control-fill);
  border: 1px solid var(--ui-control-line);
  cursor: var(--cursor-action);
  white-space: nowrap;
}

.combat-telemetry-tab.is-selected,
.combat-telemetry-tab[aria-selected='true'] {
  color: var(--text);
  border-color: var(--accent);
  background: var(--ui-control-fill-hover);
}

.combat-telemetry-history {
  position: relative;
  flex: 0 1 9.5rem;
  max-width: 42%;
  min-width: 0;
  z-index: 2;
}

.combat-telemetry-list {
  display: flex;
  flex-direction: column;
  gap: calc(3px * var(--ui-scale));
  height: calc(5 * 22px * var(--ui-scale) + 4 * 3px * var(--ui-scale));
  max-height: calc(5 * 22px * var(--ui-scale) + 4 * 3px * var(--ui-scale));
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  min-height: 0;
  flex: 0 0 auto;
  touch-action: pan-y;
}

.combat-telemetry-empty {
  display: flex;
  align-items: center;
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  padding: 0 calc(6px * var(--ui-scale));
  background: transparent;
}

.combat-telemetry-bar-row {
  position: relative;
  flex: 0 0 auto;
  height: calc(22px * var(--ui-scale));
  background: var(--ui-control-fill);
  overflow: hidden;
}

.combat-telemetry-bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  opacity: 0.85;
  pointer-events: none;
}

.combat-telemetry-bar-label {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(8px * var(--ui-scale));
  height: 100%;
  padding: 0 calc(6px * var(--ui-scale));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: var(--text);
  text-shadow: 0 1px 0px rgba(0, 0, 0, 0.85);
  font-variant-numeric: tabular-nums;
}

.combat-telemetry-bar-name {
  font-weight: var(--type-weight-strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.combat-telemetry-bar-stats {
  flex-shrink: 0;
  white-space: nowrap;
}

.combat-telemetry-footer {
  border-top: 1px solid var(--grid-line);
  padding-top: calc(6px * var(--ui-scale));
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  flex-shrink: 0;
}

.combat-telemetry-participant {
  display: flex;
  flex-direction: column;
  gap: calc(3px * var(--ui-scale));
  flex: 0 0 auto;
}

.combat-telemetry-bar-row.is-report-source {
  cursor: var(--cursor-action);
}

.combat-telemetry-bar-row.is-pinned {
  outline: 1px solid var(--accent);
  outline-offset: -1px;
}

.combat-telemetry-breakdown {
  box-sizing: border-box;
  flex: 0 0 auto;
  margin-left: calc(8px * var(--ui-scale));
  max-height: calc(4 * 22px * var(--ui-scale) + 3 * 3px * var(--ui-scale));
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  padding: calc(4px * var(--ui-scale));
  background: rgba(7, 12, 14, 0.55);
  border: 1px solid var(--accent);
  display: flex;
  flex-direction: column;
  gap: calc(3px * var(--ui-scale));
  pointer-events: auto;
}

.combat-telemetry-breakdown[hidden] {
  display: none;
}

.combat-telemetry-breakdown-list {
  display: flex;
  flex-direction: column;
  gap: calc(3px * var(--ui-scale));
  flex: 0 0 auto;
  min-height: 0;
}

.combat-telemetry-breakdown-empty {
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  padding: calc(4px * var(--ui-scale)) 0;
}

.combat-telemetry-breakdown-leading {
  display: flex;
  align-items: center;
  gap: calc(4px * var(--ui-scale));
  min-width: 0;
}

.combat-telemetry-breakdown-icon {
  width: calc(14px * var(--ui-scale));
  height: calc(14px * var(--ui-scale));
  flex-shrink: 0;
  object-fit: contain;
}

.worldmap-body {
  display: flex;
  flex-direction: column;
  gap: calc(5 * var(--gp));
}

/* A height-capped flex column: every row but the map holds its own height, so a
   window short of room runs out of it for the picture, not for the words. */

.worldmap-body > *:not(.worldmap-stage) {
  flex-shrink: 0;
}

/* One row above the frame naming what the frame is about. */

.worldmap-bar {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  min-height: calc(11 * var(--gp));
}

/* The frame's shape, which the short layout also sizes the window from. */

.window.win-worldmap {
  --worldmap-aspect: 1;
}

/* The map's frame: square, the full width of the window. The plane view inside it carries
   the canvas, the pins, the place card and the zoom controls. */

.worldmap-stage {
  position: relative;
  min-height: 0;
  width: 100%;
  aspect-ratio: var(--worldmap-aspect);
}

.worldmap-stage .world-plane {
  position: absolute;
  inset: 0;
  width: auto;
  aspect-ratio: auto;
}

.worldmap-zone-head {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  min-width: 0;
  flex: 1;
}

.worldmap-zone-name {
  font-weight: var(--type-weight-strong);
  color: var(--text);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

/* The place's standing marks float over its own map, in the top corner the
   zoom controls leave free below them: state worn on the picture, not mixed
   into its name. The chip backing is the short layout's own header plate, so
   floating chips and title bars read as one kit, and no notch clip — the marks
   open cards whose focus rings reach past the edge. */

.worldmap-zone-marks {
  position: absolute;
  top: calc(4 * var(--gp));
  right: calc(4 * var(--gp));
  z-index: 1;
  display: flex;
  align-items: center;
  gap: calc(2 * var(--gp));
  padding: calc(2 * var(--gp)) calc(3 * var(--gp));
  background: color-mix(in srgb, var(--pixel-night) 88%, transparent);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-ink);
}

.worldmap-zone-marks[hidden] {
  display: none;
}

.worldmap-zone-marks .hud-mark,
.worldmap-zone-mark {
  width: calc(12 * var(--gp));
  height: calc(12 * var(--gp));
  object-fit: contain;
}

.worldmap-zone-level {
  padding: 0 calc(3 * var(--gp));
  background: var(--pixel-ink);
  color: var(--info);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: calc(7 * var(--gp));
  white-space: nowrap;
}

.worldmap-remote {
  color: var(--info);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.worldmap-foot {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: calc(7 * var(--gp));
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  border-top: var(--gp) solid var(--pixel-dusk);
  padding-top: calc(3 * var(--gp));
}

/* Ruled off the authored line beside it: without the rule the coordinates read
   as the next words of the sentence they sit against. */

.worldmap-foot-pos {
  color: var(--text);
  white-space: nowrap;
  border-left: var(--gp) solid var(--pixel-dusk);
  padding-left: calc(5 * var(--gp));
}

.worldmap-foot-pos:empty {
  display: none;
}

.worldmap-info {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--gp));
}

/* A picked place's card, standing over the point that was clicked. */

.worldmap-card {
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
  width: max-content;
  max-width: calc(120 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-night) 94%, transparent);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
  color: var(--text);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  transform: translate(-50%, calc(-100% - 4 * var(--gp)));
  cursor: default;
}

.worldmap-card-title {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
}

.worldmap-card-name {
  font-weight: var(--type-weight-strong);
  color: var(--pixel-cream);
}

.worldmap-card-line {
  margin: 0;
  color: var(--muted);
}

.worldmap-card-here {
  color: var(--accent);
}

.worldmap-card-guide {
  align-self: flex-start;
}

/* A short landscape screen draws the same thing as desktop: the map fills the window,
   its name floats over its top edge, coordinates sit beside zoom controls bottom-right.
   The close cap takes a narrow gutter beside the map (over it, it'd sit on a plate's marks); the
   title bar folds away but its title stays the window's accessible name; legend waits for the
   taller layout. Stage height is the profile's window-body room; the 22 grid steps are the body's
   side padding plus the frame's padding/border. */

@media (orientation: landscape) and (max-height: 600px) {
  .window.win-worldmap {
    --worldmap-close: calc(14 * var(--gp));
    --worldmap-side: calc(var(--worldmap-close) + 4 * var(--gp));
    --worldmap-room-h: calc(100dvh - 16px - 6 * var(--gp));
    --worldmap-room-w: calc(100dvw - 32px);
    --worldmap-stage-h: round(
      down,
      min(
        calc(var(--worldmap-room-h) - 15 * var(--gp)),
        calc(
          (var(--worldmap-room-w) - 22 * var(--gp) - var(--worldmap-side)) / var(--worldmap-aspect)
        )
      ),
      var(--gp)
    );
    width: calc(
      var(--worldmap-stage-h) * var(--worldmap-aspect) + 22 * var(--gp) + var(--worldmap-side)
    );
    max-width: none;
  }
  /* The title bar is folded away, so nothing is left to drag the window by: it rests
     centred however a player once placed it, or a saved spot could leave it off-centre
     or under a notch with no way to move it back. */
  .window.win-worldmap,
  .window.win-worldmap.win-placed {
    top: 8px !important;
    left: 50% !important;
    right: auto !important;
    bottom: auto !important;
    transform: translateX(-50%) !important;
  }
  [data-ui-profile='handheld'] .window.win-worldmap.win-placed {
    top: 50% !important;
    transform: translate(-50%, -50%) !important;
  }
  /* A phone keeps a strip of play under every other window. The map is the one
     a player opens to stop and read, so it takes the whole safe glass. */
  [data-ui-profile='handheld'] .window.win-worldmap {
    --worldmap-close: round(up, var(--hud-touch-min), calc(2 * var(--gp)));
    --hud-window-max-h: calc(
      100dvh - var(--hud-safe-top, 8px) - var(--hud-safe-bottom, 8px) - 16px
    );
    --hud-window-max: calc(
      var(--worldmap-stage-h) * var(--worldmap-aspect) + 22 * var(--gp) + var(--worldmap-side)
    );
    --worldmap-room-h: round(
      down,
      calc(var(--hud-window-max-h) - 6 * var(--gp)),
      calc(2 * var(--gp))
    );
    --worldmap-room-w: calc(100dvw - var(--hud-safe-left, 8px) - var(--hud-safe-right, 8px) - 16px);
  }
  .window.win-worldmap .win-body.worldmap-body {
    display: block;
    position: relative;
    max-height: none;
    padding-inline-end: calc(8 * var(--gp) + var(--worldmap-side));
  }
  .win-worldmap .worldmap-stage {
    height: var(--worldmap-stage-h);
    width: auto;
    margin: 0;
  }
  .win-worldmap .win-head {
    position: absolute;
    z-index: 2;
    top: calc(9 * var(--gp));
    right: calc(10 * var(--gp));
    left: auto;
    height: auto;
    min-height: 0;
    padding: 0;
  }
  .win-worldmap .win-head > span:first-child,
  .win-worldmap .win-head::after {
    display: none;
  }
  .win-worldmap .worldmap-bar,
  .win-worldmap .worldmap-info {
    position: absolute;
    z-index: 1;
    left: calc(11 * var(--gp));
    pointer-events: none;
  }
  /* The info corner only reads out; taps pass through it to the map. */
  .win-worldmap .worldmap-bar > * {
    pointer-events: auto;
  }
  .win-worldmap .worldmap-bar {
    top: calc(10 * var(--gp));
    right: calc(11 * var(--gp) + var(--worldmap-side));
    align-items: flex-start;
  }
  /* The coordinates sit against the zoom controls, level with Find me: the readout
     beside the button that answers it. The square is 42 grid steps inset 3 from the
     map's corner with a 2-step gap between its buttons. */
  .win-worldmap .worldmap-info {
    /* Measured down from the map's top edge, which the body's padding fixes exactly
       (its bottom can sit a rounding step above the body's), then lifted by its own
       height so a party line above the coordinates grows upward. */
    top: calc(7 * var(--gp) + var(--worldmap-stage-h) - 4 * var(--gp));
    translate: 0 -100%;
    right: calc(56 * var(--gp) + var(--worldmap-side));
    align-items: flex-end;
    gap: calc(2 * var(--gp));
  }
  .win-worldmap .worldmap-foot-pos {
    display: flex;
    align-items: center;
    min-height: calc(20 * var(--gp));
    box-sizing: border-box;
  }
  .win-worldmap .worldmap-foot-pos:empty {
    display: none;
  }
  .win-worldmap .worldmap-foot-blurb {
    display: none;
  }
  .win-worldmap .worldmap-foot {
    border: 0;
    padding: 0;
  }
  .win-worldmap .worldmap-zone-head {
    flex: 0 1 auto;
  }
  .win-worldmap .worldmap-zone-head,
  .win-worldmap .worldmap-remote,
  .win-worldmap .worldmap-foot-pos {
    padding: var(--gp) calc(3 * var(--gp));
    border: 0;
    background: color-mix(in srgb, var(--pixel-night) 88%, transparent);
    box-shadow: inset 0 0 0 var(--gp) var(--pixel-ink);
  }
  /* Only the read-out chips wear the notch clip. */
  .win-worldmap .worldmap-remote,
  .win-worldmap .worldmap-foot-pos {
    clip-path: var(--pixel-notch);
  }
  /* A short stage has no room for a column of four; they gather into a corner square. */
  .win-worldmap .world-plane-controls {
    display: grid;
    grid-template-columns: repeat(2, max-content);
  }
}

.window.win-friends {
  width: calc(176 * var(--gp));
  max-width: calc(100vw - 48px);
}

.sw-list.friends-roster {
  max-height: calc(150 * var(--gp));
  margin-top: calc(4 * var(--gp));
}

/* The row itself does nothing on click; its buttons say what they do. */

.sw-row.friends-row {
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: calc(3 * var(--gp));
  min-height: calc(17 * var(--gp));
  padding-block: calc(2 * var(--gp));
  cursor: default;
}

.sw-row.friends-row[data-name] {
  grid-template-columns: minmax(0, 1fr) auto;
}

.friends-row.off .sw-name {
  color: var(--muted);
}

.friends-row-actions {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--gp));
}

/* Square bitmap buttons keep a long roster dense; the name stays the widest thing in a row. */

.friends-icon-btn.sw-edge,
.friends-icon-btn.sw-more {
  display: grid;
  place-items: center;
  width: calc(13 * var(--gp));
  min-width: 0;
  height: calc(13 * var(--gp));
  padding: 0;
}

.friends-icon-btn img {
  display: block;
  width: calc(10 * var(--gp));
  height: calc(10 * var(--gp));
  image-rendering: pixelated;
  pointer-events: none;
}

.friends-icon-btn.sw-edge:active,
.friends-icon-btn.sw-more:active {
  box-shadow: inset var(--gp) var(--gp) 0 var(--pixel-night);
}

.friends-icon-btn:active img {
  transform: translateY(var(--gp));
}

.friends-group + .friends-group {
  border-top: var(--gp) solid var(--pixel-dusk);
}

.friends-group-head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  justify-content: space-between;
  padding: calc(3 * var(--gp)) calc(4 * var(--gp)) calc(2 * var(--gp));
  border-bottom: var(--gp) solid var(--pixel-dusk);
  background: color-mix(in srgb, var(--pixel-ink) 70%, var(--pixel-night));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.friends-group-count {
  font-variant-numeric: tabular-nums;
}

.sw-status.friends-status {
  min-height: 0;
  padding: calc(3 * var(--gp)) var(--gp) 0;
}

.friends-status[hidden] {
  display: none;
}

.friends-find {
  position: relative;
  display: block;
  margin-top: calc(4 * var(--gp));
}

.friends-find::before {
  content: '';
  position: absolute;
  z-index: 1;
  left: calc(4 * var(--gp));
  top: 50%;
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  transform: translateY(-50%);
  pointer-events: none;
  background: url('/assets/hud-search-C2MSQsDv.webp') center / contain no-repeat;
  opacity: 0.8;
}

.friends-find .ron-field {
  width: 100%;
  height: calc(14 * var(--gp));
  padding-left: calc(15 * var(--gp));
}

.sw-pane .friends-empty {
  display: grid;
  justify-items: center;
  gap: calc(2 * var(--gp));
  margin-top: calc(4 * var(--gp));
  padding: calc(10 * var(--gp)) calc(8 * var(--gp));
  text-align: center;
  border: var(--gp) dashed var(--pixel-dusk);
}

.friends-empty-ico {
  width: calc(22 * var(--gp));
  height: calc(22 * var(--gp));
  margin-bottom: calc(2 * var(--gp));
  object-fit: contain;
  image-rendering: pixelated;
  opacity: 0.9;
}

.friends-empty .sw-empty-hint {
  max-width: calc(140 * var(--gp));
  margin-top: 0;
  color: var(--muted);
}

.friends-foot {
  margin: calc(3 * var(--gp)) var(--gp) 0;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

body.high-contrast .sw-row.friends-row {
  border-color: #6f7d92;
  background: #0a0e14;
}

.window.win-party {
  width: calc(170 * var(--gp));
  max-width: calc(100vw - 48px);
}

.window.win-party .win-body,
.window.win-friends .win-body,
.window.win-guild .win-body {
  max-height: round(down, min(72vh, 560px), calc(2 * var(--gp)));
}

.window.win-system-utility {
  top: clamp(84px, 14vh, 120px);
  left: auto;
  right: clamp(24px, 8vw, 130px);
  transform: none;
  width: calc(230 * var(--gp));
  max-width: calc(100vw - 48px);
}

.window.win-system-utility .win-body {
  max-height: round(down, min(72vh, 560px), calc(2 * var(--gp)));
}

.win-head {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: calc(5 * var(--gp));
  flex: 0 0 auto;
  font-family: var(--font-display);
  -webkit-font-smoothing: none;
  font-weight: var(--type-weight-display);
  letter-spacing: 0.02em;
  font-size: var(--type-window-title-size);
  box-shadow: none;
}

.win-head::after {
  content: '';
  position: absolute;
  bottom: 0;
}

.win-head > span:first-child {
  display: inline-flex;
  align-items: center;
  gap: calc(5 * var(--gp));
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.win-close {
  position: relative;
  flex: 0 0 auto;
  padding: 0;
  cursor: var(--cursor-action);
  color: transparent;
  font-size: 0;
  background-image: url('/assets/hud-close-Bz6Icy_E.webp');
  background-position: center;
  background-repeat: no-repeat;
}

.win-body {
  overflow-y: auto;
}

.bank-summary-row,
.storage-sec-card,
.storage-sec-status,
.storage-log-row,
.sw-list,
.sysutil-status,
.sysutil-row,
.guild-notice-form,
.guild-disband-form {
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.bank-summary {
  display: grid;
  gap: calc(3 * var(--gp));
  margin-bottom: calc(5 * var(--gp));
}

.bank-summary-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(6 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
}

.bank-summary-label {
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.bank-summary-value {
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-variant-numeric: tabular-nums;
}

.bank-amount {
  display: grid;
  gap: calc(3 * var(--gp));
  margin-bottom: calc(4 * var(--gp));
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.bank-amount input {
  width: 100%;
  font-variant-numeric: tabular-nums;
}

.bank-quick {
  display: flex;
  flex-wrap: wrap;
  gap: calc(3 * var(--gp));
  margin-bottom: calc(4 * var(--gp));
}

/* The quick chips count money; their digits stay tabular on the kit button. */

.bank-quick .ron-btn {
  font-variant-numeric: tabular-nums;
}

.bank-actions {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(3 * var(--gp));
}

.storage-sec-card,
.storage-sec-status {
  padding: calc(4 * var(--gp));
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.storage-sec-status {
  margin-top: calc(4 * var(--gp));
  color: var(--muted);
}

.storage-log-list {
  display: grid;
  gap: calc(3 * var(--gp));
  max-height: calc(120 * var(--gp));
  overflow-y: auto;
}

.storage-log-row {
  display: grid;
  grid-template-columns: calc(24 * var(--gp)) minmax(0, 1fr);
  gap: calc(2 * var(--gp)) calc(4 * var(--gp));
  align-items: baseline;
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
}

.storage-log-put {
  color: var(--good);
  font-weight: var(--type-weight-strong);
}

.storage-log-take {
  color: var(--accent);
  font-weight: var(--type-weight-strong);
}

.storage-log-item {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.storage-log-meta {
  grid-column: 2;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.storage-log-empty {
  padding: calc(4 * var(--gp));
  color: var(--muted);
  border: var(--gp) solid var(--pixel-dusk);
}

.sw-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
}

.sw-tabs {
  display: flex;
  flex: 0 0 auto;
  gap: calc(2 * var(--gp));
  margin-bottom: calc(5 * var(--gp));
}

/* A row seated on the frame itself keeps clear of its rim, in line with a body's inset. */

.win-frame > .sw-tabs {
  padding-inline: calc(6 * var(--gp));
}

.sw-tab {
  display: inline-flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  min-height: calc(15 * var(--gp));
  padding: calc(2 * var(--gp)) calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  clip-path: var(--pixel-notch);
  background: var(--pixel-ink);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  color: var(--muted);
  cursor: var(--cursor-action);
}

.sw-tab:hover {
  color: var(--pixel-cream);
}

.sw-tab[aria-selected='true'] {
  background: var(--pixel-dusk);
  color: var(--pixel-cream);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}

.sw-tab-count {
  min-width: 1.4em;
  padding: 0 calc(3 * var(--gp));
  background: var(--pixel-night);
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
}

.sw-tab[aria-selected='true'] .sw-tab-count {
  background: color-mix(in srgb, var(--gold) 12%, var(--pixel-night));
  color: var(--gold-ink);
}

/* A face may carry art before its word: a narrow frame drops the word and keeps the picture, but a tab with no art keeps its word at every width. */

.sw-tab-ico {
  display: block;
  width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  object-fit: contain;
  opacity: 0.72;
}

.sw-tab[aria-selected='true'] .sw-tab-ico {
  opacity: 1;
}

@media (max-width: 520px) {
  .sw-tab:has(.sw-tab-ico) {
    padding-inline: calc(3 * var(--gp));
  }
  .sw-tab:has(.sw-tab-ico) .sw-tab-label {
    display: none;
  }
}

.sw-pane[hidden] {
  display: none;
}

.sw-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: calc(3 * var(--gp));
  margin-bottom: calc(4 * var(--gp));
  padding: 0 var(--gp) calc(4 * var(--gp));
  border-bottom: var(--gp) solid var(--pixel-dusk);
  background: transparent;
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.sw-summary-strong {
  color: var(--text);
  font-weight: var(--type-weight-strong);
}

.sw-summary-sep {
  opacity: 0.55;
}

.sw-section {
  margin-top: calc(5 * var(--gp));
}

.sw-section-title {
  margin-bottom: calc(3 * var(--gp));
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.sw-list {
  display: grid;
  gap: 0;
  max-height: calc(130 * var(--gp));
  overflow-y: auto;
}

.sw-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  gap: calc(4 * var(--gp));
  align-items: center;
  min-height: calc(22 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  border: 0;
  border-bottom: var(--gp) solid var(--pixel-dusk);
  border-left: var(--gp) solid transparent;
  background: transparent;
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  cursor: var(--cursor-action);
}

.sw-row:last-child {
  border-bottom: 0;
}

.sw-row.off {
  color: var(--muted);
}

.sw-row.is-self {
  border-left-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, var(--pixel-night));
}

.sw-row.is-dead {
  border-left-color: var(--danger);
}

.sw-row:hover {
  background: var(--row-hover);
}

.sw-row:focus-visible,
.sw-tab:focus-visible,
.sw-more:focus-visible,
.sw-edge:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.sw-dot {
  width: calc(4 * var(--gp));
  height: calc(4 * var(--gp));
  background: var(--pixel-lilac);
  flex: 0 0 auto;
}

.sw-dot.on {
  background: var(--good);
}

.sw-id {
  min-width: 0;
  display: grid;
  gap: var(--gp);
}

.sw-name,
.sw-meta {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sw-meta {
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.sw-you {
  margin-left: calc(2 * var(--gp));
  padding: 0 calc(2 * var(--gp));
  border: var(--gp) solid color-mix(in srgb, var(--gold) 45%, var(--pixel-night));
  color: var(--gold-ink);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.sw-presence {
  justify-self: end;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  text-transform: lowercase;
  white-space: nowrap;
}

.sw-presence.is-online {
  color: var(--good);
}

.sw-more,
.sw-edge {
  width: auto;
  min-width: calc(13 * var(--gp));
  height: calc(12 * var(--gp));
  padding: 0 calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  clip-path: var(--pixel-notch);
  background: var(--pixel-dusk);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  cursor: var(--cursor-action);
  color: var(--pixel-cream);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
}

.sw-more:hover,
.sw-edge:hover {
  background: color-mix(in srgb, var(--pixel-slate) 45%, var(--pixel-dusk));
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-lilac),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}

.sw-actions {
  display: flex;
  gap: calc(3 * var(--gp));
  margin-top: 0;
}

/* The seat states only the height so the field lines up with the submit button. */

.sw-actions .ron-field {
  flex: 1 1 auto;
  height: calc(15 * var(--gp));
}

.sw-empty {
  padding: calc(7 * var(--gp)) calc(6 * var(--gp));
  color: var(--muted);
  border: 0;
}

.sw-empty-title {
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-medium);
}

.sw-empty-hint {
  margin-top: calc(2 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.35;
}

.sw-sub {
  min-width: 0;
  display: flex;
  justify-content: space-between;
  gap: calc(4 * var(--gp));
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.sw-badge {
  justify-self: end;
  padding: 0 calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  text-transform: uppercase;
}

.sw-badge.lead {
  color: var(--gold-ink);
  border-color: color-mix(in srgb, var(--gold) 45%, var(--pixel-night));
}

/* A downed unit reads the one danger red everywhere, painted inline (DANGER_COLOR) so every palette mode reaches it. */

.party-roster {
  max-height: calc(120 * var(--gp));
}

.party-member-row {
  grid-template-columns: auto minmax(0, 1fr) auto auto;
}

.party-share {
  display: grid;
  gap: calc(2 * var(--gp));
  margin: calc(5 * var(--gp)) 0 0;
  padding: calc(5 * var(--gp)) var(--gp) 0;
  border-top: var(--gp) solid var(--pixel-dusk);
  background: transparent;
}

.party-toggle-row {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  margin-top: calc(3 * var(--gp));
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.party-toggle-row.is-disabled {
  opacity: 0.55;
}

/* The party is under one loot rule, so the two choices are radios in one group. */

.party-loot-rule {
  display: grid;
  gap: var(--gp);
  margin: calc(4 * var(--gp)) 0 0;
  padding: 0;
  border: 0;
}

.party-loot-rule legend {
  padding: 0;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.party-loot-rule-row {
  align-items: flex-start;
}

.party-loot-rule-row input {
  margin-top: var(--gp);
}

.party-loot-rule-row span {
  display: grid;
  gap: var(--gp);
}

.party-loot-rule-hint {
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.party-prefs {
  margin-top: calc(5 * var(--gp));
  padding: calc(4 * var(--gp)) var(--gp) 0;
  border-top: var(--gp) solid var(--pixel-dusk);
  background: transparent;
}

.party-invite-section {
  margin-top: calc(5 * var(--gp));
}

.guild-roster {
  max-height: calc(130 * var(--gp));
}

.window.win-guild {
  width: calc(180 * var(--gp));
  max-width: calc(100vw - 48px);
}

.window.win-guild .sw-tabs {
  overflow-x: auto;
  padding-bottom: var(--gp);
}

.window.win-guild .sw-tab {
  flex: 0 0 auto;
}

.window.win-guild .sw-card {
  display: grid;
  gap: calc(3 * var(--gp));
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
}

.window.win-guild .sw-stat {
  display: flex;
  justify-content: space-between;
  gap: calc(5 * var(--gp));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.window.win-guild .sw-stat-label {
  color: var(--muted);
}

.window.win-guild .sw-stat-val {
  min-width: 0;
  color: var(--text);
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.guild-sort {
  display: flex;
  gap: calc(2 * var(--gp));
  margin-left: auto;
}

.guild-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: calc(5 * var(--gp));
}

.guild-notice-form,
.guild-disband-form {
  display: grid;
  gap: calc(3 * var(--gp));
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
}

.guild-notice-form textarea {
  resize: vertical;
}

.guild-member-row {
  grid-template-columns: auto minmax(0, 1fr) auto;
}

.guild-member-row.is-managed {
  grid-template-columns: auto minmax(0, 1fr) auto;
}

.party-prefs + .ron-btn {
  margin-top: calc(4 * var(--gp));
}

.sysutil-status {
  padding: calc(4 * var(--gp));
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.sysutil-section {
  margin-top: calc(5 * var(--gp));
}

.sysutil-list {
  display: grid;
  gap: calc(3 * var(--gp));
  max-height: calc(75 * var(--gp));
  overflow-y: auto;
}

.sysutil-row {
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sysutil-empty {
  padding: calc(4 * var(--gp));
  color: var(--muted);
  border: var(--gp) solid var(--pixel-dusk);
}

/* Plain vertical stack, NOT display:grid (a stray grid once forced every section into 46px columns). Only the bag grid scrolls: fixed-height flex column, no body scroll. */

.win-inv .win-body {
  max-height: round(down, 74vh, calc(2 * var(--gp)));
  overflow: auto;
}

.inv-window .inv-grid {
  flex: 1 1 auto;
  overflow-y: auto;
  align-content: start;
}

.inv-amt {
  position: absolute;
  right: var(--gp);
  bottom: var(--gp);
  z-index: 1;
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--pixel-cream);
  line-height: 1;
  padding: 0 var(--gp);
  background: var(--pixel-ink);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.inv-refine {
  position: absolute;
  left: var(--gp);
  top: var(--gp);
  z-index: 1;
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--gold-value);
  line-height: 1;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.inv-search {
  flex: 1;
  min-width: calc(30 * var(--gp));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.inv-hint {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: var(--muted);
  margin-bottom: calc(3 * var(--gp));
}

.inv-ctx .context-item {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  padding: calc(3 * var(--gp)) calc(5 * var(--gp));
}

.skill-list {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
}

.item-fact {
  display: block;
  min-width: 0;
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  line-height: 1.3;
  overflow-wrap: anywhere;
  white-space: normal;
}

.shop-panel,
.cashshop-panel,
.mail-panel,
.itemsvc-panel,
.refine-panel,
.armory-panel,
.informant-panel,
.frontline-panel,
.trade-panel {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: var(--text);
  background: var(--ui-frame-fill);
}

/* A frame holds the tallest it has been while open, so the working area takes the surplus instead of leaving a void; inert while the frame is sized by content. */

.win-body,
.shop-body,
.cashshop-content,
.mail-workspace,
.itemsvc-content,
.refine-body,
.trade-body {
  flex-grow: 1;
}

/* The vault window's own layout: the bag beside the shelves, one cell grammar
   on both sides. It lives in its own sheet because it is a whole window's
   working layout, not another rule in the shared content sheet; cells still
   reuse `.inv-cell` from inventory.css so a stack looks the same wherever it
   sits, and only the panes and their chrome are here. */

.storage-overlay {
  position: fixed;
  inset: 0;
  z-index: 36;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--pixel-ink) 50%, transparent);
}

.storage-panel {
  --win-frame-w: 860;
  --win-frame-h: 540;
  --win-frame-inset-y: 72px;
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--gp));
}

.vault-panes {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(5 * var(--gp));
}

.vault-pane {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  padding: calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--sw-well);
  box-shadow: var(--sw-well-light);
  clip-path: var(--pixel-notch);
}

/* A pane that will take the drop wears the key bracket inside its outline. */

.vault-pane--drop {
  box-shadow: var(--ui-focus-ring);
}

.vault-pane-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(4 * var(--gp));
  min-width: 0;
}

.vault-pane-title {
  margin: 0;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.vault-capacity {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  flex: none;
}

.vault-capacity-bar {
  width: calc(32 * var(--gp));
}

.vault-capacity-count {
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-variant-numeric: tabular-nums;
}

.vault-filters {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  flex-wrap: wrap;
}

.vault-cats {
  display: flex;
  gap: calc(2 * var(--gp));
  min-width: 0;
}

/* A shelf tab is a sunk well and the open one stands up as a plate, as the Bag's do. */

.vault-cat {
  padding: var(--gp) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  color: var(--muted);
  clip-path: var(--pixel-notch);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  cursor: var(--cursor-action);
}

.vault-cat--on {
  background: var(--pixel-dusk);
  color: var(--pixel-cream);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}

.vault-cat:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.vault-search {
  flex: 1;
  min-width: calc(45 * var(--gp));
}

.vault-grid {
  --inv-slot: calc(22 * var(--gp));
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  align-content: start;
  display: grid;
  grid-template-columns: repeat(auto-fill, var(--inv-slot));
  gap: calc(2 * var(--gp));
  justify-content: start;
}

.vault-empty {
  flex: 1;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: calc(6 * var(--gp));
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.5;
}

/* Handheld: a phone in landscape has the width for two panes but not the height
   for two full grids, so the window narrows and the cell grid tightens rather
   than the panes stacking — stacking would put the shelves below the fold, and
   the whole point is seeing both sides at once. Keyed off the play shell's own
   profile attribute, not a viewport width: the shell stamps the profile, and a
   phone in landscape is wider than any width query would catch. */

[data-ui-profile='handheld'] .storage-panel {
  --win-frame-w: 720;
  --win-frame-h: 380;
}

[data-ui-profile='handheld'] .vault-pane {
  padding: calc(2 * var(--gp));
}

[data-ui-profile='handheld'] .vault-pane-title {
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

/* A phone's slot keeps its smaller design size, stepped to whole pairs of HUD pixels. */

[data-ui-profile='handheld'] .vault-grid {
  --inv-slot: round(calc(38px * var(--ui-scale)), calc(2 * var(--gp)));
}

/* Shop and premium-catalog window layouts. */

/* Modal NPC shop composes the same chrome as draggable windows. */

.shop-panel {
  --win-frame-w: 430;
  --win-frame-h: 620;
  /* The list is long and the window is narrow: it has always kept more of the
     glass clear below it than the wider counters do. */
  --win-frame-fill-h: 72dvh;
}

.shop-body {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--gp));
  min-height: 0;
  padding: calc(5 * var(--gp)) calc(6 * var(--gp)) calc(6 * var(--gp));
}

.shop-list {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  min-height: 0;
  overflow-y: auto;
}

/* Each ware is a sunk well (service-windows.css); the pointer lifts its face. */

.shop-row {
  display: grid;
  grid-template-columns:
    calc(16 * var(--gp))
    minmax(calc(43 * var(--gp)), 1fr)
    auto
    calc(29 * var(--gp))
    calc(36 * var(--gp));
  align-items: center;
  gap: calc(4 * var(--gp));
  min-height: calc(23 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  background: var(--sw-well);
  border: var(--gp) solid var(--pixel-ink);
  box-shadow: var(--sw-well-light);
  clip-path: var(--pixel-notch);
}

.shop-row:hover {
  background: var(--pixel-night);
}

.shop-row-icon {
  width: calc(15 * var(--gp));
  height: calc(15 * var(--gp));
  object-fit: contain;
}

.shop-row-copy {
  min-width: 0;
}

.shop-row-facts {
  min-width: 0;
  margin-top: var(--gp);
}

.shop-row-name {
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-medium);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.shop-row-meta {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.shop-qty {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--gp);
}

.shop-step {
  min-width: calc(12 * var(--gp));
  min-height: calc(12 * var(--gp));
  padding: 0;
}

.shop-qty-value {
  min-width: calc(11 * var(--gp));
  text-align: center;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-variant-numeric: tabular-nums;
}

.shop-row-total {
  text-align: right;
}

.shop-empty {
  padding: calc(9 * var(--gp)) calc(4 * var(--gp));
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  text-align: center;
}

@media (max-width: 560px) {
  .shop-row {
    grid-template-columns: calc(16 * var(--gp)) minmax(0, 1fr) auto;
  }
  .shop-qty {
    grid-column: 2;
    justify-content: flex-start;
  }
  .shop-row-total {
    grid-column: 3;
    grid-row: 1;
  }
  .shop-row-action {
    grid-column: 3;
    grid-row: 2;
  }
}

.cashshop-panel {
  --win-frame-w: 500;
  --win-frame-h: 660;
}

.cashshop-balance {
  color: var(--accent);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
}

.cashshop-toolbar {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  align-items: center;
  gap: calc(5 * var(--gp));
  padding: calc(4 * var(--gp)) calc(6 * var(--gp));
  border-block-end: var(--gp) solid var(--pixel-dusk);
}

.cashshop-current-tab {
  color: color-mix(in srgb, var(--accent) 62%, var(--text));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.cashshop-amount {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

.cashshop-amount input {
  width: calc(32 * var(--gp));
  min-height: calc(14 * var(--gp));
}

.cashshop-list + .cashshop-tab-heading {
  margin-top: calc(4 * var(--gp));
}

.cashshop-content {
  min-height: 0;
  overflow-y: auto;
  padding: calc(2 * var(--gp)) calc(6 * var(--gp)) calc(6 * var(--gp));
}

.cashshop-section {
  margin-top: calc(5 * var(--gp));
}

.cashshop-section-title,
.cashshop-list {
  display: grid;
  max-height: calc(105 * var(--gp));
  overflow-y: auto;
  border-block-start: var(--gp) solid var(--pixel-dusk);
}

/* A list is one well, split by dusk rules; each row carries a slate mark at
   its leading edge. */

.cashshop-list {
  border: var(--gp) solid var(--pixel-ink);
  background: var(--sw-well);
  box-shadow: var(--sw-well-light);
  clip-path: var(--pixel-notch);
}

.cashshop-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: calc(2 * var(--gp)) calc(4 * var(--gp));
  align-items: center;
  min-height: calc(22 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp)) calc(3 * var(--gp)) calc(5 * var(--gp));
  border-block-end: var(--gp) solid var(--pixel-dusk);
  background: transparent;
}

.cashshop-row:last-child {
  border-block-end: 0;
}

.cashshop-row::before {
  position: absolute;
  inset: calc(4 * var(--gp)) auto calc(4 * var(--gp)) 0;
  width: var(--gp);
  content: '';
  background: var(--pixel-slate);
}

.cashshop-row:hover {
  background: var(--row-hover);
}

.cashshop-row-info {
  grid-template-columns: minmax(0, 1fr);
}

.cashshop-row-main {
  min-width: 0;
}

.cashshop-row-title {
  min-width: 0;
  overflow: hidden;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cashshop-row-meta {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

@media (max-width: 560px) {
  .cashshop-toolbar {
    grid-template-columns: auto 1fr;
  }
}

/* ===== Shared service-window chrome ========================================
   The parts every modal service window wears the same way, defined once: the
   purse in its header, the row of faces under it, the status line at its foot,
   and the sentence a face shows when it has nothing to list. A window's own
   sheet owns its dimensions and its working layout; it does not restate these.
   ============================================================================ */

/* A list, a row card or a pane inside a service window is a sunk pixel well
   (pixel-chrome.css): the ink outline, a face a step under the window's, lit
   along its lower right. Each sheet paints its wells from these two. */

.shop-panel,
.cashshop-panel,
.mail-panel,
.itemsvc-panel,
.storage-panel {
  --sw-well: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  --sw-well-light: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

/* What the player is carrying, in a window header. The reviewed coin, then the
   number — the same pair the bag's footer draws, so gold reads as gold
   wherever a window prices something. */

.sw-purse {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: calc(3 * var(--gp));
  color: var(--accent);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* One text field for a service window — an amount, a name, a mail draft, a
   filter word — is a kit field (`ron-field` in ui-kit.css): the paint and the
   focus ring live there, once, for every surface. A window's sheet owns its
   dimensions and its working layout; it does not restate the paint. */

/* The gold a row asks for — coin and amount; short reads as short so the
   price and the row's dead button never disagree. */

.sw-price {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: calc(2 * var(--gp));
  color: var(--accent);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.sw-price.is-short {
  color: var(--danger);
}

.sw-price-coin {
  width: calc(7 * var(--gp));
  height: calc(7 * var(--gp));
  object-fit: contain;
  display: block;
}

.sw-purse-coin {
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  object-fit: contain;
  display: block;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

/* The last thing the window said, at its foot: one line, announced, and it
   stands until the next answer replaces it. */

.sw-status {
  flex: 0 0 auto;
  min-height: calc(10 * var(--gp));
  padding: 0 calc(7 * var(--gp)) calc(4 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-medium);
}

.sw-status[data-tone='info'] {
  color: var(--muted);
}

.sw-status[data-tone='ok'] {
  color: var(--good);
}

.sw-status[data-tone='warn'] {
  color: var(--warn);
}

.sw-status[data-tone='error'] {
  color: var(--danger);
}

/* Mail and item-service window layouts. */

.mail-panel {
  --win-frame-w: 660;
  --win-frame-h: 640;
}

.mail-workspace {
  display: grid;
  grid-template-columns: minmax(calc(105 * var(--gp)), 0.82fr) minmax(0, 1.35fr);
  min-height: 0;
  overflow: hidden;
}

.mail-inbox-pane,
.mail-reader-pane,
.mail-compose-pane {
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
}

.mail-inbox-pane {
  border-inline-end: var(--gp) solid var(--pixel-dusk);
}

.mail-compose-pane {
  grid-column: 1 / -1;
}

.mail-section {
  padding: calc(5 * var(--gp)) calc(6 * var(--gp));
}

.mail-inbox-section {
  padding-block-end: 0;
}

/* The inbox is the shared DataGrid; the host gives it the pane's height budget
 * and the rows keep the mail reading: title + meta line, unread weight, the
 * accent edge a selected row wears. */

.mail-grid-host {
  min-height: 0;
}

.mail-grid-host .dgrid {
  height: auto;
  max-height: calc(195 * var(--gp));
}

.mail-grid-host .dgrid-row {
  cursor: var(--cursor-action);
}

.mail-grid-host .dgrid-body {
  max-height: calc(180 * var(--gp));
}

.mail-cell {
  min-width: 0;
  display: grid;
  gap: var(--gp);
}

.mail-row-title {
  min-width: 0;
  overflow: hidden;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mail-row-title.is-unread {
  color: var(--text);
}

.mail-row-title.is-unread::after {
  content: '';
  display: inline-block;
  width: calc(3 * var(--gp));
  height: calc(3 * var(--gp));
  margin-inline-start: calc(2 * var(--gp));
  background: var(--accent);
  vertical-align: middle;
}

.mail-row-meta {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: 1.35;
}

.mail-read {
  display: grid;
  gap: calc(3 * var(--gp));
}

.mail-read-card {
  color: var(--text);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

/* The letter hangs off a dusk rule. */

.mail-body {
  min-height: calc(45 * var(--gp));
  border-inline-start: var(--gp) solid var(--pixel-dusk);
  padding-inline-start: calc(5 * var(--gp));
  color: color-mix(in srgb, var(--text) 82%, var(--muted));
  white-space: pre-wrap;
  line-height: 1.48;
}

.mail-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: calc(3 * var(--gp));
  margin-top: calc(5 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-dusk);
  padding-block-start: calc(4 * var(--gp));
}

.mail-attachment-item {
  min-width: min(100%, calc(90 * var(--gp)));
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(2 * var(--gp));
  padding: var(--gp) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  color: var(--text);
  background: var(--sw-well);
  box-shadow: var(--sw-well-light);
  clip-path: var(--pixel-notch);
}

/* An attachment reads like an item everywhere: art, rarity-coloured name, ×count. */

.mail-attachment-icon {
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  object-fit: contain;
  flex: none;
}

.mail-attachment-name {
  min-width: 0;
  overflow: hidden;
  font-weight: var(--type-weight-medium);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mail-gold {
  margin-top: calc(3 * var(--gp));
}

.mail-attachment-preview {
  min-width: 0;
  margin-top: calc(4 * var(--gp));
}

.mail-actions {
  display: flex;
  flex-wrap: wrap;
  gap: calc(3 * var(--gp));
  margin-top: calc(5 * var(--gp));
}

/* The row's buttons are kit buttons; the mail surface only holds them to the
   compact height and type size it has always used. A list row's delete keeps
   the kit's small size. */

.mail-actions button,
.mail-action {
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

.mail-actions button {
  min-height: calc(14 * var(--gp));
  padding-inline: calc(4 * var(--gp));
}

.mail-compose {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(4 * var(--gp)) calc(5 * var(--gp));
}

.mail-compose > .mail-actions {
  grid-column: 1 / -1;
}

.mail-field {
  display: grid;
  gap: calc(2 * var(--gp));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

.mail-field textarea {
  width: 100%;
}

.mail-field ron-select {
  width: 100%;
}

.mail-field textarea {
  resize: vertical;
}

.mail-attach-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: calc(3 * var(--gp));
}

.mail-attach-form .mail-actions {
  grid-column: 1 / -1;
  margin-top: 0;
}

.mail-field-wide {
  grid-column: 1 / -1;
}

/* The latest results run the window's width under a dusk rule, on the window's
   own face, so the frame's rim stays unbroken beside them. */

.mail-result {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: calc(4 * var(--gp));
  min-height: calc(16 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-dusk);
  padding: calc(3 * var(--gp)) calc(6 * var(--gp));
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
}

.mail-result-history {
  min-width: 0;
  max-height: calc(29 * var(--gp));
  display: grid;
  gap: var(--gp);
  overflow-y: auto;
}

.mail-result-line {
  display: flex;
  min-width: 0;
  align-items: baseline;
  gap: calc(3 * var(--gp));
}

.mail-result-line strong {
  flex: 0 0 auto;
  color: var(--text);
  font-weight: var(--type-weight-strong);
}

.mail-result-line span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 620px) {
  .mail-grid-host .dgrid-row {
    min-height: calc(20 * var(--gp));
  }
  /* A phone-width glass gives the inbox the screen, minus a hairline. */
  .mail-panel {
    --win-frame-inset-x: 20px;
    --win-frame-inset-y: 20px;
    --win-frame-w: 100000;
  }
  .mail-head {
    grid-template-columns: minmax(0, 1fr) auto;
  }
  .mail-head .win-close {
    grid-column: 2;
    grid-row: 1 / span 2;
  }
  .mail-workspace {
    display: block;
    overflow-y: auto;
  }
  .mail-inbox-pane {
    border-inline-end: 0;
    border-block-end: var(--gp) solid var(--pixel-dusk);
  }
  .mail-grid-host .dgrid {
    max-height: calc(90 * var(--gp));
  }
  .mail-grid-host .dgrid-body {
    max-height: calc(75 * var(--gp));
  }
  .mail-compose {
    grid-template-columns: minmax(0, 1fr);
  }
  .mail-field-wide,
  .mail-compose > .mail-actions {
    grid-column: 1;
  }
  .mail-result {
    display: grid;
  }
  .mail-result {
    grid-template-columns: minmax(0, 1fr);
  }
}

.itemsvc-panel {
  --win-frame-w: 540;
  --win-frame-h: 680;
}

.itemsvc-content {
  min-height: 0;
  overflow-y: auto;
  padding: calc(2 * var(--gp)) calc(6 * var(--gp)) calc(6 * var(--gp));
}

.itemsvc-section {
  margin-top: calc(5 * var(--gp));
}

/* A section's rows sit in one well, split by dusk rules; each row carries a
   slate mark at its leading edge. */

.itemsvc-list {
  display: grid;
  max-height: calc(115 * var(--gp));
  overflow-y: auto;
  border: var(--gp) solid var(--pixel-ink);
  background: var(--sw-well);
  box-shadow: var(--sw-well-light);
  clip-path: var(--pixel-notch);
}

.itemsvc-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--gp) calc(4 * var(--gp));
  min-height: calc(23 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp)) calc(3 * var(--gp)) calc(5 * var(--gp));
  border-block-end: var(--gp) solid var(--pixel-dusk);
  background: transparent;
  color: var(--text);
}

.itemsvc-list > .itemsvc-row:last-child {
  border-block-end: 0;
}

.itemsvc-row::before {
  position: absolute;
  inset: calc(4 * var(--gp)) auto calc(4 * var(--gp)) 0;
  width: var(--gp);
  content: '';
  background: var(--pixel-slate);
}

.itemsvc-row:hover {
  background: var(--row-hover);
}

.itemsvc-row-title {
  min-width: 0;
  overflow: hidden;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.itemsvc-row-meta {
  grid-column: 1;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

.itemsvc-actions {
  grid-column: 2;
  grid-row: 1 / span 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: end;
  gap: calc(3 * var(--gp));
  margin-top: 0;
}

.itemsvc-actions input {
  width: calc(32 * var(--gp));
  height: calc(14 * var(--gp));
  font-variant-numeric: tabular-nums;
}

.itemsvc-actions input[type='text'] {
  width: calc(132px * var(--type-scale, 1));
}

.itemsvc-result {
  min-height: calc(8 * var(--gp));
  margin-top: calc(4 * var(--gp));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

.itemsvc-result .itemsvc-row {
  min-height: 0;
  grid-template-columns: minmax(0, 1fr);
}

@media (max-width: 560px) {
  .itemsvc-head {
    grid-template-columns: minmax(0, 1fr) auto;
  }
  .itemsvc-head .win-close {
    grid-column: 2;
    grid-row: 1 / span 2;
  }
  .itemsvc-row {
    grid-template-columns: minmax(0, 1fr);
  }
  .itemsvc-actions {
    grid-column: 1;
    grid-row: 3;
    justify-content: start;
  }
}

/* Refining composes the shared modal frame, header, gauge, item slot and button kit; local paint is the ladder pips, step arrow and protect switch.
   Colour never carries a state alone: rungs differ in shape and the gauge prints its percent. */

/* The frame height is stated (`is-stable` on the panel) and each face scrolls its own reading; it clears the tallest anvil. */

.refine-panel {
  --win-frame-w: 760;
  --win-frame-h: 660;
  --refine-well-face: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  --refine-well-light: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

.refine-body {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

/* Anvil: rack left, piece and readings right; each face scrolls its own columns. */

.refine-anvil {
  display: grid;
  flex: 1 1 0;
  grid-template-columns: calc(98 * var(--gp)) minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  min-height: 0;
  overflow: hidden;
}

.refine-anvil.is-bare {
  grid-template-columns: minmax(0, 1fr);
}

.refine-rack {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--gp));
  min-height: 0;
  padding: calc(6 * var(--gp));
  border-inline-end: var(--gp) solid var(--pixel-dusk);
  background: var(--refine-well-face);
}

.refine-rail-title,
.refine-block h3 {
  margin: 0;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.refine-block h3 {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(4 * var(--gp));
}

.refine-block h3 small {
  color: var(--accent);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0;
  text-transform: none;
}

.refine-rack-grid {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
  min-height: 0;
  overflow-y: auto;
}

.refine-gear {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: calc(4 * var(--gp));
  padding: calc(2 * var(--gp));
  border: var(--gp) solid transparent;
  color: var(--text);
  background: transparent;
  font: inherit;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  text-align: start;
  clip-path: var(--pixel-notch);
  cursor: var(--cursor-action);
}

.refine-gear:hover {
  border-color: var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-slate);
}

.refine-gear:focus-visible {
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent) !important;
}

.refine-gear.is-picked {
  border-color: var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
}

.refine-gear[disabled] {
  opacity: 0.5;
  cursor: var(--cursor-default);
}

.refine-gear-name {
  overflow: hidden;
  font-weight: var(--type-weight-medium);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.refine-bench {
  display: flex;
  flex-direction: column;
  gap: calc(6 * var(--gp));
  min-height: 0;
  padding: calc(6 * var(--gp)) calc(7 * var(--gp));
  overflow-y: auto;
}

.refine-bench.is-empty {
  align-items: center;
  justify-content: center;
}

.refine-empty {
  margin: 0;
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-style: italic;
  text-align: center;
}

.refine-empty--inline {
  text-align: start;
}

.refine-primer {
  max-width: calc(180 * var(--gp));
  padding-block: 0;
  text-align: center;
}

.refine-hero {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(6 * var(--gp));
}

.refine-hero-art {
  position: relative;
}

.refine-hero-name {
  overflow: hidden;
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  font-weight: var(--type-weight-strong);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.refine-hero-sub {
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.refine-hero-step {
  display: inline-flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  padding: calc(3 * var(--gp)) calc(6 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--refine-well-face);
  box-shadow: var(--refine-well-light);
  clip-path: var(--pixel-notch);
  font-variant-numeric: tabular-nums;
}

.refine-step-from {
  color: var(--muted);
  font-size: var(--type-section-heading-size);
  font-family: var(--type-section-heading-family);
  -webkit-font-smoothing: var(--type-section-heading-smoothing);
  font-weight: var(--type-weight-strong);
}

.refine-step-to {
  color: var(--accent);
  font-size: var(--type-callout-size);
  font-family: var(--type-callout-family);
  -webkit-font-smoothing: var(--type-callout-smoothing);
  font-weight: var(--type-weight-label);
}

.refine-step-done {
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

/* One arrow shape, drawn so it keeps its weight at every UI scale and needs no glyph coverage. */

.refine-step-arrow,
.refine-gain-arrow {
  width: calc(7 * var(--gp));
  height: var(--gp);
  position: relative;
  background: var(--muted);
}

.refine-step-arrow::after,
.refine-gain-arrow::after {
  content: '';
  position: absolute;
  inset-inline-end: 0;
  top: 0;
  width: var(--gp);
  height: var(--gp);
  background: var(--muted);
  box-shadow:
    calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--muted),
    calc(-1 * var(--gp)) var(--gp) 0 var(--muted),
    calc(-2 * var(--gp)) calc(-2 * var(--gp)) 0 var(--muted),
    calc(-2 * var(--gp)) calc(2 * var(--gp)) 0 var(--muted);
}

.refine-verdict {
  position: absolute;
  inset-inline-start: 50%;
  top: 50%;
  z-index: 2;
  padding: var(--gp) calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  color: #10161a;
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-label);
  white-space: nowrap;
  pointer-events: none;
  animation: refine-verdict-rise 900ms ease-out forwards;
}

.refine-verdict[data-kind='success'] {
  background: var(--good, #6fd06a);
}

.refine-verdict[data-kind='held'] {
  background: var(--accent);
}

.refine-verdict[data-kind='drop'] {
  background: var(--danger);
  color: #fff;
}

.refine-verdict[data-kind='miss'] {
  background: var(--muted);
}

@keyframes refine-verdict-rise {
  0% {
    opacity: 0;
    transform: translate(-50%, -30%);
  }
  18% {
    opacity: 1;
    transform: translate(-50%, -110%);
  }
  75% {
    opacity: 1;
    transform: translate(-50%, -125%);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -155%);
  }
}

body.reduce-flashing .refine-verdict,
body.reduce-motion .refine-verdict {
  animation: none;
  opacity: 1;
  transform: translate(-50%, -120%);
}

@media (prefers-reduced-motion: reduce) {
  .refine-verdict {
    animation: none;
    opacity: 1;
    transform: translate(-50%, -120%);
  }
}

.refine-block {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
}

/* A rung that cannot miss is a square block and one that can is a narrower notch, so the guaranteed band survives greyscale. */

.refine-ladder {
  display: flex;
  align-items: flex-end;
  gap: calc(2 * var(--gp));
  margin: 0;
  padding: 0 0 calc(7 * var(--gp));
  list-style: none;
}

.refine-pip {
  position: relative;
  display: flex;
  flex: 1;
  align-items: flex-end;
  justify-content: center;
  min-width: calc(3 * var(--gp));
}

.refine-pip-mark {
  width: 100%;
  height: calc(8 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--refine-well-face);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
}

.refine-pip.is-risky .refine-pip-mark {
  height: calc(5 * var(--gp));
}

.refine-pip.is-reached .refine-pip-mark {
  background: var(--pixel-ochre);
  box-shadow: inset 0 var(--gp) 0 var(--pixel-honey);
}

.refine-pip.is-cap::after {
  content: '';
  position: absolute;
  inset-block: calc(-2 * var(--gp)) calc(-2 * var(--gp));
  inset-inline-end: calc(-2 * var(--gp));
  width: var(--gp);
  background: var(--accent);
}

.refine-pip.is-next .refine-pip-mark {
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-cream);
}

.refine-pip-here {
  position: absolute;
  top: 100%;
  margin-block-start: var(--gp);
  color: var(--text);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
}

/* Only the row height and band fills are local; the percent is printed inside so no band relies on hue. */

.refine-odds {
  --gauge-h: calc(9 * var(--gp));
}

.refine-odds-fill[data-band='sure'] {
  background: var(--good, #6fd06a);
}

.refine-odds-fill[data-band='likely'] {
  background: #c9c05e;
}

.refine-odds-fill[data-band='even'] {
  background: var(--accent);
}

.refine-odds-fill[data-band='long'] {
  background: #c2543c;
}

body.high-contrast .refine-odds {
  --gauge-ring-w: 2px;
}

.refine-miss {
  display: flex;
  gap: calc(4 * var(--gp));
  margin: 0;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.refine-miss-label {
  flex: 0 0 auto;
  color: var(--muted);
  font-weight: var(--type-weight-strong);
}

.refine-miss[data-kind='drop'] .refine-miss-copy {
  color: var(--danger);
  font-weight: var(--type-weight-medium);
}

.refine-miss[data-kind='protected'] .refine-miss-copy {
  color: var(--accent);
  font-weight: var(--type-weight-medium);
}

.refine-miss[data-kind='guaranteed'] .refine-miss-copy {
  color: var(--good, #6fd06a);
  font-weight: var(--type-weight-medium);
}

.refine-gain {
  margin: 0;
  padding: 0;
  list-style: none;
}

.refine-gain-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto auto calc(27 * var(--gp));
  align-items: center;
  gap: calc(4 * var(--gp));
  padding: calc(2 * var(--gp)) 0;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-variant-numeric: tabular-nums;
}

.refine-gain-label {
  overflow: hidden;
  color: var(--muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.refine-gain-before {
  color: var(--muted);
}

.refine-gain-after {
  color: var(--text);
  font-weight: var(--type-weight-strong);
}

.refine-gain-delta {
  color: var(--good, #6fd06a);
  font-weight: var(--type-weight-strong);
  text-align: end;
}

.refine-costs {
  margin: 0;
  padding: 0;
  list-style: none;
}

.refine-cost {
  display: grid;
  grid-template-columns: calc(11 * var(--gp)) minmax(0, 1fr) auto calc(39 * var(--gp));
  align-items: center;
  gap: calc(4 * var(--gp));
  padding: calc(2 * var(--gp)) 0;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-variant-numeric: tabular-nums;
}

.refine-cost-icon {
  width: calc(11 * var(--gp));
  height: calc(11 * var(--gp));
  object-fit: contain;
}

.refine-cost-coin {
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  margin-inline: calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-honey);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-ochre);
  clip-path: var(--pixel-notch);
}

.refine-cost-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.refine-cost-need {
  color: var(--text);
  font-weight: var(--type-weight-strong);
}

.refine-cost-have {
  color: var(--muted);
  text-align: end;
}

.refine-cost.is-short .refine-cost-need,
.refine-cost.is-short .refine-cost-have {
  color: var(--danger);
  font-weight: var(--type-weight-strong);
}

.refine-protect {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(5 * var(--gp));
  margin-block-start: calc(3 * var(--gp));
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--refine-well-face);
  box-shadow: var(--refine-well-light);
  clip-path: var(--pixel-notch);
}

.refine-protect.is-on {
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
}

.refine-switch {
  display: inline-flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  padding: 0;
  border: 0;
  color: var(--text);
  background: transparent;
  font: inherit;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
  cursor: var(--cursor-action);
}

.refine-switch[disabled] {
  opacity: 0.5;
  cursor: var(--cursor-default);
}

.refine-switch:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}

.refine-switch:focus-visible .refine-switch-track {
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent);
}

.refine-switch-track {
  position: relative;
  box-sizing: border-box;
  width: calc(17 * var(--gp));
  height: calc(9 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.refine-switch-knob {
  position: absolute;
  inset-block-start: var(--gp);
  inset-inline-start: var(--gp);
  width: calc(5 * var(--gp));
  height: calc(5 * var(--gp));
  background: var(--pixel-slate);
  box-shadow: inset var(--gp) var(--gp) 0 var(--pixel-lilac);
}

.refine-switch[aria-checked='true'] .refine-switch-track {
  background: color-mix(in srgb, var(--accent) 35%, var(--pixel-ink));
}

.refine-switch[aria-checked='true'] .refine-switch-knob {
  background: var(--pixel-ochre);
  box-shadow: inset var(--gp) var(--gp) 0 var(--pixel-honey);
  translate: calc(8 * var(--gp)) 0;
}

.refine-protect-copy {
  margin: 0;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.refine-visit {
  margin: 0;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-variant-numeric: tabular-nums;
}

.refine-visit-label {
  margin-inline-end: calc(3 * var(--gp));
  font-weight: var(--type-weight-strong);
}

.refine-foot {
  flex: 0 0 auto;
  padding: calc(5 * var(--gp)) calc(7 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-dusk);
  background: var(--refine-well-face);
}

.refine-counter {
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  gap: calc(5 * var(--gp));
  min-height: 0;
  padding: calc(7 * var(--gp)) calc(7 * var(--gp));
  overflow-y: auto;
}

.refine-counter-intro {
  margin: 0;
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

/* Offers take the room the frame leaves, so held items sit at the foot like the commit button on the anvil. */

.refine-trades {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  margin: 0;
  padding: 0;
  list-style: none;
}

.refine-trade {
  display: grid;
  grid-template-columns: calc(17 * var(--gp)) minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: calc(5 * var(--gp));
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--refine-well-face);
  box-shadow: var(--refine-well-light);
  clip-path: var(--pixel-notch);
}

.refine-trade.is-empty {
  opacity: 0.55;
}

.refine-trade-icon {
  width: calc(16 * var(--gp));
  height: calc(16 * var(--gp));
  object-fit: contain;
}

.refine-trade-copy {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.refine-trade-name {
  overflow: hidden;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-medium);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.refine-trade-yield {
  color: var(--accent);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
}

.refine-trade-stock {
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-variant-numeric: tabular-nums;
}

.refine-holding {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  margin: 0;
  padding-block-start: calc(3 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-dusk);
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-medium);
}

/* The whole-stock trade stands over the face that raised it; the counter's rows go quiet while it is up. */

.refine-confirm {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: safe center;
  justify-content: center;
  padding: calc(7 * var(--gp));
  overflow-y: auto;
  background: color-mix(in srgb, var(--pixel-ink) 72%, transparent);
  animation: refine-confirm-in 120ms ease-out;
}

.refine-confirm-card {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--gp));
  flex: 0 0 auto;
  width: min(calc(180 * var(--gp)), 100%);
  padding: calc(7 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow:
    inset 0 0 0 var(--gp) var(--danger),
    inset calc(-2 * var(--gp)) calc(-2 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.refine-confirm-card h3 {
  margin: 0;
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
}

.refine-confirm-deal {
  margin: 0;
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-medium);
}

.refine-confirm-warn {
  margin: 0;
  color: var(--danger);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-medium);
}

.refine-confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: calc(4 * var(--gp));
  padding-block-start: calc(2 * var(--gp));
}

@keyframes refine-confirm-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .refine-confirm {
    animation: none;
  }
}

/* Narrow frames stack the rack above the bench; the rack keeps one strip. */

@media (max-width: 760px) {
  .refine-anvil {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
  }
  .refine-anvil.is-bare {
    grid-template-rows: minmax(0, 1fr);
  }
  .refine-rack {
    border-inline-end: 0;
    border-block-end: var(--gp) solid var(--pixel-dusk);
  }
  .refine-rack-grid {
    flex-direction: row;
    overflow-x: auto;
    overflow-y: hidden;
  }
  .refine-gear {
    flex: 0 0 auto;
    grid-template-columns: auto;
  }
  .refine-gear-name {
    display: none;
  }
}

/* The Faction Armory: four faces on one counter (what a spare piece is worth, what's opened,
   what it can seal, and the bench where a seal goes into a slot — armory-bench.css). Composes
   the shared modal frame, header, face row, purse/status line, gauge and button kit; the only
   local paint is the row grammar those faces share. Colour never carries a state alone: a
   locked row shows its lock and progress, a short price prints the number it cannot pay, and
   every closed track prints its own count. */

/* Four faces of very different lengths: the frame is stated (`is-stable` on
   the panel) rather than followed, so changing face changes the reading and not
   the window. */

.armory-panel {
  --win-frame-w: 720;
  --win-frame-h: 680;
  --win-frame-fill-h: 78dvh;
  --armory-well-face: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  --armory-well-light: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

/* The room the stated frame holds open comes from `win-frame-body`; this owns
   only how the face inside it is laid out. */

.armory-body {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* One face fills the body and scrolls its own list; the head above it stays. */

.armory-face {
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  gap: calc(5 * var(--gp));
  min-height: 0;
  padding: calc(6 * var(--gp)) calc(7 * var(--gp));
  overflow-y: auto;
}

.armory-filters {
  display: flex;
  flex-wrap: wrap;
  flex: 0 0 auto;
  align-items: center;
  gap: calc(4 * var(--gp));
}

.armory-type-filter {
  flex: 0 0 auto;
  min-width: calc(75 * var(--gp));
}

.armory-unlocked-filter {
  flex: 0 0 auto;
}

.armory-search {
  flex: 1 1 calc(90 * var(--gp));
  min-width: 0;
}

/* The one thing every row of a face has in common, said once above them
   instead of repeated in each row. */

.armory-note {
  flex: 0 0 auto;
  margin: 0;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: 1.4;
}

/* The face scrolls, so the list never shrinks to fit a short glass: a list
   that shrank would paint its rows under whatever follows it. */

.armory-rows {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  gap: 0;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: var(--gp) solid var(--pixel-ink);
  background: var(--armory-well-face);
  box-shadow: var(--armory-well-light);
  clip-path: var(--pixel-notch);
  list-style: none;
}

.armory-row {
  display: grid;
  grid-template-columns:
    minmax(calc(75 * var(--gp)), 1fr)
    calc(61 * var(--gp))
    calc(39 * var(--gp))
    calc(44 * var(--gp));
  align-items: center;
  gap: calc(4 * var(--gp));
  min-height: calc(17 * var(--gp));
  padding: calc(2 * var(--gp)) calc(3 * var(--gp));
  border: 0;
  border-block-end: var(--gp) solid var(--pixel-dusk);
  background: transparent;
}

.armory-row:last-child {
  border-block-end: 0;
}

.armory-row:hover {
  background: var(--pixel-night);
}

/* A locked row is quieter, not unreadable: its own track is the reason. */

.armory-row.is-locked {
  background: color-mix(in srgb, var(--pixel-ink) 40%, transparent);
}

/* Every face uses the same four tracks. Empty progress cells stay empty;
   item, amount and action never slide sideways when a row changes state. */

.armory-row--donate.is-marked {
  background: color-mix(in srgb, var(--accent) 9%, transparent);
  box-shadow: inset var(--gp) 0 0 var(--accent);
}

/* The piece a row is about: art beside the name. Art and name are one handle;
   hover, focus or tap opens the bag's item card. */

.armory-row-item {
  display: grid;
  grid-column: 1;
  grid-template-columns: calc(14 * var(--gp)) minmax(0, 1fr);
  align-items: center;
  column-gap: calc(4 * var(--gp));
  row-gap: var(--gp);
  min-width: 0;
}

.armory-item-handle {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: calc(14 * var(--gp)) minmax(0, 1fr);
  align-items: center;
  column-gap: calc(4 * var(--gp));
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: var(--cursor-help, help);
}

.armory-item-handle:focus-visible {
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent) !important;
}

.armory-row-item > .armory-row-sub {
  grid-column: 2;
}

.armory-row-icon {
  width: calc(14 * var(--gp));
  height: calc(14 * var(--gp));
  object-fit: contain;
  display: block;
}

.armory-row-name {
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-body-compact-readable-size);
  font-family: var(--type-body-compact-readable-family);
  -webkit-font-smoothing: var(--type-body-compact-readable-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-ligatures: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.armory-row-sub {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: 1.35;
}

.armory-ench {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: calc(14 * var(--gp));
  height: calc(14 * var(--gp));
}

.armory-ench-base {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* The badge sits in the corner the tooltip layer never covers, over a dark
   plate so a gold badge reads over a gold stat emblem. */

.armory-ench-badge {
  position: absolute;
  right: calc(-2 * var(--gp));
  bottom: calc(-2 * var(--gp));
  width: 52%;
  height: 52%;
  padding: 6%;
  background: var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
  object-fit: contain;
}

.armory-track-cell {
  display: grid;
  grid-column: 2;
  gap: calc(2 * var(--gp));
  width: 100%;
}

.armory-track {
  --gauge-h: max(9px, calc(5 * var(--gp)));
  width: 100%;
}

.armory-track-fill {
  background: var(--accent);
}

.armory-track-count {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  text-align: center;
}

/* The price itself is the shared sw-price panel; only the buy press is local. */

.armory-row > .sw-price {
  grid-column: 3;
  justify-self: end;
}

.armory-buy {
  grid-column: 4;
  width: 100%;
}

/* A closed row's lock stands where the press will. Progress belongs to the
   dedicated track beside it; the action column only answers whether it opens. */

.armory-lock {
  display: grid;
  grid-column: 4;
  justify-items: center;
  gap: var(--gp);
  width: 100%;
}

.armory-lock-ring {
  position: relative;
  display: grid;
  place-items: center;
  width: calc(14 * var(--gp));
  height: calc(14 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.armory-lock-ico {
  position: relative;
  width: 62%;
  height: 62%;
  object-fit: contain;
  display: block;
}

.armory-donate {
  grid-column: 4;
  width: 100%;
  white-space: nowrap;
}

/* What the bag holds that the face is not offering. */

.armory-worn {
  flex: 0 0 auto;
  margin: 0;
  padding: calc(3 * var(--gp)) calc(5 * var(--gp));
  border-inline-start: var(--gp) solid var(--warn);
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.4;
}

.armory-how,
.armory-primer {
  flex: 0 0 auto;
  display: grid;
  gap: calc(3 * var(--gp));
  padding: calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--armory-well-face);
  box-shadow: var(--armory-well-light);
  clip-path: var(--pixel-notch);
}

.armory-how {
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
}

.armory-primer {
  box-shadow:
    inset 0 var(--gp) 0 var(--accent),
    var(--armory-well-light);
}

.armory-primer-kicker {
  color: var(--gold-label);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-emphasis);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.armory-primer h2 {
  margin: 0;
  color: var(--text);
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
}

.armory-primer p {
  margin: 0;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.4;
}

/* Three beats, each drawn: the art the window already uses for that beat with
   its step number on the plate, a title, and one line. */

.armory-beats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.armory-beat {
  display: grid;
  grid-template-columns: calc(15 * var(--gp)) minmax(0, 1fr);
  align-items: center;
  gap: calc(4 * var(--gp));
  min-width: 0;
  padding-inline: calc(4 * var(--gp));
  border-inline-end: var(--gp) solid var(--pixel-dusk);
}

.armory-beat:first-child {
  padding-inline-start: 0;
}

.armory-beat:last-child {
  padding-inline-end: 0;
  border-inline-end: 0;
}

.armory-beat-art {
  position: relative;
  display: grid;
  place-items: center;
  width: calc(15 * var(--gp));
  height: calc(15 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}

.armory-beat-art img {
  width: 78%;
  height: 78%;
  object-fit: contain;
  display: block;
}

.armory-beat-n {
  position: absolute;
  top: calc(-3 * var(--gp));
  left: calc(-3 * var(--gp));
  display: grid;
  place-items: center;
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  border: var(--gp) solid color-mix(in srgb, var(--accent) 65%, var(--pixel-ink));
  background: var(--pixel-ink);
  color: var(--gold-label);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
}

.armory-beat-title {
  min-width: 0;
  color: var(--text);
  font-size: var(--type-label-readable-size);
  font-family: var(--type-label-readable-family);
  -webkit-font-smoothing: var(--type-label-readable-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: 1.2;
}

/* Compact desktop ledgers still meet the coarse-pointer floor on handheld
   glass. Padding is folded into the 44px row instead of making it taller. */

[data-ui-profile='handheld'] .armory-row {
  min-height: var(--hud-touch-min);
  padding-block: 0;
}

[data-ui-profile='handheld'] .armory-item-handle,
[data-ui-profile='handheld'] .armory-buy,
[data-ui-profile='handheld'] .armory-donate,
[data-ui-profile='handheld'] .armory-unlocked-filter {
  min-height: var(--hud-touch-min);
}

/* ===== The Faction Armory: the enchant bench ===============================
   Three choices in order, then one press. The pieces, then the slots of the
   chosen piece, then the seals each run as one wrapped row of chips; the
   press that spends the seal sits at the foot and names the deal once it can
   be made. Row and icon grammar come from armory-window.css. */

.armory-bench {
  gap: 0;
  overflow: hidden;
}

/* The choices scroll as one column while the committing action remains in the
   frame. A ready bench never makes the player hunt below the fold to finish. */

.armory-bench-scroll {
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  gap: calc(5 * var(--gp));
  min-height: 0;
  padding-inline-end: calc(2 * var(--gp));
  padding-block-end: calc(4 * var(--gp));
  overflow-y: auto;
  overscroll-behavior: contain;
}

.armory-bench-scroll > .armory-step {
  flex: 0 0 auto;
}

.armory-step {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  min-height: 0;
}

.armory-step h3 {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  margin: 0;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.armory-step.is-done h3 {
  color: var(--text);
}

.armory-step.is-done .armory-step-n {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, var(--pixel-ink));
}

/* What a step says when it has nothing to offer yet: one quiet line, not the
   face-sized empty state. */

.armory-step-hint {
  margin: 0;
  padding: var(--gp) 0;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-style: italic;
}

.armory-step-n {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--pixel-ink);
  color: var(--accent);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0;
}

/* One choice per chip, wrapped into a row so a bag of five pieces reads as
   five things to pick between, not a list to scroll. */

.armory-picks {
  display: flex;
  flex-wrap: wrap;
  gap: calc(2 * var(--gp));
  max-height: calc(66 * var(--gp));
  overflow-y: auto;
}

.armory-seal-choice {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(4 * var(--gp));
  flex: 0 1 auto;
  min-width: calc(75 * var(--gp));
  max-width: calc(120 * var(--gp));
  padding: calc(2 * var(--gp)) calc(4 * var(--gp)) calc(2 * var(--gp)) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  color: var(--text);
  background: var(--armory-well-face);
  box-shadow: var(--armory-well-light);
  font: inherit;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  text-align: start;
  clip-path: var(--pixel-notch);
  cursor: var(--cursor-action);
}

.armory-seal-choice:hover:not(.is-refused) {
  background: var(--pixel-night);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-slate);
}

.armory-pick {
  position: absolute;
  inset: 0;
  width: 100%;
  border: 0;
  background: transparent;
  cursor: var(--cursor-action);
}

.armory-seal-choice > :not(.armory-pick) {
  position: relative;
  pointer-events: none;
}

.armory-pick-name--ref {
  pointer-events: auto;
}

.armory-pick:focus-visible {
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent) !important;
}

.armory-seal-choice.is-picked {
  background: var(--pixel-night);
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
}

/* Keep the effect readable while marking incompatible seals unavailable. */

.armory-pick:disabled {
  cursor: var(--cursor-default);
}

.armory-seal-choice.is-refused .armory-pick-icon {
  opacity: 0.45;
}

.armory-pick-icon,
.armory-ench.armory-pick-icon {
  width: calc(13 * var(--gp));
  height: calc(13 * var(--gp));
  object-fit: contain;
  display: block;
}

.armory-pick-copy {
  display: grid;
  gap: var(--gp);
  min-width: 0;
}

.armory-pick-name {
  overflow: hidden;
  font-weight: var(--type-weight-medium);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.armory-pick-sub {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

/* How many of the same seal the bag holds: one chip, one count. */

.armory-pick-count {
  padding: 0 calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
}

/* The pieces are the bag's own cells (inventory.css), so a full bag reads as
   the bag does: a grid two rows tall that scrolls, a search above it once the
   bag is long. The padding keeps the picked cell's outline inside the scroll. */

.armory-gear-search {
  flex: 0 0 auto;
}

.armory-gear-grid {
  flex: 0 0 auto;
  max-height: calc(49 * var(--gp));
  padding: var(--gp);
  overflow-y: auto;
}

.armory-slots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(calc(85 * var(--gp)), 1fr));
  gap: calc(3 * var(--gp));
}

.armory-slot {
  display: grid;
  gap: calc(2 * var(--gp));
  min-width: 0;
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  color: var(--text);
  background: var(--armory-well-face);
  box-shadow: var(--armory-well-light);
  font: inherit;
  text-align: start;
  clip-path: var(--pixel-notch);
  cursor: var(--cursor-action);
}

.armory-slot:hover {
  background: var(--pixel-night);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-slate);
}

.armory-slot:focus-visible {
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent) !important;
}

.armory-slot.is-picked {
  background: var(--pixel-night);
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
}

/* An open slot is an empty ink well: there is room here. */

.armory-slot:not(.is-held) {
  background: var(--pixel-ink);
  box-shadow: none;
}

.armory-slot-name {
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.armory-slot-holds {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: calc(3 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-medium);
}

.armory-slot:not(.is-held) .armory-slot-holds {
  grid-template-columns: minmax(0, 1fr);
  color: var(--muted);
}

.armory-slot-ico,
.armory-ench.armory-slot-ico {
  width: calc(11 * var(--gp));
  height: calc(11 * var(--gp));
  object-fit: contain;
}

.armory-slot-note {
  min-height: 1em;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

.armory-slot-note.is-warn {
  color: var(--warn);
  font-weight: var(--type-weight-strong);
}

/* The press that spends the seal sits at the foot of the bench rather than
   floating in the middle of it, however short the three choices run. */

.armory-bench-foot {
  flex: 0 0 auto;
  padding-block-start: calc(4 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-dusk);
}

[data-ui-profile='handheld'] .armory-seal-choice,
[data-ui-profile='handheld'] .armory-slot,
[data-ui-profile='handheld'] .armory-bench-foot .ron-btn {
  min-height: var(--hud-touch-min);
}

/* The informant window. The frame, the header, the purse and the status line
   come from the shared service-window chrome; everything here is the card grid
   and the one picker the map watch needs. A card's state is a word first — the
   tint only agrees with it. Each card is a shallow pixel well (pixel-chrome.css)
   with its state as one HUD pixel down the start edge. */

.informant-panel {
  --win-frame-w: 660;
  /* No height of its own: the card grid runs as long as the war does, and the
     window keeps a deeper margin above and below than the counters do. */
  --win-frame-inset-y: 96px;
}

.informant-head {
  --sw-head-accent: #b98ad8;
}

.informant-lede {
  margin: 0;
  padding: calc(4 * var(--gp)) calc(6 * var(--gp)) 0;
  color: var(--muted);
  font-size: var(--type-body-compact-readable-size);
  font-family: var(--type-body-compact-readable-family);
  -webkit-font-smoothing: var(--type-body-compact-readable-smoothing);
  line-height: 1.4;
}

.informant-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(calc(130 * var(--gp)), 1fr));
  /* Rows follow their cards: a squeezed list scrolls instead of shrinking a card
     under its own words. */
  grid-auto-rows: max-content;
  gap: calc(4 * var(--gp));
  overflow-y: auto;
  padding: calc(5 * var(--gp)) calc(6 * var(--gp));
}

.informant-empty {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.informant-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-content: center;
  gap: calc(2 * var(--gp)) calc(5 * var(--gp));
  min-height: calc(34 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  padding: calc(4 * var(--gp));
  background: var(--informant-face, color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night)));
  box-shadow:
    inset var(--gp) 0 0 var(--informant-edge, var(--pixel-slate)),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

/* Live is the state the whole Crown is spending on right now, so it is the only
   one that carries the informant's colour. */

.informant-card.is-live {
  --informant-edge: #b98ad8;
  --informant-face: color-mix(in srgb, #b98ad8 14%, var(--pixel-ink));
}

.informant-card.is-cooldown {
  --informant-edge: var(--pixel-dusk);
}

.informant-name {
  margin: 0;
  color: var(--gold-ink, #f7e3a5);
  font-size: var(--type-body-compact-readable-size);
  font-family: var(--type-body-compact-readable-family);
  -webkit-font-smoothing: var(--type-body-compact-readable-smoothing);
  font-weight: var(--type-weight-label);
  line-height: 1.2;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.informant-reveals {
  margin: 0;
  color: #cbd2dc;
  font-size: max(12px, var(--type-body-compact-readable-size));
  font-family: var(--type-body-compact-readable-family);
  -webkit-font-smoothing: var(--type-body-compact-readable-smoothing);
  line-height: 1.35;
}

.informant-map {
  grid-column: 1;
  justify-self: stretch;
}

.informant-foot {
  grid-column: 2;
  grid-row: 1 / span 3;
  display: grid;
  align-content: center;
  justify-items: end;
  gap: calc(2 * var(--gp));
}

.informant-state {
  min-width: 0;
  color: var(--muted);
  font-size: var(--type-metadata-readable-size);
  font-family: var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
  font-variant-numeric: tabular-nums;
  font-weight: var(--type-weight-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.informant-state.is-live {
  color: #c9a6e8;
}

.informant-state.is-cooldown {
  color: #8fb8d8;
}

.informant-buy {
  min-width: calc(32 * var(--gp));
}

.informant-status {
  margin-block-start: auto;
}

body.high-contrast .informant-card {
  --informant-face: var(--pixel-ink);
}

[data-ui-profile='handheld'] .informant-panel {
  --win-frame-w: 700;
  --win-frame-fill-w: calc(100dvw - var(--hud-safe-left) - var(--hud-safe-right));
  /* The deep margin above and below is a desktop reading: on a glass the safe
     box is the margin, and asking for both leaves a phone with a stub. */
  --win-frame-inset-y: 0px;
}

[data-ui-profile='handheld'] .informant-cards {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(3 * var(--gp));
}

[data-ui-profile='handheld'] .informant-buy {
  min-width: var(--hud-touch-min);
  min-height: var(--hud-touch-min);
  padding-inline: calc(5 * var(--gp));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

/* Player-to-player trade. Two facing offer plates, the ritual rail between the
   deal and the bag strip, and one detail card that reads whatever the pointer
   rests on. The frame itself comes from the shared service-window family. */

.trade-panel {
  --win-frame-w: 560;
  --win-frame-h: 700;
  /* Each plate is a shallow pixel well (pixel-chrome.css): the ink outline, a
     face a step under the window's, lit along its lower right. */
  --trade-well-face: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  --trade-well-light: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

.trade-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: calc(4 * var(--gp));
}

/* The partner is who this window is about, so the name carries the accent while
   the window keeps its own one-word title. */

.trade-partner {
  min-width: 0;
  overflow: hidden;
  color: color-mix(in srgb, var(--accent) 70%, var(--text));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.trade-body {
  display: flex;
  flex-direction: column;
  gap: calc(5 * var(--gp));
  min-height: 0;
  overflow-y: auto;
  padding: calc(6 * var(--gp)) calc(7 * var(--gp)) calc(7 * var(--gp));
}

.trade-deal {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(5 * var(--gp));
  min-width: 0;
}

.trade-plate {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  min-width: 0;
  padding: calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--trade-well-face);
  box-shadow: var(--trade-well-light);
  clip-path: var(--pixel-notch);
}

/* A plate that has stopped moving says so on its own edge: locked takes the
   accent, confirmed the success tone. Neither is hue alone — the state word sits
   in the plate's own header. */

.trade-plate[data-state='locked'] {
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
}

.trade-plate[data-state='confirmed'] {
  box-shadow: inset 0 0 0 var(--gp) var(--good);
}

.trade-plate-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(3 * var(--gp));
  min-width: 0;
}

.trade-plate-title {
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.trade-plate-state {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.trade-plate[data-state='locked'] .trade-plate-state {
  color: var(--accent);
}

.trade-plate[data-state='confirmed'] .trade-plate-state {
  color: var(--good);
}

.trade-plate-body {
  display: flex;
  align-items: center;
  padding: calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
}

/* A fixed lattice, not a list that grows a box: both plates hold the same shape
   whatever is in them, so a partner adding an item never reflows the deal. */

.trade-list {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  align-content: start;
  justify-items: center;
  gap: calc(2 * var(--gp));
  width: 100%;
}

/* Square, and capped: a plate given a whole narrow screen must not blow its
   cells up to the size of the art they hold. */

.trade-list .item-slot {
  --slot-size: min(100%, calc(28 * var(--gp)));
  width: min(100%, calc(28 * var(--gp)));
  aspect-ratio: 1;
  height: auto;
}

.trade-list .item-slot.filled {
  animation: trade-cell-in 160ms ease-out;
}

.trade-list .item-slot.empty {
  background: var(--trade-well-face);
  border-color: var(--pixel-dusk);
  box-shadow: none;
}

.trade-list .item-slot.empty::before {
  background: none;
}

.trade-plate-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(3 * var(--gp));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
}

.trade-plate-count {
  color: var(--muted);
}

.trade-plate-gold {
  color: var(--accent);
  font-weight: var(--type-weight-strong);
}

.trade-detail {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: calc(5 * var(--gp));
  min-height: calc(23 * var(--gp));
  padding: calc(3 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--trade-well-face);
  box-shadow: var(--trade-well-light);
  clip-path: var(--pixel-notch);
}

.trade-detail.is-empty {
  grid-template-columns: minmax(0, 1fr);
}

.trade-detail .item-slot {
  --slot-size: calc(19 * var(--gp));
}

.trade-detail-copy {
  display: grid;
  gap: var(--gp);
  min-width: 0;
}

.trade-detail-name {
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-medium);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.trade-detail-facts {
  display: grid;
  gap: var(--gp);
  min-width: 0;
}

.trade-detail-tier {
  margin-inline-start: calc(4 * var(--gp));
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.trade-detail-hint {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

/* Four columns: who, then one per step. Both rows are read at a glance, which
   is the whole question a trade asks — who has moved and who has not. */

.trade-steps {
  display: grid;
  grid-template-columns: auto repeat(3, 1fr);
  align-items: center;
  gap: calc(2 * var(--gp)) calc(3 * var(--gp));
  padding: calc(4 * var(--gp)) calc(6 * var(--gp)) calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--trade-well-face);
  box-shadow: var(--trade-well-light);
  clip-path: var(--pixel-notch);
}

.trade-step-name {
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.09em;
  text-align: center;
  text-transform: uppercase;
}

.trade-step-name.is-current {
  color: var(--accent);
}

.trade-steps-who {
  max-width: calc(45 * var(--gp));
  padding-inline-end: calc(3 * var(--gp));
  overflow: hidden;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The track that turns three states into progress: each cell draws the rail
   behind its own node, and the end cells draw only their half of it. */

.trade-pip-cell {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(7 * var(--gp));
}

/* The rail runs through the pip's middle row of HUD pixels. */

.trade-pip-cell::before {
  content: '';
  position: absolute;
  top: calc(3 * var(--gp));
  left: 0;
  right: 0;
  height: var(--gp);
  background: var(--pixel-dusk);
}

.trade-pip-cell[data-pos='first']::before {
  left: 50%;
}

.trade-pip-cell[data-pos='last']::before {
  right: 50%;
}

.trade-pip {
  position: relative;
  box-sizing: border-box;
  width: calc(7 * var(--gp));
  height: calc(7 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
}

.trade-pip.is-reached {
  background: var(--pixel-ochre);
  box-shadow: inset var(--gp) var(--gp) 0 var(--pixel-honey);
}

.trade-stage {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  padding-top: calc(4 * var(--gp));
  border-top: var(--gp) solid var(--pixel-dusk);
}

.trade-stage-head {
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.trade-bag {
  display: flex;
  gap: calc(2 * var(--gp));
  overflow-x: auto;
  padding-bottom: calc(2 * var(--gp));
}

.trade-bag-cell {
  flex: 0 0 auto;
  padding: var(--gp);
  border: var(--gp) solid transparent;
  background: transparent;
  cursor: var(--cursor-action);
}

.trade-bag-cell .item-slot {
  --slot-size: calc(21 * var(--gp));
}

.trade-bag-cell.is-selected {
  border-color: var(--accent);
  background: var(--pixel-night);
}

.trade-bag-cell:focus-visible {
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent) !important;
}

.trade-bag-cell:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}

.trade-bag-empty {
  margin: 0;
  padding: calc(6 * var(--gp)) 0;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  text-align: center;
}

.trade-offer-picker {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  flex-wrap: wrap;
}

.trade-amount,
.trade-gold-entry {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--gp));
}

/* The gold lane sits opposite the item lane, with its own hairline between them
   so the two acts never read as one long row of controls. */

.trade-gold-entry {
  margin-inline-start: auto;
  padding-inline-start: calc(5 * var(--gp));
  border-inline-start: var(--gp) solid var(--pixel-dusk);
}

.trade-gold-mark {
  color: var(--accent);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-label);
}

.trade-offer-picker input {
  width: calc(37 * var(--gp));
  min-height: calc(14 * var(--gp));
  font-variant-numeric: tabular-nums;
}

.trade-amount input {
  width: calc(27 * var(--gp));
  text-align: center;
}

/* The picker's steppers and offer button are kit buttons at the row's own
   height; the surface only seats them. */

.trade-step-btn {
  min-width: calc(14 * var(--gp));
}

/* Weight carries the ladder: Confirm is the gold act, Lock the step before it,
   Cancel the quiet way out on the far side of the row. */

.trade-actions {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  padding-top: calc(5 * var(--gp));
  border-top: var(--gp) solid var(--pixel-dusk);
}

.trade-actions-gap {
  flex: 1 1 auto;
}

/* The commit row's three weights — Confirm gold, Lock the matte control,
   Cancel danger — are the kit's variants at this row's height. */

.trade-quit,
.trade-secondary,
.trade-primary {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

@keyframes trade-cell-in {
  from {
    opacity: 0;
    transform: scale(0.86);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .trade-list .item-slot.filled {
    animation: none;
  }
}

body.reduce-motion .trade-list .item-slot.filled {
  animation: none;
}

/* One column of plates once the window is narrower than two can hold, and the
   bag strip's controls stack rather than squeeze. */

@media (max-width: 560px) {
  .trade-deal {
    grid-template-columns: minmax(0, 1fr);
  }
  .trade-gold-entry {
    margin-inline-start: 0;
    padding-inline-start: 0;
    border-inline-start: 0;
  }
}

/* A talk is staged: the speaker's illustration stands at the plate's left, words land a character at a time, each answer wears its key. The plate is the pixel window's (hud-pixel-window.css). */

/* The talk stands bottom-centre, above the action bars and under the cast lane. The plate never shrinks below what an answer needs; long menus scroll. */

.npc-win {
  bottom: 90px;
  left: 50%;
  transform: translateX(-50%);
  width: calc(280 * var(--gp));
  max-width: 92vw;
  max-height: max(36vh, calc(120 * var(--gp)));
  flex-direction: row;
  align-items: stretch;
  pointer-events: auto;
}

/* An offer is a whole page, so its window may take more screen than a talk line; answers still scroll on a small viewport. */

.npc-win.npc-offer {
  max-height: max(62vh, calc(215 * var(--gp)));
}

.npc-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
}

.npc-win.hud-layout-ghost .npc-body,
.npc-win.hud-layout-ghost .npc-speaker {
  display: none;
}

/* The standee is taller than its column and rises out of the frame. Decorative; the name plate carries identity. */

.npc-speaker {
  position: relative;
  flex: 0 0 calc(70 * var(--gp));
  align-self: stretch;
  min-height: calc(62 * var(--gp));
}

/* The standee grows with the conversation: plate height for a greeting, full length for a long menu. */

.npc-speaker-art {
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  width: calc(102 * var(--gp));
  height: calc(100% + 44 * var(--gp));
  min-height: calc(98 * var(--gp));
  max-height: calc(170 * var(--gp));
  object-fit: contain;
  object-position: bottom center;
  pointer-events: none;
}

.npc-nameplate {
  display: flex;
  align-items: center;
}

.npc-name {
  font-weight: var(--type-weight-label);
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.npc-nameplate-rule {
  flex: 1 1 auto;
}

.npc-cutin {
  grid-template-columns: calc(26 * var(--gp)) minmax(0, 1fr);
  align-items: center;
  gap: calc(5 * var(--gp));
  margin: calc(-2 * var(--gp)) 0 calc(6 * var(--gp));
  padding: calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.npc-cutin-sigil {
  display: grid;
  place-items: center;
  width: calc(26 * var(--gp));
  height: calc(26 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-dusk),
    inset calc(-2 * var(--gp)) calc(-2 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
  color: var(--accent);
  font-weight: var(--type-weight-label);
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  letter-spacing: 0;
}

.npc-cutin-copy {
  min-width: 0;
}

.npc-cutin-name {
  color: var(--accent);
  font-weight: var(--type-weight-label);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  letter-spacing: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.npc-cutin-id {
  margin-top: var(--gp);
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  letter-spacing: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A boss tomb's body: the fallen boss's card as a spirit (drained, brightened, translucent) beside the facts of its fall; it floats inside the page. */

.npc-tomb-slot {
  margin: 0 0 calc(5 * var(--gp));
}

.npc-tomb {
  display: flex;
  align-items: center;
  gap: calc(7 * var(--gp));
}

.npc-tomb-spirit {
  flex: 0 0 auto;
  display: grid;
  place-items: end center;
  width: calc(42 * var(--gp));
}

.npc-tomb-spirit-img {
  width: calc(42 * var(--gp));
  height: calc(56 * var(--gp));
  filter: grayscale(1) brightness(1.6);
  opacity: 0.55;
}

.npc-tomb-copy {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
}

.npc-tomb-name {
  color: var(--accent);
  font-weight: var(--type-weight-label);
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  margin-bottom: calc(2 * var(--gp));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.npc-tomb-line {
  color: var(--text);
  opacity: 0.85;
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  line-height: round(1.45em, var(--gp));
  font-variant-numeric: tabular-nums;
}

.npc-tomb-returns {
  color: var(--accent);
  opacity: 1;
}

/* Every character is in the page from the first frame; only its landing animates, so skipping the reveal costs nothing. */

/* The words land in a pre-sized block so the window does not resize under the cursor; long speech scrolls inside it and only the answer list changes window height. */

.npc-text {
  /* Five lines where there is room, the first thing to give way when the plate is capped shorter. */
  flex: 0 1 auto;
  height: calc(var(--type-prose-size) * 1.55 * 5);
  min-height: calc(var(--type-prose-size) * 1.55 * 2);
  overflow-y: auto;
  overscroll-behavior: contain;
  white-space: pre-wrap;
  margin-bottom: calc(6 * var(--gp));
  font-size: var(--type-prose-size);
  font-family: var(--type-prose-family);
  -webkit-font-smoothing: var(--type-prose-smoothing);
  line-height: 1.55;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.npc-ch {
  animation: npc-ch-in 150ms ease-out backwards;
}

@keyframes npc-ch-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.npc-text-settled .npc-ch,
body.reduce-motion .npc-ch {
  animation: none;
}

/* A timed step is the shared gauge (hud-gauge.css); the script writes the fill colour inline. */

.npc-progress {
  width: 100%;
  margin: var(--gp) 0 calc(6 * var(--gp));
}

.npc-progress-text {
  margin-top: calc(3 * var(--gp));
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

body.reduce-motion .npc-progress-fill {
  transition: none !important;
}

.npc-controls {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  align-items: stretch;
  margin-top: auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Reserves the travel a held button sinks by; without it a held button raises this panel's scrollbar. */
  padding-bottom: var(--gp);
}

.npc-controls .ron-btn {
  align-self: flex-end;
}

.npc-menu-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(5 * var(--gp));
  width: 100%;
  padding: calc(3 * var(--gp)) calc(5 * var(--gp));
  text-align: left;
  background: var(--pixel-dusk);
  border: var(--gp) solid var(--pixel-ink);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
  color: var(--accent);
}

.npc-menu-portal-status {
  display: block;
  margin-top: calc(2 * var(--gp));
  color: var(--text);
  font-size: inherit;
  line-height: 1.4;
}

.npc-menu-item[aria-disabled='true'] {
  color: var(--muted);
  cursor: not-allowed;
}

.npc-menu-item:hover,
.npc-menu-item:focus-visible {
  background: color-mix(in srgb, var(--pixel-slate) 45%, var(--pixel-dusk));
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-lilac),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}

.npc-menu-item:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.npc-menu-key {
  display: grid;
  place-items: center;
  min-width: calc(11 * var(--gp));
  height: calc(11 * var(--gp));
  padding: 0 calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-slate);
  background: var(--pixel-ink);
  color: var(--accent);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-label);
  font-variant-numeric: tabular-nums;
}

.npc-menu-item:hover .npc-menu-key,
.npc-menu-item:focus-visible .npc-menu-key {
  background: color-mix(in srgb, var(--accent) 22%, var(--pixel-ink));
}

/* A handheld has no number row or Esc, so the entry answers to the thumb alone. */

[data-ui-profile='handheld'] .npc-menu-key {
  display: none;
}

.npc-menu-face {
  min-width: 0;
}

/* The mark the NPCs there wear, at the far edge of the row so destinations sort down one column. */

.npc-menu-quest-mark {
  width: calc(10 * var(--gp));
  height: calc(10 * var(--gp));
  object-fit: contain;
}

.npc-menu-cancel {
  color: var(--muted);
}

.npc-menu-cancel .npc-menu-key {
  color: var(--muted);
}

/* An option that hands something over shows the item's art, real name and the stats that decide the pick. */

.npc-menu-item-rich {
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
}

.npc-menu-item-rich .npc-menu-face {
  display: flex;
  align-items: center;
  gap: calc(5 * var(--gp));
}

.npc-item-art {
  display: flex;
  flex: 0 0 auto;
  gap: calc(2 * var(--gp));
}

.npc-item-icon {
  width: calc(20 * var(--gp));
  height: calc(20 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-dusk),
    inset calc(-2 * var(--gp)) calc(-2 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
  object-fit: contain;
}

.npc-item-body {
  display: flex;
  flex-direction: column;
  gap: var(--gp);
  min-width: 0;
}

.npc-item-label {
  color: var(--text);
}

.npc-item-name {
  color: var(--accent);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.npc-item-stats {
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-variant-numeric: tabular-nums;
}

.npc-item-label,
.npc-item-name,
.npc-item-stats {
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
}

/* A mandatory pick where every answer hands over an item (the Awakening weapon choice) takes the whole stage in the reward screen's grammar: question as headline, answers as a row of cards. */

.npc-win.npc-hand {
  position: fixed;
  inset: 0;
  z-index: 60;
  transform: none;
  width: auto;
  max-width: none;
  max-height: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: calc(9 * var(--gp));
  overflow-y: auto;
  overscroll-behavior: contain;
  animation: npc-hand-veil 0.28s ease both;
}

@keyframes npc-hand-veil {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

body.reduce-motion .npc-win.npc-hand {
  animation: none;
}

/* The standee is kept, centred above the question, so the pick stays Renn's conversation. */

.npc-hand .npc-speaker {
  flex: 0 0 calc(75 * var(--gp));
  align-self: center;
  width: calc(100 * var(--gp));
}

.npc-hand .npc-body {
  flex: 0 1 auto;
  width: min(100%, round(calc(880px * var(--ui-scale)), var(--gp)));
  align-items: center;
}

.npc-hand .npc-nameplate {
  justify-content: center;
  margin: 0 0 calc(4 * var(--gp));
}

.npc-hand .npc-nameplate-rule {
  display: none;
}

.npc-hand .npc-name {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  letter-spacing: 0.16em;
}

.npc-hand .npc-text {
  flex: 0 0 auto;
  height: auto;
  min-height: 0;
  overflow: visible;
  margin-bottom: calc(10 * var(--gp));
  color: #ffe9a8;
  font-size: var(--type-callout-size);
  font-family: var(--type-callout-family);
  -webkit-font-smoothing: var(--type-callout-smoothing);
  font-weight: var(--type-weight-label);
  line-height: round(up, 1.35em, calc(2 * var(--gp)));
  text-align: center;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.npc-controls.npc-menu-hand {
  display: grid;
  /* Whole cards, centred; a narrow viewport wraps without orphaning one. Columns step in whole HUD pixels and rows are even counts so centring lands on the grid. */
  grid-template-columns: repeat(
    auto-fit,
    minmax(
      round(calc(150px * var(--ui-scale)), var(--gp)),
      round(calc(196px * var(--ui-scale)), var(--gp))
    )
  );
  grid-auto-rows: 1fr;
  justify-content: center;
  width: 100%;
  gap: calc(6 * var(--gp));
  align-items: stretch;
  margin-top: 0;
  padding-bottom: calc(5 * var(--gp));
  overflow: visible;
}

.npc-menu-hand .npc-menu-item-rich {
  position: relative;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  justify-items: center;
  gap: calc(3 * var(--gp));
  padding: calc(7 * var(--gp)) calc(4 * var(--gp)) calc(5 * var(--gp));
  text-align: center;
  transition: transform 140ms steps(2, end);
  animation: npc-card-deal 0.38s steps(5, end) both;
}

.npc-menu-hand .npc-menu-item-rich:nth-child(1) {
  animation-delay: 0.04s;
}

.npc-menu-hand .npc-menu-item-rich:nth-child(2) {
  animation-delay: 0.1s;
}

.npc-menu-hand .npc-menu-item-rich:nth-child(3) {
  animation-delay: 0.16s;
}

.npc-menu-hand .npc-menu-item-rich:nth-child(4) {
  animation-delay: 0.22s;
}

@keyframes npc-card-deal {
  from {
    opacity: 0;
    transform: translateY(calc(5 * var(--gp)));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.npc-menu-hand .npc-menu-item-rich:hover,
.npc-menu-hand .npc-menu-item-rich:focus-visible {
  transform: translateY(calc(-2 * var(--gp)));
}

body.reduce-motion .npc-menu-hand .npc-menu-item-rich {
  animation: none;
}

body.reduce-motion .npc-menu-hand .npc-menu-item-rich:hover,
body.reduce-motion .npc-menu-hand .npc-menu-item-rich:focus-visible {
  transform: none;
}

.npc-menu-hand .npc-menu-key {
  position: absolute;
  top: calc(3 * var(--gp));
  left: calc(3 * var(--gp));
}

.npc-menu-hand .npc-menu-face {
  flex-direction: column;
  align-items: center;
  gap: calc(4 * var(--gp));
}

.npc-menu-hand .npc-item-art {
  display: grid;
  place-items: center;
  width: calc(28 * var(--gp));
  height: calc(28 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-dusk),
    inset calc(-2 * var(--gp)) calc(-2 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
}

.npc-menu-hand .npc-item-icon {
  width: 82%;
  height: 82%;
  border: none;
  background: transparent;
  box-shadow: none;
  clip-path: none;
}

.npc-menu-hand .npc-item-body {
  align-items: center;
  gap: calc(2 * var(--gp));
}

.npc-menu-hand .npc-item-label {
  font-weight: var(--type-weight-label);
}

.npc-menu-hand .npc-item-stats {
  width: 100%;
  margin-top: calc(2 * var(--gp));
  padding-top: calc(3 * var(--gp));
  border-top: var(--gp) solid var(--pixel-ink);
}

/* A menu whose answers are places keeps the plate in the rail while the world plane (world-plane-view.css) opens where answers would be. Teleports are pins on it; dead-end answers keep the row grammar. */

.npc-win.npc-travel {
  max-height: max(78vh, calc(230 * var(--gp)));
}

.npc-controls.npc-travel-board {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
}

.npc-travel-pip {
  position: absolute;
  display: grid;
  place-items: center;
  width: calc(15 * var(--gp));
  height: calc(15 * var(--gp));
  transform: translate(-50%, -50%);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.npc-travel-pip-icon {
  display: block;
  width: calc(12 * var(--gp));
  height: calc(12 * var(--gp));
  image-rendering: pixelated;
  filter: drop-shadow(0 var(--gp) 0 rgb(8 11 16 / 85%));
  transition: filter 0.12s ease;
}

.npc-travel-pip:hover .npc-travel-pip-icon,
.npc-travel-pip:focus-visible .npc-travel-pip-icon {
  filter: drop-shadow(0 0 calc(2 * var(--gp)) rgb(242 207 122 / 80%))
    drop-shadow(0 var(--gp) 0 rgb(8 11 16 / 85%));
}

.npc-travel-pip:focus-visible {
  outline: var(--gp) dashed var(--accent);
  outline-offset: calc(-1 * var(--gp));
}

.npc-travel-pip[aria-disabled='true'] {
  opacity: 0.45;
}

.npc-input {
  width: 100%;
}

/* The accept/decline moment: what the quest asks and pays, Accept as the one bright thing. Rises in once; a redraw for late item art does not replay it. */

.npc-quest-offer {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--gp));
  margin-bottom: calc(5 * var(--gp));
  padding: calc(6 * var(--gp)) calc(7 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.npc-quest-offer-enter {
  animation: npc-quest-offer-in 180ms steps(3, end);
}

@keyframes npc-quest-offer-in {
  from {
    opacity: 0;
    transform: translateY(calc(3 * var(--gp)));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

body.reduce-motion .npc-quest-offer-enter {
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  .npc-quest-offer-enter {
    animation: none;
  }
}

.npc-quest-offer-eyebrow {
  color: color-mix(in srgb, var(--accent) 72%, var(--muted));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.npc-quest-offer-title {
  color: var(--accent);
  font-weight: var(--type-weight-label);
  font-size: var(--type-section-heading-size);
  font-family: var(--type-section-heading-family);
  -webkit-font-smoothing: var(--type-section-heading-smoothing);
  letter-spacing: 0.02em;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.npc-quest-offer-desc {
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  line-height: round(1.5em, var(--gp));
}

.npc-quest-offer-objectives {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
  margin: var(--gp) 0 0;
  padding: 0;
  list-style: none;
}

.npc-quest-offer-objective {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
}

.npc-quest-offer-objective-icon {
  width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.npc-quest-offer-objective-label {
  min-width: 0;
}

.npc-quest-offer-count {
  margin-inline-start: auto;
  color: var(--accent);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
}

.npc-quest-offer-rewards-title {
  margin-top: calc(2 * var(--gp));
  padding-top: calc(4 * var(--gp));
  border-top: var(--gp) solid var(--pixel-dusk);
  color: color-mix(in srgb, var(--accent) 72%, var(--muted));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.npc-quest-offer-rewards {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
}

.npc-quest-offer-reward {
  display: flex;
  align-items: center;
  gap: calc(5 * var(--gp));
}

.npc-quest-offer-reward-icon {
  width: calc(22 * var(--gp));
  height: calc(22 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-dusk),
    inset calc(-2 * var(--gp)) calc(-2 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
  object-fit: contain;
}

.npc-quest-offer-reward-name {
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  min-width: 0;
}

.npc-quest-offer-actions {
  display: flex;
  justify-content: flex-end;
  gap: calc(4 * var(--gp));
}

.npc-quest-offer-actions .ron-btn {
  align-self: auto;
}

.npc-quest-turnin-objective-done .npc-quest-offer-objective-label {
  color: var(--good, #63c08a);
  text-decoration: line-through;
  text-decoration-color: color-mix(in srgb, var(--good, #63c08a) 75%, transparent);
}

.npc-quest-turnin-objective-done .npc-quest-offer-count {
  color: var(--good, #63c08a);
}

.hotbar {
  bottom: 12px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 6px;
}

/* A slot is a square pixel well; its outline is four strips skipping the corner pixels (--well-edge),
   so the well is notched without clipping itself and a lesson halo can stand round it. */

.hot-slot {
  --well-line: var(--pixel-ink);
  --well-edge: var(--pixel-ink);
  --well-face: var(--pixel-night);
  width: calc(28 * var(--gp));
  height: calc(28 * var(--gp));
  background:
    linear-gradient(var(--well-edge) 0 0) var(--gp) 0 / calc(100% - 2 * var(--gp)) var(--gp)
      no-repeat border-box,
    linear-gradient(var(--well-edge) 0 0) var(--gp) 100% / calc(100% - 2 * var(--gp)) var(--gp)
      no-repeat border-box,
    linear-gradient(var(--well-edge) 0 0) 0 var(--gp) / var(--gp) calc(100% - 2 * var(--gp))
      no-repeat border-box,
    linear-gradient(var(--well-edge) 0 0) 100% var(--gp) / var(--gp) calc(100% - 2 * var(--gp))
      no-repeat border-box,
    var(--well-face) padding-box;
  border: var(--gp) solid transparent;
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: calc(3 * var(--gp));
  box-shadow:
    var(--pixel-rim),
    inset 0 0 0 calc(3 * var(--gp)) var(--well-line),
    inset calc(4 * var(--gp)) calc(4 * var(--gp)) 0 rgb(0 0 0 / 35%);
  transition: filter 0.12s;
}

.hot-slot:hover {
  filter: brightness(1.18);
}

/* Top-left badge: the assigned hotkey, on a notched ink plate that stays legible over the icon. */

.hot-key {
  position: absolute;
  top: calc(3 * var(--gp));
  left: calc(3 * var(--gp));
  z-index: 3;
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  color: #eef1f5;
  height: auto;
  line-height: var(--type-leading-tight);
  box-sizing: border-box;
  padding: 0 calc(2 * var(--gp));
  background: var(--pixel-ink);
  clip-path: var(--pixel-notch);
  box-shadow: inset 0 var(--gp) 0 var(--pixel-dusk);
}

.hot-slot.needs-target {
  --well-line: color-mix(in srgb, var(--gold) 55%, var(--pixel-ink));
}

.hot-name {
  position: absolute;
  right: calc(3 * var(--gp));
  bottom: calc(3 * var(--gp));
  z-index: 2;
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  box-sizing: border-box;
  height: auto;
  line-height: var(--type-leading-tight);
  color: #eef1f5;
  padding: 0 calc(2 * var(--gp));
  background: var(--pixel-ink);
  clip-path: var(--pixel-notch);
  box-shadow: inset 0 var(--gp) 0 var(--pixel-dusk);
  max-width: 84%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hot-name:empty {
  display: none;
}

.chat-log {
  /* Height is owned by the resizable rule below (--chat-log-h); this is only a viewport cap. */
  max-height: 72vh;
  overflow-y: auto;
  padding: 2px 2px;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  pointer-events: auto;
}

.chat-line {
  margin: 1px 0;
  line-height: 1.3;
  word-wrap: break-word;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.chat-line.public {
  color: var(--text);
}

.chat-line.system {
  color: var(--accent);
}

.chat-line.whisper {
  color: #4fd0e0;
}

.chat-line.party {
  color: #5fd35f;
}

.chat-line.guild {
  color: #e0913d;
}

.inv-section {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: var(--type-weight-medium);
  color: var(--accent);
  margin: 8px 0 4px;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  border-bottom: 1px solid var(--ui-line-soft);
  padding-bottom: 4px;
}

.inv-section::before {
  content: '';
  flex: 0 0 auto;
  width: 3px;
  height: 12px;
  background: linear-gradient(180deg, var(--accent), var(--accent-2));
}

.inv-empty {
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  padding: 2px 0 6px;
}

.inv-footer {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: calc(12px * var(--ui-scale));
  padding-top: 9px;
  margin-top: 2px;
  border-top: 1px solid var(--ui-line-soft);
}

.inv-weight {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: calc(7px * var(--ui-scale));
}

.inv-weight-ico {
  flex: 0 0 auto;
  display: inline-flex;
  color: #8a93a3;
}

.inv-weight-ico .inv-ico-img {
  width: calc(19px * var(--ui-scale));
  height: calc(19px * var(--ui-scale));
  object-fit: contain;
  display: block;
}

.inv-weight-bar {
  flex: 1 1 0;
  width: auto;
  min-width: 0;
}

.inv-weight-text {
  flex: 0 0 auto;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  color: #c7ceda;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Band edge colour, not its fill: a state that escalates must not make its own number harder to read. */

.inv-weight-text[data-band='heavy'] {
  color: var(--hud-load-heavy-ring);
}

.inv-weight-text[data-band='overloaded'] {
  color: var(--hud-load-overloaded-ring);
}

.inv-gold {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: calc(5px * var(--ui-scale));
}

.inv-gold-ico {
  display: inline-flex;
  color: #f2cf7a;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.5));
}

.inv-gold-ico .inv-ico-img {
  width: calc(21px * var(--ui-scale));
  height: calc(21px * var(--ui-scale));
  object-fit: contain;
  display: block;
}

.inv-gold-val {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-label);
  color: var(--gold-value);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-shadow: 0 1px 0px #000;
}

.inv-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
}

.inv-row-name {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.inv-row-name--stacked {
  display: flex;
  flex-direction: column;
  gap: 1px;
  overflow: visible;
  white-space: normal;
}

.inv-row-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.inv-row-opts {
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  opacity: 0.85;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.inv-row-acts {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}

.inv-act {
  pointer-events: auto;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  padding: 3px 8px;
  cursor: var(--cursor-action);
  background: var(--panel-2);
  border: 1px solid var(--accent);
  color: var(--accent);
}

.inv-act:hover {
  background: var(--accent);
  color: #1a1206;
}

.inv-act.drop {
  border-color: #5a4453;
  color: #a98;
}

.inv-act.drop:hover {
  background: #7a3a3a;
  color: #fff;
  border-color: #7a3a3a;
}

.target-panel {
  flex-direction: column;
  align-items: center;
  gap: 4px;
  background: transparent;
  border: 0;
  padding: 0;
  min-width: 160px;
  pointer-events: none;
}

/* The focused unit's health is the shared `.hud-gauge` at the character's own vitals height, so the two frames read as one kind of thing. */

.target-panel.unit-frame {
  flex-direction: row;
  align-items: flex-start;
  gap: 8px;
  width: min(78vw, calc(278px * var(--ui-scale)));
  min-width: min(70vw, calc(232px * var(--ui-scale)));
  max-width: min(78vw, calc(278px * var(--ui-scale)));
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.76));
}

.unit-portrait > canvas.unit-portrait-live {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: none;
}

.unit-portrait.has-3d > canvas.unit-portrait-live {
  display: block;
}

.unit-portrait.has-3d {
  background-image: none !important;
}

/* Creatures keep their whole body in the tile; humanoids are framed on head and shoulders. */

.unit-portrait.has-art {
  background-size: cover;
  background-position: 50% 24%;
}

.unit-portrait.has-art.art-humanoid {
  background-size: auto 260%;
  background-position: 50% 4%;
}

.target-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
  gap: var(--gp);
}

.target-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  justify-content: space-between;
}

.target-body > .target-hp {
  margin-top: round(calc(3px * var(--ui-scale)), 1px);
}

.unit-frame .target-name {
  display: flex;
  align-items: center;
  gap: 5px;
  flex: 1;
  min-width: 0;
}

.target-dist {
  font-size: var(--type-metadata-readable-size);
  font-family: var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
  color: #7f8b99;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex: 0 0 auto;
  transition: color 0.12s ease;
}

.target-dist.oor {
  color: var(--danger, #e0533d);
  font-weight: var(--type-weight-strong);
}

/* A caption too long for the frame is cut at the row, never inside a token. */

.target-class {
  display: flex;
  align-items: baseline;
  gap: 0;
  flex-wrap: wrap;
  min-width: 0;
  overflow: visible;
  mask-image: linear-gradient(to right, #000 calc(100% - 14px), transparent);
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 14px), transparent);
}

.tgt-class-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  flex: 0 0 auto;
  font-size: var(--type-metadata-readable-size);
  font-family: var(--type-metadata-readable-family);
  -webkit-font-smoothing: var(--type-metadata-readable-smoothing);
  line-height: round(1.45em, 1px);
  padding: 0;
  border: 0;
  background: none;
  color: #8e9aa8;
  white-space: nowrap;
}

.tgt-class-chip + .tgt-class-chip {
  margin-left: 6px;
  padding-left: 6px;
  border-left: 1px solid #4f5a67;
}

.tgt-class-chip img {
  width: 11px;
  height: 11px;
  display: block;
  align-self: center;
}

/* A downed unit's danger red is painted inline at the chip so every palette mode reaches it. */

.tgt-class-chip.dead {
  font-weight: var(--type-weight-strong);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.target-cast {
  margin-top: var(--gp);
}

/* The windup is the shared cast bar (hud-cast.css); aimed at the player, its edge turns cream. */

.target-cast.targets-player .hud-cast-track {
  --gauge-ring: var(--pixel-cream);
}

.target-cast.interrupted .hud-gauge-label {
  color: color-mix(in srgb, var(--danger) 45%, #fff);
}

.target-status {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  margin-top: 3px;
  justify-content: flex-start;
}

body.high-contrast .tgt-class-chip {
  color: #fff;
  font-weight: var(--type-weight-strong);
}

/* The dead chip's danger red is painted inline, so no override rule is needed. */

/* "This one is aimed at me" outranks the high-contrast ring too. */

body.high-contrast .target-cast.targets-player .hud-cast-track {
  --gauge-ring: #fff;
}

/* Slot pulses repaint the well line: brass when assigned, green off cooldown, red with a shake when the server refuses a press. */

.hot-slot.flash {
  animation: hotflash 0.6s ease-out;
}

@keyframes hotflash {
  from {
    --well-line: var(--accent);
  }
}

.hot-slot.ready {
  animation: hotready 0.5s ease-out;
}

@keyframes hotready {
  from {
    --well-line: var(--accent-2, #5fd38a);
  }
}

.hot-slot.failed {
  animation: hotfail 0.42s ease-out;
}

@keyframes hotfail {
  0% {
    --well-edge: var(--danger);
    --well-line: var(--danger);
    transform: translateX(calc(-1 * var(--gp)));
  }
  35% {
    transform: translateX(var(--gp));
  }
  100% {
    transform: translateX(0);
  }
}

body.reduce-flashing :is(.hot-slot, .action-bars .hot-slot).failed {
  animation: none;
  --well-edge: var(--danger);
  --well-line: var(--danger);
}

/* z-index sits above the window band (WINDOW_Z_CEIL): a menu inside a .window is trapped in its stacking context,
   clipped and misplaced. */

.context-menu {
  position: fixed;
  z-index: 200;
  min-width: calc(130px * var(--type-scale, 1));
  padding: calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
  pointer-events: auto;
  display: flex;
  flex-direction: column;
}

.context-title {
  font-weight: var(--type-weight-strong);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  color: var(--accent);
  padding: calc(2 * var(--gp)) calc(4 * var(--gp)) calc(3 * var(--gp));
  border-bottom: var(--gp) solid var(--pixel-dusk);
}

.context-item.drop {
  color: #d9a3a3;
}

.context-item.drop:is(:hover, :focus-visible) {
  background: color-mix(in srgb, var(--pixel-debuff) 45%, var(--pixel-night));
  color: var(--pixel-cream);
}

/* A menu row is a <button>: strip its native chrome here rather than per menu. */

.context-item {
  display: block;
  width: 100%;
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  cursor: var(--cursor-action);
}

.context-item:is(:hover, :focus-visible) {
  background: var(--pixel-dusk);
  color: var(--pixel-cream);
}

.context-item:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.status-tray-content {
  display: flex;
  flex-wrap: wrap;
  gap: calc(2 * var(--gp));
  max-width: calc(110 * var(--gp));
}

/* A status is a pixel chip: ink edge, one line in its own colour (--chip), single-pixel corner cut; every HUD status chip is this at its own size. */

.status-icon,
.tgt-status-chip,
.pf-chip {
  --chip: var(--pixel-lilac);
  --chip-time: var(--pixel-cream);
  --frac: 1;
  position: relative;
  box-sizing: border-box;
  border: var(--gp) solid var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) var(--chip);
  clip-path: var(--pixel-notch);
}

.status-icon {
  --chip-art: calc(15 * var(--gp));
  width: max-content;
  min-width: calc(17 * var(--gp));
  flex: none;
  height: max(calc(17 * var(--gp)), calc(var(--type-micro-size) * 1.2 + 4 * var(--gp)));
  background: var(--pixel-night);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
  cursor: var(--cursor-default);
}

/* Time left: a one-pixel top bar, full at --frac:1 and empty at 0, set per tick; only timed statuses opt in. */

.status-icon.timed::before,
.tgt-status-chip.timed::before,
.pf-chip.timed::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  width: round(up, calc(var(--frac) * 100%), var(--gp));
  height: var(--gp);
  background: var(--chip-time);
  pointer-events: none;
}

/* An applied budget (a shield's absorb) empties on a different clock from the duration, so it is a bar on the base edge, opposite the time bar. */

.status-icon.charged::after,
.tgt-status-chip.charged::after,
.pf-chip.charged::after {
  content: '';
  position: absolute;
  left: var(--gp);
  right: var(--gp);
  bottom: var(--gp);
  z-index: 2;
  height: var(--gp);
  background: linear-gradient(
    90deg,
    #7fd3ff 0 round(up, calc(var(--charge, 1) * 100%), var(--gp)),
    var(--pixel-ink) 0
  );
  pointer-events: none;
}

.status-icon .status-abbr,
.status-icon .status-time {
  position: relative;
  z-index: 3;
}

.status-abbr {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--accent);
}

.status-time {
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  color: var(--muted);
}

.status-icon.arted {
  background-repeat: no-repeat;
  justify-content: flex-end;
  cursor: help;
}

:is(.status-icon.arted, .tgt-status-chip, .pf-chip) .status-time {
  position: relative;
  z-index: 3;
  margin-bottom: var(--gp);
  background: var(--pixel-ink);
  color: var(--pixel-cream);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
  line-height: var(--type-leading-tight);
  text-align: center;
  white-space: nowrap;
}

@supports (width: calc-size(max-content, size)) {
  :is(.status-icon.arted, .tgt-status-chip, .pf-chip) .status-time {
    width: calc-size(max-content, round(up, size + var(--gp), calc(2 * var(--gp))) - var(--gp));
  }
  .pf-chip-focus .status-time {
    width: calc-size(max-content, round(up, size, calc(2 * var(--gp))));
  }
}

:is(.status-icon.arted, .tgt-status-chip, .pf-chip) .status-time:empty {
  display: none;
}

:is(.status-icon.arted, .tgt-status-chip, .pf-chip).charged .status-time {
  margin-bottom: calc(2 * var(--gp));
}

/* The chip everywhere but the self tray: one status reads the same on every frame; a surface chooses only tile size and whether to print the countdown. */

.tgt-status-chip,
.pf-chip {
  --chip: var(--pixel-buff);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  pointer-events: auto;
  cursor: help;
}

/* A party row's chip is too small for an art line, so its status colour is its outline. */

.pf-chip:not(.pf-chip-focus) {
  border-color: var(--chip);
  box-shadow: none;
}

/* Only the countdown takes the tile's base; the stack badge keeps its corner tag or it would cover the art. */

.tgt-status-chip .status-time,
.pf-chip .status-time {
  font-size: var(--type-micro-readable-size);
  font-family: var(--type-micro-readable-family);
  -webkit-font-smoothing: var(--type-micro-readable-smoothing);
}

.tgt-status-chip .status-stacks,
.pf-chip .status-stacks {
  min-width: calc(5 * var(--gp));
  padding: 0 var(--gp);
  font-size: var(--type-glyph-readable-size);
  font-family: var(--type-glyph-readable-family);
  -webkit-font-smoothing: var(--type-glyph-readable-smoothing);
}

/* The overflow tile names the hidden statuses and takes focus where the chips do. */

.status-chip-overflow {
  --chip: var(--accent-2);
  background-image: none;
  background: var(--pixel-night);
  justify-content: center;
  cursor: help;
  padding: 0;
  font: inherit;
}

.tgt-status-chip .status-abbr,
.pf-chip .status-abbr {
  font-size: var(--type-micro-readable-size);
  font-family: var(--type-micro-readable-family);
  -webkit-font-smoothing: var(--type-micro-readable-smoothing);
}

.tgt-status-chip {
  --chip-art: calc(11 * var(--gp));
}

.pf-chip {
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
}

.pf-buffs-focus {
  gap: calc(2 * var(--gp));
}

.pf-chip-focus {
  --chip-art: calc(10 * var(--gp));
}

/* A chip is a square wide enough for a three-character timer, which sits on the art's lower edge. */

:is(.status-icon.arted, .tgt-status-chip, .pf-chip-focus) {
  width: max-content;
  min-width: max(
    calc(var(--chip-art) + 2 * var(--gp)),
    calc(2.2 * var(--type-micro-size) + 4 * var(--gp))
  );
  height: auto;
  min-height: 0;
  aspect-ratio: 1;
  padding: 0;
  background-size: calc(100% - 2 * var(--gp)) calc(100% - 2 * var(--gp));
  background-position: center;
}

/* Buffs green, harmful debuffs/CC red, owned passives gold; the label and hover card also say Debuff/Harmful effect, so meaning survives colourblindness. */

:is(.status-icon, .tgt-status-chip, .pf-chip).buff {
  --chip: var(--pixel-buff);
}

:is(.status-icon, .tgt-status-chip, .pf-chip).debuff {
  --chip: var(--pixel-debuff);
}

:is(.status-icon, .tgt-status-chip, .pf-chip).passive {
  --chip: var(--pixel-ochre);
}

.status-icon.buff .status-abbr {
  color: #6fd06a;
}

.status-icon.debuff .status-abbr {
  color: #ff8a76;
}

/* Always-on passives get a timerless lane below the timed buffs, wrapping onto their own rows. */

.status-passive-lane {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: calc(2 * var(--gp));
  margin-top: calc(2 * var(--gp));
  padding-top: calc(2 * var(--gp));
  border-top: var(--gp) solid var(--pixel-dusk);
}

.status-icon.passive.arted {
  justify-content: center;
}

.status-stacks {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 4;
  min-width: calc(7 * var(--gp));
  padding: 0 calc(2 * var(--gp));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(up, 1.2em, var(--gp));
  text-align: center;
  color: var(--pixel-ink);
  background: var(--accent);
  text-shadow: none;
}

/* Windowed-trigger chips: while charging the time bar is a gold fill meter (--frac = stacks/max) and the icon dims;
   at the firing count the line turns gold; a spent capstone washes dark like a skill on cooldown. */

:is(.status-icon, .tgt-status-chip, .pf-chip).charging {
  --chip-time: var(--accent);
  filter: saturate(0.65) brightness(0.62);
}

:is(.status-icon, .tgt-status-chip, .pf-chip).ready {
  --chip: var(--accent);
  --chip-time: var(--accent);
}

:is(.tgt-status-chip, .pf-chip).cooldown {
  box-shadow:
    inset 0 0 0 var(--gp) var(--chip),
    inset 0 0 0 calc(20 * var(--gp)) rgb(20 14 28 / 62%);
}

/* Spent capstone: an inset box-shadow wash under the chip's line greys the icon without competing with the time bar or countdown. */

.status-icon.cooldown {
  --chip-time: #d2e0ff;
  box-shadow:
    inset 0 0 0 var(--gp) var(--chip),
    inset 0 0 0 calc(20 * var(--gp)) rgb(20 14 28 / 62%);
}

.status-icon.cooldown .status-time {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: auto;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: 1;
  color: var(--pixel-cream);
  background: none;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.hot-slot::before {
  content: '';
  position: absolute;
  pointer-events: none;
  inset: 0;
  z-index: 1;
  opacity: 0;
}

.hot-icon,
.hot-key,
.hot-name,
.hot-cd {
  z-index: 3;
}

.minimap-content.minimap-clickable {
  pointer-events: auto;
  cursor: var(--cursor-action);
}

.minimap-canvas {
  position: absolute;
  inset: 0;
  width: 100% !important;
  height: 100% !important;
  background: rgba(32, 55, 47, 0.92);
  box-shadow: none;
  z-index: 1;
}

/* Overflow chip: collapses auras beyond the tray cap into one '+N' tile so a Stun/Freeze is never pushed out of view. */

.status-icon.status-overflow {
  --chip: var(--accent-2);
  cursor: help;
}

.status-icon.status-overflow .status-abbr {
  color: var(--muted);
}

.item-tooltip {
  /* The card is enterable: the pointer can cross to read its rows and a touch can tap it. It closes on the grace timer,
     an outside tap or Escape; rows are not selectable so the opening hold leaves no highlight. */
  position: fixed;
  z-index: 210;
  min-width: calc(150px * var(--type-scale, 1));
  max-width: calc(300px * var(--type-scale, 1));
  pointer-events: auto;
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
}

.item-tooltip--comparison {
  grid-auto-flow: column;
  grid-auto-columns: minmax(calc(100 * var(--gp)), calc(145 * var(--gp)));
  gap: calc(4 * var(--gp));
  width: max-content;
  min-width: 0;
  max-width: calc(100vw - 16px - var(--safe-left, 0px) - var(--safe-right, 0px));
  padding: 0;
  pointer-events: auto;
  background: none;
  border: 0;
  box-shadow: none;
  clip-path: none;
}

.item-tooltip--comparison.item-tooltip--left {
  direction: rtl;
}

.item-tooltip--comparison .tt-panel {
  direction: ltr;
  min-width: 0;
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  overflow-wrap: anywhere;
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
}

.tt-equipped-label {
  color: var(--accent);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.45px;
  text-transform: uppercase;
  margin-bottom: calc(2 * var(--gp));
}

.tt-compare-hint {
  margin-top: calc(4 * var(--gp));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  text-align: right;
}

.tt-compare-section {
  margin-bottom: calc(4 * var(--gp));
  padding-bottom: calc(3 * var(--gp));
  border-bottom: var(--gp) solid var(--pixel-dusk);
}

.tt-line.tt-neutral {
  color: var(--muted);
}

.tt-compare-grid {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--gp) calc(5 * var(--gp));
  align-items: baseline;
  margin-bottom: var(--gp);
}

.tt-compare-row {
  display: contents;
}

.tt-compare-label,
.tt-compare-value,
.tt-compare-effect {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.35;
}

.tt-compare-label {
  color: #b8c0cc;
}

.tt-compare-value {
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.tt-compare-row.tt-gain .tt-compare-value {
  color: var(--good);
}

.tt-compare-row.tt-loss .tt-compare-value {
  color: var(--danger);
}

.tt-compare-row.tt-neutral .tt-compare-label,
.tt-compare-row.tt-neutral .tt-compare-value {
  color: var(--muted);
  font-weight: var(--type-weight-normal);
}

.tt-compare-row--effect .tt-compare-effect {
  grid-column: 1 / -1;
}

.tt-compare-row--effect.tt-gain .tt-compare-effect {
  color: var(--good);
}

.tt-compare-row--effect.tt-loss .tt-compare-effect {
  color: var(--danger);
}

/* The Gained/Lost tag is the only lane marker, so it stays legible at the smallest UI scale. */

.tt-compare-tag {
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-strong);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  opacity: 0.75;
}

.tt-name {
  margin-bottom: calc(2 * var(--gp));
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  font-weight: var(--type-weight-display);
}

.tt-heading {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  margin-bottom: calc(3 * var(--gp));
}

.tt-heading .tt-name {
  margin-bottom: 0;
}

.tt-icon {
  flex: 0 0 auto;
  width: calc(16 * var(--gp));
  height: calc(16 * var(--gp));
  object-fit: contain;
}

.tt-line {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: #b8c0cc;
  margin: var(--gp) 0;
}

.tt-mastery-details {
  max-height: min(50dvh, 400px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.tt-mastery-details > div {
  margin: var(--gp) 0;
}

.tt-description {
  margin: calc(3 * var(--gp)) 0;
  color: #cdd3dd;
  line-height: 1.35;
}

.tt-quest {
  display: inline-block;
  margin: calc(2 * var(--gp)) 0 var(--gp);
  padding: var(--gp) calc(3 * var(--gp));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: #ead8a5;
  border: var(--gp) solid var(--accent-2);
  background: color-mix(in srgb, var(--accent) 14%, var(--pixel-night));
}

.tt-on {
  color: var(--accent);
}

.tt-rowlabel {
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--muted);
  margin: calc(3 * var(--gp)) 0 calc(2 * var(--gp));
}

.tt-stats {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: calc(2 * var(--gp)) calc(5 * var(--gp));
}

.tt-amt {
  font-weight: var(--type-weight-strong);
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.tt-eff {
  color: #cdd3dd;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

@media (max-width: 760px) {
  .item-tooltip--comparison {
    grid-auto-columns: minmax(calc(95 * var(--gp)), calc(120 * var(--gp)));
  }
}

/* A handheld's HUD pixel stays 2px, so desktop columns and art would outgrow its scaled text. */

[data-ui-profile='handheld'] .item-tooltip--comparison {
  grid-auto-columns: minmax(calc(75 * var(--gp)), calc(110 * var(--gp)));
}

[data-ui-profile='handheld'] .item-tooltip .tt-icon {
  width: calc(12 * var(--gp));
  height: calc(12 * var(--gp));
}

[data-ui-profile='handheld'] .item-tooltip .tt-opt-ico {
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
}

/* A signature milestone's check: a square box with a one-pixel edge; a reached
   one fills gold and carries an ink check drawn in whole HUD pixels. */

.tt-signature-milestone {
  display: inline-flex;
  align-items: baseline;
  gap: calc(3 * var(--gp));
}

.tt-signature-check {
  position: relative;
  flex: 0 0 calc(6 * var(--gp));
  box-sizing: border-box;
  width: calc(6 * var(--gp));
  height: calc(6 * var(--gp));
  border: var(--gp) solid var(--muted);
  transform: translateY(var(--gp));
}

.tt-signature-milestone.is-reached .tt-signature-check {
  border-color: var(--accent);
  background: var(--accent);
}

/* The check is four HUD pixels on the box's inner 4 x 4 grid: one stroke down
   to the left, one up to the right. */

.tt-signature-milestone.is-reached .tt-signature-check::after {
  content: '';
  position: absolute;
  left: 0;
  top: calc(2 * var(--gp));
  width: var(--gp);
  height: var(--gp);
  background: var(--pixel-ink);
  box-shadow:
    var(--gp) var(--gp) 0 var(--pixel-ink),
    calc(2 * var(--gp)) 0 0 var(--pixel-ink),
    calc(3 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-ink);
}

/* Quantity / confirm modal (drop, withdraw, skill level) */

.qd-overlay {
  position: fixed;
  inset: 0;
  z-index: 220;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--pixel-ink) 55%, transparent);
  padding: var(--hud-safe-top) var(--hud-safe-right) var(--hud-safe-bottom) var(--hud-safe-left);
}

.qd-panel {
  width: calc(320px * var(--type-scale, 1));
  max-width: 100%;
  max-height: 100%;
  overflow-y: auto;
}

.qd-field {
  margin: calc(7 * var(--gp)) 0 calc(9 * var(--gp));
}

/* The amount is a sunk well, as the kit's field is; focus is its inset bracket. */

.qd-field input[type='number'] {
  width: 100%;
  padding: calc(5 * var(--gp)) calc(6 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  color: var(--text);
  font-size: var(--type-prose-size);
  font-family: var(--type-prose-family);
  -webkit-font-smoothing: var(--type-prose-smoothing);
}

.qd-field input[type='number']:focus {
  outline: none;
}

.qd-field input[type='number']:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.qd-slider {
  width: 100%;
  margin-top: calc(5 * var(--gp));
  accent-color: var(--accent);
}

.qd-actions {
  display: flex;
  flex-wrap: wrap;
  gap: calc(4 * var(--gp));
}

.qd-actions .ron-btn {
  flex: 1 0 max-content;
  white-space: nowrap;
}

/* FPS readout (bottom-right): night plate with uncut corners so the layout editor's outline is not clipped. */

.fps-hud {
  position: fixed;
  right: calc(var(--hud-safe-right) + 28 * var(--gp));
  bottom: var(--hud-safe-bottom);
  z-index: 18;
  pointer-events: none;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: #8a93a3;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  background: var(--pixel-night);
  border: var(--gp) solid var(--pixel-ink);
  padding: 0 calc(4 * var(--gp));
}

.fps-hud.is-hidden {
  display: none;
}

/* A hidden chip still has a ghost place in the layout editor, so turning it off never strands its saved position. */

.hud-layout-editing .fps-hud.is-hidden {
  display: block;
  opacity: 0.45;
}

.chat-name {
  color: #9fd3ff;
  cursor: var(--cursor-action);
  pointer-events: auto;
  font-weight: var(--type-weight-medium);
}

.chat-name:hover {
  text-decoration: underline;
}

.chat-log {
  pointer-events: auto;
  overflow-y: auto;
}

/* The map-name banner is styled in screen-overlays.css, including its z-index over the warp cover. */

.window {
  pointer-events: auto;
}

.win-head {
  user-select: none;
}

.hot-slot {
  position: relative;
  overflow: hidden;
}

/* Hidden covers leave layout: iOS keeps a compositor veil from a full-viewport `opacity: 0` layer. */

.map-transition {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 44;
  pointer-events: none;
  background: #05070b;
  opacity: 0;
  transition: opacity 0.28s ease;
}

.map-transition:not(.show) {
  display: none;
}

.map-transition.show {
  display: block;
  opacity: 1;
  pointer-events: auto;
}

/* The crossing's phase line reuses the join cover's readout; it is held back until the crossing is slow enough to read as a freeze (`screen-map-change-controller`). */

.map-transition__phase {
  position: absolute;
  /* Hung off the destination banner's band: a fixed percentage gap would close at large `--ui-scale`. Centred on a whole HUD pixel. */
  top: 26%;
  left: round(50%, var(--gp));
  transform: translate(round(-50%, var(--gp)), calc(round(-50%, var(--gp)) + 31 * var(--gp)));
  font-size: var(--type-prose-size);
  font-family: var(--type-prose-family);
  -webkit-font-smoothing: var(--type-prose-smoothing);
  font-weight: var(--type-weight-medium);
  letter-spacing: 0.04em;
  color: color-mix(in srgb, var(--text) 86%, var(--muted));
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  text-align: center;
  opacity: 0;
  transition: opacity 220ms ease;
}

.map-transition__phase.show {
  opacity: 1;
}

/* A warp raises the cover instantly because the render thread stops compositing during the map rebuild; only the reveal fades. */

.map-transition.instant {
  transition: none;
}

.virtual-stick {
  position: fixed;
  left: max(18px, var(--safe-left));
  bottom: max(24px, var(--safe-bottom));
  z-index: 19;
  display: none;
  width: 112px;
  height: 112px;
  pointer-events: auto;
  touch-action: none;
  user-select: none;
}

/* Fallback paint only: the handheld profile draws the stick's base and cap (hud-virtual-stick.css). */

.virtual-stick-base {
  position: absolute;
  inset: 0;
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 60%, transparent);
}

.virtual-stick-knob {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 42px;
  height: 42px;
  margin: -21px 0 0 -21px;
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ochre);
  box-shadow: inset 0 var(--gp) 0 var(--pixel-honey);
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.virtual-stick.active .virtual-stick-base {
  border-color: var(--pixel-ochre);
}

@media (pointer: coarse) {
  .virtual-stick {
    display: block;
  }
}

/* Off-screen threat indicator: a chevron on the screen edge toward an attacker that hit from off-screen. */

.screen-threat-indicators {
  position: fixed;
  inset: 0;
  z-index: 18;
  pointer-events: none;
}

.threat-chevron {
  position: absolute;
  pointer-events: none;
  font-size: var(--type-hero-size);
  font-family: var(--type-hero-family);
  -webkit-font-smoothing: var(--type-hero-smoothing);
  color: #ff5a4a;
  line-height: 1;
  text-shadow:
    var(--gp) 0 0 var(--pixel-ink),
    calc(-1 * var(--gp)) 0 0 var(--pixel-ink),
    0 var(--gp) 0 var(--pixel-ink),
    0 calc(-1 * var(--gp)) 0 var(--pixel-ink);
  opacity: 0;
}

.threat-chevron.show {
  animation: threat-flash 1s ease-out;
}

@keyframes threat-flash {
  0% {
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  60% {
    opacity: 0.9;
  }
  100% {
    opacity: 0;
  }
}

body.reduce-flashing .threat-chevron.show {
  animation: none;
  opacity: 0.85;
}

.inv-icon {
  flex-shrink: 0;
  image-rendering: auto;
}

/* Equipment paperdoll: the group does not clip, so a lit slot's halo stands clear; each slot paints itself (hud-primitives-items-grid.css). */

.paperdoll {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: calc(4 * var(--gp));
  align-items: center;
  margin-bottom: var(--gp);
  padding: calc(5 * var(--gp));
  background: color-mix(in srgb, var(--pixel-ink) 35%, var(--pixel-night));
  border: var(--gp) solid var(--pixel-dusk);
}

.pd-col {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
}

.pd-slot {
  position: relative;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  cursor: var(--cursor-action);
}

.pd-slot:not(.pd-filled) {
  cursor: var(--cursor-default);
}

.pd-slot:not(.pd-filled):hover {
  border-color: var(--pixel-dusk);
}

.inv-draggable {
  cursor: grab;
}

.inv-draggable:active {
  cursor: grabbing;
}

.pd-slot.pd-drop {
  border-color: var(--good);
}

@media (prefers-reduced-motion: reduce) {
  .map-banner,
  .map-transition,
  .map-transition__phase,
  .target-dist,
  .menu-btn,
  .menu-items,
  .menu-collapse-icon,
  .chat-wrap,
  .chat-content,
  .chat-collapse-btn,
  .chat-collapse-icon {
    transition: none !important;
  }
  .adv-build-tab[data-build-pending] .adv-build-tab-count,
  .chat-collapse-btn.attention-arrive,
  .chat-collapse-btn.attention-arrive::after {
    animation: none !important;
  }
}

.announce-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 38;
  pointer-events: none;
  padding: 7px 16px;
  text-align: center;
  font-weight: var(--type-weight-medium);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  color: #ffe9a8;
  background: var(--pixel-night);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  transform: translateY(-110%);
  transition: transform 0.35s ease;
}

.announce-bar.show {
  transform: translateY(0);
}

#game-canvas {
  touch-action: none;
}

@media (max-width: 820px), (pointer: coarse) {
  html:not([data-ui-profile='handheld']) .hot-slot {
    width: 52px;
    height: 52px;
  }
  html:not([data-ui-profile='handheld']) .menu-btn {
    width: 48px;
    height: 48px;
  }
  html:not([data-ui-profile='handheld']) .menu-glyph,
  html:not([data-ui-profile='handheld']) .menu-icon {
    width: 38px;
    height: 38px;
  }
  html:not([data-ui-profile='handheld']) .inv-act {
    padding: 8px 12px;
  }
  html:not([data-ui-profile='handheld']) .window {
    max-width: 94vw;
  }
  html:not([data-ui-profile='handheld']) .chat-wrap {
    width: 64vw;
  }
  html:not([data-ui-profile='handheld']) .status-tray {
    max-width: 60vw;
  }
  html:not([data-ui-profile='handheld']) .target-panel.unit-frame {
    min-width: min(70vw, calc(100 * var(--gp)));
    max-width: 78vw;
  }
}

@media (max-width: 560px) {
  html:not([data-ui-profile='handheld']) .fps-hud {
    font-size: var(--type-micro-size);
    font-family: var(--type-micro-family);
    -webkit-font-smoothing: var(--type-micro-smoothing);
  }
  html:not([data-ui-profile='handheld']) .target-class {
    display: none;
  }
  html:not([data-ui-profile='handheld']) .window.win-quests {
    top: 72px;
    left: 3vw;
    right: auto;
    width: 94vw;
    max-width: 94vw;
  }
}

.chat-wrap {
  position: fixed;
  bottom: var(--hud-safe-bottom);
  left: var(--hud-safe-left);
  z-index: 19;
  width: var(--chat-w, 360px);
  max-width: 92vw;
  /* The launcher is absolute (it outlives the collapse), so the row states its own height instead of taking it from the entry box. */
  --chat-row: calc(17 * var(--gp));
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  background: color-mix(in srgb, var(--pixel-ink) 45%, transparent);
  background-clip: padding-box;
  border: 0;
  /* As wide as the folded panel's clear edge (hud-fold-docks.css), so the launcher holds still when the panel opens. */
  border-left: 1px solid transparent;
  box-shadow: inset var(--gp) 0 0 var(--pixel-dusk);
  padding: calc(4 * var(--gp)) calc(6 * var(--gp));
  pointer-events: auto;
  transition:
    width 180ms cubic-bezier(0.2, 0.78, 0.24, 1),
    padding 180ms ease;
}

.chat-content {
  /* The collapse animates this bound, so it tracks the log, tab strip, catch-up pill row and entry row. */
  max-height: calc(var(--chat-log-h, 150px) + 28 * var(--gp) + var(--chat-row));
  opacity: 1;
  transform: translateY(0);
  overflow: hidden;
  transition:
    max-height 180ms cubic-bezier(0.2, 0.78, 0.24, 1),
    opacity 120ms ease,
    transform 180ms cubic-bezier(0.2, 0.78, 0.24, 1);
}

.chat-wrap.is-collapsed .chat-content {
  max-height: 0;
  opacity: 0;
  transform: translateY(calc(3 * var(--gp)));
  pointer-events: none;
}

.chat-tabs {
  display: flex;
  gap: calc(4 * var(--gp));
  margin-bottom: calc(2 * var(--gp));
  padding-right: calc(8 * var(--gp));
  pointer-events: auto;
}

.chat-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-medium);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  padding: var(--gp) calc(3 * var(--gp));
  cursor: var(--cursor-action);
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  color: var(--pixel-lilac);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
}

.chat-tab:hover {
  color: var(--pixel-cream);
}

.chat-tab.active {
  background: var(--pixel-dusk);
  color: var(--pixel-cream);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}

/* Per-tab unread badge; its line follows the text, so a larger HUD pixel never stretches the tab. */

.chat-badge {
  min-width: calc(8 * var(--gp));
  padding: 0 calc(2 * var(--gp));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: round(1.1em, var(--gp));
  text-align: center;
  color: var(--pixel-ink);
  font-weight: var(--type-weight-strong);
  border: var(--gp) solid var(--pixel-ink);
  background: var(--accent);
}

.chat-log {
  /* Fixed height (player-resizable via --chat-log-h) so the panel never resizes as messages arrive; messages pin to the bottom. */
  height: var(--chat-log-h, 150px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  --chat-log-cut: linear-gradient(
    rgb(0 0 0 / 0.25) 0 calc(2 * var(--gp)),
    rgb(0 0 0 / 0.5) 0 calc(4 * var(--gp)),
    rgb(0 0 0 / 0.75) 0 calc(6 * var(--gp)),
    #000 0
  );
  -webkit-mask-image: var(--chat-log-cut);
  mask-image: var(--chat-log-cut);
}

/* Bottom-pin few messages without clipping scroll: an auto top-margin collapses once the log overflows
   (justify-content:flex-end would make the top rows unreachable). */

.chat-log > :first-child {
  margin-top: auto;
}

/* Resize grip: the free corner of the tab strip on the side the panel grows towards; it mirrors left when the HUD editor hangs the panel off the right edge. */

.chat-resize {
  position: absolute;
  top: calc(2 * var(--gp));
  right: calc(2 * var(--gp));
  z-index: 4;
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  cursor: nesw-resize;
  pointer-events: auto;
  opacity: 0;
  transition: opacity 0.12s;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.chat-resize::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: var(--gp);
  height: var(--gp);
  box-shadow:
    0 var(--gp) var(--accent),
    var(--gp) calc(2 * var(--gp)) var(--accent),
    calc(2 * var(--gp)) calc(3 * var(--gp)) var(--accent),
    calc(3 * var(--gp)) calc(4 * var(--gp)) var(--accent),
    calc(4 * var(--gp)) calc(5 * var(--gp)) var(--accent),
    calc(5 * var(--gp)) calc(6 * var(--gp)) var(--accent),
    calc(6 * var(--gp)) calc(7 * var(--gp)) var(--accent),
    calc(3 * var(--gp)) 0 var(--accent),
    calc(4 * var(--gp)) var(--gp) var(--accent),
    calc(5 * var(--gp)) calc(2 * var(--gp)) var(--accent),
    calc(6 * var(--gp)) calc(3 * var(--gp)) var(--accent),
    calc(7 * var(--gp)) calc(4 * var(--gp)) var(--accent);
}

.chat-wrap[data-hud-anchor-x='right'] .chat-resize {
  right: auto;
  left: calc(2 * var(--gp));
  cursor: nwse-resize;
  transform: scaleX(-1);
}

.chat-wrap[data-hud-anchor-x='right'] .chat-tabs {
  padding-right: 0;
  padding-left: calc(8 * var(--gp));
}

/* A top-anchored panel keeps its launcher beside the tabs; reserve that corner while the opposite one stays free for the grip. */

.chat-wrap[data-hud-anchor-y='top'] .chat-tabs {
  min-height: var(--chat-row);
  align-items: center;
  padding-left: max(var(--hud-fold-reserve-left), calc(8 * var(--gp)));
  padding-right: max(var(--hud-fold-reserve-right), calc(8 * var(--gp)));
}

.chat-wrap.is-collapsed .chat-resize {
  display: none;
}

.chat-wrap:hover .chat-resize {
  opacity: 0.65;
}

.chat-resize:hover {
  opacity: 1;
}

/* The launcher stays on the saved HUD corner in both states, so opening never moves the pointer target. */

/* Catch-up pill: shown only when a line arrives while scrolled up; click re-pins to the bottom. */

.chat-new-msgs {
  align-self: center;
  margin-top: calc(2 * var(--gp));
  padding: var(--gp) calc(6 * var(--gp));
  cursor: var(--cursor-action);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-medium);
  pointer-events: auto;
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
}

.chat-new-msgs,
.chat-send {
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ochre);
  color: var(--pixel-ink);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-honey),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0
      color-mix(in srgb, var(--pixel-ochre) 60%, var(--pixel-ink));
  clip-path: var(--pixel-notch);
}

.chat-new-msgs:hover,
.chat-send:hover {
  background: color-mix(in srgb, var(--pixel-honey) 35%, var(--pixel-ochre));
}

.chat-entry {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--gp));
  width: calc(100% - var(--chat-row) - 4 * var(--gp));
  box-sizing: border-box;
  margin-top: calc(3 * var(--gp));
  margin-left: calc(var(--chat-row) + 4 * var(--gp));
}

.chat-wrap[data-hud-anchor-x='right'] .chat-entry {
  margin-right: calc(var(--chat-row) + 4 * var(--gp));
  margin-left: 0;
}

.chat-wrap[data-hud-anchor-y='top'] .chat-entry {
  width: 100%;
  margin-right: 0;
  margin-left: 0;
}

.chat-input {
  flex: 1;
  min-width: 0;
  box-sizing: border-box;
  height: max(var(--chat-row), calc(var(--type-body-compact-size) * 1.2 + 10 * var(--gp)));
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  color: var(--pixel-cream);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.chat-input::placeholder {
  color: var(--muted);
  opacity: 1;
}

.chat-send {
  display: none;
  flex: none;
  align-items: center;
  justify-content: center;
  height: var(--chat-row);
  padding: 0 calc(5 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  cursor: var(--cursor-action);
}

.chat-input:focus {
  outline: none;
}

/* The notch clips anything drawn outside these pieces, so focus is the inset bracket. */

.chat-tab:focus-visible,
.chat-new-msgs:focus-visible,
.chat-input:focus-visible,
.chat-send:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.chat-line.channel {
  color: var(--accent-2);
}

.chat-line.server {
  color: #8fd6ff;
}

.chat-line.announce {
  color: var(--accent);
  font-weight: var(--type-weight-medium);
}

.chat-line.error {
  color: #ff7a7a;
}

.chat-line.emote {
  color: #c9a0ff;
  font-style: italic;
}

.chat-source {
  display: inline-block;
  margin-right: calc(2 * var(--gp));
  padding: 0 calc(2 * var(--gp));
  border: var(--gp) solid color-mix(in srgb, #8fd6ff 45%, var(--pixel-ink));
  color: #c9ecff;
  background: color-mix(in srgb, #419ddc 18%, var(--pixel-ink));
  font-size: var(--type-relative-secondary-size);
  font-family: var(--type-relative-secondary-family);
  -webkit-font-smoothing: var(--type-relative-secondary-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(0.9em, var(--gp));
  text-transform: uppercase;
}

.chat-time {
  color: var(--muted);
  font-size: var(--type-relative-secondary-size);
  font-family: var(--type-relative-secondary-family);
  -webkit-font-smoothing: var(--type-relative-secondary-smoothing);
  opacity: 0.8;
}

.hud-gauge-fill.hp.critical,
.hud-gauge-fill.sp.critical {
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.65);
}

/* Hidden covers leave layout entirely: iOS keeps a compositor veil from a full-viewport `opacity: 0` fixed layer. */

.crit-vignette {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  box-shadow: none;
}

.crit-vignette.show {
  display: block;
  opacity: 0.55;
}

@media (prefers-reduced-motion: reduce) {
  .hud-disclosure-revealed {
    animation: none;
  }
}

body.reduce-flashing .hud-disclosure-revealed {
  animation: none;
}

/* In-app "Reduce motion" kills the DOM keyframes and transitions the OS media query disables, for opted-in users too. */

body.reduce-motion .map-banner,
body.reduce-motion .map-transition,
body.reduce-motion .map-transition__phase,
body.reduce-motion .target-dist,
body.reduce-motion .announce-bar,
body.reduce-motion .menu-items,
.reduce-motion .chat-wrap,
.reduce-motion .chat-content {
  transition: none !important;
}

body.reduce-flashing .target-dist {
  transition: none !important;
}

body.reduce-motion .coach-banner.coach-banner-enter,
body.reduce-motion .threat-chevron.show,
body.reduce-motion .hud-disclosure-revealed {
  animation: none;
}

body.reduce-motion .status-icon.timed::before {
  transition: none;
}

/* Bottom-centre prompt column (pickup line, kit-swap offer) docks above the alert feed and action bars; the fixed anchor is the un-railed fallback. */

.screen-interaction-prompts {
  position: fixed;
  bottom: calc(var(--hud-safe-bottom) + var(--hotbar-h));
  left: 50%;
  z-index: 20;
  display: flex;
  /* The column grows upward from its bottom edge: a new strip arrives at the top and never shifts one already there. */
  flex-direction: column;
  align-items: center;
  gap: calc(6px * var(--ui-scale));
  max-width: min(calc(560px * var(--ui-scale)), calc(100vw - 2 * var(--hud-edge)));
  transform: translateX(-50%);
  pointer-events: none;
}

.screen-interaction-prompts > [hidden] {
  display: none;
}

.screen-interaction-prompts[data-hud-anchor-x='left'] {
  align-items: flex-start;
}

.screen-interaction-prompts[data-hud-anchor-x='right'] {
  align-items: flex-end;
}

/* An idle column measures nothing; the layout editor gets a body to measure and drag. */

.hud-layout-editing .screen-interaction-prompts {
  min-width: calc(200px * var(--ui-scale));
  min-height: calc(40px * var(--ui-scale));
  pointer-events: auto;
}

/* High-contrast theme (body.high-contrast): raises panel opacity, lightens muted text, strengthens borders; palette.ts brightens rarity/minimap colours in step. */

body.high-contrast {
  --muted: #d2d8e2;
  --text: #ffffff;
  --danger: #ff5a44;
  --hud-load-heavy-ring: #ffd35c;
  --hud-load-overloaded-ring: #ff7a62;
}

body.high-contrast .status-panel,
body.high-contrast .target-panel,
body.high-contrast .menu-buttons,
body.high-contrast .menu-btn,
body.high-contrast .panel,
body.high-contrast .panel-box,
body.high-contrast .chat-log,
body.high-contrast .chat-tab,
body.high-contrast .npc-win,
body.high-contrast .shop-panel,
body.high-contrast .cashshop-panel,
body.high-contrast .mail-panel,
body.high-contrast .itemsvc-panel,
body.high-contrast .refine-panel,
body.high-contrast .armory-panel,
body.high-contrast .informant-panel,
body.high-contrast .frontline-panel,
body.high-contrast .trade-panel {
  background: #0a0e14 !important;
  border-color: #6f7d92 !important;
}

body.high-contrast .window,
body.high-contrast .enhance-panel {
  background: #0a0e14;
  border-color: #6f7d92;
}

/* A well's outline skips its corner pixels, so it takes the stronger edge
   through its own channels. */

body.high-contrast .hot-slot {
  --well-edge: #6f7d92;
  --well-face: #0a0e14;
}

body.high-contrast .win-head {
  border-bottom-color: #6f7d92;
}

body.high-contrast .shop-row,
body.high-contrast .cashshop-row,
body.high-contrast .mail-grid-host .dgrid-row,
body.high-contrast .itemsvc-row {
  border-color: #6f7d92;
  background: #0a0e14;
}

/* Wayfind bar: names where the ground trail leads, with the control that stops following it. Docks in the bottom-centre rail, tinted like the trail (--wayfind-accent). */

:root {
  --wayfind-accent: #d8c798;
}

.wayfind-bar {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  box-sizing: border-box;
  max-width: 100%;
  padding: calc(2 * var(--gp)) calc(3 * var(--gp)) calc(2 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: inset var(--gp) 0 0 var(--wayfind-accent);
  clip-path: var(--pixel-notch);
  color: var(--text);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  pointer-events: auto;
}

/* Centred in its rail, so its width is an even count of HUD pixels and the notch never lands on a half pixel. */

@supports (width: calc-size(max-content, size)) {
  .wayfind-bar {
    width: calc-size(max-content, round(up, size, calc(2 * var(--gp))));
  }
}

.wayfind-bar[data-hud-anchor-x='right'] {
  flex-direction: row-reverse;
  padding-inline: calc(3 * var(--gp)) calc(5 * var(--gp));
  box-shadow: inset calc(-1 * var(--gp)) 0 0 var(--wayfind-accent);
}

.wayfind-bar[data-hud-anchor-x='right'] .wayfind-bar-copy {
  align-items: flex-end;
  text-align: right;
}

.wayfind-bar-icon {
  display: block;
  flex: none;
  width: calc(12 * var(--gp));
  height: calc(12 * var(--gp));
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.wayfind-bar-copy {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.wayfind-bar-label {
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(up, calc(var(--type-body-size) * 1.2), var(--gp));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wayfind-bar-distance {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: round(up, calc(var(--type-label-size) * 1.2), var(--gp));
  color: var(--pixel-lilac);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The stop control is the game's close cap (hud-pixel-window.css); this only places it. */

.wayfind-bar-stop {
  margin-inline-start: auto;
}

/* Held open by the layout editor with no route: the placeholder is the whole widget, so the strip's parts stand down. */

.wayfind-bar.hud-layout-ghost .wayfind-bar-icon,
.wayfind-bar.hud-layout-ghost .wayfind-bar-copy,
.wayfind-bar.hud-layout-ghost .wayfind-bar-stop {
  display: none;
}

body.high-contrast .wayfind-bar {
  border-color: var(--wayfind-accent);
  background: #0a0e14;
}

/* Recall: a one-slot action bar left of the main bar (action-bars.css owns that column); the slot inherits hotbar chrome. */

.action-bar--recall {
  display: flex;
  justify-content: flex-end;
}

/* Not offered on this map: dimmed and inert, with no sweep or number, so it never reads as a cooldown. */

.recall-slot.is-blocked {
  opacity: 0.45;
  filter: grayscale(0.8);
}

.recall-slot:disabled {
  cursor: default;
}

/* Coach banner: the Renn-led teaching line, apart from the quest tracker and chat. Edges land on the HUD pixel grid (--gp), kept even so a centred line never lands on half a pixel. */

/* Not docked: it must stay above the window it told the player to open, which a dock row's z-index ceiling would prevent. It opens under the top-centre cluster's published edge. */

.coach-banner {
  position: absolute;
  top: round(
    max(11%, var(--safe-top), calc(var(--hud-top-center-bottom, 0px) + var(--hud-gap))),
    var(--gp)
  );
  left: round(50%, var(--gp));
  transform: translateX(round(-50%, var(--gp)));
  display: flex;
  justify-content: center;
  align-items: flex-start;
  pointer-events: none;
  /* WINDOW_Z_CEIL (window-stack.ts): above every HUD and floating window, below interactive overlays. At 40 the auto-opened Skills window painted over the instruction. It also stays over a dealt hand's veil, which has no headline of its own. */
  z-index: 119;
  width: round(
    down,
    min(calc(620px * var(--ui-scale)), calc(100% - 2 * var(--hud-edge))),
    calc(2 * var(--gp))
  );
  max-width: round(down, calc(100% - 2 * var(--hud-edge)), calc(2 * var(--gp)));
  /* A conversation can rise into this lane on short glass; the banner stays between the target and the bottom dock and scrolls its words. */
  max-block-size: max(
    0px,
    calc(
      var(--hud-dock-center-room, 100dvh) - var(--hud-top-center-bottom, 0px) - 2 * var(--hud-gap)
    )
  );
  overflow-y: auto;
  touch-action: pan-y;
  --feedback-enter-x: 0px;
  --feedback-enter-y: calc(-4 * var(--gp));
}

.coach-banner[data-hud-anchor-x='left'] {
  --feedback-enter-x: calc(-4 * var(--gp));
}

.coach-banner.coach-banner--scrolls {
  pointer-events: auto;
}

/* While editing, the banner previews inside the centre scroll rail. */

.hud-layout-editing .coach-banner.hud-layout-preview-flow {
  max-block-size: none;
  max-inline-size: 100%;
  grid-column: 1 / -1;
}

.hud-layout-editing .coach-banner.hud-layout-preview-flow:not(.hud-layout-detached) {
  position: static;
  transform: none;
}

.coach-banner[data-hud-anchor-x='right'] {
  --feedback-enter-x: calc(4 * var(--gp));
}

.coach-banner[data-hud-anchor-y='bottom'] {
  --feedback-enter-y: calc(4 * var(--gp));
}

.coach-banner.coach-banner-enter .coach-banner-card {
  animation: coach-banner-in var(--hud-fold-duration, 180ms) steps(4, jump-end);
}

@keyframes coach-banner-in {
  from {
    opacity: 0;
    transform: translate(var(--feedback-enter-x), var(--feedback-enter-y));
  }
  to {
    opacity: 1;
    transform: translate(0, 0);
  }
}

body.reduce-flashing .coach-banner.coach-banner-enter .coach-banner-card,
body.reduce-motion .coach-banner.coach-banner-enter .coach-banner-card {
  animation: none;
}

.coach-banner-card {
  --coach-portrait: calc(32 * var(--gp));
  position: relative;
  display: grid;
  grid-template-columns: var(--coach-portrait) minmax(0, 1fr);
  align-items: stretch;
  box-sizing: border-box;
  width: 100%;
  min-height: calc(var(--coach-portrait) + 6 * var(--gp));
  padding: calc(2 * var(--gp));
  overflow: hidden;
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
}

.coach-banner[data-hud-anchor-x='right'] .coach-banner-card {
  grid-template-columns: minmax(0, 1fr) var(--coach-portrait);
}

.coach-banner-card--anonymous,
.coach-banner[data-hud-anchor-x='right'] .coach-banner-card--anonymous {
  grid-template-columns: minmax(0, 1fr);
}

/* The presenter has no well: a box round the figure sat as a stray square or stretched thin as the copy wrapped. */

.coach-banner-portrait-frame {
  position: relative;
  align-self: center;
  width: var(--coach-portrait);
  height: var(--coach-portrait);
  overflow: hidden;
}

.coach-banner[data-hud-anchor-x='right'] .coach-banner-portrait-frame {
  grid-column: 2;
  grid-row: 1;
}

.coach-banner-speaking .coach-banner-portrait-frame::after {
  content: '';
  position: absolute;
  inset: auto calc(var(--coach-portrait) / 4) 0;
  height: var(--gp);
  background: var(--pixel-cream);
}

.coach-banner-portrait-frame[hidden],
.coach-banner-heading[hidden] {
  display: none;
}

.coach-banner-portrait {
  width: 100%;
  height: 100%;
}

.coach-banner-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: calc(2 * var(--gp));
  min-width: 0;
  padding: calc(3 * var(--gp)) calc(5 * var(--gp));
}

.coach-banner[data-hud-anchor-x='right'] .coach-banner-copy {
  grid-column: 1;
  grid-row: 1;
  align-items: flex-end;
  text-align: right;
}

.coach-banner-heading {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  min-width: 0;
}

.coach-banner[data-hud-anchor-x='right'] .coach-banner-heading {
  justify-content: flex-end;
}

.coach-banner-name {
  color: var(--accent);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-label);
  line-height: round(up, 1em, calc(2 * var(--gp)));
}

.coach-banner-role {
  overflow-x: clip;
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: round(up, 0.12em, 1px);
  line-height: round(up, 1em, calc(2 * var(--gp)));
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}

.coach-banner-text {
  color: var(--text);
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  font-weight: var(--type-weight-medium);
  line-height: round(1.35em, calc(2 * var(--gp)));
  text-align: left;
  text-shadow: 0 1px 0 var(--pixel-ink);
}

.coach-banner[data-hud-anchor-x='right'] .coach-banner-text {
  text-align: right;
}

/* The words reveal like the dialog's, on a smaller stage: the reveal element drops the dialog page's fixed height and scroll. */

.coach-banner-text .npc-text {
  height: auto;
  min-height: 0;
  max-height: none;
  overflow: visible;
  margin: 0;
  font-size: inherit;
  font-family: inherit;
  line-height: inherit;
  text-align: inherit;
}

/* The input half: keycaps or the touch control's picture as a chip under the sentence, so spoken words never carry a key name. */

.coach-banner-instruction {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(2 * var(--gp)) calc(4 * var(--gp));
  color: var(--accent);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: round(up, 0.04em, 1px);
  line-height: round(up, 1em, calc(2 * var(--gp)));
}

.coach-banner[data-hud-anchor-x='right'] .coach-banner-instruction {
  justify-content: flex-end;
}

.coach-instruction-keys {
  display: inline-flex;
  gap: var(--gp);
}

/* A keycap and a control share one pixel piece; the face and the letter's line are both even HUD pixel heights so the letter centres. */

.coach-instruction-key,
.coach-instruction-control {
  box-sizing: border-box;
  border: var(--gp) solid var(--pixel-ink);
  clip-path: var(--pixel-notch);
}

.coach-instruction-key {
  display: grid;
  place-items: center;
  min-width: calc(12 * var(--gp));
  height: calc(12 * var(--gp));
  padding: 0 calc(2 * var(--gp)) calc(2 * var(--gp));
  background: var(--pixel-dusk);
  box-shadow:
    inset 0 var(--gp) 0 var(--pixel-slate),
    inset 0 calc(-2 * var(--gp)) 0 var(--pixel-night);
  color: var(--pixel-cream);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-label);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  line-height: round(up, 1em, calc(2 * var(--gp)));
}

/* WASD as a keyboard cluster. Every cap is pinned because sparse auto-flow would backfill the empty top corners. Bind order is up, left, down, right. */

.coach-instruction-cluster {
  display: inline-grid;
  grid-template-columns: repeat(3, auto);
  gap: calc(2 * var(--gp));
  justify-items: center;
}

.coach-instruction-cluster .coach-instruction-key:nth-child(1) {
  grid-column: 2;
  grid-row: 1;
}

.coach-instruction-cluster .coach-instruction-key:nth-child(2) {
  grid-column: 1;
  grid-row: 2;
}

.coach-instruction-cluster .coach-instruction-key:nth-child(3) {
  grid-column: 2;
  grid-row: 2;
}

.coach-instruction-cluster .coach-instruction-key:nth-child(4) {
  grid-column: 3;
  grid-row: 2;
}

/* On glass the chip pictures the touch control: the dock command's own icon, so the Bag the coach names is the Bag on the rail. */

.coach-instruction-control {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: calc(14 * var(--gp));
  height: calc(14 * var(--gp));
  background: var(--pixel-night);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-lilac),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

.coach-instruction-control-icon {
  display: block;
  width: calc(10 * var(--gp));
  height: calc(10 * var(--gp));
  object-fit: contain;
  pointer-events: none;
}

.coach-instruction-control[data-control='back'] {
  background-image: url('/assets/hud-close-Bz6Icy_E.webp');
  background-position: center;
  background-repeat: no-repeat;
  background-size: calc(10 * var(--gp)) calc(10 * var(--gp));
}

.coach-instruction-control[data-control='move'] {
  border: 0;
  background: var(--pixel-stick-chip, none);
  box-shadow: none;
  clip-path: none;
}

.coach-instruction-stick-knob {
  display: block;
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  background: var(--pixel-stick-chip-cap, none);
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

body.high-contrast .coach-banner-card {
  background: var(--pixel-ink);
  border-color: var(--accent);
}

@media (max-width: 620px) {
  .coach-banner {
    top: round(max(8%, var(--safe-top)), var(--gp));
    width: round(down, calc(100% - 2 * var(--hud-edge)), calc(2 * var(--gp)));
  }
  .coach-banner-card {
    --coach-portrait: calc(24 * var(--gp));
  }
  .coach-banner-copy {
    padding: calc(2 * var(--gp)) calc(3 * var(--gp));
  }
  .coach-banner-text {
    font-size: var(--type-body-size);
    font-family: var(--type-body-family);
    -webkit-font-smoothing: var(--type-body-smoothing);
  }
}

[data-ui-profile='handheld'] .coach-banner {
  /* A combat lesson is a caption over the stage; wide enough for a short imperative on one line, with the monsters still visible. */
  width: max-content;
  max-width: round(down, min(40vw, 320px), calc(2 * var(--gp)));
  top: round(calc(var(--hud-top-center-bottom, 80px) + var(--hud-gap, 8px)), var(--gp));
}

/* Longer narration takes a wider measure so extra words spend width, not stage height. */

[data-ui-profile='handheld'] .coach-banner.coach-banner-narrative {
  max-width: round(down, min(56vw, 460px), calc(2 * var(--gp)));
}

[data-ui-profile='handheld'][data-shell-state~='npc'] .coach-banner {
  display: none !important;
}

[data-ui-profile='handheld'] .coach-banner-card {
  --coach-portrait: calc(12 * var(--gp));
}

/* The portrait is identity enough; dropping the name/role row leaves the instruction as the only line spending height. */

[data-ui-profile='handheld'] .coach-banner-heading {
  display: none;
}

[data-ui-profile='handheld'] .coach-banner-copy {
  gap: 0;
  padding: var(--gp) calc(3 * var(--gp));
}

[data-ui-profile='handheld'] .coach-banner-text {
  font-size: var(--type-handheld-body-compact-size);
  font-family: var(--type-handheld-body-compact-family);
  -webkit-font-smoothing: var(--type-handheld-body-compact-smoothing);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
}

/* The phone's dialog page fixes its text box at three lines; the banner's reveal takes the plate's height. */

[data-ui-profile='handheld'] .coach-banner-text .npc-text {
  height: auto;
  min-height: 0;
  max-height: none;
  overflow: visible;
  font-size: inherit;
  font-family: inherit;
  line-height: inherit;
}

/* A short landscape desktop can still carry both teaching surfaces, but the
   full portrait-and-byline treatment spends the strip between the target rail
   and a live conversation. Keep the speaker visible and collapse only that
   chrome; the words retain their desktop measure and stay on one line. */

@media (max-height: 640px) {
  [data-ui-profile='desktop'] .coach-banner-card {
    --coach-portrait: calc(16 * var(--gp));
  }
  [data-ui-profile='desktop'] .coach-banner-heading {
    display: none;
  }
  [data-ui-profile='desktop'] .coach-banner-copy {
    gap: 0;
    padding: var(--gp) calc(3 * var(--gp));
  }
}

/* Fold identity: every collapsible HUD surface keeps an anchored core; collapse keeps the surface icon and its critical live state. */

:root {
  --hud-fold-size: max(36px, calc(42px * var(--ui-scale, 1)));
  --hud-fold-inset: max(4px, round(calc(6px * var(--ui-scale, 1)), 1px));
  --hud-fold-shell-size: calc(var(--hud-fold-size) + 2 * var(--hud-fold-inset));
  --hud-fold-reserve-gap: 0px;
  --hud-fold-reserve: calc(var(--hud-fold-shell-size) + var(--hud-fold-reserve-gap));
  --hud-fold-reserve-left: var(--hud-fold-reserve);
  --hud-fold-reserve-right: 0px;
  --hud-fold-reserve-top: var(--hud-fold-reserve);
  --hud-fold-reserve-bottom: 0px;
  --hud-fold-duration: 180ms;
  --hud-fold-fade-duration: 110ms;
  --hud-fold-ease: cubic-bezier(0.2, 0.78, 0.24, 1);
  --hud-fold-offset: 6px;
  --hud-fold-scale: 0.97;
}

@media (pointer: coarse) {
  :root {
    --hud-fold-size: max(44px, calc(42px * var(--ui-scale, 1)));
  }
}

.hud-fold-trigger {
  position: relative;
  isolation: isolate;
  box-sizing: border-box;
  width: var(--hud-fold-size);
  height: var(--hud-fold-size);
  flex: 0 0 var(--hud-fold-size);
  display: grid;
  place-items: center;
  padding: 0;
  overflow: visible;
  border: 0;
  color: var(--muted);
  background: none;
  cursor: var(--cursor-action);
  transition:
    color 120ms ease,
    filter 120ms ease;
  /* The plate's paint. A state repaints these, not the button's outline or shadow, which the plate would cover. */
  --plate-line: var(--pixel-ink);
  --plate-face: var(--pixel-slate);
  --plate-rim: var(--pixel-rim);
}

/* The plate: ink outline, rim and slate face, notched off each corner. Drawn on a pseudo-element so a call's halo (hud-attention.css) can trace the plate alone; the outline is four strips that skip the corner pixels, since a clip would cut that halo. */

.hud-fold-trigger::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border: var(--gp) solid transparent;
  background:
    linear-gradient(var(--plate-line) 0 0) var(--gp) 0 / calc(100% - 2 * var(--gp)) var(--gp)
      no-repeat border-box,
    linear-gradient(var(--plate-line) 0 0) var(--gp) 100% / calc(100% - 2 * var(--gp)) var(--gp)
      no-repeat border-box,
    linear-gradient(var(--plate-line) 0 0) 0 var(--gp) / var(--gp) calc(100% - 2 * var(--gp))
      no-repeat border-box,
    linear-gradient(var(--plate-line) 0 0) 100% var(--gp) / var(--gp) calc(100% - 2 * var(--gp))
      no-repeat border-box,
    var(--plate-face) padding-box;
  box-shadow: var(--plate-rim);
  pointer-events: none;
}

.hud-fold-trigger:hover,
.hud-fold-trigger[aria-expanded='true'] {
  color: var(--text);
  filter: brightness(1.15);
}

.hud-fold-trigger[aria-expanded='true'] {
  --plate-line: var(--accent);
}

.hud-fold-trigger:active {
  filter: brightness(0.92);
}

.hud-fold-trigger:focus-visible {
  outline: none !important;
  box-shadow: none !important;
  --plate-rim:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--focus-ring, #fff0bd);
}

.hud-fold-glyph {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: calc(var(--hud-fold-size) - 8px);
  height: calc(var(--hud-fold-size) - 8px);
  background: transparent;
}

.hud-fold-icon {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: auto;
  pointer-events: none;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.78));
  transition: opacity var(--hud-fold-fade-duration) ease;
}

.hud-fold-icon--compact {
  opacity: 1;
  transform: none;
}

.hud-fold-icon--expanded {
  opacity: 0;
  transform: none;
}

.hud-fold-trigger[aria-expanded='true'] .hud-fold-icon--compact {
  opacity: 0;
  transform: none;
}

.hud-fold-trigger[aria-expanded='true'] .hud-fold-icon--expanded {
  opacity: 1;
  transform: none;
}

/* The shared opposing rail for folded unit and Core identities; each surface supplies its own fill and paint. */

.hud-fold-side-meter {
  position: absolute;
  z-index: 3;
  top: 5px;
  bottom: 5px;
  width: 3px;
  pointer-events: none;
  background: linear-gradient(
    to top,
    var(--hud-fold-meter-paint, var(--muted)) 0 var(--hud-fold-meter, 0%),
    var(--hud-fold-meter-track, rgba(10, 16, 15, 0.9)) var(--hud-fold-meter, 0%) 100%
  );
  box-shadow: 0 0 0 1px rgba(5, 9, 11, 0.84);
}

.hud-fold-side-meter--left {
  left: -3px;
}

.hud-fold-side-meter--right {
  right: -3px;
}

.hud-fold-side-meter[data-hp-band='healthy'] {
  --hud-fold-meter-paint: var(--hud-hp-healthy-line);
}

.hud-fold-side-meter[data-hp-band='hurt'] {
  --hud-fold-meter-paint: var(--hud-hp-hurt-line);
}

.hud-fold-side-meter[data-hp-band='execute'] {
  --hud-fold-meter-paint: var(--hud-hp-execute-line);
}

.hud-fold-surface[data-hud-anchor-x='right'] .hud-fold-side-meter--left {
  right: -3px;
  left: auto;
}

.hud-fold-surface[data-hud-anchor-x='right'] .hud-fold-side-meter--right {
  right: auto;
  left: -3px;
}

.hud-fold-badge {
  position: absolute;
  top: calc(-3 * var(--gp));
  right: calc(-3 * var(--gp));
  z-index: 3;
  display: grid;
  place-items: center;
  min-width: calc(9 * var(--gp));
  height: max(calc(7 * var(--gp)), calc(var(--type-glyph-size) * 1.2 + 2 * var(--gp)));
  box-sizing: border-box;
  padding: 0 calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  color: var(--pixel-ink);
  background: var(--pixel-honey);
  font-size: var(--type-glyph-size);
  font-family: var(--type-glyph-family);
  -webkit-font-smoothing: var(--type-glyph-smoothing);
  font-weight: var(--type-weight-emphasis);
  line-height: 1;
  box-shadow:
    inset 0 var(--gp) 0 var(--pixel-cream),
    inset 0 calc(-1 * var(--gp)) 0 var(--pixel-ochre);
  clip-path: var(--pixel-notch);
  pointer-events: none;
}

/* Rounded up to whole HUD pixels so the right edge and notch stay on the grid. */

@supports (width: calc-size(max-content, size)) {
  .hud-fold-badge:not(.hud-fold-badge--marks) {
    width: calc-size(max-content, round(up, size, var(--gp)));
  }
}

.hud-fold-badge[hidden] {
  display: none;
}

/* A badge with marks is a rack for art; a filled disc behind them muddies their colour. */

.hud-fold-badge--marks {
  gap: 1px;
  grid-auto-flow: column;
  height: auto;
  min-width: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  clip-path: none;
}

.hud-fold-badge-mark {
  width: calc(13px * var(--ui-scale, 1));
  height: calc(13px * var(--ui-scale, 1));
  object-fit: contain;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.85));
}

/* The folded identity carries compact telemetry; expanded surfaces already show it, so the duplicate ring goes. */

.hud-fold-decoration,
.hud-fold-badge {
  transition:
    opacity var(--hud-fold-fade-duration) ease,
    visibility 0s linear;
}

.hud-fold-trigger[aria-expanded='true']
  > .hud-fold-decoration:not(.hud-fold-decoration--persistent),
.hud-fold-trigger[aria-expanded='true'] > .hud-fold-badge {
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--hud-fold-fade-duration) ease,
    visibility 0s linear var(--hud-fold-fade-duration);
}

.hud-fold-surface.hud-fold-anchor-x-right:not([data-hud-anchor-x]) .hud-fold-badge,
.hud-fold-surface[data-hud-anchor-x='right'] .hud-fold-badge {
  right: auto;
  left: calc(-3 * var(--gp));
}

.hud-fold-trigger.attention-arrive {
  animation: hud-fold-attention-arrive 180ms ease-out;
}

.menu-fold-slot {
  display: contents;
}

@keyframes hud-fold-attention-arrive {
  50% {
    filter: brightness(1.4);
  }
}

/* Shared fold geometry: surfaces supply expanded size and layout; motion, clipping, inertness and trigger placement live here. Layout-editor anchors override a surface's dock default. */

.hud-fold-surface {
  /* Room the trigger needs on its own side, zero elsewhere; the anchor decides which corner holds it. Also declared at :root because a surface in a shadow root reads this sheet through its own link first. */
  --hud-fold-reserve: calc(var(--hud-fold-shell-size) + var(--hud-fold-reserve-gap, 0px));
  --hud-fold-reserve-left: var(--hud-fold-reserve);
  --hud-fold-reserve-right: 0px;
  --hud-fold-reserve-top: var(--hud-fold-reserve);
  --hud-fold-reserve-bottom: 0px;
  --hud-fold-trigger-left: var(--hud-fold-inset);
  --hud-fold-trigger-right: auto;
  --hud-fold-trigger-top: var(--hud-fold-inset);
  --hud-fold-trigger-bottom: auto;
  --hud-fold-origin-x: left;
  --hud-fold-origin-y: top;
  --hud-fold-shift-x: calc(-1 * var(--hud-fold-offset));
  --hud-fold-shift-y: calc(-1 * var(--hud-fold-offset));
  --hud-fold-clip-top: 0;
  --hud-fold-clip-right: 100%;
  --hud-fold-clip-bottom: 100%;
  --hud-fold-clip-left: 0;
  position: relative;
  box-sizing: border-box;
  width: var(--hud-fold-expanded-width, var(--hud-fold-shell-size));
  min-width: var(
    --hud-fold-expanded-min-width,
    var(--hud-fold-expanded-width, var(--hud-fold-shell-size))
  );
  height: var(--hud-fold-expanded-height, var(--hud-fold-shell-size));
  min-height: var(
    --hud-fold-expanded-min-height,
    var(--hud-fold-expanded-height, var(--hud-fold-shell-size))
  );
  overflow: visible;
  transition:
    width var(--hud-fold-duration) var(--hud-fold-ease),
    min-width var(--hud-fold-duration) var(--hud-fold-ease),
    height var(--hud-fold-duration) var(--hud-fold-ease),
    min-height var(--hud-fold-duration) var(--hud-fold-ease);
}

/* A railed fold keeps its full expanded slot while collapsed, so that empty area must pass taps through to the world or touch players cannot tap to walk. The trigger and anything visible while folded re-arm themselves. */

.hud-fold-surface.is-collapsed {
  width: var(--hud-fold-shell-size);
  min-width: var(--hud-fold-shell-size);
  height: var(--hud-fold-shell-size);
  min-height: var(--hud-fold-shell-size);
  pointer-events: none;
  background: transparent;
  border: 0;
  box-shadow: none;
}

/* Except while the player arranges the HUD: the widget itself is what gets grabbed. */

.hud-layout-editing .hud-fold-surface.is-collapsed {
  pointer-events: auto;
}

/* Hidden content still measures auto-sized surfaces; fixed-size surfaces reuse their authored expanded dimensions. */

.hud-fold-surface.hud-fold-preserve-rail-slot.hud-railed:not(.hud-layout-detached).is-collapsed {
  width: var(--hud-fold-expanded-width, var(--hud-fold-shell-size));
  min-width: var(
    --hud-fold-expanded-min-width,
    var(--hud-fold-expanded-width, var(--hud-fold-shell-size))
  );
  height: var(--hud-fold-expanded-height, var(--hud-fold-shell-size));
  min-height: var(
    --hud-fold-expanded-min-height,
    var(--hud-fold-expanded-height, var(--hud-fold-shell-size))
  );
}

.hud-fold-surface-trigger {
  position: absolute;
  left: var(--hud-fold-trigger-left);
  right: var(--hud-fold-trigger-right);
  top: var(--hud-fold-trigger-top);
  bottom: var(--hud-fold-trigger-bottom);
  z-index: 8;
  pointer-events: auto;
}

.hud-fold-content {
  opacity: 1;
  visibility: visible;
  transform: translate(0, 0) scale(1);
  transform-origin: var(--hud-fold-origin-x) var(--hud-fold-origin-y);
  /* Open, the content keeps the room a lit piece's halo and hop need; the clip stays an inset so the fold animates it. */
  clip-path: inset(calc(-1 * var(--pixel-halo-reach, 0px)));
  transition:
    opacity var(--hud-fold-fade-duration) ease 45ms,
    transform var(--hud-fold-duration) var(--hud-fold-ease),
    clip-path var(--hud-fold-duration) var(--hud-fold-ease),
    visibility 0s linear;
}

.hud-fold-surface.is-collapsed .hud-fold-content {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translate(var(--hud-fold-shift-x), var(--hud-fold-shift-y))
    scale(var(--hud-fold-scale));
  clip-path: inset(
    var(--hud-fold-clip-top) var(--hud-fold-clip-right) var(--hud-fold-clip-bottom)
      var(--hud-fold-clip-left)
  );
  transition:
    opacity var(--hud-fold-fade-duration) ease,
    transform var(--hud-fold-duration) var(--hud-fold-ease),
    clip-path var(--hud-fold-duration) var(--hud-fold-ease),
    visibility 0s linear var(--hud-fold-duration);
}

.hud-fold-surface.hud-fold-anchor-x-center:not([data-hud-anchor-x]),
.hud-fold-surface[data-hud-anchor-x='center'] {
  --hud-fold-reserve-left: 0px;
  --hud-fold-reserve-right: 0px;
  --hud-fold-trigger-left: calc(50% - var(--hud-fold-size) / 2);
  --hud-fold-origin-x: center;
  --hud-fold-shift-x: 0px;
  --hud-fold-clip-right: 50%;
  --hud-fold-clip-left: 50%;
}

.hud-fold-surface.hud-fold-anchor-x-right:not([data-hud-anchor-x]),
.hud-fold-surface[data-hud-anchor-x='right'] {
  --hud-fold-reserve-left: 0px;
  --hud-fold-reserve-right: var(--hud-fold-reserve);
  --hud-fold-trigger-left: auto;
  --hud-fold-trigger-right: var(--hud-fold-inset);
  --hud-fold-origin-x: right;
  --hud-fold-shift-x: var(--hud-fold-offset);
  --hud-fold-clip-right: 0;
  --hud-fold-clip-left: 100%;
}

.hud-fold-surface[data-hud-anchor-x='left'] {
  --hud-fold-reserve-left: var(--hud-fold-reserve);
  --hud-fold-reserve-right: 0px;
  --hud-fold-trigger-left: var(--hud-fold-inset);
  --hud-fold-trigger-right: auto;
  --hud-fold-origin-x: left;
  --hud-fold-shift-x: calc(-1 * var(--hud-fold-offset));
  --hud-fold-clip-right: 100%;
  --hud-fold-clip-left: 0;
}

.hud-fold-surface.hud-fold-anchor-y-bottom:not([data-hud-anchor-y]),
.hud-fold-surface[data-hud-anchor-y='bottom'] {
  --hud-fold-reserve-top: 0px;
  --hud-fold-reserve-bottom: var(--hud-fold-reserve);
  --hud-fold-trigger-top: auto;
  --hud-fold-trigger-bottom: var(--hud-fold-inset);
  --hud-fold-origin-y: bottom;
  --hud-fold-shift-y: var(--hud-fold-offset);
  --hud-fold-clip-top: 100%;
  --hud-fold-clip-bottom: 0;
}

.hud-fold-surface[data-hud-anchor-y='top'] {
  --hud-fold-reserve-top: var(--hud-fold-reserve);
  --hud-fold-reserve-bottom: 0px;
  --hud-fold-trigger-top: var(--hud-fold-inset);
  --hud-fold-trigger-bottom: auto;
  --hud-fold-origin-y: top;
  --hud-fold-shift-y: calc(-1 * var(--hud-fold-offset));
  --hud-fold-clip-top: 0;
  --hud-fold-clip-bottom: 100%;
}

body.reduce-motion .hud-fold-trigger,
body.reduce-motion .hud-fold-icon,
body.reduce-motion .hud-fold-content,
body.reduce-motion .hud-fold-surface,
body.reduce-motion .hud-fold-decoration,
body.reduce-motion .hud-fold-badge,
.reduce-motion .hud-fold-trigger,
.reduce-motion .hud-fold-icon,
.reduce-motion .hud-fold-content,
.reduce-motion .hud-fold-surface,
.reduce-motion .hud-fold-decoration,
.reduce-motion .hud-fold-badge {
  transition: none !important;
  animation: none !important;
}

body.reduce-flashing .hud-fold-trigger,
.reduce-flashing .hud-fold-trigger {
  animation: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .hud-fold-trigger,
  .hud-fold-icon,
  .hud-fold-content,
  .hud-fold-surface,
  .hud-fold-decoration,
  .hud-fold-badge {
    transition: none !important;
    animation: none !important;
  }
}

body.high-contrast .hud-fold-trigger {
  --plate-line: currentColor;
}

/* Chat and the command dock use the same shell footprint around the trigger. */

.menu-buttons.is-collapsible {
  padding: var(--hud-fold-inset);
}

.menu-buttons.is-collapsible.is-collapsed {
  background: transparent;
  border: 0;
  box-shadow: none;
}

.menu-buttons .menu-collapse-btn.hud-fold-trigger {
  width: var(--hud-fold-size);
  height: var(--hud-fold-size);
  flex-basis: var(--hud-fold-size);
}

.chat-wrap {
  --hud-fold-reserve-gap: 8px;
  --chat-row: var(--hud-fold-size);
  padding: round(calc(8px * var(--ui-scale, 1)), 1px);
}

.chat-wrap.hud-fold-surface:not(.is-collapsed) {
  width: var(--chat-w, calc(340px * var(--ui-scale, 1)));
  min-width: min(64vw, var(--chat-w, calc(340px * var(--ui-scale, 1))));
  height: auto;
  min-height: var(--hud-fold-shell-size);
}

.chat-wrap.is-collapsed {
  width: var(--hud-fold-shell-size);
  min-width: var(--hud-fold-shell-size);
  height: var(--hud-fold-shell-size);
  min-height: var(--hud-fold-shell-size);
  padding: var(--hud-fold-inset);
  background: transparent;
  border: 0;
  border-left: 1px solid transparent;
  box-shadow: none;
}

.chat-collapse-badge[hidden] {
  display: none;
}

.chat-wrap .hud-ticker__line.system {
  color: var(--accent);
}

.chat-wrap .hud-ticker__line.whisper {
  color: #4fd0e0;
}

.chat-wrap .hud-ticker__line.party {
  color: #79d67a;
}

.chat-wrap .hud-ticker__line.guild {
  color: #e2a15d;
}

.chat-wrap .hud-ticker__line.quest {
  color: var(--gold-label);
}

/* Folded, the chat's passing lines stand beside its launcher, on the open side. */

.chat-wrap > .hud-ticker {
  bottom: var(--hud-fold-inset);
  left: calc(var(--hud-fold-shell-size) + 2 * var(--gp));
}

.chat-wrap:not(.is-collapsed) > .hud-ticker {
  display: none;
}

.chat-wrap[data-hud-anchor-x='right'] > .hud-ticker {
  right: calc(var(--hud-fold-shell-size) + 2 * var(--gp));
  left: auto;
  align-items: flex-end;
}

.chat-wrap[data-hud-anchor-y='top'] > .hud-ticker {
  top: var(--hud-fold-inset);
  bottom: auto;
}

.chat-tabs {
  overflow-x: auto;
  touch-action: pan-x pan-y;
}

/* Editing forces every preview on. Keep the centre stack in the measured
   gap below the toolbar, and let scrolling expose its remaining widgets. */

.hud-layout-editing .hud-dock-row--top > .hud-dock--topCenter {
  max-block-size: max(
    0px,
    calc(
      var(--hud-dock-room) - var(--hud-layout-bar-reserve) - 2 * var(--hud-gap) +
        var(--hud-safe-top)
    )
  );
  overflow-y: auto;
  touch-action: pan-y;
  pointer-events: auto;
}

.hud-layout-editing .hud-dock--topCenter .hud-rail--centerPrimary {
  max-block-size: none;
  flex-shrink: 0;
}

.hud-layout-editing .hud-dock--topCenter .hud-layout-widget {
  touch-action: pan-y;
}

/* Reserve at least half the editor's reading area for the top centre stack.
   The bottom previews share the other half instead of growing above the toolbar. */

.hud-layout-editing {
  --hud-editor-bottom-room: max(
    0px,
    calc((100dvh - var(--hud-layout-bar-reserve) - var(--hud-safe-bottom) - 4 * var(--hud-gap)) / 2)
  );
}

.hud-layout-editing .hud-dock--bottomCenter,
[data-ui-profile='handheld'] .hud-layout-editing .hud-dock--bottomLeft {
  max-block-size: var(--hud-editor-bottom-room);
  overflow-y: auto;
  pointer-events: auto;
  touch-action: pan-y;
}

.hud-layout-editing .hud-dock--bottomCenter .hud-rail,
[data-ui-profile='handheld'] .hud-layout-editing .hud-dock--bottomLeft .hud-rail {
  flex-shrink: 0;
}

.hud-layout-editing .hud-dock--bottomCenter .hud-layout-widget {
  touch-action: pan-y;
}

[data-ui-profile='handheld'] .hud-layout-editing [data-hud-widget='interactionPrompts'] {
  touch-action: pan-y;
}

/* The right editor column also forces radar, season, and quests on together.
   Scroll their whole stack instead of starving the quest content of height. */

.hud-layout-editing .hud-dock--topRight {
  overflow-y: auto;
  pointer-events: auto;
  touch-action: pan-y;
}

.hud-layout-editing .hud-dock--topRight .hud-rail--rightPrimary {
  max-block-size: none;
  flex-shrink: 0;
}

.hud-layout-editing
  .hud-dock--topRight
  .hud-rail
  > [data-hud-widget='questTracker'].hud-railed:not(.hud-layout-detached) {
  flex-shrink: 0;
}

.hud-layout-editing .hud-dock--topRight .hud-layout-widget {
  touch-action: pan-y;
}

/* Reserve the launcher outside the scrolling viewport: padding alone lets a
   long tab strip scroll underneath the top corner's trigger. */

.chat-wrap[data-hud-anchor-y='top'] .chat-tabs {
  margin-inline: var(--hud-fold-reserve-left) var(--hud-fold-reserve-right);
  padding-inline: 0;
}

/* A folded surface's passing lines (hud-ticker.ts): a few short plates that
   stand beside or above the launcher and leave on their own. The surface that
   owns the ticker places it; this sheet draws the lines. Also linked inside the
   quest tracker's shadow root. */

.hud-ticker {
  position: absolute;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--gp);
  width: max-content;
  /* A surface with less room narrows it through --hud-ticker-width. */
  max-width: var(
    --hud-ticker-width,
    round(down, min(calc(300px * var(--ui-scale, 1)), 60vw), var(--gp))
  );
  pointer-events: none;
}

.hud-ticker:empty {
  display: none;
}

.hud-ticker__line {
  max-width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  padding: var(--gp) calc(3 * var(--gp));
  border-left: var(--gp) solid color-mix(in srgb, currentColor 60%, transparent);
  background: color-mix(in srgb, var(--pixel-ink, #140e1c) 80%, transparent);
  color: var(--text, #e8e2d2);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: round(1.25em, var(--gp));
  text-overflow: ellipsis;
  text-shadow: 0 1px 0 #000;
  white-space: nowrap;
  animation: hud-ticker-in 160ms steps(2, end) both;
  transition: opacity 240ms steps(2, end);
}

.hud-ticker__line.is-leaving {
  opacity: 0;
}

@keyframes hud-ticker-in {
  /* Two steps over two grid units, so the held frame still sits on the grid. */
  from {
    opacity: 0;
    transform: translateY(calc(2 * var(--gp)));
  }
}

.hud-ticker__line.is-still {
  animation: none;
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  .hud-ticker__line {
    animation: none;
    transition: none;
  }
}

/* Skills/action bar: the cluster is always expanded and carries no fold
   trigger, so the shared fold sheet only lends it the anchored surface
   geometry. The bars themselves, plus the innate rail (Attack/cycle column +
   Recall) standing off the left end — and the same width reserved blank on the
   right, so the bar stack the player aims at sits at the centre of the surface
   box. The railed HUD centres the box; centring the box therefore centres the
   bars. */

.action-bars.hud-fold-surface {
  --hud-fold-expanded-width: round(
    calc(8 * var(--action-bars-slot) + 14 * var(--gp) + 2 * var(--action-bars-innate-rail)),
    2px
  );
  --hud-fold-expanded-min-width: var(--hud-fold-expanded-width);
  --hud-fold-expanded-height: auto;
  --hud-fold-expanded-min-height: var(--hud-fold-shell-size);
  width: var(--hud-fold-expanded-width);
  min-width: var(--hud-fold-expanded-min-width);
  height: var(--hud-fold-expanded-height);
  min-height: var(--hud-fold-expanded-min-height);
}

/* A menu button stays a square big enough for its three-letter key cap. */

.menu-btn {
  min-width: calc(var(--type-glyph-size) * 2 + 8 * var(--gp));
  min-height: calc(var(--type-glyph-size) * 2 + 8 * var(--gp));
}

html:not([data-ui-profile='handheld']) .hud-dock--topLeft .hud-rail--leftPrimary {
  overflow-y: auto;
  flex-shrink: 1;
  display: grid;
  grid-template-columns: max-content minmax(0, max-content);
  place-items: stretch start;
}

/* Buffs sit beside the character frame, so they never push the widgets under it. */

html:not([data-ui-profile='handheld'])
  .hud-dock--topLeft
  .hud-rail--leftPrimary
  > :not([data-hud-widget='statusTray']) {
  grid-column: 1;
}

html:not([data-ui-profile='handheld'])
  .hud-dock--topLeft
  .hud-rail--leftPrimary
  > [data-hud-widget='status'] {
  align-self: start;
}

html:not([data-ui-profile='handheld'])
  .hud-dock--topLeft
  .hud-rail--leftPrimary
  > [data-hud-widget='statusTray'].hud-railed:not(.hud-layout-detached) {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: start;
}

/* The quest list gives ground first, down to its header and a few lines; past
   that the war strip above it scrolls for the rest, so neither leaves the rail.
   That scroll is wheel-only: a folded strip's shifted panel and sub-pixel shrink
   would otherwise draw scrollbars on a strip with nothing hidden. */

:root:not([data-ui-profile='handheld'])
  .hud-dock-row--top
  .hud-rail
  > [data-hud-widget='questTracker'].hud-railed:not(.hud-layout-detached) {
  flex-shrink: 1000;
  min-block-size: calc(var(--hud-fold-shell-size, 44px) + 4 * var(--type-body-size));
}

:root:not([data-ui-profile='handheld'])
  .hud-dock-row--top
  .hud-rail
  > [data-hud-widget='warState'].hud-railed:not(.hud-layout-detached) {
  flex-shrink: 1;
  min-block-size: var(--hud-fold-shell-size, 44px);
  overflow: hidden auto;
  scrollbar-width: none;
}

/* The player and their selected unit wear one frame: a round face in a pixel ring (hud-pixel-rings.ts, drawn for a 32 HUD pixel face), a gold level plate, then the name row and gauges. Both are always open. */

.unit-frame {
  --uf-2: round(calc(2px * var(--ui-scale, 1)), 1px);
  --uf-3: round(calc(3px * var(--ui-scale, 1)), 1px);
  --uf-4: round(calc(4px * var(--ui-scale, 1)), 1px);
  --uf-6: round(calc(6px * var(--ui-scale, 1)), 1px);
  --uf-8: round(calc(8px * var(--ui-scale, 1)), 1px);
  /* One even width for both frames so gauges match in length and a centred frame lands on a whole pixel. Never narrower than "HP 99,999 / 99,999" and its percent at the metadata size; text does not follow the HUD scale. */
  --uf-w: max(
    round(calc(272px * var(--ui-scale, 1)), 2px),
    round(up, calc(var(--uf-face) + var(--uf-gap) + 15 * var(--type-metadata-size)), 2px)
  );
  --uf-gap: round(calc(8px * var(--ui-scale, 1)), 2px);
  --uf-head: max(calc(var(--type-heading-size) * 1.2), round(calc(18px * var(--ui-scale, 1)), 1px));
  --uf-hp: calc(9 * var(--gp));
  --uf-sp: calc(7 * var(--gp));
  --uf-exp: calc(4 * var(--gp));
  --uf-face: calc(32 * var(--gp));
  --uf-face-ring: var(--pixel-ring-face);
  --uf-edge: var(--pixel-honey);
  --uf-face-edge: var(--uf-edge);
  box-sizing: border-box;
  padding: 0 0 var(--uf-4);
  background: transparent;
  border: 0;
  box-shadow: none;
}

.unit-frame-face {
  position: relative;
  flex: 0 0 auto;
  box-sizing: border-box;
  width: var(--uf-face);
  height: var(--uf-face);
}

body.high-contrast .unit-frame {
  --uf-edge: rgba(255, 255, 255, 0.82);
}

.unit-frame-face::before {
  position: absolute;
  top: calc(-1 * var(--gp));
  left: calc(-1 * var(--gp));
  z-index: 2;
  width: var(--gp);
  height: var(--gp);
  content: '';
  color: var(--uf-face-edge);
  box-shadow: var(--uf-face-ring);
  pointer-events: none;
}

.unit-portrait {
  background: #0c1016 center / cover no-repeat;
}

.hud-self-portrait-slot {
  display: contents;
}

.unit-frame-face .unit-portrait {
  position: relative;
  z-index: 1;
  display: block;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border: 0;
  background-color: var(--pixel-night);
  box-shadow: none;
  clip-path: circle(calc(50% - var(--gp)) at 50% 50%);
}

/* The plate overlaps the ring's base by four HUD pixels and grows downward so tall digits never cover the face. */

.unit-frame-level {
  position: absolute;
  top: calc(100% - 4 * var(--gp));
  left: 50%;
  z-index: 3;
  display: grid;
  place-items: center;
  box-sizing: border-box;
  min-width: calc(11 * var(--gp));
  height: max(calc(8 * var(--gp)), calc(var(--type-micro-readable-size) * 1.2 + 2 * var(--gp)));
  padding: 0 calc(2 * var(--gp));
  translate: -50% 0;
  border: var(--gp) solid var(--pixel-ink);
  color: #ffe1a0;
  background: var(--pixel-night);
  font-size: var(--type-micro-readable-size);
  font-family: var(--type-micro-readable-family);
  -webkit-font-smoothing: var(--type-micro-readable-smoothing);
  font-weight: var(--type-weight-emphasis);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  text-shadow: 0 1px 0px #000;
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-honey),
    inset 0 0 0 var(--gp) var(--pixel-ochre);
  clip-path: var(--pixel-notch);
  pointer-events: none;
}

.unit-frame-level[hidden] {
  display: none;
}

.unit-frame-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-width: 0;
}

.status-panel.self-frame {
  width: min(var(--uf-w), calc(100vw - 24px));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.self-frame .hud-self-content {
  display: flex;
  align-items: flex-start;
  gap: var(--uf-gap);
}

/* The frame is a press target that names the player for a helping skill; the panel around it passes the pointer on. */

.self-frame .hud-self-content > * {
  cursor: var(--cursor-action);
  pointer-events: auto;
}

.self-frame.critical {
  --uf-face-edge: var(--danger);
}

.unit-frame-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--uf-8);
  min-width: 0;
  height: var(--uf-head);
}

.hud-character-name:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.hud-character-name,
.target-panel .target-name {
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  font-weight: var(--type-weight-label);
  line-height: var(--uf-head);
  text-overflow: ellipsis;
  text-shadow:
    1px 0 0 #000,
    -1px 0 0 #000,
    0 1px 0 #000,
    0 -1px 0 #000;
  white-space: nowrap;
}

.target-name-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.self-frame .hud-self-hp {
  --gauge-h: var(--uf-hp);
  margin-top: var(--uf-3);
}

/* Absorb appends to HP, shifting inside the track at the end; it matches the HP fill's pixel snapping so a full shield can start at zero. */

.self-frame .hud-self-absorb-fill {
  left: clamp(
    min(var(--gp), calc(var(--absorb-start, 0%) * 10000)),
    round(nearest, var(--absorb-start, 0%), var(--gp)),
    calc(100% - var(--gp))
  );
  z-index: 2;
  background:
    repeating-linear-gradient(
      135deg,
      rgb(255 255 255 / 35%) 0 var(--gp),
      transparent var(--gp) calc(3 * var(--gp))
    ),
    var(--hud-hp-healthy-fill);
  box-shadow: inset var(--gp) 0 0 var(--pixel-ink);
}

.self-frame .hud-self-sp {
  --gauge-h: var(--uf-sp);
  margin-top: var(--uf-2);
}

.self-frame .exp-bar {
  --gauge-h: var(--uf-exp);
  margin-top: var(--uf-3);
}

.target-panel.unit-frame {
  --uf-face-edge: var(--target-tier-edge, var(--uf-edge));
  align-items: flex-start;
  gap: var(--uf-gap);
  width: min(78vw, var(--uf-w));
  min-width: 0;
  max-width: min(78vw, var(--uf-w));
  padding: 0 0 var(--uf-4);
  filter: none;
}

.target-panel .target-head {
  align-items: center;
  height: var(--uf-head);
}

.target-panel.unit-frame .target-head,
.target-panel.unit-frame .target-class {
  text-shadow:
    1px 0 0 #000,
    -1px 0 0 #000,
    0 1px 0 #000,
    0 -1px 0 #000;
}

.target-panel.unit-frame .tgt-class-chip {
  color: color-mix(in srgb, var(--text) 70%, var(--muted));
}

.target-panel.unit-frame .target-dist:not(.oor) {
  color: color-mix(in srgb, var(--text) 62%, var(--muted));
}

.target-panel .target-body > .target-hp {
  --gauge-h: var(--uf-hp);
  margin-top: var(--uf-3);
}

.status-tray:not(.has-statuses):not(.hud-layout-ghost) {
  display: none;
}

[data-ui-profile='handheld'] :is(.self-frame, .target-panel.unit-frame) {
  --uf-face: calc(24 * var(--gp));
  --uf-face-ring: var(--pixel-ring-face-compact);
}

[data-ui-profile='handheld'] .unit-frame {
  --uf-hp: calc(7 * var(--gp));
  --uf-sp: calc(6 * var(--gp));
  --uf-exp: calc(3 * var(--gp));
}

[data-ui-profile='handheld'] .self-frame .exp-bar {
  margin-top: 0;
}

/* Larger text can ask for more width than a handheld has, so each frame stays in its lane and ellipsizes. */

[data-ui-profile='handheld'] .target-panel.unit-frame {
  --uf-lane: max(
    0px,
    calc(100vw - 2 * (var(--hud-thumb-right) + var(--hud-skill-wheel-w) + var(--hud-gap)))
  );
  width: min(78vw, var(--uf-w), var(--uf-lane));
  max-width: min(78vw, var(--uf-w), var(--uf-lane));
}

[data-ui-profile='handheld'] .status-panel.self-frame {
  max-width: 100cqw;
}

[data-ui-profile='handheld'] .status-icon {
  --chip-art: calc(13 * var(--gp));
  min-width: calc(15 * var(--gp));
}

[data-ui-profile='handheld'] .pf-chip:not(.pf-chip-focus) {
  width: calc(6 * var(--gp));
  height: calc(6 * var(--gp));
}

/* An ally's role medallion (hud-role-medallion.ts), on the face's upper right, clear of the level plate. */

.role-medallion {
  --medallion-cells: 16;
  position: absolute;
  top: calc(-2 * var(--gp));
  right: calc(-4 * var(--gp));
  z-index: 3;
  display: grid;
  place-items: center;
  width: calc(var(--medallion-cells) * var(--gp));
  height: calc(var(--medallion-cells) * var(--gp));
  background: var(--role-medallion-ring);
  pointer-events: none;
}

.role-medallion[hidden] {
  display: none;
}

.role-medallion img {
  width: calc((var(--medallion-cells) - 6) * var(--gp));
  height: calc((var(--medallion-cells) - 6) * var(--gp));
  image-rendering: pixelated;
}

.pf-role {
  --medallion-cells: 11;
  top: calc(-4 * var(--gp));
  right: calc(-2 * var(--gp));
}

.pf-role img {
  width: calc((var(--medallion-cells) - 4) * var(--gp));
  height: calc((var(--medallion-cells) - 4) * var(--gp));
}

/* ===== The party =======================================================
   Each ally wears the character's frame at a smaller size: the face with the
   level on its base, the name row, one health gauge, then whatever they carry.
   The face is a smaller ring. The widget box never takes
   the pointer; only the frames do, so a tap between them reaches the world. */

.party-frames {
  /* Never narrower than a twelve-letter name needs beside the face. */
  --uf-party-w: max(
    round(calc(204px * var(--ui-scale, 1)), 1px),
    round(
      up,
      calc(
        14 * var(--gp) + round(calc(6px * var(--ui-scale, 1)), 1px) + 10 * var(--type-heading-size)
      ),
      1px
    )
  );
  display: flex;
  flex-direction: column;
  width: min(var(--uf-party-w), calc(100vw - 24px));
  max-width: 100%;
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
  pointer-events: none;
}

.pf-list {
  display: flex;
  flex-direction: column;
  gap: round(calc(5px * var(--ui-scale, 1)), 1px);
}

/* Preserve access to every ally when the dock shares its height with notices. */

:root:not([data-ui-profile='handheld']) .party-frames .pf-list {
  min-block-size: 0;
  overflow-y: auto;
}

.pf-frame.party-unit {
  --uf-head: max(calc(var(--type-heading-size) * 1.2), round(calc(16px * var(--ui-scale, 1)), 1px));
  --uf-hp: calc(7 * var(--gp));
  /* 14 HUD pixels across: the ring hud-pixel-rings.ts draws for an ally. */
  --uf-face: calc(14 * var(--gp));
  --uf-face-ring: var(--pixel-ring-party-face);
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--uf-6);
  cursor: var(--cursor-action);
  pointer-events: auto;
}

.party-unit .unit-frame-level {
  min-width: calc(9 * var(--gp));
  height: max(calc(6 * var(--gp)), calc(var(--type-micro-readable-size) * 1.2 + 2 * var(--gp)));
  padding: 0 var(--gp);
}

.pf-target {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  color: inherit;
  background: none;
  font: inherit;
  text-align: left;
  cursor: inherit;
}

.pf-target:focus-visible {
  outline: none;
}

.pf-top {
  display: flex;
  align-items: center;
  gap: var(--uf-6);
  min-width: 0;
  height: var(--uf-head);
  text-shadow:
    1px 0 0 #000,
    -1px 0 0 #000,
    0 1px 0 #000,
    0 -1px 0 #000;
}

.pf-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  font-weight: var(--type-weight-label);
  line-height: var(--uf-head);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pf-frame .pf-hp {
  --gauge-h: var(--uf-hp);
  margin-top: var(--uf-2);
}

.pf-frame .pf-buffs {
  gap: var(--uf-2);
  margin-top: var(--uf-3);
}

/* The row is one press target: the gauge and the tiles inside it are read, not
   clicked past, so they keep the row's cursor. The tiles keep their card. */

.pf-frame .pf-chip {
  cursor: inherit;
}

.pf-frame:hover {
  --uf-face-edge: color-mix(in srgb, var(--accent) 70%, var(--uf-edge));
}

.pf-frame:hover .pf-name {
  color: color-mix(in srgb, var(--accent) 35%, var(--text));
}

/* The name takes focus, but the ally is what the player is choosing. */

.pf-frame:has(.pf-target:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.pf-frame.pf-oor {
  opacity: 0.5;
  cursor: var(--cursor-default);
}

.pf-frame.pf-offline {
  opacity: 0.45;
}

/* The crown is 22x14 art pixels on the icon's 32-pixel canvas, drawn at half a HUD pixel each. */

.pf-crown {
  --pf-crown-px: calc(var(--gp) / 2);
  flex: none;
  width: calc(22 * var(--pf-crown-px));
  height: calc(14 * var(--pf-crown-px));
  background: var(--pf-crown) calc(-5 * var(--pf-crown-px)) calc(-9 * var(--pf-crown-px)) /
    calc(32 * var(--pf-crown-px)) no-repeat;
  image-rendering: pixelated;
}

.pf-frame.pf-lowhp,
.pf-frame.pf-dead {
  --uf-face-edge: var(--danger);
}

.pf-frame.pf-lowhp .pf-hp .hud-gauge-fill {
  filter: saturate(1.2) brightness(1.08);
}

.pf-frame.pf-dead .unit-portrait {
  filter: grayscale(1) brightness(0.6);
}

.pf-dead .hud-gauge-label {
  color: #ffd0cc;
  text-transform: uppercase;
}

/* A helping aim is armed: every frame it can land on glows, the character's own
   included when the ability may name the caster. A face already edged red keeps
   that edge: low health is the reason to pick it. */

.party-frames[data-aim='support'] .pf-frame:not(.pf-oor, .pf-offline, .pf-lowhp, .pf-dead),
:root[data-shell-state~='aim-self'] body .self-frame:not(.critical) {
  --uf-face-edge: var(--accent);
}

.party-frames[data-aim='support'] .pf-frame:not(.pf-oor, .pf-offline) .unit-frame-face,
:root[data-shell-state~='aim-self'] body .self-frame .unit-frame-face {
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--accent) 70%, transparent))
    drop-shadow(0 2px 3px rgba(0, 0, 0, 0.72));
}

/* A phone's left column also holds the war strip and the quest tracker, so the
   party shares the buff row: each ally is a small face with their level on its
   base and their health on an upright bar beside it, the way the war emblem
   carries its own. The name and the statuses stay on the row's label and in the
   focus panel. */

@media (max-height: 520px) {
  [data-ui-profile='handheld'] .party-frames {
    width: auto;
    max-width: 100%;
  }

  [data-ui-profile='handheld'] .pf-list {
    flex-flow: row wrap;
    gap: max(4px, round(calc(6px * var(--ui-scale, 1)), 1px));
  }

  [data-ui-profile='handheld'] .pf-frame.party-unit {
    --uf-face: calc(14 * var(--gp));
    --pf-bar-w: calc(3 * var(--gp));
    display: block;
    width: calc(var(--uf-face) + 2px + var(--pf-bar-w));
  }

  [data-ui-profile='handheld'] .party-unit .unit-frame-body {
    position: absolute;
    top: 0;
    left: calc(var(--uf-face) + 2px);
    width: var(--pf-bar-w);
    height: var(--uf-face);
  }

  /* The control covers the whole frame, so a tap anywhere on it lands; its words
     stay for the screen reader. It stays inside the frame: a press area past the
     frame's edge would reach outside the safe area wherever the frame is parked. */
  [data-ui-profile='handheld'] .party-unit .pf-target {
    position: absolute;
    top: 0;
    left: calc(-1 * (var(--uf-face) + 2px));
    z-index: 3;
    width: calc(var(--uf-face) + 2px + var(--pf-bar-w));
    height: calc(var(--uf-face) + var(--uf-4));
  }

  [data-ui-profile='handheld'] .party-unit .pf-top {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* The gauge is laid on its side, so it fills from the bottom up. */
  [data-ui-profile='handheld'] .party-unit .pf-hp {
    --gauge-h: var(--pf-bar-w);
    --gauge-clip: none;
    /* The edge is drawn over the fill; at this width a thicker one is all edge. */
    --gauge-ring-w: 1px;
    position: absolute;
    top: 100%;
    left: 0;
    width: var(--uf-face);
    margin: 0;
    transform-origin: 0 0;
    rotate: -90deg;
  }

  [data-ui-profile='handheld'] .party-unit .pf-hp .hud-gauge-label,
  [data-ui-profile='handheld'] .party-unit .pf-buffs {
    display: none;
  }
}

/* A round radar, always open, with the map's name and the player's cell on a plaque under the
   frame. The disc is one of the few round shapes pixel-chrome.css allows; its frame is a pixel
   ring the radar draws for its own size (minimap.ts), with danger marks and the day/night dial
   in gold sockets set into that ring. The ring is --radar-d across, a whole even number of HUD
   pixels, left edge snapped to a whole screen pixel (--radar-x) so no HUD pixel spans two; the
   disc sits one HUD pixel inside it. */

.minimap-frame {
  --radar-d: round(down, calc(164px * var(--ui-scale, 1)), calc(2 * var(--gp)));
  --radar-x: round(down, calc(50% - var(--radar-d) / 2), 1px);
  --radar-gap: round(calc(5px * var(--ui-scale, 1)), 1px);
  position: relative;
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--radar-gap);
  box-sizing: border-box;
  /* The plaque may run a little wider than the frame so a map's name reads whole. */
  width: max-content;
  min-width: var(--radar-d);
  max-width: min(
    100%,
    max(round(calc(var(--radar-d) * 1.5), 1px), calc(12 * var(--type-label-size)))
  );
  pointer-events: none;
}

.minimap-content {
  position: relative;
  flex: 0 0 auto;
  align-self: flex-start;
  box-sizing: border-box;
  width: calc(var(--radar-d) - 2 * var(--gp));
  height: calc(var(--radar-d) - 2 * var(--gp));
  margin: var(--gp) 0 0 calc(var(--radar-x) + var(--gp));
  overflow: hidden;
  isolation: isolate;
  background: #20372f;
}

/* The disc is cut to a pixel circle, which would clip a focus ring drawn round
   it, so keyboard focus lights the whole radar with the halo instead. */

.minimap-content.minimap-clickable:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}

.minimap-frame:has(.minimap-content.minimap-clickable:focus-visible) {
  filter: var(--pixel-halo);
}

/* The ring's painter: one HUD pixel up and left of the ring, so no ring pixel
   falls under its own box. */

.minimap-frame::before {
  position: absolute;
  top: calc(-1 * var(--gp));
  left: calc(var(--radar-x) - var(--gp));
  z-index: 3;
  width: var(--gp);
  height: var(--gp);
  content: '';
  box-shadow: var(--radar-ring, none);
  pointer-events: none;
}

.minimap-caption {
  position: relative;
  display: grid;
  justify-items: center;
  box-sizing: border-box;
  min-width: calc(var(--radar-d) * 0.7);
  max-width: 100%;
  /* The caption sits clear of the bezel's outer ring. */
  margin-top: round(calc(3px * var(--ui-scale, 1)), 1px);
  padding: calc(2 * var(--gp)) calc(6 * var(--gp));
  color: var(--text);
  /* A gold plate in the ring's own trim: ink outline, a lit gold row, the ochre
     trim, a night face (the level plate's recipe). */
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow:
    inset 0 var(--gp) 0 var(--pixel-honey),
    inset 0 0 0 var(--gp) var(--pixel-ochre);
  clip-path: var(--pixel-notch);
  text-align: center;
  text-shadow: 1px 1px 0 #000;
}

.minimap-caption-name {
  max-width: 100%;
  overflow: hidden;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-label);
  line-height: round(calc(var(--type-label-size) * 1.3), 1px);
  letter-spacing: 0.02em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.minimap-caption-cell {
  color: var(--muted);
  font-size: var(--type-micro-readable-size);
  font-family: var(--type-micro-readable-family);
  -webkit-font-smoothing: var(--type-micro-readable-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
  line-height: round(calc(var(--type-micro-readable-size) * 1.2), 1px);
  white-space: nowrap;
}

/* What this ground does to a player standing on it, worn on the disc's top edge.
   It sits on the frame rather than inside the content, because the content is
   itself the button that opens the world map. */

.minimap-danger-row {
  position: absolute;
  top: calc(-4 * var(--gp));
  left: var(--radar-x);
  z-index: 5;
  display: flex;
  width: var(--radar-d);
  gap: calc(4 * var(--gp));
  justify-content: center;
  pointer-events: none;
}

/* Each mark sits in a socket across the rim's top, either side of the north
   notch. The socket is 14 HUD pixels across (hud-pixel-rings.ts). */

.minimap-danger-row .minimap-danger-mark {
  box-sizing: border-box;
  width: calc(14 * var(--gp));
  height: calc(14 * var(--gp));
  padding: calc(3 * var(--gp));
  background: var(--pixel-socket-mark);
  filter: drop-shadow(0 var(--gp) 0 rgba(0, 0, 0, 0.45));
}

/* The day/night dial rides the rim's upper-left diagonal, centred on the rim,
   in a socket 18 HUD pixels across. */

.minimap-dial {
  --radar-r: calc(var(--radar-d) / 2);
  --dial-at: round(
    down,
    calc(var(--radar-r) - (var(--radar-r) - 3 * var(--gp)) * 0.7071 - 9 * var(--gp)),
    var(--gp)
  );
  position: absolute;
  top: var(--dial-at);
  left: calc(var(--radar-x) + var(--dial-at));
  z-index: 5;
  box-sizing: border-box;
  width: calc(18 * var(--gp));
  height: calc(18 * var(--gp));
  padding: calc(3 * var(--gp));
  background: var(--pixel-socket-dial);
  filter: drop-shadow(0 var(--gp) 0 rgba(0, 0, 0, 0.45));
  pointer-events: none;
}

.minimap-danger-row[hidden] {
  display: none;
}

/* The phone's radar shares its column with the right-thumb stack, so the disc
   is dealt from the short axis and the plaque carries the map's name alone. */

[data-ui-profile='handheld'] .minimap-frame {
  max-width: min(100%, 28vw, max(calc(var(--radar-d) * 1.5), calc(12 * var(--type-label-size))));
  --radar-d: round(
    down,
    min(
      calc(132px * var(--ui-scale, 1)),
      22dvh,
      max(
        44px,
        calc(var(--hud-dock-right-room, 100dvh) - var(--type-label-size) * 1.3 - 12 * var(--gp))
      )
    ),
    calc(2 * var(--gp))
  );
  --radar-gap: round(calc(4px * var(--ui-scale, 1)), 1px);
}

/* The phone's disc is too small to seat the dial beside the marks, so it sits on
   the rim's west side instead. */

[data-ui-profile='handheld'] .minimap-dial {
  top: calc(var(--radar-r) - 9 * var(--gp));
  left: calc(var(--radar-x) - 6 * var(--gp));
}

[data-ui-profile='handheld'] .minimap-caption {
  margin-top: 1px;
  padding: var(--gp) calc(3 * var(--gp));
}

[data-ui-profile='handheld'] .minimap-caption-cell {
  display: none;
}

/* Keep the command chip beside the right-thumb controls. */

[data-ui-profile='handheld'] .hud-dock--bottomRight .hud-rail--bottomRightPrimary {
  flex-direction: row-reverse;
  align-items: flex-end;
}

/* ===== Guild window (guild-window.ts / guild-window-views.ts own these gw-* visuals) =====
   Crest header, info stat tiles, a flat guild-skill card list, and the rank editor,
   drawn in the HUD's pixel material (pixel-chrome.css): ink outlines, flat faces,
   HUD-pixel rules and square tags. */

.gw-guildhead {
  display: flex;
  align-items: center;
  gap: calc(6 * var(--gp));
  padding: var(--gp) var(--gp) calc(5 * var(--gp));
  margin-bottom: calc(2 * var(--gp));
  border-bottom: var(--gp) solid var(--pixel-dusk);
}

/* The crest is a sunk well: an ink outline round the emblem, notched. */

.gw-crest {
  position: relative;
  overflow: hidden;
  width: calc(24 * var(--gp));
  height: calc(24 * var(--gp));
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--type-screen-heading-size);
  font-family: var(--type-screen-heading-family);
  -webkit-font-smoothing: var(--type-screen-heading-smoothing);
  font-weight: var(--type-weight-label);
  color: var(--accent);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  border: var(--gp) solid var(--pixel-ink);
  clip-path: var(--pixel-notch);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.gw-crest-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.gw-crest-img--fallback {
  object-fit: contain;
  padding: calc(3 * var(--gp));
}

.gw-crest.editable {
  cursor: var(--cursor-action);
}

.gw-crest.editable:hover {
  border-color: var(--accent);
}

/* The emblem covers the crest's face, so the focus bracket rides a layer above it. */

.gw-crest:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}

.gw-crest:focus-visible::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  box-shadow: var(--ui-focus-ring) !important;
  pointer-events: none;
}

.gw-crest-file {
  display: none;
}

/* Always-visible camera badge so the master immediately sees the crest is
   editable (click anywhere on the crest to change the emblem). */

.gw-crest-edit {
  position: absolute;
  right: calc(-1 * var(--gp));
  bottom: calc(-1 * var(--gp));
  z-index: 2;
  pointer-events: none;
  min-width: calc(11 * var(--gp));
  height: calc(8 * var(--gp));
  padding: 0 calc(2 * var(--gp));
  line-height: calc(8 * var(--gp));
  font-size: var(--type-glyph-size);
  font-family: var(--type-glyph-family);
  -webkit-font-smoothing: var(--type-glyph-smoothing);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--accent);
  color: var(--pixel-ink);
  box-shadow: calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-ink);
}

.gw-crest.editable:hover .gw-crest-edit {
  transform: translateY(calc(-1 * var(--gp)));
}

.gw-crest.uploading {
  opacity: 0.55;
}

.gw-crest.uploading::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  margin: calc(-5 * var(--gp)) 0 0 calc(-5 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  border-top-color: var(--accent);
  background: var(--pixel-ink);
  animation: ui-spin 0.7s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .gw-crest.uploading::after {
    animation: none;
  }
}

body.reduce-motion .gw-crest.uploading::after {
  animation: none;
}

.gw-guildhead-text {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--gp);
}

.gw-guildname {
  font-size: var(--type-section-heading-size);
  font-family: var(--type-section-heading-family);
  -webkit-font-smoothing: var(--type-section-heading-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--text);
  letter-spacing: 0.3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gw-guildsub {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: var(--muted);
}

/* Guild-master badge in the Info header: a square tag lined in the rank's gold. */

.gw-role-chip {
  margin-left: auto;
  flex: none;
  align-self: flex-start;
  padding: calc(2 * var(--gp)) calc(4 * var(--gp));
  border: var(--gp) solid color-mix(in srgb, var(--gold) 45%, var(--pixel-night));
  color: var(--gold-ink);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: color-mix(in srgb, var(--gold) 10%, var(--pixel-night));
}

/* Info facts share one ledger strip instead of three nested cards. */

.gw-statgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(calc(42 * var(--gp)), 1fr));
  margin-bottom: var(--gp);
  border-block: var(--gp) solid var(--pixel-dusk);
}

.gw-stattile {
  display: flex;
  flex-direction: column;
  gap: var(--gp);
  min-width: 0;
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  border-inline-end: var(--gp) solid var(--pixel-dusk);
}

.gw-stattile:last-child {
  border-inline-end: 0;
}

.gw-stattile:first-child {
  padding-inline-start: var(--gp);
}

.gw-stattile:last-child {
  padding-inline-end: var(--gp);
}

.window.win-guild .gw-expcard,
.window.win-guild .guild-notice {
  border: 0;
  background: transparent;
}

.window.win-guild .gw-expcard {
  margin: 0;
  padding: calc(4 * var(--gp)) var(--gp);
  border-block-end: var(--gp) solid var(--pixel-dusk);
}

.window.win-guild .guild-notice {
  border-inline-start: var(--gp) solid color-mix(in srgb, var(--accent) 42%, var(--pixel-night));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  color: color-mix(in srgb, var(--text) 82%, var(--muted));
  line-height: 1.42;
}

.gw-stattile-label {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.gw-stattile-val {
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gw-expcard {
  margin-bottom: var(--gp);
}

/* Ally/enemy relation chips. The ink is the semantic relation colour, resolved
   at paint time by the guild window (Player Relation Presentation) — the chip
   only derives its line and text from that token. A chip is a square tag. */

.gw-relations {
  display: flex;
  flex-wrap: wrap;
  gap: calc(3 * var(--gp));
}

.gw-relation {
  padding: calc(2 * var(--gp)) calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

.gw-relation.is-ally,
.gw-relation.is-enemy {
  border-color: color-mix(in srgb, var(--gw-relation-ink) 42%, var(--pixel-night));
  color: color-mix(in srgb, var(--gw-relation-ink) 55%, white);
}

/* ===== Guild skills: flat card list (mirrors the abilities catalog) =====
   Each card is a flat night row in the list's well, its slate line down the start. */

.gw-points {
  margin-left: auto;
  padding: var(--gp) calc(4 * var(--gp));
  border: var(--gp) solid color-mix(in srgb, var(--gold) 40%, var(--pixel-night));
  color: var(--gold-label);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
}

.gw-skills {
  gap: calc(3 * var(--gp));
}

.gw-skill-card {
  display: grid;
  grid-template-columns: calc(19 * var(--gp)) minmax(0, 1fr) auto;
  gap: calc(5 * var(--gp));
  align-items: center;
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  border-left: calc(2 * var(--gp)) solid var(--pixel-slate);
  background: var(--pixel-night);
}

.gw-skill-icon {
  width: calc(19 * var(--gp));
  height: calc(19 * var(--gp));
  object-fit: cover;
  box-shadow: 0 0 0 var(--gp) var(--pixel-ink);
}

.gw-skill-copy {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
}

.gw-skill-name {
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gw-skill-facts {
  display: flex;
  flex-wrap: wrap;
  gap: calc(2 * var(--gp));
}

.gw-skill-facts span {
  padding: var(--gp) calc(3 * var(--gp));
  background: var(--pixel-ink);
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

.gw-skill-facts .gw-skill-lv {
  border: var(--gp) solid color-mix(in srgb, var(--gold) 42%, var(--pixel-night));
  background: color-mix(in srgb, var(--gold) 8%, var(--pixel-night));
  color: var(--gold-label);
}

/* The upgrade press is a raised plate in the buff green, notched like the kit's. */

.gw-skill-upgrade {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(3 * var(--gp));
  min-height: calc(15 * var(--gp));
  padding: calc(3 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-buff) 35%, var(--pixel-night));
  color: var(--pixel-cream);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  cursor: var(--cursor-action);
  clip-path: var(--pixel-notch);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-buff),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-ink);
}

.gw-skill-upgrade img {
  width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  object-fit: contain;
}

.gw-skill-upgrade:hover {
  transform: translateY(calc(-1 * var(--gp)));
  background: color-mix(in srgb, var(--pixel-buff) 50%, var(--pixel-night));
}

.gw-skill-upgrade:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

/* ===== Guild ranks: read view + master editor =====
   A rank is a shallow pixel well; the one being edited takes a gold line inside its ink. */

.gw-ranks {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
}

.gw-rank-card {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.gw-rank-card.is-editing {
  background: color-mix(in srgb, var(--gold) 5%, var(--pixel-night));
  box-shadow: inset 0 0 0 var(--gp) color-mix(in srgb, var(--gold) 35%, var(--pixel-night));
}

.gw-rank-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(4 * var(--gp));
}

.gw-rank-name {
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gw-rank-seats {
  flex: none;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.gw-rank-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(4 * var(--gp));
  flex-wrap: wrap;
}

.gw-rank-perms {
  display: flex;
  flex-wrap: wrap;
  gap: calc(2 * var(--gp));
}

.gw-rank-tax {
  flex: none;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

/* Rank name and tax fields are kit fields (ron-field); the seats keep the
   rank editor's own metrics. */

.gw-rank-name-input {
  min-width: 0;
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-medium);
}

.gw-perm-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: calc(3 * var(--gp));
}

.gw-perm-toggle {
  display: inline-flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  padding: calc(2 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  cursor: var(--cursor-action);
}

.gw-perm-toggle input {
  margin: 0;
  accent-color: var(--accent);
}

.gw-perm-toggle.is-on {
  border-color: color-mix(in srgb, var(--gold) 50%, var(--pixel-night));
  color: var(--gold-label);
  background: color-mix(in srgb, var(--gold) 12%, var(--pixel-night));
}

.gw-tax-field {
  display: inline-flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.gw-tax-field input {
  width: calc(29 * var(--gp));
  padding: calc(2 * var(--gp)) calc(3 * var(--gp));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}

.gw-tax-suffix {
  color: var(--muted);
}

.gw-rank-save {
  margin-top: var(--gp);
}

/* Inline member management (master): rank picker + expel, no hidden right-click. */

.guild-member-manage {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
}

.guild-rank-pick ron-select {
  max-width: round(up, calc(108px * var(--type-scale, 1)), var(--gp));
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* The card is on screen only while a death is unresolved, so the layout editor is
   the one place it has to appear on demand: otherwise the surface a player most
   wants to move is the one surface they can never reach. */

.hud-layout-editing .lost-gear {
  display: block;
  min-width: calc(100 * var(--gp));
  min-height: calc(20 * var(--gp));
  pointer-events: auto;
}

/* Screen interaction prompts extracted from game-screen composition. They stack
   in the bottom-centre prompt column, which owns the placement and the gap; each
   strip states only its own look: an opaque night plate sized to its words, an ink
   outline and one HUD pixel of tone inside it, notched. */

.loot-prompt,
.weapon-swap-prompt {
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.loot-prompt:focus-visible,
.weapon-swap-prompt:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.loot-prompt {
  max-width: 100%;
  pointer-events: auto;
  padding: calc(3 * var(--gp)) calc(6 * var(--gp));
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  cursor: var(--cursor-action);
}

.weapon-swap-prompt {
  max-width: 100%;
  pointer-events: auto;
  padding: calc(3 * var(--gp)) calc(7 * var(--gp));
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  cursor: var(--cursor-action);
  box-shadow: inset 0 0 0 var(--gp) var(--gold);
  color: var(--gold-value);
}

.weapon-swap-prompt__icon {
  width: calc(12 * var(--gp));
  height: calc(12 * var(--gp));
  object-fit: contain;
  vertical-align: middle;
  margin-right: calc(3 * var(--gp));
}

/* ===== The centre combat banners ========================================
   Two plates under the target frame: the lockout that holds the character
   (FROZEN 3s) and the warning that an enemy cast is aimed at them. Each is a
   pixel plate in the HUD's one material, the ink outline and the rim with
   notched corners round a night face, and its countdown is the shared gauge
   drawn as a line (.hud-gauge--xs). The fill's paint is the banner's state:
   gold for a lockout, orange or red for a cast by how bad it lands. */

.screen-combat-overlays {
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
}

.screen-combat-overlays__lockout,
.screen-combat-overlays__incoming {
  position: absolute;
  /* Centred on a whole HUD pixel, whatever the viewport's width. */
  left: round(50%, var(--gp));
  z-index: 41;
  box-sizing: border-box;
  /* The plate hugs its label (--banner-text-w, whole pairs of HUD pixels, set by
     screen-combat-overlays.ts), and the bar is never shorter than a glance can
     read. Every edge lands on the HUD pixel grid. */
  width: max(calc(56 * var(--gp)), calc(var(--banner-text-w, 0px) + 12 * var(--gp)));
  max-width: round(
    down,
    calc(100vw - 24px - var(--safe-left) - var(--safe-right)),
    calc(2 * var(--gp))
  );
  padding: calc(3 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
  text-align: center;
  transform: translateX(round(-50%, var(--gp)));
}

/* The label's box is the text's width rounded up to the grid, centred; the text
   sits a whole CSS pixel inset in it, and its line is whole HUD pixels tall. */

.screen-combat-overlays__lockout-label,
.screen-combat-overlays__incoming-label {
  box-sizing: border-box;
  width: var(--banner-text-w, auto);
  max-width: 100%;
  margin-inline: auto;
  padding-inline-start: var(--banner-text-inset, 0px);
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: left;
  white-space: nowrap;
}

.screen-combat-overlays__lockout-label {
  color: var(--gold-value);
  font: var(--type-weight-label) var(--type-title-size) var(--type-title-family);
  -webkit-font-smoothing: var(--type-title-smoothing);
  line-height: var(--type-leading-tight);
  /* Whole-pixel tracking keeps a pixel font's glyphs, and the plate that hugs
     them, on the grid. */
  letter-spacing: round(up, 0.11em, 1px);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.screen-combat-overlays__incoming-label {
  font: var(--type-weight-strong) var(--type-body-size) var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  line-height: var(--type-leading-tight);
  letter-spacing: round(up, 0.055em, 1px);
  text-transform: uppercase;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.screen-combat-overlays__lockout-track,
.screen-combat-overlays__incoming-track {
  margin-top: var(--gp);
}

/* The fill steps a whole HUD pixel at a time. A countdown ticks every 100ms,
   and easing each step would drag it behind. */

.screen-combat-overlays .hud-gauge-fill {
  width: round(down, var(--banner-fill, 0%), var(--gp));
  transition: none;
}

.screen-combat-overlays__lockout-fill {
  background: var(--gold-value);
}

.screen-combat-overlays__announcement {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 520px) {
  /* Reclaim the unused desktop header gutter so the target frame cannot cover
     the off-target incoming-cast lane on short phone viewports. */
  .screen-combat-overlays__incoming {
    top: calc(63 * var(--gp)) !important;
  }
  .screen-combat-overlays__lockout {
    top: calc(82 * var(--gp)) !important;
  }
}

/* A handheld hangs both plates under its top-centre cluster. A cluster that
   stands low (larger text, the layout toolbar over it) lifts a plate back onto
   the glass, over the cluster's foot. */

[data-ui-profile='handheld'] .screen-combat-overlays__incoming {
  --plate-top: round(calc(var(--hud-top-center-bottom, 80px) + var(--hud-gap, 8px)), var(--gp));
}

[data-ui-profile='handheld'] .screen-combat-overlays__lockout {
  --plate-top: round(
    calc(var(--hud-top-center-bottom, 80px) + var(--hud-gap, 8px) + 2 * var(--gp)),
    var(--gp)
  );
}

[data-ui-profile='handheld']
  :is(.screen-combat-overlays__incoming, .screen-combat-overlays__lockout) {
  top: var(--plate-top) !important;
  max-width: round(down, 42vw, calc(2 * var(--gp)));
  translate: 0 min(0px, calc(100dvh - var(--hud-safe-bottom) - var(--plate-top) - 100%));
}

[data-ui-profile='handheld'] .screen-combat-overlays__lockout-label {
  font-size: var(--type-handheld-body-compact-size);
  font-family: var(--type-handheld-body-compact-family);
  -webkit-font-smoothing: var(--type-handheld-body-compact-smoothing);
  letter-spacing: round(up, 0.08em, 1px);
}

/* Death card: scrim and headline use the critical-interruption language, the rest the functional-window language (pixel-chrome.css). */

.death-overlay {
  position: fixed;
  inset: 0;
  /* Full-viewport pointer trap: must stay under every recovery/system surface a dead player still needs,
       or a disconnect after dying strands them. */
  z-index: 40;
  display: none;
  /* The scrim scrolls, not the card, so a card taller than the viewport is not clipped out of reach. */
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: max(calc(12 * var(--gp)), var(--safe-top)) max(calc(12 * var(--gp)), var(--safe-right))
    max(calc(12 * var(--gp)), var(--safe-bottom)) max(calc(12 * var(--gp)), var(--safe-left));
  color: var(--text);
  /* The danger tone every surface on the card derives from. */
  --death-tone: var(--danger);
  --death-ink: color-mix(in srgb, var(--danger) 38%, var(--pixel-cream));
  --death-band-fill: color-mix(in srgb, var(--danger) 8%, var(--pixel-night));
  --death-band-line: color-mix(in srgb, var(--danger) 40%, var(--pixel-dusk));
  /* Flat ink scrim, no blur: a full-viewport filter would blur the scene every frame. */
  background: color-mix(in srgb, var(--pixel-ink) 86%, transparent);
}

.death-overlay:focus {
  outline: none;
}

/* Shared window dragging writes a persisted position here; entry motion stays on the inner card so it never fights it. */

.death-card-positioner {
  position: fixed;
  left: round(down, 50%, 1px);
  top: round(down, 50%, 1px);
  width: min(calc(212 * var(--gp)), calc(100vw - 16px - var(--safe-left) - var(--safe-right)));
  max-height: calc(100dvh - 16px - var(--safe-top) - var(--safe-bottom));
  overflow: hidden;
  transform: translate(round(-50%, 1px), round(-50%, 1px));
}

/* Same ink outline, notch and night face as windows (hud-pixel-window.css); the rim draws over the edge so full-bleed bands run under it. */

/* Only the report scrolls: the header and the stand-up actions stay on screen. */

.death-card {
  position: relative;
  width: 100%;
  max-height: inherit;
  display: flex;
  flex-direction: column;
  text-align: start;
  --muted: var(--pixel-lilac);
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: none;
  clip-path: var(--pixel-notch);
  animation: death-card-in 180ms steps(5, end) both;
}

.death-card::before {
  display: none;
}

.death-card::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 5;
  box-shadow: var(--pixel-rim);
  pointer-events: none;
}

@keyframes death-card-in {
  from {
    opacity: 0;
    transform: translateY(calc(5 * var(--gp)));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.death-card__head {
  position: relative;
  flex-shrink: 0;
  display: grid;
  gap: var(--gp);
  padding: calc(7 * var(--gp)) calc(8 * var(--gp)) calc(6 * var(--gp)) calc(10 * var(--gp));
  user-select: none;
  touch-action: none;
}

.death-card__head::before {
  content: '';
  position: absolute;
  top: calc(9 * var(--gp));
  left: calc(4 * var(--gp));
  width: var(--gp);
  height: calc(10 * var(--gp));
  background: var(--death-tone);
}

/* The handheld title bar is shorter, so its tick rides higher. */

[data-ui-profile='handheld'] .death-card__head::before {
  top: calc(5 * var(--gp));
  height: calc(8 * var(--gp));
}

.death-card__head::after {
  content: '';
  position: absolute;
  left: calc(5 * var(--gp));
  right: calc(5 * var(--gp));
  bottom: 0;
  height: var(--gp);
  background: var(--pixel-dusk);
}

.death-card__title {
  margin: 0;
  font-family: var(--font-display);
  -webkit-font-smoothing: none;
  font-size: var(--type-death-heading-size);
  font-weight: var(--type-weight-strong);
  line-height: round(1.1em, var(--gp));
  letter-spacing: 0.015em;
  color: var(--text);
}

.death-card__killer {
  margin: 0;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-medium);
  letter-spacing: 0.01em;
  color: color-mix(in srgb, var(--death-tone) 42%, var(--text));
}

.death-card__lore {
  margin: var(--gp) 0 0;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-style: italic;
  line-height: round(1.4em, var(--gp));
  color: color-mix(in srgb, var(--text) 62%, var(--pixel-night));
}

.death-card__body {
  display: grid;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
}

/* The header draws its own rule below; a block under it drops its own top rule or the two stack at different insets. */

.death-card__head + .death-card__foot,
.death-card__head + .death-card__body > :first-child,
.death-card__head + .death-card__body > .death-loss > :first-child {
  border-block-start: 0;
}

.death-band {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  min-height: calc(15 * var(--gp));
  margin: 0;
  padding: calc(2 * var(--gp)) calc(7 * var(--gp));
  border-block-end: var(--gp) solid var(--death-band-line);
  background: var(--death-band-fill);
}

.death-band__label {
  min-width: 0;
  color: color-mix(in srgb, var(--death-tone) 46%, var(--text));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-emphasis);
  line-height: round(1.25em, var(--gp));
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* Keeps its own case: a duration would otherwise print "12S". */

.death-band__meta {
  margin-inline-start: auto;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  text-align: end;
}

.death-band__count {
  display: grid;
  place-items: center;
  min-width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  margin-inline-start: auto;
  border: var(--gp) solid var(--death-band-line);
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
}

.death-card__risk {
  position: relative;
  margin: 0;
  padding: calc(4 * var(--gp)) calc(7 * var(--gp)) calc(4 * var(--gp)) calc(8 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-dusk);
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-medium);
  line-height: round(1.4em, var(--gp));
}

/* Opens no card, so it must not carry the help cursor the others do. */

.death-card__risk-mark {
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  margin-inline-end: calc(3 * var(--gp));
  vertical-align: calc(-2 * var(--gp));
  cursor: inherit;
}

.death-card__risk::before {
  content: '';
  position: absolute;
  left: calc(2 * var(--gp));
  top: 0;
  bottom: 0;
  width: var(--gp);
  background: var(--death-tone);
}

.death-loss {
  display: grid;
  min-width: 0;
}

.death-loss__items {
  display: grid;
  gap: calc(2 * var(--gp));
  margin: 0;
  padding: calc(4 * var(--gp)) calc(7 * var(--gp));
  list-style: none;
}

.death-loss__item {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  min-width: 0;
}

.death-loss__slot {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: calc(14 * var(--gp));
  height: calc(14 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.death-loss__icon {
  width: calc(10 * var(--gp));
  height: calc(10 * var(--gp));
  object-fit: contain;
}

.death-loss__name {
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.death-loss__refine {
  flex: 0 0 auto;
  margin-inline-start: auto;
  color: var(--accent);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-label);
  font-variant-numeric: tabular-nums;
}

.death-loss--held {
  position: relative;
  margin: 0;
  padding: calc(4 * var(--gp)) calc(7 * var(--gp)) calc(4 * var(--gp)) calc(8 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-dusk);
  color: color-mix(in srgb, var(--good) 52%, var(--text));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
}

.death-loss--held::before {
  content: '';
  position: absolute;
  left: calc(2 * var(--gp));
  top: 0;
  bottom: 0;
  width: var(--gp);
  background: var(--good);
}

.death-card__foot {
  flex-shrink: 0;
  display: grid;
  gap: calc(4 * var(--gp));
  padding: calc(6 * var(--gp)) calc(7 * var(--gp)) calc(7 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  text-align: center;
}

/* Non-actionable wait: HP hit 0, the authoritative death state has not landed. */

.death-card__pending {
  margin: 0;
  padding: calc(4 * var(--gp)) 0;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-medium);
  color: var(--muted);
  animation: death-pending-breathe 1.8s ease-in-out infinite;
}

@keyframes death-pending-breathe {
  0%,
  100% {
    opacity: 0.72;
  }
  50% {
    opacity: 1;
  }
}

.death-timer {
  display: grid;
  justify-items: center;
}

/* Fixed height: swapping a two-line countdown for one ready word must not move the choices under the cursor. */

.death-timer__readout {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: var(--gp);
  height: calc(25 * var(--gp));
}

.death-timer__label {
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.14em;
}

.death-timer__value {
  font-size: var(--type-hero-size);
  font-family: var(--type-hero-family);
  -webkit-font-smoothing: var(--type-hero-smoothing);
  font-weight: var(--type-weight-label);
  line-height: round(1.05em, var(--gp));
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.death-timer__unit {
  margin-inline-start: var(--gp);
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--muted);
}

.death-timer__ready {
  font-family: var(--font-display);
  -webkit-font-smoothing: none;
  font-size: var(--type-display-size);
  font-weight: var(--type-weight-strong);
  line-height: round(1.1em, var(--gp));
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
}

/* Three HUD pixels tall: ink outline above and below leaves one row of fill. */

.death-timer__track {
  --gauge-h: calc(3 * var(--gp));
  margin-top: calc(2 * var(--gp));
}

.death-timer__fill {
  background: color-mix(in srgb, var(--death-tone) 70%, var(--pixel-slate));
}

.death-timer.is-ready .death-timer__fill {
  background: var(--accent);
}

.death-fatigue {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--gp) calc(4 * var(--gp));
  cursor: help;
}

.death-fatigue__label {
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

.death-fatigue__meter {
  display: inline-flex;
  gap: calc(2 * var(--gp));
}

.death-fatigue__seg {
  width: calc(7 * var(--gp));
  height: calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--pixel-ink);
}

.death-fatigue__seg.is-on {
  border-color: color-mix(in srgb, var(--death-tone) 55%, var(--pixel-ink));
  background: color-mix(in srgb, var(--death-tone) 72%, var(--pixel-lilac));
}

.death-actions {
  display: grid;
  gap: calc(3 * var(--gp));
}

/* A disabled button drops its pointer events, so the tooltip lives on a box behind it. */

.death-action-slot {
  display: block;
}

button.death-action {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(5 * var(--gp));
  width: 100%;
  min-height: calc(19 * var(--gp));
  padding: calc(4 * var(--gp)) calc(7 * var(--gp));
  font-size: var(--type-prose-size);
  font-family: var(--type-prose-family);
  -webkit-font-smoothing: var(--type-prose-smoothing);
  text-align: center;
}

/* Label left, cost tag right; when they no longer fit one line the tag drops to its own. */

.death-action--split {
  justify-content: space-between;
  flex-wrap: wrap;
}

.death-action--split .death-action__label {
  text-align: left;
}

.death-action--split .death-action__tag {
  margin-left: auto;
}

.death-action__label {
  font-size: var(--type-prose-size);
  font-family: var(--type-prose-family);
  -webkit-font-smoothing: var(--type-prose-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(1.2em, var(--gp));
}

.death-action__tag {
  flex: none;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.01em;
  opacity: 0.82;
  white-space: nowrap;
}

/* The locked choice is already dimmed; dimming its tag too would breach the contrast floor. */

button.death-action:disabled .death-action__tag {
  opacity: 1;
}

.death-action--ghost .death-action__tag {
  color: var(--muted);
  opacity: 1;
}

body.high-contrast .death-overlay {
  background: color-mix(in srgb, var(--pixel-ink) 94%, transparent);
}

body.high-contrast .death-card {
  border-color: var(--pixel-lilac);
}

body.high-contrast .death-card__foot {
  background: var(--pixel-ink);
}

/* The white gauge edge would cover the timer's one row of fill. */

body.high-contrast .death-timer__track {
  --gauge-ring: transparent;
}

body.high-contrast .death-action__tag {
  opacity: 1;
}

body.high-contrast .death-fatigue__label,
body.high-contrast .death-timer__label {
  color: var(--pixel-cream);
}

@media (prefers-reduced-motion: reduce) {
  .death-card {
    animation: none;
  }
  .death-card__pending {
    animation: none;
    opacity: 1;
  }
}

body.reduce-motion .death-card,
body.reduce-flashing .death-card {
  animation: none;
}

body.reduce-motion .death-card__pending,
body.reduce-flashing .death-card__pending {
  animation: none;
  opacity: 1;
}

/* Death recap: one control, closed by default, over three groups under the card's bands: the last blow, the damage split, the hits. */

/* Rows keep their own height so a closed recap stays one control, not a slab on handheld. */

.death-recap {
  display: grid;
  align-content: start;
  min-width: 0;
  border-block-start: var(--gp) solid var(--pixel-dusk);
  text-align: start;
}

.death-recap__detail {
  display: grid;
  min-width: 0;
}

.death-recap__blow {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(5 * var(--gp));
  padding: calc(4 * var(--gp)) calc(7 * var(--gp));
}

.death-recap__blow-icon {
  width: calc(17 * var(--gp));
  height: calc(17 * var(--gp));
  padding: var(--gp);
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow: inset 0 0 0 var(--gp) color-mix(in srgb, var(--death-tone) 40%, var(--pixel-dusk));
  clip-path: var(--pixel-notch);
  object-fit: contain;
}

.death-recap__blow-body {
  display: grid;
  gap: var(--gp);
  min-width: 0;
}

.death-recap__blow-name {
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(1.2em, var(--gp));
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.death-recap__blow-hp {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.death-recap__blow-amount {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--gp);
  font-size: var(--type-screen-heading-size);
  font-family: var(--type-screen-heading-family);
  -webkit-font-smoothing: var(--type-screen-heading-smoothing);
  font-weight: var(--type-weight-label);
  line-height: round(1.05em, var(--gp));
  font-variant-numeric: tabular-nums;
  color: var(--death-ink);
}

/* A crit is a square tag so it does not compete with a four-figure number. */

.death-recap__crit {
  padding: 0 calc(2 * var(--gp));
  border: var(--gp) solid color-mix(in srgb, var(--accent) 46%, var(--pixel-night));
  font-size: var(--type-glyph-size);
  font-family: var(--type-glyph-family);
  -webkit-font-smoothing: var(--type-glyph-smoothing);
  font-weight: var(--type-weight-label);
  line-height: calc(6 * var(--gp));
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.death-recap__split {
  display: grid;
  gap: calc(3 * var(--gp));
  padding: calc(4 * var(--gp)) calc(7 * var(--gp)) calc(5 * var(--gp));
}

.death-recap__sources {
  display: grid;
  gap: calc(4 * var(--gp));
  margin: 0;
  padding: 0;
  list-style: none;
}

.death-recap__source {
  display: grid;
  gap: var(--gp);
  min-width: 0;
}

.death-recap__source-head {
  display: flex;
  align-items: baseline;
  gap: calc(4 * var(--gp));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--text);
}

.death-recap__source-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.death-recap__source-amount {
  margin-inline-start: auto;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--text) 82%, var(--muted));
}

.death-recap__source-pct {
  min-width: calc(15 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
  text-align: end;
  color: var(--muted);
}

/* Three HUD pixels leave one row of flat fill inside the ink outline. */

.death-recap__bar {
  --gauge-h: calc(3 * var(--gp));
}

.death-recap__bar-fill {
  background: var(--death-tone);
}

/* A player killer wears the opponent relation colour, resolved at paint time onto --recap-relation-tone; never the self gold. */

.death-recap__source.is-player .death-recap__bar-fill {
  background: var(--recap-relation-tone);
}

.death-recap__abilities {
  display: flex;
  flex-wrap: wrap;
  gap: calc(2 * var(--gp));
}

.death-recap__ability {
  display: inline-flex;
  align-items: center;
  gap: calc(2 * var(--gp));
  min-width: 0;
  padding: var(--gp) calc(2 * var(--gp)) var(--gp) var(--gp);
  border: var(--gp) solid var(--pixel-dusk);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  color: var(--muted);
}

.death-recap__ability-icon {
  width: calc(7 * var(--gp));
  height: calc(7 * var(--gp));
  object-fit: contain;
}

.death-recap__ability-name {
  max-width: calc(54 * var(--gp));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.death-recap__ability-amount {
  font-variant-numeric: tabular-nums;
  font-weight: var(--type-weight-strong);
  color: color-mix(in srgb, var(--text) 80%, var(--pixel-night));
}

.death-recap__earlier {
  margin: 0;
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-medium);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.death-recap__toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(3 * var(--gp));
  min-height: calc(13 * var(--gp));
  margin: calc(4 * var(--gp)) calc(7 * var(--gp));
  padding: var(--gp) calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  font: inherit;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.04em;
  color: var(--muted);
  cursor: var(--cursor-action);
}

.death-recap__toggle:hover {
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-slate);
  color: var(--accent);
}

/* The notch clips anything drawn outside the plate, so focus is the inset bracket. */

.death-recap__toggle:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.death-recap__toggle-caret {
  flex: none;
  width: calc(5 * var(--gp));
  height: calc(3 * var(--gp));
  background: currentcolor;
  clip-path: polygon(
    0 0,
    var(--gp) 0,
    var(--gp) var(--gp),
    calc(2 * var(--gp)) var(--gp),
    calc(2 * var(--gp)) calc(2 * var(--gp)),
    calc(3 * var(--gp)) calc(2 * var(--gp)),
    calc(3 * var(--gp)) var(--gp),
    calc(4 * var(--gp)) var(--gp),
    calc(4 * var(--gp)) 0,
    100% 0,
    100% var(--gp),
    calc(4 * var(--gp)) var(--gp),
    calc(4 * var(--gp)) calc(2 * var(--gp)),
    calc(3 * var(--gp)) calc(2 * var(--gp)),
    calc(3 * var(--gp)) 100%,
    calc(2 * var(--gp)) 100%,
    calc(2 * var(--gp)) calc(2 * var(--gp)),
    var(--gp) calc(2 * var(--gp)),
    var(--gp) var(--gp),
    0 var(--gp)
  );
}

.death-recap__toggle[aria-expanded='true'] .death-recap__toggle-caret {
  transform: scaleY(-1);
}

.death-recap__timeline {
  display: grid;
  gap: var(--gp);
  margin: 0;
  padding: 0;
  max-height: calc(103 * var(--gp));
  overflow-y: auto;
  list-style: none;
}

/* The list scrolls inside the card; a cut edge fades in three hard steps to read as more below. Only a cut list gets it, so the killing blow stays clear. */

.death-recap__timeline.is-scrollable {
  mask-image: linear-gradient(
    180deg,
    #000 calc(100% - 9 * var(--gp)),
    rgb(0 0 0 / 66%) 0 calc(100% - 6 * var(--gp)),
    rgb(0 0 0 / 33%) 0 calc(100% - 3 * var(--gp)),
    transparent 0
  );
}

.death-recap__hit {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--gp) calc(4 * var(--gp));
  padding: calc(2 * var(--gp)) calc(3 * var(--gp));
  background: color-mix(in srgb, var(--pixel-ink) 40%, var(--pixel-night));
}

.death-recap__hit.is-final {
  background: color-mix(in srgb, var(--death-tone) 12%, var(--pixel-night));
  box-shadow: inset var(--gp) 0 0 var(--death-tone);
}

.death-recap__hit-time {
  min-width: calc(27 * var(--gp));
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: var(--muted);
}

.death-recap__hit.is-final .death-recap__hit-time {
  color: color-mix(in srgb, var(--death-tone) 44%, var(--text));
}

.death-recap__hit-icon {
  width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  object-fit: contain;
}

.death-recap__hit-body {
  display: grid;
  min-width: 0;
}

.death-recap__hit-label {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.death-recap__hit-source {
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.death-recap__hit-amount {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--gp));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-label);
  font-variant-numeric: tabular-nums;
  color: var(--death-ink);
}

.death-recap__hit-hp {
  grid-column: 3 / -1;
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
}

/* Three HUD pixels, as the share strips: two would leave no row for the fill. */

.death-recap__hit-hp-bar {
  --gauge-h: calc(3 * var(--gp));
  flex: 1;
}

/* Odd HUD pixel count like the bar beside it, so the bar centres on a whole pixel. */

.death-recap__hit-hp-text {
  min-width: calc(23 * var(--gp));
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  line-height: calc(5 * var(--gp));
  font-variant-numeric: tabular-nums;
  text-align: end;
  color: var(--muted);
}

body.high-contrast .death-recap__ability {
  border-color: var(--pixel-lilac);
  color: var(--pixel-cream);
}

body.high-contrast .death-recap__toggle {
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-lilac);
  color: var(--pixel-cream);
}

body.high-contrast .death-recap__hit:not(.is-final) {
  background: var(--pixel-dusk);
}

/* High contrast's white gauge edge would cover the one row these thin bars fill. */

body.high-contrast .death-recap__bar,
body.high-contrast .death-recap__hit-hp-bar {
  --gauge-ring: transparent;
}

/* Critical interruptions and short-lived screen feedback share one material,
   hierarchy, and 180ms motion language. They stay lighter than a normal window:
   an ink outline and one HUD pixel of tone round a night plate, no rim, while a
   flat dim keeps the world as context. */

.screen-modal {
  display: none;
  position: fixed;
  inset: 0;
  align-items: center;
  justify-content: center;
  padding: max(calc(10 * var(--gp)), var(--safe-top)) max(calc(10 * var(--gp)), var(--safe-right))
    max(calc(10 * var(--gp)), var(--safe-bottom)) max(calc(10 * var(--gp)), var(--safe-left));
  color: var(--text);
  background: color-mix(in srgb, var(--pixel-ink) 78%, transparent);
  animation: screen-modal-scrim-in 180ms ease-out both;
}

/* Session band: above every window, or a window paints over the only card that can recover the session. */

.reconnect-overlay {
  z-index: 400;
}

.kick-overlay {
  z-index: 401;
}

.screen-modal[data-tone='warning'] {
  --screen-modal-tone: var(--accent);
}

.screen-modal[data-tone='danger'] {
  --screen-modal-tone: var(--danger);
  background: color-mix(in srgb, var(--pixel-ink) 84%, transparent);
}

/* The panel spans a whole number of HUD-pixel pairs, so it centres on the grid. */

.screen-modal__panel {
  position: relative;
  width: min(calc(270 * var(--gp)), round(down, calc(100vw - 32px), calc(2 * var(--gp))));
  display: grid;
  justify-items: center;
  gap: calc(5 * var(--gp));
  padding: calc(14 * var(--gp)) calc(16 * var(--gp)) calc(13 * var(--gp));
  overflow: hidden;
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  /* The tone line: one HUD pixel of the modal's tone along the top. */
  box-shadow: inset 0 var(--gp) 0 var(--screen-modal-tone, transparent);
  clip-path: var(--pixel-notch);
  text-align: center;
  animation: screen-modal-panel-in 180ms steps(4, jump-end) both;
}

.screen-modal__signal {
  width: calc(22 * var(--gp));
  height: calc(2 * var(--gp));
  margin-bottom: calc(2 * var(--gp));
  background: var(--screen-modal-tone);
}

/* While the session retries, the signal is a flat ink track with a tone block
   that crosses it a HUD pixel at a time. */

.screen-modal[data-state='reconnecting'] .screen-modal__signal,
.screen-modal[data-state='restarting'] .screen-modal__signal {
  overflow: hidden;
  background: var(--pixel-ink);
}

.screen-modal[data-state='reconnecting'] .screen-modal__signal::after,
.screen-modal[data-state='restarting'] .screen-modal__signal::after {
  content: '';
  display: block;
  width: calc(11 * var(--gp));
  height: 100%;
  background: var(--screen-modal-tone);
  animation: screen-modal-scan 1.15s steps(11, jump-end) infinite alternate;
}

.screen-modal__title {
  margin: 0;
  color: var(--text);
  font-family: var(--font-display);
  -webkit-font-smoothing: none;
  font-size: var(--type-screen-display-size);
  font-weight: var(--type-weight-strong);
  line-height: 1.08;
  letter-spacing: 0.015em;
}

.screen-modal__message {
  max-width: calc(220 * var(--gp));
  min-height: calc(10 * var(--gp));
  margin: 0;
  color: color-mix(in srgb, var(--text) 70%, var(--muted));
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  line-height: 1.48;
}

.screen-modal[data-tone='danger'] .screen-modal__message {
  color: color-mix(in srgb, var(--danger) 42%, var(--text));
}

.screen-modal__actions {
  display: flex;
  justify-content: center;
  gap: calc(5 * var(--gp));
  margin-top: calc(5 * var(--gp));
}

.screen-modal__actions[hidden] {
  display: none;
}

/* A kit button (ui-kit.css) paints itself; this only sizes it. */

.screen-modal__action,
button.screen-modal__action {
  width: auto;
  min-width: calc(63 * var(--gp));
  min-height: calc(19 * var(--gp));
  padding: calc(5 * var(--gp)) calc(9 * var(--gp));
}

/* Map entry is a location title drawn straight over the world, no plate: a hard
   ink outline on the name and a flat accent rule above and below.
   Also the crossing's title card: it sits one band above the warp cover, so the
   destination reads while the screen is still covered for the map build. That is
   why the z-index lives here rather than with the cover. */

.map-banner {
  position: fixed;
  top: round(26%, var(--gp));
  left: round(50%, var(--gp));
  z-index: 45;
  pointer-events: none;
  opacity: 0;
  display: grid;
  place-items: center;
  min-width: min(calc(216 * var(--gp)), round(down, calc(100vw - 32px), calc(2 * var(--gp))));
  padding: calc(8 * var(--gp)) calc(17 * var(--gp));
  color: var(--text);
  font-family: var(--font-display);
  -webkit-font-smoothing: none;
  font-size: var(--type-screen-hero-size);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.025em;
  text-shadow:
    var(--gp) 0 0 var(--pixel-ink),
    calc(-1 * var(--gp)) 0 0 var(--pixel-ink),
    0 var(--gp) 0 var(--pixel-ink),
    0 calc(-1 * var(--gp)) 0 var(--pixel-ink);
  /* It drops in a HUD pixel at a time. */
  transform: translate(round(-50%, var(--gp)), calc(round(-50%, var(--gp)) - 4 * var(--gp)));
  transition:
    opacity 180ms ease,
    transform 180ms steps(4, jump-end);
}

.map-banner::before,
.map-banner::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  width: round(38%, calc(2 * var(--gp)));
  height: var(--gp);
  margin-inline: auto;
  background: var(--accent);
  box-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.map-banner::before {
  top: 0;
}

.map-banner::after {
  bottom: var(--gp);
  background: var(--accent-2);
}

.map-banner.show {
  opacity: 1;
  transform: translate(round(-50%, var(--gp)), round(-50%, var(--gp)));
}

/* The name is the title; the line under it says what the place is for. The line
   is body text at reading width, never a second title — a subtitle set at title
   weight reads as two competing names. */

.map-banner__name {
  line-height: 1.12;
  text-align: center;
}

.map-banner__line {
  max-width: min(calc(280 * var(--gp)), calc(100vw - 64px));
  margin-top: calc(4 * var(--gp));
  color: var(--muted);
  font-size: var(--type-prose-size);
  font-family: var(--type-prose-family);
  -webkit-font-smoothing: var(--type-prose-smoothing);
  font-weight: var(--type-weight-normal);
  letter-spacing: 0;
  line-height: 1.42;
  text-align: center;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  text-wrap: balance;
}

/* An empty line element must not hold open the gap above it. */

.map-banner:not(.has-line) .map-banner__line {
  display: none;
}

/* Broadcasts use a compact local rail: a night plate sized to the message,
   with one HUD pixel of accent along its top. The message is the state; no
   decorative emoji or unexplained badge competes with it. */

.announce-bar {
  top: max(calc(5 * var(--gp)), var(--safe-top));
  right: auto;
  left: round(50%, var(--gp));
  box-sizing: border-box;
  width: max-content;
  max-width: min(calc(310 * var(--gp)), round(down, calc(100vw - 32px), calc(2 * var(--gp))));
  padding: calc(3 * var(--gp)) calc(12 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  color: color-mix(in srgb, var(--accent) 56%, var(--text));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  letter-spacing: 0.018em;
  background: var(--pixel-night);
  box-shadow: inset 0 var(--gp) 0 var(--accent);
  clip-path: var(--pixel-notch);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  transform: translate(round(-50%, var(--gp)), calc(-100% - var(--safe-top) - 6 * var(--gp)));
  transition: transform 180ms steps(4, jump-end);
}

.announce-bar.show {
  transform: translate(round(-50%, var(--gp)), 0);
}

/* A shard taking its place in the world reads in the Awakening's teal, not the
   broadcast rail's gold: the same bar, the world's own voice for a birth. */

.announce-bar.tone-shardborn {
  color: color-mix(in srgb, #7ec8b8 72%, var(--text));
  box-shadow: inset 0 var(--gp) 0 #7ec8b8;
}

@keyframes screen-modal-scrim-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes screen-modal-panel-in {
  from {
    opacity: 0;
    transform: translateY(calc(4 * var(--gp)));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes screen-modal-scan {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(calc(11 * var(--gp)));
  }
}

@media (max-width: 560px) {
  .screen-modal__panel {
    padding: calc(12 * var(--gp)) calc(8 * var(--gp)) calc(11 * var(--gp));
  }

  .screen-modal__title {
    font-size: var(--type-overlay-heading-size);
    font-family: var(--font-display);
  }
  .screen-modal__actions {
    width: 100%;
    flex-direction: column;
  }
  .screen-modal__action,
  button.screen-modal__action {
    width: 100%;
  }

  .map-banner {
    min-width: round(down, calc(100vw - 20px), calc(2 * var(--gp)));
    font-size: var(--type-overlay-heading-size);
    font-family: var(--font-display);
  }
}

@media (prefers-reduced-motion: reduce) {
  .screen-modal,
  .screen-modal__panel,
  .screen-modal[data-state='reconnecting'] .screen-modal__signal::after,
  .screen-modal[data-state='restarting'] .screen-modal__signal::after {
    animation: none;
  }

  .map-banner,
  .announce-bar {
    transition: none;
  }
}

body.reduce-motion .screen-modal,
body.reduce-motion .screen-modal__panel,
body.reduce-motion .screen-modal[data-state='reconnecting'] .screen-modal__signal::after,
body.reduce-motion .screen-modal[data-state='restarting'] .screen-modal__signal::after {
  animation: none;
}

body.reduce-motion .map-banner,
body.reduce-motion .announce-bar {
  transition: none;
}

body.high-contrast .screen-modal {
  background: color-mix(in srgb, var(--pixel-ink) 92%, transparent);
}

body.high-contrast .screen-modal__panel {
  border-color: #c6d1ce;
}

body.high-contrast .screen-modal__message {
  color: var(--text);
}

:root:not([data-shell-state~='broadcast-view']) > .broadcast-mode,
.broadcast-mode.broadcast-connecting {
  background: var(--pixel-ink);
}

/* Authentication expiry and an unprepared character roster must never put account UI on
   stream. The operator can prepare the private profile without ?broadcast=1; capture mode
   shows only this neutral holding card until the world mount is ready. */

:root:not([data-shell-state~='broadcast-view']) > .broadcast-mode > *,
.broadcast-mode.broadcast-connecting > * {
  visibility: hidden !important;
}

.broadcast-holding-card {
  display: none;
}

:root:not([data-shell-state~='broadcast-view']) > .broadcast-mode > .broadcast-holding-card,
.broadcast-mode.broadcast-connecting > .broadcast-holding-card {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: grid;
  place-items: center;
  visibility: visible !important;
  color: color-mix(in srgb, var(--pixel-cream) 84%, var(--pixel-ink));
  background: var(--pixel-ink);
  font-size: var(--type-narrative-lead-size);
  font-family: var(--font-display);
  -webkit-font-smoothing: none;
  letter-spacing: 0.14em;
}

.broadcast-view {
  position: relative;
  overflow: hidden;
}

/* The shadow session uses the complete ordinary HUD. It stays inert locally and the
   server independently rejects every mutating viewer envelope. */

.broadcast-view > :not(#game-canvas):not(.broadcast-overlay) {
  pointer-events: none;
  user-select: none;
}

.broadcast-view .broadcast-player-frame.is-awaiting-broadcast-focus {
  visibility: hidden;
}

.broadcast-view .perf-warning-banner {
  display: none;
}

.broadcast-view #game-canvas {
  pointer-events: none;
  cursor: none !important;
}

.broadcast-overlay {
  position: fixed;
  inset: 0;
  z-index: 1200;
  color: var(--pixel-cream);
  font-family: var(--font-ui);
  -webkit-font-smoothing: none;
  pointer-events: none;
  user-select: none;
}

.broadcast-overlay__signature {
  display: flex;
  align-items: center;
}

/* The stream's signature is a notice plate: a night face sized to its words,
   an ink outline, and one HUD pixel of accent along the top. */

.broadcast-overlay__signature {
  position: absolute;
  right: max(calc(11 * var(--gp)), var(--safe-right));
  bottom: max(calc(10 * var(--gp)), var(--safe-bottom));
  gap: calc(5 * var(--gp));
  padding: calc(3 * var(--gp)) calc(5 * var(--gp));
  background: var(--pixel-night);
  border: var(--gp) solid var(--pixel-ink);
  box-shadow: inset 0 var(--gp) 0 var(--accent);
  clip-path: var(--pixel-notch);
}

/* A square tag with a dusk edge on the plate's flat face. */

.broadcast-overlay__live {
  padding: var(--gp) calc(2 * var(--gp));
  color: color-mix(in srgb, #e1e7eb 88%, var(--pixel-night));
  border: var(--gp) solid var(--pixel-dusk);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.14em;
}

.broadcast-overlay__brand {
  font-size: var(--type-prose-size);
  font-family: var(--type-prose-family);
  -webkit-font-smoothing: var(--type-prose-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.09em;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

/* The pixel grid the isometric world draws on, enforced for the whole
   document UI. Last on purpose: it outranks every rounded or blurred corner
   the sheets above may still carry. */

/* The UI sits on the pixel grid: square corners, no glass blur, nearest-neighbour upscale. Loaded last and installed into every Lit shadow root via typography-shadow.css; owns the HUD grid unit and the small-instrument material. `!important` overrides older sheets from one place. */

*,
*::before,
*::after {
  border-radius: 0 !important;
}

/* Deliberate round elements opt back in: the thumb stick, border spinners, the radar disc and conic loading rings. */

.pixel-round,
.pixel-round::before,
.pixel-round::after,
.virtual-stick-base,
.virtual-stick-knob,
.dgrid-spinner,
.gw-crest.uploading::after {
  border-radius: 50% !important;
}

*,
*::before,
*::after {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}

img,
.status-icon.arted,
.tgt-status-chip,
.pf-chip {
  image-rendering: pixelated;
}

/* Focus is drawn in hard steps: an ink line, then the brass key line. */

*:focus-visible {
  outline: 2px solid var(--bg) !important;
  outline-offset: 0 !important;
  box-shadow: 0 0 0 4px var(--accent) !important;
}

.hot-slot:focus-visible,
.status-icon:focus-visible,
.tgt-status-chip:focus-visible,
.pf-chip:focus-visible {
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--bg),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent) !important;
}

/* Small instruments draw in HUD pixels (--gp, two screen pixels at authored scale; applyUiScale sets it). Gold trim only where the HUD names who or where. */

@property --gp {
  syntax: '<length>';
  inherits: true;
  initial-value: 2px;
}

:root {
  --gp: max(1px, round(calc(2px * var(--ui-scale, 1)), 1px));
  --pixel-ink: #140e1c;
  --pixel-night: #261c34;
  --pixel-dusk: #3e3350;
  --pixel-slate: #5f5870;
  --pixel-lilac: #8d8698;
  --pixel-ochre: #c2862c;
  --pixel-honey: #ffd46b;
  --pixel-cream: #f6eedb;
  --pixel-buff: #7cae4b;
  --pixel-debuff: #d9533a;
  --pixel-rim:
    inset var(--gp) var(--gp) 0 var(--pixel-lilac),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk),
    inset 0 0 0 calc(2 * var(--gp)) var(--pixel-slate);
  /* Each pixel piece loses one pixel at each corner so a one-pixel outline runs unbroken; a deeper cut would expose the interior. */
  --pixel-notch: polygon(
    var(--gp) 0,
    calc(100% - var(--gp)) 0,
    calc(100% - var(--gp)) var(--gp),
    100% var(--gp),
    100% calc(100% - var(--gp)),
    calc(100% - var(--gp)) calc(100% - var(--gp)),
    calc(100% - var(--gp)) 100%,
    var(--gp) 100%,
    var(--gp) calc(100% - var(--gp)),
    0 calc(100% - var(--gp)),
    0 var(--gp),
    var(--gp) var(--gp)
  );
  /* A cue is a halo two HUD pixels round the piece's steps (accent then ink); the piece never clips itself. */
  --pixel-halo: drop-shadow(var(--gp) 0 0 var(--accent))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--accent)) drop-shadow(0 var(--gp) 0 var(--accent))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--accent)) drop-shadow(var(--gp) 0 0 var(--pixel-ink))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--pixel-ink))
    drop-shadow(0 var(--gp) 0 var(--pixel-ink))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--pixel-ink));
  /* Room a lit piece needs round it: the halo's two pixels plus the two the hop lifts it (hud-attention.css). */
  --pixel-halo-reach: calc(4 * var(--gp));
}

/* A small button is a plate; notching a pseudo-element keeps the button unclipped so a halo can stand round it. A state repaints --plate-*. */

.pixel-plate {
  --plate-line: var(--pixel-ink);
  --plate-face: var(--pixel-slate);
  --plate-rim: var(--pixel-rim);
  position: relative;
  isolation: isolate;
  border: 0;
  background: none;
}

.pixel-plate::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border: var(--gp) solid var(--plate-line);
  background: var(--plate-face);
  box-shadow: var(--plate-rim);
  clip-path: var(--pixel-notch);
  pointer-events: none;
}

.pixel-plate:not(:disabled):hover {
  filter: brightness(1.15);
}

.pixel-plate:disabled {
  --plate-face: var(--pixel-night);
  --plate-rim: none;
}

.pixel-plate:focus-visible {
  outline: none !important;
  box-shadow: none !important;
  --plate-rim:
    inset 0 0 0 var(--gp) var(--pixel-ink), inset 0 0 0 calc(2 * var(--gp)) var(--accent);
}

/* A slot's cooldown sweeps inside its well. --hot-cd (1 to 0) is registered so the lock transition animates on-grid; skill cooldown drains down, the global lock drains up as a lighter wash. */

@property --well-line {
  syntax: '<color>';
  inherits: true;
  initial-value: transparent;
}

@property --well-edge {
  syntax: '<color>';
  inherits: true;
  initial-value: transparent;
}

@property --hot-cd {
  syntax: '<number>';
  inherits: false;
  initial-value: 1;
}

.hot-cd {
  position: absolute;
  inset: auto calc(3 * var(--gp)) calc(3 * var(--gp));
  height: round(down, calc(var(--hot-cd) * (100% - 6 * var(--gp))), var(--gp));
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgb(20 14 28 / 72%);
  box-shadow: inset 0 var(--gp) 0 var(--pixel-slate);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  color: #fff;
  text-shadow: 0 1px 0 #000;
  pointer-events: none;
}

.hot-cd--lock {
  inset: calc(3 * var(--gp)) calc(3 * var(--gp)) auto;
  background: rgb(20 14 28 / 34%);
  box-shadow: inset 0 calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  transition: --hot-cd 0.1s linear;
}

/* A content-sized widget rounds up to a whole pixel so pieces below stay on the grid. Zero specificity: any stated height wins. */

@supports (height: calc-size(auto, size)) {
  :where(.hud-railed) {
    height: calc-size(auto, round(up, size, 1px));
  }
}

/* A text-sized chip rounds up to whole HUD pixels, a centred one to an even count so it never lands on half a pixel. */

@supports (width: calc-size(max-content, size)) {
  .hot-key,
  .hot-name,
  .menu-key {
    width: calc-size(max-content, round(up, size, var(--gp)));
  }
  .unit-frame-level,
  .minimap-caption {
    width: calc-size(max-content, round(up, size, calc(2 * var(--gp))));
  }
  .minimap-caption {
    height: calc-size(auto, round(up, size, var(--gp)));
  }
}

/* The HUD's one call to a control, shared by document and Lit shadow roots. The piece stays as it
   rests (face/rim/art never repainted); the call is the material's halo (--pixel-halo) plus a hop in
   whole HUD pixels and a side-to-side shake. A lesson calls every 2s with a brighter ring; a waiting
   choice hops/shakes every 4.8s; a just-arrived command holds still. A component marks a target with
   .hud-attention-target and data-hud-attention; the coach's {key:*} intents name the rest, advancing
   through visible state (dock launcher, Bag/Skills, wearable item, Close) without acting for the player. */

/* A lesson. */

:is(
  [data-hud-attention='lesson'].hud-attention-target,
  [data-hud-attention='lesson'] .hud-attention-target,
  [data-coach-actions~='attack'] .action-bars .action-bars__attack,
  :root:not([data-shell-state~='inventory'])
    [data-coach-actions~='inventory']
    .menu-buttons:not(.is-collapsed)
    .menu-btn[data-menu-id='inventory'],
  :root:not([data-shell-state~='inventory'])
    [data-coach-actions~='inventory']
    .menu-buttons.is-collapsed
    .menu-collapse-btn,
  :root:not([data-shell-state~='skills'])
    [data-coach-actions~='skills']
    .menu-buttons:not(.is-collapsed)
    .menu-btn[data-menu-id='skills'],
  :root:not([data-shell-state~='skills'])
    [data-coach-actions~='skills']
    .menu-buttons.is-collapsed
    .menu-collapse-btn,
  [data-coach-actions~='back'] .win-close.coach-action-target,
  [data-coach-actions~='wear'] .win-inv.is-open .inv-cell--equippable,
  [data-coach-guide] .win-quests .qa-quest-item.is-story .qa-objective-guide,
  .action-bars .hot-slot:is(.coach, .coach-hold, .coach-place):not(.hot-dragging),
  .adv-build-choice.is-place.is-coach-place
) {
  /* An empty slot rests at half strength; the slot a lesson names is fully there. */
  opacity: 1;
  /* !important so the call survives a piece's own hover and focus filters: the
     coached control is often focused exactly while the coach points at it. The
     piece's own light is kept (--hud-attention-light, below). */
  --hud-attention-halo: var(--pixel-halo);
  filter: brightness(calc(var(--hud-attention-light, 1) * var(--hud-attention-flash, 1)))
    var(
      --hud-attention-own-halo,
      var(--hud-attention-halo) var(--hud-attention-ring, brightness(1))
    ) !important;
  animation: var(--hud-attention-motion, hud-attention-call 2s linear infinite);
}

/* A fold trigger's badge and meter hang off its plate, so a halo traced round
   the whole button would bend round them. The plate wears the halo; the button
   keeps the light and the hop. */

.hud-fold-trigger {
  --hud-attention-own-halo: brightness(1);
}

.hud-fold-trigger::before {
  filter: var(--hud-attention-halo, none) var(--hud-attention-ring, brightness(1));
}

/* A lit slot or bag cell stands over its packed neighbours, so its halo is whole. */

.action-bars .hot-slot:is(.coach, .coach-hold, .coach-place),
[data-coach-actions~='wear'] .win-inv.is-open .inv-cell--equippable {
  z-index: 1;
}

/* The move stick's ring is hollow, so a shadow of it would ring its well too. It
   wears the same halo rasterised round its ring (hud-virtual-stick.css), and only
   its base hops, so the thumb's target never moves. */

:root:not([data-shell-state~='window'])
  [data-coach-actions~='move']
  .virtual-stick:not(.active)
  .virtual-stick-base {
  animation: var(--hud-attention-motion, hud-attention-call 2s linear infinite);
}

/* A choice waiting on the player. The folded dock's launcher calls for the
   command hidden inside it. */

:is(
  [data-hud-attention='pending'].hud-attention-target,
  .menu-items .menu-btn.has-attention,
  .menu-buttons.is-collapsed .menu-collapse-btn[data-menu-attention]
) {
  --hud-attention-halo: var(--pixel-halo);
  filter: brightness(calc(var(--hud-attention-light, 1) * var(--hud-attention-flash, 1)))
    var(
      --hud-attention-own-halo,
      var(--hud-attention-halo) var(--hud-attention-ring, brightness(1))
    ) !important;
  animation: var(--hud-attention-motion, hud-attention-call-soft 4.8s linear infinite);
}

/* A dock command whose reveal moment just arrived (onboarding-disclosure.ts). */

.menu-items .menu-btn.is-revealed {
  --hud-attention-halo: var(--pixel-halo);
  filter: brightness(var(--hud-attention-light, 1))
    var(--hud-attention-own-halo, var(--hud-attention-halo)) !important;
}

/* The halo replaces a lit piece's own filter, so the piece's hover and press
   light is carried here instead: brighter under the pointer, dimmer held down.
   Not inherited, so a hovered container never lights what is inside it. */

@property --hud-attention-light {
  syntax: '<number>';
  inherits: false;
  initial-value: 1;
}

:hover:not(:disabled) {
  --hud-attention-light: 1.15;
}

:active:not(:disabled) {
  --hud-attention-light: 0.92;
}

/* The call's lit rings, traced like --pixel-halo: honey while the piece is up,
   cream at the top of the hop, and the third pixel a landing rings out. Fixed
   colours, so they resolve here and inherit into shadow roots. */

:root {
  --hud-attention-halo-lit: drop-shadow(var(--gp) 0 0 var(--pixel-honey))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--pixel-honey))
    drop-shadow(0 var(--gp) 0 var(--pixel-honey))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--pixel-honey))
    drop-shadow(var(--gp) 0 0 var(--pixel-ink))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--pixel-ink))
    drop-shadow(0 var(--gp) 0 var(--pixel-ink))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--pixel-ink));
  --hud-attention-halo-flash: drop-shadow(var(--gp) 0 0 var(--pixel-cream))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--pixel-cream))
    drop-shadow(0 var(--gp) 0 var(--pixel-cream))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--pixel-cream))
    drop-shadow(var(--gp) 0 0 var(--pixel-ink))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--pixel-ink))
    drop-shadow(0 var(--gp) 0 var(--pixel-ink))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--pixel-ink));
  --hud-attention-ring-honey: drop-shadow(var(--gp) 0 0 var(--pixel-honey))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--pixel-honey))
    drop-shadow(0 var(--gp) 0 var(--pixel-honey))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--pixel-honey));
  --hud-attention-ring-accent: drop-shadow(var(--gp) 0 0 var(--accent))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--accent)) drop-shadow(0 var(--gp) 0 var(--accent))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--accent));
}

/* A hop and shake in whole HUD pixels: each step holds until the next, so nothing sits between
   pixels or gets scaled/turned. The piece hops, flashes, rings out as it lands, shakes twice, with
   ring/shake staying inside --pixel-halo-reach. Keyframes swap whole filter pieces
   (--hud-attention-halo/-ring/-flash), which a filter can take between steps without a blend. */

@keyframes hud-attention-call {
  0%,
  40%,
  100% {
    translate: 0 0;
    --hud-attention-halo: var(--pixel-halo);
    --hud-attention-ring: brightness(1);
    --hud-attention-flash: 1;
    animation-timing-function: step-end;
  }
  5% {
    translate: 0 calc(-1 * var(--gp));
    --hud-attention-halo: var(--hud-attention-halo-lit);
    animation-timing-function: step-end;
  }
  9% {
    translate: 0 calc(-2 * var(--gp));
    --hud-attention-halo: var(--hud-attention-halo-flash);
    --hud-attention-flash: 1.12;
    animation-timing-function: step-end;
  }
  15% {
    translate: 0 calc(-1 * var(--gp));
    --hud-attention-halo: var(--hud-attention-halo-lit);
    --hud-attention-flash: 1;
    animation-timing-function: step-end;
  }
  19% {
    translate: 0 0;
    --hud-attention-ring: var(--hud-attention-ring-honey);
    animation-timing-function: step-end;
  }
  22% {
    translate: calc(-1 * var(--gp)) 0;
    animation-timing-function: step-end;
  }
  25% {
    translate: var(--gp) 0;
    --hud-attention-ring: var(--hud-attention-ring-accent);
    animation-timing-function: step-end;
  }
  28% {
    translate: calc(-1 * var(--gp)) 0;
    --hud-attention-ring: brightness(1);
    animation-timing-function: step-end;
  }
  31% {
    translate: var(--gp) 0;
    animation-timing-function: step-end;
  }
  34% {
    translate: 0 0;
    animation-timing-function: step-end;
  }
  62% {
    translate: calc(-1 * var(--gp)) 0;
    --hud-attention-halo: var(--hud-attention-halo-lit);
    animation-timing-function: step-end;
  }
  65% {
    translate: var(--gp) 0;
    animation-timing-function: step-end;
  }
  68% {
    translate: calc(-1 * var(--gp)) 0;
    animation-timing-function: step-end;
  }
  71% {
    translate: 0 0;
    --hud-attention-halo: var(--pixel-halo);
    animation-timing-function: step-end;
  }
}

/* A choice that can wait may stand for the whole session, so its call is only
   the hop and shake: a translate the compositor runs without restyling the page.
   The lit steps above swap custom properties, which restyle every frame, and
   are kept for a lesson's short stay. */

@keyframes hud-attention-call-soft {
  0%,
  15.5%,
  100% {
    translate: 0 0;
    animation-timing-function: step-end;
  }
  2% {
    translate: 0 calc(-1 * var(--gp));
    animation-timing-function: step-end;
  }
  4% {
    translate: 0 calc(-2 * var(--gp));
    animation-timing-function: step-end;
  }
  6% {
    translate: 0 calc(-1 * var(--gp));
    animation-timing-function: step-end;
  }
  8% {
    translate: 0 0;
    animation-timing-function: step-end;
  }
  9.5% {
    translate: calc(-1 * var(--gp)) 0;
    animation-timing-function: step-end;
  }
  11% {
    translate: var(--gp) 0;
    animation-timing-function: step-end;
  }
  12.5% {
    translate: calc(-1 * var(--gp)) 0;
    animation-timing-function: step-end;
  }
  14% {
    translate: var(--gp) 0;
    animation-timing-function: step-end;
  }
}

/* Inherited custom properties cross shadow boundaries, including when the
   preference changes while a lesson is active. The resting halo stays; the hop,
   shake, flash and ring stop. */

:is(.reduce-motion, .reduce-flashing) {
  --hud-attention-motion: none;
}

@media (prefers-reduced-motion: reduce) {
  :root,
  :host {
    --hud-attention-motion: none;
  }
}

/* The profile sheet is deliberately NOT imported here. This bundle is loaded
   before the standalone HUD sheets, so a copy taken from inside it would land
   ahead of the rules it has to outrank. Each entry point loads it itself, after
   everything else. */
/* The window states its own height, so searching cannot make the frame or rows jump. */
.win-body.skill-mode-adventurer,
.adv-active-detail {
  --adv-well-face: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  --adv-well-light: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}
.win-body.skill-mode-adventurer {
  display: grid;
  grid-template-columns: minmax(0, 1fr) round(
      down,
      clamp(calc(132 * var(--gp)), 32%, calc(170 * var(--gp))),
      var(--gp)
    );
  /* Margins, not grid gaps, so empty tab and notice rows cost nothing. */
  grid-template-rows: auto auto minmax(0, 1fr);
  column-gap: calc(5 * var(--gp));
  row-gap: 0;
  width: 100%;
  min-width: 0;
  height: round(down, min(72vh, calc(320 * var(--gp))), calc(2 * var(--gp)));
  /* Beat .win-body's 68vh cap; 72px is the skills window's default top. */
  max-height: round(
    down,
    calc(100vh - 72px - var(--hotbar-h, calc(48 * var(--gp))) - calc(20 * var(--gp) + 8px)),
    calc(2 * var(--gp))
  );
  padding: calc(4 * var(--gp));
  overflow: hidden;
}
.adv-build-tabs {
  grid-row: 1;
  grid-column: 1 / -1;
  margin-bottom: calc(3 * var(--gp));
}
.adv-build-notice {
  grid-row: 2;
  grid-column: 1 / -1;
  margin-bottom: calc(3 * var(--gp));
}
.adv-build-active-pane,
.adv-role-pane {
  grid-row: 3;
  grid-column: 1;
}
.adv-build-panel {
  grid-row: 3;
  grid-column: 2;
}
/* The window-wide reset sits at the end: it refunds both currencies and belongs to neither tab. */
.adv-build-tabs {
  display: flex;
  align-items: stretch;
  gap: calc(3 * var(--gp));
}
.adv-build-tablist {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: round(down, calc((100% - 3 * var(--gp)) / 2), var(--gp));
  grid-auto-columns: minmax(0, 1fr);
  flex: 1 1 auto;
  gap: calc(3 * var(--gp));
  min-width: 0;
}
/* An inactive tab is a sunk well so the active one reads as a raised plate. */
.adv-build-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(3 * var(--gp));
  min-height: calc(16 * var(--gp));
  padding: calc(2 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-label);
  cursor: var(--cursor-action);
}
.adv-build-tab-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.adv-build-tab:hover {
  color: var(--text);
  background: var(--pixel-night);
}
.adv-build-tab.is-active {
  z-index: 1;
  background: var(--pixel-dusk);
  color: var(--text);
  box-shadow:
    inset 0 calc(-2 * var(--gp)) 0 var(--accent),
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) 0 0 var(--pixel-night);
}
.adv-build-tab[data-build-pending] {
  color: var(--text);
}
/* Filled gold means spendable points; only this tab shows the number. */
.adv-build-tab-count {
  display: grid;
  place-items: center;
  flex: none;
  min-width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  padding: 0 calc(2 * var(--gp));
  background: var(--gold);
  color: var(--pixel-ink);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-emphasis);
  font-variant-numeric: tabular-nums;
}
/* Matches tab height; .refund-button is the shared bronze archetype. */
.adv-build-respec-wrap {
  display: inline-flex;
  flex: 0 0 auto;
}
.refund-button.adv-build-respec {
  width: calc-size(max-content, round(up, size, var(--gp)));
  min-height: calc(16 * var(--gp));
  padding: 0 calc(5 * var(--gp));
  white-space: nowrap;
}
.adv-build-notice {
  height: calc-size(auto, round(up, size, var(--gp)));
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-debuff) 14%, var(--pixel-night));
  box-shadow: inset 0 0 0 var(--gp) color-mix(in srgb, var(--pixel-debuff) 50%, var(--pixel-dusk));
  color: #efb2a9;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}
.adv-build-active-pane,
.adv-role-pane {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--gp));
  min-height: 0;
  overflow: hidden;
}
.adv-build-pane-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(3 * var(--gp)) calc(5 * var(--gp));
}
/* One tag: the level that pays the next point. */
.adv-points {
  display: inline-flex;
  align-items: center;
  width: calc-size(max-content, round(up, size, var(--gp)));
  min-width: 0;
  min-height: calc(13 * var(--gp));
  padding: var(--gp) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--pixel-ink);
}
.adv-points-note {
  overflow: hidden;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Sunk wells; the accent line marks an active filter. */
.adv-build-toolbar {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(3 * var(--gp));
}
/* Wide enough that the caret clears "Todas las funciones". */
.adv-build-toolbar ron-select {
  flex: 0 1 auto;
  max-width: calc(176px * var(--type-scale, 1));
}
.adv-build-search {
  position: relative;
  display: flex;
  align-items: center;
  flex: 1 1 round(up, calc(140px * var(--type-scale, 1)), var(--gp));
  min-width: round(up, calc(120px * var(--type-scale, 1)), var(--gp));
}
.adv-build-search::before {
  content: '';
  position: absolute;
  z-index: 1;
  left: calc(4 * var(--gp));
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  pointer-events: none;
  background: url('/assets/hud-search-C2MSQsDv.webp') center / contain no-repeat;
  filter: saturate(0.8) brightness(0.9);
}
.adv-build-search input {
  width: 100%;
  min-width: 0;
  height: calc(14 * var(--gp));
  padding: calc(2 * var(--gp)) calc(5 * var(--gp)) calc(2 * var(--gp)) calc(13 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  color: var(--text);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  outline: none;
}
.adv-build-search input:focus {
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
}
.adv-build-search:focus-within::before {
  filter: saturate(1.1) brightness(1.12);
}
/* Two control heights: 16 HUD px for chrome rows, 19 for list and action bar. */
.adv-build-pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-width: 0;
  width: calc-size(max-content, round(up, size, var(--gp)));
  height: calc(16 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  cursor: var(--cursor-action);
}
.adv-build-toggle {
  padding: 0 calc(6 * var(--gp));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  white-space: nowrap;
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
}
.adv-build-pill:hover {
  background: var(--pixel-night);
}
.adv-build-pill.is-active,
.adv-build-pill:focus-within {
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
}
.adv-build-toggle.is-active {
  color: var(--gold-label);
}
/* A row is identity only; the panel owns every action. */
.adv-active-catalog {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: calc(3 * var(--gp));
}
.adv-role-tab.adv-ability-tab {
  grid-template-columns: calc(16 * var(--gp)) minmax(0, 1fr);
  gap: calc(3 * var(--gp));
  min-height: calc(20 * var(--gp));
  padding: var(--gp) calc(4 * var(--gp)) var(--gp) calc(3 * var(--gp));
  border-color: var(--pixel-dusk);
  background: var(--adv-well-face);
  box-shadow:
    inset var(--gp) 0 0 var(--role-accent),
    var(--adv-well-light);
}
.adv-role-tab.adv-ability-tab:hover,
.adv-role-tab.adv-ability-tab.is-active {
  background: var(--pixel-night);
}
.adv-role-tab.adv-ability-tab.is-active {
  background: color-mix(in srgb, var(--role-accent) 14%, var(--pixel-night));
  box-shadow:
    inset var(--gp) 0 0 var(--role-accent),
    inset 0 0 0 var(--gp) var(--role-accent),
    var(--adv-well-light);
}
.adv-role-tab.adv-ability-tab .adv-role-tab-crest {
  width: calc(16 * var(--gp));
  height: calc(16 * var(--gp));
  border: 0;
  background: none;
  overflow: visible;
}
.adv-role-tab.adv-ability-tab .adv-role-tab-crest img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.adv-active-group .adv-role-tree-head {
  flex: 0 0 auto;
  grid-template-columns: calc(18 * var(--gp)) minmax(0, 1fr);
  min-height: calc(25 * var(--gp));
  padding: calc(3 * var(--gp)) calc(5 * var(--gp));
}
.adv-active-group .adv-role-crest {
  width: calc(18 * var(--gp));
  height: calc(18 * var(--gp));
  border: 0;
  background: none;
  overflow: visible;
}
.adv-active-group .adv-role-crest img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.adv-active-card {
  --adv-card-edge: var(--pixel-slate);
  display: grid;
  grid-template-columns: calc(16 * var(--gp)) minmax(0, 1fr) auto;
  gap: calc(3 * var(--gp));
  align-items: center;
  flex: 0 0 auto;
  height: calc-size(auto, round(up, size, var(--gp)));
  min-height: calc(20 * var(--gp));
  padding: var(--gp) calc(4 * var(--gp)) var(--gp) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--adv-well-face);
  box-shadow:
    inset var(--gp) 0 0 var(--adv-card-edge),
    var(--adv-well-light);
  clip-path: var(--pixel-notch);
  cursor: var(--cursor-action);
}
.adv-active-card:hover {
  background: var(--pixel-night);
  box-shadow:
    inset var(--gp) 0 0 var(--adv-card-edge),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-slate);
}
.adv-active-card.is-selected,
.adv-active-card.is-selected:hover {
  background: color-mix(in srgb, var(--accent) 10%, var(--pixel-night));
  box-shadow:
    inset var(--gp) 0 0 var(--adv-card-edge),
    inset 0 0 0 var(--gp) var(--accent),
    var(--adv-well-light);
}
.adv-active-card.is-learned {
  --adv-card-edge: var(--accent);
}
.adv-active-card.is-available {
  --adv-card-edge: #6fc06a;
}
.adv-active-card.is-granted {
  --adv-card-edge: #7fa8d8;
}
/* The outer state line marks learned, available and item-granted skills; available art is dimmed. */
.adv-active-card.is-available .adv-active-icon {
  opacity: 0.58;
  filter: saturate(0.7);
}
.adv-active-card.is-planned,
.adv-active-card.is-registered {
  opacity: 0.6;
}
.adv-active-card[draggable='true'] {
  cursor: grab;
}
.adv-active-card.is-dragging {
  opacity: 0.55;
  cursor: grabbing;
}
.adv-active-icon {
  width: calc(16 * var(--gp));
  height: calc(16 * var(--gp));
  object-fit: contain;
}
.adv-active-copy {
  display: flex;
  flex-direction: column;
  gap: var(--gp);
  min-width: 0;
}
.adv-active-copy > strong {
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  white-space: nowrap;
}
/* One line is the budget; the panel finishes the sentence. */
.adv-active-description {
  margin: 0;
  overflow: hidden;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: 1.3;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.adv-build-state {
  display: inline-flex;
  justify-content: center;
  padding: var(--gp) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-emphasis);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
.adv-build-state.is-granted {
  border-color: color-mix(in srgb, #7fa8d8 55%, var(--pixel-dusk));
  color: #bcd6f2;
}
/* The card scrolls; the action bar pins to the bottom so the verb stays in frame. */
.adv-build-panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  border: var(--gp) solid var(--pixel-ink);
  background: var(--adv-well-face);
  box-shadow: var(--adv-well-light);
  clip-path: var(--pixel-notch);
}
.adv-build-panel-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
.adv-build-panel-body > .inv-empty {
  padding: calc(7 * var(--gp));
  text-align: center;
}
.adv-build-panel .adv-active-detail {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 0;
  background: none;
  box-shadow: none;
  clip-path: none;
}
/* Opaque, so the card above cannot show through. */
.adv-build-actionbar {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  gap: calc(3 * var(--gp));
  padding: calc(4 * var(--gp));
  border-top: var(--gp) solid var(--pixel-dusk);
  background: var(--adv-well-face);
  box-shadow: var(--adv-well-light);
}
/* Every verb is the same height; colour and order say which to press. */
.adv-build-action-slot {
  display: flex;
  min-width: 0;
}
.adv-build-action-slot .adv-build-choice {
  flex: 1;
  min-height: calc(19 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}
/* Plate on a notched layer so the button is not clipped and a lesson halo can surround it. */
.adv-build-choice {
  --plate-line: var(--pixel-ink);
  --plate-face: var(--pixel-dusk);
  --plate-rim:
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(3 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  border: 0;
  background: none;
  color: var(--text);
  font-weight: var(--type-weight-label);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  cursor: var(--cursor-action);
}
.adv-build-choice::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border: var(--gp) solid var(--plate-line);
  background: var(--plate-face);
  box-shadow: var(--plate-rim);
  clip-path: var(--pixel-notch);
  pointer-events: none;
}
.adv-build-choice-icon {
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  flex: none;
  object-fit: contain;
}
.adv-build-choice:hover:not(:disabled) {
  transform: translateY(calc(-1 * var(--gp)));
}
.adv-build-choice:active:not(:disabled) {
  transform: translateY(0);
}
.adv-build-choice:disabled,
.adv-build-choice[aria-disabled='true'] {
  cursor: not-allowed;
  filter: grayscale(1);
  opacity: 0.42;
}
.adv-build-choice.is-learn {
  --plate-face: color-mix(in srgb, var(--pixel-buff) 40%, var(--pixel-night));
  --plate-rim:
    inset var(--gp) var(--gp) 0 var(--pixel-buff),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-ink);
  color: #d6ffd1;
}
.adv-build-choice.is-place {
  --plate-face: color-mix(in srgb, #5a7ea8 40%, var(--pixel-night));
  --plate-rim:
    inset var(--gp) var(--gp) 0 #5a7ea8,
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-ink);
  color: #cfe4ff;
}
.adv-build-choice.is-refund {
  --plate-face: color-mix(in srgb, var(--pixel-ochre) 30%, var(--pixel-night));
  --plate-rim:
    inset var(--gp) var(--gp) 0 color-mix(in srgb, var(--pixel-ochre) 75%, var(--pixel-night)),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-ink);
  color: #f1d59a;
}
.adv-build-choice.is-learn:hover:not(:disabled) {
  --plate-face: color-mix(in srgb, var(--pixel-buff) 52%, var(--pixel-night));
}
.adv-build-choice.is-refund:hover:not(:disabled) {
  --plate-face: color-mix(in srgb, var(--pixel-ochre) 40%, var(--pixel-night));
}
/* The notch clips outside the pieces, so focus brackets draw inside them. */
.adv-build-choice:focus-visible {
  outline: none !important;
  box-shadow: none !important;
  --plate-rim: var(--ui-focus-ring);
}
.adv-build-tab:focus-visible,
.adv-build-pill:focus-visible,
.adv-active-card:focus-visible,
.adv-role-tab:focus-visible,
.adv-role-node:focus-visible,
.adv-build-search input:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}
/* Same card as the hotbar tooltip and entity reference. */
.adv-active-detail {
  min-height: 0;
  max-height: 100%;
  overflow-y: auto;
  padding: calc(6 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
}
/* The shared tooltip layer is sized for terse tooltips, so the card restates its width and height cap. */
.item-tooltip:has(> .adv-active-detail) {
  width: round(down, min(340px, calc(100vw - 16px)), var(--gp));
  max-width: none;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
}
.item-tooltip > .adv-active-detail {
  max-height: min(84vh, 720px);
}
.adv-active-detail-header {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
}
.adv-active-detail-header > div {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gp) calc(3 * var(--gp));
  min-width: 0;
}
.adv-active-detail-header h3 {
  margin: var(--gp) 0 0;
  color: var(--text);
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  line-height: 1.2;
}
.adv-active-detail-icon {
  width: calc(17 * var(--gp));
  height: calc(17 * var(--gp));
  box-shadow: 0 0 0 var(--gp) var(--pixel-ink);
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}
/* Summary and effects lead the card. Margins are pinned against the UA <p> default. */
.adv-active-detail-summary {
  margin: calc(4 * var(--gp)) 0;
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  line-height: 1.35;
}
.adv-active-effects {
  margin-bottom: calc(4 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp)) calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-buff) 10%, var(--pixel-ink));
  box-shadow: inset var(--gp) 0 0 var(--pixel-buff);
}
.adv-active-effects > strong {
  display: block;
  color: #b7d6a6;
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-emphasis);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}
.adv-active-facts {
  display: flex;
  flex-wrap: wrap;
  gap: calc(2 * var(--gp));
}
.adv-active-facts > span {
  display: inline-flex;
  flex: 0 1 auto;
  align-items: center;
  gap: calc(2 * var(--gp));
  min-width: 0;
  padding: var(--gp) calc(3 * var(--gp)) var(--gp) calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--pixel-ink);
  color: var(--text);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: 1.25;
}
.adv-active-fact-icon {
  flex: 0 0 auto;
  width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}
.adv-active-footprint {
  margin-top: calc(4 * var(--gp));
  overflow: hidden;
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--pixel-ink);
}
.adv-footprint-layer + .adv-footprint-layer {
  border-top: var(--gp) solid var(--pixel-dusk);
}
.adv-footprint-layer > header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(4 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  border-bottom: var(--gp) solid var(--pixel-dusk);
}
.adv-footprint-layer > header strong {
  color: var(--text);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.adv-footprint-layer > header span {
  color: var(--gold-label);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-label);
}
.adv-footprint-content {
  display: grid;
  grid-template-columns: minmax(calc(40 * var(--gp)), 0.72fr) minmax(calc(55 * var(--gp)), 1fr);
  align-items: center;
  gap: calc(4 * var(--gp));
  padding: calc(3 * var(--gp));
}
.adv-footprint-canvas {
  display: block;
  width: 100%;
  min-height: calc(37 * var(--gp));
  border: var(--gp) solid var(--pixel-night);
  background: var(--pixel-ink);
}
.adv-footprint-content > div {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
  min-width: 0;
}
.adv-footprint-content > div strong {
  color: var(--text);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.2;
}
.adv-footprint-content > div span {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: 1.25;
}
.adv-active-mechanics {
  margin: calc(2 * var(--gp)) 0 0;
  padding-left: calc(8 * var(--gp));
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  line-height: 1.35;
}
.adv-active-mechanics li + li {
  margin-top: calc(2 * var(--gp));
}
.adv-active-scales-from {
  margin: calc(3 * var(--gp)) 0 0;
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.adv-active-mechanics::marker,
.adv-active-mechanics li::marker {
  color: var(--pixel-buff);
}
.adv-active-affinity {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(2 * var(--gp));
  padding-top: calc(3 * var(--gp));
  border-top: var(--gp) solid var(--pixel-dusk);
}
.adv-active-affinity strong {
  flex-basis: auto;
  margin-right: var(--gp);
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.adv-active-affinity span {
  padding: var(--gp) calc(3 * var(--gp));
  background: var(--pixel-dusk);
  color: var(--text);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: 1.3;
}
.adv-active-edit-note {
  margin: calc(3 * var(--gp)) 0 0;
  padding: calc(3 * var(--gp));
  background: var(--pixel-ink);
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.3;
}
.adv-mastery-detail-path {
  color: var(--gold-label);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.adv-mastery-trigger {
  color: var(--text);
}
/* The path rail is wide enough for the longest path name; "Physical DPS" truncated at 50px. */
.adv-role-layout {
  display: grid;
  grid-template-columns: minmax(calc(75 * var(--gp)), calc(86 * var(--gp))) minmax(0, 1fr);
  gap: calc(4 * var(--gp));
  flex: 1;
  min-height: 0;
}
.adv-role-rail {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  min-height: 0;
  overflow-y: auto;
  padding: var(--gp) calc(2 * var(--gp)) var(--gp) var(--gp);
}
/* An entry is a shallow well with its path colour down the left edge; --adv-tab-line is the channel a state repaints. */
.adv-role-tab {
  --role-accent: var(--gold);
  /* A third column only when an entry holds a count; a fixed auto column wastes its gap on names. */
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: calc(16 * var(--gp)) minmax(0, 1fr);
  grid-auto-columns: auto;
  align-items: center;
  gap: calc(3 * var(--gp));
  min-height: calc(20 * var(--gp));
  height: calc-size(auto, round(up, size, var(--gp)));
  padding: var(--gp) calc(4 * var(--gp)) var(--gp) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--adv-well-face);
  color: var(--text);
  cursor: var(--cursor-action);
  text-align: left;
  box-shadow:
    inset 0 0 0 var(--gp) var(--adv-tab-line, transparent),
    inset var(--gp) 0 0 var(--role-accent),
    var(--adv-well-light);
  clip-path: var(--pixel-notch);
}
.adv-role-tab:hover {
  background: var(--pixel-night);
}
.adv-role-tab.is-active {
  --adv-tab-line: var(--role-accent);
  background: color-mix(in srgb, var(--role-accent) 14%, var(--pixel-night));
}
.adv-role-tab-crest {
  display: grid;
  place-items: center;
  width: calc(16 * var(--gp));
  height: calc(16 * var(--gp));
}
.adv-role-tab-crest img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.adv-role-tab-body {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
  min-width: 0;
}
.adv-role-tab-title {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: calc(3 * var(--gp));
}
.adv-role-tab-body strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-label);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
}
/* The window's one progress shape: filled is held, hollow is room left under a ceiling. */
.adv-role-tab-pips {
  display: flex;
  gap: var(--gp);
  min-height: calc(2 * var(--gp));
}
.adv-role-tab-pips i {
  flex: none;
  width: round(
    down,
    calc((100% - (var(--adv-pip-slots, 6) - 1) * var(--gp)) / var(--adv-pip-slots, 6)),
    var(--gp)
  );
  height: calc(2 * var(--gp));
  background: var(--pixel-dusk);
}
.adv-role-tab-pips i.is-on {
  background: var(--role-accent);
}
/* The card is as tall as its content, capped at the pane, so short paths leave no empty card. */
.adv-role-tree-view {
  --role-accent: var(--gold);
  align-self: start;
  display: flex;
  flex-direction: column;
  height: calc-size(auto, round(up, size, var(--gp)));
  max-height: 100%;
  min-height: 0;
  overflow: hidden;
  border: var(--gp) solid var(--pixel-ink);
  background: var(--adv-well-face);
  box-shadow:
    inset 0 calc(2 * var(--gp)) 0 var(--role-accent),
    var(--adv-well-light);
  clip-path: var(--pixel-notch);
}
.adv-role-tree-head {
  display: grid;
  grid-template-columns: calc(18 * var(--gp)) minmax(0, 1fr);
  align-items: center;
  gap: calc(4 * var(--gp));
  height: calc-size(auto, round(up, size, var(--gp)));
  min-height: calc(25 * var(--gp));
  padding: calc(3 * var(--gp)) calc(5 * var(--gp));
  border-bottom: var(--gp) solid var(--pixel-dusk);
}
/* Rows take only the height their two lines need; a 1fr here stretched six rungs across the card. */
.adv-role-nodes {
  display: grid;
  grid-auto-rows: max-content;
  align-content: start;
  row-gap: calc(9 * var(--gp));
  margin: 0;
  padding: calc(3 * var(--gp)) calc(3 * var(--gp)) calc(5 * var(--gp));
  list-style: none;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
/* Same palette as the role medallion (role-blend.ts); stays distinct under common colour-vision deficiencies. */
.adv-role-tree--tank {
  --role-accent: #6fb4dc;
}
.adv-role-tree--physical_dps {
  --role-accent: #9e2c34;
}
.adv-role-tree--magical_dps {
  --role-accent: #6a4aa8;
}
.adv-role-tree--healer {
  --role-accent: #bcd86a;
}
.adv-role-medallion {
  position: static;
  flex: none;
}
.adv-role-crest {
  display: grid;
  place-items: center;
  width: calc(18 * var(--gp));
  height: calc(18 * var(--gp));
}
.adv-role-crest img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.adv-role-identity {
  display: flex;
  flex-direction: column;
  gap: var(--gp);
  min-width: 0;
}
.adv-role-identity strong {
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
}
.adv-role-identity small {
  color: var(--muted);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.25;
}
/* A node is one row tall. The next purchasable node is marked on its emblem; the panel holds the button. The step above stands outside the box, so nothing clips. */
.adv-role-node {
  position: relative;
  display: grid;
  grid-template-columns: calc(16 * var(--gp)) minmax(0, 1fr);
  align-items: center;
  gap: calc(3 * var(--gp));
  min-height: calc(20 * var(--gp));
  padding: var(--gp) calc(4 * var(--gp)) var(--gp) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--adv-well-face);
  box-shadow:
    inset var(--gp) 0 0 var(--role-accent),
    var(--adv-well-light);
  cursor: var(--cursor-action);
}
/* The step from the rung above: a line and arrowhead that light once that step is taken. */
.adv-role-node + .adv-role-node::before,
.adv-role-node + .adv-role-node::after {
  content: '';
  position: absolute;
  background: var(--adv-step, var(--pixel-dusk));
}
.adv-role-node + .adv-role-node::before {
  left: calc(11 * var(--gp));
  top: calc(-9 * var(--gp));
  width: var(--gp);
  height: calc(4 * var(--gp));
}
.adv-role-node + .adv-role-node::after {
  left: calc(9 * var(--gp));
  top: calc(-5 * var(--gp));
  width: calc(5 * var(--gp));
  height: calc(3 * var(--gp));
  clip-path: polygon(
    0 0,
    100% 0,
    100% var(--gp),
    calc(100% - var(--gp)) var(--gp),
    calc(100% - var(--gp)) calc(2 * var(--gp)),
    calc(100% - 2 * var(--gp)) calc(2 * var(--gp)),
    calc(100% - 2 * var(--gp)) 100%,
    calc(2 * var(--gp)) 100%,
    calc(2 * var(--gp)) calc(2 * var(--gp)),
    var(--gp) calc(2 * var(--gp)),
    var(--gp) var(--gp),
    0 var(--gp)
  );
}
.adv-role-node.is-learned + .adv-role-node {
  --adv-step: var(--role-accent);
}
/* The next purchasable step is drawn lighter than the ones behind it. */
.adv-role-node.is-learned + .adv-role-node.is-available {
  --adv-step: color-mix(in srgb, var(--role-accent) 60%, var(--pixel-cream));
}
.adv-role-node.is-learned {
  background: color-mix(in srgb, var(--role-accent) 10%, var(--adv-well-face));
}
.adv-role-node.is-available:hover,
.adv-role-node.is-learned:hover {
  background: color-mix(in srgb, var(--role-accent) 16%, var(--adv-well-face));
}
.adv-role-node.is-selected {
  border-color: var(--role-accent);
  background: color-mix(in srgb, var(--role-accent) 18%, var(--adv-well-face));
}
.adv-role-node.is-locked {
  opacity: 0.48;
  filter: saturate(0.4);
}
.adv-role-icon {
  display: grid;
  place-items: center;
  width: calc(16 * var(--gp));
  height: calc(16 * var(--gp));
}
.adv-role-icon > img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.adv-role-copy {
  display: flex;
  flex-direction: column;
  gap: var(--gp);
  min-width: 0;
}
.adv-role-copy > strong {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}
.adv-role-copy > span {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: 1.25;
}
/* Squeezed window: below 620px the panel goes under the list and keeps its pinned action bar. */
@media (max-width: 900px) {
  .win-body.skill-mode-adventurer {
    grid-template-columns: minmax(0, 1fr) round(
        down,
        clamp(calc(119 * var(--gp)), 34%, calc(150 * var(--gp))),
        var(--gp)
      );
  }
  .adv-role-layout {
    grid-template-columns: minmax(calc(64 * var(--gp)), calc(74 * var(--gp))) minmax(0, 1fr);
  }
}
@media (max-width: 620px) {
  .win-body.skill-mode-adventurer {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1.35fr) minmax(0, 1fr);
    row-gap: calc(4 * var(--gp));
  }
  .adv-build-active-pane,
  .adv-role-pane {
    grid-row: 3;
    grid-column: 1;
  }
  .adv-build-panel {
    grid-row: 4;
    grid-column: 1;
  }
  .adv-role-layout {
    grid-template-columns: minmax(calc(56 * var(--gp)), calc(66 * var(--gp))) minmax(0, 1fr);
  }
}
/* The body keeps overflow hidden against the shared handheld rule; a scrolling body would carry the pinned action bar off screen. */
[data-ui-profile='handheld'] .win-skills .win-body.skill-mode-adventurer {
  height: auto;
  max-height: none;
  padding: calc(4 * var(--gp));
  overflow: hidden;
}
/* 17 HUD px, not the 44px chrome floor, which would spend a fifth of the shortest glass on one row. */
[data-ui-profile='handheld'] .skill-mode-adventurer .adv-build-tab {
  min-height: calc(17 * var(--gp));
}
[data-ui-profile='handheld'] .skill-mode-adventurer .adv-build-pill {
  height: calc(17 * var(--gp));
}
[data-ui-profile='handheld'] .skill-mode-adventurer .adv-build-notice {
  padding: calc(2 * var(--gp)) calc(4 * var(--gp));
}
/* Acts sit side by side to give the card above its row back. */
[data-ui-profile='handheld'] .adv-build-actionbar {
  flex-direction: row;
  padding: calc(3 * var(--gp));
}
[data-ui-profile='handheld'] .adv-build-action-slot {
  flex: 1;
}
[data-ui-profile='handheld'] .adv-build-action-slot:first-child:not(:last-child) {
  flex: 0 0 round(down, calc((100% - 3 * var(--gp)) / 2), var(--gp));
}
[data-ui-profile='handheld'] .adv-build-action-slot .adv-build-choice {
  min-height: calc(20 * var(--gp));
}
/* On a 390px glass the group head repeats the lit rail entry and costs two list rows. */
[data-ui-profile='handheld'] .skill-mode-adventurer .adv-role-tree-head {
  display: none;
}
/* The panel scroller takes vertical panning back from the pinned play shell. */
[data-ui-profile='handheld'] .adv-build-panel .adv-active-detail {
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
}
/* The catalog's chrome keeps its content height and wraps within its column.
   Reading size is independent of the window's HUD geometry. */
.skill-mode-adventurer .adv-build-pane-head {
  flex-shrink: 0;
  min-width: 0;
}
.skill-mode-adventurer .adv-role-layout {
  grid-template-rows: minmax(0, 1fr);
}
.skill-mode-adventurer .adv-build-toolbar {
  min-width: 0;
  max-width: 100%;
}
.skill-mode-adventurer .adv-build-search input,
.skill-mode-adventurer .adv-build-toolbar .ron-select__trigger {
  height: auto;
  min-height: max(calc(16 * var(--gp)), calc(1.3 * var(--type-label-size) + 4 * var(--gp)));
}
.skill-mode-adventurer .adv-build-pill {
  height: auto;
  min-height: max(calc(16 * var(--gp)), calc(1.3 * var(--type-metadata-size) + 2 * var(--gp)));
}
.skill-mode-adventurer .adv-build-tab-count {
  height: auto;
  min-height: max(calc(9 * var(--gp)), calc(1.3 * var(--type-micro-size)));
}
.skill-mode-adventurer .adv-active-footprint {
  min-width: 0;
  overflow-wrap: anywhere;
}
.skill-mode-adventurer .adv-footprint-content {
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 1fr);
}
/* The title bar cannot hold translated tabs at every text size. Keep the
   controls in the body grid, where chrome gets its height before the lists. */
[data-ui-profile='handheld'] .window.win-skills .adv-build-tabs {
  position: static;
  height: auto;
  margin-bottom: calc(3 * var(--gp));
}
[data-ui-profile='handheld'] .window.win-skills .adv-build-tablist {
  flex: 1 1 auto;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-columns: minmax(0, 1fr);
}
[data-ui-profile='handheld']
  .window.win-skills
  .adv-build-tabs
  :is(.adv-build-tab, .adv-build-respec) {
  height: auto;
  min-height: max(calc(17 * var(--gp)), calc(1.3 * var(--type-label-size) + 4 * var(--gp)));
}
[data-ui-profile='handheld'] .skill-mode-adventurer .adv-build-toolbar {
  flex-wrap: wrap;
  flex-basis: 100%;
}
[data-ui-profile='handheld'] .skill-mode-adventurer .adv-build-search {
  min-width: min(100%, calc(120px * var(--type-scale)));
}
[data-ui-profile='handheld'] .skill-mode-adventurer .adv-build-search {
  flex: 1 1 0;
}
[data-ui-profile='handheld'] .skill-mode-adventurer .adv-build-toolbar .adv-build-pill {
  flex: 0 0 auto;
}
/* Character sheet in the HUD's pixel material: ink-well plates with a notched corner, stat colour one HUD pixel
   down the left edge, gold for the level alone. Window width stays fixed. */

/* Gear beside the readout at every width; the stat grid fits its fourteen plates into the sheet height, so neither column scrolls. */
.window.win-stats {
  width: calc(580px * var(--ui-scale));
  max-width: 96vw;
}

/* The stats element mounts directly under .window, so .stats-grid is the window body. */
.stats-grid {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  padding: calc(4 * var(--gp)) calc(4 * var(--gp)) calc(3 * var(--gp));
  box-sizing: border-box;
  min-height: 0;
  overflow: auto;
  container-type: inline-size;
  /* Plate metrics; the emblem shrinks with the row (`cqh`) instead of hiding a stat behind a scrollbar. */
  --stat-grid-gap: calc(2 * var(--gp));
  --stat-tile-pad-x: calc(3 * var(--gp));
  --stat-tile-pad-y: calc(2 * var(--gp));
  --stat-tile-emblem: min(calc(26px * var(--ui-scale)), 19cqh, 9cqw);
  --stats-list-height: clamp(calc(155px * var(--ui-scale)), 35cqw, calc(198px * var(--ui-scale)));
  --stats-panel-height: var(--stats-list-height);
  --stats-well-face: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  --stats-well-light: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

/* Columns scale, never reflow; the readout carries the floor, so the gear column gives ground as the sheet narrows. */
.stats-sheet-content {
  display: grid;
  grid-template-columns:
    minmax(0, calc(270px * var(--ui-scale)))
    minmax(min(calc(260px * var(--ui-scale)), 100%), 1fr);
  align-items: stretch;
  gap: calc(4 * var(--gp));
  min-width: 0;
}

.stats-gear {
  min-width: 0;
}
.stats-readout {
  min-width: 0;
  min-height: 0;
}
.stats-effects {
  min-width: 0;
}

/* Keep the bonus row in view on landscape phones; larger text scales can still scroll the body. */
[data-ui-profile='handheld'] .stats-grid:has(.stats-effects) {
  --stats-panel-height: min(
    var(--stats-list-height),
    max(calc(100px * var(--ui-scale)), calc(var(--hud-window-max-h) - 186px * var(--ui-scale)))
  );
}

/* Container width trims slots and portrait together so a narrow window leaves no tall empty gutters. */
.stats-gear .paperdoll {
  align-items: center;
  height: var(--stats-panel-height);
  max-width: 100%;
  gap: calc(2 * var(--gp));
  margin-bottom: 0;
  padding: var(--gp);
  box-sizing: border-box;
}
.stats-gear .paperdoll .pd-col {
  gap: calc(2 * var(--gp));
}
.stats-gear .paperdoll .pd-slot {
  --slot-size: clamp(calc(22px * var(--ui-scale)), 5.5cqw, calc(38px * var(--ui-scale)));
}
.stats-gear .paperdoll .pd-mannequin {
  flex: 1 1 auto;
  height: min(100%, clamp(calc(104px * var(--ui-scale)), 24cqw, calc(142px * var(--ui-scale))));
  min-width: 0;
  max-width: calc(190px * var(--ui-scale));
  padding: var(--gp);
}
.stats-gear .paperdoll .pd-mannequin-img {
  max-height: 100%;
}

/* The heading wraps; translated stat names must not push the row out of line. */
.attr-head {
  position: relative;
  flex-wrap: nowrap;
}
.attr-head > span {
  min-width: 0;
}
.equipment-panel {
  display: flex;
  flex-direction: column;
  gap: calc(8px * var(--ui-scale));
}
.equip-empty {
  text-align: center;
  color: var(--muted);
  padding: calc(8px * var(--ui-scale));
}
.equipment-effects {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(132px * var(--ui-scale))), 1fr));
  gap: var(--stat-grid-gap);
  min-width: 0;
  min-height: calc(44px * var(--ui-scale));
}
.equipment-effect {
  min-width: 0;
}
.equipment-effect-ref {
  display: block;
}
.equipment-effect-face {
  display: grid;
  grid-template-columns: calc(26px * var(--ui-scale)) minmax(0, 1fr) auto;
  column-gap: calc(6px * var(--ui-scale));
  align-items: center;
}
.equipment-effect-face .equipment-effect-icon {
  width: 100%;
  height: auto;
}
.equipment-effect-copy {
  display: grid;
  min-width: 0;
  line-height: 1.15;
}
.equipment-effect-name {
  color: var(--text);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  overflow-wrap: anywhere;
}
.equipment-effect-amount {
  display: grid;
  justify-items: start;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-label);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}
.equipment-effect-count {
  align-self: start;
  padding: 0 calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  color: var(--text);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.equipment-effect.is-inactive .equipment-effect-card {
  --stat-accent: var(--pixel-slate);
  opacity: 0.68;
}

.stats-identity {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: calc(6px * var(--ui-scale));
  padding: calc(2 * var(--gp)) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--stats-well-face);
  box-shadow: var(--stats-well-light);
  clip-path: var(--pixel-notch);
}
.si-hero {
  grid-column: 1;
  min-width: 0;
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  gap: calc(4px * var(--ui-scale));
}
.si-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 0 1 auto;
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-label);
  line-height: 1.1;
}
.si-affiliations {
  display: flex;
  align-items: center;
  gap: calc(4px * var(--ui-scale));
  flex: 1 1 calc(190px * var(--ui-scale));
  min-width: 0;
  flex-wrap: wrap;
  padding-left: calc(3 * var(--gp));
  border-left: var(--gp) solid var(--pixel-dusk);
}
.si-faction {
  min-width: 0;
}
.si-side {
  grid-column: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: calc(2px * var(--ui-scale));
  min-width: 0;
}

.identity-chip {
  display: inline-flex;
  align-items: center;
  gap: calc(7px * var(--ui-scale));
  min-width: 0;
  max-width: 100%;
}
.identity-icon {
  position: relative;
  flex: 0 0 auto;
  width: calc(24px * var(--ui-scale));
  height: calc(24px * var(--ui-scale));
  border: 1px solid var(--identity-ring, var(--accent));
  background: color-mix(in srgb, var(--identity-ring, var(--accent)) 14%, rgba(8, 12, 18, 0.55));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 2px 0px rgba(0, 0, 0, 0.35);
  object-fit: contain;
  padding: calc(4px * var(--ui-scale));
  box-sizing: border-box;
  overflow: hidden;
}
.identity-chip--md .identity-icon {
  width: calc(32px * var(--ui-scale));
  height: calc(32px * var(--ui-scale));
  padding: calc(5px * var(--ui-scale));
}
.identity-icon--guild {
  display: grid;
  place-items: center;
  padding: 0;
}
.identity-icon__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.identity-body {
  display: flex;
  flex-direction: column;
  gap: calc(1px * var(--ui-scale));
  min-width: 0;
}
.identity-body--single {
  justify-content: center;
}
.identity-primary {
  font-weight: var(--type-weight-label);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  line-height: 1.15;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.identity-chip--md .identity-primary {
  font-size: var(--type-heading-size);
  font-family: var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
}
.si-faction-chip .identity-primary {
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.35px;
  color: color-mix(in srgb, var(--text) 88%, var(--muted));
}
.stats-identity .identity-icon {
  width: calc(10 * var(--gp));
  height: calc(10 * var(--gp));
  padding: var(--gp);
  border: var(--gp) solid var(--identity-ring, var(--pixel-slate));
  background: var(--pixel-ink);
  box-shadow: none;
  clip-path: var(--pixel-notch);
}
.stats-identity .hud-guild {
  gap: calc(3px * var(--ui-scale));
  padding-left: calc(4px * var(--ui-scale));
}
.stats-identity .hud-guild-emblem {
  width: calc(16px * var(--ui-scale));
  height: calc(16px * var(--ui-scale));
}
.stats-identity .hud-guild-label {
  font-size: var(--type-ornament-size);
  font-family: var(--type-ornament-family);
  -webkit-font-smoothing: var(--type-ornament-smoothing);
}
.stats-identity .hud-guild-name {
  font-size: var(--type-glyph-size);
  font-family: var(--type-glyph-family);
  -webkit-font-smoothing: var(--type-glyph-smoothing);
}
.identity-secondary {
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-medium);
  line-height: 1.15;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.identity-chip--md .identity-secondary {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

/* Pending header has no name, so the sync message carries the header at full size. */
.stats-pending-title {
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.3px;
  color: var(--accent);
}
.si-levels {
  display: flex;
  align-items: center;
}
.si-lv {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  padding: 0 calc(6px * var(--ui-scale));
  line-height: 1;
}
.si-lv + .si-lv {
  border-left: var(--gp) solid var(--pixel-dusk);
}
.si-lv-k {
  font-size: var(--type-glyph-size);
  font-family: var(--type-glyph-family);
  -webkit-font-smoothing: var(--type-glyph-smoothing);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--muted);
  margin-top: 1px;
}
.si-lv-v {
  font-size: var(--type-prose-size);
  font-family: var(--type-prose-family);
  -webkit-font-smoothing: var(--type-prose-smoothing);
  font-weight: var(--type-weight-label);
  color: #f0dcac;
  font-variant-numeric: tabular-nums;
}

.stats-pending-head {
  grid-template-columns: 1fr;
}
.stats-pending-note {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: 1.3;
}

.col-head {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--gp));
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  font-weight: var(--type-weight-strong);
  color: var(--pixel-lilac);
  padding-bottom: var(--gp);
  margin-bottom: var(--gp);
  border-bottom: var(--gp) solid var(--pixel-dusk);
}
.col-head::before {
  content: '';
  flex: 0 0 auto;
  width: var(--gp);
  height: calc(5 * var(--gp));
  background: var(--pixel-lilac);
}

.grp-attr {
  --grp: var(--accent);
  --grp-soft: color-mix(in srgb, var(--gold) 14%, transparent);
  --grp-glow: color-mix(in srgb, var(--gold) 50%, transparent);
}

.stat-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  color: var(--grp, var(--accent));
}
.stat-ico-img {
  width: 82%;
  height: 82%;
  object-fit: contain;
  image-rendering: auto;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

.stat-ico--tile {
  position: relative;
  box-sizing: border-box;
  width: calc(21 * var(--gp));
  height: calc(21 * var(--gp));
  background: var(--pixel-ink);
  border: var(--gp) solid var(--pixel-ink);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
  overflow: hidden;
}
.stat-ico--tile .stat-ico-img {
  width: 96%;
  height: 96%;
}

/* Fourteen plates on one grid, three across: emblem, server-resolved number, and a bar splitting it by source. The bar is always its own full value. */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: minmax(0, 1fr);
  gap: var(--stat-grid-gap);
  height: var(--stats-panel-height);
  margin: 0;
  padding: 0;
  list-style: none;
  min-width: 0;
  /* Five rows share a height-bound sheet on handheld: a short row gives up margin and art before its bar can cross the number. */
  --stat-tile-pad-y: clamp(var(--gp), round(down, 2.1cqh, var(--gp)), calc(2 * var(--gp)));
  --stat-tile-emblem: min(calc(26px * var(--ui-scale)), 14cqh, 9cqw);
  /* Size container so the emblem measures against its row (`cqh`); overflow stays visible so the focus ring is not clipped. */
  container-type: size;
}

.stat-tile,
.equipment-effect-card {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: calc(3px * var(--ui-scale));
  min-width: 0;
  min-height: 0;
  padding: var(--stat-tile-pad-y) var(--stat-tile-pad-x)
    calc(var(--stat-tile-pad-y) + calc(2 * var(--gp)));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--stats-well-face);
  box-shadow:
    inset var(--gp) 0 0 var(--stat-accent, var(--pixel-slate)),
    var(--stats-well-light);
  clip-path: var(--pixel-notch);
  box-sizing: border-box;
  cursor: help;
}

.equipment-effect-card {
  grid-template-columns: minmax(0, 1fr);
  min-height: calc(44px * var(--ui-scale));
  height: 100%;
}

.stat-tile:hover,
.equipment-effect-card:hover {
  background: var(--pixel-night);
  box-shadow:
    inset var(--gp) 0 0 var(--stat-accent, var(--pixel-slate)),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-slate);
}
/* Keyboard focus is an inset bracket, never the hover tint; the notch cuts anything drawn outside the plate. */
.stat-tile:focus-visible,
.equipment-effect-card:focus-visible {
  outline: none;
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent);
}

.stat-tile .stat-ico--tile {
  width: round(down, var(--stat-tile-emblem), calc(2 * var(--gp)));
  height: round(down, var(--stat-tile-emblem), calc(2 * var(--gp)));
}

.stat-tile-value {
  grid-column: 2;
  justify-self: end;
  min-width: 0;
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-label);
  line-height: 1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The unit is a smaller caption so "1.72/sec" fits a plate a third of the readout wide. */
.stat-tile-unit {
  margin-left: var(--gp);
  font-size: var(--type-glyph-size);
  font-family: var(--type-glyph-family);
  -webkit-font-smoothing: var(--type-glyph-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--muted);
}

.stat-bar {
  position: absolute;
  left: var(--stat-tile-pad-x);
  right: var(--stat-tile-pad-x);
  bottom: calc(2 * var(--gp));
  height: var(--gp);
  background: var(--pixel-dusk);
  overflow: hidden;
}
.stat-bar > span {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--stat-from, 0%);
  width: var(--stat-fill, 0%);
}
.stat-bar-gear {
  background: var(--pixel-lilac);
}
.stat-bar-build {
  background: var(--pixel-honey);
}

/* A stat on its ceiling: the bar runs into a wall. The stop carries its own ink edge because it sits on the honey bonus segment. */
.stat-tile[data-at-ceiling] .stat-bar::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: calc(3 * var(--gp));
  background: var(--pixel-cream);
  border-left: var(--gp) solid var(--pixel-ink);
  box-sizing: border-box;
}

.stat-tile--pending {
  opacity: 0.82;
  cursor: default;
}

.stats-section {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
}

/* High contrast lights every plate edge and the bar track. */
body.high-contrast .stats-grid {
  --stats-well-light: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-lilac);
}
body.high-contrast .stat-bar {
  background: var(--pixel-slate);
}
/* The refund control, worn by the Skills window's build reset: a refund icon
   on a bronze plate of the HUD's material (pixel-chrome.css), one
   press to arm and a second to send — `is-confirming` is the armed state, lined
   in the accent. Matches the panel's own Refund in the skill window so the whole
   vocabulary reads as one action. */
.refund-button {
  display: inline-flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  padding: calc(2 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background-color: color-mix(in srgb, var(--pixel-ochre) 30%, var(--pixel-night));
  color: #f1d59a;
  box-shadow:
    inset var(--gp) var(--gp) 0 color-mix(in srgb, var(--pixel-ochre) 75%, var(--pixel-night)),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-ink);
  clip-path: var(--pixel-notch);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  line-height: 1;
  cursor: var(--cursor-action);
}
.refund-button img {
  width: calc(7 * var(--gp));
  height: calc(7 * var(--gp));
  flex: none;
  object-fit: contain;
}
.refund-button:hover:not(:disabled) {
  background-color: color-mix(in srgb, var(--pixel-ochre) 40%, var(--pixel-night));
  transform: translateY(calc(-1 * var(--gp)));
}
.refund-button:active:not(:disabled) {
  transform: translateY(0);
}
.refund-button.is-confirming {
  background-color: color-mix(in srgb, var(--pixel-ochre) 45%, var(--pixel-night));
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
}
/* Hover falls through to the wrapper so its title tooltip still shows while the
   button is disabled (browsers suppress a disabled control's own tooltip). */
.refund-button:disabled {
  pointer-events: none;
  cursor: not-allowed;
  filter: grayscale(1);
  opacity: 0.42;
}
/* The notch clips anything drawn outside the plate, so the focus bracket is
   drawn inside it. */
.refund-button:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}
/* Inventory (Bag): header, filter chips, slot grid, footer. Tabs, slots and rhythm are drawn by the pixel window (hud-pixel-window.css); this sheet keeps layout and type. */

.inv-window {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.inv-header {
  display: flex;
  align-items: center;
  border-bottom: var(--gp) solid var(--pixel-dusk);
}
.inv-hd-ico {
  display: inline-flex;
  color: var(--accent);
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}
.inv-hd-ico .inv-ico-img {
  object-fit: contain;
  display: block;
}
.inv-hd-title {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--accent);
}
.inv-hd-count {
  margin-left: auto;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-label);
  color: #c7ceda;
  font-variant-numeric: tabular-nums;
}

.inv-filter {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  cursor: var(--cursor-action);
}
.inv-filter-ico {
  display: inline-flex;
  flex: 0 0 auto;
}
.inv-filter-ico .inv-ico-img {
  object-fit: contain;
  display: block;
}
.inv-filter-label {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: var(--type-leading-tight);
  letter-spacing: 0.2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.inv-filter-count {
  flex: 0 0 auto;
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-label);
  text-align: center;
  font-variant-numeric: tabular-nums;
}
body.high-contrast .inv-filter {
  border-width: calc(2 * var(--gp));
}
@media (max-width: 460px) {
  .inv-filter-label {
    display: none;
  }
}

.inv-toolbar {
  display: flex;
  align-items: stretch;
}

.inv-grid {
  display: grid;
  justify-content: start;
  box-sizing: border-box;
  align-content: start;
}
.inv-cell {
  position: relative;
  aspect-ratio: 1;
  min-width: 0;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: var(--cursor-action);
  overflow: hidden;
}
.inv-cell .inv-icon {
  width: 78%;
  height: 78%;
  object-fit: contain;
  position: relative;
  z-index: 1;
  pointer-events: none;
}

.inv-cell-empty {
  cursor: var(--cursor-default);
}

.inv-cell .inv-refine,
.inv-cell .inv-amt {
  z-index: 2;
}

/* Quest-item corner marker; the accessible label and the tooltip repeat the tag, so colour is not the only cue. */
.inv-cell .inv-quest {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 2;
  width: 0;
  height: 0;
  border-top: calc(4 * var(--gp)) solid var(--accent);
  border-right: calc(4 * var(--gp)) solid transparent;
  pointer-events: none;
}

.inv-empty {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--muted);
  padding: calc(9 * var(--gp));
}

body.high-contrast .inv-cell {
  border-width: calc(2 * var(--gp));
}

.win-inv .inv-footer {
  margin-top: 0;
}
.win-inv .inv-weight-text {
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}
.win-inv .inv-gold-val {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

/* Each rolled option is one effect phrase on its own line; long phrases wrap with a hanging indent. */
.tt-opts {
  display: grid;
  gap: calc(2 * var(--gp));
  margin: calc(2 * var(--gp)) 0;
}
.tt-rowqual {
  float: right;
  text-transform: none;
  letter-spacing: 0;
  opacity: 0.85;
}
/* Base is the same on every copy, so it reads quieter than the rolled bands; colour alone left four sentences of profile rules outweighing the three rolled lines the player is deciding between. */
.tt-opts--base .tt-opt {
  color: var(--muted);
  border-left-color: var(--pixel-slate);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-regular);
  line-height: 1.36;
}
.tt-opts--base .tt-opt:first-child {
  color: #cdd3dd;
  font-weight: var(--type-weight-medium);
}
/* An unfilled trait seat is potential: a dashed edge and italic label keep it from reading as something the item has. */
.tt-opt--empty {
  color: var(--muted);
  font-weight: var(--type-weight-regular);
  font-style: italic;
  border-left-style: dashed;
  border-left-color: var(--pixel-slate);
}
.tt-opt {
  position: relative;
  padding-left: calc(4 * var(--gp));
  border-left: var(--gp) solid var(--opt, var(--accent));
  color: var(--opt, var(--accent));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-medium);
  line-height: 1.32;
  overflow-wrap: break-word;
}
.tt-opt-hint {
  color: var(--muted);
  font-style: italic;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  opacity: 0.9;
}

/* A rich item can run taller than a short landscape viewport, so the card scrolls inside itself. The cap is the glass the device leaves the page, not the viewport, which would put rows under the home indicator. */
.item-tooltip {
  max-height: calc(100dvh - 16px - var(--safe-top, 0px) - var(--safe-bottom, 0px));
  overflow: auto;
}

/* The rarity word sits under the name, which is already in the rarity colour. */
.tt-heading-text {
  min-width: 0;
}
.tt-kindline {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  letter-spacing: 0.3px;
}

.tt-chips {
  display: flex;
  flex-wrap: wrap;
  gap: calc(2 * var(--gp));
  margin: calc(3 * var(--gp)) 0 calc(2 * var(--gp));
}
.tt-chip {
  display: inline-flex;
  align-items: baseline;
  gap: calc(2 * var(--gp));
  padding: var(--gp) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--pixel-ink);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  line-height: round(up, 1.2em, var(--gp));
}
.tt-chip-k {
  color: var(--muted);
}
.tt-chip-v {
  color: #cdd3dd;
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
}
/* An owned state takes the HUD's gold and a stronger edge so the cue survives greyscale. */
.tt-chip--on {
  border-color: var(--accent-2);
  background: color-mix(in srgb, var(--accent) 14%, var(--pixel-night));
}
.tt-chip--on .tt-chip-k,
.tt-chip--on .tt-chip-v {
  color: var(--accent);
}

/* A capability emblem: the stat or ability art, badged with what it does. The badge vocabulary is the Faction Armory bench's. */
.tt-opt--iconed {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: calc(4 * var(--gp));
  align-items: start;
}
.tt-opt-body {
  min-width: 0;
}
.tt-opt-ico {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: calc(10 * var(--gp));
  height: calc(10 * var(--gp));
  margin-top: var(--gp);
}
.tt-opt-ico-base {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
}
.tt-opt-ico-badge {
  position: absolute;
  right: calc(-2 * var(--gp));
  bottom: calc(-2 * var(--gp));
  width: 58%;
  height: 58%;
  padding: 6%;
  background: var(--pixel-ink);
  box-shadow: 0 0 0 var(--gp) var(--pixel-dusk);
  object-fit: contain;
}

.tt-compare-section > .tt-rowlabel:first-child {
  margin-top: 0;
  color: var(--accent);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
}

/* The rule a trigger obeys is quieter than the effect it qualifies and never shares its line. */
.tt-opt-note {
  display: block;
  margin-top: var(--gp);
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-regular);
  line-height: 1.3;
}

[data-ui-profile='handheld'] .inv-filter {
  min-height: var(--hud-touch-min);
}

[data-ui-profile='handheld'] .inv-filter-label {
  display: none;
}

[data-ui-profile='handheld'] .armory-onboarding-facts {
  grid-template-columns: 1fr;
}
/* Pre-game frame and atoms, scoped under `.menu-root`, `.menu-overlay`, `.menu-toast`.
   Every screen is one head/middle/foot frame filling the glass; the page never scrolls.
   Sizes come from `clamp()` on viewport height, so the width breakpoint only decides
   whether the roster sits beside or under the hero. */

.menu-root,
.menu-overlay,
.menu-toast {
  -webkit-font-smoothing: none;
  --line: var(--ui-line);
  --line-strong: #4c5d60;
  --panel-3: var(--panel-raised);
  --ink: #1a1206;
  --text-2: #b9c0cc;

  --accent-line: rgba(201, 164, 94, 0.52);

  --s1: calc(2 * var(--gp));
  --s2: calc(4 * var(--gp));
  --s3: calc(6 * var(--gp));
  --s4: calc(8 * var(--gp));
  --s5: calc(12 * var(--gp));

  --dur-fast: 120ms;
  --dur: 170ms;
  --dur-slow: 240ms;
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);

  --focus-ring: 0 0 0 var(--gp) var(--bg), 0 0 0 calc(2 * var(--gp)) var(--accent);

  /* Critical controls clear notches and gesture bars; background art continues beneath. */
  --menu-safe-top: max(var(--s3), var(--safe-top));
  --menu-safe-right: max(var(--s3), var(--safe-right));
  --menu-safe-bottom: max(var(--s3), var(--safe-bottom));
  --menu-safe-left: max(var(--s3), var(--safe-left));

  /* Both shrink with the glass height; chrome gives way, controls keep their touch size. */
  --pg-gap: round(clamp(6px, 2.2dvh, 20px), var(--gp));

  /* Minimum control height: a touch target that never condenses, rounded up to the grid. */
  --pg-touch: round(up, 44px, var(--gp));

  /* Scale for every non-control size, so the whole screen steps down together. */
  --pg-condense: 1;

  /* Whole steps of the 9px grid; fields stay at two because mobile Safari zooms on focus under 16px. */
  --pg-type-metadata-size: var(--type-compact-size);
  --pg-type-metadata-family: var(--font-ui-small);
  --pg-type-label-size: var(--type-reading-size);
  --pg-type-label-family: var(--font-ui-small);
  --pg-type-body-compact-size: var(--type-reading-size);
  --pg-type-body-compact-family: var(--font-ui);
  --pg-type-body-size: var(--type-reading-size);
  --pg-type-body-family: var(--font-ui);
  --pg-type-prose-size: var(--type-reading-size);
  --pg-type-prose-family: var(--font-ui);
  --pg-type-heading-size: var(--type-reading-size);
  --pg-type-heading-family: var(--font-ui);
  --pg-type-title-size: var(--type-reading-size);
  --pg-type-title-family: var(--font-ui);
  --pg-type-overlay-heading-size: var(--type-tier-3x);
  --pg-type-overlay-heading-family: var(--font-ui);
  --pg-type-prose-readable-size: var(--type-reading-size);
  --pg-type-prose-readable-family: var(--font-ui);
  --pg-type-panel-title-size: var(--type-reading-size);
  --pg-type-panel-title-family: var(--font-ui);
}

/* Short landscape phone (~390px, ~320 under browser chrome): chrome and type step down, touch size does not. */

@media (max-height: 34rem) {
  .menu-root,
  .menu-overlay,
  .menu-toast {
    --pg-condense: 0.88;
    --pg-type-label-size: var(--type-compact-size);
    --pg-type-body-compact-size: var(--type-compact-size);
    --pg-type-body-size: var(--type-compact-size);
    --pg-type-prose-size: var(--type-compact-size);
    --pg-type-heading-size: var(--type-compact-size);
    --pg-type-heading-family: var(--font-ui-large);
  }
}

@media (max-height: 26rem) {
  .menu-root,
  .menu-overlay,
  .menu-toast {
    --pg-condense: 0.8;
  }
}

/* The stage clips: the vista is scaled past its box to drift, and scrolling would count the bleed as overflow. */

.menu-root {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 100dvh;
  overflow: clip;
  color: var(--text);
}

.pg-shell {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--pg-gap);
  height: 100dvh;
  padding: var(--menu-safe-top) var(--menu-safe-right) var(--menu-safe-bottom) var(--menu-safe-left);
}

.pg-head,
.pg-foot {
  flex: 0 0 auto;
  min-width: 0;
}

/* The one scroll container. `safe` centring falls back to top-aligned when content is taller,
   so the head is never pushed above the scroll origin. */

.pg-main {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: safe center;
  gap: var(--pg-gap);
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.pg-main > * {
  flex: 0 0 auto;
  width: 100%;
  min-width: 0;
}

.pg-foot {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s4);
  font-weight: var(--type-weight-medium);
  font-size: var(--pg-type-label-size);
  font-family: var(--pg-type-label-family);
  line-height: round(1em, var(--gp));
  letter-spacing: 0.4px;
  color: var(--muted);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

/* Build line only; it hides on a short glass instead of pushing the frame. */

@media (max-height: 26rem) {
  .pg-foot {
    display: none;
  }
  /* Landscape phone: the wordmark head hides so the card gets the row. */
  .login-screen > .pg-head {
    position: absolute;
    z-index: 3;
    inset-block-start: var(--menu-safe-top);
    inset-inline: var(--menu-safe-left) var(--menu-safe-right);
    pointer-events: none;
  }
  .login-screen > .pg-head .ront-brand {
    display: none;
  }
}

.screen-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-size: cover;
  background-position: center 32%;
  background-repeat: no-repeat;
  transform: scale(1.04);
  animation: screen-bg-drift 40s ease-in-out infinite alternate;
}

@keyframes screen-bg-drift {
  from {
    transform: scale(1.04) translate3d(-0.6%, 0, 0);
  }
  to {
    transform: scale(1.08) translate3d(0.6%, -1%, 0);
  }
}

.screen-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(6, 9, 14, 0.36);
}

/* Ambient plane mounted once across login and character select; the sky steps down in hard bands. */

.menu-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background: linear-gradient(
    #16203a 0 round(12%, var(--gp)),
    #111829 round(12%, var(--gp)) round(26%, var(--gp)),
    #0c1018 round(26%, var(--gp)) round(44%, var(--gp)),
    var(--bg) round(44%, var(--gp))
  );
}

.menu-aurora {
  position: absolute;
  inset: -20%;
  opacity: 0.5;
  will-change: transform;
  background: linear-gradient(
    transparent 0 round(22%, var(--gp)),
    rgba(64, 120, 150, 0.2) round(22%, var(--gp)) round(24%, var(--gp)),
    rgba(120, 100, 160, 0.16) round(24%, var(--gp)) round(26%, var(--gp)),
    color-mix(in srgb, var(--gold) 6%, transparent) round(26%, var(--gp)) round(27%, var(--gp)),
    transparent round(27%, var(--gp))
  );
  animation: menu-aurora-drift 48s ease-in-out infinite alternate;
}

.menu-aurora.menu-aurora--b {
  opacity: 0.32;
  animation-duration: 67s;
  animation-direction: alternate-reverse;
}

@keyframes menu-aurora-drift {
  from {
    transform: translate3d(-3%, 0, 0) scale(1.05);
  }
  to {
    transform: translate3d(3%, 2%, 0) scale(1.12);
  }
}

.menu-particles {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.menu-panel {
  --pg-panel-py: round(clamp(10px, 2.6dvh, 24px), var(--gp));
  --pg-panel-px: round(clamp(12px, 2vw, 26px), var(--gp));
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--pg-gap);
  padding: var(--pg-panel-py) var(--pg-panel-px);
  /* Ink outline, dusk inner line, night face, one pixel notched off each corner.
       No filter: it would rasterize the labels. */
  --panel-line: var(--pixel-dusk);
  background: var(--pixel-night);
  border: var(--gp) solid var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) var(--panel-line);
  clip-path: var(--pixel-notch);
  color: var(--text);
  animation: menu-surface-in var(--dur) var(--ease) both;
}

.menu-panel.is-danger {
  --panel-line: color-mix(in srgb, var(--pixel-debuff) 55%, var(--pixel-dusk));
}

.menu-panel__title {
  margin: 0;
  font-weight: var(--type-weight-strong);
  font-size: var(--pg-type-panel-title-size);
  font-family: var(--pg-type-panel-title-family);
  line-height: round(1.2em, var(--gp));
  letter-spacing: 0.3px;
}

.menu-panel__title--icon {
  display: flex;
  align-items: center;
  gap: var(--s2);
}

.menu-panel__title-icon {
  flex: none;
  width: calc(12 * var(--gp));
  height: calc(12 * var(--gp));
  object-fit: contain;
}

.menu-panel__sub {
  margin: calc(-1 * var(--pg-gap) + var(--s1)) 0 0;
  color: var(--muted);
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  line-height: round(1.45em, var(--gp));
}

.menu-panel__body {
  display: flex;
  flex-direction: column;
  gap: var(--s4);
}

/* Decisive actions stick to the bottom of the scroller; the offset never engages when the card fits. */

.menu-panel__actions {
  position: sticky;
  bottom: 0;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  margin-block-start: auto;
}

/* In a card the pinned row bleeds to the card edges and redraws the inner line along them. */

.menu-panel > .menu-panel__actions {
  bottom: calc(-1 * var(--pg-panel-py));
  margin-inline: calc(-1 * var(--pg-panel-px));
  margin-block-end: calc(-1 * var(--pg-panel-py));
  padding: var(--s2) var(--pg-panel-px) var(--pg-panel-py);
  background: var(--pixel-night);
  box-shadow:
    inset var(--gp) 0 0 var(--panel-line),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--panel-line);
}

.menu-panel__actions > .menu-button {
  flex: 1 1 auto;
}

/* Pairs split the row in whole-gp halves; grown from their labels they land on half pixels. */

.menu-panel__actions:has(> .menu-button:first-child:nth-last-child(2)) {
  justify-content: space-between;
}

.menu-panel__actions > .menu-button:is(:first-child:nth-last-child(2), :last-child:nth-child(2)) {
  flex: 0 1 round(down, calc(50% - var(--s3) / 2), var(--gp));
}

@keyframes menu-surface-in {
  from {
    opacity: 0;
    transform: translateY(calc(3 * var(--gp)));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* HUD plate: ink outline, lit rim, face, notched corners. Variants repaint --plate-*. */

.menu-button {
  overflow-wrap: anywhere;
  --plate-line: var(--pixel-ink);
  --plate-face: var(--pixel-night);
  --plate-rim: var(--pixel-rim);
  position: relative;
  display: inline-flex;
  white-space: normal;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: var(--pg-touch);
  padding: 0 var(--s4);
  border: var(--gp) solid var(--plate-line);
  font-weight: var(--type-weight-medium);
  font-size: var(--pg-type-prose-size);
  font-family: var(--pg-type-prose-family);
  line-height: var(--type-leading-tight);
  cursor: var(--cursor-action);
  color: var(--text);
  background: var(--plate-face);
  box-shadow: var(--plate-rim);
  clip-path: var(--pixel-notch);
  transition: filter var(--dur-fast);
}

.menu-button:hover {
  filter: brightness(1.15);
}

.menu-button:active {
  filter: brightness(0.92);
}

/* A notch clips anything drawn outside it, so the notched pieces take the ring inside their rim. */

.menu-button,
.cs-slot,
.create-faction {
  --focus-ring:
    inset 0 0 0 var(--gp) var(--pixel-ink), inset 0 0 0 calc(2 * var(--gp)) var(--accent);
}

.menu-button:focus-visible {
  outline: none !important;
  box-shadow: var(--focus-ring) !important;
}

.menu-button[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

/* aria-disabled stays clickable so its handler can say what would unlock it; only `disabled` swallows input. */

.menu-button[aria-disabled='true'] {
  opacity: 0.45;
  cursor: not-allowed;
}

.menu-button--primary {
  --plate-face: var(--pixel-ochre);
  --plate-rim:
    inset var(--gp) var(--gp) 0 var(--pixel-honey),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 #8a561c;
  color: var(--pixel-ink);
  font-weight: var(--type-weight-label);
}

.menu-button--ghost {
  color: var(--text);
}

.menu-button--ghost:hover {
  color: #ffe7a8;
}

.menu-button--danger {
  --plate-face: #34161c;
  color: #ff8a70;
}

.menu-button--block {
  width: 100%;
}

/* Loading: hide the label, centre the spinner, keep the width. */

.menu-button.is-loading {
  color: transparent;
  opacity: 1;
  pointer-events: none;
}

.menu-button.is-loading::after {
  color: var(--pixel-ink);
}

.menu-button--ghost.is-loading::after,
.menu-button--danger.is-loading::after {
  color: var(--accent);
}

.menu-field {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
}

.menu-field__label {
  font-weight: var(--type-weight-medium);
  font-size: var(--pg-type-label-size);
  font-family: var(--pg-type-label-family);
  line-height: round(1.3em, var(--gp));
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--muted);
}

.menu-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.menu-input {
  width: 100%;
  min-height: var(--pg-touch);
  padding: 0 var(--s3);
  color: var(--text);
  /* Under 16px mobile Safari zooms on focus and never zooms back. */
  font-size: var(--pg-type-prose-readable-size);
  font-family: var(--pg-type-prose-readable-family);
  background: #1a1326;
  border: var(--gp) solid var(--pixel-ink);
  box-shadow:
    inset var(--gp) var(--gp) 0 #0f0a16,
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.menu-input:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  pointer-events: none;
}

.menu-input::placeholder {
  color: var(--pixel-slate);
}

.menu-input:focus {
  outline: none !important;
  border-color: var(--accent);
  box-shadow:
    inset var(--gp) var(--gp) 0 #0f0a16,
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk) !important;
}

.menu-input[aria-invalid='true'] {
  border-color: var(--pixel-debuff);
  padding-right: calc(17 * var(--gp));
}

.menu-field.is-invalid .menu-input-wrap::after {
  content: '';
  position: absolute;
  right: calc(5 * var(--gp));
  top: round(down, calc(50% - 4.5 * var(--gp)), var(--gp));
  width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  background: url('/assets/hud-warning-F43PQiZD.webp') center / contain no-repeat;
  pointer-events: none;
}

.menu-field__hint {
  line-height: round(1.2em, var(--gp));
  font-size: var(--pg-type-label-size);
  font-family: var(--pg-type-label-family);
  color: var(--muted);
}

.menu-reveal {
  position: absolute;
  right: var(--s1);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: none;
  background: none;
  color: var(--muted);
  cursor: var(--cursor-action);
  transition:
    color var(--dur),
    background var(--dur);
}

.menu-reveal:hover:not(:disabled) {
  color: var(--text);
  background: var(--pixel-dusk);
}

/* Held during sign-in: dimmed, inert, no hover lift. */

.menu-reveal:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

.menu-reveal:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.menu-reveal__icon {
  width: 22px;
  height: 22px;
  object-fit: contain;
  filter: saturate(0.75) brightness(0.9);
}

.menu-reveal:hover:not(:disabled) .menu-reveal__icon {
  filter: saturate(1) brightness(1.08);
}

.menu-status {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  min-height: round(calc(8 * var(--gp) * var(--pg-condense)), var(--gp));
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  line-height: round(1.35em, var(--gp));
  color: var(--muted);
}

.menu-status::before {
  content: '';
  flex: 0 0 auto;
}

.menu-status:empty {
  visibility: hidden;
}

.menu-status.is-info {
  color: var(--muted);
}

.menu-status.is-error {
  color: var(--danger);
}

.menu-status.is-error::before {
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  background: url('/assets/hud-warning-F43PQiZD.webp') center / contain no-repeat;
}

/* Pixel spinner: eight cells round a square; --spin-u is the cell half-width. It never rotates, so cells stay on the grid. */

.menu-spinner {
  position: relative;
  flex: none;
  width: calc(8 * var(--spin-u, var(--gp)));
  height: calc(8 * var(--spin-u, var(--gp)));
  color: var(--accent);
}

.menu-spinner::after,
.menu-button.is-loading::after {
  --spin-3: calc(3 * var(--spin-u, var(--gp)));
  --spin-6: calc(6 * var(--spin-u, var(--gp)));
  --spin-on: currentColor;
  --spin-hi: color-mix(in srgb, currentColor 60%, transparent);
  --spin-lo: color-mix(in srgb, currentColor 35%, transparent);
  --spin-off: color-mix(in srgb, currentColor 15%, transparent);
  content: '';
  position: absolute;
  top: round(down, calc(50% - 4 * var(--spin-u, var(--gp))), var(--gp));
  left: round(down, calc(50% - 4 * var(--spin-u, var(--gp))), var(--gp));
  width: calc(2 * var(--spin-u, var(--gp)));
  height: calc(2 * var(--spin-u, var(--gp)));
  animation: pg-spin 0.8s steps(1, end) infinite;
}

@keyframes pg-spin {
  0% {
    box-shadow:
      0 0 0 var(--spin-on),
      var(--spin-3) 0 0 var(--spin-off),
      var(--spin-6) 0 0 var(--spin-off),
      var(--spin-6) var(--spin-3) 0 var(--spin-off),
      var(--spin-6) var(--spin-6) 0 var(--spin-off),
      var(--spin-3) var(--spin-6) 0 var(--spin-off),
      0 var(--spin-6) 0 var(--spin-lo),
      0 var(--spin-3) 0 var(--spin-hi);
  }
  12.5% {
    box-shadow:
      0 0 0 var(--spin-hi),
      var(--spin-3) 0 0 var(--spin-on),
      var(--spin-6) 0 0 var(--spin-off),
      var(--spin-6) var(--spin-3) 0 var(--spin-off),
      var(--spin-6) var(--spin-6) 0 var(--spin-off),
      var(--spin-3) var(--spin-6) 0 var(--spin-off),
      0 var(--spin-6) 0 var(--spin-off),
      0 var(--spin-3) 0 var(--spin-lo);
  }
  25% {
    box-shadow:
      0 0 0 var(--spin-lo),
      var(--spin-3) 0 0 var(--spin-hi),
      var(--spin-6) 0 0 var(--spin-on),
      var(--spin-6) var(--spin-3) 0 var(--spin-off),
      var(--spin-6) var(--spin-6) 0 var(--spin-off),
      var(--spin-3) var(--spin-6) 0 var(--spin-off),
      0 var(--spin-6) 0 var(--spin-off),
      0 var(--spin-3) 0 var(--spin-off);
  }
  37.5% {
    box-shadow:
      0 0 0 var(--spin-off),
      var(--spin-3) 0 0 var(--spin-lo),
      var(--spin-6) 0 0 var(--spin-hi),
      var(--spin-6) var(--spin-3) 0 var(--spin-on),
      var(--spin-6) var(--spin-6) 0 var(--spin-off),
      var(--spin-3) var(--spin-6) 0 var(--spin-off),
      0 var(--spin-6) 0 var(--spin-off),
      0 var(--spin-3) 0 var(--spin-off);
  }
  50% {
    box-shadow:
      0 0 0 var(--spin-off),
      var(--spin-3) 0 0 var(--spin-off),
      var(--spin-6) 0 0 var(--spin-lo),
      var(--spin-6) var(--spin-3) 0 var(--spin-hi),
      var(--spin-6) var(--spin-6) 0 var(--spin-on),
      var(--spin-3) var(--spin-6) 0 var(--spin-off),
      0 var(--spin-6) 0 var(--spin-off),
      0 var(--spin-3) 0 var(--spin-off);
  }
  62.5% {
    box-shadow:
      0 0 0 var(--spin-off),
      var(--spin-3) 0 0 var(--spin-off),
      var(--spin-6) 0 0 var(--spin-off),
      var(--spin-6) var(--spin-3) 0 var(--spin-lo),
      var(--spin-6) var(--spin-6) 0 var(--spin-hi),
      var(--spin-3) var(--spin-6) 0 var(--spin-on),
      0 var(--spin-6) 0 var(--spin-off),
      0 var(--spin-3) 0 var(--spin-off);
  }
  75% {
    box-shadow:
      0 0 0 var(--spin-off),
      var(--spin-3) 0 0 var(--spin-off),
      var(--spin-6) 0 0 var(--spin-off),
      var(--spin-6) var(--spin-3) 0 var(--spin-off),
      var(--spin-6) var(--spin-6) 0 var(--spin-lo),
      var(--spin-3) var(--spin-6) 0 var(--spin-hi),
      0 var(--spin-6) 0 var(--spin-on),
      0 var(--spin-3) 0 var(--spin-off);
  }
  87.5% {
    box-shadow:
      0 0 0 var(--spin-off),
      var(--spin-3) 0 0 var(--spin-off),
      var(--spin-6) 0 0 var(--spin-off),
      var(--spin-6) var(--spin-3) 0 var(--spin-off),
      var(--spin-6) var(--spin-6) 0 var(--spin-off),
      var(--spin-3) var(--spin-6) 0 var(--spin-lo),
      0 var(--spin-6) 0 var(--spin-hi),
      0 var(--spin-3) 0 var(--spin-on);
  }
}

.menu-crest {
  position: relative;
  display: grid;
  place-items: center;
  width: calc(28 * var(--gp));
  height: calc(28 * var(--gp));
  color: var(--accent);
  background: color-mix(in srgb, var(--crest-tint, var(--gold)) 22%, #1a1326);
  border: var(--gp) solid var(--crest-ring, var(--pixel-ink));
  box-shadow:
    inset var(--gp) var(--gp) 0 #0f0a16,
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.menu-crest--sm {
  width: calc(20 * var(--gp));
  height: calc(20 * var(--gp));
}

.menu-crest__bitmap {
  width: round(72%, var(--gp));
  height: round(72%, var(--gp));
  object-fit: contain;
  display: block;
}

/* Missing art is explicit readable text, never a blank disc. */

.faction-icon {
  flex: 0 0 auto;
  width: calc(16 * var(--gp));
  height: calc(16 * var(--gp));
  border: var(--gp) solid var(--faction-ring, var(--pixel-ink));
  background: color-mix(in srgb, var(--faction-ring, var(--accent)) 14%, #1a1326);
  box-shadow:
    inset var(--gp) var(--gp) 0 #0f0a16,
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  object-fit: contain;
  padding: calc(3 * var(--gp));
  box-sizing: border-box;
}

/* Crown art is a 32-pixel grid; padding would drop every other pixel, so its own clear margin keeps the ring off the border. */

.faction-icon--sm {
  width: calc(18 * var(--gp));
  height: calc(18 * var(--gp));
  padding: 0;
}

.faction-icon--md {
  width: calc(20 * var(--gp));
  height: calc(20 * var(--gp));
  padding: calc(3 * var(--gp));
}

.faction-icon--lg {
  width: round(clamp(52px, 11dvh, 84px), var(--gp));
  height: round(clamp(52px, 11dvh, 84px), var(--gp));
  padding: calc(4 * var(--gp));
}

.faction-icon-missing {
  color: var(--muted);
  font-size: var(--pg-type-metadata-size);
  font-family: var(--pg-type-metadata-family);
  font-weight: var(--type-weight-strong);
  line-height: round(1.2em, var(--gp));
}

.faction-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
}

.faction-chip__name {
  font-weight: var(--type-weight-medium);
  font-size: var(--pg-type-body-size);
  font-family: var(--pg-type-body-family);
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.faction-chip--unknown .faction-chip__name {
  color: var(--muted);
  font-weight: var(--type-weight-regular);
}

.ront-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
  color: #e9b94e;
}

.ront-brand__mark {
  flex: none;
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.ront-brand__text {
  display: flex;
  min-width: 0;
  flex-direction: column;
}

/* Each line rounds against its own size; an em set on the column would inherit as the column's pixels. */

.ront-brand__name,
.ront-brand__tag {
  line-height: round(1.02em, var(--gp));
}

.ront-brand__name {
  font-family: var(--font-display);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.05em;
  background: linear-gradient(
    #f4cd6e 0 round(50%, var(--gp)),
    #e9b94e round(50%, var(--gp)) round(75%, var(--gp)),
    #b78f2e round(75%, var(--gp))
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* The lockup sits on the brightest band; a one-pixel ink outline keeps the art undimmed. */
  filter: drop-shadow(var(--gp) 0 0 var(--pixel-ink))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--pixel-ink))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--pixel-ink))
    drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.ront-brand__tag {
  font-weight: var(--type-weight-medium);
  letter-spacing: 0.06em;
  white-space: nowrap;
  color: #d3cbb8;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.ront-brand__initial {
  color: #f6dc96;
}

.ront-brand--hero .ront-brand__mark {
  width: round(clamp(40px, 8dvh, 68px), var(--gp));
  height: round(clamp(40px, 8dvh, 68px), var(--gp));
}

.ront-brand--hero .ront-brand__name {
  font-size: var(--type-pregame-hero-size);
  font-family: var(--type-pregame-hero-family);
  -webkit-font-smoothing: var(--type-pregame-hero-smoothing);
}

.ront-brand--hero .ront-brand__tag {
  margin-top: calc(2 * var(--gp));
  font-size: var(--type-pregame-metadata-size);
  font-family: var(--type-pregame-metadata-family);
  -webkit-font-smoothing: var(--type-pregame-metadata-smoothing);
}

.ront-brand--compact .ront-brand__mark {
  width: round(clamp(26px, 5dvh, 38px), var(--gp));
  height: round(clamp(26px, 5dvh, 38px), var(--gp));
}

.ront-brand--compact .ront-brand__name {
  font-size: var(--type-pregame-heading-size);
  font-family: var(--type-pregame-heading-family);
  -webkit-font-smoothing: var(--type-pregame-heading-smoothing);
}

.ront-brand--compact .ront-brand__tag {
  margin-top: var(--gp);
  font-size: var(--type-pregame-badge-size);
  font-family: var(--type-pregame-badge-family);
  -webkit-font-smoothing: var(--type-pregame-badge-smoothing);
}

@media (max-height: 26rem) {
  .ront-brand__tag {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .screen-bg {
    animation: none;
    transform: scale(1.04);
  }
  .menu-aurora {
    animation: none;
  }
  .menu-panel,
  .menu-overlay__card,
  .menu-overlay__scrim,
  .menu-toast {
    animation: none;
  }
  .create-faction__check {
    transition: none;
  }
}

body.reduce-motion .screen-bg {
  animation: none;
  transform: scale(1.04);
}

body.reduce-motion .menu-aurora {
  animation: none;
}

body.reduce-motion .menu-panel,
body.reduce-motion .menu-overlay__card,
body.reduce-motion .menu-toast {
  animation: none;
}

body.high-contrast .menu-panel,
body.high-contrast .cs-roster,
body.high-contrast .cs-actions,
body.high-contrast .menu-input,
body.high-contrast .menu-overlay__card,
body.high-contrast .menu-toast {
  border-color: var(--text);
}

body.high-contrast .screen-bg::after {
  background: rgba(4, 6, 9, 0.88);
}

/* The four pre-game screens (login, character select, create, delete) on the pre-game sheet's frame and atoms: a head, middle and foot sized to the glass. The sign-in card scrolls its middle; the character screens scroll only a long roster or tall form inside its own box. */

.login-consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: calc(5 * var(--gp));
  align-items: start;
  color: var(--text-2);
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  line-height: round(1.45em, var(--gp));
}

.login-consent__check {
  appearance: none;
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  margin: var(--gp) 0 0;
  border: var(--gp) solid var(--pixel-ink);
  background: #1a1326;
  box-shadow:
    inset var(--gp) var(--gp) 0 #0f0a16,
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  cursor: var(--cursor-action);
}

.login-consent__check:checked {
  box-shadow:
    inset 0 0 0 var(--gp) #1a1326,
    inset 0 0 0 calc(3 * var(--gp)) var(--pixel-honey);
}

.login-consent a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.login-brand {
  display: flex;
  justify-content: center;
}

.login-panel {
  width: min(28rem, 100%);
  margin-inline: auto;
}

.login-panel .menu-panel__body {
  gap: var(--s3);
}

/* Official provider marks keep their published colours and proportions; each login button reserves the same left rail so labels stay centred. */

.auth-provider-mark {
  display: block;
  flex: 0 0 auto;
  object-fit: contain;
}

.auth-provider-mark--discord {
  width: 24px;
  height: 18px;
}

.auth-provider-mark--google {
  width: 20px;
  height: 20px;
}

.login-provider {
  padding-inline: calc(26 * var(--gp));
}

.login-provider__mark {
  position: absolute;
  inset-inline-start: calc(8 * var(--gp));
  inset-block-start: 50%;
  transform: translateY(-50%);
}

.login-provider__label {
  line-height: var(--type-leading-tight);
}

.login-provider.is-loading .login-provider__mark {
  opacity: 0;
}

.login-discord,
.menu-button--discord {
  color: #fff;
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.2px;
  --plate-face: #5865f2;
  --plate-rim:
    inset var(--gp) var(--gp) 0 #7c86f5, inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 #3c449e;
}

.login-google,
.menu-button--google {
  color: #1f1f1f;
  font-weight: var(--type-weight-regular);
  letter-spacing: 0.15px;
  --plate-face: #fff;
  --plate-rim: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 #c9ccd1;
}

.login-or {
  display: flex;
  align-items: center;
  gap: var(--s3);
  color: var(--muted);
  font-size: var(--pg-type-label-size);
  font-family: var(--pg-type-label-family);
  font-weight: var(--type-weight-medium);
  letter-spacing: 1.4px;
  line-height: round(1.2em, var(--gp));
  text-transform: uppercase;
}

.login-or::before,
.login-or::after {
  content: '';
  flex: 1 1 auto;
  height: var(--gp);
  background: var(--pixel-dusk);
}

.login-switch {
  display: block;
  width: 100%;
  min-height: var(--pg-touch);
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  text-align: center;
  cursor: var(--cursor-action);
}

.login-switch:hover:not(:disabled) {
  color: var(--text);
  text-decoration: underline;
}

.login-switch:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

.login-switch:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* A phone held sideways is wide and short, so the card deals the provider on one side and the account fields on the other, but only when it offers both. */

@media (min-width: 40rem) and (max-height: 34rem) {
  /* Two columns, not two half-screens: wider fields would make the card read as a page. */
  .login-panel:has(#login-user) {
    width: min(34rem, 100%);
  }
  .login-panel .menu-panel__body:has(#login-user) {
    display: grid;
    --login-col: round(down, calc((100% - 10 * var(--gp) - 2 * var(--s4)) / 2), var(--gp));
    grid-template-columns: var(--login-col) minmax(0, 1fr) var(--login-col);
    grid-template-areas:
      'consent or email'
      'discord or pass'
      'google  or submit'
      'status  .  switch';
    column-gap: var(--s4);
    align-items: end;
  }
  .login-panel:has(#login-user) .login-consent {
    grid-area: consent;
    align-self: center;
  }
  .login-panel:has(#login-user) .login-discord {
    grid-area: discord;
  }
  .login-panel:has(#login-user) .login-google {
    grid-area: google;
  }
  .login-panel .menu-field:has(#login-user) {
    grid-area: email;
  }
  .login-panel .menu-field:has(#login-pass) {
    grid-area: pass;
  }
  .login-panel:has(#login-user) button[type='submit'] {
    grid-area: submit;
  }
  .login-panel:has(#login-user) .menu-status {
    grid-area: status;
  }
  .login-panel .login-switch {
    grid-area: switch;
  }
  .login-panel .login-or {
    grid-area: or;
    flex-direction: column;
    align-self: stretch;
  }
  .login-panel .login-or::before,
  .login-panel .login-or::after {
    width: var(--gp);
    height: auto;
  }
}

.account-choice {
  width: min(30rem, 100%);
  margin-inline: auto;
}

.account-choice__body {
  gap: var(--s4);
}

.account-choice__email,
.account-choice__intro,
.account-choice__warning p {
  margin: 0;
  color: var(--muted);
  line-height: round(1.5em, var(--gp));
}

.account-choice__email {
  color: var(--text);
  font-weight: var(--type-weight-strong);
}

.account-choice__actions {
  display: grid;
  gap: var(--s3);
}

.account-choice__warning {
  display: grid;
  gap: var(--s3);
  padding: var(--s4);
  border: var(--gp) solid var(--pixel-ink);
  background: #34161c;
  box-shadow: inset 0 0 0 var(--gp) color-mix(in srgb, var(--pixel-debuff) 55%, var(--pixel-dusk));
  clip-path: var(--pixel-notch);
}

.account-choice__confirm-title {
  margin: 0;
  color: var(--text);
  font-size: var(--pg-type-title-size);
  font-family: var(--pg-type-title-family);
}

.account-choice__confirm-title:focus {
  outline: none;
}

.account-choice__irreversible {
  color: var(--danger) !important;
  font-weight: var(--type-weight-strong);
}

.account-choice__status:empty {
  display: none;
}

/* The character screens never scroll the page; only a long roster inside its list and a form inside its card scroll. */

.cs-screen > .pg-main {
  overflow: hidden;
}

.cs-header {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-width: 0;
  min-height: var(--pg-touch);
}

.cs-header__title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding-left: var(--s3);
  border-left: var(--gp) solid var(--pixel-dusk);
  font-weight: var(--type-weight-strong);
  font-size: var(--pg-type-label-size);
  font-family: var(--pg-type-label-family);
  line-height: round(1.3em, var(--gp));
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(238, 233, 222, 0.8);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cs-header__spacer {
  flex: 1 1 auto;
}

@media (max-width: 40rem) {
  .cs-header__title {
    display: none;
  }
}

.cs-header > .menu-button {
  flex: 0 0 auto;
  padding-inline: var(--s4);
}

.account-methods {
  position: fixed;
  inset: 0;
  z-index: 90;
  padding: max(var(--s4), var(--safe-top)) max(var(--s4), var(--safe-right))
    max(var(--s4), var(--safe-bottom)) max(var(--s4), var(--safe-left));
  background: rgba(7, 9, 13, 0.72);
}

.account-methods[hidden] {
  display: none;
}

.account-methods__panel {
  width: min(31rem, 100%);
  max-height: min(36rem, 100%);
  margin: auto;
  overflow: auto;
}

.account-methods__body {
  display: grid;
  gap: var(--s3);
}

.account-methods__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  min-height: var(--pg-touch);
  padding: var(--s3);
  border: var(--gp) solid var(--pixel-ink);
  background: #1a1326;
  box-shadow:
    inset var(--gp) var(--gp) 0 #0f0a16,
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.account-methods__identity {
  display: grid;
  grid-template-columns: calc(14 * var(--gp)) minmax(0, 1fr);
  align-items: center;
  gap: var(--s3);
  min-width: 0;
}

.account-methods__identity-copy {
  display: grid;
  gap: var(--gp);
  min-width: 0;
  line-height: round(1.2em, var(--gp));
}

.account-methods__provider-mark {
  justify-self: center;
}

.account-methods__button-mark {
  width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
}

.account-methods__state {
  color: var(--muted);
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  line-height: round(1.2em, var(--gp));
}

.account-methods__state.is-linked {
  color: var(--accent-2);
}

.account-methods__link {
  flex: 0 0 auto;
}

.account-methods__remove {
  flex: 0 0 auto;
}

@supports (width: calc-size(max-content, size)) {
  :where(.account-methods__row > :is(.account-methods__link, .account-methods__remove)) {
    width: calc-size(max-content, round(up, size, var(--gp)));
  }
}

.account-methods__confirmation {
  display: grid;
  gap: var(--s3);
}

.account-methods__confirmation p {
  margin: 0;
  color: var(--muted);
  line-height: round(1.5em, var(--gp));
}

.account-methods__confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--s2);
}

.account-methods__hint {
  margin: 0;
  color: var(--muted);
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  line-height: round(1.5em, var(--gp));
}

.account-methods__actions {
  display: flex;
  justify-content: flex-end;
}

@media (max-width: 34rem) {
  .cs-header > .menu-button {
    padding-inline: var(--s2);
    font-size: var(--pg-type-label-size);
    font-family: var(--pg-type-label-family);
  }
  .account-methods__row {
    align-items: stretch;
    flex-direction: column;
  }
  .account-methods__link {
    width: 100%;
  }
  .account-methods__remove {
    width: 100%;
  }
  .account-methods__confirm-actions {
    align-items: stretch;
    flex-direction: column;
  }
}

/* The body fills the middle with one stage: the tile roster and action bar, or one at a time the first-hero invitation and the create/delete forms. */

.cs-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  width: min(76rem, 100%);
  margin-inline: auto;
}

.cs-stage {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--pg-gap);
}

/* A form takes the roster's place, centred, scrolling inside its own card. */

.cs-stage > .menu-panel {
  flex: 1 1 auto;
  min-height: 0;
}

.cs-roster {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, min(100%, 9.5rem));
  grid-auto-rows: max-content;
  scroll-snap-type: y proximity;
  scroll-padding-block: var(--s2);
  gap: var(--s2);
  align-content: safe center;
  justify-content: center;
  padding: var(--s2);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}

.cs-roster[hidden] {
  display: none;
}

.cs-empty[hidden] {
  display: none;
}

.cs-slot {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  min-width: 0;
  min-height: var(--pg-touch);
  padding: calc(3 * var(--gp));
  text-align: center;
  --plate-line: var(--pixel-ink);
  border: var(--gp) solid var(--plate-line);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
  color: var(--text);
  cursor: var(--cursor-action);
  scroll-snap-align: start;
  transition: filter var(--dur-fast);
}

.cs-slot:hover {
  filter: brightness(1.15);
}

.cs-slot:focus-visible {
  outline: none !important;
  box-shadow: var(--focus-ring) !important;
  z-index: 1;
}

.cs-slot[aria-current='true'] {
  --plate-line: var(--accent);
  background: var(--pixel-dusk);
}

.cs-slot__figure {
  position: relative;
  display: flex;
  flex: 1 0 auto;
  width: 100%;
  min-height: calc(32 * var(--gp));
  aspect-ratio: 1;
  max-height: round(clamp(64px, 16dvh, 96px), var(--gp));
  overflow: hidden;
  background: #1a1326;
  box-shadow:
    inset var(--gp) var(--gp) 0 #0f0a16,
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-slate);
}

.cs-slot__figure::after {
  content: '';
  position: absolute;
  left: 18%;
  right: 18%;
  bottom: 0;
  height: var(--gp);
  background: var(--pixel-dusk);
}

.cs-slot__portrait {
  position: absolute;
  inset: calc(2 * var(--gp)) 0 var(--gp);
}

/* The Crown rides the figure as a badge; the full faction name stays in the accessible label and action bar. */

.cs-slot__figure .faction-icon--sm,
.cs-slot__figure .faction-icon-missing {
  position: absolute;
  inset-block-start: calc(2 * var(--gp));
  inset-inline-start: calc(2 * var(--gp));
}

.cs-slot__body {
  display: grid;
  gap: var(--gp);
  min-width: 0;
  padding: 0 var(--s1);
}

.cs-slot__name {
  font-weight: var(--type-weight-medium);
  font-size: var(--pg-type-body-size);
  font-family: var(--pg-type-body-family);
  line-height: round(1.25em, var(--gp));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cs-slot__meta {
  font-size: var(--pg-type-label-size);
  font-family: var(--pg-type-label-family);
  line-height: round(1.3em, var(--gp));
  color: var(--muted);
  white-space: nowrap;
}

.cs-create {
  min-height: var(--pg-touch);
  white-space: normal;
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  line-height: round(1.15em, var(--gp));
  text-align: center;
  color: #ddcfaf;
}

.cs-create[hidden] {
  display: none;
}

.cs-slot:disabled,
.cs-create:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

.cs-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: var(--pg-touch);
  padding: var(--s2) var(--s3);
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.cs-actions[hidden] {
  display: none;
}

.cs-actions__id {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  gap: var(--gp);
}

.cs-actions__nameline {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
}

.cs-actions__name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: var(--type-weight-strong);
  font-size: var(--pg-type-panel-title-size);
  font-family: var(--pg-type-panel-title-family);
  line-height: round(1.15em, var(--gp));
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.cs-actions__level {
  flex: 0 0 auto;
  padding: calc(2 * var(--gp)) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-ochre);
  clip-path: var(--pixel-notch);
  color: var(--pixel-honey);
  font-weight: var(--type-weight-strong);
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  line-height: round(1em, var(--gp));
  white-space: nowrap;
}

.cs-actions__nameline .faction-chip {
  flex: 0 0 auto;
}

.cs-actions__nameline .faction-chip__name {
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

.cs-actions__where {
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  color: rgba(238, 233, 222, 0.86);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cs-actions .menu-button--primary {
  flex: 0 1 20rem;
}

.cs-actions .cs-actions__delete {
  flex: 0 0 auto;
}

.cs-empty {
  flex: 0 0 auto;
  align-self: center;
  margin: auto;
  align-items: center;
  justify-content: center;
  width: min(26rem, 100%);
  padding: round(clamp(18px, 3.4dvh, 32px), var(--gp)) round(clamp(18px, 3vw, 28px), var(--gp));
}

.cs-stage > .cs-empty {
  flex: none;
}

.cs-empty .menu-panel__sub {
  max-width: 34ch;
  margin: 0;
}

.cs-empty .menu-button {
  min-width: min(14rem, 100%);
}

.cs-body--solo .cs-roster {
  grid-template-columns: minmax(0, min(100%, 22rem));
  justify-content: center;
}

.cs-body--solo .cs-slot__figure {
  max-height: round(down, min(56dvh, 20rem), var(--gp));
}

@media (min-width: 52rem) and (min-height: 34rem) {
  .cs-roster {
    grid-template-columns: repeat(auto-fit, 11rem);
    gap: var(--s3);
  }
  .cs-slot__figure {
    min-height: calc(42 * var(--gp));
    max-height: none;
  }
}

/* Screen-level failure line for a server error no form owns; the live region stays in the tree when empty. */

.cs-status {
  flex: 0 0 auto;
  justify-content: center;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  padding: var(--s2) var(--s3);
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: inset 0 0 0 var(--gp) color-mix(in srgb, var(--pixel-debuff) 55%, var(--pixel-dusk));
  clip-path: var(--pixel-notch);
  text-align: center;
}

.cs-status:empty {
  visibility: visible;
  margin-block-start: calc(-1 * var(--pg-gap));
  min-height: 0;
  padding: 0;
  border-width: 0;
  background: none;
}

.cs-status:empty::before {
  content: none;
}

/* A phone held sideways: the head keeps only the way out in its corner and the roster starts under that button. */

@media (max-height: 28rem) {
  .cs-screen > .cs-header {
    position: absolute;
    z-index: 3;
    top: var(--menu-safe-top);
    right: var(--menu-safe-right);
    min-height: 0;
  }
  .cs-screen > .cs-header > .ront-brand,
  .cs-screen > .cs-header > .cs-header__title,
  .cs-screen > .cs-header > .cs-header__spacer {
    display: none;
  }
  .cs-screen > .cs-header > .menu-button {
    min-height: calc(18 * var(--gp));
  }
  .cs-screen:has(.cs-stage > :is(.create-panel, .delete-panel)) > .cs-header {
    display: none;
  }
  .cs-screen .cs-body:has(.cs-roster:not([hidden])) {
    padding-top: calc(18 * var(--gp) + var(--s2));
  }
  .cs-actions__where {
    display: none;
  }
}

/* Both forms are bounded cards standing where the hero stood. A form taller
   than the glass scrolls inside its own card; its decisive row stays pinned to
   the card's foot. */

.cs-root .create-panel,
.cs-root .delete-panel {
  flex: 0 1 auto;
  align-self: center;
  margin: auto;
  max-height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  gap: var(--s3);
  padding-bottom: 0;
}

.cs-root .create-panel {
  width: min(44rem, 100%);
}

.cs-root .delete-panel {
  width: min(30rem, 100%);
}

.cs-root .menu-panel > .menu-panel__actions {
  bottom: 0;
  margin-block-end: 0;
  padding: var(--s3) var(--pg-panel-px) var(--pg-panel-py);
}

.cs-root .menu-panel > .menu-status:empty {
  display: none;
}

.create-fields {
  display: flex;
  flex-direction: column;
  max-width: 22rem;
}

.create-count {
  align-self: flex-end;
  margin-top: var(--gp);
  line-height: round(1.2em, var(--gp));
  font-size: var(--pg-type-label-size);
  font-family: var(--pg-type-label-family);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.create-faction-select {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.create-faction-select__head {
  display: flex;
  flex-direction: column;
  gap: var(--gp);
}

.create-faction-select__title {
  margin: 0;
  font-size: var(--pg-type-heading-size);
  font-family: var(--pg-type-heading-family);
  font-weight: var(--type-weight-strong);
  line-height: round(1.2em, var(--gp));
}

.create-faction-select__sub,
.create-faction-select__stake,
.create-faction-select__permanent {
  margin: 0;
  max-width: 64ch;
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  line-height: round(1.45em, var(--gp));
  color: var(--muted);
}

.create-faction-select__stake {
  color: var(--text-2);
}

.create-factions {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s3);
}

/* A Crown card is a plate: the crest on its own ground at the left, the name,
   epithet and description beside it. The description is never cut. The chosen
   Crown takes its ring colour as the plate's outline. */

.create-faction {
  --faction-panel: var(--pixel-night);
  --plate-line: var(--pixel-ink);
  position: relative;
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr);
  align-items: stretch;
  padding: 0;
  overflow: hidden;
  text-align: left;
  border: var(--gp) solid var(--plate-line);
  background: var(--faction-panel);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
  cursor: var(--cursor-action);
  transition: filter var(--dur-fast);
}

.create-faction:hover {
  filter: brightness(1.12);
}

.create-faction:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

.create-faction[aria-checked='true'] {
  --plate-line: var(--faction-ring, var(--accent));
  --faction-panel: var(--pixel-dusk);
}

/* Focus is drawn inside the rim, and the chosen outline stays beside it. */

.create-faction:focus-visible {
  outline: none !important;
  box-shadow: var(--focus-ring) !important;
}

.create-faction:not([aria-checked='true']) .create-faction__art {
  filter: saturate(0.55) brightness(0.7);
}

.create-faction:not([aria-checked='true']):hover .create-faction__art {
  filter: saturate(0.85) brightness(0.9);
}

.create-faction__check {
  position: absolute;
  z-index: 2;
  top: var(--s2);
  right: var(--s2);
  /* The sign-in box's pip, in the Crown's ring colour. */
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: #1a1326;
  box-shadow:
    inset 0 0 0 var(--gp) #1a1326,
    inset 0 0 0 calc(3 * var(--gp)) var(--faction-ring, var(--accent));
  opacity: 0;
}

.create-faction[aria-checked='true'] .create-faction__check {
  opacity: 1;
}

.create-faction__art {
  position: relative;
  display: grid;
  place-items: center;
  padding: var(--s2);
  transition: filter var(--dur) var(--ease);
}

.create-faction__art > .faction-icon--lg {
  width: calc(28 * var(--gp));
  height: calc(28 * var(--gp));
  padding: calc(4 * var(--gp));
}

/* The Crown's art stands dimmed under one flat ink wash. */

.create-faction--has-bg .create-faction__art {
  background: var(--faction-bg, none) center / cover no-repeat;
}

.create-faction--has-bg .create-faction__art::after {
  content: '';
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--pixel-ink) 40%, transparent);
  pointer-events: none;
}

.create-faction__art > * {
  position: relative;
  z-index: 1;
}

.create-faction__body {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-content: center;
  align-items: baseline;
  column-gap: var(--s2);
  padding: var(--s3) calc(var(--s4) + 11 * var(--gp)) var(--s3) var(--s3);
}

.create-faction__name {
  font-weight: var(--type-weight-strong);
  font-size: var(--pg-type-prose-size);
  font-family: var(--pg-type-prose-family);
  line-height: round(1.2em, var(--gp));
  color: var(--text);
}

.create-faction__tagline {
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  font-weight: var(--type-weight-strong);
  line-height: round(1.2em, var(--gp));
  color: var(--faction-ring, var(--accent));
}

.create-faction__blurb {
  grid-column: 1 / -1;
  margin: calc(2 * var(--gp)) 0 0;
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  line-height: round(1.4em, var(--gp));
  color: var(--text-2, var(--muted));
}

/* One blurb at a time: the chosen (or focused) Crown expands to its paragraph,
   the other keeps to name and epithet. The screen opens with less to read, and
   comparing is one arrow key or tap — selection or focus brings the paragraph
   straight back. Plain :focus, deliberately: this is a visibility condition,
   not a focus treatment (a pointer press selects the card anyway), and the
   focus contract reads :focus-visible selectors as ring-drawing rules. */

.create-faction:not(.is-selected):not(:focus) .create-faction__blurb {
  display: none;
}

/* A narrow glass: a slimmer crest column, and the epithet under the name
   rather than beside it. */

@media (max-width: 40rem) {
  .create-faction {
    grid-template-columns: 4.5rem minmax(0, 1fr);
  }
  .create-faction__body {
    grid-template-columns: minmax(0, 1fr);
  }
  .create-faction__art > .faction-icon--lg {
    width: calc(24 * var(--gp));
    height: calc(24 * var(--gp));
    padding: calc(3 * var(--gp));
  }
}

/* Wide and short (a phone held sideways): the copy takes one column, the two
   Crowns the other, so both cards stand whole on the glass above the row that
   commits. The select's children are dealt to the grid directly. */

@media (min-width: 40rem) and (max-height: 34rem) {
  .cs-root .create-panel {
    width: min(52rem, 100%);
    display: grid;
    grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
    grid-template-areas:
      'title     crowns'
      'name      crowns'
      'crownhead crowns'
      'status    permanent'
      'actions   actions';
    grid-template-rows: auto auto 1fr auto auto;
    column-gap: var(--s5);
    row-gap: var(--s3);
    align-items: start;
  }
  .create-panel > .menu-panel__title {
    grid-area: title;
  }
  .create-panel > .create-fields {
    grid-area: name;
    max-width: none;
  }
  .create-panel > .create-faction-select {
    display: contents;
  }
  .create-panel .create-faction-select__head {
    grid-area: crownhead;
  }
  .create-panel .create-faction-select__sub {
    display: none;
  }
  .create-panel .create-faction-select__permanent {
    grid-area: permanent;
  }
  .create-panel .create-factions {
    grid-area: crowns;
    grid-template-columns: minmax(0, 1fr);
  }
  .create-panel .create-factions {
    align-self: start;
  }
  .create-panel > .menu-status {
    grid-area: status;
    align-self: end;
  }
  .create-panel > .menu-status:empty {
    display: block;
    visibility: hidden;
  }
  .create-panel > .menu-panel__actions {
    grid-area: actions;
  }
  .create-faction {
    grid-template-columns: 4rem minmax(0, 1fr);
  }
  .create-faction__art > .faction-icon--lg {
    width: calc(22 * var(--gp));
    height: calc(22 * var(--gp));
    padding: calc(3 * var(--gp));
  }
  .create-faction__body {
    padding: var(--s1) calc(var(--s4) + 11 * var(--gp)) var(--s1) var(--s2);
  }
  .create-faction__name {
    font-size: var(--pg-type-body-size);
    font-family: var(--pg-type-body-family);
  }
  .create-faction__tagline,
  .create-faction__blurb {
    font-size: var(--pg-type-label-size);
    font-family: var(--pg-type-label-family);
  }
  .create-faction__blurb {
    margin-top: var(--gp);
    line-height: round(1.35em, var(--gp));
  }
}

/* On the shortest glass the way out sits in the top-right corner, so the form
   keeps to the left of it. */

@media (min-width: 40rem) and (max-height: 28rem) {
  .cs-root .create-panel {
    width: min(52rem, calc(100% - 4.75rem));
    margin-inline: 0 auto;
    grid-template-columns: minmax(0, round(down, clamp(11rem, 27%, 14rem), var(--gp))) minmax(
        0,
        1fr
      );
  }
}

.delete-echo {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s3);
  border: var(--gp) solid var(--pixel-ink);
  background: #1a1326;
  box-shadow:
    inset var(--gp) var(--gp) 0 #0f0a16,
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.delete-echo__body {
  display: flex;
  flex-direction: column;
  gap: var(--gp);
  min-width: 0;
}

.delete-echo__name {
  font-weight: var(--type-weight-strong);
  font-size: var(--pg-type-heading-size);
  font-family: var(--pg-type-heading-family);
  line-height: round(1.2em, var(--gp));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.delete-echo__meta {
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  color: var(--muted);
}

.delete-panel .menu-panel__sub {
  margin: 0;
}

/* Session overlays and the reconnect pill. These are body-level surfaces rather
   than screens: they wrap whatever is on the page, in the pre-game flow and in
   the world alike, and so they carry their own frame instead of the screen one. */

/* The overlay, not the card, is the scroll container. A card is a short stack of
   flex children whose heights land on fractions of a pixel, so a card that owns
   `overflow-y: auto` rounds its own content one pixel past its own box and shows
   a scrollbar over nothing. Scrolling from out here only ever engages when the
   card genuinely outgrows the viewport. */

.menu-overlay {
  position: fixed;
  inset: 0;
  /* Session band: above the loading cover too — a drop mid-warp must not hide
     behind it. */
  z-index: 400;
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  overflow: auto;
  overscroll-behavior: contain;
  padding: var(--menu-safe-top) var(--menu-safe-right) var(--menu-safe-bottom) var(--menu-safe-left);
}

.menu-overlay--fatal {
  z-index: 401;
}

/* The handheld portrait cover sits above every session card: nothing behind it
   can be read or pressed while the device is upright. */

.menu-overlay--landscape-gate {
  z-index: 402;
}

/* Opaque map-enter loading cover. Stacks above the whole HUD (which reaches
   z-index ~220) so the DOM HUD and the not-yet-revealed black canvas stay hidden
   until the first frame composites. */

.menu-overlay--cover {
  z-index: 300;
  background: #070a0f;
}

.menu-overlay__scrim {
  position: fixed;
  inset: 0;
  /* One flat ink wash: the world stays readable behind it. */
  background: color-mix(in srgb, var(--pixel-ink) 78%, transparent);
  animation: menu-fade 180ms ease-out both;
}

.menu-overlay__card {
  position: relative;
  z-index: 1;
  /* `100%` and not `100vw - 32px`: the overlay already holds the safe insets, and
     a percentage of its content box keeps giving way when a classic scrollbar
     claims its 15px, instead of forcing a second bar along the bottom. */
  width: round(down, min(calc(272 * var(--gp) * var(--pg-condense)), 100%), var(--gp));
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s2);
  padding: round(clamp(18px, 3.4dvh, 30px), var(--gp)) round(clamp(20px, 4vw, 34px), var(--gp));
  overflow: hidden;
  text-align: center;
  /* The menu panel's material: ink outline, dusk line inside, night face, notched. */
  background: var(--pixel-night);
  border: var(--gp) solid var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  color: var(--text);
  animation: menu-pop 180ms cubic-bezier(0.2, 0.78, 0.24, 1) both;
}

.menu-overlay__card[data-tone='danger'] {
  box-shadow: inset 0 0 0 var(--gp) color-mix(in srgb, var(--pixel-debuff) 55%, var(--pixel-dusk));
}

.menu-overlay__icon {
  width: round(clamp(28px, 5dvh, 38px), var(--gp));
  height: round(clamp(28px, 5dvh, 38px), var(--gp));
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.menu-overlay__title {
  font-weight: var(--type-weight-strong);
  font-size: var(--type-pregame-title-size);
  font-family: var(--type-pregame-title-family);
  -webkit-font-smoothing: var(--type-pregame-title-smoothing);
  line-height: round(1.08em, var(--gp));
}

.menu-overlay__msg {
  max-width: 40ch;
  font-size: var(--pg-type-body-size);
  font-family: var(--pg-type-body-family);
  color: color-mix(in srgb, var(--text) 70%, var(--muted));
  line-height: round(1.48em, var(--gp));
}

/* A quieter line under the message: an aside the player can act on later, never the
   thing the card is about. The rotate cover's Home Screen hint is the only one. */

.menu-overlay__aside {
  max-width: 40ch;
  margin-top: var(--s1);
  font-size: var(--pg-type-body-compact-size);
  font-family: var(--pg-type-body-compact-family);
  color: var(--muted);
  line-height: round(1.44em, var(--gp));
}

/* The entering cover's live phase line — the join's real phases landing one after
   another are the liveness signal (the cover has no spinner). */

.menu-overlay__phase {
  font-size: var(--pg-type-prose-size);
  font-family: var(--pg-type-prose-family);
  font-weight: var(--type-weight-medium);
  letter-spacing: 0.04em;
  color: color-mix(in srgb, var(--text) 86%, var(--muted));
}

.menu-overlay__card[data-tone='danger'] .menu-overlay__msg {
  color: color-mix(in srgb, var(--danger) 42%, var(--text));
}

/* A card that is already centred and already has its own ground needs neither
   the pin nor the bleed. */

.menu-overlay__actions {
  position: static;
  margin: var(--s2) 0 0;
  padding: 0;
  background: none;
  justify-content: center;
  margin-top: var(--s2);
}

.menu-overlay__actions .menu-button {
  min-width: min(9rem, 100%);
}

@keyframes menu-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes menu-pop {
  from {
    opacity: 0;
    transform: scale(0.98);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Non-blocking reconnect pill (bottom-centre). */

.menu-toast {
  position: fixed;
  left: 50%;
  bottom: max(var(--s5), var(--safe-bottom));
  transform: translateX(-50%);
  /* Session band: the one line telling the player a recovery is running must not
     sit under a window, the ESC menu or the help sheet. */
  z-index: 402;
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: calc(4 * var(--gp)) var(--s4);
  background: var(--pixel-night);
  border: var(--gp) solid var(--pixel-ink);
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-dusk),
    inset calc(2 * var(--gp)) 0 0 var(--accent);
  clip-path: var(--pixel-notch);
  color: color-mix(in srgb, var(--accent) 68%, var(--text));
  font-weight: var(--type-weight-medium);
  font-size: var(--pg-type-body-size);
  font-family: var(--pg-type-body-family);
  line-height: round(1em, var(--gp));
  animation: menu-toast-in var(--dur-slow) var(--ease) both;
  width: max-content;
  max-width: calc(100% - var(--menu-safe-left) - var(--menu-safe-right));
}

@keyframes menu-toast-in {
  from {
    opacity: 0;
    transform: translate(-50%, calc(4 * var(--gp)));
  }
  to {
    opacity: 1;
    transform: translateX(-50%);
  }
}

.world-prologue {
  position: fixed;
  inset: 0;
  z-index: 4000;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: #05080d;
  color: #fffaf0;
  opacity: 1;
  transition: opacity 200ms ease;
}

.world-prologue.is-leaving {
  opacity: 0;
}

.world-prologue__picture {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: #000;
}

.world-prologue__video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  transition: opacity 240ms ease;
}

.world-prologue.is-ready .world-prologue__video {
  opacity: 1;
}

.world-prologue__caption {
  position: absolute;
  z-index: 4;
  right: max(8vw, var(--safe-right));
  bottom: max(9%, calc(var(--safe-bottom) + 11 * var(--gp)));
  left: max(8vw, var(--safe-left));
  min-height: 2.6em;
  padding: calc(5 * var(--gp)) calc(9 * var(--gp));
  /* A quiet subtitle bar: flat ink, notched, the line in a hard ink shadow. */
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  clip-path: var(--pixel-notch);
  color: #fffaf0;
  font: var(--type-weight-regular) var(--type-prologue-lead-size)/1.35
    var(--type-prologue-lead-family);
  -webkit-font-smoothing: var(--type-prologue-lead-smoothing);
  line-height: round(1.35em, var(--gp));
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  text-align: center;
  text-wrap: balance;
}

.world-prologue__caption:empty {
  visibility: hidden;
}

.world-prologue__skip {
  position: absolute;
  z-index: 6;
  right: max(calc(9 * var(--gp)), var(--safe-right));
  bottom: max(1.3%, var(--safe-bottom));
  display: inline-flex;
  min-height: calc(22 * var(--gp));
  align-items: center;
  gap: calc(4 * var(--gp));
  padding: calc(5 * var(--gp)) calc(7 * var(--gp));
  /* The menu plate: ink outline, lit rim, night face, notched; so the focus
     bracket is drawn inside the rim. */
  --focus-ring:
    inset 0 0 0 var(--gp) var(--pixel-ink), inset 0 0 0 calc(2 * var(--gp)) var(--accent);
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
  color: #fffaf0;
  font: var(--type-weight-medium) var(--type-body-size)/var(--type-leading-tight)
    var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  letter-spacing: 0.04em;
  cursor: pointer;
}

.world-prologue__skip:hover {
  filter: brightness(1.15);
}

.world-prologue__skip:focus-visible {
  outline: none !important;
  box-shadow: var(--focus-ring) !important;
}

/* The key is a square tag sunk into the plate. */

.world-prologue__skip kbd {
  padding: var(--gp) calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  background: var(--pixel-ink);
  color: inherit;
  font: inherit;
}

body[data-ui-profile='handheld'] .world-prologue__skip kbd {
  display: none;
}

body.high-contrast .world-prologue__caption,
body.high-contrast .world-prologue__skip {
  border-color: #f4d58a;
  background: #05070b;
}

@media (prefers-reduced-motion: reduce) {
  .world-prologue,
  .world-prologue__video {
    transition: none;
  }
}

body.reduce-motion .world-prologue,
body.reduce-motion .world-prologue__video {
  transition: none;
}

@media (max-height: 30rem) {
  .world-prologue__skip {
    top: max(calc(5 * var(--gp)), var(--safe-top));
    bottom: auto;
  }

  .world-prologue__caption {
    right: max(13vw, var(--safe-right));
    bottom: max(10%, calc(var(--safe-bottom) + 9 * var(--gp)));
    left: max(13vw, var(--safe-left));
    min-height: 0;
    padding: calc(4 * var(--gp)) calc(6 * var(--gp));
    font-size: var(--type-pregame-body-size);
    font-family: var(--type-pregame-body-family);
    -webkit-font-smoothing: var(--type-pregame-body-smoothing);
  }
}

/* A title card between two cinematics: dark hard bands, a letterbox band above
   and below the two gold rules. */

.cinematic-chapter-break {
  z-index: 4000;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: linear-gradient(
    #090b11 0 round(13%, var(--gp)),
    #111018 round(13%, var(--gp)) round(87%, var(--gp)),
    #07090d round(87%, var(--gp))
  );
  isolation: isolate;
}

.cinematic-chapter-break::before,
.cinematic-chapter-break::after {
  position: absolute;
  inset-inline: round(8%, var(--gp));
  height: var(--gp);
  content: '';
  background: var(--accent-line);
}

.cinematic-chapter-break::before {
  top: round(13%, var(--gp));
}

.cinematic-chapter-break::after {
  bottom: round(13%, var(--gp));
}

.cinematic-chapter-break__content {
  z-index: 1;
  width: min(42rem, 100%);
  margin: auto;
  text-align: center;
}

.cinematic-chapter-break__eyebrow {
  margin: 0 0 var(--s3);
  color: var(--accent);
}

.cinematic-chapter-break__title {
  margin: 0;
  color: var(--text);
  font-family: var(--font-display);
  -webkit-font-smoothing: none;
  font-size: var(--type-cinematic-title-size);
  font-weight: var(--type-weight-strong);
  line-height: round(1.02em, var(--gp));
  letter-spacing: 0.02em;
  text-wrap: balance;
}

.cinematic-chapter-break__copy {
  max-width: 34rem;
  margin: var(--s5) auto 0;
  color: var(--muted);
  font-size: var(--pg-type-prose-size);
  font-family: var(--pg-type-prose-family);
  line-height: round(1.55em, var(--gp));
  text-wrap: balance;
}

.cinematic-chapter-break__actions {
  position: static;
  justify-content: center;
  margin-top: var(--s5);
}

.cinematic-chapter-break__actions .menu-button {
  min-width: min(15rem, 100%);
}

.cinematic-chapter-break__button-icon {
  display: block;
  flex: 0 0 auto;
  width: 1.75em;
  height: 1.75em;
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
  pointer-events: none;
  user-select: none;
}

body.high-contrast .cinematic-chapter-break {
  background: #05070b;
}

@media (max-width: 34rem) {
  .cinematic-chapter-break__actions {
    flex-direction: column;
  }
  .cinematic-chapter-break__actions .menu-button {
    width: 100%;
  }
}

@media (max-height: 30rem) {
  .cinematic-chapter-break__copy {
    margin-top: var(--s3);
  }
  .cinematic-chapter-break__actions {
    margin-top: var(--s4);
  }
}
/* Stacked action bars: cluster layout and stacking only; per-slot visuals are reused from styles.css. Rows are emitted main-first in the DOM (the layout anchor) and rendered bottom-up via flex column-reverse; stack order top to bottom is Extra Bar 2, Extra Bar 1, Main. */

.action-bars {
  --action-bars-slot: max(
    calc(22 * var(--gp)),
    calc(2 * var(--type-metadata-size) * 1.2 + 6 * var(--gp))
  );
  /* The innate rail rides at the left end of the cluster, held off its neighbour by a gap. The fold surface (hud-fold-widgets.css) reserves the same width on its right, so the bar stack sits at the centre of the surface box and at screen centre. */
  /* Even, so the centred bars keep an even width and a whole-pixel left edge. */
  --action-bars-recall-gap: round(calc(12px * var(--ui-scale, 1)), 2px);
  --action-bars-innate-rail: calc(2 * (var(--action-bars-slot) + var(--action-bars-recall-gap)));
  position: fixed;
  bottom: var(--hud-safe-bottom);
  left: 50%;
  transform: translateX(-50%);
  pointer-events: none; /* gaps pass clicks through; slots opt back in below */
  z-index: 30;
}

/* A body-level overlay avoids the arc buttons' clip-path and HUD transforms. */
.skill-aim-stick {
  box-sizing: border-box;
  position: fixed;
  z-index: 100;
  transform: translate(-50%, -50%);
  border: 1px solid var(--accent);
  background: rgb(7 12 14 / 78%);
  box-shadow:
    0 0 0 2px var(--bg),
    inset 0 0 0 3px rgb(201 164 94 / 12%);
  pointer-events: none;
  display: grid;
  place-items: center;
}

.skill-aim-stick__cancel {
  position: absolute;
  box-sizing: border-box;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 0;
  background: var(--ui-control-fill);
  border: 1px solid var(--ui-line-bright);
}

.skill-aim-stick__cancel img {
  width: 66%;
  height: 66%;
  object-fit: contain;
  filter: brightness(1.8);
}

.skill-aim-stick__knob {
  position: relative;
  box-sizing: border-box;
  width: 36px;
  height: 36px;
  border: 2px solid var(--gold-ink);
  background: rgb(7 12 14 / 95%);
  box-shadow: 0 0 0 1px var(--bg);
  overflow: hidden;
}

.skill-aim-stick__knob img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.skill-aim-stick[data-cancel='true'] {
  border-color: var(--ui-line-bright);
  box-shadow:
    0 0 0 2px var(--bg),
    inset 0 0 0 3px rgb(133 151 153 / 8%);
}

.skill-aim-stick[data-cancel='true']:not([data-tap='true']) .skill-aim-stick__cancel {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 20%, var(--ui-control-fill));
}
.skill-aim-stick[data-cancel='true'] .skill-aim-stick__knob {
  visibility: hidden;
}
.action-bars .hot-slot[data-skill-aiming='true'] {
  opacity: 0;
}

.action-bars .hot-slot {
  touch-action: none;
}

/* The innate rail first, then the stack of real bars, in a row so innate slots sit beside the bars. */
.action-bars__content {
  display: flex;
  flex-direction: row;
  align-items: flex-end; /* Recall rests on the main bar's bottom edge */
  gap: var(--action-bars-recall-gap);
}

.action-bars__stack {
  display: flex;
  flex-direction: column-reverse; /* main (first child) sits at the bottom */
  align-items: center;
  gap: 4px;
}

.action-bar {
  display: flex;
  flex-direction: row;
  gap: calc(2 * var(--gp));
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
}

.action-bar.is-hidden {
  display: none;
}

/* The combat anchor is a run of individual wells, never a dark panel across the world. */
.action-bars .hot-slot {
  width: var(--action-bars-slot);
  height: var(--action-bars-slot);
  pointer-events: auto;
}
.action-bars .hot-slot:not(.filled) {
  opacity: 0.5;
}

/* Slot-to-slot drag: the picked-up slot fades and the valid drop target lights up. */
.action-bars .hot-slot.hot-dragging {
  opacity: 0.35;
  cursor: grabbing;
}
.action-bars .hot-slot.hot-dragging.hot-discarding {
  opacity: 0.12;
  filter: grayscale(0.9);
  transform: scale(0.82);
}
.action-bars .hot-slot.pd-drop {
  --well-line: var(--accent);
}

/* Native skill-window drags use a staged occupied slot, kept off-canvas but fully rendered until the browser captures the drag image. */
.action-bars.hotbar-drag-image {
  top: -1000px;
  right: auto;
  bottom: auto;
  left: -1000px;
  transform: none;
  z-index: -1;
}
.action-bars.hotbar-drag-image .hot-slot {
  pointer-events: none;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .action-bars .hot-slot.hot-dragging.hot-discarding {
    transform: none;
    transition: none;
  }
}
.reduce-motion .action-bars .hot-slot.hot-dragging.hot-discarding {
  transform: none;
  transition: none;
}

.action-bars .hot-key {
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  height: auto;
  line-height: var(--type-leading-tight);
}

/* In-place config: one gear just off the right end of the bar stack, hanging off the stack so it stays at the bars' edge whatever the slot size and lands inside the blank band the fold reserves, which clips anything outside it. */
.action-bars__stack {
  position: relative;
}
.action-bars__config {
  --action-bars-config-size: calc(13 * var(--gp));
  position: absolute;
  right: calc(-1 * (var(--action-bars-config-size) + 3 * var(--gp)));
  bottom: 0;
  display: flex;
  align-items: flex-end;
  pointer-events: auto;
}
/* The gear is a plate of the HUD's material; in config mode its outline turns brass. */
.action-bar__handle {
  display: grid;
  place-items: center;
  width: var(--action-bars-config-size);
  height: var(--action-bars-config-size);
  padding: 0;
  cursor: var(--cursor-action);
}
.action-bar__handle img {
  display: block;
  width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  object-fit: contain;
}
.action-bar__handle[aria-pressed='true'] {
  --plate-line: var(--accent);
}

/* Config mode: every slot is a rebind target; the armed slot's inner line is brass. */
.action-bars.is-configuring .hot-slot {
  --well-line: var(--pixel-dusk);
  opacity: 1;
}
.action-bars.is-configuring .hot-slot.is-rebinding {
  --well-line: var(--accent);
}

/* The rest of the HUD steps back while configuring so the bars are the subject; docked widgets stop taking clicks until Done. */
.action-bars-configuring .hud-railed:not(.is-configuring):not(:has(.is-configuring)) {
  opacity: 0.3;
  filter: saturate(0.4);
  pointer-events: none;
  transition:
    opacity 140ms ease,
    filter 140ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .action-bars-configuring .hud-railed:not(.is-configuring):not(:has(.is-configuring)) {
    transition: none;
  }
}

/* The panel is portaled to body, since the fold clips anything beside the bars, and rides above the cluster anchored on the bar stack. */
.action-bars-config {
  position: fixed;
  z-index: 130;
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--gp));
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
  color: var(--pixel-cream);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  white-space: nowrap;
}
.action-bars-config__row {
  display: flex;
  align-items: center;
  gap: calc(6 * var(--gp));
}
.action-bars-config__bars {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--gp));
}
.action-bars-config__label {
  margin-right: var(--gp);
  color: var(--pixel-lilac);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}
/* A choice is a sunk well; the picked one stands up as a plate. */
.action-bars-config__bar,
.action-bars-config__lock {
  --action-bars-config-pick: calc(12 * var(--gp));
  display: grid;
  place-items: center;
  box-sizing: border-box;
  width: var(--action-bars-config-pick);
  height: var(--action-bars-config-pick);
  padding: 0;
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  color: var(--pixel-lilac);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
  cursor: var(--cursor-action);
}
.action-bars-config__bar:hover,
.action-bars-config__lock:hover {
  color: var(--pixel-cream);
}
.action-bars-config__bar.is-picked,
.action-bars-config__lock.is-picked {
  background: var(--pixel-dusk);
  color: var(--pixel-cream);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}
.action-bars-config__bar:focus-visible,
.action-bars-config__lock:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}
.action-bars-config__lock img {
  display: block;
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  object-fit: contain;
  opacity: 0.65;
  filter: grayscale(0.7);
}
.action-bars-config__lock.is-picked img {
  opacity: 1;
  filter: none;
}
.action-bars-config__done {
  width: calc(12 * var(--gp));
  min-height: calc(12 * var(--gp));
  height: calc(12 * var(--gp));
  margin-left: auto;
  padding: 0;
}
.action-bars-config__done img {
  display: block;
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
  object-fit: contain;
}
/* A thumb needs a whole target, not a 24px mark. */
[data-ui-profile='handheld'] :is(.action-bars-config__bar, .action-bars-config__lock) {
  --action-bars-config-pick: var(--hud-touch-min);
}
[data-ui-profile='handheld'] .action-bars-config__done {
  width: var(--hud-touch-min);
  min-height: var(--hud-touch-min);
  height: var(--hud-touch-min);
}
.action-bars-config__hint {
  margin: 0;
  color: var(--pixel-lilac);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}
.action-bars-config__hint.is-armed {
  color: var(--accent);
}

.action-bars__rotate {
  display: none;
}

/* Innate combat commands on desktop: Attack and target-cycle in their own column at the left end of the rail. They are real hot-slots (createHudHotbarSlot) so chrome, badge, hover and sizing come from the shared slot styles; handheld restyles the same classes into the thumb cluster. */
.action-bars__innate {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* An innate key is a three-letter cap (SPC, TAB); its chip sits a pixel nearer the corner so the cap stays inside the square well's outline. */
.action-bars .innate-slot .hot-key {
  top: calc(2 * var(--gp));
  left: calc(2 * var(--gp));
  padding-inline: var(--gp);
}

/* Slot-lock cue: slots keep firing and take a new skill; only drag-off, slot-to-slot move and clear are refused. */
.action-bars.is-locked .hot-slot {
  cursor: var(--cursor-action);
}

/* A slot the coach names (.coach, .coach-hold, .coach-place) wears the lesson's halo (hud-attention.css); nothing is drawn into the well. */

.action-bars.is-placing {
  z-index: 130;
}

.action-bars.is-placing:not(:has(.coach-place)) .action-bar--main .hot-slot {
  --well-line: var(--accent);
}

.action-bars__place-prompt {
  position: absolute;
  right: 0;
  bottom: calc(100% + 8px);
  width: max-content;
  max-width: min(310px, calc(100dvw - 24px));
  padding: 7px 10px;
  border: 1px solid color-mix(in srgb, var(--accent) 72%, transparent);
  background: rgba(8, 12, 17, 0.96);
  box-shadow: 0 6px 0px rgba(0, 0, 0, 0.48);
  color: var(--text);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: 1.3;
  text-align: center;
  pointer-events: none;
}
/* ESC root menu + tabbed Settings window. Standalone from styles.css (which stays
   frozen). Reuses .panel from styles.css and the button kit's classes read-only.
   Spacing is in HUD pixels (--gp) and every control is the HUD's pixel material
   (pixel-chrome.css): an ink outline, a flat face, a one-pixel light. */

.esc-root,
.settings-win {
  position: fixed;
  inset: 0;
  /* System-menu band: above every window, or a window covers the menu and stays clickable through it. */
  z-index: 150;
  display: none;
  align-items: center;
  justify-content: center;
  /* Centred inside the safe edges, not the glass: a column taller than a phone's
     safe box scrolls rather than resting on the home bar. */
  padding: var(--hud-safe-top) var(--hud-safe-right) var(--hud-safe-bottom) var(--hud-safe-left);
  background: color-mix(in srgb, var(--pixel-ink) 60%, transparent);
}
.esc-root__panel {
  width: max-content;
  min-width: min(100%, calc(240px * var(--type-scale, 1)));
  max-width: 100%;
  max-height: 100%;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--gp));
}
.esc-root__panel h1 {
  margin: 0 0 calc(3 * var(--gp));
}
/* The menu's buttons are the kit's variants, stacked full-width; the surface
   only hangs the key cap off the edge. */
.esc-root__btn {
  position: relative;
  flex-shrink: 0;
  white-space: nowrap;
  /* Reserve the shortcut's width on both sides to keep labels centred. */
  padding-inline: calc(6 * var(--gp) + 4ch);
}
/* Key cap worn by whichever control Escape currently performs (Resume at the menu
   root, Back inside Settings), so the key's next effect is readable at a glance. */
.esc-key-cap {
  flex: none;
  padding: 0 calc(3 * var(--gp));
  border: var(--gp) solid currentColor;
  font: var(--type-weight-medium) var(--type-metadata-size)/1.6 var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  opacity: 0.55;
}
/* Taken out of flow so the label stays on the same centre line as its siblings. */
.esc-root__btn .esc-key-cap {
  position: absolute;
  right: calc(6 * var(--gp));
  top: 50%;
  transform: translateY(-50%);
}

/* Themed volume sliders (replace the native blue OS range control): an ink slot
   with a dusk track and a flat fill, and a square knob in the kit's primary. */
.settings-range {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  /* The browser's default range margin pushes a full-width slider past the pane. */
  margin: 0;
  height: calc(10 * var(--gp));
  background: transparent;
  cursor: var(--cursor-action);
  --fill: 50%;
}
.settings-range::-webkit-slider-runnable-track {
  box-sizing: border-box;
  height: calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: linear-gradient(
    90deg,
    var(--accent) 0 var(--fill),
    var(--pixel-dusk) var(--fill) 100%
  );
}
.settings-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  width: calc(5 * var(--gp));
  height: calc(8 * var(--gp));
  margin-top: calc(-3 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ochre);
  box-shadow: inset var(--gp) var(--gp) 0 var(--pixel-honey);
}
.settings-range:focus-visible {
  outline: none;
}
.settings-range:focus-visible::-webkit-slider-thumb {
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-honey),
    0 0 0 var(--gp) var(--accent);
}
.settings-range::-moz-range-track {
  box-sizing: border-box;
  height: calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-dusk);
}
.settings-range::-moz-range-progress {
  height: calc(2 * var(--gp));
  background: var(--accent);
}
.settings-range::-moz-range-thumb {
  box-sizing: border-box;
  width: calc(5 * var(--gp));
  height: calc(8 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ochre);
  box-shadow: inset var(--gp) var(--gp) 0 var(--pixel-honey);
}

/* Sound on/off: a themed toggle instead of a dominating gold bar. */
.settings-toggle {
  width: 100%;
  padding: calc(4 * var(--gp)) calc(6 * var(--gp));
  cursor: var(--cursor-action);
  font-weight: var(--type-weight-strong);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, var(--pixel-night));
  border: var(--gp) solid var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) color-mix(in srgb, var(--accent) 60%, var(--pixel-ink));
  clip-path: var(--pixel-notch);
}
.settings-toggle:hover {
  background: color-mix(in srgb, var(--accent) 22%, var(--pixel-night));
}
.settings-toggle.is-off {
  color: var(--muted);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

.settings-dialog {
  width: calc(600px * var(--type-scale, 1));
  max-width: 94vw;
  /* One frame for every tab. The height is fixed rather than content-driven, so
     switching tabs never resizes the window; a tab taller than the frame scrolls
     inside .settings-pane-host. Sized to seat the tallest non-scrolling tab
     (Display) with room to spare. Its text grows with --type-scale and its
     chrome (padding, title, selects, buttons) with --ui-scale. Clamped to the
     viewport and to the safe box .settings-win pads. */
  height: min(calc(420px * var(--type-scale, 1) + 130px * var(--ui-scale, 1)), 88dvh, 100%);
  display: flex;
  flex-direction: column;
  gap: calc(5 * var(--gp));
  overflow: hidden;
}
.settings-dialog__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(6 * var(--gp));
}
.settings-dialog__title {
  margin: 0;
}
/* Back is the kit's ghost at the dialog's own padding; the key cap beside it
   is the surface's to hang. */
.settings-back {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}
.settings-body {
  display: flex;
  gap: calc(7 * var(--gp));
  min-height: 0;
  flex: 1;
}

/* Left rail of tabs */
.settings-rail {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow-y: auto;
  gap: calc(2 * var(--gp));
  width: calc(140px * var(--type-scale, 1));
  flex: 0 0 calc(140px * var(--type-scale, 1));
  border-right: var(--gp) solid var(--pixel-dusk);
  padding-right: calc(5 * var(--gp));
}
.settings-rail__tab {
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: var(--type-leading-tight);
  flex-shrink: 0;
  text-align: left;
  padding: calc(5 * var(--gp)) calc(6 * var(--gp));
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  background: transparent;
  border: var(--gp) solid transparent;
  color: var(--muted);
  cursor: var(--cursor-action);
  clip-path: var(--pixel-notch);
}
.settings-rail__tab:hover {
  background: var(--pixel-night);
  color: #e6e6e6;
}
.settings-rail__tab.is-active {
  background: var(--pixel-night);
  border-color: var(--pixel-ink);
  color: var(--accent);
  font-weight: var(--type-weight-medium);
  box-shadow:
    inset var(--gp) 0 0 var(--accent),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

/* A notched control clips a ring drawn outside it, so keyboard focus is the bracket inside. */
.settings-toggle:focus-visible,
.settings-rail__tab:focus-visible,
.settings-controls__key:focus-visible {
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent) !important;
}

/* Content pane */
.settings-pane-host {
  flex: 1;
  min-width: 0;
  overflow-y: auto;
}
.settings-pane {
  display: none;
  flex-direction: column;
  gap: calc(5 * var(--gp));
}

/* One control row */
.settings-row {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
}
.settings-row--check {
  flex-direction: row;
  align-items: center;
  gap: calc(4 * var(--gp));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  color: var(--muted);
  cursor: var(--cursor-action);
}
.settings-row__label {
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  color: var(--muted);
}
.settings-row__note {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: var(--muted);
  opacity: 0.75;
}
.settings-row__head {
  display: flex;
  justify-content: space-between;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  color: var(--muted);
}

/* Per-tab footer (reset row) */
.settings-footer {
  display: flex;
  justify-content: flex-end;
  gap: calc(4 * var(--gp));
  margin-top: calc(3 * var(--gp));
  padding-top: calc(5 * var(--gp));
  border-top: var(--gp) solid var(--pixel-dusk);
}

/* Controls (rebind grid) */
.settings-controls {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--gp));
}
.settings-controls__grid {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: calc(2 * var(--gp)) calc(5 * var(--gp));
  align-items: center;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
}
.settings-controls__label {
  color: var(--muted);
}
.settings-controls__key {
  min-width: calc(110px * var(--type-scale, 1));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  padding: var(--gp) calc(4 * var(--gp));
  background: var(--pixel-night);
  border: var(--gp) solid var(--pixel-ink);
  color: #e6e6e6;
  cursor: var(--cursor-action);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}
.settings-controls__key.is-reassigned {
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
}
.settings-controls__ref {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: var(--muted);
  line-height: 1.6;
  margin-top: calc(2 * var(--gp));
}
.settings-controls__ref b {
  color: var(--accent);
}
/* Same two-column shape as the rebind grid above it, so the pointer verbs read
   as more rows of the same reference rather than a paragraph after it. */
.settings-controls__ref-grid {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--gp) calc(5 * var(--gp));
  align-items: baseline;
  margin-top: calc(2 * var(--gp));
}
/* HUD feedback primitives (AlertStack, ResultFlash). Lines over the world are opaque night plates with a one-pixel tone edge; text drawn over the world wears a hard ink outline instead of a plate. */

.alert-stack {
  position: fixed;
  left: round(50%, var(--gp));
  bottom: calc(var(--hotbar-h, calc(48 * var(--gp))) + 6 * var(--gp));
  transform: translateX(round(-50%, var(--gp)));
  display: flex;
  flex-direction: column-reverse; /* newest line nearest the action bars */
  align-items: center;
  gap: calc(2 * var(--gp));
  max-width: 90vw;
  pointer-events: none;
  z-index: 22;
  --feedback-enter-x: 0px;
  --feedback-enter-y: calc(4 * var(--gp));
}

.alert-stack[data-hud-anchor-x='left'] {
  align-items: flex-start;
  --feedback-enter-x: calc(-4 * var(--gp));
}

.alert-stack[data-hud-anchor-x='right'] {
  align-items: flex-end;
  --feedback-enter-x: calc(4 * var(--gp));
}

.alert-stack[data-hud-anchor-y='top'] {
  flex-direction: column;
  --feedback-enter-y: calc(-4 * var(--gp));
}

.alert-line {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: calc(3 * var(--gp));
  max-width: 100%;
  padding: calc(2 * var(--gp)) calc(6 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: inset var(--gp) 0 0 currentColor;
  clip-path: var(--pixel-notch);
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-medium);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  animation: hud-feedback-in var(--hud-fold-duration, 180ms) steps(4, jump-end) both;
}

.alert-line .alert-msg {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Colour is always paired with the tone line and the text, never hue-only. */

.alert-line.error {
  color: var(--danger);
}

.alert-line.warn {
  color: var(--accent-2);
}

.alert-line.info {
  color: var(--muted);
}

.alert-line.skill {
  color: var(--skillmsg, #b48ce0);
}

.alert-stack[data-hud-anchor-x='right'] .alert-line {
  flex-direction: row-reverse;
  box-shadow: inset calc(-1 * var(--gp)) 0 0 currentColor;
  text-align: right;
}

.alert-stack[data-hud-anchor-x='center'] .alert-line {
  box-shadow: inset 0 var(--gp) 0 currentColor;
  text-align: center;
}

.alert-line .alert-x {
  font-variant-numeric: tabular-nums;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--accent);
  opacity: 0.9;
}

.alert-line .alert-x:empty {
  display: none;
}

.alert-line.leaving {
  animation: alert-out 200ms ease-in both;
}

@keyframes hud-feedback-in {
  from {
    opacity: 0;
    transform: translate(var(--feedback-enter-x), var(--feedback-enter-y));
  }
  to {
    opacity: 1;
    transform: translate(0, 0);
  }
}

@keyframes alert-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

/* Motion opt-out: gated by the OS query and the two runtime body classes. Removal stays timer-driven so lines clear on time. */

@media (prefers-reduced-motion: reduce) {
  .alert-line,
  .alert-line.leaving {
    animation: none;
  }
}

body.reduce-flashing .alert-line,
body.reduce-flashing .alert-line.leaving,
body.reduce-motion .alert-line,
body.reduce-motion .alert-line.leaving {
  animation: none;
}

/* Notice feed: same row grammar as the alert line. Docked below the party on desktop and below the radar on handheld, clear of the cast lane. */

.notice-feed {
  display: flex;
  flex-direction: column; /* newest at the bottom; live rows never shift */
  align-items: stretch;
  gap: calc(2 * var(--gp));
  width: max-content;
  max-width: min(100%, 92vw, max(calc(160 * var(--gp)), calc(16 * var(--type-body-size))));
  pointer-events: none;
  z-index: 36;
  --feedback-enter-x: calc(4 * var(--gp));
  --feedback-enter-y: calc(-4 * var(--gp));
}

.notice-feed[data-hud-anchor-x='left'] {
  --feedback-enter-x: calc(-4 * var(--gp));
}

.notice-feed[data-hud-anchor-x='center'] {
  align-items: center;
  --feedback-enter-x: 0px;
}

.notice-feed[data-hud-anchor-y='bottom'] {
  flex-direction: column-reverse;
  --feedback-enter-y: calc(4 * var(--gp));
}

/* Desktop's left rail ends above chat, so the feed drops its oldest rows off the top and the party keeps its frames. */

:root:not([data-ui-profile='handheld'])
  .hud-dock--topLeft
  [data-hud-widget='notices'].hud-railed:not(.hud-layout-detached) {
  flex-shrink: 1;
  min-block-size: 0;
  overflow: hidden;
  justify-content: flex-end;
}

@media (max-height: 520px) {
  [data-ui-profile='handheld']
    .hud-dock--topRight
    :is([data-hud-widget='lostGear'], [data-hud-widget='notices']).hud-railed:not(
      .hud-layout-detached
    ) {
    margin-inline-end: calc(max(var(--hud-touch-min), 24 * var(--gp)) + 9 * var(--gp));
  }
}

/* A phone's right rail stops above the thumb cluster (--hud-dock-right-room); the feed caps and drops its oldest rows, and yields entirely on the shortest glasses. */

[data-ui-profile='handheld']
  .hud-dock--topRight
  [data-hud-widget='notices'].hud-railed:not(.hud-layout-detached) {
  flex-shrink: 1;
  min-height: 0;
  overflow: hidden;
  justify-content: flex-end;
}

.notice-row {
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: calc(5 * var(--gp));
  padding: calc(2 * var(--gp)) calc(4 * var(--gp)) calc(2 * var(--gp)) calc(6 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: inset calc(-1 * var(--gp)) 0 0 var(--notice-tone, var(--muted));
  clip-path: var(--pixel-notch);
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  font-weight: var(--type-weight-medium);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  animation: hud-feedback-in var(--hud-fold-duration, 180ms) steps(4, jump-end) both;
}

.notice-row[data-unfit] {
  visibility: hidden;
}

.notice-feed[data-hud-anchor-x='left'] .notice-row {
  padding-right: calc(6 * var(--gp));
  padding-left: calc(4 * var(--gp));
  box-shadow: inset var(--gp) 0 0 var(--notice-tone, var(--muted));
}

.notice-feed[data-hud-anchor-x='right'] .notice-row {
  flex-direction: row-reverse;
  text-align: right;
}

.notice-feed[data-hud-anchor-x='right'] .notice-row__copy {
  align-items: flex-end;
}

.notice-feed[data-hud-anchor-x='center'] .notice-row {
  box-shadow: inset 0 var(--gp) 0 var(--notice-tone, var(--muted));
}

/* One tone per notice intent; a failure must never read as a neutral system line. */

.notice-row--notable {
  --notice-tone: var(--accent);
}

.notice-row--positive {
  --notice-tone: var(--good);
}

.notice-row--negative {
  --notice-tone: var(--danger);
}

.notice-row--neutral {
  --notice-tone: var(--muted);
}

.notice-row--notable .notice-row__title {
  color: var(--accent);
}

.notice-row--negative .notice-row__title {
  color: var(--danger);
}

.notice-row__icon {
  flex: 0 0 auto;
  width: calc(15 * var(--gp));
  height: calc(15 * var(--gp));
  image-rendering: auto;
  box-shadow: 0 0 0 var(--gp) var(--pixel-ink);
}

.notice-row__copy {
  display: flex;
  flex-direction: column;
  gap: var(--gp);
  flex: 1 1 auto;
  min-width: 0;
  line-height: var(--type-leading-tight);
}

.notice-row__eyebrow {
  color: var(--notice-tone, var(--muted));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* An item name ellipsises; a sentence wraps whole, since the tail of "Quest complete - 500 Gold" matters. */

.notice-row__title {
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.notice-row__title.is-wrapping {
  overflow: visible;
  white-space: normal;
  overflow-wrap: anywhere;
}

.notice-row__badge {
  flex: 0 0 auto;
  align-self: flex-start;
  font-variant-numeric: tabular-nums;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--notice-tone, var(--accent));
}

.notice-row__badge.is-empty {
  display: none;
}

.notice-row.is-leaving {
  animation: notice-out 200ms ease-in both;
}

@keyframes notice-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .notice-row,
  .notice-row.is-leaving {
    animation: none;
  }
}

body.reduce-flashing .notice-row,
body.reduce-flashing .notice-row.is-leaving,
body.reduce-motion .notice-row,
body.reduce-motion .notice-row.is-leaving {
  animation: none;
}

/* ResultFlash: all sizes are whole HUD pixels; motion is gated by readReduceFlashing() and readDisableDamageFlashes() in JS and by the reduced-motion blocks below. */

/* Result rings: hard rings, no blur. A notched piece clips outside itself, so the ring is drawn inside. */

:is(.item-slot, .informant-card):is(.rf-glow, .rf-static) {
  --rf-inset: inset;
}

@keyframes rf-success {
  0% {
    box-shadow: var(--rf-inset,) 0 0 0 0 color-mix(in srgb, var(--gold) 85%, transparent);
  }
  100% {
    box-shadow: var(--rf-inset,) 0 0 0 calc(8 * var(--gp))
      color-mix(in srgb, var(--gold) 0%, transparent);
  }
}

@keyframes rf-fail {
  0%,
  100% {
    transform: translateX(0);
    box-shadow: var(--rf-inset,) 0 0 0 var(--gp) rgba(224, 83, 61, 0);
  }
  20% {
    transform: translateX(calc(-2 * var(--gp)));
    box-shadow: var(--rf-inset,) 0 0 0 var(--gp) rgba(224, 83, 61, 0.95);
  }
  40% {
    transform: translateX(calc(2 * var(--gp)));
  }
  60% {
    transform: translateX(calc(-2 * var(--gp)));
    box-shadow: var(--rf-inset,) 0 0 0 var(--gp) rgba(224, 83, 61, 0.7);
  }
  80% {
    transform: translateX(calc(2 * var(--gp)));
  }
}

@keyframes rf-proc {
  0% {
    box-shadow: var(--rf-inset,) 0 0 0 0 var(--rf-tint, var(--accent));
  }
  55% {
    box-shadow: var(--rf-inset,) 0 0 0 calc(2 * var(--gp)) var(--rf-tint, var(--accent));
  }
  100% {
    box-shadow: var(--rf-inset,) 0 0 0 0 transparent;
  }
}

@keyframes rf-levelup {
  0% {
    box-shadow: var(--rf-inset,) 0 0 0 0 color-mix(in srgb, var(--gold) 90%, transparent);
    filter: brightness(1.35);
  }
  100% {
    box-shadow: var(--rf-inset,) 0 0 0 calc(11 * var(--gp))
      color-mix(in srgb, var(--gold) 0%, transparent);
    filter: brightness(1);
  }
}

.rf-glow.success {
  animation: rf-success 360ms ease-out;
}

.rf-glow.fail {
  animation: rf-fail 360ms steps(2, jump-end);
}

.rf-glow.proc {
  animation: rf-proc 420ms ease-out;
}

.rf-glow.levelup {
  animation: rf-levelup 900ms ease-out;
}

.rf-glow.heal {
  --rf-tint: var(--good);
  animation: rf-proc 420ms ease-out;
}

.rf-glow.mana {
  --rf-tint: var(--info);
  animation: rf-proc 420ms ease-out;
}

.rf-static {
  box-shadow: var(--rf-inset,) 0 0 0 var(--gp) var(--rf-tint, var(--accent));
}

.rf-static.success,
.rf-static.levelup,
.rf-static.proc {
  --rf-tint: var(--accent);
}

.rf-static.fail {
  --rf-tint: var(--danger);
}

.rf-static.heal {
  --rf-tint: var(--good);
}

.rf-static.mana {
  --rf-tint: var(--info);
}

@keyframes float-rise {
  0% {
    opacity: 0;
    transform: translate(round(-50%, 1px), var(--gp)) translateX(var(--rf-drift, 0px));
  }
  12% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(round(-50%, 1px), calc(-14 * var(--gp))) translateX(var(--rf-drift, 0px));
  }
}

.float-num {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translate(round(-50%, 1px), 0);
  font: var(--type-weight-strong) var(--type-heading-size) / var(--type-leading-solid)
    var(--type-heading-family);
  -webkit-font-smoothing: var(--type-heading-smoothing);
  text-shadow:
    var(--gp) 0 0 var(--pixel-ink),
    calc(-1 * var(--gp)) 0 0 var(--pixel-ink),
    0 var(--gp) 0 var(--pixel-ink),
    0 calc(-1 * var(--gp)) 0 var(--pixel-ink);
  pointer-events: none;
  white-space: nowrap;
  z-index: 30;
  animation: float-rise 900ms steps(15, jump-end) forwards;
}

.float-num.heal {
  color: var(--good);
}

.float-num.mana {
  color: var(--info);
}

.float-num.crit {
  color: var(--accent);
  font-size: var(--type-callout-size);
  font-family: var(--type-callout-family);
  -webkit-font-smoothing: var(--type-callout-smoothing);
  font-weight: var(--type-weight-label);
}

/* 1.4x + bolder, not colour-only */

.float-num.static {
  animation: none;
  transform: translate(round(-50%, 1px), calc(-3 * var(--gp)));
  transition: opacity 240ms linear;
}

.big-burst {
  position: fixed;
  left: round(50%, var(--gp));
  top: round(38%, var(--gp));
  transform: translate(round(-50%, var(--gp)), round(-50%, var(--gp)));
  pointer-events: none;
  z-index: 120;
  text-align: center;
  font: var(--type-weight-label) var(--type-hero-size) / 1.05 var(--font-display);
  -webkit-font-smoothing: none;
  letter-spacing: var(--gp);
  text-shadow:
    var(--gp) 0 0 var(--pixel-ink),
    calc(-1 * var(--gp)) 0 0 var(--pixel-ink),
    0 var(--gp) 0 var(--pixel-ink),
    0 calc(-1 * var(--gp)) 0 var(--pixel-ink);
  animation: rf-levelup 1200ms ease-out forwards;
}

.big-burst.levelup {
  color: var(--accent);
}

.big-burst.refine-ok {
  color: var(--good);
}

.big-burst.refine-fail {
  color: var(--danger);
}

.big-burst.craft-ok {
  color: var(--good);
}

.big-burst.craft-fail {
  color: var(--danger);
}

.big-burst.gameover {
  color: var(--danger);
  font-size: var(--type-gameover-size);
  font-family: var(--font-display);
  -webkit-font-smoothing: none;
}

.big-burst.static {
  top: round(22%, var(--gp));
  box-shadow: none;
  animation: none;
  transition: opacity 260ms linear;
}

@media (prefers-reduced-motion: reduce) {
  .rf-glow,
  .float-num,
  .big-burst {
    animation-duration: 1ms !important;
  }
}

body.reduce-motion .rf-glow,
body.reduce-motion .float-num,
body.reduce-motion .big-burst {
  animation-duration: 1ms !important;
}

/* The flyer sits on the body so no window clips it and is driven by the Web Animations API; these rules only style the icon. */

.loot-fly {
  position: fixed;
  left: 0;
  top: 0;
  width: calc(20 * var(--gp));
  height: calc(20 * var(--gp));
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  /* Above every window and overlay, below tooltips and context menus, which the player asked to read. */
  z-index: 190;
}

.loot-fly-icon {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* Rarity rides the crossing as a one-pixel tier outline so it reads in peripheral vision. A common item only lifts. */
  filter: drop-shadow(var(--gp) 0 0 var(--loot-fly-tint))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--loot-fly-tint))
    drop-shadow(0 var(--gp) 0 var(--loot-fly-tint))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--loot-fly-tint))
    drop-shadow(var(--gp) 0 0 var(--pixel-ink))
    drop-shadow(calc(-1 * var(--gp)) 0 0 var(--pixel-ink))
    drop-shadow(0 var(--gp) 0 var(--pixel-ink))
    drop-shadow(0 calc(-1 * var(--gp)) 0 var(--pixel-ink));
}

.loot-fly[data-rarity='common'] .loot-fly-icon {
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.loot-fly-count {
  position: absolute;
  right: calc(-1 * var(--gp));
  bottom: calc(-2 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  color: #fff;
  text-shadow:
    var(--gp) 0 0 var(--pixel-ink),
    calc(-1 * var(--gp)) 0 0 var(--pixel-ink),
    0 var(--gp) 0 var(--pixel-ink),
    0 calc(-1 * var(--gp)) 0 var(--pixel-ink);
}

.loot-fly-count:empty {
  display: none;
}

/* Every rung of the bag ladder takes `loot-land` while reacting. Glow and border animate in script because a bag cell's inline rarity colour is outranked only by an animation. */

/* ItemSlot and Paperdoll: sizes are whole HUD pixels (--gp); each cell honours an optional --slot-size. */

/* A slot is a sunk well. item-slot.ts writes the item's rarity colour as the border colour. --slot-edge is the border width. */

.item-slot {
  --slot-size: calc(22 * var(--gp));
  --slot-edge: var(--gp);
  position: relative;
  width: var(--slot-size);
  height: var(--slot-size);
  box-sizing: border-box;
  border: var(--slot-edge) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: var(--cursor-action);
  user-select: none;
}

.item-slot.filled {
  background: var(--pixel-ink);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}

.item-slot.empty {
  cursor: var(--cursor-default);
}

.item-slot.locked {
  cursor: var(--cursor-default);
  opacity: 0.7;
}

/* Hover is a gold line over the rarity line; focus is the inset bracket, since the notch clips outside. */

.item-slot.filled:hover {
  outline: var(--gp) solid var(--accent);
  outline-offset: calc(-1 * var(--gp));
}

.item-slot:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.item-slot .is-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.item-slot .is-icon img {
  width: 80%;
  height: 80%;
  object-fit: contain;
  image-rendering: auto;
  display: block;
}

/* Steel slot emblem on an empty cell as a "what goes here" hint; specificity beats the item-icon img rule so the smaller size wins. */

.item-slot .is-icon .is-empty-img {
  width: 52%;
  height: 52%;
  object-fit: contain;
  opacity: 0.32;
  filter: grayscale(0.15) brightness(1.05);
  pointer-events: none;
  transition: opacity 0.12s ease;
}

.item-slot.empty:hover .is-icon .is-empty-img {
  opacity: 0.5;
}

/* Corner badges sit flush inside the edge so a narrow slot fits a rarity name and a stack count. */

.item-slot .is-rarity-label {
  position: absolute;
  left: 0;
  bottom: 0;
  max-width: 100%;
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-badge-size);
  font-family: var(--type-badge-family);
  -webkit-font-smoothing: var(--type-badge-smoothing);
  font-weight: var(--type-weight-label);
  line-height: 1;
  text-overflow: clip;
  pointer-events: none;
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}

/* A seal: the blank seal as ground, the icon of what it writes in its well, and that icon's badge clear of a stack count. */

.item-seal {
  position: relative;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
}

.item-seal > img {
  display: block;
  object-fit: contain;
  pointer-events: none;
}

.item-seal > img.item-seal-ground {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
}

.item-seal > img.item-seal-face {
  grid-area: 1 / 1;
  width: 50%;
  height: 50%;
}

.item-seal > img.item-seal-badge {
  position: absolute;
  top: -6%;
  right: -8%;
  width: 40%;
  height: 40%;
  padding: 5%;
  box-sizing: border-box;
  background: var(--pixel-ink);
  box-shadow: 0 0 0 var(--gp) var(--pixel-dusk);
}

.item-slot .is-icon .item-seal.is-ench {
  width: 80%;
  height: 80%;
}

.item-slot .is-qty {
  position: absolute;
  right: 0;
  bottom: 0;
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  font-variant-numeric: tabular-nums;
  color: var(--text);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  pointer-events: none;
}

.item-slot .is-badge.refine-up {
  position: absolute;
  left: 0;
  top: 0;
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-strong);
  color: var(--accent);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
  pointer-events: none;
}

/* Corner state flags use bitmap art so state is never hue-only. */

.item-slot .is-flag {
  position: absolute;
  top: 0;
  right: 0;
  width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
  pointer-events: none;
}

.item-slot.damaged.bound .is-flag.bound {
  right: calc(9 * var(--gp));
}

.item-slot.damaged {
  border-color: var(--danger);
}

.item-slot.damaged .is-icon img {
  filter: grayscale(0.7) brightness(0.85);
}

.item-slot.bound {
  border-color: var(--accent);
}

.item-slot.switch {
  outline: var(--gp) dashed var(--accent);
  outline-offset: calc(-1 * var(--gp));
  opacity: 0.92;
}

.paperdoll {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(4 * var(--gp));
}

.paperdoll .pd-col {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
}

.paperdoll .pd-mannequin {
  position: relative;
  flex: 1 1 auto;
  min-width: calc(48 * var(--gp));
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(3 * var(--gp));
  /* The figure stands in a pixel well on an ink floor band. */
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow:
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk),
    inset 0 calc(-6 * var(--gp)) 0 var(--pixel-ink);
  clip-path: var(--pixel-notch);
  overflow: hidden;
}

.paperdoll .pd-mannequin-img {
  width: 100%;
  height: calc(115 * var(--gp));
  position: relative;
  z-index: 1;
  max-width: 100%;
  max-height: calc(115 * var(--gp));
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.paperdoll .pd-slot[data-eqp] {
  flex: 0 0 auto;
}

/* A two-handed weapon takes the shield slot: the weapon shows dimmed with a marker so the slot reads as blocked. */

.paperdoll .pd-slot.pd-blocked {
  opacity: 0.6;
}

.paperdoll .pd-slot.pd-blocked .is-icon img {
  filter: grayscale(0.5) brightness(0.82);
}

body.high-contrast .item-slot {
  --slot-edge: calc(2 * var(--gp));
}

body.high-contrast .item-slot.filled:hover {
  outline-width: calc(2 * var(--gp));
  outline-offset: calc(-2 * var(--gp));
}

/* DataGrid: the sortable list behind bag, storage, vend, market, refine, mail, quest and roster. The host sets --row-hover and --sel-bar (falls back to --accent). */

.dgrid {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
  color: var(--text);
}

.dgrid-tools {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  padding: calc(2 * var(--gp)) calc(3 * var(--gp));
  border-bottom: var(--gp) solid var(--pixel-dusk);
}

.dgrid-search {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
}

.dgrid-count {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: var(--muted);
}

.dgrid-head {
  display: grid;
  align-items: stretch;
  gap: var(--gp);
  padding: 0 calc(3 * var(--gp));
  border-bottom: var(--gp) solid var(--pixel-dusk);
  background: var(--pixel-ink);
  position: sticky;
  top: 0;
  z-index: 1;
}

.dgrid-th {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--gp));
  padding: calc(2 * var(--gp));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: round(up, 1.2em, var(--gp));
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--muted);
  user-select: none;
}

.dgrid-th.align-r {
  justify-content: flex-end;
}

.dgrid-th.align-c {
  justify-content: center;
}

.dgrid-th.sortable {
  cursor: var(--cursor-action);
}

.dgrid-th.sortable:hover {
  color: var(--text);
}

.dgrid-th.sortable:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.dgrid-th.sorted {
  color: var(--text);
}

.dgrid-sort {
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  line-height: 1;
  color: var(--accent);
}

.dgrid-sort:empty {
  display: none;
}

.dgrid-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 0 calc(3 * var(--gp)) calc(2 * var(--gp));
}

.dgrid-row {
  display: grid;
  align-items: center;
  gap: var(--gp);
  padding: calc(2 * var(--gp)) 0 var(--gp);
  border-bottom: var(--gp) solid var(--pixel-dusk);
  border-left: calc(2 * var(--gp)) solid transparent; /* reserve the selection bar gutter */
  cursor: var(--cursor-default);
}

.dgrid-row:hover {
  outline: var(--gp) solid var(--accent);
  outline-offset: calc(-1 * var(--gp));
  background: var(--row-hover, var(--pixel-dusk));
}

.dgrid-row.selected {
  border-left-color: var(--sel-bar, var(--accent));
  background: var(--row-hover, var(--pixel-dusk));
}

.dgrid-row:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

@supports (height: calc-size(auto, size)) {
  .dgrid-head,
  .dgrid-row {
    height: calc-size(auto, round(up, size, var(--gp)));
  }
}

.dgrid-cell {
  min-width: 0;
  padding: 0 calc(2 * var(--gp));
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.dgrid-cell.align-r {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.dgrid-cell.align-c {
  text-align: center;
}

.dgrid-foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: calc(4 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  border-top: var(--gp) solid var(--pixel-dusk);
  font-variant-numeric: tabular-nums;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  color: var(--muted);
}

.dgrid-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(12 * var(--gp));
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-style: italic;
}

.dgrid-busy {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgb(20 14 28 / 50%);
  z-index: 3;
}

.dgrid-spinner {
  width: calc(14 * var(--gp));
  height: calc(14 * var(--gp));
  border: calc(2 * var(--gp)) solid var(--pixel-dusk);
  border-top-color: var(--accent);
  animation: ui-spin 720ms linear infinite;
}

@keyframes dgrid-row-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes dgrid-row-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

.dgrid-row.dgrid-entering {
  animation: dgrid-row-in 120ms ease-out both;
}

.dgrid-row.dgrid-leaving {
  animation: dgrid-row-out 120ms ease-in both;
  pointer-events: none;
}

body.high-contrast .dgrid-row {
  border-bottom-width: calc(2 * var(--gp));
}

body.high-contrast .dgrid-row.selected {
  border-left-width: calc(3 * var(--gp));
}

body.high-contrast .dgrid-row:hover {
  outline-width: calc(2 * var(--gp));
  outline-offset: calc(-2 * var(--gp));
  background: none;
}

/* Reduced motion or flashing: no spinner spin or row fades; JS also skips the enter/leave classes. */

@media (prefers-reduced-motion: reduce) {
  .dgrid-spinner {
    animation: none;
  }
  .dgrid-row.dgrid-entering,
  .dgrid-row.dgrid-leaving {
    animation: none;
  }
}

body.reduce-motion .dgrid-spinner,
body.reduce-flashing .dgrid-spinner {
  animation: none;
}

body.reduce-motion .dgrid-row.dgrid-entering,
body.reduce-motion .dgrid-row.dgrid-leaving,
body.reduce-flashing .dgrid-row.dgrid-entering,
body.reduce-flashing .dgrid-row.dgrid-leaving {
  animation: none;
}

/* ===== EnhanceWindow (HUD spec §3.2) — grade / enchant / reform shell ========
   The window wears the shared service-window chrome — the modal frame, the
   win-head header, pricePanel gold, the shared `.hud-gauge`, statusPanel and
   the ron-btn kit; the only local paint is the two selection lists and the
   chance fill. Composes ItemSlot (target) and ResultFlash (results).
   Tokens only; every size is whole HUD pixels (--gp). */

/* The frame comes from the shared -panel rule; this owns only the working
   column and the window's dimensions. */

.enhance-panel {
  --win-frame-w: 560;
  --win-frame-h: 560;
  display: flex;
  flex-direction: column;
  color: var(--text);
}

/* The working body between the header and the status line. */

.enhance-panel .enhance-win {
  display: flex;
  flex-direction: column;
  gap: calc(5 * var(--gp));
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  padding: calc(5 * var(--gp));
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
}

/* Target row: the worked ItemSlot + its (refine-prefixed) name. */

.enhance-win .enhance-target {
  display: flex;
  align-items: center;
  gap: calc(5 * var(--gp));
}

.enhance-win .enhance-name {
  font-weight: var(--type-weight-medium);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.enhance-win .enhance-name.muted {
  color: var(--muted);
  font-weight: var(--type-weight-normal);
  font-style: italic;
}

/* Equipment + material lists sit side by side so the gauge and action stay in view. */

.enhance-win .enhance-lists {
  display: flex;
  gap: calc(5 * var(--gp));
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

.enhance-win .enhance-equips {
  height: calc(86 * var(--gp));
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}

.enhance-win .enhance-mats {
  height: calc(86 * var(--gp));
  display: flex;
  flex-direction: column;
  flex: 1.35;
  min-width: 0;
}

/* Column header row — the muted labels over each list. */

.enhance-cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) repeat(
      2,
      minmax(calc(2.4rem * var(--type-scale, 1)), calc(3.2rem * var(--type-scale, 1)))
    );
  gap: calc(3 * var(--gp));
  padding: 0 calc(3 * var(--gp)) calc(2 * var(--gp));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.enhance-cols.cols-one {
  grid-template-columns: minmax(0, 1fr);
}

.enhance-cols span:not(:first-child) {
  text-align: right;
}

/* Rows: listbox options rendered in Lit. The picked row carries its state in
   words and weight, never hue alone. The list is a sunk well; a row is a flat
   face whose one-pixel line takes the hover and picked states. */

.enhance-rows {
  display: flex;
  flex-direction: column;
  gap: var(--gp);
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--gp);
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
}

.enhance-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) repeat(
      2,
      minmax(calc(2.4rem * var(--type-scale, 1)), calc(3.2rem * var(--type-scale, 1)))
    );
  gap: calc(3 * var(--gp));
  align-items: center;
  width: 100%;
  min-width: 0;
  padding: calc(2 * var(--gp)) calc(3 * var(--gp));
  line-height: round(up, 1.2em, var(--gp));
  border: var(--gp) solid transparent;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  text-align: left;
  cursor: var(--cursor-action);
}

.enhance-row:hover:not(:disabled) {
  border-color: var(--pixel-slate);
  background: var(--pixel-dusk);
}

.enhance-row:focus-visible {
  outline: none !important;
  box-shadow: var(--ui-focus-ring) !important;
}

.enhance-row.is-picked {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: var(--type-weight-strong);
}

.enhance-row:disabled {
  opacity: 0.55;
  cursor: var(--cursor-default);
}

.enhance-row-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.enhance-row-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.enhance-row.insufficient .enhance-have-short,
.enhance-have-short {
  color: var(--danger);
  font-weight: var(--type-weight-strong);
}

.enhance-empty {
  margin: 0;
  padding: calc(4 * var(--gp));
  color: var(--muted);
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-style: italic;
}

/* Gold cost line — the amount itself is the shared pricePanel. */

.enhance-win .enhance-gold {
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* Success gauge — the shared `.hud-gauge` at window scale; only the row height
   and the `.chance` fill's flat ochre are local. */

.enhance-win .enhance-gauge {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
}

.enhance-win .enhance-gauge-label {
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--muted);
}

.enhance-win .enhance-gauge .hud-gauge {
  --gauge-h: calc(8 * var(--gp));
  --gauge-ring: var(--pixel-dusk);
}

body.high-contrast .enhance-win .enhance-gauge .hud-gauge {
  --gauge-ring-w: calc(2 * var(--gp));
}

.enhance-win .hud-gauge-fill.chance {
  background: var(--pixel-ochre);
}

/* Guarantee / protect copy — never hue-only. */

.enhance-win .enhance-guaranteed,
.enhance-win .enhance-protect {
  margin: 0;
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  font-weight: var(--type-weight-medium);
  color: var(--good, #6fd06a);
}

.enhance-win .enhance-blessing {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--gp));
  font-size: var(--type-body-compact-size);
  font-family: var(--type-body-compact-family);
  -webkit-font-smoothing: var(--type-body-compact-smoothing);
  cursor: var(--cursor-action);
}

.enhance-win .enhance-blessing input {
  margin: 0;
}

/* Smith pick-dialog (HUD §3.2) — the small "choose one item" window shared by
   the equip picker, the appraise list and the card-insert list. Reuses the
   GameWindow chrome + DataGrid; only the body layout + the gold confirm button
   (mirrors .enhance-action, scoped here) are local. Tokens only. */

.smith-pick {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--gp));
  min-width: calc(110 * var(--gp));
  padding: calc(2 * var(--gp));
  color: var(--text);
  font-size: var(--type-body-size);
  font-family: var(--type-body-family);
  -webkit-font-smoothing: var(--type-body-smoothing);
}

.smith-pick .smith-pick-grid {
  height: calc(110 * var(--gp));
  display: flex;
}

.smith-pick .smith-pick-grid .dgrid {
  min-height: 0;
}

.smith-pick .smith-pick-action {
  align-self: stretch;
}

/* ── 2.f Overhead speech and the threat bar ─────────────────────────────────
   Names, bars and marks over actors are pixel sprites drawn in the scene. What an
   actor says stays HTML: a free-typed line in any script reads at the device's own
   resolution. Each bubble is positioned in CSS pixels from the renderer's speech
   feed, its tail on the point above the actor's overhead stack. */

.speech-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none; /* a bubble must never eat a click meant for the actor */
  z-index: 6; /* over the canvas, under every HUD window and the target panel */
  contain: strict; /* bubble writes can't invalidate layout outside this layer */
}

/* A bubble is the HUD's box: same ink, same hairline, same 1px black edge. A lit
   top edge in the speaker's accent and a tail, the only one in the HUD, are what
   make it read as spoken rather than as one more gauge. */

.speech-bubble {
  --speech-accent: var(--gold);
  position: absolute;
  top: 0;
  left: 0;
  width: max-content;
  max-width: calc(190px * var(--ui-scale));
  /* Lifts the tail's tip clear of the point the bubble hangs from. */
  margin-top: calc(-6px * var(--ui-scale));
  will-change: transform;
  padding: calc(3px * var(--ui-scale)) calc(8px * var(--ui-scale));
  border: 1px solid rgba(0, 0, 0, 0.65);
  /* Thicker than the other three edges and never faded: at gameplay distance a
     hairline accent disappears, and this edge is the only thing separating your
     own line from everyone else's. */
  border-top: calc(2px * var(--ui-scale)) solid var(--speech-accent);
  background: rgba(4, 6, 10, 0.86);
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(0, 0, 0, 0.5);
  font: var(--type-weight-regular) var(--type-label-size) / 1.35 var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  color: #e9eef6;
  text-align: center;
  text-shadow: 0 1px 0px #000;
  /* A long line wraps rather than clipping: the glyph budget that keeps it to a
     few rows is applied where the line is raised, and the chat log keeps the
     whole thing either way. Nothing here may set `overflow`, which would take the
     tail with it. */
  overflow-wrap: break-word;
}

/* Your own line reads cool, so it separates from the warm accent every other
   speaker on screen is drawn with. */

.speech-bubble.self {
  --speech-accent: #9bd0ff;
}

.speech-bubble::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: calc(-5px * var(--ui-scale));
  width: 0;
  height: 0;
  transform: translateX(-50%);
  border-left: calc(4px * var(--ui-scale)) solid transparent;
  border-right: calc(4px * var(--ui-scale)) solid transparent;
  border-top: calc(5px * var(--ui-scale)) solid rgba(4, 6, 10, 0.86);
}

/* The threat bar is the HUD's shared `.hud-gauge`, drawn on the target panel. */

.nameplate-bar {
  width: 100%;
}

/* Threat: how close the local player is to taking this monster. 100% = holding
   it. The band carries the colour AND the label, never colour alone. */

.nameplate-threat {
  --threat-accent: #7f8b9c;
}

.nameplate-threat-fill {
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--threat-accent) 92%, #fff 8%),
    var(--threat-accent)
  );
}

.nameplate-threat[data-band='holding'] {
  --gauge-ring: var(--threat-accent);
}

@media (prefers-reduced-motion: reduce) {
  .nameplate-bar-fill {
    transition: none;
  }
}

body.reduce-motion .nameplate-bar-fill,
body.reduce-flashing .nameplate-bar-fill {
  transition: none;
}

/* High contrast: bubbles and gauge labels float over a live scene, so they cannot
   rely on a text shadow alone to stay legible. */

body.high-contrast .nameplate-bar-label {
  color: #fff;
  text-shadow:
    1px 0 0 #000,
    -1px 0 0 #000,
    0 1px 0 #000,
    0 -1px 0 #000;
}

body.high-contrast .speech-bubble {
  background: rgba(0, 0, 0, 0.94);
  border-color: #fff;
  color: #fff;
  text-shadow:
    1px 0 0 #000,
    -1px 0 0 #000,
    0 1px 0 #000,
    0 -1px 0 #000;
}

body.high-contrast .speech-bubble::after {
  border-top-color: rgba(0, 0, 0, 0.94);
}

/* Health is the panel's headline; threat is the line under it. Same box, same
   tokens, drawn thinner and off full chroma so a monster already on the player
   does not paint a saturated slab across the frame. */

.target-threat {
  /* Tall enough for its label's 9px line inside the rim; thinner reads cut the text. */
  --gauge-h: calc(7 * var(--gp));
  margin-top: var(--gp);
}

.target-threat .nameplate-threat-fill {
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--threat-accent) 42%, transparent),
    color-mix(in srgb, var(--threat-accent) 28%, transparent)
  );
}

/* Holding is the band the player is normally in, so at panel size it is the
   resting state of the frame, not an alarm: the accent stays on the fill and the
   box keeps the neutral edge every other gauge has. */

.target-threat[data-band='holding'] {
  --gauge-ring: rgba(220, 232, 226, 0.16);
}

.target-threat .nameplate-threat-label {
  font-size: var(--type-glyph-readable-size);
  font-family: var(--type-glyph-readable-family);
  -webkit-font-smoothing: var(--type-glyph-readable-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.86);
}

/* HUD marks: the small standing facts a surface used to print as a word tag —
   contested ground, the gear a death here can take, the place you are standing
   in. One size language, so a mark is the same object wherever it is worn and a
   player learns it once.
   The art carries its own colour and value, so nothing here tints or fills
   behind it; a drop shadow is all a mark needs to hold its edge over terrain. */

.hud-mark {
  width: calc(15px * var(--ui-scale, 1));
  height: calc(15px * var(--ui-scale, 1));
  flex: none;
  object-fit: contain;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.8));
}

.hud-mark[hidden] {
  display: none;
}

/* A mark is the anchor of the card that explains it, so the pointer has to be
   able to land on it even where its surface is otherwise inert. */

.hud-mark:not([aria-hidden='true']) {
  pointer-events: auto;
  cursor: var(--cursor-help, help);
}

.hud-mark:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Quest journal: owner-grouped accordion with detail kept beside its navigation row.
   Drawn in the HUD's pixel material (pixel-chrome.css): hard HUD-pixel rules, flat
   faces, square tags, and each quest's owner colour as a one-pixel line. */
.window.win-quests {
  width: calc(270 * var(--gp));
  max-width: calc(100vw - 32px);
}

.win-quests .win-body {
  max-height: min(72vh, calc(320 * var(--gp)));
  padding: 0;
  overflow: auto;
}

ront-quest-achievement-window,
.qa-section {
  display: block;
  min-width: 0;
}

.qa-journal-list {
  min-width: 0;
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
}

.qa-owner-group {
  --qa-owner-color: var(--accent);
}
.qa-owner-group + .qa-owner-group {
  border-block-start: var(--gp) solid var(--pixel-dusk);
}

.qa-owner-heading {
  position: sticky;
  z-index: 3;
  top: 0;
  min-height: calc(15 * var(--gp));
  border-block-end: var(--gp) solid var(--pixel-ink);
  padding: 0 calc(5 * var(--gp));
  background: color-mix(in srgb, var(--qa-owner-color) 8%, var(--pixel-night));
  box-shadow: inset 0 calc(-1 * var(--gp)) 0
    color-mix(in srgb, var(--qa-owner-color) 40%, var(--pixel-dusk));
}

.qa-owner {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  min-height: inherit;
  margin: 0;
  color: color-mix(in srgb, var(--qa-owner-color) 72%, var(--text));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-emphasis);
  letter-spacing: 0.12em;
  line-height: 1;
  text-transform: uppercase;
}

.qa-owner img {
  width: calc(11 * var(--gp));
  height: calc(11 * var(--gp));
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.qa-owner small {
  display: grid;
  place-items: center;
  min-width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  margin-inline-start: auto;
  border: var(--gp) solid color-mix(in srgb, var(--qa-owner-color) 32%, var(--pixel-dusk));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

.qa-owner small::before {
  content: attr(data-count);
}

.qa-owner-list {
  display: grid;
}
.qa-quest-item {
  min-width: 0;
}
.qa-quest-item + .qa-quest-item {
  border-block-start: var(--gp) solid var(--pixel-dusk);
}

.qa-quest-index-button {
  position: relative;
  display: grid;
  grid-template-columns: calc(5 * var(--gp)) minmax(0, 1fr) auto;
  gap: calc(2 * var(--gp)) calc(4 * var(--gp));
  align-items: center;
  width: 100%;
  min-height: calc(24 * var(--gp));
  border: 0;
  padding: calc(4 * var(--gp)) calc(5 * var(--gp));
  color: var(--text);
  background: transparent;
  font: inherit;
  text-align: start;
  cursor: var(--cursor-action);
}

.qa-quest-index-button::after {
  position: absolute;
  inset: calc(4 * var(--gp)) auto calc(4 * var(--gp)) 0;
  width: var(--gp);
  content: '';
  background: color-mix(in srgb, var(--qa-owner-color) 52%, var(--pixel-night));
}

.qa-quest-index-button:hover {
  background: var(--pixel-night);
}

.qa-quest-item.is-expanded > .qa-quest-index-button {
  background: color-mix(in srgb, var(--qa-owner-color) 13%, var(--pixel-night));
  box-shadow: inset var(--gp) 0 0 color-mix(in srgb, var(--qa-owner-color) 78%, var(--text));
}

.qa-quest-index-button:focus-visible {
  z-index: 1;
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent) !important;
}

.qa-quest-index-button .qa-row-title {
  grid-column: 2;
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-label);
  line-height: 1.25;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.qa-index-objective {
  grid-column: 2;
  min-width: 0;
  overflow: hidden;
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.qa-quest-index-button > strong {
  grid-column: 3;
  grid-row: 2;
  color: var(--text);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* A story row says where on the road it is, in the track's own brass, so the
   chapter count the compass reads is the same count the journal shows. */
.qa-index-story {
  color: color-mix(in srgb, var(--qa-owner-color) 78%, var(--text));
  font-weight: var(--type-weight-label);
  letter-spacing: 0.04em;
}

/* A one-shot step previews as a word, not a fraction. */
.qa-index-step {
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.qa-index-step.is-done {
  color: var(--good);
}

.qa-lifecycle {
  grid-column: 3;
  grid-row: 1;
  align-self: start;
  border: var(--gp) solid color-mix(in srgb, var(--qa-owner-color) 40%, var(--pixel-dusk));
  padding: var(--gp) calc(2 * var(--gp));
  color: color-mix(in srgb, var(--qa-owner-color) 68%, var(--text));
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-emphasis);
  letter-spacing: 0.07em;
  line-height: 1.2;
  text-transform: uppercase;
  white-space: nowrap;
}

.qa-row-chevron {
  grid-column: 1;
  grid-row: 1 / span 2;
  width: calc(5 * var(--gp));
  height: calc(3 * var(--gp));
  background: var(--muted);
  /* A chevron stepped in HUD pixels: it points down under an open row and at
     the title of a closed one. */
  clip-path: polygon(
    0 0,
    calc(2 * var(--gp)) 0,
    calc(2 * var(--gp)) var(--gp),
    calc(3 * var(--gp)) var(--gp),
    calc(3 * var(--gp)) 0,
    calc(5 * var(--gp)) 0,
    calc(5 * var(--gp)) var(--gp),
    calc(4 * var(--gp)) var(--gp),
    calc(4 * var(--gp)) calc(2 * var(--gp)),
    calc(3 * var(--gp)) calc(2 * var(--gp)),
    calc(3 * var(--gp)) calc(3 * var(--gp)),
    calc(2 * var(--gp)) calc(3 * var(--gp)),
    calc(2 * var(--gp)) calc(2 * var(--gp)),
    var(--gp) calc(2 * var(--gp)),
    var(--gp) var(--gp),
    0 var(--gp)
  );
  rotate: -90deg;
}

.qa-quest-item.is-expanded .qa-row-chevron {
  rotate: none;
}

.qa-lifecycle--ready {
  border-color: color-mix(in srgb, var(--accent) 70%, var(--pixel-ink));
  color: color-mix(in srgb, var(--accent) 70%, var(--text));
  background: color-mix(in srgb, var(--accent) 14%, var(--pixel-ink));
}

/* The pane opens under its row rather than appearing: a short settle from just
   above, so the eye follows the chevron down into the detail. */
.qa-quest-detail-pane {
  --qa-owner-color: var(--accent);
  min-width: 0;
  animation: qa-detail-open 160ms ease-out backwards;
  border-block-start: var(--gp) solid var(--pixel-ink);
  padding: calc(5 * var(--gp)) calc(6 * var(--gp)) calc(7 * var(--gp)) calc(14 * var(--gp));
  background: var(--pixel-night);
}

.qa-quest-description {
  margin: 0;
  border-inline-start: var(--gp) solid
    color-mix(in srgb, var(--qa-owner-color) 55%, var(--pixel-night));
  padding-inline-start: calc(5 * var(--gp));
  color: color-mix(in srgb, var(--text) 72%, var(--muted));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.42;
}

.qa-objective-section {
  margin-block-start: calc(5 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-dusk);
  padding-block-start: calc(4 * var(--gp));
}

.qa-objective-section h3 {
  margin: 0 0 calc(4 * var(--gp));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-emphasis);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.qa-objectives {
  display: grid;
  gap: calc(4 * var(--gp));
}

.qa-objective {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: calc(2 * var(--gp)) calc(4 * var(--gp));
  align-items: center;
}

.qa-objective-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(5 * var(--gp));
  color: var(--text);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}

.qa-objective-heading span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.qa-objective-heading strong {
  flex: 0 0 auto;
  color: var(--text);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
}

/* A scripted step's instruction is a whole sentence, not a target name: it wraps
   instead of clipping, and its row carries no counter or bar. */

.qa-objective--goal .qa-objective-heading span {
  overflow: visible;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.42;
  white-space: normal;
}

@keyframes qa-detail-open {
  from {
    opacity: 0;
    translate: 0 calc(-2 * var(--gp));
  }
  to {
    opacity: 1;
    translate: 0 0;
  }
}

/* A step is a checklist line: a state word where the counter sits on a counted
   row, and no bar. Done is said in the journal's one "finished" colour. */
.qa-objective--step .qa-objective-heading span {
  overflow: visible;
  white-space: normal;
  line-height: 1.35;
}
.qa-step-state {
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.qa-objective--step.is-done .qa-step-state {
  color: var(--good);
}
/* A contested event's share: own Crown over the other (quest-crown-share.ts). */
.qa-progress-pill .crown-share-ours {
  background: var(--good);
}
.qa-progress-pill .crown-share-theirs {
  background: color-mix(in srgb, var(--danger) 70%, var(--pixel-night));
}

.qa-progress-pill {
  width: 100%;
  --gauge-h: calc(4 * var(--gp));
}

/* The own share lies under the shared one and shows past its end; an ink
   pixel column at the shared fill's end parts the two. */
.qa-progress-shared {
  background: var(--qa-owner-color);
  box-shadow:
    inset calc(-1 * var(--gp)) 0 0 rgb(255 255 255 / 35%),
    var(--gp) 0 0 var(--pixel-ink);
}

.qa-progress-self {
  background: repeating-linear-gradient(
    90deg,
    color-mix(in srgb, var(--accent) 38%, var(--text)) 0 var(--gp),
    var(--accent-2) var(--gp) calc(2 * var(--gp))
  );
}

.qa-quest-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(4 * var(--gp)) calc(7 * var(--gp));
  margin-block-start: calc(5 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-dusk);
  padding-block-start: calc(4 * var(--gp));
}

.qa-quest-detail,
.qa-self-contribution {
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
}
.qa-self-contribution {
  color: color-mix(in srgb, var(--accent) 62%, var(--text));
  font-weight: var(--type-weight-strong);
}
.qa-quest-detail--urgent {
  color: var(--danger);
  font-weight: var(--type-weight-label);
}

.qa-quest-reward {
  flex-basis: 100%;
  border-inline-start: var(--gp) solid color-mix(in srgb, var(--accent) 62%, var(--pixel-ink));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  color: color-mix(in srgb, var(--accent) 62%, var(--text));
  background: color-mix(in srgb, var(--accent) 10%, var(--pixel-ink));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.35;
}

/* Itemized rewards: each promised item as icon + name, on the same accent rail
   the prose reward line uses. */
.qa-reward-section {
  margin-block-start: calc(5 * var(--gp));
}

.qa-reward-section h3 {
  margin: 0 0 calc(3 * var(--gp));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.qa-reward-items {
  display: flex;
  flex-wrap: wrap;
  gap: calc(3 * var(--gp)) calc(5 * var(--gp));
}

.qa-reward-item {
  display: inline-flex;
  align-items: center;
  gap: calc(3 * var(--gp));
  border: var(--gp) solid color-mix(in srgb, var(--accent) 34%, var(--pixel-ink));
  padding: calc(2 * var(--gp)) calc(4 * var(--gp)) calc(2 * var(--gp)) calc(2 * var(--gp));
  color: color-mix(in srgb, var(--accent) 62%, var(--text));
  background: color-mix(in srgb, var(--accent) 8%, var(--pixel-ink));
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.qa-reward-item-icon {
  width: calc(11 * var(--gp));
  height: calc(11 * var(--gp));
  object-fit: contain;
}

.qa-reward-exp > span {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* The day's double: an icon beside the title and on the EXP it doubles. */
.qa-reward-boost,
.qa-boost-mark {
  flex: 0 0 auto;
  width: calc(9 * var(--gp));
  height: calc(9 * var(--gp));
  object-fit: contain;
}
.qa-boost-mark {
  grid-column: 3;
  grid-row: 1;
  align-self: start;
}

/* Achievements use one continuous chronicle plane: rank first, milestones second,
   recent authority events last. Rows are separated by rhythm and rails rather
   than nested card containers. */
.window.win-achievements {
  width: calc(235 * var(--gp));
  max-width: calc(100vw - 32px);
}

.win-achievements .win-body {
  max-height: min(72vh, calc(310 * var(--gp)));
  padding: 0;
  overflow: auto;
}

.qa-achievements {
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
}

.qa-achievements-overview {
  display: grid;
  grid-template-columns: calc(29 * var(--gp)) minmax(0, 1fr) auto;
  gap: calc(2 * var(--gp)) calc(6 * var(--gp));
  align-items: center;
  padding: calc(7 * var(--gp)) calc(7 * var(--gp)) calc(6 * var(--gp));
  border-block-end: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: inset 0 calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

.qa-achievements-emblem {
  grid-row: 1 / span 3;
  width: calc(29 * var(--gp));
  height: calc(29 * var(--gp));
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}

.qa-achievements-rank {
  display: grid;
  gap: var(--gp);
}
.qa-achievements-rank span {
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.13em;
  text-transform: uppercase;
}
.qa-achievements-rank strong {
  color: color-mix(in srgb, var(--accent) 64%, var(--text));
  font-size: var(--type-title-size);
  font-family: var(--font-display);
  -webkit-font-smoothing: none;
  line-height: 1.1;
}

.qa-achievements-totals {
  display: flex;
  align-items: center;
  justify-content: end;
  gap: calc(6 * var(--gp));
}
.qa-achievements-totals span {
  display: grid;
  justify-items: end;
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.qa-achievements-totals strong {
  color: var(--text);
  font-size: var(--type-prose-size);
  font-family: var(--type-prose-family);
  -webkit-font-smoothing: var(--type-prose-smoothing);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

.qa-achievement-level {
  grid-column: 2 / -1;
  display: flex;
  justify-content: space-between;
  gap: calc(4 * var(--gp));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}
.qa-achievement-level strong {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.qa-achievement-level-progress {
  grid-column: 2 / -1;
  --gauge-h: calc(4 * var(--gp));
}
.qa-achievement-level-progress span {
  background: var(--accent);
}

.qa-achievement-list {
  display: grid;
}
.qa-achievement-row {
  position: relative;
  display: grid;
  grid-template-columns: calc(17 * var(--gp)) minmax(0, 1fr) auto;
  gap: calc(4 * var(--gp));
  align-items: center;
  min-height: calc(27 * var(--gp));
  padding: calc(4 * var(--gp)) calc(6 * var(--gp));
  border-block-end: var(--gp) solid var(--pixel-dusk);
}
.qa-achievement-row::before {
  position: absolute;
  inset: calc(4 * var(--gp)) auto calc(4 * var(--gp)) 0;
  width: var(--gp);
  content: '';
  background: var(--pixel-slate);
}
.qa-achievement-row--claimable {
  background: color-mix(in srgb, var(--accent) 7%, var(--pixel-night));
}
.qa-achievement-row--claimable::before {
  background: var(--accent);
}
.qa-achievement-row--rewarded {
  opacity: 0.76;
}
.qa-achievement-row--rewarded::before {
  background: color-mix(in srgb, var(--good) 68%, var(--pixel-ink));
}
.qa-achievement-row-icon {
  width: calc(17 * var(--gp));
  height: calc(17 * var(--gp));
  object-fit: contain;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}
.qa-achievement-row-copy {
  min-width: 0;
}
.qa-row-title {
  min-width: 0;
  overflow: hidden;
  color: var(--text);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  font-weight: var(--type-weight-label);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.qa-row-meta {
  margin-top: calc(2 * var(--gp));
  color: var(--muted);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}
.qa-achievement-state {
  grid-column: 3;
  grid-row: 1;
  justify-self: end;
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.qa-achievement-row--claimable .qa-achievement-state {
  color: color-mix(in srgb, var(--accent) 72%, var(--text));
}
.qa-achievement-row .ron-btn {
  grid-column: 3;
  grid-row: 1;
  margin-top: calc(19px * var(--ui-scale));
}

.qa-achievement-result {
  margin: calc(5 * var(--gp)) calc(6 * var(--gp)) 0;
  border-inline-start: var(--gp) solid var(--muted);
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  color: var(--muted);
  background: var(--pixel-ink);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
}
.qa-achievement-result.is-success {
  border-color: var(--good);
  color: color-mix(in srgb, var(--good) 66%, var(--text));
}
.qa-achievement-result.is-failure {
  border-color: var(--danger);
  color: color-mix(in srgb, var(--danger) 68%, var(--text));
}

.qa-achievement-activity {
  padding: calc(6 * var(--gp));
}
.qa-achievement-activity h2 {
  margin: 0 0 calc(3 * var(--gp));
  color: var(--muted);
  font-size: var(--type-micro-size);
  font-family: var(--type-micro-family);
  -webkit-font-smoothing: var(--type-micro-smoothing);
  font-weight: var(--type-weight-label);
  letter-spacing: 0.13em;
  text-transform: uppercase;
}
.qa-achievement-activity .qa-row {
  display: grid;
  gap: var(--gp);
  padding: calc(4 * var(--gp)) 0;
  border-block-end: var(--gp) solid var(--pixel-dusk);
}
.qa-empty {
  padding: calc(9 * var(--gp));
  color: var(--muted);
  text-align: center;
}
.qa-empty--quests {
  display: grid;
  justify-items: center;
  gap: calc(4 * var(--gp));
  padding-block: calc(27 * var(--gp));
}
.qa-empty--quests img {
  width: calc(29 * var(--gp));
  height: calc(29 * var(--gp));
  object-fit: contain;
  opacity: 0.82;
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}
/* One centred line: two centred lines of different lengths cannot both sit on whole pixels. */
.qa-empty--quests small {
  color: color-mix(in srgb, var(--muted) 78%, transparent);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.4;
}
.qa-empty--achievements {
  display: grid;
  justify-items: center;
  gap: calc(4 * var(--gp));
}
.qa-empty--achievements img {
  width: calc(22 * var(--gp));
  height: calc(22 * var(--gp));
  object-fit: contain;
  opacity: 0.7;
}
/* The shared primer shape, sized for the icon it sits under. */
.qa-empty--achievements .sw-empty {
  max-width: 40ch;
  padding: 0;
}

@media (max-width: 720px) {
  .window.win-quests,
  .window.win-achievements {
    top: calc(27 * var(--gp));
    left: 50%;
    right: auto;
    width: 94vw;
    max-width: 94vw;
    transform: translateX(-50%);
  }
  .win-quests .win-body {
    max-height: 72vh;
  }
  .qa-achievements-overview {
    grid-template-columns: calc(24 * var(--gp)) minmax(0, 1fr);
  }
  .qa-achievements-emblem {
    width: calc(24 * var(--gp));
    height: calc(24 * var(--gp));
  }
  .qa-achievements-totals {
    grid-column: 2;
    justify-content: start;
  }
  .qa-achievement-level,
  .qa-achievement-level-progress {
    grid-column: 1 / -1;
  }
  .qa-achievement-row {
    grid-template-columns: calc(15 * var(--gp)) minmax(0, 1fr) auto;
  }
  .qa-achievement-row-icon {
    width: calc(15 * var(--gp));
    height: calc(15 * var(--gp));
  }
  .qa-quest-index-button .qa-row-title {
    grid-column: 2 / -1;
    display: -webkit-box;
    overflow: hidden;
    white-space: normal;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
  }
  .qa-quest-index-button:has(.qa-lifecycle) .qa-lifecycle {
    grid-column: 2 / -1;
    grid-row: 2;
    justify-self: start;
  }
  .qa-quest-index-button:has(.qa-lifecycle) .qa-index-objective {
    grid-row: 3;
  }
  .qa-quest-index-button:has(.qa-lifecycle) > strong {
    grid-row: 3;
  }
  .qa-quest-index-button:has(.qa-lifecycle) .qa-row-chevron {
    grid-row: 1 / span 3;
  }
  .qa-quest-detail-pane {
    padding-inline: calc(12 * var(--gp)) calc(5 * var(--gp));
  }
}

@media (prefers-reduced-motion: reduce) {
  .qa-row-chevron,
  .qa-progress-shared,
  .qa-progress-self {
    transition: none;
  }
  .qa-quest-detail-pane {
    animation: none;
  }
}

.reduce-motion .qa-row-chevron,
.reduce-motion .qa-progress-shared,
.reduce-motion .qa-progress-self {
  transition: none;
}
.reduce-motion .qa-quest-detail-pane {
  animation: none;
}

/* The journal's guide control (doc "Wayfinding"): offered only on objectives the
   authority can resolve to a place, so pressing it always does something. It is
   the tracker's route arrow, a pixel plate (pixel-chrome.css) on the HUD grid. */
.qa-objective-guide {
  --qa-guide: round(up, max(26px, calc(13 * var(--gp))), var(--gp));
  display: inline-flex;
  grid-column: 1;
  justify-self: end;
  align-items: center;
  justify-content: center;
  width: var(--qa-guide);
  height: var(--qa-guide);
  margin-top: var(--gp);
  padding: 0;
  cursor: var(--cursor-action);
}
.qa-objective-guide img {
  display: block;
  width: calc(100% - 2 * var(--gp));
  height: calc(100% - 2 * var(--gp));
  object-fit: contain;
}
body.high-contrast .qa-objective-guide {
  --plate-line: var(--wayfind-accent);
}

[data-ui-profile='handheld'] .qa-objective-guide {
  --qa-guide: round(up, max(32px, calc(16 * var(--gp))), var(--gp));
}

[data-ui-profile='handheld'] .qa-achievements-overview {
  grid-template-columns: calc(24 * var(--gp)) minmax(0, 1fr);
}

[data-ui-profile='handheld'] .qa-quest-index-button .qa-row-title {
  grid-column: 2 / -1;
  display: -webkit-box;
  overflow: hidden;
  white-space: normal;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

/* A landscape phone is wider than the 720px restack above but runs the same
   two-line title, which spans the row: the turn-in chip has to take the row
   under the title there too, or it draws on top of it. */
[data-ui-profile='handheld'] .qa-quest-index-button:has(.qa-lifecycle) .qa-lifecycle {
  grid-column: 2 / -1;
  grid-row: 2;
  justify-self: start;
}
[data-ui-profile='handheld'] .qa-quest-index-button:has(.qa-lifecycle) .qa-index-objective {
  grid-row: 3;
}
[data-ui-profile='handheld'] .qa-quest-index-button:has(.qa-lifecycle) > strong {
  grid-row: 3;
}
[data-ui-profile='handheld'] .qa-quest-index-button:has(.qa-lifecycle) .qa-row-chevron {
  grid-row: 1 / span 3;
}
/* The Archive: tab chips that count, a grid of cards, the open page beside it,
   and a gauge of the whole. A locked card keeps its art as a shape — a creature
   or person as a black silhouette, a place or item dimmed — and no name.
   Every surface is the HUD's pixel material (pixel-chrome.css): an ink outline,
   a flat face, a one-pixel light or identity line, a notched corner. */
.window.win-archive {
  width: calc(380 * var(--gp));
  max-width: calc(100vw - 32px);
  --archive-well-face: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  --archive-well-light: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
}

/* The body is the height authority: the grid and the page scroll inside it so
   the tab strip and the gauge stay put however long a tab gets. */
.win-archive .win-body {
  display: flex;
  flex-direction: column;
  height: min(76vh, calc(300 * var(--gp)));
  padding: 0;
  overflow: hidden;
}

ront-archive-window,
.archive {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

/* Tabs */
.archive-tabs {
  display: flex;
  gap: calc(2 * var(--gp));
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  border-block-end: var(--gp) solid var(--pixel-dusk);
}

.archive-tab {
  position: relative;
  display: flex;
  flex: 1 1 0;
  align-items: baseline;
  justify-content: center;
  gap: calc(3 * var(--gp));
  min-width: 0;
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--archive-well-face);
  color: color-mix(in srgb, var(--fg) 62%, transparent);
  font: inherit;
  cursor: pointer;
  box-shadow: var(--archive-well-light);
}

.archive-tab:hover {
  color: var(--fg);
  background: var(--pixel-night);
}

.archive-tab.is-active {
  background: var(--pixel-night);
  color: var(--fg);
  box-shadow: inset 0 0 0 var(--gp) var(--accent);
}

.archive-tab-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.archive-tab-count {
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--fg) 48%, transparent);
}

.archive-tab.is-complete .archive-tab-count {
  color: var(--accent);
}

/* A find not yet looked at: a lit pixel block on the tab and on the card. */
.archive-tab.has-new::after,
.archive-card-new {
  position: absolute;
  inset-block-start: calc(-2 * var(--gp));
  inset-inline-end: calc(-2 * var(--gp));
  width: calc(5 * var(--gp));
  height: calc(5 * var(--gp));
  background: var(--accent);
  content: '';
  box-sizing: border-box;
  border: var(--gp) solid var(--pixel-ink);
}

.archive-tab.has-new::after {
  inset-block-start: var(--gp);
  inset-inline-end: calc(3 * var(--gp));
}

/* Body */
.archive-body {
  display: grid;
  flex: 1 1 auto;
  grid-template-columns: minmax(0, 1fr) minmax(0, 44%);
  min-height: 0;
}

.archive-index {
  min-width: 0;
  overflow-y: auto;
  border-inline-end: var(--gp) solid var(--pixel-dusk);
  background: var(--archive-well-face);
}

.archive-primer {
  margin: 0;
  padding: calc(5 * var(--gp)) calc(6 * var(--gp)) 0;
  color: color-mix(in srgb, var(--fg) 62%, transparent);
  font-style: italic;
  line-height: 1.45;
}

.archive-group {
  margin: calc(5 * var(--gp)) calc(6 * var(--gp)) 0;
  color: color-mix(in srgb, var(--fg) 52%, transparent);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.archive-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(calc(49 * var(--gp)), 1fr));
  gap: calc(4 * var(--gp));
  padding: calc(4 * var(--gp)) calc(6 * var(--gp));
}

/* Cards: a well lined in the find's rarity. */
.archive-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--gp));
  min-width: 0;
  padding: calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  color: var(--fg);
  font: inherit;
  text-align: center;
  cursor: pointer;
  box-shadow: inset 0 0 0 var(--gp)
    color-mix(in srgb, var(--rarity-color, var(--pixel-dusk)) 55%, var(--pixel-dusk));
  clip-path: var(--pixel-notch);
}

.archive-card:hover {
  background: var(--pixel-dusk);
}
/* The notch clips a ring drawn outside the card, so keyboard focus is the bracket inside it. */
.archive-card:focus-visible {
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent) !important;
}

.archive-card.is-active {
  background: var(--pixel-dusk);
  box-shadow:
    inset 0 0 0 var(--gp) var(--pixel-ink),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent);
}

.archive-card-art {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  height: calc(44 * var(--gp));
  overflow: hidden;
}

.archive-card-art :is(img, ront-pixel-portrait) {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  pointer-events: none;
}

.archive-card-art ront-pixel-portrait {
  width: 100%;
  height: 100%;
}

.archive-card-art.kind-plate img {
  image-rendering: pixelated;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center bottom;
}

.archive-card-art.kind-icon {
  align-items: center;
  height: calc(32 * var(--gp));
}

.archive-card-art.kind-icon img {
  max-height: calc(26 * var(--gp));
}

.archive-card-art.kind-tile {
  align-items: center;
  height: calc(32 * var(--gp));
}

.archive-card-ordinal {
  display: grid;
  place-items: center;
  width: calc(20 * var(--gp));
  height: calc(20 * var(--gp));
  border: var(--gp) solid color-mix(in srgb, var(--accent) 50%, var(--pixel-ink));
  color: var(--accent);
  font-size: var(--type-section-heading-size);
  font-family: var(--type-section-heading-family);
  -webkit-font-smoothing: var(--type-section-heading-smoothing);
  font-weight: var(--type-weight-strong);
  background: var(--pixel-ink);
}

.archive-card-title {
  display: block;
  overflow: hidden;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
  line-height: 1.25;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Locked: the shape stays, the name goes, and the well goes dark. */
.archive-card.is-locked {
  background: var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-night);
}
.archive-card.is-locked .archive-card-title,
.archive-rung.is-locked .archive-rung-name {
  color: color-mix(in srgb, var(--fg) 38%, transparent);
  font-style: italic;
}

.archive-card.is-locked.kind-figure ront-pixel-portrait {
  filter: brightness(0) saturate(0);
  opacity: 0.55;
}

.archive-card.is-locked.kind-plate img,
.archive-card.is-locked.kind-icon img,
.archive-rung.is-locked img {
  filter: grayscale(1) brightness(0.55);
  opacity: 0.6;
}

.archive-card.is-locked .archive-card-ordinal {
  border-color: var(--pixel-dusk);
  color: color-mix(in srgb, var(--fg) 38%, transparent);
}

/* Page */
.archive-page {
  min-width: 0;
  padding: calc(6 * var(--gp));
  overflow-y: auto;
}

.archive-page.is-locked {
  color: color-mix(in srgb, var(--fg) 52%, transparent);
}

.archive-page-head {
  display: flex;
  gap: calc(6 * var(--gp));
  align-items: flex-end;
  margin-block-end: calc(5 * var(--gp));
}

.archive-page-head .archive-card-art {
  flex: 0 0 auto;
  width: calc(56 * var(--gp));
  height: calc(66 * var(--gp));
}

.archive-page.kind-plate .archive-page-head {
  flex-direction: column;
  align-items: stretch;
}
.archive-page.kind-plate .archive-page-head .archive-card-art {
  width: 100%;
  height: calc(48 * var(--gp));
}
.archive-page.kind-icon .archive-page-head .archive-card-art {
  width: calc(36 * var(--gp));
  height: calc(36 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--rarity-color, var(--pixel-night)) 14%, var(--pixel-ink));
  box-shadow: inset 0 0 0 var(--gp)
    color-mix(in srgb, var(--rarity-color, var(--pixel-dusk)) 60%, var(--pixel-dusk));
  clip-path: var(--pixel-notch);
}

.archive-page.is-locked .archive-page-head .archive-card-art :is(img, ront-pixel-portrait) {
  filter: brightness(0) saturate(0);
  opacity: 0.4;
}

.archive-page-lead {
  min-width: 0;
}

.archive-page-title {
  margin: 0 0 calc(3 * var(--gp));
  font-size: var(--type-section-heading-size);
  font-family: var(--type-section-heading-family);
  -webkit-font-smoothing: var(--type-section-heading-smoothing);
}

.archive-facts {
  display: flex;
  flex-wrap: wrap;
  gap: calc(2 * var(--gp));
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.archive-facts li,
.archive-fact-link {
  padding: 0 calc(3 * var(--gp));
  border: var(--gp) solid var(--pixel-dusk);
  color: color-mix(in srgb, var(--fg) 72%, transparent);
}

.archive-facts li:has(> .archive-fact-link) {
  padding: 0;
  border: none;
}

.archive-fact-link {
  display: inline-block;
  background: color-mix(in srgb, var(--accent) 10%, var(--pixel-ink));
  border-color: color-mix(in srgb, var(--accent) 50%, var(--pixel-ink));
  color: var(--fg);
  font: inherit;
  font-size: inherit;
  cursor: pointer;
}

.archive-fact-link:hover {
  background: color-mix(in srgb, var(--accent) 22%, var(--pixel-ink));
}

.archive-page-body {
  margin: 0;
  line-height: 1.55;
}

.archive-section {
  margin-block-start: calc(6 * var(--gp));
}

.archive-section-title {
  margin: 0 0 calc(3 * var(--gp));
  color: color-mix(in srgb, var(--fg) 52%, transparent);
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  font-weight: var(--type-weight-strong);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.archive-ladder {
  display: flex;
  gap: calc(3 * var(--gp));
  margin: 0;
  padding: 0;
  list-style: none;
}

.archive-rung {
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  align-items: center;
  gap: calc(2 * var(--gp));
  min-width: 0;
  padding: calc(3 * var(--gp)) calc(2 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: color-mix(in srgb, var(--rarity-color, var(--pixel-night)) 10%, var(--pixel-night));
  box-shadow: inset 0 0 0 var(--gp)
    color-mix(in srgb, var(--rarity-color, var(--pixel-dusk)) 60%, var(--pixel-dusk));
  clip-path: var(--pixel-notch);
}

.archive-rung img {
  width: calc(18 * var(--gp));
  height: calc(18 * var(--gp));
  object-fit: contain;
}
.archive-rung.is-locked {
  background: var(--pixel-ink);
  box-shadow: inset 0 0 0 var(--gp) var(--pixel-night);
}

.archive-rung-name {
  max-width: 100%;
  overflow: hidden;
  font-size: var(--type-metadata-size);
  font-family: var(--type-metadata-family);
  -webkit-font-smoothing: var(--type-metadata-smoothing);
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.archive-rail {
  display: flex;
  gap: calc(3 * var(--gp));
  overflow-x: auto;
  padding-block-end: calc(2 * var(--gp));
}

.archive-rail .archive-card {
  flex: 0 0 calc(44 * var(--gp));
}
.archive-rail .archive-card-art {
  height: calc(32 * var(--gp));
}

.archive-empty,
.archive-hint {
  margin: 0;
  padding: calc(6 * var(--gp));
  color: color-mix(in srgb, var(--fg) 52%, transparent);
}

/* Gauge: an ink slot, a dusk track, a flat fill that grows a HUD pixel at a time. */
.archive-foot {
  display: flex;
  gap: calc(5 * var(--gp));
  align-items: center;
  padding: calc(3 * var(--gp)) calc(6 * var(--gp));
  border-block-start: var(--gp) solid var(--pixel-dusk);
  color: color-mix(in srgb, var(--fg) 62%, transparent);
  font-size: var(--type-label-size);
  font-family: var(--type-label-family);
  -webkit-font-smoothing: var(--type-label-smoothing);
}

.archive-gauge {
  flex: 1 1 auto;
  height: calc(3 * var(--gp));
  overflow: hidden;
  background: var(--pixel-dusk);
  border: var(--gp) solid var(--pixel-ink);
}

.archive-gauge-fill {
  display: block;
  width: round(down, calc(var(--fill, 0) * 100%), var(--gp));
  height: 100%;
  background: var(--accent);
  transition: width 320ms ease-out;
}

.archive-foot-text {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
}
.archive-foot.is-complete .archive-foot-text {
  color: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  .archive-gauge-fill {
    transition: none;
  }
}

/* Handheld, and any landscape frame too short for two rows of cards: the grid
   becomes a rail above the page. */
@media (max-width: 720px), (max-height: 480px) {
  /* Fixed tracks, not auto: an auto track sizes to the rail's content and a
     max-height on the rail leaves the difference as dead space above the page. */
  .archive-body {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 46%) minmax(0, 1fr);
  }
  .archive-index {
    overflow: auto;
    border-inline-end: none;
    border-block-end: var(--gp) solid var(--pixel-dusk);
  }
  .archive-grid {
    display: flex;
  }
  .archive-grid .archive-card {
    flex: 0 0 calc(46 * var(--gp));
  }
  .archive-group {
    margin-block: calc(2 * var(--gp)) 0;
  }
  .archive-grid {
    padding-block: calc(2 * var(--gp));
  }
  .archive-grid .archive-card {
    padding: calc(2 * var(--gp));
  }
  .archive-grid .archive-card-art {
    height: calc(28 * var(--gp));
  }
  .archive-tab-label {
    font-size: var(--type-handheld-label-size);
    font-family: var(--type-handheld-label-family);
    -webkit-font-smoothing: var(--type-handheld-label-smoothing);
  }
  .archive-page {
    padding: calc(4 * var(--gp)) calc(6 * var(--gp));
  }
  .archive-page-head .archive-card-art {
    width: calc(32 * var(--gp));
    height: calc(36 * var(--gp));
  }
  .archive-page.kind-plate .archive-page-head {
    flex-direction: row;
    align-items: flex-end;
  }
  .archive-page.kind-plate .archive-page-head .archive-card-art {
    width: calc(60 * var(--gp));
    height: calc(28 * var(--gp));
  }
  .archive-page.kind-icon .archive-page-head .archive-card-art {
    width: calc(28 * var(--gp));
    height: calc(28 * var(--gp));
  }
}
/* Handheld presentation profile; desktop is the unprefixed HUD. Do not use max-width or (pointer: coarse) alone as a phone signal. */
/* ===== The thumb wheel's coins ==========================================
   On a handheld the skills, Recall, Attack and the left column's buttons are
   coins a thumb lands on: pixel discs, painted from the maps hud-wheel-coins.ts
   rasterises for the size each coin came out at. The ring is the slot's
   material bent round: ink, the lit rim, slate, then the well line a slot's
   pulses repaint (--well-line). No cue paints over a coin; a cue that calls for
   one stands round it as the material's halo (--pixel-halo).
   hud-wheel-coins.ts sets each coin's maps on it: --coin-disc (the face),
   --coin-ring, and the clips for what is drawn inside it (--coin-clip for the
   coin's box, --coin-clip-cd and --coin-clip-lock for the cooldown washes). The
   coin itself is never clipped, so a halo can stand round it. */
[data-ui-profile='handheld'] .action-bars :is(.hot-slot, .action-bars__rotate) {
  /* A slot that needs a target keeps its plain well; on a disc the tint reads
     as a stray ring over the art. */
  --well-line: var(--pixel-ink);
  border: 0;
  background: var(--coin-disc, none);
  clip-path: none;
  /* Every square fill, inset frame and outline a slot state draws. */
  background-color: transparent !important;
  outline: none !important;
  box-shadow: none !important;
}
[data-ui-profile='handheld'] .action-bars .hot-slot .hot-icon {
  clip-path: var(--coin-clip, none);
}
[data-ui-profile='handheld'] .action-bars .hot-slot .hot-cd {
  clip-path: var(--coin-clip-cd, none);
}
[data-ui-profile='handheld'] .action-bars .hot-slot .hot-cd--lock {
  clip-path: var(--coin-clip-lock, none);
}
/* A coin that backs out of the running windup (cast-cancel-arm.ts) shows its
   X alone. The cooldown and action lock the cast started at acceptance keep
   running under it and come back when the windup ends; a wash over the X would
   read as a button that cannot be pressed. */
[data-ui-profile='handheld'] .action-bars .hot-slot.cancels-cast .hot-cd {
  display: none !important;
}
/* The ring rides over the icon, so the art is framed the way a square slot's is. */
[data-ui-profile='handheld'] .action-bars .hot-slot::before {
  inset: 0;
  z-index: 4;
  opacity: 1;
  background: var(--coin-ring, none);
}
/* A state a square well draws as a frame inside it — the bar a skill is being
   placed on, a drop target, the slot a key is being bound to, focus — would be a
   square over the disc, so a coin wears it round itself as the halo. A lesson's
   call is the same halo (hud-attention.css). */
[data-ui-profile='handheld'] .action-bars .hot-slot.pd-drop,
[data-ui-profile='handheld']
  .action-bars.is-placing:not(:has(.coach-place))
  .action-bar--main
  .hot-slot,
[data-ui-profile='handheld'] .action-bars.is-configuring .hot-slot.is-rebinding,
[data-ui-profile='handheld'] .action-bars :is(.hot-slot, .action-bars__rotate):focus-visible {
  /* The halo is the whole cue; the ring a square well tints stays plain. */
  --well-line: var(--pixel-ink);
  opacity: 1;
  filter: var(--pixel-halo);
}
/* The rotate coin's glyph stands over its ring, and its bar readout hangs off
   the coin's corner. A readout wider than the coin moves right until it starts
   at the coin's left edge, the column's own. */
[data-ui-profile='handheld'] .action-bars .action-bars__rotate {
  background: none;
}
[data-ui-profile='handheld'] .action-bars__rotate::before {
  position: absolute;
  inset: 0;
  z-index: -1;
  content: '';
  background: var(--coin-ring, none), var(--coin-disc, none);
}
[data-ui-profile='handheld'] .action-bars__rotate-chip {
  position: absolute;
  right: calc(-1 * var(--gp));
  bottom: calc(-1 * var(--gp));
  box-sizing: border-box;
  height: auto;
  padding: 0 calc(2 * var(--gp));
  translate: max(0px, 100% - var(--hud-touch-coin) - var(--gp)) 0;
  color: #eef1f5;
  background: var(--pixel-ink);
  box-shadow: inset 0 var(--gp) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  font-size: var(--type-handheld-micro-size);
  font-family: var(--type-handheld-micro-family);
  -webkit-font-smoothing: var(--type-handheld-micro-smoothing);
  font-weight: var(--type-weight-strong);
  line-height: var(--type-leading-tight);
  white-space: nowrap;
  pointer-events: none;
}
/* A stack count sits centred on the coin's floor; a corner would fall off the
   disc. It may span the coin's width: a cut count reads as a different number. */
[data-ui-profile='handheld'] .action-bars .hot-name {
  right: 0;
  bottom: calc(3 * var(--gp));
  left: 0;
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
}
@supports (width: calc-size(max-content, size)) {
  [data-ui-profile='handheld'] .action-bars .hot-name {
    width: calc-size(max-content, round(up, size, calc(2 * var(--gp))));
  }
  [data-ui-profile='handheld'] .action-bars__rotate-chip {
    width: calc-size(max-content, round(up, size, var(--gp)));
  }
}
/* ===== The handheld move stick ==========================================
   A pixel instrument in the thumb coins' material: a coin's ring round a well
   the world shows through, a pip at each heading, and a thumb cap that steps
   across the grid a HUD pixel at a time. virtual-stick.ts rasterises the base
   (--stick-base) and the cap (--stick-cap) for the size they come out at here,
   and names the heading being pushed (data-heading), which lights its pip.
   Both pieces are sized in even HUD pixels, so the cap sits on the base's
   centre pixel for pixel. The box stays --hud-stick: the thumb row measures
   from it. */
[data-ui-profile='handheld'] .virtual-stick {
  --stick-size: round(down, var(--hud-stick), calc(2 * var(--gp)));
  --stick-cap-size: round(down, calc(var(--hud-stick) * 0.44), calc(2 * var(--gp)));
  background-color: transparent !important;
}
[data-ui-profile='handheld'] .virtual-stick-base,
[data-ui-profile='handheld'] .virtual-stick.active .virtual-stick-base {
  inset: 0 auto auto 0;
  width: var(--stick-size);
  height: var(--stick-size);
  border: 0;
  border-radius: 0 !important;
  background: var(--stick-base, none);
  box-shadow: none;
}
[data-ui-profile='handheld'] .virtual-stick-knob {
  left: calc((var(--stick-size) - var(--stick-cap-size)) / 2);
  top: calc((var(--stick-size) - var(--stick-cap-size)) / 2);
  width: var(--stick-cap-size);
  height: var(--stick-cap-size);
  margin: 0;
  border: 0;
  border-radius: 0 !important;
  background: var(--stick-cap, none);
  box-shadow: none;
  /* The cap stands a HUD pixel proud of the well... */
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}
/* ...and a thumb on it presses it flat and lights its face. */
[data-ui-profile='handheld'] .virtual-stick.active .virtual-stick-knob {
  --cap-face: var(--pixel-lilac);
  --cap-lit: var(--pixel-cream);
  translate: 0 var(--gp);
  filter: none;
}
[data-ui-profile='handheld']
  .virtual-stick:is([data-heading='n'], [data-heading='ne'], [data-heading='nw'])
  .virtual-stick-base {
  --pip-n: var(--pixel-cream);
}
[data-ui-profile='handheld']
  .virtual-stick:is([data-heading='e'], [data-heading='ne'], [data-heading='se'])
  .virtual-stick-base {
  --pip-e: var(--pixel-cream);
}
[data-ui-profile='handheld']
  .virtual-stick:is([data-heading='s'], [data-heading='se'], [data-heading='sw'])
  .virtual-stick-base {
  --pip-s: var(--pixel-cream);
}
[data-ui-profile='handheld']
  .virtual-stick:is([data-heading='w'], [data-heading='nw'], [data-heading='sw'])
  .virtual-stick-base {
  --pip-w: var(--pixel-cream);
}
/* The move lesson's call: the thumb coins' halo, two HUD pixels round the
   ring's steps, the accent then ink. */
:root:not([data-shell-state~='window'])[data-ui-profile='handheld']
  [data-coach-actions~='move']
  .virtual-stick-base::before {
  content: '';
  position: absolute;
  inset: calc(-2 * var(--gp));
  background: var(--stick-halo, none);
  pointer-events: none;
}
[data-ui-profile='handheld'] .hud-dock-row--top {
  top: var(--hud-safe-top);
  left: var(--hud-safe-left);
  right: var(--hud-safe-right);
  grid-template-columns: minmax(0, 1fr) minmax(var(--hud-center-width, 0px), auto) minmax(0, 1fr);
}
[data-ui-profile='handheld'] .hud-dock-row--bottom {
  left: var(--hud-safe-left);
  right: var(--hud-safe-right);
  bottom: var(--hud-safe-bottom);
}
[data-ui-profile='handheld'] .hud-dock--topLeft .hud-rail {
  flex-flow: column;
  align-items: flex-start;
  max-width: min(15rem, 32vw);
}
/* The column's width, which the character's frame fits (hud-unit-frames.css). */
[data-ui-profile='handheld'] .hud-dock--topLeft {
  overflow-y: auto;
  container-type: inline-size;
}
[data-ui-profile='handheld'] :is(.hud-dock--topLeft, ront-hud-lost-gear-card) {
  touch-action: pan-y;
}
/* The dock owns scrolling; each inner rail keeps its content height so it
   cannot spill into the next rail when reading text grows. */
[data-ui-profile='handheld'] .hud-dock--topLeft .hud-rail {
  max-block-size: none;
}
/* The radar's rail ends above the thumb cluster (`--hud-dock-right-room`), and
   the notice feed below the radar gives ground: hud-primitives-feedback.css
   caps it to the room left, so the rail may shrink to that room. */
[data-ui-profile='handheld'] .hud-dock-row--top .hud-rail:has(> [data-hud-widget='notices']) {
  flex-shrink: 1;
}
[data-ui-profile='handheld'] .hud-dock--bottomRight {
  padding-bottom: calc(
    var(--hud-skill-wheel-h) + 8px + var(--hud-thumb-bottom) - var(--hud-safe-bottom)
  );
  align-items: flex-end;
}
/* Fixed thumb controls still reserve their horizontal reach for center strips. */
[data-ui-profile='handheld'] .hud-dock--bottomCenter {
  max-inline-size: max(
    0px,
    calc(100vw - 2 * (var(--hud-thumb-right) + var(--hud-skill-wheel-w) + var(--hud-gap)))
  );
}
[data-ui-profile='handheld'] .hud-layout-editing .notice-feed {
  touch-action: pan-y;
}
[data-ui-profile='handheld'] .hud-layout-handle {
  width: var(--hud-touch-min, 44px);
  height: var(--hud-touch-min, 44px);
  border: 2px dashed var(--gold);
  background: rgb(10 14 20 / 25%);
  clip-path: none;
  opacity: 1;
  pointer-events: auto;
  z-index: 64;
  cursor: grab;
  touch-action: none;
}
[data-ui-profile='handheld'] .hud-layout-handle:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}
/* Both command previews are visible while editing. Share a row so the
   centre stack still leaves room for guidance above the phone's home bar. */
[data-ui-profile='handheld'] .hud-layout-editing .hud-rail--centerPrimary {
  display: grid;
  grid-template-columns: repeat(2, auto);
  row-gap: 0;
  justify-items: center;
}
[data-ui-profile='handheld']
  .hud-layout-editing
  .hud-rail--centerPrimary
  > :is(
    [data-hud-widget='target'],
    [data-hud-widget='lootRolls'],
    .hud-layout-seat:has(+ :is([data-hud-widget='target'], [data-hud-widget='lootRolls']))
  ) {
  grid-column: 1 / -1;
}
:root {
  --hud-touch-min: 44px;
  --ime-inset: 0px;
}
[data-ui-profile='handheld'] {
  /* The bezel: default distance from the glass edge; --hud-safe-* takes this or the device inset, whichever is larger. */
  --hud-edge: 8px;
  /* Short-axis budget: thumbs stay in corner capsules. JS may stamp exact px. */
  --hud-skill: clamp(44px, 11dvh, 52px);
  --hud-skill-aa: clamp(56px, 15dvh, 72px);
  --hud-skill-gap: 6px;
  --hud-touch-coin: round(up, var(--hud-touch-min), calc(2 * var(--gp)));
  /* Near ring coins are smaller than the far ring's so a second four fit between Attack and the far ring. */
  --hud-skill-inner: clamp(40px, 10dvh, 48px);
  /* Both rings put four coins on the quarter turn between above and left of Attack (0/30/60/90 deg); past 0 a coin leaves the screen edge, past 90 it drops below Attack. */
  --hud-arc-r-inner: max(
    calc((var(--hud-skill-inner) + var(--hud-skill-gap)) / (2 * sin(15deg))),
    calc(var(--hud-skill-aa) / 2 + var(--hud-skill-gap) + var(--hud-skill-inner) / 2)
  );
  --hud-arc-r: max(
    calc((var(--hud-skill) + var(--hud-skill-gap)) / (2 * sin(15deg))),
    calc(
      var(--hud-arc-r-inner) + var(--hud-skill-inner) / 2 + var(--hud-skill) / 2 +
        var(--hud-skill-gap)
    )
  );
  --hud-skill-wheel-w: round(
    up,
    calc(
      var(--hud-skill-aa) / 2 + var(--hud-arc-r) + var(--hud-skill) / 2 + 12px +
        max(var(--hud-touch-min), var(--hud-skill))
    ),
    2px
  );
  --hud-skill-wheel-h: round(
    up,
    calc(var(--hud-skill-aa) / 2 + var(--hud-arc-r) + var(--hud-skill) / 2 + 8px),
    2px
  );
  /* The aim stick opens on the pressed coin and reaches one coin past it, rim 20px beyond (hud-aim-stick.ts); the wheel sits at the safe edge or further in so the whole stick stays on the glass. */
  --hud-aim-clear: round(up, calc(var(--hud-skill) + 20px - var(--hud-skill-aa) / 2), 2px);
  --hud-thumb-right: max(var(--hud-safe-right), var(--hud-aim-clear));
  --hud-thumb-bottom: max(var(--hud-safe-bottom), var(--hud-aim-clear));
  --hud-stick: round(clamp(80px, 22dvh, 112px), 2px);
  --hud-cluster-inset: 8px;
  --hud-window-max: min(520px, calc(100vw - 64px));
  --hud-window-max-h: min(
    82dvh,
    calc(100dvh - var(--hud-safe-top, 8px) - var(--hud-safe-bottom, 8px) - 16px)
  );
}
@media (min-width: 1100px) {
  [data-ui-profile='handheld'] {
    --hud-cluster-inset: 16px;
    --hud-window-max: min(780px, calc(100vw - 72px));
  }
}
/* Pin the play shell only after the world mounts: a frozen html/body on iOS freezes the orientation query and clips login and character select. */
html[data-ui-profile='handheld']:not([data-shell-state~='menu']),
html[data-ui-profile='handheld']:not([data-shell-state~='menu']) body {
  overflow: hidden;
  overscroll-behavior: none;
  width: 100%;
  width: 100dvw;
  height: 100%;
  height: 100dvh;
  touch-action: none;
}
html[data-ui-profile='handheld']:not([data-shell-state~='menu']) #app {
  width: 100%;
  height: 100%;
  overflow: hidden;
  touch-action: none;
}
html[data-ui-profile='handheld'][data-shell-state~='menu'],
html[data-ui-profile='handheld'][data-shell-state~='menu'] body,
html[data-ui-profile='handheld'][data-shell-state~='menu'] #app {
  height: auto;
  min-height: 100%;
  min-height: 100dvh;
  overflow: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
}
html[data-ui-profile='handheld'][data-shell-state~='menu'] #app {
  display: block;
}
html[data-ui-profile='handheld'] #game-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  touch-action: none;
}
/* The play shell is pinned so a world drag never pans the page; scrolling surfaces hand the vertical pan back for themselves. */
html[data-ui-profile='handheld'] .win-body,
html[data-ui-profile='handheld'] .chat-log,
html[data-ui-profile='handheld'] .npc-text,
html[data-ui-profile='handheld'] .npc-controls,
html[data-ui-profile='handheld'] .death-card__body,
html[data-ui-profile='handheld'] .death-recap__timeline {
  touch-action: pan-y;
}
[data-ui-profile='handheld'] .action-bars,
[data-ui-profile='handheld'] .action-bars.hud-railed:not(.hud-layout-detached) {
  --action-bars-slot: var(--hud-skill);
  position: fixed;
  top: auto;
  right: var(--hud-thumb-right);
  bottom: var(--hud-thumb-bottom);
  left: auto;
  transform: none;
  pointer-events: none;
  width: var(--hud-skill-wheel-w);
  min-width: var(--hud-skill-wheel-w);
  height: var(--hud-skill-wheel-h);
  min-height: var(--hud-skill-wheel-h);
  padding: 0;
  margin: 0;
  z-index: 30;
}
/* The runtime portals an active placement bar out of its dock row, so this layer belongs to that surface alone: no importance override. */
[data-ui-profile='handheld'] .action-bars.is-placing {
  z-index: 130;
}
[data-ui-profile='handheld'] .action-bars__place-prompt {
  right: calc(100% + 8px);
  bottom: 0;
  width: min(220px, 54vw);
  max-width: calc(100dvw - var(--hud-safe-left) - var(--hud-safe-right) - 16px);
  font-size: var(--type-body-compact-readable-size);
  font-family: var(--type-body-compact-readable-family);
  -webkit-font-smoothing: var(--type-body-compact-readable-smoothing);
}
[data-ui-profile='handheld'] .action-bars.hud-fold-surface.is-collapsed {
  width: var(--hud-skill-wheel-w);
  min-width: var(--hud-skill-wheel-w);
  height: var(--hud-skill-wheel-h);
  min-height: var(--hud-skill-wheel-h);
  pointer-events: none;
}
[data-ui-profile='handheld'] .action-bars .hud-fold-trigger,
[data-ui-profile='handheld'] .action-bars .hot-key {
  display: none;
}
[data-ui-profile='handheld'] .action-bars.hud-fold-surface.is-collapsed .hud-fold-content {
  display: flex;
  visibility: visible;
  opacity: 1;
  pointer-events: none;
  transform: none;
  clip-path: none;
}
[data-ui-profile='handheld'] .action-bars__content {
  position: relative;
  width: var(--hud-skill-wheel-w);
  height: var(--hud-skill-wheel-h);
}
[data-ui-profile='handheld'] .action-bars__stack {
  position: absolute;
  inset: 0;
}
/* All three bars stack in one box; only the rotated-to one is drawn, outranking the desktop hidden-extra rule. */
[data-ui-profile='handheld'] .action-bar.is-arc {
  position: absolute;
  inset: 0;
  display: block;
  width: auto;
  height: auto;
  flex-wrap: nowrap;
  flex-direction: row;
}
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot,
[data-ui-profile='handheld'] .action-bars__recall .hot-slot,
[data-ui-profile='handheld'] .action-bars__attack,
[data-ui-profile='handheld'] .action-bars__rotate,
[data-ui-profile='handheld'] .action-bars__cycle {
  position: absolute;
  box-sizing: border-box;
  overflow: hidden;
  pointer-events: auto;
}
[data-ui-profile='handheld'] .action-bars__attack {
  display: flex;
  right: 0;
  bottom: 0;
  width: round(var(--hud-skill-aa), calc(2 * var(--gp)));
  height: round(var(--hud-skill-aa), calc(2 * var(--gp)));
  z-index: 3;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: var(--cursor-action);
}
[data-ui-profile='handheld'] .action-bars__attack img,
[data-ui-profile='handheld'] .action-bars__rotate img,
[data-ui-profile='handheld'] .action-bars__cycle img {
  width: 70%;
  height: 70%;
  object-fit: contain;
  pointer-events: none;
}
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot:nth-child(1),
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot:nth-child(5) {
  --hud-arc-a: 0deg;
}
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot:nth-child(2),
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot:nth-child(6) {
  --hud-arc-a: 30deg;
}
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot:nth-child(3),
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot:nth-child(7) {
  --hud-arc-a: 60deg;
}
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot:nth-child(4),
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot:nth-child(8) {
  --hud-arc-a: 90deg;
}
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot:nth-child(-n + 4) {
  right: round(
    calc(var(--hud-skill-aa) / 2 + var(--hud-arc-r) * sin(var(--hud-arc-a)) - var(--hud-skill) / 2),
    1px
  );
  bottom: round(
    calc(var(--hud-skill-aa) / 2 + var(--hud-arc-r) * cos(var(--hud-arc-a)) - var(--hud-skill) / 2),
    1px
  );
  width: round(var(--hud-skill), calc(2 * var(--gp)));
  height: round(var(--hud-skill), calc(2 * var(--gp)));
}
[data-ui-profile='handheld'] .action-bar.is-arc .hot-slot:nth-child(n + 5):nth-child(-n + 8) {
  display: block;
  right: round(
    calc(
      var(--hud-skill-aa) / 2 + var(--hud-arc-r-inner) * sin(var(--hud-arc-a)) -
        var(--hud-skill-inner) / 2
    ),
    1px
  );
  bottom: round(
    calc(
      var(--hud-skill-aa) / 2 + var(--hud-arc-r-inner) * cos(var(--hud-arc-a)) -
        var(--hud-skill-inner) / 2
    ),
    1px
  );
  width: round(var(--hud-skill-inner), calc(2 * var(--gp)));
  height: round(var(--hud-skill-inner), calc(2 * var(--gp)));
}
[data-ui-profile='handheld'] .action-bars__recall {
  position: absolute;
  right: auto;
  left: 0;
  bottom: round(calc(var(--hud-touch-min) + 8px), 1px);
  width: round(var(--hud-skill), calc(2 * var(--gp)));
  height: round(var(--hud-skill), calc(2 * var(--gp)));
  z-index: 2;
}
[data-ui-profile='handheld'] .action-bars__recall .hot-slot {
  inset: 0;
  width: 100%;
  height: 100%;
}
/* Left column, bottom up: Cycle, Recall, then the arc's current bar. Rotate doubles as a readout of eight of the twenty-four bound slots. */
[data-ui-profile='handheld'] .action-bars__rotate {
  display: flex;
  overflow: visible;
  right: auto;
  left: 0;
  bottom: calc(var(--hud-touch-min) + var(--hud-skill) + 16px);
  width: var(--hud-touch-coin);
  height: var(--hud-touch-coin);
  z-index: 2;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: var(--cursor-action);
}
[data-ui-profile='handheld'] .action-bars__cycle {
  display: flex;
  right: auto;
  left: 0;
  bottom: 0;
  width: var(--hud-touch-coin);
  height: var(--hud-touch-coin);
  z-index: 2;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: var(--cursor-action);
}
[data-ui-profile='handheld'] .action-bars__config {
  display: none;
}
[data-ui-profile='handheld'] .action-bars__stack .action-bar:not(.is-arc),
[data-ui-profile='handheld'] .action-bars__stack .action-bar:not(.is-arc) .hot-slot {
  display: none !important;
}
[data-ui-profile='handheld'] .fps-hud {
  display: none;
}
[data-ui-profile='handheld'] .virtual-stick {
  display: block;
  width: var(--hud-stick);
  height: var(--hud-stick);
  z-index: 30;
}
[data-ui-profile='desktop'] .virtual-stick {
  display: none;
}
[data-ui-profile='handheld'] .menu-buttons.is-collapsible {
  isolation: auto;
}
[data-ui-profile='handheld'] .menu-buttons.is-collapsed .menu-items {
  display: none;
  will-change: auto;
}
[data-ui-profile='handheld'] .hud-safe-area-probe {
  inset: auto;
  width: 1px;
  height: 1px;
}
[data-ui-profile='handheld'] .overlay.window:not(.is-open),
[data-ui-profile='handheld'] .npc-win:not(.is-open) {
  display: none !important;
}
[data-ui-profile='handheld'] .menu-buttons {
  --menu-scale: 1;
}
[data-ui-profile='handheld'] .menu-btn {
  width: max(var(--hud-touch-min), calc(48px * var(--ui-scale, 1)));
  height: max(var(--hud-touch-min), calc(48px * var(--ui-scale, 1)));
}
[data-ui-profile='handheld'] [data-hud-widget='menu']:not(.hud-layout-detached) {
  overflow: visible;
  z-index: 48;
}
/* Cards rest centred on the glass; a dragged card carries its own coordinate (`win-placed`), so centring stands aside. */
[data-ui-profile='handheld'] .window:not(.win-placed) {
  top: 50% !important;
  left: 50% !important;
  right: auto !important;
  bottom: auto !important;
  transform: translate(-50%, -50%) !important;
}
[data-ui-profile='handheld'] .window {
  position: fixed !important;
  width: var(--hud-window-max) !important;
  max-width: var(--hud-window-max) !important;
  max-height: var(--hud-window-max-h) !important;
  box-sizing: border-box;
  /* The frame and its chrome never scroll; otherwise thumb drift on Close begins a card scroll and cancels the click. */
  overflow: hidden;
}
[data-ui-profile='handheld'] .win-head {
  min-height: var(--hud-touch-min);
  touch-action: none;
}
[data-ui-profile='handheld'] .win-close {
  width: var(--hud-touch-min);
  height: var(--hud-touch-min);
  /* The whole square takes the thumb; the control is painted inside, clear of the frame's clip and a lesson's halo (hud-attention.css). */
  padding: var(--pixel-halo-reach, 0px);
  border: 0;
  background-clip: content-box;
  outline: 1px solid var(--ui-control-line);
  outline-offset: calc(-1 * var(--pixel-halo-reach, 0px) - 1px);
}
/* The skills window keeps the frame budget every window gets, and the cast wheel
   sits behind it rather than the window shrinking to clear the wheel. On a phone
   in landscape the wheel is most of the glass, so reserving room for it leaves
   the window its own title bar and nothing else — and a window too short to show
   a skill cannot be dragged from at all. The window is pinned to the top inset so
   what it does keep is the part a thumb can reach. */
[data-ui-profile='handheld'] .window.win-skills {
  --skills-glass-w: calc(100dvw - var(--hud-safe-left, 8px) - var(--hud-safe-right, 8px) - 16px);
  /* The card is drawn in HUD pixels: its rail, panel and chrome rows are all
     multiples of --gp, while handheld type stays one size. A larger interface
     step grows --gp, and a card that could not grow with it crushed the ability
     list to a sliver. So the card takes the player's HUD pixel only while the
     glass holds it at that size - 390 HUD pixels wide, 128 tall - and the step
     otherwise stops at the largest whole pixel that fits. It never goes under
     the default step's pixel: a glass too small for the card at that size
     keeps the card it always had. */
  --gp: max(
    1px,
    round(
      max(
        min(calc(2px * var(--ui-scale, 1)), 2px),
        min(
          calc(2px * var(--ui-scale, 1)),
          calc(var(--skills-glass-w) / 390),
          calc(var(--hud-window-max-h) / 128)
        )
      ),
      1px
    )
  );
  /* The build flows left to right on a handheld — chrome rail beside the
     catalog — so this one window spends the landscape width the shared cap
     leaves idle. Centered, its margins stay at least the safe inset; 390 HUD
     pixels is 780px at the default step, the wide-glass shared cap, so no glass
     draws this card narrower than its siblings. */
  --hud-window-max: min(calc(390 * var(--gp)), var(--skills-glass-w));
  /* The height is the shared budget, whose 82dvh ceiling still leaves a strip of
     the thumb cluster under the card: placement lifts the whole cluster above
     it, and the resting layout shows where that second step will happen. A
     tighter cap left a Safari phone two ability rows. */
}
/* The rest pin, like the centring rule, yields to a card the player has dragged. */
[data-ui-profile='handheld'] .window.win-skills:not(.win-placed) {
  top: var(--hud-safe-top) !important;
  transform: translateX(-50%) !important;
}
/* Every window body caps itself against the frame budget, except the skills
   list. That one is a flex column whose own sheet gives it a fixed height for
   the desktop cockpit, so a second cap here would fight it rather than replace
   it; the rule below releases the fixed height instead and lets the body take
   whatever the frame left. The skills window is excluded by name so that stays
   a decision rather than a specificity accident. */
[data-ui-profile='handheld'] .window:not(.win-skills) .win-body {
  max-height: calc(var(--hud-window-max-h) - 3.25rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
/* One height decision, made by the frame: the body takes the room it left and
   releases every cap it carries for the desktop cockpit — the base rule budgets
   against a hotbar and a 72px default top that a landscape phone does not have,
   which on a 320px glass leaves a list about a hundred pixels tall. */
[data-ui-profile='handheld'] .win-skills .win-body {
  flex: 1 1 auto;
  height: auto;
  min-height: 0;
  max-height: none;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
/* Collapsed rail folds shrink to the edge chip. Desktop keeps the empty slot
   so neighbours do not jump; a landscape phone cannot spend that empty strip. */
[data-ui-profile='handheld']
  .hud-fold-surface.hud-fold-preserve-rail-slot.hud-railed:not(
    .hud-layout-detached
  ).is-collapsed:not(.action-bars) {
  width: var(--hud-fold-shell-size) !important;
  min-width: var(--hud-fold-shell-size) !important;
  height: var(--hud-fold-shell-size) !important;
  min-height: var(--hud-fold-shell-size) !important;
  padding: var(--hud-fold-inset);
}
[data-ui-profile='handheld'] .chat-wrap.hud-railed:not(.hud-layout-detached) {
  margin: 0;
  transform: translateY(calc(-1 * var(--ime-inset, 0px)));
  z-index: 30;
}
[data-ui-profile='handheld'] .chat-send {
  display: inline-flex;
  min-width: var(--hud-touch-min);
  min-height: var(--hud-touch-min);
}
/* The damage meter is disabled on a handheld: it docks in no handheld rail and
   is never drawn, including while the layout editor is open. */
[data-ui-profile='handheld'] .combat-telemetry-fold {
  display: none !important;
}
[data-ui-profile='handheld'] .loot-prompt {
  min-height: var(--hud-touch-min);
  pointer-events: auto;
  cursor: var(--cursor-action);
}
[data-ui-profile='handheld'] .death-card-positioner {
  width: min(var(--hud-window-max), calc(100vw - 24px));
  max-height: var(--hud-window-max-h);
  overflow: hidden;
}
[data-ui-profile='handheld'] button.death-action {
  min-height: var(--hud-touch-min);
}
[data-ui-profile='handheld'] .npc-win {
  position: fixed !important;
  top: 50% !important;
  bottom: auto !important;
  left: 50% !important;
  right: auto !important;
  transform: translate(-50%, -50%) !important;
  width: min(28rem, calc(100vw - 72px));
  max-width: min(28rem, calc(100vw - 72px));
  max-height: min(46dvh, var(--hud-window-max-h));
  z-index: 45;
}
[data-ui-profile='handheld'] .npc-menu-item,
[data-ui-profile='handheld'] .npc-controls .ron-btn {
  min-height: var(--hud-touch-min);
}
[data-ui-profile='handheld'] .npc-speaker {
  flex-basis: 88px;
  min-height: 0;
}
/* A dealt hand keeps the whole stage on handheld too: the veil undoes the
   centred talk-window treatment above. A landscape phone is short, so the
   standee steps aside (its inline display needs the !important) and the
   question keeps a readable size; the cards are what the height is for. */
[data-ui-profile='handheld'] .npc-win.npc-hand {
  top: 0 !important;
  right: 0 !important;
  bottom: 0 !important;
  left: 0 !important;
  transform: none !important;
  width: auto;
  max-width: none;
  max-height: none;
  /* The veil may bleed to the bezel; the hand the player reads and presses may
     not. Its ordinary inset remains the floor when the device has no cutout. */
  padding: max(calc(18px * var(--ui-scale)), var(--safe-top))
    max(calc(18px * var(--ui-scale)), var(--safe-right))
    max(calc(18px * var(--ui-scale)), var(--safe-bottom))
    max(calc(18px * var(--ui-scale)), var(--safe-left));
}
[data-ui-profile='handheld'] .npc-hand .npc-speaker {
  display: none !important;
}
[data-ui-profile='handheld'] .npc-hand .npc-text {
  height: auto;
  min-height: 0;
  max-height: none;
  overflow: visible;
  font-size: var(--type-handheld-heading-size);
  font-family: var(--type-handheld-heading-family);
  -webkit-font-smoothing: var(--type-handheld-heading-smoothing);
}
[data-ui-profile='handheld'] .npc-speaker-art {
  width: 96px;
  min-height: 0;
  height: calc(100% + 24px);
  max-height: 120px;
}
[data-ui-profile='handheld'] .npc-win.npc-offer {
  max-height: min(70dvh, var(--hud-window-max-h));
}
[data-ui-profile='handheld'] .npc-text {
  height: calc(12px * 1.45 * 3);
  min-height: calc(12px * 1.45 * 2);
  max-height: 4.8rem;
  overflow-y: auto;
  font-size: var(--type-handheld-body-compact-size);
  font-family: var(--type-handheld-body-compact-family);
  -webkit-font-smoothing: var(--type-handheld-body-compact-smoothing);
  line-height: 1.45;
}
[data-ui-profile='handheld'] .target-class {
  display: none;
}
[data-ui-profile='handheld'] .unit-frame .target-name {
  font-size: var(--type-handheld-heading-size);
  font-family: var(--type-handheld-heading-family);
  -webkit-font-smoothing: var(--type-handheld-heading-smoothing);
}
[data-ui-profile='handheld'] .target-status {
  margin-top: var(--gp);
  gap: var(--gp);
}
[data-ui-profile='handheld'] .notice-feed {
  max-width: min(22vw, 10rem);
  max-height: 1.2rem;
  overflow: hidden;
  z-index: 5;
}
[data-ui-profile='handheld'] .notice-row {
  font-size: var(--type-handheld-label-size);
  font-family: var(--type-handheld-label-family);
  -webkit-font-smoothing: var(--type-handheld-label-smoothing);
  padding: 3px 8px 3px 10px;
}
[data-ui-profile='handheld'] [data-hud-widget='lostGear']:not(.hud-layout-handle) {
  max-width: min(12rem, 28vw);
  max-height: min(26dvh, 7.5rem);
  overflow-y: auto;
}
/* On a phone the corner keeps to the character frame's width: the frame leads,
   its buffs and the party's faces share the line under it, and a focused ally
   takes the line under those. What does not fit on a line wraps to the next,
   so the corner never reaches the centre column. A tablet is tall enough to
   stack the rail, so it still does. */
@media (max-height: 520px) {
  [data-ui-profile='handheld'] .hud-dock--topLeft .hud-rail--leftChips {
    display: flex;
    flex-flow: row wrap;
    align-items: flex-start;
    align-content: flex-start;
    gap: var(--hud-gap);
    width: min(round(calc(244px * var(--ui-scale, 1)), 2px), calc(100vw - 24px));
    max-width: 100%;
  }

  [data-ui-profile='handheld'] .hud-dock--topLeft .hud-rail--leftChips > [data-hud-widget='status'],
  [data-ui-profile='handheld']
    .hud-dock--topLeft
    .hud-rail--leftChips
    > [data-hud-widget='partyFocus'] {
    flex: 0 0 100%;
  }

  [data-ui-profile='handheld']
    .hud-dock--topLeft
    .hud-rail--leftChips
    > [data-hud-widget='statusTray'],
  [data-ui-profile='handheld']
    .hud-dock--topLeft
    .hud-rail--leftChips
    > [data-hud-widget='partyFrames'] {
    flex: 0 1 auto;
    min-width: 0;
  }
}
[data-ui-profile='handheld'] .status-tray {
  max-width: min(24vw, 12rem);
}
/* Only while the stack floats free. Docked in a rail it is `position: relative`,
   where an offset moves the box but not the slot it was given — the alerts lift
   off the rail and leave an empty band the height of the thumb stick behind. */
[data-ui-profile='handheld'] .alert-stack.hud-layout-detached,
[data-ui-profile='handheld'] .alert-stack:not(.hud-railed) {
  bottom: calc(var(--hud-stick) + 16px);
}
[data-ui-profile='handheld'] .death-overlay {
  overflow: hidden;
  padding: 8px;
}
[data-ui-profile='handheld'] .death-card {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(13rem, 0.85fr);
  grid-template-rows: auto minmax(0, 1fr);
  max-height: var(--hud-window-max-h);
}
[data-ui-profile='handheld'] .death-card__head {
  grid-column: 1 / -1;
  padding: 8px 12px 8px 16px;
}
[data-ui-profile='handheld'] .death-card__title {
  font-size: var(--type-handheld-title-size);
  font-family: var(--font-display);
  -webkit-font-smoothing: none;
}
[data-ui-profile='handheld'] .death-card__body {
  min-height: 0;
  overflow-y: auto;
}
[data-ui-profile='handheld'] .death-card__foot {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 0;
}
[data-ui-profile='handheld'] .death-card:not(:has(.death-card__body)) .death-card__foot {
  grid-column: 1 / -1;
}
[data-ui-profile='handheld'] .death-timer__value {
  font-size: var(--type-handheld-screen-heading-size);
  font-family: var(--type-handheld-screen-heading-family);
  -webkit-font-smoothing: var(--type-handheld-screen-heading-smoothing);
}
[data-ui-profile='handheld'] .menu-overlay {
  align-items: center;
  justify-content: center;
}
[data-ui-profile='handheld'] .menu-overlay__card {
  width: min(var(--hud-window-max), 100%);
  max-height: var(--hud-window-max-h);
  overflow-y: auto;
  padding: 16px 20px;
}
[data-ui-profile='handheld'] .menu-button {
  min-height: var(--hud-touch-min);
}
/* Live occupants hide overlapping stage chrome only; quest tracker, chat, and closed HUD
   windows are unaffected. Cancel stays in the skill cluster so a windup doesn't hide the
   radar column. The cast strip and command chip share the space above the thumb cluster —
   only the two transient cards under the radar step back, clearing the radar and the strip. */
@media (max-height: 520px) {
  /* NPC replies need room beside the left thumb controls.
     Action bars and quests step back while the conversation is open.
     Keep the stick, chat and menu reachable beside the dialogue. */
  [data-ui-profile='handheld'] .npc-win {
    top: calc(var(--hud-top-center-bottom, 76px) + var(--hud-gap)) !important;
    max-width: min(
      28rem,
      calc(
        100vw - 2 *
          (var(--hud-safe-left) + var(--hud-stick) + 2 * var(--hud-touch-coin) + 4 * var(--hud-gap))
      )
    );
    transform: translateX(-50%) !important;
    max-height: calc(
      100dvh - var(--hud-top-center-bottom, 76px) - var(--hud-safe-bottom) - var(--hud-gap) * 2
    );
  }
  [data-ui-profile='handheld'][data-shell-state~='npc'] [data-hud-widget='actionBars'],
  [data-ui-profile='handheld'][data-shell-state~='npc'] [data-hud-widget='questTracker'],
  [data-ui-profile='handheld'][data-shell-state~='npc'] .screen-combat-overlays,
  [data-ui-profile='handheld'][data-shell-state~='npc'] .alert-stack {
    display: none !important;
  }
}
[data-ui-profile='handheld'][data-shell-state~='modal'] .coach-banner,
[data-ui-profile='handheld'][data-shell-state~='modal'] [data-hud-widget='lostGear'],
[data-ui-profile='handheld'][data-shell-state~='modal'] .notice-feed,
[data-ui-profile='handheld'][data-shell-state~='modal'] .character-skill-flow,
[data-ui-profile='handheld'][data-shell-state~='npc'] [data-hud-widget='lostGear'],
[data-ui-profile='handheld'][data-shell-state~='npc'] .notice-feed,
[data-ui-profile='handheld'][data-shell-state~='npc'] .character-skill-flow,
[data-ui-profile='handheld'][data-shell-state~='death'] .coach-banner,
[data-ui-profile='handheld'][data-shell-state~='death'] [data-hud-widget='lostGear'],
[data-ui-profile='handheld'][data-shell-state~='death'] .notice-feed,
[data-ui-profile='handheld'][data-shell-state~='death'] .character-skill-flow,
[data-ui-profile='handheld'][data-shell-state~='death'] .screen-combat-overlays {
  display: none !important;
}
[data-ui-profile='handheld'] .shop-body,
[data-ui-profile='handheld'] .trade-body,
[data-ui-profile='handheld'] .cashshop-content,
[data-ui-profile='handheld'] .itemsvc-content {
  max-height: calc(var(--hud-window-max-h) - 3.25rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}
[data-ui-profile='handheld'] .shop-row-action,
[data-ui-profile='handheld'] .trade-actions .ron-btn,
[data-ui-profile='handheld'] .shop-tab {
  min-height: var(--hud-touch-min);
}
/* A handheld's left-thumb row (HUD_DOCK_RAILS_HANDHELD): the stick, then the chat,
   quest and command-menu launchers level with its foot. Chat opens a window standing
   over the stick, quests open the quest window, and the menu unfolds its grid above
   its launcher. Folded, chat and quests pass their news on one short ticker above
   chat's launcher; the tracker hands its steps over (HUD_THUMB_ROW_NEWS_EVENT). */
[data-ui-profile='handheld'] .hud-dock--bottomLeft .hud-rail--bottomLeftPrimary {
  flex-direction: row;
  align-items: flex-end;
  width: max-content;
}
[data-ui-profile='handheld'] .hud-dock--bottomLeft .chat-wrap.hud-railed:not(.hud-layout-detached) {
  width: var(--hud-fold-shell-size);
  min-width: var(--hud-fold-shell-size);
  height: var(--hud-fold-shell-size);
  min-height: var(--hud-fold-shell-size);
  padding: var(--hud-fold-inset);
  border: 0;
  background: transparent;
  box-shadow: none;
}
/* The window: the row's full reach above the stick, left-aligned with it. The
   keyboard lifts the whole launcher by its inset, so the window gives up the same
   height and its top stays on the glass. */
[data-ui-profile='handheld']
  .hud-dock--bottomLeft
  .chat-wrap.hud-railed:not(.hud-layout-detached)
  > .chat-content {
  position: absolute;
  bottom: calc(var(--hud-stick) + var(--hud-gap));
  left: calc(-1 * (var(--hud-stick) + var(--hud-gap)));
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  width: round(down, min(60vw, calc(420px * var(--ui-scale, 1))), var(--gp));
  height: round(
    down,
    calc(
      100dvh - var(--hud-safe-top) - var(--hud-thumb-bottom) - var(--hud-stick) - 2 *
        var(--hud-gap) - var(--ime-inset, 0px)
    ),
    var(--gp)
  );
  padding: calc(3 * var(--gp)) calc(4 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
}
[data-ui-profile='handheld']
  .hud-dock--bottomLeft
  .chat-wrap.hud-railed:not(.hud-layout-detached):not(.is-collapsed)
  > .chat-content {
  max-height: none;
}
[data-ui-profile='handheld']
  .hud-dock--bottomLeft
  .chat-wrap.hud-railed:not(.hud-layout-detached)
  .chat-log {
  flex: 1 1 auto;
  height: auto;
  min-height: 0;
  max-height: none;
}
[data-ui-profile='handheld']
  .hud-dock--bottomLeft
  .chat-wrap.hud-railed:not(.hud-layout-detached)
  .chat-tabs {
  padding-right: 0;
}
[data-ui-profile='handheld']
  .hud-dock--bottomLeft
  .chat-wrap.hud-railed:not(.hud-layout-detached)
  .chat-entry {
  width: 100%;
  margin-left: 0;
}
/* The window is as big as the glass allows; there is nothing left to drag it to. */
[data-ui-profile='handheld']
  .hud-dock--bottomLeft
  .chat-wrap.hud-railed:not(.hud-layout-detached)
  .chat-resize {
  display: none;
}
/* Chat's passing lines stand above its launcher, edge to edge with it, in the
   stick's shoulder and the band over it. The prompts rail keeps that band clear,
   so a prompt is never drawn under them; the reserve is sized for the chat
   ticker's three rows (chat-view.ts). */
[data-ui-profile='handheld'] .hud-dock--bottomLeft {
  /* The row's foot stands level with the skill wheel's, which may sit above the
     safe edge to leave its aim sticks room (--hud-thumb-bottom). */
  padding-bottom: calc(var(--hud-thumb-bottom) - var(--hud-safe-bottom));
  --hud-ticker-width: round(down, min(calc(256px * var(--ui-scale, 1)), 30vw), var(--gp));
  --thumb-row-news: calc(
    3 * (round(calc(var(--type-label-size) * 1.25), var(--gp)) + 2 * var(--gp)) + 2 * var(--gp)
  );
}
[data-ui-profile='handheld'] .hud-dock--bottomLeft .hud-rail--bottomLeftPrompts {
  margin-bottom: max(
    0px,
    round(
      up,
      calc(var(--thumb-row-news) + 2 * var(--gp) + var(--hud-fold-shell-size) - var(--hud-stick)),
      var(--gp)
    )
  );
}
[data-ui-profile='handheld']
  .hud-dock--bottomLeft
  .chat-wrap.hud-railed:not(.hud-layout-detached)
  > .hud-ticker {
  top: auto;
  right: auto;
  bottom: calc(100% + 2 * var(--gp));
  left: var(--hud-fold-inset);
  align-items: flex-start;
}
/* The season crest is off on a handheld: it docks in no handheld rail, and the
   menu dock still opens the season window. */
[data-ui-profile='handheld'] ront-hud-war-state {
  display: none !important;
}
/* A window the player opened from the row covers the combat banners (freeze
   lockout, enemy cast, announcements), which the row otherwise stands under. */
[data-ui-profile='handheld']
  .hud-dock-row--bottom:has(
    ront-menu-dock:not(.is-collapsed),
    .hud-dock--bottomLeft .chat-wrap.hud-railed:not(.is-collapsed)
  ) {
  z-index: 41;
}
/* Windows wear the HUD's pixel material over every sheet that paints them. */
/* Every window over the world wears the HUD's one material (pixel-chrome.css) in HUD pixels (--gp). Inside a window the panel tokens take the pixel palette, so --ui-line, --ui-control-fill and --muted follow the frame. */
.window,
.panel,
.win-frame,
.npc-win {
  --ui-frame-fill: var(--pixel-night);
  --panel: var(--pixel-ink);
  --panel-2: var(--pixel-dusk);
  --panel-raised: var(--pixel-dusk);
  --ui-surface: var(--pixel-ink);
  --ui-surface-raised: var(--pixel-night);
  --ui-line: var(--pixel-dusk);
  --ui-line-soft: var(--pixel-dusk);
  --ui-line-bright: var(--pixel-slate);
  --ui-control-fill: var(--pixel-ink);
  --ui-control-fill-hover: var(--pixel-dusk);
  --ui-control-line: var(--pixel-slate);
  --ui-control-line-hover: var(--pixel-lilac);
  --grid-line: var(--pixel-dusk);
  --row-hover: rgb(141 134 152 / 10%);
  --muted: var(--pixel-lilac);
}
/* The step a held frame's height moves in (window-height-latch.ts): whole HUD pixel pairs. */
@property --win-frame-quantum {
  syntax: '<length>';
  inherits: false;
  initial-value: 0px;
}
/* HUD windows (.window), service counters (.win-frame) and plain panels (.panel) share one frame. */
.window,
.panel,
.win-frame,
.npc-win {
  --win-frame-quantum: calc(2 * var(--gp));
}
.window,
.panel,
.win-frame {
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
}
.window {
  padding: calc(2 * var(--gp));
}
.window::before {
  display: none;
}
.panel h1 {
  border-left: 0;
  padding-left: 0;
  line-height: round(up, 1.15em, calc(2 * var(--gp)));
}
.esc-root__panel {
  gap: calc(4 * var(--gp));
  padding: calc(6 * var(--gp)) calc(7 * var(--gp));
}
.esc-root__panel h1 {
  margin: 0 0 calc(3 * var(--gp));
}
.esc-key-cap {
  padding: 0 calc(3 * var(--gp));
  border: var(--gp) solid currentColor;
  line-height: round(up, 1.4em, calc(2 * var(--gp)));
}
.esc-root__btn .esc-key-cap {
  right: calc(6 * var(--gp));
  text-align: start;
}
/* The standee rises out of its plate, so the plate is painted behind it on a clipped layer and the window stays unclipped. */
.npc-win {
  isolation: isolate;
  border: 0;
  background: none;
  box-shadow: none;
}
.npc-win::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 0;
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-night);
  box-shadow: var(--pixel-rim);
  clip-path: var(--pixel-notch);
  pointer-events: none;
}
.npc-speaker-art {
  filter: drop-shadow(0 var(--gp) 0 var(--pixel-ink));
}
.npc-speaker-glow,
.npc-speaker-floor {
  display: none;
}
.npc-name {
  color: var(--pixel-cream);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}
.npc-speaking .npc-name {
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}
.npc-nameplate-rule {
  height: var(--gp);
  background: var(--pixel-dusk);
}
.npc-win {
  gap: calc(7 * var(--gp));
  padding: calc(8 * var(--gp)) calc(9 * var(--gp));
}
.npc-nameplate {
  gap: calc(4 * var(--gp));
  margin: 0 0 calc(4 * var(--gp));
}
.npc-name {
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
}
.npc-text {
  --npc-line: round(1.55em, var(--gp));
  height: calc(5 * var(--npc-line));
  min-height: calc(2 * var(--npc-line));
  margin-bottom: calc(6 * var(--gp));
  line-height: var(--npc-line);
}
[data-ui-profile='handheld'] .npc-text {
  --npc-line: round(1.45em, var(--gp));
  height: calc(3 * var(--npc-line));
  min-height: calc(2 * var(--npc-line));
  max-height: calc(4 * var(--npc-line));
  line-height: var(--npc-line);
}
.win-head {
  height: round(calc(40px * var(--ui-scale)), calc(2 * var(--gp)));
  padding: 0 calc(3 * var(--gp)) calc(2 * var(--gp)) calc(5 * var(--gp));
  background: none;
  color: var(--pixel-cream);
  text-shadow: 0 var(--gp) 0 var(--pixel-ink);
}
.win-head > span:first-child {
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
}
.win-body {
  padding: calc(7 * var(--gp)) calc(8 * var(--gp)) calc(8 * var(--gp));
  max-height: round(down, min(68vh, calc(720px * var(--ui-scale))), calc(2 * var(--gp)));
}
.win-head::after {
  left: 0;
  right: 0;
  height: calc(2 * var(--gp));
  background: linear-gradient(var(--pixel-ink) 50%, var(--pixel-dusk) 50%);
}
.win-close {
  width: calc(14 * var(--gp));
  height: calc(14 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background-color: var(--pixel-night);
  background-size: calc(10 * var(--gp)) calc(10 * var(--gp));
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-lilac),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  clip-path: var(--pixel-notch);
  transition: none;
}
.win-close:hover {
  border-color: var(--pixel-ink);
  background-color: color-mix(in srgb, var(--pixel-debuff) 40%, var(--pixel-night));
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-debuff),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-ink);
}
.win-close:active {
  transform: translateY(var(--gp));
}
/* On glass the cap is a thumb's width and the bar grows to hold it clear of the rim. */
[data-ui-profile='handheld'] .win-head {
  height: auto;
  padding-block: var(--gp);
}
[data-ui-profile='handheld'] .win-close {
  width: round(up, var(--hud-touch-min), calc(2 * var(--gp)));
  height: round(up, var(--hud-touch-min), calc(2 * var(--gp)));
}
.inv-act {
  box-sizing: border-box;
  min-height: calc(14 * var(--gp));
  padding: 0 calc(6 * var(--gp));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-dusk);
  color: var(--pixel-cream);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
  transition: none;
}
.inv-act:hover {
  border-color: var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-slate) 45%, var(--pixel-dusk));
  color: var(--pixel-cream);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-lilac),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}
.inv-act.drop,
.inv-act.drop:hover {
  border-color: var(--pixel-ink);
  background: color-mix(in srgb, var(--pixel-debuff) 45%, var(--pixel-night));
  color: var(--pixel-cream);
}
/* Clipped pieces lose anything drawn outside, so the focus bracket is drawn inside. */
.inv-act:focus-visible,
.win-close:focus-visible,
.inv-filter:focus-visible {
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--bg),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent) !important;
}
.inv-window {
  gap: calc(4 * var(--gp));
}
.inv-header {
  padding-bottom: calc(2 * var(--gp));
  border-bottom-width: var(--gp);
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
}
.inv-header {
  gap: calc(3 * var(--gp));
}
.inv-hd-ico .inv-ico-img {
  width: calc(10 * var(--gp));
  height: calc(10 * var(--gp));
}
.inv-toolbar {
  gap: calc(2 * var(--gp));
}
.inv-filters {
  display: grid;
  grid-template-columns:
    repeat(3, round(down, calc((100% - 6 * var(--gp)) / 4), var(--gp)))
    minmax(0, 1fr);
  gap: calc(2 * var(--gp));
}
/* A tab is a sunk well; the open one stands up as a plate. */
.inv-filter {
  justify-content: flex-start;
  gap: calc(2 * var(--gp));
  padding: calc(2 * var(--gp)) calc(3 * var(--gp));
  line-height: round(up, 1em, calc(2 * var(--gp)));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  color: var(--pixel-lilac);
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
  clip-path: var(--pixel-notch);
  transition: none;
}
.inv-filter:hover {
  border-color: var(--pixel-ink);
  color: var(--pixel-cream);
}
.inv-filter.active {
  border-color: var(--pixel-ink);
  background: var(--pixel-dusk);
  color: var(--pixel-cream);
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-slate),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-night);
}
.inv-filter-ico .inv-ico-img {
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
}
.inv-filter-count,
.inv-filter.active .inv-filter-count {
  min-width: 0;
  margin-left: auto;
  padding: 0;
  background: none;
  color: inherit;
}
.inv-grid {
  /* Stepped to whole HUD pixel pairs so a phone's smaller scale still gets a smaller slot. */
  --inv-slot: max(
    round(calc(44px * var(--ui-scale)), calc(2 * var(--gp))),
    calc(3 * var(--type-metadata-size))
  );
  grid-template-columns: repeat(auto-fill, var(--inv-slot));
  gap: calc(2 * var(--gp));
}
.inv-cell,
.inv-cell:hover,
.inv-cell[aria-selected='true'],
.inv-cell--selected {
  width: var(--inv-slot, 100%);
  min-height: var(--inv-slot, calc(42px * var(--ui-scale)));
  border: var(--gp) solid var(--pixel-ink);
  background: var(--pixel-ink);
  box-shadow:
    inset 0 0 0 var(--gp) var(--inv-rarity-frame, var(--pixel-dusk)),
    inset calc(-2 * var(--gp)) calc(-2 * var(--gp)) 0 var(--pixel-night);
  outline: none;
  clip-path: var(--pixel-notch);
  transform: none;
  transition: none;
}
.inv-cell:hover {
  filter: brightness(1.18);
}
.inv-cell:hover,
.inv-cell[aria-selected='true'],
.inv-cell--selected {
  box-shadow:
    inset 0 0 0 var(--gp) var(--inv-rarity-frame, var(--pixel-dusk)),
    inset 0 0 0 calc(2 * var(--gp)) var(--accent);
}
.inv-cell:focus-visible {
  outline: none !important;
  box-shadow:
    inset 0 0 0 var(--gp) var(--inv-rarity-frame, var(--pixel-dusk)),
    inset 0 0 0 calc(3 * var(--gp)) var(--accent) !important;
}
.inv-cell-empty,
.inv-cell-empty:hover {
  opacity: 1;
  background: color-mix(in srgb, var(--pixel-ink) 55%, var(--pixel-night));
  box-shadow: inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0 var(--pixel-dusk);
  filter: none;
}
.inv-cell .inv-quest {
  border-top-width: calc(4 * var(--gp));
  border-right-width: calc(4 * var(--gp));
}
.win-inv .win-body {
  padding: calc(5 * var(--gp)) calc(6 * var(--gp));
}
.inv-window .inv-grid {
  min-height: 0;
  /* The lesson halo's room (hud-attention.css) stays inside the scroller on every side, since the call shakes sideways. */
  margin: calc(-2 * var(--gp)) calc(-1 * var(--gp)) 0 calc(-4 * var(--gp));
  padding: var(--pixel-halo-reach);
}
.win-inv .inv-footer {
  gap: calc(4 * var(--gp));
  padding-top: calc(3 * var(--gp));
  border-top: var(--gp) solid var(--pixel-dusk);
}
.win-inv .inv-footer * {
  line-height: round(up, 1.2em, calc(2 * var(--gp)));
}
.win-inv :is(.inv-weight, .inv-gold) {
  gap: calc(2 * var(--gp));
}
.win-inv .inv-weight-ico .inv-ico-img,
.win-inv .inv-gold-ico .inv-ico-img {
  width: calc(8 * var(--gp));
  height: calc(8 * var(--gp));
}
.npc-controls {
  gap: calc(3 * var(--gp));
  padding-bottom: var(--gp);
}
/* The answer keeps the primary plate's bevel; a ring outside would be cut by the notch. */
.npc-said .npc-controls .ron-btn--primary {
  box-shadow:
    inset var(--gp) var(--gp) 0 var(--pixel-honey),
    inset calc(-1 * var(--gp)) calc(-1 * var(--gp)) 0
      color-mix(in srgb, var(--pixel-ochre) 60%, var(--pixel-ink));
}
[data-ui-profile='handheld'] .window:not(.win-skills) .win-body {
  max-height: round(down, calc(var(--hud-window-max-h) - 3.25rem), calc(2 * var(--gp)));
}
/* A lit piece stands unclipped, since a clip would cut the lesson halo (hud-attention.css). */
[data-coach-actions~='back'] .win-close.coach-action-target,
[data-coach-actions~='wear'] .win-inv.is-open .inv-cell--equippable {
  clip-path: none;
}
