/* start.lu stylesheet (the project is Gazelle; the site is start.lu).

   Everything is drawn from tokens, and four attributes on <html> choose them:
     data-palette  colours          data-font   type
     data-shape    boxes and lines  data-mode   light, dark or the device's choice
   The same attributes work on any element, which is how the look picker draws its
   samples: a swatch carries its own palette, a sample box its own shape. */

/* ======================================================================
   1. Colour palettes. Each defines a light set (--l-*) and a dark set (--d-*);
      section 2 decides which one is live. --accent-ink is whatever reads on top
      of --accent, which is not always white: Slate's amber is light enough that
      it needs dark ink under it, the way Mono's white accent does.
   ====================================================================== */

:root, [data-palette="gazelle"] {
    --l-bg: #f3f5f9;  --l-surface: #ffffff; --l-surface-2: #eaeef5; --l-ink: #151d2a; --l-ink-soft: #5b6779;
    --l-line: #d8deea; --l-accent: #2b64ee; --l-accent-ink: #ffffff; --l-accent-soft: #e2eafd;
    --d-bg: #0f131a;  --d-surface: #171d27; --d-surface-2: #1e2633; --d-ink: #e8edf5; --d-ink-soft: #98a4b7;
    --d-line: #29333f; --d-accent: #6b97ff; --d-accent-ink: #0a0f1a; --d-accent-soft: #1d2a45;
}

[data-palette="sand"] {
    --l-bg: #f5f0e6;  --l-surface: #fffdf8; --l-surface-2: #efe7d8; --l-ink: #2a2218; --l-ink-soft: #7b6a55;
    --l-line: #e1d5c1; --l-accent: #c0561e; --l-accent-ink: #ffffff; --l-accent-soft: #f6e2d3;
    --d-bg: #191512;  --d-surface: #231d17; --d-surface-2: #2d251e; --d-ink: #f0e7d9; --d-ink-soft: #b4a48f;
    --d-line: #3b3128; --d-accent: #e98d57; --d-accent-ink: #1b1108; --d-accent-soft: #3f2a1b;
}

[data-palette="forest"] {
    --l-bg: #f0f4ef;  --l-surface: #ffffff; --l-surface-2: #e4ece3; --l-ink: #151f18; --l-ink-soft: #56675a;
    --l-line: #d1dcd1; --l-accent: #1d7a4b; --l-accent-ink: #ffffff; --l-accent-soft: #dbeee2;
    --d-bg: #0e1411;  --d-surface: #151e19; --d-surface-2: #1b261f; --d-ink: #e2ede5; --d-ink-soft: #93a89a;
    --d-line: #27352c; --d-accent: #4fca85; --d-accent-ink: #06130b; --d-accent-soft: #15301e;
}

[data-palette="ocean"] {
    --l-bg: #edf4f6;  --l-surface: #ffffff; --l-surface-2: #dfecef; --l-ink: #112128; --l-ink-soft: #4f6a73;
    --l-line: #cddde2; --l-accent: #0e7b93; --l-accent-ink: #ffffff; --l-accent-soft: #d4edf2;
    --d-bg: #0c1417;  --d-surface: #131f28; --d-surface-2: #192933; --d-ink: #e1edf1; --d-ink-soft: #8fa9b2;
    --d-line: #23353e; --d-accent: #43bfda; --d-accent-ink: #05161b; --d-accent-soft: #10343f;
}

[data-palette="berry"] {
    --l-bg: #f8f1f5;  --l-surface: #ffffff; --l-surface-2: #f0e4ec; --l-ink: #23151e; --l-ink-soft: #6f5567;
    --l-line: #e4d1de; --l-accent: #a52577; --l-accent-ink: #ffffff; --l-accent-soft: #f5dbeb;
    --d-bg: #160f13;  --d-surface: #1f151f; --d-surface-2: #2a1c29; --d-ink: #f1e4ec; --d-ink-soft: #b293a9;
    --d-line: #3a2937; --d-accent: #ea6fba; --d-accent-ink: #1b0b16; --d-accent-soft: #3f1f39;
}

[data-palette="slate"] {
    --l-bg: #f1f1f3;  --l-surface: #ffffff; --l-surface-2: #e7e7eb; --l-ink: #1a1b1e; --l-ink-soft: #62646b;
    --l-line: #d6d7dc; --l-accent: #d87706; --l-accent-ink: #241a00; --l-accent-soft: #fcead0;
    --d-bg: #121315;  --d-surface: #1a1b1e; --d-surface-2: #222327; --d-ink: #e9e9eb; --d-ink-soft: #9d9fa7;
    --d-line: #2f3035; --d-accent: #f6a01c; --d-accent-ink: #1a1000; --d-accent-soft: #3c2a0a;
}

[data-palette="midnight"] {
    --l-bg: #edeefa;  --l-surface: #ffffff; --l-surface-2: #e2e4f6; --l-ink: #181a33; --l-ink-soft: #5b5e86;
    --l-line: #d2d5ee; --l-accent: #4d45e3; --l-accent-ink: #ffffff; --l-accent-soft: #dfdffb;
    --d-bg: #0a0b19;  --d-surface: #12142a; --d-surface-2: #191c36; --d-ink: #e7e8fb; --d-ink-soft: #9b9fc9;
    --d-line: #262a4d; --d-accent: #8e88f7; --d-accent-ink: #0a0a1f; --d-accent-soft: #232450;
}

[data-palette="mono"] {
    --l-bg: #ffffff;  --l-surface: #ffffff; --l-surface-2: #f1f1f1; --l-ink: #000000; --l-ink-soft: #4d4d4d;
    --l-line: #bfbfbf; --l-accent: #000000; --l-accent-ink: #ffffff; --l-accent-soft: #e6e6e6;
    --d-bg: #000000;  --d-surface: #0c0c0c; --d-surface-2: #191919; --d-ink: #ffffff; --d-ink-soft: #a8a8a8;
    --d-line: #3a3a3a; --d-accent: #ffffff; --d-accent-ink: #000000; --d-accent-soft: #262626;
}

/* ======================================================================
   2. Mode. The live tokens (--bg, --ink ...) come from the light set unless the
      element, or the device on its behalf, asks for the dark one. Semantic colours
      (ok, bad, warning, lock) are palette-independent and set per mode.
   ====================================================================== */

:root, [data-palette] {
    --bg: var(--l-bg); --surface: var(--l-surface); --surface-2: var(--l-surface-2);
    --ink: var(--l-ink); --ink-soft: var(--l-ink-soft); --line: var(--l-line);
    --accent: var(--l-accent); --accent-ink: var(--l-accent-ink); --accent-soft: var(--l-accent-soft);
    --shadow-rgb: 20 30 50;
    --ok-bg: #e4f5ea; --ok-ink: #1a6b3a; --bad-bg: #fdecea; --bad-ink: #a12d20;
    --warn-bg: #fdf3d8; --warn-ink: #7f5a00; --danger: #c0392b; --lock: #b08600;
}

