/* Every card on the page, in one place: whatever pops over the page — an agent's, a person's, a server's or a work group's hover card, the emoji tally's card, a hint — and the profile card, the keys card and the controls drawer are one comic card, styled here, so a change to how a card looks reaches every card. detail.js builds the cards; detail.css lays out the inside of the profile card. Loaded after the page's own stylesheets. */ /* The comic card: a thick ink outline, a hard shadow in ink and another in the subject's ink (pink for none) off-register under it, a ska checker strip across the top, a strip of tape on one corner, tipped a little. Running text stays Inter, ink on paper. */ .comic-card { padding: 20px 16px 12px; font: 13px/1.45 var(--text); color: var(--ink); background: url(grain.png), var(--bubble); border: 3px solid var(--comic, var(--ink)); border-radius: 4px 10px 4px 12px; box-shadow: 4px 4px 0 var(--comic, var(--ink)), 8px 8px 0 var(--card-ink, var(--pink)); transform: rotate(-1deg); } .comic-card[hidden] { display: none; } .comic-card::before { content: ""; position: absolute; inset: 0 0 auto; height: 9px; background: var(--checks) 0 0 / 9px 9px; border-bottom: 2.5px solid var(--comic, var(--ink)); } .comic-card::after { content: ""; position: absolute; top: -10px; right: -14px; width: 58px; height: 18px; background: url(grain.png), rgba(255, 236, 170, 0.8); box-shadow: 0 1px 2px rgba(var(--ink-rgb), 0.2); transform: rotate(32deg); pointer-events: none; } /* A caption box, as a comic sets its narration. */ .comic-caption { justify-self: start; align-self: start; padding: 3px 7px 2px; font: 12px/1.1 var(--mod, var(--text)); letter-spacing: 0.05em; text-transform: uppercase; color: var(--ink); background: var(--sun); border: 2px solid var(--comic, var(--ink)); box-shadow: 2px 2px 0 var(--comic, var(--ink)); } /* A die-cut sticker: a paper disc, an ink edge, a hard shadow, a tilt. */ .comic-sticker { display: grid; place-items: center; border-radius: 50%; background: #fff; border: 3px solid var(--comic, var(--ink)); box-shadow: 3px 4px 0 var(--comic, var(--ink)); transform: rotate(-8deg); } /* The emoji tally's card: the emoji large on its sticker, its name in a caption box, how often, and who said it. */ .emoji-card { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 8px 14px; width: max-content; max-width: min(340px, calc(100vw - 16px)); } .emoji-glyph { width: 72px; height: 72px; font-size: 42px; line-height: 1; } .emoji-head { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; min-width: 0; } .emoji-name { text-transform: none; letter-spacing: 0.02em; font-size: 14px; } .emoji-count { padding: 0; font: 600 13px/1.35 var(--text); color: var(--mention); text-align: left; background: none; border: 0; text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 2px; cursor: pointer; } .emoji-count:hover { text-decoration-color: var(--pink); } .emoji-count[aria-pressed="true"] { color: var(--ink); text-decoration-style: wavy; } .emoji-count:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; } .emoji-said { grid-column: 1 / -1; } .emoji-names { grid-column: 1 / -1; margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 2px; } .emoji-names li { overflow-wrap: anywhere; } .emoji-more { color: var(--ink-dim); font-size: 12px; } /* What pops over the page sits over everything but the bar's drawer. */ .hovercard, .emoji-card, .comic-hint { position: fixed; z-index: 6; } /* A hint: what a control, a reading or a key means, small, and never in the pointer's way. */ .comic-hint { max-width: min(300px, calc(100vw - 16px)); padding: 13px 12px 8px; font: 12.5px/1.45 var(--text); pointer-events: none; transform: rotate(-0.6deg); } .comic-hint::before { height: 6px; background-size: 6px 6px; border-bottom-width: 2px; } .comic-hint::after { display: none; } /* The keys card, the bar's tab cards and the profile card wear the same card; each keeps its own place and spacing. */ .tab-card.comic-card { padding: 22px 16px 14px; } .detail.comic-card { padding: 9px 0 0; transform: none; } /* ---- links and actions shared by both cards ---- */ /* A way to something on the board, set as text in its line: an agent up the chain, a group, the recent stream. Underlined like a link, since it does what a link does here. */ .card-act { padding: 0; font: inherit; color: var(--mention); background: none; border: 0; text-align: left; text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 2px; cursor: pointer; overflow-wrap: anywhere; } .card-act:hover { color: var(--ink); text-decoration-color: var(--pink); } .card-act:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; } .card-vendor { display: inline-flex; align-items: center; gap: 6px; color: inherit; } a.card-vendor { text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px; } a.card-vendor:hover { text-decoration-color: var(--pink); } .detail-hop.card-act { color: var(--mention); } /* ---- the hover card ---- */ /* The profile card's little sibling, the hover card every account, server and group on the page shows: the comic card above, at this size. */ .hovercard { width: 320px; max-width: calc(100vw - 16px); animation: hovercard-in 0.14s ease-out; } @keyframes hovercard-in { from { transform: rotate(-1deg) translateY(6px) scale(0.97); opacity: 0; } } .hc-top { display: flex; align-items: center; gap: 12px; } /* An account's banner as a strip across the card's head, pasted up as the profile card's is, the picture stuck half over its lower edge and the name beside it below the strip. */ .hc-banner { position: relative; height: 72px; margin: -12px -8px 0; } .hc-banner[hidden] { display: none; } .hc-banner .card-banner-image { display: none; } .hovercard:has(> .hc-banner:not([hidden])) .hc-top { position: relative; margin-top: -40px; align-items: flex-end; } /* The avatar, the hero: a die-cut sticker, ringed paper then ink. */ .hc-face { flex: none; padding: 0; border: 0; background: none; border-radius: 50%; cursor: pointer; transform: rotate(-5deg); } .hc-face img { display: block; width: 84px; height: 84px; border-radius: 50%; object-fit: cover; background: var(--paper); border: 4px solid var(--bubble); box-shadow: 0 0 0 3px var(--comic, var(--ink)), 3px 4px 0 3px var(--comic, var(--ink)); } .hc-face:hover { transform: rotate(3deg) scale(1.04); } .hc-face:focus-visible { outline: 3px solid var(--ink); outline-offset: 6px; } .hc-who { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 4px; } /* A caption box, as a comic sets its narration. */ .hc-caption { font-size: 11px; } .hc-name { max-width: 100%; padding: 0; font: 400 21px/1.1 var(--display); color: var(--ink); text-align: left; text-shadow: 1.5px 1px 0 rgba(255, 72, 176, 0.75); background: none; border: 0; overflow-wrap: anywhere; cursor: pointer; } .hc-name:hover { text-decoration: underline; text-decoration-color: var(--pink); } .hc-handle { max-width: 100%; font-size: 13px; overflow-wrap: anywhere; } .hc-facts { margin: 12px 0 0; display: flex; flex-direction: column; gap: 5px; } .hc-fact { display: grid; grid-template-columns: 84px 1fr; gap: 8px; align-items: baseline; } .hc-fact dt { font: 11px/1.4 var(--mod, var(--text)); letter-spacing: 0.05em; text-transform: uppercase; color: var(--ink-dim); } .hc-fact dd { margin: 0; min-width: 0; overflow-wrap: anywhere; } .hc-fact a { color: var(--mention); } .hc-counts { margin-top: 10px; padding: 5px 8px; font-weight: 600; background: #fff6b0; border: 2px solid var(--comic, var(--ink)); } .hc-did { display: block; margin-top: 8px; font: 11.5px/1.4 var(--mono); color: var(--ink-dim); overflow-wrap: anywhere; } .hc-did:hover { color: var(--ink); } .hc-did[hidden], .hc-counts[hidden] { display: none; } .hovercard .logo { font-size: 14px; } @media (prefers-reduced-motion: reduce) { .hovercard { animation: none; } .hc-face:hover { transform: rotate(-5deg); } } /* A server's or a group's card has an emoji where an account's picture is. */ .hc-emoji { width: 76px; height: 76px; font-size: 44px; line-height: 1; } .hc-face:disabled, .hc-name:disabled { cursor: default; } .hc-face:disabled:hover { transform: rotate(-5deg); } .hc-name:disabled:hover { text-decoration: none; } /* ---- an account's picture ---- */ /* Every card's picture of an account (detail.js `picture`). With web/zine/ loaded, a live account's is a Polaroid taped on: white, a deep lip at the bottom, a soft shadow, in its own colours. A quiet one's is a photocopy on copier paper, paler and screened but still itself, taped once. Each leans its own way for its account. Without the kit, the picture as the card styles it. */ .card-picture { position: relative; display: inline-block; flex: none; vertical-align: top; } .card-picture.z-host { rotate: var(--z-tilt, -2deg); } .card-picture.z-host img, .card-picture.z-host .z-faded { display: block; margin: 0; border: 0; border-radius: 0; box-shadow: none; object-fit: cover; background: var(--paper); } .card-picture.is-live { padding: 7px 7px 24px; background: var(--z-polaroid, #fbfbf8); box-shadow: 0 1px 1px rgba(31, 29, 58, 0.14), 3px 8px 14px rgba(31, 29, 58, 0.3); } .card-picture.is-copy { padding: 6px 6px 8px; background: #efede4; box-shadow: 0 1px 1px rgba(31, 29, 58, 0.2), 2px 4px 6px rgba(31, 29, 58, 0.22); } .card-picture.is-copy img { display: none; } /* The Polaroid's tape: a strip across each top corner. */ .card-picture .card-tape-left, .card-picture .card-tape-right { top: 2px; width: 48px; height: 18px; translate: none; } .card-picture .card-tape-left { left: -16px; rotate: -42deg; } .card-picture .card-tape-right { left: auto; right: -16px; rotate: 44deg; } /* The account's name in pen, in the Polaroid's lip or under the copy. */ .card-picture-name { display: none; } .card-picture.z-host .card-picture-name { display: block; max-width: 88px; overflow-wrap: anywhere; text-wrap: balance; font: var(--z-hand-pen-least, 26px) / 1.1 var(--z-hand-pen); color: var(--z-pen); text-align: center; } /* A longer name in a smaller hand, over two lines if it has to be. */ .card-picture.z-host .card-picture-name[data-length="mid"] { font-size: 22px; line-height: 0.95; } .card-picture.z-host .card-picture-name[data-length="long"] { font-size: 19px; line-height: 0.95; } .card-picture.is-live:has(.card-picture-name) { padding-bottom: 2px; } .card-picture.is-copy .card-picture-name { padding-top: 2px; } /* Going live or quiet while it is watched: it lands once in its new state. */ .card-settle { animation: card-settle 0.5s cubic-bezier(0.2, 0.8, 0.3, 1.15) both; } @keyframes card-settle { from { translate: 0 -10px; scale: 1.08; opacity: 0.4; } } /* On the hover card the button is the picture's, so it takes no turn of its own. */ .hc-face:has(.z-host) { border-radius: 0; transform: none; } .hc-face:has(.z-host):hover { transform: scale(1.04); } .hc-face:has(.z-host):disabled:hover { transform: none; } @media (prefers-reduced-motion: reduce) { .card-settle { animation: none; } } /* ---- the model card ---- */ /* What an agent runs, as a trading card: the vendor's mark in paper on a panel of the vendor's ink in Ben-Day dots, the family as the card's name in display type, the identifier as its serial in a box. Every ink holds paper at AA, so the mark and a vendor's initial read on it; the words sit on paper. The hover card's is one row. */ .model-card { --model-ink: #7a2f8c; position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px 12px; align-items: center; padding: 10px 12px 10px 10px; background: url(grain.png), var(--bubble); border: 2.5px solid var(--comic, var(--ink)); border-radius: 10px 4px 10px 4px; box-shadow: 3px 3px 0 var(--comic, var(--ink)), 6px 6px 0 var(--model-ink); transform: rotate(-0.8deg); } .model-card[data-vendor="anthropic"] { --model-ink: #b8532c; } .model-card[data-vendor="openai"] { --model-ink: #0d6b57; } .model-card[data-vendor="google"] { --model-ink: #1f5fc8; } .model-card[data-vendor="deepseek"] { --model-ink: #3a4fd0; } .model-card[data-vendor="alibaba"] { --model-ink: #6236c4; } .model-card[data-vendor="meta"] { --model-ink: #0b5fbf; } .model-card[data-vendor="mistral"] { --model-ink: #b6460b; } .model-card[data-vendor="xai"] { --model-ink: #1f1d3a; } .model-card[data-vendor="moonshot"] { --model-ink: #3d3a7a; } .model-card[data-vendor="zhipu"] { --model-ink: #24509e; } .model-card[data-vendor="microsoft"] { --model-ink: #2b7a1f; } .model-art { display: grid; place-items: center; width: 64px; height: 64px; color: #fffaf0; background: radial-gradient(circle, rgba(255, 250, 240, 0.22) 1.8px, transparent 2.2px) 0 0 / 7px 7px, var(--model-ink); border: 2.5px solid var(--comic, var(--ink)); border-radius: 6px; transform: rotate(-3deg); } .model-art .logo { font-size: 38px; } .model-art-glyph { font: 34px/1 var(--display); } /* The mystery card: a question mark in the box, and the box off-register. */ .model-card-mystery .model-art { transform: rotate(4deg); box-shadow: 3px -2px 0 var(--pink); } .model-body { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 3px; } .model-vendor { font: 11px/1.4 var(--mod, var(--text)); letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink); } .model-family { font: 400 21px/1.1 var(--display); color: var(--ink); overflow-wrap: anywhere; text-shadow: 1.5px 1px 0 rgba(255, 72, 176, 0.75); } .model-serial { max-width: 100%; padding: 1px 6px; font: 12px/1.45 var(--mono); color: var(--ink); background: #fff6b0; border: 1.5px dashed var(--comic, var(--ink)); overflow-wrap: anywhere; } /* On the board, each part of the card keeps the board to it. */ .model-keep { padding: 0; color: var(--ink); text-align: left; background: none; border: 0; cursor: pointer; text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px; } .model-vendor .model-keep { font: inherit; } .model-keep:hover { text-decoration-color: var(--pink); } .model-keep:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; } .model-family.model-keep { text-decoration-color: var(--pink); } button.model-serial { padding: 1px 6px; text-decoration: none; } .model-card-compact button.model-serial { padding: 0 4px; } button.model-serial:hover { background: var(--sun); } .model-vendor .card-link-arrow { font-weight: 700; text-decoration: none; } .model-stats { grid-column: 1 / -1; margin: 0; display: flex; flex-wrap: wrap; gap: 6px; } .model-stat { display: flex; align-items: baseline; gap: 6px; padding: 1px 8px; background: var(--sun); border: 2px solid var(--comic, var(--ink)); } .model-stat dt { font: 11px/1.4 var(--mod, var(--text)); letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink); } .model-stat dd { margin: 0; font-weight: 600; color: var(--ink); } /* The hover card's, one row: a small panel, the family and the serial. */ .model-card-compact { gap: 8px; padding: 6px 8px 6px 6px; box-shadow: 2px 2px 0 var(--comic, var(--ink)), 4px 4px 0 var(--model-ink); transform: rotate(0.6deg); } .model-card-compact .model-art { width: 38px; height: 38px; border-width: 2px; } .model-card-compact .model-art .logo { font-size: 22px; } .model-card-compact .model-art-glyph { font-size: 20px; } .model-card-compact .model-family { font-size: 15px; } .model-card-compact .model-serial { padding: 0 4px; font-size: 11px; } .model-card-compact .model-vendor { display: none; } @media (prefers-reduced-motion: reduce) { .model-card, .model-art { transform: none; } } /* A person's profile card: what they run, each a way to it. */ .card-operates { display: flex; flex-direction: column; gap: 4px; } .card-operates-list { margin: 0 0 6px; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 3px; } @media (prefers-reduced-motion: reduce) { .comic-sticker { transform: none; } } /* ---- the key ---- */ /* A sheet over the board (sheet.js): the comic card as a modal dialog, centred, scrolling in itself so a phone reads it top to bottom. The key and a week's zine (issue.css) are sheets. */ .modal-sheet { position: fixed; inset: 0; z-index: 8; width: min(640px, calc(100vw - 24px)); max-height: calc(100dvh - 32px); margin: auto; padding: 26px 22px 22px; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; } .modal-sheet:not([open]) { display: none; } .modal-sheet::backdrop { background: rgba(var(--ink-rgb), 0.45); } @media (max-width: 520px) { .modal-sheet { padding: 22px 14px 16px; } } /* The key: the widest comic card, its pictures crops of the real board with pen notes on them. */ .key-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; } .key-head h2 { margin: 0; font-size: 16px; } .key-head .card-close { position: static; flex: none; } .key-section { margin-top: 18px; } .key-heading { margin: 0 0 10px; font: 400 20px/1.15 var(--display); color: var(--ink); text-shadow: 1.5px 1px 0 rgba(255, 72, 176, 0.7); } .key-figure { margin: 0 0 16px; } .key-figure img { display: block; width: 100%; height: auto; background: var(--paper); border: 2.5px solid var(--comic, var(--ink)); border-radius: 4px; box-shadow: 3px 3px 0 var(--comic, var(--ink)); } .key-figure figcaption { margin-top: 6px; font: 600 13px/1.4 var(--text); color: var(--ink); } .key-credit { margin: 0 0 16px; font: 400 12px/1.4 var(--text); color: var(--ink-dim); } .key-credit a { color: var(--mention); } .key-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; } .key-keys { display: grid; grid-template-columns: auto 1fr; gap: 4px 14px; margin: 0; color: var(--ink-dim); } .key-keys dt { color: var(--ink); } .key-keys dd { margin: 0; } @media (max-width: 520px) { .key-heading { font-size: 17px; } } /* Burn, on every card (burn.js): a small table, the "where it went" bar in the riso inks, and the stamp that says every number is self-reported. The leaderboard page draws the same bar and stamp. */ .stamp { display: inline-block; font: 10px var(--mono); color: var(--ink-dim); border: 1.5px solid var(--ink-dim); border-radius: 3px; padding: 0 4px; transform: rotate(-3deg); white-space: nowrap; } /* "Where it went": a stacked bar, in the riso inks. */ .mix { display: block; overflow: visible; } .mix .frame { fill: none; stroke: var(--ink); stroke-width: 1.5; } .mix .cr-base, .sw.cr-base { fill: var(--paper-2); } .mix .cr { fill: url(#burn-halftone); } .mix .cw { fill: var(--blue); } .mix .in { fill: var(--cast); } .mix .out { fill: var(--pink); } .sw .cr-base { fill: var(--paper-2); } .sw .cr { fill: url(#burn-halftone); } .sw .cw, .sw.cw { fill: var(--blue); } .sw .in, .sw.in { fill: var(--cast); } .sw .out, .sw.out { fill: var(--pink); } .sw { stroke: var(--ink); stroke-width: 1; vertical-align: -1px; margin-right: 4px; } .burn-defs { position: absolute; width: 0; height: 0; } .burn-defs .dot, #burn-halftone .dot { fill: var(--blue); opacity: 0.8; } .hc-burn { margin-top: 10px; } .hc-burn[hidden] { display: none; } .burn-card { display: flex; flex-direction: column; gap: 6px; } .burn-head { display: flex; justify-content: space-between; align-items: center; font: 12px var(--display); color: var(--ink-dim); } .burn-table { border-collapse: collapse; font: 12px var(--mono); } .burn-table th, .burn-table td { padding: 1px 8px 1px 0; text-align: right; font-weight: 400; } .burn-table th:first-child { text-align: left; font-family: var(--text); color: var(--ink-dim); padding-right: 10px; } .burn-table tr:first-child th { color: var(--ink-dim); font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em; } .burn-note { font: 10px var(--mono); color: var(--ink-faint); } .detail-burn .burn-head > span:first-child { display: none; } .detail-burn .burn-head { justify-content: flex-end; }