/* texture.css: depth on Relay's surfaces, and NOTHING ELSE.
 *
 * ⛔⛔ PAINT ONLY, with one asked for exception (your own chat bubbles, below).
 * Large surfaces also take --tx-dim, a faint black layer under their texture:
 * the reader found the board read grey, because the grain and sheens are light
 * specks on near black. It darkens what is under the light, not the light.
 * Every declaration in this file is one of background-image,
 * box-shadow or backdrop-filter, plus background-color in the group colour
 * candidates at the bottom. None of them takes part in layout, so nothing can
 * move, grow, shrink or wrap because of this file, and that is the owner's rule
 * for the redesign: same places, same sizes, same words, a new texture. If a
 * rule here ever needs a margin, a padding, a border width, a position or a
 * size, it does not belong here.
 *
 * ⚠️ WHY !important. The board is one template with ~3,900 inline styles
 * (web/tpl/relay.html), and an inline style beats any stylesheet rule that is
 * not important. `background: #101010` inline also sets background-image to
 * none, so the only way to lay a gradient OVER the existing colour, without
 * touching the colour, is an important background-image. The colour itself
 * stays inline and stays the template's.
 *
 * ⚠️ Hooked by `data-skin` attributes on the containers in relay.html, never
 * by matching inline style text, except for the small controls inside a hooked
 * surface where the selector is scoped to that surface.
 *
 * ⚠️ NEVER override box-shadow on a to-do or issue ROW: its inline box-shadow
 * is the drag and drop insertion line (`it.dropLine`). The row's etched top
 * edge is a 1px background gradient for exactly that reason.
 *
 * ⚠️ NO WHITE OVER A GROUP'S COLOUR. Round 1 laid a white sheen across the
 * group header, on top of its 6% colour wash, and that is half of why the
 * groups read cloudy and pastel. Light belongs on neutral surfaces only.
 *
 * The switches, all attributes on any ancestor (<html> on the board, a frame
 * in the lab), so one page can show several side by side:
 *   data-texture  "deep" turns the skin on (index.html sets it on <html>);
 *                 absent is today's flat board
 *   data-chrome   "titanium" puts the metal frame on dialogs (index.html sets
 *                 it on <html>); absent, dialogs keep Deep's outline
 */

/* ── which way the light falls ────────────────────────────────────────────────
 * Every shadow in this file is rgba(var(--tx-ink), a × --tx-shade) and every
 * highlight rgba(var(--tx-lite), a). On the dark board that is black and white,
 * exactly the colours the file was written in.
 *
 * ⭐ THE LIGHT THEME IS THE DARK BOARD INVERTED (prototype.js applyTheme puts
 * invert() on <html>), so a black shadow came out as a pale GLOW and a white
 * highlight as a dark line: the depth read upside down, and the board looked
 * like the old flat one with a smudge. Reported 2026-10-22, "everything works
 * on black, but on light, it's still the old textures". Swapping ink and lite
 * here means the inversion lands each one the right way round, and --tx-shade
 * softens the shadows, which were tuned to show on near black and are far too
 * heavy on a light page.
 *
 * ⚠️ --tx-dim and --tx-grain are NOT swapped. The dim is there to stop the grain
 * greying a surface, and inverted, both already do the light theme's version of
 * the same job: dark specks on a light surface, with a pale layer under them. */
[data-texture] {
  --tx-ink: 0, 0, 0;
  --tx-lite: 255, 255, 255;
  --tx-shade: 1;
}
html[data-texture][style*="invert"] {
  --tx-ink: 255, 255, 255;
  --tx-lite: 0, 0, 0;
  --tx-shade: 0.45;
  /* ⭐ THE GROUP'S TOP EDGE, as clear in light as in dark (Loucas, 28 October
   * 2026: "on light there is a horizontal color line missing"). Inverted, the
   * 65% mix of a pale group colour lands as a pale tint on a near white page and
   * all but vanishes; full strength and 2px read like the dark board's line. */
  --tx-grp-rim: 100%;
  --tx-grp-rim-w: 2px;
  /* the outline round a group box is black on black in dark; inverted it was a
   * dark line drawn right over the coloured top edge, so light leaves it out */
  --tx-grp-ring: 0;
  /* ⭐ NO DRAWN OUTLINES IN LIGHT (Loucas, 28 October 2026: "on dark there is a
   * black outline everywhere; in light it doesn't look great"). On the dark
   * board the 1px outline round every surface, the crisp line under its edge
   * and the dialog's 4px frame line are black on black and read as depth;
   * inverted they are drawn grey lines, and the board looked like a wireframe.
   * Light keeps the soft cast shadow, which is how a light page shows depth. */
  --tx-ring: 0;
  --tx-contact: transparent;
  --tx-frame-line: transparent;
}

/* ── the strength: Deep ────────────────────────────────────────────────────────
 * Chosen by the reader over Soft, whose gentler values are gone. index.html
 * sets data-texture="deep" on <html>; the lab sets it on its frames. */
[data-texture="deep"] {
  --tx-lit: transparent; /* a full width top light: none, the streak is the light */
  --tx-rim: rgba(var(--tx-lite), 0.03); /* the rest of the rim, all round */
  --tx-sheen: rgba(var(--tx-lite), 0.016); /* the top of a surface's gradient */
  --tx-glow: rgba(var(--tx-lite), 0.016); /* the ambient pool in a corner */
  --tx-key: rgba(var(--tx-lite), 0.07); /* a raised control's face */
  --tx-etch: rgba(var(--tx-lite), 0.035); /* the light line under a divider */
  --tx-contact: rgba(
    var(--tx-ink),
    calc(0.7 * var(--tx-shade))
  ); /* the crisp shadow right under an edge */
  --tx-cast: rgba(
    var(--tx-ink),
    calc(0.8 * var(--tx-shade))
  ); /* the long soft shadow onto what is below */
  --tx-well: rgba(var(--tx-ink), calc(0.6 * var(--tx-shade))); /* a recessed field's inner shadow */
  --tx-bezel: rgba(var(--tx-lite), 0.022);
  --tx-bezel-edge: rgba(var(--tx-lite), 0.05);
  --tx-frame-line: transparent; /* data-chrome: the dark line outside the metal */
  --tx-cta-sheen: rgba(var(--tx-lite), 0.16); /* an orange action button's lit face */
  --tx-cta-lit: rgba(var(--tx-lite), 0.3); /* and its top edge */
  --tx-streak: radial-gradient(
    44% 1.5px at 50% 0,
    rgba(var(--tx-lite), 0.12),
    transparent
  ); /* the reflection mid top edge */
  --tx-dim: rgba(
    0,
    0,
    0,
    0.24
  ); /* laid under the texture on large surfaces, so the grain does not grey them */
  --tx-blur: 7px;
  --tx-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.04'/%3E%3C/svg%3E");
}