[data-mode="dark"] {
    --bg: var(--d-bg); --surface: var(--d-surface); --surface-2: var(--d-surface-2);
    --ink: var(--d-ink); --ink-soft: var(--d-ink-soft); --line: var(--d-line);
    --accent: var(--d-accent); --accent-ink: var(--d-accent-ink); --accent-soft: var(--d-accent-soft);
    --shadow-rgb: 0 0 0;
    --ok-bg: #14301f; --ok-ink: #7fd39b; --bad-bg: #331917; --bad-ink: #f0928a;
    --warn-bg: #3a2e0c; --warn-ink: #f2cd6a; --danger: #e05c4c; --lock: #d9b13a;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-mode="light"]), [data-palette]:not([data-mode="light"]) {
        --bg: var(--d-bg); --surface: var(--d-surface); --surface-2: var(--d-surface-2);
        --ink: var(--d-ink); --ink-soft: var(--d-ink-soft); --line: var(--d-line);
        --accent: var(--d-accent); --accent-ink: var(--d-accent-ink); --accent-soft: var(--d-accent-soft);
        --shadow-rgb: 0 0 0;
        --ok-bg: #14301f; --ok-ink: #7fd39b; --bad-bg: #331917; --bad-ink: #f0928a;
        --warn-bg: #3a2e0c; --warn-ink: #f2cd6a; --danger: #e05c4c; --lock: #d9b13a;
    }
    :root:not([data-mode="light"]) { color-scheme: dark; }
}

:root { color-scheme: light; }
:root[data-mode="dark"] { color-scheme: dark; }

/* ======================================================================
   3. Shapes: corners, lines, fills and shadows for every box on the page.

      A shape also says how the controls inside a card are drawn, because a fill
      that works under one shape disappears under another: a white button reads
      clearly inside an outlined card and vanishes on the white card Soft draws.
      So --button-bg and --field-bg are picked per shape against the --card-bg they
      sit on, always from the palette in play rather than from white, and
      --button-hover is kept a step away from --button-bg so hovering shows.

      Controls also keep their own edge, --control-border-w and --control-border-c,
      instead of the card's. A card may go without a line; a button may not, or
      there is nothing to tell the visitor where it is. The edge is --ink-soft,
      which is the palette's own muted ink and clears 3:1 against every surface
      these palettes offer, so the button stays findable in all sixteen of them.
      Only Outline and Brutal, which already draw a heavy --ink line, keep theirs.
   ====================================================================== */

:root, [data-shape="soft"] {
    --radius: 14px; --radius-sm: 9px; --radius-tile: 8px; --radius-pill: 999px;
    --border-w: 1px; --border-c: var(--line);
    --card-bg: var(--surface);
    --shadow: 0 1px 2px rgb(var(--shadow-rgb) / .05), 0 10px 30px rgb(var(--shadow-rgb) / .06);
    --hover: var(--surface-2);
    --lift: translateY(-1px);
    --button-bg: var(--surface-2);
    --button-hover: var(--accent-soft);
    --field-bg: var(--surface);
    --control-border-w: 1px;
    --control-border-c: var(--ink-soft);
}

[data-shape="sharp"] {
    --radius: 0px; --radius-sm: 0px; --radius-tile: 0px; --radius-pill: 0px;
    --border-w: 1px; --border-c: var(--line);
    --card-bg: var(--surface);
    --shadow: none;
    --hover: var(--surface-2);
    --lift: none;
    --button-bg: var(--surface-2);
    --button-hover: var(--accent-soft);
    --field-bg: var(--surface);
    --control-border-w: 1px;
    --control-border-c: var(--ink-soft);
}

[data-shape="round"] {
    --radius: 26px; --radius-sm: 16px; --radius-tile: 999px; --radius-pill: 999px;
    --border-w: 0px; --border-c: transparent;
    --card-bg: var(--surface);
    --shadow: 0 2px 6px rgb(var(--shadow-rgb) / .05), 0 18px 46px rgb(var(--shadow-rgb) / .10);
    --hover: var(--accent-soft);
    --lift: translateY(-1px);
    --button-bg: var(--accent-soft);
    --button-hover: color-mix(in srgb, var(--accent-soft) 78%, var(--accent));
    --field-bg: var(--surface-2);
    --control-border-w: 1px;
    --control-border-c: var(--ink-soft);
}

[data-shape="outline"] {
    --radius: 8px; --radius-sm: 6px; --radius-tile: 5px; --radius-pill: 6px;
    --border-w: 2px; --border-c: var(--ink);
    --card-bg: var(--bg);
    --shadow: none;
    --hover: var(--surface-2);
    --lift: none;
    --button-bg: var(--surface);
    --button-hover: var(--accent-soft);
    --field-bg: var(--surface);
    --control-border-w: var(--border-w);
    --control-border-c: var(--border-c);
}

[data-shape="flat"] {
    --radius: 12px; --radius-sm: 8px; --radius-tile: 8px; --radius-pill: 999px;
    --border-w: 0px; --border-c: transparent;
    --card-bg: var(--surface-2);
    --shadow: none;
    --hover: var(--accent-soft);
    --lift: none;
    --button-bg: var(--accent-soft);
    --button-hover: color-mix(in srgb, var(--accent-soft) 78%, var(--accent));
    --field-bg: var(--surface);
    --control-border-w: 1px;
    --control-border-c: var(--ink-soft);
}

[data-shape="brutal"] {
    --radius: 0px; --radius-sm: 0px; --radius-tile: 0px; --radius-pill: 0px;
    --border-w: 2px; --border-c: var(--ink);
    --card-bg: var(--surface);
    --shadow: 5px 5px 0 var(--ink);
    --hover: var(--accent-soft);
    --lift: translate(-1px, -1px);
    --button-bg: var(--surface-2);
    --button-hover: var(--accent-soft);
    --field-bg: var(--surface);
    --control-border-w: var(--border-w);
    --control-border-c: var(--border-c);
}

/* ======================================================================
   4. Type.
   ====================================================================== */

:root, [data-font="system"] {
    --font: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-size: 0.9375rem; --head-weight: 700; --head-tracking: .06em; --head-case: uppercase; --head-size: 0.78125rem;
}
[data-font="inter"]   { --font: "Inter", system-ui, sans-serif; }
[data-font="nunito"]  { --font: "Nunito", system-ui, sans-serif; --font-size: 0.96875rem; --head-weight: 800; }
[data-font="grotesk"] { --font: "Space Grotesk", system-ui, sans-serif; --head-tracking: .04em; }
[data-font="lora"]    { --font: "Lora", Georgia, serif; --font-size: 0.96875rem; --head-case: none; --head-tracking: 0; --head-size: 0.9375rem; }
[data-font="georgia"] { --font: Georgia, "Iowan Old Style", "Times New Roman", serif; --font-size: 0.96875rem; --head-case: none; --head-tracking: 0; --head-size: 0.9375rem; }
[data-font="mono"]    { --font: ui-monospace, "Cascadia Code", Consolas, "SF Mono", Menlo, monospace; --font-size: 0.84375rem; --head-tracking: .04em; }

