Polish owl login after design review; add DESIGN.md

Fixes from the finish review of the natural owl:
- thinner glasses frames, closer to the user's reference owl
- smile-eyes on success instead of flat half-lids
- the page no longer shifts when an error appears; the card grows down
- invalid field keeps a red outline while focused
- stars stay clear of the title, owl and card
- softer ear tufts, warm glow under the owl, larger owl on desktop

DESIGN.md and .impeccable/design.json record the shipped system.
The surface brief records the seed reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
VasanthandClaude Opus 5.5 committed 2026-10-22 12:04:16 +05:30
1 parent 54fa7de9b0
commit 0317358dcf
4 files changed
+387 -16

No files matched your search

+123
View File
@@ -0,0 +1,123 @@
{
"schemaVersion": 2,
"generatedAt": "2026-10-22T12:00:00Z",
"title": "Design System: Charge Billed Automation",
"extensions": {
"colorMeta": {
"night": { "role": "neutral", "displayName": "Night Navy", "canonical": "#040b26", "tonalRamp": ["oklch(15% 0.057 267)", "oklch(25% 0.057 267)", "oklch(35% 0.057 267)", "oklch(45% 0.057 267)", "oklch(55% 0.057 267)", "oklch(68% 0.057 267)", "oklch(80% 0.057 267)", "oklch(95% 0.057 267)"] },
"panel": { "role": "neutral", "displayName": "Card Navy", "canonical": "#0c1638", "tonalRamp": ["oklch(15% 0.068 268)", "oklch(25% 0.068 268)", "oklch(35% 0.068 268)", "oklch(45% 0.068 268)", "oklch(55% 0.068 268)", "oklch(68% 0.068 268)", "oklch(80% 0.068 268)", "oklch(95% 0.068 268)"] },
"panel-line": { "role": "neutral", "displayName": "Card Edge", "canonical": "#26335e", "tonalRamp": ["oklch(15% 0.078 269)", "oklch(25% 0.078 269)", "oklch(35% 0.078 269)", "oklch(45% 0.078 269)", "oklch(55% 0.078 269)", "oklch(68% 0.078 269)", "oklch(80% 0.078 269)", "oklch(95% 0.078 269)"] },
"field": { "role": "neutral", "displayName": "Well Navy", "canonical": "#050c28", "tonalRamp": ["oklch(15% 0.059 268)", "oklch(25% 0.059 268)", "oklch(35% 0.059 268)", "oklch(45% 0.059 268)", "oklch(55% 0.059 268)", "oklch(68% 0.059 268)", "oklch(80% 0.059 268)", "oklch(95% 0.059 268)"] },
"field-line": { "role": "neutral", "displayName": "Field Edge", "canonical": "#56689c", "tonalRamp": ["oklch(15% 0.085 269)", "oklch(25% 0.085 269)", "oklch(35% 0.085 269)", "oklch(45% 0.085 269)", "oklch(55% 0.085 269)", "oklch(68% 0.085 269)", "oklch(80% 0.085 269)", "oklch(95% 0.085 269)"] },
"pill-fill": { "role": "neutral", "displayName": "Button Navy", "canonical": "#0a1435", "tonalRamp": ["oklch(15% 0.066 268)", "oklch(25% 0.066 268)", "oklch(35% 0.066 268)", "oklch(45% 0.066 268)", "oklch(55% 0.066 268)", "oklch(68% 0.066 268)", "oklch(80% 0.066 268)", "oklch(95% 0.066 268)"] },
"pill-fill-hover": { "role": "neutral", "displayName": "Button Navy Lifted", "canonical": "#101d45", "tonalRamp": ["oklch(15% 0.077 267)", "oklch(25% 0.077 267)", "oklch(35% 0.077 267)", "oklch(45% 0.077 267)", "oklch(55% 0.077 267)", "oklch(68% 0.077 267)", "oklch(80% 0.077 267)", "oklch(95% 0.077 267)"] },
"pill-line": { "role": "neutral", "displayName": "Moonlight Edge", "canonical": "#c9d5f2", "tonalRamp": ["oklch(15% 0.042 268)", "oklch(25% 0.042 268)", "oklch(35% 0.042 268)", "oklch(45% 0.042 268)", "oklch(55% 0.042 268)", "oklch(68% 0.042 268)", "oklch(80% 0.042 268)", "oklch(95% 0.042 268)"] },
"pill-text": { "role": "neutral", "displayName": "Pure White", "canonical": "#ffffff", "tonalRamp": ["oklch(15% 0 0)", "oklch(25% 0 0)", "oklch(35% 0 0)", "oklch(45% 0 0)", "oklch(55% 0 0)", "oklch(68% 0 0)", "oklch(80% 0 0)", "oklch(95% 0 0)"] },
"ink": { "role": "neutral", "displayName": "Starlight Ink", "canonical": "#eef2ff", "tonalRamp": ["oklch(15% 0.018 272)", "oklch(25% 0.018 272)", "oklch(35% 0.018 272)", "oklch(45% 0.018 272)", "oklch(55% 0.018 272)", "oklch(68% 0.018 272)", "oklch(80% 0.018 272)", "oklch(95% 0.018 272)"] },
"ink-2": { "role": "neutral", "displayName": "Mist Ink", "canonical": "#a9b6d8", "tonalRamp": ["oklch(15% 0.051 269)", "oklch(25% 0.051 269)", "oklch(35% 0.051 269)", "oklch(45% 0.051 269)", "oklch(55% 0.051 269)", "oklch(68% 0.051 269)", "oklch(80% 0.051 269)", "oklch(95% 0.051 269)"] },
"owl": { "role": "primary", "displayName": "Owl Orange", "canonical": "#ec7d33", "tonalRamp": ["oklch(15% 0.16 50)", "oklch(25% 0.16 50)", "oklch(35% 0.16 50)", "oklch(45% 0.16 50)", "oklch(55% 0.16 50)", "oklch(68% 0.16 50)", "oklch(80% 0.16 50)", "oklch(95% 0.16 50)"] },
"owl-soft": { "role": "primary", "displayName": "Lamplight Orange", "canonical": "#f5a25a", "tonalRamp": ["oklch(15% 0.132 60)", "oklch(25% 0.132 60)", "oklch(35% 0.132 60)", "oklch(45% 0.132 60)", "oklch(55% 0.132 60)", "oklch(68% 0.132 60)", "oklch(80% 0.132 60)", "oklch(95% 0.132 60)"] },
"error": { "role": "semantic", "displayName": "Soft Alarm", "canonical": "#ff9a9a", "tonalRamp": ["oklch(15% 0.121 20)", "oklch(25% 0.121 20)", "oklch(35% 0.121 20)", "oklch(45% 0.121 20)", "oklch(55% 0.121 20)", "oklch(68% 0.121 20)", "oklch(80% 0.121 20)", "oklch(95% 0.121 20)"] }
},
"typographyMeta": {
"display": { "displayName": "Display", "purpose": "Product name above the card. Single instance." },
"title": { "displayName": "Title", "purpose": "Signed-in confirmation heading. Single instance." },
"body": { "displayName": "Body", "purpose": "Subtitle and running copy, usually in Mist Ink." },
"label": { "displayName": "Label", "purpose": "Field labels, 8px above the field." },
"button": { "displayName": "Button", "purpose": "Pill button label." },
"input": { "displayName": "Input", "purpose": "Typed text; 16px avoids mobile zoom." },
"message": { "displayName": "Message", "purpose": "Error and caps-lock lines under the field." }
},
"shadows": [
{ "name": "night-lift", "value": "0 18px 40px rgba(0, 3, 15, .5)", "purpose": "The sign-in card only; the single raised surface. Single instance." }
],
"focusRings": [
{ "name": "control-focus", "value": "outline: 2px solid #ec7d33; outline-offset: 2px (input, plus border-color #ec7d33), 3px (pill button), 0 (reveal icon button)", "purpose": "Keyboard focus on every interactive element; turns #ff9a9a on an invalid field." }
],
"motion": [
{ "name": "control-transition", "value": ".15s ease-out", "purpose": "Pill button border and fill on hover." },
{ "name": "gaze", "value": "transform .14s ease-out", "purpose": "Owl irises following the caret." },
{ "name": "blink", "value": "transform .08s ease-out, 160ms, every 2.5-6s", "purpose": "Owl eyelids." },
{ "name": "breathe", "value": "3.2s ease-in-out infinite, translateY(1.5px)", "purpose": "Owl idle bob." },
{ "name": "shake-no", "value": ".65s ease-in-out; glasses wobble .65s with .07s delay", "purpose": "Wrong password." },
{ "name": "tilt", "value": ".8s ease-in-out, rotate(-10deg)", "purpose": "Empty submit." },
{ "name": "hop", "value": ".75s cubic-bezier(.3, .6, .35, 1), translateY(-14px) then -3px rebound; wings flap .75s; smile-eyes .12s ease-out", "purpose": "Successful sign-in." },
{ "name": "twinkle", "value": "4s ease-in-out infinite, opacity to .15", "purpose": "About a third of the stars." },
{ "name": "reduced-motion", "value": "prefers-reduced-motion: reduce", "purpose": "All owl and star animation and transitions off, no blink, success goes straight to the signed-in panel." }
],
"breakpoints": [
{ "name": "narrow", "value": "420px", "purpose": "Owl shrinks from 212px to 172px wide." }
]
},
"components": [
{
"name": "Pill Button",
"kind": "button",
"refersTo": "button-pill",
"description": "The dark outlined primary pill, after the user's HOOT button. Full card width. The only button variant in the build.",
"html": "<button class=\"ds-pill\">Sign in</button>",
"css": ".ds-pill { width: 100%; height: 46px; background: #0a1435; color: #fff; border: 1.5px solid var(--pill-line, #c9d5f2); border-radius: 999px; font: 600 15px \"Segoe UI Variable Text\", \"Segoe UI\", system-ui, -apple-system, sans-serif; letter-spacing: .02em; cursor: pointer; transition: border-color .15s ease-out, background-color .15s ease-out; } .ds-pill:hover { border-color: var(--owl, #ec7d33); background: #101d45; } .ds-pill:active { transform: translateY(1px); } .ds-pill:focus-visible { outline: 2px solid var(--owl, #ec7d33); outline-offset: 3px; } @media (prefers-reduced-motion: reduce) { .ds-pill { transition: none; } }"
},
{
"name": "Pill Password Field",
"kind": "input",
"refersTo": "input-pill",
"description": "Recessed dark pill field with the show/hide eye inset at its right end; error state turns border and outline Soft Alarm.",
"html": "<div class=\"ds-wrap\"><label class=\"ds-label\" for=\"ds-pw\">Password</label><div class=\"ds-field\"><input class=\"ds-input\" id=\"ds-pw\" type=\"password\" value=\"hoot\"><button type=\"button\" class=\"ds-reveal\" aria-label=\"Show password\"><svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M2.5 12s3.5-6.5 9.5-6.5 9.5 6.5 9.5 6.5-3.5 6.5-9.5 6.5S2.5 12 2.5 12z\"/><circle cx=\"12\" cy=\"12\" r=\"2.8\"/></svg></button></div></div>",
"css": ".ds-wrap { width: 312px; color: var(--ink, #eef2ff); font: 15px/1.5 \"Segoe UI Variable Text\", \"Segoe UI\", system-ui, sans-serif; } .ds-label { display: block; font-weight: 600; margin-bottom: 8px; } .ds-field { position: relative; } .ds-input { width: 100%; box-sizing: border-box; height: 46px; padding: 0 52px 0 20px; background: var(--field, #050c28); color: var(--ink, #eef2ff); border: 1px solid var(--field-line, #56689c); border-radius: 999px; font: 16px \"Segoe UI Variable Text\", \"Segoe UI\", system-ui, sans-serif; letter-spacing: .04em; caret-color: var(--owl, #ec7d33); } .ds-input:focus-visible { outline: 2px solid var(--owl, #ec7d33); outline-offset: 2px; border-color: var(--owl, #ec7d33); } .ds-input[aria-invalid=\"true\"] { border-color: var(--error, #ff9a9a); outline-color: var(--error, #ff9a9a); } .ds-reveal { position: absolute; top: 4px; right: 4px; width: 38px; height: 38px; display: grid; place-items: center; padding: 0; background: none; border: 0; border-radius: 50%; color: var(--ink-2, #a9b6d8); cursor: pointer; } .ds-reveal:hover { color: var(--ink, #eef2ff); background: rgba(201, 213, 242, .1); } .ds-reveal:focus-visible { outline: 2px solid var(--owl, #ec7d33); outline-offset: 0; color: var(--ink, #eef2ff); } .ds-reveal svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }"
},
{
"name": "Field Messages",
"kind": "custom",
"description": "Error line in Soft Alarm and caps-lock note in Lamplight Orange, 14px, 8px under the field.",
"html": "<div class=\"ds-msgs\"><p class=\"ds-note\">Caps Lock is on</p><p class=\"ds-error\">That password isn't right. Try again.</p></div>",
"css": ".ds-msgs { background: var(--panel, #0c1638); padding: 12px 16px; font: 14px/1.5 \"Segoe UI Variable Text\", \"Segoe UI\", system-ui, sans-serif; } .ds-note, .ds-error { margin: 8px 0 0; } .ds-note { color: var(--owl-soft, #f5a25a); } .ds-error { color: var(--error, #ff9a9a); }"
},
{
"name": "Night Card",
"kind": "card",
"refersTo": "card",
"description": "The single raised surface: Card Navy, 1px Card Edge, 18px corners, night-lift shadow. Single instance.",
"html": "<section class=\"ds-card\"><h2 class=\"ds-title\">Run screen coming soon</h2><p class=\"ds-body\">You're signed in. This is where you'll start and watch the bot.</p></section>",
"css": ".ds-card { width: min(360px, 100%); box-sizing: border-box; padding: 28px 24px 24px; background: var(--panel, #0c1638); border: 1px solid var(--panel-line, #26335e); border-radius: 18px; box-shadow: 0 18px 40px rgba(0, 3, 15, .5); color: var(--ink, #eef2ff); font: 15px/1.5 \"Segoe UI Variable Text\", \"Segoe UI\", system-ui, sans-serif; } .ds-title { margin: 0; font-size: 20px; } .ds-body { margin: 6px 0 0; color: var(--ink-2, #a9b6d8); }"
},
{
"name": "Night Sky Header",
"kind": "custom",
"description": "Night Navy ground with small round stars, display product name and Mist Ink subtitle.",
"html": "<div class=\"ds-sky\"><span style=\"left:12%;top:20%;--c:#6ea8ff\"></span><span style=\"left:80%;top:30%;--c:#4fd1c5\"></span><span style=\"left:30%;top:78%;--c:#f29c4b\"></span><span style=\"left:66%;top:84%;--c:#dfe7ff\"></span><h1 class=\"ds-h1\">Charge Billed Automation</h1><p class=\"ds-sub\">Sign in to run the bot</p></div>",
"css": ".ds-sky { position: relative; padding: 48px 16px; background: var(--night, #040b26); color: var(--ink, #eef2ff); text-align: center; font: 15px/1.5 \"Segoe UI Variable Text\", \"Segoe UI\", system-ui, sans-serif; } .ds-sky span { position: absolute; width: 2.5px; height: 2.5px; border-radius: 50%; background: var(--c); opacity: .7; animation: ds-twinkle 4s ease-in-out infinite; } @keyframes ds-twinkle { 50% { opacity: .15; } } .ds-h1 { margin: 0; font-size: clamp(24px, 6vw, 30px); font-weight: 650; line-height: 1.2; letter-spacing: -.01em; } .ds-sub { margin: 8px 0 0; color: var(--ink-2, #a9b6d8); } @media (prefers-reduced-motion: reduce) { .ds-sky span { animation: none; } }"
}
],
"narrative": {
"northStar": "The Owl's Night Watch",
"overview": "A calm night sky, one lit card, and a smooth, softly shaded orange owl perched on its top edge who watches you type. Everything around the owl is quiet and dark: deep navy ground, a few small round stars, dark outlined pill controls, and the platform's own UI face. The owl is the only warm thing on the screen and the only thing that moves with purpose; its reactions (eyes following the caret, a head-shake on a wrong password, a hop on success) carry the feedback alongside plain text, never instead of it.\n\nThe world is rendered natural, not game-like. The user explicitly rejected a pixel-art or game look (\"it must not look like a game, be natural\"): shapes are smooth vector curves with radial-gradient shading, stars are soft round dots, motion is short and eased. This is an Operate tool for an ops team, so density stays low and copy stays plain.\n\nThe system has been built on one surface so far (the sign-in page). Anything below described as a single instance has only that one use in the build and should be treated as provisional, not a pattern.",
"keyCharacteristics": [
"Deep navy night ground with a sparse, seeded field of small round stars, kept clear of text and controls.",
"One warm accent, owl orange, reserved for the owl, focus rings, caret, selection and the hover border.",
"Dark outlined pill controls for both the field and the button, after the user's HOOT button.",
"Platform UI face for every text role, including the product name.",
"A smooth shaded owl mascot whose states are the page's expressive feedback; reduced motion turns them all off."
],
"rules": [
{ "name": "The One Warm Thing Rule", "body": "Orange belongs to the owl. In the UI it appears only as a signal (focus, caret, selection, hover border, the caps-lock note); controls and surfaces stay navy.", "section": "colors" },
{ "name": "The Clear Sky Rule", "body": "Stars never sit behind text, the owl or the card; they are placed with a 10px keep-out around each and redrawn on resize from a fixed seed so they do not jump.", "section": "colors" },
{ "name": "The Single Lift Rule", "body": "One raised surface per screen; controls are outlined, not shadowed.", "section": "elevation" }
],
"dos": [
"Do keep the ground Night Navy and let the owl be the only warm, shaded object on screen.",
"Do use Owl Orange for focus rings (2px outline) on every interactive element.",
"Do build controls as dark outlined pills (999px, 46px tall) for both fields and primary buttons.",
"Do say in text whatever the owl expresses; the owl is decoration with feedback, never the only feedback.",
"Do give every owl or star animation a reduced-motion path that turns it off.",
"Do keep stars small (1.5 to 3px), round, sparse, seeded and clear of text and controls.",
"Do use clearly fake sample data in any design, mockup or screenshot (real run output is PHI)."
],
"donts": [
"Don't make it look like a game: no pixel art, stepped edges, chunky pixel fonts or arcade effects (user decision, 22 Oct).",
"Don't fill controls with orange; orange is a signal, not a surface.",
"Don't add shadows to controls; the card is the only lifted object.",
"Don't add a second type family for display; hierarchy comes from weight and size in the platform face."
]
}
}
+1 -1
View File
@@ -19,6 +19,6 @@ STORY: The ops user sees the owl, types the G2 password, and the owl's eyes foll
FIRST VIEWPORT: Centered column. Product name "Charge Billed Automation", then the card with the owl perched on its top edge (feet on the border), password field with show/hide, full-width pill Sign in. The night sky fills the viewport.
FORM: Pinned by the user (owl screenshot); no roll was run. seed: none (user-pinned direction)
FORM: The user's pinned owl world (their screenshot, then "be natural", not game-like) governs; the roll was run for the record and does not override it. seed:60012e4e290e73f6
FINISH: unreviewed and undocumented is unfinished; this build ends with the finish review, the verdict, DESIGN.md, and every shipping raster carrying its provenance
+233
View File
@@ -0,0 +1,233 @@
---
name: Charge Billed Automation
description: A local ops tool for running the Charge Billed bot, set in a quiet night sky watched by an orange owl.
colors:
night: "#040b26"
panel: "#0c1638"
panel-line: "#26335e"
field: "#050c28"
field-line: "#56689c"
pill-fill: "#0a1435"
pill-fill-hover: "#101d45"
pill-line: "#c9d5f2"
pill-text: "#ffffff"
ink: "#eef2ff"
ink-2: "#a9b6d8"
owl: "#ec7d33"
owl-soft: "#f5a25a"
error: "#ff9a9a"
typography:
display:
fontFamily: "Segoe UI Variable Text, Segoe UI, system-ui, -apple-system, sans-serif"
fontSize: "clamp(24px, 6vw, 30px)"
fontWeight: 650
lineHeight: 1.2
letterSpacing: "-0.01em"
title:
fontFamily: "Segoe UI Variable Text, Segoe UI, system-ui, -apple-system, sans-serif"
fontSize: "20px"
fontWeight: 700
body:
fontFamily: "Segoe UI Variable Text, Segoe UI, system-ui, -apple-system, sans-serif"
fontSize: "15px"
fontWeight: 400
lineHeight: 1.5
label:
fontFamily: "Segoe UI Variable Text, Segoe UI, system-ui, -apple-system, sans-serif"
fontSize: "15px"
fontWeight: 600
lineHeight: 1.5
button:
fontFamily: "Segoe UI Variable Text, Segoe UI, system-ui, -apple-system, sans-serif"
fontSize: "15px"
fontWeight: 600
letterSpacing: "0.02em"
input:
fontFamily: "Segoe UI Variable Text, Segoe UI, system-ui, -apple-system, sans-serif"
fontSize: "16px"
fontWeight: 400
letterSpacing: "0.04em"
message:
fontFamily: "Segoe UI Variable Text, Segoe UI, system-ui, -apple-system, sans-serif"
fontSize: "14px"
fontWeight: 400
lineHeight: 1.5
rounded:
card: "18px"
pill: "999px"
round: "50%"
spacing:
tight: "8px"
control-gap: "20px"
card: "24px"
components:
button-pill:
backgroundColor: "{colors.pill-fill}"
textColor: "{colors.pill-text}"
typography: "{typography.button}"
rounded: "{rounded.pill}"
height: "46px"
width: "100%"
button-pill-hover:
backgroundColor: "{colors.pill-fill-hover}"
input-pill:
backgroundColor: "{colors.field}"
textColor: "{colors.ink}"
typography: "{typography.input}"
rounded: "{rounded.pill}"
padding: "0 52px 0 20px"
height: "46px"
width: "100%"
icon-button-reveal:
textColor: "{colors.ink-2}"
rounded: "{rounded.round}"
size: "38px"
card:
backgroundColor: "{colors.panel}"
rounded: "{rounded.card}"
padding: "28px 24px 24px"
width: "min(360px, 100%)"
---
# Design System: Charge Billed Automation
## Overview
**Creative North Star: "The Owl's Night Watch"**
A calm night sky, one lit card, and a smooth, softly shaded orange owl perched on its top edge who watches you type. Everything around the owl is quiet and dark: deep navy ground, a few small round stars, dark outlined pill controls, and the platform's own UI face. The owl is the only warm thing on the screen and the only thing that moves with purpose; its reactions (eyes following the caret, a head-shake on a wrong password, a hop on success) carry the feedback alongside plain text, never instead of it.
The world is rendered natural, not game-like. The user explicitly rejected a pixel-art or game look ("it must not look like a game, be natural"): shapes are smooth vector curves with radial-gradient shading, stars are soft round dots, motion is short and eased. This is an Operate tool for an ops team, so density stays low and copy stays plain.
The system has been built on one surface so far (the sign-in page). Anything below described as a single instance has only that one use in the build and should be treated as provisional, not a pattern.
**Key Characteristics:**
- Deep navy night ground with a sparse, seeded field of small round stars, kept clear of text and controls.
- One warm accent, owl orange, reserved for the owl, focus rings, caret, selection and the hover border.
- Dark outlined pill controls for both the field and the button, after the user's HOOT button.
- Platform UI face for every text role, including the product name.
- A smooth shaded owl mascot whose states are the page's expressive feedback; reduced motion turns them all off.
## Colors
A cold, near-monochrome navy ramp lit by a single warm orange; the warmth belongs to the owl.
### Primary
- **Owl Orange** (`owl`): the owl's mid-tone and the system's only accent. Used for focus outlines on every control, the hover border on the pill button, the text caret, and the text-selection background (with Night as the selected text). It is never a fill for controls.
- **Lamplight Orange** (`owl-soft`): the gentler orange for advisory text, currently only the "Caps Lock is on" note (single instance).
### Neutral
- **Night Navy** (`night`): the page ground and the sky. Also the scrollbar track.
- **Card Navy** (`panel`): the one raised surface, the sign-in card.
- **Card Edge** (`panel-line`): the card's 1px border and the scrollbar thumb.
- **Well Navy** (`field`): the input fill, slightly darker than the card so the field reads as recessed.
- **Field Edge** (`field-line`): the input's resting 1px border (about 3.4:1 against the field).
- **Button Navy** (`pill-fill`) and **Button Navy Lifted** (`pill-fill-hover`): the pill button's fill at rest and on hover. These live as literal values in the button rule, not as custom properties.
- **Moonlight Edge** (`pill-line`): the button's 1.5px outline. At 10% alpha it is also the reveal icon's hover wash.
- **Starlight Ink** (`ink`): primary text and input text.
- **Mist Ink** (`ink-2`): secondary text (the subtitle, body copy under the signed-in title) and the resting reveal icon.
- **Pure White** (`pill-text`): the pill button label only.
### Semantic
- **Soft Alarm** (`error`): error message text and the invalid field's border and focus outline. A light coral chosen to read on navy, not a saturated red.
### Star field
Stars are drawn by script from four colors (Sky Blue `#6ea8ff`, Teal `#4fd1c5`, Ember `#f29c4b`, Frost `#dfe7ff`), 1.5 to 3px, 0.45 to 0.9 opacity, about a third twinkling. These are illustration values, not UI tokens.
### Named Rules
**The One Warm Thing Rule.** Orange belongs to the owl. In the UI it appears only as a signal (focus, caret, selection, hover border, the caps-lock note); controls and surfaces stay navy.
**The Clear Sky Rule.** Stars never sit behind text, the owl or the card; they are placed with a 10px keep-out around each and redrawn on resize from a fixed seed so they do not jump.
## Typography
**Display Font:** Segoe UI Variable Text (with Segoe UI, system-ui, -apple-system, sans-serif)
**Body Font:** the same stack
**Label/Mono Font:** none distinct
**Character:** One platform face for everything, as the direction contract specifies for this Windows-hosted ops tool. Hierarchy comes from weight and size, not from a second family.
### Hierarchy
- **Display** (650, clamp(24px, 6vw, 30px), 1.2, -0.01em, balanced wrapping): the product name above the card. Single instance.
- **Title** (700, 20px): the signed-in confirmation heading. Single instance.
- **Body** (400, 15px, 1.5): subtitle and running copy, usually in Mist Ink.
- **Label** (600, 15px): field labels, 8px above the field.
- **Button** (600, 15px, 0.02em): the pill button label.
- **Input** (400, 16px, 0.04em): typed text; 16px keeps mobile browsers from zooming.
- **Message** (400, 14px): the error and caps-lock lines under the field.
## Layout
A single centered column on a full-viewport sky. The column is anchored a fixed distance above mid-screen (top padding `max(32px, 50vh - 250px)`, 16px sides, 48px bottom) rather than vertically centered, so a message appearing in the card grows the card downward instead of moving the owl. The card is `min(360px, 100%)` wide, with its top margin reserving the owl's height (owl width × 150/160 + 12px) so the owl perches on the card's top edge with its feet 7px over the border.
Spacing is small and repeated: 8px between label and field, title and subtitle, and field and message lines; 20px between the field block and the button; 24px card padding (28px at top). Card content is left-aligned inside a centered page.
One breakpoint: at 420px and below the owl shrinks from 212px to 172px wide; nothing else reflows.
## Elevation & Depth
Mostly tonal: the night ground, the slightly lighter card, and the slightly darker recessed field carry the layering. The card is the one lifted object, with a single deep, soft ambient shadow that sinks it into the night rather than floating it. Under the owl a faint orange radial glow grounds it on the card. No other element casts a shadow.
### Shadow Vocabulary
- **Night lift** (`box-shadow: 0 18px 40px rgba(0, 3, 15, .5)`): the sign-in card only. Single instance.
### Named Rules
**The Single Lift Rule.** One raised surface per screen; controls are outlined, not shadowed.
## Shapes
Full round pills (999px) for both the field and the primary button; the reveal icon button is a 38px circle inset 4px into the field's right end. The card uses a gently rounded 18px corner with a 1px border. The owl is all smooth curves: dome head with ear tufts, egg body, round eyes and round glasses. Stars are circles. Nothing in the system is square-cornered or stepped.
## Components
### Buttons
Dark, outlined and calm, after the user's HOOT button.
- **Shape:** full pill (999px), 46px tall, full card width.
- **Primary (pill):** Button Navy fill, Pure White label (600, 15px, 0.02em), 1.5px Moonlight Edge outline, 20px above it.
- **Hover:** border turns Owl Orange and the fill lifts to Button Navy Lifted, over 0.15s ease-out.
- **Active:** nudges down 1px.
- **Focus:** 2px Owl Orange outline, 3px offset.
- The only button variant in the build; there is no secondary or ghost button yet.
### Inputs / Fields
- **Style:** Well Navy fill, 1px Field Edge border, full pill (999px), 46px tall, 20px left padding and 52px right padding to clear the reveal button; Starlight Ink text at 16px with 0.04em tracking. Label sits above in Label weight.
- **Focus:** 2px Owl Orange outline at 2px offset and the border also turns Owl Orange.
- **Error:** when invalid, the border and focus outline turn Soft Alarm, and a Soft Alarm message (14px) appears 8px below; the message is announced and clears as soon as the user types.
- **Caps Lock:** a Lamplight Orange note, "Caps Lock is on", appears below while the key is on and hides on blur.
- **Reveal (show/hide password):** a 38px circular icon button inside the field's right end, Mist Ink at rest; on hover Starlight Ink with a 10% Moonlight wash; focus is a 2px Owl Orange outline at 0 offset. The icon is a standard 24-unit stroke eye (20px, 1.8 stroke, round caps and joins) that swaps to eye-off; it does not steal focus from the field. This is the build's only icon.
### Cards / Containers
- **Corner Style:** 18px.
- **Background:** Card Navy, 1px Card Edge border.
- **Shadow Strategy:** Night lift (see Elevation & Depth).
- **Internal Padding:** 28px top, 24px sides and bottom.
- Single instance: the sign-in card, which hosts the owl on its top edge.
### The Owl (signature component)
An inline SVG (viewBox 160×150, 212px wide, 172px at 420px and below), smooth and shaded with named gradients: fur (`#f8ad66` → `#ee7f36` → `#c55a1f`), darker wings (`#df6f2c` → `#b14e1a`), cream face disc (`#fff1df` → `#f2cba1`), peach belly (`#fbd6a9` → `#efb072`) with faint chevron feather marks, brown irises (`#b8692c` → `#6a3211`) with near-black pupils and white catchlights, a gradient beak, small orange feet, and round near-black glasses (`#1d1b20`) with a soft white glint. It is decorative (`aria-hidden`); every state it shows is also stated in text.
States:
- **Idle:** a breathing bob of 1.5px over 3.2s, continuous.
- **Blink:** eyelids close for 160ms at random 2.5 to 6s intervals; skipped during the success hop.
- **Gaze:** while the password field has focus, the irises look down and slide from left to right as the typed text (or masked dots) fills the field, tracking the caret; they recenter on blur.
- **Empty submit (tilt):** the head tilts -10deg and back over 0.8s.
- **Wrong password (no):** a 0.65s damped head-shake, with the glasses wobbling on a 70ms delay so they lag the head.
- **Success (hop):** a 0.75s hop (14px, then a 3px rebound), both wings flap, and the eyes close into upward smile arcs; then the signed-in panel replaces the form and receives focus.
- **Reduced motion:** all owl and star animation and transitions are off, blinking stops, and success goes straight to the signed-in panel. The gaze still repositions, without easing.
## Do's and Don'ts
### Do:
- **Do** keep the ground Night Navy and let the owl be the only warm, shaded object on screen.
- **Do** use Owl Orange for focus rings (2px outline) on every interactive element.
- **Do** build controls as dark outlined pills (999px, 46px tall) for both fields and primary buttons.
- **Do** say in text whatever the owl expresses; the owl is decoration with feedback, never the only feedback.
- **Do** give every owl or star animation a reduced-motion path that turns it off.
- **Do** keep stars small (1.5 to 3px), round, sparse, seeded and clear of text and controls.
- **Do** use clearly fake sample data in any design, mockup or screenshot (real run output is PHI).
### Don't:
- **Don't** make it look like a game: no pixel art, stepped edges, chunky pixel fonts or arcade effects (user decision, 22 Oct).
- **Don't** fill controls with orange; orange is a signal, not a surface.
- **Don't** add shadows to controls; the card is the only lifted object.
- **Don't** add a second type family for display; hierarchy comes from weight and size in the platform face.
+30 -15
View File
@@ -17,7 +17,7 @@
--owl: #ec7d33;
--owl-soft: #f5a25a;
--error: #ff9a9a;
--owl-w: 188px;
--owl-w: 212px;
--ui: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, sans-serif;
color-scheme: dark;
scrollbar-color: var(--panel-line) var(--night);
@@ -51,8 +51,8 @@
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 32px 16px 48px;
/* Anchored near the middle rather than centered, so an error line grows the card downward instead of moving the owl. */
padding: max(32px, calc(50vh - 250px)) 16px 48px;
text-align: center;
}
h1 {
@@ -100,7 +100,7 @@
letter-spacing: .04em;
}
input:focus-visible { outline: 2px solid var(--owl); outline-offset: 2px; border-color: var(--owl); }
input[aria-invalid="true"] { border-color: var(--error); }
input[aria-invalid="true"] { border-color: var(--error); outline-color: var(--error); }
.reveal {
position: absolute;
top: 4px;
@@ -163,7 +163,8 @@
.iris { transition: transform .14s ease-out; }
.lid { transform-box: fill-box; transform-origin: 50% 0; transform: scaleY(0); transition: transform .08s ease-out; }
.owl.blink .lid { transform: scaleY(1); }
.owl.happy .lid { transform: scaleY(.55); }
.smile { transform-box: fill-box; transform-origin: 50% 100%; transform: scaleY(0); transition: transform .12s ease-out; }
.owl.happy .smile { transform: none; }
.owl.idle #bob { animation: breathe 3.2s ease-in-out infinite; }
@keyframes breathe { 50% { transform: translateY(1.5px); } }
@@ -193,7 +194,7 @@
@keyframes flap-r { 20%, 60% { transform: rotate(-32deg); } 40%, 80% { transform: rotate(-8deg); } }
@media (max-width: 420px) {
:root { --owl-w: 164px; }
:root { --owl-w: 172px; }
}
@media (prefers-reduced-motion: reduce) {
.sky .tw, .owl, .owl * { animation: none !important; transition: none !important; }
@@ -229,10 +230,14 @@
<linearGradient id="beak" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#f4a142"/><stop offset="1" stop-color="#cf6620"/>
</linearGradient>
<radialGradient id="glow">
<stop offset="0" stop-color="#ffaa5a" stop-opacity=".35"/><stop offset="1" stop-color="#ffaa5a" stop-opacity="0"/>
</radialGradient>
<clipPath id="eye-l"><circle cx="59" cy="59" r="16"/></clipPath>
<clipPath id="eye-r"><circle cx="101" cy="59" r="16"/></clipPath>
</defs>
<ellipse cx="80" cy="146" rx="54" ry="8" fill="url(#glow)"/>
<g id="body">
<path fill="url(#fur)" d="M80 66C114 66 136 90 134 116C132 136 110 146 80 146C50 146 28 136 26 116C24 90 46 66 80 66Z"/>
<ellipse cx="80" cy="116" rx="30" ry="24" fill="url(#belly)"/>
@@ -253,7 +258,7 @@
</g>
<g id="bob"><g id="head">
<path fill="url(#fur)" d="M32 38C29 24 32 12 38 5C44 16 52 22 60 22ZM128 38C131 24 128 12 122 5C116 16 108 22 100 22Z"/>
<path fill="url(#fur)" d="M33 38C29 26 31 14 37 8C40 6 42 9 45 14C49 19 54 22 60 22ZM127 38C131 26 129 14 123 8C120 6 118 9 115 14C111 19 106 22 100 22Z"/>
<path fill="url(#fur)" d="M80 10C112 10 138 30 138 58C138 82 114 98 80 98C46 98 22 82 22 58C22 30 48 10 80 10Z"/>
<path fill="none" stroke="#f9b978" stroke-width="2" stroke-linecap="round" opacity=".7" d="M62 22q4-5 9-2M77 17q4-4 8 0M90 20q4-3 8 1"/>
<path fill="url(#face)" d="M80 34C96 26 124 30 128 54C132 76 112 92 94 88C88 87 84 90 80 94C76 90 72 87 66 88C48 92 28 76 32 54C36 30 64 26 80 34Z"/>
@@ -262,11 +267,13 @@
<circle cx="59" cy="59" r="16" fill="#fffaf2"/>
<g class="iris"><circle cx="59" cy="59" r="10.5" fill="url(#iris)"/><circle cx="59" cy="59" r="5.5" fill="#1b0e08"/><circle cx="55" cy="55" r="3" fill="#fff"/><circle cx="62.5" cy="62.5" r="1.4" fill="#fff" opacity=".8"/></g>
<rect class="lid" x="43" y="43" width="32" height="32" fill="#eebc8d"/>
<g class="smile"><path fill="#eebc8d" d="M43 63Q59 49 75 63L75 76L43 76Z"/><path fill="none" stroke="#6a3211" stroke-width="1.6" stroke-linecap="round" d="M45 62Q59 50 73 62"/></g>
</g>
<g clip-path="url(#eye-r)">
<circle cx="101" cy="59" r="16" fill="#fffaf2"/>
<g class="iris"><circle cx="101" cy="59" r="10.5" fill="url(#iris)"/><circle cx="101" cy="59" r="5.5" fill="#1b0e08"/><circle cx="97" cy="55" r="3" fill="#fff"/><circle cx="104.5" cy="62.5" r="1.4" fill="#fff" opacity=".8"/></g>
<rect class="lid" x="85" y="43" width="32" height="32" fill="#eebc8d"/>
<g class="smile"><path fill="#eebc8d" d="M85 63Q101 49 117 63L117 76L85 76Z"/><path fill="none" stroke="#6a3211" stroke-width="1.6" stroke-linecap="round" d="M87 62Q101 50 115 62"/></g>
</g>
<path fill="url(#beak)" d="M75 72C77 68 83 68 85 72C84 78 82 83 80 86C78 83 76 78 75 72Z"/>
@@ -274,9 +281,9 @@
<g id="glasses" fill="none" stroke-linecap="round">
<path stroke="#fff" stroke-width="2.2" opacity=".5" d="M46 47Q52 41 60 41M88 47Q94 41 102 41"/>
<g stroke="#1d1b20">
<circle cx="59" cy="58" r="20" stroke-width="4.5"/>
<circle cx="101" cy="58" r="20" stroke-width="4.5"/>
<path stroke-width="4" d="M77.5 54Q80 50 82.5 54M39.5 52L28 48M120.5 52L132 48"/>
<circle cx="59" cy="58" r="20" stroke-width="2.4"/>
<circle cx="101" cy="58" r="20" stroke-width="2.4"/>
<path stroke-width="2.2" d="M78.5 54Q80 51.5 81.5 54M39 52L28 48M121 52L132 48"/>
</g>
</g>
</g></g>
@@ -318,17 +325,25 @@ const done = document.getElementById("done");
const irises = owl.querySelectorAll(".iris");
const reducedMotion = matchMedia("(prefers-reduced-motion: reduce)");
(function drawSky(el) {
// Seeded so the stars stay put; none behind the text, owl or card.
function drawSky() {
let seed = 7;
const rand = () => (seed = (seed * 16807) % 2147483647) / 2147483647;
const colors = ["#6ea8ff", "#4fd1c5", "#f29c4b", "#dfe7ff"];
const keepOut = [...document.querySelectorAll("h1, .sub, .card, .owl")].map(e => e.getBoundingClientRect());
let html = "";
for (let i = 0; i < 60; i++) {
html += `<span class="${rand() < .35 ? "tw" : ""}" style="left:${(rand() * 100).toFixed(2)}%;top:${(rand() * 100).toFixed(2)}%;` +
`--s:${(1.5 + rand() * 1.5).toFixed(1)}px;--c:${colors[Math.floor(rand() * 4)]};--o:${(.45 + rand() * .45).toFixed(2)};--d:${(rand() * 4).toFixed(2)}s"></span>`;
const tw = rand() < .35, x = rand() * innerWidth, y = rand() * innerHeight;
const size = (1.5 + rand() * 1.5).toFixed(1), color = colors[Math.floor(rand() * 4)];
const alpha = (.45 + rand() * .45).toFixed(2), delay = (rand() * 4).toFixed(2);
if (keepOut.some(r => x > r.left - 10 && x < r.right + 10 && y > r.top - 10 && y < r.bottom + 10)) continue;
html += `<span class="${tw ? "tw" : ""}" style="left:${x.toFixed(0)}px;top:${y.toFixed(0)}px;` +
`--s:${size}px;--c:${color};--o:${alpha};--d:${delay}s"></span>`;
}
el.innerHTML = html;
})(document.getElementById("sky"));
document.getElementById("sky").innerHTML = html;
}
drawSky();
addEventListener("resize", drawSky);
function look(dx, dy) {
irises.forEach(g => { g.style.transform = `translate(${dx}px, ${dy}px)`; });