/* ⭐ DECIDED: THE LIGHT IS A SOFT STREAK. A short, dim reflection in the middle
 * of a surface's top edge, fading out before the corners, instead of round 1's
 * full width top light, which read too bright. Rejected beside it: matte (no
 * light), an even rim, and carved (a shadow inside the top edge). The streak
 * is --tx-streak in each strength; --tx-lit, the full width line, is kept as a
 * token and set to nothing, so a rule that asks for it draws nothing. */

/* ── the chrome rim: titanium, on dialogs ─────────────────────────────────────
 * ⭐ DECIDED: TITANIUM. data-chrome="titanium" on <html> (index.html) turns it
 * on. A dark metal frame, like the edge of a laptop or a phone: low contrast,
 * lit from above so the top edge catches the light and the bottom sits in
 * shadow, one thin bevel line, nothing that glints. 3px of metal outside the
 * box, where Deep's outline sits. Satin, the same frame in a lighter grey, was
 * the other candidate; tools/texture_chrome_frame.py can still draw it.
 *
 * ⛔ DIALOGS ONLY, the reader's choice. Taken off the group boxes (a group's rim
 * is its own colour, E1, and a metal frame fought that coloured edge) and off
 * the side menu folders.
 * Round 4's mirror chrome was rejected as too shiny and pulling all the
 * attention.
 *
 * ⚠️ WHY border-image AND NOT A PSEUDO ELEMENT. Dialogs and the folders set
 * their own overflow, which would clip a ::before ring and, in the Session
 * route, scroll it away with the content. border-image is the box's own
 * border, so its overflow never clips it, and border-image-width and
 * border-image-outset never take part in layout.
 *
 * ⚠️ ONE IMAGE PER CORNER RADIUS. A frame drawn for a 14px box on a
 * 12px box leaves its corners off the curve. tools/texture_chrome_frame.py
 * draws them; rerun it and paste its output here if a radius changes.
 *
 * ⚠️ NOT the Active work cards either: their border colour says whose session
 * it is (orange for yours), and a metal frame would erase that. */