/* ======================================================================
   5. Base, and the bit of character on top of it

      Two things keep the portal from being merely tidy. Hover and press use a
      spring rather than a straight ease, so a tile answers back when you touch it;
      and every category carries a hue of its own, turned round from the palette's
      accent, so the board reads as a set of neighbourhoods instead of one blue
      wall. Both are drawn from the palette in play - a palette with no hue in it,
      Mono, has nothing to turn and stays black and white.
   ====================================================================== */

* { box-sizing: border-box; }

:root {
    /* Overshoots and settles: the difference between moving and being nudged. */
    --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
    --ease-out: cubic-bezier(.2, .8, .3, 1);
    --chip-turn: 0deg;
}

/* One turn of the colour wheel per category, spread far enough apart to tell
   neighbours from each other and stopping short of a full circle. */
[data-tint="0"] { --chip-turn: 0deg; }
[data-tint="1"] { --chip-turn: 45deg; }
[data-tint="2"] { --chip-turn: 95deg; }
[data-tint="3"] { --chip-turn: 150deg; }
[data-tint="4"] { --chip-turn: 215deg; }
[data-tint="5"] { --chip-turn: 290deg; }

html { background: var(--bg); }

body {
    margin: 0; min-height: 100vh;
    color: var(--ink);
    font: var(--font-size)/1.5 var(--font);
    /* A wash of the accent at the top of the page, fading into the ground, with a
       soft bloom off to one side so the ground has somewhere to catch the light. */
    background:
        var(--bg)
        radial-gradient(60rem 22rem at 88% -6%, var(--accent-soft), transparent 70%) no-repeat,
        linear-gradient(180deg, var(--accent-soft), var(--bg) 380px) no-repeat;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { line-height: 1.25; }

.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;
}

/* Every box on the page: columns, widgets, sheets, panels, cards. */
.column, .widget, .sheet, .panel, .edit-column, .page-card a, .choice {
    background: var(--card-bg);
    border: var(--border-w) solid var(--border-c);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}

/* Small uppercase labels: column titles, widget titles, table heads. */
.column-head, .widget-head, .table th, .picker-axis legend, .adslot-empty {
    font-size: var(--head-size);
    font-weight: var(--head-weight);
    letter-spacing: var(--head-tracking);
    text-transform: var(--head-case);
    color: var(--ink-soft);
}

/* ======================================================================
   6. Chrome: top bar, page, footer, flash
   ====================================================================== */

.topbar {
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    padding: 10px 20px;
    background: color-mix(in srgb, var(--surface) 86%, transparent);
    backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
    border-bottom: var(--border-w) solid var(--border-c);
    position: sticky; top: 0; z-index: 20;
}

/* The brand: the mark, the wordmark, and the tagline when there is room for it. The mark
   keeps its own colours - it is the Luxembourg flag, and the flag does not change with the
   palette - except under Mono, which has no colour anywhere and gets it in grey. */
.brand { display: flex; align-items: center; gap: 10px; min-width: 0; color: var(--ink); }
.brand:hover { text-decoration: none; }

.brand-logo {
    display: block; width: 32px; height: 32px; flex: 0 0 auto;
    border-radius: 7.5px;
    box-shadow: 0 4px 12px rgb(20 33 61 / .28);
    transition: transform .25s var(--ease-spring);
}
.brand:hover .brand-logo { transform: rotate(-8deg) scale(1.08); }
[data-palette="mono"] .brand-logo { filter: grayscale(1); }

.brand-word { font-weight: 800; font-size: 1.15rem; letter-spacing: -.03em; line-height: 1; white-space: nowrap; }
.brand-tld { color: var(--accent); }

.brand-tagline {
    color: var(--ink-soft); font-size: 0.8125rem; font-weight: 500; white-space: nowrap;
    padding-left: 10px; border-left: 1px solid var(--line);
    overflow: hidden; text-overflow: ellipsis;
}
@media (max-width: 900px) { .brand-tagline { display: none; } }
.is-mobile .brand-tagline { display: none; }

