schema: design.v1 name: smashandclash version: 1.0.0 status: lock updated_at: "2026-10-05T00:00:00Z" description: "Smash&Clash · Arena Pop Blue - the official look of the two-player strategy card game: tilted candy buttons with a hard lip on a bright blue world, sticker-white type with a navy outline, one sun-yellow primary per screen. For clients built on the Smash&Clash SDK and API: use it as is, or extend it with your own flavour." $schema: https://raw.githubusercontent.com/AgentsORG/DESIGN/main/schema/design.v1.schema.json agent: skill: design instructions: | You are holding a .design living visual contract (schema design.v1): the official design system of Smash&Clash, for clients built on its SDK and API (https://docs.smashandclash.in/build/overview). If the AgentsORG `design` skill is installed, activate it - then still obey THIS file as source of truth. If the skill is absent, follow these instructions exactly. For the craft bar this file is silent on, use the AgentsORG design-engineering skill (npx skills add AgentsORG/design-engineering). DEFAULT AND FLAVOUR - The default is Smash&Clash exactly as this file says. Build that unless the user asks for their own look. - Their own flavour: create `.design` beside this file with `extends: [./smashandclash.design]` and override ONLY the paths in policy.flavor.may_change. Never override policy.flavor.must_keep: card frame colours, value-badge colours, the you/them player colours, the card art and its proportions, and the access rules (44px targets, visible focus, AA contrast, reduced motion). Those carry game meaning or player safety, not taste. - The art, audio and characters stay Smash&Clash's: credit Smash&Clash, never present them as your own. READ - Load this file before any UI generation or restyle. Large file? Normative core first (intent, constraints, policy/decisions, tokens, components, themes, voice, locked); rationale on demand. - Order: overview/intent -> constraints -> policy/decisions -> tokens -> voice -> rationale -> components/patterns -> integrations -> locked. - Tokens and structured rules are normative. Rationale is judgment when tokens under-specify. FOLLOW (generate or edit UI) - Calibrate treatment per surface: patterns..treatment > intent.treatment (utilitarian = restrained product craft; editorial = distinctive identity). - Prefer catalog components; obey when / when_not and decisions.* (first match wins). - Bind every listed component property (backgroundColor, textColor, typography, rounded, padding, size, height, width). - Never invent raw hex/spacing/radius when a token exists. - Apply patterns.*; enforce constraints.always / never; apply voice.* to all UI copy. - Concentrate boldness in intent.signature; keep everything around it quiet. - Themes: generate for the active mode (themes.default); modes are designed, never inverted. - Match the project's existing styling stack - do not switch stacks. - Craft defaults when this file is silent: one primary CTA; nested radius = outer - padding; transform/opacity only (<300ms); 44x44 targets; focus visible; prefers-reduced-motion; no transition:all. UPDATE - Edit this file in place when design changes. Git is history. - Ask before changing any path in locked. Bump version (SemVer). VERIFY - Compare tokens <-> CSS/Tailwind and components <-> imports; report drift per token group as added/removed/modified plus a regression flag before fixing. PRECEDENCE 1) User prompt 2) This file 3) design skill 4) Generic taste skills 5) Model defaults NEVER - Invent a parallel design system beside this file - Embed binaries or full page HTML trees here - Claim affiliation with third-party brands used only as visual references - Label an opponent "CPU", or offer easy / medium / hard: the opponent is a name, and its strength adapts overview: | Smash&Clash looks like a toy you can press. The world is a bright radial sky blue; on it sit chunky candy buttons tilted -8 degrees, each standing on a hard, solid "lip" that collapses when pressed. Titles are sticker type - Luckiest Guy, uppercase, white with a navy outline - the same language as the wordmark and the focus ring. Ink is navy, never black; light surfaces are blue-tinted "sugar". One sun-yellow action leads every screen; everything else is quiet sugar, and colour elsewhere means something: blue is you, orange is them, grape is Mutators, sky is Classic, cherry is danger. The cards are the heroes: the real card art, the real card back, with value badges in red, yellow, blue and green. intent: reference: "The bright, tactile lobby language of mobile arena games (the chunky tilted buttons and sticker titles of a Brawl Stars or Fall Guys menu), applied to a two-player card board game on a sky-blue world" direction: playful-geometric signature: "Tilted (-8deg) candy slabs on a hard solid lip, with one sun-yellow primary per screen, on a radial sky-blue world" treatment: editorial density: comfortable energy: high playfulness: high trust: medium emotion: excited voice: register: "Short, upbeat and plain - a friendly game host, never a system. Talk to the player as 'you'; name the opponent by their name." casing: "Type labels in sentence case ('Play a friend'); display and label faces uppercase them in CSS. Body copy stays sentence case." terminology: cpu: "never shown - the opponent is a name (a persona, a player, an agent)" difficulty: "never easy / medium / hard - the opponent adapts to your rating" ai_opponent: "the house opponent" ruleset_default: "Mutators" ruleset_alt: "Classic" friend_code: "friend code" leave_live_match: "Leave (counts as a loss)" action_naming: "A button names its exact action and keeps it through the flow: Resign -> 'Resign?' -> Resigned. Confirms are verbs ('Resign', 'Leave'), never 'OK' or 'Yes'." errors: "Say what happened and what to do next, in one line, without blame: 'Could not join the match. Check the code and try again.'" targets: - web - mobile - name: tv notes: "Couch mode: 5% overscan on every edge, root steps up 1.25x, everything reachable by a gamepad" sources: - type: url ref: https://www.smashandclash.in - type: repo path: "src/ui/arena/tokens.css" note: "Arena Pop · Blue tokens: primitives + the SEMANTIC block components read" - type: repo path: "src/ui/arena/docs" note: "DESIGN.md, fills, typography, motion, layout, focus ring, icons, component pages" - type: repo path: "src/ui/arena/kit.ts" note: "slab, heroSlab, ibtn, tile, tabs, seg, chips, switch, ribbon, screenHeader factories" - type: repo path: "src/engine/cards.ts" note: "CARD_COLOR_HEX frame colours; card aspect 825x1125" - type: file path: "assets/card-template.svg" note: "Value-badge colours" - type: url ref: https://www.smashandclash.in/api/v1/games/assets note: "The live asset kit (fonts, card back, audio) clients load" tokens: color: primary: "{tokens.color.candy.sun.base}" on-primary: "{tokens.color.ink}" world: deep: "#016dcb" mid: "#0a8fe0" bright: "#0abeff" pale: "#8adfff" mist: "#d9f5ff" ink: "#0d1a4a" ink-2: "#22357a" ink-3: "#4a5e9c" ink-deep: "#06102f" glass: "rgb(13 26 74 / 0.82)" glass-soft: "rgb(13 26 74 / 0.62)" scrim: "rgb(6 16 47 / 0.5)" shadow-ink: "rgb(6 16 47)" sugar: "#ffffff" sugar-2: "#eef6ff" sugar-3: "#dcebff" sugar-edge: "#b4d0f0" candy: sun: { hi: "#ffe872", base: "#ffc21a", lip: "#d98a00" } sugar: { hi: "#ffffff", base: "#e6f0ff", lip: "#b4d0f0" } mint: { hi: "#8bf7cf", base: "#22d39a", lip: "#0e9a6c" } grape: { hi: "#8a4bff", base: "#5b25d6", lip: "#3b139e" } sky: { hi: "#5ed3ff", base: "#1398f0", lip: "#0a62b8" } gum: { hi: "#ff8cc8", base: "#ff3e9a", lip: "#c4126a" } cherry: { hi: "#ff5a5a", base: "#e02030", lip: "#9e0f18" } text: body: "{tokens.color.ink}" muted: "{tokens.color.ink-2}" subtle: "{tokens.color.ink-3}" error: "#b0105c" danger: "#c0121e" on-fill: "{tokens.color.ink}" on-deep: "#ffffff" action: primary: "{tokens.color.candy.sun.base}" primary-hi: "{tokens.color.candy.sun.hi}" primary-lip: "{tokens.color.candy.sun.lip}" secondary: "{tokens.color.candy.sugar.base}" danger: "{tokens.color.candy.cherry.base}" state: success: "{tokens.color.candy.mint.base}" error: "{tokens.color.candy.gum.base}" player: you: "#2173e8" you-hi: "#5fa6ff" you-lip: "#134a9f" them: "#f4581f" them-hi: "#ff9a62" them-lip: "#a8380c" mode: mutators: "{tokens.color.candy.grape.base}" classic: "{tokens.color.world.bright}" card-frame: red: "#ce3a3d" orange: "#eca441" green: "#56c841" blue: "#3493da" purple: "#b241ec" pink: "#fc41a3" gray: "#8a8f9c" card-badge: top: "#FD5656" right: "#FFDE59" bottom: "#5271FF" left: "#7ED957" typography: display: fontFamily: ["Luckiest Guy", "Lilita One", "system-ui", "sans-serif"] fontWeight: 400 letterSpacing: "0.02em" lineHeight: 1 screen-title: fontFamily: ["Luckiest Guy", "Lilita One", "system-ui", "sans-serif"] fontSize: "clamp(1.875rem, 1.2rem + 2.4vw, 3rem)" fontWeight: 400 lineHeight: 1 ribbon-title: fontFamily: ["Luckiest Guy", "Lilita One", "system-ui", "sans-serif"] fontSize: "clamp(1.5rem, 1.2rem + 1vw, 2rem)" fontWeight: 400 lineHeight: 1 hero-label: fontFamily: ["Luckiest Guy", "Lilita One", "system-ui", "sans-serif"] fontSize: "2.25rem" fontWeight: 400 lineHeight: 1 card-value: fontFamily: ["Luckiest Guy", "system-ui", "sans-serif"] fontWeight: 400 lineHeight: 1 fontFeature: "\"tnum\" 1" label: fontFamily: ["Lilita One", "Luckiest Guy", "system-ui", "sans-serif"] fontSize: "1.0625rem" fontWeight: 400 lineHeight: 1.05 label-lg: fontFamily: ["Lilita One", "Luckiest Guy", "system-ui", "sans-serif"] fontSize: "1.375rem" fontWeight: 400 lineHeight: 1.05 body: fontFamily: ["Rubik", "system-ui", "Segoe UI", "Roboto", "sans-serif"] fontSize: "1rem" fontWeight: 600 lineHeight: 1.35 caption: fontFamily: ["Rubik", "system-ui", "Segoe UI", "Roboto", "sans-serif"] fontSize: "0.875rem" fontWeight: 600 lineHeight: 1.3 micro: fontFamily: ["Rubik", "system-ui", "Segoe UI", "Roboto", "sans-serif"] fontSize: "0.75rem" fontWeight: 800 lineHeight: 1.1 numeral: fontFamily: ["Rubik", "system-ui", "sans-serif"] fontWeight: 800 fontFeature: "\"tnum\" 1" spacing: unit: 4 xs: 4 sm: 8 md: 12 lg: 16 xl: 24 xxl: 32 gutter: "clamp(0.75rem, 0.5rem + 1.4vw, 2rem)" target-min: "2.75rem" ring-room-x: "1.375rem" ring-room-y: "0.75rem" icon-gap: "0.625rem" radius: sm: 12 md: 18 lg: 26 xl: 34 icon-button: "30%" card: "7%" full: 9999 shape: skew: "-8deg" unskew: "8deg" card-aspect: 0.7333 lip: sm: 4px md: 6px hero: 8px pressed: 2px elevation: lip-sm: "0 4px 0 var(--sc-lip, #b4d0f0)" lip: "0 6px 0 var(--sc-lip, #b4d0f0)" lip-hero: "0 8px 0 var(--sc-lip, #b4d0f0)" lip-pressed: "0 2px 0 var(--sc-lip, #b4d0f0)" panel: "0 6px 0 #b4d0f0" plate: "0 4px 0 #06102f" cast: "0 10px 24px rgb(6 16 47 / 0.28)" grape-text: "0 2px 0 rgb(6 16 47 / 0.55)" border: ring-gap: 3px ring-band: 3px ring-keyline: 2px ring-band-color: "#ffffff" ring-keyline-color: "{tokens.color.ink}" motion: duration: press: 90ms exit: 150ms fade: 180ms enter: 250ms wipe: 560ms stagger: screen: 45ms dialog: 40ms tabs: 35ms list: 30ms max-items: 8 easing: out: "cubic-bezier(0.23, 1, 0.32, 1)" pop: "cubic-bezier(0.34, 1.56, 0.64, 1)" cam: "cubic-bezier(0.65, 0, 0.35, 1)" exit: "cubic-bezier(0.4, 0, 1, 1)" wipe: "cubic-bezier(0.76, 0, 0.24, 1)" spring: press: { duration: 0.12s, bounce: 0 } release: { duration: 0.42s, bounce: 0.5 } hover: { duration: 0.36s, bounce: 0.45 } settle: { duration: 0.3s, bounce: 0.2 } pill: { duration: 0.38s, bounce: 0.25 } pop: { duration: 0.42s, bounce: 0.4 } panel: { duration: 0.45s, bounce: 0.2 } stamp: { duration: 0.5s, bounce: 0.45 } background: world: "radial-gradient(130% 110% at 50% 0%, #0abeff 0%, #016dcb 80%)" panel: "linear-gradient(180deg, #ffffff, #eef6ff)" sheet: "linear-gradient(180deg, #ffffff, #eef6ff 70%, #dcebff)" candy: "linear-gradient(180deg, var(--sc-hi, #ffffff), var(--sc-base, #e6f0ff))" breakpoint: stack: "(max-aspect-ratio: 19/20)" split: "(min-aspect-ratio: 19/20)" short: "(min-aspect-ratio: 19/20) and (max-height: 30rem)" big-screen: "(min-width: 112.5rem) and (min-height: 62.5rem)" four-k: "(min-width: 160rem) and (min-height: 90rem)" opacity: disabled: 0.5 glass: 0.82 glass-soft: 0.62 zIndex: page: 25 overlay: 30 layer: 40 toast: 50 hints: 55 wipe: 60 iconography: set: "house set - 24-unit viewBox, currentColor strokes" stroke: 2.4 caps: round joins: round sizes: { sm: 16, md: 20, lg: 24 } emoji: never sound: enabled: true material: "soft rounded candy-toy pops and plinks, cute cartoon, dry with no reverb, one hit, no sharp click" peak: -3dBFS loudness: feedback: -18LUFS game: -14LUFS music: -16LUFS duration: tap: 60ms hover: 50ms place: 200ms capture: 350ms deny: 150ms sync-lag-max: 30ms locked: - tokens.color.card-frame - tokens.color.card-badge - tokens.color.player - tokens.color.mode - tokens.shape.card-aspect - tokens.spacing.target-min - tokens.border - assets - policy.flavor.must_keep themes: default: arena-pop-blue modes: arena-pop-blue: tokens: {} high-contrast: tokens: color: glass: "rgb(13 26 74 / 0.97)" glass-soft: "rgb(13 26 74 / 0.97)" scrim: "rgb(6 16 47 / 0.72)" border: ring-gap: 2px ring-band: 4px ring-keyline-color: "#000000" assets: logo: light: "https://www.smashandclash.in/logo.svg" wordmark: "https://www.smashandclash.in/logo-wordmark.svg" favicon: "https://www.smashandclash.in/favicon.svg" icon: "https://www.smashandclash.in/icon.png" card_back: "https://www.smashandclash.in/Card_Back_v2.png" card_template: "https://www.smashandclash.in/card-template.svg" font_files: - "https://www.smashandclash.in/LuckiestGuy-Regular.ttf" - "https://www.smashandclash.in/fonts/lilita-one-latin-400-normal.woff2" - "https://www.smashandclash.in/fonts/rubik-latin-wght-normal.woff2" kit: "https://www.smashandclash.in/api/v1/games/assets" sounds: tap: "https://www.smashandclash.in/audio/sfx/click-v2.mp3" hover: "https://www.smashandclash.in/audio/sfx/hover-v2.mp3" place: "https://www.smashandclash.in/audio/sfx/cardPlace.mp3" capture: "https://www.smashandclash.in/audio/sfx/capture.mp3" deny: "https://www.smashandclash.in/audio/sfx/deny-v2.mp3" cards: "https://www.smashandclash.in/api/v1/games/cards" components: button: description: "The candy slab: a face tilted -8deg on a solid lip, label in the label face, optional icon" import: "src/ui/arena/kit.ts#slab" when: ["any labelled action", "a row in a list of destinations (size row)", "dialog and sheet actions (size sm)"] when_not: ["icon-only controls (use icon-button)", "a second sun on the same screen", "navigation inside prose (use a link)"] variants: [sun, sugar, mint, grape, sky, gum, cherry] states: [default, hover, pressed, focus, disabled] anatomy: [icon-left, label, sub-pill, icon-right, lip] status: stable tokens: sun: backgroundColor: "{tokens.color.candy.sun.base}" textColor: "{tokens.color.text.on-fill}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" height: "52px" padding: "0 22px" shadow: "0 6px 0 #d98a00" sugar: backgroundColor: "{tokens.color.candy.sugar.base}" textColor: "{tokens.color.text.on-fill}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" height: "52px" padding: "0 22px" shadow: "0 6px 0 #b4d0f0" mint: backgroundColor: "{tokens.color.candy.mint.base}" textColor: "{tokens.color.text.on-fill}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" height: "52px" shadow: "0 6px 0 #0e9a6c" grape: backgroundColor: "{tokens.color.candy.grape.base}" textColor: "{tokens.color.text.on-deep}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" height: "52px" shadow: "0 6px 0 #3b139e" sky: backgroundColor: "{tokens.color.candy.sky.base}" textColor: "{tokens.color.text.on-fill}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" height: "52px" shadow: "0 6px 0 #0a62b8" gum: backgroundColor: "{tokens.color.candy.gum.base}" textColor: "{tokens.color.text.on-fill}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" height: "52px" shadow: "0 6px 0 #c4126a" cherry: backgroundColor: "{tokens.color.candy.cherry.base}" textColor: "{tokens.color.text.on-deep}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" height: "52px" shadow: "0 6px 0 #9e0f18" size-sm: height: "44px" padding: "0 16px" size-row: height: "48px" typography: "{tokens.typography.label}" pressed: shadow: "0 2px 0 var(--sc-lip, #b4d0f0)" disabled: opacity: 0.5 notes: "The face is a gradient from the fill's hi (top) to its base (bottom) with a gloss band; the hit area never moves and is at least 44px; the face squashes on press (spring press) and pops on hover / focus. White labels (grape, cherry) carry the grape-text shadow." hero-button: description: "The screen's one primary action, at the foot of a pane: the biggest sun slab, with a shine sweep" import: "src/ui/arena/kit.ts#heroSlab" when: ["THE primary action of a screen or pane (PLAY, START, REMATCH, Create room)"] when_not: ["secondary actions", "destructive actions (a destructive action is a confirm dialog)", "more than one per screen"] variants: [sun] status: stable tokens: sun: backgroundColor: "{tokens.color.candy.sun.base}" textColor: "{tokens.color.text.on-fill}" typography: "{tokens.typography.hero-label}" rounded: "{tokens.radius.lg}" height: "5.25rem" shadow: "0 8px 0 #d98a00" icon-button: description: "A rounded-square sugar puck with a lip, holding one icon; never a circle, never tilted" import: "src/ui/arena/kit.ts#ibtn" when: ["settings, friends, back, close and other icon-only header controls", "toolbars (replay transport)"] when_not: ["toggles that stay pressed (use a switch or tabs)", "actions that need words to be understood"] variants: [default, sm, close] status: stable tokens: default: backgroundColor: "{tokens.color.candy.sugar.base}" textColor: "{tokens.color.text.body}" rounded: "{tokens.radius.icon-button}" size: "48px" shadow: "0 5px 0 #b4d0f0" sm: size: "44px" shadow: "0 4px 0 #b4d0f0" close: backgroundColor: "{tokens.color.candy.gum.base}" textColor: "{tokens.color.text.on-deep}" size: "44px" tile: description: "An art card for a small grid of places: art over a tilted label plate, optional count chip" import: "src/ui/arena/kit.ts#tile" when: ["a grid of destinations (How to play, Replays, More)"] when_not: ["single actions (use button)", "lists longer than six"] variants: [grape, sky, gum, sun, mint, sugar, cherry] status: stable tokens: grape: backgroundColor: "{tokens.color.candy.grape.base}" textColor: "{tokens.color.text.on-deep}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.lg}" height: "5.5rem" sky: backgroundColor: "{tokens.color.candy.sky.base}" textColor: "{tokens.color.text.on-fill}" rounded: "{tokens.radius.lg}" gum: backgroundColor: "{tokens.color.candy.gum.base}" textColor: "{tokens.color.text.on-fill}" rounded: "{tokens.radius.lg}" tabs: description: "Tilted tabs on an ink plate; the selected tab wears sun and a sliding pill" import: "src/ui/arena/kit.ts#tabs" when: ["switching between panels of one screen (Profile: Stats, Matches, Champions)"] when_not: ["choosing a value (use segmented)", "filtering one list (use chips)"] variants: [default] states: [default, selected, focus] tokens: default: backgroundColor: "{tokens.color.ink}" textColor: "{tokens.color.text.on-deep}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" selected: backgroundColor: "{tokens.color.candy.sun.base}" textColor: "{tokens.color.text.on-fill}" segmented: description: "Equal columns in one ink trough; the thumb is sun" import: "src/ui/arena/kit.ts#seg" when: ["choosing one value of two to four (Mutators | Classic)"] when_not: ["panels (use tabs)", "more than four options (use chips)"] variants: [default] tokens: default: backgroundColor: "{tokens.color.ink}" textColor: "{tokens.color.text.on-deep}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" height: "44px" thumb: backgroundColor: "{tokens.color.candy.sun.base}" textColor: "{tokens.color.text.on-fill}" switch: description: "On is mint with a check; off is a pale track with a cross" import: "src/ui/arena/kit.ts#switchCtl" when: ["an on/off setting"] when_not: ["three or more states", "an action"] variants: ["on", "off"] tokens: "on": backgroundColor: "{tokens.color.candy.mint.base}" textColor: "{tokens.color.text.on-fill}" width: "56px" height: "32px" rounded: "{tokens.radius.full}" "off": backgroundColor: "{tokens.color.sugar-3}" textColor: "{tokens.color.text.muted}" toast: description: "A tilted glass pill above the thumb zone; lives 2.6s; never takes focus" import: "src/ui/arena/toast.ts#toast" when: ["confirming something already done", "a non-blocking error"] when_not: ["anything the player must answer (use dialog)", "the only way to undo something"] variants: [info, success, error] tokens: info: backgroundColor: "{tokens.color.glass}" textColor: "{tokens.color.text.on-deep}" typography: "{tokens.typography.body}" rounded: "{tokens.radius.md}" success: backgroundColor: "{tokens.color.glass}" textColor: "{tokens.color.text.on-deep}" error: backgroundColor: "{tokens.color.glass}" textColor: "{tokens.color.text.on-deep}" dialog: description: "A centred sugar card on a navy scrim, topped by a ribbon; Esc / pad B / Back close it" import: "src/ui/arena/overlay.ts#openLayer" when: ["a decision the player must make", "a short form or a share sheet"] when_not: ["passive notices (use toast)", "a whole screen (use a page)"] variants: [dialog, wide, confirm, destructive] tokens: dialog: backgroundColor: "{tokens.color.sugar}" textColor: "{tokens.color.text.body}" typography: "{tokens.typography.body}" rounded: "{tokens.radius.xl}" width: "24rem" padding: "1.25rem" shadow: "0 6px 0 #b4d0f0" wide: width: "40rem" destructive: borderColor: "{tokens.color.candy.cherry.base}" notes: "Confirms: the quiet action (sugar 'Cancel') first and focused, the verb last. Destructive confirms use a cherry ribbon and a cherry confirm." ribbon: description: "A tilted title banner across the top of a layer" import: "src/ui/arena/kit.ts#ribbon" when: ["the title of a dialog or sheet"] when_not: ["the title of a full screen (use screen-header)"] variants: [grape, gum, sky, cherry] tokens: grape: backgroundColor: "{tokens.color.candy.grape.base}" textColor: "{tokens.color.text.on-deep}" typography: "{tokens.typography.ribbon-title}" sky: backgroundColor: "{tokens.color.candy.sky.base}" textColor: "{tokens.color.text.on-fill}" cherry: backgroundColor: "{tokens.color.candy.cherry.base}" textColor: "{tokens.color.text.on-deep}" screen-header: description: "A back icon-button and a skewed sticker title at the top of a full screen" import: "src/ui/arena/kit.ts#screenHeader" when: ["the top of a full screen or routed page (Settings, Profile, Friends, Leaderboard)"] when_not: ["dialogs (use ribbon)"] variants: [default] tokens: default: textColor: "{tokens.color.text.on-deep}" typography: "{tokens.typography.screen-title}" player-plate: description: "A seat's name, avatar and score in a match: blue for you, orange for them - whoever sits where" when: ["the in-match HUD", "result screens", "VS splash"] when_not: ["lists of players (use rows)"] variants: [you, them] tokens: you: backgroundColor: "{tokens.color.player.you}" textColor: "{tokens.color.text.on-deep}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" shadow: "0 6px 0 #134a9f" them: backgroundColor: "{tokens.color.player.them}" textColor: "{tokens.color.text.on-deep}" typography: "{tokens.typography.label}" rounded: "{tokens.radius.md}" shadow: "0 6px 0 #a8380c" notes: "Viewer-relative, never seat-relative. White text on these fills needs 24px+ or the grape-text shadow." game-card: description: "A character card: the real art inside a frame in its colour, four value badges in fixed colours" when: ["any card in a hand, on the board, in a list or a deck view"] when_not: ["a face-down card (use card-back)"] variants: [face, built, on-board-you, on-board-them, frozen] tokens: face: rounded: "{tokens.radius.card}" built: typography: "{tokens.typography.card-value}" rounded: "{tokens.radius.card}" on-board-you: borderColor: "{tokens.color.player.you}" on-board-them: borderColor: "{tokens.color.player.them}" frozen: opacity: 0.9 notes: "face = the finished card face (card list: image, 563x768) shown as is. built = the frameless art (card list: art) centred in a frame of the card's own colour (card list: colorHex, one of tokens.color.card-frame), with value badges top / right / bottom / left in tokens.color.card-badge, values in card-value type. Aspect 825:1125 always. Values are printed from the owner's side: seat B's cards are turned round on the board. Never recolour, redraw or crop the character art." card-back: description: "The real Smash&Clash card back for every face-down card" when: ["the other player's hand", "the draw pile", "a card being dealt"] when_not: ["a decorative star or a placeholder - the back is always the real artwork"] variants: [default] tokens: default: rounded: "{tokens.radius.card}" board-tile: description: "One of the 15 tiles of the 3x5 board; a placed card fills it" when: ["the board"] variants: [empty, playable, power, chess, overrun] tokens: empty: backgroundColor: "rgb(255 255 255 / 0.18)" rounded: "{tokens.radius.sm}" playable: borderColor: "{tokens.color.candy.sun.base}" borderWidth: 3px power: borderWidth: 3px chess: backgroundColor: "{tokens.color.mode.mutators}" overrun: borderColor: "{tokens.color.candy.grape.hi}" notes: "Highlight playable tiles from the game view's moves; a tile the player cannot play on never lights up. A power tile's border is its colour from tokens.color.card-frame." patterns: lobby: treatment: editorial allowed: [player-chip, icon-buttons, champion-stage, mode-segmented, tiles, hero-button] forbidden: [stat_strip, more_than_one_sun, dense_text] prioritize: [hero-button] match: treatment: editorial allowed: [player-plates, board, hand, card-back, score, turn_banner, hint-bar] forbidden: [modal_over_the_board_without_pause, cpu_label, seat_coloured_by_position] result: treatment: editorial allowed: [sticker_title, rating_roll, hero-button, replay, share] forbidden: [blocking_input_during_celebration] settings: treatment: utilitarian allowed: [screen-header, rows, switches, segmented, sliders] forbidden: [suns_on_every_row, decorative_scenes] list_page: treatment: utilitarian allowed: [screen-header, rows, one_sun_action, empty_state] forbidden: [page_scroll - panes scroll, fixed_heights] policy: hierarchy: [typography, contrast, spacing, color] reuse: prefer_existing_components: true invent_threshold: "only if no component covers the interaction" fallback_order: [semantic_token, nearest_approved_token, ask] if_missing: nearest accessibility: contrast: AA focus_visible: required reduced_motion: honor min_target: "2.75rem (44px at 100% text size, grows with it)" text_floor: "12px; prose 14-16px" text_size: "every size in rem so a 125% / 150% text setting scales it" responsive: if_mobile: reduce_padding_before_font_size layouts: "STACK in portrait, SPLIT in landscape, SHORT for landscape phones; panes scroll, the page never does" color: accent_cycle: [candy.grape, candy.sky, candy.gum] flavor: default: smashandclash how: "Create .design with extends: [./smashandclash.design] and override only may_change paths" may_change: - tokens.color.world - tokens.background - tokens.color.candy - tokens.color.sugar - tokens.color.sugar-2 - tokens.color.sugar-3 - tokens.color.sugar-edge - tokens.color.glass - tokens.color.ink - tokens.color.text - tokens.color.action - tokens.color.state - tokens.typography.display.fontFamily - tokens.typography.label.fontFamily - tokens.typography.body.fontFamily - tokens.radius - tokens.shape.skew - tokens.shape.lip - tokens.motion - tokens.sound.material - voice.register - intent must_keep: - tokens.color.card-frame - tokens.color.card-badge - tokens.color.player - tokens.shape.card-aspect - tokens.spacing.target-min - tokens.border - policy.accessibility - "the real card art, card back and character voices, credited to Smash&Clash" - "voice.terminology.cpu and voice.terminology.difficulty" decisions: button: - if: "it destroys something or cannot be undone (sign out, remove, resign, restart, leave a live match)" then: { component: dialog, variant: destructive, confirm: cherry } - if: "it is the one thing this screen wants next" then: { component: hero-button, fallback: "button sun (size sm) inside a row" } - if: "it finishes an edit or means ON / saved" then: { component: button, variant: mint } - if: "it enters a mode or a place" then: { component: button, variant: "the place's colour - grape = online / Mutators, sky = local / Classic / replays, gum = how to play" } - if: "anything else" then: { component: button, variant: sugar } color: - if: "colouring a player (plate, card edge, score)" then: { you: "{tokens.color.player.you}", them: "{tokens.color.player.them}", rule: "by viewer, never by seat" } - if: "colouring a ruleset" then: { mutators: "{tokens.color.mode.mutators}", classic: "{tokens.color.mode.classic}", rule: "always with its name written" } - if: "a label on grape, cherry or a player plate" then: { text: "{tokens.color.text.on-deep}", shadow: "{tokens.elevation.grape-text}" } - if: "a label on sun, sugar, mint, sky or gum" then: { text: "{tokens.color.text.on-fill}" } card: - if: "the card is face down or in the other hand" then: { component: card-back, rule: "never reveal it" } - if: "the game's own look is wanted" then: { component: game-card, variant: face } - if: "a custom card" then: { component: game-card, variant: built } motion: - if: "a response to a press, drag or toggle right now" then: { use: "{tokens.motion.spring.release}", animate: "transform, opacity" } - if: "something leaves" then: { easing: "{tokens.motion.easing.exit}", duration: "{tokens.motion.duration.exit}" } - if: "a new screen" then: { duration: "{tokens.motion.duration.wipe}", easing: "{tokens.motion.easing.wipe}", reduced: cross-fade } - if: "anything else that enters" then: { easing: "{tokens.motion.easing.out}", duration: "{tokens.motion.duration.enter}" } sound: - if: "hover-only, focus, scroll or keystroke" then: { sound: none } - if: "the player turned sound off or the tab is hidden" then: { sound: none } - if: "a card is placed, captures, is captured, is blocked, or wins" then: { sound: "the character's voice line from the kit", priority: "capture > hurt > place" } - if: "a press" then: { sound: "{tokens.sound.duration.tap}", trigger: "the settle of the press" } constraints: always: - one sun (primary) action per screen or pane - every control's hit area is at least 44px (tokens.spacing.target-min) - the focus ring is the sticker halo - white band and navy keyline (tokens.border.ring-*), keyboard and pad only - viewer-relative colour - you are blue, the other side is orange, in every seat arrangement - the real card art and card back - never a stand-in - sizes in rem so the player's text-size setting scales them; never below 12px - honour reduced motion (cross-fade instead of movement) - credit Smash&Clash for the art, audio and characters never: - label an opponent "CPU" or reveal what kind of player it is - offer easy / medium / hard - white text on sun, mint, sky or gum - more than one sun on a screen - cherry for anything that is not destructive or dangerous - recolour, redraw, crop or caption the character art as your own - emoji or third-party icon packs in the UI - animate width, height, top, left or margin; transition all - black shadows - every cast shadow is navy (tokens.color.shadow-ink) - a circle for an icon button examples: good: - ref: "https://www.smashandclash.in" note: "The lobby: one sun PLAY at the foot, grape / sky mode slabs, tiles, the champion on the blue world" - ref: "https://docs.smashandclash.in/build/overview" note: "Building a client: card ids, moves as data, the kit" bad: - ref: "https://docs.smashandclash.in/build/design#what-to-avoid" note: "Two yellow buttons side by side ('Play' and 'Cancel'): Cancel is sugar" - ref: "https://docs.smashandclash.in/build/design#what-to-avoid" note: "A red 'Easy' / 'Hard' picker before a match" - ref: "https://docs.smashandclash.in/build/design#what-to-avoid" note: "The opponent's plate reading 'CPU'" - ref: "https://docs.smashandclash.in/build/design#what-to-avoid" note: "A star or a blue rectangle standing in for the card back" rationale: overview: | A toy you can press. Every control is a piece of candy: a gradient face, a gloss band, a solid lip that squashes when pressed and springs back. The world stays blue so the candy pops. The sticker type and the focus ring share the wordmark's language - white with a navy edge - so even keyboard focus looks like part of the brand. colors: | Navy ink, never black: text, outlines, plates and every cast shadow use the ink family. Light surfaces are sugar (blue-tinted white). The seven candies are the whole palette of controls: sun leads (one per screen), sugar is quiet and the default, mint means done / on, grape and sky are places (online / Mutators, local / Classic), gum is playful (how to play, error chips), cherry is danger only. Colour that means something in the game is fixed: blue you, orange them, the seven card frame colours (power tiles match them), the four value-badge colours. typography: | Three faces, three jobs. Luckiest Guy for screen titles, ribbons, the hero label and card values - uppercase, one weight. Lilita One for every control label and name - uppercase by CSS, one weight. Rubik 600 for copy, 700-800 for small bold and numbers (tabular figures). Never set a weight on the display or label faces. Body 16, captions 14, the floor 12 - and in rem, so a player's 150% text setting grows them. layout: | Fluid on width AND height, 360px phones to 4K, portrait and landscape, safe areas and TV overscan. The page never scrolls; panes do, and they keep room for the focus ring. Pad screen edges with the safe-area insets and a fluid gutter. Big screens and couch mode step the whole root up. elevation: | Depth is a hard lip, not a blur: a solid underside in the fill's darker tone (4px small, 6px default, 8px hero; 2px pressed). Panels sit on a sugar-edge lip. The one soft shadow is a navy cast under floating pieces; never black. In CSS, a candy sets --sc-hi, --sc-base and --sc-lip to its fill's three colours (tokens.color.candy..hi / base / lip) and reads background.candy and elevation.lip*. shapes: | Tilted (-8deg): buttons, tabs, ribbons, label plates, toasts, screen titles. Upright: icon buttons (rounded squares, 30% corners, never circles), player chip, switch, slider, dialog panels, cards. Radii 12 / 18 / 26 / 34; cards round at 7% of their width. components: | Build every control from the catalogue; the hit area never moves (the face does), and it is never smaller than 44px. Disabled controls dim and say 'no' with a sound; they never vanish. Dialogs close with Esc, gamepad B or system Back, and focus the safe action first. motion: | Springs for anything that answers a touch (press, release, hover, toggle); five named curves for one-shots; exits are quicker than entrances. Input is never blocked by an animation - a new surface is live on its first frame. Ambient loops pause while a dialog is open or the tab is hidden. Reduced motion keeps short fades and the static focus ring. sound: | A game, so sound is on by default with separate music, effects and voice levels the player controls. UI sounds are soft candy pops; the characters speak on place, capture, chain, blocked, hurt and win. Sound always has a visual twin and lands on the contact frame of the motion it belongs to. flavor: | Your own client can have its own flavour: a different world colour, other candies, other faces for titles and labels, rounder or sharper corners, a different tilt, other motion. Keep what carries game meaning (card frame and badge colours, you/them colours, card proportions) and what keeps players safe (targets, focus, contrast, reduced motion) exactly as they are. Start from this file with extends and override only policy.flavor.may_change; the default is always Smash&Clash. dos: - "One sun per screen; Cancel next to it is sugar" - "Navy ink and navy shadows" - "Real card art and the real card back" - "Name every player; colour by viewer (you blue, them orange)" - "rem sizes, 44px targets, the sticker focus ring" donts: - "Black text or black shadows" - "White labels on light candies" - "Circles for icon buttons; emoji for icons" - "'CPU', or easy / medium / hard" - "Blocking input for an animation" integrations: {} exports: css: path: "./smashandclash.tokens.css" selector: ":root" prefix: "sc-" mode_strategy: data-attribute attribute: data-theme provenance: owner: "Smash&Clash (https://www.smashandclash.in)" contact: "support@smashandclash.in" review: "Extracted from the shipping Arena Pop · Blue system; the game repository's tokens.css is the implementation" license: "The file: free to use and extend for clients built for Smash&Clash. The art, audio, characters and name stay Smash&Clash's." omitted: - section: integrations.shadcn reason: "The game uses its own kit (src/ui/arena); clients map the tokens into their own stack" - section: integrations.figma reason: "No Figma source; the code is canonical"