:is([data-chrome][data-texture], [data-chrome] [data-texture]) {
  --tx-bezel: transparent;
  --tx-bezel-edge: transparent;
  --tx-frame-line: rgba(var(--tx-ink), calc(0.6 * var(--tx-shade)));
}
:is([data-chrome][data-texture], [data-chrome] [data-texture]) [data-skin="dialog"] {
  border-image:
    url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22102%22 height=%22102%22 viewBox=%220 0 102 102%22%3E %3Cdefs%3E %3CclipPath id=%22r%22%3E%3Cpath clip-rule=%22evenodd%22 d=%22M17,0H85A17,17 0 0 1 102,17V85A17,17 0 0 1 85,102H17A17,17 0 0 1 0,85V17A17,17 0 0 1 17,0ZM17,4H85A13,13 0 0 1 98,17V85A13,13 0 0 1 85,98H17A13,13 0 0 1 4,85V17A13,13 0 0 1 17,4Z%22/%3E%3C/clipPath%3E %3ClinearGradient id=%22t%22 gradientUnits=%22userSpaceOnUse%22 x1=%220%22 y1=%224%22 x2=%220%22 y2=%220%22%3E%3Cstop offset=%220.0000%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.3000%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.6000%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.8200%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/linearGradient%3E %3ClinearGradient id=%22b%22 gradientUnits=%22userSpaceOnUse%22 x1=%220%22 y1=%2298%22 x2=%220%22 y2=%22102%22%3E%3Cstop offset=%220.0000%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.3000%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.6000%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.8200%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/linearGradient%3E %3ClinearGradient id=%22l%22 gradientUnits=%22userSpaceOnUse%22 x1=%224%22 y1=%220%22 x2=%220%22 y2=%220%22%3E%3Cstop offset=%220.0000%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.3000%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.6000%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.8200%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/linearGradient%3E %3ClinearGradient id=%22g%22 gradientUnits=%22userSpaceOnUse%22 x1=%2298%22 y1=%220%22 x2=%22102%22 y2=%220%22%3E%3Cstop offset=%220.0000%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.3000%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.6000%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.8200%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/linearGradient%3E %3CradialGradient id=%22c1%22 gradientUnits=%22userSpaceOnUse%22 cx=%2217%22 cy=%2217%22 r=%2217%22%3E%3Cstop offset=%220.7647%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.8353%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.9059%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.9576%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/radialGradient%3E %3CradialGradient id=%22c2%22 gradientUnits=%22userSpaceOnUse%22 cx=%2285%22 cy=%2217%22 r=%2217%22%3E%3Cstop offset=%220.7647%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.8353%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.9059%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.9576%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/radialGradient%3E %3CradialGradient id=%22c3%22 gradientUnits=%22userSpaceOnUse%22 cx=%2217%22 cy=%2285%22 r=%2217%22%3E%3Cstop offset=%220.7647%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.8353%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.9059%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.9576%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/radialGradient%3E %3CradialGradient id=%22c4%22 gradientUnits=%22userSpaceOnUse%22 cx=%2285%22 cy=%2285%22 r=%2217%22%3E%3Cstop offset=%220.7647%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.8353%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.9059%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.9576%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/radialGradient%3E %3ClinearGradient id=%22d%22 gradientUnits=%22userSpaceOnUse%22 x1=%220%22 y1=%220%22 x2=%220%22 y2=%22102%22%3E%3Cstop offset=%220%22 stop-color=%22%23fff%22 stop-opacity=%22.16%22/%3E%3Cstop offset=%22.35%22 stop-color=%22%23fff%22 stop-opacity=%220%22/%3E%3Cstop offset=%22.6%22 stop-color=%22%23000%22 stop-opacity=%220%22/%3E%3Cstop offset=%221%22 stop-color=%22%23000%22 stop-opacity=%22.42%22/%3E%3C/linearGradient%3E %3Cfilter id=%22s%22 x=%22-20%25%22 y=%22-200%25%22 width=%22140%25%22 height=%22500%25%22%3E%3CfeGaussianBlur stdDeviation=%220.35%22/%3E%3C/filter%3E %3C/defs%3E %3Cg clip-path=%22url(%23r)%22%3E %3Crect x=%2217%22 y=%220%22 width=%2268%22 height=%224%22 fill=%22url(%23t)%22/%3E %3Crect x=%2217%22 y=%2298%22 width=%2268%22 height=%224%22 fill=%22url(%23b)%22/%3E %3Crect x=%220%22 y=%2217%22 width=%224%22 height=%2268%22 fill=%22url(%23l)%22/%3E %3Crect x=%2298%22 y=%2217%22 width=%224%22 height=%2268%22 fill=%22url(%23g)%22/%3E %3Crect x=%220%22 y=%220%22 width=%2217%22 height=%2217%22 fill=%22url(%23c1)%22/%3E %3Crect x=%2285%22 y=%220%22 width=%2217%22 height=%2217%22 fill=%22url(%23c2)%22/%3E %3Crect x=%220%22 y=%2285%22 width=%2217%22 height=%2217%22 fill=%22url(%23c3)%22/%3E %3Crect x=%2285%22 y=%2285%22 width=%2217%22 height=%2217%22 fill=%22url(%23c4)%22/%3E %3Crect width=%22102%22 height=%22102%22 fill=%22url(%23d)%22/%3E %3Cg filter=%22url(%23s)%22%3E %3Cellipse cx=%2251.0%22 cy=%223.00%22 rx=%2228.8%22 ry=%220.88%22 fill=%22%23fff%22 opacity=%220.12%22/%3E %3C/g%3E %3C/g%3E %3C/svg%3E")
    19 / 19px / 3px stretch !important;
}
:is([data-chrome][data-texture], [data-chrome] [data-texture])
  [data-skin="dialog"][style*="border-radius: 12px"] {
  border-image:
    url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2298%22 height=%2298%22 viewBox=%220 0 98 98%22%3E %3Cdefs%3E %3CclipPath id=%22r%22%3E%3Cpath clip-rule=%22evenodd%22 d=%22M15,0H83A15,15 0 0 1 98,15V83A15,15 0 0 1 83,98H15A15,15 0 0 1 0,83V15A15,15 0 0 1 15,0ZM15,4H83A11,11 0 0 1 94,15V83A11,11 0 0 1 83,94H15A11,11 0 0 1 4,83V15A11,11 0 0 1 15,4Z%22/%3E%3C/clipPath%3E %3ClinearGradient id=%22t%22 gradientUnits=%22userSpaceOnUse%22 x1=%220%22 y1=%224%22 x2=%220%22 y2=%220%22%3E%3Cstop offset=%220.0000%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.3000%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.6000%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.8200%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/linearGradient%3E %3ClinearGradient id=%22b%22 gradientUnits=%22userSpaceOnUse%22 x1=%220%22 y1=%2294%22 x2=%220%22 y2=%2298%22%3E%3Cstop offset=%220.0000%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.3000%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.6000%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.8200%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/linearGradient%3E %3ClinearGradient id=%22l%22 gradientUnits=%22userSpaceOnUse%22 x1=%224%22 y1=%220%22 x2=%220%22 y2=%220%22%3E%3Cstop offset=%220.0000%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.3000%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.6000%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.8200%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/linearGradient%3E %3ClinearGradient id=%22g%22 gradientUnits=%22userSpaceOnUse%22 x1=%2294%22 y1=%220%22 x2=%2298%22 y2=%220%22%3E%3Cstop offset=%220.0000%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.3000%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.6000%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.8200%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/linearGradient%3E %3CradialGradient id=%22c1%22 gradientUnits=%22userSpaceOnUse%22 cx=%2215%22 cy=%2215%22 r=%2215%22%3E%3Cstop offset=%220.7333%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.8133%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.8933%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.9520%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/radialGradient%3E %3CradialGradient id=%22c2%22 gradientUnits=%22userSpaceOnUse%22 cx=%2283%22 cy=%2215%22 r=%2215%22%3E%3Cstop offset=%220.7333%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.8133%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.8933%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.9520%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/radialGradient%3E %3CradialGradient id=%22c3%22 gradientUnits=%22userSpaceOnUse%22 cx=%2215%22 cy=%2283%22 r=%2215%22%3E%3Cstop offset=%220.7333%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.8133%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.8933%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.9520%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/radialGradient%3E %3CradialGradient id=%22c4%22 gradientUnits=%22userSpaceOnUse%22 cx=%2283%22 cy=%2283%22 r=%2215%22%3E%3Cstop offset=%220.7333%22 stop-color=%22%230e0e0e%22/%3E%3Cstop offset=%220.8133%22 stop-color=%22%23262626%22/%3E%3Cstop offset=%220.8933%22 stop-color=%22%23434343%22/%3E%3Cstop offset=%220.9520%22 stop-color=%22%235a5a5a%22/%3E%3Cstop offset=%221.0000%22 stop-color=%22%23242424%22/%3E%3C/radialGradient%3E %3ClinearGradient id=%22d%22 gradientUnits=%22userSpaceOnUse%22 x1=%220%22 y1=%220%22 x2=%220%22 y2=%2298%22%3E%3Cstop offset=%220%22 stop-color=%22%23fff%22 stop-opacity=%22.16%22/%3E%3Cstop offset=%22.35%22 stop-color=%22%23fff%22 stop-opacity=%220%22/%3E%3Cstop offset=%22.6%22 stop-color=%22%23000%22 stop-opacity=%220%22/%3E%3Cstop offset=%221%22 stop-color=%22%23000%22 stop-opacity=%22.42%22/%3E%3C/linearGradient%3E %3Cfilter id=%22s%22 x=%22-20%25%22 y=%22-200%25%22 width=%22140%25%22 height=%22500%25%22%3E%3CfeGaussianBlur stdDeviation=%220.35%22/%3E%3C/filter%3E %3C/defs%3E %3Cg clip-path=%22url(%23r)%22%3E %3Crect x=%2215%22 y=%220%22 width=%2268%22 height=%224%22 fill=%22url(%23t)%22/%3E %3Crect x=%2215%22 y=%2294%22 width=%2268%22 height=%224%22 fill=%22url(%23b)%22/%3E %3Crect x=%220%22 y=%2215%22 width=%224%22 height=%2268%22 fill=%22url(%23l)%22/%3E %3Crect x=%2294%22 y=%2215%22 width=%224%22 height=%2268%22 fill=%22url(%23g)%22/%3E %3Crect x=%220%22 y=%220%22 width=%2215%22 height=%2215%22 fill=%22url(%23c1)%22/%3E %3Crect x=%2283%22 y=%220%22 width=%2215%22 height=%2215%22 fill=%22url(%23c2)%22/%3E %3Crect x=%220%22 y=%2283%22 width=%2215%22 height=%2215%22 fill=%22url(%23c3)%22/%3E %3Crect x=%2283%22 y=%2283%22 width=%2215%22 height=%2215%22 fill=%22url(%23c4)%22/%3E %3Crect width=%2298%22 height=%2298%22 fill=%22url(%23d)%22/%3E %3Cg filter=%22url(%23s)%22%3E %3Cellipse cx=%2249.0%22 cy=%223.00%22 rx=%2228.8%22 ry=%220.88%22 fill=%22%23fff%22 opacity=%220.12%22/%3E %3C/g%3E %3C/g%3E %3C/svg%3E")
    17 / 17px / 3px stretch !important;
}
/* ── the canvas behind everything ──────────────────────────────────────────── */
[data-texture] [data-skin="shell"] {
  background-image:
    var(--tx-grain), radial-gradient(1100px 520px at 55% -8%, var(--tx-glow), transparent 70%),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
}