.topbar-nav { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.topbar-nav a, .topbar-nav .link-button {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 6px 11px; border-radius: var(--radius-pill);
    color: var(--ink-soft); font-size: 0.875rem;
}
.topbar-nav a:hover, .topbar-nav .link-button:hover { color: var(--ink); background: var(--hover); text-decoration: none; }
.topbar-nav .cta { background: var(--accent); color: var(--accent-ink); font-weight: 600; }
.topbar-nav .cta:hover { background: var(--accent); color: var(--accent-ink); opacity: .9; }
.nav-flag { font-weight: 600; color: var(--ink); }

/* On a narrow screen the row cannot hold the brand and the nav side by side - with the
   language switch and the light/dark button there are simply too many things - so the
   brand takes the first line and the nav the second, rather than the nav wrapping back
   over the wordmark. */
@media (max-width: 700px) {
    .topbar { flex-wrap: wrap; row-gap: 8px; padding: 8px 12px; }
    .topbar .brand { flex: 1 0 100%; }
    .topbar-nav { width: 100%; }
    .topbar-nav a, .topbar-nav .link-button { padding: 5px 8px; }
}

.nav-look-dot {
    width: 12px; height: 12px; border-radius: 50%;
    background: conic-gradient(var(--accent) 0 50%, var(--accent-soft) 50% 100%);
    border: 1px solid var(--line);
}

/* Light and dark. One button rather than a menu, because there are only two answers
   a visitor can mean by asking; the third setting, "follows your device", stays on
   the look picker where it can be explained. */
.nav-mode {
    display: inline-grid; place-items: center; width: 30px; height: 30px;
    border: var(--control-border-w) solid var(--control-border-c); border-radius: var(--radius-pill);
    background: var(--button-bg); color: var(--ink); cursor: pointer; font-size: 0.9375rem; line-height: 1;
    transition: background-color .14s var(--ease-out), transform .18s var(--ease-spring);
}
.nav-mode:hover { background: var(--button-hover); }
.nav-mode:active { transform: scale(.94); }

/* All three languages at once. Nobody should have to open a menu to find out whether
   their language is offered at all, and three two-letter labels fit where a menu would. */
.langswitch {
    display: inline-flex; margin: 0; overflow: hidden;
    border: var(--control-border-w) solid var(--control-border-c); border-radius: var(--radius-pill);
    background: var(--button-bg);
}
.langswitch .lang {
    border: 0; padding: 5px 9px; min-height: 28px;
    background: none; color: var(--ink-soft); cursor: pointer;
    font: inherit; font-size: 0.75rem; font-weight: 600; letter-spacing: .03em;
    transition: background-color .14s var(--ease-out), color .14s var(--ease-out);
}
.langswitch .lang + .lang { border-left: 1px solid var(--control-border-c); }
.langswitch .lang:hover { background: var(--button-hover); color: var(--ink); }
.langswitch .lang-on { background: var(--accent); color: var(--accent-ink); }
.langswitch .lang-on:hover { background: var(--accent); color: var(--accent-ink); opacity: .92; }

.page { padding: 20px; max-width: 1680px; margin: 0 auto; }

.sitefoot {
    display: flex; gap: 18px; justify-content: center; flex-wrap: wrap;
    padding: 28px 20px; color: var(--ink-soft); font-size: 0.8125rem;
}
.sitefoot-brand strong { color: var(--ink); font-weight: 700; }
.sitefoot a { color: var(--ink-soft); }
.sitefoot a:hover { color: var(--ink); }

.flash {
    max-width: 1680px; margin: 12px auto 0; padding: 10px 14px;
    border-radius: var(--radius-sm); font-size: 0.875rem;
}
.flash-ok { background: var(--ok-bg); color: var(--ok-ink); }
.flash-bad { background: var(--bad-bg); color: var(--bad-ink); }

/* ======================================================================
   7. Desktop board: four fixed columns, three of links and the widget column
   ====================================================================== */

.board {
    display: grid; gap: 16px; align-items: start;
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

.board-col { display: grid; gap: 16px; align-content: start; min-width: 0; }

/* The four columns hold as long as they stay readable: below that, two, then one.
   The widget column is the last child either way, so it lands under the links. */
@media (max-width: 1080px) {
    .board { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
}
@media (max-width: 640px) {
    .board { grid-template-columns: minmax(0, 1fr); }
}

.column { padding: 12px 12px 14px; }

.column-head {
    margin: 0 0 8px; padding-bottom: 8px;
    border-bottom: 1px solid var(--line);
    display: flex; align-items: center; gap: 9px;
}

.column-icon {
    display: grid; place-items: center; width: 22px; height: 22px; flex: 0 0 auto;
    border-radius: var(--radius-tile);
    background: var(--accent); color: var(--accent-ink);
    font-size: 0.6875rem; letter-spacing: 0; font-family: var(--font);
    filter: hue-rotate(var(--chip-turn));
    transition: transform .25s var(--ease-spring);
}
.column:hover .column-icon { transform: rotate(-6deg) scale(1.1); }

.column-empty, .widget-empty { color: var(--ink-soft); font-size: 0.875rem; margin: 6px 0; }

.tiles { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }

/* .tile-face is the same tile with nothing behind it: the link editor's preview,
   which has to look exactly like the board but must not take the visitor there. */
.tile > a, .tile > .tile-face {
    display: flex; align-items: center; gap: 9px;
    padding: 6px 8px; margin: 0 -2px;
    border-radius: var(--radius-tile);
    color: var(--ink);
    transition: background-color .14s var(--ease-out), transform .18s var(--ease-spring);
}
.tile > a:hover { background: var(--hover); text-decoration: none; transform: var(--lift); }
.tile > a:active { transform: scale(.985); }

.tile-icon {
    display: grid; place-items: center; flex: 0 0 26px; height: 26px;
    border-radius: var(--radius-tile);
    background: var(--accent-soft); color: var(--accent);
    font-size: 0.78125rem; font-weight: 700;
    filter: hue-rotate(var(--chip-turn));
    transition: transform .22s var(--ease-spring);
}
.tile > a:hover .tile-icon { transform: rotate(-7deg) scale(1.14); }

.tile-body { display: grid; min-width: 0; }
.tile-title { font-weight: 500; font-size: 0.875rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tile-note { color: var(--ink-soft); font-size: 0.75rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tile-lock { margin-left: auto; font-size: 0.6875rem; color: var(--lock); }

/* ======================================================================
   8. Widget column
   ====================================================================== */

.widget { padding: 14px; }
.widget-head { margin: 0 0 10px; }

.widget-search form { display: flex; gap: 8px; }
.widget-search input { flex: 1 1 auto; min-width: 0; }

.clock-time { font-size: 2.125rem; font-weight: 700; letter-spacing: -.01em; font-variant-numeric: tabular-nums; line-height: 1.1; }
.clock-date { color: var(--ink-soft); font-size: 0.8125rem; margin-top: 2px; }

.weather-now { display: flex; align-items: center; gap: 12px; }
.weather-glyph {
    font-size: 2.25rem; line-height: 1;
    animation: drift 6s ease-in-out infinite;
}

/* Barely there, and on a long enough cycle to read as weather rather than as a gif. */
@keyframes drift {
    0%, 100% { transform: translateY(0) rotate(0); }
    50%      { transform: translateY(-3px) rotate(-4deg); }
}
.weather-temp { font-size: 2rem; font-weight: 700; letter-spacing: -.01em; }
.weather-meta { color: var(--ink-soft); font-size: 0.75rem; line-height: 1.4; }

.weather-days { list-style: none; margin: 12px 0 0; padding: 10px 0 0; border-top: 1px solid var(--line); display: grid; gap: 6px; }
.weather-days li { display: grid; grid-template-columns: 3.2rem 2rem 1fr; align-items: center; font-size: 0.8125rem; }
.day-name { color: var(--ink-soft); }
.day-glyph { text-align: center; }
.day-range { text-align: right; font-variant-numeric: tabular-nums; }

.news-list, .traffic-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.news-list li, .traffic-list li {
    display: grid; gap: 2px; font-size: 0.8125rem;
    padding-left: 10px; border-left: 3px solid var(--accent-soft);
}
.news-list li, .traffic-list li { transition: border-left-color .14s var(--ease-out), padding-left .18s var(--ease-spring); }
.news-list li:hover, .traffic-list li:hover { border-left-color: var(--accent); padding-left: 13px; }
.news-list a, .traffic-list a { color: var(--ink); font-weight: 500; }
.news-list a:hover, .traffic-list a:hover { color: var(--accent); }
.news-title, .traffic-title { font-weight: 500; }
.news-meta {
    display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; margin-top: 2px;
    color: var(--ink-soft); font-size: 0.6875rem; letter-spacing: .03em;
}

/* The paper the headline came from, in the accent rather than in the muted ink the
   timestamp beside it takes: with several papers merged into one list, the name is
   what the eye should land on first. */
.news-source {
    color: var(--accent); font-weight: 700; text-transform: uppercase;
    filter: hue-rotate(var(--chip-turn));
}
.news-when { text-transform: uppercase; }
.news-when::before { content: "·"; margin-right: 6px; }
.traffic-note { color: var(--ink-soft); font-size: 0.75rem; }

.widget-links { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; font-size: 0.875rem; }
.widget-link { display: inline-block; margin-top: 10px; font-size: 0.8125rem; }

.badge {
    display: inline-block; min-width: 18px; padding: 0 6px; margin-left: 6px;
    border-radius: var(--radius-pill); background: var(--accent); color: var(--accent-ink);
    font-size: 0.6875rem; font-weight: 600; text-align: center;
}

/* ======================================================================
   9. Ads
   ====================================================================== */

.adslot {
    display: grid; place-items: center;
    width: 100%; max-width: var(--ad-w); min-height: var(--ad-h);
    margin: 0 auto 20px; overflow: hidden;
    border: 1px dashed var(--line); border-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--surface-2) 60%, transparent);
}
.adslot img { max-width: 100%; height: auto; display: block; }
.functions .adslot { margin-bottom: 0; }

.adslot-empty { display: grid; gap: 2px; place-items: center; font-size: 0.6875rem; }
.adslot-size { opacity: .7; font-weight: 400; letter-spacing: 0; }

.sticky-ad {
    position: sticky; bottom: 0; z-index: 15;
    padding: 6px 0; background: var(--bg);
    border-top: 1px solid var(--line);
}
.sticky-ad .adslot { margin-bottom: 0; }

/* ======================================================================
   10. Mobile board: a tab strip over a swipe track
   ====================================================================== */

.is-mobile .page { padding: 12px; }

.tabstrip {
    display: flex; gap: 6px; overflow-x: auto; padding-bottom: 8px;
    margin-bottom: 12px; scrollbar-width: none;
    position: sticky; top: 52px; z-index: 10;
    background: linear-gradient(var(--bg) 80%, transparent);
}
.tabstrip::-webkit-scrollbar { display: none; }

.tab {
    flex: 0 0 auto; display: flex; align-items: center; gap: 6px;
    padding: 9px 14px;
    border: var(--border-w) solid var(--border-c); border-radius: var(--radius-pill);
    background: var(--card-bg); color: var(--ink-soft);
    font: inherit; font-size: 0.875rem; cursor: pointer;
}
.tab { transition: transform .2s var(--ease-spring), background-color .14s var(--ease-out); }
.tab-active { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); font-weight: 600; transform: scale(1.04); }
.tab:active { transform: scale(.96); }
/* The tab icon carries its category's tint, so the strip reads as the same set of
   colours as the board. The chosen tab is already accent-on-accent and wants none. */
.tab-icon { font-size: 0.8125rem; color: var(--accent); filter: hue-rotate(var(--chip-turn)); }
.tab-active .tab-icon { color: inherit; filter: none; }

/* One panel per column, swiped horizontally with snap points. */
.swipe {
    display: flex; align-items: start; gap: 12px;
    overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* Room for the shadow of the panels; the track clips otherwise. */
    padding: 4px 4px 12px; margin: -4px -4px 0;
}
.swipe::-webkit-scrollbar { display: none; }

.panel {
    /* A phone gets one panel per screen. On a wide screen - the mobile view
       previewed from a desktop - the panels stay phone-sized and several show at
       once, rather than one column stretched across the window. */
    flex: 0 0 min(100%, 460px); min-width: 0; padding: 10px;
    scroll-snap-align: start; scroll-snap-stop: always;
}

.tiles-mobile { gap: 3px; }
.tiles-mobile .tile > a { padding: 11px 10px; }
.tiles-mobile .tile-icon { flex-basis: 34px; height: 34px; font-size: 0.875rem; }
.tiles-mobile .tile-title { font-size: 0.9375rem; }

.is-mobile .widget { border: 0; box-shadow: none; border-radius: 0; padding: 12px 0; border-bottom: 1px solid var(--line); background: none; }
.is-mobile .widget:last-child { border-bottom: 0; }

/* ======================================================================
   11. Sheets, forms, buttons, tables
   ====================================================================== */

.sheet { padding: 20px; margin: 0 auto 20px; max-width: 1100px; }
.sheet-narrow { max-width: 460px; }
.sheet-medium { max-width: 880px; }
.sheet-danger { border-color: var(--danger); }
.sheet h1 { margin: 0 0 6px; font-size: 1.5rem; letter-spacing: -.01em; }
.sheet h2 { margin: 0 0 10px; font-size: 1.125rem; }

.sheet-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }

.page-head { max-width: 1100px; margin: 0 auto 16px; }
.page-head h1 { margin: 0 0 4px; font-size: 1.625rem; letter-spacing: -.01em; }
.page-sub { margin: 0 0 4px; color: var(--ink); }
.page-meta { margin: 0; color: var(--ink-soft); font-size: 0.8125rem; }

.hint { color: var(--ink-soft); font-size: 0.8125rem; }

/* A plain bulleted list on an ordinary sheet, where the legal pages' own list styles
   do not reach. */
.bullets { margin: 0 0 12px; padding-left: 20px; display: grid; gap: 6px; }

.stack { display: grid; gap: 12px; margin-top: 12px; }
.stack-tight { gap: 6px; }
.row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }

/* .field-label is the same caption for a control that is not one input in one
   label - the icon field, which is a box and a row of suggestions together. */
label > span, .field-label { display: block; font-size: 0.8125rem; color: var(--ink-soft); margin-bottom: 4px; }

input, select, textarea, button { font: inherit; }

/* :where() rather than :not() so this rule stays at the specificity of a bare
   element: a class that sizes one control - .icon-input, .inline-form - then wins
   without having to shout. */
input:where(:not([type=checkbox]):not([type=radio])), select, textarea {
    width: 100%; padding: 9px 11px;
    border: var(--control-border-w) solid var(--control-border-c); border-radius: var(--radius-sm);
    background: var(--field-bg); color: var(--ink);
    min-height: 40px;
}

input:focus, select:focus, textarea:focus, button:focus-visible, a:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px;
}

.icon-input { width: 4.5rem; text-align: center; }

.check { display: flex; align-items: center; gap: 8px; }
.check > span { margin: 0; color: var(--ink); }
.check input { width: auto; accent-color: var(--accent); }

.fieldset { border: var(--border-w) solid var(--border-c); border-radius: var(--radius-sm); padding: 10px 12px; display: grid; gap: 8px; }
.fieldset legend { color: var(--ink-soft); font-size: 0.8125rem; padding: 0 4px; }
.fieldset-plain { border: 0; padding: 0; }
.fieldset-plain legend { padding: 0; }

.button, .link-button {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    padding: 8px 14px; min-height: 38px;
    border: var(--control-border-w) solid var(--control-border-c); border-radius: var(--radius-sm);
    background: var(--button-bg); color: var(--ink);
    cursor: pointer; font-size: 0.875rem; font-weight: 500;
    transition: background-color .14s var(--ease-out), transform .18s var(--ease-spring);
}
.button:active, .icon-button:active { transform: scale(.96); }
.button:hover { background: var(--button-hover); text-decoration: none; transform: var(--lift); }
.button-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
[data-shape="brutal"] .button-primary, [data-shape="outline"] .button-primary { border-color: var(--ink); }
.button-primary:hover { background: var(--accent); opacity: .92; }
.button-danger { border-color: var(--danger); color: var(--danger); background: var(--button-bg); }
.button-danger:hover { background: var(--bad-bg); color: var(--bad-ink); }
.button-google { width: 100%; }
.button-small { padding: 5px 10px; min-height: 32px; font-size: 0.8125rem; }
.button[disabled] { opacity: .5; cursor: not-allowed; }

.link-button { border: 0; background: none; color: var(--accent); padding: 0; min-height: 0; font-weight: 400; }
.link-button:hover { text-decoration: underline; background: none; }