/* ── 1. the side menu ──────────────────────────────────────────────────────── */
/* A column lit from above, with its inner edge catching the light and a soft
 * shadow cast onto the page beside it. */
[data-texture] [data-skin="nav"] {
  background-image:
    var(--tx-grain), linear-gradient(180deg, var(--tx-sheen), transparent 280px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset -1px 0 0 var(--tx-rim),
    1px 0 0 var(--tx-contact),
    14px 0 34px -18px var(--tx-cast) !important;
}
/* The project folders and the Active work cards: raised tiles. */
[data-texture] [data-skin="nav-card"],
[data-texture] [data-skin="nav-work"] {
  background-image:
    var(--tx-streak), linear-gradient(180deg, var(--tx-sheen), transparent 46px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    inset 0 0 0 1px var(--tx-rim),
    0 1px 0 var(--tx-contact),
    0 8px 18px -10px var(--tx-cast) !important;
}

/* ── 2. the box rows sit in (To-dos, Issues, Pendings, Ideas) ──────────────── */
/* ⭐ DECIDED: E1 WITH A TINTED HEADER, after six rounds of group colours. The
 * box's top rim is the group's colour instead of white, the header takes a
 * faint tint of the same colour as the group's name (strongest by the name,
 * fading across), and the name keeps its colour. Rejected on the way: a richer
 * palette, a colour glow, a lit edge, a white name, and moving the colour to a
 * tab, a spine, the divider or the count chip.
 *
 * ⛔ NO COLOUR OUTSIDE THE BOX. A faint glow of the group colour was cast above
 * it, and the reader asked for the colour to stay within the group: the rim and
 * the header tint are inside, every shadow outside is black.
 *
 * --grp is the group's colour (g.fg), set inline on the group section in
 * relay.html. Without it the rim falls back to grey and the header to no tint.
 *
 * ⚠️ THE HEADER'S OLD WASH IS REPLACED, NOT LAYERED OVER. GROUP_PALETTE pairs
 * each light name colour with a wash of a DIFFERENT, deeper base colour, so
 * the header never matched the name, which is part of why it read cloudy. */
[data-texture] [data-skin="group"] {
  background-image:
    var(--tx-streak), radial-gradient(120% 150px at 0% 0%, var(--tx-glow), transparent 70%),
    linear-gradient(180deg, var(--tx-sheen), transparent 140px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 0 var(--tx-grp-rim-w, 1px) 0
    color-mix(in srgb, var(--grp-shown, var(--grp, #8a8a8a)) var(--tx-grp-rim, 65%), transparent),
    inset 0 0 0 1px var(--tx-rim),
    0 0 0 1px
    rgba(var(--tx-ink), calc(var(--tx-ring, 1) * var(--tx-grp-ring, 0.35) * var(--tx-shade))),
    0 1px 0 var(--tx-contact),
    0 22px 44px -28px var(--tx-cast) !important;
}
[data-texture] [data-skin="group-head"] {
  background-color: transparent !important;
  background-image: linear-gradient(
    90deg,
    color-mix(in srgb, var(--grp-shown, var(--grp, transparent)) 10%, transparent),
    color-mix(in srgb, var(--grp-shown, var(--grp, transparent)) 3%, transparent) 75%
  ) !important;
}
/* Etched dividers: each row's top pixel catches the light under the dark line
 * above it. A gradient and not a shadow, see the header. */
[data-texture] [data-skin="row"] {
  background-image: linear-gradient(180deg, var(--tx-etch) 0 1px, transparent 1px) !important;
}

/* ── 3 and 4. every dialog, the Session route included ─────────────────────── */
/* The page behind goes soft, the dialog floats: lit from above, a rim all
 * round, a dark outline against the page, and in "deep" a bezel. */
[data-texture] [data-skin="scrim"] {
  backdrop-filter: blur(var(--tx-blur)) saturate(0.85);
  -webkit-backdrop-filter: blur(var(--tx-blur)) saturate(0.85);
}
[data-texture] [data-skin="dialog"],
[data-texture] [data-skin="dialog"] > [style*="position: sticky"] {
  background-image:
    var(--tx-streak), var(--tx-grain),
    radial-gradient(90% 220px at 50% 0%, var(--tx-glow), transparent 75%),
    linear-gradient(180deg, var(--tx-sheen), transparent 220px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
}
[data-texture] [data-skin="dialog"] {
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    inset 0 0 0 1px var(--tx-rim),
    0 0 0 1px rgba(var(--tx-ink), calc(var(--tx-ring, 1) * 0.7 * var(--tx-shade))),
    0 0 0 4px var(--tx-frame-line),
    0 0 0 6px var(--tx-bezel),
    0 0 0 7px var(--tx-bezel-edge),
    0 40px 90px -20px rgba(var(--tx-ink), calc(0.8 * var(--tx-shade))),
    0 16px 32px -16px rgba(var(--tx-ink), calc(0.6 * var(--tx-shade))) !important;
}

/* Every menu (role="menu": the account menu, the board's Filter, a message's
 * actions, the right-click menus) floats like a small dialog: the same lit
 * surface and cast shadow, with no bezel, because a frame that heavy on a list
 * of five words reads as a window rather than a menu. */
[data-texture] :is([role="menu"], [role="listbox"][style*="z-index"]) {
  background-image:
    var(--tx-grain), linear-gradient(180deg, var(--tx-sheen), transparent 160px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    inset 0 0 0 1px var(--tx-rim),
    0 0 0 1px rgba(var(--tx-ink), calc(var(--tx-ring, 1) * 0.7 * var(--tx-shade))),
    0 22px 48px -14px rgba(var(--tx-ink), calc(0.75 * var(--tx-shade))),
    0 8px 18px -10px rgba(var(--tx-ink), calc(0.55 * var(--tx-shade))) !important;
}

/* Status dots and stacked avatars cut themselves out of the panel with a ring
 * painted in the old flat panel colour (#101010 to #171717). On a textured
 * panel that ring no longer matches what is under it, and in light, inverted,
 * it reads as an outline round every online dot (Loucas, 28 October 2026). A
 * transparent ring with the fill kept inside it is the real cut-out: whatever
 * the panel is, the gap shows it. */
[data-texture]
span[style*="border-radius: 50%"]:is(
  [style*="solid #101010"],
  [style*="solid #121212"],
  [style*="solid #151515"],
  [style*="solid #171717"]
) {
  border-color: transparent !important;
  background-clip: padding-box !important;
}

/* ── inside a dialog: set into it ─────────────────────────────────────────────
 * The dialog floats; what is inside it sits down in it, so a dialog reads in
 * two levels of depth. The reader chose "set into" over "raised" for this.
 *
 * Panels (any bordered box: the recap's project rows and stats strip, the
 * Session route's tab strip, its callout, "No plan filed") are recessed: a
 * soft shadow under the top edge and a faint lit line along the lower lip.
 * Fields are recessed wells, like the side menu's search box; their focus is
 * an orange border, which this never touches. The Session route's selected tab
 * (aria-pressed) is raised out of its recessed track, like a key.
 *
 * ⚠️ THE OUTERMOST PANEL ONLY. A bordered box inside a bordered box keeps its
 * paint, so the shadows never stack into a well inside a well.
 * ⚠️ NOT a panel whose inline style already has a box-shadow. */
[data-texture]
  [data-skin="dialog"]
  div[style*="border: 1px solid"]:not([style*="box-shadow"]):not(
    [data-skin="dialog"] div[style*="border: 1px solid"] div
  ) {
  box-shadow:
    inset 0 1px 3px var(--tx-well),
    0 1px 0 var(--tx-etch) !important;
}
[data-texture]
  [data-skin="dialog"]
  :is(input, textarea, select)[style*="border: 1px solid"]:not([type="checkbox"]):not(
    [type="radio"]
  ):not([style*="box-shadow"]) {
  box-shadow:
    inset 0 1px 2px var(--tx-well),
    0 1px 0 var(--tx-etch) !important;
}
[data-texture] [data-skin="dialog"] button[aria-pressed="true"]:not([style*="box-shadow"]) {
  background-image: linear-gradient(180deg, var(--tx-key), transparent 75%) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    0 1px 1px var(--tx-contact),
    0 2px 6px -2px rgba(var(--tx-ink), calc(0.55 * var(--tx-shade))) !important;
}

/* ── 5. the activity rail ─────────────────────────────────────────────────── */
[data-texture] [data-skin="rail"] {
  background-image:
    var(--tx-grain), linear-gradient(180deg, var(--tx-sheen), transparent 280px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 1px 0 0 var(--tx-rim),
    -1px 0 0 var(--tx-contact),
    -14px 0 34px -18px var(--tx-cast) !important;
}
[data-texture] [data-skin="feed-row"] {
  background-image: linear-gradient(180deg, var(--tx-etch) 0 1px, transparent 1px) !important;
}
[data-texture] [data-skin="tile"] {
  background-image: linear-gradient(180deg, var(--tx-key), transparent) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    0 2px 6px -2px var(--tx-contact) !important;
}
/* The Messages list slides up over the feed, so it casts upwards. */
[data-texture] [data-skin="rail-sheet"] {
  background-image:
    linear-gradient(180deg, var(--tx-sheen), transparent 120px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    0 -14px 30px -16px var(--tx-cast) !important;
}
[data-texture] [data-skin="rail-foot"] {
  background-image: linear-gradient(180deg, var(--tx-key), transparent) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-rim),
    0 -12px 26px -14px var(--tx-cast) !important;
}

/* ── 6. the Sessions page, and a project's Overview > Sessions ───────────────
 * Session cards and the stat tiles are windows like the group boxes: the soft
 * streak, a rim, a shadow beneath, and the neutral rim: a closed card's border
 * is the same grey for every outcome (ST in component.js), and the outcome
 * lives in its round mark, which stays the template's.
 *
 * ⚠️ THE RUNNING BAR GETS EDGES AND SHADOW ONLY. Its orange glow is an inline
 * background IMAGE (a gradient), so a background-image rule here would erase
 * it. That is why it is a rule of its own rather than one of the windows.
 *
 * The sort strip is a recessed track with the chosen sort (aria-pressed)
 * raised out of it, exactly like the Session route's tabs. The round state
 * marks are small raised discs, like the rail's icon tiles. */
[data-texture] :is([data-skin="sess-card"], [data-skin="sess-tile"]) {
  background-image:
    var(--tx-streak), radial-gradient(120% 150px at 0% 0%, var(--tx-glow), transparent 70%),
    linear-gradient(180deg, var(--tx-sheen), transparent 140px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 0 0 0 1px var(--tx-rim),
    0 0 0 1px rgba(var(--tx-ink), calc(var(--tx-ring, 1) * 0.35 * var(--tx-shade))),
    0 1px 0 var(--tx-contact),
    0 18px 36px -24px var(--tx-cast) !important;
}
[data-texture] [data-skin="sess-live"] {
  box-shadow:
    inset 0 0 0 1px var(--tx-rim),
    0 0 0 1px rgba(var(--tx-ink), calc(var(--tx-ring, 1) * 0.35 * var(--tx-shade))),
    0 1px 0 var(--tx-contact),
    0 18px 36px -24px var(--tx-cast) !important;
}
[data-texture] [data-skin="sess-sort"] {
  box-shadow:
    inset 0 1px 3px var(--tx-well),
    0 1px 0 var(--tx-etch) !important;
}
[data-texture] [data-skin="sess-sort"] button[aria-pressed="true"]:not([style*="box-shadow"]) {
  background-image: linear-gradient(180deg, var(--tx-key), transparent 75%) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    0 1px 1px var(--tx-contact),
    0 2px 6px -2px rgba(var(--tx-ink), calc(0.55 * var(--tx-shade))) !important;
}
[data-texture] [data-skin="sess-mark"] {
  background-image: linear-gradient(180deg, var(--tx-key), transparent) !important;
  box-shadow:
    inset 0 1px 0 rgba(var(--tx-lite), 0.06),
    0 2px 6px -2px var(--tx-contact) !important;
}
/* ── 7. the board's tab strips ───────────────────────────────────────────────
 * The sub navigation strip (To-dos, Issues, Pending, Ideas, and the same strip
 * on Production, Overview and Settings: eight copies) is a recessed track with
 * the selected tab raised out of it, like the Session route's tabs and the
 * Sessions sort. The selected tab is the one span whose inline background is
 * the faint orange (component.js bdNav, ovNav, prNav: on ? rgba(255,138,0,.08)
 * : transparent).
 *
 * The project's own tabs (Board, Production, Overview, Settings) are folder
 * tabs, open at the bottom and joined to the page. The selected one (inline
 * #101010 against #141414) takes the window light and an inner rim, and NO
 * shadow beneath: a shadow would cut it off from the page it opens onto. */
[data-texture] [data-skin="subnav"] {
  box-shadow:
    inset 0 1px 3px var(--tx-well),
    0 1px 0 var(--tx-etch) !important;
}
[data-texture] [data-skin="subnav"] span[style*="background: rgba(255,138,0,.08)"] {
  background-image: linear-gradient(180deg, var(--tx-key), transparent 75%) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    0 1px 1px var(--tx-contact),
    0 2px 6px -2px rgba(var(--tx-ink), calc(0.55 * var(--tx-shade))) !important;
}
[data-texture] [data-skin="tabs"] span[style*="background: #101010"] {
  background-image:
    var(--tx-streak), linear-gradient(180deg, var(--tx-sheen), transparent),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 1px 0 0 var(--tx-rim),
    inset -1px 0 0 var(--tx-rim),
    inset 0 1px 0 var(--tx-rim) !important;
}

/* ── 8. the rest of the board ────────────────────────────────────────────────
 * The reader's "do them all now": every control, menu, field, strip and panel
 * the five surfaces did not reach, found by parsing relay.html (169 panels,
 * 117 chip controls, 28 floating menus, 50 fields, 5 underlined strips), and
 * the chat. Each rule is scoped to #root, plus [data-skin="shell"] for the
 * lab's frames, so the lab's "today" columns stay as they are.
 *
 * ⚠️ NOTHING HERE TOUCHES AN ELEMENT THAT ALREADY HAS AN INLINE box-shadow,
 * except the floating menus, whose own shadow is the one being replaced. */

/* Chip controls (Collapse all, filters, clickable pills): raised like keys.
 * ⚠️ NOT the folder tabs, which are clickable bordered spans too: they join the
 * page below (border-bottom 0, or margin-bottom -1px), and a key's shadow
 * under them would cut them off it. */
[data-texture]
  :is(#root, [data-skin="shell"])
  span[style*="cursor: pointer"][style*="border: 1px solid"]:not([style*="box-shadow"]):not(
    [data-skin]
  ):not([style*="border-bottom: 0"]):not([style*="margin-bottom: -1px"]) {
  background-image: linear-gradient(180deg, var(--tx-key), transparent 75%) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    0 1px 1px var(--tx-contact) !important;
}
/* Floating menus and dropdowns: lifted like the dialogs (a rim, a dark
 * outline, a long shadow), without the dialogs' blur or titanium frame. */
[data-texture]
  :is(#root, [data-skin="shell"])
  :is(div, span)[style*="position: absolute"][style*="box-shadow"][style*="border: 1px solid"]:not(
    [data-skin]
  ),
[data-texture]
  :is(#root, [data-skin="shell"])
  :is(div, span)[style*="position: fixed"][style*="box-shadow"][style*="border: 1px solid"]:not(
    [data-skin]
  ) {
  background-image:
    var(--tx-streak), linear-gradient(180deg, var(--tx-sheen), transparent 120px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 0 0 0 1px var(--tx-rim),
    0 0 0 1px rgba(var(--tx-ink), calc(var(--tx-ring, 1) * 0.6 * var(--tx-shade))),
    0 18px 40px -12px rgba(var(--tx-ink), calc(0.8 * var(--tx-shade))),
    0 6px 14px -6px rgba(var(--tx-ink), calc(0.6 * var(--tx-shade))) !important;
}
/* Fields everywhere, and the boxes that hold a borderless one (the search
 * boxes, the chat composers): recessed wells. Focus stays an orange border. */
[data-texture]
  :is(#root, [data-skin="shell"])
  :is(input, textarea, select)[style*="border: 1px solid"]:not([type="checkbox"]):not(
    [type="radio"]
  ):not([style*="box-shadow"]),
[data-texture]
  :is(#root, [data-skin="shell"])
  div:has(> input, > textarea, > .chatcompose)[style*="border: 1px solid"]:not(
    [style*="box-shadow"]
  ):not([data-skin]) {
  box-shadow:
    inset 0 1px 2px var(--tx-well),
    0 1px 0 var(--tx-etch) !important;
}
/* The underlined tab strips (Activity, Review, Triage, Vault, Account) are
 * folder tabs like the project's own: the selected one (#101010 against
 * #141414) takes the window light and an inner rim, no shadow beneath. */
[data-texture]
  :is(#root, [data-skin="shell"])
  section[style*="border-bottom: 1px solid #262626"]
  span[style*="margin-bottom: -1px"][style*="background: #101010"] {
  background-image:
    var(--tx-streak), linear-gradient(180deg, var(--tx-sheen), transparent),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 1px 0 0 var(--tx-rim),
    inset -1px 0 0 var(--tx-rim),
    inset 0 1px 0 var(--tx-rim) !important;
}
/* The standard window panel on every page (#101010, a #1e1e1e border): the
 * same window as the group boxes and the session cards. OUTERMOST ONLY, so a
 * window inside a window keeps its paint, and never inside a dialog, whose
 * insides are set in rather than raised. */
[data-texture]
  :is(#root, [data-skin="shell"])
  :is(div, section)[style*="background: #101010"][style*="border: 1px solid #1e1e1e"]:not(
    [data-skin]
  ):not([style*="box-shadow"]):not(
    [style*="background: #101010"][style*="border: 1px solid #1e1e1e"] *
  ):not([data-skin="dialog"] *) {
  background-image:
    var(--tx-streak), radial-gradient(120% 150px at 0% 0%, var(--tx-glow), transparent 70%),
    linear-gradient(180deg, var(--tx-sheen), transparent 140px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 0 0 0 1px var(--tx-rim),
    0 0 0 1px rgba(var(--tx-ink), calc(var(--tx-ring, 1) * 0.35 * var(--tx-shade))),
    0 1px 0 var(--tx-contact),
    0 18px 36px -24px var(--tx-cast) !important;
}

/* ── the chat ─────────────────────────────────────────────────────────────────
 * The Chat page's panels are standard windows (above). The room strip is a
 * recessed track with the room chips raised like keys; message bubbles sit
 * slightly up off the thread; the docked chat windows float like dialogs, with
 * their title bars lit. The docked window's own upward shadow is replaced by
 * the float shadow, cast upwards because the window rises from the bottom. */
[data-texture] [data-skin="chat-rooms"] {
  box-shadow:
    inset 0 1px 3px var(--tx-well),
    0 1px 0 var(--tx-etch) !important;
}
[data-texture] [data-skin="chat-rooms"] span[style*="border: 1px solid"] {
  background-image: linear-gradient(180deg, var(--tx-key), transparent 75%) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    0 1px 1px var(--tx-contact) !important;
}
[data-texture] [data-skin="bubble"] {
  background-image: linear-gradient(
    180deg,
    rgba(var(--tx-lite), 0.035),
    transparent 70%
  ) !important;
  box-shadow:
    inset 0 0 0 1px var(--tx-rim),
    0 1px 0 var(--tx-contact),
    0 4px 10px -6px rgba(var(--tx-ink), calc(0.6 * var(--tx-shade))) !important;
}
/* ⭐ YOUR OWN BUBBLES: DARK WITH AN ORANGE EDGE, the reader's pick over the lit
 * bright orange (which looked unchanged) and a quieter orange. They are dark
 * like everyone else's, with an orange rim, a faint orange tint inside and
 * warm white text, the same idea as the group boxes' coloured edge.
 * ⚠️ THE ONE COLOUR CHANGE IN THIS FILE, asked for by the reader for the chat:
 * the inline fill (#ff8a00), border and text (#140a00 / #2a1400, component.js)
 * are overridden here. On the Chat page and in the docked chat windows. */
[data-texture] [data-skin="bubble"][style*="background: #ff8a00"] {
  background-color: #17120e !important;
  background-image: linear-gradient(
    180deg,
    rgba(255, 138, 0, 0.13),
    rgba(255, 138, 0, 0.05)
  ) !important;
  border-color: rgba(255, 138, 0, 0.6) !important;
  color: #f3e7da !important;
  box-shadow:
    inset 0 1px 0 rgba(255, 138, 0, 0.35),
    0 1px 0 rgba(var(--tx-ink), calc(0.5 * var(--tx-shade))),
    0 4px 10px -6px rgba(var(--tx-ink), calc(0.6 * var(--tx-shade))) !important;
}
[data-texture] [data-skin="chat-dock"] {
  background-image:
    var(--tx-streak), linear-gradient(180deg, var(--tx-sheen), transparent 160px),
    linear-gradient(var(--tx-dim), var(--tx-dim)) !important;
  box-shadow:
    inset 0 0 0 1px var(--tx-rim),
    0 0 0 1px rgba(var(--tx-ink), calc(var(--tx-ring, 1) * 0.6 * var(--tx-shade))),
    0 -18px 40px -12px rgba(var(--tx-ink), calc(0.8 * var(--tx-shade))),
    0 -6px 14px -6px rgba(var(--tx-ink), calc(0.6 * var(--tx-shade))) !important;
}
[data-texture] [data-skin="chat-dock-head"] {
  background-image:
    var(--tx-streak), linear-gradient(180deg, var(--tx-key), transparent) !important;
}

/* The chat composer's box is a class (.chat-shell in base.css), not an inline
 * style, so it is named here. Its focus is an orange border, never touched. */
[data-texture] :is(#root, [data-skin="shell"]) .chat-shell {
  box-shadow:
    inset 0 1px 2px var(--tx-well),
    0 1px 0 var(--tx-etch) !important;
}

/* ── every button on the board, and the side menu's search well ─────────────
 * Dark bordered buttons are raised keys; orange action buttons are lit from
 * above, with a light top edge, a darker bottom one and a tight shadow, so they
 * sit on the surface instead of being printed on it. Colours stay the
 * template's: the light is white and black over them.
 *
 * ⚠️ SCOPED TO #root, the app's container, and to [data-skin="shell"] for the
 * lab's frames. NOT to the shell alone: some dialogs (New project among them)
 * are drawn beside the board's root rather than inside it, and scoping to the
 * shell missed every button in them. A button outside both (the lab's "today"
 * columns, which strip every hook) stays as it is.
 *
 * ⚠️ NOT a button whose inline style already has a box-shadow. On this board
 * that is five of them: three shelf handles, the selected tab's underline and
 * a selection ring, and each of those shadows means something.
 *
 * ⚠️ #3131 NOR a button whose background is a picture. The account button on
 * Home draws the profile photo as its inline background, and this gradient's
 * !important painted over it, leaving an empty circle beside the bell. */
[data-texture]
  :is(#root, [data-skin="shell"])
  button[style*="border: 1px solid"]:not([style*="box-shadow"]):not(
    [style*="background: #ff8a00"]
  ):not([style*="url("]) {
  background-image: linear-gradient(180deg, var(--tx-key), transparent 75%) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    0 1px 1px var(--tx-contact) !important;
}
[data-texture]
  :is(#root, [data-skin="shell"])
  button[style*="background: #ff8a00"]:not([style*="box-shadow"]) {
  background-image: linear-gradient(
    180deg,
    var(--tx-cta-sheen),
    transparent 55%,
    rgba(var(--tx-ink), calc(0.1 * var(--tx-shade)))
  ) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-cta-lit),
    inset 0 -1px 0 rgba(var(--tx-ink), calc(0.2 * var(--tx-shade))),
    0 1px 0 rgba(var(--tx-ink), calc(0.5 * var(--tx-shade))),
    0 4px 10px -4px rgba(var(--tx-ink), calc(0.7 * var(--tx-shade))) !important;
}
/* The project search box is a recessed well. */
[data-texture] [data-skin="nav"] div:has(> input) {
  box-shadow:
    inset 0 1px 2px var(--tx-well),
    0 1px 0 var(--tx-rim) !important;
}

/* ── the sign in page (login.html) ────────────────────────────────────────────
 * Its card is a dialog (data-skin="dialog" on .card); inside it (data-skin=
 * "login" on .cols) the fields and buttons are styled by class, not inline, so
 * they get the board's well and the board's orange button here by class. */
[data-texture] [data-skin="login"] input:not([type="checkbox"]):not([type="radio"]) {
  box-shadow:
    inset 0 1px 2px var(--tx-well),
    0 1px 0 var(--tx-etch) !important;
}
[data-texture] [data-skin="login"] button.go:not(.ghost) {
  background-image: linear-gradient(
    180deg,
    var(--tx-cta-sheen),
    transparent 55%,
    rgba(var(--tx-ink), calc(0.1 * var(--tx-shade)))
  ) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-cta-lit),
    inset 0 -1px 0 rgba(var(--tx-ink), calc(0.2 * var(--tx-shade))),
    0 1px 0 rgba(var(--tx-ink), calc(0.5 * var(--tx-shade))),
    0 4px 10px -4px rgba(var(--tx-ink), calc(0.7 * var(--tx-shade))) !important;
}
[data-texture] [data-skin="login"] button.ghost {
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    0 1px 1px var(--tx-contact) !important;
}

/* ── the group colours in the light theme ─────────────────────────────────────
 * ⭐ The light theme is the dark board inverted (invert + hue-rotate keep the
 * hue and flip the lightness), so a group's pale name colour on dark landed as
 * a dark, dull one on light: orange went brown, the soft red a dusty dark pink
 * (Loucas, 28 October 2026: "the colors we have on light, they don't make
 * sense"). Here, in light only, each group colour is replaced by its own hue at
 * mid lightness and fuller saturation, which the inversion lands as a clean,
 * vivid colour on the light page. Worked out from --grp by the browser, so
 * every group and every new palette entry follows; dark is untouched.
 * ⚠️ PAINT ONLY, like the rest of this file: color, stroke and background-color
 * on the header's own name, chevron and dot. */
html[data-texture][style*="invert"] [data-skin="group"] {
  --grp-shown: hsl(from var(--grp, #8a8a8a) h min(100, calc(s * 1.25)) 60%);
}
html[data-texture][style*="invert"] [data-skin="group-head"] b {
  color: var(--grp-shown) !important;
}
html[data-texture][style*="invert"] [data-skin="group-head"] > svg {
  stroke: var(--grp-shown) !important;
}
html[data-texture][style*="invert"]
  [data-skin="group-head"]
  span[style*="border-radius: 50%"][style*="width: 8px"] {
  background-color: var(--grp-shown) !important;
}

/* ── pill strips: the Session route's filters, home Settings' sub tabs, and the
 * project's sub tabs (the subnav strip under Board, Production, Overview and
 * Settings: "same for the sub tabs of any of the 4 main tabs") ──────────────
 * (Loucas, 28 October 2026: the Settings sub tabs should look like the route's
 * toggles, and both should look the same in light.) A recessed track; every
 * pill a raised key; the selected one lit. Each pill's own inline fill (#141414
 * unselected, #101010 selected on the route) is what made the keys read raised
 * on dark and sunken once inverted, so the fill is left to the track and the
 * key is drawn with light and shadow, which the light theme turns the right
 * way round. The selected pill is the one whose label is the orange #ffb45c.
 * An aria-hidden span is not a pill: the route window's edge fade is one, and
 * this rule would draw it as an empty key. */
[data-texture] [data-skin="pill-strip"] {
  box-shadow:
    inset 0 1px 3px var(--tx-well),
    0 1px 0 var(--tx-etch) !important;
}
[data-texture]
  :is([data-skin="pill-strip"], [data-skin="subnav"])
  > :is(span:not([aria-hidden]), button) {
  background-color: transparent !important;
  background-image: linear-gradient(
    180deg,
    rgba(var(--tx-lite), 0.06),
    rgba(var(--tx-lite), 0.02)
  ) !important;
  box-shadow:
    inset 0 1px 0 rgba(var(--tx-lite), 0.07),
    inset 0 0 0 1px rgba(var(--tx-lite), 0.035),
    0 1px 2px rgba(var(--tx-ink), calc(0.6 * var(--tx-shade))) !important;
}
[data-texture]
  :is([data-skin="pill-strip"], [data-skin="subnav"])
  > :is(span, button)[style*="color: #ffb45c"] {
  background-image: linear-gradient(180deg, var(--tx-key), transparent 75%) !important;
  box-shadow:
    inset 0 1px 0 var(--tx-lit),
    0 1px 1px var(--tx-contact),
    0 2px 6px -2px rgba(var(--tx-ink), calc(0.55 * var(--tx-shade))) !important;
}

/* The pinned pill stays put while the rest scroll under it, and two things let
 * them show (the owner, 31 October 2026: "the tabs gets ghosted on top off
 * other"). The transparent fill above left it see through, so it takes the
 * track's own colour and never reads as a box of its own. And every pill carries
 * z-index: 1 inline, which counts on a flex item even when it is not positioned,
 * so later pills painted over it. It has to stand one above them. */
[data-texture] [data-skin="pill-strip"] > button[style*="position: sticky"] {
  z-index: 2 !important;
  background-color: inherit !important;
}
/* It pins inside the track's padding, so a pill scrolling past would still show
 * in that gap. This covers it. */
[data-texture] [data-skin="pill-strip"] > button[style*="position: sticky"]::before {
  content: "";
  position: absolute;
  top: -5px;
  bottom: -5px;
  right: 100%;
  width: 5px;
  background-color: inherit;
}