.icon-button {
    display: inline-grid; place-items: center; width: 30px; height: 30px;
    border: var(--control-border-w) solid var(--control-border-c); border-radius: var(--radius-sm);
    background: var(--button-bg); color: var(--ink-soft); cursor: pointer; font-size: 0.8125rem;
}
.icon-button:hover { background: var(--button-hover); color: var(--ink); text-decoration: none; }
.icon-danger { color: var(--danger); border-color: var(--danger); }
.icon-button-small { width: 26px; height: 26px; font-size: 0.8125rem; }
.icon-button:disabled { opacity: .35; cursor: not-allowed; }
.icon-button:disabled:hover { background: var(--button-bg); color: var(--ink-soft); }

/* Hidden is the shown glyph with a line drawn through it, so the two states are one
   stroke apart rather than two unrelated pictures. The glyph is a plain character
   and not an emoji, so it takes the ink colour the look asks for. */
.icon-eye { position: relative; font-size: 0.875rem; }
.icon-eye-off::after {
    content: ''; position: absolute; left: 50%; top: 50%;
    width: 17px; height: 2px; margin: -1px 0 0 -8.5px;
    background: currentColor; border-radius: 1px; transform: rotate(-45deg);
}

.inline-form { display: inline-flex; gap: 6px; align-items: center; margin: 0; }
.inline-form input:where(:not([type=checkbox]):not([type=radio])), .inline-form select { width: auto; }

.divider { display: grid; place-items: center; margin: 16px 0; color: var(--ink-soft); font-size: 0.75rem; }
.divider span { padding: 0 10px; }

.field-errors, .field-error { color: var(--danger); font-size: 0.8125rem; }
/* An untouched form still renders both of these - the summary with an empty list
   inside it - so :empty alone leaves a gap in a laid-out form. The validation
   scripts mark the quiet state, and that is what has to be hidden. */
.field-errors:empty, .field-error:empty,
.validation-summary-valid, .field-validation-valid { display: none; }

/* ======================================================================
   12. The link editor, moderation, speciality pages

      The editor mirrors the board it edits: the same categories in the same order,
      each wearing the tinted chip it wears on the dashboard, so a link is changed
      where the eye already looks for it. A row keeps chip, name and tools on one
      line while the column is wide enough for them, and drops the tools whole onto
      a second line rather than letting them break up into a heap - which is what
      the old row did as soon as a column narrowed.
   ====================================================================== */

.customize-grid {
    display: grid; gap: 14px; align-items: start;
    grid-template-columns: repeat(auto-fill, minmax(min(380px, 100%), 1fr));
    margin: 16px 0 0;
}

.edit-column {
    padding: 12px; background: var(--surface-2); box-shadow: none;
    display: grid; gap: 10px; align-content: start;
}
[data-shape="flat"] .edit-column, [data-shape="outline"] .edit-column { background: var(--card-bg); }

/* The name on one line and the column's own tools on the next: a long title then
   has nowhere to push the buttons to, which is how they used to end up outside
   the card altogether. */
.edit-column-head { display: grid; gap: 8px; }
.edit-column-name { display: flex; align-items: center; gap: 6px; margin: 0; }
.edit-column-name .icon-input { flex: 0 0 3.25rem; }
.edit-column-name .edit-column-title { flex: 1 1 auto; min-width: 0; font-weight: 600; }

.edit-column-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.edit-column-count { color: var(--ink-soft); font-size: 0.75rem; }
.edit-column-tools { display: flex; gap: 4px; }

.edit-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }

.edit-row {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px 9px;
    padding: 8px 9px; border-radius: var(--radius-sm);
    background: var(--surface); border: var(--border-w) solid var(--border-c);
    transition: border-color .14s var(--ease-out);
}
.edit-row:hover, .edit-row:focus-within { border-color: var(--accent); }

/* The same chip the link wears on the board, tint and all. */
.edit-row-icon {
    display: grid; place-items: center; flex: 0 0 26px; height: 26px;
    border-radius: var(--radius-tile);
    background: var(--accent-soft); color: var(--accent);
    font-size: 0.8125rem; font-weight: 700;
    filter: hue-rotate(var(--chip-turn));
}

.edit-row-main { flex: 1 1 6rem; display: grid; min-width: 0; }
.edit-row-title { display: flex; align-items: center; gap: 5px; min-width: 0; font-weight: 500; }
.edit-row-title .tile-lock { margin-left: 0; }
.edit-row-name, .edit-row-url { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.edit-row-url { color: var(--ink-soft); font-size: 0.75rem; }
.edit-row-flags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.edit-row-flags:empty { display: none; }

/* The tools travel as one block: either they sit at the end of the row, or they
   take the next line together. */
.edit-row-tools { display: flex; flex-wrap: nowrap; gap: 3px; margin-left: auto; }

.edit-row-locked { border-left: 3px solid var(--lock); }
.edit-row-hidden { opacity: .65; }
.edit-row-hidden .edit-row-icon { filter: grayscale(1); }

/* The same gold edge one level up, for a whole category the operator keeps. */
.edit-column-locked { border-left: 3px solid var(--lock); }

/* The operator's lock, ticked in the column head. It wraps onto its own line
   under the name, and reads as a quiet note until it is on. */
.check-lock { flex: 1 0 100%; }
.check-lock > span { color: var(--ink-soft); font-size: 0.75rem; }
.check-lock:has(input:checked) > span { color: var(--ink); font-weight: 600; }

.edit-empty {
    margin: 0; padding: 12px 10px; text-align: center;
    border: 1px dashed var(--control-border-c); border-radius: var(--radius-sm);
    color: var(--ink-soft); font-size: 0.8125rem;
}

/* A dashed slot rather than a filled button: it reads as the empty place a new
   thing goes into. The dashes are the controls' own edge colour, which is kept
   clear of every surface the palettes offer, and hovering fills it from the look. */
.add-slot {
    display: flex; align-items: center; justify-content: center; gap: 7px;
    width: 100%; padding: 9px 12px; min-height: 38px;
    border: 1px dashed var(--control-border-c); border-radius: var(--radius-sm);
    background: none; color: var(--ink-soft);
    font-size: 0.8125rem; font-weight: 500; cursor: pointer;
    transition: background-color .14s var(--ease-out), color .14s var(--ease-out),
                border-color .14s var(--ease-out);
}
.add-slot:hover {
    background: var(--button-hover); color: var(--ink);
    border-color: var(--accent); border-style: solid; text-decoration: none;
}
.add-slot-plus { font-size: 1rem; line-height: 1; }

.add-column {
    display: grid; gap: 8px; align-content: start; padding: 12px;
    border: 1px dashed var(--control-border-c); border-radius: var(--radius);
}
.add-column h2 { margin: 0; font-size: 0.8125rem; color: var(--ink-soft); }
.add-column-row { display: flex; gap: 6px; }
.add-column-row .icon-input { flex: 0 0 3.25rem; }
.add-column-row input:not(.icon-input) { flex: 1 1 auto; min-width: 0; }

/* A remark about the page rather than about something the visitor just did:
   quieter than a flash, and it stays put. */
.note {
    display: flex; align-items: flex-start; gap: 9px;
    margin: 12px 0 0; padding: 9px 12px;
    border-radius: var(--radius-sm); border-left: 3px solid var(--lock);
    background: var(--accent-soft); color: var(--ink);
    font-size: 0.8125rem;
}
.note-mark { flex: 0 0 auto; }

.pill {
    display: inline-block; padding: 1px 8px; border-radius: var(--radius-pill);
    background: var(--surface-2); color: var(--ink-soft); font-size: 0.6875rem;
}
.pill-hidden { background: var(--warn-bg); color: var(--warn-ink); }
/* Locked is not a warning, so it takes the look's own tint rather than the amber
   one. Ink on accent-soft is the pairing the note above already uses. */
.pill-lock { background: var(--accent-soft); color: var(--ink); }

/* ======================================================================
   12b. One link, open for editing

      The form on the left, and on the right the tile exactly as the board will
      draw it, kept in step with the fields as they are typed. It is the only
      honest answer to "what will this look like", and it costs one small script.
   ====================================================================== */

.link-editor {
    display: grid; gap: 20px; align-items: start; margin-top: 14px;
    grid-template-columns: minmax(0, 1fr) minmax(0, 264px);
}
.link-editor > .form-actions { grid-column: 1 / -1; }

@media (max-width: 760px) {
    .link-editor { grid-template-columns: minmax(0, 1fr); gap: 16px; }
}

.link-fields { display: grid; gap: 14px; margin: 0; min-width: 0; }
.field-note { display: block; margin-top: 4px; color: var(--ink-soft); font-size: 0.75rem; }
.field-note code { font-family: ui-monospace, Consolas, monospace; background: var(--surface-2); padding: 1px 4px; border-radius: var(--radius-sm); }

.icon-field { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.icon-field .icon-input { flex: 0 0 auto; }
.icon-choices { display: flex; flex-wrap: wrap; gap: 4px; }
.icon-choice {
    display: grid; place-items: center; width: 30px; height: 30px;
    border: var(--control-border-w) solid var(--control-border-c); border-radius: var(--radius-sm);
    background: var(--button-bg); cursor: pointer; font-size: 0.875rem; line-height: 1;
}
.icon-choice:hover { background: var(--button-hover); }

/* One tick per surface, drawn as a card so the chosen ones can be seen at a
   glance instead of as two identical squares in a list. */
.option-list { display: grid; gap: 6px; }
.option {
    display: flex; align-items: center; gap: 10px;
    padding: 9px 11px; border-radius: var(--radius-sm);
    border: var(--control-border-w) solid var(--control-border-c);
    background: var(--field-bg); cursor: pointer;
    transition: background-color .14s var(--ease-out), border-color .14s var(--ease-out);
}
.option:hover { background: var(--button-hover); }
.option:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.option input { width: auto; accent-color: var(--accent); flex: 0 0 auto; }
/* The option is a label, so its text would otherwise be caught by the caption rule
   above and drawn as a muted 13px hint. It is the option name; it reads as ink. */
.option-text { display: grid; min-width: 0; margin-bottom: 0; color: var(--ink); font-size: var(--font-size); }
.option-note { color: var(--ink-soft); font-size: 0.75rem; }
/* Muted ink on the tinted fill of a chosen option is only 4.15:1 in Sand, so the note
   takes full ink once the box is ticked. It reads as the chosen one either way. */
.option:has(input:checked) .option-note { color: var(--ink); }
/* The one operator-only tick on the link editor: set a little apart from the
   options every member gets, and wearing the padlock so it is recognisable
   before it is read. */
.option-lock { margin-top: 4px; }
.option-mark { margin-right: 6px; }

.link-preview {
    position: sticky; top: 16px;
    display: grid; gap: 10px; padding: 12px;
    border-radius: var(--radius); background: var(--surface-2);
}
[data-shape="flat"] .link-preview, [data-shape="outline"] .link-preview { background: var(--card-bg); }
/* Stacked under the fields there is nothing to stick beside, so it travels with them.
   This has to come after the rule it undoes, not with the rest of the narrow layout. */
@media (max-width: 760px) {
    .link-preview { position: static; }
}
.link-preview h2 {
    margin: 0; font-size: var(--head-size); font-weight: var(--head-weight);
    letter-spacing: var(--head-tracking); text-transform: var(--head-case); color: var(--ink-soft);
}
.link-preview-board { padding: 10px; border-radius: var(--radius-sm); background: var(--card-bg); }
.link-preview-note { margin: 0; color: var(--ink-soft); font-size: 0.75rem; }

.form-actions {
    display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
    padding-top: 14px; border-top: 1px solid var(--line);
}
.form-actions-end { margin-left: auto; }

.table { width: 100%; border-collapse: collapse; margin-top: 12px; }
.table th, .table td { text-align: left; padding: 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
.row-tools { display: flex; gap: 6px; }

.status { display: inline-block; padding: 2px 10px; border-radius: var(--radius-pill); font-size: 0.75rem; background: var(--surface-2); color: var(--ink-soft); }
.status-published { background: var(--ok-bg); color: var(--ok-ink); }
.status-rejected { background: var(--bad-bg); color: var(--bad-ink); }
.status-pendingreview { background: var(--warn-bg); color: var(--warn-ink); }

.page-cards { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); }
.page-card a {
    display: grid; gap: 4px; padding: 14px; height: 100%;
    color: var(--ink);
    transition: transform .18s var(--ease-spring), border-color .14s var(--ease-out);
}
.page-card a:hover { text-decoration: none; border-color: var(--accent); transform: var(--lift); }
.page-card-icon { font-size: 1.375rem; transition: transform .25s var(--ease-spring); transform-origin: left center; }
.page-card a:hover .page-card-icon { transform: rotate(-8deg) scale(1.15); }
.page-card-title { font-weight: 600; }
.page-card-note, .page-card-meta { color: var(--ink-soft); font-size: 0.8125rem; }

.place-list { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 6px; }

/* ======================================================================
   13. The look picker
   ====================================================================== */

.picker-axis { border: 0; padding: 0; margin: 0; min-width: 0; }
.picker-axis legend { padding: 0; margin-bottom: 10px; }

.choices { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.choices-modes { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); max-width: 520px; }

.choice {
    position: relative; display: grid; gap: 2px; padding: 10px;
    cursor: pointer; transition: transform .18s var(--ease-spring), border-color .14s var(--ease-out);
}
.choice:hover { transform: var(--lift); }
.choice:active { transform: scale(.98); }
.choice input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.choice:has(input:checked) { border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: -1px; }
.choice:has(input:focus-visible) { outline: 3px solid var(--accent); outline-offset: 2px; }
.choice-name { font-weight: 600; font-size: 0.875rem; margin-top: 8px; }
.choice-note { color: var(--ink-soft); font-size: 0.75rem; }

.choice-preview { display: block; height: 76px; border-radius: var(--radius-sm); overflow: hidden; }

/* A palette sample is a tiny page drawn from that palette's own tokens. */
.swatch {
    position: relative; display: block; height: 100%;
    background: var(--bg); border: 1px solid var(--line);
    font-family: system-ui, sans-serif;
}
.swatch-bar { position: absolute; top: 0; left: 0; right: 0; height: 12px; background: var(--accent); }
.swatch-card {
    position: absolute; left: 10px; right: 10px; top: 22px; bottom: 10px;
    display: grid; grid-template-columns: 18px 1fr; align-items: center; gap: 8px; padding: 8px;
    background: var(--surface); border: 1px solid var(--line); border-radius: 6px;
}
.swatch-dot { width: 18px; height: 18px; border-radius: 5px; background: var(--accent-soft); border: 1px solid var(--accent); }
.swatch-line { height: 6px; border-radius: 3px; background: var(--ink); opacity: .85; }

.mode-demo { display: flex; gap: 0; }
.mode-demo .swatch { flex: 1 1 0; }
.swatch-half + .swatch-half { border-left: 0; }

.type-demo {
    display: grid; place-items: center;
    background: var(--surface-2); color: var(--ink);
    font-family: var(--font); font-size: 2.125rem; font-weight: var(--head-weight); line-height: 1;
}

/* A shape sample carries its own shape tokens; the box inside is drawn from them. */
.shape-demo { display: grid; place-items: center; padding: 10px 12px; background: var(--surface-2); }
.shape-demo-box {
    width: 100%; height: 100%; display: flex; align-items: center; gap: 8px; padding: 8px 10px;
    background: var(--card-bg); border: var(--border-w) solid var(--border-c);
    border-radius: var(--radius); box-shadow: var(--shadow);
}
[data-shape="outline"] .shape-demo-box, [data-shape="flat"] .shape-demo-box { background: var(--surface); }
[data-shape="brutal"] .shape-demo-box { box-shadow: 3px 3px 0 var(--ink); margin: 0 3px 3px 0; }
.shape-demo-chip { width: 18px; height: 18px; flex: 0 0 auto; border-radius: var(--radius-tile); background: var(--accent); }
.shape-demo-tile { height: 10px; flex: 1 1 auto; border-radius: var(--radius-tile); background: var(--accent-soft); }

.picker-reset { margin-top: 16px; }

/* ======================================================================
   14. Legal pages and the cookie banner
   ====================================================================== */

.legal { max-width: 760px; }
.legal-head { margin-bottom: 4px; }
.legal-head h1 { margin: 0 0 4px; }
.legal-head .hint { margin: 0; }

.legal section { margin-top: 26px; }
.legal h2 { margin: 0 0 8px; font-size: 1.1875rem; }
.legal h3 { margin: 20px 0 6px; font-size: 0.9375rem; }
.legal p { margin: 0 0 10px; }
.legal ul { margin: 0 0 10px; padding-left: 20px; display: grid; gap: 6px; }
.legal li { padding-left: 2px; }
/* The article that names the ground for a use, set apart from the paragraph it closes. */
.legal-basis { display: block; margin-top: 4px; color: var(--ink-soft); font-style: normal; font-size: 0.8125rem; }
.legal code { font-family: ui-monospace, Consolas, monospace; font-size: 0.78125rem; background: var(--surface-2); padding: 1px 5px; border-radius: var(--radius-sm); }

/* The row of links carried by every legal page. */
.legal-nav {
    display: flex; flex-wrap: wrap; gap: 4px;
    margin: 14px 0 4px; padding: 8px 0;
    border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.legal-nav a { padding: 4px 10px; border-radius: var(--radius-pill); color: var(--ink-soft); font-size: 0.8125rem; }
.legal-nav a:hover { background: var(--hover); color: var(--ink); text-decoration: none; }
.legal-nav-current { background: var(--accent-soft); color: var(--accent); font-weight: 600; }

/* An unconfigured imprint is a deployment fault, and says so rather than hiding. */
.legal-missing {
    margin-top: 16px; padding: 12px 14px;
    border-radius: var(--radius-sm); border-left: 3px solid var(--warn-ink);
    background: var(--warn-bg); color: var(--warn-ink);
}
.legal-missing p { margin: 6px 0 0; }
.legal-missing code { background: rgb(var(--shadow-rgb) / .08); color: inherit; }

.legal-facts { display: grid; grid-template-columns: 9rem 1fr; gap: 6px 12px; margin: 0 0 12px; }
.legal-facts dt { color: var(--ink-soft); font-size: 0.8125rem; }
.legal-facts dd { margin: 0; }
/* A postal address is written down as it would be on an envelope, so the line breaks
   configuration carries have to survive being put on the page. */
.legal-facts dd.legal-address { white-space: pre-line; }

.legal-summary { padding: 14px 16px; border-radius: var(--radius-sm); background: var(--surface-2); }
.legal-summary h2 { font-size: 0.9375rem; }
.legal-summary ul { margin-bottom: 0; }

/* Cookie tables are four columns of prose; on a phone they scroll rather than squash. */
.table-scroll { overflow-x: auto; }
.table-scroll .table { min-width: 540px; }

.consent-settings { padding: 16px; border-radius: var(--radius-sm); background: var(--surface-2); }
.consent-settings .check { align-items: flex-start; }
.consent-settings .check input { margin-top: 4px; }
.consent-state { font-weight: 500; }

.adslot-consent { font-size: 0.6875rem; }

/* The banner. Fixed to the bottom, above everything, and gone the moment it is
   answered. It never covers the whole page: the portal stays readable behind it. */
.consent {
    position: fixed; inset: auto 0 0 0; z-index: 60;
    padding: 12px; background: var(--surface);
    border-top: var(--border-w) solid var(--border-c);
    box-shadow: 0 -8px 30px rgb(var(--shadow-rgb) / .12);
    animation: consent-in .18s ease-out;
}

@keyframes consent-in { from { transform: translateY(100%); } to { transform: none; } }

.consent-inner {
    max-width: 1100px; margin: 0 auto;
    display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
}

.consent-text { flex: 1 1 380px; min-width: 0; }
.consent-text h2 { margin: 0 0 4px; font-size: 1rem; }
.consent-text p { margin: 0; font-size: 0.84375rem; color: var(--ink-soft); }
.consent-text a { color: var(--accent); }

/* Accepting and refusing are the same size, side by side: an answer only counts as
   freely given when saying no costs no more than saying yes. */
.consent-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0; }
.consent-actions .button { min-width: 140px; justify-content: center; }
.consent-more { font-size: 0.8125rem; color: var(--ink-soft); padding: 0 4px; }

/* The mobile sticky advertisement lives in the same corner; the banner wins until
   it is answered, and the slot comes back the moment it is. */
body:has(.consent) .sticky-ad { display: none; }
body:has(.consent) .sitefoot { padding-bottom: 96px; }

@media (max-width: 640px) {
    .consent-inner { align-items: stretch; }
    .consent-actions { width: 100%; }
    .consent-actions .button { flex: 1 1 0; min-width: 0; }
    .consent-more { width: 100%; text-align: center; padding: 2px 0 0; }
    .legal-facts { grid-template-columns: 1fr; gap: 0 0; }
    .legal-facts dd { margin-bottom: 10px; }
}

/* ======================================================================
   15. Motion
   ====================================================================== */

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { transition: none !important; animation: none !important; }
    .swipe { scroll-behavior: auto; }
}
